diff --git a/CHANGELOG.md b/CHANGELOG.md index add4b86e..55360adf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ The format is loosely inspired by Keep a Changelog. ### Changed +- **Web 0.15.1, third hint and robot game moved:** eight harder exercises get a third hint that gives the outline of the solution box by box (L9 Schaltjahr, L10 Taschenrechner, L12 Summe bis 0, L14 Rechteck, L15 Summe und Maximum, L17 Rückwärts and Wörter zählen, L19 Absteigend sortieren; de/en/pt, with the variable names of each language). Students working alone are no longer stuck after two hints; the sample solution stays teacher-only. VisuBot: the game „Wo landet der mBot2?“ moves from lesson 1 „Struktogramm und Editor“ (where the commands with numbers in brackets were not explained yet) to lesson 2 „Der mBot2“, right after „Befehle für den mBot2“ and „Erste Fahrt“ (de/en). Saved step positions in these two lessons may shift by one. - **Web 0.15.0, release:** version number only, no further changes. 0.15.0 bundles everything since 0.14.x: VisuBot as a robotics-only world with its own basic lessons, a game in every lesson, repaired lesson steps (0.14.34) and lessons that are easier for self-study (0.14.35). - **Web 0.14.35, lessons easier for self-study:** VisuBot lesson 3 gets a new step „So sieht Java aus“ before the first Java exercise: where the Code area is, the square with a variable in Java, semicolons, the `for` head, curly brackets, upper and lower case, and how to solve a Java exercise (Im Editor öffnen, type, Prüfen); plus a Kompetenz and checklist item. VisuBot lesson 2 explains the counter `i` of the for loop (what `int i = 0`, `i < 5`, `i++` mean, table of the five runs). VisuBot says `true`/`false` like the editor instead of Ja/Nein (lesson text, hints, tasks). VisuBot lesson 1 (Struktogramm und Editor) says that every exercise ends with Prüfen, often in several worlds, and that the hints help. VisuStruct lesson 4 explains `"Text: " + variable` in the lesson text before the exercise „Rechteck“ (before, only its second hint did). Lesson 2 names the tool buttons Kopieren, Einfügen and Rückgängig for tablets without a keyboard and points to the Simulation button. The tasks of lessons 29–40 get a list „Du bist fertig, wenn …“ with things you can see in the window, so students working alone know when they are done (de/en/pt; VisuBot de/en). - **Web 0.14.34, broken lesson steps repaired:** lesson 3 step „Ausprobieren“ ended with „probiere Folgendes aus:“ and no list, and the checklist sat in the same step without its own heading; now there are four things to try (title, save in the workspace, open again in a second tab, export PNG and PDF), the step comes before the game, and „Checkliste“ is its own step (de/en/pt). VisuBot lesson „Sensoren“ step „Was liefert der Sensor?“ had no text; it now explains that a sensor gives a value, that a comparison turns it into `true` or `false` (table with three conditions), the comparison operators and `==` vs. `=` (de/en). The cloze explanation in lesson 4 pointed to a lesson „Java“; it is called „Struktogramm und Code“ (de/en/pt). New tests: the checklist stands in its own step „Checkliste“, and no text ends with a colon with nothing after it. diff --git a/web/lessons/de/09-bedingungen-verknuepfen.md b/web/lessons/de/09-bedingungen-verknuepfen.md index d6f10467..0ecd38fc 100644 --- a/web/lessons/de/09-bedingungen-verknuepfen.md +++ b/web/lessons/de/09-bedingungen-verknuepfen.md @@ -179,6 +179,7 @@ test: 2000 -> Schaltjahr braucht: verzweigung tipp: Prüfe die Regel zuerst an Beispielen: 2024 ist ein Schaltjahr, 1900 nicht, 2000 schon. Teilbar heißt: Der Rest ist 0. tipp: Teilbar durch 4 heißt `jahr % 4 == 0`, nicht teilbar durch 100 heißt `jahr % 100 != 0`. Verbinde diese beiden mit `&&`, setze Klammern darum und hänge mit `||` den Fall für 400 an. +tipp: Fast die Lösung: Eine einzige Verzweigung mit der Bedingung `(jahr % 4 == 0 && jahr % 100 != 0) || jahr % 400 == 0`. Im true-Zweig steht `output: "Schaltjahr"`, im false-Zweig `output: "kein Schaltjahr"`. lösung: l08-schaltjahr-loesung.visustruct ::: diff --git a/web/lessons/de/10-fallauswahl.md b/web/lessons/de/10-fallauswahl.md index 69a93314..e1ceb0b1 100644 --- a/web/lessons/de/10-fallauswahl.md +++ b/web/lessons/de/10-fallauswahl.md @@ -76,6 +76,7 @@ test: 1, x, 2 -> Unbekanntes Rechenzeichen braucht: fallauswahl tipp: Lies erst alle drei Werte ein. Danach entscheidet eine Fallauswahl über das Rechenzeichen, was gerechnet wird. tipp: Lege vor der Fallauswahl `int ergebnis = 0` an. In jedem Fall rechnest du zum Beispiel `ergebnis = a + b` und gibst danach `ergebnis` aus. Die Fallnamen sind `"+"`, `"-"` und `"*"` in Anführungszeichen, weil das Rechenzeichen ein `String` ist. +tipp: Das Gerüst von oben nach unten: drei Eingaben (`int a`, `String zeichen`, `int b`), dann `int ergebnis = 0`, dann eine Fallauswahl über `zeichen`. Im Fall `"+"` stehen `ergebnis = a + b` und `output: ergebnis`, bei `"-"` und `"*"` genauso. Im Sonst-Fall steht `output: "Unbekanntes Rechenzeichen"`. lösung: l09-rechner-loesung.visustruct ::: diff --git a/web/lessons/de/12-do-while-schleife.md b/web/lessons/de/12-do-while-schleife.md index ea7b5553..2953f0b4 100644 --- a/web/lessons/de/12-do-while-schleife.md +++ b/web/lessons/de/12-do-while-schleife.md @@ -80,6 +80,7 @@ test: 0 -> 0 braucht: doUntilSchleife tipp: Du brauchst eine Variable für die Summe, die vor der Schleife bei 0 beginnt. In jedem Durchlauf kommt die neue Zahl dazu. tipp: Lege vor der Schleife `int summe = 0` und `int zahl = 0` an. In der Schleife fragst du `zahl` ab und rechnest `summe = summe + zahl`. Die 0 zu addieren schadet nicht. Die Schleife läuft weiter, solange `zahl != 0` ist. +tipp: Das Gerüst: `int summe = 0` und `int zahl = 0`, dann eine Do-while-Schleife mit der Bedingung `zahl != 0`. In ihr stehen die Eingabe von `zahl` und `summe = summe + zahl`. Unter der Schleife steht `output: summe`. lösung: l11-summe-loesung.visustruct ::: diff --git a/web/lessons/de/14-verschachteln.md b/web/lessons/de/14-verschachteln.md index c2415976..62b0050d 100644 --- a/web/lessons/de/14-verschachteln.md +++ b/web/lessons/de/14-verschachteln.md @@ -74,6 +74,7 @@ test: 2, 2 -> ## | ## braucht: forSchleife tipp: Du brauchst zwei Schleifen ineinander: eine für die Zeilen und darin eine für die Zeichen einer Zeile. tipp: Baue es wie das Dreieck. Der Unterschied: Die innere Schleife zählt immer bis `breite`, nicht bis zur Zeilennummer. Die äußere Schleife zählt bis `hoehe`. +tipp: Das Gerüst: Eingaben `breite` und `hoehe`. Äußere For-Schleife `int zeile = 1`, `zeile <= hoehe`, `zeile++`. Darin zuerst `String text = ""`, dann die innere For-Schleife `int spalte = 1`, `spalte <= breite`, `spalte++` mit `text = text + "#"`, und unter der inneren Schleife `output: text`. lösung: l13-rechteck-loesung.visustruct ::: diff --git a/web/lessons/de/15-arrays.md b/web/lessons/de/15-arrays.md index 282e7923..ac126a3f 100644 --- a/web/lessons/de/15-arrays.md +++ b/web/lessons/de/15-arrays.md @@ -148,6 +148,7 @@ test: -5, -2, -9, -1, -3 -> Summe: -20 | Maximum: -1 braucht: forSchleife, verzweigung tipp: Gehe das Array mit einer Schleife durch. Zähle jeden Wert zur Summe und merke dir den größten bisher gesehenen Wert. tipp: Rechne Summe und Maximum in eigenen Variablen aus und gib sie erst am Ende aus, z. B. mit `output: "Summe: " + summe`. Beginnt dein Maximum bei 0, scheitert der dritte Test. +tipp: Das Gerüst: Array anlegen und mit einer Schleife einlesen. Dann `int summe = 0` und `int max = zahlen[0]`. Eine zweite Schleife rechnet `summe = summe + zahlen[i]`, und eine Verzweigung `zahlen[i] > max` setzt im true-Zweig `max = zahlen[i]`. Zum Schluss die beiden Ausgaben. lösung: l14-summe-max-loesung.visustruct ::: diff --git a/web/lessons/de/17-zeichenketten.md b/web/lessons/de/17-zeichenketten.md index 067fb45f..cf127b50 100644 --- a/web/lessons/de/17-zeichenketten.md +++ b/web/lessons/de/17-zeichenketten.md @@ -145,6 +145,7 @@ test: a -> a braucht: forSchleife tipp: Gehe das Wort Zeichen für Zeichen durch, aber von hinten nach vorn, und baue dabei einen neuen Text zusammen. tipp: Lege `String rueckwaerts = ""` an. Die Schleife beginnt beim letzten Index `wort.length() - 1` und zählt mit `i--` bis 0 herunter. In jedem Durchlauf hängst du `wort.charAt(i)` hinten an. +tipp: Das Gerüst: Eingabe `wort`, dann `String rueckwaerts = ""`. For-Schleife mit Start `int i = wort.length() - 1`, Bedingung `i >= 0` und Schritt `i--`. Darin `rueckwaerts = rueckwaerts + wort.charAt(i)`. Unter der Schleife `output: rueckwaerts`. lösung: zk-rueckwaerts-loesung.visustruct ::: @@ -159,6 +160,7 @@ test: Struktogramme machen Spaß -> Wörter: 3 braucht: anweisung tipp: Zwischen den Wörtern steht immer ein Leerzeichen. Welche Methode zerlegt einen Text an einem Zeichen? tipp: Zerlege den Satz mit `satz.split(" ")` in ein String-Array. Seine Länge ist die Anzahl der Wörter. +tipp: Das ganze Programm hat drei Kästen: die Eingabe `satz`, dann `String[] woerter = satz.split(" ")` und zum Schluss `output: "Wörter: " + woerter.length`. lösung: zk-woerter-loesung.visustruct ::: diff --git a/web/lessons/de/19-suchen-und-sortieren.md b/web/lessons/de/19-suchen-und-sortieren.md index ffb329af..c72fe26e 100644 --- a/web/lessons/de/19-suchen-und-sortieren.md +++ b/web/lessons/de/19-suchen-und-sortieren.md @@ -121,6 +121,7 @@ test: 2, 9, 2, 7, 6 -> 9 | 7 | 6 | 2 | 2 braucht: forSchleife, verzweigung tipp: Schau dir die Bedingung in der Verzweigung an. Sie entscheidet, wann zwei Nachbarn getauscht werden. tipp: Du musst nur ein einziges Zeichen ändern. Wann sollen zwei Nachbarn getauscht werden, wenn die größere Karte nach links soll? +tipp: Ändere in der Verzweigung `karten[i] > karten[i + 1]` in `karten[i] < karten[i + 1]`. Dann wird getauscht, wenn rechts die größere Karte liegt, und die große Karte wandert nach links. lösung: ss-absteigend-loesung.visustruct ::: diff --git a/web/lessons/de/visubot/00-struktogramm-und-editor.md b/web/lessons/de/visubot/00-struktogramm-und-editor.md index 6cef656c..c41423bc 100644 --- a/web/lessons/de/visubot/00-struktogramm-und-editor.md +++ b/web/lessons/de/visubot/00-struktogramm-und-editor.md @@ -118,48 +118,6 @@ richtig: Sequenz > Zwei Schritte nacheinander, ohne Bedingung und ohne Wiederholung. ::: -## Spiel: Wo landet der mBot2? - -::: spiel fahrt -titel: Spiel: Wo landet der mBot2? -intro: Lies das Programm und tippe auf das Feld, auf dem der mBot2 am Ende steht. Danach fährt er die Strecke vor. Jedes Feld ist 30 cm groß. Vier Runden. -frage: Auf welchem Feld steht der mBot2 am Ende? - -runde: - mbot.forward(60); - mbot.turnRight(); - mbot.forward(30); -karte: ..... | ..... | ..^.. -ziel: 3,0 -> Zwei Felder nach vorn, nach rechts drehen, ein Feld weiter. - -runde: - mbot.forward(30); - mbot.turnLeft(); - mbot.forward(60); -karte: ..... | ..... | ..^.. -ziel: 0,1 -> Ein Feld nach vorn, dann schaut er nach links und fährt zwei Felder. - -runde: - mbot.turnRight(); - mbot.turnRight(); - mbot.forward(30); -karte: ..... | ..^.. | ..... -ziel: 2,2 -> Zweimal rechts drehen heißt: Er schaut nach hinten. Dann fährt er ein Feld zurück, nach unten. - -runde: - mbot.forward(30); - mbot.turnRight(); - mbot.forward(30); - mbot.turnRight(); - mbot.forward(30); -karte: .... | .... | .^.. -ziel: 2,2 -> Hoch, nach rechts, und nach der zweiten Drehung schaut er nach unten. -::: - ## Checkliste Schätze dich bei jedem Punkt ehrlich ein: ☂️ noch nicht, ⛅ teilweise, ☀️ kann ich sicher. Bei ⛅ und ☂️ hilft dir **Nachlesen**. Danach kommt der Wissenstest. Er zeigt dir, ob deine Einschätzung stimmt. diff --git a/web/lessons/de/visubot/01-der-mbot2.md b/web/lessons/de/visubot/01-der-mbot2.md index 4ccf2751..0155579b 100644 --- a/web/lessons/de/visubot/01-der-mbot2.md +++ b/web/lessons/de/visubot/01-der-mbot2.md @@ -285,6 +285,48 @@ tipp: Fünf Kästen `mbot.forward()` untereinander. Jeder fährt 10 cm. lösung: vb-gerade-loesung.visustruct ::: +## Spiel: Wo landet der mBot2? + +::: spiel fahrt +titel: Spiel: Wo landet der mBot2? +intro: Lies das Programm und tippe auf das Feld, auf dem der mBot2 am Ende steht. Danach fährt er die Strecke vor. Jedes Feld ist 30 cm groß. Vier Runden. +frage: Auf welchem Feld steht der mBot2 am Ende? + +runde: + mbot.forward(60); + mbot.turnRight(); + mbot.forward(30); +karte: ..... | ..... | ..^.. +ziel: 3,0 +> Zwei Felder nach vorn, nach rechts drehen, ein Feld weiter. + +runde: + mbot.forward(30); + mbot.turnLeft(); + mbot.forward(60); +karte: ..... | ..... | ..^.. +ziel: 0,1 +> Ein Feld nach vorn, dann schaut er nach links und fährt zwei Felder. + +runde: + mbot.turnRight(); + mbot.turnRight(); + mbot.forward(30); +karte: ..... | ..^.. | ..... +ziel: 2,2 +> Zweimal rechts drehen heißt: Er schaut nach hinten. Dann fährt er ein Feld zurück, nach unten. + +runde: + mbot.forward(30); + mbot.turnRight(); + mbot.forward(30); + mbot.turnRight(); + mbot.forward(30); +karte: .... | .... | .^.. +ziel: 2,2 +> Hoch, nach rechts, und nach der zweiten Drehung schaut er nach unten. +::: + ## Den echten mBot2 verbinden ::: mbot2 diff --git a/web/lessons/en/09-bedingungen-verknuepfen.md b/web/lessons/en/09-bedingungen-verknuepfen.md index af23925c..07be3712 100644 --- a/web/lessons/en/09-bedingungen-verknuepfen.md +++ b/web/lessons/en/09-bedingungen-verknuepfen.md @@ -179,6 +179,7 @@ test: 2000 -> Leap year braucht: verzweigung tipp: Check the rule with examples first: 2024 is a leap year, 1900 is not, 2000 is. “Can be divided” means the remainder is 0. tipp: Divisible by 4 means `year % 4 == 0`, not divisible by 100 means `year % 100 != 0`. Join these two with `&&`, put brackets around them and add the case for 400 with `||`. +tipp: Almost the solution: one single branch with the condition `(year % 4 == 0 && year % 100 != 0) || year % 400 == 0`. The true branch has `output: "Leap year"`, the false branch `output: "Not a leap year"`. lösung: l08-schaltjahr-loesung.visustruct ::: diff --git a/web/lessons/en/10-fallauswahl.md b/web/lessons/en/10-fallauswahl.md index a9c8e835..7ce8219e 100644 --- a/web/lessons/en/10-fallauswahl.md +++ b/web/lessons/en/10-fallauswahl.md @@ -76,6 +76,7 @@ test: 1, x, 2 -> Unknown operator braucht: fallauswahl tipp: First read in all three values. After that, a switch on the operator decides what is calculated. tipp: Before the switch, create `int result = 0`. In each case you calculate, for example, `result = a + b` and then output `result`. The case names are `"+"`, `"-"` and `"*"` in quotation marks, because the operator is a `String`. +tipp: The outline from top to bottom: three inputs (`int a`, `String operator`, `int b`), then `int result = 0`, then a switch over `operator`. Case `"+"` holds `result = a + b` and `output: result`, cases `"-"` and `"*"` the same. The default case holds `output: "Unknown operator"`. lösung: l09-rechner-loesung.visustruct ::: diff --git a/web/lessons/en/12-do-while-schleife.md b/web/lessons/en/12-do-while-schleife.md index e5de46e2..fc12d7aa 100644 --- a/web/lessons/en/12-do-while-schleife.md +++ b/web/lessons/en/12-do-while-schleife.md @@ -80,6 +80,7 @@ test: 0 -> 0 braucht: doUntilSchleife tipp: You need a variable for the sum that starts at 0 before the loop. In every pass the new number is added. tipp: Before the loop, create `int sum = 0` and `int number = 0`. In the loop you ask for `number` and calculate `sum = sum + number`. Adding the 0 does no harm. The loop keeps running as long as `number != 0`. +tipp: The outline: `int sum = 0` and `int number = 0`, then a do-while loop with the condition `number != 0`. Inside it: the input of `number` and `sum = sum + number`. Below the loop: `output: sum`. lösung: l11-summe-loesung.visustruct ::: diff --git a/web/lessons/en/14-verschachteln.md b/web/lessons/en/14-verschachteln.md index 3e204309..f9641fb1 100644 --- a/web/lessons/en/14-verschachteln.md +++ b/web/lessons/en/14-verschachteln.md @@ -74,6 +74,7 @@ test: 2, 2 -> ## | ## braucht: forSchleife tipp: You need two loops inside each other: one for the lines and inside it one for the characters of a line. tipp: Build it like the triangle. The difference: the inner loop always counts up to `width`, not up to the line number. The outer loop counts up to `height`. +tipp: The outline: inputs `width` and `height`. Outer for loop `int line = 1`, `line <= height`, `line++`. Inside it first `String text = ""`, then the inner for loop `int column = 1`, `column <= width`, `column++` with `text = text + "#"`, and below the inner loop `output: text`. lösung: l13-rechteck-loesung.visustruct ::: diff --git a/web/lessons/en/15-arrays.md b/web/lessons/en/15-arrays.md index 92bbc1f8..f2a73902 100644 --- a/web/lessons/en/15-arrays.md +++ b/web/lessons/en/15-arrays.md @@ -148,6 +148,7 @@ test: -5, -2, -9, -1, -3 -> Sum: -20 | Maximum: -1 braucht: forSchleife, verzweigung tipp: Go through the array with a loop. Add every value to the sum and remember the largest value seen so far. tipp: Calculate the sum and the maximum in variables of their own and only output them at the end, e.g. with `output: "Sum: " + sum`. If your maximum starts at 0, the third test fails. +tipp: The outline: create the array and read it in with a loop. Then `int sum = 0` and `int max = numbers[0]`. A second loop calculates `sum = sum + numbers[i]`, and a branch `numbers[i] > max` sets `max = numbers[i]` in its true branch. Finally the two outputs. lösung: l14-summe-max-loesung.visustruct ::: diff --git a/web/lessons/en/17-zeichenketten.md b/web/lessons/en/17-zeichenketten.md index c6a86780..f856513e 100644 --- a/web/lessons/en/17-zeichenketten.md +++ b/web/lessons/en/17-zeichenketten.md @@ -145,6 +145,7 @@ test: a -> a braucht: forSchleife tipp: Go through the word character by character, but from back to front, and build a new text as you go. tipp: Create `String backwards = ""`. The loop starts at the last index `word.length() - 1` and counts down to 0 with `i--`. In every pass you add `word.charAt(i)` at the end. +tipp: The outline: input `word`, then `String backwards = ""`. For loop with start `int i = word.length() - 1`, condition `i >= 0` and step `i--`. Inside it `backwards = backwards + word.charAt(i)`. Below the loop `output: backwards`. lösung: zk-rueckwaerts-loesung.visustruct ::: @@ -159,6 +160,7 @@ test: I like goats -> Words: 3 braucht: anweisung tipp: There is always a space between the words. Which method splits a text at a character? tipp: Split the sentence into a String array with `sentence.split(" ")`. Its length is the number of words. +tipp: The whole program has three boxes: the input `sentence`, then `String[] words = sentence.split(" ")` and finally `output: "Words: " + words.length`. lösung: zk-woerter-loesung.visustruct ::: diff --git a/web/lessons/en/19-suchen-und-sortieren.md b/web/lessons/en/19-suchen-und-sortieren.md index d70e77e9..40a8b852 100644 --- a/web/lessons/en/19-suchen-und-sortieren.md +++ b/web/lessons/en/19-suchen-und-sortieren.md @@ -121,6 +121,7 @@ test: 2, 9, 2, 7, 6 -> 9 | 7 | 6 | 2 | 2 braucht: forSchleife, verzweigung tipp: Look at the condition in the branch. It decides when two neighbours are swapped. tipp: You only need to change one single character. When should two neighbours be swapped if the larger card is supposed to go to the left? +tipp: In the branch, change `cards[i] > cards[i + 1]` to `cards[i] < cards[i + 1]`. Then two neighbours swap when the bigger card is on the right, and the big card moves to the left. lösung: ss-absteigend-loesung.visustruct ::: diff --git a/web/lessons/en/visubot/00-struktogramm-und-editor.md b/web/lessons/en/visubot/00-struktogramm-und-editor.md index 3dc53c9f..7d7952a0 100644 --- a/web/lessons/en/visubot/00-struktogramm-und-editor.md +++ b/web/lessons/en/visubot/00-struktogramm-und-editor.md @@ -118,48 +118,6 @@ richtig: sequence > Two steps one after another, with no condition and no repetition. ::: -## Game: Where does the mBot2 end up? - -::: spiel fahrt -titel: Game: Where does the mBot2 end up? -intro: Read the program and tap the field where the mBot2 is at the end. Then it drives the route for you. Each field is 30 cm. Four rounds. -frage: On which field is the mBot2 at the end? - -runde: - mbot.forward(60); - mbot.turnRight(); - mbot.forward(30); -karte: ..... | ..... | ..^.. -ziel: 3,0 -> Two fields forward, turn right, one more field. - -runde: - mbot.forward(30); - mbot.turnLeft(); - mbot.forward(60); -karte: ..... | ..... | ..^.. -ziel: 0,1 -> One field forward, then it faces left and drives two fields. - -runde: - mbot.turnRight(); - mbot.turnRight(); - mbot.forward(30); -karte: ..... | ..^.. | ..... -ziel: 2,2 -> Turning right twice means it faces backwards. Then it drives one field down. - -runde: - mbot.forward(30); - mbot.turnRight(); - mbot.forward(30); - mbot.turnRight(); - mbot.forward(30); -karte: .... | .... | .^.. -ziel: 2,2 -> Up, to the right, and after the second turn it faces down. -::: - ## Checklist Rate yourself honestly for each point: ☂️ not yet, ⛅ partly, ☀️ I can do this confidently. For ⛅ and ☂️, **Review** helps you. Then comes the quiz. It shows you whether your self-assessment is right. diff --git a/web/lessons/en/visubot/01-der-mbot2.md b/web/lessons/en/visubot/01-der-mbot2.md index c91e10bc..6d3730d9 100644 --- a/web/lessons/en/visubot/01-der-mbot2.md +++ b/web/lessons/en/visubot/01-der-mbot2.md @@ -285,6 +285,48 @@ tipp: Five boxes `mbot.forward()` one below the other. Each drives 10 cm. lösung: vb-gerade-loesung.visustruct ::: +## Game: Where does the mBot2 end up? + +::: spiel fahrt +titel: Game: Where does the mBot2 end up? +intro: Read the program and tap the field where the mBot2 is at the end. Then it drives the route for you. Each field is 30 cm. Four rounds. +frage: On which field is the mBot2 at the end? + +runde: + mbot.forward(60); + mbot.turnRight(); + mbot.forward(30); +karte: ..... | ..... | ..^.. +ziel: 3,0 +> Two fields forward, turn right, one more field. + +runde: + mbot.forward(30); + mbot.turnLeft(); + mbot.forward(60); +karte: ..... | ..... | ..^.. +ziel: 0,1 +> One field forward, then it faces left and drives two fields. + +runde: + mbot.turnRight(); + mbot.turnRight(); + mbot.forward(30); +karte: ..... | ..^.. | ..... +ziel: 2,2 +> Turning right twice means it faces backwards. Then it drives one field down. + +runde: + mbot.forward(30); + mbot.turnRight(); + mbot.forward(30); + mbot.turnRight(); + mbot.forward(30); +karte: .... | .... | .^.. +ziel: 2,2 +> Up, to the right, and after the second turn it faces down. +::: + ## Connecting the real mBot2 ::: mbot2 diff --git a/web/lessons/pt/09-bedingungen-verknuepfen.md b/web/lessons/pt/09-bedingungen-verknuepfen.md index 43bf5175..e18e0a47 100644 --- a/web/lessons/pt/09-bedingungen-verknuepfen.md +++ b/web/lessons/pt/09-bedingungen-verknuepfen.md @@ -179,6 +179,7 @@ test: 2000 -> Ano bissexto braucht: verzweigung tipp: Confirma primeiro a regra com exemplos: 2024 é bissexto, 1900 não é, 2000 é. “Divisível” quer dizer que o resto é 0. tipp: Divisível por 4 é `ano % 4 == 0`, não divisível por 100 é `ano % 100 != 0`. Junta estas duas com `&&`, põe parênteses à volta e acrescenta o caso do 400 com `||`. +tipp: Quase a solução: uma única decisão com a condição `(ano % 4 == 0 && ano % 100 != 0) || ano % 400 == 0`. No ramo true fica `output: "Ano bissexto"`, no ramo false `output: "Não é ano bissexto"`. lösung: l08-schaltjahr-loesung.visustruct ::: diff --git a/web/lessons/pt/10-fallauswahl.md b/web/lessons/pt/10-fallauswahl.md index 9fc12039..7a16b1dd 100644 --- a/web/lessons/pt/10-fallauswahl.md +++ b/web/lessons/pt/10-fallauswahl.md @@ -76,6 +76,7 @@ test: 1, x, 2 -> Operador desconhecido braucht: fallauswahl tipp: Primeiro lê os três valores. Depois, uma seleção sobre o operador decide o que é calculado. tipp: Antes da seleção, cria `int resultado = 0`. Em cada caso calculas, por exemplo, `resultado = a + b` e depois mostras `resultado`. Os nomes dos casos são `"+"`, `"-"` e `"*"` entre aspas, porque o operador é uma `String`. +tipp: O esqueleto de cima para baixo: três entradas (`int a`, `String operador`, `int b`), depois `int resultado = 0`, depois uma seleção múltipla sobre `operador`. No caso `"+"` ficam `resultado = a + b` e `output: resultado`, em `"-"` e `"*"` igual. No caso senão fica `output: "Operador desconhecido"`. lösung: l09-rechner-loesung.visustruct ::: diff --git a/web/lessons/pt/12-do-while-schleife.md b/web/lessons/pt/12-do-while-schleife.md index ef4d5e93..acb2226f 100644 --- a/web/lessons/pt/12-do-while-schleife.md +++ b/web/lessons/pt/12-do-while-schleife.md @@ -80,6 +80,7 @@ test: 0 -> 0 braucht: doUntilSchleife tipp: Precisas de uma variável para a soma que começa em 0 antes do ciclo. Em cada iteração, o novo número é somado. tipp: Antes do ciclo, cria `int soma = 0` e `int numero = 0`. No ciclo pedes `numero` e calculas `soma = soma + numero`. Somar o 0 não faz mal. O ciclo continua enquanto `numero != 0`. +tipp: O esqueleto: `int soma = 0` e `int numero = 0`, depois um ciclo do-while com a condição `numero != 0`. Dentro: a entrada de `numero` e `soma = soma + numero`. Por baixo do ciclo: `output: soma`. lösung: l11-summe-loesung.visustruct ::: diff --git a/web/lessons/pt/14-verschachteln.md b/web/lessons/pt/14-verschachteln.md index 73218716..709f069f 100644 --- a/web/lessons/pt/14-verschachteln.md +++ b/web/lessons/pt/14-verschachteln.md @@ -74,6 +74,7 @@ test: 2, 2 -> ## | ## braucht: forSchleife tipp: Precisas de dois ciclos, um dentro do outro: um para as linhas e, lá dentro, um para os caracteres de uma linha. tipp: Constrói-o como o triângulo. A diferença: o ciclo interior conta sempre até `largura`, não até ao número da linha. O ciclo exterior conta até `altura`. +tipp: O esqueleto: entradas `largura` e `altura`. Ciclo for exterior `int linha = 1`, `linha <= altura`, `linha++`. Dentro, primeiro `String texto = ""`, depois o ciclo for interior `int coluna = 1`, `coluna <= largura`, `coluna++` com `texto = texto + "#"`, e por baixo do ciclo interior `output: texto`. lösung: l13-rechteck-loesung.visustruct ::: diff --git a/web/lessons/pt/15-arrays.md b/web/lessons/pt/15-arrays.md index afcd2b2f..f46218dd 100644 --- a/web/lessons/pt/15-arrays.md +++ b/web/lessons/pt/15-arrays.md @@ -148,6 +148,7 @@ test: -5, -2, -9, -1, -3 -> Soma: -20 | Máximo: -1 braucht: forSchleife, verzweigung tipp: Percorre o array com um ciclo. Soma cada valor à soma e guarda o maior valor visto até agora. tipp: Calcula a soma e o máximo em variáveis próprias e só os mostra no fim, p. ex. com `output: "Soma: " + soma`. Se o teu máximo começar em 0, o terceiro teste falha. +tipp: O esqueleto: criar o array e lê-lo com um ciclo. Depois `int soma = 0` e `int max = numeros[0]`. Um segundo ciclo calcula `soma = soma + numeros[i]`, e uma decisão `numeros[i] > max` põe `max = numeros[i]` no ramo true. No fim, as duas saídas. lösung: l14-summe-max-loesung.visustruct ::: diff --git a/web/lessons/pt/17-zeichenketten.md b/web/lessons/pt/17-zeichenketten.md index 32742d39..b0f13c5d 100644 --- a/web/lessons/pt/17-zeichenketten.md +++ b/web/lessons/pt/17-zeichenketten.md @@ -145,6 +145,7 @@ test: a -> a braucht: forSchleife tipp: Percorre a palavra caractere a caractere, mas de trás para a frente, e vai construindo um novo texto. tipp: Cria `String invertida = ""`. O ciclo começa no último índice `palavra.length() - 1` e conta para trás até 0 com `i--`. Em cada iteração acrescentas `palavra.charAt(i)` no fim. +tipp: O esqueleto: entrada `palavra`, depois `String invertida = ""`. Ciclo for com início `int i = palavra.length() - 1`, condição `i >= 0` e passo `i--`. Dentro, `invertida = invertida + palavra.charAt(i)`. Por baixo do ciclo, `output: invertida`. lösung: zk-rueckwaerts-loesung.visustruct ::: @@ -159,6 +160,7 @@ test: Eu gosto de cabras -> Palavras: 4 braucht: anweisung tipp: Entre as palavras há sempre um espaço. Que método divide um texto num caractere? tipp: Divide a frase num array de Strings com `frase.split(" ")`. O seu comprimento é o número de palavras. +tipp: O programa todo tem três blocos: a entrada `frase`, depois `String[] palavras = frase.split(" ")` e no fim `output: "Palavras: " + palavras.length`. lösung: zk-woerter-loesung.visustruct ::: diff --git a/web/lessons/pt/19-suchen-und-sortieren.md b/web/lessons/pt/19-suchen-und-sortieren.md index c735dcdd..d99d1d8c 100644 --- a/web/lessons/pt/19-suchen-und-sortieren.md +++ b/web/lessons/pt/19-suchen-und-sortieren.md @@ -121,6 +121,7 @@ test: 2, 9, 2, 7, 6 -> 9 | 7 | 6 | 2 | 2 braucht: forSchleife, verzweigung tipp: Olha para a condição na decisão. É ela que decide quando dois vizinhos são trocados. tipp: Só precisas de alterar um único caractere. Quando devem ser trocados dois vizinhos, se a carta maior deve ir para a esquerda? +tipp: Na decisão, troca `cartas[i] > cartas[i + 1]` por `cartas[i] < cartas[i + 1]`. Assim os vizinhos trocam quando a carta maior está à direita, e a carta grande vai para a esquerda. lösung: ss-absteigend-loesung.visustruct ::: diff --git a/web/package-lock.json b/web/package-lock.json index 82969cbc..131caa5a 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -1,12 +1,12 @@ { "name": "visustruct-web", - "version": "0.15.0", + "version": "0.15.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "visustruct-web", - "version": "0.15.0", + "version": "0.15.1", "dependencies": { "@codemirror/autocomplete": "^6.20.4", "@codemirror/commands": "^6.11.1", diff --git a/web/package.json b/web/package.json index 95b6436e..4a6bd39b 100644 --- a/web/package.json +++ b/web/package.json @@ -1,7 +1,7 @@ { "name": "visustruct-web", "private": true, - "version": "0.15.0", + "version": "0.15.1", "type": "module", "scripts": { "dev": "vite", diff --git a/website/app/assets/flowApp-CPQeq7Uk.js b/website/app/assets/flowApp-RdEaBhPZ.js similarity index 99% rename from website/app/assets/flowApp-CPQeq7Uk.js rename to website/app/assets/flowApp-RdEaBhPZ.js index 8f62ed0b..011a9064 100644 --- a/website/app/assets/flowApp-CPQeq7Uk.js +++ b/website/app/assets/flowApp-RdEaBhPZ.js @@ -1,4 +1,4 @@ -var dt=Object.defineProperty;var lt=(i,t,e)=>t in i?dt(i,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):i[t]=e;var y=(i,t,e)=>lt(i,typeof t!="symbol"?t+"":t,e);import{t as h,g as ct,i as I,w as ht,o as ut,f as ft,q as G,u as pt,v as gt,x as wt,y as vt,z as mt,l as xt,n as yt}from"./index-B8lDfJ72.js";const et=["start","anweisung","ein","verzweigung","unterprogramm","ende"],m=20,st={start:"#d1f2d9",ende:"#d1f2d9",anweisung:"#e5f0ff",ein:"#f2e6ff",verzweigung:"#fff4d6",unterprogramm:"#e5f0ff"},H=16,bt=170;function _t(i,t,e){const n=[];for(const s of i.split(` +var dt=Object.defineProperty;var lt=(i,t,e)=>t in i?dt(i,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):i[t]=e;var y=(i,t,e)=>lt(i,typeof t!="symbol"?t+"":t,e);import{t as h,g as ct,i as I,w as ht,o as ut,f as ft,q as G,u as pt,v as gt,x as wt,y as vt,z as mt,l as xt,n as yt}from"./index-DuzNMqv5.js";const et=["start","anweisung","ein","verzweigung","unterprogramm","ende"],m=20,st={start:"#d1f2d9",ende:"#d1f2d9",anweisung:"#e5f0ff",ein:"#f2e6ff",verzweigung:"#fff4d6",unterprogramm:"#e5f0ff"},H=16,bt=170;function _t(i,t,e){const n=[];for(const s of i.split(` `)){let o="";for(const r of s.split(/\s+/).filter(Boolean)){const a=o?`${o} ${r}`:r;o&&e(a)>t?(n.push(o),o=r):o=a}n.push(o)}return n.length?n:[""]}const U=i=>Math.round(i/m)*m;function C(i,t){const e=_t(i.text,bt,t),n=Math.max(0,...e.map(t)),s=e.length*H;let o,r;if(i.shape==="verzweigung")o=Math.max(140,n*1.7+30),r=Math.max(80,s*1.8+24);else{const a=i.shape==="ein"?44:i.shape==="unterprogramm"?40:i.shape==="anweisung"?24:36;o=Math.max(i.shape==="start"||i.shape==="ende"?100:120,n+a),r=Math.max(40,s+18)}return{x:i.x,y:i.y,w:Math.ceil(o/m)*m,h:Math.ceil(r/m)*m,lines:e}}function V(i){return i==="ende"?[]:i==="verzweigung"?["ja","nein"]:["out"]}const P=i=>i!=="start";function j(i,t,e){var s;if(e==="out")return"bottom";const n=((s=i.yesRight)==null?void 0:s.includes(t.id))??!1;return e==="ja"===n?"right":"bottom"}function F(i,t){return t==="bottom"?[i.x,i.y+i.h/2]:[i.x+i.w/2,i.y]}const $t=i=>[i.x,i.y-i.h/2];function Lt(i,t,e,n=0){const[s,o]=F(i,t),[r,a]=$t(e),d=m,u=Math.max(i.x+i.w/2,e.x+e.w/2)+d*(1.5+n);if(t==="bottom"){if(a>=o+d){if(s===r)return[[s,o],[r,a]];const l=o+d;return[[s,o],[s,l],[r,l],[r,a]]}return[[s,o],[s,o+d],[u,o+d],[u,a-d],[r,a-d],[r,a]]}const p=e.x-e.w/2;if(p>=s+d&&Math.abs(e.y-o)=o+d){if(r>=s+d)return[[s,o],[r,o],[r,a]];const l=s+d;return[[s,o],[l,o],[l,a-d],[r,a-d],[r,a]]}const f=Math.max(s+d,u);return[[s,o],[f,o],[f,a-d],[r,a-d],[r,a]]}function nt(i=""){return{title:i,nodes:[],edges:[]}}function it(i,t){const e=new Set([...i.nodes.map(s=>s.id),...i.edges.map(s=>s.id)]);let n=1;for(;e.has(`${t}${n}`);)n++;return`${t}${n}`}function q(i,t,e,n,s){const o=it(i,"n");return{doc:{...i,nodes:[...i.nodes,{id:o,shape:t,x:U(e),y:U(n),text:s}]},id:o}}function J(i,t,e,n){return{...i,nodes:i.nodes.map(s=>s.id===t?{...s,x:Math.max(m*4,U(e)),y:Math.max(m*2,U(n))}:s)}}function Et(i,t,e){return{...i,nodes:i.nodes.map(n=>n.id===t?{...n,text:e}:n)}}function _(i,t,e,n){const s=i.nodes.find(a=>a.id===t),o=i.nodes.find(a=>a.id===n);if(!s||!o||t===n||!V(s.shape).includes(e)||!P(o.shape))return i;const r=i.edges.filter(a=>!(a.from===t&&a.port===e));return{...i,edges:[...r,{id:it(i,"e"),from:t,port:e,to:n}]}}function kt(i,t){return V(t.shape).find(e=>!i.edges.some(n=>n.from===t.id&&n.port===e))}function St(i,t){var e;return{...i,nodes:i.nodes.filter(n=>n.id!==t),edges:i.edges.filter(n=>n.from!==t&&n.to!==t),yesRight:(e=i.yesRight)==null?void 0:e.filter(n=>n!==t)}}function Mt(i,t){return{...i,edges:i.edges.filter(e=>e.id!==t)}}function ot(i,t){const e=new Set(i.yesRight??[]);return e.has(t)?e.delete(t):e.add(t),{...i,yesRight:[...e]}}function b(i){return JSON.stringify({format:"visuflow",version:1,...i},null,2)}function W(i){let t;try{t=JSON.parse(i)}catch{return}if(!t||typeof t!="object")return;const e=t;if(!Array.isArray(e.nodes)||!Array.isArray(e.edges))return;const n=[];for(const o of e.nodes)!o||typeof o.id!="string"||!et.includes(o.shape)||!Number.isFinite(o.x)||!Number.isFinite(o.y)||n.some(r=>r.id===o.id)||n.push({id:o.id,shape:o.shape,x:o.x,y:o.y,text:typeof o.text=="string"?o.text:""});let s={title:typeof e.title=="string"?e.title:"",nodes:n,edges:[]};for(const o of e.edges)!o||typeof o.from!="string"||typeof o.to!="string"||typeof o.port!="string"||(s=_(s,o.from,o.port,o.to));return Array.isArray(e.yesRight)&&(s.yesRight=e.yesRight.filter(o=>typeof o=="string"&&n.some(r=>r.id===o))),s}const z="http://www.w3.org/2000/svg",X="visuflow.doc",At=100,Y=14,rt=`${Y}px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif`,B="#1c1c1e",w=i=>i.replace(/[&<>"]/g,t=>({"&":"&","<":"<",">":">",'"':"""})[t]);function It(i){try{return localStorage.getItem(i)}catch{return null}}function Z(i,t){try{localStorage.setItem(i,t)}catch{}}function Ct(){return xt("visustruct",yt())}function D(i,t,e){const n=URL.createObjectURL(new Blob([t],{type:e})),s=document.createElement("a");s.href=n,s.download=i,s.click(),setTimeout(()=>URL.revokeObjectURL(n),1e3)}function v(i,t={}){const e=document.createElementNS(z,i);for(const[n,s]of Object.entries(t))e.setAttribute(n,String(s));return e}let N;function R(i){return N===void 0&&(N=document.createElement("canvas").getContext("2d")),N?(N.font=rt,N.measureText(i).width):i.length*Y*.55}const Rt=i=>h(`web_visuflow_shape_${i}`),T=i=>h(`web_visuflow_text_${i}`);function at(i,t){const e=t.x-t.w/2,n=t.x+t.w/2,s=t.y-t.h/2,o=t.y+t.h/2;return i==="verzweigung"?v("path",{d:`M${t.x} ${s} L${n} ${t.y} L${t.x} ${o} L${e} ${t.y} Z`}):i==="ein"?v("path",{d:`M${e+14} ${s} L${n} ${s} L${n-14} ${o} L${e} ${o} Z`}):i==="unterprogramm"?v("path",{d:`M${e} ${s} H${n} V${o} H${e} Z M${e+10} ${s} V${o} M${n-10} ${s} V${o}`}):v("rect",{x:e,y:s,width:t.w,height:t.h,rx:i==="anweisung"?2:t.h/2})}function Bt(i){const t=v("text",{"text-anchor":"middle","font-size":Y,fill:B});return i.lines.forEach((e,n)=>{const s=v("tspan",{x:i.x,y:i.y+5+(n-(i.lines.length-1)/2)*H});s.textContent=e,t.append(s)}),t}function Q(i){const t=v("svg",{viewBox:"0 0 64 36",width:64,height:36,"aria-hidden":"true"}),e=at(i,{x:32,y:18,w:i==="verzweigung"?54:56,h:i==="verzweigung"?32:26});return e.setAttribute("fill",st[i]),e.setAttribute("stroke",B),e.setAttribute("stroke-width","1.5"),t.append(e),t.outerHTML}function tt(){let i=nt(h("web_visuflow_example_title"));const t=[],e=(p,f,l,c)=>{const g=q(i,p,f,l,c);i=g.doc,t.push(g.id)};e("start",240,60,T("start")),e("anweisung",240,160,h("web_visuflow_example_water")),e("anweisung",240,260,h("web_visuflow_example_bag")),e("verzweigung",240,380,h("web_visuflow_example_hot")),e("anweisung",480,380,h("web_visuflow_example_wait")),e("anweisung",240,500,h("web_visuflow_example_drink")),e("ende",240,600,T("ende"));const[n,s,o,r,a,d,u]=t;return i=_(i,n,"out",s),i=_(i,s,"out",o),i=_(i,o,"out",r),i=ot(i,r),i=_(i,r,"ja",a),i=_(i,a,"out",r),i=_(i,r,"nein",d),i=_(i,d,"out",u),i}function Tt(){return q(nt(),"start",240,60,T("start")).doc}class Dt{constructor(t){y(this,"shell");y(this,"svg");y(this,"scroller");y(this,"status");y(this,"titleInput");y(this,"doc");y(this,"selection");y(this,"history",[]);y(this,"future",[]);y(this,"editor");y(this,"dragLine");document.documentElement.classList.add("visuflow-theme"),history.replaceState(history.state,"",`${location.pathname}?visuflow${location.hash}`),this.doc=W(It(X)??"")??tt(),this.shell=document.createElement("div"),this.shell.className="shell visuflow",t.replaceWith(this.shell),this.build(),this.render(),window.addEventListener("keydown",e=>this.onKey(e))}build(){const t=(l,c,g,x=c)=>``,e=et.map(l=>``).join("");this.shell.innerHTML=`
VisuFlow ${w(h("web_visuflow_subtitle"))} @@ -28,7 +28,7 @@ var dt=Object.defineProperty;var lt=(i,t,e)=>t in i?dt(i,t,{enumerable:!0,config ${ht()}
- ${w(h("web_about_version_fmt").replace("%@","0.15.0"))} + ${w(h("web_about_version_fmt").replace("%@","0.15.1"))}
diff --git a/website/app/assets/index-B8lDfJ72.js b/website/app/assets/index-DuzNMqv5.js similarity index 99% rename from website/app/assets/index-B8lDfJ72.js rename to website/app/assets/index-DuzNMqv5.js index 655639e5..dc9ce651 100644 --- a/website/app/assets/index-B8lDfJ72.js +++ b/website/app/assets/index-DuzNMqv5.js @@ -3058,6 +3058,7 @@ test: 2000 -> Schaltjahr braucht: verzweigung tipp: Prüfe die Regel zuerst an Beispielen: 2024 ist ein Schaltjahr, 1900 nicht, 2000 schon. Teilbar heißt: Der Rest ist 0. tipp: Teilbar durch 4 heißt \`jahr % 4 == 0\`, nicht teilbar durch 100 heißt \`jahr % 100 != 0\`. Verbinde diese beiden mit \`&&\`, setze Klammern darum und hänge mit \`||\` den Fall für 400 an. +tipp: Fast die Lösung: Eine einzige Verzweigung mit der Bedingung \`(jahr % 4 == 0 && jahr % 100 != 0) || jahr % 400 == 0\`. Im true-Zweig steht \`output: "Schaltjahr"\`, im false-Zweig \`output: "kein Schaltjahr"\`. lösung: l08-schaltjahr-loesung.visustruct ::: @@ -3282,6 +3283,7 @@ test: 1, x, 2 -> Unbekanntes Rechenzeichen braucht: fallauswahl tipp: Lies erst alle drei Werte ein. Danach entscheidet eine Fallauswahl über das Rechenzeichen, was gerechnet wird. tipp: Lege vor der Fallauswahl \`int ergebnis = 0\` an. In jedem Fall rechnest du zum Beispiel \`ergebnis = a + b\` und gibst danach \`ergebnis\` aus. Die Fallnamen sind \`"+"\`, \`"-"\` und \`"*"\` in Anführungszeichen, weil das Rechenzeichen ein \`String\` ist. +tipp: Das Gerüst von oben nach unten: drei Eingaben (\`int a\`, \`String zeichen\`, \`int b\`), dann \`int ergebnis = 0\`, dann eine Fallauswahl über \`zeichen\`. Im Fall \`"+"\` stehen \`ergebnis = a + b\` und \`output: ergebnis\`, bei \`"-"\` und \`"*"\` genauso. Im Sonst-Fall steht \`output: "Unbekanntes Rechenzeichen"\`. lösung: l09-rechner-loesung.visustruct ::: @@ -3974,6 +3976,7 @@ test: 0 -> 0 braucht: doUntilSchleife tipp: Du brauchst eine Variable für die Summe, die vor der Schleife bei 0 beginnt. In jedem Durchlauf kommt die neue Zahl dazu. tipp: Lege vor der Schleife \`int summe = 0\` und \`int zahl = 0\` an. In der Schleife fragst du \`zahl\` ab und rechnest \`summe = summe + zahl\`. Die 0 zu addieren schadet nicht. Die Schleife läuft weiter, solange \`zahl != 0\` ist. +tipp: Das Gerüst: \`int summe = 0\` und \`int zahl = 0\`, dann eine Do-while-Schleife mit der Bedingung \`zahl != 0\`. In ihr stehen die Eingabe von \`zahl\` und \`summe = summe + zahl\`. Unter der Schleife steht \`output: summe\`. lösung: l11-summe-loesung.visustruct ::: @@ -4583,6 +4586,7 @@ test: 2, 2 -> ## | ## braucht: forSchleife tipp: Du brauchst zwei Schleifen ineinander: eine für die Zeilen und darin eine für die Zeichen einer Zeile. tipp: Baue es wie das Dreieck. Der Unterschied: Die innere Schleife zählt immer bis \`breite\`, nicht bis zur Zeilennummer. Die äußere Schleife zählt bis \`hoehe\`. +tipp: Das Gerüst: Eingaben \`breite\` und \`hoehe\`. Äußere For-Schleife \`int zeile = 1\`, \`zeile <= hoehe\`, \`zeile++\`. Darin zuerst \`String text = ""\`, dann die innere For-Schleife \`int spalte = 1\`, \`spalte <= breite\`, \`spalte++\` mit \`text = text + "#"\`, und unter der inneren Schleife \`output: text\`. lösung: l13-rechteck-loesung.visustruct ::: @@ -4961,6 +4965,7 @@ test: -5, -2, -9, -1, -3 -> Summe: -20 | Maximum: -1 braucht: forSchleife, verzweigung tipp: Gehe das Array mit einer Schleife durch. Zähle jeden Wert zur Summe und merke dir den größten bisher gesehenen Wert. tipp: Rechne Summe und Maximum in eigenen Variablen aus und gib sie erst am Ende aus, z. B. mit \`output: "Summe: " + summe\`. Beginnt dein Maximum bei 0, scheitert der dritte Test. +tipp: Das Gerüst: Array anlegen und mit einer Schleife einlesen. Dann \`int summe = 0\` und \`int max = zahlen[0]\`. Eine zweite Schleife rechnet \`summe = summe + zahlen[i]\`, und eine Verzweigung \`zahlen[i] > max\` setzt im true-Zweig \`max = zahlen[i]\`. Zum Schluss die beiden Ausgaben. lösung: l14-summe-max-loesung.visustruct ::: @@ -5636,6 +5641,7 @@ test: a -> a braucht: forSchleife tipp: Gehe das Wort Zeichen für Zeichen durch, aber von hinten nach vorn, und baue dabei einen neuen Text zusammen. tipp: Lege \`String rueckwaerts = ""\` an. Die Schleife beginnt beim letzten Index \`wort.length() - 1\` und zählt mit \`i--\` bis 0 herunter. In jedem Durchlauf hängst du \`wort.charAt(i)\` hinten an. +tipp: Das Gerüst: Eingabe \`wort\`, dann \`String rueckwaerts = ""\`. For-Schleife mit Start \`int i = wort.length() - 1\`, Bedingung \`i >= 0\` und Schritt \`i--\`. Darin \`rueckwaerts = rueckwaerts + wort.charAt(i)\`. Unter der Schleife \`output: rueckwaerts\`. lösung: zk-rueckwaerts-loesung.visustruct ::: @@ -5650,6 +5656,7 @@ test: Struktogramme machen Spaß -> Wörter: 3 braucht: anweisung tipp: Zwischen den Wörtern steht immer ein Leerzeichen. Welche Methode zerlegt einen Text an einem Zeichen? tipp: Zerlege den Satz mit \`satz.split(" ")\` in ein String-Array. Seine Länge ist die Anzahl der Wörter. +tipp: Das ganze Programm hat drei Kästen: die Eingabe \`satz\`, dann \`String[] woerter = satz.split(" ")\` und zum Schluss \`output: "Wörter: " + woerter.length\`. lösung: zk-woerter-loesung.visustruct ::: @@ -6621,6 +6628,7 @@ test: 2, 9, 2, 7, 6 -> 9 | 7 | 6 | 2 | 2 braucht: forSchleife, verzweigung tipp: Schau dir die Bedingung in der Verzweigung an. Sie entscheidet, wann zwei Nachbarn getauscht werden. tipp: Du musst nur ein einziges Zeichen ändern. Wann sollen zwei Nachbarn getauscht werden, wenn die größere Karte nach links soll? +tipp: Ändere in der Verzweigung \`karten[i] > karten[i + 1]\` in \`karten[i] < karten[i + 1]\`. Dann wird getauscht, wenn rechts die größere Karte liegt, und die große Karte wandert nach links. lösung: ss-absteigend-loesung.visustruct ::: @@ -15818,6 +15826,7 @@ test: 2000 -> Leap year braucht: verzweigung tipp: Check the rule with examples first: 2024 is a leap year, 1900 is not, 2000 is. “Can be divided” means the remainder is 0. tipp: Divisible by 4 means \`year % 4 == 0\`, not divisible by 100 means \`year % 100 != 0\`. Join these two with \`&&\`, put brackets around them and add the case for 400 with \`||\`. +tipp: Almost the solution: one single branch with the condition \`(year % 4 == 0 && year % 100 != 0) || year % 400 == 0\`. The true branch has \`output: "Leap year"\`, the false branch \`output: "Not a leap year"\`. lösung: l08-schaltjahr-loesung.visustruct ::: @@ -16042,6 +16051,7 @@ test: 1, x, 2 -> Unknown operator braucht: fallauswahl tipp: First read in all three values. After that, a switch on the operator decides what is calculated. tipp: Before the switch, create \`int result = 0\`. In each case you calculate, for example, \`result = a + b\` and then output \`result\`. The case names are \`"+"\`, \`"-"\` and \`"*"\` in quotation marks, because the operator is a \`String\`. +tipp: The outline from top to bottom: three inputs (\`int a\`, \`String operator\`, \`int b\`), then \`int result = 0\`, then a switch over \`operator\`. Case \`"+"\` holds \`result = a + b\` and \`output: result\`, cases \`"-"\` and \`"*"\` the same. The default case holds \`output: "Unknown operator"\`. lösung: l09-rechner-loesung.visustruct ::: @@ -16734,6 +16744,7 @@ test: 0 -> 0 braucht: doUntilSchleife tipp: You need a variable for the sum that starts at 0 before the loop. In every pass the new number is added. tipp: Before the loop, create \`int sum = 0\` and \`int number = 0\`. In the loop you ask for \`number\` and calculate \`sum = sum + number\`. Adding the 0 does no harm. The loop keeps running as long as \`number != 0\`. +tipp: The outline: \`int sum = 0\` and \`int number = 0\`, then a do-while loop with the condition \`number != 0\`. Inside it: the input of \`number\` and \`sum = sum + number\`. Below the loop: \`output: sum\`. lösung: l11-summe-loesung.visustruct ::: @@ -17343,6 +17354,7 @@ test: 2, 2 -> ## | ## braucht: forSchleife tipp: You need two loops inside each other: one for the lines and inside it one for the characters of a line. tipp: Build it like the triangle. The difference: the inner loop always counts up to \`width\`, not up to the line number. The outer loop counts up to \`height\`. +tipp: The outline: inputs \`width\` and \`height\`. Outer for loop \`int line = 1\`, \`line <= height\`, \`line++\`. Inside it first \`String text = ""\`, then the inner for loop \`int column = 1\`, \`column <= width\`, \`column++\` with \`text = text + "#"\`, and below the inner loop \`output: text\`. lösung: l13-rechteck-loesung.visustruct ::: @@ -17721,6 +17733,7 @@ test: -5, -2, -9, -1, -3 -> Sum: -20 | Maximum: -1 braucht: forSchleife, verzweigung tipp: Go through the array with a loop. Add every value to the sum and remember the largest value seen so far. tipp: Calculate the sum and the maximum in variables of their own and only output them at the end, e.g. with \`output: "Sum: " + sum\`. If your maximum starts at 0, the third test fails. +tipp: The outline: create the array and read it in with a loop. Then \`int sum = 0\` and \`int max = numbers[0]\`. A second loop calculates \`sum = sum + numbers[i]\`, and a branch \`numbers[i] > max\` sets \`max = numbers[i]\` in its true branch. Finally the two outputs. lösung: l14-summe-max-loesung.visustruct ::: @@ -18396,6 +18409,7 @@ test: a -> a braucht: forSchleife tipp: Go through the word character by character, but from back to front, and build a new text as you go. tipp: Create \`String backwards = ""\`. The loop starts at the last index \`word.length() - 1\` and counts down to 0 with \`i--\`. In every pass you add \`word.charAt(i)\` at the end. +tipp: The outline: input \`word\`, then \`String backwards = ""\`. For loop with start \`int i = word.length() - 1\`, condition \`i >= 0\` and step \`i--\`. Inside it \`backwards = backwards + word.charAt(i)\`. Below the loop \`output: backwards\`. lösung: zk-rueckwaerts-loesung.visustruct ::: @@ -18410,6 +18424,7 @@ test: I like goats -> Words: 3 braucht: anweisung tipp: There is always a space between the words. Which method splits a text at a character? tipp: Split the sentence into a String array with \`sentence.split(" ")\`. Its length is the number of words. +tipp: The whole program has three boxes: the input \`sentence\`, then \`String[] words = sentence.split(" ")\` and finally \`output: "Words: " + words.length\`. lösung: zk-woerter-loesung.visustruct ::: @@ -19378,6 +19393,7 @@ test: 2, 9, 2, 7, 6 -> 9 | 7 | 6 | 2 | 2 braucht: forSchleife, verzweigung tipp: Look at the condition in the branch. It decides when two neighbours are swapped. tipp: You only need to change one single character. When should two neighbours be swapped if the larger card is supposed to go to the left? +tipp: In the branch, change \`cards[i] > cards[i + 1]\` to \`cards[i] < cards[i + 1]\`. Then two neighbours swap when the bigger card is on the right, and the big card moves to the left. lösung: ss-absteigend-loesung.visustruct ::: @@ -28583,6 +28599,7 @@ test: 2000 -> Ano bissexto braucht: verzweigung tipp: Confirma primeiro a regra com exemplos: 2024 é bissexto, 1900 não é, 2000 é. “Divisível” quer dizer que o resto é 0. tipp: Divisível por 4 é \`ano % 4 == 0\`, não divisível por 100 é \`ano % 100 != 0\`. Junta estas duas com \`&&\`, põe parênteses à volta e acrescenta o caso do 400 com \`||\`. +tipp: Quase a solução: uma única decisão com a condição \`(ano % 4 == 0 && ano % 100 != 0) || ano % 400 == 0\`. No ramo true fica \`output: "Ano bissexto"\`, no ramo false \`output: "Não é ano bissexto"\`. lösung: l08-schaltjahr-loesung.visustruct ::: @@ -28807,6 +28824,7 @@ test: 1, x, 2 -> Operador desconhecido braucht: fallauswahl tipp: Primeiro lê os três valores. Depois, uma seleção sobre o operador decide o que é calculado. tipp: Antes da seleção, cria \`int resultado = 0\`. Em cada caso calculas, por exemplo, \`resultado = a + b\` e depois mostras \`resultado\`. Os nomes dos casos são \`"+"\`, \`"-"\` e \`"*"\` entre aspas, porque o operador é uma \`String\`. +tipp: O esqueleto de cima para baixo: três entradas (\`int a\`, \`String operador\`, \`int b\`), depois \`int resultado = 0\`, depois uma seleção múltipla sobre \`operador\`. No caso \`"+"\` ficam \`resultado = a + b\` e \`output: resultado\`, em \`"-"\` e \`"*"\` igual. No caso senão fica \`output: "Operador desconhecido"\`. lösung: l09-rechner-loesung.visustruct ::: @@ -29499,6 +29517,7 @@ test: 0 -> 0 braucht: doUntilSchleife tipp: Precisas de uma variável para a soma que começa em 0 antes do ciclo. Em cada iteração, o novo número é somado. tipp: Antes do ciclo, cria \`int soma = 0\` e \`int numero = 0\`. No ciclo pedes \`numero\` e calculas \`soma = soma + numero\`. Somar o 0 não faz mal. O ciclo continua enquanto \`numero != 0\`. +tipp: O esqueleto: \`int soma = 0\` e \`int numero = 0\`, depois um ciclo do-while com a condição \`numero != 0\`. Dentro: a entrada de \`numero\` e \`soma = soma + numero\`. Por baixo do ciclo: \`output: soma\`. lösung: l11-summe-loesung.visustruct ::: @@ -30108,6 +30127,7 @@ test: 2, 2 -> ## | ## braucht: forSchleife tipp: Precisas de dois ciclos, um dentro do outro: um para as linhas e, lá dentro, um para os caracteres de uma linha. tipp: Constrói-o como o triângulo. A diferença: o ciclo interior conta sempre até \`largura\`, não até ao número da linha. O ciclo exterior conta até \`altura\`. +tipp: O esqueleto: entradas \`largura\` e \`altura\`. Ciclo for exterior \`int linha = 1\`, \`linha <= altura\`, \`linha++\`. Dentro, primeiro \`String texto = ""\`, depois o ciclo for interior \`int coluna = 1\`, \`coluna <= largura\`, \`coluna++\` com \`texto = texto + "#"\`, e por baixo do ciclo interior \`output: texto\`. lösung: l13-rechteck-loesung.visustruct ::: @@ -30486,6 +30506,7 @@ test: -5, -2, -9, -1, -3 -> Soma: -20 | Máximo: -1 braucht: forSchleife, verzweigung tipp: Percorre o array com um ciclo. Soma cada valor à soma e guarda o maior valor visto até agora. tipp: Calcula a soma e o máximo em variáveis próprias e só os mostra no fim, p. ex. com \`output: "Soma: " + soma\`. Se o teu máximo começar em 0, o terceiro teste falha. +tipp: O esqueleto: criar o array e lê-lo com um ciclo. Depois \`int soma = 0\` e \`int max = numeros[0]\`. Um segundo ciclo calcula \`soma = soma + numeros[i]\`, e uma decisão \`numeros[i] > max\` põe \`max = numeros[i]\` no ramo true. No fim, as duas saídas. lösung: l14-summe-max-loesung.visustruct ::: @@ -31161,6 +31182,7 @@ test: a -> a braucht: forSchleife tipp: Percorre a palavra caractere a caractere, mas de trás para a frente, e vai construindo um novo texto. tipp: Cria \`String invertida = ""\`. O ciclo começa no último índice \`palavra.length() - 1\` e conta para trás até 0 com \`i--\`. Em cada iteração acrescentas \`palavra.charAt(i)\` no fim. +tipp: O esqueleto: entrada \`palavra\`, depois \`String invertida = ""\`. Ciclo for com início \`int i = palavra.length() - 1\`, condição \`i >= 0\` e passo \`i--\`. Dentro, \`invertida = invertida + palavra.charAt(i)\`. Por baixo do ciclo, \`output: invertida\`. lösung: zk-rueckwaerts-loesung.visustruct ::: @@ -31175,6 +31197,7 @@ test: Eu gosto de cabras -> Palavras: 4 braucht: anweisung tipp: Entre as palavras há sempre um espaço. Que método divide um texto num caractere? tipp: Divide a frase num array de Strings com \`frase.split(" ")\`. O seu comprimento é o número de palavras. +tipp: O programa todo tem três blocos: a entrada \`frase\`, depois \`String[] palavras = frase.split(" ")\` e no fim \`output: "Palavras: " + palavras.length\`. lösung: zk-woerter-loesung.visustruct ::: @@ -32145,6 +32168,7 @@ test: 2, 9, 2, 7, 6 -> 9 | 7 | 6 | 2 | 2 braucht: forSchleife, verzweigung tipp: Olha para a condição na decisão. É ela que decide quando dois vizinhos são trocados. tipp: Só precisas de alterar um único caractere. Quando devem ser trocados dois vizinhos, se a carta maior deve ir para a esquerda? +tipp: Na decisão, troca \`cartas[i] > cartas[i + 1]\` por \`cartas[i] < cartas[i + 1]\`. Assim os vizinhos trocam quando a carta maior está à direita, e a carta grande vai para a esquerda. lösung: ss-absteigend-loesung.visustruct ::: @@ -41347,48 +41371,6 @@ richtig: Sequenz > Zwei Schritte nacheinander, ohne Bedingung und ohne Wiederholung. ::: -## Spiel: Wo landet der mBot2? - -::: spiel fahrt -titel: Spiel: Wo landet der mBot2? -intro: Lies das Programm und tippe auf das Feld, auf dem der mBot2 am Ende steht. Danach fährt er die Strecke vor. Jedes Feld ist 30 cm groß. Vier Runden. -frage: Auf welchem Feld steht der mBot2 am Ende? - -runde: - mbot.forward(60); - mbot.turnRight(); - mbot.forward(30); -karte: ..... | ..... | ..^.. -ziel: 3,0 -> Zwei Felder nach vorn, nach rechts drehen, ein Feld weiter. - -runde: - mbot.forward(30); - mbot.turnLeft(); - mbot.forward(60); -karte: ..... | ..... | ..^.. -ziel: 0,1 -> Ein Feld nach vorn, dann schaut er nach links und fährt zwei Felder. - -runde: - mbot.turnRight(); - mbot.turnRight(); - mbot.forward(30); -karte: ..... | ..^.. | ..... -ziel: 2,2 -> Zweimal rechts drehen heißt: Er schaut nach hinten. Dann fährt er ein Feld zurück, nach unten. - -runde: - mbot.forward(30); - mbot.turnRight(); - mbot.forward(30); - mbot.turnRight(); - mbot.forward(30); -karte: .... | .... | .^.. -ziel: 2,2 -> Hoch, nach rechts, und nach der zweiten Drehung schaut er nach unten. -::: - ## Checkliste Schätze dich bei jedem Punkt ehrlich ein: ☂️ noch nicht, ⛅ teilweise, ☀️ kann ich sicher. Bei ⛅ und ☂️ hilft dir **Nachlesen**. Danach kommt der Wissenstest. Er zeigt dir, ob deine Einschätzung stimmt. @@ -41715,6 +41697,48 @@ tipp: Fünf Kästen \`mbot.forward()\` untereinander. Jeder fährt 10 cm. lösung: vb-gerade-loesung.visustruct ::: +## Spiel: Wo landet der mBot2? + +::: spiel fahrt +titel: Spiel: Wo landet der mBot2? +intro: Lies das Programm und tippe auf das Feld, auf dem der mBot2 am Ende steht. Danach fährt er die Strecke vor. Jedes Feld ist 30 cm groß. Vier Runden. +frage: Auf welchem Feld steht der mBot2 am Ende? + +runde: + mbot.forward(60); + mbot.turnRight(); + mbot.forward(30); +karte: ..... | ..... | ..^.. +ziel: 3,0 +> Zwei Felder nach vorn, nach rechts drehen, ein Feld weiter. + +runde: + mbot.forward(30); + mbot.turnLeft(); + mbot.forward(60); +karte: ..... | ..... | ..^.. +ziel: 0,1 +> Ein Feld nach vorn, dann schaut er nach links und fährt zwei Felder. + +runde: + mbot.turnRight(); + mbot.turnRight(); + mbot.forward(30); +karte: ..... | ..^.. | ..... +ziel: 2,2 +> Zweimal rechts drehen heißt: Er schaut nach hinten. Dann fährt er ein Feld zurück, nach unten. + +runde: + mbot.forward(30); + mbot.turnRight(); + mbot.forward(30); + mbot.turnRight(); + mbot.forward(30); +karte: .... | .... | .^.. +ziel: 2,2 +> Hoch, nach rechts, und nach der zweiten Drehung schaut er nach unten. +::: + ## Den echten mBot2 verbinden ::: mbot2 @@ -47346,48 +47370,6 @@ richtig: sequence > Two steps one after another, with no condition and no repetition. ::: -## Game: Where does the mBot2 end up? - -::: spiel fahrt -titel: Game: Where does the mBot2 end up? -intro: Read the program and tap the field where the mBot2 is at the end. Then it drives the route for you. Each field is 30 cm. Four rounds. -frage: On which field is the mBot2 at the end? - -runde: - mbot.forward(60); - mbot.turnRight(); - mbot.forward(30); -karte: ..... | ..... | ..^.. -ziel: 3,0 -> Two fields forward, turn right, one more field. - -runde: - mbot.forward(30); - mbot.turnLeft(); - mbot.forward(60); -karte: ..... | ..... | ..^.. -ziel: 0,1 -> One field forward, then it faces left and drives two fields. - -runde: - mbot.turnRight(); - mbot.turnRight(); - mbot.forward(30); -karte: ..... | ..^.. | ..... -ziel: 2,2 -> Turning right twice means it faces backwards. Then it drives one field down. - -runde: - mbot.forward(30); - mbot.turnRight(); - mbot.forward(30); - mbot.turnRight(); - mbot.forward(30); -karte: .... | .... | .^.. -ziel: 2,2 -> Up, to the right, and after the second turn it faces down. -::: - ## Checklist Rate yourself honestly for each point: ☂️ not yet, ⛅ partly, ☀️ I can do this confidently. For ⛅ and ☂️, **Review** helps you. Then comes the quiz. It shows you whether your self-assessment is right. @@ -47714,6 +47696,48 @@ tipp: Five boxes \`mbot.forward()\` one below the other. Each drives 10 cm. lösung: vb-gerade-loesung.visustruct ::: +## Game: Where does the mBot2 end up? + +::: spiel fahrt +titel: Game: Where does the mBot2 end up? +intro: Read the program and tap the field where the mBot2 is at the end. Then it drives the route for you. Each field is 30 cm. Four rounds. +frage: On which field is the mBot2 at the end? + +runde: + mbot.forward(60); + mbot.turnRight(); + mbot.forward(30); +karte: ..... | ..... | ..^.. +ziel: 3,0 +> Two fields forward, turn right, one more field. + +runde: + mbot.forward(30); + mbot.turnLeft(); + mbot.forward(60); +karte: ..... | ..... | ..^.. +ziel: 0,1 +> One field forward, then it faces left and drives two fields. + +runde: + mbot.turnRight(); + mbot.turnRight(); + mbot.forward(30); +karte: ..... | ..^.. | ..... +ziel: 2,2 +> Turning right twice means it faces backwards. Then it drives one field down. + +runde: + mbot.forward(30); + mbot.turnRight(); + mbot.forward(30); + mbot.turnRight(); + mbot.forward(30); +karte: .... | .... | .^.. +ziel: 2,2 +> Up, to the right, and after the second turn it faces down. +::: + ## Connecting the real mBot2 ::: mbot2 @@ -76644,7 +76668,7 @@ ${l}`)}es=TW(((o=e.find(([l])=>l==="begriffe.md"))==null?void 0:o[1])??"")}funct

