From 6156eb3a052aae1d119066c6648fa37a22b95448 Mon Sep 17 00:00:00 2001
From: Dogfather
`. Wer nur die Marken entfernt, bekommt viermal das Wort
+ * „Liga" -- die Nummer steckt im `start`-Merkmal, nicht im Text. Aus
+ * „1. Liga", „2. Liga", „3. Liga" wuerde eine unbrauchbare Liste
+ * gleicher Zeilen, und niemand koennte sagen, welche Liga gemeint
+ * ist. Deshalb werden Nummern gesetzt, nicht verworfen. */
+export function textAusHtml(html) {
+ let text = String(html || "");
+ if (!text) return "";
+
+ /* Nummerierte Aufzaehlungen: jede `]*)>([\s\S]*?)<\/ol>/gi, (ganz, merkmale, inhalt) => {
+ const m = /\bstart\s*=\s*["']?(\d+)/i.exec(merkmale);
+ let n = m ? parseInt(m[1], 10) : 1;
+ return inhalt.replace(/
/gi, "\n")
+ /* `
gut
") === "gut", "Skripte fallen weg"); +ok(textAusHtml("") === "" && textAusHtml(null) === "" && textAusHtml(undefined) === "", + "nichts hinein ergibt nichts heraus"); +ok(textAusHtml("a
\n\n\n\nb
") === "a\n\nb", + "mehr als eine Leerzeile wird eine"); + +/* ===================================================================== + 6. DIE BEENDETE KAMPAGNE — der Fall, den der Bauplan nicht kannte + ===================================================================== */ +melde(""); +melde("=== 6. Eine abgelaufene Kampagne hat kein Interaktionsschema ==="); + +{ + const wert = datenAusSeite(seite.beendet); + /* GEGENPROBE/VORAUSSETZUNG: Das Feld ist wirklich weg. Sonst würde + der Rückfallweg gar nicht geprüft, und die Zeilen danach wären + grün, ohne etwas zu messen. */ + ok(!("ac_schema_with_interaction_rules" in wert.globalData.activityInfo), + "activityInfo.ac_schema_with_interaction_rules fehlt in dieser Seite"); + ok(wert.globalData.activityInfo.activity_status === 16, + `ihr Zustand ist „beendet“ (${wert.globalData.activityInfo.activity_status})`); + ok(!!wert.schema, "aber value.schema ist da"); + + const b = leseKampagne(seite.beendet); + ok(b.auszug.gelesen_aus === "value.schema", + `gelesen wurde aus ${b.auszug.gelesen_aus}`); + ok(b.pflicht.titel === "Sonne im Gepäck", `Titel: ${b.pflicht.titel}`); + ok(b.pflicht.id === "7657456323453405959", `Nummer: ${b.pflicht.id}`); + ok(b.pflicht.start === "2026-07-03" && b.pflicht.ende === "2026-07-07", + `Zeitraum: ${b.pflicht.start} bis ${b.pflicht.ende}`); + ok(b.hinweise.length === 0, + `und vollständig gelesen (${b.hinweise.length} Hinweise)`); + + /* Die Bausteine heißen dort `…_rep_remove`. Dass der Name trotzdem + erkannt wird, ist die eigentliche Leistung. */ + ok(JSON.stringify(wert.schema).includes("_rep_remove"), + "ihre Bausteinnamen tragen die Endung _rep_remove"); + ok(b.auszug.bausteine.length === 10 + && b.auszug.bausteine.every((n) => !n.endsWith("_rep_remove")), + `${b.auszug.bausteine.length} Bausteine erkannt, Endung abgeschnitten`); + ok(b.kuer.aufgaben.length > 0 && b.kuer.preise.length > 0 && !!b.kuer.bannerUrl, + `Aufgaben (${b.kuer.aufgaben.length}), Preise (${b.kuer.preise.length}) und Banner da`); +} + +/* ===================================================================== + 7. OHNE PREISE — 201 mit Hinweis, nicht 502 + ===================================================================== */ +melde(""); +melde("=== 7. Eine Kampagne ohne Preise ist unvollständig, nicht unlesbar ==="); + +{ + const p = leseKampagne(seite.ohnePreise); + ok(p.pflicht.titel === "Stern Stunde" && !!p.pflicht.start && !!p.pflicht.ende, + `sie wird gelesen: ${p.pflicht.titel}, ${p.pflicht.start} bis ${p.pflicht.ende}`); + ok(p.kuer.preise.length === 0, `keine Preise gelesen (${p.kuer.preise.length})`); + ok(p.hinweise.some((h) => h.includes("Preise")), + `und das steht als Hinweis da: „${p.hinweise.find((h) => h.includes("Preise"))}“`); + ok(p.hinweise.length === 1, + `genau ein Hinweis, nicht mehr (${p.hinweise.length}) — nur die Preise fehlen`); + ok(p.kuer.aufgaben.length > 0 && p.kuer.geschenke.length > 0 && !!p.kuer.bannerUrl, + `alles andere ist da: ${p.kuer.aufgaben.length} Aufgaben,` + + ` ${p.kuer.geschenke.length} Geschenke, Banner ja`); + ok(regelnText(p.kuer, p.hinweise).includes("Bitte nachtragen"), + "die Kachel sagt selbst, dass sie unvollständig ist"); + ok(!regelnText(p.kuer, p.hinweise).includes("BELOHNUNGEN"), + "und behauptet keinen Preisabschnitt, den es nicht gibt"); + + /* DER MILDERE FALL: Baustein da, Liste leer. Hier aus Gipfelstürmer + im Speicher hergestellt — beide Wege müssen denselben Hinweis + ergeben, sonst hängt das Verhalten daran, WIE TikTok nichts + konfiguriert hat. */ + const leer = umbauen(seite.gipfel, (w) => { + const s = JSON.parse(w.globalData.activityInfo.ac_schema_with_interaction_rules); + let getroffen = 0; + (function lauf(k, t = 0) { + if (!k || typeof k !== "object" || t > 20) return; + if (typeof k.type === "string" && k.type.includes("live_reward_introduction") + && k.props?.rewardConfig) { k.props.rewardConfig.list = []; getroffen++; } + for (const v of Object.values(k)) { + if (Array.isArray(v)) { for (const x of v) lauf(x, t + 1); } + else if (v && typeof v === "object") lauf(v, t + 1); + } + })(s); + if (getroffen !== 1) throw new Error(`erwartete 1 Preisbaustein, fand ${getroffen}`); + w.globalData.activityInfo.ac_schema_with_interaction_rules = JSON.stringify(s); + }); + const l = leseKampagne(leer); + ok(l.kuer.preise.length === 0 && l.hinweise.some((h) => h.includes("Preise")), + "auch ein leerer Preisbaustein ergibt denselben Hinweis"); + ok(l.kuer.aufgaben.length === 5, + `und der Rest bleibt unberührt (${l.kuer.aufgaben.length} Aufgaben)`); +} + +/* ===================================================================== + 8. DER DRITTE AUSGANG DES LESERS — Aufbau unbekannt + ===================================================================== */ +melde(""); +melde("=== 8. Wenn TikTok die Seite umbaut ==="); + +/** Macht das Datenpaket auf, lässt daran ändern, schreibt es zurück. + * Steht hier und nicht im Leser: Der Leser liest, er baut nicht. */ +function umbauen(html, aendern) { + const marke = html.indexOf("id=\"__MODERN_ROUTER_DATA__\""); + const a = html.indexOf(">", marke) + 1; + const e = html.indexOf("", a); + const daten = JSON.parse(html.slice(a, e)); + aendern(daten.loaderData.home_page.COSMIC_D_K.value, daten); + return html.slice(0, a) + JSON.stringify(daten) + html.slice(e); +} + +/** Fängt den Fehler und gibt ihn zurück — oder `null`, wenn keiner kam. */ +function faengt(tun) { + try { tun(); return null; } catch (f) { return f; } +} + +{ + const f = faengt(() => leseKampagne(seite.kaputt)); + ok(f instanceof KampagneUnlesbar, `es gibt einen Fehler, und zwar ${f?.name}`); + ok(f?.art === "aufbau", `Sorte „${f?.art}“ — die Seite, nicht das Feld`); + ok(/__MODERN_ROUTER_DATA__/.test(f?.grund || ""), + `der Grund nennt, was fehlt: „${f?.grund}“`); + + /* GEGENPROBE: Die vollständige Seite wirft NICHT. Ohne diese Zeile + wäre eine Lesefunktion, die immer wirft, hier grün. */ + ok(faengt(() => leseKampagne(seite.gipfel)) === null, + "Gegenprobe: die vollständige Seite wirft nicht"); + + /* Die kaputte Seite enthält bewusst ein ANDERES JSON-Skript und eine + Zeile mit der Kampagnennummer. Wer „das erste Skript“ nimmt oder + „irgendwo die Nummer“, wird hier grün und im Betrieb falsch. */ + ok(seite.kaputt.includes("__NEXT_DATA__") + && seite.kaputt.includes("7691493175936699143"), + "sie enthält einen Lockvogel: ein anderes JSON und die Nummer"); + + /* Paket da, aber ohne unseren Ast. */ + const ohneAst = seite.gipfel.replace(/"COSMIC_D_K"/, "\"COSMIC_ANDERS\""); + const f2 = faengt(() => leseKampagne(ohneAst)); + ok(f2?.art === "aufbau" && /COSMIC_D_K/.test(f2?.grund || ""), + `ein umbenannter Ast wird benannt: „${f2?.grund}“`); + + /* Paket da, aber kein JSON. */ + const kaputtesJson = seite.gipfel.replace( + "id=\"__MODERN_ROUTER_DATA__\">{", "id=\"__MODERN_ROUTER_DATA__\">{{"); + const f3 = faengt(() => leseKampagne(kaputtesJson)); + ok(f3?.art === "aufbau" && /kein lesbares JSON/.test(f3?.grund || ""), + `unlesbares JSON wird als solches gemeldet: „${(f3?.grund || "").slice(0, 70)}…“`); + + /* Paket und Ast da, aber beide Gerüstquellen weg. */ + const ohneGeruest = umbauen(seite.gipfel, (w) => { + delete w.globalData.activityInfo.ac_schema_with_interaction_rules; + delete w.schema; + }); + const f4 = faengt(() => leseKampagne(ohneGeruest)); + ok(f4?.art === "aufbau" && /Seitengeruest fehlt/.test(f4?.grund || ""), + `fehlt BEIDES, sagt der Grund das: „${(f4?.grund || "").slice(0, 60)}…“`); + + /* Und: die zweite Quelle rettet die erste. */ + const nurZweite = umbauen(seite.gipfel, (w) => { + w.schema = w.globalData.activityInfo.ac_schema_with_interaction_rules; + delete w.globalData.activityInfo.ac_schema_with_interaction_rules; + }); + const z = leseKampagne(nurZweite); + ok(z.auszug.gelesen_aus === "value.schema" && z.kuer.aufgaben.length === 5, + "fällt die erste Quelle weg, liest die zweite dasselbe"); +} + +/* ===================================================================== + 9. DER ZWEITE AUSGANG — Pflichtfeld fehlt, KEINE Kachel + ===================================================================== */ +melde(""); +melde("=== 9. Ohne Zeitraum entsteht keine Kachel ==="); + +{ + const ohneEnde = umbauen(seite.gipfel, (w) => { delete w.globalData.activityInfo.end_time; }); + const f = faengt(() => leseKampagne(ohneEnde)); + ok(f instanceof KampagneUnlesbar && f.art === "pflicht", + `ohne Enddatum: ${f?.name}, Sorte „${f?.art}“`); + ok(/Ende/.test(f?.grund || ""), `und der Grund sagt welches Feld: „${f?.grund}“`); + + const ohneStart = umbauen(seite.gipfel, (w) => { w.globalData.activityInfo.start_time = null; }); + ok(faengt(() => leseKampagne(ohneStart))?.art === "pflicht", "ohne Beginn ebenso"); + + const ohneTitel = umbauen(seite.gipfel, (w) => { w.globalData.pageInfo.title = " "; }); + ok(faengt(() => leseKampagne(ohneTitel))?.art === "pflicht", "ohne Titel ebenso"); + + /* DIE ZONE IST PFLICHT, und sie wird NICHT ersetzt. `time_zone` + bleibt in der Seite stehen — wer darauf ausweicht, rechnet nach + dem 25.10.2026 falsch. */ + const ohneZone = umbauen(seite.gipfel, (w) => { + delete w.globalData.activityInfo.tz_location_name; + }); + const fz = faengt(() => leseKampagne(ohneZone)); + ok(fz?.art === "pflicht" && /tz_location_name/.test(fz?.grund || ""), + `ohne Zeitzone: „${fz?.grund}“`); + ok(datenAusSeite(ohneZone).globalData.activityInfo.time_zone === "+02:00", + "Gegenprobe: der feste Versatz +02:00 stand bereit und wurde NICHT genommen"); + + /* Sekunden statt Millisekunden wären das Jahr 1970 — und ein Datum + von 1970 sieht aus wie ein Datum. */ + const sekunden = umbauen(seite.gipfel, (w) => { + w.globalData.activityInfo.end_time = Math.floor(1_791_410_399_000 / 1000); + }); + const fs = faengt(() => leseKampagne(sekunden)); + ok(fs?.art === "pflicht", + "ein Zeitstempel in Sekunden wird abgelehnt, nicht ins Jahr 1970 gerechnet"); + + /* Und zwei fehlende Felder nennt er BEIDE. */ + const zwei = umbauen(seite.gipfel, (w) => { + delete w.globalData.activityInfo.end_time; + w.globalData.pageInfo.title = ""; + }); + const f2 = faengt(() => leseKampagne(zwei)); + ok(/Ende/.test(f2?.grund || "") && /Titel/.test(f2?.grund || ""), + `fehlen zwei, nennt er zwei: „${f2?.grund}“`); +} + +/* ===================================================================== + 10. EIN PLATZHALTER OHNE TEXT FÄLLT AUF + ===================================================================== */ +melde(""); +melde("=== 10. Ein Wörterbuch mit Lücken wird gemeldet, nicht verschwiegen ==="); + +{ + const luecke = umbauen(seite.gipfel, (w) => { + const s = JSON.parse(w.globalData.activityInfo.ac_schema_with_interaction_rules); + /* Beide Wörterbücher anfassen -- der Leser mischt sie. */ + /* AUS BEIDEN WOERTERBUECHERN DIESELBEN Schluessel. + Beim ersten Versuch wurden sechs Eintraege nur aus + `value.sourceTextMap` geloescht -- und nichts fehlte, weil der + Leser beide mischt und das Woerterbuch IM SCHEMA einspringt. + Das ist richtiges Verhalten und hier gleich mitbewiesen: Erst + wenn der Schluessel in BEIDEN fehlt, fehlt der Text. */ + const treffer = Object.keys(w.sourceTextMap || {}) + .filter((k) => k.includes("rewardIntroFormData")).slice(0, 6); + if (treffer.length < 2) throw new Error("keine Preis-Einträge zum Löschen gefunden"); + for (const k of treffer) { delete w.sourceTextMap[k]; delete (s.sourceTextMap || {})[k]; } + const raus = treffer.length; + void raus; + w.globalData.activityInfo.ac_schema_with_interaction_rules = JSON.stringify(s); + }); + const l = leseKampagne(luecke); + ok(l.auszug.platzhalter_ohne_eintrag > 0, + `${l.auszug.platzhalter_ohne_eintrag} Platzhalter ohne Text — und das steht im Auszug`); + ok(l.hinweise.some((h) => h.includes("Wörterbuch")), + `und als Hinweis: „${l.hinweise.find((h) => h.includes("Wörterbuch"))}“`); + const text = regelnText(l.kuer, l.hinweise) + aufgabenText(l.kuer); + ok(!text.includes("$$__activity_"), + "und kein Platzhalter steht dafür in der Kachel"); +} + +/* ===================================================================== + 11. DER LESER LIEST NUR — nachgewiesen am Quelltext + ===================================================================== */ +melde(""); +melde("=== 11. Kein Netz, keine Datenbank, keine Uhr — im Quelltext ==="); + +{ + const quelle = readFileSync(join(HIER, "kampagne-lesen.mjs"), "utf8"); + /* Kommentare weg: Der Kopf der Datei SPRICHT über fetch und + Datenbank, und ein Wort in einer Begründung ist kein Aufruf. */ + const code = quelle + .replace(/\/\*[\s\S]*?\*\//g, (m) => m.replace(/[^\n]/g, " ")) + .replace(/^\s*\/\/.*$/gm, ""); + + const verboten = [ + [/\bfetch\s*\(/, "fetch("], + [/node:sqlite/, "node:sqlite"], + [/node:fs|node:http|node:https|node:net|node:dns|node:child_process/, "ein Zugriff nach draußen"], + [/require\s*\(/, "require("], + [/\bexpress\b/, "express"], + [/Date\s*\.\s*now\s*\(/, "Date.now()"], + [/new\s+Date\s*\(\s*\)/, "new Date() ohne Argument"], + ]; + const gefunden = verboten.filter(([muster]) => muster.test(code)).map(([, n]) => n); + ok(code.length > 5000 && gefunden.length === 0, + `${code.length} Zeichen Code geprüft, nichts davon verboten` + + (gefunden.length ? ` — gefunden: ${gefunden.join(", ")}` : "")); + + const einfuhren = (code.match(/^import\s/gm) || []).length; + ok(einfuhren === 0, + `die Datei führt NICHTS ein (${einfuhren}) — sie hängt an nichts`); + + /* GEGENPROBE: Derselbe Prüfer findet `fetch(` dort, wo es hingehört. + Ohne sie wäre die Zeile oben auch grün, wenn das Muster nie passt. */ + const helfer = readFileSync(join(HIER, "helfer-tiktok.mjs"), "utf8") + .replace(/\/\*[\s\S]*?\*\//g, (m) => m.replace(/[^\n]/g, " ")); + ok(/\bfetch\s*\(/.test(helfer), + "Gegenprobe: derselbe Prüfer findet fetch( in helfer-tiktok.mjs"); +} + +/* ===================================================================== + 12. ZWEIMAL LESEN GIBT ZWEIMAL DASSELBE + ===================================================================== */ +melde(""); +melde("=== 12. Gleiche Eingabe, gleiches Ergebnis ==="); + +{ + const a = JSON.stringify(leseKampagne(seite.gipfel)); + const b = JSON.stringify(leseKampagne(seite.gipfel)); + ok(a.length > 2000 && a === b, + `zwei Läufe, ${a.length} Zeichen, Zeichen für Zeichen gleich`); + + /* Und alle vier Seiten zusammen, damit keine davon still ausfällt. */ + let gelesen = 0; + let geworfen = 0; + for (const [name, text] of Object.entries(seite)) { + try { leseKampagne(text); gelesen++; } + catch { geworfen++; void name; } + } + ok(gelesen === 3 && geworfen === 1, + `${gelesen} der vier Seiten lesen sich, ${geworfen} wirft (die kaputte)`); +} + +melde(""); +melde(`${geprueft} Pruefungen, ${fehler} Fehler`); +melde(fehler ? "NICHT IN ORDNUNG" : "ALLES IN ORDNUNG"); +process.exit(fehler ? 1 : 0); diff --git a/server/pruef-struktur.mjs b/server/pruef-struktur.mjs index 3011708b..a8fe39d5 100644 --- a/server/pruef-struktur.mjs +++ b/server/pruef-struktur.mjs @@ -1190,7 +1190,28 @@ console.log(`\n=== Ruft ein Modul etwas, das es nie eingefuehrt hat? ===`); return raus; }; - const quellen = ["workspace.js", "helfer-zeit.mjs", "helfer-tag.mjs"]; + /* ABGELEITET, NICHT AUFGEZAEHLT -- nachgetragen am 07.10.2026. + + Der Kommentar oben verspricht das seit immer; die Zeile darunter + hielt es nicht ein. Hier standen drei Namen von Hand, und damit + war der Wachposten so weit blind, wie die Liste alt war: Nur + Namen aus workspace.js, helfer-zeit.mjs und helfer-tag.mjs + konnten ueberhaupt auffallen. + + GEMESSEN beim Verschieben von istTikTok (07.10.2026): Die alte + Liste kannte 98 Namen und sah 508 Aufrufe an -- die abgeleitete + kennt 148 und sieht 1025. In der Luecke dazwischen stand ein + echter Fehler: mess-fokus.mjs rief eigenerPort() auf, und die + Einfuhr dazu lag INNERHALB eines Blockkommentars. Die Datei + brach beim Start mit ReferenceError ab -- seit dem 01.10.2026, + ohne dass es jemandem auffiel, weil sie von Hand gestartet wird. + Genau der Fall aus dem Kommentar oben: die Datei faellt erst um, + wenn jemand sie braucht. + + Die Liste ist jetzt keine mehr. Wer einen neuen Helfer anlegt, + ist ohne eigenes Zutun mitgeprueft. */ + const quellen = ["workspace.js", ...readdirSync(SERVER) + .filter((n) => n.startsWith("helfer-") && n.endsWith(".mjs")).sort()]; const hausNamen = new Map(); // Name -> woher for (const q of quellen) { for (const n of exporte(readFileSync(join(SERVER, q), "utf8"))) hausNamen.set(n, q); @@ -1369,7 +1390,18 @@ console.log(`\n=== Wird der TAG in Ortszeit gebildet -- ueberall? ===`); LISTE, DIE NIEMAND PFLEGT. Deshalb wird nachgesehen, dass jede ausgenommene Datei das Muster WIRKLICH enthaelt — raeumt es jemand weg, ist die Ausnahme veraltet und faellt auf. */ - const AUSNAHMEN_UTC = new Set(["pruef-struktur.mjs", "pruef-tagesgrenze.mjs"]); + const AUSNAHMEN_UTC = new Set(["pruef-struktur.mjs", "pruef-tagesgrenze.mjs", + /* pruef-kampagne-lesen.mjs (07.10.2026): aus demselben Grund wie + pruef-tagesgrenze.mjs. Sie stellt den falschen Weg dem richtigen + gegenueber und WEIST NACH, dass der Unterschied auffaellt: + + start_time 1791064800000 + toISOString().slice(0, 10) -> "2026-10-03" falsch + tagInZone(…, "Europe/Berlin")-> "2026-10-04" richtig + + Die beiden Zeilen sind die Gegenproben selbst. Ohne sie bewiese + die Pruefung nur, dass eine Zahl gleich einer anderen ist. */ + "pruef-kampagne-lesen.mjs"]); { const schal = [...AUSNAHMEN_UTC].filter((n) => { const t = readFileSync(join(SERVER, n), "utf8"); diff --git a/server/pruefdaten/LIESMICH.md b/server/pruefdaten/LIESMICH.md new file mode 100644 index 00000000..d605ad85 --- /dev/null +++ b/server/pruefdaten/LIESMICH.md @@ -0,0 +1,98 @@ +# Gespeicherte TikTok-Kampagnenseiten — Herkunft und Eingriffe + +Diese Dateien sind die Eingabe für `server/pruef-kampagne-lesen.mjs`. +Sie liegen hier, damit das Auslesen einer Kampagnenseite **ohne Netz, ohne Server +und ohne Datenbank** geprüft werden kann. Eine Prüfung, die dafür das echte TikTok +braucht, misst fremde Verfügbarkeit statt unseren Code und wird irgendwann rot, +ohne dass etwas kaputt ist. + +## Woher sie kommen + +Alle vier wurden am **07.10.2026** von `www.tiktok.com` geholt, **unangemeldet**. +Das ist nachprüfbar in den Dateien selbst: + + globalData.userInfo = { "uid": "0" } + env.anchor_id, env.user_id = "" + +Es steckt also **keine Person** darin — kein Name, kein Handle, keine Sitzung, kein +Keks. Die 6 Treffer für „nickname" sind Einstellungsnamen +(`hide_user_nickname`) und ein Platzhalter (`{nickname_or_handlename}`), keine echte +Person. Deshalb dürfen sie hier liegen. + +## Warum gepackt (Brotli) und nicht als Klartext + +Eine Seite ist rund 1 MB; gepackt sind es 150 KB. Das Zurückpacken +(`brotliDecompressSync`, in Node eingebaut, keine neue Abhängigkeit) wurde beim +Anlegen jeder Datei **sofort gegengeprüft**: Der Inhalt kommt Byte für Byte +identisch zurück. Eine Ablage, die man nie zurückgespielt hat, ist eine Hoffnung. + +Die Prüfung hält zusätzlich die SHA-256-Summe des **entpackten** Inhalts fest. +Ändert sich eine Datei, wird die Prüfung rot und nennt die neue Summe — das ist +Absicht: Eine Prüfdatei, die sich still ändert, macht jedes grüne Häkchen darüber +wertlos. + +## Die vier Dateien + +| Datei | Kampagne | `activity_id` | Zustand | Eingriff | +|---|---|---|---|---| +| `kampagne-gipfelstuermer.html.br` | Gipfelstürmer | 7691493175936699143 | läuft (`activity_status` 15) | **keiner** | +| `kampagne-beendet.html.br` | Sonne im Gepäck | 7657456323453405959 | beendet (16) | **keiner** | +| `kampagne-ohne-preise.html.br` | Stern Stunde | 7670899782609996552 | beendet (16) | Preisbaustein entfernt, siehe unten | +| `kampagne-kaputt.html` | — | — | — | vollständig selbst geschrieben | + +### `kampagne-gipfelstuermer.html.br` — der vollständige Fall + +Unverändert. Alles, was eine Kachel braucht, ist darin: Titel, Zeitraum, Zone, +5 Aufgaben, 5 Kampagnengeschenke, 6 Preisgruppen, 2 Klapptexte (Ligen und +Teilnahmebedingungen), Banner, Länder. + +Sie ist außerdem der Beleg für den wichtigsten Satz des Lesers: +**Im Wörterbuch stehen 135 Einträge, im Seitengerüst nur 134 Platzhalter.** Der +Überzählige lautet „1 schenkende Person = 100 Punkte" und gehört zu einer früheren +Fassung der Kampagne. Wer das Wörterbuch durchliest statt im Gerüst +nachzuschlagen, schreibt diese Regel in die Kachel, und das Team richtet seinen +Stream danach aus. + +### `kampagne-beendet.html.br` — der Fall, den der Bauplan nicht kannte + +Unverändert. Diese Seite liefert `activityInfo.ac_schema_with_interaction_rules` +**nicht mehr** — bei einer beendeten Kampagne ist das Feld weg. Das Gerüst steht nur +noch unter `value.schema`, und die Bausteine heißen dort `…_rep_remove`. + +Ohne diese Datei wäre der Rückfallweg ungeprüft, und abgelaufene Kampagnen ließen +sich nicht nachtragen. + +### `kampagne-ohne-preise.html.br` — der einzige Eingriff + +**Es gibt keine echte Kampagne ohne Preise.** Alle vier am 07.10.2026 geholten +Seiten haben sechs Preisgruppen. Dieser Fall muss deshalb hergestellt werden, und +das ist hier offen dokumentiert, statt in einem Skript zu verschwinden: + +Grundlage ist die unveränderte Seite von **Stern Stunde**. Daraus wurde in +`loaderData.home_page.COSMIC_D_K.value` jeder Baustein entfernt, dessen `type` +`live_reward_introduction` enthält — **zwei** Stück, einer in +`activityInfo.ac_schema_with_interaction_rules`, einer in `value.schema`. Danach +wurde das Datenpaket neu geschrieben (`JSON.stringify`); die Seite um das Paket +herum ist unverändert. + +Entfernt wurde der **ganze Baustein**, nicht nur seine Liste. Das ist der härtere +Fall: Dann fehlt auch die Überschrift, und der Leser kann nicht einmal sagen, wie +der Abschnitt hieß. Der mildere Fall (Baustein da, Liste leer) wird in der Prüfung +zusätzlich im Speicher aus Gipfelstürmer hergestellt — beide müssen denselben +Hinweis erzeugen. + +### `kampagne-kaputt.html` — vollständig selbst geschrieben + +369 Bytes, kein echter Abzug. Eine Seite, die aussieht wie eine TikTok-Seite und +das Datenpaket **nicht** enthält. Sie steht für „TikTok hat die Seite umgebaut" und +muss den dritten Ausgang auslösen: `KampagneUnlesbar` mit `art: "aufbau"` und einem +Grund, der `__MODERN_ROUTER_DATA__` nennt — nicht „Fehler 502". + +Sie enthält bewusst ein **anderes** JSON-Skript (`__NEXT_DATA__`) und eine +Zeile, in der `activityId` vorkommt. Wer „das erste Skript" oder „irgendwo die +Nummer" nimmt, wird hier grün und im Betrieb falsch. + +## Keine Testdaten im Live-System + +Diese Dateien werden ausschließlich gelesen. Sie wandern nie in eine Datenbank, und +es entsteht aus ihnen nie eine Kachel auf `workspace.dogfather-universe.com`. diff --git a/server/pruefdaten/kampagne-beendet.html.br b/server/pruefdaten/kampagne-beendet.html.br new file mode 100644 index 0000000000000000000000000000000000000000..2d6aff0adbbbdbd16c65a715387b480b6931e187 GIT binary patch literal 152773 zcmV(-K-|AuCar!Wnq&9OM67gO#P|}i} zF*?`hy0`DnXgFGbhUg;*g(F+4ejJTF($uk%*pheJ?05G2)o~~8*JVjx3{GuscFP+R zY4g$0UXP&I?<3SOV*Fvl6zPahFhJ=9Pp(WtUDV=XgKR%xu7)A%T_yc1cQsUoQNhmk zNC<2Vg)qIVKqeT5Xlz&%j4gb-Fy!r{7roVsj)J2aPM{IxV+8(gMvp92LpL^hSd!g~1M*Af*pBWiYp*~zGrA9bXy&c0*V z*}A{uZWg2EsL5>xNm8`)1j11;J6dL^=SsiGA#U?wk&3S&9E3BgN`(NA==7rzt54Fv z5xjQ7H`UL%*(M@|= D# z!f=a;G;`vC+`Sx^+SUuk{jdfL> zFSbZinS!Q}O96oIL^%*12f2M(QUDmXB*=okK#T9_ZLkZaJmq4C+H7~dm7n%S<3Vl@ zYpGoQlkV4YPS7ImTB(uj`gAHOqb32*@5@V+G&wE)0@+(PXBu;!vfyH2F+g3ebh-Zh z&<8Ax4e1a-H5wL-dhf G zrE=m0Lqg{jMwaMQUBz>XAMMvdsK57q4x0r6D~=%$(Jof6Pr+sP7WV+;<}#~2XT4(w zo1q?8l+zA6v4OM(U2sbP?w=&>1^k6d!39npGPn^{+cJfjsPihGm>Yd=Hbj~WQb;lb z*J8@Lwx_s>3-|U1cvW~GVSbOr*6bTd(ikO<`fr5|>)1d5w|0fNPp+}kf0f~q4AhYu zXu}uEfVF`)=?LbtI$J8U9C_V=^h_aU5hAEEvv^w+^fY!ArVHs;0YJAp`)sY+Jlz%N z|ML&xmkW6`Xa=q8bvq~-N;mmgaC@C+rO}+E)ahpH59p>nAd(zghr-~67M>>nSTEw~ zZmL(cu|kp_?*d?&JX7==CSBT14Y-GsmgGoqc(nT7T`9nJVoVvs_uqNycgk-=a?>{+ z7XOS^1?u!?Y&{>JR_x;ruKTk;8B_`TN3*E5>^pjEy$gW;%E09|Pn?N6`y4uK;{!%Y zR6w5KKcwJbM&(5{u A^fdzHFf+Sycg|`$*Fxdm^oqz;WPGEpJ5K7ey(pU8R#))8^ zPCtgU6^NE`kbdb%YAyCy&!q91{jKs)h~j%K{#GEXpMl~a7z!s)`El~|L^v`BDlsNz z`1?Xj&{0nbQh1oow7PkktmQWROj|PJm(u-UTX=0Vg>i8E)Us Ck4%SIpeO9@YpIY76;~ z3-<8 t(`7;i&pF%}B$sunK&MgYo1*E_fr5WLFX+g1$G5@o@k-6`- zGo?OJ2Dig-_%Kzpz^N^cMkMHqTG{ x;u%(^h?@RX7HStx)be%p~g zCyi!sKzcx8-g>_fdhf*X`yl!~V#Cok&8m8m|J+S$uJ* %d=Bi)MP>@!Ur%DR jY*>GM8)m57P@s-GFz=()>|zj;^t$6_mr_bltWjw3qESkH>+O=8-HEc zpLb+(hNZ~J*yhCK&HYAKGOR98UW`*6mUf~sQ*7CGDB+h4X{*HX*mQ76E8qFAME~a_8aE^a)2j#f_N%^uh6q4Xo*#8mPm3@r0Od{eKtxYj= z;5#3?3Gy@DQ&Wn2_O!Bb;%zXgF<>$8-Itq>FTBTM`@R=ZMnbr1?`bUBrQzYIXeG5F zHm9y(>reE+Ozc&0iSOH!_QtxjPHn8fRsj}~5rleUx0L^~S-1TXZz7(|_mgzSPrM+E zUXRdbJYCH3T2P~NjYy4)S!XvGJ5^3la*jJ2c@7T>?CnoCJNKH336>Bzy2nx9E|(P{ zI*_M|K4dNVUTF~wca0cp=CKbdPp~tV(vR`7eZ&SXJ)8$w{Y5rn>8rQ`h?v9XwGD)F z7*1deN-cmM4>z3^J_Q{Ve%xQp{cF|rD%q9ReXazwLM*)GfCm;%+ggK<)%`qfw!W^s zI4a}hxZBM{j`*#-^XpRa7J$8T4Fa>)-v7`>gQg*;H3sJB+Q;B@H61&;LxPLb3wEL( zBzFrn7Zx>9SX$Qo4aTlHdSEl(p!N(b85!2(Z4y|-=PO~99sd?C0$H+WC{zD%G@$1U zq;)xLr_xl304ZhUgCYDD(A-Wxbi9s%gS|Z3gM?5FRd^!)*hd^c2y#^{d}`9`7_fO7 zD`*b4a gEz*hvek(3lXqdbCjNEtW-WRyElVj+M ziPr=gq5wX@ 1g{r^9?W zq(HYqJ}s1Ec~MBz#mJh)%vj9Ki#f{@M )LN1P=5hF=Kxgu)51m@#08cb6|6+Al7AT>gq)&QFH{V?_+3Ki37OJk=V3u zSF==$piChAI&zu$rm4dB0|}pL=?0M`pZB>Q>yr8)2h`U{-B{LAGi>!#GT7^7gAyIc z63h&v!Ba?`shX0k(SVpOdi$&5I0{rPt6ljy(iA%@+NUB9;7!nmU4Ofxi+0q&Koj4W zBM#m9qB%h`*%HlF?TwY;X2mGPDfnKZA+-Re063A%v{^^WsVoASav%Al9CBSCsib7( z-%^I_yzQ!{y#mePLMAVmRulleoqzrbusV^Q2`JI_^N_qaTMbC(jZappt^@kQv3?Dy zVkp#|5R^`s5@1*OjZWSkPTtP%KLnITei8-T0r&;8ya~N|cNY+E&sT6>f5zes<9jaw z{`?bSm|U*0VPXr3lWN7h`Ejhvc-dv5lPWsm)zNAITLXSwA^1rjvf%Fbzi99At2n -WibH^TEs((7~+?-j7tt Q*6E2U=;_7*|NmxxkJrT$b?&Z?|0R#GMKIls$Lc)YslQnAz)pEsUl3^+qA z3ky)e%x{?GSulif>@~qNpRHQDrk_}L_`H|-2!SaR!oACCi(g(SXPdRfim@oTD@u{l zw@lKBI8I6D2{}+8)QwI>k=0&{l|ED_%?h0$pRd!vN|?5gy!<<5budwuik`rIKY4eV z#zWf)N)ei9+Vr$uaM#*EqkU}%Q0-rp38b@TeTFz9+P3OGow}A@3|NCF>t9{~bAQ^& zD*wx0kJEj(Oz*Cz&Z1H~S50odCFiN{y9Dy{viP;KE|If1jLWN87ygTRfPyYV5ZLrt z@Bv^i<6l$$G*xO G0 zCkl&@4I+g-K0gv1P(%Xh`jXkO{Fu{R# F?u7sZKLpXpM#)9yeb)=`-QO;8I(10A z^N51Jfmc8?(Az^9@@H~8;IVNqR$X`bX0P?Dqu&OBn|HbUuZ6x&jz=hIP^}KGmob0x znv?L>dfcSRq#Bb?Ye%~YA wS-?ctL;_NrkT_TLG!KaVfp*N8r$Rfh8$f+zWQoM~e$E@6SflW0q}d9=DESod zbH^jn)WxZfKnii&!OfbtzVXhV>L)%UzW&G;ptSea;h*IH^f-&L+kC0m?a+)u=LH#| z%UkkBJw*~4 eA6n?v j$c2E~t_Htn4wK<1D7u)8QQ;<(uklBW?|M@RBpg!%17q{SF z3jRu7*sC-iMW;Bj?#J5(OoD-CH3lAA`Az#G(U?Sp>YL*4km7F*Z}o43yXp>?n)d~p z5rrf**-0>6zeR4N_ZFLP!5kZ%%v3z%i1U P0Lj7<(pQsTo4*n`;H!?yAs|oqPRpfJME@DjP$M?0n&`I zxocbe1!9e{?D9g8(8D voe zhZ?g8_;zYv5hgwwaE;lD^w2^!^|+zeQDbhK!W~Do%-g;*wE$Jy0RPmxd}{t9Se`9w zdZ%~7 Yydmti(%!0n62MB1VXb)gB)Vn+-XwQL*I3lhlF{4rbB5vA)E&|YiFkE>+eY}$o z&vAnVbs3xjW%~kZsG#Y3{~}+3wz7{H?10ya gRg*@K+#PFKjNE>uYZ3iCOkBM6*77#l`a781E zqf!NPm&O(DJ4QW-gJuknJIgL9`z_JO+djDb%pz=ORJcJ?x44veRQ4iDf&&rf*gM*i zc&I`Q{AXpY`@dD7!5c|79^KF=(5^w`3czzxTl{yqCjb|VtPVscQ9bx0iW0HhR={@M zaM?E!J1G24rYs`-;Ld2O0r%hI_V!3{IoKIjgo6s)66Mz-+B;?12mnrbrajHgn(Bo# z$c`}yfe7lm8WLGdAEKcZc1ds=Xh?1q)EY>{YIKbK7J2O!@d4X-Tq(*SX(D2x*OVz+ z={?t(GZ*=5+apw ZETheaM%=K zx({NApRA0rrp*iTcN6fzq|$4jlx4u9DUYv!PGdVTFh9=eFBe~WE^~3_@ghFEgZkP s)ZYn;wCoqQE!=Ay~iS>%Q=YhlvthBYh5Q7 ziIJF+xXvJ?6l nL}*yN_i_Aw~+Zm_7Rs!c?tdv6Wqm8N{?4xOerLJ?3UlCO*v*_F||W4IZ)1VO<#S z3ZTJOs%rW%2GFJ!v)}J!sh;A|E}>2|fVQ*jyL)14zY|R(bzMkAn!~9U-1ksya6g=X ziC$=jBnIQaromG$1Qsu+KruPM^=#g-1@5v7Z;by-VKGh#g(n1m;myo9;WUT7&^T znAUOjlpJ#^(q|!y$7Se|=NZ#P9&Lmaq-`Wj+Ej<67GjU0z1kxrQDc^3Cv{d4hD7+B zZl 8iFA}YeVoe0CW)47qTG&q!=L99egYk*IAE<7Bw ziA<#iW2<$ClNnQtWMDOOqU%;!KQ~ zTl+LjJb}oO?&hDe6j?jISOW^S`}LDmiBPn=2{3p7!m!yZB$S7Jae6q40hGoVxG~kR z96m{I4crK3R4{yV+I@^T;~)j_RzWT;;3uiZti%wP;DY%v=VZEH`i56)M>8{PP9k+S z+YYjfpDIn*Dl@@pQpm8|IdGad7J553B5}hGhZ2HK7P+4*qIhTy6}?zVI{863rb@P~ zBCGfNqZ$jcgqDwrcrl~-NFNT<|E4|h6#KaC0Ap%>$wnBu`czggvo4lY`N|KTm;?$2 zg?L`RVJTz*vaCq~V{-bxFR&g37_2sfp$mMdFd!HEeyIGA+_M#Q(<5K*n?dLH{4l^Q zRG+`Vubuh|9^W;J^GyeU1AQBh|Lrd(5;0)nz^b{)kdF^itjS9H{l;VHe!I_0n#m3X zIqD{o|Fo33yLG!y+CV=HMSvZtK^1LtO3y9OL`^Ja`X#WVFIiojo|FxYdopzNLgn}D zsa3qI8X28aeHk(VRq#(%psAXS2>;;7j3+e`)a0G9nm%#OL?%(SrqWVT*CA0`W#@Kb zRamfkk}LS5bQHN@$MOCa3wjON-F7BAq?3!ZXI%gFIQsmK5Ex?BJT>z6UU{@I<&F zx-^eX=9ys(>arEK#&6d2kTq#sM%?*M8)7A5!qR#Kopec3NnT_GCW%yTyq|SaFIiJl zx>cHHTpns~Pt$K|1~VqxXt;B@LSQkGG1W7Ab vE^j>rnf(1 Fyx)_)eN5en&?Q{4Br|gP}37`nXUs* z-oadq#ne?}4fBrv3DQkb=}DOo;sif&oJw<-&?mj%!go-0qB?>cNUE=@ZVVMI>x#R7 zwzoe?aXOd+cr_lV@$XVdc7Y(XoX6Ap+YL;DA(MiFy93@-YR%)qM^^HTg8Kk^K!v}~ z10rDv*uGO?9g|9lI;o_2f#>Fn&P4(e 9``cxdMch<%>o4ieu$Fo>hT9!hCFjAp zAg%PdkF8+W8*9{kf>azt9skvqDNcYeg+nETpj8EC7*$mS2;oFU6+}VdG(XZ!b6oSX zqj3LUlj8q<@^E`@4->TUPwjjh<%TitTBodSa4J&xB?UOe`My#n5am|vg%`5|y(DJn zm6!lg|KB`$B{aQ5tO{;fa&1`m-Gnk|COmkQQWa124MwCEy}U>U0iTAlS_8YF^{&s| zjJo$YPeW2lWBVMOVh9M@{n| nnmDOcFUenHL(~zThtV?cF(}aMFp{X&MMy?7 zF%W5-y!Kx{ax_MzhnP8EUjF|S^Reh$rRI&Z6V2oyDJVV{*vQ&{Fu(C>`|WbyR$x(DD??Jc2UU3`Z~`wUD^lY$tH5qyh<;akGuHdgUj(aR zFsRb>9=1nw?DPB^ZvQtlXwx+x03rmWCTgfC$06HybNFsDRK!WnvYn>`77hZ{wENYA zDsCv1`j;6X5kiU~B^@Nm7$+BTZ)}1-c&Z-D=Es#@X(j=peo)Ces-C$_i>ZR}w_u5| zcHPRuTYgQK1HbxKaqb4jSH-i!;0o!iqAR$N!eV^V+Y78$C0Rb7RX%mpYn>o8k4;AA zFYE3clwe8|#3gH!6jZ->DE* ziko%rjYTueiEWq?7Z;?JULzPz44Ql!>P;~@AnqCdgBZo>kTQ$?Y*LS;2%r5$+wzh7 zv-8e06fKc)qjGQ#Vqb8|%r)NR!-Nm(4cy0_k$fN`*!zZH!MHa2U@lvToN|j>;sNKL z-6AkIyKV{6nhqyfHZ5uC# JXD-a{y|T ?fnOKWLS2`8VOB^yX zgCJr^@erb&S@osY;%3)VY3)e7^43%)v$vxpR;ki_^|f8Q8K<%q$?^H{xqf<-fAFjq z0)ux a+S>XSTtKE2sLp9?WD(jbpK zs7h1aenG&1z`sEOtdR-h600bH?Tol1q!^6vqYZT6X)o|!v7lwTnsS;F{jDaRQa7%( zSaqzZ*SZzRBsZVPh3rR2jpi4?9(*u(s_nf68}v~zu5A9s#izmoSJX4R|Ay4|_3=R< zQbJ0NPYL|9j&Y$J&q_Jf+SK%R1Qpx0*_G16qUWwu2TK4M-KXg+gtVx{7?<7_z*8)8 zgLaElt^^uS5GdxhQw9evwI<4*jg-iyp%F8{1~cUCi;(U;59(7!XVKVouZ`syF~BlY zH8P`YwqP`#AW+PGqu-)REX9-~o=_gJ+00dHiz|k|k4OuG>sUfYh$Is)XuWgd%bMBd zI$~&HuMstW)cbc0wS%Cdt(YZ+MNH13X7A0TqGGa@XX!d0T8dmOLE{Mm#oT`*Q(p*J z8d=l>)a{3M0Bn=g5 QlOi5K%z(7|z70pW=GN&Ii1R{kL4;O-=k;%i9NEqqKhth8h zPv^kCgfO#|!yE`Ko4Cql+~jK!auTV-_KQqc15I*PPr !af+QPHh18_qqaC#glPR$7Zp^8AVN+4Fe6 z)?-I?C3{T31{A}g|EaiZ_^!s{Jm`q{+nWHqH0zlU29X0&lfgsVmO0>{zqx>s?2fn> ziWw?KKfTnsAR`WYGKNPfMiMjZs3USozC;?t7xcHRBUz-1FTVkT;GZ2ln;yx`G5dn% zyusa&`OaHVzkr_>QzPMbxDmM|!*tv-*n457*Y->*lT+&ump{3$&D)IV%XT+CC2FO} zV-}Y5$YXpkh}^X+7w7uQ7jvrC5U0A%D}-E*8`*zNEdwD;1<>1$>%2J)^i4W@7*fEM zEiWw@)tFFjQ)))4d!Q?wismH_8JS^E8IePZ9| SWx7AEkf=ABTCg{PVF-nZ$WSg=ft%UR9xV3 zaKan{7TL0UJ`fcHT|P%W;CDKE$Pl`#1?Gs{-I_B+hqF$SghN+470pW=GBP6|$_in~ z8lTRk-F4E&>HSafumD$;VD5cA*J87znYlVyo~ h*6KlV4 z!;W;S$jPW|+Mq_T#G~v~$4AVyw7*(`kbA(0lGwaOBI;xWfL2S?v(F|x*4->rg_J$6 zSgJ9HRboqx)w$Nyx8&sE^I7VlIBKtDq5%{rp^EeEt#RPE2ex^G2d(SKtukF-xLu3l zj&eIboEY*r3NxqHq(HY;$O2Zm#LBvahZFPYN=R97e)plsO_O|KVjN0O(HHiPnF%u8 zViY1~I@t>nhhjt~%$r|+r2SlN&11b?YIAsZa<7<<{%fsClsqN MWsWF^1^5phQ?p=>F_sZY6rbdZ$v93dS(DEe$64gAWOx_EPUw>^@2Ybs z*Eqr%SJAD45dGiuwLW|mKb%83lSJ{xQY6Qgr1y01<#Sk{(UYDr*I 1S%i}k2H-X z>>@5JE3|vPa|bcZrw=6GX=kAxF%W;xsW65hDaqG )h(`zRuo0G $rQq?8Gs{{Hni%B~!P=tv9+^g+xwp?s_`wn$v6ZswMUJU7 z__C;RLnuZXyOXf6RZHy#a-PoJiGrkqT`ZfByO9hdA?l;DVm!JYZuzR!&*)uddAc7< zqaEvaIHWTk Sot0uA6p7=%$Ys(GFBAJy0+HO_YbGn1t&WF z3 iB%K#Cd|(D(RkShL}OXKnBPpN;wd zaI1FhF%E>GYre0!?UldJM(9x*X Q{5w53dZHiNy8zcceNcrOx9oUupZEA=joq+Fb>?qOA_YfJLb=}2x2Zv^ zV7-;*nQw@bK9ah!LJmDHmtijf2U8X-1uylxX`J{?Y-VtJHq^0u&szT{(1-UScilai zd+R9r!hSxNnUndOL1HZs|7-UPbiJSG{)c&O1EUh-bUjlI92Aq@;@dcRDfGJKVs9sW z)2b3ZU(~kN4&?G*^FwNF5m`rV&g?!AQgm$NzA1%F+sL)cDOLuLu6>v9@b6ohbG0-S z%Ht?<>7KpPf&MoAi9Lzd(LMe$vCUMxMehh&a*j~+inb^klsoO(6MkSmFZ( o7qv6D*ONQzO2xk3Y+m53qtSOW^-Up{ zOn&O_cHmF<6fTBvzd!IlzMr=4FU0VZNT-3Z+5Qn1Jwz;B9zcUTYBBFS*Ys{bsK5k1 zNd0)XSCJ#+_H-0@e y8`WY{xkpd*TOB%#?--tK hQ4D9BHG)Iq_9QT*&{TNtg4oUGJgA#t{No2 zaPRP!ch%<|=A&kMw5z)#E8+`nGe)t)v#vj>YNF+UE9<^_V#Vy+*kLxlFJrM=x$@@N zyM4l(5REJ`TLz&F0@D>Iefx(1%9|9L2Us`*O4rxi@`tf}E04TE(eMuZd1W-Fs$v 3;_#*fUAV_|)%kh9h@b-bf2S*hISqd*vI3Q63qFW>nUW!MXFRI6uWGZrr zT$H(fB{yK{IGrBunPyeUu@Pn>V277VJ9R93?!?XgMd9yBnlGYq-gkiH5&Ko1)>|>S z6)zJ1lNBdoUPDzl{r~8mDdN(NdGH({xj3&O1i^#3QYPq}Roty=&QkzKgN`hEN9_P; z0}mRUd%q(B1Hma0O9FrNK)5dBeal;L;vXb {mnKV|k zTH|D4YUOh&R$T+~)5QVryn|P+S=@Y~(9`K;nrI8@GcR)OdA4r;GGW}v@$m=aA$!<* z+1`K9%m2f6dG&UP_2Wah$KBG2w`26+X(p0cX+J8GLuU(8I%6_TQ|!2X==N&_tozK0 z0&8HP=vjiV+sA3}ZB_Wuv9|HiZ7d7WkLTk9)lb!}5UM2|Ldb`j%!@R^f$=nj_;uux z#x1c!znK(TzqmAfcJ-gzy6Z6h+>>!~BWb64Y#-Q-zPl7uHF8@e >7 z+~phTx?66=K2zhKT=|vnbw%54%q-_RKy;A3^=`#Rz}#MocS65817IYhGHo)0av&?# zvow9nvZ%F_GVw&2YoJi)PARy~CPlV_nfgXPYs?@PFI}GpVg<+8S6OSn(!}-p4jF}` zzIpGX9CN8A_)0PdLk3L1v%){D&A2S))pgRHJYibBiq#j9=!n=(Wbb*SP)O0yXQCbC z%%@DMJVe(hwi2A8s0*`aku2V1Tn Ri|E4T<8#z@EVnC&h8p;_h>D^}iHFw-H}OQ7 z4LI;rl}y*A3gSSN1QdCr(bWB`&|XOpJ92C}89qn}#K`BTD$)Nx$cX#LO3cZxSgs5i z`%nG9F2{CO{F`e%7enhO+9OXoA==Uv@&^obiVZK{+3^IXiTsfP#c1x=_x}$ULOpH9 zR<1c? S t;1lDOf z 9_V2gX0wBWI|ZP*YAi={hDB%> zlfK8011S0`u_zUeeTsW`fzXg1$n?eV9fe8VxOC`>sEs#+6EV!xT`MiDJ#R; 1ef35ARdI}Q``40q`QvbPQF?K8AV)d|%m_ixr j=gkg5li6z=&$0BX_tr&xV(8 zv@rQU;5gmJVug(PjOEr_!(#5E4rD@CXnkMbW|~m2mJcgBYw`m6FCI+i4eSiP>lVmT z)7p~T+uK{i^vD{a0G@mT&JG6MSB+G7EQMoFQ?#}{-e2Ff$Si|20JZQ8x)ikov5gJy zgWW}{T!s35c*{4{yGpmZhGLZ< (rNwB-HgGQH>g01A3s^n)} ({xyY z3?$61CcSRcWNxHZL0yXw4 q@5X5_*e>0EY{u=Jq ztKd^QL&N`A_csT5lcwt_#D1#QZ~NwT#5 @=DfGYE^U#3 zxn&k&b{~U6qDNMYNqsER6W-d|Rd_m?q0imVv>QCIZx0Wfl$eR Ls#tNCR&I5OW_?+-hdcTE@=11?VFcNy zZ&W Vf~TEmLuF`xF7)$O~PicUs^hpJ$ww@W_z67~<0l;SlzLXyo3A zu?p6l)qJhDLUuGHVd#d6z|!H;m6&p|VY>Z=g!LrzN;%LIRgT2AQxuo%*{@9$CgmjR zdrj|NT}(amfbsxytpF}vX_U<%-)q c48nWVFLT?Z3m(g D5A;M= zEfABUdY>w#I(<{x5#1Q*k_xIv1*oJLEkj|Cmh+}!lx&~PvkbVgv#X?H7&g1bR( rroi0M=E7|U8Jri!R8d+gx zuO^F@ ztTQ5(w~9u|Gn)I~9od-Nvc6t*tL>m#oprVPJy%aCg%&PbAFu$Z)(96{=DBuKifrGD zWrdIEDk6ZsXI&}DmCTleR3Fery%wR&y9&iI(xnr0ue<2B7*jF?xw_?1z`4@~hQg!* zaLtp7y0=}$to0Rp;X`MVH}30>*>LGOd1jk+>D{cNV;+{6Z%$ct`$Uh4Tf6c@k2~?L z>g>^9VgNY43Z;StRpVll2o|}UCiTHvn7qb_{wQUObk6}%XGZQ93O(}{2OlymDYiVr z5Kd=a?@vTIO_^%SF5SDJG(8kL@t$ntn&lVR_q_n|RVCHuN7B3aAX1~1&@*YaNH0Lx zRC-{!i`4zBXK%onLoeX&< {zJ+k_MQHGtu{p*}p*zEJoHVw!EEhJ9$XF^% zlFie`l*%G#^NfI*gR#yteOZl38bNN@BT_=rjNAA?!x&vbB^SGY#Cw%yC;??0|8!f% z!JERFB#jljq^IKr+&RdGY?2Ux@edIhgc~tO5#SF!=zXyrG{X*-5eLtxBaN&bvnI!M zi>k5kFkq=Uv(yyc@jp&h4O!=ChH(l{nKaqv%aflQ+{6tFH$uxp;w+@0bVR%D1G3M@ zz$zDu>pUsBU|Kh^dk?;cH$3`xAihuygepgPu3wBrw#g2pbP=B8#bRu;^0}zP&?I#2 z+emd|6&NUE)RGRfj3L{wg-ECHte1*$&8p|2wuMGk4`P@s0J>aB6Fz(H 6NPfzP!3kwlj-#Gu-(ehCFU!pdduO{n;TwI2McIIPJFHHe#?xUP z+@>#!`dL=)irY`pIV3(kk@#R*e0n1B=|S*88ooUUzC8%O*jC@3N_~4O^+((0uV*rU zJ(FEi;$+_z&&;XPzFez+x33lcdr$x7ElZ@nOHz`F JNQ=lFA+K9SDI^qkBJ@~(%0Un+qY_2@>t#VgduKyK-{=d9q5<<3RN-kn z1$A(Hd9o;FQMoJ7bvlQH;7ABa3&D{Pj6eVlk`YKoAfc@!S4wiFG=JM@JQ
0zjj1&L}v0DB&^+pNxv3hZ-ECa>c0lc&MQ;Di4e*`ww;CjjH2Dm1{AV z*{A|+RGodOi)vKi6xYPGHJ26_iHqRUa1~qy*H%}ltJK{#cQSXfD*(l@n WbEm-n=>z=iM88k@I2e^6vhO&4S$=l5-_dtm+;@Ve z7rN+_TXeQtbV>jT&;m#R0cd~%D1fb?6qLfY!DKMmt>hmDA3n#a(APaH&DS2K$3cp4 zSZ%kI-)2aYWv#SRPEZ+2MPb$La)!xJE(zTlxs)PuI2jCG``ED3c)v#HSVr8koTahC zAtXc#At3~!K? kx2!WJ%#(*EfFVWsMv^g zUpr-zAcjbM;C{Eugg6Wl)<6qoxJ3TKVRDx6VZqPt*$J481bP+{dh7uv-hdusWc9=X zOfmsIfe1Zp023-e4-Z1m2|(ll(EI*5dygMPFCSFTzPydswP {G8~_*Zd^|wqcad@bBHBs@ z`_yNFeOi7Xls?r6;WU|tfR2rdT{+$p>)nemS(+&dp9A(|(|r^j?#T!5rG4R-j1qL} zArRYMxV^<& Z9p)so7lYv-rlm^0^Vb?w`m(OR5`+P{bDS#O?Duqi|`yT7Gs;0 z&qW=ECZTKJMyeaDz(5(JmUNh94B3V)L^_3My;O{ARy_~3Ei|%v5W@{PfCfV~iO`;Y zWE#3r4_lJKLbLFnEC0)PxI6Uuxm6wzdeP~nMp6$IMNl9@P=K!8BYNsGTloi?puo1G zDhEB+Bg7)wWCc9)MP6sF)MuY#bcmhg}YL|m5AEMufu!%eqsmDSRz zor!=LV&tw`auE-1V#L!A%#o#!74H#cg(4^A)IntDM;G9NrzzaR@Y*+Mvt@8lH3F8x zOUbACwS4q5S)&inqte`Gv%A8S;i?f}rMWoLF`T|iaNixFpGwI<@yb0>cV(Jn;Dpzi zN&LnP0ha&$CjR|1^vcTqRFdYb73Ba5d{C^AlftlKg;h+T?J%qvHH7gK>%x&|tLRw) zKLM+VhT??83=yGl0wGg095Ddn8VCSHwX2D$?n%rc64f8XfKv=9koXv(fUJNpKvLqY zK{ApQ=O0oars$bc TSNMpfEGK+5PgRwu+(GJdDtJ%@`r36 zZS5B{w80v87~ZE4_NJb6V2(Xx`|Qx3LIVv}a`-@qy=zsXb2F(KZuxGnF}u{=-sDW5 zSk{Pcmvx1F-ik!K{Fg$hOuXp O<{!^xD9%3F3roO;luE0cvgr9XCq;k*Gl13t z$U!&Tl3n~@5X~dXjHP8kt_Z+rnhoRCTbwI;oLCY7dMUV|0q7;5+h~o#OTYea8JT?M zVe~eBxr*q>Zo(tj4Ri#n`3?N33GkcHXwX2KwKZI|a^zEl#)8Y!fDz 0>Grz?tT*=+$1L`tC@}_r|OOFnmNxqv*ILZ*NeePc49JWH}b@Y>?CgRuC*$; z4AlXr3QWfP;beOd4w4JN2q^ENkuSKM2LaANi4&u=u*FhSPjbw*jwCYQkVX&DCyj28 zPZE=!Z>5AQhT3X^;k8v`nBPd*WlGv?Lr^xEMX!(q#gRW7rvz}} >H3_@gx0&h|RnUQz)lgHFBmFk#6Ovp=NlMa7Q#NID=jFH@Hs4F> z7Vw2>g2;>a_NEN2$@dR#hb#~oxCPk(`SvN%5$DRT+ G*vm*wY-y|ewE@r}OYqHfH*9am>g ?RSLsxgLO>?>zdiW zZ~na2^pk!4!~FNYaMPA$F3n>=CT7{>1>j 716ss`8^kZ=OMOn^ayFo|(9qK&>Ko z1pPrPDy78YPNW9%Q;vdI8I>^Vc=kncV7)9#Z0~Gp>>GViQ8i}XqAEU(r>Kr@FIN`E ztSWbf`avfAbR 4*gBKtPBF+JS&}AfVJ%w4+kAqf#7f8?IwAT*u7bPsE>V zX;dZ}m3&6!+d~bRQE?>-ls1( 3V(qR6AVu(Ks!qL0K!@M-u8zJhP7uhduSZ<{}vKeKlazv?YXRS!w3dPP#z6EYR; zAE|2dNM$=m%T0HR{GUDpvJ;_CIS582itG#Gmj&6`(9stZ_noBa{jNIYR-Nruof1Mq zv=9 GO2#>!y)vzHRL}o0g2{AIEMv_sy`9%UWuuq`5Mj zqQbJ KuvJCOjg5TBAL*W7w#`KUZ}}ZSUobyQsD?I96$oJ01`j|8lV6QU@IsE zrLb)<8LX`_GFIdjrgXj58bJII_1BM1fCUm79hd;JwV-_JSU?NmWB>DSBTJ&oU)31f z9|kN~npa!+% JRP`PjY%fbon zuYlx0e%ai&kPpk>{0+Iomsuu6$!LX1@y9r^4Vo29HMdwW4Bi vOS5)%H zU(q+|wtD8)fYy_K{R0Mg;B&q{pCQecAAP2ycsCh+5g(?NCGpJ9>0SQ#eR7l@Lc5{I zj#gZR3d {xs9rF -{}{-D@A#5K<~m)~_K<0eB?Xs;?@f!pp7Jzyvl6CR?8d0S=s{EZ8SB4- z`zVYTn}}k?Cc;X2%cx3TvJAYEiVCcfijCfQ^|=VY`eZDvWvN(M+k)|Svr(+wY*_DW zK2+;VpDc!#&Z#O!r}yTknu~c-l|AK2*8VncRc&wEEzPv)HnYr{Z!@e9T7YVU3?%TG z%qU E);f&)D2#^ z)vA S`XFsvL}b(a3*RPP4DKXnu|H9$xb=R*>7{JX1B$TabAAz z@0m9ahx4~3x6cF)=@#5P ^G$X0Ok#9B0gaiB@4VeH0`MzI@%p7-E*^&`mB zmPc8%*hCU3Hj&lITP8K~l3k#cR7@b1RAj_oeJY}_J{LRd&jRr;7PiHr?PilmyV Cj#V&XVkTU~G%&%+i-`3}M-unO_Q*E=*W$nYf*E~sx+?;DSqJ3} zB@8Z4#REb8%*J14q&ZRGG`^Gw$r_I1zdp;xC5c{=Z^=>szbeMT<4p~QIm%J>boiB^ zK|bdpz@%B^LIuuP(C}0*EY6t=YGDTPZGTzUrDOt;OKZhN-fu=-?RqQNyOf_x>*)Gp ztfBM0wLy%Bj4Llx<%X7Hp UxyZfuer`4O&Cn&xRrRzmvQisGZan9iqP}jw ziF(|Id)c|pP7af0C(=dOj7;AbCuX;zFZUx8`(4jAtjTS$-JXWJ-W1#Gv)D#xp>taQ z8uMj(R%J(D9c!@Y&3*Q^>uXl9@cmPUjpV||Ppjc;$c2~IhOhZPIrQ_Algykm_2Sm( zlHBF|0h7U9tfJWyZ(rF7yN`65mldwahRsjmZTkz|`LjjvCf@_XCsp7H w2#B>>uwwABToBk2|bzJM+e4TU3dKB2ZiUCyZ7IvOy~Gb5c>WH)N@PZ_NNoe z@aL;@8XJCiGXiZRk3Tf0_!)Go&mx*Hu^U;YnXlYnl<*x^&{IdoU0t7uBhi 06xaf@frS9^VyM(In8A1xDyp0C_s6!RTX&{IdoU0t7uW6+n7 z!gncrSh)UW)<1V2Z&CaC<#c^@?bqjMlD@$3(Gq2Y^HsMEAAGjM(|hN*xU1?3anSh! z+ TAVM1XU zTmTlq=cG1;kfE5z$R#Ag5ELdX@L|hf>tF_$049K~gRO%tgWZGsMDbFdA(u`8V4=X- zJ_v74xB<=Q+!vuUgb9H~Z~<5YpOf13L55}?BbSf}V^5ffz{k7{u?}HC2oM6qI>b7} zI(&mhKjVLA&mZP5iS9MFhv$8&ym=I+dz1X?1m^MM4E?;luE?edeG9vjF|h-MK_9e) z(I42|4P@WlA7s281M{|r$NgQ~Ze4U4Kb22?IvqZPl5#NziOE2%kdAMhlETTJImvKR zUB^eq_c_dVMOwG%Hh&Vm)=%W06HK@HQ~7na&7TIfWE8#nh1Y^cYbtrog 3N zpdx{JP&Ak|KmwNl3EVad`=){wKu5+; aI$AkGMrrJ zB%`w?hyVAqZ;bUL&RtJ2_wPhLJB(Kv-*(%&;)5xF&Y-Sq%F;kiJFj`N$_Gh$a8mcL z?&QbM e^r!sBiw07i4OE*;M z#7Xa>x5V_YBtyg+RJ4iC5(CG*Jkdyw2h{yNnV6Qi3{LA%QU^i_EKY-)2O?tO(nA9e zM#Tjt##Jb(L1 }!nm~1pyb(|+lNtk1@v8_vZQ$rT|7}lM*j|~+kAHZ{k$0p zSfQfb=xk%)xR-A1cyP{e3e5F>x7$*rB8jgc4Ys1~(5x664YWX9z*&nJnfp9KR@^ zGI|yR7_u?RB0DdicW}~>d}QHDzh=gpWSzru5=|%da+)nWb!xhm^m&@dEjwDuoDpC` zpO?zqH5UZvy6 hwfl_oQQ z?@msEn7?jF(`BD0?v>mVoWKI&y3h3<;^s44uJ?TIId0N}$s~F&iCKLIt#-2bsj4N+ zNNa5ocROonr6pR 3b4jNhmHeqX;2{En$Ls{%bLP{ C{WNFq04s19%);H_J-}qO z TR5mZ|kt&<0zPfd&67U=MApC^giRg3v+mHwO?Mh8YbWe=&hH~ zTLvw4{GKog$HN312X6suxu6fAzLRt8$N~{`{E^gQ&fHw^4ej=j>Nw{}!-InbXV9L* zKLO!(ZxSVHA*hMQNEPkEWo{EHnmtt6mL9h`_%*fYZs%qAoobh034Vv#1!$}%-Su~& zbk)}dvfZZy`w@Qya7$SW6tu`?XC_V52#*Og!Ug2`YmHcT{|eBhtx$Ov5sm>sEoDS! z0k{I9F*jP%zzM^8G^nJD4Am*Am6R}baFeKZh}!56zVq6q+F^KJw^cJB&ug {r_TToN21y$KFj~*M)l?{p^lty`zRysu* zS9%BMBvL8TK7l(l^%m!X&y!v;erIQN>xy&H=jLCJSZ)?4w~MnD M zl5&?Ch3e-Hwb?p#yW3gkE_XTO+~Kx-jUwG?56mUyt~3VK&n>xev>+D1Cf3_M^mu89 z55fSg+?Ez0emo&;7(wAj7V59DQ}%RpA{sZnQ{f(sPLJ5ypG(1>i%uKk|8nhRQVvsi z*^Skg8ih5QiuGk{dX4lXAo@QcGRlTbQ%YILwr7&;GMR19B )@Q z{yyRfIX{UB9`%xhK425p;*)R+%|$1i6uCF7z+=EH918=$;jM}c0CZFYI=0LMpksn| zOXdL3h;niD=t1 m%b)sX9K|h Lb) zJPUU>a;ofbqAhKtRM@@50+{i`9nVdp2Xz(-)*+7D(=fuXQ#8tlHJ(m$;^;nJ*zt0{ z%lk)Aaf8s@rTwDNoO~!X7+5Iq4;<2TmgvG0G_15mZYCzQ%4w6JCh6ua0gI#-DfAnF z`W2L#&)T)Fd<83aRk^CkE-x0LP579H0f5w$Id~14P2OH!hFDWKzh&E=Yj)F=N}AGy zUECVUEs@-cUy?*4bK-IDRfX)>N9SrD0N x-|EbTt~U%p07ON`>1 DYRGmVA;w}clpUHjms*DOW+E` T$5HK2=oeT?N zIY)vy2Z2={|D_)KRdLjpbih|Q&35WPe*TOSn{tb_eEVgEr-bozy8TEI(?km=|IXSp zP?-^`6aWbV7AJzH1nVG*&y8}RcottV${FwszHpRN;5usGG%0INm>cBJ=G>+xf1xt< z_*m~lV68sJ`w!TLp|-c5^D>i8MTnZJvy( Zi0YY(uE38)tc z*rLbG-Hl7e2Qf|?4>nF3CqEuJ`qpsMs2E4k<}TZvyU7=5ah8ov>F(r0=T&mmKCH}3 z8uTlA T)$_{DL)pT`>ws&s}=-V6?k9`+z%hHim?sz+FS#UFsvL;4(P2 z)Qj6uKEf}iWTvx(2#OeF78i?0twKBS=aa|&gxyrH8l${}Mj!a>kL}^f>B}GPl`z|d z_8Dk%!7kq% !O=i0a2b&)|wpazngG zaRJ?fvj!?ZA#0h5WrF%2eV}Ow_Khb#A^=kqiB^&d6GyeePau72Ht-__6jb9i?JF;F z`u*?Y=qreZns`cI79LP>Wv75E!2aa0blbu`uVwo{+qNHv9@cRL^jgR`{ed%b0uJwF z%LM>grpu+v2oIk1)(+Ekdd7V(PkX~3J+RN^MF@)JFk_o{d>Vc*MUiN%rf4}39e$*M zcqRYgyo8(4ImI6PAsvAkRf%QQ8F!bM{CYUT(d3iYS5w^>Y}dF(8P*6!GAi9UrZ1Ir z_`;3gi(qsP{K11tSI;SaL<)l g{_z6%s=Qow=icSKBtW?vZD+sYP#%-EBE0yn; zIM%_6Z2SD1Ql&guPR1XxtkgLt{v^t8t*{QwZdke1jBw3H7~ses{{r2_xB99)I-&>6 z943Q43xcFD7b#IQ&5$XgMk{~P@O)Z) E>PZ7Z%!?;v*(<|6ks_*{)hCKjVlGF(*riZIENBhd` z>u=f0D*T %q`{$!+05^KJ!h%82<8+5$-2KUEYeb1P37 z?+bMsPaW^;cIWn~>Ktr4BRRa%Z!U7Mzt7z7Z--;goqQSRL-D1Y>Gb)on?L1nf67=> zKCOM{bl(GH=UXCQdC{VbsT}KTewz5o@|3N6j_*0LbMrm7@402quSxzQH-A5F?mjku zF{jNL-}%HZTI6op_8EUafB51n_fw{fD89DI5<#Y5TYSDKqFlkc2oOb-EZER*9w!nZ z4|YtPFR&E8>`x!}IA{AqAZNy>!M~$p;l8nEFRj`4*L &AaVWqX zUFF @RTId{|L zjP0D=;@n4>Grsf1$8Q(%+gx_bbUF9b>CC-*>~{P-u-encgbp`=6UQQmFUD6tfTcey zgF*5(YB8c6&?wm}V2!$YX% CyfoXVTZ_c4N?L`2^I=qjS2A0J%v__$h(YgG^U)k ziY`(?qoa4m^Nu9(^iV+(l)MRf_I8WmZMXwFf+YZ0CRNM^o~XS1tn(n*U&uFGqAt z{`)mLI-+IuHTrfVwE!Y#S%H08^H-~HcWZZxNPrNC1dPP|d353;u(qNfpr@2J6+BiN znTW|9GArQ%mqA_5_F3K=>Y*7O$R`$HCl~{A>Ek5QfaRJ$f})B#S!T0Al~?gkbYIXx z^#Ux-T&;Dq;*bta5s@O0zgYqcAHV_yXjlgT70h0RQ89S$(5IvjL=T#@4N3*oo_Z7X z_*K#IYt!ElKkGaRKx Gsq@ny=U$8bEE1u5`$|H z34K3=C?rj78&=%`x(1gAwG6c$c0#FWZ)2h2Wu<-L`9p&Mze(!6L)e_i#H6m!95Eo$ zpR@Zcr_<$A5cm*syr0}u4hX7TafJEi2Ra{$D)(v4(yu~iiV@|1ZIl^szr52yTe@m{x zI90}*Xtqriv)0uSYcod{Lvk++dN0u~*E>VIeox?ZKwwl@0tnb@3u~uSs zP+6#Jalt5UN-c~T1;sxBKRiOP`QL>1gywj705lky+6D9sMFp#ISxkl4l`~YGQ7NCX z!#Z|w1I!A4Sor=bL&3f!*d}oo!rq`gX;Ic1P7#m)k)8<#8Kb?ZE`(*<@Vd`f7I_J^ zkdvjWJssI>3{NAMwQ!9!x_<0bDtZb&nb2{bu6m--IRKW{4>&e83xb-%AT6jtZo*&} z0R_q0C6gaBHbxF6w0NZ~F(|c{VYW&sh4^n=jMiLOA-Ee4X4+$^3^V4Bd5^!q2c-k* zvOq${wN8vujvZ6iUfBLZP44n0bA{_>JL@bT`3l7{>%v-k3k z-D(6Yedga&tLLZ%dd(@A IW0V!z4z)M);p5A)xY$#o^I)|#88GHHqb zsy;b%_@|~JI|T#}#r*DC?cSfgf=)ppwiHKk9?O$2TYjUOF`qnQxs0dgWjs@LgO@{L zZ1)eIF0z0ppK^ejV_}R){}8sqG;WKi4dU2JVC@xhyPU0t7EeNX-6QIdv)tJ>1SQjk zjJFmcF4Ye$tFA>TBRm^PMK8D`o^{IIgJSo>rY%`V2YKboPe0B9nAKuzWhH)y*pV&5 zP&Y^-a)Ud2VJ&Zp|EvR^NfETZY{>-+tu`T$E#*yZU_2OY?l T zryP#ii#F}7P>966wCD%G4w M9X{8%dhuAYld95O%mKS$bhWCoCD@&?) zwH@{%dD$9m=0D@2XcFmiH*r&k*M++;Z6-@AOH_6{1kPU@9p15$hXsrL6(zN%N0HRY z(REW00nHd#Gr%ors>Z?oB!H`p+Pl{in)Qw_=t^s&+2zj^dXV*=$7(ClT;UNfy}m^F z>G5E!a@HRh0|wx0k(>XtT{7w$m37XXDx(k_J^Pk5={%+~92Ez-$z8jd{nIuyBPL!a z#nm(`>eRL@CyI5XD`n{j6HG6WcH9E`{(_nyrIYwwhFeHlQ(GRvf=F%?*Pz^D9{x(~ z8j_;)HNPu5RzJwhXeLWvJlfG9yD|a3PobTfQhn|z3HOk||KRRapAKs6^4A#Uxr_-L zN&`)&DNP?rv5_DmleuwcXER{5x9IIER3Hb>JJW6CoKy_wjv?)q)U614Gh=jrkmXca zMhDLveo=g8^fVR>nWl|!@Q30*EoEA)Nzx?q5tt@iE5}GD)1IEDiQq$Fw~4A&iL;=c z^WAQkD(uD9YPUN9Abty~zPT+Ybh>yb;5!#pbYhWb0FQ42WZgo*fLoza4d3zL=xlL0 ziupH~!>M&wK~Sn3zjWCeo^oqKJsP>B7h`JItK?h{IV(J~3&l*U8cn*n93P wK=D_%eYx1) t)%21jk3yP8rqZV;6afIdxeIJVw|{PCdaLg+Z%e`H^VSGJ#F+qQ zIEP>~6AP=HNZKBDH06IJL8X_JQMfPv^eLBz!M>?6xy#X#ZOO327UGK+*2(&S$AYt( z$xC8`L7*-m7uoH)UNVZ^{pD)yM`j`NwRnP9SL%xET3zb3lOHD$_Q2*ncFHfjJF!HJ zb+~*5vB_%-HyPxkkND&Ft>KTyv8H
Z**_I-5pY4O_w#C@DnC`+duvOIv69472N<#eW!ihltj91 z(`Ycc|9b>0mx^Cglzj8wX&9K|UsH6HS= 6l0+!7_OZvQr3lOF_FQGRCKn#gsltNm+3E;pBIScBkar #V2g^g+prb_HA5V^Of?`JGZ1@^Qkzi>|AXQz8vGrAYUSbdE)Q*~x_bUogUT{L zIA2gB^~1rEdKMq|*-p3?9!RYtx%h`g1qL!!MWS3{hBgHj7JpTfuhiULo!S7M)tg{h zr`9+ !7>UoZqwD&Mc>$@h^pU3FPejOQo zC$MXc56%uD-!oV9$b>j%M9r$~E=1mHtot}WS* B# uQRM?F_@GwHv)Bt>%;}Vk{q~c2&=IHc5Zd*B^1E@J!gk0!VTR`4&yn-z4@f$ z5DOY5Ut-9Pc&=a=*#?Fiwho@hJdxx7b6I&=ke $B4_ z&e+PzWRakJ-|>&WV;C=mub{qM- O~SGjDPeaMi8rK$R51c`ACP{y< 7WWG !!q*;bP<&? zTf;w=^JUA8{1*BlQHfM>wojcK!TYsLb9KptsdCQ~0D%8a41z%-?nE4B`CZh(9Ai29 zGRerJX8*hrMO49TH>%L%XX^eMp1ultl1LS2ZKn3fV(wVHD9OuIr$pY?6I$?zk^_^K zf+5*9uEhQeR+NVSa};zvF5i2HvQRDSBvNnM6qYTqhlaP@%xLQzhw6jF#dbX+_%IHo z+ux=~?oj7DmE);5ppr&X_BIA#LnAG7Y1T&DwPY@mpnOrsx% ^U6m&o7$D*df5m#C(1Fp*+fI z@U#!VwOsoE)1TDV@FS#C^#AmZYiX&U&aNT0{+#C4@KH=BbJp;hmUYFvH~&QQL(Ukw z*0$5S+kT{VSsiGna@OwG^?B#x+)kf3rAhbW_j~arxpznL%oyZ!zsGVY^J7;*=5y|^ zsLqpHK9MSIo9cLSt?fJZdZgRACmxD^H;<#CW4O-d1|!YdlF%V{zjAD`EEOcjA2J+z z%4O}oTW<=ALj31o1|=QlT!Z+7D8&NvJm_V~3;q_l_S&K%36}yUoObWqJw;uL=}~_3 znfi499nBeR;u25{TN?ZG6;62OznnN &~Vir|nSpK_m7JCRh}+e*e=s+>(r7+^n!fU|*jcQ1P<*^0p^7T#oeHf2vM; zriGNVWS@J!wGmA{zq@K<8sad28!@n8ERU_t*Da@hUHK{DYeyr-U0dfT^5V!6*(Mbq zspV&Wv;KBvqS{tq%Uh$m#T>Eb)>{BdW_1 sp)S^r>TH(TE@J0)%W0Ux0wiSca(3| z9eZdn%jL4hBIA0i-<||+w~ZxP-N~%-qh%7DwH3$uQ<`OJQn|OpZqP(x=eQlAH5kJ% z*e5?f$`SkbX60pUI(ib5qxykX2K|U`Y111PM#7{G#?lhw;dn*P{IV)^OY}$H9nP zKB-s|w ngn5YnwA4oWT4>vIS z^-Cec3k>SlmH)`@iD-!ke>g;Y4WcsfE@miA;4^mW5$$R3XP>r~5xWMXWUts-|MbDG zg``qIs>?7Q{5Z?7V-Lg?AtBB=Ff)-Mzl*Q +E)$2W91060%3E*C$YD>VI5cW(;lWu7jJaJsYzuyMwYBLBA(Bqn{Z z@x-V7v>?t4w%&tn26Po(->glQQUfs isLB|UrG`-?VxEuTcYU7M`EROi@ h!Ag)%N3>QtJ^l^PUmUD!; )cQ>^|<7sfQ# z(K3N%aA<)L70gHZi~vo&BE$#xQ82?ioBJX}MX*8zO Vd1%SdfD*@O2nyPGsUn`7dtro`V%qt2)meq z beIyrSPlaTJRDl(tWUXzrjcIbN`|DfyPqHjN~(hrx6z&urx{Mm|XB|kjscC+3d zg!@RX mDNpl>G*J zBBUW-GE9%+D($n4Tw>yQGa^%~V`tO`p=Z#fxyEde;xx_o>rqrCm4olQr#-0oR0kDL zADU$VtE)e#sywK86pqI2h1sl4(BnegocNQvJhX*w37qrqdxd`deC~?v`JGa$9_a@+ zjpUb@Zc!MXn!3qL`QKR}B{|x;C7?W0HuvX!A{WN$tgDn_Ety)#2aWz;#WNgCoEbG@ zmtV+ITgQ%H8$|Hful9Fo(@??4^d%zGsARrFtt nP^5JBWX3}Mq_+j3XUYfj_gCj{%`bm_9z)Z1a|Y#a_$tK8nfWz=lDsbE z4@M9bDfP3TkhYsOCqK}e5!!zmU<&lKa<|)G{`mRNKUP1~g%rV-SJ>KX }GpCZ~_08AVB~)P%ww@ow=wxe)a{iMki3Re|o<=co<` (%_CEx7ZDrw4n!O{^{v|ci zOZyM4$lFfF uUObbe9;q=CAla4PQa=k?V88_| 2WK3Z|6$ z?jJ(o&^v|8I)*{iD3K`=pjuM#7!A1%Y92Zya~t1`ai%tv?~5u4svq6JPgh7Efja{5 zNU8v(uNuZi2}JHu4B0;o|6lp~dmu*qCL_|FF)fzGtHo9Yl8F_l`RaDz h9@p&DDh*Euh%~TDCg=b*eRi!U7%o+cEl8sTf`|b0zup>>?a%7 zZ4cX%m!avv=~ZNNbh=>77E~E 8o 0q!XAlS1|Z@&begSzn1@z9h;&Xd|MG%+I05H( zdt4Z$K&o-k9t9}m$;+5M*hrWU30C#H AHNze_kVRk8s&5$_ZpH Tw7UN*tT za!+c7^(blm#0ND}B= nWf8TIbdIH)J zG;{e$O LbTB^~3 z6TtmBb-9SAd9ig0h<$8)GgKfY!MdRaSt4Du*&@j=wgT^Ars>L_P_St|J;;(gIRq1# zNkcFZEnTTdq|Ljw0d+W$mPW&J3j1aH96*oO8dc;03mdVKg;qYo@#IT(wpb$sk}^WA z#rEXXhps|#%9L91qw}tcK19mFK%YI5h=(BbgPAd=q2srr3c96$>A Z2V*viL1%qV zQXeK41u--C%n4Bb^C_|8G`sjL4Kc7`+9@Y-z|McC9Z6J3F@QwF6o40zr1L6`9ZB>= z1X@JlLJ~idKE{BiZY8hz#UM!9H%m=Qz!~P@sXo-zu6N2w V@88@@!_e5;@rz;Nkh#}>Cz+E%66EjRKH->O!vQ4Pu`osh zC>J6)(S;e%U*H+Ifm1|k#=yB9kk$?_j$EA1(9!1C5a<&S@mn}+a`)7_?3BIE<=nu* zBcw0=McWhPe2+`Wn5KALpBX3(DnBBq2;OMpapO(w&WKD-qG@wvm~e-!>eQui$uq_@ z_B^vyxfl9S|KRG1aw`_Qh!Jj5pa~BP!37{bDwuO0$^~eIv^FQIOh1(3BJn20h~fM2 z)9y^nCX_>wNX?5sU?xh(Niy?u;)K`gNB2M8R5!{;gQZ|3LG-$bLAVhsOB;#rnuK2e zjrQL+o)vBGv2|WHjvIBJnaN@chw%HkEwUQ9yN+191kwAP?#`Q=0MdRKv5q*NIR25Z z5PI&F^sctn56O|)0-imCwl}}8xc^prWiS)(rZNni{?Nzcdy L55{g2h|9 zh|5^PS>&C^PSra&nSD<9c?5bEQT(@yNNHD`9P##ri1xl=Fljr0KA33532u+)rICo6 zjHAAyWjI}^ht;D&_2sITapajcaD-^Wupm_Ze$Rz(SU5X5I3@DNSrovwlXB+$Dn{5? zWLQp!y5xqM75<;zt0ZDdl)-+>`Qain-D9}jmx&{xNcJO#l4FDibOP8Wcf^eh2%D)P z1fR1edy$fM8FnC>e@mG6d6Y+GTp)7~0hF}|^V4YCsjY5_GfHD9#~ZtlzbaS0n!DHW zh#QhPhe`zfsFQvf_Zf;ITsQR6F8X=G?6VVU4`Hc24B)QzP?MQ>+H9+)iT1$4&Adg+ zAWdf#Mw9-nZDB(2SE!u{`^^pwHHK5ym;wxHzih49ER d8UboibZu6-?Iz+Z#^?RF#U@VRTykb&*$}6q zx+TbFB^x$)R{9%LmE11Y5HBl@`>HiWuT!LOep1_P8csa|td{0RmGnCHDpN|7mLaB# z`895_M!D-lcD$9g s3U7_v8MWJ5u1>y0^ zbCB9YKHUUwFXU=FxVqeV6Vc6qto96XGh4=KzqZ*XV%Xzy58 vJAXEb8*{!h_?{ucn{pyobTFZ2)EgvT<*%?Byik&lik`iy$cLXs>GLm zeJWIiNxH;s5f^jJR_caRAm|D$Mq+715`r28q8<$;!CcCz$(mDRhd%X88li6?Xki)j z=N2U;d1Fcjs$j=lccg`NP?^oUSjmwKBD!KJy?W$jHdU-h-k5XIz=*mXY60;N`9`JY zRgcT`5jx5MZIGA^Av8jJJ3f=FdldWSngs&-lO#mY2%;vltU!}78>%5n9xXN-R3;-! z*|o-{lqd1QgZpm)JlMRq<6{#dXQ4FU0=o3(;geGMlYd-{MxF$??N;V(xSTpY_Zfib zD~Nj{u1@PJV)`Em_cfiXBMyqdQA}bPYcgS3Ll3UYS|SP7HA(_tm5|C*_T*LzdaFbX zF *rq}yi&dNniNnPIzx-TKHb37y= zdQYtB@pmZP-q*!RT$WIJYvPRrjdpM*rDay)tk^jCSWjRB F@yyZU@xp_z`3t8iny(a6@S(Kd6Ts z%_SOv-Z>WoSLA3ISW#x-6H!(!!bLssQjMPkmQnW84k4$<+Ko8+LtPtH{D(l=&cv1< z`Ql(y9Evdpf~kxEsr|^2A<=g&q^_YzBj%3Elj}TLB}Fe@iF5M{XB_6E}RY_8B38x7O;JAp9@xxgZfRLO`!qKw{b`sJs#m zl28>j(HrG%niP IVd0%CW9I$hc1uA@YSLs+ z6#(98eqZq%MsZA|ZPcFW#CTMdsY&Y31a;N!_7<$vaxDLicz>hS)gxJv0~}lLs=X#m z2|yLyp$N!;kc^;0QCRM^u9*Xl=}bLnos-f-V5Z-7TfdH&_8GCL=XzgGC$&5;5t8CF z2`}@I2D@O?Wel;8h0XBOZ<5135^QEl^_%&Zm%>t}7t*)gyi4j=NLtp`Y&3Fdq{KJ^ zL*)b!Hge;ZGJJxA`;}@k7}3_bUqi*vS$~_YO}N-7Rk84La$n;$7cdz};Xe&;2h?2A z>j7ac4zShcZZlxwBoa06|K9wC@hnaq^L$_tB%Q}#Ia|C$sEPwZMOh`vKP~A6y_gJl zF-8C4qppYwQ^99s1%^u6&R1F{x%y6!wdZOuF7$>BY4Y!rdNJ2W9e =3mY%Ej_{O8; zvX1>0t^m}hG?G9fQV3Re(~*jS9r3@Sh=~3u{WRk41sSy|c7Sv1^r|Md(QM7QZyn&} zmU_(jQ{hOsvtTyC1Eu_QC`D}L)Ey^Tn{Qs6Zss!4M+)nglA-04!8T8fVR;pn1sH3> zW57fA#spcqD-02{tR8DVw$f5YB)GLNV|V4qA&=XY(m^6bRY&UQYufbHkTl+$S`x9p ze6{^3Akk| !d9Jy-SHz)`d+XRq> zWEcQr_w} ^ zMeRMtL&*gx%LFdG8r4+G6qjMF?2`wO6g@GFR4J|8>;mSx*4WZBe@spk%8*z)7)G}{ zIq#oxWMp7hHclOlL=YHraBJMdHxmAkxS~nR8q^Q?V-7q1;F}w->Kf P-`nh`YkiK#I8aTCQq!egODxOy &YuPv z?12{k5`^Z6ZC5L2l;yY;8T0zN6i~@*r-x7UytHErG-INAlsU$`Oo54onzKRU9=Gsk z0)5|v#r6km#0h_;v{ICXZ3U%e@}|aukc9Sc7_wcMo7=^-A?`gPJ%@Fy#SArq)N+TR z=;*v|{)w+*viRGNt90NDHWN9owq($f2DZk)*qX+56`X&;2%rJTZQu#1tv2#Z53?et zO2gNfWMek3rQHWN$*B8&phIJ7#XM4YuJWRpuFjI$H|qu$8DImZs3lBO7N$qn{O{fR zGPEdexZe48Q5iGLXbsw_OXGx|Gxb6`D9saf5zxUM`Vhm3lq;{H@<)y@(ItE8AQVTZ zSAVFftGNjJ0~Y-d_;sQ&YD1NNDoX0rXqF|g9%(n<*+YxO19|}U=6fkd56pO`3P!B8 zHETDhUN~%Qn5m?KpQRB~JEVkS7DjeT9TsrrfX=T2q~sz+yQak0IcAtS!2t{!rCrPk z)KkS^9!eGH1f!aA?f%C^gq%Kva5QSMs0p)5RZub;gw>M95Uw#8Ro-73cIXzwGeqze zCUX;C1AM}a=)WVq!xT~yW1uHv=VYG#ryi&s@;V$3MK@O%>%`2n2r-{-?W`TLcbLin z%Bc->4X%*XGrRDomo(G10hZI<>oJ}vQ4}d400{5IpT!VEpSXVVn$`dYe$CZ1mka`c zAV(tI3I<8=hY$qPYe&P5Oc0XVs?E&Ef36>cj%%PnY3vSGte*=xSfpy%^$q?posX#> zkg%!6QboifmT=`NHRoA;1e7u4y#qreVyJuxa2>CQP;4x4{3tt0zxVa !oqAVj=brsT0k05Pj&7R_z~{9|2Ebj6Yxw4924_XK^}5cU b4+IC40j-RPmL1JoGe6l$l1keWxU66 zm34HXPN&D1nb}|rl&ZpFlb*Tea-82`?Q1j=nGl~Net{ah0bxG7ASpMjqT`McH;B>+ zReSwlt7r%OUwjw|&0yI0l&8MN9Axk4=e(Y?}cN5Co4lMQ$YSRRsw8L+_ z_J%e1`@&m^eH6$ZR~i>kov^8}`492 -cO(Who2Ev#4gW-*ohGV)W5!m*;MreM{wzex1%c@&Si8)kL;En_vF%! zQy5!(^$*Et>GF*S&|eqbezU|yBvqs+jKDLewA*~r*NKG7@^M1-9*1yuyb?EPb!Phl z3E-ipWmW9Fgqcx!vTf`oB^PhKc*6a!>-a9`^0eA429&q=}Z)*qytK0^rCFO7=r zFg1Mjfesa2;RY3kE?mjp>p`(b#~E~cmx>WNhSUh+%jPdtK}*~R794z|8IJ}dsIt(D zj=H490a?uNT9s3j5_d%V#dxut)+rI1aP`OF16FRuj E3-mDBmG#IKWd(p8jxK%0p;qb6?J(WpsBRIs&)K)d@!1xJLR6h9JOC5=hzYI?F%= z7fOg4&exwR Ue1 z;}4&TeUA^7XhrC&Qtk+AoD0M`y*t;vFv2HsZJD=E+aZP(G(}m9$vmgtyS+pwX Mel1Bu5LJ>|y8+O^19bk%*@!~y9f)nybrCsCG`hL>l+b&k`;&|{Jl|Ka0D+=m zv7}DlyVjxACps*z^)d`+hsSoR7Z-cdCp(@P?T^vdI%REoy576fV>WhH!T+N?nH8J8 z1{@a(t9mcpY+lHdQbgCrk2U!(Q X zmw{p=(rqMx9OSBBGC=ZW*R}^l8PENCK|eA?H?*0qk(y$8k8IexLzYmwD}BFx5oHbt zW{^Scb-u2YH=W@DhzL!pXa&^=9@Ugam8E>%mQB fL?mrnyA{~Hgox!54Q{y(r@V$ zBE!j-l3)rGg;-I;4kG1d0Z1GJ*` HjI*C-Qgt7tvocL zoFmO%bR`G>)g0$-9hti#y+pFeyXmcOtduHlIA8`X9$7rst-cwti7)UD9nbE1&HB(X z5LP87bZSi#<3y|`ItppotLKZ6?3LG)vdSSwg44ES9c{8=tI=AO;x&Q?NeTBx=u}B@ zzo;p!Rd!X5mAB#kOuB_#Yi0MfE*V93;F1}JA@}g~pQ~zh#fyy{AX7|3P`{XtGk9vq zCNDDLFkeE{Et7;Ooz^N Oz===pHOWSj~Yq{&N=766Y`Qu$5Z;SJANFay!qPgMOP5UD1` zT4pYwj7Kt?!#Mu-Rb>{c)Pk<;F~6P3DPi_uj47X_E-@yxI`y$}VqxDqCq|j@A`tYc zdYe9gim+t PhJkN744g9oRDY878!D{DCxpX^aL7+qRrJ~|qP%p%vo}Ua zmF=K4uY}`dn`BiXZdVK|#+ ;9tEsVTS8o%)w@Bmds}5GwwL$ z4P>RvBjlxPMc$u$VkrPo9>53;JVdl(< FYVs%&tLRddBHYYryX3 xudI`RApxv(=yLF;44i15*ToR@5S-7=BP zu;;DY;nsrBKe6JpH;-fna#Tn3WM|i#)$6lFnv%%!LT$bLP!r|yNr#C<9mmOhsAw8e z6;3iI90Hy!m)J;+DCq{FPz8={4wb(jtc(yxr#R6^zYI%OZ#%SpHLl$J?#4+ZVNK&- zmr>=9O+9IvsByY`x#0MJ$TBGjXx~gcR_=X #}=VU)hHD80;t?Tkt?gE zsnZU^7t<~b>LkFfc0x`2ZU?7#4E3faa}F`0Iij)IOXV4{5GDZxzpGsCdT+=*_U++! z=jt|Rq+uQV!I=OK!}q!JIef?i7ZZFyWr%V+m>Q^;QI^vlwXohcV!$T2BB^30S9@H( zmV}w0daW|#ak7qsvU6*#^> <^4?7bn^&!%N**%R^fh(i`nBY>c!^r(}<} zFu8GU`=A;WDvuK1SB;{79!bQ9*<50 tk_ zC|rxpC^8$>vR<)lX`?CEAzDd18V740rX|Ll$C+z$I~ct`rd5fy(HgwNbVL;`?ne(D ztQg`_an_47E2j