# LPIC-Prüfungssimulator > Stand: 29.10.2026 · Statische Web-Anwendung (reveal.js 5.1.0, Dracula-Theme), läuft direkt von `file://` und von jedem statischen Webserver. > Inoffizielles Lernwerkzeug, nicht mit dem Linux Professional Institute (LPI) verbunden. „LPIC“ ist eine Marke des LPI. > Die Nutzungsrechte an Fragen und Code klärt jeder Empfänger selbst; reveal.js steht unter MIT-Lizenz (`vendor/reveal/LICENSE`). ## Dokumente | Datei | Inhalt | |---|---| | [docs/exam_format.md](docs/exam_format.md) | LPIC-1: Prüfungsformat, Objectives 5.0 mit Gewicht, LPI-Regeln, Quellen | | [docs/question_rules.md](docs/question_rules.md) | Regeln für Fragen (technisch und inhaltlich) | | [docs/decisions.md](docs/decisions.md) | Festlegungen mit Begründung, offene Punkte | | [docs/REVIEW.md](docs/REVIEW.md) | Anleitung für Prüfer | | [AGENTS.md](AGENTS.md) | Hinweise für KI-Assistenten der Prüfer | ## Benutzung | Weg | Aufruf | |---|---| | Lokal | `index.html` im Browser öffnen (Doppelklick genügt, kein Server nötig) | | Export + Webserver | `python3 tools/build_bank.py -e` schreibt nur die Laufzeitdateien nach `dist/` (ohne `data/`, `tools/`, `tests/`), dann `python3 -m http.server 8080 -d dist` | **Startseite:** Prüfung wählen (LPIC-1 101 oder 102), Modus wählen, im Lernmodus optional Topics, Anzahl und Reihenfolge. | Modus | Ablauf | |---|---| | Lernmodus | Antwort wählen → **Weiter** (→, Leertaste, „Auflösen ▸“) zeigt die Auflösung: richtig/falsch, Erläuterung je Option, Gesamterläuterung, Manpage-Verweis. Nochmal Weiter → nächste Frage. Aufgelöste Fragen sind gesperrt. | | Prüfungsmodus | 60 Fragen, 90 Minuten Countdown, Auswahl gewichtet nach Objectives (Gewicht = Fragenzahl wie in der echten Prüfung). Fragen markieren, frei vor/zurück, Abgabe auf der letzten Folie (automatisch bei Zeitablauf). Danach Auswertung je Topic und Auflösung aller Fragen. | Tasten: → / Leertaste weiter · ← zurück · `1`–`5` Antwort wählen · Enter im Textfeld = weiter. ## Speichern, Pause, Fortsetzen - Jede Eingabe wird sofort im Browser gespeichert (`localStorage`, Schlüssel `lpic_sim.session`). Beim nächsten Öffnen bietet die Startseite **Fortsetzen** an. - **Export** (Werkzeugleiste) lädt die Sitzung als JSON herunter (`lpic_sim___.json`). Die Datei enthält die Fragen selbst; sie bleibt damit auch nach Änderungen an der Fragenbank und auf anderen Rechnern nutzbar. - **Import** erkennt das Format selbst: Eine Sitzung wird an der gespeicherten Stelle fortgesetzt, ein Fragenpaket in die Bank übernommen (und im Browser gemerkt). - `localStorage` gilt je Browser und Herkunft: `file://` und `http://…` sehen getrennte Daten – dafür Export/Import nutzen. ## Fragen ergänzen 1. Datei `data//questions_.json` bearbeiten oder neu anlegen (Schema: [`data/schema/questions.schema.json`](data/schema/questions.schema.json) – VSCode/VSCodium validiert über den `$schema`-Eintrag). 2. `python3 tools/build_bank.py -c` prüft alle Fragen und zeigt Prüfstatus und Abdeckung je Objective. 3. `python3 tools/build_bank.py` erzeugt `js/bank.js` (diese Datei nie von Hand ändern), mit `-e` zusätzlich den Export `dist/`. Ohne Build-Schritt: dieselbe JSON-Datei im Simulator über **Import** laden. ### Quelltext vs. ausgelieferte Bank | | Quelltext `data/*.json` | `js/bank.js` / Export | |---|---|---| | Form | Klartext-JSON, für Prüfer lesbar und kommentierbar | ChaCha20-verschlüsselt (RFC 8439), Base64 | | Zweck | Durchsicht, Freigabe/Ablehnung, Pflege | Auslieferung, kein Klartext auf der Platte | - **PSK:** Umgebung `LPIC_SIM_PSK`, sonst `tools/.psk` (beim ersten Build zufällig erzeugt, Rechte 600, nicht weitergeben – im Prüferpaket nicht enthalten). Der Schlüssel ist `SHA-256("lpic-sim/bank/v1:" + PSK)` und steht als `build`-Kennung in `bank.js`, die Nonce als `rev` – der PSK selbst nirgends. - **Grenze:** Der Browser muss ohne Eingabe entschlüsseln können, also wird der Schlüssel mit ausgeliefert. Das verhindert Klartext auf der Platte, Suchen mit `grep` und zufälliges Mitlesen, schützt aber **nicht** vor jemandem, der gezielt `app.js` und `bank.js` analysiert. - **Weiterhin im Klartext:** exportierte Sitzungen (JSON-Datei), die gespeicherte Sitzung und importierte Pakete im `localStorage` – sie enthalten die Fragen der jeweiligen Sitzung. ### Prüfvermerk (Review) Prüfer tragen je Frage einen Vermerk ein; ohne Vermerk gilt `pending`: ```json "review": { "status": "rejected", "by": "Prüfer A", "date": "2026-10-30", "note": "Option C ebenfalls korrekt" } ``` | Status | Wirkung beim Build | |---|---| | `pending` | übernommen (Standard), mit `--approved-only` nicht | | `approved` | übernommen | | `rejected` | nie übernommen; bleibt im Quelltext zur Nachbearbeitung | Der Vermerk selbst wird nicht in die Bank übernommen. Freigabe-Build: `python3 tools/build_bank.py --approved-only -e`. ### Format einer Frage ```json { "id": "103.4-007", "objective": "103.4", "type": "single", "difficulty": 2, "question": "Text mit `Code` und **Betonung**", "code": "optionaler\nmehrzeiliger Block", "options": [ { "id": "a", "text": "…", "correct": true, "explanation": "warum richtig" }, { "id": "b", "text": "…", "correct": false, "explanation": "warum falsch" } ], "explanation": "Gesamterläuterung", "references": ["man 1 bash"] } ``` | `type` | Regel (geprüft von `build_bank.py` und beim Import) | |---|---| | `single` | genau 5 Optionen `a`–`e`, genau 1 richtig | | `multi` | genau 5 Optionen, 2–4 richtig; der Simulator zeigt „Wählen Sie ZWEI/DREI“ und begrenzt die Auswahl | | `fill` | keine Optionen, `answers` = akzeptierte Antworten (erste = Musterlösung), Leerraum wird normalisiert, `case_sensitive` (Standard `true`) | ### Regeln für Fragen Verbindlich in [docs/question_rules.md](docs/question_rules.md); Prüfablauf in [docs/REVIEW.md](docs/REVIEW.md). ## Weitere Prüfungen (z. B. LPIC-2) Ordner `data/lpic2_201/` mit `exam.json` (Aufbau wie [`data/lpic1_101/exam.json`](data/lpic1_101/exam.json): `level`, `code`, `questions`, `duration_min`, Topics/Objectives mit Gewicht) und `questions_*.json` anlegen, dann `build_bank.py`. Die Startseite gruppiert automatisch nach `level`. Alternativ zur Laufzeit: ein Fragenpaket mit zusätzlichem Schlüssel `"definition"` (Inhalt einer `exam.json`) importieren. ## Inhalt | Pfad | Inhalt | |---|---| | `index.html` | Einstieg | | `js/app.js` | Logik (Sitzung, Bewertung, Speichern, Import, Darstellung); reine Funktionen unter `window.LPICSim.core` | | `js/bank.js` | **erzeugt** – verschlüsselte Fragenbank als `window.LPIC_BANK` (Script statt JSON, damit es unter `file://` lädt) | | `dist/` | **erzeugt** mit `build_bank.py -e` – Export zum Ausliefern | | `release/` | **erzeugt** mit `build_bank.py -b` – Prüferpaket `lpic-sim_.tar.gz` | | `docs/`, `AGENTS.md` | Dokumente (siehe oben) | | `css/simulator.css` | Ergänzungen zum Dracula-Theme | | `data/` | Quelle der Fragen: je Prüfung `exam.json` + `questions_*.json`, Schema unter `schema/` | | `tools/build_bank.py` | Prüfung und Build der Fragenbank (nur Python-Standardbibliothek) | | `tests/selftest.html` | Tests der Kernlogik inkl. ChaCha20-Testvektor RFC 8439 (44 Prüfungen) | | `tests/ui_smoke.html` | UI-Rauchtest im iframe: Lernmodus, Prüfungsmodus, Abgabe, Import (27 Prüfungen) | | `vendor/reveal/` | reveal.js 5.1.0 unverändert (MIT), Herkunft und Prüfsumme in `VERSION.txt` | ## Tests ```bash cd simulator python3 tools/build_bank.py -c chromium --headless --allow-file-access-from-files --virtual-time-budget=5000 --dump-dom tests/selftest.html | grep -o 'RESULT[^<]*' chromium --headless --allow-file-access-from-files --virtual-time-budget=40000 --dump-dom tests/ui_smoke.html | grep -oE '(FAIL|RESULT)[^<]*' ``` `--allow-file-access-from-files` braucht nur der iframe-Test, nicht der Simulator selbst. ## Pflege - Fragen: Bediener und Agent; nach jeder Änderung `build_bank.py -c` und Build, `bank.js` mit einchecken. - Neue Objectives-Version: `exam.json` anpassen (Version, Abrufdatum), betroffene Fragen prüfen. - reveal.js-Update: neue `dist/`-Dateien nach `vendor/reveal/`, `VERSION.txt` aktualisieren, Tests laufen lassen.