${Oe(p("simulation_trace"))}

${Oe(p("simulation_variables"))}

${Oe(p("simulation_output"))}

- `;const e=a=>this.element.querySelector(a);this.buttons={play:e("[data-sim=play]"),pause:e("[data-sim=pause]"),step:e("[data-sim=step]"),stop:e("[data-sim=stop]")},this.buttons.play.addEventListener("click",()=>this.play()),this.buttons.pause.addEventListener("click",()=>this.pause()),this.buttons.step.addEventListener("click",()=>this.step()),this.buttons.stop.addEventListener("click",()=>this.reset()),this.editButton=e(".sim-edit"),this.editButton.addEventListener("click",()=>this.onEdit());const t=e("[data-sim=highlight]");t.value=this.highlightMode,t.addEventListener("change",()=>{this.highlightMode=t.value,km(Im,this.highlightMode)});const n=e("[data-sim=delay]");n.value=this.delay,n.addEventListener("change",()=>{this.delay=n.value,km(Nr,this.delay)}),this.inputSection=e(".sim-input > div"),this.trace=e(".sim-trace"),this.variables=e(".sim-vars"),this.output=e(".sim-output"),this.notice=e(".sim-notice")}collectOutput(){const e=this.engine.state.outputLines;for(;this.printedr.localeCompare(o));if(n.length===0)this.variables.innerHTML=`

