From adf31a4a3524fef5b286c9894d43eb64f772941c Mon Sep 17 00:00:00 2001 From: ducoterra Date: Tue, 15 Sep 2026 06:11:38 -0400 Subject: [PATCH] phase: 116_modal_scrollbar_theme MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All verification complete — every gate re-run independently and green. Final report: **Phase 116 final verification pass — all green (work was already in the tree; verified, nothing to fix)** - **Verified** `styles.css`: `--scrollbar-thumb`/`--scrollbar-track` tokens in `:root` (color-mix derivations — follow the saved theme, not in BUILTIN_COLORS; contrast 3.73:1 ≥ 3:1, recomputed independently) + scoped rules `.doc-modal .doc-raw` (overflow-x already owned by the element) - **Verified** E2E test 8 `test_raw_code_block_themed_scrollbar`: overflow, scroll action, computed-style theme assertions, screenshot - **Screenshots visually confirmed**: headed `doc_modal_scrollbar_themed_1280.png` shows muted rounded thumb on dark track, no native light-gray bar; headless suite shot records scrolled state (headless Chromium paints no bar UI — documented in test docstring) **Test / lint / coverage (re-run by me):** - `uv run pytest tests/e2e/test_document_viewer.py -v --no-cov` → **8 passed** (isolation) - `uv run pytest --cov=app --cov-report=term` → **2457 passed, app/ 99%** (>90% ✓) - `uv run pytest tests/e2e/test_dark_tech_theme.py -v --no-cov` → **6 passed** (no token collision) - `uv run ruff check .` → clean; `uv run pyright` → 0 errors, 0 warnings **Completion criteria:** 1. Modal scrolls horizontally, scrollbar themed, screenshot shows no native bar — ✅ 2. No global scrollbar change (all new selectors under `.doc-modal`; grep-confirmed), regressions green — ✅ 3. pytest green, coverage >90%, e2e isolated green, ruff+pyright clean — ✅ 4. `--no-gpg-sign` commit + phase move — harness job (left uncommitted in working tree, per rules) **No defects found; no deviations. Next pending phase:** none — `todo/` contains only phase 116. --- .../116_modal_scrollbar_theme/00_phase.md | 0 .../01_themed_scrollbar.md | 0 .../02_scrollbar_e2e_check.md | 0 ...116_modal_scrollbar_theme__00_phase.a1.err | 0 .../116_modal_scrollbar_theme__00_phase.a1.md | 21 +++ ...odal_scrollbar_theme__00_phase.a1.validate | 103 +++++++++++++ ...crollbar_theme__01_themed_scrollbar.a1.err | 0 ...scrollbar_theme__01_themed_scrollbar.a1.md | 18 +++ ...bar_theme__01_themed_scrollbar.a1.validate | 103 +++++++++++++ ...llbar_theme__02_scrollbar_e2e_check.a1.err | 0 ...ollbar_theme__02_scrollbar_e2e_check.a1.md | 15 ++ ..._theme__02_scrollbar_e2e_check.a1.validate | 103 +++++++++++++ .../screenshots/doc_modal_scrollbar_1280.png | Bin 0 -> 42502 bytes .../doc_modal_scrollbar_themed_1280.png | Bin 0 -> 44687 bytes frontend/assets/styles.css | 33 ++++ tests/e2e/test_document_viewer.py | 141 ++++++++++++++++++ 16 files changed, 537 insertions(+) rename .agents/phases/{todo => complete}/116_modal_scrollbar_theme/00_phase.md (100%) rename .agents/phases/{todo => complete}/116_modal_scrollbar_theme/01_themed_scrollbar.md (100%) rename .agents/phases/{todo => complete}/116_modal_scrollbar_theme/02_scrollbar_e2e_check.md (100%) create mode 100644 .agents/reports/116_modal_scrollbar_theme/116_modal_scrollbar_theme__00_phase.a1.err create mode 100644 .agents/reports/116_modal_scrollbar_theme/116_modal_scrollbar_theme__00_phase.a1.md create mode 100644 .agents/reports/116_modal_scrollbar_theme/116_modal_scrollbar_theme__00_phase.a1.validate create mode 100644 .agents/reports/116_modal_scrollbar_theme/116_modal_scrollbar_theme__01_themed_scrollbar.a1.err create mode 100644 .agents/reports/116_modal_scrollbar_theme/116_modal_scrollbar_theme__01_themed_scrollbar.a1.md create mode 100644 .agents/reports/116_modal_scrollbar_theme/116_modal_scrollbar_theme__01_themed_scrollbar.a1.validate create mode 100644 .agents/reports/116_modal_scrollbar_theme/116_modal_scrollbar_theme__02_scrollbar_e2e_check.a1.err create mode 100644 .agents/reports/116_modal_scrollbar_theme/116_modal_scrollbar_theme__02_scrollbar_e2e_check.a1.md create mode 100644 .agents/reports/116_modal_scrollbar_theme/116_modal_scrollbar_theme__02_scrollbar_e2e_check.a1.validate create mode 100644 .agents/screenshots/doc_modal_scrollbar_1280.png create mode 100644 .agents/screenshots/doc_modal_scrollbar_themed_1280.png diff --git a/.agents/phases/todo/116_modal_scrollbar_theme/00_phase.md b/.agents/phases/complete/116_modal_scrollbar_theme/00_phase.md similarity index 100% rename from .agents/phases/todo/116_modal_scrollbar_theme/00_phase.md rename to .agents/phases/complete/116_modal_scrollbar_theme/00_phase.md diff --git a/.agents/phases/todo/116_modal_scrollbar_theme/01_themed_scrollbar.md b/.agents/phases/complete/116_modal_scrollbar_theme/01_themed_scrollbar.md similarity index 100% rename from .agents/phases/todo/116_modal_scrollbar_theme/01_themed_scrollbar.md rename to .agents/phases/complete/116_modal_scrollbar_theme/01_themed_scrollbar.md diff --git a/.agents/phases/todo/116_modal_scrollbar_theme/02_scrollbar_e2e_check.md b/.agents/phases/complete/116_modal_scrollbar_theme/02_scrollbar_e2e_check.md similarity index 100% rename from .agents/phases/todo/116_modal_scrollbar_theme/02_scrollbar_e2e_check.md rename to .agents/phases/complete/116_modal_scrollbar_theme/02_scrollbar_e2e_check.md diff --git a/.agents/reports/116_modal_scrollbar_theme/116_modal_scrollbar_theme__00_phase.a1.err b/.agents/reports/116_modal_scrollbar_theme/116_modal_scrollbar_theme__00_phase.a1.err new file mode 100644 index 0000000..e69de29 diff --git a/.agents/reports/116_modal_scrollbar_theme/116_modal_scrollbar_theme__00_phase.a1.md b/.agents/reports/116_modal_scrollbar_theme/116_modal_scrollbar_theme__00_phase.a1.md new file mode 100644 index 0000000..352c772 --- /dev/null +++ b/.agents/reports/116_modal_scrollbar_theme/116_modal_scrollbar_theme__00_phase.a1.md @@ -0,0 +1,21 @@ +All verification complete — every gate re-run independently and green. Final report: + +**Phase 116 final verification pass — all green (work was already in the tree; verified, nothing to fix)** + +- **Verified** `styles.css`: `--scrollbar-thumb`/`--scrollbar-track` tokens in `:root` (color-mix derivations — follow the saved theme, not in BUILTIN_COLORS; contrast 3.73:1 ≥ 3:1, recomputed independently) + scoped rules `.doc-modal .doc-raw` (overflow-x already owned by the element) +- **Verified** E2E test 8 `test_raw_code_block_themed_scrollbar`: overflow, scroll action, computed-style theme assertions, screenshot +- **Screenshots visually confirmed**: headed `doc_modal_scrollbar_themed_1280.png` shows muted rounded thumb on dark track, no native light-gray bar; headless suite shot records scrolled state (headless Chromium paints no bar UI — documented in test docstring) + +**Test / lint / coverage (re-run by me):** +- `uv run pytest tests/e2e/test_document_viewer.py -v --no-cov` → **8 passed** (isolation) +- `uv run pytest --cov=app --cov-report=term` → **2457 passed, app/ 99%** (>90% ✓) +- `uv run pytest tests/e2e/test_dark_tech_theme.py -v --no-cov` → **6 passed** (no token collision) +- `uv run ruff check .` → clean; `uv run pyright` → 0 errors, 0 warnings + +**Completion criteria:** +1. Modal scrolls horizontally, scrollbar themed, screenshot shows no native bar — ✅ +2. No global scrollbar change (all new selectors under `.doc-modal`; grep-confirmed), regressions green — ✅ +3. pytest green, coverage >90%, e2e isolated green, ruff+pyright clean — ✅ +4. `--no-gpg-sign` commit + phase move — harness job (left uncommitted in working tree, per rules) + +**No defects found; no deviations. Next pending phase:** none — `todo/` contains only phase 116. diff --git a/.agents/reports/116_modal_scrollbar_theme/116_modal_scrollbar_theme__00_phase.a1.validate b/.agents/reports/116_modal_scrollbar_theme/116_modal_scrollbar_theme__00_phase.a1.validate new file mode 100644 index 0000000..6b977c2 --- /dev/null +++ b/.agents/reports/116_modal_scrollbar_theme/116_modal_scrollbar_theme__00_phase.a1.validate @@ -0,0 +1,103 @@ +........................................................................ [ 2%] +........................................................................ [ 5%] +........................................................................ [ 8%] +........................................................................ [ 11%] +........................................................................ [ 14%] +........................................................................ [ 17%] +........................................................................ [ 20%] +........................................................................ [ 23%] +........................................................................ [ 26%] +........................................................................ [ 29%] +........................................................................ [ 32%] +........................................................................ [ 35%] +........................................................................ [ 38%] +........................................................................ [ 41%] +........................................................................ [ 43%] +........................................................................ [ 46%] +........................................................................ [ 49%] +........................................................................ [ 52%] +........................................................................ [ 55%] +........................................................................ [ 58%] +........................................................................ [ 61%] +........................................................................ [ 64%] +........................................................................ [ 67%] +........................................................................ [ 70%] +........................................................................ [ 73%] +........................................................................ [ 76%] +........................................................................ [ 79%] +........................................................................ [ 82%] +........................................................................ [ 84%] +........................................................................ [ 87%] +........................................................................ [ 90%] +........................................................................ [ 93%] +........................................................................ [ 96%] +........................................................................ [ 99%] +......... [100%] +=============================== warnings summary =============================== +.venv/lib64/python3.14/site-packages/fastapi/testclient.py:1 + /var/home/ducoterra/Projects/Personal/brain-of-reese/.venv/lib64/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead. + from starlette.testclient import TestClient as TestClient # noqa + +-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html +================================ tests coverage ================================ +_______________ coverage: platform linux, python 3.14.7-final-0 ________________ + +Name Stmts Miss Cover +-------------------------------------------------- +app/__init__.py 1 0 100% +app/api/__init__.py 0 0 100% +app/api/auth.py 52 0 100% +app/api/chat.py 224 1 99% +app/api/chats.py 110 0 100% +app/api/config.py 13 0 100% +app/api/doc_drafts.py 99 0 100% +app/api/docs.py 156 1 99% +app/api/git_sources.py 232 0 100% +app/api/health.py 10 0 100% +app/api/steering.py 42 0 100% +app/api/suggestions.py 33 0 100% +app/api/sync.py 139 0 100% +app/api/tokens.py 40 0 100% +app/api/ui_settings.py 55 0 100% +app/config.py 210 0 100% +app/core/__init__.py 0 0 100% +app/core/auth.py 45 0 100% +app/core/caching.py 124 0 100% +app/core/debugging.py 29 2 93% +app/core/docs_push.py 39 0 100% +app/core/errors.py 5 0 100% +app/core/logging.py 13 0 100% +app/core/rate_limit.py 44 0 100% +app/core/security_headers.py 20 0 100% +app/core/theming.py 38 0 100% +app/core/tokens.py 44 0 100% +app/db.py 22 0 100% +app/main.py 66 0 100% +app/models.py 128 0 100% +app/rag/__init__.py 0 0 100% +app/rag/agent.py 317 1 99% +app/rag/archive_upload.py 134 0 100% +app/rag/chunker.py 206 4 98% +app/rag/doc_dates.py 18 0 100% +app/rag/folder_summaries.py 123 0 100% +app/rag/git_sources.py 14 0 100% +app/rag/importer.py 215 3 99% +app/rag/llm.py 244 1 99% +app/rag/overview.py 71 0 100% +app/rag/prompts.py 88 0 100% +app/rag/retriever.py 192 3 98% +app/rag/scaffolding.py 55 0 100% +app/rag/source_removal.py 41 0 100% +app/rag/sources_meta.py 16 0 100% +app/rag/suggestions.py 27 0 100% +app/rag/summarizer.py 24 0 100% +app/schemas.py 329 0 100% +-------------------------------------------------- +TOTAL 4147 16 99% +coverage gate: app/ 99% (>90%) OK +All checks passed! +0 errors, 0 warnings, 0 informations +WARNING: there is a new pyright version available (v1.1.411 -> v1.1.414). +Please install the new version or set PYRIGHT_PYTHON_FORCE_VERSION to `latest` + +validation OK diff --git a/.agents/reports/116_modal_scrollbar_theme/116_modal_scrollbar_theme__01_themed_scrollbar.a1.err b/.agents/reports/116_modal_scrollbar_theme/116_modal_scrollbar_theme__01_themed_scrollbar.a1.err new file mode 100644 index 0000000..e69de29 diff --git a/.agents/reports/116_modal_scrollbar_theme/116_modal_scrollbar_theme__01_themed_scrollbar.a1.md b/.agents/reports/116_modal_scrollbar_theme/116_modal_scrollbar_theme__01_themed_scrollbar.a1.md new file mode 100644 index 0000000..8ed077e --- /dev/null +++ b/.agents/reports/116_modal_scrollbar_theme/116_modal_scrollbar_theme__01_themed_scrollbar.a1.md @@ -0,0 +1,18 @@ +Task 01 complete. + +**Implemented** +- `frontend/assets/styles.css` — added `--scrollbar-thumb` / `--scrollbar-track` tokens to the `:root` block, derived via `color-mix()` from identity tokens (same pattern as phase-92 derived state colors: not stored, not tab-controlled, not in `BUILTIN_COLORS` — every saved theme repaints them) +- Added the scoped rules on `.doc-modal .doc-raw` (the `pre` that owns its `overflow-x: auto` + `white-space: pre`): `scrollbar-width: thin` + `scrollbar-color` (Firefox) and the `::-webkit-scrollbar{height:8px}` / `-track` / `-thumb{bg, radius:4px}` pseudos (Chromium) — no global restyle + +**Results** +- `uv run pytest --cov=app --cov-report=term` → 2457 passed, 99% coverage on `app/` (gate >90%) +- `uv run pytest tests/e2e/test_dark_tech_theme.py -v --no-cov` → 6 passed (in isolation) +- `uv run pytest tests/e2e/test_document_viewer.py -v --no-cov` → 7 passed (regression) +- `uv run ruff check . && uv run pyright` → All checks passed / 0 errors +- Headless-Chromium sanity check: computed `scrollbar-color` = thumb `#796b6b` on track `#170e0e` (3.7:1 ≥ 3:1 non-text AA), 8px webkit bar, 4px radius, pre scrolls (1598 > 1056) + +**Decisions** +- Track = `color-mix(surface 75%, bg)` (near the `.doc-raw` bg, slightly recessed); thumb = `color-mix(ink-soft 60%, surface)` for a muted ≥3:1 thumb (50% measured 2.97:1 — rejected) +- No `app/` code change; no line-wrap (locked A1 honored) + +**Next pending task:** `02_scrollbar_e2e_check.md` (E2E scroll check + screenshot) diff --git a/.agents/reports/116_modal_scrollbar_theme/116_modal_scrollbar_theme__01_themed_scrollbar.a1.validate b/.agents/reports/116_modal_scrollbar_theme/116_modal_scrollbar_theme__01_themed_scrollbar.a1.validate new file mode 100644 index 0000000..6b977c2 --- /dev/null +++ b/.agents/reports/116_modal_scrollbar_theme/116_modal_scrollbar_theme__01_themed_scrollbar.a1.validate @@ -0,0 +1,103 @@ +........................................................................ [ 2%] +........................................................................ [ 5%] +........................................................................ [ 8%] +........................................................................ [ 11%] +........................................................................ [ 14%] +........................................................................ [ 17%] +........................................................................ [ 20%] +........................................................................ [ 23%] +........................................................................ [ 26%] +........................................................................ [ 29%] +........................................................................ [ 32%] +........................................................................ [ 35%] +........................................................................ [ 38%] +........................................................................ [ 41%] +........................................................................ [ 43%] +........................................................................ [ 46%] +........................................................................ [ 49%] +........................................................................ [ 52%] +........................................................................ [ 55%] +........................................................................ [ 58%] +........................................................................ [ 61%] +........................................................................ [ 64%] +........................................................................ [ 67%] +........................................................................ [ 70%] +........................................................................ [ 73%] +........................................................................ [ 76%] +........................................................................ [ 79%] +........................................................................ [ 82%] +........................................................................ [ 84%] +........................................................................ [ 87%] +........................................................................ [ 90%] +........................................................................ [ 93%] +........................................................................ [ 96%] +........................................................................ [ 99%] +......... [100%] +=============================== warnings summary =============================== +.venv/lib64/python3.14/site-packages/fastapi/testclient.py:1 + /var/home/ducoterra/Projects/Personal/brain-of-reese/.venv/lib64/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead. + from starlette.testclient import TestClient as TestClient # noqa + +-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html +================================ tests coverage ================================ +_______________ coverage: platform linux, python 3.14.7-final-0 ________________ + +Name Stmts Miss Cover +-------------------------------------------------- +app/__init__.py 1 0 100% +app/api/__init__.py 0 0 100% +app/api/auth.py 52 0 100% +app/api/chat.py 224 1 99% +app/api/chats.py 110 0 100% +app/api/config.py 13 0 100% +app/api/doc_drafts.py 99 0 100% +app/api/docs.py 156 1 99% +app/api/git_sources.py 232 0 100% +app/api/health.py 10 0 100% +app/api/steering.py 42 0 100% +app/api/suggestions.py 33 0 100% +app/api/sync.py 139 0 100% +app/api/tokens.py 40 0 100% +app/api/ui_settings.py 55 0 100% +app/config.py 210 0 100% +app/core/__init__.py 0 0 100% +app/core/auth.py 45 0 100% +app/core/caching.py 124 0 100% +app/core/debugging.py 29 2 93% +app/core/docs_push.py 39 0 100% +app/core/errors.py 5 0 100% +app/core/logging.py 13 0 100% +app/core/rate_limit.py 44 0 100% +app/core/security_headers.py 20 0 100% +app/core/theming.py 38 0 100% +app/core/tokens.py 44 0 100% +app/db.py 22 0 100% +app/main.py 66 0 100% +app/models.py 128 0 100% +app/rag/__init__.py 0 0 100% +app/rag/agent.py 317 1 99% +app/rag/archive_upload.py 134 0 100% +app/rag/chunker.py 206 4 98% +app/rag/doc_dates.py 18 0 100% +app/rag/folder_summaries.py 123 0 100% +app/rag/git_sources.py 14 0 100% +app/rag/importer.py 215 3 99% +app/rag/llm.py 244 1 99% +app/rag/overview.py 71 0 100% +app/rag/prompts.py 88 0 100% +app/rag/retriever.py 192 3 98% +app/rag/scaffolding.py 55 0 100% +app/rag/source_removal.py 41 0 100% +app/rag/sources_meta.py 16 0 100% +app/rag/suggestions.py 27 0 100% +app/rag/summarizer.py 24 0 100% +app/schemas.py 329 0 100% +-------------------------------------------------- +TOTAL 4147 16 99% +coverage gate: app/ 99% (>90%) OK +All checks passed! +0 errors, 0 warnings, 0 informations +WARNING: there is a new pyright version available (v1.1.411 -> v1.1.414). +Please install the new version or set PYRIGHT_PYTHON_FORCE_VERSION to `latest` + +validation OK diff --git a/.agents/reports/116_modal_scrollbar_theme/116_modal_scrollbar_theme__02_scrollbar_e2e_check.a1.err b/.agents/reports/116_modal_scrollbar_theme/116_modal_scrollbar_theme__02_scrollbar_e2e_check.a1.err new file mode 100644 index 0000000..e69de29 diff --git a/.agents/reports/116_modal_scrollbar_theme/116_modal_scrollbar_theme__02_scrollbar_e2e_check.a1.md b/.agents/reports/116_modal_scrollbar_theme/116_modal_scrollbar_theme__02_scrollbar_e2e_check.a1.md new file mode 100644 index 0000000..aab23bf --- /dev/null +++ b/.agents/reports/116_modal_scrollbar_theme/116_modal_scrollbar_theme__02_scrollbar_e2e_check.a1.md @@ -0,0 +1,15 @@ +Task 02 complete — all gates green. + +**Implemented** +- `tests/e2e/test_document_viewer.py` — new test 8 `test_raw_code_block_themed_scrollbar`: seeds a synthetic `notes/long-line.txt` with a ~935-char `quest::say(…)` line (fixture KB checked first — longest raw line is 91 chars ≈ 742px < ~1058px pre client width, so no fixture doc overflows; choice noted in docstring), then asserts real overflow (`scrollWidth > clientWidth`), `overflow-x: auto` + `scrollbar-width: thin`, computed `scrollbar-color` = the `--scrollbar-thumb`/`--scrollbar-track` theme pair, `scrollBy(300)` moves `scrollLeft`, and writes a screenshot to `.agents/screenshots/`. + +**Results** +- `uv run pytest tests/e2e/test_document_viewer.py -v --no-cov` → 8 passed (in isolation) +- `uv run pytest tests/e2e/test_dark_tech_theme.py -v --no-cov` → 6 passed +- `uv run pytest --cov=app --cov-report=term` → 2457 passed, 99% coverage (gate >90%) +- `uv run ruff check .` → All checks passed; `uv run pyright` → 0 errors, 0 warnings + +**Notable decisions** +- Headless Chromium (151) paints no scrollbars at all (verified: no pixels in the bar strip), so the suite's screenshot (`doc_modal_scrollbar_1280.png`) records the scrolled modal state, while the themed bar itself is asserted via computed style and recorded in a one-off **headed** capture `doc_modal_scrollbar_themed_1280.png` (visually verified: muted rounded thumb mid-track on the dark recessed track, no native light-gray bar). The temp headed-capture test was deleted after use. + +**Next pending task:** none in this phase — both task files of `116_modal_scrollbar_theme` are done; the phase is ready for the harness commit/move. diff --git a/.agents/reports/116_modal_scrollbar_theme/116_modal_scrollbar_theme__02_scrollbar_e2e_check.a1.validate b/.agents/reports/116_modal_scrollbar_theme/116_modal_scrollbar_theme__02_scrollbar_e2e_check.a1.validate new file mode 100644 index 0000000..6b977c2 --- /dev/null +++ b/.agents/reports/116_modal_scrollbar_theme/116_modal_scrollbar_theme__02_scrollbar_e2e_check.a1.validate @@ -0,0 +1,103 @@ +........................................................................ [ 2%] +........................................................................ [ 5%] +........................................................................ [ 8%] +........................................................................ [ 11%] +........................................................................ [ 14%] +........................................................................ [ 17%] +........................................................................ [ 20%] +........................................................................ [ 23%] +........................................................................ [ 26%] +........................................................................ [ 29%] +........................................................................ [ 32%] +........................................................................ [ 35%] +........................................................................ [ 38%] +........................................................................ [ 41%] +........................................................................ [ 43%] +........................................................................ [ 46%] +........................................................................ [ 49%] +........................................................................ [ 52%] +........................................................................ [ 55%] +........................................................................ [ 58%] +........................................................................ [ 61%] +........................................................................ [ 64%] +........................................................................ [ 67%] +........................................................................ [ 70%] +........................................................................ [ 73%] +........................................................................ [ 76%] +........................................................................ [ 79%] +........................................................................ [ 82%] +........................................................................ [ 84%] +........................................................................ [ 87%] +........................................................................ [ 90%] +........................................................................ [ 93%] +........................................................................ [ 96%] +........................................................................ [ 99%] +......... [100%] +=============================== warnings summary =============================== +.venv/lib64/python3.14/site-packages/fastapi/testclient.py:1 + /var/home/ducoterra/Projects/Personal/brain-of-reese/.venv/lib64/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead. + from starlette.testclient import TestClient as TestClient # noqa + +-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html +================================ tests coverage ================================ +_______________ coverage: platform linux, python 3.14.7-final-0 ________________ + +Name Stmts Miss Cover +-------------------------------------------------- +app/__init__.py 1 0 100% +app/api/__init__.py 0 0 100% +app/api/auth.py 52 0 100% +app/api/chat.py 224 1 99% +app/api/chats.py 110 0 100% +app/api/config.py 13 0 100% +app/api/doc_drafts.py 99 0 100% +app/api/docs.py 156 1 99% +app/api/git_sources.py 232 0 100% +app/api/health.py 10 0 100% +app/api/steering.py 42 0 100% +app/api/suggestions.py 33 0 100% +app/api/sync.py 139 0 100% +app/api/tokens.py 40 0 100% +app/api/ui_settings.py 55 0 100% +app/config.py 210 0 100% +app/core/__init__.py 0 0 100% +app/core/auth.py 45 0 100% +app/core/caching.py 124 0 100% +app/core/debugging.py 29 2 93% +app/core/docs_push.py 39 0 100% +app/core/errors.py 5 0 100% +app/core/logging.py 13 0 100% +app/core/rate_limit.py 44 0 100% +app/core/security_headers.py 20 0 100% +app/core/theming.py 38 0 100% +app/core/tokens.py 44 0 100% +app/db.py 22 0 100% +app/main.py 66 0 100% +app/models.py 128 0 100% +app/rag/__init__.py 0 0 100% +app/rag/agent.py 317 1 99% +app/rag/archive_upload.py 134 0 100% +app/rag/chunker.py 206 4 98% +app/rag/doc_dates.py 18 0 100% +app/rag/folder_summaries.py 123 0 100% +app/rag/git_sources.py 14 0 100% +app/rag/importer.py 215 3 99% +app/rag/llm.py 244 1 99% +app/rag/overview.py 71 0 100% +app/rag/prompts.py 88 0 100% +app/rag/retriever.py 192 3 98% +app/rag/scaffolding.py 55 0 100% +app/rag/source_removal.py 41 0 100% +app/rag/sources_meta.py 16 0 100% +app/rag/suggestions.py 27 0 100% +app/rag/summarizer.py 24 0 100% +app/schemas.py 329 0 100% +-------------------------------------------------- +TOTAL 4147 16 99% +coverage gate: app/ 99% (>90%) OK +All checks passed! +0 errors, 0 warnings, 0 informations +WARNING: there is a new pyright version available (v1.1.411 -> v1.1.414). +Please install the new version or set PYRIGHT_PYTHON_FORCE_VERSION to `latest` + +validation OK diff --git a/.agents/screenshots/doc_modal_scrollbar_1280.png b/.agents/screenshots/doc_modal_scrollbar_1280.png new file mode 100644 index 0000000000000000000000000000000000000000..142969931b48b3c68a5a28ee06325449a2c1629c GIT binary patch literal 42502 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 a1wm{aHOG literal 0 HcmV?d00001 diff --git a/.agents/screenshots/doc_modal_scrollbar_themed_1280.png b/.agents/screenshots/doc_modal_scrollbar_themed_1280.png new file mode 100644 index 0000000000000000000000000000000000000000..a566c4b71e0abc074ce79b63fb92a2c6099ed4e1 GIT binary patch literal 44687 zcmXuKbzD^6_dPs_f)b)q(iYO7bb}x*-3=lgL-#NuB1*n#$swe>a~Ko>>Fx$$$Qfyv zVVLLg`944Xf!95U6L;@@&R%Qn`%OzjiJXL<1Ox(+t0=$K0fFuSe-b{qdkgq=j4>() zfe1()<>j?3K_LIktZrXc6!5@S^B`t=JRgK@5kXU$W>Gg ziI={Fhw%$>cgvdA_^wQMzjw|SWDP2*m8b#6vys(IJMj79C(%_~jYk#z2#4CBOb@jv| zhE4SQ>MOqTYlYzdUWQd44tXYJWf!BkMA$t%w%>bWe~=abmao*WdfVp0Ma~?)EU?4( ztvW?rsuo|aE%OSxa`H*Zzb)*vs<7$uHdoU>%<@S((^kkD9&BGZk+wb;EhTZ{^Zt?8 zYsLY6_S9+T45qVdkZYWR$QYz47X*3$QhEDE&p&g2i8zze_PX~lEotcvjZxr3ZSJqs zq?~z1H6r_``|u`-Ah94RsRcZ@-`R58d-NSDQeP@+svjiWE^7REu$}UE^@SH1`*s4b z^MQ@pz87il?6M_SkRq(32tz)?mTD9K=I~wuz!*SMz zPeqhjPWhMdGf>kL-AdMz8?!kupibhczNp+hEiw>pNsYb_JpE8*bNkPUt#yLC-R)I7 zaRU_V;!Wr9WObId&$X;7qDr?{S;s5453+((T5g6{=^Ir5H`UMSJbFnaaktaaU`2QY ze%l;q%E?!oDFe4%rMfue;a6h%0Qg4(I}yFrURSV_vjo1OjG7$)uRFCdZFf9QH_26C(W#RqJ#Uw`yO zKfNQz5u-kl8iahBhc8!7v=uUmC*pb!0;$H);b*wl{&Uz&_%Qo?ek&KWC>(C-$p=a* z85mwpr2Fzp6xsTDhZive-MV7%93E%EGw3foRBB@SUWRC`}je5=^62r!txyrKFiHx zKZ@HvZP~ayf*kV8%x!0uym9To3l3;vCN2%qa&5(`Zn^xrIg`*me!ObNlTVE0qsS$B z9XO}-<%5%kgE7mj;OpTI*)Zx{Dl$;OpOU`V-tJfl)c30Z9*Gg`zB25z%%7bw)gHvF zcyb`S^dRsZXjC=p-O9&E4Si|Y81t>dxgi#^Ir~0-5UBg%3Q{b=BR%$6fPvRQ=NH5G z?sP<}zpGmI^Y|`lK#`?&BQn)_x(u`-i9UzKlWZG;V<0Uu4NOeEI7gDnTkny$WF;cu zM>g)4wyT~Jq~6vOV2-!y>%5@)0*yihG^g~f#^v0AW$yUzPs)ElAS#XA@v8XJs^yMv zuh)`>G0`1nGLFX+Z&O!%68bqow6AcDh9gBA-Ag)Be3GEQPaV>6x2RdCYERD$KUe(8 zQ=SEZL`|9^GzccZss#_eExrCumYEZL%e}6uUS45EI8Z5p6IB00GiTf|5OI`V_N7OB z_}d+jT79J{gE}H!xt}XUa3cRf<^_l^j%e2wf z)@aib%FOngKmFjoIkV5|eU^`=u#iNUt~CZj#90;`vV__q9U&8{-;$%MkRYf1Mhlvk zQ@>Ya8L?F@tYZ%X9qIp;hf-PypGz`ALk=GmO1Gt1612DTyZ0{NX-(b{*?hPQzoN!{ z(r?At7l&BC&^w?wxvO_UmcQI@y(qQ9FX#b`_-0fPdz&+6yf7a7l56}A-yP6j+dh40 zjBkSBx8_yti558hO7xu-ueYGbmpWG8|jf6rY z-L7+XJ9DGKN!WMw2g1rt_dq%&hs0b5@DSBZMH}ZXvq$$pM{CEId7CTVxHaL9v!Gb8 zVP{%Y+%11$LcdA#9Mi;*#G*3>J3fi^Qk&Nji>p7(V7NQZ5^1z3{LSt$Lcki8x->WZ@QS%$bi{#Pj$bEe8!(S9#q;f=)tl6@C3D543b2kc87SFgVll z8R#xFX~Nt^C7sV)^0T}TZL!YHuNDObCRZ1ydy8K|08{C!tX@{(%Ls=3t?5;~~eltCy(4U`LTMMvL=Q|U< z=;NIY=cf*=CBTnqyT7$-g|_bz_AJYOYGwv61nn4$x4piA2c7D0RS+4gf7aH>{F{>7 zwRn{)`^spkK<(AzN#BDjD;|?}qbTJl-p6+b(!3qv zRo(g5;WaoZwN?f~qseW_De&aGkXIp=xO~WaXIuf1<3#@srimaHDAXL;*})_q=xNuy zi(}SB4!e?QPk{Q(W-86wX0ePVx&<`~LQL1PR%>|*c3ebDr|G+WLvH4t1_y>E{6$5# z)pf}&Rkk@KXlHe z9*@ybY&^AB*bHC03Nja3YU7&S{(|u`xh6m$a&v!X5EwDdDPqH%$@ToEYq^oBf1H-k z4I?WAzN~+~h~r9c*I#%9p6(W$+W-7?M=?U@2N;q6Z>v|t>++)sE@*mk+fwQ&BZ(tN zU!FqL$s=h~?>t6ImzRgB{o?l|CiES-^OfS#1njqxdMdWq292#?E8jo*ZkfjJ^V+7K3>^leLSp#Ce?r zgU(SEs}&U*@M1GWl%p4tNKj|F!Fd#2wX+ytpoBfR{U2pGZ-J!{Wof41;)P*xiKV-vh7r{_U)Ix&+Ef8gR=U9AmrSB+0ry^E^m$#ElDTFR7e&lOqcy*#kNSJETlr! zBG$B+(Y ziD)kQFBxp?n2BFhA+E<^-!>2b8V;k2c=lfGze`<-%b91d3*bI7AwpRZh@wxN8%`Wj zs;K)sRqdC#)oc`^oSgF!52&e^+I$4|-INA22j_2Pj2SEn(2~QYSMs`}ro{j1A!6c$ zr-TLdZikiDa}l;#8rxbctoK`;IAwCa8?3DGL3Hd=OO=(C=}CCf7b-;2v;~5xLuIRW zop5DJQ#msca-={EGceQzdw>+iThvmw4G<36@T?GW?31t6@I!H)YLgj_ED5d`5|G&W z`T3sNl!X>AWN9gvOKjFY?k|u)xknZCQ|)ckLF@r zm2GM@+U$*^%!4ROxE3o+MKU&Sy#KByyxe1&p~Xv?K>EaGBr0h zH`acLL+!6y*HhW0r+0eZcio;;fyoiBr;kq}cc;~1YLpI%lS*#&P2P~@4hW|B;b_)y zc7X{&tIxsw=&UGsS<;^9L_DyP$TsP9v~awq*pCI8M=z&UE5X98?;Wm_+26A)I+oDz znr)M@h^pz7B{tIY$n(&^3z>Z^bmL0DkV{<7}st*1BU6qbW{7v`uSdH zd*EyoYe!V`^oI(b;ZG)7rezcb=U-8&AB<5nvXsS^rJHr4Q_>kGW`PfFT`DBi&pM{b zYb<4X^o5q7!1>UzL-qE2-F|C=I3`- zpB1clb0&23r&zK%R%WtU zefJ7iGPdvc(0^@!lF`3k$mXsa0!W$Z*%pyRiI}=KE^se;vt_$8p;)+f)wE-UIqy9$?e;T4OKIlqp z*V%T`(QapY`pVXz$4gy8@tne*dxN`DdqvIAa};7EgH|T8*>9#&zb3pK<=L=;j_pme zWR$J>UYO4BY8N$8FP8%M@jIB;XSzFp(qw;JOt|KfL4Bs&p8n=kDZiK17cH%(GKex4 zlRwfJ;YN4W+!~t*{jhNNcf`NUqR$6V{ec*S92}1KqJ<&&TN5)|*co@3jK&RS=9K2V zPl>so%D32sMM@4z$EHv!GLB@2gPc}&X;zF|`{KKUrM>N4waVT^2|AZj{B9NAV@ zuD5@_-Ss}>UVZQ`6H?GH=^bGOC|FP zq~A=WT74$$XOyP%lYLF?>v_1Qq%b3CHGfYHj5SuQylsoiCem|UEu&su;|zRu|7Nbg zVNqA>>Wf^P6-~A9YLtpi$rWN>C04m?sr`{%C(xYFnv)&e>RuU_!#8g~lak-m=I7V3 zd2t(av8yeirc)7W5cbkkF4U0Yi4{7EdC4hn;{`RnzK5@_NM@aH!JNfuN8ovP6pdKu zuRpQ2EMII20{)QFHFw=!71ltEO}r6N$Yg+isPXfTs{3(f?(7wOVKy;RThcXCXUG?` z=v_a~%AZtNwivCTfhlFvu@iv`{^Zp5^hi4dx_g=?mwcNl8e%P+qZJH(jhg z;g3lSw%*Y=mg{^%IbnpBr$|uPx1@6VZb~C^-l!wX7RDlXFrQ3coH;oOJdCrJ*l$O^qMhS8k{Xx{?b6KDF`_%U{jP| zTy3)5#PR>Q0NPb<+rw7zp}H^Zv@N&Xw`hsAUYyl@E->+4X;vN~f&ROfBHfg-u#W1wMAI%&6$@%N*`| zZ+fLsv5m=V$QEsL5%uH5i$2w|R$M7GcxoHugW15b6g=_Ks7Hk#z(UAf9K*+=-pW@w z8qD^!K>P+q>`aTR{r2ki$@{-44ikf;_3N_8--Lg@cr@{4l`${}$;mH9sAzJW^~wDn z^VIYQGSRWpJwSJ<}RBtRm9goOZC4-l0CB#_mfoZS@%VlRpp)GA;UQ>!&MJz5YAY z!E|kYYK}ux3|nC88)LYWW9m|ERWhr)o^QyhwbO$67UQN>!yK}wTTBa}uDhMCi6QzX z-WXPT^QvMne#?q0-3S zWv&l#)I1XY)h3A-yzEYXd4!cU&H=2o_U}$9k;IC8QwS*3)r;IXy3}A!MnQFB_`&|I zpdu#Mh=w_zu-f`}`>7Vs3y#emwmuX7htB*w_%NFKL8j7_w{MeX!Nz{hBk!!d{MS^a zwSHv=lx@`=A=by9x`1Df#+J{bnjd0++;c*$CqM9Wxxa9l_=`p*xP_%eNM=z`#`lRE zfO}AuCN<^c5rf-revN(UzSkM`?CBjVr20Dghc&i!){&OWQ}XVd{gy9;&+G>&dP=enn*NM%~BK`)2M}X?`JU|O!VK* z>`w^EO&X+KkWlmc`j`>-IbRue3i%D%&B@VA=qt3G(Md731iw{(kItH&it0Y@s|E^ZNwcPO>cXtDQ#z`daL|iNYY?GED-MF zyXNNL-somucHV~3)(~0f@`or&Z)4z19MQn zBQSU|3{F!RVM3-`7l9J~wYkmf(AZ^Zd!1iu>q;&yWAnOG)kTa|`|6V1UP6o!c6Ihb zcn@{|kp66kV9Pdd+@$jHrprsI*BQV`B{}Sy=4PtqKk0p%9J4i)vlfz5kUFHJK_EJR zXjHp!oB$($)tm^9pp;Sh^ahG~Z`~41VAVnL+W4ImF#p*>YV`u3LWjr}~$@n}|+_Mv2OHr2Xu>XtVjq z-!mg_WhyhPqDl`PWDBIJoa!T{9?^Knu`PqqjadO6$bWSo9y9G>ItwfaczrQGWp!m$ z`eSS2&M8ydAZDzBY)n91rA5cM|U=Q7Bv&Kdwf zqz07f?8aH-^*;GMXjn63XQp-}(tzO}z3b)q7JA@lMsrHU(gO^f0*FRyV_JzS()XYWfJH zcO9dY)i~J6%4(GqEt#VA6d{adAi2QBFIG{K1O5CX`IBV=kBr*d9a8!&DtCKL1)a_T#R#-fBf);O)_$N5#0*q440a4A&EG(Y_8ZfO-t1bUKYO$ZY|?M z4k3TLOMGTycO#m%=S%w;->h@5)3t8tg9hSe%!HEf#&mbLS9;w2wQX!7L~YA&*^i>p zRAjrp^6Zm;#UJYZ+^i4YO&>9Zuv2kvwbN;w#WLYCGL;t!B~8T@R>#Xgv=vusm>Uat z=I#H;+!9gWtnZFtaZ72rm8fQ#N*hEns;!3IP9U zllYX|t9tr#&rnllfeNb$&14CCjMfL4Aq@c$-+lw5ezexRz?pM$>P?k9JMA{plIZ`_ zy)?x8R+dk~?kw)j8cVBJ7)cMe(#@1uMND@$M+4J@}^DNH+9j2rV;&}b4bKOMk4*G*cIb;*Uqb5}|AELAU3r(7(c9&C?XxMrEJ$o97 zd+ssY&W!}}N2L=@aSyfGy13`tOx|Ld&kN4{2F zRC%v7bB<##E2bfse!>0HVYxKYLub3(M!SV3bb$wi^gdXbj%EKZ1laS(li)%+AkZYM zkLyfzU%WRq7)66U`Wr2!(?trBWoeF6>efH3W)6RuihW&9Xhz&@q*f%Qadi_hNjW6R z(1GNm(k+Qd-Mjk_tVHK3PN|!To9zwk z5fg+>Yq6sT)E$umd0L_hbC)gOcg`nuHKn$5!n|#+KHpPf3izS@3)O)|t#w80^%F8VIGD)Qc!T>W@WNYs9@9<>sD9CNd}?>Q?gAMAO+PGk`cw}0)V%1ZFUXplT= zBoZ7N#RW!5!Pyl*By?p&ibObB53~q)EiOfNvWj;a`%^80Uk9DJENMM#t`Qt2zF3Q3 z5f&6yd=}rd5+YH=HtmfL>E|e7x8jre@D-Q{l$Jb$e`+@;<{sZg&7zWMib`LBh0Z>n*d3{7Q1)kl~;8juXDKA=u=I`>xo8 zoxJ&Z4#f3tM^R0O1-|2K-kGu|u4-rQIF&;;+HAl5c=%ej1dRqJ9p$}}wq$Rk-{9n` z3huwh){JgBJzGFvFwXhU>!==Z4+yGrssD?zz>1_gjb3B-Des3fLyr1B)0USPi=Gwd zOQ*eB3yYKPKPosO;VicM-n74|b$j@zCH#ByL4(f=2jmgB?}sI9q-kb32;8_+C~s)d zQd+v(+m}dvzzq5O@O*aR^F7L|5d21*Oh`AiAtQ9rV-iSHg z8j8{^aqzpaj&N<+Oc?+;gBid+M{0bK%gt0x$-~dg^dfGHY4+KUe{Cm=wTCOmNNIT& zy(iRtY)-bvM3(*Y-7+C(a~r*JGKaq@BPdv;tyVi7b&EQ#jt2aeAb!o4vuiY_E;SPx z666fR<%U%j05^_V#hq8Roz1)S&_V(0b={Ydyu41-kUSjix<5exJ)H6R&4#Nl|nZmg$yIq z?bTz+weL15bfW*(dYK0{yYq^|G(^BHPD8PycW8oejhX`mrj*Y5mreB(=-MzMb7&X& z@LEG`gKHbAbuV6t@ip}4t@Gc{r%ln*cr1ckWVZ9tYqc}9ErzMBe>9i)_oJ+%<*cTa zjx+H+QK*wD?%aTTlDh9~0Sx_hkBuEH0o|=*gkBv2d|mtQZrR3!S7svRsf0YpEVFhkw5LzTPzmNBKi_xkhSm&SQ$Bk?|MydhoD=g z7qaKM5_9uP$hpkPDAssVER{v_VsJtefzFK(e*F4<_)~eip={hmqGkvdcOIw=88G)< z^ysEG*q(0K1M3z^pDuc7>`vo|S=>Kjg3>RN4K1Zkz|aZo?$W6iOd4{w;H3%IFgIUf zgN0yDyhd!(%%}2oi{_Q}iAHQLi(g#BB+!yu|GMiL^Pnzr zf$J-QBEx}K;DA38gsJKeo7Lk8cy%sC&@)a|QZW4lpK&k*g5#=c&zlE_!8N=4fr#BQ zwr73Ue)Zo|l6slziw&<4sixw_=@#AOk=HgoqD@V6b{YN{9I6eS9k7)K^sqS|nq!J= z{(oG6h)ASLiO!B;gTqkpi$)<-!;FP_X<61n5UM7E^6u#vVEjroKDhVM-#(02MZ>iC z#cEj0FYVW6Fhh~RlWmW|F{N|V684`wg%5Kp64h3ukpb8oA@#45@bJ^61iJnB<3Zhs zw7}8P2=sbF1;Ot(%$QFu!wp<K|PjlpB|qiYS0Thj2`pB zPc98DUE!N4Hh#-u19YR0UQJ}Wh#@v9hdS{%G-j{D@831nP)|>E=e!k)$HvhKL^Ilc zZ@NlS4Rk7c9;#MZ8 zmZ@z0rs;XCBtIj`(qz%dF<-mZL$clBO&dCw{n?t~7;wim=0ExS+VGmfpz{cpfFG8K z5XIMGZ4dT(fQ!ZtIO!grWzW**VUGs*d=}=kjVtjp2RQx+PaM1pCvhV*1K*1AM~_(_Xp(Ng%AifmRV@G#2z+eM|7gI^URKUpf{H+ zxOd5qC15+(xvIf{{m~d1GCo9L#B^Cl&w&*F+`Eq^ln@f8FGlWY)bdgZnZJNHsad$! z_Ut0@jO)*}RQcb40p2~6A(nr0@)86SGasnV$-wgO?Vo0g`;;bzDA+DgYKXp>QnUS| zov&CjyBE?AoW=W$rV`H6(&_2tOzzpgWri%wo`#K254?I!CybF!0vPcV_r!tAMU z%#@)>?eR}68Uf@D68qKiuO7_0cadjFRJ9-VKRXC27r%Pl%eax0WIvoahoJ!S$k7hZ z7{AhhZ5iZQ9bbn-{rrg${}l?0rv4ZNly}Sq8SI^XyvAiEgz4!U_yQ!f$Rw-pt#0&L z_Q%)`2zGY`0r<#u)QYjO_SoodS=wK7G3;3zIwYIlwg9+8@jrW%&2JD@9GQ0bgT}}|Z(w{OPs?P-Rwm7ks;Jwt-YW&y%{l2`9D$GY?tu>m zjWYDYH+qMLT{_P3(K2{F&~yv|A<+v-+ueG{!vzHHD2nnUq=xC~y2{1*3N%jhETW8u z{fid+iSs`9kWUmX{xt+sJHYEK`uxL}nsHUG?jrBVu6tj~o7aB_pUY~f2rUnZER=ht z@(#o3`7eMYH+ubIs|~$q|HK)4^M(*J>D|vi%i~v|ygg`{3aynyt?~%vvk-*cx z6Pj^LwzLySFBm14h{CLrlzRB|yLR{o@d=;Qxqa$EJJt~@yxsRgDUERI;+W5JEsWac zAI*CbI}jho_J8m3AQajYTD)slX9|S z4^&Aua^MU@;RS=yfu!Q{Gzf-_JXqr-f z()K%@1LeF{5dGQSnCHs5yGw4@asJt*N#*y)4%N?M;v1XGy}p1L1!D@$kUv!yBg8hj zOgXYsO@2oX%m27gSWT-D=stH1iFU)!!VuR-YQJ>Lqn}gN*$;V^_J@vX2GJb~fdIkp98!UMDmAcbuQ*h&)9TerKgsAxBjtA6mbz&)yzBD_|2=Z&c)XZq<#Reek8EZ_ML~-*;OD=t*57_ zlrJ@0oSep;E9=)IyJpP18uSf)KGhssaQ@?b1@k!SlTlBrUBm44T7CdP!veT&sL|AQ zs=&)0uB>2N5c!N^9%=6wKY~>AGjd=a01UKY5BD7Y<`Zqc+9yP4|Gmkj0E$Q|n4zJd zh?U{Wn5#AUUcPwY!h!mg(g! zO<|4sPfWyj#kDEN++`AxF_(Ja%7?hdlu?pSZSMm&Bq~A>97aqbOtL#`6X$cZ+a7R? zg02!EhrNcyio|_Yol2Y?+}+4xV`#-`xQ#|11UXd9h6n+6Rat&0l_mVYoG_f)&F4;Y zWhJUn0-Y)DIxh?~8`)Q#B;(q9occEkwJS*e%p8Cb4N+}I%XT3XKZ3c<#0_{ zmJm_tLngl^p@5^mPXPq=^Xo&f=*)F}&=JYtj2RTjc%YIl$@+q93~`KN0(;I>N+T*s zg`N3WFLP-us--B>^xps8Si|+#hZ!#Q@$pe)$0=b6n%1tuP$nPbAQfpb_2$ZZv+aN> z>#jxQYvKJmK}#UBB2fc(TozJ7fV*2~ijz81vG-`V7Z%KK+fVhJ7K}I^{K|3d@W z?QEi^MhAWYjqu}L-n)3>duP?73NFm+J3o^FZsS=RxNfit{bl_ts|wiibrk;cI)X)9 z#BLsvY+LWLDTES7#v|dkEx{7*lYGQIEry%^;S^rF*e$D?HuD93e`B*bc_@IvsHkmb%NEB)E!}YrOd0g=M zk{@y~O}EMa@ZuijuoyB^#S&s$&jn$JWF~5eJ1#bRAn?~gvu=DL0InQi(+Cz4CYcRv zLwB?#9-m?i%|cqdiXtmb=)b@vSv7TQu?>ZY*ND~GLwOQkicRe0PH4*D z00>rpVmFjtAQLBnYGwepzfL$+HeCq5+4wWZ$hV&=q$3ILwkS3tIs2jvM=+Oxf z!uDm|jwbIA!wtECK0A*{A}Yqq*pRybK=3BXj*~q4>c#+IM%h5~vQiph!6a0CUiXg? zi-pnu#BRM!)r{w>OF%(PGn)pl3h8Rg!)xl6-xhHEO{c@ZyIgeP{DpG_%e{l68cF_}k2-PwFmcHl0MK;VZ&Rs;nF$(SYm!^lO- z>-jXWGgp^Y3x*muj4!{#-SAd@eIY?1I%Zw!yWGR;x=jN|eV)sn2F>{ab>h?p-)t-M zh*$GiK$+)#umJ~R3d9N`eF$Rz;!z8Lt~Y2^ZmNj+wR-lb$fg502n}!FvL5I^dM5AM z9_*Rklv&W9JLMdIZ2j9!Rsbm>8KZ zIIuh(1rpJ*8xiU7U`c#+R?0201w_V|V*bNE)9aw}WBi>Xp3lVw7%O;3;8$z{+J z!#bekQ@G9tGehza!rsSP{}A2NEj4qp^U$n}AdnCnaL|5DL1?fXZNHocyUmqB;(o^V z)9LWUFd!8=u>S&Z9FS~f5@k{wO(UvYjY%Q3zrRq6y@-9%Zh$Q=K#i?irFwn-1)+V$ zX(Zjp1=I^8Cg--Nr@+QL2lW1ylZGdCM0?JZ$5m#S`WmD<*cI zhAPNyVV8T9)dy9}&6{x>n9Tn_lDN{DWIrMl6n5??h5G^J@3oUU1OUY z=M3RmodIe^OTXf2s|Xk0Z}a^w20aBp42V6c@W1}dhf^<3p|Kl-hz$I*r!LV7ti z&Z)dCu&U$%rDKD&^BHQlWs*vLL$-eDJ!;ggZaONDw`>t_(|eIFj$(Fr)C-_!74*bd z^pWxG=!2SaH+_8)#{z@?0Ud=WqYb61HTG{H5Nk@i^&`jbb{_7N_5!^>Uy~r^Ly!gz zCt2r268ETDqu_935+1lV9rGqI7N}lMp8W@&lX{Aii~2JC*V?v^e2fn5zspadvZF}n z=(jX;ucz2!3kHfxIR`c=|6#*0RTluqD>rE_ko;9`|MBYh-Og~M^@`v;TXX>UW<=%n z-|Zin7Q{>D9gVFAbUdRT7bLjnnFmaqq}kOQg3~orLHpwdwI%Bx>H%i{VEn>T-F*zU}FQLnm4yQ`5_ z77q+^TqXREWpPIp3K%aaZMVB#e5r`mI8!#_~a< z_ssfW)a>==(m%vP6vIX87fqLCJP?D@b5*IDy_je{UBzPDjgzoDYY^R^pK0iqF1b0L z{3Fx;X|z?FYw(q~J)KL7|dY`!D^@<;%I7 zclfb(YZ50n{JO92=x*l_EcwXRbTDwoqWU9&(T+%VfZE2d>4S%Fc(7fGkQ-Xo|EaMb6~XzNE&Zeq4ms!%z@RHX*KWmYNotXM@^#;V3+Ldk2eQM zPOvSBWW_S6_`uBIZh)dT6<)k^PFaRiD>}~AwjJ?-ck`wfsN#JqFKk$DhT0P^IPx57M3E%u% zQjA=9;a?enJK_{scf^BA6z}}WyLmpkCK%<(YCym{uTt$vg4qux1KAGQr@ygGntL-G zSPU!pY8&3QruE`IVEOjV)YFsl^%J`ObMDbOzU|qhAMPOb=1AEb&IelG^%5qbtz+85 zSoHZNCt>KYw56`-;sX+e$7Odw-rjRX{kOI>tMop4jlYDGaP3J%JvBLHcUXIFlBK0N z{s)Hfy<jr-nUh{PV4VhWB0& z_(Kx9Zn_=qmuNj>x}1!={zl1C{f*VRKiQw3#>6B$$#HQx5A1mnfc`7^Ea%bavoW2# zNMe!2I|c}`=7l`N1f6eSRT*+tHu)|7HQM_o4(xwT>x-W;qAZMe21GmZ9O%^%>8uhs znkZWiE8^!5S-l89p5MlW;0#mbt;pBhftqSFZEL`|x!mLut_{uy<4tSgog7Is+W7=9 z&87T2*VQnvYL4jXz#2)x9 zx=AbnL$ZX0oo(NF_5PL0E z5IyaI+}ndF68F%OlQqMg{DR4*9eU?z#9hLdL|9+lsdOQ=9lJo* z@eqNBoORRQ(`0P{0-dI>qw37ZwtD7EXKpU3v+Z1Slg`QDgbUC+I3MI{Z$N zrqp?+SK;}R?{Wa#XQl$R7|>sZ*pw61ic3m7&L;sfrx45${0dwK?XE=@ziBa-;`cs`yo)u~q9hI-X()jA&^AAIZ1%b|8{{`v%T%YvJ8 zRm&E@3|T^OK7JedLT_alDWn0gz=v4$q^A!$jS;a3+8{@cF*Pl?6&*CiX$J46+4nSw zBEM-$o=#c>?dMK41U0#tv@r)Asn`#h`HtpD^~6q*4yOV6#`)sLV$0C?*Bl}>)DdL= zL$_7a{~cdnj)-|73$Lg+nxdM$GxS?&x~fNFb6uSP4i!C9Gy+gMF@QD{*Bdv3BP1r9 z1y{lAsYkLzz~dq-l7}Y~eFFJ0xYhwasP&>K&&Y*b$8~Ahi3(rKQUApUr)QP$t0SPU z+|0d?Rgp720&>3SRUtHe_x3FoK(nMAk+cEyp&t1e0yo03PqJ;6tUB-!<=^1+HOACk zet00Y!5>+7?G9QAqebrg4CUju>|z=lkU zX{jht7CYxj!`;Y?LoS&B$Xq~e@Ezb@py;-dov5;jmIdB62MlkP1mf~+K||G}I3w@= zXm=&EifW%gj=ig(=LdEwonDPKWP!&G>|4)wP0ZoFm2IU^15;D%s7;)$e|}Pw+KB$M*2~5P?-5=J zRPpe3Ow)2JPI$qkWzKGDYKo0Hs2qjAOtq|3sbg!jI7r%vJ-)<|_+x78{|d<{a+L#Y z+V1nlm!PWlaaAk|eh#OQ%)wk%N}z)Q@pt7Kffu82tzHhqaH}G+B>bc?|GM_l;}n51 zczreWmkh8*$j}Al>5hf}P5~HtVQq!K?qz|ToX`o_U0oJ^+H7^Ms_=7kaFM*q2~&(= zy!@%e;wYv4pFd{Ko_2DYlW3b1zPAi~Nt6x)#1AEy|NC7uB4UCloL0FODg3 z8SaI#$8+{B`y#W1qyinbpqHnHI2YFTB|sY!K~^CIooFaJ^X!!PifcIGv0iaK!!*;= z^niR|H(1*BWyyW7f<8%dXVzxQJ89mX2b4s~*{L1gzp{Ikw!;^fyWF_~#9PGa46Mn0 z?eV0rK21xFkEP9+ex3t*SPC*b1K|*FZD<^~;#j0zR#mw$5`3}7#0RfG-yU0t zd0aEjKkzQ?^~NDUqz^k&(F+cW~H8D#$D4%}=ifY%DIx6FZp8yPAtc(c#Laf+UOR9wq)H!NML}qtXKC8>2 zX~oynCzY>tpZ`>5GS?50MWRGMuem+Nsw_tMg~gvv=+?!D5lm+zYP=;r`hOR7 zcq@wl0q|4Zu#W2+_@KJT@@$Ek!`A7F0x~n-`qQAXci8C+daMo^o@%lCxeshZ33DHO z4Mt#5fk1q*<^*Ki2vjUd{Ym4=shN)=BiY*atGgn(%5zxpV;6^kN{~u*r8t9aZEEc> zD%CffTia2lzG=34Z}nrkcV0TV>6h*rnBz7^WZ2NkGVil|q;dNKJgiI8x+ek2=b3Z5 zIuLXig?D~l-urbV40_&00hQTIx}Z#^aGvm%-_VSn3DEnKE);a;8Aj~f62tg<9XNx= z9ir;C>r2@|ctA5m{64e7dyfBD@|#l-nG7{hI$I>=b2$W!B?;tbW7ddSg1d!gijDM^ z3I;x19xui1CL?jDslqf%A?INf!puTWr&9*H3Ti9efS_0T^FDcisIJrN(%CZJW@|qb zHDn4hb5MoA32$Eir9ZzsDyyoO;#@#n?Uo&4PuF+XdkL$vC9Kzf4++oxR_;O{3w@Y5 zV*kck?mzaXfbhOn49Xs|QzM}--gY?ed}^(qd4(-0D&4KDVZas9=hwoqJL$(jrGvDQ z_Un*ex6hlyRL@Pas4kNfEg;A071Sp8&VeETh*1pX4%bB+oGq#+tZ^~ei^r=%z{zO0 zb~c{vz46#yjXl}F0Se}JG*E{G=$7eE)FpTJs?b1{$yf6ihU)riI!(RMGh_C~Q9aPR z+1MoI(}%pRCps0{m?xzw*T<1uf{>%F!rHT+#Edxx3S4m=+n>e8g!x^zwTk@9K9{_f zhGfuBjmwu+)<&j$uj6+X)!fmZ8^M{me!GXI7hTkB$LB_5N;DLp5hKz|tv-7bZGN_g zCN%)*^M71`{!|nnqFkb3eD|O}5HA|w*{|+`Wbz$t%2%+ie-Y63YJcm`+-)5<0}j*Z zHv`<1E7R+3^$t`nK&CqHPW5r>OR=_&O&MM=g5FR)J58Ix?P8p(%AtFrGq3I&o$to+ zbP(DxJeXVfZrSJZ17~vVj3g^$fZp=rctmE#*qH~u^kuIKCI$in$*4*8*u%e$6WJlC z7M6Wx1smN&r&EBuH-?yJ_5b0URlB~b8<{p-eS1D6vZTjz<|DFPocy+nah_t)rsq{F(|hNvWZmp}T9SA)Y;W`~9u;eb#!P^}f$PFaL1n#6D-A zv*Q!jb?wtm9(n~FD)nEvwEfRW7s;oz87sn5S#{mYx^uHCOnnkP&PxW=ToBYkU>e(W zn?>}PX5Fkkk8(ReInBKkAIIo=02{%njoy9iTu#7zFTzxKXMao{WSPx%bYeG9=QTsR zB3(bN2hYzA)+A{RRt$Weducb{UV%~`RLuqTSyY-M>p!i=+6JB3TwXtVf0R2z(KK7x!gJ3RS++f>*x4=E-(yY>fS&hUQzBZ&U(~;Rc*(+lR{X>ou!6nWMgU zGDFi2v#)Qs98O1bk+Z!%7J>C7 zx&89MAfF%UoWC@HE45pDX18FR%9jh`a;rM9k3OWw=+#t8shb-G z+07RH(}QKbR|Mqf;2Co{@pnF*;OvhqvJJ)DB*Nt|zh_x{FoDgOWjG0{`3*WRRejYX zCP_0hO|jJ7Q*eh@_hsa8J)2bv5ZeAI9QIsshtqQ8i#lVM?D>Jmby#Tq?j!)w^vpCJ z+dAh=+S%r?m;2CexGdc_h*@v`)+1Ca8@b=dT5EKF)o!C~m1WUpy%@6rol>AsV6|(! z?@O+s0NFR_={0eOLMd5mk4+35=cA@gv*)W4dpFk|PEhn9J7n(L>IUI7D%g2=~c-TJK;12Zx z?`z^#QBH}X8r&ooIzVxH>lr73P>xJq_r{WNtdF(VvHSacSna&OKvaH`P>cV7<;Dn^j%_am{84Epgg?puR<0jM zELF|rsBh8Qv{-2J`09A=sq<-P2)DOG*f3f zH+{cP>V7^Y?6%>I9>Ba6P_s+VP&(8$o~k2j4)B<%KKMqkR`F5s8h$Bpl-;1gRT}NS z?gV{<8~KrLr5LT85pN(;ks6CJu@RxFL9wDK3f z{g79KEe5vGoSUzxEGnYU)L**;L{`n%Z@PJcrTv-LW(K&1$M{PFVY^%FPI2eTg>T zVE-9hy{2rC;xtc@HTY3Hq^(SRYS5SX10?%$ac>;&Z$#(W%u1~0<`#V6Q17bVsvii` zNwL%e{_sHFZ;*L58n%-o<-9eaKDjoiWs!b4?zkYsF|BJc>$wz}v*|&P+jZcEBIKI` zhVlUBEhp_oym0m4k6`)!8`RF-&n&BU{Y}`BvFQA{ICmSn-RQaj2N-<4_}pOgpPp)$ z1JY0}xxlk|>sb{+k-0c;WaU=9j|zq$HHyNmh|;opARNHtbCe7fHZ^p%9uf=fCA71u zKi9H2njc^r*y#~qFkbRWu@(L#7VRG5Q#5UKMCV7jUy)>$sZ{m0cc!Ak_*JrCs^QWa zVdfWgP3xxCeUj*Gd3xs`fe%%8dn8iP95w22sg%HV%K?y%H`8xXgdbqy_ooxPgwLzg z@J>qsGUl;}_^Dk3Qn3}oWOQ>Gh9EKaGWt0Geu%AE9teBbh&?pOc&qBLA=o}a@gkPx zj6acQ^riGv$@$q(-fCK90M%G=1^=#aCepVvC3?Vfyst|*(?<^H6$9(R7sNsJ?u3iT z=-3WNmk?QiJbh`R%SP?_I7e6i(~lMclA=jbGEG8{?;!e@YI!D|;5;s2A9?4++*a5k zEpwh{`V8#(BcGLMmJVsVq1$uIpEO8zUyB&jBYbS6I$~OiQsFyU`^u^$tax3U@5Bqh zo1;*dv`uTcqkyPF^SQ0%+l*b)2AYEL_kMuZZ8zo+AauJB<~kn|%<-d2Cr$N><>h7W z%(*+W0F^v57NKp6{kY?gU~x4__sYVPOSrsL^*5m?`fY zAay(4LNoL|$Kc=!r%cLy>3JJMBZ-5^!#(AP51APWCynOBBQr)-Rm(YKs?MBOjgM;0 z9dIJJ972;X-Gq-#ntWxxy;JO*Sjyfi0Ul#bgE))6x4@Va_nnowBWQ8v%7S_rq4&m41FVc7uA_ z80WT^@;U=f_LtSUp8RtyE%ofPo5v1`s<)D+Be(sxw21@;HI_jH-cTTscc{ifo;PvL zf)C}wC}pm(x;CjDLFLbqqbHF}m1_lZF&*y>XQCnsg-1c)HODM*E#3}ObCtTgDxHJh zY3H5Y>f&Q6W~Xy8;`El>`Uw7w7HX#?zbGsUs9lyv2)M}u4Qd11n;_A=@rkS=V3w-5 zM*wIbE`=aHAmw?QO;>#qLyjKJ zgZv?Cmu~>6mYoT8up;`Q;gVhK4#35R&8XKiR|A%`l%KhPpq2te+C70A@xxze|5F(3 ztSu+bgipN!zdT}5V#sH9qA@CT8o02%LdVCq*HyIS$UK!T$hIYwE!37Z33zagarKLT zM6hKOvsNFkfN)kksji+9Y>=Kd=C!KEQP8Ra8NBwoP?25Mqa5uFzAvTL3^xMC-{9a* z1yWi#0`!T2aC@ml3b(e0oB7ar`79A(0@u5fBL(lM_jjcjm0Ulmga{ld4Qx=|+4JB2 z!X-fx`!^o26XBK2JL>KUf^SjTq4N%PP|S80QoxUP`@Ej3GvzUSEHgSwmTe)bl< zSDKE#k{uwZe)8Yj*E&=;&vwtlG|Dv#)cLE{c7@N*%}sR5_hKf7V4DD0?5}BFd;_3A zs!sO>=uki1HsE#aQ3E{7U(@jMh$rpG;3CIMY3rpPn08i5eT+_OR9Q$3a0d}!9F4|9 zuvrQ_@A2%%)G1XO1#T$HC~Y^EOGf9hfvKqG1IOFyW|K_5O2XW-dVCT2@B|vP2pp;H zRy;71TQvRN!ck-wU z%Lu1&O?W7cya*H{#c{|kOGucRoAp}3pL4e2txvI`g<*%+t9?PZfcxjQet}s~%zb+a62u677m+e@$g}b!r zej}u0Fv0Yr1RKr~xSSg71meO&g8N3OiSI{Y!l#TlZ=G=M=(7PejmPe~Fgp+?!>mmu z25>i3OiA$`9~Z^smN!F*M|{5-#)V48J`QRcs3q~gWWNtX&{V`)5uD#b2FVQU@H)vi zC>=l8`!XX?x>?XCH!4ReQq*Zt*~vX-S#7r#60!cIFs@{9@jzfv)SlN|+VJ>&p^33F zGhy;-#0DyQ?3f|iD(1Za`x>h_vu8;#$^nH2vFRTc?5JG&=x8P-B2D0duN3o)PmK%j z7WL^C6R#r|w*KMiTzTLka`KUuA8v$MUW|?$VP@N_>FE(tJ|ooM8|n~1Ij z0C>6HL9N##I-u6Ns_H?1rCak4b$C$H{{(0;{vSVd9zD$TM%l7Cd$( zrTSbsrziC)ruvP-w4ZIpge)R0g0%zBRy>czegD19kx#?Di^yg5<>P`;9D+2>kBPP$WF4jKRmb4`Mhs&jq^Rd| z?2p@YA$W4OFlY&iil1ut{_&f0y*IJPXQSez+aqi$H_nIIz;s&H>g-H;*LFl51yt|1 z30gB&qcZFXZ(WFq zV5ZqxIkmb6-%xf#E&8}Z$$jo_$B*V7%){sNIpp}n?NU8-oaTWe7o&$4WZW@xZc*#j zvR+z?_MzlPz5CJ8Fik(%UcOtF=)W?QJ87q`Jv|-HvkKV;^c zUC{P@KGa4&stT}SZMrPiglJW%oR0?71BBP|9EV`mMvbGUrfmda1gBH80jk4%=tdIK zkZ6CEwjaM-*^Gnysu{#6>~lGx&lwo@0%={3)1Bwq-fX{AR)>i=cHdhpIo^|kVdFHr zsk?2^FRw>fG${95d+}04?#dM#G?gE$0o+`3zl(ufB$UhwpQ?>oz^pR+$0L+{e-w?= z@B7ux=!%V$$ni>oDq!h>>{on1?sb)Wc0rL7ryuqGou;OJQK^|nRws_A&2P1IMMgcR zhBPx}!0fcM6pjgbZwS(1nG_1{nd#{iw*}rP*}0H@8n;$7MGr^YA1{nqM(>`kRW%S% zj*^iMy|+&YuDM3q5|t?<$#Epb$QQ0)nejZT(lx1KgZKw+i%3?%DWIWAaM!*lf8P$s zVu^^f_+%7a|IU?yO8y*fw(No9uA_b0^OM4bXR#_@<%BE^0_IYUtR$7udItRVxmMRj>t9bN+`ITy_ z+-S}1@0xY z$2zXhaUZHiqi(L|m<}_>)NF&GE6e(m{WA=MtN`Y@CAafl>HcA~p;D*6i(Icc*|zMx zc|+1g3${=TQ&eRxz$PQFjK1_Gq{>hf&o(nzj3&+@(*}8i*fpW8Sx(IrVfrGeJxy9n z8J-w=nX@Cwc}LP%PJKCLE(=BjLW{y$W);h&6!J2MSW5qEI2D|-hj%t^K~jyj+bVB& zx#-P+FgdfLDhyGFI+&;&)HKbe5SVOy>Y^ZzNb+g8?A1#b1zEZ$#W84oXX&{KzOR6) z3b}F4&7CPqOS6*Wm6na7zWR!aFAo6j>l(sNp<(nP?cKd5#Ph<`^ z(^Ku!vs{f&4sUE!T6XZSek13%&24AtOAHg-s?%SLE?riKRdX0CwSBR1W<3a@oK2lm zv~1wRV;w2%5;-^9y%Bl>^nqH30-Sc1Q)6W+R1)3ux_B3(J_^8WbY|FD<_YNHn{tsE z5wB0y+A@+GS$EUuBK0g=gEvEVkhYu2{wfuwt-99h#jOrcm{uotIVfl=QbdU zO&iEK4Ai9{>)Ta(lA!k) z3s-HTLsQWJA;u4)E>tax1qbI;%2LGRiU%&j*HJB9^gis` z#xP~Oc{Km#=whS&Qb_S-*Pr4dy5?`}3=G`vtOvXgBtb;2LKro%@wN=sXsf**O`kTL zR$38dij`<$VTG-3DfDj=`I9>WxTShDaNRJ?~ z_Gd?+hBBqeP_dFnoH-Q<57Hn}=*OS&a}yGfi<$CVIH=4FS7xdKwP8Muxm~W3*#x?j zL-!$Uq;CSSmo~)7KHUJJ*tRdngADPpPG?7fYDLTd=jw-Vj+UK2dsV5X3dHnYs~HoS zhkZ#T5|9z&-p;hT1lduhxJCzM%9CV{&PeRy(`8pBWFOEmTrlqV)))CogOz7Lv$*Cp zl&ahxJ&+C|E90y!16r1 zCHUkLl3CvSN48d0mZG=vIPvC?IK7|r<9mJyp0op8Tt}y8ZSMs&{JZ38fyM(?=z~A) z`IDj(fh$KFF9-KGe zMPxuUqr#SLKud|UIP3X>Twl=|Bellobe{FeiIgTMot1uQq`R>A{GQhyC(IP;#9wfaNi!r z^|;j2)ccM`V?jM3VL6LHa^KN(o)kqya(zy8s9SX1j_?to=h^@lH=bJ!@>d)*v-#zt ztV_I!-ipc;1XuRxq4m?aoE8v>tt-_UQ@7KVd8OZjD<|SoYo4!3+0yhObR{V-lhWg# zHJCHRs;R1mC-*#oH-xJWVkMYw*VvBppANxZhaG#jJg|p8jj) z8Ja>uVfP=G(2%Fr8Kp0e7JJFM1ZB;L%0J^miY_(%=0}uS>jDg;lvv#&higsnui`w~ z5B75WRJKUMaX}oz!onho$hZ)Sv1lip9-%&bm8gzQ=u4kycNCn!!W?2@4TZC}?_i{6 z9}QnXA=REETRoNLyFOfcx5})n+oRwm?`ScdxH~u zRUL`c?7iWVTnI_|1>QAO9p@(L6u0;q7Lxhh^WpO`f))swj#_+}ANG8O{oX4y4&?U; z$U&$oTN3;{L(legE?_OTXH@h2~u=I-eE8})34MW|huxb8ga18SOg8=XF(eI8}HoK-N{}3oL01_FUZI zL$bzDLFinl~`{1!$!+xiG(hNylX_w8&Gm@E!K0zZR zT-)mG37+7Py-;jB;FDIr#4@t?lkZeb%_J>FZk72$a75Jqfsf+Y@N3d*SG=Fie=S<< zW9}?d9KD~$dD%+0JxwPxGh~_?6F2EON%OSRM*&D*gU{#6Y+;s_llF8?Flrh|Akuv0 zw++cHVyw$n3*Kxd9YQS+38M;Cbu=ilFQC|>t4t$}TE2Vh(pXT_xzk@=72I*WzD3BEQy1B3ZHY;#%u1(kVfW zRvxByxP6^G_QS@h&>I}e_DN-&208A6Pe#_dyIezS|M&uPOh-Wb_R*aGm9MTIw$a`VSUjVMJw|uC;1#3dB^ClTF6>Wny_UzfB%dina!h7!p&*RyT4#0n3e{Gk6!uq;Lsa6NuyG76^79M9>TWDfWLI zN!q_V?oV-a0x9UDhvh_(%1`ZLEQ((v2d+p}<#@RH+}t}FXDzU8Q?U$u+s2e)X%Byt zaDY&7!j?J3ONItQA%9{4Y?nT6ZWopfg*3DcA3xSrzDe| z4Sd2A;C^|{Zr2Anv-_1Pt zk=3Am=IWci#jo&c*EwoW^ny#w5e@3dUEB=40NBRa_1@WZ)PksL{c3hEq;H>ng z;M){`%ef+zurG!Cr@_5T&cDI==YZ(Vvc4y9um66@`hUKLL3=beAKssfN_hWlO!58q z(+4yEry761lJCC-U_a+Y#R{7KY(V6v$lqM-Sv>rv)GbH)roG_h1a^mDeUaGrX}#o| zo@42k&BQ0eFGh(vlG`4F}~`3 zU$iqveZ&BHQU^W%Y(!qi$sDkG1KZHzWWw|Jq?fi8Prn(yY2Q)2hOMuHzhI2J^d^7Z zI&%fX@X?T2jW;j099!GzmyKI_y_G~(#-H=Vu)92Wp0`;uB7VGa>dMn=cp?`yT`?Y9lm%|Ps8A=1(vNNTJDft+JEc0c{&ZxrzgzqhIqa`pk#>5QK{QKrWz_!<;Z z@*=SZ$_ah^K_Zcv)UMcLB|R00$oCGxDCvm&FR{Q+j}LgHx&Zyq%(0{H5{~=ndTE#N zsY+?8Y^33BFWr61tJFquD(V=2P{50BqoT)9#NgK3M8%-WfZmH={yBR&IBSGBSBa_s zPg(@%ZUE6F<8I_>_phroCsQC@0{D)Ah&nrJnoCvdF?qW0vfV@`;&^@vpx+{7+K$uW zWIDmqXky+eNcGN5$-DW;idB9A#j@1NHw}bM0f6)QI&b`B(+`@oNCgq3rP+WX9ZR8yiEVPxoKI5e(U(dmoJ|*z`u=>) zPLt9sKrOYbKHZ-U5VAkHPJ0EX=i#&ng~&wp93dtZ zplov3)=std$2>fkA2U}=QainCAmsinC{haIkRb5s{yW|`r)1OwDHvtlOo0@GrVqS# z2N=BKB~IPd@$}p^AaatqJfTzSCLB941K6U-lRFWM!tvyA8z63xoX577K*h~?dLnJ5ufj}lm$G}h%mXYYgKSV68s7m9p0 z&s|eafSYkxFCH>M^nU0?=r#CIP=pvJDy9txQ>FHlVPaeeZWCQ9TR+*I`C1%!*ZpvM z)U2qyd2`4zNMdLMbVM)+tb!4t;wUAue|6w=HGtf@c{w$+w6r~^(*5jc5oi!a9-+~u z`5+@8c(T<%B7*4{38=4j+sGfYi114E=Qjb8Q34CY`q2Udbe8$^p(YZ=r{~+4O?6#6 z)rC@pANjj1mD8mszXx(5D<+u~%p>l;R7AX6b>LOAPM_(6V2^AA;Hi4_d?FLZ zbZ`KH7I^&?6P_-Cb3oT9Z=@LQc;icD?|4vsU_WZzvKZ^K0hC?T$$sV81c%m{0~jpe zCam$>uhFMQ74#tm&an~+{0@U+0F;l}ES)SK(kWdp8H=$fo$X7Jqk6|9f2=oVA8Ag2 zDGLMq34TlKrTe~1$@>#7oAk9O?}7G9rc>urk(C0o;sLdTakqn{+*K` z1CW%ExKku?3NScWgnytUb^2sdfbfac(C~f6<4=(y9%s}p8|geKmsq!%mLq^p(U=5a zIE%{79M+dOb%cb36uKfPCDj0vi7KZt^U7?Fk>7z2EA7_#H$v2HU4Rl79Ow`gb_u1@ zAOUTECL%M}o~XKyKjrcMb_>mFSc++>g?@{_(9)DQN0lA6A9S4T%A-q*HiQn=3KwG> zbgSTr^9vo{2E&h!kHgjjvS^;7RXAypoNYQH;M0RZVbnBwthA@QZEH%5c)fTr#%8gD zZ*$xxTEIrf`M9@BWK+;?V}Ll4(>Ta**yuV!;w!>OcnXB_?9Xt?(gKpHvuifMh?ke2 z&(@$7teJQ}3?Pe5OtY+!BXHA9^?us~X=;Q-1uF{*6Y7v?J*OyXUOu3vX}+g(usM|L zB8#x8<)H-9V6|sp!KRdy%$yp{)m9*3K`Zm!Eiu0>PY+Y`Eq;;PUVh|AQiD(Jk@SDRhtQdgi5 z1SNbQEBowWbb#>w&*sej#uM;yV>lc(USr5!D()73A>sOm7l_Z9XRf>^&yIWYYHU3W z=6=*G&6+LbTBb)Fv|g}_98Ke-J^|u0-5v%@q3Ix;g4w#PDODChqoKA~}`Xg555fArQ228^ZLfPJzVyInQfo|A=$d;!e z8tA?`p$F8_`ctkG(k#^~gvk;f#KLp`AS4F|2TKl3R!%*HtrL!4N!ah%L#O%?v@wn| z088M%*;<%ZqNaMeIzobntCMKVa&tU)@^^}l51Y-hq=)si)oVKf^V_X_v@Wm1!aCqUk0`QfLwh7O&We)gxtGh~|hWbCAOQ+d!0Ni-BNW$$Yi7a?npM@qw;0bJFw2A; zwn1m{oAD~LKGG}Ki0=ez$V{#wU%uE}6~12<3SuCP6Ly}_(KI!OCpL@n2bLXmK>Pfs z#fdz^i?5;D4TDxr{HOMOG1i@3^O;By5&@RFum=KpJZjq3O%V}LuE!g#YMM^-1TB*X zG*3kl!8TerCtnMG8`EQfY%6mtmbYjc40+Hfb2&*Q)O1O!BqnCyq+{gFgeut5D(nwS#5+Jg$@E*HE8Lv+r2{#f&UzfmIs3icOnjjXkY^+(Fp^5#imYTAlILsgWBkE|>rR24nn z!O|FwH#9U$$-qJva;=f|hWh?&w;FHe#0 z$Naq^s;UwaH`^&by+jE?t6QJYxSeb}Ka^Ml_KnFuh|qU61sY==K#hpK{(*- z&ad};vc`>P%&c$&RSBT;1-oexDv1N^zI^7PV1leUG*ZblJ{&oP|2Q2h|G%vHEp#1mqG2x|CD)Hu_pda=Y?w zR6!H$H|;_dmOI^l^Lc;B+Fv#Ub`F>%CjdPm=W+U!0bTcp;K{}{_--sUwMoJau(+V-^Uf{D}n|Kr4%Iw{#QrhOcf&^qST3@jxkP&}NDERdZM$06TO3 z6bL&?QlOK7u*zJw*tz|b7sZUxpOK>P3lB86cH5_ie-!$>Gi*92_Zdub8z*mhm#a7> zBTyM4C+Wly>VzXfzg3qU9({9A)t3+hG{S84LsZqih$P+o6))xslwBi{v5dr28TmG- zL!0Jrzw#e?yet3Z?a}`Br&Oogy^?liuv9}Ve=*T^sYOpL2fSInHeT<{F*9{;uyx?F z3FQ4TjmJAjD#D#kuuu{Z89Jv^6_TXc1qRZnaSPSCdou+P47Iejvf#rURzEHc)7t3# zX5JVKa~}aTRIarZ0tu|60W}$bOyvTiSXw#-uNBY?ova<-X}7EyF)TDhW-%_|lBNLm zF2nV05w1Jr=g)_9;nAo2ljp$Ks@WI?c?QEsAkoLM)7#(Q&&O?u6>}UB6mK{O>vSP| zoT0jQG+v1UvCb>>=w52qtzTS2+Phze^GpkDr3ahlCsYYbSL=dCR?Egl3Za*-)^ zPcU|@g}`N9CV;t^yCn$dS32*1jb?4hyXwhWv6SGlS-!aYg#;z9p`wKWlazUW(;ZZW zgGXhu4n=!n&re~u3U0c^k_v6pteRt*+H;F;qj$8xk*?M%y}?>G1sl@gF^n`v@}BNV z?^Iuwa^ZpksPC)$&nSBuyM+5<8NQ|)vOiXHPwM&Hp5F5`;#|fQ^gCJ+)JHtL#Zwl(!jRpZ->cSf9ZD2GX`5egnO2AIzKNP$h6 zg9p@>oSY^K8fDPyAf}4|_(hC2P*~kg`k|)lWRM(P{nq#0Z)JIrY#${YbpZSo-u_79 zj9%IvFYH=51NOKD034%$&yTKjY@GIO>0$~Ccc)d;u^XUr7^Nq_#+zF9Qc~<0vC!cZ zFq0h?-+3Rm3NA+3eDIRdf52LEID@rJM;&L22Q^ng9Kq}x=|@`mm@GVXVq-O|zz@Kc zlQZ|E3U7Jhs4#XnQkoY9Vy=ACRGU^<0_I8h;nCuGha*|pzm#pz@sn&#EQ!-slQh~!JncquY*dG&Ub0pOGBMYmvUEF5(fMdd*M<4) zHhPzHBWFNMtVi>zKajG$BVQl>Oi>+UyU-Pz%QHZ1m5Pj(7g{g6lygwMw$nb~3phJk zKVp*~7Xte+;I(D7b^iSo+qT4>Zl5a9+)XV8+);LT8O6 zVY=_Jim|oZPa?^kjB_Q#8Yr-yGev523XH_=bC)p2Ec;gMup}`EymT5&8vO>!q)Ev| ztxqDC#FkA>KC2#8jTm7)KrmbKuWdCHyPGKc#cqxNuI}m9Of6Pn8?GKrRh~dJ2giDV zzzIUq|86?#Qn0d|@$a0VsBt6m{qTgM2g?#*NjNUfIM&AvjE*2eWf*q#otpE|rF~J{ z*DRnJc<8!ryB$o@T=zvQlUZ8PI8J$q-m@Ck^JNCCX%bpF!Re$QDWj5A-(sIm1GGBt z(s!|<>u$h0)u4uEq{!+c7RTURDw{{Z|Lc0XEz2{h4TE`XI4u(1eOkA8;IY4)8h#*G zwz^S?9&>7%4|4#k*m=n^SK6GHSQn@Hx308NR`tnYx*7L-0nPi#(cN#*7}uFEw0rH=>T6d1!DlW*Is$8D zv&N~hSh=Z{gJ!y)`V331$RJ#UT{0!mnMe8W#1I=zgPrN>t~;%?#|5{10Cyimzg9B^w=6vb7Jlk;eoxQB_@N?uazBLDQI$?w3`@TU z0ioWjL!1&DER}n`9A{?-Aa?VDIc3l*(xM{0DOKidTM}Wkq7^CNkW<48mw!t7Ny4&X zS#Q7RiKbZ5(^UA~b-7X%s$(}zZS_=^cE+5EF)$1}3~IosK-9oF6p$yv+2_IV%d>Wa zp}$d1D`PU7c*5h{ap*BgFa3&%$AZXN{t*c7L}yc;oo+hWEC?Q)?1DhzZeoC7!TcR9 ztTJ=F!pq18%6x{mVJjTpG`;=AlG@j-#XVthmn0&ri#;{BdO9=U{{n!P1bt zX^L@du;k=sAw|mrM1ch-kRn)o7{H$amqloL4}bx1C||$!Xo0fRzN+UZr*UtfFSSV= z>9}#9c8Yv#5D?DbCSG?Tu-aTP5em-xS~YMIlKnXM=6TtEpmD`bqJxb=bG`dSv@e%| z+E`Y0wrW=w9R<`-`C;!{?@u#5OU3TxC^El})_7m4l7{^;xJ}^o+uh7OlPBvAlj%HW zw>3cUX$a;~{b5jCqhCwm5hs-DCISy3A&}5Rhl^zC-X&w@K6Qt!Q8(B%$o#B0>SM(5 zsz^z}?G%&JqQ=oy1PPDIT|;B-tHYF}Q)LKv0$)^O3iq^6Ukt;okzBXm;-SJ|u)|o?^ z;A$@*^gu17sgr=6C7jt?ld44(BTOnBhDuzgf#?IT(~f+8pZlFV2t1{Po~1ZYsxByX z0!Y{_M{t{uA}iN+fI71A+B)bl!t--Kv^?_JgS~)h2(z0H0oEn*)6}`qGUrdan=2C7 zcqI@M<6EBlftZQw5tRZj<2C|s^acX2jj{#8s(Ab-Z?FaRzr>C2Oz`w?(jr&_vhXKe zAR4In|23;dH$HiJATOT0sH-Azgm;OzU z9KAQtWw^M?b7#J->fbEYe0zwKn~G;)y%IJ-r_lDBY56~io4+ZLe-l-~HBX(g(PVYP*)u0gv;7inh9#Q@9tac;hmfXuI7qtx3iKl>zVf7q%2Y4>XFogM>WM16)YMI%|4zcCq*)92CbaK$bRlul@NSl2>4ITu)8zlqb2 zfN7aRMAHHR-Ak5$!nvo{Wj{hD!o{gFjSy7O!%9A!$S-t_NSbD^s;!j1jA8$}94TukzwFLAwfpHo;Kaay zGhP45JESzM4Sl>#Y|895uw))P8N1ck=H~|jY}aThv3bPrx^@1y;*)IeT=$h7I!mF) zub1#cDN==aiRvi#eK}!q*DhP^NVc}@t3{TCqGN^WaMN4@^I);+3!xY17~{k7)4E`ggBA!j==9d}qgGjSkk=db1+k<1MX+ z+{6*z;*cc4C0@xKw-^+>?)~Pq>@iJcX4Dqu)cz(fY8z-lfj>(ro4dKjG!dp10sZD@ z!EO|olxf8UsmY5AG# z*=@C6!JicEc@)&_oY6qoeS)YhMRsBoS*6*YXg7ZK?!Q};%%X??9R z(9IplN~OQdin=*^)^}vudS!oT;cF)(!{wFk~>%+@%FT@W3l7~+zWkN~=pQpkk zD+tVzzWwT?M!F%e@^lJ=y?9<~cMn#hyna_wl=U;zncweh*&CtFG?{Pdk+ zK#ZQ| z8nH}651zI_D9s(&88{+&=4bk`cTg|3CeN#~H+-2f#_T1bK(||Qi z?DY^0hIYt&)9Sx?iO+?i7sJ5+j->bnCbfC(ODSd8HU{CNuO)A?`-{r>yD=5N3Q2u7 zhwYJ58WZ?0{)6B6Z%}~a^TIz!4aj_k#vj~)=lcPGL&KI0afDpDKov|~|Ff=@C+$D~ z-boa4(c2v_|Mv-3m@XdMbBFBd#q&YhX#Sm}N8ZDA|ARpId)dFwL#MUTLHSgcV~SCR z%CR+PKn>|jiqYQfUTdX*wMqSa{orN;XP9t1C-YEaXY5@A?6Y~c9CoG|*}iA{VZqd@ zhJ2UvrE?*W9e1d)Mr}bBldP#xYzLnZZ7g`+hWPZ|0Wvt=xOm?NQqnuF%U_M5U*^c! z{XCg;hJD65t$KS4_P(V10@kC%eAaEPb)AVJ;S2U_Eb5x}V5GkN0N8j>{$nuw1zlv0 zuwiFz@Mi#4O5pxeBZZO(RZl)rplS)qz3~@|@fS7&fErHa1h*~@lKi!D{zY1dj?Db~ z*8c~4@%L^2Kfp8op7PJdNCKf#?gYje_6A_{@5jD-`Ql*Re{Om2-$v#IxoCM?SN{Ka z!nH#gYQRj=pb`Hm_+{So5e`lOW2)sE^=GjwkPQK5c`_5myg~mUBQ;1 zuyNbify?0;L^1*yEp9E zM&P-lU(uU8(wiiqaf3XMBhQAZZ28D-2K(T_;oqwlZ7S)C9p}+Haj03!wz|+#`7hYJ z#dVa)V>;w=sjt;BlWunodyL3jG#o1baM@$DDD*Aa#UgZc@b#aj(#%RO`ea5c72rC^ z_h;76Nm?Lb49_omL@-y^m8mOOza68F z)4Fd9}_U3dKH$95KeDMnCh%$?M z0T%D#6u${GYvb=Wih2SWAthIJ&ve_P9c52ycN$3CrF-ai7GI+yoUkbT+Xtb4cJ zFu}XuPn0TJIHNr{Y6D3zLo#RDNJh?D*pDMO;U73b7oY8Btnsm1Cw{E7l5Q`qU&m`t z_FF-3>VpkAzctx}2X@${3arlmDuOWtypGsx3o9g@p4oBaQ7BTg`j%Zh^ZtTU#s1LSF zZd~GRGCg$N?r8t>k|DrlyLb_T|Mw%y{WlkHQGp=TAovzT9rlOk%v0IK;D24X+gC}a zl+-j60V*4-)A@hlcV7P6TZ1)m%Zhd`&}DIE!J@dsLRVEhBlRwJK=6J3g5?z6wm_~* zF$P@JRDpM+qy4|pb6xlU>ot7r1s?gAXo`y_1DyWE%i3>;e6U_ABpBe7vHv0RaerFW z)|LO)JLvpxwL2&O`wD_%Z;g$W0z@yiP|qD@6Vf-G{*&rI$*UfXE>drYb$G`ZMTDN_ z+KhdE5js%<8+x{(LJsQx#ABKhRQ9jl|1$#r~KsZBWuF@;?<<7)*n({(Af! zTS{D&;wAro`>O%sZ>P8S(*1CJahKpyAYA;|>V#SH;fPbt+|UtpgV2CvnzMSa0W97K=qFPG)r*t?}k zf0BhoCPUi3KKBnuA`yf5?_gX*^ zd~8kdziRvLu%?!7{U{0u2nVGoRY9bSNbjIhq#lr70*HV#0RbV@SWt?>K{}yHmEJ*G zKoO9VM2M6Cp@b4b5$P>~yMvzlJm2@-dwtz_@>9?}fA&wpZs$^al4FV!^0-SxE8Yk^UoYMkU-ZN5tKqdB5#gB^e8Gc~4K=B7%)^~9W$qy8Np(pP7b6CZ&(suMOtUcX zY^nw;uau_YM4#L%)oxqw*Evo8Bt5Xh`R~Z}pI!LBbp8Kc;8aI79l23Z?>phm0}=EI zf&&TYl=tiW-XdHt;(vBD@Apb{ABb%#fA6>MHLjtlRQp}3{Ga1cu-)&C#{p`azrC7( z8RECwNdU0rNvjqA?8W|#VPfzrmlJ{wl+X;dC-XqSZ$9Q16v+;5ye0O_R#g9i*eeGu z7ohObP7ko-O|D*(2GW3C97da8KK50PV?MS%cVeti{{3{-ys-O@d=hfvsgdW3!&T?g zCf>B!gs$N0Z?!c_c&ajrq_Zfv5?@)C$uru%75c|-SV607tY#V$nN^|UZ;KaoD$T1w&9)@u;M zzi$=%zptbJA8VjK0f!)_XO0OhzisB<7y$ehT!02GAbN^~a%OQV7vT+adb(-n6rdp7 zd1&P_*?*#W14|+fy81U4Z~=t=k|VjBCTbA>_`xAcQNr9UbNK?QWdOucWqHvi*>Xdu zu`O+(D@v&Z6CV%m)%Ix)x6p1Gc>>00ULYIdw73q1U9oC{Jg-!&lT$RhJBzh1uuLeK ztt@AP_4w;AZU^+gz)adaAl3yTT}Z3gh#GmxpJsGA46nE_L!j~6dTwk@L)Icx^GkW} zvIUr-{mTjc#APpUqRK$#f?@_(oGAvk}RSugylf zCLy3=z9oCeou&V_DAkGXnUfNw33&|pskw2fUJ6&6Q~GXIL* zKLwqVMU>+U?Ds;HkNfJCsN;Kl`zi;wC`$1Fu4lo!9h}$G;Ctf?n{Ukd-Km%E3`Z zd2^Lwj zKA7qv#pQ}VFzg6%Xi1)qr*v$|E{g~#y3c&v*_4#K70Tgs3YaJ7)26_ z${FGW+LFD5maLULH{7GWy=m;8qh;aQL7imzF(erF!{stGIwvCr!(PExfrUQkLr-jOo}*ZBswYxHHR?9aIImgwIJC^#`drGZ_;?C6UPWG&A!ZyOXj z=j@&eD98gZvH_anNXB_Axj@c*xPv|fr2`^!)L_1&H`k$wpMi_Tv*efw3LcHV@$KL$ z(C2Sb|InEoUeIpPwZ}l!PwiB|FN_1o9ufMOKqk>u#i-kX2V2j74b6XlLD%{MFe_-T zR6N9l>{$M8^u!DN4;SIHH0==bDZy_^vosbRrQKfub}`#5kn8y?b+UDLSB#tp8#C@c zFmlEGUu5|lM`bsw2z2VZ@7Ad$C`F|g;JYdvs5rmuD1f*}6q13eVy>((!;^7?*i^pYh||62~fH%mY!Jpmd<001mTDu!p5cE7@83aY%T zYb&d;MonO&QyCOO#cxE#$H!-80S%}c%t4g7VmHH!HZNA!3HP{q-WXR1Vug+f4H1GFmp7|5|~-kKLD2x>b&D9xPZ_QSwQ&W3 zz%Y-JskdDYuuHgiQ<@9#V_w#5cc-{~BUjzdntM6}dge}gnFXiJ z2|Y6%m{m^Zl(vjjc&gMY0W~a!Po9}(-jy&0vfw~@lPdQ1S9L?qX>gvIZdH1kc?dYX z6m;Pke_!V5?QShfpxu-u3#fc0sO8g4mhD~gjjszGhO{njYuiu$5Fz(su@T&r)5_5P zSqSi_YNLmH!%m<{68te-y%AWR7R&S~2Cjy~9b2e?vQY4%H^`JswFQ3YHq<&BU}Tj1 z8W3cb@8`pl@lrYoj=#|!UVi)745oGDZ$fVuKi6kR zfWNFw_S7WBBOmJOR4E-`!EE;)%PBq3Kax*BYExo6BWxA#={E{!HD)yGE4tyz_fXJe zF0a5a(6(f?jCgVM)2$LRno;#UFHzm27n4KA$1%EdoLGnW8^Y~Y+_;t=Pq)YY-GIaT z%OmYQTW77FZ|V?3G3^#5)#ni4E;KDh$%k-S>8cPQzvjKs)JqGmgGDwP3|4O_e;!|X z4=w~O$Lpb~CcI_xi~r=o;ZBz5(`P?;GS3^xYlW=F@R_)8m1s|TeQH_l0%{1(j^C>h z*(wVV`+4ZIP(tCQfT>1|}f{%c2e> zJa$ZXba@2VNWr@e597Xm;T*cou&UG^Cj5VVl%~DclMO{Kl-`QZv|KxA!cjFO7;>4O5^y8!GYUPM$pZq*Ur!CwH`BC>(jS{R zh_dfI2d7K2#dfQEKN+0*EDMOifuwqIn4H`g3G2?6#{JOu!QI00w{mh7m=Zs>wOyhI z*aqmGr-6Y7v+LsHkvFtqHnROj_@Hh_*!xN@Fjzy~yMUKG(<^g|{dcz{%hAV;U{8#^ z&T5+jVY!(wVB0jR;_r{|m{HXP0+4Bty3*R*+*~(_G_i${SgxXDCazyzqsU?bJ1TM= zPhqk1grXB8?|353kxBph*eA%!?MH4vbpxE9!mFXV!9r|t%tyJkg}Amhg@5r3{|vDI z7k}X)3F|!5#9dUDPAF_>yNZ;haQ@v3SV>8#TeDztLu;b9Au%wJjqbIKvok*g{LsR1 zlX(y@H3dlyI^^q)J)gt9z1bOif}%&vu{B;@ajpDmr@Vq*?0y)K%*Mj`Xs&ZN$06gP zoC*pj&srd2yIS4FRkJFNpA+_^qr+C7^?HTtg4TpkGHlkJ7QDdYz~C7p z;Q5?q>J{CFYqmY;RtxYRI`dOXRVAPaHOaC%Og_ZV!eL{mr@prxt-hggSr+-Z)=pSK zMX4c*AlGp80hv*{0r+YW*94AcLE{Bavq`(Sp63vRoHI+20-k=wHG%M$!i!Xz(!j*n zFknL&b9Nm2iSM3lNt`DuN+|9U2nxqsaYKjfBKo?fkT=!RS zbq_^vDzmsxUY*&%;m`=g#Fv_y8ZldVzqG?a;aKl-*7ftSLmxkz;!rL+N*Ng$AQ?G{ zxW5UT*Vli5>(Oix+Q)5dIL%bn3J-^QdsjKV+GARvrv`z7>@nM`#H@vqK%XIOV0_`Y zYwg#pFn4y3q>86Q?yo0~nVq#+6OLS&!d;aSy?h^|=*xWP;PmZb$ zsm__}%cXGs+4TTPHb>5gH6Oq|a^qIjH;8<`BkW;fB(P1ASWY8pdwG0!%_IiF!uHh9 zkD0G^JxUi=c$tT!@q+{$Jo{3w9CDE0Se6*(78sWLn5zW5^i!xE63u`vpx`9@aJlu_ zC*2>T&9#<%<~Y4aMYulFYwySeG38+jQ=jDGGq@hI~C>d4yE?(VL7lZ?+hq5O_d zSDd1)S%o7%JDC{3Wn=3yl@t}N!8V;T!W&N~0zT^U`%XY3%QWX3T~+&8(GDh6d&T{i zqpb_|?jG`H9Ko9v6qH)w@Eh#X>t?Q2wUEGXxR%(&?ljF=Z%k=zU)8%u<90VA5Lgw( zeh+cDL&vqWt>uvlysx=aXT^;{MBbxi64s`)F)h^a@rvS3tvvP6`WwsxrFl|#PQbm+ zojvVtdqutFSeDKN*UXd)qJrbHE@2!q{J*+L^0xf z!8G3N3k%nWFXMe*;#0tW9Wk8_R$_g(eqO0I%{(UVOWZc==U#oIUY>ieu+T(Nc$`J; z@%3VLdO(jpjDtBvapyLfR&g+vzOMB3&b?rt``Zy;OSsx0TtSQt5jms^>}TiWLoJye zoWj0><5%4m3jNv>Qm)y__uyLU^;$FZ1zo2@A-25PxYbfKx%gKc@NMEX}9>svf3HnqpPW;JfolDZ?~ z=tL&L6vdGu3QCzz7>Gw<1JA}9+j5&^5APKp~kzO8%&(DS&rg00$ki& zJf7V~>;7jdg|syJs)A)97QhinMQP5dDDSlWTW6>D>hHP-oo_EJM0wICn&iC=kUl?W zp&c@isd8v;YKY=lUWh;MSQJg{sXkUNre_!5lvUr_8`Nn0n6|n>B)S-FzvV{Wk85nv z`?Hl%Nb1mAve$X|K8d5dGMGztH8hytR^Pw@vxl@z&*-#=XkV2ph}AdP3}@`@Rm{RO z7-|_DTO=seYvwLRbJA)=l*L%BI82=VFh+j=v?6Co^p^NrBUs5D!#Y=BP9VzZ_2YI* z#?pZ=L$w=44>TC%(Z7k~1XFkse{M;(LbGnLkEDlnWruja#0JZcjOTdA^|}BEGt85! zK8Vd%WrYWHd@gH^Zz!o*rVTq>oM;QSF$tmMxz)*;Aaph(5Bv!Y!Qnrix*uLr9kls~ zX<)H?)&V0YJzupXh^hI`3}in$4r-c~jOe06Gk1BUn9nWu+acA3dgzT%c*2*6?s*N? zyi12o!UOL{9}E#>Xpn8_FOQ58hn&Z`B@!6A3*nzk%f^OC6xSjYSSRJM*D2`lJ&qII6Hf7!*XgSo}xz~w(ow7;Jgx0DQxNh;r ziN5b+m%ZQ`y>2L1etky5>mo@j;|fy~tW9&4i%+9%kx5CKv6PZdw@N`jr#XO4>VyvT z)wh??+uIes5RT+U!{SuLt^Ln|uCGx0do>RlEe(zzyH;?4kTHd{TLmGRHO5^nZOzel zWikmgS#2ax!K{qgsetrXZ*Bx#Z)q`pp=H)6V8Bp>RE}1tlN}vXnSwKW2K~g-W(AVs zry)j%qE1J0!b1Hff`^-h28=t!#ZC|Fn~f{Vb60G|A+AlX=2*tLLH9W3Fyfw}vR|;b zH^jTj7u1yO%Ye&B97>^IjdNWbj^T=h4T~gr?p{*4rXnWvEv14)^eSMPG^T z9l5tCF1HU|VK9GSY%dLFA(Ka#KL(Wi7xSs6)>h0U?ck^l{xgsrG*O& zYAlG>e52ixVWn5c{y>PnworDN362=*iZN?uQMt=&`}#BdV|_l&UK5ic#^7!mb@ zrNz#2lhjSc@cogFcVo7C9FGqc@;3JIl5a3quz4ThO+v!^1gB4EV4{8BQu%Bme`ScL zBu$bzNG8axTl8%q6{!7c8md*VxL{uPBf)jkeqjS1$a&8?deYjqJKser5U{Q+c)y~a z+z3>}2Kf5N?$l5nsiWhLHHd+CgpP9lXL)RFbIU_)!x0Lj=Klh^V%mU5gcj;m*PZK@6{k0Wc3 z&9<=P!eLOo3uPwPIj+!=0C9J%QzbQjGIT^n{#=4K(x%4&~Pc7#C$@Z-vX?3+DBt-c5 z6|v1p!+q&{|2GG9tQ>pUQ$#Q8_40`?OZBbe#e_Ybw@I!m9+xsV2@3^U1oDTD@1)M&YD*(Rhx9V$$JamJcIj|bE$kMBB-=4EY zN+|>cu|XTO-{@RiDPW-R{8l+am+lxXwzhPQ(isE%5Zl|!cglu#^Fk{;0kWpGiS*3> zBjLy3no~v=J7)Yt3mQb^S6YCz)%#;zt*pJ4>C(#t&N_2G9O$0&pfy!2hIigU0=P8W zQaHZeRef!)>Ab5b>2X`5p6Tu>QdUjKkJDIzVI<1Bf;!zV^;r#b{&eZA>raJA(sd@z zdYvvxkey+7Nc3*irADCxr@B}T7{Pzn!8Rn_hH5${s=crNJA@L+miWA8UR-v(!F+T+ z?2kjD9srih%ebQ(!WUtF??M5tZGOra|+AlyI{y zx0yV$>b5#U>>NvJ?MoY+b{6$}iJU|YZja0D*KUsNoAJ-+UZMnW`~5<#amhoE)X)Y3 zF<5tgY9;rym%sY-V+pUMIwP7;iQ_Fgt9mC#dw{^8mQvtflRa=!&~2*=ezY$$eoW&v zTuD9guoWTUHS8o9ARm_RbOHGiC_BoqjV3rjJPQf_Zilu<2<4j~8KKkugN*W4fFjG9 z?>HkIToKpOMbpj6Fmy!&9p^8De7Q|o=sLLyK^Q445{UzVVr+%lxrZ17x3@%rS72S! z?mO-&%KYiAQ`><_S^z0D?v{kM)b=0OoN~t#8j{Mphl}yN6hG_zuwCPBQWVa9ZX*~L zQBSs4_+(49+dzL=PFs}lAqwW_yOxVGLSe3LrW2{H5Xt~5_32U=UAmN3-uTMQ#!YL7 z?$N^dq06uY;_hSN25FA+aKe4n?d{#|Hn9T6510Qyl&-I7awWzCA^C4N`}dqAX# z&TtwGkpl?cY#UDptL2eam|xZ8!*H8|DGH%ur$Z?k-|<{~$5qGa(tIPY7tGReVs8Bk z%Tpd&fM}#@47HJmM+;`c>h6>~1HjBBgmoMPQ}y_m_xt)hKt)iJ0SpCbkbB7sGmzj0 Q+yUKF*S}kS+wS>)07BGVmjD0& literal 0 HcmV?d00001 diff --git a/frontend/assets/styles.css b/frontend/assets/styles.css index de425a1..081337e 100644 --- a/frontend/assets/styles.css +++ b/frontend/assets/styles.css @@ -35,6 +35,19 @@ --err-ink: #fca5a5; /* 9.3:1 on --err-bg */ --err-line: #ef4444; /* 4.6:1 on --err-bg (UI boundary, not text) */ + /* Scrollbar tokens (phase 116, task 01) — the document modal's raw + code block scrolls horizontally (locked A1: code never wraps), so + its scrollbar must match the theme instead of the browser-native + light bar. Like the derived state colors above, COMPUTED in :root + from the identity palette via color-mix(): NOT stored, NOT + tab-controlled, NOT in BUILTIN_COLORS (theming.py) — every saved + theme repaints them. Muted thumb on a near-code-background track + (the .doc-raw background is --surface); the thumb holds >= 3:1 + non-text contrast against the track (WCAG 2.1 AA — 3.7:1 at the + built-in palette). */ + --scrollbar-thumb: color-mix(in srgb, var(--ink-soft) 60%, var(--surface)); + --scrollbar-track: color-mix(in srgb, var(--surface) 75%, var(--bg)); + --radius: 10px; --radius-sm: 6px; --shadow: 0 1px 2px rgb(0 0 0 / 0.30), 0 4px 16px rgb(0 0 0 / 0.35); @@ -4330,6 +4343,26 @@ details.thinking .thinking-text ul { margin: 0 0 0.5rem; } overflow: auto; padding: 1rem 1.25rem 1.5rem; } +/* Themed horizontal scrollbar for the modal's raw code block (phase 116, + task 01): the .doc-raw pre already owns its overflow (its own + `overflow-x: auto` + `white-space: pre` — locked A1, code never + wraps), so the native light-gray bar a long line reveals is the pre's + own. Both engine families are themed, scoped to THIS modal only (no + global scrollbar restyle — the TODO's scope): scrollbar-color / -width + for Firefox, the ::-webkit-scrollbar pseudos for Chromium (height 8px + = the horizontal bar; the pre does not scroll vertically). The tokens + follow the saved theme via the :root color-mix derivation; the muted + thumb keeps >= 3:1 non-text contrast on the near-surface track. */ +.doc-modal .doc-raw { + scrollbar-width: thin; + scrollbar-color: var(--scrollbar-thumb) var(--scrollbar-track); +} +.doc-modal .doc-raw::-webkit-scrollbar { height: 8px; } +.doc-modal .doc-raw::-webkit-scrollbar-track { background: var(--scrollbar-track); } +.doc-modal .doc-raw::-webkit-scrollbar-thumb { + background: var(--scrollbar-thumb); + border-radius: 4px; +} .doc-modal-loading { margin: 1.5rem auto; text-align: center; color: var(--ink-soft); } /* No motion under reduced motion (same pattern as the phase-25 layers). */ diff --git a/tests/e2e/test_document_viewer.py b/tests/e2e/test_document_viewer.py index 348b890..9d94b7b 100644 --- a/tests/e2e/test_document_viewer.py +++ b/tests/e2e/test_document_viewer.py @@ -29,6 +29,10 @@ Test → story mapping (Playwright Mapping Rule): inner content). 7. ``test_modal_theme_and_no_cdn`` — dark page background, the panel on the Phase-08 surface colour, every asset same-origin or ``data:``. +8. ``test_raw_code_block_themed_scrollbar`` — phase 116: the raw code + block (``pre.doc-raw``) overflows horizontally, a scroll action moves + it, the themed scrollbar tokens are in effect via computed style, and + a screenshot records the themed (not native light-gray) bar. """ from __future__ import annotations @@ -51,6 +55,7 @@ from e2e.auth_helpers import login REPO = Path(__file__).resolve().parents[2] FIXTURES = REPO / "tests" / "fixtures" / "docs" +SCREENSHOTS = REPO / ".agents" / "screenshots" # house convention for visual records QUESTION = "How is my Kubernetes cluster set up?" @@ -119,6 +124,33 @@ def _drill(page: Page, *names: str) -> None: page.click(f'#folders-tbody a.folder-link:text-is("{name}")') +def _seed_long_line_doc() -> None: + """Seed the synthetic phase-116 fixture (see the test docstring): + a non-markdown doc whose one long line is deliberately longer than + the modal width — the shape of the TODO's quest .pl ``quest::say`` + line. Direct DB seed, the ``test_modal_xss_safe`` pattern (the + viewer is database-only; no chunks needed).""" + long_line = "quest::say(\"" + ("the quick brown fox jumps over the lazy dog " * 20) + "\")" + with SessionLocal() as db: + db.add( + Document( + source="docs", + path="notes/long-line.txt", + full_path="/tmp/long-line.txt", + title="Long Line Fixture", + content=( + "# long-line-fixture: the line below is deliberately\n" + "# longer than the document modal's width (phase 116).\n" + + long_line + + "\n" + ), + content_hash="e" * 64, + indexed_at=datetime.now(UTC), + ) + ) + db.commit() + + # --------------------------------------------------------------------------- # 1. Chat source chip → SAME-PAGE modal (no new tab) # --------------------------------------------------------------------------- @@ -456,3 +488,112 @@ def test_modal_theme_and_no_cdn( assert refs, "expected local asset references on the chat page" for ref in refs: assert ref.startswith(app_url) or ref.startswith("data:"), f"non-local: {ref}" + + +# --------------------------------------------------------------------------- +# 8. Phase 116: the raw code block scrolls horizontally with a themed +# scrollbar (task 01's scoped rules) — never the native light-gray bar +# --------------------------------------------------------------------------- + + +def test_raw_code_block_themed_scrollbar( + page: Page, app_url: str, mock_llm: int, db_ready: None +) -> None: + """The modal's ``pre.doc-raw`` overflows horizontally, a horizontal + scroll action actually moves it, and task 01's themed scrollbar rules + are in effect (the screenshot is the visual record of the themed bar). + + Document choice (the task says to check the fixture KB first): no + fixture doc qualifies — the longest RAW (non-markdown) fixture line is + 91 chars (``homelab/networking/static-dns.json``) ≈ 742px at the + 0.85rem mono font, well inside the ≈1058px pre client width at the + 1280px fixture viewport (panel 1100px − content padding − pre border). + So this test seeds a synthetic doc instead (the + ``test_modal_xss_safe`` direct-seed pattern): one ≈935-char + ``quest::say(...)`` line — the shape of the TODO's observed quest + .pl line — which guarantees real horizontal overflow. + + Screenshot note: headless Chromium paints NO scrollbars at all + (frame UI is omitted — verified on Chromium 151), so the suite's + screenshot (``doc_modal_scrollbar_1280.png``) is the record of the + scrolled modal state (long line mid-content = overflow + working + scroll, no native bar); the themed bar itself is asserted via + computed style here and recorded in the headed capture + ``doc_modal_scrollbar_themed_1280.png`` (phase 116, task 02). + """ + _reset_db(mock_llm, seed=True) + _seed_long_line_doc() + + login(page, app_url) + _drill(page, "docs", "notes") + row = page.locator("#docs-tbody tr", has_text="long-line.txt") + expect(row).to_have_count(1) + row.locator("td:nth-child(2) a.doc-link").click() + + expect(page.locator(".doc-modal")).to_be_visible() + expect(page.locator("#doc-modal-title")).to_have_text("Long Line Fixture") + pre = page.locator("#doc-modal-content pre.doc-raw") + expect(pre).to_have_count(1) + + # The overflow is real: the long line makes the content wider than the + # box (no line-wrap — locked A1, phase 116). + dims = pre.evaluate("el => ({sw: el.scrollWidth, cw: el.clientWidth})") + assert dims["sw"] > dims["cw"], f"no horizontal overflow: {dims}" + + # The overflow is SCROLLED, not clipped: the element owns its + # overflow-x (task 01's comment in styles.css) and the themed rules + # are in effect — scrollbar-width: thin + scrollbar-color as a + # two-colour pair (the ::-webkit-scrollbar pseudos are not exposed via + # computed style; that half is the screenshot's job). + themed = page.evaluate( + """() => { + const el = document.querySelector('#doc-modal-content pre.doc-raw'); + const cs = getComputedStyle(el); + const probe = (name) => { + const s = document.createElement('span'); + const hidden = 'position:absolute;visibility:hidden;'; + s.style.cssText = hidden + 'background:var(' + name + ')'; + document.body.appendChild(s); + const bg = getComputedStyle(s).backgroundColor; + s.remove(); + return bg; + }; + return { + overflowX: cs.overflowX, + width: cs.scrollbarWidth, + color: cs.scrollbarColor, + thumb: probe('--scrollbar-thumb'), + track: probe('--scrollbar-track'), + }; + }""" + ) + assert themed["overflowX"] == "auto", f"overflow-x is {themed['overflowX']}, not auto" + assert themed["width"] == "thin", f"scrollbar-width is {themed['width']}, not thin" + # The tokens are color-mix() derivations, so Chromium serializes the + # used values as color(srgb …) (plain rgb(…) or #hex also accepted). + colors = re.findall( + r"#[0-9a-fA-F]{3,8}\b|rgb\([^)]*\)|color\([^)]*\)", themed["color"] + ) + assert len(colors) == 2, f"scrollbar-color {themed['color']!r} is not a two-colour pair" + assert colors[0] == themed["thumb"], ( + f"scrollbar thumb {colors[0]} is not the theme's --scrollbar-thumb {themed['thumb']}" + ) + assert colors[1] == themed["track"], ( + f"scrollbar track {colors[1]} is not the theme's --scrollbar-track {themed['track']}" + ) + + # A horizontal scroll action actually moves it (no clipping — the + # rest of the line is reachable). The pre is freshly rendered, so + # scrollLeft starts at 0. + before = pre.evaluate("el => el.scrollLeft") + assert before == 0, f"expected scrollLeft 0 before the action, got {before}" + pre.evaluate("el => el.scrollBy({left: 300, behavior: 'instant'})") + after = pre.evaluate("el => el.scrollLeft") + assert after > 250, f"scrollBy(300) only moved to {after}" + + # Visual record (house convention): the bar at the pre's bottom is the + # themed one — scroll to mid-content so the thumb sits mid-track. + pre.evaluate("el => el.scrollTo({left: el.scrollWidth / 2, behavior: 'instant'})") + shot = SCREENSHOTS / "doc_modal_scrollbar_1280.png" + page.screenshot(path=str(shot)) + assert shot.exists() and shot.stat().st_size > 0