From 33bb505d44c9aa71d5b62896980b2a9120e76564 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 4 Nov 2026 04:07:05 +0000 Subject: [PATCH] =?UTF-8?q?Web=200.15.5:=20Kleinigkeiten=20aus=20der=20zwe?= =?UTF-8?q?iten=20Lektionspr=C3=BCfung?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01Ugz28SUi7WrLyAgxYxQzrJ --- CHANGELOG.md | 1 + web/lessons/de/04-variablen-und-datentypen.md | 2 +- web/lessons/de/22-try-und-catch.md | 2 +- web/lessons/de/28-erstes-fenster.md | 2 +- web/lessons/de/30-der-knopf-reagiert.md | 2 +- web/lessons/de/35-taschenrechner.md | 2 +- web/lessons/de/36-zahlenraten.md | 2 +- .../de/37-viele-knoepfe-ein-zuhoerer.md | 2 +- web/lessons/de/38-innere-klassen.md | 2 +- web/lessons/de/aufgaben/einheitenrechner.md | 6 ++ web/lessons/de/aufgaben/wuerfel-mvc.md | 7 ++ web/lessons/en/04-variablen-und-datentypen.md | 2 +- web/lessons/en/22-try-und-catch.md | 2 +- web/lessons/en/28-erstes-fenster.md | 2 +- web/lessons/en/30-der-knopf-reagiert.md | 2 +- web/lessons/en/35-taschenrechner.md | 2 +- web/lessons/en/36-zahlenraten.md | 2 +- .../en/37-viele-knoepfe-ein-zuhoerer.md | 2 +- web/lessons/en/38-innere-klassen.md | 2 +- web/lessons/en/aufgaben/einheitenrechner.md | 6 ++ web/lessons/en/aufgaben/wuerfel-mvc.md | 7 ++ web/lessons/pt/04-variablen-und-datentypen.md | 2 +- web/lessons/pt/22-try-und-catch.md | 2 +- web/lessons/pt/28-erstes-fenster.md | 2 +- web/lessons/pt/30-der-knopf-reagiert.md | 2 +- web/lessons/pt/35-taschenrechner.md | 2 +- web/lessons/pt/36-zahlenraten.md | 2 +- .../pt/37-viele-knoepfe-ein-zuhoerer.md | 2 +- web/lessons/pt/38-innere-klassen.md | 2 +- web/lessons/pt/aufgaben/einheitenrechner.md | 6 ++ web/lessons/pt/aufgaben/wuerfel-mvc.md | 7 ++ web/package-lock.json | 4 +- web/package.json | 2 +- web/test/lessons.test.ts | 6 ++ ...lowApp-CDuFZyj_.js => flowApp-B31MybDd.js} | 4 +- .../{index-BULnZN5t.js => index-_t0Bkwfx.js} | 99 +++++++++++++------ ...tApp-BjkXZsrO.js => objectApp-Dl0a6-GP.js} | 8 +- ...Zip-D1vNO4Uu.js => projectZip-cdq8RhEl.js} | 2 +- ...obot3d-BEFl6o8i.js => robot3d-BlWxLlAd.js} | 2 +- website/app/index.html | 2 +- 40 files changed, 151 insertions(+), 66 deletions(-) rename website/app/assets/{flowApp-CDuFZyj_.js => flowApp-B31MybDd.js} (99%) rename website/app/assets/{index-BULnZN5t.js => index-_t0Bkwfx.js} (99%) rename website/app/assets/{objectApp-BjkXZsrO.js => objectApp-Dl0a6-GP.js} (99%) rename website/app/assets/{projectZip-D1vNO4Uu.js => projectZip-cdq8RhEl.js} (99%) rename website/app/assets/{robot3d-BEFl6o8i.js => robot3d-BlWxLlAd.js} (99%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 95fa90b0..1653d3f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ The format is loosely inspired by Keep a Changelog. ### Changed +- **Web 0.15.5, small lesson fixes from the second review:** the free tasks „Einheitenrechner“ (after L36) and „Würfeln mit MVC“ (after L41) get a list „Du bist fertig, wenn …“ with things you can see in the window and console. L38 „Viele Knöpfe, ein Zuhörer“: Ludwig's tip in the task „Zahlenschloss“ talked about the calculator; it now helps with the task (count wrong attempts, `setEnabled(false)`, stars with a separate `eingabe`). Steps „Profiwissen: …“ in L23, L29, L31, L36 and L37 lose the prefix (Holger: no separate Profiwissen), L39 refers to the step by name. L5 Angeberwissen no longer mentions the coffee-cup logo. de/en/pt. New test: no step title starts with „Profiwissen“. - **Web 0.15.4, lesson 1 split in two:** VisuStruct lesson 1 „Was ist ein Struktogramm?“ was very long (15 steps). It now covers algorithm, reading a structure chart, the three building blocks, „Erst die Struktur, dann der Code“, the game „Welcher Baustein?“, checklist and quiz. The new lesson 2 „PAP und Pseudocode“ (`01-weitere-darstellungen.md`) takes the flowchart part (PAP elements, exercise „Kuchen backen als PAP“, jumps/GOTO/spaghetti code, pseudocode and comparison) with its own Kompetenzen, a new game „Welche Darstellung?“ (structure chart, flowchart or pseudocode, eight rounds), checklist and quiz (de/en/pt). VisuStruct now numbers lessons like VisuBot: in file order, so the new lesson keeps file number 01 and no file is renamed (progress stays). All later lessons move up by one; „Lektion N“ in texts and `nach:` in tasks are renumbered automatically. Saved step positions in lesson 1 may point to a later step than before. New test checks the split and the renumbered references. - **Web 0.15.3, VisuBot orange like visucode.de:** the VisuBot theme in the app used #e07000 (buttons, selection, focus) and #f08a00 („Bot“ in the title bar), the visucode.de start page uses #c2410c with the gradient #ea580c → #c2410c (css/visucode.css, MARKE.md). The app now uses the same values; white text on the accent goes from 3.2 : 1 to 5.2 : 1. The command group „Fahren“ (stripe and dot) moves from the old VisuBot orange #d96a00 to #c2410c as well. - **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. diff --git a/web/lessons/de/04-variablen-und-datentypen.md b/web/lessons/de/04-variablen-und-datentypen.md index a13706e4..c98f4a68 100644 --- a/web/lessons/de/04-variablen-und-datentypen.md +++ b/web/lessons/de/04-variablen-und-datentypen.md @@ -214,7 +214,7 @@ System.out.println("Gesamt: " + gesamtPreis + " Euro"); Wie der Computer deinen Java-Code versteht und warum er auf Windows, macOS und Linux gleich läuft, erfährst du in der Lektion „Struktogramm und Code“. ::: angeberwissen -Java hieß zuerst **Oak** (Eiche), nach dem Baum vor dem Bürofenster von James Gosling. Sein Team bei Sun Microsystems wollte ab 1991 kleine Geräte wie Fernseh-Boxen programmieren. Den Namen Oak hatte aber schon eine andere Firma. Also wurde es 1995 **Java**, wie der Kaffee von der Insel Java. Deshalb ist das Logo eine dampfende Tasse. +Java hieß zuerst **Oak** (Eiche), nach dem Baum vor dem Bürofenster von James Gosling. Sein Team bei Sun Microsystems wollte ab 1991 kleine Geräte wie Fernseh-Boxen programmieren. Den Namen Oak hatte aber schon eine andere Firma. Also wurde es 1995 **Java**, wie der Kaffee von der Insel Java. ::: ## Text in Java diff --git a/web/lessons/de/22-try-und-catch.md b/web/lessons/de/22-try-und-catch.md index a095c3d2..dd0444fc 100644 --- a/web/lessons/de/22-try-und-catch.md +++ b/web/lessons/de/22-try-und-catch.md @@ -135,7 +135,7 @@ try { „zwölf“ kann Java nicht umwandeln und wirft eine `NumberFormatException`. Das Programm gibt „Das ist keine Zahl: zwölf“ aus. Ändere die erste Zeile in `String eingabe = "12";` und führe es noch einmal aus: Jetzt erscheint „Doppelt: 24“. -## Profiwissen: Exceptions sind Objekte +## Exceptions sind Objekte Das steht nicht im Lehrplan, ist aber praktisch zu wissen. diff --git a/web/lessons/de/28-erstes-fenster.md b/web/lessons/de/28-erstes-fenster.md index b7047614..8a19a53e 100644 --- a/web/lessons/de/28-erstes-fenster.md +++ b/web/lessons/de/28-erstes-fenster.md @@ -82,7 +82,7 @@ Erst einrichten, dann zeigen. Wie im Theater: Der Vorhang geht erst auf, wenn di Probier es aus: Lösche die Zeile mit `setVisible(true)` und führe das Programm noch einmal aus. Das Programm läuft, aber du siehst kein Fenster. -## Profiwissen: Klassen und Objekte +## Klassen und Objekte Das steht nicht im Lehrplan, hilft dir aber, Swing zu verstehen. diff --git a/web/lessons/de/30-der-knopf-reagiert.md b/web/lessons/de/30-der-knopf-reagiert.md index f90c161f..0f01f872 100644 --- a/web/lessons/de/30-der-knopf-reagiert.md +++ b/web/lessons/de/30-der-knopf-reagiert.md @@ -167,7 +167,7 @@ frage: Wie viele Zeilen „Klick!“ stehen danach in der Konsole? > Der Zuhörer läuft bei **jedem** Klick, nicht nur beim ersten. Drei Klicks, drei Zeilen. ::: -## Profiwissen: ActionListener ist ein Interface +## ActionListener ist ein Interface Das steht nicht im Lehrplan. Wenn du wissen willst, was hinter dem Pfeil steckt, lies weiter. diff --git a/web/lessons/de/35-taschenrechner.md b/web/lessons/de/35-taschenrechner.md index 0b502a4f..d935d079 100644 --- a/web/lessons/de/35-taschenrechner.md +++ b/web/lessons/de/35-taschenrechner.md @@ -123,7 +123,7 @@ geteilt.addActionListener(e -> { Mit `double` und `Double.parseDouble(…)` gibt es Nachkommastellen: 7 / 2 ergibt 3.5. Dafür wirft Java bei Kommazahlen keine Exception beim Teilen durch 0. Das Ergebnis heißt dann `Infinity`, also „unendlich“. ::: -## Profiwissen: eine eigene Methode +## Eine eigene Methode Das steht nicht im Lehrplan, macht den Code aber kürzer. diff --git a/web/lessons/de/36-zahlenraten.md b/web/lessons/de/36-zahlenraten.md index 1f4a8c42..f86974b5 100644 --- a/web/lessons/de/36-zahlenraten.md +++ b/web/lessons/de/36-zahlenraten.md @@ -102,7 +102,7 @@ public class Zahlenraten { Mit `setEnabled(true)` schaltest du einen Knopf wieder ein. So kannst du zum Beispiel einen Knopf erst freigeben, wenn etwas eingegeben wurde. ::: -## Profiwissen: mit 7 Versuchen gewinnen +## Mit 7 Versuchen gewinnen ::: angeberwissen Wer geschickt rät, braucht nie mehr als 7 Versuche. Rate immer die Mitte des Bereichs, der noch übrig ist: erst 50, dann 25 oder 75 und so weiter. Jeder Tipp halbiert den Bereich: 100, 50, 25, 13, 7, 4, 2, 1. Das ist die **binäre Suche** aus Lektion 19. Weil 2 hoch 7 = 128 größer als 100 ist, reichen 7 Tipps. diff --git a/web/lessons/de/37-viele-knoepfe-ein-zuhoerer.md b/web/lessons/de/37-viele-knoepfe-ein-zuhoerer.md index 3c418686..4293ced2 100644 --- a/web/lessons/de/37-viele-knoepfe-ein-zuhoerer.md +++ b/web/lessons/de/37-viele-knoepfe-ein-zuhoerer.md @@ -267,7 +267,7 @@ Dann mach es besser: - im Zusatz die Anzeige nur Sterne zeigt, der Code aber trotzdem geprüft wird. ::: ludwig -Auch beim Taschenrechner aus Lektion 35 reicht ein Zuhörer für +, -, \* und /. Prüfe darin mit `e.getActionCommand().equals("+")`, welches Rechenzeichen geklickt wurde. +Zähle im Zweig für **OK** bei jedem falschen Code `versuche++` und prüfe danach `if (versuche >= 3)`. Dann schaltet `ok.setEnabled(false)` den Knopf ab, wie beim Zahlenraten. Für die Sterne: `eingabe = eingabe + e.getActionCommand();` und `anzeige.setText(anzeige.getText() + "*");`. Verglichen wird dann `eingabe`, nicht der Text der Anzeige. ::: ## Checkliste diff --git a/web/lessons/de/38-innere-klassen.md b/web/lessons/de/38-innere-klassen.md index d6048a03..415961f2 100644 --- a/web/lessons/de/38-innere-klassen.md +++ b/web/lessons/de/38-innere-klassen.md @@ -19,7 +19,7 @@ kurz: Einen Zuhörer als benannte innere Klasse, als anonyme Klasse und als Lamb Den Klickzähler aus Lektion 32 kennst du schon. Heute schreibst du seinen Zuhörer auf **drei Arten**, die alle genau dasselbe tun: 1. als **benannte innere Klasse**, wie man es vor Java 8 meistens gemacht hat, -2. als **anonyme Klasse**, die du aus dem Profiwissen in Lektion 30 kennst, +2. als **anonyme Klasse**, die du aus Lektion 30 („ActionListener ist ein Interface“) kennst, 3. als **Lambda** mit dem Pfeil, so wie bisher. In fremdem Code, in Büchern und im Internet triffst du alle drei Schreibweisen. Nach dieser Lektion erkennst du sie. diff --git a/web/lessons/de/aufgaben/einheitenrechner.md b/web/lessons/de/aufgaben/einheitenrechner.md index 49409492..fc8b829a 100644 --- a/web/lessons/de/aufgaben/einheitenrechner.md +++ b/web/lessons/de/aufgaben/einheitenrechner.md @@ -42,6 +42,12 @@ public class Einheiten { } ``` +**Du bist fertig, wenn …** + +- 1.5 nach **in cm** „150.0 cm“ zeigt, nach **in mm** „1500.0 mm“, +- 1500 nach **in km** „1.5 km“ zeigt, +- „abc“ im Feld „Bitte eine Zahl eingeben“ zeigt und das Fenster offen bleibt. + Zusatz: Ein vierter Knopf **in Fuß** rechnet in die englische Einheit um. Ein Fuß sind 0.3048 m. ::: ludwig diff --git a/web/lessons/de/aufgaben/wuerfel-mvc.md b/web/lessons/de/aufgaben/wuerfel-mvc.md index cf96f944..e3d055bf 100644 --- a/web/lessons/de/aufgaben/wuerfel-mvc.md +++ b/web/lessons/de/aufgaben/wuerfel-mvc.md @@ -31,6 +31,13 @@ Deine Aufgabe: 3. Schreibe die View `StatistikAnzeige`. Sie zeigt zum Beispiel „Sechsen: 2 von 10 Würfen“. 4. Der Controller ist der Zuhörer am Knopf: Er lässt das Model würfeln und gibt beiden Views die neuen Werte. +**Du bist fertig, wenn …** + +- in der Konsole nach zehn Würfen `wuerfe` gleich 10 ist und `sechsen` zwischen 0 und 10 liegt, +- jeder Klick auf **Würfeln** eine neue Zahl von 1 bis 6 in der `AugenAnzeige` zeigt, +- die `StatistikAnzeige` nach jedem Klick einen Wurf mehr zählt und Sechsen richtig mitzählt, +- im Model kein `JLabel` und in den Views kein `Math.random` steht. + Zusatz: Ein Knopf **Neues Spiel** setzt alles auf Anfang. Die Methode dafür gehört ins Model. ::: ludwig diff --git a/web/lessons/en/04-variablen-und-datentypen.md b/web/lessons/en/04-variablen-und-datentypen.md index a9b41c83..0b920edb 100644 --- a/web/lessons/en/04-variablen-und-datentypen.md +++ b/web/lessons/en/04-variablen-und-datentypen.md @@ -214,7 +214,7 @@ System.out.println("Total: " + totalPrice + " euros"); How the computer understands your Java code and why it runs the same on Windows, macOS and Linux is explained in the lesson “Structure chart and code”. ::: angeberwissen -Java was first called **Oak**, after the tree outside James Gosling’s office window. From 1991 his team at Sun Microsystems wanted to program small devices such as TV set-top boxes. But another company already had the name Oak. So in 1995 it became **Java**, like the coffee from the island of Java. That is why the logo is a steaming cup. +Java was first called **Oak**, after the tree outside James Gosling’s office window. From 1991 his team at Sun Microsystems wanted to program small devices such as TV set-top boxes. But another company already had the name Oak. So in 1995 it became **Java**, like the coffee from the island of Java. ::: ## Text in Java diff --git a/web/lessons/en/22-try-und-catch.md b/web/lessons/en/22-try-und-catch.md index b3a350dc..5c1aec01 100644 --- a/web/lessons/en/22-try-und-catch.md +++ b/web/lessons/en/22-try-und-catch.md @@ -135,7 +135,7 @@ try { Java cannot convert “twelve” and throws a `NumberFormatException`. The program prints “That is not a number: twelve”. Change the first line to `String input = "12";` and run it again: now “Double: 24” appears. -## Expert knowledge: exceptions are objects +## Exceptions are objects This is not in the curriculum, but it is useful to know. diff --git a/web/lessons/en/28-erstes-fenster.md b/web/lessons/en/28-erstes-fenster.md index f877ebfa..e4a4170a 100644 --- a/web/lessons/en/28-erstes-fenster.md +++ b/web/lessons/en/28-erstes-fenster.md @@ -82,7 +82,7 @@ Set up first, then show. Like in the theatre: the curtain only goes up once the Try it: delete the line with `setVisible(true)` and run the program again. The program runs, but you do not see a window. -## Expert knowledge: classes and objects +## Classes and objects This is not in the curriculum, but it helps you understand Swing. diff --git a/web/lessons/en/30-der-knopf-reagiert.md b/web/lessons/en/30-der-knopf-reagiert.md index fce47cce..6e2e229c 100644 --- a/web/lessons/en/30-der-knopf-reagiert.md +++ b/web/lessons/en/30-der-knopf-reagiert.md @@ -167,7 +167,7 @@ frage: How many lines “Click!” are in the console afterwards? > The listener runs on **every** click, not only on the first one. Three clicks, three lines. ::: -## Expert knowledge: ActionListener is an interface +## ActionListener is an interface This is not in the curriculum. If you want to know what is behind the arrow, read on. diff --git a/web/lessons/en/35-taschenrechner.md b/web/lessons/en/35-taschenrechner.md index 30e2b9d8..0c43631a 100644 --- a/web/lessons/en/35-taschenrechner.md +++ b/web/lessons/en/35-taschenrechner.md @@ -123,7 +123,7 @@ divide.addActionListener(e -> { With `double` and `Double.parseDouble(…)` you get decimal places: 7 / 2 gives 3.5. In return, Java throws no exception when dividing decimal numbers by 0. The result is then `Infinity`. ::: -## Expert knowledge: a method of your own +## A method of your own This is not in the curriculum, but it makes the code shorter. diff --git a/web/lessons/en/36-zahlenraten.md b/web/lessons/en/36-zahlenraten.md index c84fb22b..06a24a22 100644 --- a/web/lessons/en/36-zahlenraten.md +++ b/web/lessons/en/36-zahlenraten.md @@ -102,7 +102,7 @@ public class GuessTheNumber { `setEnabled(true)` switches a button back on. That way you can, for example, only allow a button once something has been entered. ::: -## Expert knowledge: winning in 7 guesses +## Winning in 7 guesses ::: angeberwissen If you guess cleverly, you never need more than 7 guesses. Always guess the middle of the range that is left: first 50, then 25 or 75 and so on. Each guess halves the range: 100, 50, 25, 13, 7, 4, 2, 1. That is the **binary search** from lesson 19. Because 2 to the power of 7 = 128 is bigger than 100, 7 guesses are enough. diff --git a/web/lessons/en/37-viele-knoepfe-ein-zuhoerer.md b/web/lessons/en/37-viele-knoepfe-ein-zuhoerer.md index 8daced7a..5e02a81f 100644 --- a/web/lessons/en/37-viele-knoepfe-ein-zuhoerer.md +++ b/web/lessons/en/37-viele-knoepfe-ein-zuhoerer.md @@ -266,7 +266,7 @@ Then make it better: - for the extra, the display only shows stars but the code is still checked. ::: ludwig -For the calculator from lesson 35, one listener is enough for +, -, \* and / too. Check inside it with `e.getActionCommand().equals("+")` which operator was clicked. +In the branch for **OK**, count `attempts++` for every wrong code and then check `if (attempts >= 3)`. Then `ok.setEnabled(false)` switches the button off, like in the guessing game. For the stars: `input = input + e.getActionCommand();` and `display.setText(display.getText() + "*");`. Then you compare `input`, not the text of the display. ::: ## Checklist diff --git a/web/lessons/en/38-innere-klassen.md b/web/lessons/en/38-innere-klassen.md index f29e3547..48d1332c 100644 --- a/web/lessons/en/38-innere-klassen.md +++ b/web/lessons/en/38-innere-klassen.md @@ -19,7 +19,7 @@ kurz: Write a listener as a named inner class, as an anonymous class and as a la You already know the click counter from lesson 32. Today you write its listener in **three ways**, all of which do exactly the same: 1. as a **named inner class**, the way it was mostly done before Java 8, -2. as an **anonymous class**, which you know from the expert knowledge in lesson 30, +2. as an **anonymous class**, which you know from lesson 30 (“ActionListener is an interface”), 3. as a **lambda** with the arrow, as before. In other people's code, in books and on the internet you will meet all three. After this lesson you will recognise them. diff --git a/web/lessons/en/aufgaben/einheitenrechner.md b/web/lessons/en/aufgaben/einheitenrechner.md index 3bf2a180..50aac46e 100644 --- a/web/lessons/en/aufgaben/einheitenrechner.md +++ b/web/lessons/en/aufgaben/einheitenrechner.md @@ -42,6 +42,12 @@ public class Units { } ``` +**You are done when …** + +- 1.5 shows "150.0 cm" after **in cm** and "1500.0 mm" after **in mm**, +- 1500 shows "1.5 km" after **in km**, +- "abc" in the field shows "Please enter a number" and the window stays open. + Extra: a fourth button **in feet** converts to the imperial unit. One foot is 0.3048 m. ::: ludwig diff --git a/web/lessons/en/aufgaben/wuerfel-mvc.md b/web/lessons/en/aufgaben/wuerfel-mvc.md index fe4d769b..78d521c6 100644 --- a/web/lessons/en/aufgaben/wuerfel-mvc.md +++ b/web/lessons/en/aufgaben/wuerfel-mvc.md @@ -31,6 +31,13 @@ Your task: 3. Write the view `StatsView`. It shows for example "Sixes: 2 of 10 rolls". 4. The controller is the listener at the button: it lets the model roll and hands the new values to both views. +**You are done when …** + +- after ten rolls in the console `rolls` is 10 and `sixes` is between 0 and 10, +- every click on **Roll** shows a new number from 1 to 6 in the `PipsView`, +- the `StatsView` counts one more roll after every click and counts the sixes correctly, +- there is no `JLabel` in the model and no `Math.random` in the views. + Extra: a button **New game** resets everything. The method for that belongs in the model. ::: ludwig diff --git a/web/lessons/pt/04-variablen-und-datentypen.md b/web/lessons/pt/04-variablen-und-datentypen.md index 7b0cd185..209f097d 100644 --- a/web/lessons/pt/04-variablen-und-datentypen.md +++ b/web/lessons/pt/04-variablen-und-datentypen.md @@ -214,7 +214,7 @@ System.out.println("Total: " + precoTotal + " euros"); Como é que o computador entende o teu código Java e porque é que ele corre igual no Windows, no macOS e no Linux, vais ver na lição “Estrutograma e código”. ::: angeberwissen -O Java chamava-se primeiro **Oak** (carvalho), por causa da árvore em frente à janela do escritório de James Gosling. A partir de 1991, a sua equipa na Sun Microsystems queria programar pequenos aparelhos, como boxes de televisão. Mas o nome Oak já pertencia a outra empresa. Assim, em 1995 passou a chamar-se **Java**, como o café da ilha de Java. É por isso que o logótipo é uma chávena a fumegar. +O Java chamava-se primeiro **Oak** (carvalho), por causa da árvore em frente à janela do escritório de James Gosling. A partir de 1991, a sua equipa na Sun Microsystems queria programar pequenos aparelhos, como boxes de televisão. Mas o nome Oak já pertencia a outra empresa. Assim, em 1995 passou a chamar-se **Java**, como o café da ilha de Java. ::: ## Texto em Java diff --git a/web/lessons/pt/22-try-und-catch.md b/web/lessons/pt/22-try-und-catch.md index ed7cf479..89d8352e 100644 --- a/web/lessons/pt/22-try-und-catch.md +++ b/web/lessons/pt/22-try-und-catch.md @@ -135,7 +135,7 @@ try { O Java não consegue converter “doze” e lança uma `NumberFormatException`. O programa escreve “Isto não é um número: doze”. Muda a primeira linha para `String entrada = "12";` e executa outra vez: agora aparece “Dobro: 24”. -## Saber de profissional: as exceções são objetos +## As exceções são objetos Isto não está no programa da disciplina, mas é útil saber. diff --git a/web/lessons/pt/28-erstes-fenster.md b/web/lessons/pt/28-erstes-fenster.md index 0104b322..97ed31f8 100644 --- a/web/lessons/pt/28-erstes-fenster.md +++ b/web/lessons/pt/28-erstes-fenster.md @@ -82,7 +82,7 @@ Primeiro preparar, depois mostrar. Como no teatro: a cortina só sobe quando o p Experimenta: apaga a linha com `setVisible(true)` e executa o programa outra vez. O programa corre, mas não vês nenhuma janela. -## Saber de profissional: classes e objetos +## Classes e objetos Isto não está no programa da disciplina, mas ajuda-te a perceber o Swing. diff --git a/web/lessons/pt/30-der-knopf-reagiert.md b/web/lessons/pt/30-der-knopf-reagiert.md index 2047bfd6..688c479e 100644 --- a/web/lessons/pt/30-der-knopf-reagiert.md +++ b/web/lessons/pt/30-der-knopf-reagiert.md @@ -167,7 +167,7 @@ frage: Quantas linhas “Clique!” há depois na consola? > O ouvinte corre a **cada** clique, não só no primeiro. Três cliques, três linhas. ::: -## Saber de profissional: ActionListener é uma interface +## ActionListener é uma interface Isto não está no programa da disciplina. Se quiseres saber o que está por trás da seta, continua a ler. diff --git a/web/lessons/pt/35-taschenrechner.md b/web/lessons/pt/35-taschenrechner.md index 63d847d3..c3be00bd 100644 --- a/web/lessons/pt/35-taschenrechner.md +++ b/web/lessons/pt/35-taschenrechner.md @@ -123,7 +123,7 @@ dividir.addActionListener(e -> { Com `double` e `Double.parseDouble(…)` há casas decimais: 7 / 2 dá 3.5. Em contrapartida, com números decimais o Java não lança nenhuma exceção ao dividir por 0. O resultado é então `Infinity`, ou seja, “infinito”. ::: -## Saber de profissional: um método próprio +## Um método próprio Isto não está no programa da disciplina, mas torna o código mais curto. diff --git a/web/lessons/pt/36-zahlenraten.md b/web/lessons/pt/36-zahlenraten.md index 14884862..004c751d 100644 --- a/web/lessons/pt/36-zahlenraten.md +++ b/web/lessons/pt/36-zahlenraten.md @@ -102,7 +102,7 @@ public class AdivinhaNumero { Com `setEnabled(true)` voltas a ligar um botão. Assim podes, por exemplo, só ativar um botão depois de alguém ter escrito alguma coisa. ::: -## Saber de profissional: ganhar com 7 tentativas +## Ganhar com 7 tentativas ::: angeberwissen Quem adivinha com jeito nunca precisa de mais de 7 tentativas. Escolhe sempre o meio do intervalo que ainda resta: primeiro 50, depois 25 ou 75 e assim por diante. Cada palpite corta o intervalo a meio: 100, 50, 25, 13, 7, 4, 2, 1. É a **pesquisa binária** da lição 19. Como 2 elevado a 7 = 128 é maior do que 100, chegam 7 palpites. diff --git a/web/lessons/pt/37-viele-knoepfe-ein-zuhoerer.md b/web/lessons/pt/37-viele-knoepfe-ein-zuhoerer.md index f1bb13cc..1c6f027b 100644 --- a/web/lessons/pt/37-viele-knoepfe-ein-zuhoerer.md +++ b/web/lessons/pt/37-viele-knoepfe-ein-zuhoerer.md @@ -266,7 +266,7 @@ Depois melhora-o: - no extra, o visor só mostra estrelas mas o código continua a ser verificado. ::: ludwig -Também na calculadora da lição 35 chega um ouvinte para +, -, \* e /. Verifica lá dentro com `e.getActionCommand().equals("+")` que sinal de operação foi clicado. +No ramo do **OK**, conta `tentativas++` a cada código errado e depois verifica `if (tentativas >= 3)`. Aí `ok.setEnabled(false)` desliga o botão, como no Adivinha o número. Para as estrelas: `entrada = entrada + e.getActionCommand();` e `visor.setText(visor.getText() + "*");`. Depois comparas `entrada`, não o texto do visor. ::: ## Lista de verificação diff --git a/web/lessons/pt/38-innere-klassen.md b/web/lessons/pt/38-innere-klassen.md index ae3924de..ac799f98 100644 --- a/web/lessons/pt/38-innere-klassen.md +++ b/web/lessons/pt/38-innere-klassen.md @@ -19,7 +19,7 @@ kurz: Escrever um ouvinte como classe interna com nome, como classe anónima e c O contador de cliques da lição 32 já conheces. Hoje escreves o seu ouvinte de **três maneiras**, que fazem todas exatamente o mesmo: 1. como **classe interna com nome**, como se fazia quase sempre antes do Java 8, -2. como **classe anónima**, que conheces do saber de profissional da lição 30, +2. como **classe anónima**, que conheces da lição 30 (“ActionListener é uma interface”), 3. como **lambda** com a seta, como até agora. Em código de outras pessoas, em livros e na internet vais encontrar as três. Depois desta lição vais reconhecê-las. diff --git a/web/lessons/pt/aufgaben/einheitenrechner.md b/web/lessons/pt/aufgaben/einheitenrechner.md index ea16e770..a1d0c800 100644 --- a/web/lessons/pt/aufgaben/einheitenrechner.md +++ b/web/lessons/pt/aufgaben/einheitenrechner.md @@ -42,6 +42,12 @@ public class Unidades { } ``` +**Terminaste quando …** + +- 1.5 mostra "150.0 cm" depois de **em cm** e "1500.0 mm" depois de **em mm**, +- 1500 mostra "1.5 km" depois de **em km**, +- "abc" no campo mostra "Escreve um número" e a janela continua aberta. + Extra: um quarto botão **em pés** converte para a unidade inglesa. Um pé são 0.3048 m. ::: ludwig diff --git a/web/lessons/pt/aufgaben/wuerfel-mvc.md b/web/lessons/pt/aufgaben/wuerfel-mvc.md index 363a641a..61e8a89d 100644 --- a/web/lessons/pt/aufgaben/wuerfel-mvc.md +++ b/web/lessons/pt/aufgaben/wuerfel-mvc.md @@ -31,6 +31,13 @@ A tua tarefa: 3. Escreve a view `VistaEstatistica`. Mostra por exemplo "Seis: 2 em 10 lançamentos". 4. O controller é o ouvinte do botão: manda o model lançar e passa os valores novos às duas views. +**Terminaste quando …** + +- na consola, depois de dez lançamentos, `lancamentos` é 10 e `seis` está entre 0 e 10, +- cada clique em **Lançar** mostra um número novo de 1 a 6 na `VistaPontos`, +- a `VistaEstatistica` conta mais um lançamento depois de cada clique e conta bem os seis, +- no model não há nenhum `JLabel` e nas views não há nenhum `Math.random`. + Extra: um botão **Novo jogo** põe tudo no início. O método para isso pertence ao model. ::: ludwig diff --git a/web/package-lock.json b/web/package-lock.json index 6d4201f7..5dddc1c0 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -1,12 +1,12 @@ { "name": "visustruct-web", - "version": "0.15.4", + "version": "0.15.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "visustruct-web", - "version": "0.15.4", + "version": "0.15.5", "dependencies": { "@codemirror/autocomplete": "^6.20.4", "@codemirror/commands": "^6.11.1", diff --git a/web/package.json b/web/package.json index e0792bd8..94711a89 100644 --- a/web/package.json +++ b/web/package.json @@ -1,7 +1,7 @@ { "name": "visustruct-web", "private": true, - "version": "0.15.4", + "version": "0.15.5", "type": "module", "scripts": { "dev": "vite", diff --git a/web/test/lessons.test.ts b/web/test/lessons.test.ts index 142c3fcf..20adb2f5 100644 --- a/web/test/lessons.test.ts +++ b/web/test/lessons.test.ts @@ -34,6 +34,12 @@ describe.each(contentLanguages)('Lernbereich: Inhalte (%s)', (lang) => { expect(reference).toContain({ de: '### Verzweigung', en: '### Branch', pt: '### Decisão' }[lang]) }) + it('kein Schritt heißt „Profiwissen: …“ (Profitipps stehen im Angeberwissen)', () => { + for (const lesson of lessons) { + for (const step of lesson.steps) expect(step.title, lesson.id).not.toMatch(/^(Profiwissen|Expert knowledge|Saber de profissional)\b/i) + } + }) + it('jede Lektion hat mindestens ein Spiel, und es steht vor der Checkliste', () => { for (const lesson of lessons) { const kinds = lesson.steps.flatMap((s) => s.blocks.map((b) => b.kind)) diff --git a/website/app/assets/flowApp-CDuFZyj_.js b/website/app/assets/flowApp-B31MybDd.js similarity index 99% rename from website/app/assets/flowApp-CDuFZyj_.js rename to website/app/assets/flowApp-B31MybDd.js index 923c722a..c20a6a69 100644 --- a/website/app/assets/flowApp-CDuFZyj_.js +++ b/website/app/assets/flowApp-B31MybDd.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-BULnZN5t.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-_t0Bkwfx.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.4"))} + ${w(h("web_about_version_fmt").replace("%@","0.15.5"))}
diff --git a/website/app/assets/index-BULnZN5t.js b/website/app/assets/index-_t0Bkwfx.js similarity index 99% rename from website/app/assets/index-BULnZN5t.js rename to website/app/assets/index-_t0Bkwfx.js index ed968db3..4dcbba6f 100644 --- a/website/app/assets/index-BULnZN5t.js +++ b/website/app/assets/index-_t0Bkwfx.js @@ -1338,7 +1338,7 @@ System.out.println("Gesamt: " + gesamtPreis + " Euro"); Wie der Computer deinen Java-Code versteht und warum er auf Windows, macOS und Linux gleich läuft, erfährst du in der Lektion „Struktogramm und Code“. ::: angeberwissen -Java hieß zuerst **Oak** (Eiche), nach dem Baum vor dem Bürofenster von James Gosling. Sein Team bei Sun Microsystems wollte ab 1991 kleine Geräte wie Fernseh-Boxen programmieren. Den Namen Oak hatte aber schon eine andere Firma. Also wurde es 1995 **Java**, wie der Kaffee von der Insel Java. Deshalb ist das Logo eine dampfende Tasse. +Java hieß zuerst **Oak** (Eiche), nach dem Baum vor dem Bürofenster von James Gosling. Sein Team bei Sun Microsystems wollte ab 1991 kleine Geräte wie Fernseh-Boxen programmieren. Den Namen Oak hatte aber schon eine andere Firma. Also wurde es 1995 **Java**, wie der Kaffee von der Insel Java. ::: ## Text in Java @@ -7775,7 +7775,7 @@ try { „zwölf“ kann Java nicht umwandeln und wirft eine \`NumberFormatException\`. Das Programm gibt „Das ist keine Zahl: zwölf“ aus. Ändere die erste Zeile in \`String eingabe = "12";\` und führe es noch einmal aus: Jetzt erscheint „Doppelt: 24“. -## Profiwissen: Exceptions sind Objekte +## Exceptions sind Objekte Das steht nicht im Lehrplan, ist aber praktisch zu wissen. @@ -9149,7 +9149,7 @@ Erst einrichten, dann zeigen. Wie im Theater: Der Vorhang geht erst auf, wenn di Probier es aus: Lösche die Zeile mit \`setVisible(true)\` und führe das Programm noch einmal aus. Das Programm läuft, aber du siehst kein Fenster. -## Profiwissen: Klassen und Objekte +## Klassen und Objekte Das steht nicht im Lehrplan, hilft dir aber, Swing zu verstehen. @@ -9679,7 +9679,7 @@ frage: Wie viele Zeilen „Klick!“ stehen danach in der Konsole? > Der Zuhörer läuft bei **jedem** Klick, nicht nur beim ersten. Drei Klicks, drei Zeilen. ::: -## Profiwissen: ActionListener ist ein Interface +## ActionListener ist ein Interface Das steht nicht im Lehrplan. Wenn du wissen willst, was hinter dem Pfeil steckt, lies weiter. @@ -11072,7 +11072,7 @@ geteilt.addActionListener(e -> { Mit \`double\` und \`Double.parseDouble(…)\` gibt es Nachkommastellen: 7 / 2 ergibt 3.5. Dafür wirft Java bei Kommazahlen keine Exception beim Teilen durch 0. Das Ergebnis heißt dann \`Infinity\`, also „unendlich“. ::: -## Profiwissen: eine eigene Methode +## Eine eigene Methode Das steht nicht im Lehrplan, macht den Code aber kürzer. @@ -11328,7 +11328,7 @@ public class Zahlenraten { Mit \`setEnabled(true)\` schaltest du einen Knopf wieder ein. So kannst du zum Beispiel einen Knopf erst freigeben, wenn etwas eingegeben wurde. ::: -## Profiwissen: mit 7 Versuchen gewinnen +## Mit 7 Versuchen gewinnen ::: angeberwissen Wer geschickt rät, braucht nie mehr als 7 Versuche. Rate immer die Mitte des Bereichs, der noch übrig ist: erst 50, dann 25 oder 75 und so weiter. Jeder Tipp halbiert den Bereich: 100, 50, 25, 13, 7, 4, 2, 1. Das ist die **binäre Suche** aus Lektion 19. Weil 2 hoch 7 = 128 größer als 100 ist, reichen 7 Tipps. @@ -11727,7 +11727,7 @@ Dann mach es besser: - im Zusatz die Anzeige nur Sterne zeigt, der Code aber trotzdem geprüft wird. ::: ludwig -Auch beim Taschenrechner aus Lektion 35 reicht ein Zuhörer für +, -, \\* und /. Prüfe darin mit \`e.getActionCommand().equals("+")\`, welches Rechenzeichen geklickt wurde. +Zähle im Zweig für **OK** bei jedem falschen Code \`versuche++\` und prüfe danach \`if (versuche >= 3)\`. Dann schaltet \`ok.setEnabled(false)\` den Knopf ab, wie beim Zahlenraten. Für die Sterne: \`eingabe = eingabe + e.getActionCommand();\` und \`anzeige.setText(anzeige.getText() + "*");\`. Verglichen wird dann \`eingabe\`, nicht der Text der Anzeige. ::: ## Checkliste @@ -11790,7 +11790,7 @@ kurz: Einen Zuhörer als benannte innere Klasse, als anonyme Klasse und als Lamb Den Klickzähler aus Lektion 32 kennst du schon. Heute schreibst du seinen Zuhörer auf **drei Arten**, die alle genau dasselbe tun: 1. als **benannte innere Klasse**, wie man es vor Java 8 meistens gemacht hat, -2. als **anonyme Klasse**, die du aus dem Profiwissen in Lektion 30 kennst, +2. als **anonyme Klasse**, die du aus Lektion 30 („ActionListener ist ein Interface“) kennst, 3. als **Lambda** mit dem Pfeil, so wie bisher. In fremdem Code, in Büchern und im Internet triffst du alle drei Schreibweisen. Nach dieser Lektion erkennst du sie. @@ -14175,7 +14175,7 @@ System.out.println("Total: " + totalPrice + " euros"); How the computer understands your Java code and why it runs the same on Windows, macOS and Linux is explained in the lesson “Structure chart and code”. ::: angeberwissen -Java was first called **Oak**, after the tree outside James Gosling’s office window. From 1991 his team at Sun Microsystems wanted to program small devices such as TV set-top boxes. But another company already had the name Oak. So in 1995 it became **Java**, like the coffee from the island of Java. That is why the logo is a steaming cup. +Java was first called **Oak**, after the tree outside James Gosling’s office window. From 1991 his team at Sun Microsystems wanted to program small devices such as TV set-top boxes. But another company already had the name Oak. So in 1995 it became **Java**, like the coffee from the island of Java. ::: ## Text in Java @@ -20609,7 +20609,7 @@ try { Java cannot convert “twelve” and throws a \`NumberFormatException\`. The program prints “That is not a number: twelve”. Change the first line to \`String input = "12";\` and run it again: now “Double: 24” appears. -## Expert knowledge: exceptions are objects +## Exceptions are objects This is not in the curriculum, but it is useful to know. @@ -21983,7 +21983,7 @@ Set up first, then show. Like in the theatre: the curtain only goes up once the Try it: delete the line with \`setVisible(true)\` and run the program again. The program runs, but you do not see a window. -## Expert knowledge: classes and objects +## Classes and objects This is not in the curriculum, but it helps you understand Swing. @@ -22513,7 +22513,7 @@ frage: How many lines “Click!” are in the console afterwards? > The listener runs on **every** click, not only on the first one. Three clicks, three lines. ::: -## Expert knowledge: ActionListener is an interface +## ActionListener is an interface This is not in the curriculum. If you want to know what is behind the arrow, read on. @@ -23901,7 +23901,7 @@ divide.addActionListener(e -> { With \`double\` and \`Double.parseDouble(…)\` you get decimal places: 7 / 2 gives 3.5. In return, Java throws no exception when dividing decimal numbers by 0. The result is then \`Infinity\`. ::: -## Expert knowledge: a method of your own +## A method of your own This is not in the curriculum, but it makes the code shorter. @@ -24157,7 +24157,7 @@ public class GuessTheNumber { \`setEnabled(true)\` switches a button back on. That way you can, for example, only allow a button once something has been entered. ::: -## Expert knowledge: winning in 7 guesses +## Winning in 7 guesses ::: angeberwissen If you guess cleverly, you never need more than 7 guesses. Always guess the middle of the range that is left: first 50, then 25 or 75 and so on. Each guess halves the range: 100, 50, 25, 13, 7, 4, 2, 1. That is the **binary search** from lesson 19. Because 2 to the power of 7 = 128 is bigger than 100, 7 guesses are enough. @@ -24555,7 +24555,7 @@ Then make it better: - for the extra, the display only shows stars but the code is still checked. ::: ludwig -For the calculator from lesson 35, one listener is enough for +, -, \\* and / too. Check inside it with \`e.getActionCommand().equals("+")\` which operator was clicked. +In the branch for **OK**, count \`attempts++\` for every wrong code and then check \`if (attempts >= 3)\`. Then \`ok.setEnabled(false)\` switches the button off, like in the guessing game. For the stars: \`input = input + e.getActionCommand();\` and \`display.setText(display.getText() + "*");\`. Then you compare \`input\`, not the text of the display. ::: ## Checklist @@ -24618,7 +24618,7 @@ kurz: Write a listener as a named inner class, as an anonymous class and as a la You already know the click counter from lesson 32. Today you write its listener in **three ways**, all of which do exactly the same: 1. as a **named inner class**, the way it was mostly done before Java 8, -2. as an **anonymous class**, which you know from the expert knowledge in lesson 30, +2. as an **anonymous class**, which you know from lesson 30 (“ActionListener is an interface”), 3. as a **lambda** with the arrow, as before. In other people's code, in books and on the internet you will meet all three. After this lesson you will recognise them. @@ -27017,7 +27017,7 @@ System.out.println("Total: " + precoTotal + " euros"); Como é que o computador entende o teu código Java e porque é que ele corre igual no Windows, no macOS e no Linux, vais ver na lição “Estrutograma e código”. ::: angeberwissen -O Java chamava-se primeiro **Oak** (carvalho), por causa da árvore em frente à janela do escritório de James Gosling. A partir de 1991, a sua equipa na Sun Microsystems queria programar pequenos aparelhos, como boxes de televisão. Mas o nome Oak já pertencia a outra empresa. Assim, em 1995 passou a chamar-se **Java**, como o café da ilha de Java. É por isso que o logótipo é uma chávena a fumegar. +O Java chamava-se primeiro **Oak** (carvalho), por causa da árvore em frente à janela do escritório de James Gosling. A partir de 1991, a sua equipa na Sun Microsystems queria programar pequenos aparelhos, como boxes de televisão. Mas o nome Oak já pertencia a outra empresa. Assim, em 1995 passou a chamar-se **Java**, como o café da ilha de Java. ::: ## Texto em Java @@ -33453,7 +33453,7 @@ try { O Java não consegue converter “doze” e lança uma \`NumberFormatException\`. O programa escreve “Isto não é um número: doze”. Muda a primeira linha para \`String entrada = "12";\` e executa outra vez: agora aparece “Dobro: 24”. -## Saber de profissional: as exceções são objetos +## As exceções são objetos Isto não está no programa da disciplina, mas é útil saber. @@ -34827,7 +34827,7 @@ Primeiro preparar, depois mostrar. Como no teatro: a cortina só sobe quando o p Experimenta: apaga a linha com \`setVisible(true)\` e executa o programa outra vez. O programa corre, mas não vês nenhuma janela. -## Saber de profissional: classes e objetos +## Classes e objetos Isto não está no programa da disciplina, mas ajuda-te a perceber o Swing. @@ -35357,7 +35357,7 @@ frage: Quantas linhas “Clique!” há depois na consola? > O ouvinte corre a **cada** clique, não só no primeiro. Três cliques, três linhas. ::: -## Saber de profissional: ActionListener é uma interface +## ActionListener é uma interface Isto não está no programa da disciplina. Se quiseres saber o que está por trás da seta, continua a ler. @@ -36745,7 +36745,7 @@ dividir.addActionListener(e -> { Com \`double\` e \`Double.parseDouble(…)\` há casas decimais: 7 / 2 dá 3.5. Em contrapartida, com números decimais o Java não lança nenhuma exceção ao dividir por 0. O resultado é então \`Infinity\`, ou seja, “infinito”. ::: -## Saber de profissional: um método próprio +## Um método próprio Isto não está no programa da disciplina, mas torna o código mais curto. @@ -37001,7 +37001,7 @@ public class AdivinhaNumero { Com \`setEnabled(true)\` voltas a ligar um botão. Assim podes, por exemplo, só ativar um botão depois de alguém ter escrito alguma coisa. ::: -## Saber de profissional: ganhar com 7 tentativas +## Ganhar com 7 tentativas ::: angeberwissen Quem adivinha com jeito nunca precisa de mais de 7 tentativas. Escolhe sempre o meio do intervalo que ainda resta: primeiro 50, depois 25 ou 75 e assim por diante. Cada palpite corta o intervalo a meio: 100, 50, 25, 13, 7, 4, 2, 1. É a **pesquisa binária** da lição 19. Como 2 elevado a 7 = 128 é maior do que 100, chegam 7 palpites. @@ -37399,7 +37399,7 @@ Depois melhora-o: - no extra, o visor só mostra estrelas mas o código continua a ser verificado. ::: ludwig -Também na calculadora da lição 35 chega um ouvinte para +, -, \\* e /. Verifica lá dentro com \`e.getActionCommand().equals("+")\` que sinal de operação foi clicado. +No ramo do **OK**, conta \`tentativas++\` a cada código errado e depois verifica \`if (tentativas >= 3)\`. Aí \`ok.setEnabled(false)\` desliga o botão, como no Adivinha o número. Para as estrelas: \`entrada = entrada + e.getActionCommand();\` e \`visor.setText(visor.getText() + "*");\`. Depois comparas \`entrada\`, não o texto do visor. ::: ## Lista de verificação @@ -37462,7 +37462,7 @@ kurz: Escrever um ouvinte como classe interna com nome, como classe anónima e c O contador de cliques da lição 32 já conheces. Hoje escreves o seu ouvinte de **três maneiras**, que fazem todas exatamente o mesmo: 1. como **classe interna com nome**, como se fazia quase sempre antes do Java 8, -2. como **classe anónima**, que conheces do saber de profissional da lição 30, +2. como **classe anónima**, que conheces da lição 30 (“ActionListener é uma interface”), 3. como **lambda** com a seta, como até agora. Em código de outras pessoas, em livros e na internet vais encontrar as três. Depois desta lição vais reconhecê-las. @@ -39163,6 +39163,12 @@ public class Einheiten { } \`\`\` +**Du bist fertig, wenn …** + +- 1.5 nach **in cm** „150.0 cm“ zeigt, nach **in mm** „1500.0 mm“, +- 1500 nach **in km** „1.5 km“ zeigt, +- „abc“ im Feld „Bitte eine Zahl eingeben“ zeigt und das Fenster offen bleibt. + Zusatz: Ein vierter Knopf **in Fuß** rechnet in die englische Einheit um. Ein Fuß sind 0.3048 m. ::: ludwig @@ -39675,6 +39681,13 @@ Deine Aufgabe: 3. Schreibe die View \`StatistikAnzeige\`. Sie zeigt zum Beispiel „Sechsen: 2 von 10 Würfen“. 4. Der Controller ist der Zuhörer am Knopf: Er lässt das Model würfeln und gibt beiden Views die neuen Werte. +**Du bist fertig, wenn …** + +- in der Konsole nach zehn Würfen \`wuerfe\` gleich 10 ist und \`sechsen\` zwischen 0 und 10 liegt, +- jeder Klick auf **Würfeln** eine neue Zahl von 1 bis 6 in der \`AugenAnzeige\` zeigt, +- die \`StatistikAnzeige\` nach jedem Klick einen Wurf mehr zählt und Sechsen richtig mitzählt, +- im Model kein \`JLabel\` und in den Views kein \`Math.random\` steht. + Zusatz: Ein Knopf **Neues Spiel** setzt alles auf Anfang. Die Methode dafür gehört ins Model. ::: ludwig @@ -40044,6 +40057,12 @@ public class Units { } \`\`\` +**You are done when …** + +- 1.5 shows "150.0 cm" after **in cm** and "1500.0 mm" after **in mm**, +- 1500 shows "1.5 km" after **in km**, +- "abc" in the field shows "Please enter a number" and the window stays open. + Extra: a fourth button **in feet** converts to the imperial unit. One foot is 0.3048 m. ::: ludwig @@ -40556,6 +40575,13 @@ Your task: 3. Write the view \`StatsView\`. It shows for example "Sixes: 2 of 10 rolls". 4. The controller is the listener at the button: it lets the model roll and hands the new values to both views. +**You are done when …** + +- after ten rolls in the console \`rolls\` is 10 and \`sixes\` is between 0 and 10, +- every click on **Roll** shows a new number from 1 to 6 in the \`PipsView\`, +- the \`StatsView\` counts one more roll after every click and counts the sixes correctly, +- there is no \`JLabel\` in the model and no \`Math.random\` in the views. + Extra: a button **New game** resets everything. The method for that belongs in the model. ::: ludwig @@ -40925,6 +40951,12 @@ public class Unidades { } \`\`\` +**Terminaste quando …** + +- 1.5 mostra "150.0 cm" depois de **em cm** e "1500.0 mm" depois de **em mm**, +- 1500 mostra "1.5 km" depois de **em km**, +- "abc" no campo mostra "Escreve um número" e a janela continua aberta. + Extra: um quarto botão **em pés** converte para a unidade inglesa. Um pé são 0.3048 m. ::: ludwig @@ -41437,6 +41469,13 @@ A tua tarefa: 3. Escreve a view \`VistaEstatistica\`. Mostra por exemplo "Seis: 2 em 10 lançamentos". 4. O controller é o ouvinte do botão: manda o model lançar e passa os valores novos às duas views. +**Terminaste quando …** + +- na consola, depois de dez lançamentos, \`lancamentos\` é 10 e \`seis\` está entre 0 e 10, +- cada clique em **Lançar** mostra um número novo de 1 a 6 na \`VistaPontos\`, +- a \`VistaEstatistica\` conta mais um lançamento depois de cada clique e conta bem os seis, +- no model não há nenhum \`JLabel\` e nas views não há nenhum \`Math.random\`. + Extra: um botão **Novo jogo** põe tudo no início. O método para isso pertence ao model. ::: ludwig @@ -77099,7 +77138,7 @@ ${l}`)}es=AW(((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,Sm(km,this.highlightMode)});const n=e("[data-sim=delay]");n.value=this.delay,n.addEventListener("change",()=>{this.delay=n.value,Sm(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(Rg(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}),...Fg(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 Rg(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,ZE="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(ZE,i);for(const[a,s]of Object.entries(e))n.setAttribute(a,String(s));return t!==void 0&&(n.textContent=t),n}function LE(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 Tm(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 WE(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:EE(196,92,Vn/2),class:"window"}));const o=Tm(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=LE(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 EE(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}`),Jg=new WeakMap;function Gg(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-BEFl6o8i.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 Jg.set(a,m),m}function NE(i,e,t=!1){return Gg(i,e,t).box}function FE(i){const e=i.querySelector(".visubot-model"),t=e&&Jg.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 RE(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=Gg([],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,Sm(km,this.highlightMode)});const n=e("[data-sim=delay]");n.value=this.delay,n.addEventListener("change",()=>{this.delay=n.value,Sm(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(Rg(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}),...Fg(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 Rg(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,ZE="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(ZE,i);for(const[a,s]of Object.entries(e))n.setAttribute(a,String(s));return t!==void 0&&(n.textContent=t),n}function LE(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 Tm(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 WE(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:EE(196,92,Vn/2),class:"window"}));const o=Tm(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=LE(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 EE(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}`),Jg=new WeakMap;function Gg(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-BlWxLlAd.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 Jg.set(a,m),m}function NE(i,e,t=!1){return Gg(i,e,t).box}function FE(i){const e=i.querySelector(".visubot-model"),t=e&&Jg.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 RE(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=Gg([],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 fg(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(jm(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=GE(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=jm(v.code),z=[];let I;i.kind==="zuhoerer"?(I=HE(xg(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(qE(A.text)):A.text.includes(` `)?B.append(VE(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 GE(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 jm(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 HE(i,e){const t=vg(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} @@ -77115,7 +77154,7 @@ ${l}`)}es=AW(((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 gN()){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))),Om(this.body),FE(this.body),this.openNeededColumns(a.blocks),Dm(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]:[]);cN(this.body)?(this.host.showEditor(),uN(this.body)&&this.host.reveal(["palette"])):mN(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(),dN(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(zm()){e.setAttribute("open","");const s=_("button",{},p("web_learn_teacher_off"));return s.addEventListener("click",()=>{BE(),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 DE(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}`))),Om(this.body),this.openNeededColumns(e.blocks),Dm(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 JE(e.game,x1);case"rescueGame":return QE(e.game,x1);case"driveGame":return XE(e.game,x1);case"crosswordGame":return UE(e.game,x1);case"caesar":return WE(e.key,e.text);case"cloze":return eN(e.cloze);case"pap":return rN(e.pap);case"textFile":return Ng(e.name,e.content);case"robotModel":return NE(e.focus,e.view,e.spin);case"robotQuiz":return RE(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=t4(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 n4(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"});Xx(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),xN(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=Mm(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=Ux(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,Mm(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),zm()&&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",pN(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",{},pg((c=d.result.files)==null?void 0:c.get(x.name)).join(" | ")||"–")));!d.passed&&!d.result.error&&qx(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)=>Zm(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=Zm(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 Zm(i){return(i.pairs??[]).map(e=>e.right).sort((e,t)=>e.localeCompare(t,"de"))}function xN(i){const e=Dg(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 vN=""+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 Yg=()=>gr()==="2";function tl(){try{localStorage.setItem(hr,"2")}catch{}}const $g=()=>gr()==="3";function Kg(){try{localStorage.setItem(hr,"3")}catch{}}const Xg=()=>gr()!==null;function ns(i){try{localStorage.setItem(hr,i==="on"?"1":"0")}catch{}}const yN=`VisuBot`,qn=()=>wi()!=="off",Lm=i=>i.replace(/[&<>"]/g,e=>({"&":"&","<":"<",">":">",'"':"""})[e]);function nl(){const i=Yg()?"object":$g()?"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")}
- ${Lm(p(t))}`}class wN{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")}

${zN()}${IN()}`,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-BEFl6o8i.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=tp(),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 ep(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 zN(){const i=(t,n,a,s,r)=>``,e=(t,n,a)=>``;return`
🎛 ${p("web_visubot_controls")} + ${Lm(p(t))}`}class wN{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")}

${zN()}${IN()}`,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-BlWxLlAd.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=tp(),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 ep(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 zN(){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)} @@ -77363,7 +77402,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-BEFl6o8i.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-BlWxLlAd.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=Tg(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&&ep(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 eQ={left:12,top:10},tQ=8,ir=8e3,Ai=16,yo=12,N2="#fafafa";function F2(i){const e=i.caption.trim();return e===""?p("diagram_title_placeholder"):e}function Dd(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 Bd(i,e){return Dd(i.caption)||Dd(e)||"VisuStruct"}function nQ(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 Od(i,e,t,n=320){const a={...i,elements:i.elements.map(ds)},s=new xh(e,t).layout(a,eQ),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=nQ(F2(i),r-2*yo,t),u=Math.ceil(Ai*1.2),m=Math.min(56,l.length*u+2),c=m+o,d=new zh(e,t).render(s,{width:r,height:o},void 0,tQ);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:N2}));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 R2(i){return` `+new XMLSerializer().serializeToString(i.svg)}async function Md(i,e){const t=Math.max(1,Math.min(e,ir/i.width,ir/i.height)),n=URL.createObjectURL(new Blob([R2(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=N2,r.fillRect(0,0,s.width,s.height),r.drawImage(a,0,0,s.width,s.height),s}finally{URL.revokeObjectURL(n)}}function iQ(i){return new Promise((e,t)=>i.toBlob(n=>n?e(n):t(new Error("PNG konnte nicht erzeugt werden.")),"image/png"))}function aQ(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 sQ(i){const e=new Blob([i]).stream().pipeThrough(new CompressionStream("deflate"));return new Uint8Array(await new Response(e).arrayBuffer())}function Zd(i){let e="FEFF";for(let t=0;t`}async function rQ(i,e,t,n,a){const{page:s,draw:r}=aQ(n.width,n.height),o=await sQ(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 @@ -77585,7 +77624,7 @@ ${c}
- ${W(p("web_about_version_fmt").replace("%@","0.15.4"))} + ${W(p("web_about_version_fmt").replace("%@","0.15.5"))}
@@ -77657,7 +77696,7 @@ ${c}

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

-

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

+

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

Holger Sebastiao

${e("about_web_label","https://visustruct.visucode.de","visustruct.visucode.de")} ${e("about_developer_label","https://www.sebastiao.org","www.sebastiao.org")} @@ -77679,4 +77718,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:Nd()}),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:Nd()}),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=Bd(this.doc,hn(this.tab));return this.offerDownload(`${s}.visustruct`,new Blob([d1(this.doc)],{type:"application/xml"}))}const t=Od(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=Bd(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([R2(t)],{type:"image/svg+xml"}));break}case"png":{const s=await Md(t,a);await this.offerDownload(`${n}.png`,await iQ(s));break}case"pdf":{const s=await Md(t,Math.max(a,3)),r=await rQ(oQ(s),s.width,s.height,t,F2(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:Ed.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 rh(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 oh(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(()=>oh(e),350)))}),document.addEventListener("focusin",i=>{const e=i.target.closest("[data-tip]");So(),e!=null&&e.matches(":focus-visible")&&oh(e)});for(const i of["pointerdown","focusout","scroll","keydown"])document.addEventListener(i,So,!0)}const Yl="visustruct.reloadedAfterError";function V2(){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 CQ(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=>{V2()&&i.preventDefault()});const AQ=W3();Promise.all([Ah(AQ,!1),Ch(Z3(),!1)]).then(()=>{H2(),jQ();const i=new URLSearchParams(location.search);if(!["visustruct","visubot","visuobject","visuflow"].some(a=>i.has(a))&&!Xg()){const a=uh();a==="visubot"?ns("on"):a==="visuobject"&&tl()}i.has("visuobject")&&tl(),i.has("visuflow")&&Kg();const t=document.getElementById("app"),n=!i.has("visustruct")&&!i.has("visubot");if(Yg()&&n)return ee(async()=>{const{ObjectApp:a}=await import("./objectApp-BjkXZsrO.js").then(s=>s.g);return{ObjectApp:a}},[],import.meta.url).then(({ObjectApp:a})=>void new a(t));if($g()&&n)return ee(async()=>{const{FlowApp:a}=await import("./flowApp-CDuFZyj_.js");return{FlowApp:a}},[],import.meta.url).then(({FlowApp:a})=>void new a(t));new SQ(t)}).then(()=>{try{sessionStorage.removeItem(Yl)}catch{}}).catch(i=>{/dynamically imported module|Importing a module script failed|error loading dynamically/i.test(String(i))&&V2()||CQ(i)});export{Yn as C,Tq as J,Zx as L,ee as _,dq as a,Mq as b,D2 as c,ZQ as d,Kg as e,ns as f,IQ as g,wa as h,me as i,AN as j,CN as k,s3 as l,MQ as m,o1 as n,tl as o,Aq as p,Dd as q,Nm as r,GW as s,p as t,R2 as u,Md as v,nl as w,iQ as x,rQ as y,oQ 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:Nd()}),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:Nd()}),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=Bd(this.doc,hn(this.tab));return this.offerDownload(`${s}.visustruct`,new Blob([d1(this.doc)],{type:"application/xml"}))}const t=Od(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=Bd(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([R2(t)],{type:"image/svg+xml"}));break}case"png":{const s=await Md(t,a);await this.offerDownload(`${n}.png`,await iQ(s));break}case"pdf":{const s=await Md(t,Math.max(a,3)),r=await rQ(oQ(s),s.width,s.height,t,F2(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:Ed.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 rh(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 oh(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(()=>oh(e),350)))}),document.addEventListener("focusin",i=>{const e=i.target.closest("[data-tip]");So(),e!=null&&e.matches(":focus-visible")&&oh(e)});for(const i of["pointerdown","focusout","scroll","keydown"])document.addEventListener(i,So,!0)}const Yl="visustruct.reloadedAfterError";function V2(){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 CQ(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=>{V2()&&i.preventDefault()});const AQ=W3();Promise.all([Ah(AQ,!1),Ch(Z3(),!1)]).then(()=>{H2(),jQ();const i=new URLSearchParams(location.search);if(!["visustruct","visubot","visuobject","visuflow"].some(a=>i.has(a))&&!Xg()){const a=uh();a==="visubot"?ns("on"):a==="visuobject"&&tl()}i.has("visuobject")&&tl(),i.has("visuflow")&&Kg();const t=document.getElementById("app"),n=!i.has("visustruct")&&!i.has("visubot");if(Yg()&&n)return ee(async()=>{const{ObjectApp:a}=await import("./objectApp-Dl0a6-GP.js").then(s=>s.g);return{ObjectApp:a}},[],import.meta.url).then(({ObjectApp:a})=>void new a(t));if($g()&&n)return ee(async()=>{const{FlowApp:a}=await import("./flowApp-B31MybDd.js");return{FlowApp:a}},[],import.meta.url).then(({FlowApp:a})=>void new a(t));new SQ(t)}).then(()=>{try{sessionStorage.removeItem(Yl)}catch{}}).catch(i=>{/dynamically imported module|Importing a module script failed|error loading dynamically/i.test(String(i))&&V2()||CQ(i)});export{Yn as C,Tq as J,Zx as L,ee as _,dq as a,Mq as b,D2 as c,ZQ as d,Kg as e,ns as f,IQ as g,wa as h,me as i,AN as j,CN as k,s3 as l,MQ as m,o1 as n,tl as o,Aq as p,Dd as q,Nm as r,GW as s,p as t,R2 as u,Md as v,nl as w,iQ as x,rQ as y,oQ as z}; diff --git a/website/app/assets/objectApp-BjkXZsrO.js b/website/app/assets/objectApp-Dl0a6-GP.js similarity index 99% rename from website/app/assets/objectApp-BjkXZsrO.js rename to website/app/assets/objectApp-Dl0a6-GP.js index fb8d049d..b04b67ca 100644 --- a/website/app/assets/objectApp-BjkXZsrO.js +++ b/website/app/assets/objectApp-Dl0a6-GP.js @@ -1,5 +1,5 @@ -const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./projectZip-D1vNO4Uu.js","./index-BULnZN5t.js","./index-riD4EcmH.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-BULnZN5t.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-_t0Bkwfx.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.4"))} + ${b(d("web_about_version_fmt").replace("%@","0.15.5"))}
@@ -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-D1vNO4Uu.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-D1vNO4Uu.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-cdq8RhEl.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-cdq8RhEl.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-D1vNO4Uu.js b/website/app/assets/projectZip-cdq8RhEl.js similarity index 99% rename from website/app/assets/projectZip-D1vNO4Uu.js rename to website/app/assets/projectZip-cdq8RhEl.js index dd39852f..81795088 100644 --- a/website/app/assets/projectZip-D1vNO4Uu.js +++ b/website/app/assets/projectZip-cdq8RhEl.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-BjkXZsrO.js";import"./index-BULnZN5t.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-Dl0a6-GP.js";import"./index-_t0Bkwfx.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-BEFl6o8i.js b/website/app/assets/robot3d-BlWxLlAd.js similarity index 99% rename from website/app/assets/robot3d-BEFl6o8i.js rename to website/app/assets/robot3d-BlWxLlAd.js index f26dbcbc..67de3101 100644 --- a/website/app/assets/robot3d-BEFl6o8i.js +++ b/website/app/assets/robot3d-BlWxLlAd.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-BULnZN5t.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-_t0Bkwfx.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 51f8033c..07a5dc08 100644 --- a/website/app/index.html +++ b/website/app/index.html @@ -6,7 +6,7 @@ VisuStruct Web - +