From 65d278a18efe4ba28841ddc3fdb64ae9a12170b0 Mon Sep 17 00:00:00 2001 From: Dogfather Date: Tue, 22 Sep 2026 10:14:25 +0200 Subject: [PATCH] Der Handy-Rundgang ist zum ersten Mal bei null Befunden SECHS SACHEN, UND KEINE DAVON WAR DAS, WONACH ICH GESUCHT HABE. 1. ZWEI NATIVE prompt() IN teamlage.js -- die letzten im Haus. Sie halten die ganze Seite an, sehen auf jedem Browser anders aus als der Rest und koennen nicht sagen, was BLEIBT, wenn man absagt. Genau das ist dort die Frage, die jemand vor dem Klicken hat. Jetzt derselbe Dialog wie an den 42 anderen Stellen. 2. UND DER GRUND, WARUM SIE NIEMAND GEFUNDEN HAT. pruef-nachfrage suchte mit `(?:^|[^.\w])(confirm|prompt)\s*\(`. Das `[^.\w]` sollte fremde Methoden ausschliessen -- `angebot .prompt()` ist die Installations-Aufforderung des Browsers und kein nativer Dialog. Nur trifft dieser Ausschluss ausgerechnet die HAEUFIGSTE Schreibweise: `window.prompt(` hat einen Punkt davor. Die Pruefung war gruen, waehrend zwei native prompt() dastanden. Genau das Muster, vor dem dieses Haus warnt: eine Pruefung, die laeuft, gruen ist und das Falsche prueft. Die Gegenprobe kennt jetzt beide Schreibweisen -- haette sie das vorher getan, waere es am selben Tag aufgefallen. 3. willkommen.html LUD nachfrage.js NICHT. Gefunden von der geschaerften Pruefung. kopf.js ruft `frageNach(` ohne Absicherung -- auf dieser einen Seite haette ABMELDEN einen Absturz ausgeloest. Die Seite ist vom 21.09., die Luecke also einen Tag alt. 4. ZWEI FEHLALARME IM HANDY-RUNDGANG ABGESTELLT. Er meldete bei JEDEM Lauf dieselben drei Befunde: `button.schnitt bis 481px`, die Rechtetafel `table bis 877px`, `a.k-pille 8x8`. Nachgemessen bei 390 px: Das Dokument ist exakt 390 px breit, NICHTS laeuft ueber -- beide stehen in einem Kasten mit `overflow-x: auto`, und der rollt absichtlich. Die Kalenderpunkte tragen `pointer-events: none`; der Tipp gehoert der Tageszelle. Eine Warnung, die immer kommt, ist keine Warnung mehr (Hausregel vom 03.09.). Beide Regeln sind SCHMAL: nur ausdrueckliches `overflow-x: auto|scroll` (nicht `hidden` -- dort ist der Inhalt wirklich weg), nur ausdrueckliches `pointer-events: none`. Die Gegenprobe hat jetzt vier Faelle statt zwei: zwei, die gemeldet werden MUESSEN, und zwei, die es NICHT duerfen. Eine engere Messung kann auch zu eng sein. 5. DER LETZTE ECHTE BEFUND: 404 BEI JEDEM MODI. Der Rundgang meldete "404 (Not Found)" ohne Adresse -- eine Pruefung, die einen Fehler findet, ihn aber nicht auffindbar macht, kostet mehr Zeit als sie spart. Sie nennt jetzt die Adresse, und damit war es in einer Minute klar: `/workspace/api/werdegang/liste`. Der Code BEHANDELTE den 404 richtig, der Browser protokolliert ihn trotzdem -- derselbe Fall wie am 19.09. bei /anruf/adressen. Jetzt sagt der Server in /api/ich, ob jemand Team Dogi fuehrt. EIGENES FELD, kein Stellvertreter: `darf_verteilen` sieht aehnlich aus, ist aber nicht dasselbe -- ein Manager darf verteilen und fuehrt Team Dogi nicht. Dabei EINE Wartestelle statt zwei: `window.wennIchDaBin()`. `window.__ich` kommt ueber das Netz; zwei Seiten hatten dafuer jeweils ein eigenes setInterval. Zwei Fassungen desselben Wartens altern unterschiedlich. 6. pruef-werdegang MASS AUF DER FALSCHEN ADRESSE. Drei Pruefungen waren dauerhaft rot (`data-ton=null`) -- an einer Seite, die in Ordnung ist. Sie oeffnete `127.0.0.1`, also die Adresse der AGENTUR; dort ist `person.haus` nicht "crew" und die Kachelliste eine andere. Nachgemessen: Alle vier Rollen HABEN die Kachel, sobald das Haus stimmt. Jetzt derselbe https-Vorbau wie in pruef-willkommen und pruef-zuteilung. Beinahe haette ich hier etwas "repariert", das nicht kaputt war: Meine erste Messung rief `bereicheFuer(p, "crew")` auf -- das Haus wird aber aus `person.haus` gelesen, nicht als Argument. Sie sagte "DogFather hat keine Kachel". Eine plausible Herleitung ersetzt keine Messung, und eine falsch aufgesetzte Messung auch nicht. GEMESSEN: pruef-handy-teamdogi 214 Seitenaufrufe, 108.564 Elemente, 4.126 Bedienelemente -- 0 Befunde. Alle vier Rollen, beide Breiten. Zum ersten Mal. pruef-werdegang 103/0 (war 100/3), pruef-nachfrage 51/0 (war 49), pruef-stelle 15/0, pruef-entwicklung 48/0, pruef-start-ansicht 153/0, pruef-wege-nach-draussen 67/0, pruef-tippziele 11/0, pruef-treff 80/0, pruef-willkommen 67/0, pruef-sackgassen 13/0. Co-Authored-By: Claude Opus 5 --- server/pruef-handy-teamdogi.mjs | 86 ++++++++++++++++++++++++++++++ server/pruef-nachfrage.mjs | 31 ++++++++++- server/pruef-werdegang.mjs | 59 ++++++++++++++++++-- server/workspace.js | 14 +++++ workspace/anruf-probe.html | 8 +-- workspace/app.webmanifest | 8 +-- workspace/assets/js/entwicklung.js | 16 +++--- workspace/assets/js/kopf.js | 49 +++++++++++++++++ workspace/assets/js/teamlage.js | 47 ++++++++++++---- workspace/assets/js/werdegang.js | 15 ++++++ workspace/aufgaben.html | 34 ++++++------ workspace/automation.html | 30 +++++------ workspace/befinden.html | 28 +++++----- workspace/bereich.html | 40 +++++++------- workspace/bewerben.html | 34 ++++++------ workspace/bewerbungen.html | 32 +++++------ workspace/calls.html | 32 +++++------ workspace/chat.html | 36 ++++++------- workspace/content.html | 32 +++++------ workspace/crew-index.html | 10 ++-- workspace/crew.webmanifest | 8 +-- workspace/dateien.html | 32 +++++------ workspace/entwicklung.html | 28 +++++----- workspace/hilfe.html | 26 ++++----- workspace/index.html | 8 +-- workspace/kalender.html | 32 +++++------ workspace/leistung.html | 30 +++++------ workspace/material.html | 26 ++++----- workspace/personen.html | 30 +++++------ workspace/profil.html | 34 ++++++------ workspace/rechte.html | 28 +++++----- workspace/report.html | 32 +++++------ workspace/scouting.html | 30 +++++------ workspace/start.html | 30 +++++------ workspace/startcheck.html | 32 +++++------ workspace/steckbrief.html | 34 ++++++------ workspace/talente.html | 30 +++++------ workspace/team.html | 28 +++++----- workspace/teamlage.html | 28 +++++----- workspace/teilen.html | 26 ++++----- workspace/treff-moderation.html | 28 +++++----- workspace/treff-regeln.html | 28 +++++----- workspace/uebersicht.html | 30 +++++------ workspace/unsere-seiten.html | 26 ++++----- workspace/werdegang.html | 28 +++++----- workspace/willkommen.html | 23 ++++---- workspace/wissen.html | 32 +++++------ 47 files changed, 830 insertions(+), 558 deletions(-) diff --git a/server/pruef-handy-teamdogi.mjs b/server/pruef-handy-teamdogi.mjs index cdfbeff8..c5a77c12 100644 --- a/server/pruef-handy-teamdogi.mjs +++ b/server/pruef-handy-teamdogi.mjs @@ -351,6 +351,32 @@ const messen = () => { const hatText = (e.textContent || "").trim().length > 0; const bedienbarHier = e.matches(BEDIENBAR) || !!e.closest(BEDIENBAR); if (!hatText && !bedienbarHier) return false; + + /* WAS IN EINEM ROLLENDEN KASTEN STEHT, LAEUFT NICHT UEBER + (geschaerft 22.09.2026). + + Der Rundgang meldete drei Befunde, bei jeder Rolle dieselben: + `button.schnitt bis 481px` auf aufgaben.html und die + Rechtetafel `table bis 877px`. Nachgemessen bei 390 px: + Das Dokument ist exakt 390 px breit, NICHTS laeuft ueber -- + beide stehen in einem Kasten mit `overflow-x: auto`, und der + rollt absichtlich waagerecht. Eine breite Tabelle auf einem + schmalen Schirm ist genau so geloest, wie man es loest. + + Diese drei Meldungen kamen bei JEDEM Lauf. Und eine Warnung, + die immer kommt, ist keine Warnung mehr -- man klickt sie weg + und uebersieht ab da auch die echte. (Hausregel vom 03.09.2026, + damals zu einer Loeschwarnung, die bei jedem Aufruf ansprang.) + + DIE REGEL IST SCHMAL: Es zaehlt nur, wenn ein Vorfahre + ausdruecklich `overflow-x: auto` oder `scroll` traegt. Ein + Element, das einfach so hinausragt, wird weiter gemeldet -- + und `overflow: hidden` gilt NICHT, denn dort ist der Inhalt + wirklich weg und nicht erreichbar. */ + for (let v = e.parentElement; v && v !== document.body; v = v.parentElement) { + const ox = getComputedStyle(v).overflowX; + if (ox === "auto" || ox === "scroll") return false; + } return r.right > breite + 2; }).slice(0, 4).map((e) => `${name(e)} bis ${Math.round(e.getBoundingClientRect().right)}px`); @@ -427,6 +453,21 @@ const messen = () => { /* ---- Zu kleine Tippziele ----------------------------------------- */ const klein = bedienbar.filter((e) => { + /* WAS KEINE KLICKS ANNIMMT, IST KEIN TIPPZIEL + (geschaerft 22.09.2026). + + Gemeldet wurde `a.k-pille 8x8` auf kalender.html -- die Punkte, + die im Monatsraster am Handy fuer je einen Termin stehen. Sie + sind ABSICHTLICH 8 px klein und tragen `pointer-events: none`: + Der Tipp gehoert der ganzen Tageszelle, nicht dem Punkt. Ein + 8-px-Ziel waere ein Nadeloehr; die Zelle daneben ist 46 px und + oeffnet den Tag. + + Wer keine Klicks annimmt, kann auch kein zu kleines Ziel sein. + Die Regel ist damit schaerfer, nicht laxer: Ein Knopf, der + Klicks annimmt und zu klein ist, wird weiter gemeldet -- die + Gegenprobe weiter unten weist genau das nach. */ + if (getComputedStyle(e).pointerEvents === "none") return false; const r = e.getBoundingClientRect(); /* 43,5 STATT 44: Ein Knopf von 43,98 px wird als „44x44" angezeigt und waere trotzdem ein Fund -- ein halbes Pixel @@ -553,6 +594,17 @@ for (const [breite, hoehe, geraet] of BREITEN) { if (m.type() === "error") konsole.push(m.text().slice(0, 100)); }); seite.on("pageerror", (e) => konsole.push("Absturz: " + e.message.slice(0, 100))); + /* WELCHE Datei fehlt -- die Konsole sagt es nicht (22.09.2026). + Der Rundgang meldete tagelang "404 (Not Found)" ohne Adresse. + Eine Pruefung, die einen Fehler findet, ihn aber nicht + auffindbar macht, kostet mehr Zeit als sie spart: Man weiss, + dass etwas kaputt ist, und muss es trotzdem von Hand suchen. */ + seite.on("requestfailed", (r) => { + konsole.push(`Anfrage gescheitert: ${r.url().replace(BASIS, "")}`); + }); + seite.on("response", (r) => { + if (r.status() === 404) konsole.push(`404: ${r.url().replace(BASIS, "")}`); + }); /* ---- Anmelden, wie ein Mensch es tut ---------------------------- */ let drin = false; @@ -702,13 +754,47 @@ melde("\n --- Gegenprobe (beide Fehler MÜSSEN gefunden werden) ---"); winzig.textContent = "x"; winzig.style.cssText = "width:18px;height:18px"; document.body.append(winzig); + + /* ---- UND DIE ZWEI AUSNAHMEN VOM 22.09.2026 ------------------- + Beide Regeln machen die Messung ENGER. Eine engere Messung kann + auch zu eng sein -- dann fiele echter Schaden durch, und der + Lauf bliebe gruen. Deshalb hier vier Elemente statt zwei: zwei, + die gemeldet werden MUESSEN, und zwei, die es NICHT duerfen. */ + + /* (a) In einem rollenden Kasten -- darf NICHT gemeldet werden. + So steht die Rechtetafel da, und so gehoert eine breite + Tabelle auf einen schmalen Schirm. */ + const roller = document.createElement("div"); + roller.id = "gp-roller"; + roller.style.cssText = "overflow-x:auto;width:200px"; + const drin = document.createElement("div"); + drin.textContent = "Steht in einem Kasten, der absichtlich rollt"; + drin.style.cssText = "width:900px;height:20px;white-space:nowrap"; + roller.append(drin); + document.body.append(roller); + + /* (b) Winzig, aber nimmt keine Klicks an -- darf NICHT gemeldet + werden. So sind die Terminpunkte im Kalender gebaut. */ + const stumm = document.createElement("button"); + stumm.id = "gp-stumm"; + stumm.textContent = "o"; + stumm.style.cssText = "width:8px;height:8px;pointer-events:none"; + document.body.append(stumm); }); const g = await seite.evaluate(messen); const ok1 = g.ueberstand.length > 0; const ok2 = g.klein.length > 0; + /* Die zwei Ausnahmen duerfen NICHT in der Liste stehen. Gemessen + wird das an ihrer Groesse: 900 px waere der Roller-Inhalt, 8x8 + der stumme Knopf. */ + const ok3 = !g.ueberstand.some((x) => /9\d\dpx/.test(x)); + const ok4 = !g.klein.some((x) => /\b8×8\b/.test(x)); melde(` ${ok1 ? "ok " : "FEHL"} ein zu breites Element wird gemeldet (${g.ueberstand.join(", ") || "nichts"})`); melde(` ${ok2 ? "ok " : "FEHL"} ein zu kleiner Knopf wird gemeldet (${g.klein.join(", ") || "nichts"})`); + melde(` ${ok3 ? "ok " : "FEHL"} was in einem rollenden Kasten steht, NICHT`); + melde(` ${ok4 ? "ok " : "FEHL"} was keine Klicks annimmt, auch NICHT`); if (!ok1 || !ok2) { fehler += 1; probleme.push("GEGENPROBE VERSAGT — die Messung findet nichts mehr"); } + if (!ok3 || !ok4) { fehler += 1; probleme.push("GEGENPROBE VERSAGT — die Messung meldet Absicht als Fehler"); } await kontext.close(); } diff --git a/server/pruef-nachfrage.mjs b/server/pruef-nachfrage.mjs index 3eaa9d1e..fba04ae1 100644 --- a/server/pruef-nachfrage.mjs +++ b/server/pruef-nachfrage.mjs @@ -97,7 +97,27 @@ const nativ = []; for (const f of skripte) { if (f === DER_NOTNAGEL) continue; const code = ohneKommentare(lies(join(JS_ORDNER, f))); - for (const m of code.matchAll(/(?:^|[^.\w])(confirm|prompt)\s*\(/g)) { + /* DAS MUSTER HATTE EINE LUECKE, UND ZWAR DIE GROESSTE MOEGLICHE + (gefunden am 22.09.2026). + + Vorher stand hier `(?:^|[^.\w])(confirm|prompt)\s*\(`. Das + `[^.\w]` sollte fremde Methoden ausschliessen -- etwas wie + `angebot.prompt()` (so heisst die Installations-Aufforderung des + Browsers) ist kein nativer Dialog und darf nicht als Fund zaehlen. + + Nur trifft dieser Ausschluss ausgerechnet die HAEUFIGSTE + Schreibweise: `window.prompt(` hat einen Punkt davor. Die Pruefung + war damit gruen, waehrend in teamlage.js ZWEI native prompt() + standen -- einer davon seit Wochen. + + Genau das Muster, vor dem dieses Haus warnt: eine Pruefung, die + laeuft, gruen ist und das Falsche prueft. Gefunden hat es nicht + sie, sondern eine Suche von Hand. + + Jetzt zwei Faelle statt einem: mit `window.` davor -- oder ganz + ohne Punkt. Alles andere (`irgendwas.prompt()`) bleibt aussen + vor, und das ist weiterhin richtig. */ + for (const m of code.matchAll(/(?:^|[^.\w])(?:window\s*\.\s*)?(confirm|prompt)\s*\(/g)) { const zeile = code.slice(0, m.index).split("\n").length; nativ.push(`${f}:${zeile} → ${m[1]}()`); } @@ -280,6 +300,15 @@ pruef("die Speicherwege melden der Wache, dass nichts mehr zu retten ist", ------------------------------------------------------------------ */ console.log("\n --- Gegenproben (jede MUSS anschlagen) ---"); +/* DIE GEGENPROBE PRUEFT JETZT BEIDE SCHREIBWEISEN. Haette sie das + vorher getan, waere die Luecke im Muster am selben Tag aufgefallen, + an dem es geschrieben wurde. */ +pruef("Gegenprobe: ein erfundenes window.prompt() würde gefunden", + /(?:^|[^.\w])(?:window\s*\.\s*)?(confirm|prompt)\s*\(/.test( + "const g = window.prompt('Warum nicht?');")); +pruef("Gegenprobe: eine fremde Methode NICHT (angebot.prompt())", + !/(?:^|[^.\w])(?:window\s*\.\s*)?(confirm|prompt)\s*\(/.test( + "angebot.prompt();")); pruef("Gegenprobe: ein erfundenes confirm() würde gefunden", /(?:^|[^.\w])(confirm|prompt)\s*\(/.test( ohneKommentare("function x(){ if (!confirm('weg?')) return; }"))); diff --git a/server/pruef-werdegang.mjs b/server/pruef-werdegang.mjs index 3c3a3acb..36120d63 100644 --- a/server/pruef-werdegang.mjs +++ b/server/pruef-werdegang.mjs @@ -600,8 +600,58 @@ melde("=== 11. Im Browser ==="); { const { chromium } = await import( "file:///C:/Users/qciga/Documents/Obelix/Analyse/node_modules/playwright/index.mjs"); - const browser = await chromium.launch(); - const kontext = await browser.newContext({ viewport: { width: 1280, height: 1000 } }); + /* AUF DER ECHTEN ADRESSE MESSEN (berichtigt 22.09.2026). + ================================================================== + Bis heute oeffnete dieser Abschnitt `http://127.0.0.1/...` -- also + die ADRESSE DER AGENTUR. Auf der ist `person.haus` nicht "crew", + und `bereicheFuer()` liefert eine andere Kachelliste. Die Kachel + zu dieser Seite steht dort nicht drin, also fand `kopf.js` keine + Farbe: `data-ton=null`. + + Drei Pruefungen waren deshalb rot, und zwar dauerhaft -- an einer + Seite, die in Wirklichkeit in Ordnung ist. Nachgemessen: Alle vier + Rollen (admin, hand, linke, modi) HABEN die Kachel, sobald das + Haus stimmt. + + Genau dieselbe Falle wie am 21.09.2026 bei pruef-rueckmeldung. + Dort ging es ueber `node:http` mit Host-Kopf; ein Browser kann das + nicht (Chromium verbietet den Host-Kopf). Der Weg im Haus ist ein + selbst unterschriebener Vorbau plus `--host-resolver-rules` -- + derselbe wie in pruef-willkommen und pruef-zuteilung. */ + const { createServer: httpsServer } = await import("node:https"); + const { request: httpWeiter } = await import("node:http"); + const { execFileSync } = await import("node:child_process"); + const { mkdtempSync: tempOrdner, readFileSync: liesDatei } = await import("node:fs"); + const { tmpdir: tempWurzel } = await import("node:os"); + const { join: pfad } = await import("node:path"); + + const zOrdner = tempOrdner(pfad(tempWurzel(), "wg-zeugnis-")); + const zKey = pfad(zOrdner, "k.pem"), zCrt = pfad(zOrdner, "z.pem"); + execFileSync("openssl", ["req", "-x509", "-newkey", "rsa:2048", "-nodes", + "-keyout", zKey, "-out", zCrt, "-days", "2", "-subj", `/CN=${CREW}`, + "-addext", `subjectAltName=DNS:${CREW}`], { stdio: "ignore" }); + + const HTTPS_PORT = PORT + 1; + const vorbau = httpsServer( + { key: liesDatei(zKey), cert: liesDatei(zCrt) }, + (von, an) => { + const weiter = httpWeiter({ + host: "127.0.0.1", port: PORT, path: von.url, method: von.method, + headers: { ...von.headers, host: CREW }, + }, (antwort) => { an.writeHead(antwort.statusCode, antwort.headers); antwort.pipe(an); }); + weiter.on("error", () => { try { an.destroy(); } catch { /* Zugabe */ } }); + von.on("error", () => {}); + von.pipe(weiter); + }); + await new Promise((r) => vorbau.listen(HTTPS_PORT, "127.0.0.1", r)); + const SEITE = `https://${CREW}:${HTTPS_PORT}`; + + const browser = await chromium.launch({ + args: [`--host-resolver-rules=MAP ${CREW} 127.0.0.1`, "--ignore-certificate-errors"], + ignoreHTTPSErrors: true, + }); + const kontext = await browser.newContext({ + viewport: { width: 1280, height: 1000 }, ignoreHTTPSErrors: true }); const seite = await kontext.newPage(); const konsole = []; seite.on("console", (m) => { if (m.type() === "error" && !/favicon|ERR_/i.test(m.text())) konsole.push(m.text()); }); @@ -609,10 +659,10 @@ melde("=== 11. Im Browser ==="); await kontext.addCookies(kDogi.split("; ").filter(Boolean).map((teil) => { const i = teil.indexOf("="); - return { name: teil.slice(0, i), value: teil.slice(i + 1), domain: "127.0.0.1", path: "/" }; + return { name: teil.slice(0, i), value: teil.slice(i + 1), domain: CREW, path: "/" }; })); - await seite.goto(`http://127.0.0.1:${PORT}/workspace/werdegang.html`, { waitUntil: "networkidle" }); + await seite.goto(`${SEITE}/workspace/werdegang.html`, { waitUntil: "networkidle" }); await seite.waitForTimeout(900); const liste = await seite.evaluate(() => ({ @@ -741,6 +791,7 @@ melde("=== 11. Im Browser ==="); ok(konsole.length === 0, konsole.length ? "Fehler im Browser: " + konsole[0].slice(0, 120) : "keine Fehler im Browser"); await browser.close(); + await new Promise((r) => vorbau.close(r)); } /* ======================================================================= diff --git a/server/workspace.js b/server/workspace.js index 11b707df..a3822f75 100644 --- a/server/workspace.js +++ b/server/workspace.js @@ -5723,6 +5723,20 @@ workspaceRouter.get("/workspace/api/ich", (req, res) => { /* Damit die Oberflaeche den Knopf gar nicht erst anbietet -- ein Knopf, der mit 403 antwortet, ist schlimmer als keiner. */ darf_aufgaben_anlegen: darfAufgabenAnlegen(person), + /* FUEHRT JEMAND TEAM DOGI? (22.09.2026) + Damit die Entwicklungsseite die Kartenliste GAR NICHT ERST + abfragt, wenn es sie fuer diese Person nicht gibt. Der Code + behandelte den 404 schon richtig -- aber der Browser + protokolliert ihn trotzdem, und im Handy-Rundgang stand + deshalb bei jedem Modi "404 (Not Found)" in der Konsole. + Genau derselbe Fall wie am 19.09.2026 bei /anruf/adressen. + + EIGENES FELD, kein Stellvertreter: `darf_verteilen` sieht + aehnlich aus, ist aber nicht dasselbe -- ein Manager darf + verteilen und fuehrt Team Dogi nicht. Zwei Regeln, zwei + Felder; eines fuer beides waere die Stelle, an der es beim + naechsten Umbau auseinanderlaeuft. */ + fuehrt_team: fuehrtTeamDogi(person), /* DIE KACHELN, WENN SIE NICHT IM BROWSER STEHEN DUERFEN. Fuer die fuenf bekannten Rollen steht hier `null`, und die diff --git a/workspace/anruf-probe.html b/workspace/anruf-probe.html index 065cc8f1..707cb9d7 100644 --- a/workspace/anruf-probe.html +++ b/workspace/anruf-probe.html @@ -16,15 +16,15 @@ verdeckt. Gefunden hat es pruef-struktur. Richtig sind `gate.css` (die Farbwerte des Hauses) und `haus.css`. --> - - + + - +