Grafik_Upgrade.md verlangt "37 didaktisch wertvolle Visualisierungen". Es sind
19: Die Abschnitte "Modul 1-4" wiederholen die Grafiken 1-18 unter den Nummern
19-36, nur Grafik 37 ist zusaetzlich. Belegt an den Skriptnamen - 38
Nennungen, 19 verschiedene Dateien, erzeuge_kombinatorik_wand.py steht dreimal
darin. Von den 19 betreffen neun bereits vorhandene Diagramme.
Umgesetzt sind die zehn wirklich neuen plus eine elfte, die aus einem
Sachfehler des Auftrags entstand: Grafik 14 sollte in Abschnitt 12.3 stehen,
nannte aber Zahlen aus Kapitel 17. Beide Stellen haben jetzt ihre eigene
Grafik mit ihren eigenen Zahlen.
Vier Vorgaben des Auftrags wurden bewusst nicht befolgt: PNG bei 300 dpi (das
Buch kennt nur SVG - die 33 verwaisten PNGs waren gerade erst geloescht
worden), Matplotlib-Standardfarben (die Buchpalette steht in 33 Diagrammen),
harte Kapitelnummern im Fliesstext ({ref:sec:...} stattdessen) und die
fehlende Byte-Reproduzierbarkeit.
Der eigentliche Ertrag waren die Selbsttests. Jeder Generator prueft seine
Zahlen gegen das, was im Kapitel steht, und bricht bei Abweichung ab. Vier
haben angeschlagen:
* Kombinatorik-Wand: 25! ergibt 491,5 Mio. Jahre, die Tabelle nennt 490 Mio. -
Rundung auf zwei signifikante Stellen, nicht Fehler des Buchs.
* Laufzeit-Diagramm: Die abgedruckte Prozentspalte laesst sich aus den
abgedruckten Zeiten nicht exakt nachrechnen (0,001/0,008 ergibt 12 %,
gedruckt sind 14 %) - die Zeiten sind gerundet, die Prozente nicht.
* Predict-then-Optimize: geratene Datenaufteilung ergab 197,35 statt 200,95
MSE. Mit TRAINING aus dem Buchprogramm stimmen alle vier Kostenwerte.
* Almgren-Chriss: ein echter Fehler im Buchprogramm.
DER FUND: analytische_loesung() minimiert die eigene Kostenfunktion nicht. Ihr
Pfad kostet 10.860,40 EUR, der DP-Pfad 10.266,24 EUR - ein Gitterverfahren
kann das kontinuierliche Optimum aber nicht unterbieten. periodenkosten()
rechnet das Risiko mit lambda/2, die geschlossene Formel setzt
kappa~^2 = lambda*sigma^2*P0^2/eta ohne dieses Halbe. Mit lambda/2 liefert die
Formel 10.264,85 EUR und denselben Pfad wie die DP, knapp UNTER der
Gitterloesung. Die Grafik zeigt bis zur Entscheidung darueber den DP-Pfad; er
ist der, den das Kapitel abdruckt.
Nachweise: Alle elf Diagramme sind ueber zwei Laeufe byte-identisch. Kein
vorhandenes Diagramm wurde veraendert. Die Lastabwurf-Grafik reproduziert die
Befundtabelle exakt (874.870/2.504.154/28 von 40 gegen 351.356/415.924/0).
Zwei Abbildungen landeten beim automatischen Einfuegen im Codeblock (ihre
Anker standen in abgedruckten Ausgaben) und wurden dahinter verschoben; eine
Pruefung ueber alle elf zeigt null Fehlplatzierungen.
Neu: bilder_04/stil_04.py buendelt Palette, rcParams und speichere().
networkx wurde entgegen der Planung nicht gebraucht - pyproject.toml bleibt
unveraendert. PDF von 781 auf 788 Seiten, 44 Diagramme, 27 Generatoren.
Veroeffentlicht: 25 Dateien.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
263 lines
15 KiB
Markdown
263 lines
15 KiB
Markdown
# CLAUDE.md
|
||
|
||
Kontext zum Repository *Optimierte Entscheidungsfindung mit Python*, Version 04.
|
||
|
||
## Vor jeder Arbeit zuerst lesen
|
||
|
||
* **`PLAN.md`** — das Ziel und der Weg dorthin: alle sechs Phasen, die Zielstruktur, der
|
||
Kapitel-Baukasten, die dreizehn verbindlichen Regeln, die Verifikationsschritte. Ändert
|
||
sich nur bei einem Kurswechsel.
|
||
* **`PROGRESS.md`** — der erreichte Stand: eine Checkliste zur Wiederaufnahme, die
|
||
Referenzwerte zum Gegenprüfen, was erledigt ist, welche Funde es unterwegs gab und **was
|
||
der konkret nächste Schritt ist**. Wird nach jedem Arbeitsschritt fortgeschrieben.
|
||
|
||
Ohne diese beiden Dateien fehlt der Kontext, um sinnvoll weiterzuarbeiten — die Kapiteltexte
|
||
allein verraten weder den Stand noch die Konventionen. Alle sechs Phasen sind abgeschlossen;
|
||
`PROGRESS.md` Abschnitt 7 nennt, was bewusst offen geblieben ist und warum.
|
||
|
||
---
|
||
|
||
## Struktur
|
||
|
||
Dieses Verzeichnis ist die Wurzel; alle Skripte leiten ihre Pfade daraus ab
|
||
(`BASIS = dirname(dirname(__file__))` bzw. `dirname(HIER)`).
|
||
|
||
```
|
||
Operations_Research_mit_Python_Version_04/ Quelle: 37 Kapiteldateien + Build-Skripte
|
||
+ NEUER_TITEL.md (Titeltext)
|
||
bilder_04/ Quelle: Diagramme + erzeuge_*.py-Generatoren
|
||
web_04/ Quelle: site.css, site.js, icons.svg,
|
||
plotly.min.js, katex/ - die statischen
|
||
Bestandteile der Website
|
||
Operations_Research_mit_Python_Version_04.md generiert: Gesamtdokument
|
||
Operations_Research_mit_Python_Version_04.pdf generiert: PDF (xelatex)
|
||
OR_HTML_04/ generiert: Mehrseiten-Website
|
||
Operations_Research_mit_Python_Version_04_Programme/ generiert: Beispielprogramme
|
||
Notebooks_04/ generiert: ein .ipynb je Kapitel
|
||
pyproject.toml Quelle: Abhängigkeiten in Gruppen
|
||
Dockerfile, .dockerignore Quelle: Kurs-Image (Programme + JupyterLab)
|
||
LICENSE, LICENSE-TEXT.md MIT fuer Code, CC BY-SA 4.0 fuer den Text
|
||
.gitattributes LF im Repository, egal auf welchem System
|
||
.env.beispiel Vorlage; die echte .env (Ziel des Uploads)
|
||
ist bewusst NICHT im Repository
|
||
pandoc-defaults-basis.yaml, pandoc/, pandoc-defaults-buch.yaml PDF-Konfiguration
|
||
```
|
||
|
||
Nur die als **Quelle** markierten Verzeichnisse werden von Hand bearbeitet. Seit dem
|
||
Umzug nach `web_04/` stimmt dieser Satz auch: Vorher lagen `site.css`, `site.js`,
|
||
`icons.svg` und `katex/` mitten im erzeugten `OR_HTML_04/`. `--check` bewacht das jetzt
|
||
(`pruefe_assets()`), und der Bau bricht ab, wenn jemand die Kopie statt der Quelle
|
||
bearbeitet hat.
|
||
|
||
Dieses Verzeichnis ist seit dem 08.09.2026 ein **eigenes Git-Repository** (`main`). Das
|
||
übergeordnete `OR_mit_Python/` ist nur noch das Archiv der Historie bis zur Trennung und
|
||
verwaltet aktiv allein `Version_03`; es trägt `Version_04/` in seiner `.gitignore`. Commits
|
||
gehören ab jetzt hierher.
|
||
|
||
## Build
|
||
|
||
```bash
|
||
cd Version_04
|
||
python3 Operations_Research_mit_Python_Version_04/build_version_04.py --check # nur prüfen
|
||
python3 Operations_Research_mit_Python_Version_04/build_version_04.py --pdf --html
|
||
python3 Operations_Research_mit_Python_Version_04/extract_programme_04.py
|
||
python3 Operations_Research_mit_Python_Version_04/erzeuge_glossar_04.py # Anhang E
|
||
python3 Operations_Research_mit_Python_Version_04/veroeffentliche_04.py # hochladen
|
||
```
|
||
|
||
`veroeffentliche_04.py` lädt `OR_HTML_04/` per `rsync --delete` nach <https://jamulix.de/OR/>
|
||
— **nicht** per `scp`, denn das überschreibt nur und löscht nie; eine aus dem Buch entfernte
|
||
Seite bliebe sonst dauerhaft online. Vorher prüft es, ob eine Quelldatei neuer ist als die
|
||
gebaute Website (die Website hing einmal wochenlang einen Bau zurück, ohne dass es auffiel),
|
||
hinterher ruft es dreizehn Adressen per HTTP ab. Bei mehr als 30 Löschungen bricht es ab —
|
||
die Liste ist dann anzusehen, bevor `--loeschgrenze N` sie freigibt. Ziel in `.env`
|
||
(nicht im Repository, Vorlage `.env.beispiel`); Anmeldung per SSH-Schlüssel, kein Passwort.
|
||
|
||
`--check` prüft mehr als die Struktur: fehlende Codezäune, Links auf nicht existierende
|
||
Dateien und **harte Kapitel-/Abschnitts-/Aufgabennummern im Quelltext**. Es meldet Datei und
|
||
Zeile. Der Suchausdruck erlaubt beliebigen Zwischenraum — der letzte gefundene Fall war ein
|
||
`Handrechnung\n12.1` über zwei Zeilen, an dem jede zeilenweise Suche vorbeiläuft.
|
||
|
||
`build_version_04.py` fasst nicht notwendige harte Zeilenumbrüche innerhalb von Absätzen
|
||
zusammen (`reflow_markdown()`) — viele Markdown-Renderer stellen einen einzelnen Umbruch
|
||
sonst fälschlich als sichtbaren Umbruch dar.
|
||
|
||
---
|
||
|
||
## Die wichtigsten Konventionen
|
||
|
||
**Keine abgeleiteten Zahlen im Quelltext.** Das ist die Regel, an der dieses Projekt am
|
||
häufigsten gescheitert ist — **zehn** Mal an verschiedenen Stellen verletzt gefunden
|
||
(Anhang A, 66 Programm-Docstrings, die Übersichtstabellen der Anhänge, `CLAUDE.md` selbst,
|
||
eine Tabellenzelle, die 98 Lösungsmarken des Anhangs, neun Denkfehler-Verweise, sieben
|
||
„Übung N.N"-Verweise in alter Zählung, die Dateiübersicht des Leser-Wegweisers,
|
||
zuletzt der Titeltext der Startseite).
|
||
Seit dem letzten Fund trägt **keine** Marke mehr eine handgeschriebene Nummer, und `--check`
|
||
bewacht jede Familie. Konkret:
|
||
|
||
* Überschriften: `# Kapitel: <Titel> {#kap:<label>}`, `## Titel {#sec:<label>}` — die Nummer
|
||
vergibt der Build (`resolve_numbering()`, `nummeriere_abschnitte()`).
|
||
* Aufgaben, Handrechnungen, Abbildungen, Micro-Quiz: `**Aufgabe ⭐ — Titel.**`,
|
||
`> **✏️ Handrechnung: Titel**`, ``,
|
||
`> **❓ Micro-Quiz: Titel**` — Nummern von `nummeriere_marken()`.
|
||
* **Lösungen in Anhang A: `**{loesung} — Titel.**`** Der Präfix kommt nicht aus
|
||
`# Anhang A:`, sondern aus dem Kapitel des umgebenden `{#sec:loesungen-<X>}`-Abschnitts —
|
||
die Zuordnung `sec:loesungen-<X>` ↔ `kap:<X>` gilt für alle 23. `--check` zählt zusätzlich
|
||
ab, dass es je Kapitel so viele Lösungen wie Aufgaben gibt.
|
||
* **Der Denkfehler bekommt bewusst gar keine Nummer.** Es gibt je Kapitel genau einen, unter
|
||
einer bereits nummerierten Überschrift. Verwiesen wird auf
|
||
`{ref:sec:<kapitel>-denkfehler}`.
|
||
* Im Fließtext `{ref:<label>}`, nie eine Literalzahl.
|
||
* **Das Glossar (Anhang E) wird erzeugt.** Die 234 Einträge stehen in
|
||
`glossar_eintraege_04.py` als Viertupel *(Anzeigename, Indexmarke, Definition,
|
||
Verweisziel)*; `erzeuge_glossar_04.py` schreibt daraus `94_Anhang_Glossar.md`. Die `.md`
|
||
**nicht** von Hand bearbeiten — `--check` bemerkt es und nennt die Quelle. Der Erzeuger
|
||
prüft außerdem gegen das Buch: Jede Indexmarke muss dort buchstabengetreu vorkommen (sonst
|
||
entstünde ein zweiter Registereintrag für dasselbe Konzept), jedes `{ref:}`-Ziel muss
|
||
existieren, und kein Verweis darf auf das Glossar selbst zeigen. Begriffe, die es nur im
|
||
Glossar gibt, stehen ausdrücklich in `NUR_IM_GLOSSAR` — sonst ließe sich ein solcher Fall
|
||
nicht von einem Tippfehler unterscheiden.
|
||
* **Der Titeltext steht in `Operations_Research_mit_Python_Version_04/NEUER_TITEL.md`** und
|
||
nirgends sonst. `titeltexte_04.py` liest ihn; die PDF-Titelseite
|
||
(`bilder_04/erzeuge_titelseite.py`) und der Hero-Block der Startseite
|
||
(`baue_landingpage()`) speisen sich daraus. Eine Titeländerung wird **einmal** dort
|
||
gemacht. Das Vorwort trägt denselben Text als Buchprosa — `pruefe_titeltexte()`
|
||
vergleicht ihn bei jedem `--check` mit der Quelle.
|
||
* **Die Dateiübersicht in `Operations_Research_mit_Python_Version_04/README.md`** steht
|
||
zwischen `<!-- KAPITELTABELLE:ANFANG -->` und `<!-- KAPITELTABELLE:ENDE -->` und wird von
|
||
`schreibe_kapiteltabelle()` aus derselben Struktur erzeugt wie die Nummern im Buch. Nicht
|
||
von Hand bearbeiten — `--check` meldet einen veralteten Block, ein Lauf ohne `--check`
|
||
zieht ihn nach.
|
||
* In Code-Kommentaren und Docstrings der Kapitel**name** („Kapitel Metaheuristiken:"), nie
|
||
die Nummer. Auch nicht im Dateinamen.
|
||
|
||
**Querverweise für die Website** laufen über `baue_seiten_registry()` /
|
||
`resolve_numbering_seite()`, nicht über `resolve_numbering()` — nur dort entsteht aus einem
|
||
seitenübergreifenden Verweis `andere-seite.html#anker`.
|
||
|
||
**Stichwortregister:** `{idx:Begriff}` bzw. `{idx:Oberbegriff!Unterbegriff}`. Vor einem neuen
|
||
Begriff prüfen, ob er schon existiert:
|
||
`grep -ohE '\{idx:[^}]+\}' Operations_Research_mit_Python_Version_04/*.md | sort -u` — sonst
|
||
entstehen zwei Registereinträge für dasselbe Konzept. `texindy` sortiert mit dem deutschen
|
||
`din5007`-Modul (Umlaute wie im Telefonbuch); das generische `-L german` bricht ab.
|
||
|
||
**Programme sind ein Artefakt, keine zweite Quelle.** Änderungen gehören in den
|
||
Kapitel-Codeblock, danach `extract_programme_04.py`. Ein Codeblock gilt als vollständiges
|
||
Programm, wenn er mit `#!/usr/bin/env python3`, einer Leerzeile und `# Name.py` beginnt.
|
||
Auch das `README.md` im Programme-Verzeichnis wird erzeugt — aus der Vorlage
|
||
`README_Programme.md`; `requirements.txt` ist die einzige dort von Hand gepflegte Datei.
|
||
|
||
**`or_kern.py` ist der gemeinsame Unterbau** aller Programme (Domänenmodell, `SolverStatus`,
|
||
`Loesung`-DTO, Abnahmeprüfung). Abgedruckt im Kapitel Praxisfallen.
|
||
|
||
**`ortools` und `highspy` lassen sich nicht im selben Prozess importieren** (beide bringen
|
||
eine eigene HiGHS-Kopie mit). Deshalb lädt `or_kern.py` Solverbibliotheken erst in der
|
||
aufrufenden Funktion, und Programme, die beide brauchen, starten getrennte Prozesse (Muster:
|
||
`Ein_System_Vier_Ansaetze.py`, `Solverwechsel_CPSAT_HiGHS.py`). `cvxpy` zieht ein
|
||
installiertes `highspy` bei der Solver-Erkennung selbst mit hinein — der Konflikt entsteht
|
||
also auch indirekt.
|
||
|
||
**Neue Kapiteldatei** ⇒ in die `DATEIEN`-Liste in `build_version_04.py`.
|
||
**Neues Programm** ⇒ drei Stellen: Kapitelkopf („Programme:"), Vorwort
|
||
(„Verzeichnis der Beispielprogramme"), bei neuer Abhängigkeit `requirements.txt` **und**
|
||
`pyproject.toml` (dort in die passende Gruppe, nicht pauschal in die Grundausstattung).
|
||
|
||
Die vollständigen **dreizehn Regeln** stehen in `PLAN.md` Abschnitt 9 — darunter, dass jede
|
||
abgedruckte Ausgabe aus einem echten Lauf stammt und dass `PROGRESS.md` in denselben Commit
|
||
gehört wie die Arbeit, die sie beschreibt.
|
||
|
||
---
|
||
|
||
## Diagramme
|
||
|
||
`bilder_04/erzeuge_*.py` erzeugen 29 der 42 Kapiteldiagramme, jeweils **aus derselben
|
||
Instanz wie das zugehörige Buchprogramm**. Die elf neueren benutzen `bilder_04/stil_04.py`
|
||
— Palette, `rcParams` und `speichere()` an einer Stelle statt elfmal; die älteren setzen
|
||
`svg.hashsalt` und `metadata={"Date": None}` weiterhin selbst. (Das 33. SVG im Verzeichnis ist `titelseite.svg`,
|
||
die der Build bei jedem Lauf selbst schreibt — deshalb nennt `README.md` 33 und diese Datei
|
||
32.) Das ist kein Selbstzweck: Von zehn nachgebauten Bildern förderten
|
||
sieben einen Fehler zutage — dreimal ein Modell, das im Buch gar nicht vorkommt, einmal
|
||
widersprüchliche Zahlen zwischen Bild und Text, einmal ein gekipptes Vorzeichen. Wer ein
|
||
Diagramm anfasst, vergleicht es zuerst mit dem Modell des Kapitels.
|
||
|
||
Die übrigen 14 sind schematisch (Kästen, Pfeile, beschriftete Formeln) und bekommen bewusst
|
||
keinen Generator — dort kann nichts driften. Das Kriterium steht in `PROGRESS.md`
|
||
Abschnitt 6c.
|
||
|
||
Konventionen der Generatoren: `plt.rcParams["svg.hashsalt"] = "or-mit-python-v04"` und
|
||
`metadata={"Date": None}` für byteidentische Läufe — **beides, sonst trägt das SVG einen
|
||
Zeitstempel und wechselnde `clip-path`-IDs**. Geschrieben wird **nur SVG**; PNG-Zweitfassungen
|
||
gab es einmal, sie wurden nirgends referenziert; stammt die Instanz aus einem
|
||
Zufallsstrom, wird die Ziehungsreihenfolge des Buchprogramms nachgespielt.
|
||
|
||
## Plotly-Figuren
|
||
|
||
`{plotly:name}` bindet `bilder_04/plotly/<name>.html` in die Kapitelseite ein. Das Fragment
|
||
wird als Rohblock ` ```{=html} ` ausgegeben — **nicht** als blankes HTML: Plotlys Fragment ist
|
||
eine einzige lange Zeile mit eingebetteten Leerzeichenketten, aus der Pandoc sonst einen
|
||
Codeblock macht. Genau daran waren alle vier Figuren kaputt, bis es die Schlussabnahme fand.
|
||
Im PDF steht stattdessen ein Hinweis auf die Website.
|
||
|
||
## Karten
|
||
|
||
`{karte:name}` bindet `bilder_04/karten/<name>.html` als `<iframe>` ein — anders als bei
|
||
Plotly **nicht** inline, weil Leaflets Stylesheet sonst in die Buchseite hineingriffe. Im PDF
|
||
steht wieder ein Hinweis auf die Website. `--check` prüft für beide Markenarten, dass die
|
||
Datei existiert.
|
||
|
||
Erzeugt werden die Karten von demselben `bilder_04/erzeuge_*.py`, das auch das zugehörige SVG
|
||
schreibt — **aus einem Lauf**, sonst zeigten die beiden Darstellungen bei einem heuristischen
|
||
Solver womöglich verschiedene Lösungen. Zwei Vorkehrungen in `erzeuge_vrp_touren.py` sind
|
||
übertragbar:
|
||
|
||
* **Byte-Reproduzierbarkeit:** Folium vergibt jedem Element eine `uuid4`. `normalisiere()`
|
||
ersetzt sie durch fortlaufende Nummern — dieselbe Sorgfalt wie `svg.hashsalt` bei den
|
||
matplotlib-Bildern.
|
||
* **Netzunabhängigkeit:** Von Foliums zehn CDN-Einbindungen bleiben die zwei gebrauchten,
|
||
umgeschrieben auf `../../assets/leaflet.*` (mitgeliefert in `web_04/assets/`); die übrigen
|
||
acht entfallen, weil die Karte nur `CircleMarker`, `PolyLine` und `Tooltip` benutzt. Ohne
|
||
Netz fehlen nur die Kartenkacheln.
|
||
|
||
**Die Instanz ist synthetisch und bleibt es.** `projiziere()` legt das 100 × 100-km-Raster
|
||
azimutal-äquidistant auf eine reale Region; `pruefe_projektion()` bricht ab, wenn die
|
||
Abstände dabei um mehr als 0,01 % verzerrt würden (gemessen: 0,001 %). Kein abgedruckter Wert
|
||
ändert sich dadurch — das war die Bedingung, unter der die Karte überhaupt möglich wurde.
|
||
|
||
---
|
||
|
||
## Veroeffentlichung
|
||
|
||
Das Buch steht online auf <https://jamulix.de/OR/>, das Repository oeffentlich auf
|
||
<https://kitux.de/forgejo/dschlueter/operations_research>.
|
||
|
||
Die Website hat vier Übersichtsseiten: `index.html` (Landing), `programme.html`,
|
||
`notebooks.html` und `stichwortverzeichnis.html`. Die beiden Downloadverzeichnisse
|
||
`programme/` und `Notebooks_04/` bekommen je eine `index.html`, die auf ihre Übersicht
|
||
weiterleitet — sonst antwortet der Webserver mit 403, weil Directory-Listing abgeschaltet
|
||
ist.
|
||
|
||
**Nach jedem `--pdf --html` gehoert `veroeffentliche_04.py` hinterher** — sonst laeuft die
|
||
veroeffentlichte Fassung dem Repository hinterher, und genau das ist einmal wochenlang
|
||
unbemerkt geblieben. Von Hand muss dabei nichts mehr geprueft werden: Das Skript weigert
|
||
sich, einen veralteten Bau hochzuladen, und ruft anschliessend vierzehn Adressen ab.
|
||
|
||
Der erste Lauf am 08.09.2026 uebertrug 213 Dateien und loeschte 35 — 33 verwaiste PNGs, ein
|
||
leeres `__pycache__/` und die geteilte Anhangseite. Alle 35 haette ein `scp`-Upload stehen
|
||
gelassen.
|
||
|
||
**`COLAB_BASIS_URL` ist bewusst leer.** Colab oeffnet Notebooks nur aus GitHub, Google Drive
|
||
oder einem Upload; die URL-Form `colab.research.google.com/github/...` ist fest auf GitHub
|
||
verdrahtet und kann eine selbstgehostete Git-Instanz nicht lesen. Statt eines toten Knopfes
|
||
bekommt jedes Kapitel einen Download-Link auf sein Notebook. Wer spaeter nach GitHub
|
||
spiegelt, traegt dort **einen** Wert ein.
|
||
|
||
Wer ohne eigene Installation rechnen will, nimmt das Kurs-Image:
|
||
`docker run --rm -p 127.0.0.1:8888:8888 or-mit-python` startet JupyterLab mit allen
|
||
25 Notebooks. Ohne Portfreigabe und mit einem Programmnamen als Argument fuehrt dasselbe
|
||
Image ein einzelnes Programm aus.
|
||
|
||
---
|
||
|
||
## Sprache
|
||
|
||
Kommentare, Ausgaben und Fließtext sind durchgängig **Deutsch** — diesen Stil beibehalten.
|