diff --git a/CHANGELOG.md b/CHANGELOG.md index 55360adf..e4493b13 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ The format is loosely inspired by Keep a Changelog. ### Changed +- **Web 0.15.2, checklist and quiz always in their own steps:** every lesson in both worlds now ends with its own „Checkliste“ step followed by its own „Wissenstest“ step, after at least one game (Holger: VisuBot lesson 1 step 5 had both in one step before 0.14.33). Three robot lessons still lacked a final quiz step: L2 „Der mBot2“ (game „Sensor oder Aktor?“ moves into its own step before the checklist, the quiz from „Sensoren und Aktoren“ moves to the new „Wissenstest“ and gets six more questions, one per checklist item), L3 „Das Quadrat“ and L27 „Eigene Methoden“ (new „Wissenstest“ with five questions each; the small quizzes inside the steps stay). de/en. A new test (`web/test/lessonEnd.ts`, used by lessons.test.ts and visubotLessons.test.ts) fails if the checklist shares a step with anything else, if the quiz is not alone in the last step, or if no game comes before the checklist. Saved self-assessments in L2 start fresh because steps moved. - **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). diff --git a/web/lessons/de/visubot/01-der-mbot2.md b/web/lessons/de/visubot/01-der-mbot2.md index 0155579b..17a56684 100644 --- a/web/lessons/de/visubot/01-der-mbot2.md +++ b/web/lessons/de/visubot/01-der-mbot2.md @@ -170,78 +170,6 @@ Das Wort kommt vom lateinischen *agere*, „handeln“: Aktoren handeln, Sensore Dein Programm liest die Sensoren und steuert die Aktoren. Das kennst du schon als Eingabe, Verarbeitung und Ausgabe. -::: quiz -? Ordne jedes Teil seiner Aufgabe zu. -→ Hallo mBot2 -= Ultraschallsensor -> misst den Abstand -= Motoren -> bewegen die Räder -= CyberPi -> führt das Programm aus -= Liniensensor -> erkennt eine dunkle Linie -? Welche Teile sind Aktoren? -→ Sensoren und Aktoren -- [x] Motoren -- [ ] Ultraschallsensor -- [x] LEDs -- [ ] Liniensensor -> Aktoren tun etwas, Sensoren messen etwas. -::: - -::: spiel frage -titel: Spiel: Sensor oder Aktor? -intro: Misst das Bauteil etwas, oder tut es etwas? Zehn Runden. -antworten: Sensor | Aktor - -runde: -frage: Der Ultraschallsensor misst, wie weit die Wand weg ist. -richtig: Sensor -> Er misst etwas: den Abstand. - -runde: -frage: Die Motoren drehen die Räder. -richtig: Aktor -> Sie tun etwas: Sie bewegen den mBot2. - -runde: -frage: Die LEDs leuchten rot. -richtig: Aktor -> Leuchten ist etwas tun, nicht messen. - -runde: -frage: Der Liniensensor erkennt das schwarze Klebeband. -richtig: Sensor -> Er misst, wie viel Licht vom Boden zurückkommt. - -runde: -frage: Der Lautsprecher piept. -richtig: Aktor -> Er gibt einen Ton aus. - -runde: -frage: Das Mikrofon hört dein Klatschen. -richtig: Sensor -> Es misst die Lautstärke. - -runde: -frage: Der Bildschirm zeigt „Hallo VisuBot!“. -richtig: Aktor -> Anzeigen ist eine Ausgabe. - -runde: -frage: Taste A merkt, dass du drückst. -richtig: Sensor -> Tasten sind Sensoren: Sie melden, ob sie gedrückt sind. - -runde: -frage: Der Lagesensor merkt, dass der mBot2 schief steht. -richtig: Sensor -> Er misst die Neigung. - -runde: -frage: Die Ringe am Ultraschallsensor leuchten blau. -richtig: Aktor -> Gemein! Das Bauteil ist ein Sensor, aber das Leuchten der Ringe ist eine Ausgabe. -::: - ## Finde die Bauteile Jetzt bist du dran: Klicke im Modell auf das gesuchte Teil. Liegst du richtig, kommt die nächste Frage. @@ -360,6 +288,66 @@ Ist der mBot2 verbunden, erscheint unter der Welt **🔧 mBot2 testen**. Klapp e Ändert sich ein Wert nicht, obwohl du etwas tust, stimmt etwas nicht. Dann sag deiner Lehrkraft Bescheid, bevor du programmierst. +## Spiel: Sensor oder Aktor? + +::: spiel frage +titel: Spiel: Sensor oder Aktor? +intro: Misst das Bauteil etwas, oder tut es etwas? Zehn Runden. +antworten: Sensor | Aktor + +runde: +frage: Der Ultraschallsensor misst, wie weit die Wand weg ist. +richtig: Sensor +> Er misst etwas: den Abstand. + +runde: +frage: Die Motoren drehen die Räder. +richtig: Aktor +> Sie tun etwas: Sie bewegen den mBot2. + +runde: +frage: Die LEDs leuchten rot. +richtig: Aktor +> Leuchten ist etwas tun, nicht messen. + +runde: +frage: Der Liniensensor erkennt das schwarze Klebeband. +richtig: Sensor +> Er misst, wie viel Licht vom Boden zurückkommt. + +runde: +frage: Der Lautsprecher piept. +richtig: Aktor +> Er gibt einen Ton aus. + +runde: +frage: Das Mikrofon hört dein Klatschen. +richtig: Sensor +> Es misst die Lautstärke. + +runde: +frage: Der Bildschirm zeigt „Hallo VisuBot!“. +richtig: Aktor +> Anzeigen ist eine Ausgabe. + +runde: +frage: Taste A merkt, dass du drückst. +richtig: Sensor +> Tasten sind Sensoren: Sie melden, ob sie gedrückt sind. + +runde: +frage: Der Lagesensor merkt, dass der mBot2 schief steht. +richtig: Sensor +> Er misst die Neigung. + +runde: +frage: Die Ringe am Ultraschallsensor leuchten blau. +richtig: Aktor +> Gemein! Das Bauteil ist ein Sensor, aber das Leuchten der Ringe ist eine Ausgabe. +::: + +## 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. ::: checkliste @@ -372,3 +360,57 @@ Schätze dich bei jedem Punkt ehrlich ein: ☂️ noch nicht, ⛅ teilweise, ☀ - Ich kann den echten mBot2 per USB-C verbinden und wieder trennen. → Den echten mBot2 verbinden - Ich kann prüfen, ob alle Sensoren und Aktoren funktionieren. → Den mBot2 testen ::: + +## Wissenstest + +::: quiz +? Ordne jedes Teil seiner Aufgabe zu. +→ Hallo mBot2 += Ultraschallsensor -> misst den Abstand += Motoren -> bewegen die Räder += CyberPi -> führt das Programm aus += Liniensensor -> erkennt eine dunkle Linie +? Welche Teile sind Aktoren? +→ Sensoren und Aktoren +- [x] Motoren +- [ ] Ultraschallsensor +- [x] LEDs +- [ ] Liniensensor +> Aktoren tun etwas, Sensoren messen etwas. +? Wie misst der Ultraschallsensor den Abstand? +→ Der Ultraschallsensor +- [ ] Er fotografiert die Wand. +- [x] Er schickt einen sehr hohen Ton los und wartet auf das Echo. +- [ ] Er tastet die Wand mit seinen blauen Ringen ab. +> Je länger das Echo braucht, desto weiter ist die Wand weg. +? Woran erkennt der Liniensensor eine schwarze Linie? +→ Unter dem Roboter +- [x] Von der schwarzen Linie kommt wenig Licht zurück. +- [ ] Die Linie ist wärmer als der Boden. +- [ ] Er hört, wie die Räder über die Linie rollen. +> Jeder Fühler leuchtet den Boden an. Heller Boden wirft viel Licht zurück, eine schwarze Linie wenig. +? Was tut `mbot.turnRight()`? +→ Befehle für den mBot2 +- [ ] Der mBot2 fährt 10 cm nach rechts. +- [x] Der mBot2 dreht sich um 90° nach rechts. +- [ ] Die rechte LED geht an. +> Ohne Zahl in den Klammern dreht er sich um 90°. `mbot.turnRight(45)` dreht nur 45°. +? Im Struktogramm stehen fünf Kästen `mbot.forward()` untereinander. Wie weit fährt der mBot2 in der Simulation? +→ Erste Fahrt +- [ ] 5 cm +- [x] 50 cm +- [ ] 10 cm +> Jedes `mbot.forward()` fährt 10 cm, also ein Kästchen im Gitter. +? Du bist mit dem echten mBot2 fertig. Was machst du, bevor du das Kabel ziehst? +→ Den echten mBot2 verbinden +- [x] Noch einmal auf **🟢 mBot2** klicken und warten, bis „Bis bald!“ dasteht +- [ ] Den Schiebeschalter auf OFF schieben +- [ ] Nichts, das Kabel darf sofort raus +> Erst nach „Bis bald!“ ist der Anschluss frei. +? Du hältst die Hand vor den Ultraschallsensor, aber unter **🔧 mBot2 testen** ändert sich der Wert nicht. Was tust du? +→ Den mBot2 testen +- [ ] Trotzdem losprogrammieren +- [x] Der Lehrkraft Bescheid sagen, bevor du programmierst +- [ ] Den Wert in der Simulation von Hand ändern +> Ändert sich ein Wert nicht, obwohl du etwas tust, stimmt am Roboter etwas nicht. +::: diff --git a/web/lessons/de/visubot/02-das-quadrat.md b/web/lessons/de/visubot/02-das-quadrat.md index 051c295a..7e58c265 100644 --- a/web/lessons/de/visubot/02-das-quadrat.md +++ b/web/lessons/de/visubot/02-das-quadrat.md @@ -328,3 +328,38 @@ Schätze dich bei jedem Punkt ehrlich ein: ☂️ noch nicht, ⛅ teilweise, ☀ - Ich kann drei Schleifen ineinander schachteln. → Vier Quadrate - Ich kann mein Programm auf den mBot2 übertragen und ohne Kabel mit Taste A starten. → Ohne Kabel fahren ::: + +## Wissenstest + +::: quiz +? Der mBot2 soll noch ohne Schleife eine Seite von 50 cm fahren und sich dann drehen. Welche Kästen brauchst du? +→ Ein Quadrat fahren +- [ ] einmal `mbot.forward()` und einmal `mbot.turnRight()` +- [x] fünfmal `mbot.forward()` und einmal `mbot.turnRight()` +- [ ] fünfmal `mbot.turnRight()` +> Jedes `mbot.forward()` fährt 10 cm, fünf davon sind 50 cm. +? Eine For-Schleife hat den Start `int i = 0`, die Bedingung `i < 5` und den Schritt `i++`. Wie oft läuft sie? +→ Immer das Gleiche +- [ ] 4-mal +- [x] 5-mal +- [ ] 6-mal +> `i` zählt 0, 1, 2, 3, 4. Das sind fünf Durchläufe. +? Warum heißt die Zählvariable der inneren Schleife `j` und nicht auch `i`? +→ Schleife in der Schleife +- [ ] In einem Programm darf jeder Buchstabe nur einmal vorkommen. +- [x] Jede Schleife braucht ihre eigene Zählvariable, sonst kommen sich die beiden in die Quere. +- [ ] `j` zählt schneller als `i`. +> Würden beide mit `i` zählen, würde die innere Schleife die äußere durcheinanderbringen. +? Wie oft führt der mBot2 bei den vier Quadraten `mbot.turnRight()` aus? +→ Vier Quadrate +- [ ] 4-mal +- [ ] 16-mal +- [x] 20-mal +> In jedem Quadrat dreht er sich viermal, das sind 4 · 4 = 16. Dazu kommt nach jedem Quadrat noch eine Drehung: 16 + 4 = 20. +? Dein Programm ist übertragen und das Kabel ist ab. Wie startest du es? +→ Ohne Kabel fahren +- [ ] mit Taste B +- [x] mit Taste A +- [ ] mit **⬆ Übertragen** +> Nach dem Übertragen zeigt der mBot2 **A = Start** und wartet auf Taste A. +::: diff --git a/web/lessons/de/visubot/22-eigene-methoden.md b/web/lessons/de/visubot/22-eigene-methoden.md index 9a72cf29..650a590f 100644 --- a/web/lessons/de/visubot/22-eigene-methoden.md +++ b/web/lessons/de/visubot/22-eigene-methoden.md @@ -297,3 +297,38 @@ Schätze dich bei jedem Punkt ehrlich ein: ☂️ noch nicht, ⛅ teilweise, ☀ - Ich kann eine überladene Methode erkennen und aufrufen. → Gleicher Name, andere Parameter: Überladung - Ich kann eine Methode mit Rückgabewert schreiben. → Methode mit Rückgabe ::: + +## Wissenstest + +::: quiz +? Das Unterprogramm `void quadrat(int seite)` soll ein Quadrat mit 30 cm Seitenlänge fahren. Wie sieht der Aufruf aus? +→ Ein Unterprogramm für das Quadrat +- [ ] `quadrat()` +- [x] `quadrat(30)` +- [ ] `int seite = quadrat(30)` +> Der Wert in den Klammern wird zum Parameter `seite`. Weil `quadrat` nichts zurückgibt, gibt es keine Zuweisung. +? In welcher Methode beginnt ein Java-Programm? +→ Methoden in Java +- [ ] in der ersten Methode der Klasse +- [x] in der Methode `main` +- [ ] in der Methode `quadrat` +> Das Programm beginnt immer in `main`. Von dort werden die anderen Methoden aufgerufen. +? Woran unterscheidet Java die überladenen Methoden `forward()`, `forward(int cm)` und `forward(int wert, String einheit)`? +→ Gleicher Name, andere Parameter: Überladung +- [ ] am Namen +- [x] an der Anzahl und am Typ der Parameter +- [ ] an der Reihenfolge im Programm +> Der Name ist bei allen gleich. Java wählt die Variante, deren Parameter zum Aufruf passen. +? `static int zentimeter(int umdrehungen) { return umdrehungen * 20; }`: Was liegt nach `int strecke = zentimeter(2);` in `strecke`? +→ Methode mit Rückgabe +- [ ] 2 +- [ ] 20 +- [x] 40 +> `return` gibt 2 · 20 = 40 zurück, und dieser Wert landet in `strecke`. +? Was steht in der Kopfzeile einer Methode, die eine ganze Zahl zurückgibt, statt `void`? +→ Methode mit Rückgabe +- [ ] `return` +- [x] `int` +- [ ] `static` +> Statt `void` steht der Datentyp des Ergebnisses in der Kopfzeile. +::: diff --git a/web/lessons/en/visubot/01-der-mbot2.md b/web/lessons/en/visubot/01-der-mbot2.md index 6d3730d9..21bf1a7e 100644 --- a/web/lessons/en/visubot/01-der-mbot2.md +++ b/web/lessons/en/visubot/01-der-mbot2.md @@ -170,78 +170,6 @@ The word comes from the Latin *agere*, “to act”: actuators act, sensors (fro Your program reads the sensors and controls the actuators. You already know this as input, processing and output. -::: quiz -? Match each part to its job. -→ Hello mBot2 -= Ultrasonic sensor -> measures the distance -= Motors -> move the wheels -= CyberPi -> runs the program -= Line sensor -> detects a dark line -? Which parts are actuators? -→ Sensors and actuators -- [x] Motors -- [ ] Ultrasonic sensor -- [x] LEDs -- [ ] Line sensor -> Actuators do something, sensors measure something. -::: - -::: spiel frage -titel: Game: sensor or actuator? -intro: Does the part measure something, or does it do something? Ten rounds. -antworten: Sensor | Actuator - -runde: -frage: The ultrasonic sensor measures how far away the wall is. -richtig: Sensor -> It measures something: the distance. - -runde: -frage: The motors turn the wheels. -richtig: Actuator -> They do something: they move the mBot2. - -runde: -frage: The LEDs glow red. -richtig: Actuator -> Glowing is doing something, not measuring. - -runde: -frage: The line sensor recognises the black tape. -richtig: Sensor -> It measures how much light comes back from the floor. - -runde: -frage: The speaker beeps. -richtig: Actuator -> It outputs a sound. - -runde: -frage: The microphone hears you clap. -richtig: Sensor -> It measures the loudness. - -runde: -frage: The screen shows “Hello VisuBot!”. -richtig: Actuator -> Showing something is an output. - -runde: -frage: Button A notices that you press it. -richtig: Sensor -> Buttons are sensors: they report whether they are pressed. - -runde: -frage: The motion sensor notices that the mBot2 is tilted. -richtig: Sensor -> It measures the tilt. - -runde: -frage: The rings on the ultrasonic sensor glow blue. -richtig: Actuator -> Tricky! The part is a sensor, but the glowing rings are an output. -::: - ## Find the parts Your turn: click the part you are looking for in the model. If you are right, the next question appears. @@ -360,6 +288,66 @@ When the mBot2 is connected, **🔧 Test the mBot2** appears below the world. Op If a value does not change although you do something, something is wrong. Then tell your teacher before you start programming. +## Game: Sensor or actuator? + +::: spiel frage +titel: Game: sensor or actuator? +intro: Does the part measure something, or does it do something? Ten rounds. +antworten: Sensor | Actuator + +runde: +frage: The ultrasonic sensor measures how far away the wall is. +richtig: Sensor +> It measures something: the distance. + +runde: +frage: The motors turn the wheels. +richtig: Actuator +> They do something: they move the mBot2. + +runde: +frage: The LEDs glow red. +richtig: Actuator +> Glowing is doing something, not measuring. + +runde: +frage: The line sensor recognises the black tape. +richtig: Sensor +> It measures how much light comes back from the floor. + +runde: +frage: The speaker beeps. +richtig: Actuator +> It outputs a sound. + +runde: +frage: The microphone hears you clap. +richtig: Sensor +> It measures the loudness. + +runde: +frage: The screen shows “Hello VisuBot!”. +richtig: Actuator +> Showing something is an output. + +runde: +frage: Button A notices that you press it. +richtig: Sensor +> Buttons are sensors: they report whether they are pressed. + +runde: +frage: The motion sensor notices that the mBot2 is tilted. +richtig: Sensor +> It measures the tilt. + +runde: +frage: The rings on the ultrasonic sensor glow blue. +richtig: Actuator +> Tricky! The part is a sensor, but the glowing rings are an output. +::: + +## 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. ::: checkliste @@ -372,3 +360,57 @@ Rate yourself honestly for each point: ☂️ not yet, ⛅ partly, ☀️ I can - I can connect the real mBot2 with USB-C and disconnect it again. → Connecting the real mBot2 - I can check that all sensors and actuators work. → Testing the mBot2 ::: + +## Quiz + +::: quiz +? Match each part to its job. +→ Hello mBot2 += Ultrasonic sensor -> measures the distance += Motors -> move the wheels += CyberPi -> runs the program += Line sensor -> detects a dark line +? Which parts are actuators? +→ Sensors and actuators +- [x] Motors +- [ ] Ultrasonic sensor +- [x] LEDs +- [ ] Line sensor +> Actuators do something, sensors measure something. +? How does the ultrasonic sensor measure the distance? +→ The ultrasonic sensor +- [ ] It takes a photo of the wall. +- [x] It sends out a very high sound and waits for the echo. +- [ ] It feels the wall with its blue rings. +> The longer the echo takes, the further away the wall is. +? How does the line sensor detect a black line? +→ Under the robot +- [x] Little light comes back from the black line. +- [ ] The line is warmer than the floor. +- [ ] It hears the wheels rolling over the line. +> Each feeler shines light on the floor. A light floor reflects a lot of light, a black line only a little. +? What does `mbot.turnRight()` do? +→ Commands for the mBot2 +- [ ] The mBot2 drives 10 cm to the right. +- [x] The mBot2 turns 90° to the right. +- [ ] The right LED switches on. +> With no number in the brackets it turns 90°. `mbot.turnRight(45)` turns only 45°. +? The structure chart has five boxes `mbot.forward()` one below the other. How far does the mBot2 drive in the simulation? +→ First drive +- [ ] 5 cm +- [x] 50 cm +- [ ] 10 cm +> Each `mbot.forward()` drives 10 cm, which is one square of the grid. +? You have finished with the real mBot2. What do you do before you pull out the cable? +→ Connecting the real mBot2 +- [x] Click **🟢 mBot2** once more and wait until “Bis bald!” appears +- [ ] Push the slide switch to OFF +- [ ] Nothing, the cable can come out right away +> Only after “Bis bald!” is the port free. +? You hold your hand in front of the ultrasonic sensor, but the value under **🔧 Test the mBot2** does not change. What do you do? +→ Testing the mBot2 +- [ ] Start programming anyway +- [x] Tell your teacher before you start programming +- [ ] Change the value in the simulation by hand +> If a value does not change although you do something, something is wrong with the robot. +::: diff --git a/web/lessons/en/visubot/02-das-quadrat.md b/web/lessons/en/visubot/02-das-quadrat.md index a28953ff..d11d4912 100644 --- a/web/lessons/en/visubot/02-das-quadrat.md +++ b/web/lessons/en/visubot/02-das-quadrat.md @@ -328,3 +328,38 @@ Rate yourself honestly for each point: ☂️ not yet, ⛅ partly, ☀️ I can - I can nest three loops. → Four squares - I can upload my program to the mBot2 and start it with button A without a cable. → Driving without a cable ::: + +## Quiz + +::: quiz +? Still without a loop, the mBot2 should drive one side of 50 cm and then turn. Which boxes do you need? +→ Driving a square +- [ ] one `mbot.forward()` and one `mbot.turnRight()` +- [x] five `mbot.forward()` and one `mbot.turnRight()` +- [ ] five `mbot.turnRight()` +> Each `mbot.forward()` drives 10 cm, five of them are 50 cm. +? A for loop has the start `int i = 0`, the condition `i < 5` and the step `i++`. How often does it run? +→ Always the same +- [ ] 4 times +- [x] 5 times +- [ ] 6 times +> `i` counts 0, 1, 2, 3, 4. That is five runs. +? Why is the counter of the inner loop called `j` and not `i` as well? +→ A loop in a loop +- [ ] Each letter may only appear once in a program. +- [x] Each loop needs its own counter, otherwise the two get in each other's way. +- [ ] `j` counts faster than `i`. +> If both counted with `i`, the inner loop would mix up the outer one. +? How often does the mBot2 run `mbot.turnRight()` for the four squares? +→ Four squares +- [ ] 4 times +- [ ] 16 times +- [x] 20 times +> In each square it turns four times, that is 4 · 4 = 16. After each square there is one more turn: 16 + 4 = 20. +? Your program has been transferred and the cable is out. How do you start it? +→ Driving without a cable +- [ ] with button B +- [x] with button A +- [ ] with **⬆ Transfer** +> After the transfer the mBot2 shows **A = Start** and waits for button A. +::: diff --git a/web/lessons/en/visubot/22-eigene-methoden.md b/web/lessons/en/visubot/22-eigene-methoden.md index ccaa5983..2980f731 100644 --- a/web/lessons/en/visubot/22-eigene-methoden.md +++ b/web/lessons/en/visubot/22-eigene-methoden.md @@ -297,3 +297,38 @@ Rate yourself honestly for each point: ☂️ not yet, ⛅ partly, ☀️ I can - I can recognise and call an overloaded method. → Same name, different parameters: overloading - I can write a method with a return value. → A method with a return value ::: + +## Quiz + +::: quiz +? The subprogram `void quadrat(int seite)` should drive a square with sides of 30 cm. What does the call look like? +→ A subprogram for the square +- [ ] `quadrat()` +- [x] `quadrat(30)` +- [ ] `int seite = quadrat(30)` +> The value in the brackets becomes the parameter `seite`. Because `quadrat` returns nothing, there is no assignment. +? In which method does a Java program start? +→ Methods in Java +- [ ] in the first method of the class +- [x] in the method `main` +- [ ] in the method `quadrat` +> The program always starts in `main`. The other methods are called from there. +? How does Java tell the overloaded methods `forward()`, `forward(int cm)` and `forward(int wert, String einheit)` apart? +→ Same name, different parameters: overloading +- [ ] by their name +- [x] by the number and type of the parameters +- [ ] by their order in the program +> The name is the same for all of them. Java chooses the variant whose parameters fit the call. +? `static int zentimeter(int umdrehungen) { return umdrehungen * 20; }`: What is in `strecke` after `int strecke = zentimeter(2);`? +→ A method with a return value +- [ ] 2 +- [ ] 20 +- [x] 40 +> `return` gives back 2 · 20 = 40, and this value ends up in `strecke`. +? A method returns a whole number. What is written in its header instead of `void`? +→ A method with a return value +- [ ] `return` +- [x] `int` +- [ ] `static` +> Instead of `void`, the header names the data type of the result. +::: diff --git a/web/package-lock.json b/web/package-lock.json index 131caa5a..478b096c 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -1,6 +1,6 @@ { "name": "visustruct-web", - "version": "0.15.1", + "version": "0.15.2", "lockfileVersion": 3, "requires": true, "packages": { diff --git a/web/package.json b/web/package.json index 4a6bd39b..da538a4d 100644 --- a/web/package.json +++ b/web/package.json @@ -1,7 +1,7 @@ { "name": "visustruct-web", "private": true, - "version": "0.15.1", + "version": "0.15.2", "type": "module", "scripts": { "dev": "vite", diff --git a/web/test/lessonEnd.ts b/web/test/lessonEnd.ts new file mode 100644 index 00000000..e1657546 --- /dev/null +++ b/web/test/lessonEnd.ts @@ -0,0 +1,24 @@ +import type { Lesson } from '../src/learn/lessonFormat' + +const GAMES = ['game', 'roundGame', 'rescueGame', 'driveGame', 'crosswordGame'] + +/** + * Jede Lektion endet so (Holger 2026-11-03): vorher mindestens ein Spiel, dann die Checkliste, zuletzt der Wissenstest. Checkliste und Wissenstest stehen nie im selben Schritt und nie zusammen mit anderem Inhalt. + * Liefert die Verstöße als lesbare Sätze, leer heißt alles in Ordnung. + */ +export function lessonEndProblems(lesson: Lesson): string[] { + const kinds = lesson.steps.map((s) => s.blocks.map((b) => b.kind as string)) + const where = (i: number) => `${lesson.id} / ${lesson.steps[i]?.title ?? '–'}` + const lists = kinds.flatMap((k, i) => (k.includes('checklist') ? [i] : [])) + if (lists.length !== 1) return [`${lesson.id}: ${lists.length} Checklisten statt einer`] + const ci = lists[0] + const last = kinds.length - 1 + const only = (i: number, kind: string) => kinds[i].includes(kind) && kinds[i].every((k) => k === kind || k === 'markdown') + const problems: string[] = [] + if (!only(ci, 'checklist')) problems.push(`${where(ci)}: Im Schritt der Checkliste steht noch anderes (${kinds[ci].join(', ')})`) + if (ci !== last - 1) problems.push(`${where(ci)}: Nach der Checkliste muss genau ein Schritt folgen, der Wissenstest`) + if (!only(last, 'quiz')) problems.push(`${where(last)}: Der letzte Schritt muss der Wissenstest sein, nur mit Fragen (${kinds[last].join(', ')})`) + const games = kinds.flatMap((k, i) => (k.some((x) => GAMES.includes(x)) ? [i] : [])) + if (!games.some((i) => i < ci)) problems.push(`${lesson.id}: Vor der Checkliste fehlt ein Spiel`) + return problems +} diff --git a/web/test/lessons.test.ts b/web/test/lessons.test.ts index f6af38a0..d7173957 100644 --- a/web/test/lessons.test.ts +++ b/web/test/lessons.test.ts @@ -15,6 +15,7 @@ import { clozeAnswerRight, clozeGaps, type Cloze } from '../src/learn/cloze' import { papFits, papLayout, parsePap } from '../src/learn/pap' import { bombParts, parseRoundGame, parseSwingWindow, simulate } from '../src/learn/roundGame' +import { lessonEndProblems } from './lessonEnd' const allBlocks = (): { where: string; block: Block }[] => [ ...lessons.flatMap((l) => l.steps.flatMap((s) => s.blocks.map((block) => ({ where: `${l.id} / ${s.title}`, block })))), ...tasks.flatMap((t) => t.blocks.map((block) => ({ where: t.id, block }))), @@ -42,6 +43,10 @@ describe.each(contentLanguages)('Lernbereich: Inhalte (%s)', (lang) => { } }) + it('jede Lektion endet mit eigenen Schritten für Checkliste und Wissenstest', () => { + expect(lessons.flatMap(lessonEndProblems)).toEqual([]) + }) + it('die Checkliste steht in einem eigenen Schritt „Checkliste“', () => { const title = { de: 'Checkliste', en: 'Checklist', pt: 'Lista de verificação' }[lang] for (const lesson of lessons) { diff --git a/web/test/visubotLessons.test.ts b/web/test/visubotLessons.test.ts index 3987f10e..eb8fa79f 100644 --- a/web/test/visubotLessons.test.ts +++ b/web/test/visubotLessons.test.ts @@ -10,6 +10,7 @@ import { documentFromJava, plainLiveJava } from '../src/core/liveSource' import { isMBotPart, MBOT_PARTS } from '../src/core/mbot' /** Unterprogramme einer Übung (`unterprogramm:`) für Aufrufe in der Musterlösung */ +import { lessonEndProblems } from './lessonEnd' const resolver = (ex: Exercise) => { const subs = ex.subprograms.map((f) => diagram(f)!) return (name: string) => subs.find((s) => subprogramName(s.caption).toLowerCase() === subprogramName(name).toLowerCase()) @@ -129,6 +130,10 @@ describe.each(['de', 'en'] as const)('VisuBot-Lektionen (%s)', (lang) => { } }) + it('jede Roboter-Lektion endet mit eigenen Schritten für Checkliste und Wissenstest', () => { + expect(robotLessons().flatMap(lessonEndProblems)).toEqual([]) + }) + it('Checklisten verweisen auf Schritte', () => { for (const l of robotLessons()) for (const s of l.steps) diff --git a/website/app/assets/flowApp-RdEaBhPZ.js b/website/app/assets/flowApp-DSAsXJlY.js similarity index 99% rename from website/app/assets/flowApp-RdEaBhPZ.js rename to website/app/assets/flowApp-DSAsXJlY.js index 011a9064..de264848 100644 --- a/website/app/assets/flowApp-RdEaBhPZ.js +++ b/website/app/assets/flowApp-DSAsXJlY.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-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(` +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-BV1XwwqD.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.1"))} + ${w(h("web_about_version_fmt").replace("%@","0.15.2"))}
diff --git a/website/app/assets/index-DuzNMqv5.js b/website/app/assets/index-BV1XwwqD.js similarity index 99% rename from website/app/assets/index-DuzNMqv5.js rename to website/app/assets/index-BV1XwwqD.js index dc9ce651..4400f7b5 100644 --- a/website/app/assets/index-DuzNMqv5.js +++ b/website/app/assets/index-BV1XwwqD.js @@ -41582,78 +41582,6 @@ Das Wort kommt vom lateinischen *agere*, „handeln“: Aktoren handeln, Sensore Dein Programm liest die Sensoren und steuert die Aktoren. Das kennst du schon als Eingabe, Verarbeitung und Ausgabe. -::: quiz -? Ordne jedes Teil seiner Aufgabe zu. -→ Hallo mBot2 -= Ultraschallsensor -> misst den Abstand -= Motoren -> bewegen die Räder -= CyberPi -> führt das Programm aus -= Liniensensor -> erkennt eine dunkle Linie -? Welche Teile sind Aktoren? -→ Sensoren und Aktoren -- [x] Motoren -- [ ] Ultraschallsensor -- [x] LEDs -- [ ] Liniensensor -> Aktoren tun etwas, Sensoren messen etwas. -::: - -::: spiel frage -titel: Spiel: Sensor oder Aktor? -intro: Misst das Bauteil etwas, oder tut es etwas? Zehn Runden. -antworten: Sensor | Aktor - -runde: -frage: Der Ultraschallsensor misst, wie weit die Wand weg ist. -richtig: Sensor -> Er misst etwas: den Abstand. - -runde: -frage: Die Motoren drehen die Räder. -richtig: Aktor -> Sie tun etwas: Sie bewegen den mBot2. - -runde: -frage: Die LEDs leuchten rot. -richtig: Aktor -> Leuchten ist etwas tun, nicht messen. - -runde: -frage: Der Liniensensor erkennt das schwarze Klebeband. -richtig: Sensor -> Er misst, wie viel Licht vom Boden zurückkommt. - -runde: -frage: Der Lautsprecher piept. -richtig: Aktor -> Er gibt einen Ton aus. - -runde: -frage: Das Mikrofon hört dein Klatschen. -richtig: Sensor -> Es misst die Lautstärke. - -runde: -frage: Der Bildschirm zeigt „Hallo VisuBot!“. -richtig: Aktor -> Anzeigen ist eine Ausgabe. - -runde: -frage: Taste A merkt, dass du drückst. -richtig: Sensor -> Tasten sind Sensoren: Sie melden, ob sie gedrückt sind. - -runde: -frage: Der Lagesensor merkt, dass der mBot2 schief steht. -richtig: Sensor -> Er misst die Neigung. - -runde: -frage: Die Ringe am Ultraschallsensor leuchten blau. -richtig: Aktor -> Gemein! Das Bauteil ist ein Sensor, aber das Leuchten der Ringe ist eine Ausgabe. -::: - ## Finde die Bauteile Jetzt bist du dran: Klicke im Modell auf das gesuchte Teil. Liegst du richtig, kommt die nächste Frage. @@ -41772,6 +41700,66 @@ Ist der mBot2 verbunden, erscheint unter der Welt **🔧 mBot2 testen**. Klapp e Ändert sich ein Wert nicht, obwohl du etwas tust, stimmt etwas nicht. Dann sag deiner Lehrkraft Bescheid, bevor du programmierst. +## Spiel: Sensor oder Aktor? + +::: spiel frage +titel: Spiel: Sensor oder Aktor? +intro: Misst das Bauteil etwas, oder tut es etwas? Zehn Runden. +antworten: Sensor | Aktor + +runde: +frage: Der Ultraschallsensor misst, wie weit die Wand weg ist. +richtig: Sensor +> Er misst etwas: den Abstand. + +runde: +frage: Die Motoren drehen die Räder. +richtig: Aktor +> Sie tun etwas: Sie bewegen den mBot2. + +runde: +frage: Die LEDs leuchten rot. +richtig: Aktor +> Leuchten ist etwas tun, nicht messen. + +runde: +frage: Der Liniensensor erkennt das schwarze Klebeband. +richtig: Sensor +> Er misst, wie viel Licht vom Boden zurückkommt. + +runde: +frage: Der Lautsprecher piept. +richtig: Aktor +> Er gibt einen Ton aus. + +runde: +frage: Das Mikrofon hört dein Klatschen. +richtig: Sensor +> Es misst die Lautstärke. + +runde: +frage: Der Bildschirm zeigt „Hallo VisuBot!“. +richtig: Aktor +> Anzeigen ist eine Ausgabe. + +runde: +frage: Taste A merkt, dass du drückst. +richtig: Sensor +> Tasten sind Sensoren: Sie melden, ob sie gedrückt sind. + +runde: +frage: Der Lagesensor merkt, dass der mBot2 schief steht. +richtig: Sensor +> Er misst die Neigung. + +runde: +frage: Die Ringe am Ultraschallsensor leuchten blau. +richtig: Aktor +> Gemein! Das Bauteil ist ein Sensor, aber das Leuchten der Ringe ist eine Ausgabe. +::: + +## 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. ::: checkliste @@ -41784,6 +41772,60 @@ Schätze dich bei jedem Punkt ehrlich ein: ☂️ noch nicht, ⛅ teilweise, ☀ - Ich kann den echten mBot2 per USB-C verbinden und wieder trennen. → Den echten mBot2 verbinden - Ich kann prüfen, ob alle Sensoren und Aktoren funktionieren. → Den mBot2 testen ::: + +## Wissenstest + +::: quiz +? Ordne jedes Teil seiner Aufgabe zu. +→ Hallo mBot2 += Ultraschallsensor -> misst den Abstand += Motoren -> bewegen die Räder += CyberPi -> führt das Programm aus += Liniensensor -> erkennt eine dunkle Linie +? Welche Teile sind Aktoren? +→ Sensoren und Aktoren +- [x] Motoren +- [ ] Ultraschallsensor +- [x] LEDs +- [ ] Liniensensor +> Aktoren tun etwas, Sensoren messen etwas. +? Wie misst der Ultraschallsensor den Abstand? +→ Der Ultraschallsensor +- [ ] Er fotografiert die Wand. +- [x] Er schickt einen sehr hohen Ton los und wartet auf das Echo. +- [ ] Er tastet die Wand mit seinen blauen Ringen ab. +> Je länger das Echo braucht, desto weiter ist die Wand weg. +? Woran erkennt der Liniensensor eine schwarze Linie? +→ Unter dem Roboter +- [x] Von der schwarzen Linie kommt wenig Licht zurück. +- [ ] Die Linie ist wärmer als der Boden. +- [ ] Er hört, wie die Räder über die Linie rollen. +> Jeder Fühler leuchtet den Boden an. Heller Boden wirft viel Licht zurück, eine schwarze Linie wenig. +? Was tut \`mbot.turnRight()\`? +→ Befehle für den mBot2 +- [ ] Der mBot2 fährt 10 cm nach rechts. +- [x] Der mBot2 dreht sich um 90° nach rechts. +- [ ] Die rechte LED geht an. +> Ohne Zahl in den Klammern dreht er sich um 90°. \`mbot.turnRight(45)\` dreht nur 45°. +? Im Struktogramm stehen fünf Kästen \`mbot.forward()\` untereinander. Wie weit fährt der mBot2 in der Simulation? +→ Erste Fahrt +- [ ] 5 cm +- [x] 50 cm +- [ ] 10 cm +> Jedes \`mbot.forward()\` fährt 10 cm, also ein Kästchen im Gitter. +? Du bist mit dem echten mBot2 fertig. Was machst du, bevor du das Kabel ziehst? +→ Den echten mBot2 verbinden +- [x] Noch einmal auf **🟢 mBot2** klicken und warten, bis „Bis bald!“ dasteht +- [ ] Den Schiebeschalter auf OFF schieben +- [ ] Nichts, das Kabel darf sofort raus +> Erst nach „Bis bald!“ ist der Anschluss frei. +? Du hältst die Hand vor den Ultraschallsensor, aber unter **🔧 mBot2 testen** ändert sich der Wert nicht. Was tust du? +→ Den mBot2 testen +- [ ] Trotzdem losprogrammieren +- [x] Der Lehrkraft Bescheid sagen, bevor du programmierst +- [ ] Den Wert in der Simulation von Hand ändern +> Ändert sich ein Wert nicht, obwohl du etwas tust, stimmt am Roboter etwas nicht. +::: `,Ow=`--- titel: Das Quadrat bereich: Losfahren @@ -42114,6 +42156,41 @@ Schätze dich bei jedem Punkt ehrlich ein: ☂️ noch nicht, ⛅ teilweise, ☀ - Ich kann drei Schleifen ineinander schachteln. → Vier Quadrate - Ich kann mein Programm auf den mBot2 übertragen und ohne Kabel mit Taste A starten. → Ohne Kabel fahren ::: + +## Wissenstest + +::: quiz +? Der mBot2 soll noch ohne Schleife eine Seite von 50 cm fahren und sich dann drehen. Welche Kästen brauchst du? +→ Ein Quadrat fahren +- [ ] einmal \`mbot.forward()\` und einmal \`mbot.turnRight()\` +- [x] fünfmal \`mbot.forward()\` und einmal \`mbot.turnRight()\` +- [ ] fünfmal \`mbot.turnRight()\` +> Jedes \`mbot.forward()\` fährt 10 cm, fünf davon sind 50 cm. +? Eine For-Schleife hat den Start \`int i = 0\`, die Bedingung \`i < 5\` und den Schritt \`i++\`. Wie oft läuft sie? +→ Immer das Gleiche +- [ ] 4-mal +- [x] 5-mal +- [ ] 6-mal +> \`i\` zählt 0, 1, 2, 3, 4. Das sind fünf Durchläufe. +? Warum heißt die Zählvariable der inneren Schleife \`j\` und nicht auch \`i\`? +→ Schleife in der Schleife +- [ ] In einem Programm darf jeder Buchstabe nur einmal vorkommen. +- [x] Jede Schleife braucht ihre eigene Zählvariable, sonst kommen sich die beiden in die Quere. +- [ ] \`j\` zählt schneller als \`i\`. +> Würden beide mit \`i\` zählen, würde die innere Schleife die äußere durcheinanderbringen. +? Wie oft führt der mBot2 bei den vier Quadraten \`mbot.turnRight()\` aus? +→ Vier Quadrate +- [ ] 4-mal +- [ ] 16-mal +- [x] 20-mal +> In jedem Quadrat dreht er sich viermal, das sind 4 · 4 = 16. Dazu kommt nach jedem Quadrat noch eine Drehung: 16 + 4 = 20. +? Dein Programm ist übertragen und das Kabel ist ab. Wie startest du es? +→ Ohne Kabel fahren +- [ ] mit Taste B +- [x] mit Taste A +- [ ] mit **⬆ Übertragen** +> Nach dem Übertragen zeigt der mBot2 **A = Start** und wartet auf Taste A. +::: `,Mw=`--- titel: Variablen und Ausgabe bereich: Losfahren @@ -47082,6 +47159,41 @@ Schätze dich bei jedem Punkt ehrlich ein: ☂️ noch nicht, ⛅ teilweise, ☀ - Ich kann eine überladene Methode erkennen und aufrufen. → Gleicher Name, andere Parameter: Überladung - Ich kann eine Methode mit Rückgabewert schreiben. → Methode mit Rückgabe ::: + +## Wissenstest + +::: quiz +? Das Unterprogramm \`void quadrat(int seite)\` soll ein Quadrat mit 30 cm Seitenlänge fahren. Wie sieht der Aufruf aus? +→ Ein Unterprogramm für das Quadrat +- [ ] \`quadrat()\` +- [x] \`quadrat(30)\` +- [ ] \`int seite = quadrat(30)\` +> Der Wert in den Klammern wird zum Parameter \`seite\`. Weil \`quadrat\` nichts zurückgibt, gibt es keine Zuweisung. +? In welcher Methode beginnt ein Java-Programm? +→ Methoden in Java +- [ ] in der ersten Methode der Klasse +- [x] in der Methode \`main\` +- [ ] in der Methode \`quadrat\` +> Das Programm beginnt immer in \`main\`. Von dort werden die anderen Methoden aufgerufen. +? Woran unterscheidet Java die überladenen Methoden \`forward()\`, \`forward(int cm)\` und \`forward(int wert, String einheit)\`? +→ Gleicher Name, andere Parameter: Überladung +- [ ] am Namen +- [x] an der Anzahl und am Typ der Parameter +- [ ] an der Reihenfolge im Programm +> Der Name ist bei allen gleich. Java wählt die Variante, deren Parameter zum Aufruf passen. +? \`static int zentimeter(int umdrehungen) { return umdrehungen * 20; }\`: Was liegt nach \`int strecke = zentimeter(2);\` in \`strecke\`? +→ Methode mit Rückgabe +- [ ] 2 +- [ ] 20 +- [x] 40 +> \`return\` gibt 2 · 20 = 40 zurück, und dieser Wert landet in \`strecke\`. +? Was steht in der Kopfzeile einer Methode, die eine ganze Zahl zurückgibt, statt \`void\`? +→ Methode mit Rückgabe +- [ ] \`return\` +- [x] \`int\` +- [ ] \`static\` +> Statt \`void\` steht der Datentyp des Ergebnisses in der Kopfzeile. +::: `,s9=`## 🤖 mBot2-Befehle Ein Befehl sagt dem mBot2, was er **tun** soll. Jeder Befehl beginnt mit \`mbot.\` und endet mit Klammern. In die Klammern schreibst du oft eine Zahl. @@ -47581,78 +47693,6 @@ The word comes from the Latin *agere*, “to act”: actuators act, sensors (fro Your program reads the sensors and controls the actuators. You already know this as input, processing and output. -::: quiz -? Match each part to its job. -→ Hello mBot2 -= Ultrasonic sensor -> measures the distance -= Motors -> move the wheels -= CyberPi -> runs the program -= Line sensor -> detects a dark line -? Which parts are actuators? -→ Sensors and actuators -- [x] Motors -- [ ] Ultrasonic sensor -- [x] LEDs -- [ ] Line sensor -> Actuators do something, sensors measure something. -::: - -::: spiel frage -titel: Game: sensor or actuator? -intro: Does the part measure something, or does it do something? Ten rounds. -antworten: Sensor | Actuator - -runde: -frage: The ultrasonic sensor measures how far away the wall is. -richtig: Sensor -> It measures something: the distance. - -runde: -frage: The motors turn the wheels. -richtig: Actuator -> They do something: they move the mBot2. - -runde: -frage: The LEDs glow red. -richtig: Actuator -> Glowing is doing something, not measuring. - -runde: -frage: The line sensor recognises the black tape. -richtig: Sensor -> It measures how much light comes back from the floor. - -runde: -frage: The speaker beeps. -richtig: Actuator -> It outputs a sound. - -runde: -frage: The microphone hears you clap. -richtig: Sensor -> It measures the loudness. - -runde: -frage: The screen shows “Hello VisuBot!”. -richtig: Actuator -> Showing something is an output. - -runde: -frage: Button A notices that you press it. -richtig: Sensor -> Buttons are sensors: they report whether they are pressed. - -runde: -frage: The motion sensor notices that the mBot2 is tilted. -richtig: Sensor -> It measures the tilt. - -runde: -frage: The rings on the ultrasonic sensor glow blue. -richtig: Actuator -> Tricky! The part is a sensor, but the glowing rings are an output. -::: - ## Find the parts Your turn: click the part you are looking for in the model. If you are right, the next question appears. @@ -47771,6 +47811,66 @@ When the mBot2 is connected, **🔧 Test the mBot2** appears below the world. Op If a value does not change although you do something, something is wrong. Then tell your teacher before you start programming. +## Game: Sensor or actuator? + +::: spiel frage +titel: Game: sensor or actuator? +intro: Does the part measure something, or does it do something? Ten rounds. +antworten: Sensor | Actuator + +runde: +frage: The ultrasonic sensor measures how far away the wall is. +richtig: Sensor +> It measures something: the distance. + +runde: +frage: The motors turn the wheels. +richtig: Actuator +> They do something: they move the mBot2. + +runde: +frage: The LEDs glow red. +richtig: Actuator +> Glowing is doing something, not measuring. + +runde: +frage: The line sensor recognises the black tape. +richtig: Sensor +> It measures how much light comes back from the floor. + +runde: +frage: The speaker beeps. +richtig: Actuator +> It outputs a sound. + +runde: +frage: The microphone hears you clap. +richtig: Sensor +> It measures the loudness. + +runde: +frage: The screen shows “Hello VisuBot!”. +richtig: Actuator +> Showing something is an output. + +runde: +frage: Button A notices that you press it. +richtig: Sensor +> Buttons are sensors: they report whether they are pressed. + +runde: +frage: The motion sensor notices that the mBot2 is tilted. +richtig: Sensor +> It measures the tilt. + +runde: +frage: The rings on the ultrasonic sensor glow blue. +richtig: Actuator +> Tricky! The part is a sensor, but the glowing rings are an output. +::: + +## 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. ::: checkliste @@ -47783,6 +47883,60 @@ Rate yourself honestly for each point: ☂️ not yet, ⛅ partly, ☀️ I can - I can connect the real mBot2 with USB-C and disconnect it again. → Connecting the real mBot2 - I can check that all sensors and actuators work. → Testing the mBot2 ::: + +## Quiz + +::: quiz +? Match each part to its job. +→ Hello mBot2 += Ultrasonic sensor -> measures the distance += Motors -> move the wheels += CyberPi -> runs the program += Line sensor -> detects a dark line +? Which parts are actuators? +→ Sensors and actuators +- [x] Motors +- [ ] Ultrasonic sensor +- [x] LEDs +- [ ] Line sensor +> Actuators do something, sensors measure something. +? How does the ultrasonic sensor measure the distance? +→ The ultrasonic sensor +- [ ] It takes a photo of the wall. +- [x] It sends out a very high sound and waits for the echo. +- [ ] It feels the wall with its blue rings. +> The longer the echo takes, the further away the wall is. +? How does the line sensor detect a black line? +→ Under the robot +- [x] Little light comes back from the black line. +- [ ] The line is warmer than the floor. +- [ ] It hears the wheels rolling over the line. +> Each feeler shines light on the floor. A light floor reflects a lot of light, a black line only a little. +? What does \`mbot.turnRight()\` do? +→ Commands for the mBot2 +- [ ] The mBot2 drives 10 cm to the right. +- [x] The mBot2 turns 90° to the right. +- [ ] The right LED switches on. +> With no number in the brackets it turns 90°. \`mbot.turnRight(45)\` turns only 45°. +? The structure chart has five boxes \`mbot.forward()\` one below the other. How far does the mBot2 drive in the simulation? +→ First drive +- [ ] 5 cm +- [x] 50 cm +- [ ] 10 cm +> Each \`mbot.forward()\` drives 10 cm, which is one square of the grid. +? You have finished with the real mBot2. What do you do before you pull out the cable? +→ Connecting the real mBot2 +- [x] Click **🟢 mBot2** once more and wait until “Bis bald!” appears +- [ ] Push the slide switch to OFF +- [ ] Nothing, the cable can come out right away +> Only after “Bis bald!” is the port free. +? You hold your hand in front of the ultrasonic sensor, but the value under **🔧 Test the mBot2** does not change. What do you do? +→ Testing the mBot2 +- [ ] Start programming anyway +- [x] Tell your teacher before you start programming +- [ ] Change the value in the simulation by hand +> If a value does not change although you do something, something is wrong with the robot. +::: `,l9=`--- titel: The square bereich: Getting started @@ -48113,6 +48267,41 @@ Rate yourself honestly for each point: ☂️ not yet, ⛅ partly, ☀️ I can - I can nest three loops. → Four squares - I can upload my program to the mBot2 and start it with button A without a cable. → Driving without a cable ::: + +## Quiz + +::: quiz +? Still without a loop, the mBot2 should drive one side of 50 cm and then turn. Which boxes do you need? +→ Driving a square +- [ ] one \`mbot.forward()\` and one \`mbot.turnRight()\` +- [x] five \`mbot.forward()\` and one \`mbot.turnRight()\` +- [ ] five \`mbot.turnRight()\` +> Each \`mbot.forward()\` drives 10 cm, five of them are 50 cm. +? A for loop has the start \`int i = 0\`, the condition \`i < 5\` and the step \`i++\`. How often does it run? +→ Always the same +- [ ] 4 times +- [x] 5 times +- [ ] 6 times +> \`i\` counts 0, 1, 2, 3, 4. That is five runs. +? Why is the counter of the inner loop called \`j\` and not \`i\` as well? +→ A loop in a loop +- [ ] Each letter may only appear once in a program. +- [x] Each loop needs its own counter, otherwise the two get in each other's way. +- [ ] \`j\` counts faster than \`i\`. +> If both counted with \`i\`, the inner loop would mix up the outer one. +? How often does the mBot2 run \`mbot.turnRight()\` for the four squares? +→ Four squares +- [ ] 4 times +- [ ] 16 times +- [x] 20 times +> In each square it turns four times, that is 4 · 4 = 16. After each square there is one more turn: 16 + 4 = 20. +? Your program has been transferred and the cable is out. How do you start it? +→ Driving without a cable +- [ ] with button B +- [x] with button A +- [ ] with **⬆ Transfer** +> After the transfer the mBot2 shows **A = Start** and waits for button A. +::: `,u9=`--- titel: Variables and output bereich: Getting started @@ -53081,6 +53270,41 @@ Rate yourself honestly for each point: ☂️ not yet, ⛅ partly, ☀️ I can - I can recognise and call an overloaded method. → Same name, different parameters: overloading - I can write a method with a return value. → A method with a return value ::: + +## Quiz + +::: quiz +? The subprogram \`void quadrat(int seite)\` should drive a square with sides of 30 cm. What does the call look like? +→ A subprogram for the square +- [ ] \`quadrat()\` +- [x] \`quadrat(30)\` +- [ ] \`int seite = quadrat(30)\` +> The value in the brackets becomes the parameter \`seite\`. Because \`quadrat\` returns nothing, there is no assignment. +? In which method does a Java program start? +→ Methods in Java +- [ ] in the first method of the class +- [x] in the method \`main\` +- [ ] in the method \`quadrat\` +> The program always starts in \`main\`. The other methods are called from there. +? How does Java tell the overloaded methods \`forward()\`, \`forward(int cm)\` and \`forward(int wert, String einheit)\` apart? +→ Same name, different parameters: overloading +- [ ] by their name +- [x] by the number and type of the parameters +- [ ] by their order in the program +> The name is the same for all of them. Java chooses the variant whose parameters fit the call. +? \`static int zentimeter(int umdrehungen) { return umdrehungen * 20; }\`: What is in \`strecke\` after \`int strecke = zentimeter(2);\`? +→ A method with a return value +- [ ] 2 +- [ ] 20 +- [x] 40 +> \`return\` gives back 2 · 20 = 40, and this value ends up in \`strecke\`. +? A method returns a whole number. What is written in its header instead of \`void\`? +→ A method with a return value +- [ ] \`return\` +- [x] \`int\` +- [ ] \`static\` +> Instead of \`void\`, the header names the data type of the result. +::: `,B9=`## 🤖 mBot2 commands A command tells the mBot2 what to **do**. Every command starts with \`mbot.\` and ends with brackets. Often you write a number in the brackets. @@ -76668,7 +76892,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-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(` + `;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-Dxll7D8C.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} @@ -76684,7 +76908,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-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")} + ${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-Dxll7D8C.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)} @@ -76932,7 +77156,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-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)+` +