${Oe(p("simulation_variables_placeholder"))}

`;else{const r=document.createElement("table");for(const o of n){const l=r.insertRow();l.insertCell().textContent=o;const u=e.variables.get(o),m=l.insertCell();u.kind==="grid"?m.append(Fg(u)):m.textContent=_e(u)}this.variables.replaceChildren(r)}e.outputLines.length===0&&e.files.size===0?this.output.innerHTML=`

${Oe(p("simulation_output_placeholder"))}

`:(this.output.replaceChildren(...e.outputLines.map(r=>{const o=document.createElement("div");return o.textContent=r,o}),...Ng(e.files)),this.output.scrollTop=this.output.scrollHeight)}updateInput(){const e=this.engine.state.inputRequest,t=this.inputSection;if(t.parentElement.classList.toggle("active",!!e),!e){t.innerHTML=`

${Oe(p("simulation_input_placeholder"))}

`;return}let n=t.querySelector("form");if(!n){n=document.createElement("form"),n.innerHTML=`

`;const l=n.querySelector("input");n.addEventListener("submit",u=>{u.preventDefault(),this.submitInput(l)}),t.replaceChildren(n),requestAnimationFrame(()=>l.focus())}const a=this.engine.state.outputLines;n.querySelector(".sim-prompt").textContent=e.prompt||(a[a.length-1]??"");const s=n.querySelector("input");s.inputMode=e.valueType==="string"||e.valueType==="boolean"?"text":"decimal";const r=this.engine.state.inputErrorNotice,o=n.querySelector(".sim-input-error");o.textContent=r?i1(r):"",o.hidden=!r}}function Fg(i){const e=document.createElement("table");e.className="sim-grid";for(const t of i.value){const n=e.insertRow();for(const a of t){const s=n.insertCell();s.textContent=String(a),a===!0&&(s.className="sim-grid-true")}}return e}const T1=Array.from("ABCDEFGHIJKLMNOPQRSTUVWXYZ"),Vn=360/T1.length,BE="http://www.w3.org/2000/svg";function Re(i,e={},...t){const n=document.createElement(i);for(const[a,s]of Object.entries(e))n.setAttribute(a,s);return n.append(...t),n}function vt(i,e={},t){const n=document.createElementNS(BE,i);for(const[a,s]of Object.entries(e))n.setAttribute(a,String(s));return t!==void 0&&(n.textContent=t),n}function OE(i,e){const t=(e%26+26)%26;return Array.from(i).map(n=>{const a=n.charCodeAt(0);return a>=65&&a<=90?String.fromCharCode((a-65+t)%26+65):a>=97&&a<=122?String.fromCharCode((a-97+t)%26+97):n}).join("")}function Sm(i,e){const t=vt("g",{class:e}),n=T1.map((a,s)=>{const r=vt("g",{transform:`rotate(${s*Vn})`});return r.append(vt("text",{x:0,y:-i,"text-anchor":"middle","dominant-baseline":"central"},a)),t.append(r),r});return{group:t,cells:n}}function ME(i,e){let t=i,n=!1,a=-t*Vn;const s=Re("section",{class:"learn-game learn-caesar"});s.append(Re("div",{class:"learn-game-head"},Re("strong",{},p("web_learn_caesar_title")))),s.append(Re("p",{class:"learn-game-status"},p("web_learn_caesar_hint")));const r=vt("svg",{viewBox:"-200 -200 400 400",class:"learn-caesar-disc",role:"img"});r.append(vt("circle",{r:196,class:"outer-disc"})),r.append(vt("path",{d:ZE(196,92,Vn/2),class:"window"}));const o=Sm(168,"outer-letters");r.append(o.group);for(let C=0;C{o.cells.forEach((L,F)=>L.classList.toggle("marked",F===C)),u.cells.forEach((L,F)=>L.classList.toggle("marked",C!==void 0&&F===(C+t)%26))},k=()=>{m.textContent=String(t),l.setAttribute("transform",`rotate(${a})`),r.setAttribute("aria-label",p("web_learn_caesar_key_fmt",t)),x.textContent=p(n?"web_learn_caesar_secret":"web_learn_caesar_plain"),w.textContent=p(n?"web_learn_caesar_plain":"web_learn_caesar_secret"),f.classList.toggle("active",!n),b.classList.toggle("active",n),z.textContent=OE(v.value,n?-t:t)||" ";const C=Array.from(v.value.toUpperCase()).reverse().find(F=>T1.includes(F));if(C===void 0)return S();const L=T1.indexOf(C);S(n?(L-t+26)%26:L)},P=C=>{t=(C%26+26)%26,a=-t*Vn,k()};c.addEventListener("click",()=>P(t-1)),d.addEventListener("click",()=>P(t+1)),f.addEventListener("click",()=>{var C;n&&(v.value=((C=z.textContent)==null?void 0:C.trim())??""),n=!1,k()}),b.addEventListener("click",()=>{var C;n||(v.value=((C=z.textContent)==null?void 0:C.trim())??""),n=!0,k()}),v.addEventListener("input",k),o.cells.forEach((C,L)=>C.addEventListener("click",()=>S(L)));let D;const A=C=>{const L=r.getBoundingClientRect();return Math.atan2(C.clientY-(L.top+L.height/2),C.clientX-(L.left+L.width/2))*180/Math.PI};l.addEventListener("pointerdown",C=>{const L=C;D=A(L)-a,l.classList.add("dragging"),r.setPointerCapture(L.pointerId),L.preventDefault()}),r.addEventListener("pointermove",C=>{if(D===void 0)return;a=A(C)-D,l.setAttribute("transform",`rotate(${a})`);const L=Math.round(-a/Vn);if((L%26+26)%26!==t){t=(L%26+26)%26;const F=a;k(),a=F,l.setAttribute("transform",`rotate(${a})`)}});const B=()=>{D!==void 0&&(D=void 0,l.classList.remove("dragging"),P(t))};return r.addEventListener("pointerup",B),r.addEventListener("pointercancel",B),k(),s}function ZE(i,e,t){const n=(a,s)=>{const r=(s-90)*Math.PI/180;return`${(a*Math.cos(r)).toFixed(2)} ${(a*Math.sin(r)).toFixed(2)}`};return`M ${n(i,-t)} A ${i} ${i} 0 0 1 ${n(i,t)} L ${n(e,t)} A ${e} ${e} 0 0 0 ${n(e,-t)} Z`}const T0=i=>p(`web_visubot_part_${i}`),Rg=new WeakMap;function Jg(i,e,t,n){const a=document.createElement("div");a.className="visubot-model";const s=document.createElement("div");s.className="visubot-stage";const r=document.createElement("div");r.className="visubot-part-label",r.hidden=!0,s.append(r);const o=(c,d,h)=>{r.hidden=!1,r.textContent=T0(c),r.style.left=`${Math.min(d+12,s.clientWidth-140)}px`,r.style.top=`${h+12}px`},l=document.createElement("p");l.className="visubot-model-hint hint",l.textContent=p("web_visubot_tap_part"),l.hidden=!!n,a.append(s,l);const u=ee(async()=>{const{Robot3D:c}=await import("./robot3d-RDgYNuY0.js");return{Robot3D:c}},[],import.meta.url).then(({Robot3D:c})=>{const d=new c(s);d.showcase(),d.highlight(i),i.includes("leds")&&d.setLed([40,90,255]),d.focusOn([],e==="unten"||e==="bottom"?"":e,!1,1),d.focusOn(i,e,t);let h;return s.addEventListener("pointerdown",g=>h={x:g.clientX,y:g.clientY}),s.addEventListener("pointerup",g=>{if(!h||Math.hypot(g.clientX-h.x,g.clientY-h.y)>5)return;const f=d.partAt(g.clientX,g.clientY);if(!f)return;if(n)return n(f);d.highlight(f);const b=s.getBoundingClientRect();o(f,g.clientX-b.left,g.clientY-b.top)}),s.addEventListener("pointermove",g=>{if(g.pointerType!=="mouse"||n)return;const f=d.partAt(g.clientX,g.clientY);if(r.hidden=!f,!f)return;const b=s.getBoundingClientRect();o(f,g.clientX-b.left,g.clientY-b.top)}),s.addEventListener("pointerleave",()=>r.hidden=!0),d}).catch(c=>{console.error(c),s.textContent=p("web_visubot_no_3d")}),m={box:a,ready:u,focus:i,view:e};return Rg.set(a,m),m}function LE(i,e,t=!1){return Jg(i,e,t).box}function WE(i){const e=i.querySelector(".visubot-model"),t=e&&Rg.get(e);for(const n of i.querySelectorAll("[data-robot-part]")){const a=(n.dataset.robotPart??"").split(",").filter(Boolean);if(n.title=a.map(T0).join(", "),!t)continue;const s=()=>void t.ready.then(o=>o==null?void 0:o.highlight(a)),r=()=>void t.ready.then(o=>o==null?void 0:o.highlight(t.focus));n.addEventListener("mouseenter",s),n.addEventListener("focus",s),n.addEventListener("mouseleave",r),n.addEventListener("blur",r),n.addEventListener("click",()=>{t.ready.then(o=>{o==null||o.highlight(a),o==null||o.focusOn(a,t.view)}),t.box.scrollIntoView({block:"nearest",behavior:"smooth"})})}}function EE(i,e){let t=0;const n=document.createElement("div");n.className="visubot-quiz-question";const a=document.createElement("p");a.className="visubot-quiz-feedback",a.setAttribute("aria-live","polite");const s=()=>{n.innerHTML=jn(`**${t+1}/${i.length}** ${i[t].question}`)},r=Jg([],void 0,!1,l=>{if(!(t>=i.length)){if(r.ready.then(u=>u==null?void 0:u.highlight(l)),l!==i[t].part){a.className="visubot-quiz-feedback wrong",a.textContent=p("web_visubot_quiz_wrong_fmt",T0(l));return}t++,a.className="visubot-quiz-feedback right",t{u.forEach(v=>{window.clearTimeout(v),window.clearInterval(v)}),u=[]},c=()=>{a.textContent=`${p("web_game_round_fmt",o+1,r)} · ${p("web_game_score_fmt",l)}`},d=()=>{const v=$("button",{class:"primary"},o+1{o++,o{const v=i.rounds[o],w=i.seconds,z=$("div",{class:"learn-bomb-fuse"},$("span",{})),I=$("span",{class:"learn-bomb-time"}),S=$("div",{class:"learn-bomb","aria-live":"polite"},$("span",{class:"learn-bomb-icon","aria-hidden":"true"},"💣"),I,z),k=$("div",{class:"learn-game-feedback",role:"status"}),P=v.wrongPart!==void 0,D=[],A=v.code.split(` + `;const e=a=>this.element.querySelector(a);this.buttons={play:e("[data-sim=play]"),pause:e("[data-sim=pause]"),step:e("[data-sim=step]"),stop:e("[data-sim=stop]")},this.buttons.play.addEventListener("click",()=>this.play()),this.buttons.pause.addEventListener("click",()=>this.pause()),this.buttons.step.addEventListener("click",()=>this.step()),this.buttons.stop.addEventListener("click",()=>this.reset()),this.editButton=e(".sim-edit"),this.editButton.addEventListener("click",()=>this.onEdit());const t=e("[data-sim=highlight]");t.value=this.highlightMode,t.addEventListener("change",()=>{this.highlightMode=t.value,km(Im,this.highlightMode)});const n=e("[data-sim=delay]");n.value=this.delay,n.addEventListener("change",()=>{this.delay=n.value,km(Nr,this.delay)}),this.inputSection=e(".sim-input > div"),this.trace=e(".sim-trace"),this.variables=e(".sim-vars"),this.output=e(".sim-output"),this.notice=e(".sim-notice")}collectOutput(){const e=this.engine.state.outputLines;for(;this.printedr.localeCompare(o));if(n.length===0)this.variables.innerHTML=`

${Oe(p("simulation_variables_placeholder"))}

`;else{const r=document.createElement("table");for(const o of n){const l=r.insertRow();l.insertCell().textContent=o;const u=e.variables.get(o),m=l.insertCell();u.kind==="grid"?m.append(Fg(u)):m.textContent=_e(u)}this.variables.replaceChildren(r)}e.outputLines.length===0&&e.files.size===0?this.output.innerHTML=`

${Oe(p("simulation_output_placeholder"))}

`:(this.output.replaceChildren(...e.outputLines.map(r=>{const o=document.createElement("div");return o.textContent=r,o}),...Ng(e.files)),this.output.scrollTop=this.output.scrollHeight)}updateInput(){const e=this.engine.state.inputRequest,t=this.inputSection;if(t.parentElement.classList.toggle("active",!!e),!e){t.innerHTML=`

${Oe(p("simulation_input_placeholder"))}

`;return}let n=t.querySelector("form");if(!n){n=document.createElement("form"),n.innerHTML=`

