diff --git a/backend/config.py b/backend/config.py index fe4c7be..ae1fe4a 100644 --- a/backend/config.py +++ b/backend/config.py @@ -5,6 +5,8 @@ TEMPLATES_DIR = PROJECT_ROOT / "templates" STORAGE_DIR = PROJECT_ROOT / "storage" FRONTEND_DIST = PROJECT_ROOT / "frontend" / "dist" DB_PATH = STORAGE_DIR / "guides.db" +PROJECTS_DIR = PROJECT_ROOT / "projects" +PROJECTS_CACHE_DIR = STORAGE_DIR / "projects" ALLOWED_FORMATS = [ "OnePager", @@ -27,7 +29,8 @@ AGENT_TIMEOUT = 3600 MAX_CONCURRENT_GENERATIONS = 6 CLAUDE_CLI = "claude" -MODEL_GUIDE = "claude-opus-4-8" +MODEL_GUIDE = "claude-opus-4-8[1m]" MODEL_BAUSTEIN_GEN = "claude-sonnet-4-6" MODEL_BAUSTEIN_REWORK = "claude-sonnet-4-6" MODEL_CHAT = "claude-sonnet-4-6" +MODEL_PROJECT_INDEX = MODEL_BAUSTEIN_GEN diff --git a/backend/generator.py b/backend/generator.py index 9a04ed1..9ad7358 100644 --- a/backend/generator.py +++ b/backend/generator.py @@ -17,6 +17,7 @@ from config import ( MODEL_BAUSTEIN_GEN, MODEL_BAUSTEIN_REWORK, MODEL_CHAT, + MODEL_PROJECT_INDEX, STORAGE_DIR, ) from database import ( @@ -28,7 +29,7 @@ from database import ( update_baustein, update_baustein_sort_orders, ) -from paths import final_paths, temp_paths +from paths import final_paths, temp_paths, project_dir, project_cache_path _semaphore = asyncio.Semaphore(MAX_CONCURRENT_GENERATIONS) _active_processes: dict[str, asyncio.subprocess.Process] = {} @@ -94,15 +95,48 @@ async def _render_pdf(html_path: Path, pdf_path: Path) -> tuple[bool, str]: return True, "" -def _build_generator_prompt(topic: str, format_name: str, html_path: Path, instructions: str = "") -> str: +def _build_project_index_prompt(name: str, cache_path: Path, has_cache: bool) -> str: + src = project_dir(name) + if has_cache: + return f"""Es existiert bereits eine verdichtete Wissensdatei zum Projekt "{name}" unter {cache_path}. + +Prüfe sie gegen das echte Projekt unter {src}. + +SCHRITT 1: Lies die bestehende Wissensdatei {cache_path}. +SCHRITT 2: Verschaffe dir mit Bash (ls/find) und Read einen vollständigen Überblick über {src}. Lies README, Doku-Ordner und den relevanten Quellcode. +SCHRITT 3: Ergänze fehlende oder veraltete wichtige Informationen. Ein früherer Lauf war evtl. schlampig und hat Wichtiges ausgelassen. +SCHRITT 4: Schreibe die vollständige, korrigierte Wissensdatei zurück nach {cache_path}. + +Die Datei muss als alleinige Faktenbasis für einen Lern-Guide ausreichen. Erfasse: Zweck, Architektur, Abläufe, wichtige Dateien, Konfiguration, Befehle, Datenstrukturen, Besonderheiten. Schreibe NUR diese eine Datei.""" + + return f"""Lies das Projekt "{name}" vollständig ein und erstelle daraus eine verdichtete Wissensdatei. + +SCHRITT 1: Verschaffe dir mit Bash (ls/find) einen Überblick über {src}. +SCHRITT 2: Lies README, Doku-Ordner und den relevanten Quellcode mit dem Read-Tool. +SCHRITT 3: Schreibe eine vollständige Wissensdatei nach {cache_path}. + +Die Datei muss als alleinige Faktenbasis für einen Lern-Guide ausreichen. Erfasse: Zweck, Architektur, Abläufe, wichtige Dateien, Konfiguration, Befehle, Datenstrukturen, Besonderheiten. Lass nichts Wichtiges aus. Schreibe NUR diese eine Datei.""" + + +def _build_generator_prompt(topic: str, format_name: str, html_path: Path, instructions: str = "", project_content: str | None = None) -> str: spec = (TEMPLATES_DIR / "Format" / f"{format_name}.md").read_text(encoding="utf-8") reference = (TEMPLATES_DIR / "Referenz" / f"{format_name}.md").read_text(encoding="utf-8") extra = f"\n\nZUSÄTZLICHE ANWEISUNGEN VOM NUTZER:\n{instructions}\n" if instructions else "" + if project_content: + research_line = ( + f'Die folgenden PROJEKT-INHALTE sind die Quelle der Wahrheit für "{topic}". ' + "Nutze sie als primäre Faktenbasis. Recherchiere per Websuche nur ergänzend, " + "um fehlende oder sich ändernde Fakten (z. B. aktuelle Versionsnummern externer Tools) zu prüfen.\n\n" + f"PROJEKT-INHALTE (Quelle der Wahrheit):\n{project_content}" + ) + else: + research_line = f'Recherchiere zuerst die aktuelle Version und aktuelle Fakten zu "{topic}" per Websuche, damit Versionsnummern und Angaben stimmen.' + return f"""Erstelle einen Lern-Guide zum Thema "{topic}" im Format "{format_name}". -Recherchiere zuerst die aktuelle Version und aktuelle Fakten zu "{topic}" per Websuche, damit Versionsnummern und Angaben stimmen. +{research_line} Schreibe die HTML-Datei nach: {html_path} @@ -144,16 +178,29 @@ Führe KEIN weasyprint aus, erzeuge KEINE PDF. """ -def _build_content_review_prompt(topic: str, format_name: str, html_path: Path) -> str: +def _build_content_review_prompt(topic: str, format_name: str, html_path: Path, project_content: str | None = None) -> str: spec = (TEMPLATES_DIR / "Format" / f"{format_name}.md").read_text(encoding="utf-8") + if project_content: + check_step = ( + "SCHRITT 2 — Fakten prüfen:\n" + f'Vergleiche den Inhalt mit den folgenden PROJEKT-INHALTEN (Quelle der Wahrheit) für "{topic}". ' + "Stimmen die Projekt-Fakten? Fehlt Wichtiges aus dem Projekt? " + "Externe/aktuelle Fakten (Versionsnummern fremder Tools) ergänzend per WebSearch prüfen.\n\n" + f"PROJEKT-INHALTE:\n{project_content}" + ) + else: + check_step = ( + "SCHRITT 2 — Fakten per Websuche prüfen:\n" + f'Recherchiere mit WebSearch, ob Versionsnummern, Jahreszahlen und zentrale Fakten zu "{topic}" aktuell und korrekt sind.' + ) + return f"""Prüfe den Inhalt der HTML-Datei {html_path} für den "{format_name}" zum Thema "{topic}". SCHRITT 1 — HTML-Datei lesen: Öffne die Datei {html_path} mit dem Read-Tool. -SCHRITT 2 — Fakten per Websuche prüfen: -Recherchiere mit WebSearch, ob Versionsnummern, Jahreszahlen und zentrale Fakten zu "{topic}" aktuell und korrekt sind. +{check_step} SCHRITT 3 — Vollständigkeit prüfen anhand dieser Spezifikation: {spec} @@ -178,7 +225,7 @@ FAIL """ -async def generate_guide(guide_id: str, topic: str, format_name: str, instructions: str = "") -> None: +async def generate_guide(guide_id: str, topic: str, format_name: str, instructions: str = "", reindex: bool = False) -> None: async with _semaphore: now = datetime.now(timezone.utc).isoformat() await update_guide(guide_id, status="generating", progress="Recherche…", updated_at=now) @@ -192,9 +239,31 @@ async def generate_guide(guide_id: str, topic: str, format_name: str, instructio current_step = "Generierung" current_timeout = AGENT_TIMEOUT + # Step 0: Projekt einlesen (nur wenn topic ein Projekt ist) + project_content: str | None = None + if project_dir(topic).is_dir(): + cache_path = project_cache_path(topic) + if reindex or not cache_path.exists(): + await _set_progress(guide_id, "Lese Projekt…") + current_step = "Projekt-Einlesen" + index_prompt = _build_project_index_prompt(topic, cache_path, cache_path.exists()) + returncode, idx_out, idx_err = await _run_claude( + guide_id, index_prompt, AGENT_TIMEOUT, + tools="Read,Bash,Write", model=MODEL_PROJECT_INDEX, + ) + if guide_id in _cancelled: + return + if returncode != 0: + await _fail(guide_id, _claude_error("Projekt-Einlese-Fehler", returncode, idx_out, idx_err)) + return + if not cache_path.exists(): + await _fail(guide_id, "Projekt-Wissensdatei wurde nicht erstellt") + return + project_content = cache_path.read_text(encoding="utf-8") + # Step 1: Generator-Agent erstellt HTML await _set_progress(guide_id, "Generiere HTML…") - gen_prompt = _build_generator_prompt(topic, format_name, html_path, instructions) + gen_prompt = _build_generator_prompt(topic, format_name, html_path, instructions, project_content) returncode, stdout, stderr = await _run_claude(guide_id, gen_prompt, AGENT_TIMEOUT, model=MODEL_GUIDE) if guide_id in _cancelled: @@ -214,7 +283,7 @@ async def generate_guide(guide_id: str, topic: str, format_name: str, instructio await _set_progress(guide_id, "Prüfe Inhalt…") current_step = "Inhalts-Review" current_timeout = AGENT_TIMEOUT - content_prompt = _build_content_review_prompt(topic, format_name, html_path) + content_prompt = _build_content_review_prompt(topic, format_name, html_path, project_content) returncode, review_out, review_err = await _run_claude(guide_id, content_prompt, AGENT_TIMEOUT, model=MODEL_GUIDE) if returncode != 0: diff --git a/backend/main.py b/backend/main.py index f63f085..4997ebe 100644 --- a/backend/main.py +++ b/backend/main.py @@ -3,7 +3,7 @@ from contextlib import asynccontextmanager from fastapi import FastAPI from fastapi.staticfiles import StaticFiles -from config import FRONTEND_DIST, STORAGE_DIR +from config import FRONTEND_DIST, STORAGE_DIR, PROJECTS_CACHE_DIR from database import init_db, close_db from routes import router @@ -12,6 +12,7 @@ from routes import router async def lifespan(app: FastAPI): (STORAGE_DIR / "html").mkdir(parents=True, exist_ok=True) (STORAGE_DIR / "pdf").mkdir(parents=True, exist_ok=True) + PROJECTS_CACHE_DIR.mkdir(parents=True, exist_ok=True) await init_db() yield await close_db() diff --git a/backend/models.py b/backend/models.py index 8592e16..47b655a 100644 --- a/backend/models.py +++ b/backend/models.py @@ -14,6 +14,12 @@ class GuideCreateRequest(BaseModel): topic: str = Field(min_length=1, max_length=100) format: FormatType instructions: str = Field(default="", max_length=2000) + reindex: bool = False + + +class ProjectResponse(BaseModel): + name: str + cached: bool class GuideReworkRequest(BaseModel): diff --git a/backend/paths.py b/backend/paths.py index d561583..a955fce 100644 --- a/backend/paths.py +++ b/backend/paths.py @@ -1,6 +1,6 @@ from pathlib import Path -from config import STORAGE_DIR +from config import STORAGE_DIR, PROJECTS_DIR, PROJECTS_CACHE_DIR def safe_basename(topic: str, format_name: str) -> str: @@ -15,3 +15,11 @@ def final_paths(topic: str, format_name: str) -> tuple[Path, Path]: def temp_paths(guide_id: str) -> tuple[Path, Path]: return STORAGE_DIR / "html" / f"{guide_id}.tmp.html", STORAGE_DIR / "pdf" / f"{guide_id}.tmp.pdf" + + +def project_dir(name: str) -> Path: + return PROJECTS_DIR / name + + +def project_cache_path(name: str) -> Path: + return PROJECTS_CACHE_DIR / f"{name}.md" diff --git a/backend/routes.py b/backend/routes.py index 22ab8db..a567d62 100644 --- a/backend/routes.py +++ b/backend/routes.py @@ -1,11 +1,12 @@ import asyncio +import shutil import uuid from datetime import datetime, timezone from fastapi import APIRouter, HTTPException from fastapi.responses import FileResponse -from config import FORMAT_META +from config import FORMAT_META, PROJECTS_DIR from database import ( create_guide, delete_guide, get_guide, list_guides, create_baustein as db_create_baustein, list_bausteine, get_baustein, delete_baustein as db_delete_baustein, @@ -18,9 +19,9 @@ from models import ( BausteinCreateRequest, BausteinReworkRequest, BausteinSortRequest, BausteinResponse, SuggestionResponse, TopicSuggestRequest, TopicSuggestion, GuideChatRequest, GuideChatResponse, - ProgressUpdate, ProgressResponse, + ProgressUpdate, ProgressResponse, ProjectResponse, ) -from paths import final_paths +from paths import final_paths, project_dir, project_cache_path router = APIRouter(prefix="/api") @@ -30,6 +31,34 @@ async def get_formats(): return FORMAT_META +def _safe_project_name(name: str) -> str: + if not name or "/" in name or "\\" in name or ".." in name or "\x00" in name: + raise HTTPException(400, "Ungültiger Projektname") + return name + + +@router.get("/projects", response_model=list[ProjectResponse]) +async def list_projects(): + if not PROJECTS_DIR.is_dir(): + return [] + result = [] + for entry in sorted(PROJECTS_DIR.iterdir()): + if entry.is_dir(): + result.append({"name": entry.name, "cached": project_cache_path(entry.name).exists()}) + return result + + +@router.delete("/projects/{name}") +async def remove_project(name: str): + _safe_project_name(name) + pdir = project_dir(name) + if not pdir.is_dir(): + raise HTTPException(404, "Projekt nicht gefunden") + shutil.rmtree(pdir) + project_cache_path(name).unlink(missing_ok=True) + return {"ok": True} + + @router.post("/topic-suggestions", response_model=list[TopicSuggestion]) async def topic_suggestions(req: TopicSuggestRequest): guides = await list_guides() @@ -51,7 +80,7 @@ async def create(req: GuideCreateRequest): "updated_at": now, } await create_guide(guide) - asyncio.create_task(generate_guide(guide["id"], guide["topic"], guide["format"], guide["instructions"])) + asyncio.create_task(generate_guide(guide["id"], guide["topic"], guide["format"], guide["instructions"], req.reindex)) return guide diff --git a/frontend/src/App.vue b/frontend/src/App.vue index d885d86..e1caaae 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -1,12 +1,13 @@ @@ -154,6 +164,10 @@ function confirmDeleteTopic(topic) { {{ line }} + + + Projekt neu einlesen + @@ -223,6 +237,18 @@ function confirmDeleteTopic(topic) { {{ t }} × + + Projekte + + {{ p }} + × + + @@ -348,6 +374,40 @@ function confirmDeleteTopic(topic) { display: block; } +.projects-divider { + cursor: default; + font-size: 0.7rem; + text-transform: uppercase; + letter-spacing: 0.05em; + color: #9ca3af; + font-weight: 700; + padding: 0.6rem 1rem 0.3rem; + margin-top: 0.4rem; + border-top: 1px solid #e2e5e9; +} + +.projects-divider:hover { + background: none; +} + +.topic-list li.project-item span::before { + content: '📁 '; +} + +.reindex-toggle { + display: flex; + align-items: center; + gap: 6px; + padding: 0.4rem 0.75rem; + font-size: 0.8rem; + color: #4b5563; + cursor: pointer; +} + +.reindex-toggle input { + cursor: pointer; +} + /* Format section */ .format-section { flex-shrink: 0; diff --git a/projects/aak/Skript.pdf b/projects/aak/Skript.pdf new file mode 100644 index 0000000..030f074 --- /dev/null +++ b/projects/aak/Skript.pdf @@ -0,0 +1,4456 @@ +%PDF-1.3 +% +1 0 obj +<< /Metadata 3 0 R /Pages 4 0 R /Type /Catalog >> +endobj +2 0 obj +<< /Author () /CreationDate (D:20250704113420+00'00') /Creator (LaTeX with hyperref) /ModDate (D:20250704113420+00'00') /Producer (LuaTeX-1.16.0) >> +endobj +3 0 obj +<< /Subtype /XML /Type /Metadata /Length 808 >> +stream + + + + + + + + +endstream +endobj +4 0 obj +<< /Count 47 /Kids [ 5 0 R 6 0 R 7 0 R 8 0 R 9 0 R 10 0 R 11 0 R 12 0 R 13 0 R 14 0 R 15 0 R 16 0 R 17 0 R 18 0 R 19 0 R 20 0 R 21 0 R 22 0 R 23 0 R 24 0 R 25 0 R 26 0 R 27 0 R 28 0 R 29 0 R 30 0 R 31 0 R 32 0 R 33 0 R 34 0 R 35 0 R 36 0 R 37 0 R 38 0 R 39 0 R 40 0 R 41 0 R 42 0 R 43 0 R 44 0 R 45 0 R 46 0 R 47 0 R 48 0 R 49 0 R 50 0 R 51 0 R ] /Type /Pages >> +endobj +5 0 obj +<< /Contents 52 0 R /MediaBox [ 0 0 595.276 841.89 ] /Parent 4 0 R /Resources << /ColorSpace 53 0 R /ExtGState 54 0 R /Font << /F104 55 0 R /F16 56 0 R /F19 57 0 R /F21 58 0 R /F22 59 0 R /F41 60 0 R /F44 61 0 R /F47 62 0 R /F59 63 0 R /F64 64 0 R >> /Pattern 65 0 R /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +6 0 obj +<< /Contents 66 0 R /MediaBox [ 0 0 595.276 841.89 ] /Parent 4 0 R /Resources << /ColorSpace 53 0 R /ExtGState 54 0 R /Font << /F16 56 0 R /F19 57 0 R /F41 60 0 R /F42 67 0 R /F44 61 0 R /F45 68 0 R /F47 62 0 R /F48 69 0 R /F50 70 0 R /F59 63 0 R /F60 71 0 R /F64 64 0 R /F65 72 0 R /F80 73 0 R >> /Pattern 65 0 R /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +7 0 obj +<< /Contents 74 0 R /MediaBox [ 0 0 595.276 841.89 ] /Parent 4 0 R /Resources << /ColorSpace 53 0 R /ExtGState 54 0 R /Font << /F16 56 0 R /F19 57 0 R /F22 59 0 R /F26 75 0 R /F41 60 0 R /F42 67 0 R /F44 61 0 R /F45 68 0 R /F47 62 0 R /F48 69 0 R /F59 63 0 R /F60 71 0 R /F63 76 0 R /F64 64 0 R /F65 72 0 R >> /Pattern 65 0 R /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +8 0 obj +<< /Contents 77 0 R /MediaBox [ 0 0 595.276 841.89 ] /Parent 4 0 R /Resources << /ColorSpace 53 0 R /ExtGState 54 0 R /Font << /F16 56 0 R /F19 57 0 R /F41 60 0 R /F42 67 0 R /F44 61 0 R /F45 68 0 R /F47 62 0 R /F48 69 0 R /F59 63 0 R /F60 71 0 R /F64 64 0 R /F65 72 0 R >> /Pattern 65 0 R /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +9 0 obj +<< /Annots 78 0 R /Contents 79 0 R /MediaBox [ 0 0 595.276 841.89 ] /Parent 4 0 R /Resources << /ColorSpace 53 0 R /ExtGState 54 0 R /Font << /F16 56 0 R /F19 57 0 R /F25 80 0 R /F28 81 0 R /F41 60 0 R /F42 67 0 R /F44 61 0 R /F45 68 0 R /F47 62 0 R /F59 63 0 R /F60 71 0 R /F64 64 0 R /F65 72 0 R >> /Pattern 65 0 R /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +10 0 obj +<< /Annots 82 0 R /Contents 83 0 R /MediaBox [ 0 0 595.276 841.89 ] /Parent 4 0 R /Resources << /ColorSpace 53 0 R /ExtGState 54 0 R /Font << /F16 56 0 R /F22 59 0 R /F26 75 0 R /F41 60 0 R /F42 67 0 R /F44 61 0 R /F45 68 0 R /F47 62 0 R /F48 69 0 R /F59 63 0 R /F60 71 0 R /F64 64 0 R >> /Pattern 65 0 R /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +11 0 obj +<< /Contents 84 0 R /MediaBox [ 0 0 595.276 841.89 ] /Parent 4 0 R /Resources << /ColorSpace 53 0 R /ExtGState 54 0 R /Font << /F16 56 0 R /F19 57 0 R /F41 60 0 R /F42 67 0 R /F44 61 0 R /F45 68 0 R /F47 62 0 R /F48 69 0 R /F56 85 0 R /F59 63 0 R /F60 71 0 R /F64 64 0 R >> /Pattern 65 0 R /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +12 0 obj +<< /Annots 86 0 R /Contents 87 0 R /MediaBox [ 0 0 595.276 841.89 ] /Parent 4 0 R /Resources << /ColorSpace 53 0 R /ExtGState 54 0 R /Font << /F16 56 0 R /F19 57 0 R /F22 59 0 R /F41 60 0 R /F42 67 0 R /F44 61 0 R /F45 68 0 R /F47 62 0 R /F48 69 0 R /F56 85 0 R /F59 63 0 R /F60 71 0 R /F64 64 0 R /F65 72 0 R >> /Pattern 65 0 R /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +13 0 obj +<< /Annots 88 0 R /Contents 89 0 R /MediaBox [ 0 0 595.276 841.89 ] /Parent 4 0 R /Resources << /ColorSpace 53 0 R /ExtGState 54 0 R /Font << /F146 90 0 R /F16 56 0 R /F19 57 0 R /F41 60 0 R /F42 67 0 R /F43 91 0 R /F44 61 0 R /F45 68 0 R /F46 92 0 R /F47 62 0 R /F48 69 0 R /F49 93 0 R /F59 63 0 R /F60 71 0 R /F64 64 0 R /F65 72 0 R /F74 94 0 R >> /Pattern 65 0 R /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +14 0 obj +<< /Contents 95 0 R /MediaBox [ 0 0 595.276 841.89 ] /Parent 4 0 R /Resources << /ColorSpace 53 0 R /ExtGState 54 0 R /Font << /F146 90 0 R /F16 56 0 R /F19 57 0 R /F28 81 0 R /F41 60 0 R /F42 67 0 R /F43 91 0 R /F44 61 0 R /F45 68 0 R /F46 92 0 R /F47 62 0 R /F48 69 0 R /F49 93 0 R /F50 70 0 R /F59 63 0 R /F60 71 0 R /F63 76 0 R /F74 94 0 R /F88 96 0 R >> /Pattern 65 0 R /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +15 0 obj +<< /Contents 97 0 R /MediaBox [ 0 0 595.276 841.89 ] /Parent 4 0 R /Resources << /ColorSpace 53 0 R /ExtGState 54 0 R /Font << /F146 90 0 R /F16 56 0 R /F41 60 0 R /F42 67 0 R /F44 61 0 R /F45 68 0 R /F46 92 0 R /F47 62 0 R /F48 69 0 R /F50 70 0 R /F59 63 0 R /F60 71 0 R /F74 94 0 R /F80 73 0 R /F88 96 0 R >> /Pattern 65 0 R /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +16 0 obj +<< /Contents 98 0 R /MediaBox [ 0 0 595.276 841.89 ] /Parent 4 0 R /Resources << /ColorSpace 53 0 R /ExtGState 54 0 R /Font << /F146 90 0 R /F16 56 0 R /F19 57 0 R /F22 59 0 R /F41 60 0 R /F42 67 0 R /F44 61 0 R /F45 68 0 R /F47 62 0 R /F48 69 0 R /F59 63 0 R /F60 71 0 R /F64 64 0 R /F65 72 0 R /F74 94 0 R /F80 73 0 R /F88 96 0 R >> /Pattern 65 0 R /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +17 0 obj +<< /Annots 99 0 R /Contents 100 0 R /MediaBox [ 0 0 595.276 841.89 ] /Parent 4 0 R /Resources << /ColorSpace 53 0 R /ExtGState 54 0 R /Font << /F16 56 0 R /F19 57 0 R /F22 59 0 R /F26 75 0 R /F41 60 0 R /F42 67 0 R /F44 61 0 R /F45 68 0 R /F46 92 0 R /F47 62 0 R /F48 69 0 R /F49 93 0 R /F59 63 0 R /F60 71 0 R /F64 64 0 R /F65 72 0 R >> /Pattern 65 0 R /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +18 0 obj +<< /Contents 101 0 R /MediaBox [ 0 0 595.276 841.89 ] /Parent 4 0 R /Resources << /ColorSpace 53 0 R /ExtGState 54 0 R /Font << /F16 56 0 R /F19 57 0 R /F22 59 0 R /F26 75 0 R /F41 60 0 R /F42 67 0 R /F43 91 0 R /F44 61 0 R /F45 68 0 R /F46 92 0 R /F47 62 0 R /F59 63 0 R /F60 71 0 R /F62 102 0 R /F64 64 0 R /F65 72 0 R /F78 103 0 R >> /Pattern 65 0 R /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +19 0 obj +<< /Contents 104 0 R /MediaBox [ 0 0 595.276 841.89 ] /Parent 4 0 R /Resources << /ColorSpace 53 0 R /ExtGState 54 0 R /Font << /F16 56 0 R /F41 60 0 R /F42 67 0 R /F44 61 0 R /F45 68 0 R /F47 62 0 R /F50 70 0 R /F59 63 0 R /F60 71 0 R /F64 64 0 R /F65 72 0 R >> /Pattern 65 0 R /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +20 0 obj +<< /Contents 105 0 R /MediaBox [ 0 0 595.276 841.89 ] /Parent 4 0 R /Resources << /ColorSpace 53 0 R /ExtGState 54 0 R /Font << /F16 56 0 R /F19 57 0 R /F22 59 0 R /F23 106 0 R /F41 60 0 R /F42 67 0 R /F44 61 0 R /F45 68 0 R /F47 62 0 R /F48 69 0 R /F59 63 0 R /F60 71 0 R /F64 64 0 R /F65 72 0 R >> /Pattern 65 0 R /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +21 0 obj +<< /Contents 107 0 R /MediaBox [ 0 0 595.276 841.89 ] /Parent 4 0 R /Resources << /ColorSpace 53 0 R /ExtGState 54 0 R /Font << /F104 55 0 R /F16 56 0 R /F19 57 0 R /F22 59 0 R /F23 106 0 R /F41 60 0 R /F42 67 0 R /F44 61 0 R /F45 68 0 R /F47 62 0 R /F59 63 0 R /F60 71 0 R /F80 73 0 R >> /Pattern 65 0 R /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +22 0 obj +<< /Contents 108 0 R /MediaBox [ 0 0 595.276 841.89 ] /Parent 4 0 R /Resources << /ColorSpace 53 0 R /ExtGState 54 0 R /Font << /F16 56 0 R /F19 57 0 R /F22 59 0 R /F41 60 0 R /F42 67 0 R /F43 91 0 R /F44 61 0 R /F45 68 0 R /F46 92 0 R /F47 62 0 R /F48 69 0 R /F50 70 0 R /F59 63 0 R /F60 71 0 R /F64 64 0 R /F65 72 0 R >> /Pattern 65 0 R /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +23 0 obj +<< /Contents 109 0 R /MediaBox [ 0 0 595.276 841.89 ] /Parent 4 0 R /Resources << /ColorSpace 53 0 R /ExtGState 54 0 R /Font << /F16 56 0 R /F19 57 0 R /F22 59 0 R /F41 60 0 R /F42 67 0 R /F44 61 0 R /F45 68 0 R /F46 92 0 R /F47 62 0 R /F48 69 0 R /F50 70 0 R /F59 63 0 R /F60 71 0 R /F64 64 0 R /F65 72 0 R >> /Pattern 65 0 R /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +24 0 obj +<< /Annots 110 0 R /Contents 111 0 R /MediaBox [ 0 0 595.276 841.89 ] /Parent 4 0 R /Resources << /ColorSpace 53 0 R /ExtGState 54 0 R /Font << /F16 56 0 R /F19 57 0 R /F22 59 0 R /F41 60 0 R /F42 67 0 R /F44 61 0 R /F45 68 0 R /F46 92 0 R /F47 62 0 R /F48 69 0 R /F49 93 0 R /F50 70 0 R /F56 85 0 R /F60 71 0 R /F64 64 0 R >> /Pattern 65 0 R /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +25 0 obj +<< /Contents 112 0 R /MediaBox [ 0 0 595.276 841.89 ] /Parent 4 0 R /Resources << /ColorSpace 53 0 R /ExtGState 54 0 R /Font << /F16 56 0 R /F19 57 0 R /F22 59 0 R /F41 60 0 R /F42 67 0 R /F43 91 0 R /F44 61 0 R /F45 68 0 R /F47 62 0 R /F48 69 0 R /F50 70 0 R /F59 63 0 R /F60 71 0 R /F64 64 0 R >> /Pattern 65 0 R /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +26 0 obj +<< /Contents 113 0 R /MediaBox [ 0 0 595.276 841.89 ] /Parent 4 0 R /Resources << /ColorSpace 53 0 R /ExtGState 54 0 R /Font << /F16 56 0 R /F19 57 0 R /F41 60 0 R /F42 67 0 R /F44 61 0 R /F45 68 0 R /F47 62 0 R /F48 69 0 R /F59 63 0 R /F60 71 0 R /F64 64 0 R /F65 72 0 R >> /Pattern 65 0 R /ProcSet [ /PDF /Text ] /XObject << /Im1 114 0 R /Im2 115 0 R /Im3 116 0 R /Im4 117 0 R >> >> /Type /Page >> +endobj +27 0 obj +<< /Contents 118 0 R /MediaBox [ 0 0 595.276 841.89 ] /Parent 4 0 R /Resources << /ColorSpace 53 0 R /ExtGState 54 0 R /Font << /F16 56 0 R /F42 67 0 R /F44 61 0 R /F47 62 0 R /F59 63 0 R /F60 71 0 R >> /Pattern 65 0 R /ProcSet [ /PDF /Text ] /XObject << /Im5 119 0 R /Im6 120 0 R /Im7 121 0 R >> >> /Type /Page >> +endobj +28 0 obj +<< /Contents 122 0 R /MediaBox [ 0 0 595.276 841.89 ] /Parent 4 0 R /Resources << /ColorSpace 53 0 R /ExtGState 54 0 R /Font << /F16 56 0 R /F19 57 0 R /F41 60 0 R /F42 67 0 R /F44 61 0 R /F45 68 0 R /F47 62 0 R /F59 63 0 R /F60 71 0 R /F64 64 0 R >> /Pattern 65 0 R /ProcSet [ /PDF /Text ] /XObject << /Im8 123 0 R /Im9 124 0 R >> >> /Type /Page >> +endobj +29 0 obj +<< /Contents 125 0 R /MediaBox [ 0 0 595.276 841.89 ] /Parent 4 0 R /Resources << /ColorSpace 53 0 R /ExtGState 54 0 R /Font << /F108 126 0 R /F16 56 0 R /F19 57 0 R /F22 59 0 R /F41 60 0 R /F42 67 0 R /F44 61 0 R /F45 68 0 R /F47 62 0 R /F48 69 0 R /F49 93 0 R /F50 70 0 R /F56 85 0 R /F60 71 0 R /F64 64 0 R /F66 127 0 R /F79 128 0 R /F80 73 0 R >> /Pattern 65 0 R /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +30 0 obj +<< /Contents 129 0 R /MediaBox [ 0 0 595.276 841.89 ] /Parent 4 0 R /Resources << /ColorSpace 53 0 R /ExtGState 54 0 R /Font << /F16 56 0 R /F19 57 0 R /F41 60 0 R /F42 67 0 R /F44 61 0 R /F45 68 0 R /F47 62 0 R /F48 69 0 R /F49 93 0 R /F50 70 0 R /F56 85 0 R /F60 71 0 R /F64 64 0 R /F79 128 0 R /F80 73 0 R >> /Pattern 65 0 R /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +31 0 obj +<< /Contents 130 0 R /MediaBox [ 0 0 595.276 841.89 ] /Parent 4 0 R /Resources << /ColorSpace 53 0 R /ExtGState 54 0 R /Font << /F104 55 0 R /F16 56 0 R /F19 57 0 R /F21 58 0 R /F22 59 0 R /F41 60 0 R /F42 67 0 R /F44 61 0 R /F45 68 0 R /F47 62 0 R /F50 70 0 R /F56 85 0 R /F59 63 0 R /F64 64 0 R /F65 72 0 R /F98 131 0 R >> /Pattern 65 0 R /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +32 0 obj +<< /Contents 132 0 R /MediaBox [ 0 0 595.276 841.89 ] /Parent 4 0 R /Resources << /ColorSpace 53 0 R /ExtGState 54 0 R /Font << /F104 55 0 R /F108 126 0 R /F16 56 0 R /F19 57 0 R /F22 59 0 R /F41 60 0 R /F44 61 0 R /F47 62 0 R /F59 63 0 R /F60 71 0 R /F64 64 0 R /F65 72 0 R /F73 133 0 R >> /Pattern 65 0 R /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +33 0 obj +<< /Contents 134 0 R /MediaBox [ 0 0 595.276 841.89 ] /Parent 4 0 R /Resources << /ColorSpace 53 0 R /ExtGState 54 0 R /Font << /F104 55 0 R /F16 56 0 R /F19 57 0 R /F41 60 0 R /F42 67 0 R /F44 61 0 R /F45 68 0 R /F47 62 0 R /F59 63 0 R /F60 71 0 R /F64 64 0 R /F65 72 0 R /F67 135 0 R /F68 136 0 R /F69 137 0 R >> /Pattern 65 0 R /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +34 0 obj +<< /Contents 138 0 R /MediaBox [ 0 0 595.276 841.89 ] /Parent 4 0 R /Resources << /ColorSpace 53 0 R /ExtGState 54 0 R /Font << /F104 55 0 R /F16 56 0 R /F19 57 0 R /F41 60 0 R /F42 67 0 R /F44 61 0 R /F45 68 0 R /F47 62 0 R /F59 63 0 R /F60 71 0 R /F64 64 0 R /F65 72 0 R >> /Pattern 65 0 R /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +35 0 obj +<< /Annots 139 0 R /Contents 140 0 R /MediaBox [ 0 0 595.276 841.89 ] /Parent 4 0 R /Resources << /ColorSpace 53 0 R /ExtGState 54 0 R /Font << /F104 55 0 R /F16 56 0 R /F19 57 0 R /F41 60 0 R /F42 67 0 R /F44 61 0 R /F45 68 0 R /F47 62 0 R /F48 69 0 R /F49 93 0 R /F50 70 0 R /F59 63 0 R /F60 71 0 R /F64 64 0 R /F65 72 0 R /F67 135 0 R /F68 136 0 R /F69 137 0 R >> /Pattern 65 0 R /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +36 0 obj +<< /Contents 141 0 R /MediaBox [ 0 0 595.276 841.89 ] /Parent 4 0 R /Resources << /ColorSpace 53 0 R /ExtGState 54 0 R /Font << /F104 55 0 R /F16 56 0 R /F19 57 0 R /F41 60 0 R /F42 67 0 R /F44 61 0 R /F45 68 0 R /F47 62 0 R /F48 69 0 R /F60 71 0 R /F64 64 0 R /F65 72 0 R /F68 136 0 R /F69 137 0 R >> /Pattern 65 0 R /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +37 0 obj +<< /Contents 142 0 R /MediaBox [ 0 0 595.276 841.89 ] /Parent 4 0 R /Resources << /ColorSpace 53 0 R /ExtGState 54 0 R /Font << /F104 55 0 R /F16 56 0 R /F19 57 0 R /F22 59 0 R /F26 75 0 R /F41 60 0 R /F42 67 0 R /F44 61 0 R /F45 68 0 R /F47 62 0 R /F48 69 0 R /F49 93 0 R /F50 70 0 R /F56 85 0 R /F59 63 0 R /F60 71 0 R /F63 76 0 R /F64 64 0 R /F65 72 0 R >> /Pattern 65 0 R /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +38 0 obj +<< /Contents 143 0 R /MediaBox [ 0 0 595.276 841.89 ] /Parent 4 0 R /Resources << /ColorSpace 53 0 R /ExtGState 54 0 R /Font << /F156 144 0 R /F16 56 0 R /F19 57 0 R /F41 60 0 R /F42 67 0 R /F44 61 0 R /F45 68 0 R /F47 62 0 R /F48 69 0 R /F50 70 0 R /F59 63 0 R /F60 71 0 R /F64 64 0 R /F65 72 0 R /F67 135 0 R /F68 136 0 R /F69 137 0 R >> /Pattern 65 0 R /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +39 0 obj +<< /Contents 145 0 R /MediaBox [ 0 0 595.276 841.89 ] /Parent 4 0 R /Resources << /ColorSpace 53 0 R /ExtGState 54 0 R /Font << /F16 56 0 R /F19 57 0 R /F41 60 0 R /F42 67 0 R /F44 61 0 R /F45 68 0 R /F46 92 0 R /F47 62 0 R /F48 69 0 R /F50 70 0 R /F59 63 0 R /F60 71 0 R /F64 64 0 R /F65 72 0 R >> /Pattern 65 0 R /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +40 0 obj +<< /Contents 146 0 R /MediaBox [ 0 0 595.276 841.89 ] /Parent 4 0 R /Resources << /ColorSpace 53 0 R /ExtGState 54 0 R /Font << /F16 56 0 R /F19 57 0 R /F41 60 0 R /F42 67 0 R /F44 61 0 R /F45 68 0 R /F47 62 0 R /F59 63 0 R /F60 71 0 R /F64 64 0 R /F65 72 0 R >> /Pattern 65 0 R /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +41 0 obj +<< /Annots 147 0 R /Contents 148 0 R /MediaBox [ 0 0 595.276 841.89 ] /Parent 4 0 R /Resources << /ColorSpace 53 0 R /ExtGState 54 0 R /Font << /F16 56 0 R /F19 57 0 R /F41 60 0 R /F42 67 0 R /F44 61 0 R /F45 68 0 R /F46 92 0 R /F47 62 0 R /F48 69 0 R /F50 70 0 R /F59 63 0 R /F60 71 0 R /F64 64 0 R /F65 72 0 R /F80 73 0 R >> /Pattern 65 0 R /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +42 0 obj +<< /Contents 149 0 R /MediaBox [ 0 0 595.276 841.89 ] /Parent 4 0 R /Resources << /ColorSpace 53 0 R /ExtGState 54 0 R /Font << /F16 56 0 R /F19 57 0 R /F41 60 0 R /F42 67 0 R /F44 61 0 R /F45 68 0 R /F46 92 0 R /F47 62 0 R /F48 69 0 R /F50 70 0 R /F59 63 0 R /F60 71 0 R /F63 76 0 R >> /Pattern 65 0 R /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +43 0 obj +<< /Contents 150 0 R /MediaBox [ 0 0 595.276 841.89 ] /Parent 4 0 R /Resources << /ColorSpace 53 0 R /ExtGState 54 0 R /Font << /F16 56 0 R /F19 57 0 R /F22 59 0 R /F41 60 0 R /F42 67 0 R /F44 61 0 R /F45 68 0 R /F46 92 0 R /F47 62 0 R /F48 69 0 R /F50 70 0 R /F56 85 0 R /F59 63 0 R /F60 71 0 R /F63 76 0 R /F64 64 0 R /F65 72 0 R >> /Pattern 65 0 R /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +44 0 obj +<< /Contents 151 0 R /MediaBox [ 0 0 595.276 841.89 ] /Parent 4 0 R /Resources << /ColorSpace 53 0 R /ExtGState 54 0 R /Font << /F105 152 0 R /F16 56 0 R /F19 57 0 R /F41 60 0 R /F42 67 0 R /F44 61 0 R /F45 68 0 R /F47 62 0 R /F48 69 0 R /F59 63 0 R /F60 71 0 R /F63 76 0 R /F64 64 0 R /F65 72 0 R /F67 135 0 R /F68 136 0 R /F69 137 0 R >> /Pattern 65 0 R /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +45 0 obj +<< /Annots 153 0 R /Contents 154 0 R /MediaBox [ 0 0 595.276 841.89 ] /Parent 4 0 R /Resources << /ColorSpace 53 0 R /ExtGState 54 0 R /Font << /F105 152 0 R /F16 56 0 R /F19 57 0 R /F25 80 0 R /F28 81 0 R /F41 60 0 R /F42 67 0 R /F43 91 0 R /F44 61 0 R /F45 68 0 R /F47 62 0 R /F48 69 0 R /F50 70 0 R /F59 63 0 R /F60 71 0 R /F64 64 0 R >> /Pattern 65 0 R /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +46 0 obj +<< /Contents 155 0 R /MediaBox [ 0 0 595.276 841.89 ] /Parent 4 0 R /Resources << /ColorSpace 53 0 R /ExtGState 54 0 R /Font << /F16 56 0 R /F19 57 0 R /F41 60 0 R /F42 67 0 R /F44 61 0 R /F45 68 0 R /F47 62 0 R /F48 69 0 R /F50 70 0 R /F59 63 0 R /F60 71 0 R /F64 64 0 R /F67 135 0 R /F68 136 0 R /F69 137 0 R >> /Pattern 65 0 R /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +47 0 obj +<< /Contents 156 0 R /MediaBox [ 0 0 595.276 841.89 ] /Parent 4 0 R /Resources << /ColorSpace 53 0 R /ExtGState 54 0 R /Font << /F16 56 0 R /F19 57 0 R /F41 60 0 R /F42 67 0 R /F44 61 0 R /F45 68 0 R /F47 62 0 R /F48 69 0 R /F49 93 0 R /F50 70 0 R /F59 63 0 R /F60 71 0 R /F80 73 0 R >> /Pattern 65 0 R /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +48 0 obj +<< /Contents 157 0 R /MediaBox [ 0 0 595.276 841.89 ] /Parent 4 0 R /Resources << /ColorSpace 53 0 R /ExtGState 54 0 R /Font << /F16 56 0 R /F19 57 0 R /F41 60 0 R /F42 67 0 R /F44 61 0 R /F45 68 0 R /F47 62 0 R /F48 69 0 R /F49 93 0 R /F59 63 0 R /F60 71 0 R /F80 73 0 R >> /Pattern 65 0 R /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +49 0 obj +<< /Contents 158 0 R /MediaBox [ 0 0 595.276 841.89 ] /Parent 4 0 R /Resources << /ColorSpace 53 0 R /ExtGState 54 0 R /Font << /F16 56 0 R /F19 57 0 R /F41 60 0 R /F42 67 0 R /F44 61 0 R /F45 68 0 R /F47 62 0 R /F48 69 0 R /F49 93 0 R /F50 70 0 R /F59 63 0 R /F60 71 0 R /F64 64 0 R >> /Pattern 65 0 R /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +50 0 obj +<< /Contents 159 0 R /MediaBox [ 0 0 595.276 841.89 ] /Parent 4 0 R /Resources << /ColorSpace 53 0 R /ExtGState 54 0 R /Font << /F108 126 0 R /F16 56 0 R /F19 57 0 R /F41 60 0 R /F42 67 0 R /F43 91 0 R /F44 61 0 R /F45 68 0 R /F46 92 0 R /F47 62 0 R /F48 69 0 R /F49 93 0 R /F59 63 0 R /F60 71 0 R /F64 64 0 R /F65 72 0 R >> /Pattern 65 0 R /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +51 0 obj +<< /Contents 160 0 R /MediaBox [ 0 0 595.276 841.89 ] /Parent 4 0 R /Resources << /ColorSpace 53 0 R /ExtGState 54 0 R /Font << /F16 56 0 R /F19 57 0 R /F22 59 0 R /F41 60 0 R /F44 61 0 R /F45 68 0 R /F47 62 0 R /F60 71 0 R /F63 76 0 R /F64 64 0 R /F80 73 0 R >> /Pattern 65 0 R /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +52 0 obj +<< /Filter /FlateDecode /Length 3275 >> +stream +xɎ>_ѡ)+ӇLJ/R$gH-O?=|O$g\ѓT|"Ip9[P(D$UdBPX~$vq.%222WR