`;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-Dxll7D8C.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 @@ -77154,7 +77378,7 @@ ${c}
- ${W(p("web_about_version_fmt").replace("%@","0.15.1"))} + ${W(p("web_about_version_fmt").replace("%@","0.15.2"))}
@@ -77226,7 +77450,7 @@ ${c}

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

-

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

+

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

Holger Sebastiao

${e("about_web_label","https://visustruct.visucode.de","visustruct.visucode.de")} ${e("about_developer_label","https://www.sebastiao.org","www.sebastiao.org")} @@ -77248,4 +77472,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-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}; + `,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-CRJPH7QB.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-DSAsXJlY.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-DkBXkNTX.js b/website/app/assets/objectApp-CRJPH7QB.js similarity index 99% rename from website/app/assets/objectApp-DkBXkNTX.js rename to website/app/assets/objectApp-CRJPH7QB.js index 06c0543b..936817b8 100644 --- a/website/app/assets/objectApp-DkBXkNTX.js +++ b/website/app/assets/objectApp-CRJPH7QB.js @@ -1,5 +1,5 @@ -const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./projectZip-hnnNIFP3.js","./index-DuzNMqv5.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-DuzNMqv5.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-BV1XwwqD.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.1"))} + ${b(d("web_about_version_fmt").replace("%@","0.15.2"))}
@@ -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-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)} + `}).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-0meShIxx.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-0meShIxx.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-hnnNIFP3.js b/website/app/assets/projectZip-0meShIxx.js similarity index 99% rename from website/app/assets/projectZip-hnnNIFP3.js rename to website/app/assets/projectZip-0meShIxx.js index 7e160f65..70221370 100644 --- a/website/app/assets/projectZip-hnnNIFP3.js +++ b/website/app/assets/projectZip-0meShIxx.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-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}; +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-CRJPH7QB.js";import"./index-BV1XwwqD.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-K0yfmoba.js b/website/app/assets/robot3d-Dxll7D8C.js similarity index 99% rename from website/app/assets/robot3d-K0yfmoba.js rename to website/app/assets/robot3d-Dxll7D8C.js index ae98cbe1..08afb5c7 100644 --- a/website/app/assets/robot3d-K0yfmoba.js +++ b/website/app/assets/robot3d-Dxll7D8C.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-DuzNMqv5.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-BV1XwwqD.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 a779966b..a63a29a3 100644 --- a/website/app/index.html +++ b/website/app/index.html @@ -6,7 +6,7 @@ VisuStruct Web - +