`;const l=n.querySelector("input");n.addEventListener("submit",u=>{u.preventDefault(),this.submitInput(l)}),t.replaceChildren(n),requestAnimationFrame(()=>l.focus())}const a=this.engine.state.outputLines;n.querySelector(".sim-prompt").textContent=e.prompt||(a[a.length-1]??"");const s=n.querySelector("input");s.inputMode=e.valueType==="string"||e.valueType==="boolean"?"text":"decimal";const r=this.engine.state.inputErrorNotice,o=n.querySelector(".sim-input-error");o.textContent=r?i1(r):"",o.hidden=!r}}function Fg(i){const e=document.createElement("table");e.className="sim-grid";for(const t of i.value){const n=e.insertRow();for(const a of t){const s=n.insertCell();s.textContent=String(a),a===!0&&(s.className="sim-grid-true")}}return e}const T1=Array.from("ABCDEFGHIJKLMNOPQRSTUVWXYZ"),Vn=360/T1.length,BE="http://www.w3.org/2000/svg";function Re(i,e={},...t){const n=document.createElement(i);for(const[a,s]of Object.entries(e))n.setAttribute(a,s);return n.append(...t),n}function vt(i,e={},t){const n=document.createElementNS(BE,i);for(const[a,s]of Object.entries(e))n.setAttribute(a,String(s));return t!==void 0&&(n.textContent=t),n}function OE(i,e){const t=(e%26+26)%26;return Array.from(i).map(n=>{const a=n.charCodeAt(0);return a>=65&&a<=90?String.fromCharCode((a-65+t)%26+65):a>=97&&a<=122?String.fromCharCode((a-97+t)%26+97):n}).join("")}function Sm(i,e){const t=vt("g",{class:e}),n=T1.map((a,s)=>{const r=vt("g",{transform:`rotate(${s*Vn})`});return r.append(vt("text",{x:0,y:-i,"text-anchor":"middle","dominant-baseline":"central"},a)),t.append(r),r});return{group:t,cells:n}}function ME(i,e){let t=i,n=!1,a=-t*Vn;const s=Re("section",{class:"learn-game learn-caesar"});s.append(Re("div",{class:"learn-game-head"},Re("strong",{},p("web_learn_caesar_title")))),s.append(Re("p",{class:"learn-game-status"},p("web_learn_caesar_hint")));const r=vt("svg",{viewBox:"-200 -200 400 400",class:"learn-caesar-disc",role:"img"});r.append(vt("circle",{r:196,class:"outer-disc"})),r.append(vt("path",{d:ZE(196,92,Vn/2),class:"window"}));const o=Sm(168,"outer-letters");r.append(o.group);for(let C=0;C{o.cells.forEach((L,F)=>L.classList.toggle("marked",F===C)),u.cells.forEach((L,F)=>L.classList.toggle("marked",C!==void 0&&F===(C+t)%26))},k=()=>{m.textContent=String(t),l.setAttribute("transform",`rotate(${a})`),r.setAttribute("aria-label",p("web_learn_caesar_key_fmt",t)),x.textContent=p(n?"web_learn_caesar_secret":"web_learn_caesar_plain"),w.textContent=p(n?"web_learn_caesar_plain":"web_learn_caesar_secret"),f.classList.toggle("active",!n),b.classList.toggle("active",n),z.textContent=OE(v.value,n?-t:t)||" ";const C=Array.from(v.value.toUpperCase()).reverse().find(F=>T1.includes(F));if(C===void 0)return S();const L=T1.indexOf(C);S(n?(L-t+26)%26:L)},P=C=>{t=(C%26+26)%26,a=-t*Vn,k()};c.addEventListener("click",()=>P(t-1)),d.addEventListener("click",()=>P(t+1)),f.addEventListener("click",()=>{var C;n&&(v.value=((C=z.textContent)==null?void 0:C.trim())??""),n=!1,k()}),b.addEventListener("click",()=>{var C;n||(v.value=((C=z.textContent)==null?void 0:C.trim())??""),n=!0,k()}),v.addEventListener("input",k),o.cells.forEach((C,L)=>C.addEventListener("click",()=>S(L)));let D;const A=C=>{const L=r.getBoundingClientRect();return Math.atan2(C.clientY-(L.top+L.height/2),C.clientX-(L.left+L.width/2))*180/Math.PI};l.addEventListener("pointerdown",C=>{const L=C;D=A(L)-a,l.classList.add("dragging"),r.setPointerCapture(L.pointerId),L.preventDefault()}),r.addEventListener("pointermove",C=>{if(D===void 0)return;a=A(C)-D,l.setAttribute("transform",`rotate(${a})`);const L=Math.round(-a/Vn);if((L%26+26)%26!==t){t=(L%26+26)%26;const F=a;k(),a=F,l.setAttribute("transform",`rotate(${a})`)}});const B=()=>{D!==void 0&&(D=void 0,l.classList.remove("dragging"),P(t))};return r.addEventListener("pointerup",B),r.addEventListener("pointercancel",B),k(),s}function ZE(i,e,t){const n=(a,s)=>{const r=(s-90)*Math.PI/180;return`${(a*Math.cos(r)).toFixed(2)} ${(a*Math.sin(r)).toFixed(2)}`};return`M ${n(i,-t)} A ${i} ${i} 0 0 1 ${n(i,t)} L ${n(e,t)} A ${e} ${e} 0 0 0 ${n(e,-t)} Z`}const T0=i=>p(`web_visubot_part_${i}`),Rg=new WeakMap;function Jg(i,e,t,n){const a=document.createElement("div");a.className="visubot-model";const s=document.createElement("div");s.className="visubot-stage";const r=document.createElement("div");r.className="visubot-part-label",r.hidden=!0,s.append(r);const o=(c,d,h)=>{r.hidden=!1,r.textContent=T0(c),r.style.left=`${Math.min(d+12,s.clientWidth-140)}px`,r.style.top=`${h+12}px`},l=document.createElement("p");l.className="visubot-model-hint hint",l.textContent=p("web_visubot_tap_part"),l.hidden=!!n,a.append(s,l);const u=ee(async()=>{const{Robot3D:c}=await import("./robot3d-K0yfmoba.js");return{Robot3D:c}},[],import.meta.url).then(({Robot3D:c})=>{const d=new c(s);d.showcase(),d.highlight(i),i.includes("leds")&&d.setLed([40,90,255]),d.focusOn([],e==="unten"||e==="bottom"?"":e,!1,1),d.focusOn(i,e,t);let h;return s.addEventListener("pointerdown",g=>h={x:g.clientX,y:g.clientY}),s.addEventListener("pointerup",g=>{if(!h||Math.hypot(g.clientX-h.x,g.clientY-h.y)>5)return;const f=d.partAt(g.clientX,g.clientY);if(!f)return;if(n)return n(f);d.highlight(f);const b=s.getBoundingClientRect();o(f,g.clientX-b.left,g.clientY-b.top)}),s.addEventListener("pointermove",g=>{if(g.pointerType!=="mouse"||n)return;const f=d.partAt(g.clientX,g.clientY);if(r.hidden=!f,!f)return;const b=s.getBoundingClientRect();o(f,g.clientX-b.left,g.clientY-b.top)}),s.addEventListener("pointerleave",()=>r.hidden=!0),d}).catch(c=>{console.error(c),s.textContent=p("web_visubot_no_3d")}),m={box:a,ready:u,focus:i,view:e};return Rg.set(a,m),m}function LE(i,e,t=!1){return Jg(i,e,t).box}function WE(i){const e=i.querySelector(".visubot-model"),t=e&&Rg.get(e);for(const n of i.querySelectorAll("[data-robot-part]")){const a=(n.dataset.robotPart??"").split(",").filter(Boolean);if(n.title=a.map(T0).join(", "),!t)continue;const s=()=>void t.ready.then(o=>o==null?void 0:o.highlight(a)),r=()=>void t.ready.then(o=>o==null?void 0:o.highlight(t.focus));n.addEventListener("mouseenter",s),n.addEventListener("focus",s),n.addEventListener("mouseleave",r),n.addEventListener("blur",r),n.addEventListener("click",()=>{t.ready.then(o=>{o==null||o.highlight(a),o==null||o.focusOn(a,t.view)}),t.box.scrollIntoView({block:"nearest",behavior:"smooth"})})}}function EE(i,e){let t=0;const n=document.createElement("div");n.className="visubot-quiz-question";const a=document.createElement("p");a.className="visubot-quiz-feedback",a.setAttribute("aria-live","polite");const s=()=>{n.innerHTML=jn(`**${t+1}/${i.length}** ${i[t].question}`)},r=Jg([],void 0,!1,l=>{if(!(t>=i.length)){if(r.ready.then(u=>u==null?void 0:u.highlight(l)),l!==i[t].part){a.className="visubot-quiz-feedback wrong",a.textContent=p("web_visubot_quiz_wrong_fmt",T0(l));return}t++,a.className="visubot-quiz-feedback right",t{u.forEach(v=>{window.clearTimeout(v),window.clearInterval(v)}),u=[]},c=()=>{a.textContent=`${p("web_game_round_fmt",o+1,r)} · ${p("web_game_score_fmt",l)}`},d=()=>{const v=$("button",{class:"primary"},o+1{o++,o{const v=i.rounds[o],w=i.seconds,z=$("div",{class:"learn-bomb-fuse"},$("span",{})),I=$("span",{class:"learn-bomb-time"}),S=$("div",{class:"learn-bomb","aria-live":"polite"},$("span",{class:"learn-bomb-icon","aria-hidden":"true"},"💣"),I,z),k=$("div",{class:"learn-game-feedback",role:"status"}),P=v.wrongPart!==void 0,D=[],A=v.code.split(` `).map((X,he)=>{if(!P){const M=$("button",{class:"ln",type:"button"},X||" ");return M.disabled=!X.trim(),D.push({button:M,line:he+1,right:he+1===v.wrongLine}),M}const ae=$("div",{class:"ln parts"});X.trim()||ae.append(" ");for(const M of pg(X)){if(!M.part){ae.append(M.text);continue}const j=$("button",{class:"part",type:"button"},M.text);D.push({button:j,line:he+1,right:he+1===v.wrongLine&&M.text===v.wrongPart}),ae.append(j)}return ae});for(const X of D)X.button.addEventListener("click",()=>F(X.right?"right":X.line===v.wrongLine?"part":"wrong",X.button));const B=$("div",{class:`learn-game-code learn-bomb-code mono${P?" by-parts":""}`,dir:"ltr"},...A),C=Date.now(),L=()=>{if(!t.isConnected&&Date.now()-C>1e3)return m();const X=Math.max(0,w-(Date.now()-C)/1e3);I.textContent=p("web_game_time_fmt",Math.ceil(X)),z.firstChild.style.width=`${X/w*100}%`,S.classList.toggle("hurry",X<=5),X<=0&&F("time")},F=(X,he)=>{m();for(const j of D)j.button.disabled=!0,j.right&&j.button.classList.add("right");P&&A[v.wrongLine-1].classList.add("right"),he&&X!=="right"&&he.classList.add("wrong");const ae=X==="right";ae&&l++,c(),S.classList.add(ae?"defused":"boom"),S.firstChild.textContent=ae?"✂️":"💥",k.className=`learn-game-feedback ${ae?"right":"wrong"}`;const M=d();k.replaceChildren($("p",{},p(ae?"web_game_defused":X==="time"?"web_game_boom_time":X==="part"?"web_game_boom_part":P?"web_game_boom_wrong_part":"web_game_boom_wrong")),Gn("div",{class:"learn-game-explain"},v.explanation),$("p",{class:"learn-bomb-fix"},`${p("web_game_fix")} `,$("code",{},v.fix.trim())),M),M.focus({preventScroll:!0})},Y=Gn("p",{class:"learn-game-question"},v.question);P&&Y.append(" ",$("span",{class:"learn-bomb-hint"},p("web_game_bomb_parts_hint"))),s.replaceChildren(S,Y,B,k),L();const ne=window.setInterval(L,200);u.push(ne)},g=()=>{const v=i.rounds[o],w=[];v.code.trim()&&w.push(_m(v.code).element),w.push(Gn("p",{class:"learn-game-question"},v.question),$("p",{class:"learn-order-hint"},p("web_game_order_hint")));const z=$("div",{class:"learn-game-options learn-order"}),I=$("div",{class:"learn-game-feedback",role:"status"});let S=0;const k=FE(v.options.length).map(D=>{const A=$("span",{class:"learn-order-badge","aria-hidden":"true"}),B=$("span",{});B.innerHTML=je(v.options[D].text);const C=$("button",{},A,B);return C.addEventListener("click",()=>{if(D!==S)return C.classList.add("wrong"),P(!1);C.classList.add("right"),A.textContent=String(++S),C.disabled=!0,S===v.options.length&&P(!0)}),z.append(C),{k:D,b:C,badge:A}}),P=D=>{for(const{k:B,b:C,badge:L}of[...k].sort((F,Y)=>F.k-Y.k))C.disabled=!0,L.textContent=String(B+1),z.append(C);D&&l++,c(),I.className=`learn-game-feedback ${D?"right":"wrong"}`;const A=d();I.replaceChildren($("p",{},p(D?"web_game_right":"web_game_wrong_short")),Gn("div",{class:"learn-game-explain"},v.explanation),A),A.focus({preventScroll:!0})};s.replaceChildren(...w,z,I)},f=()=>{if(m(),i.kind==="bombe"||i.kind==="reihenfolge"){c(),i.kind==="bombe"?h():g();return}const v=i.rounds[o];c();const w=_m(v.code),z=[];let I;i.kind==="zuhoerer"?(I=RE(bg(v.code),w),z.push($("div",{class:"learn-swing-row"},w.element,I.element)),v.clicks.length&&z.push($("p",{class:"learn-swing-clicks"},`${p("web_game_clicks")} `,...v.clicks.flatMap((A,B)=>[...B?[" → "]:[],$("code",{},A)])))):v.code.trim()&&z.push(w.element),z.push(Gn("p",{class:"learn-game-question"},v.question));const S=$("div",{class:`learn-game-options ${i.kind==="layout"?"pictures":""}`}),k=$("div",{class:"learn-game-feedback",role:"status"}),P=v.options.map(A=>{const B=$("button",{});return i.kind==="layout"?B.append(GE(A.text)):A.text.includes(` `)?B.append(JE(A.text)):B.innerHTML=je(A.text),B.addEventListener("click",()=>D(A.right,B)),S.append(B),B}),D=(A,B)=>{P.forEach((L,F)=>{L.disabled=!0,v.options[F].right&&L.classList.add("right")}),A||B.classList.add("wrong"),A&&l++,c(),k.className=`learn-game-feedback ${A?"right":"wrong"}`;const C=d();k.replaceChildren($("p",{},p(A?"web_game_right":"web_game_wrong_short")),Gn("div",{class:"learn-game-explain"},v.explanation)),k.append(C),I&&(u=I.replay(v.clicks,()=>C.before($("p",{class:"learn-swing-try"},p("web_game_try"))))),C.focus({preventScroll:!0})};s.replaceChildren(...z,S,k)},b=()=>{m(),a.textContent="";const v=$("button",{class:"primary"},p("web_game_again"));v.addEventListener("click",()=>{o=l=0,f()}),s.replaceChildren($("p",{class:"learn-game-result"},p("web_game_done_fmt",l,r)),$("p",{},p(l===r?"web_game_perfect":l>=r*.7?"web_game_good":"web_game_practice_short")),v)},x=$("button",{class:"primary"},p("web_game_start"));return x.addEventListener("click",f),s.append(Gn("p",{},i.intro),x),t}function FE(i){const e=[...Array(i).keys()];for(;e.every((t,n)=>t===n);)for(let t=i-1;t>0;t--){const n=Math.floor(Math.random()*(t+1));[e[t],e[n]]=[e[n],e[t]]}return e}function _m(i){const e=i.split(` `).map(n=>$("div",{class:"ln"},n||" "));return{element:$("pre",{class:"learn-game-code mono",dir:"ltr"},...e),highlight(n,a){e.forEach((s,r)=>s.classList.toggle("hit",n!==void 0&&r>=n&&r<=(a??n)))}}}function RE(i,e){const t=xg(i),n=$("div",{class:"learn-swing-window",dir:"ltr"});n.append($("div",{class:"learn-swing-title"},i.title||" "));const a=$("div",{class:"learn-swing-body"}),s=new Map;for(const c of i.labels){const d=$("div",{class:"learn-swing-label"},t.texts[c.name]);s.set(c.name,d),a.append(d)}const r=i.buttons.map(c=>{const d=$("button",{class:"learn-swing-button",disabled:""},t.texts[c.name]);return s.set(c.name,d),a.append(d),d}),o=$("p",{class:"learn-swing-event",role:"status"}),l=$("pre",{class:"learn-swing-console mono",hidden:""});n.append(a,o,l);const u=c=>{var h,g;const d=s.get(c.button);d.classList.add("pressed"),window.setTimeout(()=>d.classList.remove("pressed"),350),e.highlight((h=c.listener)==null?void 0:h.from,(g=c.listener)==null?void 0:g.to),o.textContent=c.listener?p("web_game_event_fmt",d.textContent??""):p("web_game_nobody"),o.className=`learn-swing-event ${c.listener?"heard":"nobody"}`;for(const[f,b]of Object.entries(c.texts)){const x=s.get(f);x&&x.textContent!==b&&(x.textContent=b,x.classList.remove("changed"),x.offsetWidth,x.classList.add("changed"))}c.console.length&&(l.hidden=!1,l.textContent+=c.console.map(f=>`${f} @@ -76660,7 +76684,7 @@ ${l}`)}es=TW(((o=e.find(([l])=>l==="begriffe.md"))==null?void 0:o[1])??"")}funct ${a}`));this.body.append(s),this.foldReference(s)}}foldReference(e){const t="visustruct.reference.open";let n=[];try{n=JSON.parse(localStorage.getItem(t)??"[]")}catch{}for(const a of[...e.querySelectorAll("h2")]){const s=a.textContent??"",r=_("details",{class:"reference-group"});r.open=n.includes(s);const o=_("summary",{},s);for(a.replaceWith(r),r.append(o);r.nextSibling&&r.nextSibling.nodeName!=="H2";)r.append(r.nextSibling);r.addEventListener("toggle",()=>{n=r.open?[...new Set([...n,s])]:n.filter(l=>l!==s);try{localStorage.setItem(t,JSON.stringify(n))}catch{}})}}showReference(){this.tab="reference",this.persist(),this.render()}persist(){xe.setView({tab:this.tab,lesson:this.lessonId,task:this.taskId})}showLesson(e){zt.some(t=>t.id===e)&&this.openLesson(e)}openLesson(e){this.tab="lessons",this.lessonId=e,this.returnTo=void 0,this.persist(),this.render(),this.body.scrollTop=0}renderLessonList(){this.body.append(_("p",{class:"hint"},p("web_learn_intro")));for(const e of cN()){this.body.append(_("h3",{class:"learn-section"},e.name));const t=_("ol",{class:"learn-list"});for(const n of e.lessons){const a=xe.lesson(n.id),s=a.done?"✓":a.step>0?p("web_learn_step_of_fmt",a.step+1,n.steps.length):"",r=_("button",{class:"learn-item"+(a.done?" done":""),"data-lesson":n.id},_("span",{class:"learn-num"},String(n.number)),_("span",{class:"learn-item-text"},_("strong",{},n.robot?`🤖 ${n.title}`:n.title),_("small",{},n.summary)),_("span",{class:"learn-status"},s));r.addEventListener("click",()=>this.openLesson(n.id)),t.append(_("li",{},r))}this.body.append(t)}this.body.append(this.renderTeacherBox())}renderLesson(e){var u;const t=xe.lesson(e.id),n=Math.min(t.step,e.steps.length-1),a=e.steps[n],s=_("button",{class:"learn-back"},`← ${p("web_learn_all_lessons")}`);s.addEventListener("click",()=>this.openLesson(void 0));const r=_("nav",{class:"learn-progress","aria-label":p("web_learn_step_of_fmt",n+1,e.steps.length)});r.append(...e.steps.map((m,c)=>{const d=p("web_learn_step_fmt",c+1,m.title),h=cthis.goToStep(e,c)),g})),this.body.append(_("div",{class:"learn-lesson-head"},_("div",{class:"learn-head-row"},s,this.stepNav(e,n,t.done,"learn-nav learn-nav-top")),_("p",{class:"learn-kicker"},`${p("web_learn_lesson_fmt",e.number)} · ${e.section}${e.robot?" · 🤖 VisuBot":""}`),_("h2",{class:"learn-title"},_("span",{class:"learn-num","aria-hidden":"true"},String(e.number)),e.title),r,_("h3",{class:"learn-step-title"},`${n+1}. ${a.title}`)));const o=((u=this.returnTo)==null?void 0:u.lesson)===e.id&&this.returnTo.step!==n?this.returnTo:void 0,l=()=>{const m=_("button",{class:"learn-return"},`↩ ${p("web_learn_back_to_checklist")}`);return m.addEventListener("click",()=>{this.returnTo=void 0,this.goToStep(e,o.step),this.body.scrollTop=o.scroll}),m};o&&this.body.append(l()),a.blocks.forEach((m,c)=>this.body.append(this.renderBlock(m,`${n}-${c}`,e))),Bm(this.body),WE(this.body),this.openNeededColumns(a.blocks),Pm(this.body,es),this.body.append(this.stepNav(e,n,t.done,"learn-nav")),o&&this.body.append(l())}stepNav(e,t,n,a){const s=_("div",{class:a}),r=_("button",{},`← ${p("web_learn_back")}`);if(r.disabled=t===0,r.addEventListener("click",()=>this.goToStep(e,t-1)),s.append(r),tthis.goToStep(e,t+1)),s.append(o)}else{const o=_("button",{class:"primary"},n?`✓ ${p("web_learn_done")}`:p("web_learn_finish"));o.addEventListener("click",()=>{xe.updateLesson(e.id,{done:!0});const l=zt.find(u=>u.number===e.number+1);this.openLesson(l==null?void 0:l.id)}),s.append(o)}return s}goToStep(e,t){xe.updateLesson(e.id,{step:t}),this.render(),this.body.scrollTop=0}openNeededColumns(e){const t=e.flatMap(n=>n.kind==="exercise"?[n.exercise]:[]);lN(this.body)?(this.host.showEditor(),rN(this.body)&&this.host.reveal(["palette"])):oN(this.body)?this.host.showFiles():t.some(n=>n.code!=="java")?this.host.showEditor():(t.length>0||this.body.querySelector(".lesson-code[data-lang=java]"))&&this.host.showJava(),uN(this.body)&&this.host.showLiveCode()}renderTaskList(){this.body.append(_("p",{class:"hint"},p("web_learn_tasks_intro")));const e=_("ul",{class:"learn-list"});for(const t of Pn){const n=this.taskExercises(t),a=n.length>0&&n.every(o=>xe.exercise(o.id).done),s=zt.find(o=>o.number===t.after),r=_("button",{class:"learn-item"+(a?" done":""),"data-task":t.id},_("span",{class:"learn-num","aria-label":p("web_learn_level_fmt",t.level)},"★".repeat(t.level)),_("span",{class:"learn-item-text"},_("strong",{},t.title),_("small",{},s?p("web_learn_after_fmt",s.number,s.title):"")),_("span",{class:"learn-status"},a?"✓":""));r.addEventListener("click",()=>{this.taskId=t.id,this.persist(),this.render(),this.body.scrollTop=0}),e.append(_("li",{},r))}this.body.append(e,this.renderTeacherBox())}renderTeacherBox(){const e=_("details",{class:"learn-teacher"},_("summary",{},p("web_learn_teacher")));if(wm()){e.setAttribute("open","");const s=_("button",{},p("web_learn_teacher_off"));return s.addEventListener("click",()=>{AE(),this.render()}),e.append(_("p",{},p("web_learn_teacher_on")),s),e}const t=_("input",{type:"password",autocomplete:"off","aria-label":p("web_learn_teacher_code"),placeholder:p("web_learn_teacher_code")}),n=_("p",{class:"learn-result",role:"status"}),a=_("form",{class:"group"},t,_("button",{type:"submit"},p("web_learn_teacher_unlock")));return a.addEventListener("submit",async s=>{s.preventDefault(),await CE(t.value)?this.render():(n.className="learn-result info",n.textContent=p("web_learn_teacher_wrong"))}),e.append(_("p",{class:"hint"},p("web_learn_teacher_intro")),a,n),e}taskExercises(e){return e.blocks.flatMap(t=>t.kind==="exercise"?[t.exercise]:[])}renderTask(e){const t=_("button",{class:"learn-back"},`← ${p("web_learn_all_tasks")}`);t.addEventListener("click",()=>{this.taskId=void 0,this.persist(),this.render()});const n=zt.find(a=>a.number===e.after);if(this.body.append(t,_("h2",{class:"learn-title"},e.title)),n){const a=_("button",{class:"link-button"},p("web_learn_after_fmt",n.number,n.title));a.addEventListener("click",()=>this.openLesson(n.id)),this.body.append(_("p",{class:"learn-kicker"},a))}e.blocks.forEach((a,s)=>this.body.append(this.renderBlock(a,`task-${s}`))),Bm(this.body),this.openNeededColumns(e.blocks),Pm(this.body,es)}renderBlock(e,t,n){switch(e.kind){case"markdown":return this.withOpenButtons(Ve("div",{class:"learn-text"},jn(e.text)));case"diagram":return this.renderDiagram(e.file,e.caption);case"exercise":return this.renderExercise(e.exercise);case"competences":return this.renderCompetences(e.items);case"checklist":return this.renderChecklist(e.items,t,n);case"quiz":return this.renderQuiz(e.questions,t,n);case"brag":return this.renderBrag(e.text,e.tip);case"images":return this.renderImages(e.files,e.caption);case"graphic":return e.animated?this.renderAnimation(e.file,e.caption):this.renderGraphic(e.file,e.caption,e.labeled);case"game":return this.renderGame(e.game);case"roundGame":return NE(e.game,x1);case"rescueGame":return HE(e.game,x1);case"driveGame":return YE(e.game,x1);case"crosswordGame":return VE(e.game,x1);case"caesar":return ME(e.key,e.text);case"cloze":return $E(e.cloze);case"pap":return iN(e.pap);case"textFile":return Eg(e.name,e.content);case"robotModel":return LE(e.focus,e.view,e.spin);case"robotQuiz":return EE(e.tasks,e.done)}}renderBrag(e,t=!1){const n=_("aside",{class:"learn-brag"});n.append(_("img",{src:x1,alt:"",width:"48",height:"48"}));const a=_("div",{},_("p",{class:"learn-brag-title"},p(t?"web_learn_ludwig_tip":"web_learn_brag")));return a.append(Ve("div",{class:"learn-text"},jn(e))),n.append(a),n}renderGame(e){const n=_("section",{class:"learn-game"}),a=_("div",{class:"learn-game-head"});a.append(_("img",{src:x1,alt:"",width:"40",height:"40"}),_("strong",{},p("web_game_title")));const s=_("p",{class:"learn-game-status"}),r=_("div",{class:"learn-game-stage"});n.append(a,s,r);let o=0,l=0;const u=()=>{const d=e4(e,o,10);s.textContent=`${p("web_game_round_fmt",o+1,10)} · ${p("web_game_score_fmt",l)}`;const h=_("div",{class:"learn-game-values mono"});for(const[w,z]of t4(d))h.append(_("code",{},`${w} = ${z}`));const g=_("div",{class:"group learn-game-answers"}),f=_("button",{class:"learn-game-true"},`✓ ${p("web_game_true")}`),b=_("button",{class:"learn-game-false"},`✗ ${p("web_game_false")}`);g.append(f,b);const x=_("div",{class:"learn-game-feedback",role:"status"}),v=w=>{f.disabled=b.disabled=!0;const z=w===d.answer;z&&l++,s.textContent=`${p("web_game_round_fmt",o+1,10)} · ${p("web_game_score_fmt",l)}`,x.className=`learn-game-feedback ${z?"right":"wrong"}`;const I=_("div",{class:"learn-game-steps mono"});Kx(d.condition,d.values).forEach((k,P)=>I.append(_("div",{},`${P?"→ ":""}${k}`)));const S=_("button",{class:"primary"},o+1<10?p("web_game_next"):p("web_game_finish"));S.addEventListener("click",()=>{o++,o<10?u():m()}),x.replaceChildren(_("p",{},p(z?"web_game_right":"web_game_wrong")),I,S),S.focus()};f.addEventListener("click",()=>v(!0)),b.addEventListener("click",()=>v(!1)),r.replaceChildren(h,_("div",{class:"learn-game-condition mono"},d.condition),g,x)},m=()=>{s.textContent="";const d=_("button",{class:"primary"},p("web_game_again"));d.addEventListener("click",()=>{o=l=0,u()}),r.replaceChildren(_("p",{class:"learn-game-result"},p("web_game_done_fmt",l,10)),_("p",{},p(l===10?"web_game_perfect":l>=10*.7?"web_game_good":"web_game_practice")),d)},c=_("button",{class:"primary"},p("web_game_start"));return c.addEventListener("click",u),r.append(_("p",{},p("web_game_intro")),c),n}renderImages(e,t){const n=_("figure",{class:"learn-figure"}),a=_("div",{class:"learn-images"});for(const s of e){const r=va(s);r&&a.append(_("img",{src:r,alt:"",loading:"lazy"}))}return n.append(a),t&&n.append(Ve("figcaption",{},je(t))),n}renderGraphic(e,t,n){const a=_("figure",{class:"learn-figure"}),s=va(e),r=n?va(n):void 0;if(s&&r){const o=_("img",{class:"learn-graphic",src:s,alt:"",loading:"lazy"}),l=_("button",{class:"learn-graphic-toggle",type:"button",title:p("web_learn_graphic_labels"),"aria-pressed":"false"},o);l.addEventListener("click",()=>{const u=l.getAttribute("aria-pressed")!=="true";l.setAttribute("aria-pressed",String(u)),o.src=u?r:s}),a.append(l,_("p",{class:"learn-graphic-hint"},p("web_learn_graphic_labels")))}else s&&a.append(_("img",{class:"learn-graphic",src:s,alt:"",loading:"lazy"}));return t&&a.append(Ve("figcaption",{},je(t))),a}renderAnimation(e,t){const n=_("figure",{class:"learn-figure"}),a=va(e);if(!a)return n;const s=_("div",{class:"learn-graphic learn-animation"}),r=_("button",{class:"learn-replay",type:"button"},`↻ ${p("web_learn_replay")}`);let o=()=>{};return fetch(a).then(l=>l.text()).then(l=>{var d,h;s.innerHTML=l;const u=s.querySelector("svg"),m=(h=(d=u==null?void 0:u.getAttribute("class"))==null?void 0:d.match(/(\S+-)svg\b/))==null?void 0:h[1];if(!u||!m)return;if(o=()=>{u.classList.remove(`${m}play`),u.getBoundingClientRect(),u.classList.add(`${m}play`)},typeof IntersectionObserver>"u")return o();const c=new IntersectionObserver(g=>{g.some(f=>f.isIntersecting)&&(c.disconnect(),o())},{threshold:.6});c.observe(s)}).catch(()=>s.append(_("img",{src:a,alt:""}))),r.addEventListener("click",()=>o()),n.append(s,r),t&&n.append(Ve("figcaption",{},je(t))),n}withOpenButtons(e){for(const t of e.querySelectorAll("pre.lesson-code[data-open=editor]")){const n=t.textContent??"",a=_("button",{class:"learn-open-code"},p("web_learn_open_in_editor"));a.addEventListener("click",()=>this.host.openJavaCode(n)),t.after(a)}return e}renderDiagram(e,t){const n=di(e),a=_("figure",{class:"learn-figure"});if(!n)return a;const s=this.host.preview(n);s&&a.append(_("div",{class:"learn-preview",dir:"ltr"},s)),t&&a.append(Ve("figcaption",{},je(t)));const r=_("button",{},p("web_learn_open_in_editor"));return r.addEventListener("click",()=>this.host.openDiagram(n,e)),a.append(r),a}renderExercise(e){const t=_("section",{class:"learn-exercise","data-exercise":e.id}),n=()=>xe.exercise(e.id),a=_("span",{class:"learn-badge"},`✓ ${p("web_learn_solved")}`);a.hidden=!n().done,t.append(_("h4",{},`${p("web_learn_exercise")}: ${e.title}`,a),pN(e),Ve("div",{class:"learn-text"},jn(e.task)));const s=_("div",{class:"learn-result",role:"status"}),r=_("div",{class:"learn-hints"}),o=_("div",{class:"group"}),l=_("button",{class:"primary"},p("web_learn_open_exercise"));l.addEventListener("click",()=>{const c=n().xml;let d=Om(e);if(c)try{d=n0(c)}catch{}this.host.openExercise(e,d)});const u=_("button",{},p("web_learn_check"));if(u.addEventListener("click",()=>{const c=this.host.exerciseDocument(e.id);if(!c){s.className="learn-result info",s.textContent=p("web_learn_open_first");return}if(c.elements.every(Kl)){s.className="learn-result info",s.textContent=p("web_learn_empty");return}this.host.stopSimulation();const d=qx(c,e.tests,this.host.subprogramsFor(e.id),ts),h=Qx(c),g=e.requires.map(x=>x==="forZaehlSchleife"?"forSchleife":x).filter(x=>x in T&&!h.has(T[x])),f=e.loopDepth!==void 0&&Yo(c.elements)x.passed)&&g.length===0&&!f;this.showResult(s,d,g,b,f),b&&(xe.updateExercise(e.id,{done:!0}),a.hidden=!1)}),o.append(l,u),e.hints.length>0){const c=_("button",{},p("web_learn_hint"));c.addEventListener("click",()=>{const d=r.children.length;if(d>=e.hints.length)return;const h=e.hints.length>1?`**${p("web_learn_hint_fmt",d+1,e.hints.length)}:** `:"";r.append(Ve("aside",{class:"lesson-note"},jn(h+e.hints[d]))),c.textContent=p("web_learn_hint_more"),c.toggleAttribute("disabled",d+1>=e.hints.length)}),o.append(c)}const m=_("button",{class:"danger-text"},p("web_learn_reset"));if(m.addEventListener("click",()=>{if(m.dataset.confirm!=="1"){m.dataset.confirm="1",m.textContent=p("web_learn_reset_confirm"),setTimeout(()=>{m.dataset.confirm="",m.textContent=p("web_learn_reset")},4e3);return}xe.resetExercise(e.id),this.host.resetExercise(e.id,Om(e)),a.hidden=!0,s.replaceChildren(),s.className="learn-result",m.dataset.confirm="",m.textContent=p("web_learn_reset")}),o.append(m),t.append(o,r,s),wm()&&e.solution){const c=di(e.solution);if(c){const d=_("details",{class:"learn-solution"},_("summary",{},p("web_learn_solution")));d.addEventListener("toggle",()=>{if(!d.open||d.querySelector(".learn-preview"))return;const h=this.host.preview(c);h&&d.append(_("div",{class:"learn-preview",dir:"ltr"},h));const g=_("button",{},p("web_learn_open_in_editor"));g.addEventListener("click",()=>{this.host.openDiagram(c,e.solution);for(const f of e.subprograms){const b=di(f);b&&this.host.openDiagram(b,f)}});for(const f of e.subprograms){const b=di(f),x=b&&this.host.preview(b);x&&d.append(_("div",{class:"learn-preview",dir:"ltr"},x))}d.append(g)}),t.append(d)}}return t}showResult(e,t,n,a,s){var o,l,u,m,c;e.className="learn-result "+(a?"ok":"fail"),e.replaceChildren(_("p",{class:"learn-result-head"},a?`🎉 ${p("web_learn_passed")}`:p("web_learn_failed")));for(const d of n)e.append(_("p",{},`✗ ${p("web_learn_missing_fmt",dN(T[d]))}`));s&&e.append(_("p",{},`✗ ${p("web_visubot_depth_fmt",s)}`));const r=_("ul",{class:"learn-tests",dir:"auto"});for(const d of t){const h=d.test.world?t.filter(x=>x.test.world).indexOf(d)+1:0,g=d.test.world?`🗺 ${p("web_visubot_world_fmt",h)}`:d.test.actions?`🤖 ${p("web_visubot_actions")}`:d.test.sensors?`🎛 ${Object.entries(d.test.sensors).map(([x,v])=>`mbot.${x}() = ${v.join(" → ")}`).join(", ")}`:d.test.drive?`🤖 ${p("web_visubot_drive")}`:d.test.inputs.length?p("web_learn_input_fmt",d.test.inputs.join(", ")):p("web_learn_no_input"),f=[`${d.passed?"✓":"✗"} ${g}`],b=_("div",{class:"learn-test-detail"});if(d.test.drive&&b.append(_("span",{},`${p("web_learn_expected")}: `,_("code",{},mi(d.test.drive)||"–")),_("span",{},`${p("web_learn_actual")}: `,_("code",{},mi(d.result.drive??[])||"–"))),d.test.actions&&b.append(_("span",{},`${p("web_learn_expected")}: `,_("code",{},mi(d.test.actions)||"–")),_("span",{},`${p("web_learn_actual")}: `,_("code",{},mi(d.result.actions??[])||"–"))),d.test.led!==void 0){const x=v=>p(v?"web_visubot_led_on":"web_visubot_led_off");b.append(_("span",{},`💡 ${p("web_learn_expected")}: ${x(d.test.led)} · ${p("web_learn_actual")}: ${x(d.result.led)}`))}if(d.test.tone!==void 0){const x=v=>p(v?"web_visubot_tone_yes":"web_visubot_tone_no");b.append(_("span",{},`🔊 ${p("web_learn_expected")}: ${x(d.test.tone)} · ${p("web_learn_actual")}: ${x(d.result.tone)}`))}d.test.screen!==void 0&&b.append(_("span",{},`📺 ${p("web_learn_expected")}: `,_("code",{},d.test.screen),` · ${p("web_learn_actual")}: `,_("code",{},d.result.screen??"–"))),d.test.world&&(((l=(o=ts(d.test.world))==null?void 0:o.goals)!=null&&l.length||(m=(u=ts(d.test.world))==null?void 0:u.targets)!=null&&m.length)&&b.append(_("span",{},d.result.atGoal?`✓ ${p("web_visubot_goal_reached")}`:`✗ ${p("web_visubot_goal_missed")}`)),d.result.bumps&&b.append(_("span",{class:"learn-error"},`⚠︎ ${p("web_visubot_bumps")}: ${d.result.bumps}`))),(!d.test.drive&&!d.test.world&&!d.test.sensors&&!d.test.actions||d.result.outputs.length)&&b.append(_("span",{},`${p("web_learn_expected")}: `,_("code",{},d.test.expected.join(" | ")||"–")),_("span",{},`${p("web_learn_actual")}: `,_("code",{},d.result.outputs.join(" | ")||"–")));for(const x of d.test.files??[])b.append(_("span",{},`📄 ${x.name}, ${p("web_learn_expected")}: `,_("code",{},x.lines.join(" | ")||"–")),_("span",{},`📄 ${x.name}, ${p("web_learn_actual")}: `,_("code",{},gg((c=d.result.files)==null?void 0:c.get(x.name)).join(" | ")||"–")));!d.passed&&!d.result.error&&Vx(d.result.outputs,d.test.expected)&&b.append(_("span",{class:"learn-error"},p("web_learn_missing_line_break"))),d.result.error&&b.append(_("span",{class:"learn-error"},i1(d.result.error))),d.result.missingInput&&b.append(_("span",{class:"learn-error"},p("web_learn_missing_input"))),d.result.tooManySteps&&b.append(_("span",{class:"learn-error"},p("web_learn_too_many_steps"))),!d.passed&&d.result.unusedInputs&&b.append(_("span",{class:"learn-error"},p("web_learn_unused_input"))),r.append(_("li",{class:d.passed?"ok":"fail"},...f,b))}e.append(r)}renderCompetences(e){const t=_("aside",{class:"learn-competences"},_("p",{class:"learn-competences-title"},p("web_learn_competences_intro"))),n=_("ul",{});for(const a of e)n.append(Ve("li",{},je(a)));return t.append(n),t}renderChecklist(e,t,n){const a=[{value:"umbrella",icon:"☂️",label:p("web_learn_rating_umbrella")},{value:"cloud",icon:"⛅",label:p("web_learn_rating_cloud")},{value:"sun",icon:"☀️",label:p("web_learn_rating_sun")}],s=_("div",{class:"learn-checklist-wrap"}),r=_("p",{class:"learn-rating-legend"});for(const l of a)r.append(_("span",{},`${l.icon} ${l.label}`));const o=_("ul",{class:"learn-checklist"});return s.append(r,o),e.forEach((l,u)=>{var v;const m=`${t}-${u}`,c=n?(v=xe.lesson(n.id).checks)==null?void 0:v[m]:void 0;let d=c===!0?"sun":c||void 0;const h=Ve("span",{class:"learn-check-text"},je(l.text)),g=_("span",{class:"learn-rating",role:"group","aria-label":h.textContent??""}),f=a.map(w=>{const z=_("button",{class:"learn-rating-button",title:w.label,"aria-label":w.label},w.icon);return z.addEventListener("click",()=>{if(d=d===w.value?void 0:w.value,b(),!n)return;const I={...xe.lesson(n.id).checks??{}};d?I[m]=d:delete I[m],xe.updateLesson(n.id,{checks:Object.keys(I).length?I:void 0})}),z}),b=()=>{f.forEach((w,z)=>w.setAttribute("aria-pressed",String(a[z].value===d))),x.dataset.rating=d??""};g.append(...f);const x=_("li",{},h,g);if(n&&l.step!==void 0){const w=l.step,z=p("web_learn_step_fmt",w+1,n.steps[w].title),I=_("button",{class:"link-button learn-check-link",title:z,"aria-label":`${p("web_learn_review")}: ${z}`},p("web_learn_review"));I.addEventListener("click",()=>{this.returnTo={lesson:n.id,step:xe.lesson(n.id).step,scroll:this.body.scrollTop},this.goToStep(n,w)}),x.append(I)}b(),o.append(x)}),s}renderQuiz(e,t,n){const a=_("div",{class:"learn-quiz"}),s=_("p",{class:"learn-score",role:"status"}),r=()=>n?xe.lesson(n.id).quiz??{}:{},o=_("div",{class:"learn-review"}),l=()=>{const u=r(),m=(f,b)=>f.pairs?f.pairs.every((x,v)=>u[`${t}-${b}-${v}`]!==void 0):u[`${t}-${b}`]!==void 0,c=(f,b)=>{var x;return!!(f.pairs?f.pairs.every((v,w)=>Mm(f)[u[`${t}-${b}-${w}`]]===f.pairs[w].right):(x=f.options[u[`${t}-${b}`]])!=null&&x.correct)},d=e.filter(m).length,h=e.filter(c).length,g=d===e.length;s.textContent=g?p("web_learn_score_fmt",h,e.length):"",o.replaceChildren(),g&&n&&this.fillChecklistReview(o,n,e,f=>c(e[f],f))};return e.forEach((u,m)=>{const c=`${t}-${m}`,d=_("fieldset",{},Ve("legend",{},je(u.question))),h=Ve("p",{class:"learn-explanation"},je(u.explanation??""));if(u.pairs){d.append(this.renderMatch(u,c,r,n,h,l),h),a.append(d);return}const g=f=>{d.querySelectorAll("button").forEach((b,x)=>{b.classList.toggle("right",f!==void 0&&u.options[x].correct),b.classList.toggle("wrong",f===x&&!u.options[x].correct),b.setAttribute("aria-pressed",String(f===x))}),h.hidden=f===void 0||!u.explanation};u.options.forEach((f,b)=>{const x=Ve("button",{class:"learn-option"},je(f.text));x.addEventListener("click",()=>{n&&xe.updateLesson(n.id,{quiz:{...r(),[c]:b}}),g(b),l()}),d.append(x)}),d.append(h),g(r()[c]),a.append(d)}),a.append(s,o),l(),a}fillChecklistReview(e,t,n,a){const s={sun:"☀️",cloud:"⛅",umbrella:"☂️"},r=xe.lesson(t.id).checks??{},o=[];let l=0;t.steps.forEach((u,m)=>u.blocks.forEach((c,d)=>{c.kind==="checklist"&&c.items.forEach((h,g)=>{const f=r[`${m}-${d}-${g}`],b=f===!0?"sun":f||void 0,x=h.step===void 0?[]:n.map((S,k)=>S.step===h.step?k:-1).filter(S=>S>=0),v=x.filter(S=>!a(S));let w="";b==="sun"&&v.length?w=p("web_learn_review_overrated_fmt",v.map(S=>S+1).join(", ")):b&&b!=="sun"&&x.length&&!v.length&&(w=p("web_learn_review_underrated")),w&&l++;const z=_("li",{class:w?"learn-review-deviation":""}),I=Ve("span",{class:"learn-check-text"},je(h.text));if(w&&I.append(_("br",{}),_("em",{},w)),z.append(I,_("span",{class:"learn-review-icon","aria-label":p(b?`web_learn_rating_${b}`:"web_learn_review_unrated")},b?s[b]:"–")),w&&b==="sun"&&h.step!==void 0){const S=h.step,k=_("button",{class:"link-button learn-check-link"},p("web_learn_review"));k.addEventListener("click",()=>{this.returnTo={lesson:t.id,step:xe.lesson(t.id).step,scroll:this.body.scrollTop},this.goToStep(t,S)}),z.append(k)}o.push(z)})})),o.length&&e.append(_("p",{class:"learn-review-title"},`📋 ${p("web_learn_review_title")}`),_("p",{},p(l?"web_learn_review_hint":"web_learn_review_match")),_("ul",{class:"learn-checklist"},...o))}renderMatch(e,t,n,a,s,r){const o=e.pairs,l=Mm(e),u=_("div",{class:"learn-match"});let m={};const c=()=>a?n():m,d=b=>a?xe.updateLesson(a.id,{quiz:b}):m=b,h=b=>c()[`${t}-${b}`],g=o.map(b=>{const x=_("select",{class:"learn-match-select"});x.append(_("option",{value:""},"–")),l.forEach((w,z)=>x.append(_("option",{value:String(z)},w)));const v=Ve("label",{class:"learn-match-left"},je(b.left));return v.append(x),u.append(v),x}),f=()=>{const b=o.every((x,v)=>h(v)!==void 0);g.forEach((x,v)=>{const w=h(v);x.value=w===void 0?"":String(w),x.classList.toggle("right",b&&l[w]===o[v].right),x.classList.toggle("wrong",b&&l[w]!==o[v].right)}),s.hidden=!b||!e.explanation};return g.forEach((b,x)=>b.addEventListener("change",()=>{const v={...c()};b.value===""?delete v[`${t}-${x}`]:v[`${t}-${x}`]=Number(b.value),d(v),f(),r()})),f(),u}}function Mm(i){return(i.pairs??[]).map(e=>e.right).sort((e,t)=>e.localeCompare(t,"de"))}function pN(i){const e=Pg(i),t=e==="beide"?"web_learn_solve_in_both":e==="code"?"web_learn_solve_in_code":"web_learn_solve_in_editor",n={editor:p("web_editor_title"),code:p("web_live_title")},a=e==="beide"?["editor","code"]:[e==="code"?"code":"editor"],s=_("p",{class:`learn-where learn-where-${e}`});for(const r of p(t,...a).split(/(\u0001(?:editor|code))/))if(r==="editor"||r==="code"){const o=r.slice(1);s.append(_("span",{class:`area-name area-${o}`},n[o]))}else r&&s.append(r);return s}const fN=""+new URL("visubot-CyGFOI9V.webp",import.meta.url).href,hr="visustruct.visubot";function gr(){try{return localStorage.getItem(hr)}catch{return null}}function wi(){const i=gr();return i==="1"||i==="kurs"?"on":"off"}const Ug=()=>gr()==="2";function tl(){try{localStorage.setItem(hr,"2")}catch{}}const Yg=()=>gr()==="3";function $g(){try{localStorage.setItem(hr,"3")}catch{}}const Kg=()=>gr()!==null;function ns(i){try{localStorage.setItem(hr,i==="on"?"1":"0")}catch{}}const bN=`VisuBot`,qn=()=>wi()!=="off",Zm=i=>i.replace(/[&<>"]/g,e=>({"&":"&","<":"<",">":">",'"':"""})[e]);function nl(){const i=Ug()?"object":Yg()?"flow":wi(),e=(n,a)=>``,t={off:"web_visubot_world_visustruct_hint",on:"web_visubot_world_visubot_hint",object:"web_visuobject_world_hint",flow:"web_visuflow_world_hint"}[i];return`
${e("off","VisuStruct")}${e("on","VisuBot")}${e("object","VisuObject")}${e("flow","VisuFlow")}
- ${Zm(p(t))}`}class xN{constructor(e=Mi){y(this,"element");y(this,"world");y(this,"view");y(this,"loading");y(this,"status");y(this,"stage");y(this,"picker");y(this,"applied",0);y(this,"sent",0);y(this,"liveStatus");y(this,"viewport");y(this,"stopListening");y(this,"realSensors");y(this,"controls",{getBrightness:50,getLoudness:0,getPitch:0,getRoll:0});y(this,"pressTimers",new Map);y(this,"check");y(this,"checking",!1);y(this,"onWorldChange");this.world=new _s(e),this.element=document.createElement("section"),this.element.className="visubot",this.element.innerHTML=`

${p("web_visubot_world")}

${p("web_visubot_world_in_preview")}

${vN()}${yN()}`,this.stage=this.element.querySelector(".visubot-stage"),this.picker=this.element.querySelector(".visubot-worlds"),this.status=this.element.querySelector(".visubot-status"),this.liveStatus=this.element.querySelector(".visubot-live"),this.viewport=this.element.querySelector(".visubot-viewport"),this.stopListening=be.listen(()=>this.updateLive()),this.setupControls(),this.check=this.element.querySelector(".visubot-check"),this.setupCheck(),this.updateLive(),this.updateStatus()}show(){this.loading??(this.loading=ee(async()=>{const{Robot3D:e}=await import("./robot3d-RDgYNuY0.js");return{Robot3D:e}},[],import.meta.url).then(({Robot3D:e})=>{this.view=new e(this.stage),this.view.setWorld(this.world.setup),this.view.place(this.world.pose,this.world.trail),this.view.setLeds(this.world.leds)}).catch(()=>{this.stage.textContent=p("web_visubot_no_3d")}))}restoreViewport(){this.viewport.parentElement!==this.element&&this.liveStatus.after(this.viewport)}setWorlds(e){this.picker.replaceChildren(),this.picker.hidden=e.length<2,e.forEach((t,n)=>{const a=document.createElement("button");a.textContent=p("web_visubot_world_fmt",n+1),a.addEventListener("click",()=>this.useWorld(t,a)),this.picker.append(a)}),this.useWorld(e[0]??Mi,this.picker.firstElementChild)}useWorld(e,t){var n,a,s,r,o;for(const l of this.picker.children)l.classList.toggle("active",l===t);e!==this.world.setup&&(this.world=new _s(e),this.applied=0,this.sent=0,(n=this.view)==null||n.setWorld(e),(a=this.view)==null||a.place(this.world.pose,this.world.trail),(s=this.view)==null||s.setLed(void 0),(r=this.view)==null||r.setScreen(void 0),this.updateStatus(),(o=this.onWorldChange)==null||o.call(this))}reset(){var e,t,n;this.world.reset(),this.applied=0,this.sent=0,this.realSensors=void 0,(e=this.view)==null||e.place(this.world.pose,this.world.trail),(t=this.view)==null||t.setLed(void 0),(n=this.view)==null||n.setScreen(void 0),this.updateStatus()}prepare(e){e.robotSensors={...this.controls,...this.world.sensors()}}setupControls(){for(const e of this.element.querySelectorAll(".visubot-controls input[type=range]")){const t=e.parentElement.querySelector("output"),n=()=>{this.controls[e.name]=Number(e.value),t.textContent=e.value};e.addEventListener("input",n),n()}for(const e of this.element.querySelectorAll(".visubot-controls button[name]"))e.addEventListener("click",()=>{const t=e.name;this.controls[t]=!0,e.classList.add("pressed"),window.clearTimeout(this.pressTimers.get(t)),this.pressTimers.set(t,window.setTimeout(()=>{this.controls[t]=!1,e.classList.remove("pressed")},1e3))})}setupCheck(){for(const e of this.check.querySelectorAll("button[data-py]"))e.addEventListener("click",()=>{const{after:t,wait:n}=e.dataset;be.run(e.dataset.py).then(()=>t?new Promise(a=>setTimeout(a,Number(n))).then(()=>be.run(t)):void 0).catch(a=>this.liveFailed(a))});this.check.addEventListener("toggle",()=>void this.readCheck())}async readCheck(){if(!this.checking){this.checking=!0;try{for(;this.check.open&&be.connected;){for(const e of this.check.querySelectorAll("[data-sensor]")){if(!this.check.open||!be.connected)break;const t=e.dataset.sensor,n=await be.ask(Pt[t].python).catch(()=>{});n!==void 0&&(e.textContent=typeof Pt[t].simulated=="boolean"?n===!0||typeof n=="number"&&n!==0?"✓":"–":String(typeof n=="number"?Math.round(n*10)/10:n))}await new Promise(e=>setTimeout(e,200))}}finally{this.checking=!1}}}get live(){return be.connected}async prepareLive(e,t=[]){const n={};for(const a of new Set(["getDistance","getLine",...t])){const s=await be.ask(Pt[a].python);typeof Pt[a].simulated=="boolean"?n[a]=s===!0||typeof s=="number"&&s!==0:typeof Pt[a].simulated=="string"?n[a]=typeof s=="string"?s:String(Pt[a].simulated):n[a]=typeof s=="number"?a==="getDistance"?Math.round(s):s:0}this.realSensors=n,e.robotSensors={...this.controls,...this.world.sensors(),...n}}async drive(e){for(;this.sentsetTimeout(n,t.args[0]))}}liveFailed(e){be.disconnect(e instanceof Error?e.message:String(e))}updateLive(){this.liveStatus.textContent=ep(),this.liveStatus.classList.toggle("connected",be.connected),this.check.hidden=!be.connected,be.connected||(this.check.open=!1),this.updateStatus()}follow(e,t){var a,s,r,o;for(;this.appliedl!==0);this.world.tick(z0),n&&((o=this.view)==null||o.moveTo(this.world.pose,this.world.trail,t)),this.updateStatus()}dispose(){var e;this.stopListening();for(const t of this.pressTimers.values())window.clearTimeout(t);(e=this.view)==null||e.dispose(),this.view=void 0,this.loading=void 0}updateStatus(){const e=this.world.lineState().toString(2).padStart(4,"0"),t=[`${p("web_visubot_distance")}: ${this.world.distance()} cm`,`${p("web_visubot_line")}: ${e}`];this.world.bumps>0&&t.push(`⚠︎ ${p("web_visubot_bumps")}: ${this.world.bumps}`),this.world.screen!==void 0&&t.push(`📺 ${this.world.screen}`),this.realSensors&&be.connected&&t.push(`🤖 ${p("web_visubot_distance")}: ${this.realSensors.getDistance} cm · ${p("web_visubot_line")}: ${Number(this.realSensors.getLine).toString(2).padStart(4,"0")}`),this.status.textContent=t.join(" · ")}}let ni;function Xg(i,e){try{ni??(ni=new AudioContext);const t=ni.createOscillator(),n=ni.createGain();t.type="square",t.frequency.value=Math.max(20,Math.min(2e4,i)),n.gain.value=.05,t.connect(n).connect(ni.destination);const a=ni.currentTime+Math.min(Math.max(e,0),5e3)/1e3;t.start(),t.stop(a)}catch{}}function vN(){const i=(t,n,a,s,r)=>``,e=(t,n,a)=>``;return`
🎛 ${p("web_visubot_controls")} + ${Zm(p(t))}`}class xN{constructor(e=Mi){y(this,"element");y(this,"world");y(this,"view");y(this,"loading");y(this,"status");y(this,"stage");y(this,"picker");y(this,"applied",0);y(this,"sent",0);y(this,"liveStatus");y(this,"viewport");y(this,"stopListening");y(this,"realSensors");y(this,"controls",{getBrightness:50,getLoudness:0,getPitch:0,getRoll:0});y(this,"pressTimers",new Map);y(this,"check");y(this,"checking",!1);y(this,"onWorldChange");this.world=new _s(e),this.element=document.createElement("section"),this.element.className="visubot",this.element.innerHTML=`

${p("web_visubot_world")}

${p("web_visubot_world_in_preview")}

${vN()}${yN()}`,this.stage=this.element.querySelector(".visubot-stage"),this.picker=this.element.querySelector(".visubot-worlds"),this.status=this.element.querySelector(".visubot-status"),this.liveStatus=this.element.querySelector(".visubot-live"),this.viewport=this.element.querySelector(".visubot-viewport"),this.stopListening=be.listen(()=>this.updateLive()),this.setupControls(),this.check=this.element.querySelector(".visubot-check"),this.setupCheck(),this.updateLive(),this.updateStatus()}show(){this.loading??(this.loading=ee(async()=>{const{Robot3D:e}=await import("./robot3d-K0yfmoba.js");return{Robot3D:e}},[],import.meta.url).then(({Robot3D:e})=>{this.view=new e(this.stage),this.view.setWorld(this.world.setup),this.view.place(this.world.pose,this.world.trail),this.view.setLeds(this.world.leds)}).catch(()=>{this.stage.textContent=p("web_visubot_no_3d")}))}restoreViewport(){this.viewport.parentElement!==this.element&&this.liveStatus.after(this.viewport)}setWorlds(e){this.picker.replaceChildren(),this.picker.hidden=e.length<2,e.forEach((t,n)=>{const a=document.createElement("button");a.textContent=p("web_visubot_world_fmt",n+1),a.addEventListener("click",()=>this.useWorld(t,a)),this.picker.append(a)}),this.useWorld(e[0]??Mi,this.picker.firstElementChild)}useWorld(e,t){var n,a,s,r,o;for(const l of this.picker.children)l.classList.toggle("active",l===t);e!==this.world.setup&&(this.world=new _s(e),this.applied=0,this.sent=0,(n=this.view)==null||n.setWorld(e),(a=this.view)==null||a.place(this.world.pose,this.world.trail),(s=this.view)==null||s.setLed(void 0),(r=this.view)==null||r.setScreen(void 0),this.updateStatus(),(o=this.onWorldChange)==null||o.call(this))}reset(){var e,t,n;this.world.reset(),this.applied=0,this.sent=0,this.realSensors=void 0,(e=this.view)==null||e.place(this.world.pose,this.world.trail),(t=this.view)==null||t.setLed(void 0),(n=this.view)==null||n.setScreen(void 0),this.updateStatus()}prepare(e){e.robotSensors={...this.controls,...this.world.sensors()}}setupControls(){for(const e of this.element.querySelectorAll(".visubot-controls input[type=range]")){const t=e.parentElement.querySelector("output"),n=()=>{this.controls[e.name]=Number(e.value),t.textContent=e.value};e.addEventListener("input",n),n()}for(const e of this.element.querySelectorAll(".visubot-controls button[name]"))e.addEventListener("click",()=>{const t=e.name;this.controls[t]=!0,e.classList.add("pressed"),window.clearTimeout(this.pressTimers.get(t)),this.pressTimers.set(t,window.setTimeout(()=>{this.controls[t]=!1,e.classList.remove("pressed")},1e3))})}setupCheck(){for(const e of this.check.querySelectorAll("button[data-py]"))e.addEventListener("click",()=>{const{after:t,wait:n}=e.dataset;be.run(e.dataset.py).then(()=>t?new Promise(a=>setTimeout(a,Number(n))).then(()=>be.run(t)):void 0).catch(a=>this.liveFailed(a))});this.check.addEventListener("toggle",()=>void this.readCheck())}async readCheck(){if(!this.checking){this.checking=!0;try{for(;this.check.open&&be.connected;){for(const e of this.check.querySelectorAll("[data-sensor]")){if(!this.check.open||!be.connected)break;const t=e.dataset.sensor,n=await be.ask(Pt[t].python).catch(()=>{});n!==void 0&&(e.textContent=typeof Pt[t].simulated=="boolean"?n===!0||typeof n=="number"&&n!==0?"✓":"–":String(typeof n=="number"?Math.round(n*10)/10:n))}await new Promise(e=>setTimeout(e,200))}}finally{this.checking=!1}}}get live(){return be.connected}async prepareLive(e,t=[]){const n={};for(const a of new Set(["getDistance","getLine",...t])){const s=await be.ask(Pt[a].python);typeof Pt[a].simulated=="boolean"?n[a]=s===!0||typeof s=="number"&&s!==0:typeof Pt[a].simulated=="string"?n[a]=typeof s=="string"?s:String(Pt[a].simulated):n[a]=typeof s=="number"?a==="getDistance"?Math.round(s):s:0}this.realSensors=n,e.robotSensors={...this.controls,...this.world.sensors(),...n}}async drive(e){for(;this.sentsetTimeout(n,t.args[0]))}}liveFailed(e){be.disconnect(e instanceof Error?e.message:String(e))}updateLive(){this.liveStatus.textContent=ep(),this.liveStatus.classList.toggle("connected",be.connected),this.check.hidden=!be.connected,be.connected||(this.check.open=!1),this.updateStatus()}follow(e,t){var a,s,r,o;for(;this.appliedl!==0);this.world.tick(z0),n&&((o=this.view)==null||o.moveTo(this.world.pose,this.world.trail,t)),this.updateStatus()}dispose(){var e;this.stopListening();for(const t of this.pressTimers.values())window.clearTimeout(t);(e=this.view)==null||e.dispose(),this.view=void 0,this.loading=void 0}updateStatus(){const e=this.world.lineState().toString(2).padStart(4,"0"),t=[`${p("web_visubot_distance")}: ${this.world.distance()} cm`,`${p("web_visubot_line")}: ${e}`];this.world.bumps>0&&t.push(`⚠︎ ${p("web_visubot_bumps")}: ${this.world.bumps}`),this.world.screen!==void 0&&t.push(`📺 ${this.world.screen}`),this.realSensors&&be.connected&&t.push(`🤖 ${p("web_visubot_distance")}: ${this.realSensors.getDistance} cm · ${p("web_visubot_line")}: ${Number(this.realSensors.getLine).toString(2).padStart(4,"0")}`),this.status.textContent=t.join(" · ")}}let ni;function Xg(i,e){try{ni??(ni=new AudioContext);const t=ni.createOscillator(),n=ni.createGain();t.type="square",t.frequency.value=Math.max(20,Math.min(2e4,i)),n.gain.value=.05,t.connect(n).connect(ni.destination);const a=ni.currentTime+Math.min(Math.max(e,0),5e3)/1e3;t.start(),t.stop(a)}catch{}}function vN(){const i=(t,n,a,s,r)=>``,e=(t,n,a)=>``;return`
🎛 ${p("web_visubot_controls")}

${p("web_visubot_controls_hint")}

${i("getBrightness","web_visubot_sensor_brightness",0,100,50)} ${i("getLoudness","web_visubot_sensor_loudness",0,100,0)} @@ -76908,7 +76932,7 @@ ${i}

${In(p("web_visubot_preview_hint"))}

-

`;const e=t=>this.element.querySelector(t);this.heightBar=e(".robotpreview-height"),this.stage=e(".robotpreview-stage"),this.status=e(".robotpreview-status"),this.picker=e(".visubot-worlds"),this.playButton=e(".robotpreview-play"),this.stackButton=e(".robotpreview-stack"),this.playButton.addEventListener("click",()=>this.playTimer===void 0?this.play():this.stopPlaying(!0)),this.stackButton.addEventListener("click",()=>this.onToggleStacked()),e(".learn-hide").addEventListener("click",()=>this.onHide()),this.rail=document.createElement("button"),this.rail.className="learn-rail robotpreview-rail",this.setStacked(!1),this.relabel()}hostSimulation(e){var t;e!==this.simulation&&((t=this.simulation)==null||t.remove(),this.simulation=e,this.element.classList.toggle("simulation",!!e),e&&(this.pause(),this.status.after(e)),this.relabel())}relabel(){const e=a=>this.element.querySelector(a),t=!!this.simulation;e("h2").textContent=`🤖 ${p(t?"web_visubot_preview_sim_title":"web_visubot_preview_title")}`,e(".hint").textContent=p(t?"web_visubot_preview_sim_hint":"web_visubot_preview_hint"),this.heightBar.title=p("web_visubot_preview_resize");const n=e(".learn-hide");n.title=p("web_visubot_preview_hide"),n.setAttribute("aria-label",p("web_visubot_preview_hide")),this.rail.title=p("web_visubot_preview_show"),this.rail.innerHTML=`${At}🤖 ${In(p("web_visubot_preview_title"))}`,this.setStacked(this.stackButton.textContent==="▥"),this.stopPlaying(!1),this.worldsKey=void 0,this.lastKey=void 0}setStacked(e){const t=e?"web_visubot_preview_side":"web_visubot_preview_stack";this.stackButton.innerHTML=e?"▥":"⬓",this.stackButton.className="icon robotpreview-stack",this.stackButton.dataset.tip=p(t),this.stackButton.setAttribute("aria-label",p(t))}show(){this.loading??(this.loading=ee(async()=>{const{Robot3D:e}=await import("./robot3d-RDgYNuY0.js");return{Robot3D:e}},[],import.meta.url).then(({Robot3D:e})=>{var t;this.view=new e(this.stage),this.view.setWorld(this.setup),this.showFrame((t=this.result)==null?void 0:t.frames.at(-1))}).catch(()=>{this.stage.textContent=p("web_visubot_no_3d")}))}update(e,t,n,a,s){if(this.simulation)return;this.show(),a!==this.worldsKey&&(this.worldsKey=a,this.setWorlds(n)),this.input={doc:e,resolve:t};const r=JSON.stringify(s)+` +

`;const e=t=>this.element.querySelector(t);this.heightBar=e(".robotpreview-height"),this.stage=e(".robotpreview-stage"),this.status=e(".robotpreview-status"),this.picker=e(".visubot-worlds"),this.playButton=e(".robotpreview-play"),this.stackButton=e(".robotpreview-stack"),this.playButton.addEventListener("click",()=>this.playTimer===void 0?this.play():this.stopPlaying(!0)),this.stackButton.addEventListener("click",()=>this.onToggleStacked()),e(".learn-hide").addEventListener("click",()=>this.onHide()),this.rail=document.createElement("button"),this.rail.className="learn-rail robotpreview-rail",this.setStacked(!1),this.relabel()}hostSimulation(e){var t;e!==this.simulation&&((t=this.simulation)==null||t.remove(),this.simulation=e,this.element.classList.toggle("simulation",!!e),e&&(this.pause(),this.status.after(e)),this.relabel())}relabel(){const e=a=>this.element.querySelector(a),t=!!this.simulation;e("h2").textContent=`🤖 ${p(t?"web_visubot_preview_sim_title":"web_visubot_preview_title")}`,e(".hint").textContent=p(t?"web_visubot_preview_sim_hint":"web_visubot_preview_hint"),this.heightBar.title=p("web_visubot_preview_resize");const n=e(".learn-hide");n.title=p("web_visubot_preview_hide"),n.setAttribute("aria-label",p("web_visubot_preview_hide")),this.rail.title=p("web_visubot_preview_show"),this.rail.innerHTML=`${At}🤖 ${In(p("web_visubot_preview_title"))}`,this.setStacked(this.stackButton.textContent==="▥"),this.stopPlaying(!1),this.worldsKey=void 0,this.lastKey=void 0}setStacked(e){const t=e?"web_visubot_preview_side":"web_visubot_preview_stack";this.stackButton.innerHTML=e?"▥":"⬓",this.stackButton.className="icon robotpreview-stack",this.stackButton.dataset.tip=p(t),this.stackButton.setAttribute("aria-label",p(t))}show(){this.loading??(this.loading=ee(async()=>{const{Robot3D:e}=await import("./robot3d-K0yfmoba.js");return{Robot3D:e}},[],import.meta.url).then(({Robot3D:e})=>{var t;this.view=new e(this.stage),this.view.setWorld(this.setup),this.showFrame((t=this.result)==null?void 0:t.frames.at(-1))}).catch(()=>{this.stage.textContent=p("web_visubot_no_3d")}))}update(e,t,n,a,s){if(this.simulation)return;this.show(),a!==this.worldsKey&&(this.worldsKey=a,this.setWorlds(n)),this.input={doc:e,resolve:t};const r=JSON.stringify(s)+` `+JSON.stringify(e);r!==this.lastKey&&(this.lastKey=r,window.clearTimeout(this.pending),this.pending=window.setTimeout(()=>this.recompute(),120))}setWorlds(e){this.worlds=e,this.picker.replaceChildren(),this.picker.hidden=e.length<2,e.forEach((t,n)=>{const a=document.createElement("button");a.textContent=p("web_visubot_world_fmt",n+1),a.addEventListener("click",()=>this.useWorld(t)),this.picker.append(a)}),this.useWorld(e[0]??Mi)}useWorld(e){var t;this.worlds.forEach((n,a)=>{var s;return(s=this.picker.children[a])==null?void 0:s.classList.toggle("active",n===e)}),!(e===this.setup&&this.result)&&(this.setup=e,(t=this.view)==null||t.setWorld(e),this.recompute())}recompute(){var e;if(this.pending=void 0,this.stopPlaying(!1),!!this.input){try{this.result=Sg(this.input.doc,this.input.resolve,this.setup)}catch{this.result=void 0}this.showFrame((e=this.result)==null?void 0:e.frames.at(-1)),this.updateStatus()}}showFrame(e,t=0){if(!this.view)return;const n=e??{pose:{...this.setup.start},trail:[{x:this.setup.start.x,y:this.setup.start.y}],leds:Array(5).fill(void 0),screen:void 0};t>0?this.view.moveTo(n.pose,n.trail,t):this.view.place(n.pose,n.trail),this.view.setLeds(n.leds),this.view.setScreen(n.screen)}play(){var a;const e=(a=this.result)==null?void 0:a.frames;if(!e||e.length<2||!this.view)return;this.stopPlaying(!1);let t=0;this.showFrame(e[0]),this.playButton.innerHTML=me.stop,this.playButton.dataset.tip=p("web_visubot_preview_stop"),this.playButton.setAttribute("aria-label",p("web_visubot_preview_stop"));const n=()=>{if(t++,t>=e.length){this.stopPlaying(!1);return}const s=e[t];s.tone&&Xg(s.tone[0],s.tone[1]),this.showFrame(s,vo-30),this.playTimer=window.setTimeout(n,vo)};this.playTimer=window.setTimeout(n,vo)}stopPlaying(e){var t;this.playTimer!==void 0&&window.clearTimeout(this.playTimer),this.playTimer=void 0,this.playButton.innerHTML=me.play,this.playButton.dataset.tip=p("web_visubot_preview_play"),this.playButton.setAttribute("aria-label",p("web_visubot_preview_play")),e&&this.showFrame((t=this.result)==null?void 0:t.frames.at(-1))}updateStatus(){const e=this.result;if(this.playButton.disabled=!e||e.frames.length<2,!e){this.status.textContent="";return}const t=[p("web_visubot_preview_distance_fmt",e.distance)];e.bumps>0&&t.push(`⚠︎ ${p("web_visubot_bumps")}: ${e.bumps}`),e.stop==="input"?t.push(p("web_visubot_preview_input")):e.stop==="limit"?t.push(p("web_visubot_preview_limit")):e.stop==="error"&&e.notice&&t.push(`⚠︎ ${i1(e.notice)}`),this.status.textContent=t.join(" · ")}pause(){window.clearTimeout(this.pending),this.pending=void 0,this.lastKey=void 0,this.stopPlaying(!1)}}const $q={left:12,top:10},Kq=8,ir=8e3,Ai=16,yo=12,E2="#fafafa";function N2(i){const e=i.caption.trim();return e===""?p("diagram_title_placeholder"):e}function Pd(i){let e=i.trim().replace(/\.visustruct$/i,"");if(e==="")return"";for(e=e.replace(/\s/g,"-").replace(/[/:\\*?"<>|]/g,"-");e.includes("--");)e=e.replace(/--/g,"-");return e=e.replace(/^-+|-+$/g,""),e.length>120&&(e=e.slice(0,120).replace(/^-+|-+$/g,"")),e}function Dd(i,e){return Pd(i.caption)||Pd(e)||"VisuStruct"}function Xq(i,e,t){const n=i.split(/\s+/),a=[];let s="";for(const r of n){const o=s?`${s} ${r}`:r;s&&t(o,Ai,"bold")>e?(a.push(s),s=r):s=o}if(s&&a.push(s),a.length>2){let r=a.slice(1).join(" ");for(;r.length>1&&t(r+"…",Ai,"bold")>e;)r=r.slice(0,-1);return[a[0],r+"…"]}return a}function Bd(i,e,t,n=320){const a={...i,elements:i.elements.map(ds)},s=new bh(e,t).layout(a,$q),r=Math.min(ir,Math.max(n,s.canvasSize.width)),o=Math.min(ir,Math.max(n,s.canvasSize.height));if(r<=2||o<=2)return;const l=Xq(N2(i),r-2*yo,t),u=Math.ceil(Ai*1.2),m=Math.min(56,l.length*u+2),c=m+o,d=new wh(e,t).render(s,{width:r,height:o},void 0,Kq);d.setAttribute("y",String(m)),d.removeAttribute("class");const h=Te("svg",{xmlns:"http://www.w3.org/2000/svg",width:r,height:c,viewBox:`0 0 ${r} ${c}`});h.append(Te("rect",{x:0,y:0,width:r,height:c,fill:E2}));const g=Te("text",{x:yo,y:0,"font-family":ar,"font-size":Ai,"font-weight":600,fill:"black"});return l.forEach((f,b)=>{const x=Te("tspan",{x:yo,y:b*u+Ai});x.textContent=f,g.append(x)}),h.append(g,d),{svg:h,width:r,height:c}}function F2(i){return` `+new XMLSerializer().serializeToString(i.svg)}async function Od(i,e){const t=Math.max(1,Math.min(e,ir/i.width,ir/i.height)),n=URL.createObjectURL(new Blob([F2(i)],{type:"image/svg+xml"}));try{const a=new Image;a.src=n,await a.decode();const s=document.createElement("canvas");s.width=Math.round(i.width*t),s.height=Math.round(i.height*t);const r=s.getContext("2d");return r.fillStyle=E2,r.fillRect(0,0,s.width,s.height),r.drawImage(a,0,0,s.width,s.height),s}finally{URL.revokeObjectURL(n)}}function eQ(i){return new Promise((e,t)=>i.toBlob(n=>n?e(n):t(new Error("PNG konnte nicht erzeugt werden.")),"image/png"))}function tQ(i,e){const a=Math.max(1,i),s=Math.max(1,e),r=f=>{const b=f.width-64,x=f.height-64;return{s:Math.min(b/a,x/s)*.98,cw:b,ch:x}},o={width:595,height:842},l={width:842,height:595},u=r(o),m=r(l),[c,d]=m.s>u.s?[l,m]:[o,u],h=a*d.s,g=s*d.s;return{page:c,draw:{x:32+(d.cw-h)/2,y:32+(d.ch-g)/2,width:h,height:g}}}async function nQ(i){const e=new Blob([i]).stream().pipeThrough(new CompressionStream("deflate"));return new Uint8Array(await new Response(e).arrayBuffer())}function Md(i){let e="FEFF";for(let t=0;t`}async function iQ(i,e,t,n,a){const{page:s,draw:r}=tQ(n.width,n.height),o=await nQ(i),l=x=>(Math.round(x*100)/100).toString(),u=`q ${l(r.width)} 0 0 ${l(r.height)} ${l(r.x)} ${l(s.height-r.y-r.height)} cm /Im0 Do Q`,m=new TextEncoder,c=[["<< /Type /Catalog /Pages 2 0 R >>"],["<< /Type /Pages /Kids [3 0 R] /Count 1 >>"],[`<< /Type /Page /Parent 2 0 R /MediaBox [0 0 ${s.width} ${s.height}] /Resources << /XObject << /Im0 4 0 R >> >> /Contents 5 0 R >>`],[`<< /Type /XObject /Subtype /Image /Width ${e} /Height ${t} /ColorSpace /DeviceRGB /BitsPerComponent 8 /Filter /FlateDecode /Length ${o.length} >> stream @@ -77130,7 +77154,7 @@ ${c}
- ${W(p("web_about_version_fmt").replace("%@","0.15.0"))} + ${W(p("web_about_version_fmt").replace("%@","0.15.1"))}
@@ -77202,7 +77226,7 @@ ${c}

VisuStruct ${W(p("web_brand_suffix"))}

-

${W(p("web_about_version_fmt").replace("%@","0.15.0"))}

+

${W(p("web_about_version_fmt").replace("%@","0.15.1"))}

Holger Sebastiao

${e("about_web_label","https://visustruct.visucode.de","visustruct.visucode.de")} ${e("about_developer_label","https://www.sebastiao.org","www.sebastiao.org")} @@ -77224,4 +77248,4 @@ ${c}

${W(p("close_unsaved_title"))}

${W(p("web_discard_message_fmt",this.fileName))}

-
`,t.addEventListener("click",n=>{const a=n.target.dataset.r;a===void 0&&n.target!==t||(t.remove(),e(a==="1"))}),document.body.append(t),t.querySelector('[data-r="0"]').focus()}):Promise.resolve(!0)}showMessage(e){this.statusLine.textContent=e,this.statusLine.classList.add("message"),setTimeout(()=>{this.statusLine.classList.remove("message"),this.updateStatus()},6e3)}loadXML(e,t,n){let a;try{a=n0(e)}catch(s){this.showMessage(p("web_err_unreadable_fmt",t,s.message));return}(this.dirty||this.tab.fileName||this.tab.exerciseId)&&this.addTab(),this.doc=a,this.tab.fileName=t.replace(/\.(strk|xml)$/i,".visustruct"),this.fileHandle=n&&/\.visustruct$/i.test(t)?n:void 0,this.resetHistory()}async open(e){const t=window;if(!t.showOpenFilePicker||this.inViewer)return e.click();try{const[n]=await t.showOpenFilePicker({types:Ed()}),a=await n.getFile();this.loadXML(await a.text(),a.name,n)}catch{}}async save(){var n,a;if(!this.downloads&&await this.saveToWorkspace())return;const e=new Blob([d1(this.doc)],{type:"application/xml"}),t=window;try{if(this.downloads){const s=this.fileName+".txt";await this.downloads.save({filename:s,data:e}),(n=this.tab).fileName??(n.fileName=this.fileName),this.dirty=!1,this.render(),this.showMessage(p("web_saved_txt_fmt",s));return}if(!this.fileHandle&&t.showSaveFilePicker&&!this.inViewer&&(this.fileHandle=await t.showSaveFilePicker({suggestedName:this.fileName,types:Ed()}),this.tab.fileName=this.fileHandle.name),this.fileHandle){const s=await this.fileHandle.createWritable();await s.write(e),await s.close()}else{const s=document.createElement("a");s.href=URL.createObjectURL(e),s.download=this.fileName,s.click(),setTimeout(()=>URL.revokeObjectURL(s.href),1e3)}(a=this.tab).fileName??(a.fileName=this.fileName),this.dirty=!1,this.render()}catch{}}async exportDiagram(e){if(e==="visustruct"){const s=Dd(this.doc,hn(this.tab));return this.offerDownload(`${s}.visustruct`,new Blob([d1(this.doc)],{type:"application/xml"}))}const t=Bd(this.doc,this.metrics,this.measure);if(!t){this.showMessage(p(e==="print"?"err_diagram_too_small_print":"err_diagram_too_small_export"));return}const n=Dd(this.doc,hn(this.tab)),a=Math.max(2,window.devicePixelRatio||1)*this.zoom;try{switch(e){case"svg":{t.svg.setAttribute("width",String(t.width*this.zoom)),t.svg.setAttribute("height",String(t.height*this.zoom)),await this.offerDownload(`${n}.svg`,new Blob([F2(t)],{type:"image/svg+xml"}));break}case"png":{const s=await Od(t,a);await this.offerDownload(`${n}.png`,await eQ(s));break}case"pdf":{const s=await Od(t,Math.max(a,3)),r=await iQ(aQ(s),s.width,s.height,t,N2(this.doc));await this.offerDownload(`${n}.pdf`,r);break}case"print":this.printDiagram(t);break}}catch(s){this.showMessage(p("web_export_failed_fmt",s instanceof Error?s.message:String(s)))}}printDiagram(e){const t=document.createElement("div");t.className="print-sheet",e.svg.removeAttribute("width"),e.svg.removeAttribute("height"),t.append(e.svg),document.body.append(t);const n=()=>t.remove();window.addEventListener("afterprint",n,{once:!0});try{window.print()}catch{n(),this.showMessage(`${p("err_print_unavailable")} ${p("web_print_hint")}`);return}setTimeout(n,6e4)}async offerDownload(e,t){try{if(this.downloads){try{await this.downloads.save({filename:e,data:t}),this.showMessage(p("web_saved_fmt",e))}catch{await this.downloads.save({filename:e+".txt",data:t}),this.showMessage(p("web_saved_txt_fmt",e+".txt"))}return}const n=document.createElement("a");n.href=URL.createObjectURL(t),n.download=e,n.click(),setTimeout(()=>URL.revokeObjectURL(n.href),1e3)}catch{this.showMessage(p("err_save_failed_fmt",e))}}setupFileDrop(){window.addEventListener("dragover",e=>{var t;(t=e.dataTransfer)!=null&&t.types.includes("Files")&&(e.preventDefault(),this.root.classList.add("file-drag"))}),window.addEventListener("dragleave",e=>{e.relatedTarget===null&&this.root.classList.remove("file-drag")}),window.addEventListener("drop",async e=>{var n;this.root.classList.remove("file-drag");const t=(n=e.dataTransfer)==null?void 0:n.files[0];t&&(e.preventDefault(),this.loadXML(await t.text(),t.name))})}onKeyDown(e){var a,s;const t=e.metaKey||e.ctrlKey,n=e.target instanceof HTMLTextAreaElement||e.target instanceof HTMLInputElement||((a=e.target)==null?void 0:a.isContentEditable)===!0;if(t&&e.key.toLowerCase()==="s")e.preventDefault(),this.save();else if(t&&e.key.toLowerCase()==="p")e.preventDefault(),this.simulating||this.exportDiagram("print");else if(t&&e.key.toLowerCase()==="o")e.preventDefault(),this.open(this.root.querySelector("input[type=file]"));else{if(n||this.simulating)return;t&&e.key.toLowerCase()==="z"?(e.preventDefault(),e.shiftKey?this.redo():this.undo()):t&&e.key.toLowerCase()==="c"&&!((s=getSelection())!=null&&s.toString())?this.copySelection()&&e.preventDefault():t&&e.key.toLowerCase()==="x"?(e.preventDefault(),this.cutSelection()):t&&e.key.toLowerCase()==="v"?(e.preventDefault(),this.paste()):t&&e.key.toLowerCase()==="y"?(e.preventDefault(),this.redo()):e.key==="F2"&&this.selected?(e.preventDefault(),this.renameVariable(this.selected)):e.key==="Delete"||e.key==="Backspace"?(e.preventDefault(),this.deleteSelection()):e.key==="Escape"&&(this.drag?this.endDrag():(this.selected=void 0,this.render()))}}svgPoint(e,t){if(!this.svg)return;const n=this.svg.getBoundingClientRect(),a=e-n.left,s=t-n.top;if(!(a<0||s<0||a>n.width||s>n.height))return{x:a/this.zoom,y:s/this.zoom}}nodeAt(e,t){for(let n=this.flat.length-1;n>=0;n--){const a=this.flat[n].frame;if(e>=a.x&&e<=a.x+a.width&&t>=a.y&&t<=a.y+a.height)return this.flat[n]}}onCanvasPointerDown(e){if(this.simulating)return;const t=this.svgPoint(e.clientX,e.clientY);if(!t)return;document.activeElement instanceof HTMLElement&&document.activeElement.blur();const n=this.nodeAt(t.x,t.y),a=n&&this.selected&&Do(n.idPath,this.selected);this.selected=n==null?void 0:n.idPath,this.render(),n&&e.pointerType!=="touch"&&!(Sn(this.doc,n.idPath)&&!a)&&this.beginDrag(e,{kind:"move",path:n.idPath})}beginDrag(e,t){e.button!==0||this.simulating||(e.preventDefault(),this.drag={source:t,pointerId:e.pointerId,startX:e.clientX,startY:e.clientY,active:!1})}onPointerMove(e){const t=this.drag;if(!t||e.pointerId!==t.pointerId)return;if(!t.active){if(Math.hypot(e.clientX-t.startX,e.clientY-t.startY)<5)return;t.active=!0,t.ghost=this.makeGhost(t.source),document.body.append(t.ghost),this.root.classList.add("dragging")}t.ghost.style.transform=`translate(${e.clientX+12}px, ${e.clientY+12}px)`,this.autoScroll(e.clientX,e.clientY);const n=this.svgPoint(e.clientX,e.clientY);t.target=n?this.dropTargetAt(n.x,n.y,t.source):void 0,this.showDropTarget(t.target)}onPointerUp(e){const t=this.drag;!t||e.pointerId!==t.pointerId||(t.active&&t.target?this.applyDrop(t.source,t.target):!t.active&&t.source.kind==="palette"?this.insertNearSelection(t.source.make()):!t.active&&t.source.kind==="sensor"&&this.insertSensor(t.source.text),this.endDrag())}endDrag(){var e,t;(t=(e=this.drag)==null?void 0:e.ghost)==null||t.remove(),this.drag=void 0,this.root.classList.remove("dragging"),this.showDropTarget(void 0)}makeGhost(e){const t=document.createElement("div");if(t.className="drag-ghost",e.kind==="palette"||e.kind==="sensor")t.textContent=e.label;else{const n=Ot(this.doc,e.path);t.textContent=`${wo(n.type)}: ${$l(n)[0]}`}return t}autoScroll(e,t){const n=this.canvasHost.getBoundingClientRect(),a=40,s=12;t>n.bottom-a&&tn.top-a&&(this.canvasHost.scrollTop-=s),e>n.right-a&&en.left-a&&(this.canvasHost.scrollLeft-=s)}dropTargetAt(e,t,n){var l;const a=((l=this.layout)==null?void 0:l.elements)??[],s=this.nodeAt(e,t);if(n.kind==="sensor")return!s||Sn(this.doc,s.idPath)?void 0:Wd.includes(Ot(this.doc,s.idPath).type)?{kind:"condition",path:s.idPath,frame:s.frame}:void 0;if(!s){const u=a[a.length-1];if(!u)return;const m=u.frame.y+u.frame.height;return t>m?n.kind==="move"&&n.path.length===1&&n.path[0]===a.length-1?void 0:{kind:"rootAppend",frame:{x:u.frame.x,y:m,width:u.frame.width,height:0}}:t=n.path.length&&n.path.every((u,m)=>r[m]===u)?void 0:Sn(this.doc,r)?{kind:"replace",path:r,frame:s.frame}:{kind:t"]/g,e=>({"&":"&","<":"<",">":">",'"':"""})[e])}function sh(i){if(!i)return[];for(const e of[...zt.flatMap(t=>t.steps.flatMap(n=>n.blocks)),...Pn.flatMap(t=>t.blocks)])if(!(e.kind!=="exercise"||e.exercise.id!==i))return e.exercise.tests.flatMap(t=>{const n=t.world?ts(t.world):void 0;return n?[n]:[]});return[]}let Jt,Ql,Ul;function rh(i){const e=i.dataset.tip;if(!e)return;Jt??(Jt=Object.assign(document.createElement("div"),{className:"tooltip",role:"tooltip"})),Jt.isConnected||document.body.append(Jt),Jt.textContent=e,Jt.hidden=!1;const t=i.getBoundingClientRect(),n=Jt.offsetWidth,a=Jt.offsetHeight,s=Math.min(Math.max(8,t.left+t.width/2-n/2),window.innerWidth-n-8),r=t.bottom+6+a{if(i.pointerType==="touch")return;const e=i.target.closest("[data-tip]");e!==Ul&&(So(),e&&(Ul=e,Ql=window.setTimeout(()=>rh(e),350)))}),document.addEventListener("focusin",i=>{const e=i.target.closest("[data-tip]");So(),e!=null&&e.matches(":focus-visible")&&rh(e)});for(const i of["pointerdown","focusout","scroll","keydown"])document.addEventListener(i,So,!0)}const Yl="visustruct.reloadedAfterError";function H2(){try{const i=Number(sessionStorage.getItem(Yl));if(i&&Date.now()-i<3e4)return!1;sessionStorage.setItem(Yl,String(Date.now()))}catch{return!1}return location.reload(),!0}function TQ(i){console.error(i);const e=(navigator.language||"").toLowerCase().startsWith("de"),t=document.createElement("div");t.className="startup-error";const n=document.createElement("h1");n.textContent=e?"VisuStruct konnte nicht starten":"VisuStruct could not start";const a=document.createElement("p");a.textContent=e?"Wahrscheinlich gibt es gerade eine neue Version. Lade die Seite neu. Hilft das nicht, drücke Strg+Umschalt+R (Mac: ⌘⇧R).":"There is probably a new version. Reload the page. If that does not help, press Ctrl+Shift+R (Mac: ⌘⇧R).";const s=document.createElement("button");s.textContent=e?"Neu laden":"Reload",s.addEventListener("click",()=>location.reload());const r=document.createElement("pre");r.textContent=String(i instanceof Error?i.message:i),t.append(n,a,s,r),(document.getElementById("app")??document.body).replaceWith(t)}window.addEventListener("vite:preloadError",i=>{H2()&&i.preventDefault()});const _Q=L3();Promise.all([Ch(_Q,!1),jh(M3(),!1)]).then(()=>{G2(),SQ();const i=new URLSearchParams(location.search);if(!["visustruct","visubot","visuobject","visuflow"].some(a=>i.has(a))&&!Kg()){const a=lh();a==="visubot"?ns("on"):a==="visuobject"&&tl()}i.has("visuobject")&&tl(),i.has("visuflow")&&$g();const t=document.getElementById("app"),n=!i.has("visustruct")&&!i.has("visubot");if(Ug()&&n)return ee(async()=>{const{ObjectApp:a}=await import("./objectApp-BSgp1317.js").then(s=>s.g);return{ObjectApp:a}},[],import.meta.url).then(({ObjectApp:a})=>void new a(t));if(Yg()&&n)return ee(async()=>{const{FlowApp:a}=await import("./flowApp-CPQeq7Uk.js");return{FlowApp:a}},[],import.meta.url).then(({FlowApp:a})=>void new a(t));new zQ(t)}).then(()=>{try{sessionStorage.removeItem(Yl)}catch{}}).catch(i=>{/dynamically imported module|Importing a module script failed|error loading dynamically/i.test(String(i))&&H2()||TQ(i)});export{Yn as C,Iq as J,Mx as L,ee as _,uq as a,Dq as b,P2 as c,BQ as d,$g as e,ns as f,yQ as g,wa as h,me as i,_N as j,TN as k,a3 as l,DQ as m,o1 as n,tl as o,_q as p,Pd as q,Em as r,NW as s,p as t,F2 as u,Od as v,nl as w,eQ as x,iQ as y,aQ as z}; + `,t.addEventListener("click",n=>{const a=n.target.dataset.r;a===void 0&&n.target!==t||(t.remove(),e(a==="1"))}),document.body.append(t),t.querySelector('[data-r="0"]').focus()}):Promise.resolve(!0)}showMessage(e){this.statusLine.textContent=e,this.statusLine.classList.add("message"),setTimeout(()=>{this.statusLine.classList.remove("message"),this.updateStatus()},6e3)}loadXML(e,t,n){let a;try{a=n0(e)}catch(s){this.showMessage(p("web_err_unreadable_fmt",t,s.message));return}(this.dirty||this.tab.fileName||this.tab.exerciseId)&&this.addTab(),this.doc=a,this.tab.fileName=t.replace(/\.(strk|xml)$/i,".visustruct"),this.fileHandle=n&&/\.visustruct$/i.test(t)?n:void 0,this.resetHistory()}async open(e){const t=window;if(!t.showOpenFilePicker||this.inViewer)return e.click();try{const[n]=await t.showOpenFilePicker({types:Ed()}),a=await n.getFile();this.loadXML(await a.text(),a.name,n)}catch{}}async save(){var n,a;if(!this.downloads&&await this.saveToWorkspace())return;const e=new Blob([d1(this.doc)],{type:"application/xml"}),t=window;try{if(this.downloads){const s=this.fileName+".txt";await this.downloads.save({filename:s,data:e}),(n=this.tab).fileName??(n.fileName=this.fileName),this.dirty=!1,this.render(),this.showMessage(p("web_saved_txt_fmt",s));return}if(!this.fileHandle&&t.showSaveFilePicker&&!this.inViewer&&(this.fileHandle=await t.showSaveFilePicker({suggestedName:this.fileName,types:Ed()}),this.tab.fileName=this.fileHandle.name),this.fileHandle){const s=await this.fileHandle.createWritable();await s.write(e),await s.close()}else{const s=document.createElement("a");s.href=URL.createObjectURL(e),s.download=this.fileName,s.click(),setTimeout(()=>URL.revokeObjectURL(s.href),1e3)}(a=this.tab).fileName??(a.fileName=this.fileName),this.dirty=!1,this.render()}catch{}}async exportDiagram(e){if(e==="visustruct"){const s=Dd(this.doc,hn(this.tab));return this.offerDownload(`${s}.visustruct`,new Blob([d1(this.doc)],{type:"application/xml"}))}const t=Bd(this.doc,this.metrics,this.measure);if(!t){this.showMessage(p(e==="print"?"err_diagram_too_small_print":"err_diagram_too_small_export"));return}const n=Dd(this.doc,hn(this.tab)),a=Math.max(2,window.devicePixelRatio||1)*this.zoom;try{switch(e){case"svg":{t.svg.setAttribute("width",String(t.width*this.zoom)),t.svg.setAttribute("height",String(t.height*this.zoom)),await this.offerDownload(`${n}.svg`,new Blob([F2(t)],{type:"image/svg+xml"}));break}case"png":{const s=await Od(t,a);await this.offerDownload(`${n}.png`,await eQ(s));break}case"pdf":{const s=await Od(t,Math.max(a,3)),r=await iQ(aQ(s),s.width,s.height,t,N2(this.doc));await this.offerDownload(`${n}.pdf`,r);break}case"print":this.printDiagram(t);break}}catch(s){this.showMessage(p("web_export_failed_fmt",s instanceof Error?s.message:String(s)))}}printDiagram(e){const t=document.createElement("div");t.className="print-sheet",e.svg.removeAttribute("width"),e.svg.removeAttribute("height"),t.append(e.svg),document.body.append(t);const n=()=>t.remove();window.addEventListener("afterprint",n,{once:!0});try{window.print()}catch{n(),this.showMessage(`${p("err_print_unavailable")} ${p("web_print_hint")}`);return}setTimeout(n,6e4)}async offerDownload(e,t){try{if(this.downloads){try{await this.downloads.save({filename:e,data:t}),this.showMessage(p("web_saved_fmt",e))}catch{await this.downloads.save({filename:e+".txt",data:t}),this.showMessage(p("web_saved_txt_fmt",e+".txt"))}return}const n=document.createElement("a");n.href=URL.createObjectURL(t),n.download=e,n.click(),setTimeout(()=>URL.revokeObjectURL(n.href),1e3)}catch{this.showMessage(p("err_save_failed_fmt",e))}}setupFileDrop(){window.addEventListener("dragover",e=>{var t;(t=e.dataTransfer)!=null&&t.types.includes("Files")&&(e.preventDefault(),this.root.classList.add("file-drag"))}),window.addEventListener("dragleave",e=>{e.relatedTarget===null&&this.root.classList.remove("file-drag")}),window.addEventListener("drop",async e=>{var n;this.root.classList.remove("file-drag");const t=(n=e.dataTransfer)==null?void 0:n.files[0];t&&(e.preventDefault(),this.loadXML(await t.text(),t.name))})}onKeyDown(e){var a,s;const t=e.metaKey||e.ctrlKey,n=e.target instanceof HTMLTextAreaElement||e.target instanceof HTMLInputElement||((a=e.target)==null?void 0:a.isContentEditable)===!0;if(t&&e.key.toLowerCase()==="s")e.preventDefault(),this.save();else if(t&&e.key.toLowerCase()==="p")e.preventDefault(),this.simulating||this.exportDiagram("print");else if(t&&e.key.toLowerCase()==="o")e.preventDefault(),this.open(this.root.querySelector("input[type=file]"));else{if(n||this.simulating)return;t&&e.key.toLowerCase()==="z"?(e.preventDefault(),e.shiftKey?this.redo():this.undo()):t&&e.key.toLowerCase()==="c"&&!((s=getSelection())!=null&&s.toString())?this.copySelection()&&e.preventDefault():t&&e.key.toLowerCase()==="x"?(e.preventDefault(),this.cutSelection()):t&&e.key.toLowerCase()==="v"?(e.preventDefault(),this.paste()):t&&e.key.toLowerCase()==="y"?(e.preventDefault(),this.redo()):e.key==="F2"&&this.selected?(e.preventDefault(),this.renameVariable(this.selected)):e.key==="Delete"||e.key==="Backspace"?(e.preventDefault(),this.deleteSelection()):e.key==="Escape"&&(this.drag?this.endDrag():(this.selected=void 0,this.render()))}}svgPoint(e,t){if(!this.svg)return;const n=this.svg.getBoundingClientRect(),a=e-n.left,s=t-n.top;if(!(a<0||s<0||a>n.width||s>n.height))return{x:a/this.zoom,y:s/this.zoom}}nodeAt(e,t){for(let n=this.flat.length-1;n>=0;n--){const a=this.flat[n].frame;if(e>=a.x&&e<=a.x+a.width&&t>=a.y&&t<=a.y+a.height)return this.flat[n]}}onCanvasPointerDown(e){if(this.simulating)return;const t=this.svgPoint(e.clientX,e.clientY);if(!t)return;document.activeElement instanceof HTMLElement&&document.activeElement.blur();const n=this.nodeAt(t.x,t.y),a=n&&this.selected&&Do(n.idPath,this.selected);this.selected=n==null?void 0:n.idPath,this.render(),n&&e.pointerType!=="touch"&&!(Sn(this.doc,n.idPath)&&!a)&&this.beginDrag(e,{kind:"move",path:n.idPath})}beginDrag(e,t){e.button!==0||this.simulating||(e.preventDefault(),this.drag={source:t,pointerId:e.pointerId,startX:e.clientX,startY:e.clientY,active:!1})}onPointerMove(e){const t=this.drag;if(!t||e.pointerId!==t.pointerId)return;if(!t.active){if(Math.hypot(e.clientX-t.startX,e.clientY-t.startY)<5)return;t.active=!0,t.ghost=this.makeGhost(t.source),document.body.append(t.ghost),this.root.classList.add("dragging")}t.ghost.style.transform=`translate(${e.clientX+12}px, ${e.clientY+12}px)`,this.autoScroll(e.clientX,e.clientY);const n=this.svgPoint(e.clientX,e.clientY);t.target=n?this.dropTargetAt(n.x,n.y,t.source):void 0,this.showDropTarget(t.target)}onPointerUp(e){const t=this.drag;!t||e.pointerId!==t.pointerId||(t.active&&t.target?this.applyDrop(t.source,t.target):!t.active&&t.source.kind==="palette"?this.insertNearSelection(t.source.make()):!t.active&&t.source.kind==="sensor"&&this.insertSensor(t.source.text),this.endDrag())}endDrag(){var e,t;(t=(e=this.drag)==null?void 0:e.ghost)==null||t.remove(),this.drag=void 0,this.root.classList.remove("dragging"),this.showDropTarget(void 0)}makeGhost(e){const t=document.createElement("div");if(t.className="drag-ghost",e.kind==="palette"||e.kind==="sensor")t.textContent=e.label;else{const n=Ot(this.doc,e.path);t.textContent=`${wo(n.type)}: ${$l(n)[0]}`}return t}autoScroll(e,t){const n=this.canvasHost.getBoundingClientRect(),a=40,s=12;t>n.bottom-a&&tn.top-a&&(this.canvasHost.scrollTop-=s),e>n.right-a&&en.left-a&&(this.canvasHost.scrollLeft-=s)}dropTargetAt(e,t,n){var l;const a=((l=this.layout)==null?void 0:l.elements)??[],s=this.nodeAt(e,t);if(n.kind==="sensor")return!s||Sn(this.doc,s.idPath)?void 0:Wd.includes(Ot(this.doc,s.idPath).type)?{kind:"condition",path:s.idPath,frame:s.frame}:void 0;if(!s){const u=a[a.length-1];if(!u)return;const m=u.frame.y+u.frame.height;return t>m?n.kind==="move"&&n.path.length===1&&n.path[0]===a.length-1?void 0:{kind:"rootAppend",frame:{x:u.frame.x,y:m,width:u.frame.width,height:0}}:t=n.path.length&&n.path.every((u,m)=>r[m]===u)?void 0:Sn(this.doc,r)?{kind:"replace",path:r,frame:s.frame}:{kind:t"]/g,e=>({"&":"&","<":"<",">":">",'"':"""})[e])}function sh(i){if(!i)return[];for(const e of[...zt.flatMap(t=>t.steps.flatMap(n=>n.blocks)),...Pn.flatMap(t=>t.blocks)])if(!(e.kind!=="exercise"||e.exercise.id!==i))return e.exercise.tests.flatMap(t=>{const n=t.world?ts(t.world):void 0;return n?[n]:[]});return[]}let Jt,Ql,Ul;function rh(i){const e=i.dataset.tip;if(!e)return;Jt??(Jt=Object.assign(document.createElement("div"),{className:"tooltip",role:"tooltip"})),Jt.isConnected||document.body.append(Jt),Jt.textContent=e,Jt.hidden=!1;const t=i.getBoundingClientRect(),n=Jt.offsetWidth,a=Jt.offsetHeight,s=Math.min(Math.max(8,t.left+t.width/2-n/2),window.innerWidth-n-8),r=t.bottom+6+a{if(i.pointerType==="touch")return;const e=i.target.closest("[data-tip]");e!==Ul&&(So(),e&&(Ul=e,Ql=window.setTimeout(()=>rh(e),350)))}),document.addEventListener("focusin",i=>{const e=i.target.closest("[data-tip]");So(),e!=null&&e.matches(":focus-visible")&&rh(e)});for(const i of["pointerdown","focusout","scroll","keydown"])document.addEventListener(i,So,!0)}const Yl="visustruct.reloadedAfterError";function H2(){try{const i=Number(sessionStorage.getItem(Yl));if(i&&Date.now()-i<3e4)return!1;sessionStorage.setItem(Yl,String(Date.now()))}catch{return!1}return location.reload(),!0}function TQ(i){console.error(i);const e=(navigator.language||"").toLowerCase().startsWith("de"),t=document.createElement("div");t.className="startup-error";const n=document.createElement("h1");n.textContent=e?"VisuStruct konnte nicht starten":"VisuStruct could not start";const a=document.createElement("p");a.textContent=e?"Wahrscheinlich gibt es gerade eine neue Version. Lade die Seite neu. Hilft das nicht, drücke Strg+Umschalt+R (Mac: ⌘⇧R).":"There is probably a new version. Reload the page. If that does not help, press Ctrl+Shift+R (Mac: ⌘⇧R).";const s=document.createElement("button");s.textContent=e?"Neu laden":"Reload",s.addEventListener("click",()=>location.reload());const r=document.createElement("pre");r.textContent=String(i instanceof Error?i.message:i),t.append(n,a,s,r),(document.getElementById("app")??document.body).replaceWith(t)}window.addEventListener("vite:preloadError",i=>{H2()&&i.preventDefault()});const _Q=L3();Promise.all([Ch(_Q,!1),jh(M3(),!1)]).then(()=>{G2(),SQ();const i=new URLSearchParams(location.search);if(!["visustruct","visubot","visuobject","visuflow"].some(a=>i.has(a))&&!Kg()){const a=lh();a==="visubot"?ns("on"):a==="visuobject"&&tl()}i.has("visuobject")&&tl(),i.has("visuflow")&&$g();const t=document.getElementById("app"),n=!i.has("visustruct")&&!i.has("visubot");if(Ug()&&n)return ee(async()=>{const{ObjectApp:a}=await import("./objectApp-DkBXkNTX.js").then(s=>s.g);return{ObjectApp:a}},[],import.meta.url).then(({ObjectApp:a})=>void new a(t));if(Yg()&&n)return ee(async()=>{const{FlowApp:a}=await import("./flowApp-RdEaBhPZ.js");return{FlowApp:a}},[],import.meta.url).then(({FlowApp:a})=>void new a(t));new zQ(t)}).then(()=>{try{sessionStorage.removeItem(Yl)}catch{}}).catch(i=>{/dynamically imported module|Importing a module script failed|error loading dynamically/i.test(String(i))&&H2()||TQ(i)});export{Yn as C,Iq as J,Mx as L,ee as _,uq as a,Dq as b,P2 as c,BQ as d,$g as e,ns as f,yQ as g,wa as h,me as i,_N as j,TN as k,a3 as l,DQ as m,o1 as n,tl as o,_q as p,Pd as q,Em as r,NW as s,p as t,F2 as u,Od as v,nl as w,eQ as x,iQ as y,aQ as z}; diff --git a/website/app/assets/objectApp-BSgp1317.js b/website/app/assets/objectApp-DkBXkNTX.js similarity index 99% rename from website/app/assets/objectApp-BSgp1317.js rename to website/app/assets/objectApp-DkBXkNTX.js index 816c423d..06c0543b 100644 --- a/website/app/assets/objectApp-BSgp1317.js +++ b/website/app/assets/objectApp-DkBXkNTX.js @@ -1,5 +1,5 @@ -const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./projectZip-D6C7FbQ-.js","./index-B8lDfJ72.js","./index-C2teIEHU.css"])))=>i.map(i=>d[i]); -var Ns=Object.defineProperty;var Os=(a,e,t)=>e in a?Ns(a,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):a[e]=t;var E=(a,e,t)=>Os(a,typeof e!="symbol"?e+"":e,t);import{t as d,i as ie,s as Ps,m as Is,g as Ds,w as Rs,J as Hs,c as Bs,a as Ws,b as Ye,p as zs,d as Vs,e as Us,f as Js,_ as wt,h as $t,j as Ks,r as _t,k as Xs,l as Ys,n as ct}from"./index-B8lDfJ72.js";function Gs(a){const e=[];let t=0;for(;ti.map(i=>d[i]); +var Ns=Object.defineProperty;var Os=(a,e,t)=>e in a?Ns(a,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):a[e]=t;var E=(a,e,t)=>Os(a,typeof e!="symbol"?e+"":e,t);import{t as d,i as ie,s as Ps,m as Is,g as Ds,w as Rs,J as Hs,c as Bs,a as Ws,b as Ye,p as zs,d as Vs,e as Us,f as Js,_ as wt,h as $t,j as Ks,r as _t,k as Xs,l as Ys,n as ct}from"./index-DuzNMqv5.js";function Gs(a){const e=[];let t=0;for(;te.text===","?", ":e.text).join("")}function ms(a){const e=[[]];let t=0;for(const s of a)s.text==="<"||s.text==="("||s.text==="["||s.text==="{"?t++:(s.text===">"||s.text===")"||s.text==="]"||s.text==="}")&&t--,s.text===","&&t===0?e.push([]):e[e.length-1].push(s);return e.filter(s=>s.length>0)}function ft(a){var t,s;const e=[];for(let i=0;i{const t=ft(e).filter(i=>i.text!=="final"),s=t[t.length-1];return{name:s!=null&&s.word?s.text:"",type:lt(t.slice(0,-1))}})}function kt(a,e,t,s){var x,L;const i=ft(a),n=new Set;let o=0;for(;o"));const r=i.slice(o);if(r.length===0||a.length===0)return[];const c=a[0].from,l=r.findIndex(S=>S.text==="("),h=r.findIndex(S=>S.text==="="),u=l>0&&(h<0||lS.text==="="),y=_<0?g:g.slice(0,_);let w=y.length-1;for(;w>0&&!y[w].word;)w--;if(w<1)return[];const $=lt(y.slice(0,w)),p=m.length>1,v=[];return m.forEach((S,k)=>{var C;const j=S.findIndex(F=>F.text==="="),M=j<0?S:S.slice(0,j),A=k===0?y[w]:M.find(F=>F.word);if(!A)return;const R=M.filter(F=>F.from>A.from&&F.text==="[").length;v.push({kind:"field",name:A.text,type:$+"[]".repeat(R),params:[],visibility:xt(n,f),isStatic:n.has("static"),isAbstract:!1,from:c,to:s,headerFrom:c,headerTo:k===0?((C=M[M.length-1])==null?void 0:C.to)??A.to:A.to,shared:p,nameFrom:A.from,nameTo:A.to})}),v}function Qs(a,e,t){var n;let s=[],i=e;for(;ih.text==="="),c=ye(a,i,"{","}");if(r){s.push(...a.slice(i,c)),i=c;continue}const l=s.map(h=>h.text);l.includes("class")||l.includes("interface")||l.includes("enum")||s.length>0&&t.members.push(...kt(s,t.name,t.kind==="interface",((n=a[c-1])==null?void 0:n.to)??o.to)),s=[],i=c;continue}s.push(o),i++}return t.bodyEnd=a.length>0?a[a.length-1].to:0,i}function oe(a){var n,o,r,c;const e=Gs(a),t=[];let s=[],i=0;for(;iw.text==="class"||w.text==="interface"),f=u>=0?h[u+1]:void 0;if(!(f!=null&&f.word)){i=ye(e,i,"{","}"),s=[];continue}let m=u;for(;m>0&&(fs.has(h[m-1].text)||h[m-1].text==="@");)m--;const g={name:f.text,kind:h[u].text==="interface"?"interface":"class",isAbstract:h.slice(m,u).some(w=>w.text==="abstract"),interfaces:[],members:[],from:((n=s[s.indexOf(h[m])])==null?void 0:n.from)??h[m].from,to:0,headerFrom:((o=s[s.indexOf(h[m])])==null?void 0:o.from)??h[m].from,headerTo:h[h.length-1].to,nameFrom:f.from,nameTo:f.to,bodyEnd:0};let _=u+2;((r=h[_])==null?void 0:r.text)==="<"&&(_=ye(h,_,"<",">"));let y="";for(;_")-1:w.word&&y==="extends"&&g.kind==="class"?g.superclass??(g.superclass=w.text):w.word&&y&&g.interfaces.push(w.text)}i=Qs(e,i+1,g),g.to=((c=e[i-1])==null?void 0:c.to)??a.length,t.push(g),s=[]}return t}function Fe(a){const e=/^([\p{L}_$][\p{L}\p{N}_$]*)(\[\])+$/u.exec(a);if(e)return{name:e[1],many:!0};const t=/^(?:ArrayList|LinkedList|List|Set|HashSet|TreeSet|Collection|Queue|Deque|ArrayDeque|Stack|Vector)<([\p{L}_$][\p{L}\p{N}_$]*)>$/u.exec(a);return t?{name:t[1],many:!0}:{name:a,many:!1}}function ei(a){const e=new Set(a.map(s=>s.name)),t=[];for(const s of a){s.superclass&&e.has(s.superclass)&&t.push({kind:"extends",from:s.name,to:s.superclass});for(const i of s.interfaces)e.has(i)&&t.push({kind:s.kind==="interface"?"extends":"implements",from:s.name,to:i});for(const i of s.members){if(i.kind!=="field")continue;const n=Fe(i.type);e.has(n.name)&&t.push({kind:"association",from:s.name,to:n.name,role:i.name,multiplicity:n.many?"0..*":"1"})}}return t}function Ge(a){const e=a.params.map(t=>`${t.name}: ${t.type}`).join(", ");return a.kind==="field"?`${a.visibility} ${a.name}: ${a.type}`:a.kind==="constructor"?`${a.visibility} ${a.name}(${e})`:`${a.visibility} ${a.name}(${e}): ${a.type}`}const ti=/^[\p{L}_$][\p{L}\p{N}_$]*$/u;function Ve(a){var c;let e=a.trim().replace(/;$/,"").trim();if(!e)return;let t;/^[+\-#~]/.test(e)&&(t=e[0],e=e.slice(1).trim());let s=!1;const i=e.split(/\s+/);for(;["static","public","private","protected"].includes(i[0]);){const l=i.shift();l==="static"?s=!0:t??(t=l==="public"?"+":l==="private"?"-":"#")}e=i.join(" ");const n=e.indexOf("(");if(n>=0){const l=e.lastIndexOf(")");if(lg.trim()).filter(Boolean).map(g=>{const _=/^([\p{L}_$][\p{L}\p{N}_$]*)\s*:\s*(.+)$/u.exec(g);if(_)return{name:_[1],type:_[2].replace(/\s+/g,"")};const y=/^(.+)\s+([\p{L}_$][\p{L}\p{N}_$]*)$/u.exec(g);return y?{name:y[2],type:y[1].replace(/\s+/g,"")}:{name:g,type:"int"}});return{kind:"method",visibility:t,name:h,type:u==null?void 0:u.replace(/\s+/g,""),params:m,isStatic:s}}const o=/^([\p{L}_$][\p{L}\p{N}_$]*)\s*(?::\s*(.+))?$/u.exec(e);if(o)return{kind:"field",visibility:t,name:o[1],type:(c=o[2])==null?void 0:c.replace(/\s+/g,""),params:[],isStatic:s};const r=/^(.+?)\s+([\p{L}_$][\p{L}\p{N}_$]*)$/u.exec(e);if(r)return{kind:"field",visibility:t,name:r[2],type:r[1].replace(/\s+/g,""),params:[],isStatic:s}}const si={"+":"public ","-":"private ","#":"protected ","~":""};function ii(a){return/^(int|long|short|byte)$/.test(a)?"0":/^(double|float)$/.test(a)?"0.0":a==="boolean"?"false":a==="char"?"' '":"null"}function bs(a,e,t){const s=e.kind==="interface",i=s?"":si[a.visibility??(a.kind==="field"?"-":"+")],n=a.isStatic?"static ":"";if(a.kind==="field")return`${i}${n}${a.type??"int"} ${a.name}`;const o=a.params.map(r=>`${r.type} ${r.name}`).join(", ");return a.name===e.name?`${i}${a.name}(${o})`:`${i}${n}${t&&!s?"abstract ":""}${a.type??"void"} ${a.name}(${o})`}const Ue=(a,e)=>a.lastIndexOf(` `,e-1)+1;function mt(a,e,t){const s=Ue(a,e),i=a.slice(s,e);let n=t;for(;n
- ${b(d("web_about_version_fmt").replace("%@","0.15.0"))} + ${b(d("web_about_version_fmt").replace("%@","0.15.1"))}
@@ -315,7 +315,7 @@ public String toString() { `,"in"),this.consolePane().input.hidden=!0,t.vm.input(e),this.debugRun())}debugError(e){var o;const t=e.pos?String(e.pos.line+1):"",s=((o=e.pos)==null?void 0:o.file.split("/").pop())??"",i=e.detail.replace(/^expected:/,""),n={syntax:"web_visuobject_dbg_err_syntax",symbol:"web_visuobject_dbg_err_symbol",unsupported:"web_visuobject_dbg_err_unsupported",nomain:"web_visuobject_no_main",type:"web_visuobject_dbg_err_type",import:"web_visuobject_dbg_err_import",typename:"web_visuobject_dbg_err_typename"}[e.code];e.pos&&this.showLine(e.pos.file,e.pos.line),this.stopDebug(),this.debugStatus(d(n,s,t,i),!0)}showDebugButtons(){const e=this.dbg,t=(e==null?void 0:e.state)==="paused";for(const s of this.shell.querySelectorAll("[data-dbg]"))s.disabled=!e||(s.dataset.dbg==="pause"?e.state!=="running":!t)}showLine(e,t){this.project.files.some(s=>s.path===e)&&e!==this.active&&this.openFile(e),this.editor.setMarks({placeholders:[],problems:[],current:t},!0)}showDebugState(){const e=this.dbg;if(!e)return;e.frames=e.vm.stack();const t=e.vm.heap(),s=e.frames[e.frame];s&&this.showLine(s.pos.file,s.pos.line);const i=e.values.size===0&&e.vars.size===0,n=new Set,o=new Map;for(const h of t)for(const u of h.fields){const f=`dbg${h.id}.${u.name}`;o.set(f,u.value),!i&&e.values.get(f)!==u.value&&n.add(f)}e.values=o;const r=new Set,c=new Map;e.frames.forEach((h,u)=>{for(const f of h.vars){const m=`${e.frames.length-u}|${h.title}|${f.name}`;c.set(m,f.value),!i&&e.vars.get(m)!==f.value&&r.add(`${h.title}|${f.name}`)}}),e.vars=c;const l={objects:this.liveObjects(t),changed:n,frames:e.frames,frame:e.frame,changedVars:r,onFrame:h=>{e.frame=h,l.frame=h;const u=e.frames[h];u&&this.showLine(u.pos.file,u.pos.line),this.objectDiagram.renderInspector()},move:(h,u)=>e.places.set(h,u)};this.objectDiagram.live=l,this.sequence=e.vm.sequence(),this.diagramMode==="object"&&this.objectDiagram.render(),this.diagramMode==="sequence"&&this.renderSequence()}renderSequence(){var n,o,r;const e=this.shell.querySelector(".vo-seqcanvas"),t=e.querySelector(".vo-seq"),s=e.querySelector(".vo-empty"),i=this.sequence;if(s.hidden=!!i&&i.events.length>0,s.textContent=d(i?"web_visuobject_seq_no_calls":"web_visuobject_seq_empty"),!i||!i.events.length)t.innerHTML="",t.setAttribute("width","0");else{const c=((n=this.dbg)==null?void 0:n.state)==="paused"||((o=this.dbg)==null?void 0:o.state)==="input",{svg:l,width:h,height:u}=Ai(i,c?i.events.length-1:void 0);t.innerHTML=l+(i.truncated?`${b(d("web_visuobject_seq_truncated"))}`:""),t.setAttribute("width",String(h)),t.setAttribute("height",String(u)),c&&((r=t.querySelector(".vo-seq-msg.current"))==null||r.scrollIntoView({block:"nearest",inline:"nearest"}))}this.renderSequenceInspector()}renderSequenceInspector(){if(this.objectDiagram.live)return this.objectDiagram.renderInspector();this.inspector.innerHTML=`

${b(d("web_visuobject_seq_hint"))}

`}liveObjects(e){const t=this.dbg,s=this.project.objects??[],i=c=>40+c.fields.length*20,n=[],o=[],r=[];for(const c of e){const l=`dbg${c.id}`,h=t.places.get(l)??s.find(u=>u.name===c.name&&u.cls===c.cls);if(!h){r.push(c);continue}t.places.set(l,{x:h.x,y:h.y}),n.push({x:h.x,y:h.y,w:260,h:i(c)})}for(const c of r){const l=i(c);let h={x:24,y:24};e:for(let u=24;u<6e3;u+=30)for(let f=24;f<=24+3*320;f+=320)if(n.every(m=>f+260+30<=m.x||m.x+m.w+30<=f||u+l+30<=m.y||m.y+m.h+30<=u)){h={x:f,y:u};break e}t.places.set(`dbg${c.id}`,h),n.push({...h,w:260,h:l})}for(const c of e){const l=`dbg${c.id}`;o.push({id:l,name:c.name,cls:c.cls,...t.places.get(l),values:Object.fromEntries(c.fields.map(h=>[h.name,h.value]))})}return o}stopDebug(e,t=!1){const s=this.dbg;s&&clearTimeout(s.timer),this.dbg=void 0,s&&(this.sequence=s.vm.sequence()),this.objectDiagram.live=void 0,this.consolePane().input.hidden=!0,this.shell.querySelector(".vo-dbg-controls").hidden=!0,this.shell.querySelector("[data-action=stop]").disabled=!0,this.shell.querySelector("[data-action=run]").disabled=!1,t||this.editor.setMarks({placeholders:[],problems:[]},!1),e&&this.debugStatus(d(e),t),this.diagramMode==="object"&&this.objectDiagram.render(),this.diagramMode==="sequence"&&this.renderSequence()}chooseWorld(e){if(e!=="object"){if(e==="flow"){Us(),location.href=`${location.pathname}?visuflow${location.hash}`;return}Js(e),location.href=`${location.pathname}?${e==="on"?"visubot":"visustruct"}${location.hash}`}}get activeFile(){return this.project.files.find(e=>e.path===this.active)}showActive(){const e=this.activeFile;this.editor.setText((e==null?void 0:e.text)??""),this.editor.setBreakpoints(e?this.breakpoints.get(e.path)??[]:[]),this.editor.setReadOnly(!e),e&&!this.openTabs.includes(e.path)&&this.openTabs.push(e.path),this.renderTabs(),J(ot,this.active??"")}renderTabs(){if(this.openTabs=this.openTabs.filter(e=>this.project.files.some(t=>t.path===e)),J(cs,JSON.stringify(this.openTabs)),this.openTabs.length===0){this.tabs.innerHTML=`${b(d("web_visuobject_no_file"))}`;return}this.tabs.innerHTML=this.openTabs.map(e=>{const t=e===this.active,s=this.isDirty(e);return`
-
`}).join("")}onTabClick(e){var i;const t=e.target,s=(i=t.closest("[data-tab]"))==null?void 0:i.dataset.tab;if(s){if(t.closest("[data-close]"))return this.closeTab(s);this.treeSelection=`file:${s}`,this.openFile(s)}}closeTab(e){const t=this.openTabs.indexOf(e);t<0||(this.openTabs.splice(t,1),e===this.active?(this.active=this.openTabs[Math.min(t,this.openTabs.length-1)],this.lastTyping=0,this.showActive(),this.refresh()):this.renderTabs())}snapshot(){return JSON.stringify({project:this.project,active:this.active})}remember(){this.history.push(this.snapshot()),this.history.length>jn&&this.history.shift(),this.future=[]}setProject(e,t=this.active){var s;this.remember(),this.lastTyping=0,this.project=e,this.active=e.files.some(i=>i.path===t)?t:(s=e.files[0])==null?void 0:s.path,this.showActive(),this.refresh()}openFile(e){if(e===this.active)return;this.active=e,this.lastTyping=0,this.showActive();const t=D(e);this.currentPackage=t,this.open.set(`pkg:${t}`,!0),this.refresh()}typed(){const e=this.activeFile;if(!e)return;const t=Date.now();t-this.lastTyping>1500&&this.remember(),this.lastTyping=t,this.project=$e(this.project,e.path,this.editor.text),this.saveBreakpoints(),this.dbg&&this.stopDebug("web_visuobject_dbg_code_changed"),this.refresh(),clearTimeout(this.renameTimer),this.renameTimer=window.setTimeout(()=>this.syncFileName(),700)}syncFileName(){var c;const e=this.activeFile;if(!e||this.editing)return;const t=Q(e.path).replace(/\.java$/i,""),s=this.classes.filter(l=>l.path===e.path);if(s.length===0||s.some(l=>l.name===t))return;const i=((c=/\bpublic\s+(?:abstract\s+|final\s+)*(?:class|interface|enum)\s+(\w+)/.exec(e.text))==null?void 0:c[1])??s[0].name;if(!pe.test(i)||s.filter(l=>l.name===i).length!==1)return;const n=le(D(e.path),`${i}.java`);if(this.project.files.some(l=>l.path===n))return;let o=Oe(this.project,e.path,n);const r=this.positions.get(t);r&&!this.positions.has(i)&&this.positions.set(i,r);for(const l of Object.keys(o.uml??{}))l.startsWith(`${t}.`)&&(o={...o,uml:ke(o.uml,l,i+l.slice(t.length))});this.openTabs=this.openTabs.map(l=>l===e.path?n:l),this.treeSelection===`file:${e.path}`&&(this.treeSelection=`file:${n}`),this.isOpen(`file:${e.path}`)&&this.open.set(`file:${n}`,!0),this.project=o,this.active=n,J(ot,n),this.savePositions(),this.refresh()}undo(e){const t=e?this.future:this.history,s=e?this.history:this.future,i=t.pop();if(i===void 0)return;s.push(this.snapshot());const n=JSON.parse(i);this.project=n.project,this.active=n.active,this.lastTyping=0,this.showActive(),this.refresh()}refresh(){J(os,Pe(this.project)),this.renderTabs(),this.classes=Ct(this.project),this.selection&&!this.findClass(this.selection.cls)&&(this.selection=void 0),this.relSelection&&!this.findRelation(this.relSelection)&&!this.findDependency(this.relSelection)&&(this.relSelection=void 0),this.editing||(this.render(),this.renderTree())}ownTypesAt(e){const t=this.activeFile;if(!t)return;const s=this.editor.view.state.doc.toString(),i=X(D(t.path)),n=oe(s).map(l=>({...l,pkg:i})),o=new Set(n.map(l=>l.name)),r=n.find(l=>l.headerFrom<=e&&e<=l.bodyEnd),c=ct()==="de"?"de":ct()==="pt-PT"?"pt":"en";return Ki([...n,...this.classes.filter(l=>l.path!==t.path&&!o.has(l.name))],{cls:r==null?void 0:r.name,pkg:i},c)}findClass(e){return this.classes.find(t=>t.name===e)}caretMoved(){var n,o;const e=this.editor.caret,t=this.classes.find(r=>r.path===this.active&&e>=r.from&&e<=r.to),s=t==null?void 0:t.members.findIndex(r=>e>=r.from&&e<=r.to),i=t?{cls:t.name,member:s!==void 0&&s>=0?s:void 0}:void 0;(i==null?void 0:i.cls)===((n=this.selection)==null?void 0:n.cls)&&(i==null?void 0:i.member)===((o=this.selection)==null?void 0:o.member)||(this.selection=i,this.editing||(this.render(),this.renderTree()))}showInCode(e,t){e.path!==this.active&&(this.active=e.path,this.lastTyping=0,this.showActive());const s=this.editor.view,[i,n]=t?[t.headerFrom,t.headerTo]:[e.nameFrom,e.nameTo],o=Math.min(n,s.state.doc.length);s.dispatch({selection:{anchor:Math.min(i,o),head:o},scrollIntoView:!0})}message(e,t=!1){this.status.textContent=e,this.status.classList.toggle("hint",t)}openFiles(){const e=document.createElement("input");e.type="file",e.multiple=!0,e.accept=".zip,.java,.visuobject,application/zip,text/plain",e.addEventListener("change",()=>void this.readFiles([...e.files??[]])),e.click()}async readFiles(e){var t;if(e.length!==0)try{const s=e.find(r=>/\.zip$/i.test(r.name));if(s){const{projectFromZip:r}=await wt(async()=>{const{projectFromZip:l}=await import("./projectZip-D6C7FbQ-.js");return{projectFromZip:l}},__vite__mapDeps([0,1,2]),import.meta.url),c=r(new Uint8Array(await s.arrayBuffer()),s.name.replace(/\.zip$/i,""));await this.newProject(c);return}const i=e.find(r=>/\.visuobject$/i.test(r.name));if(i){const r=qt(await i.text());if(!r)throw new Error("format");await this.newProject(r);return}const n=At(this.project.name,await Promise.all(e.map(async r=>({name:r.name,text:await r.text()}))));let o=this.project;for(const r of n.files)o=et(o,r.path,r.text);this.setProject(o,(t=n.files[0])==null?void 0:t.path)}catch{this.message(d("web_visuobject_open_failed"))}}async save(){this.workspace?await this.writeCurrent():await this.downloadZip()}async downloadZip(){const{projectToZip:e}=await wt(async()=>{const{projectToZip:s}=await import("./projectZip-D6C7FbQ-.js");return{projectToZip:s}},__vite__mapDeps([0,1,2]),import.meta.url),t=e(this.project);Ln(`${this.project.name||"Projekt"}.zip`,t.slice().buffer,"application/zip")}isDirty(e){var t;return!this.workspace||this.saved===void 0?!1:e===void 0?this.saved!==Pe(this.project):this.savedFiles.get(e)!==((t=this.project.files.find(s=>s.path===e))==null?void 0:t.text)}markSaved(){this.saved=Pe(this.project),this.savedFiles=new Map(this.project.files.map(e=>[e.path,e.text]))}async restoreWorkspace(){if(!$t())return;const e=await Ks(us);if(e!=null&&e.ready){const t=await _t(e.handle);if(t)return this.useWorkspace(t.root,!0)}this.pendingFolder=e==null?void 0:e.handle,this.renderWorkspace()}async useWorkspace(e,t=!1){var s;this.workspace=e,this.pendingFolder=void 0,J(rt,"0");try{this.projects=await is(e);const i=se(We),n=this.project;if(t&&i&&this.projects.includes(i)){const o={active:this.active,tabs:[...this.openTabs],positions:new Map(this.positions)};await this.loadProject(i),this.positions=o.positions,this.savePositions(),Pe(n)!==this.saved&&(this.project=n),this.openTabs=o.tabs.filter(r=>this.project.files.some(c=>c.path===r)),this.active=this.project.files.some(r=>r.path===o.active)?o.active:(s=this.project.files[0])==null?void 0:s.path,this.showActive(),this.refresh()}else!this.projects.some(o=>o.toLowerCase()===ge(n.name).toLowerCase())&&n.files.length?(this.folder=ge(n.name),await this.writeCurrent(!1)):this.projects.length?await this.loadProject(this.projects.includes(i??"")?i:this.projects[0]):(this.folder=ge(n.name),await this.writeCurrent(!1))}catch(i){this.message(d("web_visuobject_ws_failed",String((i==null?void 0:i.message)??i)))}this.renderWorkspace(),this.refresh()}async loadProject(e){var i;const{project:t,positions:s}=await wn(this.workspace,e);this.folder=e,this.project=t,this.markSaved(),this.message(""),this.history=[],this.future=[],this.lastTyping=0,this.selection=void 0,this.relSelection=void 0,this.treeSelection=void 0,this.currentPackage=void 0,this.positions=new Map(Object.entries(s)),this.savePositions(),this.openTabs=[],this.active=(i=t.files[0])==null?void 0:i.path,J(We,e),this.showActive(),this.refresh()}async writeCurrent(e=!0){const t=this.workspace;if(!t)return!1;const s=ge(this.project.name),i=this.folder,n=new Set(this.classes.map(r=>r.name)),o=Object.fromEntries([...this.positions].filter(([r])=>n.has(r)));if(s!==i&&this.projects.some(r=>r!==i&&r.toLowerCase()===s.toLowerCase()))return this.message(d("web_visuobject_ws_taken",this.project.name)),!1;try{return await xn(t,s,this.project,o),i&&i!==s&&this.projects.includes(i)&&await t.remove(i),this.folder=s,this.projects=await is(t),J(We,s),this.markSaved(),e&&this.message(d("web_visuobject_ws_saved",t.name,s),!0),this.refresh(),!0}catch(r){return this.message(d("web_visuobject_ws_failed",String((r==null?void 0:r.message)??r))),!1}}async switchProject(e){if(!(!this.workspace||e===this.folder)&&!(this.isDirty()&&!await this.writeCurrent(!1)))try{await this.loadProject(e)}catch(t){this.message(d("web_visuobject_ws_failed",String((t==null?void 0:t.message)??t)))}}async newProject(e,t,s=!1){var n,o;if(!this.workspace){this.setProject(e,t??((n=e.files[0])==null?void 0:n.path)),e.files.length===0&&!s&&this.editProjectName();return}if(this.isDirty()&&!await this.writeCurrent(!1))return;const i=ns(ge(e.name),this.projects);this.project={...e,name:i},this.folder=i,this.history=[],this.future=[],this.openTabs=[],this.positions.clear(),this.savePositions(),this.active=e.files.some(r=>r.path===t)?t:(o=e.files[0])==null?void 0:o.path,this.showActive(),this.refresh(),await this.writeCurrent(!1)&&(this.message(d("web_visuobject_ws_created",i),!0),e.files.length===0&&!s&&this.editProjectName())}get currentPlace(){const e=this.currentPackage??(this.active?D(this.active):ce(this.project)[0]??"");return{root:U(e),pkg:X(e)}}async newFromWizard(e){var u;const t=this.currentPlace,s=(f,m)=>{let g=f;for(let _=2;m(g);_++)g=f+_;return g},i=await an(e,{roots:ue(this.project),packagesIn:f=>ce(this.project,f).map(X),classes:this.classes,root:t.root,pkg:t.pkg,suggest:f=>f==="project"?ns(d("web_visuobject_project_name"),this.workspace?[...this.projects,this.folder??""]:[]):f==="folder"?s("test",m=>ue(this.project).includes(m)):f==="package"?s(d("web_visuobject_new_package_name"),m=>ce(this.project).includes(re(t.root,m))):this.uniqueClassName(d(f==="class"?"web_visuobject_new_class_name":"web_visuobject_new_interface_name")),check:(f,m,g,_)=>{if(!m)return d("web_visuobject_new_name_missing");if(f==="project")return this.workspace&&this.projects.some(y=>y!==this.folder&&y.toLowerCase()===ge(m).toLowerCase())?d("web_visuobject_ws_taken",m):void 0;if(f==="folder")return!Je(m)||ue(this.project).includes(m)?d("web_visuobject_bad_folder",m):void 0;if(f==="package")return!Mt(m)||ce(this.project).includes(re(g,m))?d("web_visuobject_bad_package",m):void 0;if(!pe.test(m))return d("web_visuobject_bad_name",m);if(this.findClass(m)||this.project.files.some(y=>y.path===le(re(g,_),`${m}.java`)))return d("web_visuobject_new_exists",m);if(m.charAt(0)!==m.charAt(0).toUpperCase())return d("web_visuobject_new_upper")}});if(!i)return;const{name:n,root:o,pkg:r}=i;if(e==="project")return this.newProject({name:n,files:[],packages:[]},void 0,!0);if(this.message(""),e==="folder")return this.currentPackage=re(n,""),this.treeSelection=`root:${n}`,this.open.set(`root:${n}`,!0),this.setProject(vi(this.project,n));if(e==="package"){const f=re(o,n);return this.currentPackage=f,this.treeSelection=`pkg:${f}`,this.open.set(`root:${o}`,!0),this.setProject(mi(this.project,f))}const c=re(o,r),l=le(c,`${n}.java`);this.currentPackage=c,this.selection={cls:n},this.open.set(`root:${o}`,!0),this.open.set(`pkg:${c}`,!0),this.setProject(et(this.project,l,this.sectioned(nn(i.options),n)),l);const h=this.findClass(n);h&&this.showInCode(h),(u=this.canvas.querySelector(`.uml-class[data-class="${CSS.escape(n)}"]`))==null||u.scrollIntoView({block:"nearest",inline:"nearest"})}editProjectName(){this.treeSelection="project",this.renderTree(),this.startEditing(this.tree.querySelector('[data-node="project"] > .vo-row .vo-label'))}renderWorkspace(){const e=this.wsBox;e.hidden=!$t();const t=this.shell.querySelector("[data-action=save]");if(t.dataset.tip=d(this.workspace?"web_visuobject_save_ws_tip":"web_visuobject_save_tip"),e.hidden)return;const s=(i,n,o="text-button",r)=>``;this.workspace?(e.className="vo-ws",e.innerHTML=`${b(this.workspace.name)} + `}).join("")}onTabClick(e){var i;const t=e.target,s=(i=t.closest("[data-tab]"))==null?void 0:i.dataset.tab;if(s){if(t.closest("[data-close]"))return this.closeTab(s);this.treeSelection=`file:${s}`,this.openFile(s)}}closeTab(e){const t=this.openTabs.indexOf(e);t<0||(this.openTabs.splice(t,1),e===this.active?(this.active=this.openTabs[Math.min(t,this.openTabs.length-1)],this.lastTyping=0,this.showActive(),this.refresh()):this.renderTabs())}snapshot(){return JSON.stringify({project:this.project,active:this.active})}remember(){this.history.push(this.snapshot()),this.history.length>jn&&this.history.shift(),this.future=[]}setProject(e,t=this.active){var s;this.remember(),this.lastTyping=0,this.project=e,this.active=e.files.some(i=>i.path===t)?t:(s=e.files[0])==null?void 0:s.path,this.showActive(),this.refresh()}openFile(e){if(e===this.active)return;this.active=e,this.lastTyping=0,this.showActive();const t=D(e);this.currentPackage=t,this.open.set(`pkg:${t}`,!0),this.refresh()}typed(){const e=this.activeFile;if(!e)return;const t=Date.now();t-this.lastTyping>1500&&this.remember(),this.lastTyping=t,this.project=$e(this.project,e.path,this.editor.text),this.saveBreakpoints(),this.dbg&&this.stopDebug("web_visuobject_dbg_code_changed"),this.refresh(),clearTimeout(this.renameTimer),this.renameTimer=window.setTimeout(()=>this.syncFileName(),700)}syncFileName(){var c;const e=this.activeFile;if(!e||this.editing)return;const t=Q(e.path).replace(/\.java$/i,""),s=this.classes.filter(l=>l.path===e.path);if(s.length===0||s.some(l=>l.name===t))return;const i=((c=/\bpublic\s+(?:abstract\s+|final\s+)*(?:class|interface|enum)\s+(\w+)/.exec(e.text))==null?void 0:c[1])??s[0].name;if(!pe.test(i)||s.filter(l=>l.name===i).length!==1)return;const n=le(D(e.path),`${i}.java`);if(this.project.files.some(l=>l.path===n))return;let o=Oe(this.project,e.path,n);const r=this.positions.get(t);r&&!this.positions.has(i)&&this.positions.set(i,r);for(const l of Object.keys(o.uml??{}))l.startsWith(`${t}.`)&&(o={...o,uml:ke(o.uml,l,i+l.slice(t.length))});this.openTabs=this.openTabs.map(l=>l===e.path?n:l),this.treeSelection===`file:${e.path}`&&(this.treeSelection=`file:${n}`),this.isOpen(`file:${e.path}`)&&this.open.set(`file:${n}`,!0),this.project=o,this.active=n,J(ot,n),this.savePositions(),this.refresh()}undo(e){const t=e?this.future:this.history,s=e?this.history:this.future,i=t.pop();if(i===void 0)return;s.push(this.snapshot());const n=JSON.parse(i);this.project=n.project,this.active=n.active,this.lastTyping=0,this.showActive(),this.refresh()}refresh(){J(os,Pe(this.project)),this.renderTabs(),this.classes=Ct(this.project),this.selection&&!this.findClass(this.selection.cls)&&(this.selection=void 0),this.relSelection&&!this.findRelation(this.relSelection)&&!this.findDependency(this.relSelection)&&(this.relSelection=void 0),this.editing||(this.render(),this.renderTree())}ownTypesAt(e){const t=this.activeFile;if(!t)return;const s=this.editor.view.state.doc.toString(),i=X(D(t.path)),n=oe(s).map(l=>({...l,pkg:i})),o=new Set(n.map(l=>l.name)),r=n.find(l=>l.headerFrom<=e&&e<=l.bodyEnd),c=ct()==="de"?"de":ct()==="pt-PT"?"pt":"en";return Ki([...n,...this.classes.filter(l=>l.path!==t.path&&!o.has(l.name))],{cls:r==null?void 0:r.name,pkg:i},c)}findClass(e){return this.classes.find(t=>t.name===e)}caretMoved(){var n,o;const e=this.editor.caret,t=this.classes.find(r=>r.path===this.active&&e>=r.from&&e<=r.to),s=t==null?void 0:t.members.findIndex(r=>e>=r.from&&e<=r.to),i=t?{cls:t.name,member:s!==void 0&&s>=0?s:void 0}:void 0;(i==null?void 0:i.cls)===((n=this.selection)==null?void 0:n.cls)&&(i==null?void 0:i.member)===((o=this.selection)==null?void 0:o.member)||(this.selection=i,this.editing||(this.render(),this.renderTree()))}showInCode(e,t){e.path!==this.active&&(this.active=e.path,this.lastTyping=0,this.showActive());const s=this.editor.view,[i,n]=t?[t.headerFrom,t.headerTo]:[e.nameFrom,e.nameTo],o=Math.min(n,s.state.doc.length);s.dispatch({selection:{anchor:Math.min(i,o),head:o},scrollIntoView:!0})}message(e,t=!1){this.status.textContent=e,this.status.classList.toggle("hint",t)}openFiles(){const e=document.createElement("input");e.type="file",e.multiple=!0,e.accept=".zip,.java,.visuobject,application/zip,text/plain",e.addEventListener("change",()=>void this.readFiles([...e.files??[]])),e.click()}async readFiles(e){var t;if(e.length!==0)try{const s=e.find(r=>/\.zip$/i.test(r.name));if(s){const{projectFromZip:r}=await wt(async()=>{const{projectFromZip:l}=await import("./projectZip-hnnNIFP3.js");return{projectFromZip:l}},__vite__mapDeps([0,1,2]),import.meta.url),c=r(new Uint8Array(await s.arrayBuffer()),s.name.replace(/\.zip$/i,""));await this.newProject(c);return}const i=e.find(r=>/\.visuobject$/i.test(r.name));if(i){const r=qt(await i.text());if(!r)throw new Error("format");await this.newProject(r);return}const n=At(this.project.name,await Promise.all(e.map(async r=>({name:r.name,text:await r.text()}))));let o=this.project;for(const r of n.files)o=et(o,r.path,r.text);this.setProject(o,(t=n.files[0])==null?void 0:t.path)}catch{this.message(d("web_visuobject_open_failed"))}}async save(){this.workspace?await this.writeCurrent():await this.downloadZip()}async downloadZip(){const{projectToZip:e}=await wt(async()=>{const{projectToZip:s}=await import("./projectZip-hnnNIFP3.js");return{projectToZip:s}},__vite__mapDeps([0,1,2]),import.meta.url),t=e(this.project);Ln(`${this.project.name||"Projekt"}.zip`,t.slice().buffer,"application/zip")}isDirty(e){var t;return!this.workspace||this.saved===void 0?!1:e===void 0?this.saved!==Pe(this.project):this.savedFiles.get(e)!==((t=this.project.files.find(s=>s.path===e))==null?void 0:t.text)}markSaved(){this.saved=Pe(this.project),this.savedFiles=new Map(this.project.files.map(e=>[e.path,e.text]))}async restoreWorkspace(){if(!$t())return;const e=await Ks(us);if(e!=null&&e.ready){const t=await _t(e.handle);if(t)return this.useWorkspace(t.root,!0)}this.pendingFolder=e==null?void 0:e.handle,this.renderWorkspace()}async useWorkspace(e,t=!1){var s;this.workspace=e,this.pendingFolder=void 0,J(rt,"0");try{this.projects=await is(e);const i=se(We),n=this.project;if(t&&i&&this.projects.includes(i)){const o={active:this.active,tabs:[...this.openTabs],positions:new Map(this.positions)};await this.loadProject(i),this.positions=o.positions,this.savePositions(),Pe(n)!==this.saved&&(this.project=n),this.openTabs=o.tabs.filter(r=>this.project.files.some(c=>c.path===r)),this.active=this.project.files.some(r=>r.path===o.active)?o.active:(s=this.project.files[0])==null?void 0:s.path,this.showActive(),this.refresh()}else!this.projects.some(o=>o.toLowerCase()===ge(n.name).toLowerCase())&&n.files.length?(this.folder=ge(n.name),await this.writeCurrent(!1)):this.projects.length?await this.loadProject(this.projects.includes(i??"")?i:this.projects[0]):(this.folder=ge(n.name),await this.writeCurrent(!1))}catch(i){this.message(d("web_visuobject_ws_failed",String((i==null?void 0:i.message)??i)))}this.renderWorkspace(),this.refresh()}async loadProject(e){var i;const{project:t,positions:s}=await wn(this.workspace,e);this.folder=e,this.project=t,this.markSaved(),this.message(""),this.history=[],this.future=[],this.lastTyping=0,this.selection=void 0,this.relSelection=void 0,this.treeSelection=void 0,this.currentPackage=void 0,this.positions=new Map(Object.entries(s)),this.savePositions(),this.openTabs=[],this.active=(i=t.files[0])==null?void 0:i.path,J(We,e),this.showActive(),this.refresh()}async writeCurrent(e=!0){const t=this.workspace;if(!t)return!1;const s=ge(this.project.name),i=this.folder,n=new Set(this.classes.map(r=>r.name)),o=Object.fromEntries([...this.positions].filter(([r])=>n.has(r)));if(s!==i&&this.projects.some(r=>r!==i&&r.toLowerCase()===s.toLowerCase()))return this.message(d("web_visuobject_ws_taken",this.project.name)),!1;try{return await xn(t,s,this.project,o),i&&i!==s&&this.projects.includes(i)&&await t.remove(i),this.folder=s,this.projects=await is(t),J(We,s),this.markSaved(),e&&this.message(d("web_visuobject_ws_saved",t.name,s),!0),this.refresh(),!0}catch(r){return this.message(d("web_visuobject_ws_failed",String((r==null?void 0:r.message)??r))),!1}}async switchProject(e){if(!(!this.workspace||e===this.folder)&&!(this.isDirty()&&!await this.writeCurrent(!1)))try{await this.loadProject(e)}catch(t){this.message(d("web_visuobject_ws_failed",String((t==null?void 0:t.message)??t)))}}async newProject(e,t,s=!1){var n,o;if(!this.workspace){this.setProject(e,t??((n=e.files[0])==null?void 0:n.path)),e.files.length===0&&!s&&this.editProjectName();return}if(this.isDirty()&&!await this.writeCurrent(!1))return;const i=ns(ge(e.name),this.projects);this.project={...e,name:i},this.folder=i,this.history=[],this.future=[],this.openTabs=[],this.positions.clear(),this.savePositions(),this.active=e.files.some(r=>r.path===t)?t:(o=e.files[0])==null?void 0:o.path,this.showActive(),this.refresh(),await this.writeCurrent(!1)&&(this.message(d("web_visuobject_ws_created",i),!0),e.files.length===0&&!s&&this.editProjectName())}get currentPlace(){const e=this.currentPackage??(this.active?D(this.active):ce(this.project)[0]??"");return{root:U(e),pkg:X(e)}}async newFromWizard(e){var u;const t=this.currentPlace,s=(f,m)=>{let g=f;for(let _=2;m(g);_++)g=f+_;return g},i=await an(e,{roots:ue(this.project),packagesIn:f=>ce(this.project,f).map(X),classes:this.classes,root:t.root,pkg:t.pkg,suggest:f=>f==="project"?ns(d("web_visuobject_project_name"),this.workspace?[...this.projects,this.folder??""]:[]):f==="folder"?s("test",m=>ue(this.project).includes(m)):f==="package"?s(d("web_visuobject_new_package_name"),m=>ce(this.project).includes(re(t.root,m))):this.uniqueClassName(d(f==="class"?"web_visuobject_new_class_name":"web_visuobject_new_interface_name")),check:(f,m,g,_)=>{if(!m)return d("web_visuobject_new_name_missing");if(f==="project")return this.workspace&&this.projects.some(y=>y!==this.folder&&y.toLowerCase()===ge(m).toLowerCase())?d("web_visuobject_ws_taken",m):void 0;if(f==="folder")return!Je(m)||ue(this.project).includes(m)?d("web_visuobject_bad_folder",m):void 0;if(f==="package")return!Mt(m)||ce(this.project).includes(re(g,m))?d("web_visuobject_bad_package",m):void 0;if(!pe.test(m))return d("web_visuobject_bad_name",m);if(this.findClass(m)||this.project.files.some(y=>y.path===le(re(g,_),`${m}.java`)))return d("web_visuobject_new_exists",m);if(m.charAt(0)!==m.charAt(0).toUpperCase())return d("web_visuobject_new_upper")}});if(!i)return;const{name:n,root:o,pkg:r}=i;if(e==="project")return this.newProject({name:n,files:[],packages:[]},void 0,!0);if(this.message(""),e==="folder")return this.currentPackage=re(n,""),this.treeSelection=`root:${n}`,this.open.set(`root:${n}`,!0),this.setProject(vi(this.project,n));if(e==="package"){const f=re(o,n);return this.currentPackage=f,this.treeSelection=`pkg:${f}`,this.open.set(`root:${o}`,!0),this.setProject(mi(this.project,f))}const c=re(o,r),l=le(c,`${n}.java`);this.currentPackage=c,this.selection={cls:n},this.open.set(`root:${o}`,!0),this.open.set(`pkg:${c}`,!0),this.setProject(et(this.project,l,this.sectioned(nn(i.options),n)),l);const h=this.findClass(n);h&&this.showInCode(h),(u=this.canvas.querySelector(`.uml-class[data-class="${CSS.escape(n)}"]`))==null||u.scrollIntoView({block:"nearest",inline:"nearest"})}editProjectName(){this.treeSelection="project",this.renderTree(),this.startEditing(this.tree.querySelector('[data-node="project"] > .vo-row .vo-label'))}renderWorkspace(){const e=this.wsBox;e.hidden=!$t();const t=this.shell.querySelector("[data-action=save]");if(t.dataset.tip=d(this.workspace?"web_visuobject_save_ws_tip":"web_visuobject_save_tip"),e.hidden)return;const s=(i,n,o="text-button",r)=>``;this.workspace?(e.className="vo-ws",e.innerHTML=`${b(this.workspace.name)} ${s("zip",d("web_visuobject_ws_zip"),"text-button",d("web_visuobject_ws_zip_tip"))} ${s("switch",d("web_visuobject_ws_switch"),"text-button")}`):this.pendingFolder?(e.className="vo-ws",e.innerHTML=`${s("reopen",d("web_visuobject_ws_reopen",this.pendingFolder.name),"text-button primary")}${s("switch",d("web_visuobject_ws_switch"),"text-button")}`):se(rt)==="1"?(e.className="vo-ws",e.innerHTML=s("open",d("web_visuobject_ws_choose"),"text-button",d("web_visuobject_ws_hint"))):(e.className="vo-ws ask",e.innerHTML=`

${b(d("web_visuobject_ws_question"))}

${b(d("web_visuobject_ws_hint"))}

diff --git a/website/app/assets/projectZip-D6C7FbQ-.js b/website/app/assets/projectZip-hnnNIFP3.js similarity index 99% rename from website/app/assets/projectZip-D6C7FbQ-.js rename to website/app/assets/projectZip-hnnNIFP3.js index 3e8ea031..7e160f65 100644 --- a/website/app/assets/projectZip-D6C7FbQ-.js +++ b/website/app/assets/projectZip-hnnNIFP3.js @@ -1 +1 @@ -import{p as Br,d as Er,a as mr,i as Gr,b as Qr,c as Vr,u as Lr,n as _r,o as pr,e as br,r as dr,f as re,s as ee}from"./objectApp-BSgp1317.js";import"./index-B8lDfJ72.js";var M=Uint8Array,K=Uint16Array,Tr=Int32Array,hr=new M([0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0,0]),gr=new M([0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13,0,0]),Sr=new M([16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15]),Wr=function(r,e){for(var n=new K(31),a=0;a<31;++a)n[a]=e+=1<>1|(F&21845)<<1;b=(b&52428)>>2|(b&13107)<<2,b=(b&61680)>>4|(b&3855)<<4,Cr[F]=((b&65280)>>8|(b&255)<<8)>>1}var V=(function(r,e,n){for(var a=r.length,f=0,v=new K(e);f>l]=c}else for(s=new K(a),f=0;f>15-r[f]);return s}),d=new M(288);for(var F=0;F<144;++F)d[F]=8;for(var F=144;F<256;++F)d[F]=9;for(var F=256;F<280;++F)d[F]=7;for(var F=280;F<288;++F)d[F]=8;var ir=new M(32);for(var F=0;F<32;++F)ir[F]=5;var ae=V(d,9,0),fe=V(d,9,1),ve=V(ir,5,0),te=V(ir,5,1),xr=function(r){for(var e=r[0],n=1;ne&&(e=r[n]);return e},X=function(r,e,n){var a=e/8|0;return(r[a]|r[a+1]<<8)>>(e&7)&n},yr=function(r,e){var n=e/8|0;return(r[n]|r[n+1]<<8|r[n+2]<<16)>>(e&7)},Ur=function(r){return(r+7)/8|0},lr=function(r,e,n){return(e==null||e<0)&&(e=0),(n==null||n>r.length)&&(n=r.length),new M(r.subarray(e,n))},oe=["unexpected EOF","invalid block type","invalid length/literal","invalid distance","stream finished","no stream handler",,"no callback","invalid UTF-8 data","extra field too long","date not in range 1980-2099","filename too long","stream finishing","invalid zip data"],I=function(r,e,n){var a=new Error(e||oe[r]);if(a.code=r,Error.captureStackTrace&&Error.captureStackTrace(a,I),!n)throw a;return a},ie=function(r,e,n,a){var f=r.length,v=a?a.length:0;if(!f||e.f&&!e.l)return n||new M(0);var i=!n,s=i||e.i!=2,l=e.i;i&&(n=new M(f*3));var c=function(fr){var vr=n.length;if(fr>vr){var nr=new M(Math.max(vr*2,fr));nr.set(n),n=nr}},t=e.f||0,o=e.p||0,u=e.b||0,h=e.l,y=e.d,w=e.m,x=e.n,T=f*8;do{if(!h){t=X(r,o,1);var z=X(r,o+1,3);if(o+=3,z)if(z==1)h=fe,y=te,w=9,x=5;else if(z==2){var U=X(r,o,31)+257,A=X(r,o+10,15)+4,m=U+X(r,o+5,31)+1;o+=14;for(var g=new M(m),B=new M(19),j=0;j>4;if(C<16)g[j++]=C;else{var E=0,k=0;for(C==16?(k=3+X(r,o,3),o+=2,E=g[j-1]):C==17?(k=3+X(r,o,7),o+=3):C==18&&(k=11+X(r,o,127),o+=7);k--;)g[j++]=E}}var W=g.subarray(0,U),J=g.subarray(U);w=xr(W),x=xr(J),h=V(W,w,1),y=V(J,x,1)}else I(1);else{var C=Ur(o)+4,O=r[C-4]|r[C-3]<<8,$=C+O;if($>f){l&&I(0);break}s&&c(u+O),n.set(r.subarray(C,$),u),e.b=u+=O,e.p=o=$*8,e.f=t;continue}if(o>T){l&&I(0);break}}s&&c(u+131072);for(var ar=(1<>4;if(o+=E&15,o>T){l&&I(0);break}if(E||I(2),q<256)n[u++]=q;else if(q==256){L=o,h=null;break}else{var H=q-254;if(q>264){var j=q-257,S=hr[j];H=X(r,o,(1<>4;G||I(3),o+=G&15;var J=ne[rr];if(rr>3){var S=gr[rr];J+=yr(r,o)&(1<T){l&&I(0);break}s&&c(u+131072);var er=u+H;if(u>8},tr=function(r,e,n){n<<=e&7;var a=e/8|0;r[a]|=n,r[a+1]|=n>>8,r[a+2]|=n>>16},Fr=function(r,e){for(var n=[],a=0;au&&(u=v[a].s);var h=new K(u+1),y=Or(n[t-1],h,0);if(y>e){var a=0,w=0,x=y-e,T=1<e)w+=T-(1<>=x;w>0;){var C=v[a].s;h[C]=0&&w;--a){var O=v[a].s;h[O]==e&&(--h[O],++w)}y=e}return{t:new M(h),l:y}},Or=function(r,e,n){return r.s==-1?Math.max(Or(r.l,e,n+1),Or(r.r,e,n+1)):e[r.s]=n},Nr=function(r){for(var e=r.length;e&&!r[--e];);for(var n=new K(++e),a=0,f=r[0],v=1,i=function(l){n[a++]=l},s=1;s<=e;++s)if(r[s]==f&&s!=e)++v;else{if(!f&&v>2){for(;v>138;v-=138)i(32754);v>2&&(i(v>10?v-11<<5|28690:v-3<<5|12305),v=0)}else if(v>3){for(i(f),--v;v>6;v-=6)i(8304);v>2&&(i(v-3<<5|8208),v=0)}for(;v--;)i(f);v=1,f=r[s]}return{c:n.subarray(0,a),n:e}},or=function(r,e){for(var n=0,a=0;a>8,r[f+2]=r[f]^255,r[f+3]=r[f+1]^255;for(var v=0;v4&&!B[Sr[D-1]];--D);var p=c+5<<3,Z=or(f,d)+or(v,ir)+i,P=or(f,u)+or(v,w)+i+14+3*D+or(A,B)+2*A[16]+3*A[17]+7*A[18];if(l>=0&&p<=Z&&p<=P)return Kr(e,t,r.subarray(l,l+c));var E,k,W,J;if(_(e,t,1+(P15&&(_(e,t,q[m]>>5&127),t+=q[m]>>12)}}else E=ae,k=d,W=ve,J=ir;for(var m=0;m255){var H=S>>18&31;tr(e,t,E[H+257]),t+=k[H+257],H>7&&(_(e,t,S>>23&31),t+=hr[H]);var G=S&31;tr(e,t,W[G]),t+=J[G],G>3&&(tr(e,t,S>>5&8191),t+=gr[G])}else tr(e,t,E[S]),t+=k[S]}return tr(e,t,E[256]),t+k[256]},le=new Tr([65540,131080,131088,131104,262176,1048704,1048832,2114560,2117632]),Rr=new M(0),se=function(r,e,n,a,f,v){var i=v.z||r.length,s=new M(a+i+5*(1+Math.ceil(i/7e3))+f),l=s.subarray(a,s.length-f),c=v.l,t=(v.r||0)&7;if(e){t&&(l[0]=v.r>>3);for(var o=le[e-1],u=o>>13,h=o&8191,y=(1<7e3||B>24576)&&(E>423||!c)){t=Dr(r,l,0,O,$,U,m,B,D,g-D,t),B=A=m=0,D=g;for(var k=0;k<286;++k)$[k]=0;for(var k=0;k<30;++k)U[k]=0}var W=2,J=0,ar=h,R=Z-P&32767;if(E>2&&p==C(g-R))for(var L=Math.min(u,E)-1,q=Math.min(32767,g),H=Math.min(258,E);R<=q&&--ar&&Z!=P;){if(r[g+W]==r[g+W-R]){for(var S=0;SW){if(W=S,J=R,S>L)break;for(var G=Math.min(R,S-2),rr=0,k=0;krr&&(rr=ur,P=er)}}}Z=P,P=w[Z],R+=Z-P&32767}if(J){O[B++]=268435456|Mr[W]<<18|Jr[J];var fr=Mr[W]&31,vr=Jr[J]&31;m+=hr[fr]+gr[vr],++$[257+fr],++U[vr],j=g+W,++A}else O[B++]=r[g],++$[r[g]]}}for(g=Math.max(g,j);g=i&&(l[t/8|0]=c,nr=i),t=Kr(l,t+1,r.subarray(g,nr))}v.i=i}return lr(s,0,a+Ur(t)+f)},ue=(function(){for(var r=new Int32Array(256),e=0;e<256;++e){for(var n=e,a=9;--a;)n=(n&1&&-306674912)^n>>>1;r[e]=n}return r})(),ce=function(){var r=-1;return{p:function(e){for(var n=r,a=0;a>>8;r=n},d:function(){return~r}}},he=function(r,e,n,a,f){if(!f&&(f={l:1},e.dictionary)){var v=e.dictionary.subarray(-32768),i=new M(v.length+r.length);i.set(v),i.set(r,v.length),r=i,f.w=v.length}return se(r,e.level==null?6:e.level,e.mem==null?f.l?Math.ceil(Math.max(8,Math.min(13,Math.log(r.length)))*1.5):20:12+e.mem,n,a,f)},Xr=function(r,e){var n={};for(var a in r)n[a]=r[a];for(var a in e)n[a]=e[a];return n},Q=function(r,e){return r[e]|r[e+1]<<8},Y=function(r,e){return(r[e]|r[e+1]<<8|r[e+2]<<16|r[e+3]<<24)>>>0},kr=function(r,e){return Y(r,e)+Y(r,e+4)*4294967296},N=function(r,e,n){for(;n;++e)r[e]=n,n>>>=8};function ge(r,e){return he(r,e||{},0,0)}function we(r,e){return ie(r,{i:2},e&&e.out,e&&e.dictionary)}var Yr=function(r,e,n,a){for(var f in r){var v=r[f],i=e+f,s=a;Array.isArray(v)&&(s=Xr(a,v[1]),v=v[0]),v instanceof M?n[i]=[v,s]:(n[i+="/"]=[new M(0),s],Yr(v,i,n,a))}},Ir=typeof TextEncoder<"u"&&new TextEncoder,Ar=typeof TextDecoder<"u"&&new TextDecoder,me=0;try{Ar.decode(Rr,{stream:!0}),me=1}catch{}var xe=function(r){for(var e="",n=0;;){var a=r[n++],f=(a>127)+(a>223)+(a>239);if(n+f>r.length)return{s:e,r:lr(r,n-1)};f?f==3?(a=((a&15)<<18|(r[n++]&63)<<12|(r[n++]&63)<<6|r[n++]&63)-65536,e+=String.fromCharCode(55296|a>>10,56320|a&1023)):f&1?e+=String.fromCharCode((a&31)<<6|r[n++]&63):e+=String.fromCharCode((a&15)<<12|(r[n++]&63)<<6|r[n++]&63):e+=String.fromCharCode(a)}};function cr(r,e){var n;if(Ir)return Ir.encode(r);for(var a=r.length,f=new M(r.length+(r.length>>1)),v=0,i=function(c){f[v++]=c},n=0;nf.length){var s=new M(v+8+(a-n<<1));s.set(f),f=s}var l=r.charCodeAt(n);l<128||e?i(l):l<2048?(i(192|l>>6),i(128|l&63)):l>55295&&l<57344?(l=65536+(l&1047552)|r.charCodeAt(++n)&1023,i(240|l>>18),i(128|l>>12&63),i(128|l>>6&63),i(128|l&63)):(i(224|l>>12),i(128|l>>6&63),i(128|l&63))}return lr(f,0,v)}function jr(r,e){if(e){for(var n="",a=0;a65535&&I(9),e+=a+4}return e},Pr=function(r,e,n,a,f,v,i,s){var l=a.length,c=n.extra,t=s&&s.length,o=zr(c);N(r,e,i!=null?33639248:67324752),e+=4,i!=null&&(r[e++]=20,r[e++]=n.os),r[e]=20,e+=2,r[e++]=n.flag<<1|(v<0&&8),r[e++]=f&&8,r[e++]=n.compression&255,r[e++]=n.compression>>8;var u=new Date(n.mtime==null?Date.now():n.mtime),h=u.getFullYear()-1980;if((h<0||h>119)&&I(10),N(r,e,h<<25|u.getMonth()+1<<21|u.getDate()<<16|u.getHours()<<11|u.getMinutes()<<5|u.getSeconds()>>1),e+=4,v!=-1&&(N(r,e,n.crc),N(r,e+4,v<0?-v-2:v),N(r,e+8,n.size)),N(r,e+12,l),N(r,e+14,o),e+=16,i!=null&&(N(r,e,t),N(r,e+6,n.attrs),N(r,e+10,i),e+=14),r.set(a,e),e+=l,o)for(var y in c){var w=c[y],x=w.length;N(r,e,+y),N(r,e+2,x),r.set(w,e+4),e+=4+x}return t&&(r.set(s,e),e+=t),e},Se=function(r,e,n,a,f){N(r,e,101010256),N(r,e+8,n),N(r,e+10,n),N(r,e+12,a),N(r,e+16,f)};function Me(r,e){e||(e={});var n={},a=[];Yr(r,"",n,e);var f=0,v=0;for(var i in n){var s=n[i],l=s[0],c=s[1],t=c.level==0?0:8,o=cr(i),u=o.length,h=c.comment,y=h&&cr(h),w=y&&y.length,x=zr(c.extra);u>65535&&I(11);var T=t?ge(l,c):l,z=T.length,C=ce();C.p(l),a.push(Xr(c,{size:l.length,crc:C.d(),c:T,f:o,m:y,u:u!=i.length||y&&h.length!=w,o:f,compression:t})),f+=30+u+x+z,v+=76+2*(u+x)+(w||0)+z}for(var O=new M(v+22),$=f,U=v-f,A=0;A65558)&&I(13);var f=Q(r,a+8);if(!f)return{};var v=Y(r,a+16),i=v==4294967295||f==65535;if(i){var s=Y(r,a-12);i=Y(r,s)==101075792,i&&(f=Y(r,s+32),v=Y(r,s+48))}for(var l=0;l|]/g,"_")||"Projekt",n={};for(const l of r.files)n[`${e}/${br(l.path)}`]=new Uint8Array(cr(l.text));const a=[...r.packages.map(l=>`${e}/${dr(l)}/${re(l).replace(/\./g,"/")}/`),...ee(r).map(l=>`${e}/${l}/`)];for(const l of a)Object.keys(n).some(c=>c.startsWith(l))||(n[l.replace(/\/\/$/,"/")]=new Uint8Array);return(r.uml&&Object.keys(r.uml).length||(f=r.notes)!=null&&f.length||(v=r.objects)!=null&&v.length)&&(n[`${e}/${$r}`]=new Uint8Array(cr(JSON.stringify({format:"visuobject",version:1,uml:r.uml??{},...(i=r.notes)!=null&&i.length?{notes:r.notes}:{},...(s=r.objects)!=null&&s.length?{objects:r.objects}:{}},null,2)))),Me(n,{level:6})}function ze(r,e){var c;const n=Ce(r),a=Object.entries(n).filter(([t])=>/\.java$/i.test(t)&&!t.startsWith("__MACOSX/")).map(([t,o])=>({name:t,text:jr(o)})),f=new Set(Object.keys(n).map(t=>t.split("/")[0])),v=f.size===1&&Object.keys(n).some(t=>t.includes("/"))?[...f][0]:e,i=v!==e,s=Br(v,[]);for(const t of a){const o=Br(v,[{name:t.name.slice(t.name.lastIndexOf("/")+1),text:t.text}]).files[0],u=t.name.split("/").slice(i?1:0,-1),h=Er(o.text).split(".").filter(Boolean),w=u.slice(u.length-h.length).join("/")===h.join("/")?u.slice(0,u.length-h.length).join("/"):"",x=w&&w!==mr&&w.split("/").every(Gr)&&!w.includes(":")?w:mr,T=Qr(Vr(x,Er(o.text)),o.path.slice(o.path.lastIndexOf("/")+1));s.files=[...s.files.filter(z=>z.path!==T),{...o,path:T}],x!==mr&&!((c=s.sourceFolders)!=null&&c.includes(x))&&(s.sourceFolders=[...s.sourceFolders??[],x])}const l=Object.entries(n).find(([t])=>t===$r||t.endsWith(`/${$r}`));if(l)try{const t=JSON.parse(jr(l[1])),o=Lr(t.uml);o&&(s.uml=o);const u=_r(t.notes);u&&(s.notes=u);const h=pr(t.objects);h&&(s.objects=h)}catch{}return s}export{ze as projectFromZip,je as projectToZip}; +import{p as Br,d as Er,a as mr,i as Gr,b as Qr,c as Vr,u as Lr,n as _r,o as pr,e as br,r as dr,f as re,s as ee}from"./objectApp-DkBXkNTX.js";import"./index-DuzNMqv5.js";var M=Uint8Array,K=Uint16Array,Tr=Int32Array,hr=new M([0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0,0]),gr=new M([0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13,0,0]),Sr=new M([16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15]),Wr=function(r,e){for(var n=new K(31),a=0;a<31;++a)n[a]=e+=1<>1|(F&21845)<<1;b=(b&52428)>>2|(b&13107)<<2,b=(b&61680)>>4|(b&3855)<<4,Cr[F]=((b&65280)>>8|(b&255)<<8)>>1}var V=(function(r,e,n){for(var a=r.length,f=0,v=new K(e);f>l]=c}else for(s=new K(a),f=0;f>15-r[f]);return s}),d=new M(288);for(var F=0;F<144;++F)d[F]=8;for(var F=144;F<256;++F)d[F]=9;for(var F=256;F<280;++F)d[F]=7;for(var F=280;F<288;++F)d[F]=8;var ir=new M(32);for(var F=0;F<32;++F)ir[F]=5;var ae=V(d,9,0),fe=V(d,9,1),ve=V(ir,5,0),te=V(ir,5,1),xr=function(r){for(var e=r[0],n=1;ne&&(e=r[n]);return e},X=function(r,e,n){var a=e/8|0;return(r[a]|r[a+1]<<8)>>(e&7)&n},yr=function(r,e){var n=e/8|0;return(r[n]|r[n+1]<<8|r[n+2]<<16)>>(e&7)},Ur=function(r){return(r+7)/8|0},lr=function(r,e,n){return(e==null||e<0)&&(e=0),(n==null||n>r.length)&&(n=r.length),new M(r.subarray(e,n))},oe=["unexpected EOF","invalid block type","invalid length/literal","invalid distance","stream finished","no stream handler",,"no callback","invalid UTF-8 data","extra field too long","date not in range 1980-2099","filename too long","stream finishing","invalid zip data"],I=function(r,e,n){var a=new Error(e||oe[r]);if(a.code=r,Error.captureStackTrace&&Error.captureStackTrace(a,I),!n)throw a;return a},ie=function(r,e,n,a){var f=r.length,v=a?a.length:0;if(!f||e.f&&!e.l)return n||new M(0);var i=!n,s=i||e.i!=2,l=e.i;i&&(n=new M(f*3));var c=function(fr){var vr=n.length;if(fr>vr){var nr=new M(Math.max(vr*2,fr));nr.set(n),n=nr}},t=e.f||0,o=e.p||0,u=e.b||0,h=e.l,y=e.d,w=e.m,x=e.n,T=f*8;do{if(!h){t=X(r,o,1);var z=X(r,o+1,3);if(o+=3,z)if(z==1)h=fe,y=te,w=9,x=5;else if(z==2){var U=X(r,o,31)+257,A=X(r,o+10,15)+4,m=U+X(r,o+5,31)+1;o+=14;for(var g=new M(m),B=new M(19),j=0;j>4;if(C<16)g[j++]=C;else{var E=0,k=0;for(C==16?(k=3+X(r,o,3),o+=2,E=g[j-1]):C==17?(k=3+X(r,o,7),o+=3):C==18&&(k=11+X(r,o,127),o+=7);k--;)g[j++]=E}}var W=g.subarray(0,U),J=g.subarray(U);w=xr(W),x=xr(J),h=V(W,w,1),y=V(J,x,1)}else I(1);else{var C=Ur(o)+4,O=r[C-4]|r[C-3]<<8,$=C+O;if($>f){l&&I(0);break}s&&c(u+O),n.set(r.subarray(C,$),u),e.b=u+=O,e.p=o=$*8,e.f=t;continue}if(o>T){l&&I(0);break}}s&&c(u+131072);for(var ar=(1<>4;if(o+=E&15,o>T){l&&I(0);break}if(E||I(2),q<256)n[u++]=q;else if(q==256){L=o,h=null;break}else{var H=q-254;if(q>264){var j=q-257,S=hr[j];H=X(r,o,(1<>4;G||I(3),o+=G&15;var J=ne[rr];if(rr>3){var S=gr[rr];J+=yr(r,o)&(1<T){l&&I(0);break}s&&c(u+131072);var er=u+H;if(u>8},tr=function(r,e,n){n<<=e&7;var a=e/8|0;r[a]|=n,r[a+1]|=n>>8,r[a+2]|=n>>16},Fr=function(r,e){for(var n=[],a=0;au&&(u=v[a].s);var h=new K(u+1),y=Or(n[t-1],h,0);if(y>e){var a=0,w=0,x=y-e,T=1<e)w+=T-(1<>=x;w>0;){var C=v[a].s;h[C]=0&&w;--a){var O=v[a].s;h[O]==e&&(--h[O],++w)}y=e}return{t:new M(h),l:y}},Or=function(r,e,n){return r.s==-1?Math.max(Or(r.l,e,n+1),Or(r.r,e,n+1)):e[r.s]=n},Nr=function(r){for(var e=r.length;e&&!r[--e];);for(var n=new K(++e),a=0,f=r[0],v=1,i=function(l){n[a++]=l},s=1;s<=e;++s)if(r[s]==f&&s!=e)++v;else{if(!f&&v>2){for(;v>138;v-=138)i(32754);v>2&&(i(v>10?v-11<<5|28690:v-3<<5|12305),v=0)}else if(v>3){for(i(f),--v;v>6;v-=6)i(8304);v>2&&(i(v-3<<5|8208),v=0)}for(;v--;)i(f);v=1,f=r[s]}return{c:n.subarray(0,a),n:e}},or=function(r,e){for(var n=0,a=0;a>8,r[f+2]=r[f]^255,r[f+3]=r[f+1]^255;for(var v=0;v4&&!B[Sr[D-1]];--D);var p=c+5<<3,Z=or(f,d)+or(v,ir)+i,P=or(f,u)+or(v,w)+i+14+3*D+or(A,B)+2*A[16]+3*A[17]+7*A[18];if(l>=0&&p<=Z&&p<=P)return Kr(e,t,r.subarray(l,l+c));var E,k,W,J;if(_(e,t,1+(P15&&(_(e,t,q[m]>>5&127),t+=q[m]>>12)}}else E=ae,k=d,W=ve,J=ir;for(var m=0;m255){var H=S>>18&31;tr(e,t,E[H+257]),t+=k[H+257],H>7&&(_(e,t,S>>23&31),t+=hr[H]);var G=S&31;tr(e,t,W[G]),t+=J[G],G>3&&(tr(e,t,S>>5&8191),t+=gr[G])}else tr(e,t,E[S]),t+=k[S]}return tr(e,t,E[256]),t+k[256]},le=new Tr([65540,131080,131088,131104,262176,1048704,1048832,2114560,2117632]),Rr=new M(0),se=function(r,e,n,a,f,v){var i=v.z||r.length,s=new M(a+i+5*(1+Math.ceil(i/7e3))+f),l=s.subarray(a,s.length-f),c=v.l,t=(v.r||0)&7;if(e){t&&(l[0]=v.r>>3);for(var o=le[e-1],u=o>>13,h=o&8191,y=(1<7e3||B>24576)&&(E>423||!c)){t=Dr(r,l,0,O,$,U,m,B,D,g-D,t),B=A=m=0,D=g;for(var k=0;k<286;++k)$[k]=0;for(var k=0;k<30;++k)U[k]=0}var W=2,J=0,ar=h,R=Z-P&32767;if(E>2&&p==C(g-R))for(var L=Math.min(u,E)-1,q=Math.min(32767,g),H=Math.min(258,E);R<=q&&--ar&&Z!=P;){if(r[g+W]==r[g+W-R]){for(var S=0;SW){if(W=S,J=R,S>L)break;for(var G=Math.min(R,S-2),rr=0,k=0;krr&&(rr=ur,P=er)}}}Z=P,P=w[Z],R+=Z-P&32767}if(J){O[B++]=268435456|Mr[W]<<18|Jr[J];var fr=Mr[W]&31,vr=Jr[J]&31;m+=hr[fr]+gr[vr],++$[257+fr],++U[vr],j=g+W,++A}else O[B++]=r[g],++$[r[g]]}}for(g=Math.max(g,j);g=i&&(l[t/8|0]=c,nr=i),t=Kr(l,t+1,r.subarray(g,nr))}v.i=i}return lr(s,0,a+Ur(t)+f)},ue=(function(){for(var r=new Int32Array(256),e=0;e<256;++e){for(var n=e,a=9;--a;)n=(n&1&&-306674912)^n>>>1;r[e]=n}return r})(),ce=function(){var r=-1;return{p:function(e){for(var n=r,a=0;a>>8;r=n},d:function(){return~r}}},he=function(r,e,n,a,f){if(!f&&(f={l:1},e.dictionary)){var v=e.dictionary.subarray(-32768),i=new M(v.length+r.length);i.set(v),i.set(r,v.length),r=i,f.w=v.length}return se(r,e.level==null?6:e.level,e.mem==null?f.l?Math.ceil(Math.max(8,Math.min(13,Math.log(r.length)))*1.5):20:12+e.mem,n,a,f)},Xr=function(r,e){var n={};for(var a in r)n[a]=r[a];for(var a in e)n[a]=e[a];return n},Q=function(r,e){return r[e]|r[e+1]<<8},Y=function(r,e){return(r[e]|r[e+1]<<8|r[e+2]<<16|r[e+3]<<24)>>>0},kr=function(r,e){return Y(r,e)+Y(r,e+4)*4294967296},N=function(r,e,n){for(;n;++e)r[e]=n,n>>>=8};function ge(r,e){return he(r,e||{},0,0)}function we(r,e){return ie(r,{i:2},e&&e.out,e&&e.dictionary)}var Yr=function(r,e,n,a){for(var f in r){var v=r[f],i=e+f,s=a;Array.isArray(v)&&(s=Xr(a,v[1]),v=v[0]),v instanceof M?n[i]=[v,s]:(n[i+="/"]=[new M(0),s],Yr(v,i,n,a))}},Ir=typeof TextEncoder<"u"&&new TextEncoder,Ar=typeof TextDecoder<"u"&&new TextDecoder,me=0;try{Ar.decode(Rr,{stream:!0}),me=1}catch{}var xe=function(r){for(var e="",n=0;;){var a=r[n++],f=(a>127)+(a>223)+(a>239);if(n+f>r.length)return{s:e,r:lr(r,n-1)};f?f==3?(a=((a&15)<<18|(r[n++]&63)<<12|(r[n++]&63)<<6|r[n++]&63)-65536,e+=String.fromCharCode(55296|a>>10,56320|a&1023)):f&1?e+=String.fromCharCode((a&31)<<6|r[n++]&63):e+=String.fromCharCode((a&15)<<12|(r[n++]&63)<<6|r[n++]&63):e+=String.fromCharCode(a)}};function cr(r,e){var n;if(Ir)return Ir.encode(r);for(var a=r.length,f=new M(r.length+(r.length>>1)),v=0,i=function(c){f[v++]=c},n=0;nf.length){var s=new M(v+8+(a-n<<1));s.set(f),f=s}var l=r.charCodeAt(n);l<128||e?i(l):l<2048?(i(192|l>>6),i(128|l&63)):l>55295&&l<57344?(l=65536+(l&1047552)|r.charCodeAt(++n)&1023,i(240|l>>18),i(128|l>>12&63),i(128|l>>6&63),i(128|l&63)):(i(224|l>>12),i(128|l>>6&63),i(128|l&63))}return lr(f,0,v)}function jr(r,e){if(e){for(var n="",a=0;a65535&&I(9),e+=a+4}return e},Pr=function(r,e,n,a,f,v,i,s){var l=a.length,c=n.extra,t=s&&s.length,o=zr(c);N(r,e,i!=null?33639248:67324752),e+=4,i!=null&&(r[e++]=20,r[e++]=n.os),r[e]=20,e+=2,r[e++]=n.flag<<1|(v<0&&8),r[e++]=f&&8,r[e++]=n.compression&255,r[e++]=n.compression>>8;var u=new Date(n.mtime==null?Date.now():n.mtime),h=u.getFullYear()-1980;if((h<0||h>119)&&I(10),N(r,e,h<<25|u.getMonth()+1<<21|u.getDate()<<16|u.getHours()<<11|u.getMinutes()<<5|u.getSeconds()>>1),e+=4,v!=-1&&(N(r,e,n.crc),N(r,e+4,v<0?-v-2:v),N(r,e+8,n.size)),N(r,e+12,l),N(r,e+14,o),e+=16,i!=null&&(N(r,e,t),N(r,e+6,n.attrs),N(r,e+10,i),e+=14),r.set(a,e),e+=l,o)for(var y in c){var w=c[y],x=w.length;N(r,e,+y),N(r,e+2,x),r.set(w,e+4),e+=4+x}return t&&(r.set(s,e),e+=t),e},Se=function(r,e,n,a,f){N(r,e,101010256),N(r,e+8,n),N(r,e+10,n),N(r,e+12,a),N(r,e+16,f)};function Me(r,e){e||(e={});var n={},a=[];Yr(r,"",n,e);var f=0,v=0;for(var i in n){var s=n[i],l=s[0],c=s[1],t=c.level==0?0:8,o=cr(i),u=o.length,h=c.comment,y=h&&cr(h),w=y&&y.length,x=zr(c.extra);u>65535&&I(11);var T=t?ge(l,c):l,z=T.length,C=ce();C.p(l),a.push(Xr(c,{size:l.length,crc:C.d(),c:T,f:o,m:y,u:u!=i.length||y&&h.length!=w,o:f,compression:t})),f+=30+u+x+z,v+=76+2*(u+x)+(w||0)+z}for(var O=new M(v+22),$=f,U=v-f,A=0;A65558)&&I(13);var f=Q(r,a+8);if(!f)return{};var v=Y(r,a+16),i=v==4294967295||f==65535;if(i){var s=Y(r,a-12);i=Y(r,s)==101075792,i&&(f=Y(r,s+32),v=Y(r,s+48))}for(var l=0;l|]/g,"_")||"Projekt",n={};for(const l of r.files)n[`${e}/${br(l.path)}`]=new Uint8Array(cr(l.text));const a=[...r.packages.map(l=>`${e}/${dr(l)}/${re(l).replace(/\./g,"/")}/`),...ee(r).map(l=>`${e}/${l}/`)];for(const l of a)Object.keys(n).some(c=>c.startsWith(l))||(n[l.replace(/\/\/$/,"/")]=new Uint8Array);return(r.uml&&Object.keys(r.uml).length||(f=r.notes)!=null&&f.length||(v=r.objects)!=null&&v.length)&&(n[`${e}/${$r}`]=new Uint8Array(cr(JSON.stringify({format:"visuobject",version:1,uml:r.uml??{},...(i=r.notes)!=null&&i.length?{notes:r.notes}:{},...(s=r.objects)!=null&&s.length?{objects:r.objects}:{}},null,2)))),Me(n,{level:6})}function ze(r,e){var c;const n=Ce(r),a=Object.entries(n).filter(([t])=>/\.java$/i.test(t)&&!t.startsWith("__MACOSX/")).map(([t,o])=>({name:t,text:jr(o)})),f=new Set(Object.keys(n).map(t=>t.split("/")[0])),v=f.size===1&&Object.keys(n).some(t=>t.includes("/"))?[...f][0]:e,i=v!==e,s=Br(v,[]);for(const t of a){const o=Br(v,[{name:t.name.slice(t.name.lastIndexOf("/")+1),text:t.text}]).files[0],u=t.name.split("/").slice(i?1:0,-1),h=Er(o.text).split(".").filter(Boolean),w=u.slice(u.length-h.length).join("/")===h.join("/")?u.slice(0,u.length-h.length).join("/"):"",x=w&&w!==mr&&w.split("/").every(Gr)&&!w.includes(":")?w:mr,T=Qr(Vr(x,Er(o.text)),o.path.slice(o.path.lastIndexOf("/")+1));s.files=[...s.files.filter(z=>z.path!==T),{...o,path:T}],x!==mr&&!((c=s.sourceFolders)!=null&&c.includes(x))&&(s.sourceFolders=[...s.sourceFolders??[],x])}const l=Object.entries(n).find(([t])=>t===$r||t.endsWith(`/${$r}`));if(l)try{const t=JSON.parse(jr(l[1])),o=Lr(t.uml);o&&(s.uml=o);const u=_r(t.notes);u&&(s.notes=u);const h=pr(t.objects);h&&(s.objects=h)}catch{}return s}export{ze as projectFromZip,je as projectToZip}; diff --git a/website/app/assets/robot3d-RDgYNuY0.js b/website/app/assets/robot3d-K0yfmoba.js similarity index 99% rename from website/app/assets/robot3d-RDgYNuY0.js rename to website/app/assets/robot3d-K0yfmoba.js index 79ee9ab3..ae98cbe1 100644 --- a/website/app/assets/robot3d-RDgYNuY0.js +++ b/website/app/assets/robot3d-K0yfmoba.js @@ -1,4 +1,4 @@ -var gl=Object.defineProperty;var _l=(i,t,e)=>t in i?gl(i,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):i[t]=e;var le=(i,t,e)=>_l(i,typeof t!="symbol"?t+"":t,e);import{C as rn,L as oo}from"./index-B8lDfJ72.js";/** +var gl=Object.defineProperty;var _l=(i,t,e)=>t in i?gl(i,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):i[t]=e;var le=(i,t,e)=>_l(i,typeof t!="symbol"?t+"":t,e);import{C as rn,L as oo}from"./index-DuzNMqv5.js";/** * @license * Copyright 2010-2025 Three.js Authors * SPDX-License-Identifier: MIT diff --git a/website/app/index.html b/website/app/index.html index 6babb012..a779966b 100644 --- a/website/app/index.html +++ b/website/app/index.html @@ -6,7 +6,7 @@ VisuStruct Web - +