From 02267d0306403614450d7afd48ec892939f7cdcd Mon Sep 17 00:00:00 2001 From: lekss361 Date: Thu, 21 May 2026 00:25:39 +0300 Subject: [PATCH] =?UTF-8?q?feat:=20add=20tradein-mvp=20subproject=20(Trade?= =?UTF-8?q?-In=20Estimator=20=D0=BF=D0=BE=D0=B4=20/trade-in)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - FastAPI backend: PostGIS estimator + 3 scrapers (Avito/Cian/Yandex) - Next.js 15 frontend: tradein.html mockup design, basePath=/trade-in - WeasyPrint PDF (Брусника-style 4-page report) - Address autocomplete с typo-tolerance + 6 EKB presets - Изолированный docker stack gendesign-tradein (отдельная postgres БД) - Caddy inline routes: gendsgn.ru/trade-in/* и /trade-in/api/v1/* - Forgejo Actions: .forgejo/workflows/deploy-tradein.yml (shell-based GHCR login) - Триггер только по paths: tradein-mvp/** (не пересекается с deploy.yml) - Образы: ghcr.io/lekss361/gendesign-tradein-{backend,frontend}:latest Первый запуск на сервере (вручную, один раз): - создать /opt/gendesign/tradein-mvp/.env.runtime (postgres pwd, contact email) - docker network create gendesign_shared (если нет) - docker compose -p gendesign-tradein up -d - docker compose -p gendesign exec caddy caddy reload --- .forgejo/workflows/deploy-tradein.yml | 192 +++ Caddyfile | 18 + tradein-mvp/.env.example | 17 + tradein-mvp/.gitignore | 50 + tradein-mvp/DEPLOY.md | 147 +++ tradein-mvp/Makefile | 63 + tradein-mvp/README.md | 196 +++ tradein-mvp/backend/.dockerignore | 13 + tradein-mvp/backend/Dockerfile | 56 + tradein-mvp/backend/app/__init__.py | 0 tradein-mvp/backend/app/api/__init__.py | 0 tradein-mvp/backend/app/api/v1/__init__.py | 0 tradein-mvp/backend/app/api/v1/admin.py | 151 +++ tradein-mvp/backend/app/api/v1/brand.py | 22 + tradein-mvp/backend/app/api/v1/geocode.py | 70 ++ tradein-mvp/backend/app/api/v1/trade_in.py | 411 +++++++ tradein-mvp/backend/app/core/__init__.py | 0 tradein-mvp/backend/app/core/config.py | 22 + tradein-mvp/backend/app/core/db.py | 21 + tradein-mvp/backend/app/main.py | 45 + tradein-mvp/backend/app/schemas/__init__.py | 0 tradein-mvp/backend/app/schemas/trade_in.py | 62 + tradein-mvp/backend/app/services/__init__.py | 0 tradein-mvp/backend/app/services/brand.py | 66 + tradein-mvp/backend/app/services/estimator.py | 462 +++++++ .../app/services/exporters/__init__.py | 0 .../app/services/exporters/trade_in_pdf.py | 979 +++++++++++++++ tradein-mvp/backend/app/services/geocoder.py | 535 ++++++++ .../backend/app/services/scrapers/__init__.py | 0 .../backend/app/services/scrapers/avito.py | 409 +++++++ .../backend/app/services/scrapers/base.py | 271 ++++ .../backend/app/services/scrapers/cian.py | 473 +++++++ .../app/services/scrapers/yandex_realty.py | 290 +++++ .../data/sql/001_trade_in_estimates.sql | 43 + .../backend/data/sql/002_core_tables.sql | 234 ++++ .../backend/data/sql/003_seed_listings.sql | 147 +++ .../sql/004_extend_trade_in_estimates.sql | 19 + tradein-mvp/backend/pyproject.toml | 38 + tradein-mvp/deploy/Caddyfile | 29 + tradein-mvp/deploy/Caddyfile.tradein-fragment | 28 + tradein-mvp/deploy/cron-scrape.sh | 79 ++ tradein-mvp/docker-compose.prod.yml | 75 ++ tradein-mvp/docker-compose.yml | 88 ++ .../docs/BRUSNIKA_REFERENCE_EKB-2485.pdf | Bin 0 -> 255846 bytes .../docs/PTITSA_MEETING_2026-05-19.pdf | Bin 0 -> 134301 bytes tradein-mvp/docs/README.md | 35 + tradein-mvp/docs/ROADMAP.md | 439 +++++++ tradein-mvp/docs/sample-prinzip.pdf | Bin 0 -> 18597 bytes tradein-mvp/docs/sample-report.pdf | Bin 0 -> 36197 bytes tradein-mvp/frontend/.dockerignore | 7 + tradein-mvp/frontend/Dockerfile | 41 + tradein-mvp/frontend/next.config.ts | 37 + tradein-mvp/frontend/package.json | 26 + tradein-mvp/frontend/src/app/globals.css | 90 ++ tradein-mvp/frontend/src/app/layout.tsx | 23 + tradein-mvp/frontend/src/app/page.tsx | 5 + tradein-mvp/frontend/src/app/providers.tsx | 19 + .../frontend/src/app/trade-in/page.tsx | 190 +++ .../src/components/trade-in/AddressInput.tsx | 265 ++++ .../src/components/trade-in/DealsCard.tsx | 187 +++ .../src/components/trade-in/EstimateForm.tsx | 350 ++++++ .../src/components/trade-in/HeroSummary.tsx | 255 ++++ .../src/components/trade-in/ListingsCard.tsx | 292 +++++ .../src/components/trade-in/OfferCard.tsx | 192 +++ .../src/components/trade-in/PriceRangeBar.tsx | 78 ++ .../components/trade-in/SourcesProgress.tsx | 208 ++++ .../src/components/trade-in/TestPresets.tsx | 185 +++ .../src/components/trade-in/trade-in.css | 1090 +++++++++++++++++ tradein-mvp/frontend/src/lib/api.ts | 92 ++ tradein-mvp/frontend/src/lib/sessionId.ts | 35 + tradein-mvp/frontend/src/lib/trade-in-api.ts | 39 + tradein-mvp/frontend/src/types/trade-in.ts | 63 + tradein-mvp/frontend/tsconfig.json | 23 + 73 files changed, 10087 insertions(+) create mode 100644 .forgejo/workflows/deploy-tradein.yml create mode 100644 tradein-mvp/.env.example create mode 100644 tradein-mvp/.gitignore create mode 100644 tradein-mvp/DEPLOY.md create mode 100644 tradein-mvp/Makefile create mode 100644 tradein-mvp/README.md create mode 100644 tradein-mvp/backend/.dockerignore create mode 100644 tradein-mvp/backend/Dockerfile create mode 100644 tradein-mvp/backend/app/__init__.py create mode 100644 tradein-mvp/backend/app/api/__init__.py create mode 100644 tradein-mvp/backend/app/api/v1/__init__.py create mode 100644 tradein-mvp/backend/app/api/v1/admin.py create mode 100644 tradein-mvp/backend/app/api/v1/brand.py create mode 100644 tradein-mvp/backend/app/api/v1/geocode.py create mode 100644 tradein-mvp/backend/app/api/v1/trade_in.py create mode 100644 tradein-mvp/backend/app/core/__init__.py create mode 100644 tradein-mvp/backend/app/core/config.py create mode 100644 tradein-mvp/backend/app/core/db.py create mode 100644 tradein-mvp/backend/app/main.py create mode 100644 tradein-mvp/backend/app/schemas/__init__.py create mode 100644 tradein-mvp/backend/app/schemas/trade_in.py create mode 100644 tradein-mvp/backend/app/services/__init__.py create mode 100644 tradein-mvp/backend/app/services/brand.py create mode 100644 tradein-mvp/backend/app/services/estimator.py create mode 100644 tradein-mvp/backend/app/services/exporters/__init__.py create mode 100644 tradein-mvp/backend/app/services/exporters/trade_in_pdf.py create mode 100644 tradein-mvp/backend/app/services/geocoder.py create mode 100644 tradein-mvp/backend/app/services/scrapers/__init__.py create mode 100644 tradein-mvp/backend/app/services/scrapers/avito.py create mode 100644 tradein-mvp/backend/app/services/scrapers/base.py create mode 100644 tradein-mvp/backend/app/services/scrapers/cian.py create mode 100644 tradein-mvp/backend/app/services/scrapers/yandex_realty.py create mode 100644 tradein-mvp/backend/data/sql/001_trade_in_estimates.sql create mode 100644 tradein-mvp/backend/data/sql/002_core_tables.sql create mode 100644 tradein-mvp/backend/data/sql/003_seed_listings.sql create mode 100644 tradein-mvp/backend/data/sql/004_extend_trade_in_estimates.sql create mode 100644 tradein-mvp/backend/pyproject.toml create mode 100644 tradein-mvp/deploy/Caddyfile create mode 100644 tradein-mvp/deploy/Caddyfile.tradein-fragment create mode 100644 tradein-mvp/deploy/cron-scrape.sh create mode 100644 tradein-mvp/docker-compose.prod.yml create mode 100644 tradein-mvp/docker-compose.yml create mode 100644 tradein-mvp/docs/BRUSNIKA_REFERENCE_EKB-2485.pdf create mode 100644 tradein-mvp/docs/PTITSA_MEETING_2026-05-19.pdf create mode 100644 tradein-mvp/docs/README.md create mode 100644 tradein-mvp/docs/ROADMAP.md create mode 100644 tradein-mvp/docs/sample-prinzip.pdf create mode 100644 tradein-mvp/docs/sample-report.pdf create mode 100644 tradein-mvp/frontend/.dockerignore create mode 100644 tradein-mvp/frontend/Dockerfile create mode 100644 tradein-mvp/frontend/next.config.ts create mode 100644 tradein-mvp/frontend/package.json create mode 100644 tradein-mvp/frontend/src/app/globals.css create mode 100644 tradein-mvp/frontend/src/app/layout.tsx create mode 100644 tradein-mvp/frontend/src/app/page.tsx create mode 100644 tradein-mvp/frontend/src/app/providers.tsx create mode 100644 tradein-mvp/frontend/src/app/trade-in/page.tsx create mode 100644 tradein-mvp/frontend/src/components/trade-in/AddressInput.tsx create mode 100644 tradein-mvp/frontend/src/components/trade-in/DealsCard.tsx create mode 100644 tradein-mvp/frontend/src/components/trade-in/EstimateForm.tsx create mode 100644 tradein-mvp/frontend/src/components/trade-in/HeroSummary.tsx create mode 100644 tradein-mvp/frontend/src/components/trade-in/ListingsCard.tsx create mode 100644 tradein-mvp/frontend/src/components/trade-in/OfferCard.tsx create mode 100644 tradein-mvp/frontend/src/components/trade-in/PriceRangeBar.tsx create mode 100644 tradein-mvp/frontend/src/components/trade-in/SourcesProgress.tsx create mode 100644 tradein-mvp/frontend/src/components/trade-in/TestPresets.tsx create mode 100644 tradein-mvp/frontend/src/components/trade-in/trade-in.css create mode 100644 tradein-mvp/frontend/src/lib/api.ts create mode 100644 tradein-mvp/frontend/src/lib/sessionId.ts create mode 100644 tradein-mvp/frontend/src/lib/trade-in-api.ts create mode 100644 tradein-mvp/frontend/src/types/trade-in.ts create mode 100644 tradein-mvp/frontend/tsconfig.json diff --git a/.forgejo/workflows/deploy-tradein.yml b/.forgejo/workflows/deploy-tradein.yml new file mode 100644 index 00000000..c0917abc --- /dev/null +++ b/.forgejo/workflows/deploy-tradein.yml @@ -0,0 +1,192 @@ +name: Deploy Trade-In + +# Forgejo Actions — отдельный pipeline для подпроекта tradein-mvp/. +# Триггерится только на изменения внутри tradein-mvp/ (или этого workflow), +# не пересекается с основным deploy.yml. +on: + push: + branches: [main] + paths: + - "tradein-mvp/**" + - ".forgejo/workflows/deploy-tradein.yml" + workflow_dispatch: + +concurrency: + group: deploy-tradein-prod + cancel-in-progress: false + +env: + IMAGE_BACKEND: ghcr.io/lekss361/gendesign-tradein-backend + IMAGE_FRONTEND: ghcr.io/lekss361/gendesign-tradein-frontend + +jobs: + changes: + runs-on: ubuntu-latest + outputs: + backend: ${{ steps.filter.outputs.backend }} + frontend: ${{ steps.filter.outputs.frontend }} + infra: ${{ steps.filter.outputs.infra }} + steps: + - uses: actions/checkout@v4 + - uses: dorny/paths-filter@v3 + id: filter + with: + filters: | + backend: + - 'tradein-mvp/backend/**' + frontend: + - 'tradein-mvp/frontend/**' + infra: + - 'tradein-mvp/docker-compose.prod.yml' + - 'tradein-mvp/deploy/**' + - '.forgejo/workflows/deploy-tradein.yml' + + build-backend: + runs-on: ubuntu-latest + needs: changes + if: | + needs.changes.outputs.backend == 'true' || + needs.changes.outputs.infra == 'true' || + github.event_name == 'workflow_dispatch' + steps: + - uses: actions/checkout@v4 + + - name: Login to GHCR (shell-based — docker/login-action@v3 unreliable под Forgejo Actions) + env: + GHCR_PAT: ${{ secrets.GHCR_PAT }} + run: | + echo "$GHCR_PAT" | docker login ghcr.io -u lekss361 --password-stdin + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build & push tradein-backend + uses: docker/build-push-action@v6 + with: + context: ./tradein-mvp/backend + push: true + cache-from: type=registry,ref=${{ env.IMAGE_BACKEND }}:buildcache + cache-to: type=registry,ref=${{ env.IMAGE_BACKEND }}:buildcache,mode=max + tags: | + ${{ env.IMAGE_BACKEND }}:latest + ${{ env.IMAGE_BACKEND }}:${{ github.sha }} + + build-frontend: + runs-on: ubuntu-latest + needs: changes + if: | + needs.changes.outputs.frontend == 'true' || + needs.changes.outputs.infra == 'true' || + github.event_name == 'workflow_dispatch' + steps: + - uses: actions/checkout@v4 + + - name: Login to GHCR (shell-based — docker/login-action@v3 unreliable под Forgejo Actions) + env: + GHCR_PAT: ${{ secrets.GHCR_PAT }} + run: | + echo "$GHCR_PAT" | docker login ghcr.io -u lekss361 --password-stdin + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build & push tradein-frontend + uses: docker/build-push-action@v6 + with: + context: ./tradein-mvp/frontend + push: true + # basePath=/trade-in baked-in во время build (Next.js) + build-args: | + NEXT_PUBLIC_BASE_PATH=/trade-in + cache-from: type=registry,ref=${{ env.IMAGE_FRONTEND }}:buildcache + cache-to: type=registry,ref=${{ env.IMAGE_FRONTEND }}:buildcache,mode=max + tags: | + ${{ env.IMAGE_FRONTEND }}:latest + ${{ env.IMAGE_FRONTEND }}:${{ github.sha }} + + deploy: + runs-on: ubuntu-latest + needs: [changes, build-backend, build-frontend] + if: | + always() && + !cancelled() && + needs.build-backend.result != 'failure' && + needs.build-frontend.result != 'failure' + steps: + - name: Deploy via SSH + uses: appleboy/ssh-action@v1.0.3 + env: + IMAGE_TAG: latest + GHCR_PAT: ${{ secrets.GHCR_PAT }} + with: + host: ${{ secrets.DEPLOY_HOST }} + username: ${{ secrets.DEPLOY_USER }} + key: ${{ secrets.DEPLOY_SSH_KEY }} + port: ${{ secrets.DEPLOY_PORT }} + envs: IMAGE_TAG,GHCR_PAT + script: | + set -euo pipefail + cd /opt/gendesign + + # repo уже clone'ен — origin = Forgejo. Подтягиваем последний main. + git fetch origin main + git reset --hard origin/main + + cd tradein-mvp + + # .env.runtime создаётся вручную при первом запуске (см. README-АДМИНУ.md). + # Здесь только подгружаем переменные для docker compose (POSTGRES_PASSWORD). + if [ ! -f .env.runtime ]; then + echo "ERROR: /opt/gendesign/tradein-mvp/.env.runtime отсутствует." + echo "Создай его вручную (см. tradein-mvp/README.md или DEPLOY.md)." + exit 1 + fi + chmod 600 .env.runtime + set -a; source .env.runtime; set +a + + # External network для Caddy (он в основном gendesign-стеке) + docker network inspect gendesign_shared >/dev/null 2>&1 \ + || docker network create gendesign_shared + + # Re-login to GHCR (PAT может быть rotated) + echo "$GHCR_PAT" | docker login ghcr.io -u lekss361 --password-stdin + + export IMAGE_TAG="$IMAGE_TAG" + docker compose -p gendesign-tradein -f docker-compose.prod.yml pull + docker compose -p gendesign-tradein -f docker-compose.prod.yml up -d + + # Применяем SQL миграции (если есть data/sql/*.sql) + # Postgres init load *.sql из /docker-entrypoint-initdb.d ТОЛЬКО при первом + # старте volume. Здесь — для повторных миграций после первого запуска. + sleep 5 + for sql_file in $(ls -1 backend/data/sql/*.sql 2>/dev/null | sort); do + fname=$(basename "$sql_file") + echo "→ Migration: $fname" + docker compose -p gendesign-tradein -f docker-compose.prod.yml exec -T postgres \ + psql -U "${TRADEIN_POSTGRES_USER:-tradein}" -d tradein \ + -v ON_ERROR_STOP=on < "$sql_file" \ + || echo " (skipped — already applied or error: $fname)" + done + + # Caddy reload — основной Caddyfile содержит inline tradein routes + # (см. Caddyfile в корне репы). Reload, чтобы Caddy перечитал DNS + # tradein-backend / tradein-frontend (они в gendesign_shared network). + cd /opt/gendesign + docker compose -p gendesign -f docker-compose.prod.yml exec -T caddy \ + caddy reload --config /etc/caddy/Caddyfile || true + + # Health check + for i in $(seq 1 30); do + docker compose -p gendesign-tradein -f /opt/gendesign/tradein-mvp/docker-compose.prod.yml \ + exec -T backend curl -fsS http://localhost:8000/health && break + sleep 1 + done + + # Cleanup старых образов + for repo in ghcr.io/lekss361/gendesign-tradein-backend \ + ghcr.io/lekss361/gendesign-tradein-frontend; do + docker images "$repo" --format '{{.Repository}}:{{.Tag}}' \ + | grep -v ':latest$' | tail -n +3 \ + | xargs -r docker rmi 2>/dev/null || true + done + docker image prune -af || true diff --git a/Caddyfile b/Caddyfile index 69a36308..d3047c2a 100644 --- a/Caddyfile +++ b/Caddyfile @@ -25,6 +25,24 @@ gendsgn.ru { file_server browse } + # Trade-In MVP subproject (tradein-mvp/) — gendesign-tradein docker stack, + # подключен через gendesign_shared network. Routes ДО универсального handle + # потому что Caddy матчит handle-блоки сверху вниз. + handle_path /trade-in/api/* { + # handle_path вырезает префикс /trade-in перед прокси → + # FastAPI получает /api/v1/... + reverse_proxy tradein-backend:8000 + } + + handle /trade-in { + redir /trade-in/ permanent + } + + handle /trade-in/* { + # Next.js basePath=/trade-in — фронт сам ждёт префикса в URL + reverse_proxy tradein-frontend:3000 + } + handle { reverse_proxy frontend:3000 } diff --git a/tradein-mvp/.env.example b/tradein-mvp/.env.example new file mode 100644 index 00000000..1fd4cdf3 --- /dev/null +++ b/tradein-mvp/.env.example @@ -0,0 +1,17 @@ +# Trade-In MVP — environment variables example. +# Скопируй в .env (или экспортируй в shell) для override defaults. + +# === Backend === +DATABASE_URL=postgresql+psycopg://tradein:tradein@postgres:5432/tradein +CORS_ORIGINS=["http://localhost:8080","http://localhost:3000"] +ENVIRONMENT=dev + +# === Frontend (build-time) === +# Backend URL для Next.js rewrites (browser обращается к /api/* — Next.js проксирует на BACKEND_URL/api/*). +# В docker compose это уже выставлено в http://backend:8000 — менять не нужно. +# BACKEND_URL=http://backend:8000 + +# === Postgres (если меняешь — синхронизируй с DATABASE_URL и docker-compose.yml) === +POSTGRES_USER=tradein +POSTGRES_PASSWORD=tradein +POSTGRES_DB=tradein diff --git a/tradein-mvp/.gitignore b/tradein-mvp/.gitignore new file mode 100644 index 00000000..233693bc --- /dev/null +++ b/tradein-mvp/.gitignore @@ -0,0 +1,50 @@ +# Trade-In MVP + +# Backend Python +backend/.venv/ +backend/__pycache__/ +backend/**/__pycache__/ +backend/*.egg-info/ +backend/.pytest_cache/ +backend/.ruff_cache/ +backend/.mypy_cache/ +backend/uv.lock + +# Frontend Node +frontend/node_modules/ +frontend/.next/ +frontend/out/ +frontend/dist/ +frontend/package-lock.json +frontend/next-env.d.ts + +# Docker +postgres-data/ +caddy-data/ +caddy-config/ + +# Env (никогда не коммитим) +.env +.env.local +.env.*.local +backend/.env +backend/.env.runtime +frontend/.env.local + +# Public html mockup (исходник от gendsgn.ru — не наш код, держим в docs) +frontend/public/tradein.html + +# Test PDF outputs +docs/sample-svg-test.pdf +docs/sample-vps-*.pdf +*.tmp.pdf + +# IDE / OS +.vscode/ +.idea/ +.DS_Store +Thumbs.db +*.swp + +# Logs +*.log diff --git a/tradein-mvp/DEPLOY.md b/tradein-mvp/DEPLOY.md new file mode 100644 index 00000000..f77bb47d --- /dev/null +++ b/tradein-mvp/DEPLOY.md @@ -0,0 +1,147 @@ +# Trade-In MVP — деплой в gendesign репо + +## Архитектура + +``` +lekss361/-gendesign/ +├── backend/ ← gendesign Python backend (НЕ ТРОГАЕМ) +├── frontend/ ← gendesign Next.js (НЕ ТРОГАЕМ) +├── docker-compose.prod.yml ← gendesign-стек +├── Caddyfile ← основной Caddy → ВКЛЮЧАЕТ tradein-mvp/deploy/Caddyfile.tradein-fragment +├── .github/workflows/ +│ ├── deploy.yml ← существующий gendesign deploy +│ └── deploy-tradein.yml ← НАШ новый, триггерится только на tradein-mvp/** +└── tradein-mvp/ ← НАША подпапка (изолированный subproject) + ├── backend/ + ├── frontend/ + ├── deploy/ + │ ├── Caddyfile.tradein-fragment ← импортится в основной Caddyfile + │ └── cron-scrape.sh + ├── docker-compose.yml ← локальный dev + ├── docker-compose.prod.yml ← production overlay (использует GHCR images) + └── .github/workflows/deploy-tradein.yml +``` + +## Прод URL routes + +| URL | Сервис | +|----------------------------------|-------------------------| +| `gendsgn.ru/trade-in/` | tradein-frontend:3000 | +| `gendsgn.ru/trade-in/api/v1/...` | tradein-backend:8000 | + +Caddy в gendesign-стеке проксирует через `handle_path /trade-in/api/*` (вырезает префикс) и `handle /trade-in/*` (Next.js basePath). + +## Прод docker stacks + +- `docker compose -p gendesign` — основной gendesign (postgres + backend + frontend + caddy + couchdb) +- `docker compose -p gendesign-tradein` — наш (tradein-postgres + tradein-backend + tradein-frontend) + +Оба подключены к `gendesign_shared` external network — туда смотрит Caddy. + +## Что нужно положить в основной Caddyfile gendesign + +В блок `gendsgn.ru { ... }` **ПЕРЕД** универсальным `handle { reverse_proxy frontend:3000 }`: + +```caddyfile +import /opt/gendesign/tradein-mvp/deploy/Caddyfile.tradein-fragment +``` + +Или вставить содержимое фрагмента inline. + +## Что нужно положить в `.env.runtime` (на сервере, НЕ в git) + +```bash +# /opt/gendesign/tradein-mvp/.env.runtime +TRADEIN_POSTGRES_USER=tradein +TRADEIN_POSTGRES_PASSWORD=<сгенерировать openssl rand -hex 32> +TRADEIN_CONTACT_EMAIL=tradein@gendsgn.ru +YANDEX_GEOCODER_KEY= # пусто пока, Nominatim fallback работает +``` + +Файл создаётся вручную при первом деплое. + +## GitHub Secrets (уже должны быть от gendesign deploy) + +- `DEPLOY_HOST` — IP сервера (94.228.121.73) +- `DEPLOY_USER` — root +- `DEPLOY_SSH_KEY` — приватный SSH ключ +- `DEPLOY_PORT` — 22 (или другой если меняли) + +## Первый деплой — пошагово + +### 1. На анто́новой машине: подготовить tradein-mvp/ к слиянию + +```bash +# clone gendesign репо (с PAT) +git clone https://@github.com/lekss361/-gendesign.git +cd -gendesign + +# скопировать tradein-mvp/ как подпапку +cp -r /Users/anton/Птица/tradein-mvp ./tradein-mvp +rm -rf ./tradein-mvp/postgres-data # на всякий +rm -rf ./tradein-mvp/.git # не нужен внутри monorepo + +# скопировать workflow в правильное место +mkdir -p .github/workflows +cp ./tradein-mvp/.github/workflows/deploy-tradein.yml .github/workflows/ + +git add tradein-mvp/ .github/workflows/deploy-tradein.yml +git commit -m "feat: add tradein-mvp subproject + deploy workflow" +git push origin main +``` + +### 2. На сервере: первый раз вручную добавить Caddy include + +```bash +ssh -i ~/.ssh/id_bot_server root@94.228.121.73 + +cd /opt/gendesign +# git reset --hard origin/main подтянет tradein-mvp/ автоматически + +# Добавить в Caddyfile (ровно одну строку в блок gendsgn.ru { ... }) +nano Caddyfile +# вставить ПЕРЕД последним handle { ... }: +# import /opt/gendesign/tradein-mvp/deploy/Caddyfile.tradein-fragment + +# Создать .env.runtime +cat > tradein-mvp/.env.runtime </dev/null 2>&1 || docker network create gendesign_shared +cd tradein-mvp +set -a; source .env.runtime; set +a +docker compose -p gendesign-tradein -f docker-compose.prod.yml pull +docker compose -p gendesign-tradein -f docker-compose.prod.yml up -d + +# Reload Caddy +cd /opt/gendesign +docker compose -p gendesign -f docker-compose.prod.yml exec -T caddy caddy reload --config /etc/caddy/Caddyfile + +# Проверить +curl -sS https://gendsgn.ru/trade-in/api/health +curl -sI https://gendsgn.ru/trade-in/ +``` + +### 3. Дальше — автодеплой + +После первого ручного запуска все следующие `git push origin main` с изменениями в `tradein-mvp/**` будут: +1. Триггерить `.github/workflows/deploy-tradein.yml` +2. Билдить и пушить новые образы в `ghcr.io/lekss361/gendesign-tradein-*` +3. SSH в сервер → `docker compose pull` → `up -d` → Caddy reload +4. Health check + +## Откат + +```bash +ssh root@94.228.121.73 +cd /opt/gendesign/tradein-mvp +# Откатиться на предыдущий SHA-тег +docker compose -p gendesign-tradein -f docker-compose.prod.yml down +IMAGE_TAG= docker compose -p gendesign-tradein -f docker-compose.prod.yml up -d +``` diff --git a/tradein-mvp/Makefile b/tradein-mvp/Makefile new file mode 100644 index 00000000..821910b3 --- /dev/null +++ b/tradein-mvp/Makefile @@ -0,0 +1,63 @@ +# Trade-In MVP — удобные команды для локальной разработки. + +.PHONY: help up down rebuild logs ps shell-backend shell-postgres test-estimate clean + +help: + @echo "Trade-In MVP — Makefile commands:" + @echo "" + @echo " make up — собрать и запустить весь стек (caddy + frontend + backend + postgres)" + @echo " make down — остановить стек (volumes остаются)" + @echo " make rebuild — пересобрать образы и перезапустить (нужно при изменении Dockerfile или deps)" + @echo " make logs — tail -f всех контейнеров" + @echo " make logs-backend — tail -f только backend" + @echo " make logs-frontend — tail -f только frontend" + @echo " make ps — статус контейнеров + healthcheck" + @echo " make shell-backend — bash внутри backend контейнера" + @echo " make shell-postgres — psql внутри postgres контейнера" + @echo " make test-estimate — пример POST /api/v1/trade-in/estimate через curl" + @echo " make clean — down + rm volumes (УДАЛИТ данные Postgres!)" + @echo "" + +up: + docker compose up -d --build + @echo "" + @echo "✅ Стек запущен." + @echo " Frontend: http://localhost:8080 (auto-redirect → /trade-in)" + @echo " Mockup preview: http://localhost:8080/preview/tradein.html" + @echo " Backend health: http://localhost:8080/health" + @echo " Backend OpenAPI: http://localhost:8000/docs" + +down: + docker compose down + +rebuild: + docker compose up -d --build --force-recreate + +logs: + docker compose logs -f --tail=100 + +logs-backend: + docker compose logs -f --tail=100 backend + +logs-frontend: + docker compose logs -f --tail=100 frontend + +ps: + docker compose ps + +shell-backend: + docker compose exec backend bash + +shell-postgres: + docker compose exec postgres psql -U tradein -d tradein + +test-estimate: + @echo "POST /api/v1/trade-in/estimate..." + @curl -sS -X POST http://localhost:8080/api/v1/trade-in/estimate \ + -H 'Content-Type: application/json' \ + -d '{"address":"ул. Малышева, 1, Екатеринбург","area_m2":54,"rooms":2,"floor":5,"total_floors":17,"year_built":1985,"house_type":"panel","repair_state":"good","has_balcony":true}' \ + | python3 -m json.tool + +clean: + docker compose down -v + @echo "⚠️ Volumes удалены — Postgres данные стёрты." diff --git a/tradein-mvp/README.md b/tradein-mvp/README.md new file mode 100644 index 00000000..adfa8223 --- /dev/null +++ b/tradein-mvp/README.md @@ -0,0 +1,196 @@ +# Trade-In MVP + +Локальный standalone-форк фичи **Trade-In Estimator** из проекта gendesign — оценка выкупной стоимости квартиры на вторичном рынке по аналогам и реальным сделкам. Layout повторяет PDF-отчёт «Брусника.Обмен» (см. [docs/](docs/)). + +## Что это и откуда взято + +| Источник | Что | Где | +|---|---|---| +| `gendesign/main` PR [#316](https://git.gendsgn.ru/lekss361/gendesign/pulls/316) TI-1 | mock endpoint + Pydantic + SQL migration | `backend/` | +| `gendesign/main` PR [#317](https://git.gendsgn.ru/lekss361/gendesign/pulls/317) TI-3 | Next.js страница + 5 компонентов + hooks | `frontend/` | +| `gendesign/main` PR [#319](https://git.gendsgn.ru/lekss361/gendesign/pulls/319) TI-2 | PDF export 4 страницы (как у Брусники) | `backend/app/services/exporters/` | +| `gendesign/main` PR [#283](https://git.gendsgn.ru/lekss361/gendesign/pulls/283) | статичный `tradein.html` mockup (для Геныча) | `frontend/public/tradein.html` | +| Встреча 19.05.2026 («Птица») | требования к MVP оценки вторички | `docs/PTITSA_MEETING_2026-05-19.pdf` | +| PDF Брусники EКБ-2485 | референс layout-а отчёта | `docs/BRUSNIKA_REFERENCE_EKB-2485.pdf` | + +## Быстрый старт + +```bash +make up # build + up весь стек (caddy + frontend + backend + postgres) +open http://localhost:8080 +``` + +Откроется `/` → автоматически редирект на `/trade-in`. Заполняешь форму (адрес/площадь/комнаты/этаж/...), нажимаешь «Оценить» — backend возвращает mock-оценку, фронт показывает median + диапазон цен + список аналогов. + +Проверка backend напрямую: +```bash +make test-estimate +# или вручную: +curl -sS -X POST http://localhost:8080/api/v1/trade-in/estimate \ + -H 'Content-Type: application/json' \ + -d '{"address":"ул. Малышева, 1","area_m2":54,"rooms":2,"floor":5,"total_floors":17}' \ + | python3 -m json.tool +``` + +OpenAPI документация: + +Для сравнения макет vs реальная фича: +- макет: +- фича: + +## Структура + +``` +tradein-mvp/ +├── docker-compose.yml # caddy + frontend + backend + postgres +├── Makefile # удобные команды (up/down/logs/test-estimate) +├── deploy/ +│ └── Caddyfile # local reverse-proxy на http://localhost:8080 +├── backend/ # FastAPI + WeasyPrint +│ ├── Dockerfile +│ ├── pyproject.toml +│ ├── app/ +│ │ ├── main.py # FastAPI entry — только trade-in router +│ │ ├── core/ +│ │ │ ├── config.py # минимальный pydantic-settings +│ │ │ └── db.py # SQLAlchemy engine + get_db +│ │ ├── api/v1/ +│ │ │ └── trade_in.py # 3 endpoint'а: POST /estimate, GET /estimate/{id}, GET /estimate/{id}/pdf +│ │ ├── schemas/ +│ │ │ └── trade_in.py # Pydantic: TradeInEstimateInput / AnalogLot / AggregatedEstimate +│ │ └── services/exporters/ +│ │ └── trade_in_pdf.py # WeasyPrint → 4-страничный PDF (cover/listings/deals/offer) +│ └── data/sql/ +│ └── 001_trade_in_estimates.sql # CREATE TABLE; применяется при первом старте postgres +├── frontend/ # Next.js 15 + React 19 + TanStack Query +│ ├── Dockerfile +│ ├── package.json +│ ├── next.config.ts # rewrites /api/* → backend +│ ├── tsconfig.json +│ ├── src/ +│ │ ├── app/ +│ │ │ ├── layout.tsx +│ │ │ ├── page.tsx # redirect → /trade-in +│ │ │ ├── globals.css +│ │ │ ├── providers.tsx # QueryClientProvider +│ │ │ └── trade-in/ +│ │ │ └── page.tsx +│ │ ├── components/trade-in/ +│ │ │ ├── EstimateForm.tsx # форма ввода (sticky 360px) +│ │ │ ├── EstimateProgress.tsx # индикатор «Парсим Циан → Авито → ...» +│ │ │ ├── EstimateResult.tsx # карточка результата +│ │ │ ├── PriceRangeBar.tsx # визуализация диапазона цен (как у Брусники) +│ │ │ └── AnalogsTable.tsx # таблица аналогов +│ │ ├── lib/ +│ │ │ ├── api.ts # apiFetch + HTTPError +│ │ │ ├── sessionId.ts # X-Session-Id из localStorage +│ │ │ └── trade-in-api.ts # useEstimateMutation + useEstimate hooks +│ │ └── types/ +│ │ └── trade-in.ts # TS типы зеркалят Pydantic schemas +│ └── public/ +│ └── tradein.html # статичный mockup от 17.05 (для side-by-side review) +└── docs/ + ├── BRUSNIKA_REFERENCE_EKB-2485.pdf # эталон layout-а + └── PTITSA_MEETING_2026-05-19.pdf # AI-протокол встречи с требованиями +``` + +## API + +`POST /api/v1/trade-in/estimate` — оценить квартиру. + +Запрос: +```json +{ + "address": "ул. Малышева, 1, кв. 5, Екатеринбург", + "area_m2": 54.0, + "rooms": 2, + "floor": 5, + "total_floors": 17, + "year_built": 1985, + "house_type": "panel", + "repair_state": "good", + "has_balcony": true +} +``` + +Ответ: +```json +{ + "estimate_id": "...uuid...", + "median_price_rub": 13125000, + "range_low_rub": 11550000, + "range_high_rub": 14700000, + "median_price_per_m2": 243056, + "confidence": "high", + "n_analogs": 8, + "period_months": 24, + "analogs": [ {"address": "...", "area_m2": 56, "price_rub": 12700000, ...} ], + "actual_deals": [ ... ], + "expires_at": "2026-05-20T22:48:00Z" +} +``` + +`GET /api/v1/trade-in/estimate/{id}` — получить сохранённую оценку (TTL 24ч) +`GET /api/v1/trade-in/estimate/{id}/pdf` — скачать 4-страничный PDF (cover / listings / deals / offer) + +## Что внутри `_mock_estimate()` (текущая реализация) + +Формула: +``` +price = base_price_by_rooms × floor_factor × repair_factor +``` + +| Поле | Значения | +|---|---| +| Базовая цена ЕКБ 2026 | студия 6.5M (260K/м²) · 1к 9.0M (225K/м²) · 2к 12.5M (208K/м²) · 3к 17.0M (213K/м²) | +| `floor_factor` | 1-й этаж = ×0.95, последний = ×0.97, остальные = ×1.00 | +| `repair_factor` | `needs_repair` = ×0.90, `standard` = ×1.00, `good` = ×1.05, `excellent` = ×1.10 | +| `confidence` | 1-3 комнаты = `high`, остальные = `medium` | +| Улицы аналогов | реальные центральные ЕКБ (Малышева, Куйбышева, 8 Марта, Белинского, пр. Ленина, Толмачёва, Радищева, Мамина-Сибиряка, Луначарского, Первомайская) | + +Каждая оценка сохраняется в `trade_in_estimates` с TTL 24 часа — UUID можно использовать для shareable links и PDF-экспорта. + +## Roadmap — что доделать + +### Phase 1 — заменить mock на реальные данные (TODO TI-1b из gendesign) + +Сейчас `_mock_estimate()` возвращает хардкод. На встрече Птица 19.05 решили: +- источники: **Циан, Авито, Дом.Клик, Я.Недвижимость, Н1, Дом РФ** +- **Объектив НЕ использовать** на вторичке (он про первичку/ДДУ) +- Росреестр для исторических сделок (квартал глубины) +- картография ЕКБ для проверки этажности/года/планировок + +### Phase 2 — то что обсуждали на встрече + +| Задача | Из протокола Птицы | +|---|---| +| Парольный вход + учёт пользователей + аналитика | 0:23:44, 0:25:54 | +| Доступ только Геныч / Загайнов / Паша (НЕ Рожкова) | 0:25:50, 0:22:35 | +| PDF-отчёт под паролем | 0:08:39 | +| Real-time парсинг ≥1/час чтобы ловить быстрые продажи | 0:40:19 | +| MVP к понедельнику 25.05.2026 | 0:26:12 | +| Демо для девелопера в четверг 28.05.2026 | 0:18:08 | + +### Phase 3 — следующие продукты (упоминалось на встрече) + +1. **Птица** — анализ участков + расселение домов (≥20% квартир дома в продаже → подсветить можно расселять) +2. **Расселение как сервис** — следствие #1 и Птицы + +См. полный протокол: [docs/PTITSA_MEETING_2026-05-19.pdf](docs/PTITSA_MEETING_2026-05-19.pdf). + +## Как это связано с прод gendesign + +| Аспект | Прод (gendsgn.ru) | Этот MVP | +|---|---|---| +| URL | | | +| Backend | shared FastAPI `/api/v1/trade-in/*` | то же самое, standalone | +| Frontend | Next.js 15 в большом monorepo | тот же код, standalone | +| Postgres | 84 таблицы, 6.83M ДДУ partitioned | только `trade_in_estimates` (1 таблица) | +| Caddy | TLS + 5 доменов + reverse-proxy | local :8080 без TLS | +| Что отрезано | site-finder, analytics, generative, scraper, OSM, NSPD, sentry, celery, redis, playwright | всё это — кроме trade-in | + +**Важно: эти два инстанса полностью изолированы.** Локальный backend пишет в свой Postgres контейнер (порт 5433), не трогает прод. Можно сломать локально что угодно — прод не пострадает. + +## Лицензия + +Internal use only. Forked from gendesign monorepo (private). diff --git a/tradein-mvp/backend/.dockerignore b/tradein-mvp/backend/.dockerignore new file mode 100644 index 00000000..236db7c7 --- /dev/null +++ b/tradein-mvp/backend/.dockerignore @@ -0,0 +1,13 @@ +.venv +__pycache__ +**/__pycache__ +*.egg-info +.pytest_cache +.ruff_cache +.mypy_cache +.git +.env +.env.local +data/sql +Dockerfile +.dockerignore diff --git a/tradein-mvp/backend/Dockerfile b/tradein-mvp/backend/Dockerfile new file mode 100644 index 00000000..bf781a85 --- /dev/null +++ b/tradein-mvp/backend/Dockerfile @@ -0,0 +1,56 @@ +# Trade-In MVP backend — lean image (FastAPI + WeasyPrint). +# Не содержит Playwright/Chromium/Celery/Redis — только то что нужно для trade-in feature. + +# ---- builder ---- +FROM python:3.12-slim AS builder + +ENV PYTHONUNBUFFERED=1 \ + PYTHONDONTWRITEBYTECODE=1 \ + UV_COMPILE_BYTECODE=1 \ + UV_LINK_MODE=copy + +RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ + --mount=type=cache,target=/var/lib/apt,sharing=locked \ + apt-get update && apt-get install -y --no-install-recommends \ + build-essential \ + libpq-dev + +RUN pip install --no-cache-dir uv + +WORKDIR /app + +COPY pyproject.toml ./ +RUN --mount=type=cache,target=/root/.cache/uv \ + uv sync --no-dev + +COPY app ./app + + +# ---- runner ---- +FROM python:3.12-slim AS runner + +ENV PYTHONUNBUFFERED=1 \ + PYTHONDONTWRITEBYTECODE=1 \ + PATH="/app/.venv/bin:$PATH" + +RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ + --mount=type=cache,target=/var/lib/apt,sharing=locked \ + apt-get update && apt-get install -y --no-install-recommends \ + libpq5 \ + libcairo2 \ + libpango-1.0-0 \ + libpangoft2-1.0-0 \ + fonts-dejavu-core \ + curl \ + && useradd --create-home --uid 1000 app + +WORKDIR /app + +COPY --from=builder --chown=app:app /app/.venv /app/.venv +COPY --from=builder --chown=app:app /app/app /app/app + +USER app + +EXPOSE 8000 + +CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"] diff --git a/tradein-mvp/backend/app/__init__.py b/tradein-mvp/backend/app/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tradein-mvp/backend/app/api/__init__.py b/tradein-mvp/backend/app/api/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tradein-mvp/backend/app/api/v1/__init__.py b/tradein-mvp/backend/app/api/v1/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tradein-mvp/backend/app/api/v1/admin.py b/tradein-mvp/backend/app/api/v1/admin.py new file mode 100644 index 00000000..89a881a5 --- /dev/null +++ b/tradein-mvp/backend/app/api/v1/admin.py @@ -0,0 +1,151 @@ +"""Admin endpoints — debug + ручной запуск парсеров. + +Пока без auth (Слой 7), потом закроем общим middleware. +""" + +from __future__ import annotations + +import asyncio +import logging +from typing import Annotated, Literal + +from fastapi import APIRouter, Depends +from pydantic import BaseModel, Field +from sqlalchemy import text +from sqlalchemy.orm import Session + +from app.core.db import get_db +from app.services.geocoder import geocode +from app.services.scrapers.avito import AvitoScraper +from app.services.scrapers.base import save_listings +from app.services.scrapers.cian import CianScraper +from app.services.scrapers.yandex_realty import YandexRealtyScraper + +logger = logging.getLogger(__name__) + +router = APIRouter() + + +class ScrapeRequest(BaseModel): + lat: float + lon: float + radius_m: int = Field(default=1000, ge=100, le=20000) + sources: list[Literal["avito", "cian", "yandex"]] = Field(default_factory=lambda: ["avito", "cian", "yandex"]) + multi_room_yandex: bool = False # Если True — скрейп Yandex по 5 сегментам комнат, не одним общим запросом. + deep_yandex: bool = False # Если True — Yandex полный обход 5 rooms × 3 sorts × 2 pages = 30 запросов / ~150s. + multi_room_cian: bool = False # Если True — скрейп Cian по 4 сегментам комнат отдельно (~4× лотов). + + +class ScrapeResult(BaseModel): + source: str + fetched: int + inserted: int + updated: int + + +class ScrapeResponse(BaseModel): + total_fetched: int + total_inserted: int + total_updated: int + by_source: list[ScrapeResult] + + +@router.post("/scrape", response_model=ScrapeResponse) +async def scrape_around( + payload: ScrapeRequest, + db: Annotated[Session, Depends(get_db)], +) -> ScrapeResponse: + """Запустить парсеры для точки (lat, lon) в радиусе radius_m метров. + + Примеры: + curl -X POST /api/v1/admin/scrape \\ + -H 'Content-Type: application/json' \\ + -d '{"lat":56.8332,"lon":60.5944,"radius_m":1000,"sources":["avito"]}' + """ + results: list[ScrapeResult] = [] + + for source in payload.sources: + scraper_cls = { + "avito": AvitoScraper, + "cian": CianScraper, + "yandex": YandexRealtyScraper, + }.get(source) + if scraper_cls is None: + continue + async with scraper_cls() as scraper: + if source == "yandex" and payload.deep_yandex: + lots = await scraper.fetch_around_multi_room( + payload.lat, payload.lon, payload.radius_m, + sorts=("DATE_DESC", "PRICE", "AREA_DESC"), + pages=(0, 1), + ) + elif source == "yandex" and payload.multi_room_yandex: + lots = await scraper.fetch_around_multi_room( + payload.lat, payload.lon, payload.radius_m + ) + elif source == "cian" and payload.multi_room_cian: + lots = await scraper.fetch_around_multi_room( + payload.lat, payload.lon, payload.radius_m + ) + else: + lots = await scraper.fetch_around( + payload.lat, payload.lon, payload.radius_m + ) + inserted, updated = save_listings(db, lots) + results.append( + ScrapeResult(source=source, fetched=len(lots), inserted=inserted, updated=updated) + ) + + return ScrapeResponse( + total_fetched=sum(r.fetched for r in results), + total_inserted=sum(r.inserted for r in results), + total_updated=sum(r.updated for r in results), + by_source=results, + ) + + +@router.post("/geocode-missing") +async def geocode_missing( + db: Annotated[Session, Depends(get_db)], + limit: int = 50, +) -> dict: + """Геокодинг listings у которых нет lat/lon (используя address). + + Запускать после scrape если парсер не достал координаты. + Nominatim rate-limited 1 req/sec — поэтому небольшой batch. + """ + rows = db.execute( + text( + """ + SELECT id, address, raw_payload + FROM listings + WHERE (lat IS NULL OR lon IS NULL) + AND COALESCE(address, '') != '' + ORDER BY scraped_at DESC + LIMIT :limit + """ + ), + {"limit": limit}, + ).mappings().all() + + geocoded = 0 + skipped = 0 + for row in rows: + result = await geocode(row["address"], db) + if result is None: + skipped += 1 + continue + db.execute( + text( + """ + UPDATE listings + SET lat = :lat, lon = :lon + WHERE id = :id + """ + ), + {"lat": result.lat, "lon": result.lon, "id": row["id"]}, + ) + db.commit() + geocoded += 1 + + return {"checked": len(rows), "geocoded": geocoded, "skipped": skipped} diff --git a/tradein-mvp/backend/app/api/v1/brand.py b/tradein-mvp/backend/app/api/v1/brand.py new file mode 100644 index 00000000..325ffac7 --- /dev/null +++ b/tradein-mvp/backend/app/api/v1/brand.py @@ -0,0 +1,22 @@ +"""Brand endpoint — frontend дёргает чтобы получить логотип/цвет для white-label.""" + +from __future__ import annotations + +from typing import Annotated + +from fastapi import APIRouter, Depends +from sqlalchemy.orm import Session + +from app.core.db import get_db +from app.services.brand import Brand, get_brand + +router = APIRouter() + + +@router.get("/{slug}", response_model=Brand) +def lookup(slug: str, db: Annotated[Session, Depends(get_db)]) -> Brand: + """GET /api/v1/brand/prinzip → {slug, name, primary_color, ...}. + + Не найден → fallback generic. + """ + return get_brand(slug, db) diff --git a/tradein-mvp/backend/app/api/v1/geocode.py b/tradein-mvp/backend/app/api/v1/geocode.py new file mode 100644 index 00000000..59fbdb9b --- /dev/null +++ b/tradein-mvp/backend/app/api/v1/geocode.py @@ -0,0 +1,70 @@ +"""Geocode endpoints — debug + frontend Suggest proxy.""" + +from __future__ import annotations + +import logging +from typing import Annotated + +from fastapi import APIRouter, Depends, HTTPException, Query +from pydantic import BaseModel +from sqlalchemy.orm import Session + +from app.core.db import get_db +from app.services.geocoder import GeocodeResult, geocode, suggest + +logger = logging.getLogger(__name__) + +router = APIRouter() + + +@router.get("/lookup", response_model=GeocodeResult) +async def lookup( + address: Annotated[str, Query(min_length=3, max_length=500)], + db: Annotated[Session, Depends(get_db)], +) -> GeocodeResult: + """Геокодинг адреса → lat/lon. + + Примеры: + /api/v1/geocode/lookup?address=ул.+Малышева+30+Екатеринбург + /api/v1/geocode/lookup?address=Куйбышева+50+Екатеринбург + """ + result = await geocode(address, db) + if result is None: + raise HTTPException(status_code=404, detail=f"Address not found: {address}") + return result + + +class SuggestItem(BaseModel): + label: str + full_address: str + lat: float + lon: float + kind: str + + +class SuggestResponse(BaseModel): + items: list[SuggestItem] + + +@router.get("/suggest", response_model=SuggestResponse) +async def suggest_addresses( + q: Annotated[str, Query(min_length=2, max_length=200, description="Запрос для автокомплита")], + limit: Annotated[int, Query(ge=1, le=15)] = 8, +) -> SuggestResponse: + """Автокомплит адресов в пределах ЕКБ. + + Используется в EstimateForm для подсказок пока пользователь печатает. + Bounded viewbox = ЕКБ (lon 60.40-60.85, lat 56.65-56.95). + + Пример: + /api/v1/geocode/suggest?q=Малышева + /api/v1/geocode/suggest?q=Цвиллинга # → пусто, такой улицы в ЕКБ нет + """ + items = await suggest(q, limit=limit) + return SuggestResponse(items=[ + SuggestItem( + label=s.label, + full_address=s.full_address, + lat=s.lat, lon=s.lon, kind=s.kind, + ) for s in items + ]) diff --git a/tradein-mvp/backend/app/api/v1/trade_in.py b/tradein-mvp/backend/app/api/v1/trade_in.py new file mode 100644 index 00000000..b9babe64 --- /dev/null +++ b/tradein-mvp/backend/app/api/v1/trade_in.py @@ -0,0 +1,411 @@ +"""Trade-In Estimator — endpoints (TI-1 mock + TI-2 PDF). + +MOCK implementation: returns realistic ЕКБ price bands by rooms/floor/repair. +TODO TI-1b: заменить _mock_estimate() на реальный SQL aggregation из +objective_lots + rosreestr_deals после OBJ-1/2 merge. +""" + +from __future__ import annotations + +import json +import logging +import random +from datetime import UTC, datetime, timedelta +from typing import Annotated +from uuid import UUID, uuid4 + +from fastapi import APIRouter, Depends, HTTPException, Response +from sqlalchemy import text +from sqlalchemy.orm import Session + +from app.core.db import get_db +from app.schemas.trade_in import AggregatedEstimate, AnalogLot, TradeInEstimateInput +from app.services.exporters.trade_in_pdf import generate_trade_in_pdf + +logger = logging.getLogger(__name__) + +router = APIRouter() + +# ЕКБ-адреса для фейковых аналогов (реальные улицы центра) +_EKB_STREETS = [ + "ул. Малышева", + "ул. Куйбышева", + "ул. 8 Марта", + "ул. Белинского", + "пр. Ленина", + "ул. Толмачёва", + "ул. Радищева", + "ул. Мамина-Сибиряка", + "ул. Луначарского", + "ул. Первомайская", +] + +# Базовые ценовые диапазоны по комнатности (ЕКБ, 2026) +_PRICE_BANDS: dict[int, dict[str, int | float | str]] = { + 0: { # студия ~25 м² + "median": 6_500_000, + "low": 5_800_000, + "high": 7_500_000, + "ppm2": 260_000, + "ref_area": 25.0, + }, + 1: { # 1к ~40 м² + "median": 9_000_000, + "low": 8_000_000, + "high": 10_500_000, + "ppm2": 225_000, + "ref_area": 40.0, + }, + 2: { # 2к ~60 м² + "median": 12_500_000, + "low": 11_000_000, + "high": 14_000_000, + "ppm2": 208_000, + "ref_area": 60.0, + }, + 3: { # 3к ~80 м² + "median": 17_000_000, + "low": 15_000_000, + "high": 19_000_000, + "ppm2": 213_000, + "ref_area": 80.0, + }, +} + + +def _floor_factor(floor: int, total_floors: int) -> float: + """±5% поправка за этаж: 1й и последний этаж снижают цену.""" + if floor == 1: + return 0.95 + if floor == total_floors: + return 0.97 + return 1.0 + + +def _repair_factor(repair_state: str | None) -> float: + """±10% поправка за состояние отделки.""" + factors = { + "needs_repair": 0.90, + "standard": 1.00, + "good": 1.05, + "excellent": 1.10, + } + return factors.get(repair_state or "standard", 1.0) + + +def _confidence(rooms: int) -> str: + if 1 <= rooms <= 3: + return "high" + return "medium" + + +def _gen_analogs( + rooms: int, + area_m2: float, + base_ppm2: int, + n: int, + *, + is_listing: bool, +) -> list[AnalogLot]: + """Генерирует список фейковых аналогов (объявления или сделки).""" + rng = random.Random(42 + rooms + n) + result: list[AnalogLot] = [] + today = datetime.now(tz=UTC).date() + for i in range(n): + street = _EKB_STREETS[i % len(_EKB_STREETS)] + building_no = rng.randint(1, 120) + apt_no = rng.randint(1, 300) + addr = f"г. Екатеринбург, {street}, {building_no}, кв. {apt_no}" + + area_jitter = area_m2 * rng.uniform(0.85, 1.15) + ppm2_jitter = int(base_ppm2 * rng.uniform(0.90, 1.10)) + price = int(area_jitter * ppm2_jitter) + + floor_val = rng.randint(2, 16) + total_fl = rng.randint(floor_val, 20) + + if is_listing: + dom = rng.randint(5, 120) + listing_dt = today - timedelta(days=dom) + else: + dom = rng.randint(10, 60) + listing_dt = today - timedelta(days=rng.randint(30, 365)) + + result.append( + AnalogLot( + address=addr, + area_m2=round(area_jitter, 1), + rooms=rooms if rooms > 0 else 0, + floor=floor_val, + total_floors=total_fl, + price_rub=price, + price_per_m2=ppm2_jitter, + listing_date=listing_dt, + days_on_market=dom, + photo_url=None, + ) + ) + return result + + +def _mock_estimate(payload: TradeInEstimateInput) -> AggregatedEstimate: + """Возвращает mock-оценку на основе диапазонов ЕКБ 2026. + + Логика: + - Берём базовый band по rooms (0-3+). + - Масштабируем на фактическую площадь относительно референсной. + - Применяем поправку за этаж (±5%) и отделку (±10%). + - Генерируем 7-10 аналогов (листинги) и 3-5 actual_deals. + """ + rooms_key = min(payload.rooms, 3) # 4к+ → диапазон 3к + band = _PRICE_BANDS[rooms_key] + + # Масштаб по площади + ref_area: float = band["ref_area"] # type: ignore[assignment] + area_scale = payload.area_m2 / ref_area + + ff = _floor_factor(payload.floor, payload.total_floors) + rf = _repair_factor(payload.repair_state) + combined = area_scale * ff * rf + + median = int(band["median"] * combined) # type: ignore[operator] + low = int(band["low"] * combined) # type: ignore[operator] + high = int(band["high"] * combined) # type: ignore[operator] + ppm2 = int(band["ppm2"] * ff * rf) # type: ignore[operator] + + n_analogs = random.randint(7, 10) + n_deals = random.randint(3, 5) + + analogs = _gen_analogs(rooms_key, payload.area_m2, ppm2, n_analogs, is_listing=True) + actual_deals = _gen_analogs( + rooms_key, payload.area_m2, int(ppm2 * 0.93), n_deals, is_listing=False + ) + + now = datetime.now(tz=UTC) + return AggregatedEstimate( + estimate_id=uuid4(), + median_price_rub=median, + range_low_rub=low, + range_high_rub=high, + median_price_per_m2=ppm2, + confidence=_confidence(payload.rooms), + n_analogs=n_analogs + n_deals, + period_months=24, + analogs=analogs, + actual_deals=actual_deals, + expires_at=now + timedelta(hours=24), + ) + + +@router.post("/estimate", response_model=AggregatedEstimate) +async def estimate( + payload: TradeInEstimateInput, + db: Annotated[Session, Depends(get_db)], +) -> AggregatedEstimate: + """Реальная оценка через SQL aggregation поверх listings + deals. + + 1. Geocode address → lat/lon + 2. PostGIS ST_DWithin радиус 800м (или 2км fallback) + 3. Tukey IQR outlier filter + 4. Median + Q1 + Q3 + confidence с explanation + """ + from app.services.estimator import estimate_quality + return await estimate_quality(payload, db) + + +# OLD MOCK PATH — оставлен как fallback для отладки; не вызывается из router. +def _estimate_legacy_mock( + payload: TradeInEstimateInput, + db: Annotated[Session, Depends(get_db)], +) -> AggregatedEstimate: + """Старая mock-реализация. НЕ используется в роутере, удалить когда стабилизируем новый estimator.""" + result = _mock_estimate(payload) + + analogs_json = json.dumps( + [a.model_dump(mode="json") for a in result.analogs], + ensure_ascii=False, + ) + deals_json = json.dumps( + [a.model_dump(mode="json") for a in result.actual_deals], + ensure_ascii=False, + ) + + db.execute( + text( + """ + INSERT INTO trade_in_estimates ( + id, address, area_m2, rooms, floor, total_floors, + year_built, house_type, repair_state, has_balcony, + median_price, range_low, range_high, median_price_per_m2, + confidence, n_analogs, analogs, actual_deals, expires_at + ) VALUES ( + CAST(:id AS uuid), + :address, :area_m2, :rooms, :floor, :total_floors, + :year_built, :house_type, :repair_state, :has_balcony, + :median_price, :range_low, :range_high, :median_price_per_m2, + :confidence, :n_analogs, + CAST(:analogs AS jsonb), + CAST(:actual_deals AS jsonb), + :expires_at + ) + """ + ), + { + "id": str(result.estimate_id), + "address": payload.address, + "area_m2": payload.area_m2, + "rooms": payload.rooms, + "floor": payload.floor, + "total_floors": payload.total_floors, + "year_built": payload.year_built, + "house_type": payload.house_type, + "repair_state": payload.repair_state, + "has_balcony": payload.has_balcony, + "median_price": result.median_price_rub, + "range_low": result.range_low_rub, + "range_high": result.range_high_rub, + "median_price_per_m2": result.median_price_per_m2, + "confidence": result.confidence, + "n_analogs": result.n_analogs, + "analogs": analogs_json, + "actual_deals": deals_json, + "expires_at": result.expires_at, + }, + ) + db.commit() + + logger.info( + "trade_in estimate saved id=%s rooms=%d area=%.1f confidence=%s", + result.estimate_id, + payload.rooms, + payload.area_m2, + result.confidence, + ) + return result + + +@router.get("/estimate/{estimate_id}", response_model=AggregatedEstimate) +def get_estimate( + estimate_id: UUID, + db: Annotated[Session, Depends(get_db)], +) -> AggregatedEstimate: + """Получить сохранённую оценку по UUID (для генерации PDF). + + Возвращает 404 если оценка не найдена или TTL истёк. + """ + row = db.execute( + text( + """ + SELECT id, median_price, range_low, range_high, median_price_per_m2, + confidence, n_analogs, analogs, actual_deals, expires_at, + address, area_m2, rooms + FROM trade_in_estimates + WHERE id = CAST(:id AS uuid) + AND expires_at > NOW() + """ + ), + {"id": str(estimate_id)}, + ).fetchone() + + if row is None: + raise HTTPException(status_code=404, detail="estimate not found or expired") + + analogs = [AnalogLot(**a) for a in (row.analogs or [])] + actual_deals = [AnalogLot(**a) for a in (row.actual_deals or [])] + + return AggregatedEstimate( + estimate_id=row.id, + median_price_rub=row.median_price, + range_low_rub=row.range_low, + range_high_rub=row.range_high, + median_price_per_m2=row.median_price_per_m2, + confidence=row.confidence, + n_analogs=row.n_analogs, + period_months=24, + analogs=analogs, + actual_deals=actual_deals, + expires_at=row.expires_at, + ) + + +@router.get("/estimate/{estimate_id}/pdf") +def estimate_pdf( + estimate_id: UUID, + db: Annotated[Session, Depends(get_db)], + brand: str | None = None, +) -> Response: + """Скачать 4-страничный PDF-отчёт для оценки trade-in. + + Возвращает application/pdf attachment. + 404 — оценка не найдена. + 410 — оценка просрочена (TTL 24ч). + """ + row = db.execute( + text( + """ + SELECT id, median_price, range_low, range_high, median_price_per_m2, + confidence, confidence_explanation, n_analogs, + analogs, actual_deals, sources_used, data_freshness_minutes, + expires_at, + address, lat, lon, area_m2, rooms, floor, total_floors, + year_built, house_type, repair_state, has_balcony + FROM trade_in_estimates + WHERE id = CAST(:id AS uuid) + """ + ), + {"id": str(estimate_id)}, + ).fetchone() + + if row is None: + raise HTTPException(status_code=404, detail="estimate not found") + + if row.expires_at.replace(tzinfo=UTC) < datetime.now(tz=UTC): + raise HTTPException(status_code=410, detail="estimate expired (24h TTL)") + + analogs = [AnalogLot(**a) for a in (row.analogs or [])] + actual_deals = [AnalogLot(**a) for a in (row.actual_deals or [])] + + estimate = AggregatedEstimate( + estimate_id=row.id, + median_price_rub=row.median_price, + range_low_rub=row.range_low, + range_high_rub=row.range_high, + median_price_per_m2=row.median_price_per_m2, + confidence=row.confidence, + confidence_explanation=row.confidence_explanation, + n_analogs=row.n_analogs, + period_months=24, + analogs=analogs, + actual_deals=actual_deals, + expires_at=row.expires_at, + target_address=row.address, + target_lat=row.lat, + target_lon=row.lon, + sources_used=row.sources_used or [], + data_freshness_minutes=row.data_freshness_minutes, + ) + input_snapshot = { + "address": row.address, + "area_m2": row.area_m2, + "rooms": row.rooms, + "floor": row.floor, + "total_floors": row.total_floors, + "year_built": row.year_built, + "house_type": row.house_type, + "repair_state": row.repair_state, + "has_balcony": row.has_balcony, + } + + from app.services.brand import get_brand as _resolve_brand + brand_obj = _resolve_brand(brand, db) + pdf_bytes = generate_trade_in_pdf(estimate, input_snapshot, brand=brand_obj) + filename = f"trade-in-{brand_obj.slug}-{estimate_id}.pdf" + logger.info( + "PDF generated estimate_id=%s brand=%s size=%d", + estimate_id, brand_obj.slug, len(pdf_bytes), + ) + return Response( + content=pdf_bytes, + media_type="application/pdf", + headers={"Content-Disposition": f'attachment; filename="{filename}"'}, + ) diff --git a/tradein-mvp/backend/app/core/__init__.py b/tradein-mvp/backend/app/core/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tradein-mvp/backend/app/core/config.py b/tradein-mvp/backend/app/core/config.py new file mode 100644 index 00000000..711797e7 --- /dev/null +++ b/tradein-mvp/backend/app/core/config.py @@ -0,0 +1,22 @@ +"""Минимальный settings для standalone trade-in MVP.""" + +from pydantic_settings import BaseSettings, SettingsConfigDict + + +class Settings(BaseSettings): + model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf-8", extra="ignore") + + database_url: str = "postgresql+psycopg://tradein:tradein@postgres:5432/tradein" + cors_origins: list[str] = ["http://localhost", "http://localhost:3000", "http://localhost:8080"] + environment: str = "dev" + + # Geocoder + yandex_geocoder_key: str | None = None # 25K req/day free после регистрации + yandex_suggest_key: str | None = None # для frontend autocomplete (proxy через backend) + contact_email: str = "erginrajpopxbe@outlook.com" # для User-Agent в Nominatim (Nominatim Usage Policy) + + # Public URL — для QR-кода в PDF, shareable links, etc. + public_url: str = "http://127.0.0.1:8080" + + +settings = Settings() diff --git a/tradein-mvp/backend/app/core/db.py b/tradein-mvp/backend/app/core/db.py new file mode 100644 index 00000000..7853cad9 --- /dev/null +++ b/tradein-mvp/backend/app/core/db.py @@ -0,0 +1,21 @@ +from collections.abc import Generator + +from sqlalchemy import create_engine +from sqlalchemy.orm import DeclarativeBase, Session, sessionmaker + +from app.core.config import settings + +engine = create_engine(settings.database_url, pool_pre_ping=True, future=True) +SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine, expire_on_commit=False) + + +class Base(DeclarativeBase): + pass + + +def get_db() -> Generator[Session, None, None]: + db = SessionLocal() + try: + yield db + finally: + db.close() diff --git a/tradein-mvp/backend/app/main.py b/tradein-mvp/backend/app/main.py new file mode 100644 index 00000000..c886cff8 --- /dev/null +++ b/tradein-mvp/backend/app/main.py @@ -0,0 +1,45 @@ +"""Trade-In MVP — FastAPI entry point. + +Standalone версия, выделена из основного gendesign repo для локальной разработки. +Только trade-in фича; никаких других роутеров (concepts/parcels/analytics/etc) нет. +""" + +from __future__ import annotations + +import logging + +from fastapi import FastAPI +from fastapi.middleware.cors import CORSMiddleware + +from app.api.v1 import admin, brand, geocode, trade_in +from app.core.config import settings + +logging.basicConfig( + level=logging.INFO, + format="%(asctime)s %(levelname)s %(name)s: %(message)s", +) + +app = FastAPI( + title="Trade-In MVP API", + description="Оценка вторичного жилья (выкупная стоимость) — копия trade-in feature из gendesign", + version="0.1.0", +) + +app.add_middleware( + CORSMiddleware, + allow_origins=settings.cors_origins, + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], +) + + +@app.get("/health") +def health() -> dict[str, str]: + return {"status": "ok", "environment": settings.environment} + + +app.include_router(geocode.router, prefix="/api/v1/geocode", tags=["geocode"]) +app.include_router(admin.router, prefix="/api/v1/admin", tags=["admin"]) +app.include_router(brand.router, prefix="/api/v1/brand", tags=["brand"]) +app.include_router(trade_in.router, prefix="/api/v1/trade-in", tags=["trade-in"]) diff --git a/tradein-mvp/backend/app/schemas/__init__.py b/tradein-mvp/backend/app/schemas/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tradein-mvp/backend/app/schemas/trade_in.py b/tradein-mvp/backend/app/schemas/trade_in.py new file mode 100644 index 00000000..4aeebd88 --- /dev/null +++ b/tradein-mvp/backend/app/schemas/trade_in.py @@ -0,0 +1,62 @@ +"""Pydantic schemas for Trade-In Estimator. + +POST /api/v1/trade-in/estimate → AggregatedEstimate +""" + +from __future__ import annotations + +from datetime import date, datetime +from typing import Literal +from uuid import UUID + +from pydantic import BaseModel, Field + + +class TradeInEstimateInput(BaseModel): + address: str = Field(min_length=3, max_length=500) + area_m2: float = Field(gt=10, lt=500) + rooms: int = Field(ge=0, le=10) # 0 = студия + floor: int = Field(ge=1, le=100) + total_floors: int = Field(ge=1, le=100) + year_built: int | None = Field(default=None, ge=1800, le=2100) + house_type: Literal["panel", "brick", "monolith", "monolith_brick", "other"] | None = None + repair_state: Literal["needs_repair", "standard", "good", "excellent"] | None = None + has_balcony: bool | None = None + + +class AnalogLot(BaseModel): + address: str + area_m2: float + rooms: int + floor: int | None + total_floors: int | None + price_rub: int + price_per_m2: int + listing_date: date | None + days_on_market: int | None + photo_url: str | None = None + # ── Новые поля (Слой 5.2 — clickable links) ── + source: str | None = None # 'avito' / 'cian' / 'domklik' / 'rosreestr' + source_url: str | None = None # ссылка на оригинальное объявление / сделку + distance_m: int | None = None # расстояние до целевой квартиры в метрах + + +class AggregatedEstimate(BaseModel): + estimate_id: UUID + median_price_rub: int + range_low_rub: int + range_high_rub: int + median_price_per_m2: int + confidence: Literal["low", "medium", "high"] + confidence_explanation: str | None = None # «Найдено 15 аналогов, разброс ±7%» + n_analogs: int + period_months: int # 24 + analogs: list[AnalogLot] # top 5-10 listings + actual_deals: list[AnalogLot] # реальные продажи last 12 mo + expires_at: datetime + # ── Дополнительные метаданные ── + target_address: str | None = None # geocoded full address + target_lat: float | None = None + target_lon: float | None = None + sources_used: list[str] = Field(default_factory=list) # ['avito', 'cian', 'rosreestr'] + data_freshness_minutes: int | None = None # сколько минут назад был самый свежий парсинг diff --git a/tradein-mvp/backend/app/services/__init__.py b/tradein-mvp/backend/app/services/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tradein-mvp/backend/app/services/brand.py b/tradein-mvp/backend/app/services/brand.py new file mode 100644 index 00000000..370ff9f7 --- /dev/null +++ b/tradein-mvp/backend/app/services/brand.py @@ -0,0 +1,66 @@ +"""Brand resolver — multi-tenant white-label. + +Читает бренд по slug из `brands` Postgres-таблицы. +Используется PDF exporter + frontend (через /api/v1/brand/{slug} endpoint). +""" + +from __future__ import annotations + +import logging +from dataclasses import dataclass + +from sqlalchemy import text +from sqlalchemy.orm import Session + +logger = logging.getLogger(__name__) + + +@dataclass(frozen=True, slots=True) +class Brand: + slug: str + name: str + logo_url: str | None + primary_color: str + accent_color: str + footer_text: str | None + pdf_disclaimer: str | None + + +_DEFAULT = Brand( + slug="generic", + name="Trade-In Estimator", + logo_url=None, + primary_color="#1d4ed8", + accent_color="#f59e0b", + footer_text=None, + pdf_disclaimer=None, +) + + +def get_brand(slug: str | None, db: Session) -> Brand: + """Возвращает Brand по slug. Fallback на 'generic' если не найден.""" + if not slug: + return _DEFAULT + row = db.execute( + text( + """ + SELECT slug, name, logo_url, primary_color, accent_color, + footer_text, pdf_disclaimer + FROM brands + WHERE slug = :slug + """ + ), + {"slug": slug.lower()}, + ).fetchone() + if row is None: + logger.info("brand not found: %s — using generic", slug) + return _DEFAULT + return Brand( + slug=row.slug, + name=row.name, + logo_url=row.logo_url, + primary_color=row.primary_color or _DEFAULT.primary_color, + accent_color=row.accent_color or _DEFAULT.accent_color, + footer_text=row.footer_text, + pdf_disclaimer=row.pdf_disclaimer, + ) diff --git a/tradein-mvp/backend/app/services/estimator.py b/tradein-mvp/backend/app/services/estimator.py new file mode 100644 index 00000000..9975723e --- /dev/null +++ b/tradein-mvp/backend/app/services/estimator.py @@ -0,0 +1,462 @@ +"""Trade-In Estimator — реальное SQL aggregation поверх listings + deals. + +Заменяет старый _mock_estimate() из api/v1/trade_in.py. + +Алгоритм: +1. Geocode address → (lat, lon) +2. SELECT listings с фильтрами: + - PostGIS ST_DWithin (geom, point, 800m) — радиус поиска + - rooms = target_rooms (точное совпадение) + - area_m2 BETWEEN target × 0.85 AND target × 1.15 + - scraped_at > NOW() - 14 days (свежие) + - is_active = true +3. Tukey outlier filter (1.5 × IQR rule) +4. Median / Q1 / Q3 / count → confidence +5. То же для deals (period = 12 mo). +6. Сохранить в trade_in_estimates + вернуть AggregatedEstimate +""" + +from __future__ import annotations + +import json +import logging +from datetime import UTC, datetime, timedelta +from typing import Any +from uuid import UUID, uuid4 + +from sqlalchemy import text +from sqlalchemy.orm import Session + +from app.schemas.trade_in import AggregatedEstimate, AnalogLot, TradeInEstimateInput +from app.services.geocoder import GeocodeResult, geocode + +logger = logging.getLogger(__name__) + + +# ── Constants ──────────────────────────────────────────────────────────────── +DEFAULT_RADIUS_M = 800 +FALLBACK_RADIUS_M = 2000 +AREA_TOLERANCE = 0.15 # ±15% площади +LISTINGS_FRESH_DAYS = 14 # объявления не старше 14 дней +DEALS_PERIOD_MONTHS = 12 # сделки за последний год + + +# ── Public ─────────────────────────────────────────────────────────────────── +async def estimate_quality( + payload: TradeInEstimateInput, db: Session +) -> AggregatedEstimate: + """Главная функция — оценка квартиры по реальным данным. + + Returns: + AggregatedEstimate с estimate_id, медианой, диапазоном, аналогами, сделками. + """ + # 1. Geocode + geo: GeocodeResult | None = None + if payload.address: + geo = await geocode(payload.address, db) + + if geo is None: + # Без координат не можем искать через PostGIS. Возвращаем low confidence. + logger.warning("geocode failed for %s — returning low-confidence estimate", payload.address) + return _empty_estimate(payload, reason="address_not_geocoded") + + # 2. Three-tier fallback: + # a) 800m + ±15% area + # b) 2km + ±15% area (fallback_used = True) + # c) 2km + ±25% area (fallback_used = True, area_widened = True) + listings, fallback_used = _fetch_analogs( + db, lat=geo.lat, lon=geo.lon, rooms=payload.rooms, area=payload.area_m2, + radius_m=DEFAULT_RADIUS_M, + ) + area_widened = False + + if len(listings) < 5: + listings_wide, _ = _fetch_analogs( + db, lat=geo.lat, lon=geo.lon, rooms=payload.rooms, area=payload.area_m2, + radius_m=FALLBACK_RADIUS_M, + ) + if len(listings_wide) > len(listings): + listings = listings_wide + fallback_used = True + + # Tier C: если даже на 2км мало — расширяем area tolerance до ±25% + # (актуально для отдалённых районов / новостроек с нестандартной планировкой) + if len(listings) < 3: + listings_widearea, _ = _fetch_analogs( + db, lat=geo.lat, lon=geo.lon, rooms=payload.rooms, area=payload.area_m2, + radius_m=FALLBACK_RADIUS_M, area_tolerance=0.25, + ) + if len(listings_widearea) > len(listings): + listings = listings_widearea + fallback_used = True + area_widened = True + + # 3. Outlier filter + listings_clean = _filter_outliers(listings) + + # 4. Aggregation + if listings_clean: + prices_ppm2 = sorted(lot["price_per_m2"] for lot in listings_clean if lot["price_per_m2"]) + median_ppm2 = _percentile(prices_ppm2, 0.5) + q1_ppm2 = _percentile(prices_ppm2, 0.25) + q3_ppm2 = _percentile(prices_ppm2, 0.75) + median_price = int(median_ppm2 * payload.area_m2) + range_low = int(q1_ppm2 * payload.area_m2) + range_high = int(q3_ppm2 * payload.area_m2) + n_analogs = len(listings_clean) + else: + median_ppm2 = 0 + median_price = 0 + range_low = 0 + range_high = 0 + n_analogs = 0 + + confidence, explanation = _compute_confidence( + n_analogs, median_ppm2, q1_ppm2 if listings_clean else 0, + q3_ppm2 if listings_clean else 0, fallback_used, area_widened, + ) + + # 5. Deals — фактические сделки за период + deals = _fetch_deals( + db, lat=geo.lat, lon=geo.lon, rooms=payload.rooms, area=payload.area_m2, + radius_m=DEFAULT_RADIUS_M, + ) + + # 6. Сохраняем в trade_in_estimates + estimate_id = uuid4() + now = datetime.now(tz=UTC) + expires_at = now + timedelta(hours=24) + + analogs_lots = [_listing_to_analog(lot) for lot in listings_clean[:10]] + deals_lots = [_deal_to_analog(d) for d in deals[:10]] + + sources_used_pre = sorted({lot.get("source") for lot in listings_clean if lot.get("source")}) + freshness_pre = _compute_freshness_minutes(listings_clean) + db.execute( + text( + """ + INSERT INTO trade_in_estimates ( + id, address, lat, lon, + area_m2, rooms, floor, total_floors, + year_built, house_type, repair_state, has_balcony, + median_price, range_low, range_high, median_price_per_m2, + confidence, confidence_explanation, n_analogs, + analogs, actual_deals, + sources_used, data_freshness_minutes, + expires_at + ) VALUES ( + CAST(:id AS uuid), + :address, :lat, :lon, + :area, :rooms, :floor, :total_floors, + :year_built, :house_type, :repair_state, :has_balcony, + :median_price, :range_low, :range_high, :median_ppm2, + :confidence, :explanation, :n_analogs, + CAST(:analogs_json AS jsonb), + CAST(:deals_json AS jsonb), + CAST(:sources_json AS jsonb), + :freshness, + :expires_at + ) + """ + ), + { + "id": str(estimate_id), + "address": geo.full_address, + "lat": geo.lat, + "lon": geo.lon, + "area": payload.area_m2, + "rooms": payload.rooms, + "floor": payload.floor, + "total_floors": payload.total_floors, + "year_built": payload.year_built, + "house_type": payload.house_type, + "repair_state": payload.repair_state, + "has_balcony": payload.has_balcony, + "median_price": median_price, + "range_low": range_low, + "range_high": range_high, + "median_ppm2": int(median_ppm2), + "confidence": confidence, + "explanation": explanation, + "n_analogs": n_analogs, + "analogs_json": json.dumps( + [a.model_dump(mode="json") for a in analogs_lots], ensure_ascii=False + ), + "deals_json": json.dumps( + [a.model_dump(mode="json") for a in deals_lots], ensure_ascii=False + ), + "sources_json": json.dumps(sources_used_pre, ensure_ascii=False), + "freshness": freshness_pre, + "expires_at": expires_at, + }, + ) + db.commit() + + logger.info( + "estimate: id=%s addr=%s rooms=%d area=%.1f → median=%d (n=%d, conf=%s)", + estimate_id, + geo.full_address[:60], + payload.rooms, + payload.area_m2, + median_price, + n_analogs, + confidence, + ) + + sources_used = sorted({lot.source for lot in analogs_lots if lot.source}) + freshness_min = _compute_freshness_minutes(listings_clean) + + return AggregatedEstimate( + estimate_id=estimate_id, + median_price_rub=median_price, + range_low_rub=range_low, + range_high_rub=range_high, + median_price_per_m2=int(median_ppm2), + confidence=confidence, + confidence_explanation=explanation, + n_analogs=n_analogs, + period_months=DEALS_PERIOD_MONTHS, + analogs=analogs_lots, + actual_deals=deals_lots, + expires_at=expires_at, + target_address=geo.full_address, + target_lat=geo.lat, + target_lon=geo.lon, + sources_used=sources_used, + data_freshness_minutes=freshness_min, + ) + + +def _compute_freshness_minutes(lots: list[dict[str, Any]]) -> int | None: + """Минут с последнего парсинга — для UI «обновлено N мин назад».""" + if not lots: + return None + from datetime import datetime as _dt + + now = _dt.now(tz=UTC) + scraped = [lot.get("scraped_at") or lot.get("listing_date") for lot in lots] + scraped_dt: list[datetime] = [] + for s in scraped: + if s is None: + continue + # listings rows из mappings — scraped_at это datetime, не date + if hasattr(s, "tzinfo"): + scraped_dt.append(s if s.tzinfo else s.replace(tzinfo=UTC)) + if not scraped_dt: + return None + return int((now - max(scraped_dt)).total_seconds() / 60) + + +# ── Internals ──────────────────────────────────────────────────────────────── +def _fetch_analogs( + db: Session, *, lat: float, lon: float, rooms: int, area: float, radius_m: int, + area_tolerance: float = AREA_TOLERANCE, +) -> tuple[list[dict[str, Any]], bool]: + """SELECT аналогов с PostGIS distance + фильтры. + + Returns: + (list_of_listings_as_dicts, fallback_radius_used_flag) + """ + rows = db.execute( + text( + """ + SELECT + source, source_url, address, lat, lon, + rooms, area_m2, floor, total_floors, + price_rub, price_per_m2, + listing_date, days_on_market, photo_urls, + scraped_at, + ST_Distance(geom::geography, ST_MakePoint(:lon, :lat)::geography) AS distance_m + FROM listings + WHERE ST_DWithin(geom::geography, ST_MakePoint(:lon, :lat)::geography, :radius) + AND rooms = :rooms + AND area_m2 BETWEEN :area_min AND :area_max + AND is_active = true + AND scraped_at > NOW() - (:fresh_days || ' days')::interval + AND price_rub > 0 + ORDER BY distance_m + LIMIT 50 + """ + ), + { + "lat": lat, + "lon": lon, + "radius": radius_m, + "rooms": rooms, + "area_min": area * (1 - area_tolerance), + "area_max": area * (1 + area_tolerance), + "fresh_days": LISTINGS_FRESH_DAYS, + }, + ).mappings().all() + + return [dict(r) for r in rows], radius_m > DEFAULT_RADIUS_M + + +def _fetch_deals( + db: Session, *, lat: float, lon: float, rooms: int, area: float, radius_m: int +) -> list[dict[str, Any]]: + rows = db.execute( + text( + """ + SELECT + source, address, lat, lon, + rooms, area_m2, floor, total_floors, + price_rub, price_per_m2, + deal_date, days_on_market, + ST_Distance(geom::geography, ST_MakePoint(:lon, :lat)::geography) AS distance_m + FROM deals + WHERE ST_DWithin(geom::geography, ST_MakePoint(:lon, :lat)::geography, :radius) + AND rooms = :rooms + AND area_m2 BETWEEN :area_min AND :area_max + AND deal_date > NOW() - (:months || ' months')::interval + AND price_rub > 0 + ORDER BY deal_date DESC + LIMIT 30 + """ + ), + { + "lat": lat, + "lon": lon, + "radius": radius_m, + "rooms": rooms, + "area_min": area * (1 - AREA_TOLERANCE), + "area_max": area * (1 + AREA_TOLERANCE), + "months": DEALS_PERIOD_MONTHS, + }, + ).mappings().all() + + return [dict(r) for r in rows] + + +def _filter_outliers(lots: list[dict[str, Any]]) -> list[dict[str, Any]]: + """Tukey IQR rule: исключаем точки вне [Q1 - 1.5×IQR, Q3 + 1.5×IQR].""" + if len(lots) < 5: + return lots # на маленькой выборке нечего фильтровать + + prices = sorted(lot["price_per_m2"] for lot in lots if lot.get("price_per_m2")) + if len(prices) < 4: + return lots + + q1 = _percentile(prices, 0.25) + q3 = _percentile(prices, 0.75) + iqr = q3 - q1 + low = q1 - 1.5 * iqr + high = q3 + 1.5 * iqr + + clean = [lot for lot in lots if low <= lot.get("price_per_m2", 0) <= high] + if len(clean) < len(lots): + logger.info("outlier filter: %d → %d (Q1=%d Q3=%d)", len(lots), len(clean), q1, q3) + return clean + + +def _percentile(sorted_values: list[float], p: float) -> float: + """Linear interpolation percentile (не округляем — оставляем float).""" + if not sorted_values: + return 0.0 + if len(sorted_values) == 1: + return float(sorted_values[0]) + n = len(sorted_values) + rank = p * (n - 1) + lo = int(rank) + hi = min(lo + 1, n - 1) + frac = rank - lo + return sorted_values[lo] + (sorted_values[hi] - sorted_values[lo]) * frac + + +def _compute_confidence( + n_analogs: int, + median_ppm2: float, + q1: float, + q3: float, + fallback_radius_used: bool, + area_widened: bool = False, +) -> tuple[str, str]: + """Confidence + explanation string. + + high — n≥10 AND IQR/median < 0.15 + medium — n≥5 OR IQR/median < 0.25 + low — иначе + """ + if median_ppm2 == 0: + return "low", "Не найдено аналогов — попробуйте уточнить адрес или расширить параметры." + + iqr = q3 - q1 + iqr_pct = iqr / median_ppm2 if median_ppm2 > 0 else 1.0 + notes = [] + if fallback_radius_used: + notes.append("расширили радиус до 2 км") + if area_widened: + notes.append("расширили допуск по площади до ±25%") + fallback_note = f" ({', '.join(notes)} из-за нехватки данных)" if notes else "" + + if n_analogs >= 10 and iqr_pct < 0.15: + return ( + "high", + f"Найдено {n_analogs} аналогов, разброс цены ±{int(iqr_pct * 100 / 2)}% от медианы{fallback_note}.", + ) + # medium только если есть достаточно точек ИЛИ узкий разброс при ≥3 точках + if n_analogs >= 5 or (n_analogs >= 3 and iqr_pct < 0.25): + return ( + "medium", + f"Найдено {n_analogs} аналогов, разброс цены ±{int(iqr_pct * 100 / 2)}% от медианы{fallback_note}.", + ) + return ( + "low", + f"Только {n_analogs} аналог{'а' if 2 <= n_analogs <= 4 else 'ов' if n_analogs != 1 else ''}, " + f"разброс ±{int(iqr_pct * 100 / 2)}% — рекомендуется ручная проверка{fallback_note}.", + ) + + +def _listing_to_analog(row: dict[str, Any]) -> AnalogLot: + return AnalogLot( + address=row.get("address") or "", + area_m2=float(row.get("area_m2") or 0), + rooms=int(row.get("rooms") or 0), + floor=row.get("floor"), + total_floors=row.get("total_floors"), + price_rub=int(row["price_rub"]), + price_per_m2=int(row.get("price_per_m2") or 0), + listing_date=row.get("listing_date"), + days_on_market=row.get("days_on_market"), + photo_url=(row.get("photo_urls") or [None])[0] if isinstance(row.get("photo_urls"), list) else None, + source=row.get("source"), + source_url=row.get("source_url"), + distance_m=int(row["distance_m"]) if row.get("distance_m") is not None else None, + ) + + +def _deal_to_analog(row: dict[str, Any]) -> AnalogLot: + """deals не имеют photo_url — упрощённо.""" + return AnalogLot( + address=row.get("address") or "", + area_m2=float(row.get("area_m2") or 0), + rooms=int(row.get("rooms") or 0), + floor=row.get("floor"), + total_floors=row.get("total_floors"), + price_rub=int(row["price_rub"]), + price_per_m2=int(row.get("price_per_m2") or 0), + listing_date=row.get("deal_date"), + days_on_market=row.get("days_on_market"), + photo_url=None, + source=row.get("source"), + source_url=None, # rosreestr сделки без публичной ссылки + distance_m=int(row["distance_m"]) if row.get("distance_m") is not None else None, + ) + + +def _empty_estimate(payload: TradeInEstimateInput, *, reason: str) -> AggregatedEstimate: + """Fallback когда нет данных для оценки.""" + now = datetime.now(tz=UTC) + return AggregatedEstimate( + estimate_id=uuid4(), + median_price_rub=0, + range_low_rub=0, + range_high_rub=0, + median_price_per_m2=0, + confidence="low", + n_analogs=0, + period_months=DEALS_PERIOD_MONTHS, + analogs=[], + actual_deals=[], + expires_at=now + timedelta(hours=24), + ) diff --git a/tradein-mvp/backend/app/services/exporters/__init__.py b/tradein-mvp/backend/app/services/exporters/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tradein-mvp/backend/app/services/exporters/trade_in_pdf.py b/tradein-mvp/backend/app/services/exporters/trade_in_pdf.py new file mode 100644 index 00000000..f7d0ac98 --- /dev/null +++ b/tradein-mvp/backend/app/services/exporters/trade_in_pdf.py @@ -0,0 +1,979 @@ +"""PDF генератор для Trade-In Estimator — Брусника-style (точное соответствие референсу docs/BRUSNIKA_REFERENCE_EKB-2485.pdf). + +Структура отчёта — 4 страницы: + 1. Cover — № отчёта + параметры объекта + 2 диапазона цен + 3 блока «Что важно» + 2. Listings — рынок квартир-аналогов по объявлениям + таблица примеров + 3. Deals — фактические сделки + таблица примеров + 4. Offer — формирование выкупной стоимости (Trade-In vs самопродажа) + 4 преимущества + +White-label через Brand: PRINZIP / Практика / generic (см. app/services/brand.py). +Расширения над Брусникой (сохранены): source badges + дистанция + кликабельные ссылки + QR-код. +""" + +from __future__ import annotations + +import base64 +import datetime as dt +import html as _html +import io +import logging +from uuid import UUID + +import segno +from PIL import Image, ImageDraw +from weasyprint import CSS, HTML + +from app.core.config import settings +from app.schemas.trade_in import AggregatedEstimate, AnalogLot + + +def _bar_svg_data_url(q_low: float = 0.20, q_high: float = 0.80) -> str: + """SVG диапазон-бара как data URI. WeasyPrint надёжно рендерит SVG (как QR-код).""" + width, height = 600, 32 + x1 = width * q_low + x2 = width * q_high + svg = ( + f'' + f'' + f'' + f'' + ) + return f"data:image/svg+xml;base64,{base64.b64encode(svg.encode('utf-8')).decode('ascii')}" + +logger = logging.getLogger(__name__) + + +# ── Source pseudo-logos (текстовые pill-badges как у Брусники с логотипами) ── +_SOURCE_LOGO_COLORS: dict[str, tuple[str, str]] = { + "avito": ("#00aaff", "#fff"), # Avito brand blue (упрощённо) + "cian": ("#0468ff", "#fff"), # Циан фирменный синий + "domklik": ("#1ab248", "#fff"), # ДомКлик зелёный Сбер + "yandex": ("#fc3f1d", "#fff"), # Я.Недвижимость красный + "n1": ("#ff6b00", "#fff"), # N1 оранжевый + "rosreestr": ("#003d82", "#fff"), # Росреестр тёмно-синий + "etazhi": ("#e30613", "#fff"), # Этажи красный +} + +_SOURCE_DISPLAY_NAMES: dict[str, str] = { + "avito": "Avito", + "cian": "Циан", + "domklik": "Домклик · Сбер", + "yandex": "Я.Недвижимость", + "n1": "N1", + "rosreestr": "Росреестр", + "etazhi": "Этажи", +} + + +def _source_logo_pill(source: str) -> str: + """Pill-badge с цветом источника (заменяет реальные логотипы Брусники).""" + bg, fg = _SOURCE_LOGO_COLORS.get(source, ("#6b7280", "#fff")) + name = _SOURCE_DISPLAY_NAMES.get(source, source.title()) + return ( + f"{_html.escape(name)}" + ) + + +def _source_badge_inline(source: str | None) -> str: + """Маленький source badge для table cells (без фона).""" + if not source: + return "" + bg, fg = _SOURCE_LOGO_COLORS.get(source, ("#6b7280", "#fff")) + name = _SOURCE_DISPLAY_NAMES.get(source, source.title()) + return ( + f"{_html.escape(name)}" + ) + + +# ── Helpers ────────────────────────────────────────────────────────────────── + + +def _fmt_rub(value: int) -> str: + """12 500 000 ₽""" + return f"{value:,}".replace(",", " ") + " ₽" + + +def _fmt_rub_m(value: int) -> str: + """3.4 млн. руб.""" + m = value / 1_000_000 + return f"{m:.1f}".replace(".", ",") + " млн. руб." + + +def _fmt_ppm2(value: int) -> str: + """101 176""" + return f"{value:,}".replace(",", " ") + + +def _report_number(estimate_id: UUID) -> str: + """Брусника-style № отчёта: 'EKБ-NNNN-XXXXXXX' где NNNN — короткий код.""" + short = int(estimate_id.int) % 10_000 + long = int(estimate_id.int) % 10_000_000_000 + return f"EKБ-{short:04d}-{long:010d}" + + +def _qr_code_data_url(text: str, size: int = 4) -> str: + """QR-код как SVG data URL.""" + qr = segno.make(text, error="m") + buf = io.BytesIO() + qr.save(buf, kind="svg", scale=size, dark="#1a1d23", light="#ffffff") + return f"data:image/svg+xml;base64,{base64.b64encode(buf.getvalue()).decode('ascii')}" + + +def _conf_label(confidence: str) -> str: + return {"high": "Высокая", "medium": "Средняя", "low": "Низкая"}.get(confidence, confidence) + + +# ── Price range SVG bar (как у Брусники) ──────────────────────────────────── + + +_BAR_PNG_URL = _bar_svg_data_url() + + +def _price_range_bar( + range_low: int, + range_high: int, + *, + label_left: str | None = None, + label_right: str | None = None, + sub_label: str = "Рынок", + days_min: int | None = None, + days_max: int | None = None, + show_days: bool = False, +) -> str: + """Полоска диапазона цен в стиле Брусники — PNG через Pillow.""" + if range_high <= range_low: + return "" + + label_left = label_left or _fmt_rub_m(range_low) + label_right = label_right or _fmt_rub_m(range_high) + + days_overlay = "" + if show_days and days_min is not None and days_max is not None: + days_overlay = ( + f'' + f'' + f'' + f'' + f'' + f'
' + f'{days_min} дней' + f'' + f'{days_max} дней' + f'
' + ) + + # Ц-таблица: 3 ячейки фиксированной ширины с background-color на td. + # Высота через padding (WeasyPrint stable с padding на td). + days_row = "" + if show_days and days_min is not None and days_max is not None: + days_row = ( + f'' + f'' + f'{days_min} дней' + f'' + f'{days_max} дней' + f'' + ) + + return ( + f'' + f'' + f'' + f'' + f'' + f'' + f'' + f'' + f'' + f'' + f'{days_row}' + f'
' + f'{_html.escape(sub_label)}' + f'
' + f'{_html.escape(label_left)}' + f'{_html.escape(label_right)}
' + ) + + +# ── Page 1: Cover ──────────────────────────────────────────────────────────── + + +def _build_cover( + estimate: AggregatedEstimate, input_snapshot: dict, brand +) -> str: # type: ignore[no-untyped-def,type-arg] + today = dt.date.today() + expires = today + dt.timedelta(days=30) + report_num = _report_number(estimate.estimate_id) + + # Короткий адрес (для cover): берём первую часть до запятой + full_address = input_snapshot.get("address", "—") + address_short = full_address.split(",")[0:3] + address_short = ", ".join(s.strip() for s in address_short) + address = _html.escape(address_short or full_address) + area = input_snapshot.get("area_m2", 0) + rooms = input_snapshot.get("rooms", 0) + floor = input_snapshot.get("floor", 0) + total_floors = input_snapshot.get("total_floors", 0) + year_built = input_snapshot.get("year_built", "—") + house_type = input_snapshot.get("house_type") + repair_state = input_snapshot.get("repair_state") + has_balcony = input_snapshot.get("has_balcony") + + house_labels = { + "panel": "Панельный", + "brick": "Кирпичный", + "monolith": "Монолитный", + "monolith_brick": "Монолит-кирпич", + "other": "Другое", + } + repair_labels = { + "needs_repair": "Требуется ремонт", + "standard": "Стандартный", + "good": "Хороший", + "excellent": "Евроремонт", + } + + rooms_label = "Студия" if rooms == 0 else f"{rooms} комнат" + ("а" if rooms == 1 else "ы" if 2 <= rooms <= 4 else "") + house_label = house_labels.get(house_type, "—") if house_type else "—" + repair_label = repair_labels.get(repair_state, "Не указано") if repair_state else "Не указано" + balcony_label = "1" if has_balcony else "0" if has_balcony is False else "—" + + # Active market subband — 4-118 days range (как у Брусники). + # Если есть days_on_market в analogs — берём min/max, иначе фиксированно. + days_min, days_max = _days_on_market_range(estimate.analogs) + + # Deals range — если deals есть, считаем; иначе fallback к listings range + deals_low, deals_high = _deals_range(estimate.actual_deals, fallback=(estimate.range_low_rub, estimate.range_high_rub)) + + listings_bar = _price_range_bar( + estimate.range_low_rub, + estimate.range_high_rub, + sub_label="Активный рынок с аналогичным состоянием ремонта", + days_min=days_min, + days_max=days_max, + show_days=True, + ) + + deals_bar = _price_range_bar( + deals_low, + deals_high, + sub_label="Диапазон цен по фактическим сделкам", + ) + + qr_url = _qr_code_data_url( + f"{settings.public_url}/trade-in?id={estimate.estimate_id}", size=3 + ) + + return f""" +
+ + +
+ {_html.escape(brand.name).upper()} +
+ +

+ АНАЛИЗ РЫНКА И РАСЧЕТ ВЫКУПНОЙ СТОИМОСТИ КВАРТИРЫ +

+ + + + + + + + + + + + + + +
№ отчета{report_num}
Дата отчета{today.strftime("%d.%m.%Y")}
Срок действия данныхдо {expires.strftime("%d.%m.%Y")}
Адрес{address}
Год постройки{year_built}
Тип дома{house_label}
Этаж / этажность{floor} / {total_floors}
Площадь{area} м²
Планировка{rooms_label}
Состояние ремонта{repair_label}
Балкон / лоджия{balcony_label}
+ +

+ Диапазон цен в объявлениях + (без учета ремонта) +

+ {listings_bar} + +

+ Диапазон цен по фактическим сделкам +

+ {deals_bar} + + +

+ Что важно при оценке стоимости квартиры: +

+ + + + + + + + + + + + + +
Цены в объявлениях — ожидания собственниковФактические сделки проходят на 5–12% ниже, что подтверждают Росреестр, ДомКлик и продажи агенств недвижимости
Ремонт оценивается по состоянию, а не по вложенным суммамИнвестиции в 400 – 600 тыс. руб. повышают цену объекта всего на 150 – 250 тыс. руб — покупатель оценивает общее состояние квартиры
Неочевидные расходы при самостоятельной продажеПри самостоятельной продаже суммарные расходы могут достигать до 15% стоимости квартиры (торг, риелтор, нотариус, справки)
+ +

+ Этот отчёт онлайн: {settings.public_url}/trade-in?id={estimate.estimate_id} +

+ +
+""" + + +def _days_on_market_range(lots: list[AnalogLot]) -> tuple[int, int]: + """Min/max days_on_market по аналогам. Fallback 4-118 как у Брусники.""" + days = [lot.days_on_market for lot in lots if lot.days_on_market is not None] + if not days: + return 4, 118 + return min(days), max(days) + + +def _deals_range(deals: list[AnalogLot], fallback: tuple[int, int]) -> tuple[int, int]: + """Min/max price от deals. Fallback к listings range.""" + if not deals: + return fallback + prices = [d.price_rub for d in deals] + return min(prices), max(prices) + + +# ── Page 2: Listings (market) ──────────────────────────────────────────────── + + +def _build_listings_page( + estimate: AggregatedEstimate, input_snapshot: dict, brand +) -> str: # type: ignore[no-untyped-def,type-arg] + n_total = estimate.n_analogs + n_with_repair = max(3, int(n_total * 0.4)) # упрощение: ~40% с указанным ремонтом + + # Source logos (pseudo) — 5 максимальных + sources_to_show = estimate.sources_used or ["avito", "cian", "domklik", "yandex", "rosreestr"] + sources_html = "".join(_source_logo_pill(s) for s in sources_to_show[:5]) + + # Params правой колонки — параметры поиска (НЕ конкретной квартиры) + area = float(input_snapshot.get("area_m2", 0) or 0) + area_min = round(area * 0.85, 1) + area_max = round(area * 1.15, 1) + rooms = input_snapshot.get("rooms", 0) + year_built = input_snapshot.get("year_built") + year_range = f"{year_built - 2}-{year_built + 2}" if year_built else "—" + house_type = input_snapshot.get("house_type") + house_label = { + "panel": "Эконом до 2000 года", + "brick": "Кирпич до 2000", + "monolith": "Современный (монолит)", + "monolith_brick": "Современный (м-к)", + "other": "Любой", + }.get(house_type, "Любой") if house_type else "Любой" + repair_state = input_snapshot.get("repair_state") + repair_label = { + "needs_repair": "Требуется ремонт", + "standard": "Стандартный", + "good": "Хороший", + "excellent": "Евроремонт", + }.get(repair_state, "Любой") if repair_state else "Любой" + rooms_label = "Студия" if rooms == 0 else f"{rooms} комнаты" + + # Полоска диапазона + days_min, days_max = _days_on_market_range(estimate.analogs) + range_bar = _price_range_bar( + estimate.range_low_rub, + estimate.range_high_rub, + sub_label="Рынок", + days_min=days_min, + days_max=days_max, + show_days=True, + ) + + # Топ-5 примеров (отсортированных по distance) + top5 = sorted(estimate.analogs, key=lambda x: x.distance_m or 9999)[:5] + examples_rows = _examples_rows(top5) + + return f""" +
+ +
+ + {_html.escape(brand.name).upper()} + +
+ +

+ РЫНОК КВАРТИР – АНАЛОГОВ ПО ОБЪЯВЛЕНИЯМ +

+ + + + + + + +
+ + + + + +
Количество объявлений по аналогичным объектам{n_total} шт.
Количество объявлений по аналогичным объектам
+ (с учётом ремонта)
{n_with_repair} шт.
+
Источники данных
+
{sources_html}
+
+ + + + + + + +
Расположение± 1 км от локации дома
Тип дома{house_label}
Год постройки{year_range}
Диапазон площади{area_min} - {area_max} м²
Планировка{rooms_label}
Состояние ремонта{repair_label}
+
+ +

Диапазон цен в объявлениях

+ {range_bar} + + +

+ Примеры аналогичных объектов с учётом ремонта +

+ + + + + + + + + + + {examples_rows} +
Адрес квартирыИсточникСтоимость 1 м², руб.Стоимость объекта, руб.Срок экспозиции, дней
+ + + +
+""" + + +def _examples_rows(lots: list[AnalogLot]) -> str: + if not lots: + return "Нет данных" + rows = [] + for lot in lots: + addr = _html.escape(lot.address) + if lot.source_url: + addr_cell = f"{addr} ↗" + else: + addr_cell = addr + rows.append( + "" + f"{addr_cell}" + f"{_source_badge_inline(lot.source)}" + f"{_fmt_ppm2(lot.price_per_m2)}" + f"{_fmt_ppm2(lot.price_rub)}" + f"{lot.days_on_market or '—'}" + "" + ) + return "".join(rows) + + +# ── Page 3: Deals ──────────────────────────────────────────────────────────── + + +def _build_deals_page( + estimate: AggregatedEstimate, input_snapshot: dict, brand +) -> str: # type: ignore[no-untyped-def,type-arg] + n_deals = len(estimate.actual_deals) + today = dt.date.today() + period_start = today - dt.timedelta(days=estimate.period_months * 30) + + # Источники для сделок — Этажи / Домклик / Росреестр + deal_sources = ["etazhi", "domklik", "rosreestr"] + sources_html = "".join(_source_logo_pill(s) for s in deal_sources) + + area = float(input_snapshot.get("area_m2", 0) or 0) + area_min = round(area * 0.85, 1) + area_max = round(area * 1.15, 1) + rooms = input_snapshot.get("rooms", 0) + year_built = input_snapshot.get("year_built") + year_range = f"{year_built - 2}–{year_built + 2}" if year_built else "—" + house_type = input_snapshot.get("house_type") + house_label = { + "panel": "Эконом до 2000 года", + "brick": "Кирпич до 2000", + "monolith": "Современный (монолит)", + }.get(house_type, "Любой") if house_type else "Любой" + rooms_label = "Студия" if rooms == 0 else f"{rooms} комнаты" + + deals_low, deals_high = _deals_range(estimate.actual_deals, fallback=(estimate.range_low_rub, estimate.range_high_rub)) + days_min, days_max = _days_on_market_range(estimate.actual_deals) + range_bar = _price_range_bar( + deals_low, deals_high, sub_label="Рынок", + days_min=days_min, days_max=days_max, show_days=True, + ) + + top5 = estimate.actual_deals[:5] + examples_rows = _examples_rows(top5) + + return f""" +
+ +
+ + {_html.escape(brand.name).upper()} + +
+ +

+ ФАКТИЧЕСКИЕ СДЕЛКИ ПО КВАРТИРАМ — АНАЛОГАМ +

+ + + + + + +
+ + + + + +
Количество сделок по аналогичном объектам{n_deals} шт.
Период сделок{period_start.strftime("%m.%Y")} – {today.strftime("%m.%Y")}
+
Источники данных
+
{sources_html}
+
+ + + + + + +
Расположение± 1 км от локации дома
Тип дома{house_label}
Год постройки{year_range}
Диапазон площади{area_min} - {area_max} м²
Планировка{rooms_label}
+
+ +

Диапазон цен по фактическим сделкам

+ {range_bar} + +
+ По данным реальных сделок, квартиры продаются в среднем на 5–12 % дешевле, + чем заявлено в объявлениях +
+ +

+ Примеры аналогичных объектов +

+ + + + + + + + + + + {examples_rows} +
Адрес квартирыИсточникСтоимость 1 м², руб.Стоимость объекта, руб.Срок экспозиции, дней
+ + + +
+""" + + +# ── Page 4: Offer (Trade-In vs Самопродажа) ────────────────────────────────── + + +def _build_offer_page( + estimate: AggregatedEstimate, brand +) -> str: # type: ignore[no-untyped-def] + median = estimate.median_price_rub + + # Расчёт расходов как у Брусники: на основе медианы + listing_price = median # цена в объявлении + torg_pct_low, torg_pct_high = 5, 15 + torg_low = int(listing_price * torg_pct_low / 100) + torg_high = int(listing_price * torg_pct_high / 100) + + # После торга — средний по диапазону для остальных % + sold_price = listing_price - int(listing_price * 0.10) # ~10% торг + + rieltor_pct_low, rieltor_pct_high = 2, 3 + rieltor_low = int(sold_price * rieltor_pct_low / 100) + rieltor_high = int(sold_price * rieltor_pct_high / 100) + + rent_low, rent_high = 90_000, 150_000 # 3 месяца аренды (фикс) + juridical_low = 19_250 # фикс + ads_low, ads_high = 4_000, 36_000 # за 3 месяца + + total_low = torg_low + rieltor_low + rent_low + juridical_low + ads_low + total_high = torg_high + rieltor_high + rent_high + juridical_low + ads_high + + brand_short = _html.escape(brand.name) + trade_in_label = f"{brand_short}.Обмен" if brand.slug != "generic" else "Trade-In" + + return f""" +
+ +
+ + {brand_short.upper()} + +
+ +

+ ФОРМИРОВАНИЕ ВЫКУПНОЙ СТОИМОСТИ +

+ +

Структура стоимости сделки

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Продажа через
{trade_in_label} +
+ Самостоятельная продажа, руб. +
+
Торг потенциальных покупателей
+
при стоимости квартиры в объявлении {_fmt_rub(listing_price)}
+
Не применимо + от {_fmt_rub(torg_low)} – {_fmt_rub(torg_high)}
+ от {torg_pct_low}–{torg_pct_high}% +
+
Услуги риэлтора при продаже квартиры
+
с минимальным торгом за {_fmt_rub(sold_price)}
+
бесплатно + {_fmt_rub(rieltor_low)} - {_fmt_rub(rieltor_high)}
+ от {rieltor_pct_low}–{rieltor_pct_high}% +
+
Аренда после сделки
+
однокомнатной квартиры на 3 месяца
+
бесплатно + {_fmt_rub(rent_low)} - {_fmt_rub(rent_high)} +
+
Юридическое сопровождение
+
Проверка документов и подготовка договоров
+
бесплатноот {_fmt_rub(juridical_low)}
+
Расходы на рекламу
+
Ежемесячное базовой продвижение объекта на Циан, Авито, Я.Недвижимости
+
бесплатно + от {_fmt_rub(ads_low)} - {_fmt_rub(ads_high)}
+ за 3 месяца +
Общие финансовые потери + от {_fmt_rub(total_low)} - {_fmt_rub(total_high)} +
+ +
+ Издержки при обмене сопоставимы с личными расходами собственника, которые возникают при + самостоятельной продаже квартиры +
+ +

Преимущества

+
+
+
+ + + +
+
Экономия времени
+
Берём на себя показы, переговоры и поиск покупателей
+
+
+
+ + + +
+
Юридическая безопасность
+
Проверяем документы, исключаем риски, сопровождаем на всех этапах
+
+
+
+ + + +
+
Фиксированная стоимость новостройки
+
Сохраняем цену выбранной планировки в {brand_short}
+
+
+
+ + + +
+
Гарантия цены
+
Снимаем угрозу колебаний рынка и удерживаем договорную стоимость
+
+
+ + + +
+""" + + +# ── CSS ────────────────────────────────────────────────────────────────────── + + +def _build_css(brand=None) -> str: # type: ignore[no-untyped-def] + primary = brand.primary_color if brand else "#1d4ed8" + return f""" +@page {{ + size: A4; + margin: 20mm 18mm 20mm 18mm; +}} +* {{ box-sizing: border-box; }} +body {{ + font-family: 'Helvetica', 'Arial', sans-serif; + font-size: 10pt; + color: #1a1d23; + margin: 0; + padding: 0; + line-height: 1.4; +}} +h1, h2, h3 {{ margin: 0; }} +.page {{ page-break-after: always; position: relative; }} +.page:last-child {{ page-break-after: avoid; }} + +.bold {{ font-weight: 700; }} + +/* Params table (Cover) */ +.params-table td {{ + padding: 2.5pt 4pt; + border-bottom: 1px solid #f3f4f6; + font-size: 9pt; +}} +.params-table td:first-child {{ + color: #6b7280; + width: 40%; +}} +.params-table td:last-child {{ + text-align: right; +}} + +/* Search params (Listings/Deals) */ +.search-params td {{ + padding: 4pt 0; + font-size: 9pt; +}} +.search-params td:first-child {{ + color: #6b7280; +}} +.search-params td:last-child {{ + text-align: right; +}} + +/* Range block */ +.range-block {{ + margin-top: 6pt; +}} + +/* Range bar — linear-gradient на одном div'е. WeasyPrint reliable. */ +.range-bar-strip {{ + width: 100%; + height: 16pt; + line-height: 14pt; + border: 1pt solid #9ca3af; + background: linear-gradient( + to right, + #ffffff 0%, #ffffff 20%, + #dc2626 20%, #dc2626 80%, + #ffffff 80%, #ffffff 100% + ); + margin: 4pt 0; + overflow: hidden; + color: transparent; + font-size: 1pt; +}} +.range-title {{ + font-size: 10pt; + font-weight: 700; + color: #1a1d23; + margin-bottom: 4pt; +}} + +/* Что важно — advice table */ +.advice-table td {{ + padding: 5pt 6pt; + border-bottom: 1px solid #f3f4f6; + vertical-align: top; + font-size: 8.5pt; + line-height: 1.3; +}} +.advice-title {{ + font-weight: 700; + width: 30%; + color: #1a1d23; +}} +.advice-text {{ + color: #4b5563; +}} + +/* Advantages (Offer) */ +.advantage-item {{ + border: 1px solid #e6e8ec; + border-radius: 4pt; + padding: 8pt; + text-align: left; +}} +.advantage-item .adv-ic {{ + display: block; + width: 28pt; + height: 28pt; + border-radius: 50%; + background: #fef2f2; + margin: 0 0 6pt 0; + line-height: 28pt; + text-align: center; +}} +.advantage-item .adv-ic svg {{ + vertical-align: middle; +}} +.advantage-item .adv-title {{ + font-weight: 700; + font-size: 8.5pt; + margin-bottom: 3pt; + color: {primary}; + letter-spacing: -0.01em; +}} +.advantage-item .adv-desc {{ + font-size: 7pt; + color: #5b6066; + line-height: 1.3; +}} +""" + + +# ── Public API ─────────────────────────────────────────────────────────────── + + +def generate_trade_in_pdf( + estimate: AggregatedEstimate, + input_snapshot: dict, # type: ignore[type-arg] + *, + brand=None, # type: ignore[no-untyped-def] +) -> bytes: + """Генерирует 4-страничный WeasyPrint PDF в стиле Брусника.Обмен. + + Pages: + 1. Cover — № отчёта + параметры + 2 диапазона + 3 блока «Что важно» + 2. Listings — рынок аналогов + источники + таблица примеров + 3. Deals — фактические сделки + источники + таблица + 4. Offer — Trade-In vs самопродажа + 4 преимущества + + Args: + estimate: AggregatedEstimate из БД + input_snapshot: ввод пользователя (address, area_m2, ...) + brand: optional Brand для white-label + + Returns: + PDF bytes для Response(media_type="application/pdf") + """ + from app.services.brand import Brand + + if brand is None: + brand = Brand( + slug="generic", + name="Trade-In", + logo_url=None, + primary_color="#1d4ed8", + accent_color="#f59e0b", + footer_text=None, + pdf_disclaimer=None, + ) + + html_str = ( + '' + f'Trade-In — {_html.escape(input_snapshot.get("address", ""))}' + "" + + _build_cover(estimate, input_snapshot, brand) + + _build_listings_page(estimate, input_snapshot, brand) + + _build_deals_page(estimate, input_snapshot, brand) + + _build_offer_page(estimate, brand) + + "" + ) + css_str = _build_css(brand=brand) + # base_url=file:/// чтобы WeasyPrint мог resolve file:// URLs для PNG + pdf_bytes = HTML(string=html_str, base_url="file:///").write_pdf(stylesheets=[CSS(string=css_str)]) + logger.info( + "PDF generated estimate_id=%s brand=%s size=%d (Brusnika-style)", + estimate.estimate_id, brand.slug, len(pdf_bytes), + ) + return pdf_bytes diff --git a/tradein-mvp/backend/app/services/geocoder.py b/tradein-mvp/backend/app/services/geocoder.py new file mode 100644 index 00000000..2c58e989 --- /dev/null +++ b/tradein-mvp/backend/app/services/geocoder.py @@ -0,0 +1,535 @@ +"""Geocoder service — address → lat/lon. + +Стратегия: +- Cache lookup в `geocode_cache` (Postgres) — TTL 90 дней +- Cache miss → Yandex Geocoder (если есть key) → fallback Nominatim +- Результат сохраняется в кэш для последующих вызовов + +Используется в: +- /api/v1/trade-in/estimate (вход — адрес от пользователя) +- /api/v1/geocode/lookup (debug endpoint) +- scraper jobs (когда нужно по адресу определить координаты) +""" + +from __future__ import annotations + +import asyncio +import logging +from dataclasses import dataclass +from typing import Literal + +import httpx +from sqlalchemy import text +from sqlalchemy.orm import Session +from tenacity import retry, stop_after_attempt, wait_exponential + +from app.core.config import settings + +logger = logging.getLogger(__name__) + + +# ── Result type ────────────────────────────────────────────────────────────── +@dataclass(frozen=True, slots=True) +class GeocodeResult: + lat: float + lon: float + full_address: str + provider: Literal["nominatim", "yandex", "cache"] + confidence: Literal["exact", "approximate", "locality"] = "approximate" + + +# ── Address normalisation ─────────────────────────────────────────────────── +def normalize_address(address: str) -> str: + """Нормализация для cache lookup: lowercase + trim + collapse whitespace. + + « Ул. МАЛЫШЕВА, 30 » → «ул. малышева, 30» + """ + return " ".join(address.lower().strip().split()) + + +# Согласные, которые часто пишут с одной буквой вместо двух (RU typos). +_DOUBLE_CONSONANTS = "лнмссккттпп" + + +def _typo_variants(query: str, limit: int = 6) -> list[str]: + """Генерация вариантов с удвоением согласных — для случая когда пользователь + написал «Цвилинга» вместо «Цвиллинга», «Толстова» вместо «Толстого» итд. + + Каждая позиция где есть одинокая согласная — кандидат на удвоение. + Возвращаем до `limit` вариантов в порядке вероятности (ближе к началу слова → выше). + """ + if len(query) < 3: + return [] + variants: list[str] = [] + chars = list(query) + for i in range(1, len(chars) - 1): + c = chars[i].lower() + if c not in _DOUBLE_CONSONANTS: + continue + prev_c = chars[i - 1].lower() + next_c = chars[i + 1].lower() + # Удваиваем только если соседи — гласные/'ь'/'ъ' (характерно для русских типо) + if prev_c in "аеёиоуыэюяьъ" and next_c in "аеёиоуыэюяьъ": + variant = query[:i + 1] + chars[i] + query[i + 1:] + if variant != query and variant not in variants: + variants.append(variant) + if len(variants) >= limit: + break + return variants + + +# ── Cache ──────────────────────────────────────────────────────────────────── +def _cache_get(db: Session, address_norm: str) -> GeocodeResult | None: + row = db.execute( + text( + """ + SELECT lat, lon, full_address, provider, confidence + FROM geocode_cache + WHERE address_normalized = :addr + AND expires_at > NOW() + """ + ), + {"addr": address_norm}, + ).fetchone() + if row is None: + return None + return GeocodeResult( + lat=row.lat, + lon=row.lon, + full_address=row.full_address, + provider="cache", + confidence=row.confidence or "approximate", + ) + + +def _cache_put(db: Session, address_norm: str, result: GeocodeResult) -> None: + db.execute( + text( + """ + INSERT INTO geocode_cache + (address_normalized, lat, lon, full_address, provider, confidence) + VALUES (:addr, :lat, :lon, :full, :provider, :conf) + ON CONFLICT (address_normalized) DO UPDATE + SET lat = EXCLUDED.lat, + lon = EXCLUDED.lon, + full_address = EXCLUDED.full_address, + provider = EXCLUDED.provider, + confidence = EXCLUDED.confidence, + created_at = NOW(), + expires_at = NOW() + interval '90 days' + """ + ), + { + "addr": address_norm, + "lat": result.lat, + "lon": result.lon, + "full": result.full_address, + "provider": result.provider, + "conf": result.confidence, + }, + ) + db.commit() + + +# ── Provider: Nominatim (OSM, без ключа) ──────────────────────────────────── +async def _nominatim_query(client: httpx.AsyncClient, address: str) -> dict | None: + """Single Nominatim search. Возвращает первый item или None. + + ВАЖНО: фильтруем результаты по ЕКБ bbox прямо тут, чтобы при опечатках + не возвращать Пермский край / Челябинск. + """ + response = await client.get( + "https://nominatim.openstreetmap.org/search", + params={ + "q": address, + "format": "json", + "limit": "3", + "countrycodes": "ru", + "addressdetails": "1", + "viewbox": EKB_BBOX["viewbox"], + "bounded": "1", # строго в ЕКБ bbox + }, + ) + response.raise_for_status() + data = response.json() + for item in data: + try: + lat_f = float(item["lat"]) + lon_f = float(item["lon"]) + if 60.40 <= lon_f <= 60.85 and 56.65 <= lat_f <= 56.95: + return item + except Exception: # noqa: BLE001 + continue + return None + + +@retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=1, max=8)) +async def _nominatim_lookup(address: str) -> GeocodeResult | None: + """OSM Nominatim — бесплатно, без ключа, 1 req/sec policy. + + Бан-policy: User-Agent с email обязателен. + Tier 1: bounded ЕКБ на оригинальный адрес. + Tier 2: bounded ЕКБ на typo-варианты (Цвилинга → Цвиллинга). + """ + headers = { + "User-Agent": f"TradeInMVP/0.1 (contact: {settings.contact_email})", + "Accept": "application/json", + "Accept-Language": "ru,en;q=0.8", + "Referer": "https://tradein-mvp.local/", + } + async with httpx.AsyncClient(timeout=10.0, headers=headers) as client: + # Tier 1: оригинал + item = await _nominatim_query(client, address) + + # Tier 2: typo-variants + if item is None: + for variant in _typo_variants(address, limit=4): + await asyncio.sleep(1.0) # Nominatim 1 req/sec policy + item = await _nominatim_query(client, variant) + if item is not None: + logger.info("nominatim typo-fixed: %s → %s", address, variant) + break + + if item is None: + return None + + confidence = "exact" if item.get("class") == "building" else "approximate" + return GeocodeResult( + lat=float(item["lat"]), + lon=float(item["lon"]), + full_address=item.get("display_name", address), + provider="nominatim", + confidence=confidence, + ) + + +# ── Provider: Yandex Geocoder (требует key, лучшее покрытие РФ) ───────────── +@retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=1, max=8)) +async def _yandex_lookup(address: str, api_key: str) -> GeocodeResult | None: + """Yandex Geocoder — 25K req/day free для самопод, лучше РФ. + + Docs: https://yandex.ru/dev/maps/geocoder/doc/desc/concepts/input_params.html + + Запрашиваем с ll+spn (центр ЕКБ) для приоритизации местных результатов, + но БЕЗ rspn — чтобы fuzzy matching работал при опечатках. + """ + # Не запихиваем "Екатеринбург" если оно уже есть в адресе (типичный кейс из suggest) + geocode_query = address if "екатеринбург" in address.lower() else f"Екатеринбург, {address}" + async with httpx.AsyncClient(timeout=10.0) as client: + response = await client.get( + "https://geocode-maps.yandex.ru/1.x/", + params={ + "apikey": api_key, + "geocode": geocode_query, + "format": "json", + "results": 5, # берем top-5, отфильтруем по ЕКБ bbox ниже + "lang": "ru_RU", + "ll": EKB_BBOX["ll"], + "spn": EKB_BBOX["spn"], + }, + ) + response.raise_for_status() + data = response.json() + + members = data.get("response", {}).get("GeoObjectCollection", {}).get("featureMember", []) + if not members: + return None + + # Фильтруем top-5 по ЕКБ bbox — игнорируем Челябинск/Уфу/Москву при опечатке + best = None + for m in members: + obj = m.get("GeoObject", {}) + try: + lon_str, lat_str = obj["Point"]["pos"].split() + lat_f, lon_f = float(lat_str), float(lon_str) + if 60.40 <= lon_f <= 60.85 and 56.65 <= lat_f <= 56.95: + best = obj + break + except Exception: # noqa: BLE001 + continue + + if best is None: + # Никто из top-5 не попал в ЕКБ → берем первый «как есть» (вне ЕКБ — но хоть что-то) + best = members[0]["GeoObject"] + + lon_str, lat_str = best["Point"]["pos"].split() + precision_raw = ( + best.get("metaDataProperty", {}) + .get("GeocoderMetaData", {}) + .get("precision", "other") + ) + confidence_map = { + "exact": "exact", + "number": "exact", + "near": "approximate", + "range": "approximate", + "street": "approximate", + } + return GeocodeResult( + lat=float(lat_str), + lon=float(lon_str), + full_address=best.get("metaDataProperty", {}) + .get("GeocoderMetaData", {}) + .get("text", address), + provider="yandex", + confidence=confidence_map.get(precision_raw, "approximate"), + ) + + +# ── Suggest (автокомплит) ─────────────────────────────────────────────────── +# ЕКБ bounding box (приблизительно): юг 56.65, запад 60.40, север 56.95, восток 60.85 +EKB_BBOX = { + "viewbox": "60.40,56.95,60.85,56.65", # Nominatim format: lon1,lat1,lon2,lat2 (NW,SE) + "ll": "60.605,56.838", # Yandex center (lon,lat) + "spn": "0.45,0.30", # Yandex span (lon,lat) +} + + +@dataclass(frozen=True, slots=True) +class GeocodeSuggestion: + label: str # формат "Малышева 30, Октябрьский район" + full_address: str # полный из геокодера + lat: float + lon: float + kind: str # 'house' / 'street' / 'locality' + + +def _parse_yandex_members(members: list[dict]) -> list[GeocodeSuggestion]: + """Yandex geocode_members → list[GeocodeSuggestion]. Чистим описание от мусора.""" + out: list[GeocodeSuggestion] = [] + for m in members: + obj = m.get("GeoObject", {}) + try: + lon_str, lat_str = obj["Point"]["pos"].split() + meta = obj.get("metaDataProperty", {}).get("GeocoderMetaData", {}) + kind = meta.get("kind", "other") + full = meta.get("text", obj.get("name", "")) + name = obj.get("name", full) + desc = obj.get("description", "") + desc_parts = [ + p.strip() for p in desc.split(",") + if p.strip() and p.strip() not in {"Россия", "Свердловская область"} + ] + label = name if not desc_parts else f"{name} · {', '.join(desc_parts)}" + out.append(GeocodeSuggestion( + label=label, full_address=full, + lat=float(lat_str), lon=float(lon_str), kind=kind, + )) + except Exception: # noqa: BLE001 + continue + return out + + +async def _yandex_geocode_request( + client: httpx.AsyncClient, api_key: str, query: str, limit: int, bounded: bool +) -> list[dict]: + """Single Yandex Geocoder request — bounded=True → строго в ЕКБ через rspn=1.""" + params: dict[str, str] = { + "apikey": api_key, + "geocode": query, + "format": "json", + "results": str(limit), + "lang": "ru_RU", + "ll": EKB_BBOX["ll"], + "spn": EKB_BBOX["spn"], + } + if bounded: + params["rspn"] = "1" + response = await client.get("https://geocode-maps.yandex.ru/1.x/", params=params) + response.raise_for_status() + data = response.json() + return data.get("response", {}).get("GeoObjectCollection", {}).get("featureMember", []) + + +@retry(stop=stop_after_attempt(2), wait=wait_exponential(multiplier=1, min=1, max=4)) +async def _yandex_suggest(query: str, api_key: str, limit: int = 8) -> list[GeocodeSuggestion]: + """Yandex Geocoder с авто-fallback на typo-tolerant режим. + + Tier 1: bounded ЕКБ (rspn=1) на оригинальный query. + Tier 2: bounded ЕКБ на typo-variants (удвоение согласных). + Tier 3: без rspn — fuzzy по всей стране, фильтр результатов по ЕКБ bbox. + """ + async with httpx.AsyncClient(timeout=8.0) as client: + # Tier 1: strict bounded на оригинал + members = await _yandex_geocode_request( + client, api_key, f"Екатеринбург, {query}", limit, bounded=True, + ) + results = _parse_yandex_members(members) + if results: + return results + + # Tier 2: bounded на typo-варианты + for variant in _typo_variants(query, limit=4): + members = await _yandex_geocode_request( + client, api_key, f"Екатеринбург, {variant}", limit, bounded=True, + ) + results = _parse_yandex_members(members) + if results: + return results + + # Tier 3: без rspn — даём fuzzy сделать своё дело, фильтр по bbox + members = await _yandex_geocode_request( + client, api_key, f"Екатеринбург, {query}", limit, bounded=False, + ) + results = _parse_yandex_members(members) + in_ekb = [ + r for r in results + if 60.40 <= r.lon <= 60.85 and 56.65 <= r.lat <= 56.95 + ] + return in_ekb + + +async def _nominatim_query_multi( + client: httpx.AsyncClient, query: str, limit: int +) -> list[dict]: + """Один Nominatim search с фильтром по ЕКБ bbox. Возвращает up to N items.""" + response = await client.get( + "https://nominatim.openstreetmap.org/search", + params={ + "q": query, + "format": "json", + "limit": str(limit), + "countrycodes": "ru", + "viewbox": EKB_BBOX["viewbox"], + "bounded": "1", + "addressdetails": "1", + }, + ) + response.raise_for_status() + data = response.json() + return data if isinstance(data, list) else [] + + +@retry(stop=stop_after_attempt(2), wait=wait_exponential(multiplier=1, min=1, max=4)) +async def _nominatim_suggest(query: str, limit: int = 8) -> list[GeocodeSuggestion]: + """Nominatim в режиме suggest. С typo-fallback (для случаев когда Yandex недоступен).""" + headers = { + "User-Agent": f"TradeInMVP/0.1 (contact: {settings.contact_email})", + "Accept": "application/json", + "Accept-Language": "ru,en;q=0.8", + } + async with httpx.AsyncClient(timeout=8.0, headers=headers) as client: + # Tier 1: оригинальный query + data = await _nominatim_query_multi(client, f"{query}, Екатеринбург", limit) + + # Tier 2: typo-варианты если оригинал пустой + if not data: + for variant in _typo_variants(query, limit=3): + await asyncio.sleep(1.0) # Nominatim 1 req/sec + data = await _nominatim_query_multi(client, f"{variant}, Екатеринбург", limit) + if data: + logger.info("nominatim suggest typo-fixed: %s → %s", query, variant) + break + + out: list[GeocodeSuggestion] = [] + for item in data: + display = item.get("display_name", "") + addr = item.get("address", {}) or {} + # Компактный лейбл: street + house_number / locality / district + street = addr.get("road") or addr.get("street") or "" + house = addr.get("house_number", "") + district = addr.get("suburb") or addr.get("city_district") or addr.get("borough") or "" + parts = [] + if street: + parts.append(f"{street}{f', {house}' if house else ''}") + elif item.get("name"): + parts.append(item["name"]) + if district: + parts.append(district) + label = " · ".join(parts) if parts else display[:80] + kind = "house" if house else ("street" if street else "locality") + out.append(GeocodeSuggestion( + label=label, full_address=display, + lat=float(item["lat"]), lon=float(item["lon"]), kind=kind, + )) + return out + + +async def suggest(query: str, limit: int = 8) -> list[GeocodeSuggestion]: + """Автокомплит адресов в ЕКБ. Yandex → Nominatim → []. + + Без кэша (дешёво, провайдеры толерируют автокомплит-запросы). + """ + if not query or len(query.strip()) < 2: + return [] + + if settings.yandex_geocoder_key: + try: + results = await _yandex_suggest(query, settings.yandex_geocoder_key, limit) + if results: + return results + except Exception: # noqa: BLE001 + logger.exception("yandex suggest failed, falling back to nominatim") + + try: + return await _nominatim_suggest(query, limit) + except Exception: # noqa: BLE001 + logger.exception("nominatim suggest failed") + return [] + + +# ── Public API ─────────────────────────────────────────────────────────────── +async def geocode(address: str, db: Session) -> GeocodeResult | None: + """Геокодинг с кэшем. Yandex → Nominatim → None. + + Args: + address: пользовательский ввод (может быть грязным — нормализуем). + db: сессия Postgres для cache lookup/write. + + Returns: + GeocodeResult или None если ни один провайдер не отвечает. + """ + if not address or len(address.strip()) < 3: + return None + + addr_norm = normalize_address(address) + + # 1. Cache + cached = _cache_get(db, addr_norm) + if cached is not None: + logger.info("geocode cache hit: %s", addr_norm) + return cached + + # 2. Yandex (если есть key) с typo-fallback + if settings.yandex_geocoder_key: + try: + result = await _yandex_lookup(address, settings.yandex_geocoder_key) + # Если результат вне ЕКБ — пробуем typo-варианты + in_ekb = result is not None and 60.40 <= result.lon <= 60.85 and 56.65 <= result.lat <= 56.95 + if result is not None and in_ekb: + _cache_put(db, addr_norm, result) + logger.info("geocode yandex: %s → (%.5f, %.5f)", addr_norm, result.lat, result.lon) + return result + # Tier 2: typo-variants + for variant in _typo_variants(address, limit=4): + try: + result = await _yandex_lookup(variant, settings.yandex_geocoder_key) + except Exception: # noqa: BLE001 + continue + if result is None: + continue + if 60.40 <= result.lon <= 60.85 and 56.65 <= result.lat <= 56.95: + _cache_put(db, addr_norm, result) + logger.info( + "geocode yandex typo-fixed: %s → %s → (%.5f, %.5f)", + addr_norm, variant, result.lat, result.lon, + ) + return result + except Exception: # noqa: BLE001 + logger.exception("yandex geocoder failed, falling back to nominatim") + + # 3. Nominatim fallback + try: + result = await _nominatim_lookup(address) + if result is not None: + _cache_put(db, addr_norm, result) + logger.info( + "geocode nominatim: %s → (%.5f, %.5f)", addr_norm, result.lat, result.lon + ) + # Nominatim rate-limit policy: 1 req/sec — спим после успешного запроса + await asyncio.sleep(1.0) + return result + except Exception: # noqa: BLE001 + logger.exception("nominatim geocoder failed") + + return None diff --git a/tradein-mvp/backend/app/services/scrapers/__init__.py b/tradein-mvp/backend/app/services/scrapers/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tradein-mvp/backend/app/services/scrapers/avito.py b/tradein-mvp/backend/app/services/scrapers/avito.py new file mode 100644 index 00000000..78a697d8 --- /dev/null +++ b/tradein-mvp/backend/app/services/scrapers/avito.py @@ -0,0 +1,409 @@ +"""Avito.ru scraper — парсинг вторички вокруг точки. + +Стратегия: HTML scrape карточек объявлений + извлечение JSON `__initialState__` +который Avito вставляет в `', re.DOTALL +) +_RE_INITIAL_STATE = re.compile( + r'window\._cianConfig\s*=\s*({.+?});', re.DOTALL +) + + +def _extract_next_data_items(html: str) -> list[dict[str, Any]]: + """Cian Next.js приложение хранит state в `__NEXT_DATA__` JSON.""" + m = _RE_NEXT_DATA.search(html) + if not m: + return [] + try: + data = json.loads(m.group(1)) + except json.JSONDecodeError: + return [] + # Структура у Cian примерно такая: props.pageProps.initialState.serpData.offers + cursor: Any = data + for key in ["props", "pageProps", "initialState"]: + if not isinstance(cursor, dict): + return [] + cursor = cursor.get(key) + if not isinstance(cursor, dict): + return [] + serp = cursor.get("results") or cursor.get("serpData") or cursor.get("data") or {} + offers = serp.get("offersSerialized") or serp.get("offers") or [] + if isinstance(offers, list): + return offers + return [] + + +def _extract_inline_offers(html: str) -> list[dict[str, Any]]: + """Альтернативный поиск offers в любом большом JSON в HTML.""" + # Найти offers: [...] inline + for match in re.finditer(r'"offers":\[(.+?)\](?=,"|\})', html): + chunk = "[" + match.group(1) + "]" + try: + offers = json.loads(chunk) + if isinstance(offers, list) and offers and isinstance(offers[0], dict): + return offers + except json.JSONDecodeError: + continue + return [] + + +# ── Title parsers (Cian-specific format) ──────────────────────────────────── + + +_RE_ROOMS = re.compile(r"(\d)-комн", re.IGNORECASE) +_RE_STUDIO = re.compile(r"студи", re.IGNORECASE) +_RE_AREA = re.compile(r"(\d+[.,]?\d*)\s*м²", re.IGNORECASE) +_RE_FLOOR = re.compile(r"(\d+)\s*/\s*(\d+)\s*эт", re.IGNORECASE) +_RE_PRICE = re.compile(r"([\d\s]+?)\s*₽") + + +def _extract_rooms_from_text(text: str) -> int | None: + if _RE_STUDIO.search(text): + return 0 + m = _RE_ROOMS.search(text) + return int(m.group(1)) if m else None + + +def _extract_area_from_text(text: str) -> float | None: + m = _RE_AREA.search(text) + return float(m.group(1).replace(",", ".")) if m else None + + +def _extract_floor_from_text(text: str) -> tuple[int | None, int | None]: + m = _RE_FLOOR.search(text) + if m: + return int(m.group(1)), int(m.group(2)) + return None, None + + +def _extract_price_rub(text: str) -> int | None: + m = _RE_PRICE.search(text) + if m: + digits = re.sub(r"\D", "", m.group(1)) + return int(digits) if digits else None + return None + + +_RE_YEAR_BUILT = re.compile(r"(?:19[5-9]\d|20[0-2]\d)\s*(?:года?\s*постройки|г\.?\s*постройки)", re.IGNORECASE) + + +def _extract_year_built(text: str) -> int | None: + """Извлечь год постройки из description: '1988 года постройки' / '2005 г. постройки'.""" + m = _RE_YEAR_BUILT.search(text) + if m: + year_m = re.search(r"(19[5-9]\d|20[0-2]\d)", m.group(0)) + if year_m: + return int(year_m.group(1)) + return None diff --git a/tradein-mvp/backend/app/services/scrapers/yandex_realty.py b/tradein-mvp/backend/app/services/scrapers/yandex_realty.py new file mode 100644 index 00000000..c78ffa50 --- /dev/null +++ b/tradein-mvp/backend/app/services/scrapers/yandex_realty.py @@ -0,0 +1,290 @@ +"""Yandex.Недвижимость scraper (realty.yandex.ru). + +Я.Недвижимость отдаёт SSR HTML с `__INITIAL_STATE__` JSON в `', + re.DOTALL, +) + + +def _extract_yandex_state(html: str) -> dict[str, Any] | None: + m = _RE_STATE.search(html) + if not m: + return None + raw = m.group(1) + # Может начинаться с `window.__INITIAL_STATE__=` префикса + raw = re.sub(r'^\s*window\.[\w_]+\s*=\s*', '', raw).rstrip(';').strip() + try: + return json.loads(raw) + except json.JSONDecodeError: + return None + + +def _items_from_state(state: dict[str, Any]) -> list[dict[str, Any]]: + """Yandex Realty: state.map.offers.points содержит список объявлений (десктоп desktop SSR).""" + for path in [ + ("map", "offers", "points"), # верифицировано на проде + ("search", "offers"), + ("offers", "points"), + ("offers", "items"), + ]: + cursor: Any = state + for key in path: + if not isinstance(cursor, dict): + cursor = None + break + cursor = cursor.get(key) + if isinstance(cursor, list) and cursor: + return cursor + return [] + + +def _map_wall_type(yandex_type: str | None) -> str | None: + if not yandex_type: + return None + mapping = { + "PANEL": "panel", + "BRICK": "brick", + "MONOLITH": "monolith", + "MONOLITH_BRICK": "monolith_brick", + "BLOCK": "panel", + } + return mapping.get(yandex_type.upper(), "other") diff --git a/tradein-mvp/backend/data/sql/001_trade_in_estimates.sql b/tradein-mvp/backend/data/sql/001_trade_in_estimates.sql new file mode 100644 index 00000000..df9e787a --- /dev/null +++ b/tradein-mvp/backend/data/sql/001_trade_in_estimates.sql @@ -0,0 +1,43 @@ +BEGIN; + +CREATE TABLE IF NOT EXISTS trade_in_estimates ( + id uuid PRIMARY KEY DEFAULT gen_random_uuid(), + + -- Input snapshot + address text NOT NULL, + lat double precision, + lon double precision, + area_m2 numeric(8, 2) NOT NULL, + rooms int NOT NULL, + floor int NOT NULL, + total_floors int NOT NULL, + year_built int, + house_type text, + repair_state text, + has_balcony boolean, + + -- Output + median_price bigint NOT NULL, + range_low bigint NOT NULL, + range_high bigint NOT NULL, + median_price_per_m2 int NOT NULL, + confidence text NOT NULL CHECK (confidence IN ('low', 'medium', 'high')), + n_analogs int NOT NULL DEFAULT 0, + analogs jsonb NOT NULL DEFAULT '[]'::jsonb, + actual_deals jsonb NOT NULL DEFAULT '[]'::jsonb, + + -- Metadata + created_at timestamptz NOT NULL DEFAULT NOW(), + expires_at timestamptz NOT NULL DEFAULT NOW() + interval '24 hours' +); + +CREATE INDEX IF NOT EXISTS trade_in_estimates_created_idx + ON trade_in_estimates (created_at DESC); + +CREATE INDEX IF NOT EXISTS trade_in_estimates_expires_idx + ON trade_in_estimates (expires_at); + +COMMENT ON TABLE trade_in_estimates IS + '#314 TradeIn MVP — стор estimates с input snapshot + aggregated output. TTL 24h.'; + +COMMIT; diff --git a/tradein-mvp/backend/data/sql/002_core_tables.sql b/tradein-mvp/backend/data/sql/002_core_tables.sql new file mode 100644 index 00000000..d0841eb2 --- /dev/null +++ b/tradein-mvp/backend/data/sql/002_core_tables.sql @@ -0,0 +1,234 @@ +-- Trade-In MVP — Core data layer (Слой 1.1). +-- Применяется автоматически после 001_trade_in_estimates.sql при первом старте postgres. + +BEGIN; + +-- ── PostGIS для гео-запросов ────────────────────────────────────────────── +CREATE EXTENSION IF NOT EXISTS postgis; + + +-- ───────────────────────────────────────────────────────────────────────── +-- listings — спарсенные объявления (Авито, Циан, ДомКлик, Я.Нед, Н1, Дом.РФ) +-- ───────────────────────────────────────────────────────────────────────── +CREATE TABLE IF NOT EXISTS listings ( + id bigserial PRIMARY KEY, + source text NOT NULL, -- avito / cian / domklik / yandex / n1 / domrf + source_url text NOT NULL, + source_id text, -- внутренний id источника (если есть) + dedup_hash text NOT NULL UNIQUE, -- sha256(source + source_url + price) — дедуп + + -- Локация + address text, + lat double precision, + lon double precision, + geom geometry(Point, 4326), -- PostGIS для ST_DWithin + region_code int, -- 66 = Свердловская обл. + + -- Параметры квартиры + rooms int, -- 0 = студия + area_m2 numeric(8, 2), + floor int, + total_floors int, + year_built int, + house_type text, -- panel / brick / monolith / monolith_brick / other + repair_state text, -- needs_repair / standard / good / excellent + has_balcony boolean, + kadastr_num text, -- если удалось вытянуть кадастр + + -- Цена + price_rub bigint NOT NULL, + price_per_m2 int, + + -- Метаданные источника + listing_date date, -- когда выставили + days_on_market int, + photo_urls jsonb DEFAULT '[]'::jsonb, + raw_payload jsonb, -- сырой ответ для дебага + + -- Quality flags + is_outlier boolean DEFAULT false, -- помечено модели после aggregation + is_active boolean DEFAULT true, -- если объявление пропало с источника + + -- Lifecycle + scraped_at timestamptz NOT NULL DEFAULT NOW(), + last_seen_at timestamptz NOT NULL DEFAULT NOW() +); + +CREATE INDEX IF NOT EXISTS listings_geom_idx ON listings USING GIST (geom); +CREATE INDEX IF NOT EXISTS listings_rooms_area_idx ON listings (rooms, area_m2) WHERE is_active = true; +CREATE INDEX IF NOT EXISTS listings_scraped_idx ON listings (scraped_at DESC) WHERE is_active = true; +CREATE INDEX IF NOT EXISTS listings_source_idx ON listings (source, scraped_at DESC); + +-- Авто-update geom из (lat, lon) +CREATE OR REPLACE FUNCTION listings_set_geom() RETURNS trigger AS $$ +BEGIN + IF NEW.lat IS NOT NULL AND NEW.lon IS NOT NULL THEN + NEW.geom := ST_SetSRID(ST_MakePoint(NEW.lon, NEW.lat), 4326); + END IF; + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +DROP TRIGGER IF EXISTS listings_set_geom_trg ON listings; +CREATE TRIGGER listings_set_geom_trg + BEFORE INSERT OR UPDATE OF lat, lon ON listings + FOR EACH ROW EXECUTE FUNCTION listings_set_geom(); + +COMMENT ON TABLE listings IS + 'Спарсенные объявления с площадок. Дедуп по dedup_hash. PostGIS geom для ST_DWithin запросов.'; + + +-- ───────────────────────────────────────────────────────────────────────── +-- deals — фактические сделки (Росреестр + Этажи + ДомКлик исторические) +-- ───────────────────────────────────────────────────────────────────────── +CREATE TABLE IF NOT EXISTS deals ( + id bigserial PRIMARY KEY, + source text NOT NULL, -- rosreestr / etazhi / domklik_history + source_id text, -- идентификатор сделки в источнике + dedup_hash text NOT NULL UNIQUE, + + -- Локация + address text, + lat double precision, + lon double precision, + geom geometry(Point, 4326), + region_code int, + kadastr_num text, + + -- Параметры квартиры + rooms int, + area_m2 numeric(8, 2), + floor int, + total_floors int, + year_built int, + house_type text, + + -- Сделка + deal_date date NOT NULL, + price_rub bigint NOT NULL, + price_per_m2 int, + days_on_market int, -- если знаем когда выставили + + raw_payload jsonb, + scraped_at timestamptz NOT NULL DEFAULT NOW() +); + +CREATE INDEX IF NOT EXISTS deals_geom_idx ON deals USING GIST (geom); +CREATE INDEX IF NOT EXISTS deals_rooms_area_idx ON deals (rooms, area_m2); +CREATE INDEX IF NOT EXISTS deals_date_idx ON deals (deal_date DESC); +CREATE INDEX IF NOT EXISTS deals_source_idx ON deals (source, deal_date DESC); + +DROP TRIGGER IF EXISTS deals_set_geom_trg ON deals; +CREATE TRIGGER deals_set_geom_trg + BEFORE INSERT OR UPDATE OF lat, lon ON deals + FOR EACH ROW EXECUTE FUNCTION listings_set_geom(); -- reuse + +COMMENT ON TABLE deals IS + 'Фактические сделки купли-продажи квартир. Источник #1 — Росреестр (дамп из prod gendesign).'; + + +-- ───────────────────────────────────────────────────────────────────────── +-- geocode_cache — кэш geocoder (Nominatim/Yandex) +-- ───────────────────────────────────────────────────────────────────────── +CREATE TABLE IF NOT EXISTS geocode_cache ( + address_normalized text PRIMARY KEY, -- lowercased trimmed адрес для lookup + lat double precision NOT NULL, + lon double precision NOT NULL, + full_address text, -- что вернул geocoder + provider text NOT NULL, -- nominatim / yandex + confidence text, -- exact / approximate / locality + raw_payload jsonb, + created_at timestamptz NOT NULL DEFAULT NOW(), + -- TTL: 90 дней — потом стоит проверить актуальность (дома сносят редко, но бывает) + expires_at timestamptz NOT NULL DEFAULT NOW() + interval '90 days' +); + +CREATE INDEX IF NOT EXISTS geocode_cache_expires_idx ON geocode_cache (expires_at); + +COMMENT ON TABLE geocode_cache IS + 'Кэш geocoder lookup. Адрес → lat/lon. TTL 90 дней.'; + + +-- ───────────────────────────────────────────────────────────────────────── +-- house_metadata — кэш данных ЕКБ Геопортала (citymap.ekburg.ru) +-- ───────────────────────────────────────────────────────────────────────── +CREATE TABLE IF NOT EXISTS house_metadata ( + id bigserial PRIMARY KEY, + lat double precision NOT NULL, + lon double precision NOT NULL, + geom geometry(Point, 4326), + kadastr_num text UNIQUE, + + -- Что вытянули из ЕКБ Геопортала / DomRF / NSPD + address text, + total_floors int, + year_built int, + house_type text, + total_units int, -- кол-во квартир в доме + construction_status text, -- сдан / строится + developer text, -- застройщик если новостройка + + source text, -- ekb_geoportal / domrf / nspd + raw_payload jsonb, + fetched_at timestamptz NOT NULL DEFAULT NOW(), + -- TTL: 30 дней + expires_at timestamptz NOT NULL DEFAULT NOW() + interval '30 days' +); + +CREATE INDEX IF NOT EXISTS house_metadata_geom_idx ON house_metadata USING GIST (geom); +CREATE INDEX IF NOT EXISTS house_metadata_expires_idx ON house_metadata (expires_at); + +DROP TRIGGER IF EXISTS house_metadata_set_geom_trg ON house_metadata; +CREATE TRIGGER house_metadata_set_geom_trg + BEFORE INSERT OR UPDATE OF lat, lon ON house_metadata + FOR EACH ROW EXECUTE FUNCTION listings_set_geom(); + +COMMENT ON TABLE house_metadata IS + 'Кэш метаданных дома по координатам/кадастру (ЕКБ Геопортал, DomRF, NSPD).'; + + +-- ───────────────────────────────────────────────────────────────────────── +-- audit_log — каждый POST /estimate и GET /estimate/{id}/pdf +-- ───────────────────────────────────────────────────────────────────────── +CREATE TABLE IF NOT EXISTS audit_log ( + id bigserial PRIMARY KEY, + event_type text NOT NULL, -- estimate_request / pdf_download / listing_click + ip_address inet, + user_agent text, + estimate_id uuid, -- FK к trade_in_estimates если применимо + payload jsonb, -- input/output для контекста + created_at timestamptz NOT NULL DEFAULT NOW() +); + +CREATE INDEX IF NOT EXISTS audit_log_created_idx ON audit_log (created_at DESC); +CREATE INDEX IF NOT EXISTS audit_log_event_type_idx ON audit_log (event_type, created_at DESC); + +COMMENT ON TABLE audit_log IS + 'Лог всех значимых событий — для analytics dashboard + rate limiting + debugging.'; + + +-- ───────────────────────────────────────────────────────────────────────── +-- brands — multi-tenant white-label +-- ───────────────────────────────────────────────────────────────────────── +CREATE TABLE IF NOT EXISTS brands ( + slug text PRIMARY KEY, -- prinzip / praktika / generic + name text NOT NULL, + logo_url text, + primary_color text DEFAULT '#1d4ed8', + accent_color text DEFAULT '#f59e0b', + footer_text text, + pdf_disclaimer text, + created_at timestamptz NOT NULL DEFAULT NOW() +); + +INSERT INTO brands (slug, name, primary_color) VALUES + ('generic', 'Trade-In Estimator', '#1d4ed8'), + ('prinzip', 'PRINZIP', '#1a1d23'), + ('praktika', 'Практика', '#e87722') +ON CONFLICT (slug) DO NOTHING; + +COMMENT ON TABLE brands IS + 'White-label бренды. Выбирается через ?brand= на frontend.'; + + +COMMIT; diff --git a/tradein-mvp/backend/data/sql/003_seed_listings.sql b/tradein-mvp/backend/data/sql/003_seed_listings.sql new file mode 100644 index 00000000..1e1c98b4 --- /dev/null +++ b/tradein-mvp/backend/data/sql/003_seed_listings.sql @@ -0,0 +1,147 @@ +-- Trade-In MVP — Seed данные для разработки (v2, фикс распределения). +-- 120 синтетических объявлений + 60 фактических сделок в центре ЕКБ. +-- Использовать пока парсеры не подключены к продакшну. + +BEGIN; + +TRUNCATE listings, deals RESTART IDENTITY CASCADE; + +-- ── Helper: 10 улиц ЕКБ с координатами ───────────────────────────────────── +WITH streets(idx, name, lat, lon) AS (VALUES + (0, 'ул. Малышева', 56.8332::float, 60.5944::float), + (1, 'ул. Куйбышева', 56.8282, 60.6114), + (2, 'ул. 8 Марта', 56.8240, 60.6000), + (3, 'ул. Белинского', 56.8160, 60.6080), + (4, 'пр. Ленина', 56.8400, 60.6100), + (5, 'ул. Толмачёва', 56.8390, 60.6020), + (6, 'ул. Радищева', 56.8300, 60.5890), + (7, 'ул. Мамина-Сибиряка', 56.8420, 60.6190), + (8, 'ул. Луначарского', 56.8350, 60.6280), + (9, 'ул. Первомайская', 56.8440, 60.6240) +), +-- 5 типов квартир (rooms, базовая площадь, базовая цена в руб 2026) +flat_types(idx, rooms, base_area, base_price) AS (VALUES + (0, 0, 28.0::float, 6500000::bigint), + (1, 1, 40.0, 9000000), + (2, 2, 60.0, 12500000), + (3, 3, 80.0, 17000000), + (4, 4, 110.0, 22000000) +), +sources(idx, name) AS (VALUES + (0, 'avito'), + (1, 'cian'), + (2, 'domklik') +), +counts(rooms, n) AS (VALUES + (0, 12), -- студии + (1, 30), -- 1к + (2, 45), -- 2к + (3, 25), -- 3к + (4, 8) -- 4+к +) +INSERT INTO listings ( + source, source_url, dedup_hash, address, lat, lon, region_code, + rooms, area_m2, floor, total_floors, year_built, house_type, + price_rub, price_per_m2, listing_date, days_on_market, scraped_at +) +SELECT + src.name AS source, + 'https://' || src.name || '.example/lot/' || row_num AS source_url, + md5(src.name || row_num::text || street.name || ft.rooms::text) AS dedup_hash, + street.name || ', ' || (10 + (row_num * 7) % 150)::text AS address, + street.lat + ((random() - 0.5) * 0.012) AS lat, -- ≈±650м jitter + street.lon + ((random() - 0.5) * 0.012) AS lon, + 66 AS region_code, + ft.rooms, + ft.base_area + (random() * 6 - 3) AS area_m2, -- ±3м² jitter + 1 + (row_num * 3) % 18 AS floor, + 9 + (row_num * 5) % 14 AS total_floors, + 1960 + (row_num * 11) % 64 AS year_built, + (ARRAY['panel', 'brick', 'monolith', 'monolith_brick'])[1 + (row_num * 7) % 4] AS house_type, + (ft.base_price * (0.85 + random() * 0.30))::bigint AS price_rub, + ((ft.base_price * (0.85 + random() * 0.30)) / (ft.base_area + (random() * 6 - 3)))::int AS price_per_m2, + CURRENT_DATE - ((row_num % 90)::text || ' days')::interval AS listing_date, + row_num % 90 AS days_on_market, + NOW() - ((row_num % 14)::text || ' days')::interval AS scraped_at +FROM ( + -- Раскрываем counts в rows: для rooms=0 12 строк, для rooms=1 30 строк, ... + SELECT + c.rooms, + row_number() OVER (PARTITION BY c.rooms) AS rooms_row, + row_number() OVER () AS row_num + FROM counts c + CROSS JOIN LATERAL generate_series(1, c.n) gs +) AS expanded +JOIN flat_types ft ON ft.rooms = expanded.rooms +JOIN streets street ON street.idx = expanded.row_num % 10 +JOIN sources src ON src.idx = expanded.row_num % 3; + + +-- ── DEALS (60 шт., цены на ~7% ниже листингов) ──────────────────────────── +WITH streets(idx, name, lat, lon) AS (VALUES + (0, 'ул. Малышева', 56.8332::float, 60.5944::float), + (1, 'ул. Куйбышева', 56.8282, 60.6114), + (2, 'ул. 8 Марта', 56.8240, 60.6000), + (3, 'ул. Белинского', 56.8160, 60.6080), + (4, 'пр. Ленина', 56.8400, 60.6100), + (5, 'ул. Толмачёва', 56.8390, 60.6020), + (6, 'ул. Радищева', 56.8300, 60.5890), + (7, 'ул. Мамина-Сибиряка', 56.8420, 60.6190) +), +flat_types(idx, rooms, base_area, base_price) AS (VALUES + (1, 1, 40.0::float, 9000000::bigint), + (2, 2, 60.0, 12500000), + (3, 3, 80.0, 17000000) +), +deal_counts(rooms, n) AS (VALUES + (1, 18), + (2, 28), + (3, 14) +) +INSERT INTO deals ( + source, dedup_hash, address, lat, lon, region_code, + rooms, area_m2, floor, total_floors, year_built, house_type, + deal_date, price_rub, price_per_m2, days_on_market, scraped_at +) +SELECT + 'rosreestr' AS source, + md5('deal:' || row_num::text || street.name || ft.rooms::text) AS dedup_hash, + street.name || ', ' || (10 + (row_num * 5) % 140)::text AS address, + street.lat + ((random() - 0.5) * 0.012) AS lat, + street.lon + ((random() - 0.5) * 0.012) AS lon, + 66, + ft.rooms, + ft.base_area + (random() * 6 - 3) AS area_m2, + 1 + (row_num * 3) % 18 AS floor, + 9 + (row_num * 5) % 14 AS total_floors, + 1960 + (row_num * 11) % 64 AS year_built, + (ARRAY['panel', 'brick', 'monolith'])[1 + (row_num * 7) % 3] AS house_type, + CURRENT_DATE - ((row_num * 6)::text || ' days')::interval AS deal_date, + -- Сделки на 5-12% ниже листингов (вывод PDF Брусники) + (ft.base_price * 0.92 * (0.85 + random() * 0.20))::bigint AS price_rub, + ((ft.base_price * 0.92 * (0.85 + random() * 0.20)) / (ft.base_area + (random() * 6 - 3)))::int AS price_per_m2, + 20 + (row_num % 100) AS days_on_market, + NOW() - ((row_num * 6)::text || ' days')::interval AS scraped_at +FROM ( + SELECT + c.rooms, + row_number() OVER () AS row_num + FROM deal_counts c + CROSS JOIN LATERAL generate_series(1, c.n) gs +) AS expanded +JOIN flat_types ft ON ft.rooms = expanded.rooms +JOIN streets street ON street.idx = expanded.row_num % 8; + + +-- ── Sanity ───────────────────────────────────────────────────────────────── +DO $$ +DECLARE + n_listings int; + n_deals int; +BEGIN + SELECT COUNT(*) INTO n_listings FROM listings; + SELECT COUNT(*) INTO n_deals FROM deals; + RAISE NOTICE 'Seed: % listings, % deals', n_listings, n_deals; +END $$; + +COMMIT; diff --git a/tradein-mvp/backend/data/sql/004_extend_trade_in_estimates.sql b/tradein-mvp/backend/data/sql/004_extend_trade_in_estimates.sql new file mode 100644 index 00000000..cdf9e87e --- /dev/null +++ b/tradein-mvp/backend/data/sql/004_extend_trade_in_estimates.sql @@ -0,0 +1,19 @@ +-- Trade-In MVP — добавляем поля для PDF/UI v2 (Слой 5.2 + 6.1). +-- confidence_explanation + sources_used + data_freshness_minutes +-- (target_address, lat, lon уже есть — переименуем при необходимости позже) + +BEGIN; + +ALTER TABLE trade_in_estimates + ADD COLUMN IF NOT EXISTS confidence_explanation text, + ADD COLUMN IF NOT EXISTS sources_used jsonb DEFAULT '[]'::jsonb, + ADD COLUMN IF NOT EXISTS data_freshness_minutes int; + +COMMENT ON COLUMN trade_in_estimates.confidence_explanation IS + 'Человекочитаемое объяснение confidence — для PDF/UI'; +COMMENT ON COLUMN trade_in_estimates.sources_used IS + 'Список источников, использованных в этой оценке (jsonb массив строк)'; +COMMENT ON COLUMN trade_in_estimates.data_freshness_minutes IS + 'Минут назад был последний парсинг для самого свежего аналога'; + +COMMIT; diff --git a/tradein-mvp/backend/pyproject.toml b/tradein-mvp/backend/pyproject.toml new file mode 100644 index 00000000..b74a88fe --- /dev/null +++ b/tradein-mvp/backend/pyproject.toml @@ -0,0 +1,38 @@ +[project] +name = "tradein-mvp-backend" +version = "0.1.0" +description = "Trade-In Estimator MVP — standalone fork of gendesign trade-in feature" +requires-python = ">=3.12" +dependencies = [ + "fastapi>=0.115.0", + "uvicorn[standard]>=0.30.0", + "sqlalchemy>=2.0.30", + "geoalchemy2>=0.15.0", # PostGIS support для SQLAlchemy + "pydantic>=2.7.0", + "pydantic-settings>=2.3.0", + "psycopg[binary]>=3.2.0", + "weasyprint>=62.0", + "jinja2>=3.1.0", + "httpx>=0.27.0", # для geocoder + scrapers + "tenacity>=9.0.0", # retry с exp backoff + "selectolax>=0.3.0", # быстрый HTML парсинг для scrapers + "segno>=1.6.0", # QR-код для PDF shareable URL + "curl-cffi>=0.7.0", # impersonate=chrome120 для Cian/Avito (TLS fingerprint) +] + +[dependency-groups] +dev = [ + "pytest>=8.0.0", + "ruff>=0.5.0", +] + +[tool.setuptools.packages.find] +include = ["app*"] + +[tool.ruff] +target-version = "py312" +line-length = 100 + +[tool.ruff.lint] +select = ["E", "F", "I", "B", "UP", "N", "RUF"] +ignore = ["RUF001", "RUF002", "RUF003"] diff --git a/tradein-mvp/deploy/Caddyfile b/tradein-mvp/deploy/Caddyfile new file mode 100644 index 00000000..101b6d59 --- /dev/null +++ b/tradein-mvp/deploy/Caddyfile @@ -0,0 +1,29 @@ +# Local Caddyfile — без TLS, всё на http://localhost:8080 +# +# Структура зеркалит прод gendesign: +# - /api/* → backend FastAPI (порт 8000) +# - /health → backend health +# - /preview/* → статические HTML mockups (включая tradein.html) +# - / → frontend Next.js (порт 3000) + +:80 { + encode zstd gzip + + handle /api/* { + reverse_proxy backend:8000 + } + + handle /health { + reverse_proxy backend:8000 + } + + # tradein.html mockup для side-by-side сравнения с реальной /trade-in страницей. + handle_path /preview/* { + root * /srv/preview + file_server browse + } + + handle { + reverse_proxy frontend:3000 + } +} diff --git a/tradein-mvp/deploy/Caddyfile.tradein-fragment b/tradein-mvp/deploy/Caddyfile.tradein-fragment new file mode 100644 index 00000000..73809453 --- /dev/null +++ b/tradein-mvp/deploy/Caddyfile.tradein-fragment @@ -0,0 +1,28 @@ +# Caddy-фрагмент: tradein-mvp под gendsgn.ru/trade-in/* +# +# Этот блок ВКЛЮЧАЕТСЯ в основной gendsgn.ru { ... } блок Caddy +# (см. /opt/gendesign/Caddyfile на bot-server). Размещение — ПЕРЕД +# универсальным `handle { reverse_proxy frontend:3000 }`, потому что +# Caddy матчит handle-блоки сверху вниз. +# +# DNS — отдельный record НЕ нужен; используется тот же gendsgn.ru. +# TLS уже включён в основном блоке (auto через Let's Encrypt). +# +# URL routes: +# gendsgn.ru/trade-in → tradein-frontend:3000 (Next.js basePath=/trade-in) +# gendsgn.ru/trade-in/api/v1/* → tradein-backend:8000 (strip префикса /trade-in) + +handle_path /trade-in/api/* { + # handle_path вырезает префикс /trade-in перед прокси → + # FastAPI получает /api/v1/... + reverse_proxy tradein-backend:8000 +} + +handle /trade-in { + redir /trade-in/ permanent +} + +handle /trade-in/* { + # Next.js basePath="/trade-in" — фронт сам ждёт префикса в URL + reverse_proxy tradein-frontend:3000 +} diff --git a/tradein-mvp/deploy/cron-scrape.sh b/tradein-mvp/deploy/cron-scrape.sh new file mode 100644 index 00000000..e2c43e3e --- /dev/null +++ b/tradein-mvp/deploy/cron-scrape.sh @@ -0,0 +1,79 @@ +#!/usr/bin/env bash +# Периодический скрейп Yandex+Avito по 5 якорям ЕКБ. +# Запускается из cron. Логи в /var/log/tradein-scrape.log +# +# Usage: ./cron-scrape.sh [yandex|avito|all] [deep|fast] +# +# Примеры в crontab: +# # Yandex deep раз в 3 часа +# 0 */3 * * * /opt/tradein-mvp/deploy/cron-scrape.sh yandex deep +# # Avito быстро каждый час +# 30 * * * * /opt/tradein-mvp/deploy/cron-scrape.sh avito fast + +set -euo pipefail + +SOURCE="${1:-all}" +MODE="${2:-fast}" +API="${API:-http://127.0.0.1:8091}" +LOG="${LOG:-/var/log/tradein-scrape.log}" + +log() { + echo "[$(date -u +'%Y-%m-%dT%H:%M:%SZ')] $*" | tee -a "$LOG" +} + +# 5 якорей по районам ЕКБ. lat lon name +# Для Yandex DATE_DESC возвращает одинаковую выдачу регардлесс — но Cian/Avito +# реально фильтруют по координатам, так что multi-anchor нужен для них. +ANCHORS=( + "56.8400 60.6050 Центр" + "56.7950 60.5300 ЮЗ" + "56.8970 60.6100 Уралмаш" + "56.7700 60.5500 Академический" + "56.8650 60.6200 Пионерский" +) + +build_payload() { + local lat="$1" lon="$2" src="$3" mode="$4" + local sources_json + case "$src" in + yandex) sources_json='["yandex"]' ;; + avito) sources_json='["avito"]' ;; + cian) sources_json='["cian"]' ;; + all) sources_json='["avito","cian","yandex"]' ;; + *) sources_json='["avito","cian","yandex"]' ;; + esac + if [[ "$mode" == "deep" ]]; then + echo "{\"lat\":$lat,\"lon\":$lon,\"radius_m\":1500,\"sources\":$sources_json,\"multi_room_yandex\":true,\"deep_yandex\":true,\"multi_room_cian\":true}" + else + echo "{\"lat\":$lat,\"lon\":$lon,\"radius_m\":1500,\"sources\":$sources_json,\"multi_room_yandex\":true,\"multi_room_cian\":true}" + fi +} + +log "=== cron-scrape start: source=$SOURCE mode=$MODE ===" + +# Circuit breaker: если Avito IP-rate-limited (3 нуля подряд) — пропускаем оставшиеся. +zero_fetch_streak=0 +for anchor in "${ANCHORS[@]}"; do + if [[ "$zero_fetch_streak" -ge 3 ]]; then + log "⚠ circuit-breaker tripped (3× zero-fetch in a row) — skipping remaining anchors" + break + fi + read -r lat lon name <<< "$anchor" + payload=$(build_payload "$lat" "$lon" "$SOURCE" "$MODE") + log "→ $name ($lat, $lon) payload=$payload" + resp=$(curl -s -X POST "$API/api/v1/admin/scrape" \ + -H "Content-Type: application/json" \ + -d "$payload" \ + -m 300 || echo '{"error":"curl_timeout"}') + log "← $name $resp" + # Парсим total_fetched — если 0, инкремент streak; иначе reset + fetched=$(echo "$resp" | grep -oE '"total_fetched":[0-9]+' | grep -oE '[0-9]+' || echo 0) + if [[ "${fetched:-0}" == "0" ]]; then + zero_fetch_streak=$((zero_fetch_streak + 1)) + else + zero_fetch_streak=0 + fi + sleep 5 +done + +log "=== cron-scrape done ===" diff --git a/tradein-mvp/docker-compose.prod.yml b/tradein-mvp/docker-compose.prod.yml new file mode 100644 index 00000000..c3da88f5 --- /dev/null +++ b/tradein-mvp/docker-compose.prod.yml @@ -0,0 +1,75 @@ +# Trade-In MVP — production overlay для деплоя ВНУТРИ gendesign-стека. +# +# Запускается из /opt/gendesign/tradein-mvp/ на bot-server: +# docker compose -p gendesign \ +# -f docker-compose.yml -f docker-compose.prod.yml up -d +# +# Особенности vs локального docker-compose.yml: +# - НЕТ своего Caddy и postgres-данных в bind mount +# (postgres контейнер один на всю машину, но изолированная БД tradein_mvp) +# - Образы тянутся из GHCR (build делает GitHub Actions) +# - Backend/frontend подключены к network gendesign_shared чтобы основной +# Caddy мог проксировать /trade-in/* → tradein-frontend +# - Frontend строится с basePath=/trade-in (см. next.config.ts) + +services: + postgres: + image: postgis/postgis:16-3.4 + container_name: tradein-postgres + environment: + POSTGRES_DB: tradein + POSTGRES_USER: ${TRADEIN_POSTGRES_USER:-tradein} + POSTGRES_PASSWORD: ${TRADEIN_POSTGRES_PASSWORD:?required} + volumes: + - tradein-postgres-data:/var/lib/postgresql/data + - ./backend/data/sql:/docker-entrypoint-initdb.d:ro + healthcheck: + test: ["CMD-SHELL", "pg_isready -U ${TRADEIN_POSTGRES_USER:-tradein}"] + interval: 10s + timeout: 5s + retries: 5 + restart: unless-stopped + networks: [tradein-net] + + backend: + image: ghcr.io/lekss361/gendesign-tradein-backend:${IMAGE_TAG:-latest} + container_name: tradein-backend + environment: + DATABASE_URL: "postgresql+psycopg://${TRADEIN_POSTGRES_USER:-tradein}:${TRADEIN_POSTGRES_PASSWORD}@postgres:5432/tradein" + PUBLIC_URL: "https://gendsgn.ru/trade-in" + CORS_ORIGINS: '["https://gendsgn.ru"]' + ENVIRONMENT: "production" + CONTACT_EMAIL: "${TRADEIN_CONTACT_EMAIL:-tradein@gendsgn.ru}" + YANDEX_GEOCODER_KEY: "${YANDEX_GEOCODER_KEY:-}" + depends_on: + postgres: + condition: service_healthy + restart: unless-stopped + networks: + - tradein-net + - gendesign_shared # чтобы Caddy gendesign-стека достучался + + frontend: + image: ghcr.io/lekss361/gendesign-tradein-frontend:${IMAGE_TAG:-latest} + container_name: tradein-frontend + environment: + NODE_ENV: production + # Frontend сам префиксит /trade-in (basePath), а fetch к API делает + # на /trade-in/api/v1/... (см. NEXT_PUBLIC_API_BASE_URL=/trade-in) + NEXT_PUBLIC_API_BASE_URL: "" + BACKEND_URL: "http://backend:8000" # internal SSR + depends_on: [backend] + restart: unless-stopped + networks: + - tradein-net + - gendesign_shared + +volumes: + tradein-postgres-data: + name: tradein-postgres-data + +networks: + tradein-net: + name: tradein-net + gendesign_shared: + external: true diff --git a/tradein-mvp/docker-compose.yml b/tradein-mvp/docker-compose.yml new file mode 100644 index 00000000..86b42825 --- /dev/null +++ b/tradein-mvp/docker-compose.yml @@ -0,0 +1,88 @@ +# Trade-In MVP — локальный стек для разработки. +# +# Архитектура зеркалит прод gendesign (Caddy -> frontend / backend / postgres), +# но всё локально без TLS — открывать http://localhost:8080 +# +# Запуск: +# docker compose up -d --build +# +# Проверки: +# curl http://localhost:8080/health # backend health через Caddy +# open http://localhost:8080 # frontend (auto-redirect → /trade-in) +# open http://localhost:8080/preview/ # tradein.html mockup для сравнения + +name: tradein-mvp + +services: + postgres: + image: postgis/postgis:16-3.4-alpine + container_name: tradein-postgres + restart: unless-stopped + environment: + POSTGRES_USER: tradein + POSTGRES_PASSWORD: tradein + POSTGRES_DB: tradein + volumes: + - postgres-data:/var/lib/postgresql/data + # SQL init scripts: 001_trade_in_estimates.sql создаст таблицу при первом старте. + - ./backend/data/sql:/docker-entrypoint-initdb.d:ro + healthcheck: + test: ["CMD-SHELL", "pg_isready -U tradein -d tradein"] + interval: 5s + timeout: 3s + retries: 10 + ports: + - "127.0.0.1:5433:5432" # local port 5433, чтобы не конфликтовать с прод-туннелем 15432 + + backend: + build: + context: ./backend + dockerfile: Dockerfile + container_name: tradein-backend + restart: unless-stopped + environment: + DATABASE_URL: postgresql+psycopg://tradein:tradein@postgres:5432/tradein + CORS_ORIGINS: '["http://localhost:8080","http://localhost:3000"]' + ENVIRONMENT: dev + depends_on: + postgres: + condition: service_healthy + volumes: + # Hot-reload: монтируем app/ в runner, uvicorn --reload подхватит изменения. + - ./backend/app:/app/app:ro + ports: + - "127.0.0.1:8000:8000" # для прямого debug-доступа в обход Caddy + + frontend: + build: + context: ./frontend + dockerfile: Dockerfile + container_name: tradein-frontend + restart: unless-stopped + environment: + BACKEND_URL: http://backend:8000 + NODE_ENV: production + depends_on: + - backend + ports: + - "127.0.0.1:3000:3000" # для прямого debug-доступа в обход Caddy + + caddy: + image: caddy:2-alpine + container_name: tradein-caddy + restart: unless-stopped + ports: + - "127.0.0.1:8080:80" # главный entry point — http://localhost:8080 + volumes: + - ./deploy/Caddyfile:/etc/caddy/Caddyfile:ro + - ./frontend/public:/srv/preview:ro # для /preview/tradein.html mockup + - caddy-data:/data + - caddy-config:/config + depends_on: + - frontend + - backend + +volumes: + postgres-data: + caddy-data: + caddy-config: diff --git a/tradein-mvp/docs/BRUSNIKA_REFERENCE_EKB-2485.pdf b/tradein-mvp/docs/BRUSNIKA_REFERENCE_EKB-2485.pdf new file mode 100644 index 0000000000000000000000000000000000000000..873c7bb6ad3325477a8ac827fa6d6de6c9877f8d GIT binary patch literal 255846 zcmb@M1yEeix90~27~CPayL)gAHn=;%-5r8E6WoF`xVr}r9)bi95Q4i)a9DnC|NGvn z-P)~vTYG1wrsm$$-S>O@oasKFZd%n3GOV0zJjk@OM+Y0ooD>`s&SrMV!ouuQZkDDV z&TbS8QZ{bRj<%kTjL7V&Zq62-=9X_KHSBFo+26`iIC64vyj}S>Yg=ch52hZL6bv5( zxj4A^ICwd^I5~I)IJlWPIOyNrZ+1$~7XN1xQBh<|CyRgXf%`x1#oUyF6PaC7iGp3( z+0D_^;XjOc{=-Pq*Ts^8U021-&eGfinO(!v%;VqA$UB-^TOzaT*jjklP;l|RRU~I= zYi;8}!Oin_-_8!sZW=D8=5IwmSbEu-TdK=Sz7k~l^)IA;CJMnNQvs|H!ZRKwL|W8cC)-dObb$4%?T=7#A1jqCy% zZggP!E;{_U>p!)Ky^&}Go7*p7{3h9GQ{4UP4@8Q>YDEyq<($S7`!jICy_6kFoyi{r zj}aJ=@~$T{VyLR&2-Flw$yD&?y$go;q%Tg_5Unom5E8qJf{&dxz`NDw~`}R8Dth;siP?G3ULnG=FRKo z2`1NcN#gd{EoxI)s+R}#Iwv>KJ6!N&u` z%xu(xs*vk(g!TMM+LGTShzaY2O#Fl5#mJZ6+qSKQ;feD;n&H8Sa4dVs2(l;^=u%o? zQr&!qef?0h>`-FwdI!?KBtQF1kDLMnr8g;4I?Shx_zM0uNSm~vj;$;Xu~91Psd(R1;69@ghK?6M+3ADxI&;lQG7 ztU>|RMSKWf`dP@}AU_iUBzuX>@cDs4Pj&n$yM>|UI0k-EVDMWZLx{LEzosZDHbxZy zL~M|y@+sa0x#J%96HnAi-}-v3%^n-|rU8x}hQ9QN=;KouVK4G`whYdHws65~X5Wr0 zW4kPa3}28G7B|JSgp&`$2H?3jOg23zFx{^3e$9sgTTg}t1umVc7t{AlmXTOpokaPL zX{f#m=yx%Ab-P?m3h}=+-Bdx<)hfcPYB%GK;jr?#UN`g2kI15}FY)FB|6*IQOJG=s z+^Tpn_y?an@}$12H9PU5DwNN!On4fw;!lk1LnINTLzRgc2lE?pkfRSPgA@$_^v+9v zH7#_o&{KBZ^oES7dWITr7}$QQmgX0?BxWb{HtSe>Yw<);2BGpVEzPjx@Vw(RV7y;q z?DDnWchPF*zSnJ4Ry$G4jzLUvt;R4)`v#(6_783mYOgzNY4F-^A=;Ye1lKlS;OhMd z8K~N{ivX%@j9o<|Qfp`+p?hHDb`eTe{J8U#Ma|cD-P}4z$$^x!kC+E;8qJ z8SFi?-L_bxH3`w{AeLTL8{%Wc-dI?}dnNcJIbAV`4WB)Q){l!yP-7^mMD1#Kdn#?f zF8f?rPEct_Z3e$if^QPnq=$UGbR%OZLE0G(BOAv%S`Aj6=(&YHhIw7VwDxc<&dO9& zAJQdKID+77S1I)F1QkC9D^tf-)Q;N>pU$|SUj;l}b5nonp&XW6i2Kw(fx*mIi45`EAc*$+nxuMZ zw69&yMfIF?;RLF9)v!(ocP5>ISNUG4WK>-W)J)Dap1D1O_R&z1HX0bH75j+6dnv0@ zwnLqKEZi$vU}d=Xokd`8TpM5Ibz)TOPEfjp_bdv>x`VC%=MVnvcN~4$ zsfrtQYbM`Vq=)f{IloEq@|WZ2G4)9gbO8s1J{NI1MIJnx^OCef6&BUw8G=Sc+wW}| z@?Wwypos)S{ZAz#eDr4f7Bb~tWX10Na3AO-&227s-a$JVdsh%izEkS$kej>M>_bPj z3`1izd@eP~TmoTg*QQlv9EYPTnpt;9J@F~4ZfMRFD5>le?n7(M?;P1D{3!)evg%ee z@r71%b04CJO=>(W|D20oe^h=ivF*4oF68)V%sT!E0^y2CUE>c0mmRvujZskz@|!jV zUgLYG%JKyYPkL6&ejt-ykwE26`rZrD0yD>MpB3jjHtwZoM{K5RT{Y~WNEEw#9L%njqm32xr*g`W@n ziM4g`BH)(ANi*L)qbI3dvnY_HK4{7h#QwEB#nr%JN92CAdCWCsqLv!T#Tpfj*`2%q z_uO$%lF6T4!U%SY?K8~~I`%`ZvHj>4ce#F$ z;)D35mf6dQ*Zg3K@o(Twsqi}UdzXhovgakj;&(Bf0yDtx{L+o}yewYWW683Lp2`9RoYAp3;r`3W)WR;e@6a-__-SaH4u|E&1?t#H&d1G%ui9ub zKf^0*aEPfpKM7$>w`Mlzrsw2^1@GuLfD*8=s4VkcuMK7!C-mMy+;TtPiKO=z1R4;c zc!>~F+P;Si82P#K)gzbs0!ii@Wx+>kmpglq-rcK*1O`2oWGva7?YFzBG-AK*>Xi`A zJQfHheTFNt1T$7=+zoLdjL9O-mNgZl9yO~Qb$U&j^v-T}kXfUC^?47=-YL7!<=h|} zn!YV8ilw7QVT;S?Vu;i+AJyhoI&9{vo4}-%D9J-C&Mxzbpgn4Z4uHHMx=lwF8HUWvH**a<&7^Vp zV-y{uGnPEPVj)uN z1ZN6LhsVt3zEMnV&lPy+b;h#9-mVzTgyFI(eLodMMTtC%^*6n2r9HhrM47@`KAPHy zOmpRa)@=_Y_9nAALetcYcWR*FB_D2%9zj{XjJvoh0^M=C?A{o?4^XIf7@Q90}D zXBMT@zxW4n@T12ja{AHiY6+4drA|ntZqv446z#;0cGQF3!D+m3BXgRu{exTX09Yrf zVIGkF0_lY;$I3l->1IpV{QL+d;lL8fWu58JJ1R_fL(PiNv)#pU{+(t%Exm77ng~)!BvTAi6c&aH}Axu#5lT4VJC<)_?JaDvTrlQKK zw0?)6*)AQlbknGN(r~eqN+GB54*m6b682zgry#H;w#4dLR}ZTf)cfq@ z5bqQSp-nO~AW_Psef^0uGa@}{)Owsi7r-)mPd=c_1f7wj8Q*Zu&7@%NUXW#(%Q&MT zQkYz8Z21Ev4WrqCzu#q>c#;$Np&K!pY^0KI!!)sTNBA}~@vwWo$@g<4Y{(H#2-jU8Xlv#|!{?!K1$aPmHQ$_SE4$#t})pAuwQ%oN<~-qbM}dB6Sa6wpK{Hs75#7pxDy48=KRZyA^|Sx_MKzMum8e zKG(@y+Mw$x@vkxruDt4V%!W(xWM&09!lJaCTsrLBW+Q^Y9R zW_@4jBT|4q2>J&{6=ykSKY8IPLV9bWnjZc-{nQM`d ziC`^F8L_d>BtqiGMURo9&Ub5KIFD6msfYv-vA+rxzQVDVVDZl>CPgkO@0mV|{>DfW zbUD|z;g5h%8Wmmdc=v9WgB)_SDGUj-5baW}3;+%`DY6^5_d3}s&`Jznnq+(5+@(XhaX zD<~;T<<{?(zO|^6;mo~n^JQWl8G%gS;P?2z{%-Wr7Q6&sQ!`b~wi^!=g!@T@G zEZqw){Bw30Dc|jUyJ6~w(d$sOxC7TtK;;Qa8SgYvoB3>X0$fabxux_r3wbPM*#&na zZt;Ev$ysm8SM+smA-;J1Mkg8Lv0(A<3%b=S-q)RXgzT|1Q#sEgg06ry2sP3{bkOGk zw8zG^wDfgxzcoMY_9}bT_1xqLYj)hT@Hg?)%^_I2g!I?R*;6StvGiD`77ySM?V%&F z5CZO8wYqA<4$PnLKNv7RvnhkJ8#lcc1w5n%89#oF=Us_ycqd{G(XL2uXMy#lNl7!2 zs7lO;O?3zy`L<}TO@PJup@W2nB2;wo>dSIZB@()p5UCySZai{4{zGNnY=K9Sabasz z=eX2N_si8Wd}t9aMs%YNk@j$d$^0iQ1*C(GG<(v`!7iSa=<&v2LlVdj!O#LpT_z;hUtQvYdYco$SgL;wk5|g< zJASHf1&@gEv?|mDc~v97g-ygC^`C1D5n-C&EqO_JhtKXKbBVqW{S;=8 z6>~6K346zMdt``iL^zTq;?4s#OG0oTIngUis=m1R6Vov0J+_HW0E;b~5rD6-m_=(n zMzq>f^^KdzvL;<5*CQ8Vsl*Pxw#q|a5F=InDHyljrYyExXIa)@VWho`NP_IdnImcp zzFk^sOrN)mOy}n(T6Ef&QqP!sD0R~I8&Hm&_q|@v?W5$)j>bgmU@Ic{HO|*H$2i^* z@Wojur!!Qg7;K`jl1_8sD=z&&^hvk0I$$Z5dg;DD&X?dTcWOyYR;Qve^`$ts>z`c1)-e1CaP^}ewP@;yCP zqgqyJLi^R1uw{MPp5;XMdEav45uF9g_ewjEq{1?&lsFk}K!Of#*T~#&=NHP_OI4`8 zKF0Pi=uZ@1RitT_pd9!D%5PM;l7)}9(Vr1vyD%Y zy~s#@B7YB~!sxcHo=Oaru3Z&gz#w#@^o$ykjHdUjGiz*@RT7rod{Wv?OU^giM67?v zHN(S7f=-KDMYdRL5Y7=+{|2m*A$uoni+QV;F)H=gg-S_*kn4(q)&o~V%W51k@V4`N zMuRJ@F>iv-C{b*gm|W0F%^N@MTfp`^GkTG6C_u|M0=ImtGk{UjYN1i~FZn_T!pZZ= z7oQXpX2(7+l=cTmUA?Zx1USpoDt_CzR}h4sT#FR-Wc}n+JXFOzATiMXh?q}F${W}H z@$2NutmWtARKu4&WfI!~8tc@wP~v-c`d5(4Z}-@LxZJ;(*1rhdKYZ+8wDA8Ee3NxE z_5H5{H(oBD|IFJa(pTccIZ&nUU-PYs=jDKdUdP7MySA-LBzw~lWFrc$FGB{uxrpge zTAo*_liQJ$@nP#Z@w4g_NV!lWbW_@p_|TP(?G27rk7Qeg3e3En%|f|h&Q|t!Bvi; zh#OzyH6+O!@9X5gnwuH97lq{1Lq6TG!qxwzqBFBhv&4`Dgm?Rq!`{;z5QG9ELn2_{ z7{n6+bO2xSOdipwfUDH(PepfIR2d%zY*>KEinE+G2#zWn*W0k{~K=BbTf5w zw|WEF6mRwYiy3or^9uYYX#BeLx(>hu%gDkB|sN?lq)Q$<~n!rFq> z&c)K2!i$rQgMz`+-PXyPLLMwj0alfkrSRh8Vq~GPu(UGubnu{X^)z*`_3%Z0T>(e| z5D^eS2=Is?5C{ng5g8R14HX3il@J>T1DBMDoQ#x+goJ{Ijh=#vg_?wf;XNY@2PY2? z4>`Sn2tSuF8#fQvKb62BAt9lnpc0^=5pYqGP;&j3kJml`79tEBOgj*U3IK}*1H^)P z9R!dA05I@xYX1@ZuLA}a2nUYi{?`cx*~e z2?QK9QxKIaE>}oW0V1_zLqDGS&vP1XGq+GAWc+soghaG-^bCwlJiL7G`2_@}K1j>R z%E^N@G_|yKboKPj-yW8=jjf%#ho_gfkFQ@?ctm7WbPOapB{ePmOGai^VNr2OX<2zi zWn)uwOKV$u$JcKIgG0k3qhsG^X6NP?7MFf4Z)|RD@9ggF9~@p>UR~e(y}i4C_(vBE z0Qlc!{kyXNNf*|eE?77?AROo)T`;iTZyz8Q96Ti_0=9%2$kY{wiYo*WS2C%fp&yBw zTm2l*%_2oZ15kl5Z=DCk0*C=r8EtS|cC#b+ zi5wZApo+3Ewem7mxag$`#RRRzii&qN6f72GMOVcfMILYgjKPpZUdlMWKffKG?YL3u zw0JFuTpT+R}@Wf*02*clW$}j?rRf=T*u00B<|VXQX<9m1Mh6jU!Y02}<2s+fqmDF&^IXq$908P5)>5!|RukIYac_C3;H4I;D5AS{{-&culHZ+2n;&QVw_R4O?l_#_SgPOE}*x@ z+eNW{$$(K^lj<)$z0I*tEz>VVc~NMP;0a>l2oWO<6HLf;EhK3dH`ji=TGI4EB@%fLMuBOXG>8+(tYCXHMQ;*4TwHC~8t( z=oC+9ABIOpe~HC~PyXxr#Wc}%933TDCfzP_?GTK}SKuoEnzdf7rfuFHlH>WX=!#!e zwz9<3vMMp&!SA2=p2QmPm$y1&0zO<&@^i=34;R6kk&R*IDSuT3pX75qpgnxwNie)u zichCfgyfJbH2{i3LQhY2EbTjgec~A)(m!dDl%Lm?^AnTVJj<3UX?VMT^cGYjPOT}_ z`LNrJMg1NRN0c!c4DzeKO3=535mHd?Y5}e?OzLVnGK?6`>mp@=<8tN@?BYsG;dY+) zE8|#kVb;RHXdD_SZ%TZthj88j@5FYseV9Z>P52P zthf$KFPIC%Rh|o-LyW0b3SFWS%LdtRp4Jy+ey91_rSD2QxH}nM#<<{7hXfK=n{oi| zQ#RC4&T%s^2VU2@|pV;g%@Foo^0NL>lU3*g}nSPy5(3uZ)o9d103Dl4<;G^h^`M}4ip$8mivWF|1rm}jDSQ6taiJ^%7_^=OK+qm z7p$NR;|4{z*V|#AT<)qdt)EyCm?p*d#@Ub6wO*RFIs`3>mtEr_|NbyPuBML=SdIQE z;iCE@?$FL>4|n^Gwe~hZ=#!EZOX4usrA)6nQw#8;#s$gyh0@a$(=3$xU%Iq=Z7(z%`( zfdfNdg6yos9or{MGElv+VtkW0{eY7kJew4Kyi5yBhPPgwz}357=pf|v-9BQ@AFhxO z^ve|ERuZ??V7<1_&#@|32y7q8G(2vrtZHu~&y~3)r*v}FvcTut?vWTie&N+QDWXq; zjAfZ7_hEC!YM5ni1MMz-NJzBc(kB;@~w+J)P?87VZvpCZ^z>jQkVvMlIQoESO9 zgF6aC8K4+)`uY;ewQhY@scO;yevKg+#(O9TB(SatodbqxFpd@jD~=S)ki|vQ6V<0- z)^Zqg53T{n(-=H&-pnPT4jlT>!UO>r&T+XhsWZJdW(-l6P)(~sZy{S_ilJ6pC|1iu z1Ra6jQj2)uEI_23`LA1-fGWCmhe_r@88G zD?l)$W)jgxGCuzk$%{axwh`>NiK^9J^*^7rJ%@|fDcbn=1$e!WS(hkoe=FG|(6ds# zlvZvwa=-lKBxLz>J0Ww~8H7VV+#HddaBmX?SDMZH3MefO0K7DxBIvF9MLxMJF}wnP z<27cPbDbIZ=DN2DY>DP*a_JwZ6+QB68(O=QpBL_<)+FRX19|?ide*Y!?2dpx?b4ww?GJ38Hb zX7NFqyU4RG%^=LTkZfl_ycV7vYD|VwU5X#*@J&}m!u^GtM=Yd-YXF$j73)gI!i1ct z7d{2gHi%<6;AT{~Dp6%bj}{LJLljlvEYy^#Ab@MjvdtoJqK<$mgj1Ro0MKZVWBe8j zV3O!7h4>T$Bly*kUEaRf7z^_lU^tbF%TxjI{Kz&(>c{|9CUIM+#)UXa9%I~0F2vrW z6y6rZOU9&qq%_2d7+U?U1=U`sCWR*hEzKn@&Mg!4w%}`a&rG%}3{=k`8T#R$HQb@x zGHt}ZRxOk?Rx@aYyZg0<>}>-EtIR1{XMco*<>+?S?u8L=;mNt@#mmhc^8;rI1u1^z z;-JCrr9QO~mV-2YK)yP+5qo$SZ`qM3nO9eXyhKI_on+%v)%5wNMOJ4_U7AFUOkZ*} zLb1tijJ_{ktvy7o5Iw$emZ3DSl%&L#IQ#NPXlCZSfsPvXze{!!X6^}0HkSvB1)!w< z6aAu%r|p+pE%<;!@(lw_yY!C^>DP)AaFRT1n$O4Md7{NyDVs(-K_q3fNV*+kvPR#* zDi)??1D~zwf6O_#u9%Ko4!PyAo}ZLPxv-vWr;GRD+Zwn|%HAy&(SP>XrgrdV9p;yK z;oa-uozqdBU(o%zz_-%Ou@~|RSg0xDnORi39J3qaQ9+AS)=F^D<3vJAY~>KY7QLCN z3)xUbc%%?nXU%`ypA{B!{R?F2Q2=W*Y%X{AsJ#LP7y1{;shu)~K3OL`Bjjc;O|-h- z`k~c?uW7KbEP*(eW#ApkA`0W&{~mma-Q+=esuI0CsI4QC0v2Ic?c}LQjBM$jRQxF0>K?SIekzc)N58`Q0q1wUY?+UaTyye*lrRc~MvH_92k355j^{*_#cUYekDP^k zPuEXqP1*{73~&6@3sulP;Xt4ArcvC+oGjn_AuF?V?Ju@KLd*o5K5Y)?0ExpD{=F(J zfZ(NN8z-1%Su7mpL8s7PDet7V+VK<-n?<^wb9Jk2rt4JWtB&aISISC4e8yT%+^FZA zK&w34WOp(VUF3Qq1YBfJdS3-l#zYf)j(rx159Gfg=Vs-5BOi{FFq#~!8X+->=C_i-R={v)T? zcCrfs=S<@@{)(w^iF=Q_&x3ZM6AOn*1)dh(u0^Xr%a0y9ffLuaspi|nqpFx?J<)xn z;HK6c{CwKBn|~(v3dobasSW9~P#=t&2v!d8DQwhfP-LTh6ltDGda32}4_iWg1%S_O zpjl^HNWkM10qrR%?4%@ z3eShizsSd|>|nXD##cs(LRfZiIbb-uM&8leXHi|Ia?Ktm8F4D8#_eX|Zej0)jD9XB z2sJ|NEUE25hsypdu^p@i`5kC(_DWHB6jTVAh99CVDds^m#a;G&%b6_y`O%lW8hD;B zU6>CTR9veGxeI#OuW+#TV3JUS_*6%-@@q)HrEuyHM}}hHkg%p%9s|L-?Y9iZZ;2QP zxr(rP@Bq>S@nYD#=5T;U9~9lTPXne;GsH$s9Y#9X#+Z>*naQLbcjQ13Io#w*&UWgy z;?1q4P_wD&8gJ0_4QzTnmgu_;+i9fk7DcMIWm@D>w{NEK?9~pL5)a#wA|%rEqT#mx z9vDqUcz&M3yfaxfOuXu+jQCS}3In=%X8zuCc8~N5=z}*tuPyLzOI|WC8poyM%S^(6 zZ!Egky8LbPzG3;#DjZueNtmH>OSOtK6$^VCZBw6UMh&UV<>@rAOHTJ{mw|WK*v|cT z?Y%lne1@Wy3~RUi^npjNbe#*$@Qn!)>6Ov**vbZ)NKo%5=0I>^SJQxWo|(#pAmsY- zs%=0J`xW44yK#Ehc5GhIJ*Zi(%B*6sRXQ)2*UL z%hMS_f|l`M4Y|zaIJ;nJ^dd8T>L*`l8>o?a!I|aJL@6quC$uuZ->l^c(Q(^DE@_I- zn7V&rDv9--sYwi$Fj_hrEBhUII=NRjjsr8*P@dvc#Jz8R=L+{Fxt?Z|#n1E2UF!^v zg12L@hPhwxK5w*te=ZrRgt_h)+c0p&t{(8(>@vT3@#K#>iygX1?a>K8y&67=$-l!C zo9R0HhMDO^N8d>mXz>b&@Cw4T__fi#DPp{i6Mv`i!aMFGDUu}I{t8Gheg*tt&Ob8p zv9zI7FrU3%M++CX-di0^@S=a1TW4_X+ej!=E-ehDMl1PxSz@jw`eaU?QGT{#;7E6A z_zI{D$rjx}bM3ZUvJSU@hp@YO>E@fR{wH(797q3M{$bRk%2V&Nr#R%synaxGvD?D^ zOdY-GNR3|cVHWcc?8yT$BeIQrn>+;*EAbpkDWWiRI&P6c+m7A_+rnJ2QRG*E2mDh6 zUdH5d4r6GZpeCwINpT4-Aaz4tK^$G*=SVHSh3e8z9cEo4f&zDEGnfRPUv0Tq6;KRx z1%r5+cS!eP#LM6(VDlK4K=gPVy9N45NuWlhuDZM!MArcONcZ0Wq1c02i%ZIQl2eMVQ{bUkQgTDn_q> z#D7j}CxlV6*G+1!cc;WYkc2!n=#Q9=o2v{mz}8J?T^-0!JxP1NP|>QMn#sdm`h7ya zx=%PAS*V1&et(ThqnhZVm`OjIbzP&nC3C(UwCH|6D)z0bPRdPr>hG`^(e<+$WZB1; zxI7~JD)Fs5KYZz;ufNZCN^O6k8`+(D!8`GiGjC|slDZrW&I6ChQLG-Bdia0)I+O zk;<=Y10~R=mNwscGrF*qt1|cCN<8u|=p&JXIlAFZEmttW&1&5_ z@!LrG(C+WQq6rA_M!r%4Aj~=Czb$OLEt*&SvTHn;iMg>%=h2|1jB%5^nsYZSi`<}7 zC`HL>EV~k$sg0v2UZq)Niz<;I#BVLJ)X|eDM`1R<0GR_hl3(U(X*QA~LVO9KDlw6(X7m16$A@CXy z6lb@ctlQ*YTx(EJO)8`l|9#M4%9g9$$|2V8X2{SeNJT)Kd-&Jbcl6$nYJ1fRM!qE5 zoRPuIzLwebDQ^eseX-#RA28`(EC%u;;eq?yG@VVnC!MU4#(uhOIRu{(+L%`W@~?A0 z8W#gXLbVUB$v<2K9G`=bkBUHuy6V>MO!Z&HIQzG3sz2g^&+k;!y!q*P6+blr?7;!b zV>C$A_`-aePUIQ2A4l|4(KgcK@oC0gf)I&TQpW$0LQEn|Evw>ta6N$BE%1$@Ih5t z^bf2No6uqxxx z5XFHqE{w536yyREtG5vHhEH`rVc-%<}k!}^uQJX ztFT8g>>Hs$c2hS?vyJvCDK5;w1}fwBtD~n53X^C$`IP-FFBVoOR7?0_8|%W5R6ksh z^n4f$*))_+@Z0m0`HpU{f2fLiwN~$m^4*Lj%!93gDLq_?q9l>kxNG+fofDkTm?JyAdAko$T&eV5Qqro?TIGc#naL z4BfsyiYGuX?ZW@Ispn~+YB9=HD^5Uazc}<$NfaIg_o4Rzv7$W7+ibO^=J!DyE`F9% zR{9SM;%t+#kskRv-I;V-7L#_1)_6TNW0`o0_nd_EH+4XTFuD?a6~NvN-ZgFF<%!AX z$I7B>Tq*4j*Rq^J9;SCms4Otpx&&=o?N%mY;Qc<+(D!bfNh@pZ0g^f?o2Dr)C`ilh z2TgAygb_skGB!44t<+BlRv*u^s+{He^GMzYX`fiTW4=qDAs0X87Sa^?9j5PkO%X0C za9gDT_RSZDox=3xX(rH7qtHremAITV+2<&S_ePRw*>#q7LMq+q;&ruhd zPtsm8>+s_3J2kRD#h8g5bK+4hv?!XMW~mA(UA+Q?=YM-jZi{4|Hrp5WUT`uFbC`=w z0cT3E4xEBKE0-N?=OBwUhqE7UMMRjn`Y4 z{Em%$=IxIa)(0Se@>yUprk(3U5W^avJSN=%y#mM#wF0EHd*@2!*=yfAj##tihlBV7 zx}6q(jhf-f{txD)$Gs78S5?hLj8>_3Jeu2bZbgKSbqwt?WOI@iJLoMC$&$nW$EW7Wh1{mt{FZo+iFwyUYh!}sOV=O>Ia-n4uW6sc*pl3gu z5_11fp<+`z>TqF6%CK2)sSFC3p)i;RcS8{&hXGcVNkTQU0;U))vjibixfIx>tf4mh zr5hg>%-B(w8xBU}Cu7326Za_vj+$Mk(;ei`L5E9)-!Zunu9Rk6vW2XN|14aEkIqtRn$(H~;~idm6a|ez&sWjHP;@ zG561gp62}O42L5T8FwOk6usKdK8^du6oR|jy+Oa~FMgbn3bs@M-v_^9<&c<=!2Fq8 z#A5&bWXl?5Z}VN93xS#n>R4KbN#H)UP-yRyU5U}Bv5SKHJ(egMI_#=L^iv3*JWj@u zm_#lJOM1FmlM`YuiFBZywXF6t^(FNWo7Q3QGnx>Tnb<|pReom_U8?=buHTAOt(OT{ z7bx1?7eVc|-h=~b<^t&>2&uP$#erYQzB7q4@lteR9jS+jBT3_01rymaDp9_9OzSIv zg-HZADB-3u*vX`)4A0Iz59AIO7v%kh%(!kUjYlnb&anSIV2A;F%@Zy}P=+iu0UJyT zX5<#<0bD3ga1eO{z}<|Sh5CuAz#+j5G&UQU`w~!=l?^Dbc~C)uCp0-X*oBwEF3gko z{B3Fkej>Aroza}>MJQK%BD3X89H-}%e9N;Z7>wls+9JCZ_UPV_W) zjqI~yFb7pSwH0r_q~sZvi+q82OY0>p78@nT#-7qONX^GUtseXK=H|$)U1yq=bZvm^ zS|Hk-hEsb9)?M=uVsdE37x^ryL758q51GuV*JDL(Z?S1$7kiapcXHbGvA8lVuI$S+ zmH7>St(zFSAy{@Sp<>A1_64ysPvVk+tSn32HKl`z6~|_cF_ctUsHCBtDZb1sC%u2l zcz)IJN%;cr_p-3xhgN+TC)L3jLeQg9!n8?%-ALpMxvz4aU`V|9ke^XRI3FTDe-w#D zyxj(pNHd)>bAYme@?BWrYG1?mY~lhnI@fFM&6dqY4@Mok-^XZA+#d`sS0eC=%I`kO z&ug|!esN|C`fRp$g*R$Pj_R>HesH^}{qZ=Gr8mu>M9s^hVx$}L!rjsGG8M;a0g<+% zX?Am>CRmR}4Qv@uaBbg75}yoIgS2guqucw@2)xWdE-`%w`pF~QSgTfLyv9MBXzoh( zR@HVbI^7c+?nvwHpg#~Fic3T>DZ`C<$Ks7J##>yZb@Pl}z_Y7DDz6}y>q3^2IqSr? zgmf?J)!kwvnT^29;ei8)VKtlWZrFr%ZLwH9tk`e6G*1-wxyEPhv<$;$@#|84fK`$c zWy&cyYK3Pdas`JW`FJBb7N#$;-oiaq{^nR`f3w5Ao#fuc=! zg&~VU*lwolq`*_<0O}}IOG%WgvD1(3?O#vF{JunVE*p!Dp$scTnnJMN*0v~%G1@Pu z{6V7v;=+0GwiJY)s^KmUMPlrmGnoy6B56K-%R~E6wo4xK{KnpqU`pPc-$ld*^LQE^ zjVI4$Qa~8l1_|gYXFylJYWJ59dY@7ofV;+e+bQeWbp^D2+?^{)^a=wbfsQs^{oez`G*@m{eHFuxl?l z2)9gzu62&zOq__sb||y#uKT#PNTqZ%`8wRgO(`>>wMuwiW`&Nj+7mLU+qPP9g!I`} z$7FVDZFuW!xq=QsQ_!uIe+mlQ?C4Rr7a!21|963SN^%y3W`sHSO&{Hg)6EpLs;R`Ham_?LeIBG=|BnBDz`F6A zN$9f=jY>}N@91Hj%i3_0U!y*a0|A}sgvamQ?};u>43uq(&D+9GjJL`sS{D@b-T+v) z>Mh>x@aI>qA{9V|q86R-)`36vwH%|AF~H$&%?PY}gettZ{gUk5eMv0@4G8MTCmTEi#EeYu5zOE4@r~WtbX+J z2F~&*P^6q*m&=tqG&i%NSsjSJEIvTec<0UV)}P|6_)EX_if&E2E9nn3EFN6RiZm$@ zP_sx(wY>srt5;Cdo&B|xnAn+R!(zGFuI_T?A3c!pVd!b{?2LEKvmuOzu5S^MBvBf+ zmYP+7jK*eL=_^pC3OfUFvUL}a3R6ZXnyS&sR&8m88y92~xi98A%+Efr;5M8Xft;B0 zhw`O9T;rv=Z+^bNq*{5yDveyWM!3+)gIx&TZyHG0d^|JT(crRYLtoYlOHFWuScD z!(29|U&AdF@oRzxn2N@_MERXBfvU<(Uj2I=2R~#$ZM}Qw{exzeT{}Nq(&{yyr4A6W zQe=v*RIX_?MfqEY9;^Ha;Ms1@E21HtehC%1zMccfuWILGYPy=F@&QiXg7Y?bufzbd zYQeq($)d=C#U=U~zsf-@LAIOEq3c+UmRpd)9w=5~zg)~&H}!5lLB9gkO-6jnrUtQC zTt;*ImRCNeaL_fJywgPW72u=Q{xm3H=6W(yRYW;z^y}}CAw&QP@dtpql-Z_;k;}#+ zHupP{=m1qUOYo24Ehj%LMco3mkoNa2U`i{c!^e6*bh+BE*1R%Co<_f9fFhqY;9iIpI7!RA8ap*b+h4hd<9vWM==t+L!!O4r5~*6vm03+=zbqkOwg0aa~ZF&n58 z|Ez&(%vOJ$PI3(VsgagjUCycYo!`lDbIBHevM1W@m!;0S7U~ub7LVOJ&}}1fau2!F zA*mn*TVp=>9@@pW#uBU}AD!~-s>{J?d;IM&aO)tb&ZU;7&ak%uYuq2ZbHeh5ov|%^Iugi;f<}}we36sQN zA$lM%1F!@kbzYC1BG^h#D~M>Kuh-9HOoj4N?$r1w~9gh1eOq&0oT5LLrI2=}D;Q3C~S6{f#rEv(jHNuy^H=_tQM zt{w{Krcw_@^cM9&E}EW8O1BzbeP%quoT9#}NaYi~P`g)sM~xM`Q!iS^%OEaGf>9!1 zHl>_*!x-b0kex3jj)YxjrgB-K%Q!5+Gv7yns#yv0^M?6Z2_5$zSuRcZ5tt!;bD#{% ztE%!NKuEnQ*$rG*hFdFy{h`x<`HJkG)Xr>DSpnYgZ{_y^0g(VZO$}-Fut%j${M55`i(4kRMcs)G?Jmj4K`Q0Xban~4_ z2d(z`DUE!;W(A(j4!C=}Y-K@nfvS40t-aA}z=C6AW8L?zmliLvj9^*n704QbIxo~e z)+Fg{LRSmhkuwMDEKINA<>XtkJZb0rT)_Bc&PAw*eQoAAk3Mn#D?q(gh=cmNv;jHX zqFl6y`ua%8sE>gKMg%W`Jf>jVGAJX`^k7mnw51~sGDFpbExW0rFWoF-2)y#_r-x*| z(G1R2pQ8}%qTq5TU4}icph-KL394Az=4+bZ3<`@JZO6&1_>Ps!_~)Y%)8uzBk$xWZ zt8-SXqwaKk*TgT8L*+;VOk}hsR?Sl!y~q}^r-iezvP~+m-9wG(TysTeGS^C4#+GtI8KETsrVwPb-UnvfUXI2J+>3}*r1?Laou8)F9@-^g)68r!z2?<@?`wRf~HR^pvnZ14fvS@L_KzIOE ztB-^RqB1u%JlP&@KiwJ*@J~0n&rXcFBGNQejGg+j!o9Nx)FN3D{jCPvkVf8hA6Ob( zf2kUeG=cbw#+-g7OXA9d|oUC6RqEV$hy}>PR#$i8oiI6E}uOr4RQcoGCXQo`o>9O?x< z0uzdb?=4p#wvdFN&l&nP@OlYY2>&x{D3{z1OG>X&lhci4O|WZL;HAuIbSXjb+p4jV z8Q1}W^5#=;ALaVs9_BO3D1rrV@v8N5l3HW=%2Rev!WPe~>QB_6PUx~IFT7t+H==$Z zimhE&osZ$rO+TurB_#$-c=qSaNSCa+r;m!>J-jXK9VkRceR=mog#}FKHRQ^CM z@XD2ndnaVvs-=UZxKv{I#N(myZfB(3Niizr;j;gGz{(35_Grz=?dLS1{Q8S|Rd}v3@ zc0#5qMz7NGH1EF$`Lb<)H~eI+GuCbQLGHSLC^hb2=YiuxkDK*38n1YsVz1Fm7*Q*H zyVH_Lq~Z#-FdV3V(cpAy<-65&58#X5CtB3fQASXyQ3hEo-X?w4014;Ue<~+380s7{ zb{@eUk{ZCNs~CjuzI6EnxgZv?Ey=g044*&^Cgr7gq|WTdG*c0GP(c#v-YZBU;)(hM zA;{(e?xhTS<+PLx5{{Qk%}nwIeNW1qL2}|DT0Gq%{iUI$#x`)oKp)y3euS^zq!2>} znD2-F^6a@#Y3eY`d0YC~D|LRY$fil3ihI<+Fqz64)LOA6wKo+V=e=M(aaf-jnr0gf zL@uUcC(;qS$C=XfeE)800Vyr6NfB)Yp|N7AFX7~;ChbRGIk$J~n%+8m-g5jQX<8*1 zu5Q4hOa<|^I|zNKPRb^Ojry7ixNa*gxDXL6PrL`qlk{>Sv+wbYMlRor%EY*1W?ZQE z9Xa9s+K{H3Z({^*gKsR(MHPWLj#mYD0!Hd znmS2gLzxg#CYWHK`u8k&VRYNr4qUPT?Yi^V64+z(L|85Z6~m%oIDm*Mp}rB)$TpEe zOxA3syi6jX4&s6+g~c2fcc#3E&4`C~EtsqbhT<>_!X27ZdrHOg8=OB-CkTobp)-gl zfE?r{Q_39>I9~xa>B8r|7}481;Vc6xo)k*(bx;83A+su&nrQ*YRU&w!2w@Ho8C#=y zyrjckQKiU29*e7H>0s@}rS6i6N0T}yHc_OmC{VupWAe6Y;dWaT;Yln3fHFv(9oE(?@YjZr!hifG*Chsxd(p-Rb%}bN2 z{5fKkjW+rdq<(g`7H22X#qat;pBA^#z-uu4cvM&}**<|A7KFr%5Vk^=E&%FQbbY7i=A$ap%8bz$%(T%Omg`soit^zi|}xs%8=Lqturu1cwfdsZKY4a?XlR2 zVT|cF3~p5I4-bqSyYQnwi+IyqRtVcl{;YC%>@lT|#9qpGMZG$PGNYzZ7=Yh9FYYDJ z=dYJIwb0gUrKP;&xpz}Sjso0ccTfaiyHbMAPu`32EzEcl6bv%BW23|ezmuZ{wd^Zq zIvC#LZ1){7<&)0V+U*Tye-tZ;>>Rb}2WQ}f;Semja75-h6*bTDxmVoLtl{<%HJM7? z;X~KnRb1c`#H?OTS?bERU2GLN!SYrz!MHeU%2Mnvb0AbRcslTDFod>^VA`~qy_E-q zQb&nM+7oB_pv7i|IqS!={V8p$y5J&xn14@@eS4~A;a0xKtvYT+-;W9sz0)|#ckHx< zP%a&6KP(pR&63{pfBCKP;smyt^*Z%dRufT;uyu@GcMv3P*mxb_Uh2dLXV~RcV^$`n z8w;&$E0%ty+&9xiKsyA&L3>h=kbDrF89z2c;IjaKmm`}82?83}TS{~8N%R+w9Zhye zBLI!31Uv;+0O8%%Am2$hd{#p?WfU5tXyD%$@ncYm$1AT;<4~B55i* z^QAAly1g5Y09;w3mkSuM*>-wWACY{={UHy!hW&*0805z)_^exrql%~{vFKKsQ+zbD zoH$jKHaL85`Hz95M6buA%1E)d$_b4M4VR6U6B2E`*ebb_4Lis|#Iz|p^z zPUkVO)I_CA>DYxbg~F_(gn;?*PM$##v!${zT6gHY`}^{|kR0VhMVJJPU#WmZACF37 zh-g+4(@N}(KKHk+#%tJbz!U-y+u88v3({d3V!0L!kebJtSxpUbEF9o*UghXb0Iy}= z)sS_BMJt8Wv%Ecc9w+lv{3T-V32X%eX6)OJRkTK4I}&?No>o1(Wi+-r&uW|l-8d~c zn>o=)v4z;AkXhefOj|)YlhFnahiNKcUUgCvGLV^+R8~0@7gEOy*AM{qh@`Bv0%&FC|kI2#I;}U4G10PC}AThLQ zmsmH$!P0QP{iR-tq5%y!xKk1#=Dm=_03}gj9pdLu6@l9@M!K)PEgMmn#0ao`-P~ernn~F2^U(`V-OxQwlvkKS&S9* zSZamKf`1B2@ZFW9tmHpABxA&VgUD7s)e8l2dQ;4D)GlYonQ4L4%W% zMbV&<09wHVcxEtFIwaN$O-t9JXfe2sj%0aEktD5T&dtH814o)LH0qPBk|*#T;1k|N zj2AU2Mk|y=2u})aG1)WBYT zG}rIsXbYEDvH;-TX$l&AB6Oj_QYjJX4qV5G^=L{72Pek9W}zn8(*JYye~;_p{V&FK zv9s|0_qZ;0w*OyYUH=*N7Y`@Pe~d)D*btRT7R7-wrj0-nm4Gl{6AK|LC=fT0fa!Ob z7ZnJBFp=?MDL{#I;tzq?HAG+zi-49dh|jA|avhWRh7pW_*42SPRaHs0Sbeumw;A!* zI=*jn?B|a-ANhPc^YN12aFagR#=}V$<_p|h zr>6--L?W9bef4(@4S$HBC7DtV#xEomUbp5K$p1x<;7g&;)(hu?(cGR4vd@@l2Uwn)@ zWjV5Qh)#AvfBO<}v}E5z{InKl|7(O#J*ep&<_Lj&KTImEVhNl6m7zzOToKevP&MtMBEJz8&km&W&-h z?e;8dzJIy3%3fjW6t7Nh(t^m=_nmq^oyY|Rmj=L3UU*q4F zZaR8xEQ^8G$QQ%pC5xO7eM1sV8qG>YGmf(^O!N^qbJzX3eD{I>MkMhh?6;NO9nsl6 zBk$T;0&pdh8cHPmNy)BsyfI^AJ@}((0Qq5mcBKJW z;r;=7Z>YI+Vu8Yyyl8)~q1fx|_MEw`wed4*V!#L2%^SQ^IrwpHxr0sLyrfg@D z9EDQyOYQr=2YN%7=>>-`KRQG{3HztrJR+sX1%+Qh7_H}9PfnGvlE=Mk5(t}ldK%0G zL|h8O4RzL;ue^j27Tyf}Gq}p{N80zxotpTC6{=sP>d+p5idS z8gE(UM~UX;vd#fG$q)8)lI@3wJO1(z8SH7Z7;%vt76!7!#sABs@vwcEM@<{1-P}FH zczQBkfz-z3irqM-O%1eX=pyrc=|btc^N$;V?qV0vlcbO_fcgsUj`7vQnYUk^06(!e zxH!iL|D*W74v66HDR~>?<_;gn@4cB^ptHt`#FQ!3{A~{r;rcpiD-cN-8X7qckZ`?u z>CA-IjW0MY+3!&(4DktCJSH~xp8)MYP=o$|3ijvxV%PjPoc&Y%KM-yH-{PkKvp-li zUS9V931}H!b{NZqBioZNI_qb_1H;QT9uLQZe%- zuqtS1a?!HuMfq})@R7I53lf^Y#WhpZie+WQTb=Fe5OKDlzh4RRKXy9)wY0aZMdU&x zO~E^(o?!QLJi7CH^btQ*^H&froW-j2K@KnQKO<)9DKui^$4kLRRT|YA+@| zKtO5)k?Qk7aOP#HAV$DpfKx424V8c_)U70vF(FX2wD@W)&dXMCY&qVv(u|SZrx$@C z8BHDuNXZG6>(+jl6Hh;iC0mpAl`$;fuvtJv&#|T1ycg@|ttE3Y3efe(&xeG8>O#YZ zmSfV1q%*Ec$Vt%zPIsR)Hw)KP@vCcuXY!*JWx6mqT_OmSXsQ(+x2nz;VR5=S)gaSn zQnz#ke4xsZxyGD|LMN6GEL)5l4y|xtshp?SsDj4WD2F68@?_}$!Adf>Q8f8w8pbu8 zQ%s&bSS)Mje|jA?oYb}@BU?BKPsN=6O|it+%D{Fow4lk-aG^(bF>)t$ccjI{8X^*h z0+M!-jgH-+-+KTf2k1WQ%AmSBpJTqtN62HRs5b^J${}}fYaEBt?IRd8n@uvjdn6zc_VQcZ&P2r%mQ4~u#?1O zc9s8_x-31uJkcB=R#7wdEAN_UWrHMz1XC{+FnamtzA+?cC9vkFLJVCpPNAH14JH|b zw~p8n?Y?=!ce0^d)TZki5b!EJ9aSRP0y79<-~Hg*7{Q55s=FV2xu-S^cI<8^#lSc; zW_4q|u^%zAatUV;+WA%;?PC?}fAxP0*5>&{P!dMs#tk9f<4p3PK*yvNIMuvpd zMYWdLNa3vUM5A!vq9s#6Q4fyje`+>3RJq>ih>}j6ik{q=r4ib_r4oIBr+lJfq zL6mbwq_GiS;}q$U)5ohr>hqq9g=hdtETnz21`S@Foxxbq3u?|PCa)(^e#4TOTC`cy z!OEH;WyF5N8nMKvh@imd7a$S(b(Id-=iS5lg>Tj-wAftNBl~U2Izd>k$*<1US9vvz z>Cqq!=pkp3r9N1Sifm^XtdTi6Zu8D>@;DUfl&JwkanSbYjGhLiprAktU}ER|BOX7T zCs`HUk5H{dO$@HZnLtX-vclcn@wfKSO)ykc!(mQGsk@{!vdvK7TJd}>u6eoc3i0ih z@!Sj1XqzsL17FwA34UrEsef)`3|5+MdAQ|5bQ{JrQ4`$_^9849fY#gu7mzj^bkU31S~f1>Ik72XjIZE?h7;<(%QC(Z2tpibOJ8DQb4WE!5^ilz1#s&q_>L^emt>6^LI z|AreP9t-7bg-=D5C)+@W3vw2V)U{bpSGHOLTdRv(I>1tjr28S-(9qG|XSW&CM8q>IrLK3w&sFO|%$=YY-C_G-zT>FEGIMs1Yx_`-!Gx6M)7Ihws*Lg+uFCYhln@ zjd^jbW6HZO*!-*7Y`~ZLS0%L!=M!$>NvC#`!32{$B}XZIu4JnSeg>{I{j#JS*cDb< z54v@f-F9%FlgoCX|B?f568*ROMUr*l@0~NoO>WL&a-GYhMZaKZ&zx#DA&ax4G``37 z9?ti6JZqNfUuv%*A^q5|H;XkcXpLO!1VFzsWQ?)jT_j>9J*5^66i3S1a@6o?65u#L zL07cg3*DFLHshT#IZTgEru+fyN$T+BPc!39+=ZYkOxvTyB`lL{e~zMAO)c&sqHd)l zIVNs^kaj5P7cvsRH4&-KLM8?Zi76Ou&cb3Ek<=qV4;lPoiNwW<-oQj*A`vcgPOMSOO zl06SQ!y?BOS6&c4{4k`~SNqOa4I7bnp?%z>2j>6WnhMU8q6fp67~<$`t?aj5w0i6d z(=C6kRb79pQuA_4+XXpaWdDvf&&lzHQtPBjHCmt2Hgx@slva~X;}D5a!>gP+bo;$& z2sZQ?@puX|Mx*aikyqgTo36iu+vslG@l(?3hpcq<=?0CZ!S;Ai6RgYhRY_`HO>xWt zkftK(HdMt%#I_9|*%x|yEvkbENwYb+x{P=noeCgu#CfDP-MA9=xcShUj$buUou2*iS5E3-PiRO`6K++o@14awPS2w%!R2s# z7zzt0kZ6wRhk1Oh(%Sc_H*a64ykYMrjQl?SQ!Dus%XQm5^@}qoEjx^>cc$j%y+z^u zE2B)aT7L^P|G%>`8r?(;66-@Y@d zYC@Ke;SuWf&oozAFD1kCvGl>SI|e&P{z1ALA&{`ARpf-(zVQvQ>7LA#K^YgSKYhy& zKR_D<6zEjvznD19eMGX~b);y%Q8wQ0DqiB!+>~=wem@L_oZ;3{I-(PmOSsTzwPhSB zoKYHLVAWErys->==k9OIxbUQYstoCm$-0Gq_D}c(nFQ}V|4-}+w*S?D7j12|^2FQ$JIeRdueCT>m^7IqRYHqNga2`4Wn z2^TvT6C3B(HKHV6$qfG0Vi7fS{Yp{r)iepSrkX6=KVKv?)~>Ej06u1Bi|?jPW;P}c zOfGKB024b4X3H;Xe`a)4t%kINo;;_Pl0CQ9cU?PP4R#$5Ge%1mX^HQ$o-&RS+^kko zlJ**2TAHqIDxOkYro5bX9@aW;+KM(BY&=xre?HXIT4uEU0vMFTvbe5{>f6n%JR?Wf22xa z{SOHh{%`3E*jd>Ar%lW$z3rbAZHRtXJq0=7r6~;h%_h7jH5IzIPVxLuOjl{i?{1nY0B6?chWN~YgeH~@~d^q6Z{qVeh zxCw12^l=>Y)8l7Tqsq!HG4?l%mk-b(d;jOUA|oOH&K*<6huXIv&#tTy0TH9J9;_te zu8FAd*84hVBowKV^$eLqUXR*ccAv5Ie)(I-X`Nk$TkjTLpC6mbXSpqqX~h1W_GgEi zKN*VBmJ4=}cf%JZ&aToPWtK5dj|OIl)0X`War#KS(35@M*KdhVzg(2@PKQOUiq@kV z*Y1n61|jDG1|LM&WMam@_r4j>I_~zt>Hhg}S|@rlK|Dj9w^#md^w`-l$Q%KsC8pJs zVi@nx!mxpPYT2M-18p)pU3c1DHzLfVGFqhI<2R+(@#dq~%R<9C-_z<*0SzdEj@9n zV3dIbd8SkE@Ulk6q*}3S2~}~$>T$)tDDpH>^5r5$<(kM1xFy6S*dokPPs3y`Z@2_F zgWOkt4bbW8%^RViq&S)u=QxIMmJ5Z;$=! zm2y-a<{*0R;Y7VpF(LXIz#P3-d)nK-TP2HWslo&y>vKa{yE9l8Kl6upiLMEHU%_>n zjI-OEScW+sEJn}kbg2n4CCTa{qOpTU#oO;Jq!a2&j)c)TCDpLE8ZQiH#fDyL&8T)x zHcQ0wIvwp4jj%NxU$y~z^MxEKGIJ#}{*~6^4>18P4E{ZAW^_|P>{QbERk!2ABRX-T zt!ieJS(-SOV;Dv{=yj}_N%K16I!~|&BwUhR`>8D10PKbhA|07SN<$8|LEN#6jz=PC z;noti_4+Swq!dD+zVssA5@gB-L8ndX%WP0R=|RVoBcTx0H;uqx6=h4VtN}9c6H6*E zg+$ZYtTC*{8%(^2K7L+H;Wdre;QJ(ZqjHm(AC|ZrRSC&wZ)Uj%u9?Nc_M#kc+>EBt z?rdaJNLGpG1@_UdBMp=Oqz0sfLI*8`L)Da5(T|=m49&yo$8M>H?C6Z9{4SX$LXif_elC7bRK8l;zC3~A3 zuT=ybNreJ^#U@|&aeiUQsoTXeb z^c`-%uEuY$qh8SEYJGHG7Qd9onhC~ZU1SEIC+?Zr2ksC3t+4=T+Ru4$w`%OAq_E~J=5{!ujLrzg-OsC zS*e5^gdI8heY$%bCtX|`nqiYe!K=NJNbmCPNsG(wyXwcuCi5zLg!FJHR1a}11oplY zX`%kILc}oiO-!if3j)TPgGi7AsN}HJlrr*6rZQUz8S>ndl$lYSY@dKTsn_$ar&;{@ zmp9}{*LrMDa=ZHkXaeRIDg-)?b5|0tdK4{NVMEk2GFgo8`g&ICJoY%zg!uL(+|{8xB)fzoCUoA1YMyf0%Z} z1Av)BLY%s?j3FzW(Oo($ll2o=Rq6b{PEs8(jkGeB&4d=sgg;TU&j6**4v3{x3_qil zNJ$k4!>c5JGAm|A@=vdzm9L;3`n{`hZ|7XxHJyyG3my2Dq!7ZbMF-vbs;Yz=5HdyA zw6RN5oD+rW_C*B>E|xI5dDCPE!@ag@A#>Be!`J!h6e4TFE6FJ%fnaR5&t z&(?*4H!yKaaVFz{BB#GMwO;v>@NR4~`aX2NJK5BtQ7#gAE5C@r#MoI z^$GmdPJrt^!FuQ3+2=9kM7|+nw4fEKMyFI7(f9P4L^SsZCe;qRSfyAfRTE-5XKtAe zk!Gt5{l&e~N!KE_JLJ>?If^y(vbeD8+%up8T6z92iJk0OrORyAJv$8{NFn!`9#C9LBjv`?ZEiIU?!M zx3D&AQhzY0Y&Spa;sd>!XoO4dXE<<&>y~DsA4TyMl`BPO{;nJB8VXX#ZpTeK#;1EM z#QgnVIj^F#Bty**IiWmO-@W}R8}%PnkcE; zH?D_EHmVwT0V;HNbtLFp^~Lognmo24_!noLxkHnLAUn#V)Z}BoZ{6#h9~q9aET0|w zuCK76M3l!WNoO@t`r9RGR?Cf%QSK9K+k)qVxzm_pi`3eHvW-jE@e2wBZ-#s(V%L=j zza^m2fVog)Zb`wO2vMr^nwe9{%}Re7MhSh6?IDOKTb9S%kDa?aeG) zFS5%5#^nxF*S0|8*>=Ex+`$H*6<1s;vaxUz2=)hBcz7t3XKr7tA|X7mRBVi_Q-ejL zq20GxGyP>oOscF{Lri){(5dah>*yox3DqaM0lF^pxB45V_LV2_m_qj?IppPNhz)Un z|6OBGAfL_%C_P@X{Ci>d#r+O{#8NQC^}Dw3$_e<0c$=%fAxfSp7S9}*syrJc89We@ z*I10KzS`4@y!&tDS-3x$Ti6~Ftz)yL@zT{?Y&ThGMm+Y8 zfFII+Dom44yIw>U#UICkzmnYZ?pt4hjd9%IOP%*M&`+slx2Wxa6eXzW5cPIIGc&c} z5L6X@`Zm)uyjpq~EVoAY&e5`7M$=iCoo#w2zk?>91oqtecySoHa>6&!6%!uvvZ19CO)V1Vo+^FP}_+o=; zTKz#5?hGh03(i-#+oZLm*!bjgzB121(-`sgN0L;ww}zluB7V%^%N`A}WN~lx$r+W1 zT+v0*@b`cLmM}P0ZoPDyW(aq?f`my28LFq;q1f{Iv~K~fwyYaa4UfmPlJ~ zYW%;0WlQh{WurKe;C^JWUhQPhOuXW~-k^zU4TIzJkD_Dhyf)TO#*43GF1S>u%2Dy< z)Dnu2YJL9LC}TXXlx6|XbW*)h6exjByu!*-f9`Tyw__wSWo+{>h%f;Z2lw=N@LQ=YOSo$V>}2D&Rx_ zLspguR{=({ub3d3f~n#Kg4GLZ49c>vj28gD14@C3fvKShr3s;_p^2M~ay9t6t1i5; ztu6xE;MHlO8(4+NEwNORr{(5&xirVsnFQSR$jZDx=l*jgl%jl#)Oj1Y;lD@~!&BOIVjs7V4sXP5Yp>s&wF2Ob4^Y=kFu3H+>hE z4Kqm<2~ADPAF2uG+7K!{_vPc}!k5QE6}GhqQ!yu&5SYlIF3~>a^OlS)p0CZ?A6ot3 zR-j3!lkN!X8mJ<@Srl@e;vg(^@o*?mPV!;fAeW$nAUL4WXe$&P_d3&{y-v}v8mNd; zk740CaG%1*Sha88L4#T-!P>@LDfV^c<3*DL(?nF7aJAJiMNteq^)zfm^B@Ds?ay+E zZk#Ld!C~l}=$sq`0^AFVMF+sia<(KpV*%vrd^w#%4dQX;BU<-rj z0p5pXOkO67CW;{nK{NwN0-M*0Q#HK~iu1$FGYs3AnJh~tU=@020kK^`q#WOsc5R!_ zoYFXv9J$hogjdu(kdFPSfMb<;Rg@#Z8Y-0hRnn=#So3;uqfQy3uF@DQ(DE924)J>n z1)88%2k6jxOV{lqDiIHUI)kwVh~nLv6B>xQ>abLs6Op?>@btuXY8KAzV)|WZST0U8 z?WG<<5x5TMIT(+PdA&LWydnH=WNlF0mNlcnjE8HsDu$% zrHho#iQNaHCKkBlpr}(1=1G#wz}Ln-Lqv;C5P(3d zr_(LW94}?#yvcXIAV38^W!V=4aTwBKC}}P{O8W8+u)tWN)N^-3It_UTxEBWS46qp; z2ke7>^GwnJ5e35rXM(;)u(b`7EJWuo8>D5y_BmxP{W3p zh)K$)>25p{pM8!!)k_^558CkaDcX~T-dHR9%a9(g7JG zL$Yfxr6m5j@hivo~8;9>;VR-nC^-bzBiL1^ZcvU^PJ;EjMq1t^G!D4>_0sx zQxEt|`ya?oO!#GY{cXw&Ye6SaZWR&z)aG`5q}dRUh;bGgnhkzp zosEed%)7x&09*N-b2k~^Z=^^LfhTRA2Z^H9-g@;i>WSGw4w>q8HcI`7^t6K<(snlm z6;1`>Xp>Rqt4v|QG%P~) zC`v7*Ud6w{RbCbnYKrq|-_=1|k@%<3SnI7XPV~ep5YYbzb>Mcd#k$$){*6fY0 zDeFkZK%9;=wwN0aN##@p?6?f(=dGW7>=X9V8$SPnFmHj9QJ7~!iusmD2r>rJVI+EI z!)oO2b*B6a1uvWnW1kGJH_8~jm#J_}Uu0BiFp1{^_V_-DW}LW%?3Bfmv@SU6 z+|j+)5OWMN2p%FM{f5Q(*RQ;_jZ~(og(wm1KmZ3#5YjQlXb^zUc5%;9^@+F{`MZ`W zBS|=cxPsS{pY?(EkW(y=rf!1~M{s=DTXn>X5InT?KAR-HxlV!Xj*(_9mQ-EIW%d-cb zZ+pFn*Y}{AV?p3SV8z(uT7xPGM7goN!D$0R+UfSLP*2h+!SY^CoHr+8BE1P^>CNG{hF!Ke*^`mk57W+WHZI{i)lG zqmmNV)EomFLiZsF0^pKlinu2b2qHmZuFR=NWYVJNjzkL7jY?5ln?dyPioy$Ar;mT! zFFizQf2arXwTXyfneSK^{Vk(HYUK!!25~Fxrk@vXuMzek$7Q3~fxs|s|BIOXSDA71 z^W{3l5uKMHDIka*r)YMJfW}%NiiT3_ux?}o{#dBs3pK&nkeSlM9I7*M@w}KmLZV=y z(z~3|i04qFqahg7I0nX8y~Ec~nOtRHF{s)2)4L43oD(!@f`SiUPf?^l4W-Lohr-Od zR7A6Ov@4UO-&>~_utt0!Xq}0iVi^{Ir3R8{Dj+F?UTK|ibi|f89aE=7`pv3RC2B;R z5V1()&oHMT^&oQ~sC0wlqtH>aNOgJh4TED13X{&C_!8mFbbBkjnE^i_e9ZCmk0E|* zo1fch0?8u0sryzYLjwq0BGGuL>1?%#2g)YFr~8P9w#P38E6RvVYAA?Rm!To$Rd!*)MzG5-O62G9y?nlj>CIWiFO9yymNiD4s!0{~HCvcMCWE?3g6Awx( z$%bc?H_1EqQsSrxBBY#f11$SOQ3&y1PpUOUp*R&;&#W=B^-hIQBgQFtsV@t@3-4qo8otEv%%d+0+nu zM68QWU78%EAQg~=FM3gv8yk_!h6D^9Q{O|@Ni|hfQa+R9CyybZtG~=&$^&&JRh2>pd>tJakD0eyJ|AtE4WHNH;Z5;))O$~RRdv!6 zP~BXiMaV=ZcG!g>gsb-+>(&d(oJ1g8Tjuk(?Bo;bhi}PqX9Q_c&VY+{1N8v!_V(yy zn1qlspX_R4)maMWJSW`6#3sWIoIq7iejY_*`OwL2Ah+d4=BAl)tpjuiawlKI@oD`h z4}1Chr7GhRGJ&tlR{j0Ds<9&U7FZ&rXDQj}iUAW_r@|e@=6M`*wevTd+)f%#C6Yu6 zUIHXYNCKbIWMRos{gnC>W?iVU{7ha9j4PGMGugwr1_l##0(y{%Bpd)FV=LH081J=9 zxGAk>N`kqRC|$Z(!Oh~fs;mwJmJ1`&sTU6uaZ7_AK2mt_o5`=$k1zLT-BjR|LrYTZ zflJ${re_Ydzf7Wpl2V9;t_yo2MP$Jf_8-Tn_0n|0X;O?*l0A{+@*>-|W4aaI(PUIX z8G+uC^?LhbLIy$i3GR>Zo=jKL#}N58uxZR3r-qYJMp5eRPP1Lf0#ZIsK|WGmCR)y~ z!o^DYRd_dzn->t6$A}OlU$*J2F{q+R(07vi_)v@jqb7q!otX>xRY7%rcVW0ht83|U zyiu+>s7Rb|LDs>+xj~CynE0kfmpTGiif8efG`qNY8bm1w|wXhhfSD4eis3CC@l5kV@%| zG~{{wf|h{^j5I=|E9iNkFGUaItu zjvP4KHhYDA&4H55jR%ls=!hpo*gO8r5DNltpb)KV<1~S?BJc45+#O}2JW#~SiMFVP*;Nrb?DeL`mi<=Eb#Mb_mx7N?z^8De zAL+R9p?ECiL8?-!p|Ch03q@yH1c@1`*I5c6GA>53I;g^KaZf#%%7}W26b552zaI}% zlu6Q`z%-x4_CuWGG>K4$tmMA2iS*7L6p&w~0sGa1AuHlEoWL+}aCE)ylQg;GpJQ2I z&Dgnv?RUH_E29w4BcApgjb}fuP&xP$xcZTBbTvFtE_P%>iu9*DemPEG)ZYis{4BjTxz<%a6)+6sauDY3x`5# ztVxLI#Ig_td&Rw*lXO&ri0Zg+9SyG70CixhbHDBypn)n%3)94>)@J5iLk-Jx=#QEE>o*^z2^f{Pb=uBu7e=zk`zF{%p9fkskRXJj^ zHC9D!g}y^hpufyLc&vvL6SAHh#QRx6{pDTgdCc$=RC;!OYO<;X|FmxNa5@wBt43C~ zcIoZu`;bL^P<-}V9~`HbZdqgX8NV=M=0iujNsh?ORzUg$2cmD9|EXdCL>1J+yo8X! z1UYCpw|&cf(R@c70?aR^53*=dOmz4bMtH+R8bx+e7`LRM?!ER*w}Ok+^{+1B}5N@%mpCQ@jYF^<#-VolNenjm^92L zEOHq*iB@PYpxzD3V2s~x9s5JN8=+fFv0DsstKg`+B#1~o5Mufw*NJZ4KKqvhRnZVd z$uL#^%t=Uc*^@cgpS{Edc19$v7m#Vx^LxI8jQfd<4|tDg{Wg=GbI6Y@WXE=Vtl$pl z`kXE^Rg@^ZlXWwFdALvxv^La8YL+xK_FChX-ZF{4WZ+8w-wWzl*=K z*+?L^d`_RueSe74Y5snHD=6;2#pkwgV?;b`0b&l)S>J!2eGI-tbZgMm^VzA`RZ@+x zQHOk5PDkLMDd4@?Mtn?s%5Js1b6QC~Wn`as2=Qwo+TW8l2x-gRMCN+j|7qsUX1xFO z`(qs&P{7ys;Gk{b*zsD|r)>KHAXNGAtYE-JZawxBe?}5-S~%*oYggm38oOh1d+qah z3Z0v<8!IFAVYw7_iId;gPX!}%zg5}S$nY5=sE&ZyQgx;+0&z1og@rv_`u^F|noT~> zTc1`q?`1vA-dTv#6w(M%PipE{P=KsfJ8zs+Y~! zK!e8F!q?xvEA#A97UiP}jdeJUq#LFf}nHhrtt4#yp9Ve$OMKiri80&WCy5WbL zMR$dl-Puk#e5yq~{=<>?O0KT1J0z7Dp@Y-nM|o8NhqB9aMQ(Nzs}VgXXW zWLu`42}*soh5lB)bjWf+ZrB%*v&uT?XZ<`7%1ft*w*>P?sN;*i@?xkOKB7)(4qp;T zR@3&dwwGHJ6`e;?_al*;R67W`N*M95`!H1ckp`(v!Muf&&tlF7~70}Fc zyi<4H#xd(U#iI1b!=d5<(VcmOc`T+blR=#XCUsplE<5*Q4{-ejJ{u?6N{mXuYE=VC zHLiW>PCz-IrE+@VA*HSm1aMzcL$P5~PcY2P!5St|e-f;kqNx||C6Sw=C$TGVg<&^v zIK+s3NTqiz&4xnqN1x($*6k1OWENU-WVSP%oD6u7wI@NdraEWUYW?A^6njh%3{G9d z=j-~0+%rdyl!M4wWG1go&|9xfYY?oZ{g^T9`7{~(0nZl;+*tOv)sbrlHy(NpUxb3x zKL1+C{&tIz`ux`X+Ug*RKNG?l2~x{*LeQ9RdKJkDt>}2(QxtgB?+4$EV=Ut<8*J=sY#STfwrxAN@4tR#=50-P)u~gbs?t+2-k7N8 z17xBjb=Tr^*1NY?M%)gpl%Toq#@0Bzd;Ep?tQsO_XxrReSo9x5LD07cyh0uaPhuHh;58K7gvN4ER@-n|YcF=AK{0J~J}=z^ z!Iog~?_Qpo^eH-NoMUTr)>u<96&xJ&j-WjPFJ2_!M&AGM_S>9FIXT-;ULGjNFH`qs zWP{|zsXLRg2IPMUVD<*l1==Fv%7j4trT&XG zHJx~rBNscMC2J?0YMuzS15(-vi9+M{{#K;^*A>khb{c)p%XWE+&mf)IsHLYK-G#PGWT)y zcKP1hV|m^P|Lh_?>hHBOCAL4ezE|k@9bC(Q;d2$*g%!BP6xyW~Iz%A1i;F{*MMxI@ z${8y1YMU)E%`0}oxcGf5?bY7bqQ2wjj5J|Q(h+fSUISK#cB+rdDba@Ioj zG6~dRL*hznzib!rDhl4Nd5%KN(6s#sZ+YSTNWFTiUY?ken<7AJ8U*D($Upz+Qus*m zK+?gY6={WQL7Z`2I=btkdUa^?dg$UnB32APcQldb-gB7G9vS+<^?KRyjJuNnBes-X zGh=xqgoz&o76E2O)Y;IzJ$6VUa}By>%nQlpfjJ@cSRB5s@ombYBm$4jEOTOaOuC}e zpMr78$zXJx{ca7jDKX~s(g zQ14D|ap?|a<1d{n4-;ChKX-1u{sMP@4}C#s7cAI++5&%ix%BsBM3_jAXb*KJenRz7 zT6rYwIQrScnRnNmcjs&2-@#G4ccsnIJW<*>)AD6!xb1iDFBe&B6P_Uy=sGe z-vORzjqV0XQ+8@*Od)d7et!9*r@SZgH%=x5#hC_8Dr~jG^al6UWcjS;l2Ut@^HbG& z>I5b<9HY-pFl@RN+s@UGwxgxoqmp%BXg6_97IuijpwNm8@jVje2Ke81|N;Ds~y%<5H z<>kq>t}1G}@5Eyus>;g8?)k^-QBY81WMq_b1u3j+gNZ+y+@L8cI4dfh%gY!WK}%ZO z1o5$_$-yqVfkMI;#KDs6X@Z|g89&oAyyD~`jFSEv^G_OKQWj38Nrd89M1)eTth|)5J59J7{3SYj>;z;4 z(U%5oGERH`j?%rO7Ro?|A6I_NcX++&Qa5NsQeNS9fh-wUrFV$Q9I2DpT87k-kE!M& zLDvZhI19+RXu;Sstet@UJp-;tJvaUh<}ewbFjVh?DY7imr+4p@ZVl)bm^}Ae!BOd= zP!&H>xRSc*M23y224kD07vv4d4vs+}0!R|Fz_-UtJE-rLVLpnk3vVFo@Zco>L#=X2 znLvs@oU=`W`zT1wgid%E2KzJlXv!#9wDe51@=S%CphYW9Y^S1z`vbljE~UT=t(orpKVbU82K^-Yg6jC2Isym44#1Q7TNo&GL$O+RQIv-BU2WrQZuTW`kF$wPY@YO@T$lcCePywppG-cxHf^K3#a znsgeglxtK@ug}#TXa4FRJK#_@!1dmMiTK4tlN~k{eed4)lS-Wtb(?i1**ta#M3J6i z91m7XTXLnUJ-L463T^&5Q5T3i^8C;ve0iF_M&?atqx_yAx*xG*URQHa;z zQu68WF?y*EY^_4unmqCJc#oPH5l6>*z87oztQ#=lE4(N2Bt`ecFP#?#UPEeStetyT zVfzNGO?(BQ=Vj%C5&A!Ps%|Y|T02^% zAWBz7AYo?%xNEx}f-u04H^-m%JDDi63Mmarzyij3$U@<|gAm-3n8>)f9%(slNi%(u+BGMK@)yQCrw6q`L6LOipyz5VGgxkV{bK*m@K}y#pyXiG%69)@5mVP44yDB|w zf|}0s+_R?d-NESL#A~@LF&{2;%8z13siH=@sN@2j=)lx=o?G(gyV^$Itw(udH|5}OL1{Y^bC0r(plwKT;uY`S^2Q*@?f-fu z9|(gRUd5x?{XOTc$!4(Ij(v(fizA&E6vK!GKjXVy_|dH^nHz@)j^0(Z=eCAOQszyG z&)9x3rH#S3nt%VXISHO3zv>a}re6?*D#oIsBn=Yi@J?YyTu-0W3O23hpL6Vvl)HUw z=o<&W86#OOF<~{JUM@ut5*!_nR~Dlg)YQgGZp6S?2mx0@{Ddt6QW8SO7APFTMsTGE zW5{B8`B$Y7Z1@BH;+l=mXa@hgPKt|&U7{ZM6<$d-r#_sm4ZqI)+)a2DCgS0N?#=~Z z6CEitu_UqX7R0Aj(Zf1PKg%9(bU>KXr_N@ianbsVh(>N&yP!l1HgBj!Bg+9^o3HDc%8s+G@qjJ!>SR-jv0S zivcb%(MLO_DRmgCyh@X)&0^e*YHxqYgLUpy)_Gyzf`NlZp8z+3fJ_RvX<@#@1DcRS zgIcU^3dy%m8dl;x6m$}fog(hTZC-nOg3T8~%_=--3GT$L&CYjQAK1o)l9U9ah>LPI zIzmy|E}mkcz*cAYXYIZub+qxswvakl)$anyRh5KTu%P!Nx}=c+1ihk4lVi| zFL-$D>MVWiD&*0%GrxZjpS|RcAjtdbG(t$1ibQ;?s9`iSH$6gI0uyxtG6-eF>Eir; z^}S}hzu*%6Sx%^>VlsU;jX6o(;&1*q813u0l@c?O!QR*_R~n?Xfs+N28K?Kr>=E5* ze!g(c(kk3EbeQQ$w_Ir(MoD1H?ohT2PC=*@vK}mTH(Qxj5T_yh?M7o%q}`W941-ED z7g0UZzJDb>mEBvYOsY;v#kFo7yA1lBDcKOpNurLj;Z`l z;{L!e>7P8~acw@%(AC}}y^sj$VI+Ejd)w%%Ktwxv?CRsR?RMpg7sjGb?^}Xwt8R8> z-fZ$NZcbj{e3@W(dfm^1Oo9EhMZtvkAUa&A=Aq{2}2ZL=WjEnuI27CP8Q$VUZ zz3)}g)f=r;q6+Q~M#WUrrgH>F-DD|M{mK^ zg2Ka434p6Teb@oIna(W)CW?bqpnpI|cXyytP$AA zN_W#}jzQ;Sz1p6vtBpvzt)U{6IhV=YTFcyq4|utnWC^fL<^1QUAk9ocg}0BUYGS&N zhL*%&Q3AB`5ReQ+z;MXe?FeKrgtVi$>R2C ze*voi>BU6yuDhQfefG_6IzRYa2GWm3=)ht!x)Uaq1Zv_uL@lPJtY;Nk?S1${X{0+V zBBvw2I%_l&%qu_@ukS%lPGH=Y3bH-DrMuv0PxH-CBm7j1P z^>SIt@9mk5a{tZZUIt4X^(&|0i4(iUehekKEaBuycHOyu)gBY7zfF)Y7Xx`k=wasl z8G9-yc&Si7e$MrkV4TS9^L@0V;u*er(etjfsH3`5hLj*?2Qg`Mz*$dJRMgJSPE{54 zlIGaNqnSVNYWenYUFS0Lcc=(Wl@5Yk%c=+3eR$! zD5IRagT<2;*bT)DlOP{MSHt0R`hDz>G=RM^!kuwCnnb6YW=`YIyVnKuCWG!PeYx;3 zsDTj5pOT8*(^5moqIliEJ=zw|mZG8jhX8DzPfW;92aVQO#%*}zEY~FoYQfAr;``8# zC#Didk@hpc$&nq;1}OfQ%y^)FPNo)6mjlkf-oiia+bt%cLXRoe+%i^A-)8@bt;DS` zC27I~gGqs0U@F}gTh=c`O6V) zLJ6_yfLpXwt;k zgc}a>ai|;*DI(%HYWcbGgF%@dV8(+=iG469A5d^{lM)@Gl^REg(m;i}j4bIcLH4&i zp~G`=m+$v(JdWQz1h;#ZXF=}+biMelTG++dai0h9qHyvz)6q!FH%L~5o6}!n=tdpi z@i%q6P9Hieu#UGIi|=x}iZJQz8@=4KG#XWW>vCdL*_JLDmMeYFMbL7K?;YuHs0TTW z538^Jt?tEs5du}DAt*8$It5|=D1V%uj=C&SoXx0KW3m#BJi3*}h;tIu;DIu@a8Sk2 zk&%I$2(93~xtJv&fYlMj9@-Hdbxuf6kCbfqbA%4*MVMb+s%BacqJ)~PjQ2@8kFOBT zloUfLQo;CeGkU(DwoqutX-1`{KEhm(&Oyr=W|kx_Nl96fE>pl9`GgP~866Wp&5nyM z;i5H>mP=TH@35WrL}P1r7m#@3qzEb67r%pFamdnP>(#bvZV`UIb~t3_-R1@S9E;2GQ5jUW?W0O$XAC8ZYjwYKgTeR8i@MJn9$>g-33t)r+Q%R5HWr`wwO`SM{ z5ca`^eyACd-ECX@T9v8SYFVIO7iW;s#~kHO@)E}-4N4bra(E?MPc`KX!1zgGxnoaz zqcYXI&QtP{VtR%_djeNKn}5@$yD)&qGo1ZCbv+VOc-_y6k|hTpFBdN-AE~4mH7y;* zW=dc3udVbXv^4GHQ%`h^nH3-I zBbWBb>;434QVWr^lqZIQ4urhqg z+CDwf5af+%0V|2i(e>i1uAaM{O|jH1{#aM@o!+)%5D7`9a!$+XDCI+xyn!q&I~zHu zoA<{ru0oAx9(9(tVRKC{i z!~x#nU4`E7_E?wt%vk(YV{r_v4mJ!mT=daXVOgKQ5U%lfnQsKVcL;Ol5e>b~`zqOf z@%}=4vX`@#&)ah2$tq!*kydFjM^~al7|g@CrWqbrdd)V`ck1hLxLliN1=jGx1+2CF z<2s`ie} z;eOlY1z2r%iT{D(>890gw((Pw11M;XJnaWyY%)&QJ5selhe#yQSy;nb>#tXAVi6t& zwU+D5@10~f&>*p?u$3R?L%XWFjaTZG;(t`lD-;kjXkZfQVfm%do@>iRRb3?aEiUOa zKJ(q$e89tF-W@|+N0Q-&`~a!5(C+g6#tf&WA8$6^%;!ljcw`UmKWdPWyokT*d%GCS z(TVUZq|{MK5>RT845X1D!&=RIXX+A5m2VcGZ}oUwf3#aG|0OoD44hJ$zFb#}h@6Q| z>h_e#Mms!qAjuCkltLO!=HFACH_;mQgh?!|{MahNKCao^DDchgJFNIqv)(HH*q;4{ zq}^%#OF?2g2i9A;O{HQ;-%sP3&)5?!sCex#k`1%v;$psR*+{J%j@am}V2;BdCasM* zTdd3ZDm=F6e8G09?)*w@m@NjEm9|+wWJWIAUH@wve_~bHeuwnIfoBk_Zh0mk8Fvx*k@^ z72em?uR4|v=x*+#cL)3J^Yvh{ZOMPDYNaiFO*{YO&k&@tHOowGuJ&&(Rj6wb;Ru5C zhFP*YKwg=~Bs_L!p4h(S+CG(zZ-r9$c1Di(<5kfVRnVr7;E+ZI4$m~dsK(x|asux3 z3*hA?eND`?R88zeRey?_*ocZs>IKtq&c=LH$>2nuo{okegf6rKrg`8mdPBPNY=r+B z=#4JF;lBXyChv|K6HnT?DW_Q+9g)0>rN&9~p(?_5KP?~_q26;WW-vK}x^Sf*RWv0VUn zYAso*B$uAzhNJM3xOn>CEhFT*yGUN{h9H;Y+3(x_3?_I70ducgNVMo}-o;qOw2O#G zE5HMbrIzU65$Mvl~RGgiyrczB$4TGe`OKY#v|o&jsiwV2FM zLFaHilJ_G%xA5pwsT7L)qOBKbx&mM1i5(4Tpg*@}pSRyXU|SzQ;AYIkSYQ*@{FZ5+ z&9?7En+>9-(fRuwrKhMV;jUCs?UMMH?N|S<8?Spwxx@IR1?oei)7kazx4}l8B<+x6 zf$w-!#`s>4x|0D$y(C+(m1Mpv|1@i9?zKOBk>n=B@%LZnn}+%81l8t;(tP=AvZ7%r zEIj9c!_^o01c(uuyyKqy)S!X~9%b4^Tb;jVNnjGVk9hnNOWI7r$>a|vXo(6E(Thxa zjX=}8%a$ua${@32#FcG0f%e#Ptup;9u)}qa>v#>ti^n8xg9C~ZIYMT7;$ck+x+VJ` zb&BVAi+I*cJm?6}$hqNvXf+!&x-7Q;RI7HH{Sn<(E7fa~2#cz+UA$6hlkFh#8ycj{ zAPjg0l8h2jc3OcY*|??viiTcS`Ob#6p(1>Fy_t3r#yMGI%D|zAdL_gtH8o^@Wx8CC<6@QhwXua=<@j%- z)42XYTh8*ub~@7kc4n=mu`h3!UV)V;UpU!tG^!sQI#qiO ztXk2bm_*jE4q(l?$L`Zv$g+@jZYM91o9_d`R>5o$M==o2n8)4(Yg9Ir4oy3dc63 z)}mOsg|cysruX6g9G8=ggBK=HgU1hcdC#A*7;#63p3R0hgG28m4QLQ>dwKoKt(OMN z(PDzuOAFEu(>O*#?fZ6sQ{R3#mHi&g)J?75{t$&hH$vE_HCL(4rcZLnef4y?-r}(7 z^Kdd-_M?Q+p!0<1^?XM`eK8^;VmO{iDB$a3t;rUdkY8F+@re6swZZcFYLm}tN7&2j z1z0(%RBh1Z185w8#r|Kf$K)L;1*JPXJHXOyfRGsbLkA?9)zsBJW5 zTlN0u(MlWoULOg4pu^En_|$~8EiW(G62sSw{JX;cV0-*IT@1HW-rvkkH4ghHg_h2 zu(mtSi{aToZl^tT6pm0Y&t)SBhOpJ!G~cUAH`8DBc^BTPDm~Kpa#^)>MDDk4yMrLSFbqY`*eS zV}jg1B$c9)wWz`Iqx?e2gYBg!;}eyZhB+Pmg+xFa{qp(#OcO<`+id6M#Vvz1c?7-i z`NwSVS?xbJ+nf^1@8@n&7X)XwvqErl&NglpVPi~)js%xB_TePB=z8H|;@JeuI*pbxy~v&Y+;692Se!tK3dFf^zQytUEMO;WuC3)T_X! zg&Y_!GPM+PsD3mW6jNM<`2$@Se(!H`J;Y4*h7LaW<#M#>l6%dTi(CF&#IMuITi+oD z0cR~C;b#%E{$u{>fB|`7PX<$MQuX-9w0mT_X4|G1_2lOA#B!BHL~#l9-3>XbrU{wH z*b#v($)=t~`=VP_UU?q4!Ek;iZUQ)kDJ_>RD>AoRerQ7T#460BkfvLZMO?R1jh2AZ zyRM&5@~JoO65-HcN(#|Q>J%iSs((+Ao6f$p4%Ue@?ANG>iNG0*xtB{t;uDK9G;5ZN zrgvcRbL_NAwl5VUJwTF)8VRHXuSUj+!QqOhlKyo~wy2(s2Oj|^V-f+vKKZTk# zJsJTRHZLGozceBM9b3KH*dIaT3Uk6*QG2@+c{a(nbiRV8GQhX9c3+Cxl#%+Lf7uRh z`GZG(>nivQl+CvB!k|Fo-VL;xKelwe&9N!&6Mo6wu&uv$k;*|qH=xz(66sIoyPExK zi&GOPW}q65e@0`YYNo%~u>-=E3#s8EKma#wew*U5Ss4)TF&5Oo`reFi4R`daL)oL+&#->KQ@0LMa&^^xCpAvFjczeXH9 z^Q2jRD_QIbf4Ir~R6peHl6>uvm#2~l=-Wf3N9rJlb?7N6O$UZz%zl?-G!seGr{Oha z?2}s{*L1MTn2JFXX94q>&B3-x7fpjLl@wTNti=#;KO_T_td&jY_etLi;Ik}U^+C=8 z6Mcz(dV+LsATGe>Ogh0gGO|LS$1`5ai3Bn!D=X@L<^d?JJYmqN z0>CI+)@d1Zda1NJ8BgQgO!!jZpy{`}k?=PCGa`;20ls%Vp3-l&)4r=P8H_>!H$5Et z1012EhF%~tE=&`u> zqKj5T+Lx+|ioMBy3feaZ>f@H8yU-Ah5`1gypLr59#bLutJ8e(!-_pMx=C^2W&o#waYa`#QaBB{(!gW_R{JhHXNIQFTai$h=l^*o9ySA3GI*@@L`RL%xVw88`<9S9@NqIrHusDG)nBSo=y9=ccqlOsVcZ}BCj^dy}HyoMxM?y$u@iCFl-NJ63Ma2&Z*;D#2!sZmGW-QUmqMRPfB;q$m0 z03n9uR2B{@YC(UdR6HSrPGbbWBk<508SP~8xB}=O45Y5Ej!vU8P0;Tx2GI2&;N0C$ z3vGA%Wv(<`c)Zt}j{|Xmgd!x!>FKHK(S&xJ3&r$3X0-X(_03Xof zij_67^TYf8NFkl|@NhhpeA$1k(fa?Fe+=|>`n)?FFHy`MW1bK~+23e$wVci&z{i(w z6a_nD)N5t7U8)4Y&)3~J6EA1S&)2&~>v_p|LV=$zH^8NxrX&4*1rSn`*Xhn*H_mpnA>fK_=?9 zX4N*$uqFolpYrYIaU)pQBkjq)oGz^HuVS6-w@W&8`-S>RAuUj;JZhsRkuD!W^>UAL z?TQ~;A4P=x-W8ds(SIDXN{otXda8E$j6E<5iy=Hx56or@)yh}v)ry7=ZJH4?I-YtE zr^-sPOYD~$KEaXRnuIw2-qr{*C?PlmSdC~e17pYhPtZ4FRLM*4Q#W}mK@5N8JUR$;wJ-R*Dx{qEs_VTs;&CyEtYL1#+?`cki z7FV5G`Ta9%U7vKGgtz9GQ$M(J6(L)5i#5*JvuHO@-VOZ2&fKjyM!150kzE&% zLBcCk{AK0|a?Qy@vXu(RIq5XRO-b6=mrNA-qnFrEosM9n1fdHyqq5@#c69&S8!yxe zVb)Yl5VNLs8dQhCOVwsM^FwORCHttXAJrZEE+;UHDyThTqmr6uuafRK=SBy5tI~J6 z*fzZi)l!K{LQ4573Tzf-l!rQbAcN1-0W4QlRh2vLe6@kvW zgVzEt8y`NBKt@Jr_J`{g#Y>cQoyp(`uE@;Vac+R3ids6WIS4T=tt=HYjaDsjn_l0bd_dKj&?6OxU&g0km9aGGL&QOG880C>n$oa? zAHS#pl!8OgSR{9ZNu6wpAJHHqtG6olBjP&n>{f$c@$BRfT&?XkBUa%!^K{kpe7nH@(3rkj4rI< z?dZmBWCfsoIC5Xv2!yA=D2|w^AL!&U>PRs49exhG1BIC&yVLaKSQmtpRq+Gkmh91o z85O@w$glJpVl+bX@fy}Ju5@|a?sRTD)K0sdxX$=4^grkhhx>?_{EAwc{SL{*ig)T*~;RoK1GFvOq1*)e4EkQm2f#DQWQ$kmNhpr{?F+dN7!ikyd=J>G_iF7Vx;x z+UoQMq-aJBtK>4ges2$!xqc~RQb^hT$AH$7&-;!X#LU7%F;`H43$q|Zt;XOJkg<(O z{P``cqBfdH(cj+>x&!>ffasWBy*zo-0n6Navp9B8_NUZgUMW6L8GhS%N)^y68^T`$ zB7LjdWbUDEGDXog;f^*f_5`U;fw(&ibyFP1zPGzE$2RM$5@>%2ui00bOQoJp zFk`+o5NR|oY8=T381yvY0YJoI6(4p%=yyAvJIqzO1>6A|*%RPMMhg?1pD$as3HiO0 z1CY%Sjz*KDh-@n~Yb>yjzCPc#f8HZXs8Glz6Fag3J_n6bp7<2%@oaJavn`Q4p>+dr zN7%7Lp`oFS`t8c-9Nu?k;l_Ra{eWUG8u;oz`Yzyjfa!0tnhow`XC1xRXiJ))1N1vz<(i3E-&?C}m)vB~*Z)`aPauym|mI3lWcV z;rKV;)xQA25fGa(=`>QewO6a8P^;_#o(N#RMv|zMrm}d1a@-Xu#Zdn7Oh6ah;=}T0 zhQwUDK#XgHO8hWBkA+hyV|Mk`iS$=0^&grp2Il}Nl@WfN9N`+%GG;t@_))6zn=DY* zM}m|FwQ^@65h0sN9Y~_Vpns?9HLq1PxS zM!6erC7I$lT#tO3kcy#5I^?FHHsMUy4=AxLoy<^C-xuh0?8B z%h9t-_!MicE`t(;LUE`sN3JdRQx=bxv~;1TXEwgs5K2qw;9#%|WCB0EdinF3=%p&< zrqxf&Yi*1ec1Mhzcgij~4SVfs3%Q@1w-q7650(?8Jy)~1w`H1mPw$64|zdrkwGOj5@CL@1%ihu?UCOAf=w8Ik`I96s- zmaJVvGM;e|*A5113$#PNvOiru?!9kpA;_eBI;G zI{uGgt+PeBh<8!vafDd*_AI-||3s@;#uABCfvj8C;PiJlfp^ih7dDW+}C*E+Lt|G~`npV}px zV`RtDua0EVswUnTm5f%iRROQz_KE`jrVtT-4+}Ule`+?Ic4^*X;xuOksC5mO&e^|J z2|Sk?eKHy@oqF-5Ukmw)MWzUvrd&sYw-QP%f6dlN@8>MG$A8poWWIGl8^%iu)3~Gw zu9H+~#5J*aOx#7uypI;|^1cdz9Fwb$8!h6yl7gk+*LoPK_M*Tx{}-`o)5Ej-xKxZq zsTsiB@X=MaZHRpF=(Z~Pb*0X%2fiyPY*bn|J9^XSOL|Y(qEg~*me2u3J^l!#Y#G@8 z_lVz|zV&l3k1w4BjFL9NX@cAqI&9DeXYS@`N?%eX_x!%?O0&ypH#n!^H=Snn-e5Fe zwqn8D769p(V}DZso!~H6wFuB90GJdL_Y8+Y+i2Vml{!uVBl`96`pDg7vsm7ySFPLP z;PZHLLahZ;>>sv;3X%MZ-o$;nAsuvG4g2 z!@qI5#k104Cpvv@HGl%2fp3`*@ett({%PqO`q?*PF}P7>!quHfeSeF6Lmhob`UhRM z=b^vdETW;{2I)Jo1UY7NO!hLK^H*00+U@&Gl~p7SEgKmfuS>xSEtn4NOr#QAFSNny39-Xwc9%;F%IXm_^8Y1zfbbn|dRG}YPbB2J#Eha}l6bO^Kx zJCNvAg{%h;!72(ca4Gr8)4i(djT+PAMD(NH>H1WI-3Vv%si_sY!2|Fv!G0msbHJ{U z3zC5ekM;@~KeWO^YGHMmk7Lepxf!klK?NXp%mt7+;B)Ds=73NEz~DK&?on3wsf_vs z)a6dQeFr;0asZuL+305H-{|P5QV##=V#Tr$-%7jtImiy+V*pT3t=oJ7KwEMdTow}u zSX8Gry~xN&Gq>Ma5dd6QMR&j662Ks4zwpcXcrC?W=ob5>z*&-w8PM?-SZC`e!MrBy zB2T#FuzS!v9)efWot8J`5&GBXKV2fyGhsC`X*)<31$-vk29zq(YYx`|dEVA))0CjM6yxCL0g!KZgY<}-KGgbhn zsG={{nM$!n0pw>Il~N9X$a4Xd0l@XkwWdO98{ml(FCqmw1wIE9*r6s71*I!1S|Grk z84~KzZ?Hh5fe>S_2fRYU^XuKAoJnlJ`;)!AJi@E7sAyj-9v2`vl~7qYU#=NN{9WU5 zy#*8&<_P-9_A$dG*RR^Oi>3l8u>$GhqN0T1QDFQ2XcCl|l(Ybd$k8Pxfv`nD;1f6( zh&AABbNwxLtnY$rUC`(?%ArCxz-=AC=HpMJA-_K<)cclF3%AX<_?Jgt`XLj)4i=cEZ(@&G!u zO1t`Mlzmicd56XP76KhW8he*6`^*5Y;k{j6V7n~ZEgVsD4j~qYUCn-`P52awqQWz+ zc_;OomYXVn#cLMs;pq66FVT&oyP0@MKX?Wa!L0H12pUdHOoRZ`uaPA5ABmjACLU-x zP*Vs`*u0lu)6sd~uS=>v{1FNvZ)m2;W&eLCfEevLJLzn>>f20Y;)iU;X z!a6W;o4>0S$34?4SM^_g7Ps~})*kE@T&Sb&BWM z4v*P%iLxI3qEih1hsi;xS1_y7b;blTgRvn&L1z%f~olq zo9!4Kxd2hU+eQcIC2Q2mPz@2sM@Lz(5%?q5EE*OowdWTXFdXnX5tfXn(b| zaP_d?Z0c%iYVyl*#yZwvc9=ElMu!PDQsIq0k;ov`eSg zEEr>8wTK*H;t6*v<7tpjvPT(07g&3=vL5J9?=YO$e02GWONDRg(QCY1oJOhfkMruH z-h1r3oP~cHpkIA*G9HMPNZtNO$(LnyRaEi7th$j!qCCt%xhk;E!VFb*z=?L~L#eQ# zv(z3>2_Z4#wJ&tTt<4v$o{i8crOXs-21hqf#R3(x;rXw~LPTkIFmNH|k5i$}ewUo@5ahAivmhNu}SuEHsJWgW%_LKewQymZd2bb)xe$%Tk{&r!o ztdP+dGjS?q!5-YHL3{xd%t(9*o@nrvyp+*cUEFzVF`Kc!-u~6@Wi=3`u2e&LL&LRP(9FljH#{_iM8Mk!Ts7d-kGaBIIlWHjD7p-`8!VN&mBTsOfVI`t z)xiBDgV_TxRKQL}L<9^nay%fx^6~NlA{|H&kE@N--QC^8!!Vw%0O0}q^=5T|j|137 z5T}b3mJfo@FtT5Ue>ExwovxOubhTE@*>TCp$ea=O0B)JfVFMt;B=VIbzTxjbzp8^^ zEzOLNcC$=Fre*eV$c|rzv=Sh3%KxRwTU2G^p-6y~B=vfJQKg=?AufTksPA{DQ4FOn zAce_R1g1%#RB*d-5uN?Qe(n~wZ2=X50yo*vLX-v(N!rLT`U|4tfxov1w8gLS7ja$I z=GN8B`)9*u!jueF*KS>bvK0%pRJ!~+vf821sL#6c-%emcA?9+~_VReZNM0SCJwl(g zNq)C|#n#rNt~b|7t@H4zHGB(%8@7It!LPt(aE8YIclAPvw@IbZ`iM=-H{{GY;=CW@ zNFkj+JC+_#XY*~9t9&-gm#pUNKW8EYhU*6FQi22H_RBd=aAzDwZX)6PJ@Eznzn-@G zkCAd(f9|{#5dfLP4Zn8x=Q;z0_hs0V9(wjWA;c*h6w@&``opJ{ig924+~rpvr<&5& zPo*huwL6i19#E6uCh$*U5}ZiRi6>U&l9b|{QJ=0(Vh@|s<s4IaF6?#{UqXvEvxV0KkjJ@0QY8^j`u+>XC+G$K(LCoKu#^8K=`3_!pEQRI z%kYerLp3CT77+FT!#PSd@2|Y7b9($8`=`V-uZ5l^EC}1I?Dx0&KRS?kUEjkpGS8T{ zy;vNr(*o9Ws@@RLGH@sYlOcMLy4sQOGjAxS`+EPBT>Et(*lanJD&E3I& zzYcVzR|g#@;U1nzmVk#sIS~rl(_Gv{a<0hqGuUM3s=RtWRA)OzOEfAl!&PDZ^IOpw z1!{R*cb3KSIbwni8Dt9lA^L6Zv%7Zcl5|gm#;3SLi-0#X3PoMV0hs52toCie!2xBw6A9S^&CKz2;}WKY?pSLvHYE|uu^H& z%gL#z?mKOx3ce6Gcz(I07kU41gYu;*;1@^J8vFf=Etn#(0RQisTN&>U+Udkd7xP!| z`U@~?k9=-JYSd_mA_*`t{~$&sy%a`_gN%kkik24s^bRtMp}3RLbyG^mXxONT^!C%q zg;>WDho5+jroKkz!XkAEAj4mRSgDi8!%ZUt5G`-hqpQ#8ThR?k^t$D zST-i(7>kf}(MLnX%RIAEP*(M1D0~4uex3uDa0V_Rj4ZD&iuH)>64Xf~mhSI`* zg(Kdn=*VIjC~eaG8Z;59%5M{#TIzq*AngcR@HsOx&{HPSDv74$qI!Dx)gJ({e*}R2 zwzjrbVRFpqOAo$k%E>gA|Hlyx7L$GErGbGUKbtQ$JFrSN%hYJ23Yg2=+)h#ZnE{;y z6^sdxngL9vv9YmS3jIGke2|fmk=|1(pnemuw_U!^Ljzwz-OuU&8epjQ9$sD91BU`b zKWGmQbhhl83NVPxre-GTpd7SU)t~G+BErQCeo)&$Cr+tJqW!QjWo-zfX^7=*N;-SL zDLB{($y~dH&#iTsy=V-@ul)D##q7aqAd-OJ>t?Y+lL^T5U2U|9{Q`PA0vJOF1e?u5 zzDV{@2A5+u5KK>C_7^e<3T`>HT(7rGudnlwl7i{JBN6hi0KOFv>ZwzsYiny`V=AUG zlW=omo0cnNa_(Ll0C^@LmhyhN*#(F$V4k}5L>h}1ZE2~M)pB+AuV2vJWk4$CN3s0B zEI9haL41Bg!)+iK*K2n>y;yC45RuQ}$8ns$i9?OQ{r&qtPtRvacuXz&lxqEsW`|AO zX`TLG$R*ai^z;*xlT{)iP#^bK>n%0F9&>VX&?O)tA=S%NivTC|QH9WdBLMS9Hq3sy zZh(+zxmv&fx=1n>Hw{O%%jYqZ%TYt^^sA~3te*!?Vn}UefBz0`?m`87+}O;#ws24l z>82hcqk78iTl)+LZh*b$o7Q#*^{`J@*)=W=hSmcS(uCqa_+EF|g-oio$C!0{l7}H} zg<8sL6SIYKSL?>@;Oftz_ZIy1+SeOM5S)FnsmTL0eKoc}yUUF{XG6_+4T5$k_Y2N4i!RRf zryR~XBrJ|^BvXN(?LKer6^pgmN=8(`igPXp{SxE*a0T9_=j)x#znPjwj>x&y96x=- zLW#cOgI&pIe2C?GJ-8pQO6lm@r5H}IIZ8Aa`uwS|_<#GUx%#tctp!_1!Ux7l4tP|+ zUYPvuVK0#^MJv`4L=IfYIf`dMAX-oDBqEQ=RL}BArj>&no0^OJYKu(jj2t`Br*dpO z6Pj&uPF=HydVRz{UbmH>Z2lBjf4aZsYq$P(M&v_Ay5MY-c{V11Qd$7r2uNi$J2NRz zH2U=qP4|HiW5wR;-hhmX0m<)`LKE7F=_=Fn{3Yd1OpW$h@M%<3(bSD4ZENZ9f=kAeTh zFn3^9Rd|8Zbb5O(@)N@5^D#~hv?A5%tcl6NzH`)MJ2BAK-m7vWe`1qW86E_?wziwW z^L^D>hF;zTlz}e{m($U!qVVEhqW^nlY{;6J)3>!xup_3#x0(>g?)aoR*B(yswQe=A z!6_pC{y~J1&5H+D(};5nMgOtj_W*yJ$T$O7ITl~p2+H_9=z(v)a5U7f|D>IJo{g8x zfN+?qylTxn&I7|p?L4(YH>~nGT4L7@ua~mRRFmwYfB1*uq9AJXgzo=RrMY|_H-N7WpLR;?lFhY0WPtxHhg784c%I^?Ov#2a|jxxk&)3Y z^xvwbFyUNw%T)yh#cji~T&}OEAbStHzYtBJc-ehw-MONf0`(|9C>SH(c5B;nXTfTk zWz)5(M$jc#{9~^~L{d<51k|YFzQ(urGjlGCfU(3}xe^QNB5dI^8m@dEan~=paAkQK4DzHIZtztTGauJcj&^vCF@LM< zn3(A+B<0BEFKB!*I}#HgInw^= z8IxKL2F>euC@k3v7eliWSe*9Mb!3=kXEK$sNwnXL(H&+5Z8Ne1g$_Y3jN9H zbhxFsdB2?nvX_K$%QFk(fxQ50d${9B?uuXdXuo4}yd&lMK+5Z;{bESEUBZo#rE>zA zKT`bpn!$JRL|z zd)W)Hhu(}aFfeEV5}#6lfoSlAel2w`eBz&e~S`3r1-XNwhp#pHA{ z8$c9%IFYty(HQD9@%1$Hg*h3M&hU@j{+3Xzxin4>}eA5D3=_Gw1PFVSak%5(W;BrNA*PzPpccyZP^X8_)0>HyQzFNtS zGWH|*d&EdRV=6_FYTqvK3kH^`>-SvwgUMF+4xcahBVOAe^CLYwkt5kg+gJFimS+bJ z5+RqNUqS$!a;~`&lEp@;jL=qO)s`0r_&eUKdcteQPjI)U6RyEQ@gJ6C8m*6uZMIvl z5p7K;EbB$$P+gdsKXL1CAFoiS&2)ITG8N4m;7qvcjXoNoq=ic?%Oz!SK*4w-?<|?g zvNx(BC*0U9Rtt3FB7N!G+&IiOnnjklJ1tAyo2(X16*juPzJN0>7r^PEZe>q9P?D4# zTUv`P=ija5_@B6Hj^#{4VP(u4VHdcdUPi$N>1fUrRL{{L!X5*Y9;6s~xAUr)D@#}^ zyFS-ws9ZtfqwgpM&AdA@>cGBDS636?TI^MluEJ+ru31V7Y=ua@%D^AL{ngpBm3oap zIR7!)bl2TI>6hw^KW{v*fF^(q<4RsQ%*yc(vz&l+@93qBBdhguzpWU)ZI;|fyiu57 ztKOcYNDUI#w1{fHZDfRDy~gt@g;lv8Qo=H~ir=NhYOOQuDKp7-K7%dgwR=FljN^jW z?KMzCm)Gh3b~IXwl5su$^c)f~G#KF#KPd8w&xM3lv%B`1o|nU6EYedl$6i~% z0Qh6A6hC)GH2$srg4r+qv4cX}$1X8;k9mng(D~KsF*iAV@s`K$(Wv9dDwJq{#EA}t zHT-dXuN(Bz^luT7R_y}dz)t_y-PDdi67bc+q z*l4hF9pL3yVvwh*QW`2%Erjz6m_qEI+=zo%sqYtE9s-kN|578<|3k&qBh5Ai<@%jV z$-X*~9*6z}CK+B^yj+#TxFfuc-2gl&gnS;`tX6=I(W6s5EcvD{tK)f_x)zgUBV~;VKWUl%o`i{%IH8aBx0fYr|N50=>2UMKk`6$+q5?h zB2%-Guspl;z27#Tq5>I8n1l$JNQ|rk+35EWd>d)9$!KV}P`G^Z7aG$_c{;jD6yxtI zog#m#tlZdnNvwYLuf?F)3N^Lkw%&YPBXl8Y6Y@IA-W=u0MP-taZF=5m3HFUZ5hk5C+kKV&yj8m2 z;c<@Xx|#F;_MCEmO=!;YNp>z{uy;4Q+Qy3jD4Z?y=A2fsD#xzDWL9hUJpLTFsDV0`b zdnCFcrdU6Y{kKRk%wFFr>AKgBd46ucjGz4KzNs zwziIEi;nj8dmKOZhNMWKkI;&wPa|4mSy~qJ?emY8@wlB=v)jB6mKno_$~Av-emqIN zuBSZy^O9xr!E|6fss|HSj((t)I?J8FH%DP)q+PeOkojsDbGKCEU$E$Xb%c!y2C5U( zZ$KN3)F~h}$2M3Auwcw7l73J~mC99{fQ_|p$0aJuo+gzyqq86K$2cY?=GhzAXF@)%i*b3_8qXxCz-2%qO#(=UGh=8lrY?D)8 zkB(%fr67X*O++pk;dxGmA5hh}sHv%0SY}sNusL3Vs{;Hwt~;w$05$PkEr*0E+?Wcv@OoK!fz9<`|jAP#!EX7|$_ofw+h# zgrllZB6wh1(h~`{sw%4DAfagdxWwI6o8Sei=Tx#qGZ0G(TLKXy*EOuW%Z$%VUNVcS zAJMSQr>^L&bXiLEd+$A10)#C-#DLBxOjILgZCoHM(hp26{MMS+LU$MkH#16AvRP-G zEG?b-@%G|O4wz!J_Zc*~xuZlsJ7`-a7O8oN%am)>C;0dKrB@n}<*J?R)TO>>yE>y9 zUgX)nU|6HV&B^|TosaezpJBQ?(?sw5_QM12L&?!ngJV+8ow9|?9d$+VynH@cmtg{I zSkF+GwPhB=#2ON}(+)ePdn(BLTKMh##ff}bi+Tlxl-kpy`RquWoH^rG;^zd<+mDOY z&Nr$iU_1favD#YIRH~HN*W7kGjICRV(AFhFTXSjOfk;K=RxFbOc2ba(lJLq$yWu#3l_wn$fmi z`^Jj~zFkvKpQ5a#lF-A~4jY=_>WRl1wFw$iP&0_d@<`d%s!#_|c*HB{1>9S}tVXH# z82sXe!u44VVojus)9zUoT6PSNQi42-*C=R+ESf65qgoK;1 z@rA&c$;s<`EV|?YcLNJX@4Z0;4_+e)rBCjB9rbXs3yi*>p^LNO}z+kUKb;a8z9 zZRt_}@(t{I!RNd1e)a-(9x*>bL7sROvKSbQ*k3IQM2XOF!XhmJvEyK>qB&&hWT?Nt z6?0QgC`v$(zlf{^99qxRj_phpS$#rrayax|2`vpFX=X7Q2)$=VTm@N#1N-zvIq%aE zCabucQt!cYjnO`ffmf;ur~5=qn9S_n>;e+MhfE@MXK)yjFz@e}zCh9_>7No_30m)R zG#DTjZE4p^Fen^+8dAueqw-g61a(h?>df7%byZhJs@lOj+hy&VPo0N#HXoi&dNBtJ z-)~OVtoucqZ|M$K?~*v9uDs6QtX;`n?cOGewD00=jw~0ALu_Xn{gCACaszH@yS!of zz0POrj>J(1de)}UB$79pHn&2iK2sT7T;DKb|EWg&z7Wen!?o7BI0&Gdth|_t(UK#K zWPoox_+$-CAsg}c|F(|YZ$ievfSC3B<>dt@0`hK$`PUoxMu*o&>JSJPJJ5mbwAN1; z;qo|H00s-dQ5i5{Re#fYJYVs+O_DE(A3I1+ltC8WXmxB*y8!ea+g1q&2e#Ygl_zx! z<*4pLsb)l+5iXd&N}>JIHNS)Om=e$rf-0f4*p2sBz*+aKA{hQ;K(=BKrO7{b6!A4> z-T!$?O2Q%I#eIA@IPd>{*7(k%^I1+%rIlF|O@fJ%i|5n^FwwX7_vze@W&_7HfUM-| z=C)h<0Nh`;rf}9y*D{ijb!!&@j&*-?(^Jn}w!jSlae#DseQi^=07y?-C<{8(%7F3& zIDlmfX6s9X7jo?=ecrnar7CoT3Ee>Za$WkkySodJ6MIqzfQNq_x7*S?G6LYj(ri)y z4uG(9fdLyJU*h2C=xArhf)keY5$nImR}7Wh9xw)R;2s>0(4Sx!J7RZ&`4{b+3fHM}n-#<(5&|kcDcQ~M{#HP4 zP)wy5_tas+DYZ=?#`_wuz$r+n0|XZPDy5C={>hq~PCrgcB+DwuptQ=tf{iTwR!@f* z9WI|!fwCXNMC#MYv=`9?r;A3N()qP1D^>Pba3DP(rqh=;s~o9Sv{=Xa`c^<$uDkw{ z;p+D5_1SNQ#ht?Q(`kD(@w1vCN*ZvoxE|7B$GKjo-s+p9-`(Cwa2W^$PmlbTQ(>mE?9{X)OS?O8VZN7j5Ek&3mrylIN5b5bK)Kg z=Xdd4BdF;54S$YdcE29xIy>ez3y4)M?9gTqau{+<$nW~JSTFw)AQM(Xdy+G#r(6p_ z;p~`6Vb)-3@oaG~Y{b>dSmP;|^ZukvnpEdm@SMtk>uy)$X8DVKrPTLw4@>jk;xc%X zl0k7}k0N4nv5--x-1FAzzRNe=XKDUXLYal|*8|P@Oc~BNjN@Blv`jRzdFdL_O)oHLG>`8BC@4K6u|H}QP{QUfDm_xvi=;x*2;NSqtpaOYQ z_Ou#hA2jFdKu1nN43M9^ycro8wn?yPv0w5TeP0hl`n$PMT7DMnxQF!m{z`y;h09^} zo?@yM$#fIm;dHSY8c_!jIGr9tL4jY*dF}3c?{MjT;{6n({;j$u&b`4RwR(c4ww<}n z0u(600U{8tv+L!%!1udGNV9A{G8~(TD@}<&3gaj}TT%b-szCm%PA)4{v&K&Bi683! z$xIzPPcdhEaw%5kz02BJ5v%V+$Cpju6w%WjE-A#zujTUHGafpk^$^!T?%5_{X`o^d`3%i!$@i1!D%RmkP+byo-IIg{^3(R6 z*yKEd@VnnER`RY2e)$ZEi*T_x&aPq2!_=COu#g9U(}6g|=b7jh*!<%VVn!@u$hXZ? zg$p6ZqZs?ZUhB7^upku;?>^@QLYizi7_bmlLwgFr0I%BI(xTb!5l~Hhx4UII5-?E zY&9xc7yLVCgZWY+l_&#!#o37za(_1Q2cu|4r^AP27BMe1+YgdKqF-gj=fmlo?fe!C z{|Z>4&b61`He*0XWGF+?idMZnRL1Vl?b4A0l;^q(3V;bpzb?=Mmu>(${T+frHC7)I>x8;RW``8IWDmQ&VY>q2VFHt%?BC-9I3} z641fkpKpMy?k+#A#!%mzgkMiL6OdnVzougYyceL!0ot*}VmbZ!V!35gv?A;G2^jDm zE@6+Hu^l|jdJ^W=L{SmMJOVtN>tfF1mg_$os$2+*vHbuuN3B22a1p0bnd$e5!pwvL zGK5N`+*7>_V2 zVPpHV{o)|BoNw2z68wwXbpEi0y}k^=3$Y3MVgBY|U$x*dQ#;`ijHcOXu%>ELHq+iH zlcdJC@x9`GsupEX(iNX+2$c|?x1)5UCBQcclPyYZ=6yYsHvAfwNPmjtG8Q3vOytqP z=JL#qVob{}MOv*}_$eT1jtc749H#o z6#NtN;?lr!h2N9GTGm4Hro7*u{MJe&;Koj7x{Y+O8Fqh_G3)MBWUR>^--{|7)De&A z&svB*)hCj2fs_TDQE*nT@_+8ltO*|;2LuO#}lkH6z}?i@}DSC3z3 z8#q}=GA$~ko0J?KsGYb(rEx%}DgkYTHp_J!%Qe7iZkrJey-Sbcm2r?w(1k8X`UI%}D~Ec68OB!gO0zBLR0lEiE})bG ztf&Xn;=n+G;aDQZhzoq5LWLT}nPNtI`uoQRty*mszc+z<)VBAK7V(XBj_t*d@Lz`S;1#a8xVQkrxze+;z7R&0(pw~L6Tv*d7{_3&qiM24 zL;5kTz%auM$O8&)+h=#*<;8Q_1;)vFh9OMJa~)FX#L7`&;Cp{osAP|RKfp+x)hCln z%bZw$cN%S64q4Ol4s~I*om&IWGw@oy_F4~o3Knd7cp5=rEIRkTu@B^13=I6K!iCRM zYNtM~B+Xhm&Ev8EO-Xp~4^=!3^>ezh$O(;F;9a)9UY(*HWW3XKtj{|Xr#)&#NEqsl zsCiB(nylTck^#%m3ZhDnoDn0qyH^P+FMf!_vlHeh{O{@qPQDAPUSo`*QOq;jB#?T{ z{C4CTL^q_@%-^KDy>f<-3G)gB^M*Qj@Z5PD(m6Poh7GwTP*<=Kcv4Aa^IY{v7-P=M z#r{Olc{3*LX#jNgbhUNknw*|qK4Su~K}V;jp$K-suYvLs0I35aB!Dfr<{v6QSR+SI zmwwhr)}s2fllNK&9J=I$o4F*NRhJ`5Gr7*7%4l>x)#7#SHkIGO+;ih$QG zK9?$NV7AlK-Pri3;7`(S%~aC%b8Ti)lCql{_obo!?WjN(z#N)bY=^+15m}yacBGc{=}FdWMpJIM+Sh84Y(ECOCvIL zKu{5g&+K%~0nY+Hj}yGNc0obGa&)y`-NW%r9`ID`6-f{hX2GCQT<^5ItUYs3!l(9; zenB6}w)74w@<=pf_lOEGvg&RwwnOG^zE;$t%q3`zJxnBqN%xb2r9%|(9rrNkkNG3BP_)?Ge8{;$o?p99_THHpuFWPnR&0$pB@%LcQYUj&ur5?5}#0mYB*tY9Z6+s z7%*x0ggF|OTlD1JQEYenR*$#X zxL2G|);LEOTmVU@iKNxAvC*VoL81A<^Vny@psg}nI`=!u4Zm#Bvc>9*7$4kYyG=#v z0h_NwsSi;LR5Q5rffO;FDesc0mAd*OSabr?Wzo9HGCjIS|4)91qLQkEe);!wFtz_+Im)y%6o7)qY(+fM~bb zZ2cQd;D*qg*eI|z(?RMusc^+tKf?>ea7CdsNG;<>bc|Zwh%f%QV!&q*knKIAQDI`N zQH7~a5!LP5jcMVGq(vwVk%fo(7QkP-B13j;@6$~)l$FgALKsYS*@NV`0P~jZ1@uET( z<)}{pEhAWgC?gOMeM=exmtRttQkUMJp!C0k5v;aH(KVi^;R&LDl8AokL+xdz;86mTe(CCf|rETg9D7;3ju>aVcIfYyUlBz~Vuh z`RIOsTm#(Hp$RoWzpF65l4A-~gs0Cv8yg!yjYxZnKAFiIR--XsL^}ytt3n4*NPSgM zjI=;cJoFexCfa_`QFGa1GpB*Z%QpD2ozyI!sI)t!m8!(J>pu@1a=7Qxgvx?ez z&ed%PbIdi0$!rktI;!8_)7Q*#bY`>?Gnn+XjqKRQaSTavVRgN$?qJggM^l4dOm}Br z5U;}dE(DTjR2(2$pWgQJ*GlISt1b&MzwlshwiFf%fgleUPl#Aqd44d( zkM3Ae`~eoC_~K^UiDci|XiTWPmC(($gu1G>cR;s1<|vt!{{~%v`E%S*58|=EZ-R(g z4T)YS5ky_0PINzDQhX0Xl*ei`K80@Gq=*g^ZB+Y^tda(DKAj(C*JU}JY+xCyUDU2l zq9s6jpj|rPSC5}Z+z23{*!1!oM(+NNG*rdY3KuDPrjsvG05}&Xz&CAmr1e%RDk>5a z6XSQi{g&nXjJGF}iq-Uv%`)Hf2RgUDRyXenJ+Pv zOKtbHS4W0?zqnmhY*3pRi*#9_oIKpio1>xF*fZYY@(KtDaAEtX`|X=cm45fH;QrZa z`5N0Ap1JN<(Hu5B)@DYB@B04E@;T`X!+)Q}p1;hU{G%>-I)9GXopks|?;>1EN8#25+gqIb zv~!iA#1)rm8bRK_w3wd!43=t4(11?WdMVbP<~SuiGouY;^)zJ959XPS!;Q|@5h`N= z!@X_1v5W!@W!mbM>B0$bvt<{P2se7jsMPhMtz$3nL8sHrw!c-Kz;Fya4o4WlXUKYj zx$F^vtip{TD5*6Moh*g0Q~o|t#*!H=+AYE~q*tkVTk{;QoEIBaJ##g0>4w2QnUZ#E~JaTQQ9>?hMzf_Ik3M|4mdg&R|>SDJ1(kz@{tvAQox;;Fl^=EZ0Oh_k&J7DeeEioPN z5g&KoZLkJo8Xod?(jk^;RYTWylcjXVAz$c!U*3C3<)t@BufPSjZ`0fkFhH>Wl&5^9 zR^l94M4nX?-uWl-Ql}Zfx*l4nNRz6><=y&6e%j~X!`q+9Ga{b7^T~PfJ>7eSV_rl^ z>HM|F0H+U~VVTDmv|GQz;i)Vzzfr{Sbi)S?>b|kMP98xbVdaow4MZ;&QU~}Ho3W6q z4!yy!urRpB{-HR6MW>x!h|S8~w{8Br+uQ5*p|#}gO<0C|UCtpwARV+X?&f`dz+thh z!-n%Rf_F6mEYQsRWvX=)3`N)WEMB=ljN#4)xr_Sq<|fw<&W-%ChUBRo=Bl&B1KYR{BY-(1S|QeM+|e906mrbVX!@% zlxfZGnR@0o>xhg-gqC>8$Y6w3R368!@(kCFOweu}Fuk&@3CEN#BEHBnF zTEifn5+crfT4dk7lF}sj3@JBUT)*mw?k?MwW~d3Rh50?Q9_9X&z#a6aJ!zYdN2|%| zf&6Abg$s8}nP8YzoeMCmWodpQW2RTmsLF?9b140lRzX~l-nZYh|6W}7B#!yb(B>jz z`!97nMhw74Cmh#ft7W%K^v}0s;bz9sdn0 zVAXO2{6bgGC&qM=a{a&^k!i9fRYPXaq>sCQ6nQ*ya&Jvy{&XoFw?`%BN|Nd~clif! zl!0^zT7EQqU_F;VS%?1b4ZyeL+9JkR5a3K!=hD;0*m~~MVj-)T$MZ$I!qu8;o z^%T}*$MPF~8P z_Kb9Yd%Bi8&>R>6$!0R&H`G-Z#KIT4##s0Et<|z6N^8p!Iz^S3OPoBem%wM8D-6KE3t1 z_)pdifg=F<@Do)_U7bFp&EJ?GY?T^IT`5(x!B@z26&U-mPw>FQZ`sa+1wUC*5NC^T zF>Hu(SkBmg_Aan-s@y!w7dA}Ou~{#)lWl@~#^lCA;$xtLoLrkYMEEXF@HXUUq&g&}p&Btjx%o9A zqfxYHrX86Mkyv0$mV$zpnLDIKKDq4ZX0)Hc%X~u1z?)WkwjF-KLs(Q8c236fz2Vpv zLI{Z+!epMRb>2jv#~3pprymv*!bCx5)>mYtv_eNtH9^UtY{IAf%o3+MSr%%}%#a?B zqq`8)le+kh9t{8Xn5|?2Hj*V`Sn8m4`!+{GdhN}2i*Zlou!V$J!ntOqTpBu*gUAY_ zt5x(;;@2xHahA}qQEOPy!qjVt(`~av3M2qAEB%>6md7L}n@C#i z<*8`%sdGQ2t}VSxz|Z}@v5in8#L@9#y7b2Nw#m5m;kNJyMXb!1{+s$k2a+DO>MxnM zggR(GrrS^mEd=+n`;93I1WFR2_DAwVtpL9EuS@T1IrwVc(+S_88;;Jytl+oTU#6|m zv-n;QED`k;T}}^bqfPEyD`yNE?$Hz<7du0w zQE2)BfwV9y;@r)T%uiaO`}1Sg#(8sHiM@q)Q*-dhv@BnEt_QEiIe0`u;4w>jb`I4~ zr)L{-HQJ*@=j&yAjB{P3JF212X6H-8XH%En)XPr1g~&uxh;3Dy-ub()>I&_nQfnb*LD{!up4>+r_9-alcu8TTO;r%j4~1+ixeh4Ufva?ke$G)hVhu z$B7?;!Fp!H`;Y?I)`AcSmhx?<+#K87mk1TwtOyymE+5{x-Ci8u$EIk0fSI{8n9X=i z|2t5(0HGnh$K|dN6!>lpa0ybYmtj8xTAi@cYpITVMSF9}%}?DR7J;L5EZ;V1A~5PU zK3x_gc%oe0nw;#OZY*aj9Fuya*6z#Bme{imuSCk&kq9}OI=!K~3OAa>G6xuA^s+76 zdNLc*lpd}#n{2o?3FEezUTWmaS0FFA?<)>g@^h?PAp{8CU-Q2z z4>}%$?)hqJPJE*WgBIDj2{yO;DX#WV9HT5t-qsddgGf&CmeriU8r|F*7c}ac?*bvz ztuH@f-NfiUAWExrl87;3CsfC6zr&e` zQ?@!N>jWnQ%Ln&>YL33G0C}4wozux6upm*d!IF^ZDgLIrcxCWe zQBE0Ur}cBn?M393n&C~Vk>W2*0dtEj(qAn;Nmp0O8@W^x&0>t@?&sIDJN2!r4UC_j z^4By`4D)%iC~*-rvPxljdh#eUT>e=6mwSQ zsgQ|4_WmmQO@$U}AfF;nlwcH6_idF9CE;Gw;iZ2q+LL*%SL-3-nbW{}Hed7RFFPL$ zY!|Eh*4}g-bCA45XR%2^#-DI~=8phDOCE3t30(X4S6=+?3TJJ;F$c=b_O@$w@+jex zV(b1wN8?LFwVmfNMma(|2G8-$yVJXXt6kQSmoOQii?sQ9xi{CI+h&UW0&lk1l|UT; zQZ}iv`9*Rmx%(7t-;{Y!dRg%MamzJ}h%$=*E!8TpqiJ_?s30psn&+8HaJYAZ@!xk< zLt-)O_R$#)kF-eE_QwskxZFUYC+{tL(nBx#nTe3o)BWPm|{)UW#z*A7J$$#JTw8r~IoHhZRn1uidehJaXkN;H* zBO}rZc9?gozt6}ZfPo|#*Vpxqn;ZT0Mt~8LNjLPhBVi9O9*0g*ZQJ109a2F;d)}Ie zt?dtj+iQerVbxddhH*T`smg&R9y#zW+B|4YeDIGoTL50-oDIr2dwE}8IGv%+Id_>{ zle6>w>JOA0-I%hacg)wbksrEHN>y7;6c$_BUXeKbUAj6;n3hnIS#Mz(d69TO-8^qX zueCX@HgH`PRE-K-UU7H#651r!TfQtdUMqCFtax3X!$(H-hG4$QV*h@pfL=pgsd>9@ z?X2K_z+!e5Kc0BAj(20f6f$~#+*&N(vVXf#rv>MRQ=@!3=lwbx{Kz?T*64bO-g}E- zlf@hz#mJwIyWH@$vpk-RNJHH6etrZpkQo1JK#JW*?^opB-tbiBoTf%GV~8~wF0Of- zD?f7_9}oi;d6AWjw_aD>`^>Jiw5^Y-K;N7ev|E~oR$bpN-znnT!ObaD?0aYg5AVYJ zyrTaIWw$`%gCEsA=0)0ZiYfWnJHcWT&lZF~xT}sF{`p?z{RacYuK6Rw0h${Ybdsz; zT)T~}K%p4C7QJ4L>325Um>MU!$K!LuUu8U%CWE8WJPsKeLHqlsJJKd8El1mpUZJq1 zbm*6hn;h#^1M+x!u2!?&Lu}$B_HsUaOwDJCEwya$h1}qmxu@|ASBsnSk1!*PG;iX= zRLlabIK)Z3F4osNh9`X)$jM;H1Tij1u7F17_!W>>cv%JvZIi6JnUgn-Us#eU&o`4zJ4VWLN*r8OAP52I%*R_lx|g~2%Ix(V?1rWC6V3`7tSY;`HyN*qzz zY>L5wRP!==3yX@DD$rO^0TV%fe*gX*a5A+9WC5@d_#sDjxXKeC>c1iz%9^oHkB)}o z!mc;F{wt-5Zt%{52=EdhzXJ@+Gao==?v&YM{2c^z#UZg+MT5(oTL>H_Jd99nJn!Qh zZy)>MAN??6borWUBvWYUu>G+bzHG`w6SU|@Frl!p0T2Nq0T8?Yz)W>>=#*veJD6C- zQew)!P&3?bj?1DoWs0sm-sUcm(44!FV7*y@xYmA$j56`FghZocPw(#C{7W@4I^(j8jws*GI_r4;sqv1tLvw7HDt^zXmv{!*)UN&E&p%9eJkI#nqe7IUan^CuKN3nFsbX9@?X2Rg{8KckrVm51WK3`^2P;s>5dVG$cfl?MumLyVfT=et*)2_FN z8w?r`w=dTG9`?X524yo$_lI|g7Tw9T0lg9zG>X!XjiI4zz%L0$ed&l=FgvK)NAl7R zgt2%Q|ALzQ@aFuSNsXljFv1NzcD>7r6bN4MLf9Q=oJfVjJry22JCdIKLy{Z>pHOmOanIbwCEK&F`?YiJZMP}_OKNb_L$~;BgQJ5ZF#YQtR8!zQ+AV;Mxifk zd*u?xVY2>y*C>^9*}@;X?}amKG^Nq!Y$ga!88b%poZ|uTM!?xQ;Yw6Ws`$G|gTzN7 zdd#fDV-}dG9XuM<^(%rUB$gV*Wh;RmBb-EHs-|#(_ULestYxe|J;%c+Z(nabA9vND z>hOiA3fZh#Z#Z?wdIn$kW!zS;Ela-Di0mJptrTK<2?;*0!nX$^97^6n>kh-HJ_3j=T*KtDKXs4pE2f@c1hhbA!H{Wl6c7sH zI3)Sf@Dd<<>7xBLLzf9KN+9a6e+P7i_uT2ZGKN!bd`!>zep3pv%WU3-VVIUBW7d1RTfH`;$4^ zS}P_)91vhWhAV<5FudBOI>=kK!Ax<$iJlLbv;nxqrm0G0Gqd5EDAn9~dO=Atn?2J1 zoufK?;t*+H`~J*aU1-$7WTDbF>&V7vV5Ki!X>8@SXzOf9?36)@9{Eb$R zPiWNDcb4wA9QfNLUM29iX@ZI&W_3*J5ChYF{3t((5Y?K`)d)g1b;1la-pCR=5eKHYwG@$yic#(ai}L3#*e14eLLRh)Y?G!O@2Egg55G z+h-a4JT>oygVJ}-PU7<)ZhSTIkD>(kjfMHyYe=B@!T-hPi=5k8 z70jE(tcBRyGdfr5r_XIE$6ocx|E)n5kzzm}o+nr4G;hz@1ltyp8xBH|r!*R?mfs>U zN_-D-HqOqYy{Yr{YQL1JuZ58Mq3jI9)Bn-5%JY8}* z9b^ut#k{EBepl9IIoNKdE`9`3jarK z9FH6`g!`qlB|VN@qB$&?l?KJWYmY@4v)6{K2%8>42{Ipjd|+6x4liI0ZzV?Q-tlYr z9DE2>G$||5#9G%N+SGRv@-?n0$`jpF-tTkg={REPk$3#-!^vtr*PiDPZ|z?AS{$Y@ z>7>R`mV!9UAzLb%{1ct~Ac9j1wv~X`Y2VA7EO5nQL{O*uZi?VBVtTdMNg+e?a!Y- zFY;KG6+6%{<#g9~cYAU2H=canpW(`&c{9Ujy&yhS+lp0M9Y6r&x#c;5ik#dKNK!PL zo&jJ~*38OEi*}dSGap4?@{F*29dm6OgPYs#i-l8x6U8fHX3IQnyYXUOGh=i5xDOftrZa+qk? zZ@|a-VX@ZfPK)?c)$Mp-^bZV5&A+mMePjAy1ld9%5GWD-IDs`Ro`L9tS_=89L}n+1 z*dKC6`}dRb%kUaQ*bZ=G^@e1AEfd_avF7ybnDwImizYa1hKNzZ`qX|fFo!HbCuD|# zqhxWJXhZgKRBerTT=$r!^`Eyt`pZJ2Ru|Jq~^zeoeY6LlB;z#{0D(yo< zD-M>9#3jlP2$Ch>hUd#ec8ho6_2z2fS4nn}<|iFp!<8n9@YR!S{%VH|-Zpi0!s>(O zQT+VI^Dup*Eby`FZnVpHL-pn>rDiB_M)2u%+zq zIprJ0e*}XVr*lZZX&tkyH7?4k;Cci5p!IMN&f|Z;R5Ah<9>SgoX8vtac&*-PU-KU( zM{Hw~YQ(zFFD(?Ria_SPw>l#Rkpbp!TwS*NLE^R`v4&sYlOE1UJv`Ict=9EEUZD*{ z#x+gZR!~yGrg0^)%unt`EkMF9#w3l(2F#9h2>SeZ^Ou-ZO6>IE31D~A%Gvj+fvX+e z!Zt2lNIEvHYUGDC0z??l(aj5F3!oiWBr)Ti3~H*KcwT>g&TX$}SybA2QY;C4v2Jv$ z5ySU?lO5NDKgOkq37{+hDTG%c9h+U2-RRB0PS;D&Z(!!XWZEU=UJ%Lf?WWmp&WjuK=hJGbcBaM3 zy`C{&umKS+KHueW&>hEZX2z$3=Rn9q7cUcX3i%p7pkKM0p))<~D`N4EIYJO*#Ri+=d zSFFSF|3oIRkhz#;NH(0gjYWT}ZHbTG+!^#09z13wFFMCMOma8hf4hyRLhaKFi}buu z+lsRxg-(+2H$NEk`ZU#!GmR~6{(Zw^yIFwn#pU(x0$?$Ktf0Ga3S?_v+!?ex@s{R* z()|$lIyy3DNqJ7i^&URB1qhrScO@W(3`BU}<#XpwY@`HA6as^S?!Z)bzf7-2_4c_d z%VM@b1o^$BZmu0%Z1B}~jPNp5H;%Huo3+5PNg-D_J_r6sF8PjI$DdsC z14NpXHMRTEMUU)C7MkvFy+I&7!CBYFX1D9NC%Kxh9dRUa0BQmkI(m z#Z=AsqiU{s%b6JN*dU<=x%{81cse-q9!pzKmjNq{e`rLdDh)4FeZggMkDE;(7G<}> zyE~|bFzBHh)L3k;HLVbM3jw3D*S|WoBn~UTM1={CAY&9*Oy1*k=?XEGu`R;Kt zd;N)8ceiOQ%mWR14HM&yXy#01s369UDo3(V`RHPs9S+67xZfAp{H+ltd|cDLlOCc1 zE-5mK2KKI%wF2Iew%a*(z=vV`WWdz@&R@=O0KKTFQZk}DYWE&_cyM2j4Eg)4B-*`k z@6k~-03%nLOzZ-d9^>6kXQ5Vf-Pe9_`pgcr^88EQfDMxg9=~Chtg^ln%9fy$_ZYqzUP#rXghD$!m)Bd z1tDp9-*9j=D&=@3ZWRj|ukAlpeeDy&aU(j6dU!2PeSC0y>aLw+NF9IItqDVG+4%Pv zCC&FBv)1YIKia+lxUyhfH@0ot&W>$PY}>YNV=}Qhv7L!AF($TcCogl~x#yg!hpPMP zzE!(=ujcOc?f$y|^;h@*qr%)O@>fp!`n*%-@HHIM>AZAM3cT-@AC~0vgWiuPWCoA% zrto)c-{$(9u_AU|oqxGqd>o6^HC?~~vGQ-?qb)fw3W|eit)|H;B-5wS60K+Wp{XVf z@nweQ%<;QlQR90}4gZIEo5V-$)9=m9k9dLhyXjn=w-Z90_nS-omlgs3&*Gl;k3a5X zt9qxh^S!vj0JNABc){umn-$kSyDlW6fN5kOI}RW`l11i=Z!c_#`m-fkz6T4P{VTul^4Yu zgFvBR!@%z9_?c-A`Cs3TX=#GRlDlU+wgW?UnAU3d?=c^{oZII&9d}N4Yt95V!${C^xiqT-&q75)_=SI6IX{S!64h?d-HZ09yir| z&6WK-b#fx*q09SX-X*^nAoVoSsj=*2+(dT?KrZdklzIDf{Yr8^p-Yfb^DTe|eB`3>4P(d3g2k z6!IrixQ?EG594F@m00&yr9T(bm7ktzjb^+j;LkNM#KTN<>zrL0WN8ycpFL-kLLc2) z>(T@{EC3Lq=qN&)qgt+xGr_g$k^87Dqo{m&U!4>ll|mAL>I&c~Dd8auTIz$jnm(*A zzNg1i)Om^<)wqf!p*79{xws;LToqp+ftCrPRElj#ko2(1*>#>IyQneg*@SP}$vEV4 zF$0{*^H2T@aS z(^OjbO7JHafRgwQU=HmcoFDwloO@SnYW3+&idxyovx&-@Gv!D)1*d>^h;%Ptik<-) zv+T?87WPchHvps}{o-aDM~ix|D{cvv&eirBQuSg!0C6Ap<{+KJXIou@L%UYv_7LyL zCBNzZPvz%R_7v~y>hB)juLUFDR$$|14}^^~XXU2cod0pY?RO?)*URkuV!Xi1XkDl= zx`oe+x&G7A&rJ{V$Hjxwj(GTzNl4Bc#rH!>{+{={Y7V%L@AJnlebroYC^xC)t)WNZ zpFrQW3jbu87#wZTiXg*mg4aZ{xU83E7y5g@c>8<30jA>4mQ!)OAx~0inz2r;sqcM<6Ecd`vca=2O+T;DvbXFA*WIJsH1xyd}zGn z#ZS;T`W`<43qNJUq7>B9!dw1Rv{8`vcKA&jZb-5-MY8!xHl}7a8az9GTyM@C1rU>{ zt>qq9&~yyX{3}LPde*daXS|SBR(}-|>9|qYyt4o8#K^Z>rD`7Y@D_c2?Dl!bCLf?p zHFaR!=2NIqM;pznex`tl8{HpROoz#}XcvLFY6MfsAhGJTJ1$6{LIhX-P@41DTGD0( z!~c4f%p!e%MaI}-b|qLI2INCu>yRG z0C0PW%dvEgs^uC``XCp#&#g@V-1YMn18AdDXPG(Ub-Oz97%7L_;kW?2CToI_{`#Ir zp=y=+V@1WaKJri>z`>`7JQb(AT6;Ku;k;k!j?e35=(RrOzicedl54F{Z@*oz<@Tc0 zKo7@9>j2S646CD(nxY|U5C8i-!?bxKCc+nIQVKt)5aokn`b2FFtT;RnBW_Ejl0|Rd zGJnY>_34H(Viywh*FL^u|diNC9tKqD;TU8EJQ6*}&d0l+w?{m5d_^eh>6; z6^KgO0U;iQj9xAQ_`}xLZolgujX8W5>l{6GP!&V&_nG~DL48!U+IAc=VF(grG z3YV_Alhz|lXI-Q`-5}8-H^8+YtGmFUd|XFE(vQ?IO4yij+@1P=LXgZ!pyd| z_krukH=S>_FukhU-F&+KXA3ROxou5`Q!}oskNVAq?~@{#!;I%$N*Xbc2^ej6ao>rD}SG}Et_}biWI08APIvU2BBpsha6pb zlm4DaWj_zr=E~~esRFS0GxWvwp`?_lv661(z#C;8k$Gy0Id$K~G(tcLyAWnC>yQb( z?fFiBhB|a`VTz>pmR0`TxKFP2lw9MPmX)dC(mMr{O??S;y8WqSJ>|1|Um0!R z$@Gv+c>dg%yh@lmfe)RBD%@g;j-7T{8@_eddm6MFpa<(ku&8)-!ZadMNp<2X>YEdM z(zgMmf%&KNjE%@b&|$n9o=K3wruDpebN)1sGQe`GBPM7dowMJqDrc}Rk)|S%ImSt~ zpcTp|jbTx%9(KALBo%kM75L})bUQ>gmj!!bF1CSJbzG6kuYg8HNCpGq1I1Fn_M$AK zt+XUN3ZCQw$M5om@JB+94q8BI=z;jwnob+9dc|*a?S|q$ozY43uxF*71^4@u07pYo z<$^TO0#eW$HXo!c5SFFn*|;x<82*JNmXNRpgH;$1jV!p@T-;4 zPU?1J3=<~}% z4@z`%mi8@g_*KYlyiPqfAe9EjUYYo&QA7CkA*mpq6yUp{>7J|>Z=@LrEe66e^Ay_x z-LxgjR0A1ZCkad3x9+|ZwNJ2UkEhv;p#UTz;xez)vDt&1zuAsWd#L^<5l#h(z?&vW zlzb3=;v-;KK@KqP%Gao6Qgo3WZM5 zDmidQ^SN$?pe`>Zot+>UU>HnfA*nnLzzTGxxsc~Lao%zYvTwmkxJ1F

k@4Wq;GWn2bcI~)I0>)Z+cisdiYU4x9Q8- zWuiU1-s3v`>^`e?krFN6)tk16sGVnER(2gQ9Y&RQ*+KUD>!P5zaPF^jp-dOALCjU# zBw=Ij_aA+~(7d@;t2~IpyxfHj@z0{LnsF?oLX0UXj#o0k(k0rwVHk9C5!em-$B_hY zcKP^ZtDq(g6&9n`8m~eDW|I9g=}2|XV25g4=d=wIAB<)t5hjc!X-?1ts}D6D1-O%G(o7d3o~AL;%Xlm^)a}b zM5T}spXt=s&L@lu{FGJLaCo2iD?yU*^Nuy={t@qJZ_vLq`7A=0ZScnZ>9&_9 zRnnYM2>bXeNdWlBqKBwBDLTARny$|oooASMik~d&cDqTfzfC&C=>`_G;9YR7)W#Rj zqKtQ{BDho?kJ;8n+Qvg3*L@v z+32+JoK*!wf4NOK$0Om49vp=rG9XRXCA8C5OM8hgeII~l@*eo+)Elfw`^Upq!2>T4 z4<`BPrCq5~uahq9TWsoHixwZN4af7#?*tWbIa>MQ{z`MNwgK6_h$hl*cv_nfXsXy9 zLKkxOO%Zy{l*f{mlU!}jL{5%Arvq;+>Cm^|WoX zZ*mwSoOit}v;w`Y6q@|}D7Yl$nOfsmS>X&$bkgoUEWK9orz=!J4Xo$s_Ml1(7PM_F z_m`%#6c!7@Tl(hV&#ZmYp+ueh-kYXhWAWUOeM+48cLXrd+a(ocJ4pQ}zOEK2BmUp$ zQj)Yz7NX&LR3-Xk)uc@&Y-KFtHsxX+-pIu5$XOg96XLK~#osyYLKsvGj_N(0PJuHQ zg`v@l?(tCkXhU&H?JuLWl-%4x=_k2$@}t?|4>t~zmq-eBaRyxrF}B++Xkte2DA8Xe zN0D(vGbBo8>&Z%dXoA2oLi=jI*3(ZuHfGvF8NoGlvAmShN-;Q{<=Z}6Pkgbw0eIph zqFTs6OhF_u56A3E3Ut^M#^aDZkKk@Ze&z2|5tcnanxcy5?ifitcg%+1B(RlATz~YZ zScWu2l_;x#giXmH^5yRcMWKmUjhtZhP)$q?NI}UO9~_Cqg;KybMU3-3Dy|8SClG=5 zlh*wFCL=G{-K|^>4PR|~sdk?xVB@CXQ2n$25NUFsW>BY?SGoLm3NCA?ny29rfaauz zAqbB=$-d24N7`!Ym+$@q(ja(FO*FS;Uq-ysj^vvc2Lub2;vrB28%vT|*@=)ip{brn z)T6Bfo7mU#(#Q-V?D1y?B$KFs=z#u(_E(=^4PzaDD9 zvpk_nz)F6d639ETNkrtw^^~=m;M|mIz15YhAZY`;O?y1dga(NyC0uTrhrIYm1{-Cr zv>OvSu?-S;HSn-~J!Y~~WM@TG&=tT`4Q0wql32{;Q93iEBh1;d_N7~{V$~CC^Y(TL zEo&}M=Bf3F7UQ|)_e56=Al6BV%1-o(>RJdp6(oB(%miU5ImD}-jqbOVohbCtfm6$r z4dXmO-D2IQi<+2|<|QKJ>es;dkCmTT_4fCEc<@Wic@|~RYYjwBEIl6fR4l0UkfmoNo8KQ3Hg zOr{>JB4<@v0n(>bqgYd|s_Oyz=NuifNIw$WFY`Rm(uUh~7d2=c>DUL$%fdM!s}3tQ zV%O5l3Qb;m6wNenh$3b$be6_T%D|G<$!PlD|~mc{@vv zzv3{@cYV+nW?GO#n3?TKWRtS)X5jiPHVm+{#%C{N8FEPEO}P(M$Q|rLC7`J(988D*h_xmasyMXde&!J#Dp77Svtq?mu!$$;n+?}_ z4LQz(i}>h)9lG3eZH~YwN0R7*%OWtzGc;a5^a64+7>EN+wU{871Dz*&+mO&rZNaX( zC)2lQ(3tDnlnWi=%pER1R;0JGW*w?Uza$JS*XDznO)csvH4JIk^KNu3OrMe30S=EJ zQHPEftLNJ~Y>-CebcVIc@flmQM#HfUxOk@GxTYjWE|o-3bt%n^ro6IY`7WsLrF;2@ z+`gl>ow)c*yY1r0lTHp32y}z@6$On<6vhYasMA<1ODgeU?f9)gw%HEM^J2p^zUfMi z<<03LN)e5|``qAk^lyAHhqDn38>0MM8wr|b?#(>j-=9ixpM8~jX6xm1bVg4yVp{E> zXIcwc`biuSi<5gJGh^2l(HNpBjp=aSEu>%P+T!wMKq%7J%)Mq4sDJS`yxNT)VpIf( zu#5{KrO@o_FsN599GXQxKReZFh*zpfr#jW?(4@&k$1YAgg|H>PDmjp|FH{X=uO4B> zg?)+sg~Z(D9_XoX6Q-Y>@~z5JXT{q{Y92ammEPD+3Zca}1Ikj??s6it=?XR;JsnV&^>iX?1IH&(v{;SeDCMlXk0v%kx z)=!SFIt=NU7#L&wPW-vKUlveua~adeW5o+s&lwnNh2pK2ZJ)rX!W(vxwgndVKCtpBt4R~>??;%#hW8$-iDBAp*8 zxNs2P8JJ(pemPx_Li!T^t4oARGNg?}P%GyTU&b?ZwHubt9$%|ZohG5%kV9m&an?5O~wtw&JjjUjpIf$5u{@(ENGKvThF~cw#8~zPtMTnTbLh1hq z)&Hi*$r7=_Fe(cXxj4C+!Y~TU5i!c!JJ}lA@bmw(G0uNArsC;fO2jB+XJ_y7Rm;`L zc6v9!1QYMF>pRY?lwZ$Lz4;o{=p%+1JXYHh?|Y-wo6;N;5a zY-nT3Xl7&R!pO?P1z_f6V`XO)Ft)dIG4*iaV`H%7;1JgUczQU=7&BPgNUNI2o6AWl zIm#=@IDX^Q;Bb=Dx7KntloN6nb5{^kS26SSQg9TuWb#l}Qj|6l)v)3+;gV8gRxy<3lozm z6PJmJ36~*&iPMOgi3MO{#=&W5WK8{qD5LTh%*HN?hEAq-E=0^M0{|#use+$rT zEDT>bbFqJgEbOfR1%Tb%-5CtsEM4sXB5Z1H=wj+*X=mi>WX@>qX6WQ%>Ey}CLT}BW z|BslVJ{zmPtv-ND-_(UcpOcG|i;IhigOlZ-|AQo(vy{+3E`4_~eIYqfeN7d6PX#*{ zF9jOZ( zng5RM{{qtg4laX+Am=-TL}0Oq?7{Oq^Uy%>Rc+WBu2o zvHT_7KUn|&PE=-2mVb;MX291-`Y%1z|DK>6ENmQHT&(|2P$hsV8eiw!`C!O_uL z)z($TNkrXF#FItT-iqD&o2Csrhqbu4p#;D~!Pu0`O-4+U%ff`&#nOaHmCe+O#rlik zCd{0UDq=#4ULy9))@GI(wq}MB>>_qnPHIg5odjk3H-MS{TL5O|_>Y;8i;akx?e8%9 zFF^eNKv9-2j&l8jqX0HGHWmN}3+w+Uj!Lr{s)?&>Njj*j+bX%JsmR;QOFDe}%TX~A zRxOeLD@WP?4QG~r;Vf=x^ED3KZ$j^< z56={WHb{xdiy!KrA3Q>reMcrBK36axKk|r}H1FRfTod2lcF(s9%LqT6MZ`jcxFn(q zW(W%gNN9+aw9LQxZ$d%Um;I$z zAJ&L~2rBIS#Q;-QqR4?DjvToll#(%*n*<+48$JF{ zcJI3-ioQ>^HmB#?qcpQ8&*8YH@w>2wOefE!tKLPXVp{mKC<$p2MT0|w#p+&b0%eE( z8(9$aiw-(Bx0?&zMZ@fV%)XMqf1+I1_;uWh#3+A%L)|rA{N9bWW4#cC7NhuCFwVfs zUkv#txOv5ToiKv%Vz7t&J$qB)IjxB#K?qv+)T$vDOf6Zg{yn*vJ`u!YQFi+XF17XO z?P_PP|JD7})}MbcQ>!zZgnu{_Z^1*m=$siBeL4cAwxf}&NRIS8s1bR#nb?+R_Q(1> z&H(pKw|{8AGMu&5&$o9cNhI+G z^s{ADUe|1N#6;)c+Il=J!G#4ed>vRl4NudscIA!`ZI=B(jimk{YUBC-ID_BZ#FYct z%f@bo8YNcJe5lUU6`GdUw!soAm^siMhoCX4leS)Jn17Zed{5_U4tn)9KK&RvwcPq{ zg@UJsb)DCRVcw0+G)ID*j&{@eRN5Kld#cZ|1(`Wh=w`KOw2A3?w0UDNf_*5F9C7-d z@O@bmYD*4DzyM}c9{~i`Lv(4$lOHN=gtit%Bk*2rR;m?>k*TH7Iz4G{QT_WV%*IJv z0xF}(l@mSCc_%irieqws#hi5Wl7&b=A8hP7EeT&AcCr zzUJHJ#*d`fl19>qwpe+4UAZDS*C_c2ZSGmE-!0-)d$=Tm}$UrkC~^@@Skb)JGG+`NraPX zb0^oMu^?5s_J!@{Gf0JOU+rTRWsgfksHE`3K_ngSYbk^QPZ4JL$K0~%#>IyP$SXwWy!{WsP{`AkT@MS|A#3_il?#$>eE)o>#Kye`{# zfK0`WaW=^LM`eZ#NM?R-i%&vFV^%*tm^ZJhcU2Z@j~*>W5Iw`HhiE+?EJ9?M5G$}D zHf?X^ds4$zoW&0aCpAvlO5EU8_MR1ys8%Z`>Wbfo0G`!^_^Xiz?l{ zlXyID-o6%ayWO2Q+3CSZC9*-{dMu05yCg(5`2ko{U37NS~)2rSUhv$^4dyqmB+=h^2Fn}LkmLNI_f#n zyi#}hCDp5K?D68Zdm#6{3CDuwQa<9)=D-Sm)0nZR zBRgSxj7omTeoh&c=?~yf+AYc!WZEc8pq4cfivYDGr~)MwZr5P!r1WC9U{)RX*?{(3 zd%m--eO!|Baje~zGM|2&otA`Y%3(_hF{F3};5TCL+>t_pw!i7?vED5#TdZJ)tYE@v zmJ5%6*f%7}o6*wx29z>nk$g8e_oG^v^{% z@5Lsk*2`8X5j&<4B`oiyuF1BYd)LVY`aHV4sh@79!t#L(b2}FbYodEQPu-tEsGmQ< zG4LtHX_ZE&@8duf7_--tncMAUdBO&^-cIUp;B$2f4C&>8Jm5I z1E;tzsQ>AovxgUt(68Y}U$j{^TS;8eIO^Ul&VG!_L{~;CKdBV!!R8z@N znTOi)8{}}fS9-c0?|lT}b9VPC$Y%?QBLjX&^ziB*Xy&M=5$xo_0*QHIOCWGPl-@Ch zqRR=t(?3ooE1_*u5m&570wIi0;l84YA@b-PY#nY)(>w|_{cX|gCSbgRA`{QLydxD( zGSpnSk06%}rxIH&yEHHo62@dfwEiB$p)+HPc(&UsE^qT2D@3pf7B5yVMJ{6FX%+mY z=NuG?*1t!>MGtFpN2jpD`;?ufvdvJYDUaPD7M7X;yjF`4Ff{wzjo#|Ta)j7xt34m6 z-G_dox;j5%l5^3EZ=5!%YcyT<>~Om4 z1+2RSa{qJRgHH!Um0~(O`Bisl3Y{q)0Dt>dN|{{qXKgErUqJ-8e)CA?#8^)`{az2$Or>eKSZc%PDvh&&f|}c zzJnuU5zkIo-uE)|)0zBqi8&c_T<2XAV+wXx$xhqgxX6}^H?oFIsaX8H)%y;i#}&WR zTaKeiJ2l87H{;mNEGm3j3BZxdipW)Dg~59Jz6g30*sVXX%}MFR|Eh*yVf&XH_dj1q zG!%@izBB^=raO?bH8lT{=+rGuz63fBjxQC0q^YI3g$ofUCk&&Ay^Xz-vV)=Vm(oGh z)Xmb^R7pbkOUYpA;;d-uBw}ytU~l*LO&ai}efYn~iEOL@maq4ue+i0bU0-hd7FHm* zl|;NQp@D@_MZr=*Noa_ubiE*t>GLC^3Y1j5D4_!tm85`Yr3yph*pA7ekNGnAJ6bL` znjR*Q=nhZ(CqKP;-Mh{C`k7dlUC%GyPddm(Nigan#OREWqcsNpm)jdcN+ReU9K495 z-}=55|17u{8i5jlGIFV(*F3V_w( z3AV@Bk6g;l1Dj=r>Ro z{442@1H3^_K^98|jzbQh@ zOi5+7&q{@veIu&ss zXJlcQ;sGeYFdkH(R1h8rieQS7J@0%=t4fDv|5@R)cq@kmrnpCwPqH%vc4Ho>7*7Q_ zt30qKi2zR5zvA|dsb!R>%RKa66GN?N$J)w@hK5G^>#T>g^jAnrLsL;vK^0}BsfIRK z0$_mLqrb67BZv`UgHPVt@I#&u@#>4Uf9r~TmLTvqDkZ7#Lc>A=AbB8>t$9<~_xWIb z*8p15fI5=&xHCq$28jZ>Ixys=*hP*;fkJsn;N;}`fejY}86S@u^N9@BsG0+wBjRtt zFR{xmG)#dLZt{X8mY_%qv4YI)M4(;G``s-d?tvV`Xu<_-=wiGiU4@@r$cuT;H`+`I ze0z|?u`Ti~wbPOG9fXa~ad&D@;FotIV@bf23KL-f8FmX%24a7!>26!+pOULt^pDr5 zV}2aURl--)T|((3B9L&%anNz#@hu@x8DI%u3DDsT4updaita!1$&}-rF7wfwoj#sI z1O<0Hk^Q-na>sxVcTvBn&*{qJvA2BnIrh)p)s~SSeOVgGgrsSg?+?fW*MslGuoPAUlg}|o zBAezN-ep3N9-9V9AXy=&$=PenGY7y=gCVgUQ4x9OU7w@NfulPCMIZ(4B>JI4Az@=1 z|HcRmU?k%9N&*gp5QaVRYLr`yhz8;3fzjp3fzV?_qT}bo5FB=vj+@)b1{wv94M3gp zNE{j^lN!#u1T==iB&qH)rQ{^L(|}A7;UzFqM=!(8R04UyNMd9|A%f6f(|tsa)ZqnQ z1#;>-f--?2;lUUlUnitfZgD}#Ipc@taKZ@E=gUA6;Y`E#^Bi7PW6RgDuK<(0ID@n# z9MSkjiDs(V;t&nij2uuxsLB1OTRsC6j}fm5*nq5_kw3|wXw;PJ&d=p>u*x`wVKx3mpvs0xzT zrk85a&sla=^+5(lXTJ|6-xn)JAKX`+8mHOk{EB^j$k7*?Vy%L10-ZrXz=2;!^%#uDjte;cUSX)r0WU zu=|No5jhPN_(mE!YzWb#PBsJ$jFG>Gh#n!g2SJeGcYiRdFo;NVCm8|J+|%F`a+fXu z{T2*XLJ3URvlatVh46_5GolBDCy_UlL|eSHU}a;x+OZD=a9CSJ9cm_1MnK9$dPSvH z;_sz_oedg-KT|qpf#wG;9Z&OadwQPo#xu#FCEkK1dD=* zDsZ)kf+1PSBO+}H$<3mg9y88 zd@sXII=CRu(@L8)a(+UMsekUj!$uDreXT;`^$r>ib4Ro+90GpP+kf=PBF^x=A`nRH+lN|8sfa|c)jXdxUkVMAh}VHXM7 z02PR{A)#=<)o~vP7J}e#DUr>3k_g6qK-b{;zQBQlQJ^%@^5iN2hzR#SPZO&fpaCgwhACYLH}UC>Scv6 zz!B017v;keX{O=zNCX`UU4jV* zI<@@MgIJ20^j?M6g$8NLH9&vuS*f~`whn2!Y-Mh|=pF$(o{FvzAJW5CPB3*bUB^F0Ep zZU4_Rvt0-qHnCQmIWP{}J%}P&;f^GJ&e(wv|zVwMjOm_3^`IWSmG>MnDqXg$iK5ud(G zU7{-(nl;?r)yPGnJ#y%jZsE+R+?OTmD}5+5ZW#Kw;QUk4f>sH93-G{R3{r(Lj;er3 zbZjgq4Z;54xMDCN*d!FPpLoBJ$O;E(KPtO7^cm`nN3abCvxY5ytTXMl8i;!OxFZ#U z{}2X)Zs#uZ8sm#-#pvd~zCDICSBU=cwXI|_?;SN9Kf8;}S=Vk?VJcJ$KgdZuK_jl% zkz+{XZXB1?uk%{aBWAbfuB;Dke`qbr!mY7SG}v3^ZmhbT+peCM6etpAAEyPt(>vo?j zDvvd4>$axq>qIth&0zf;2W>sKKgOpwKu_nJ@rS*XsjXb0xWX;K)0`-vvX9+qB(`@9 z;#C5ii0U4zR#LOjh@K34-3=cK9tBH*d@a#$YzNLxI}3ZcR?FQ9@|1*f)TP!EQ@ zW3=9?w9c!l&n+nMzys#_;7?<(G}a;Vd{r6bbZw`64M+vXADXSogs)*+wHz*1CIM6< z6a~C24iy$d6rEK-V~`Vkft}FAqG8-INF){13BJet&8Tp(_m*yIbnJV2qME%RGD;gG z&~uC+ur`cNam;QkkX2C=TdxYJB3V9o9+lj=%$4l}5;$oUwsS`#(U&j`3tNy@%FZiC z{L^Bd-``FN8U+i0M$L>0pT`CVD~(?d3ys_ecf%`I)Yj-xD~IQ@;X*zCq_(&d2uF;B zlkhA|1&$vY1NuWqaE!0ivm?~$iqzJvCT`U;3QfYBkloH z(aOsKrerzp@GV@!i2u9IUk1y;}D*z-Q{0WhH8dv6;R;q|2 zl}!dD#h|5K55jab07+*a>#hQVAj0t|hbgqSJWIUz6+9qL6p?5KM=>3! z1|*PJY+7o>ea>mfn5w@JCb%93QWzR1rATEwzyCEObl5{#3s#EUWXZryZiZ42 z85_>t0B5@^ok$V{m=s$4?C3oh4g>@sB~KMJAL4A?pfZL%)ZZF7N~}aB&l*`6cyi7; z$&s0FOar;kc_iCN)5Ktw&1>I5MR^Yl>C~bNridkx8d9&@F%?CZ7R$jP6Er7@4Zc?~ z&nD!D)%0oXjD3_z6E~7*VhMKCkZh>9Iiad6jVcvZ4MhTV0YzRrLL)a3JBT8@LD?Zx zS4hqGH;qwrf2xFH;BW8+z~H@7Nh(%~N+J&jqB$&OV#1*l0*e7v3bR09;9$WF$ib^T z;5lXs0Edtp1gbg&fUklg+!c+K9-+oOaH()JAnqqD8WvmLLSgVcQr<#ch!!o5$`L1s zY1Nttq~!bi5;GaZTc+W%~id9Sbf1)Gcb-7Z= zm$t4fXbL<>wjG{p0#{Rp-_EZy{VJ(T-)gqE7$*V*Sc(MRUIbQJ#Xe$<7@B-6yECZu zCx+-KYlA`x+|YqCr!XJ&un)MbI}Udw!;7VUrj;~lxXRbEO+Y>{@E~f~Nn(=cynJq}^fGxP?=kYT; zzg{DpB@|EVWyfC>ZMO=UBvD6580Rh^7gjgsZBV`+kH&Fm~Nu^I_piXRRUaQ z1yl{QMFY?Lc(2_68|I73Zsq(E@~+;^dwsPsr==F8MW5-`Kn8g6QhdvviZ}VGFriQ2 z?>xn~?ZL;}$IvW~HV$|8QH85tB#=$${+Zbr-Z#tuCb6#Pf3v;rmBOVeU3;kV5p^_9 zs{~Uj#`pA~vs+Jk*b_D4GfQ<0G*+vs2<#vc608vVT>kiSF70J2G7#>KiitnfV<{-; zM)Z7WAE%??b@nnlhps$j9agG3@w-ejK@o8H=iC>QhK9?eI79%=JhwtGOJ*XHF7)3Aqpr-97^U&@J94od7j#?8Q2~jE>b&` z|DwKk-5ow%t2 z@*yiCXr1*?7YAE*G~V!G@L$j4DwAB?pD1e`h~(so%FtfyK{7>5j#dE&U_wcx#6@t4 zaKpM?poi5$i<%>2p~HxI-6*M2K%^}?M7c=sz`=2Sd7yH9RF!$%a8}a!`4Chv8hR!% z_}?3aqIvz~L0`Pyi}6T!bVo)hSmm9c)${dW(HK$aU}B*l%IL+*3x*)57=`Rpz>ctx zG~|2L5`aP?dd1MhN~#eg(JidTp(-DRmMx#=2+*{?C1>( zpHgZg3K`&=Bs`zXC^yxB+r7|I>MJj%?In}>(r_-JfJa4DiI6-Bmf&n1kS9Bm%g(pl zR7hV6pHo&xsb+I!Z2Brgyf3b4lodK+!SH+OklttRB zrEas{L@wJhlP}qgHjx57=8eCjDo)k&QA_^|^l-E|qssTuii=O3VcBbJ2tskN!T)zS2pXHyw(vk=L4Y zy?8)e%3bqmu7J}kW06YeQe;xCzoujAwGdi|@DrI4(Pz z$;|7fj5>pqVh;}2{a{zYDa=3VW#&kEmvVUWJ8r{{bD1hIxf30Ty^fS&Ks%1^#d3%K zdjhwIk4~w3-0MT!!x8fKtY?e%mf5EKruzi}zs;X6eC_SSOeJ4~03(kNUVxI!dYiw=%ULUQvNDCN zbS4wC*I8?b=WXtQsE8b&wCz=I!5A=(&}p*vqx%OEpU>3;!ucbF+s1OS#GkxvheKkg zV#h6AIv*4cQ=^?C%dhiZ_ynvE^Al~95^_E7>j-F)`JQt>AhGIjR8tQpFK{{OyzZvw z6~uE1c!*7R=BpNRF>^*iMg@Uwf!aXyl2~`={lVi{<+OzLemS0nZ*A7%v1r_*MJckK zh}O>&eqCkcE#%;V&?mEtXr+)*DkE zmy*Tlsb~B_TTCJFwErY9#`p2B*drgqp3Jz$?z|p4nli6kw1!&*+L|BIvN+%g zhHuZuSh4>rWKpP8y9!XK;rF$C1{n>SicN!yT|Iv}3Tc9wv}KS zf0kdFrUbamBvw``@cyX(+=-}(7ca@#1wNsE;@@`aP>swHs?#Ua(eq_a~7#G z3+Zg4XpfPQPz7gts&qJAhRhC*W0Yy{;C`{W3Ot+YZ@5?>C9K6T7%TaX;Oyo#vBJZB zw~|Gwo*qv2=|T7GCDerB?_Gy1{+WOZpq#f|`@ye&k%{W;C1o`E{b%@w=FR=NmmYQB z$4Jb1;+IM9TtXB#U1S%fI+`zYZyC;rx>=YxJ$&!gc(e%ees+AP8n+pB%E?yh0~=as zKO*VE%LU+G87_!J8M7knXziL=Fc_7~SQO%+uB70duvEEQU+*>^c{qDmU6MLJH;$d7 z>YcwyrX7j}Cd*X_MDI#A+<=v(7F%K`vL5&@bgy#8**>n54E>^}I-s8tWI zg9`I;U)-PJ9Bf?ITEAMDZ)#BH?#AgcPwGjm`HH-8+g#kO9DD@liN`u!!&O%)FRGIb z48`O&ve&*6$4^od@Ug6bQBbcrX|>2$9iSWUW1nwutgZS-cf6)GcV}*1xN=ggTj=*lTC>e{rXYqpkslelJ0%@ zZ7ifn&>E;1<0MrP*LbXZ7nOp#57=^>F$N8%F z4rbJe^aoH}v>D!E%zMy*_)Up`;4UWMqvv8uOYqH}TpZ6_)($5)A5ZSfD1Dh+eTSkK$Pa*@~N|cx9f;V3Nz=FWJE)Ua>2&!3x@_RCPIkUy16~@uvbFV~r(Mby?!N z!!j)+-A^Aa9TlCAS|w%8aN`Om#Q^37Vs%iD{{dJ)r@wu=x8=0(QTuOR7f=#B_8A0x zey{a}_{E!IbsUPIu8Gffn7hwz+3{H?igVQ{Hd{tP$`f+v`V-B^Z0f!`_KFG`Boy&J ze)-`W%R<_W{BHcNtkX4cPe8tH5kLX1!;%1=*Aa&oo=yibW4Em5n zm2Ak_EEi#O#xs}E8@etGTXy7JcA35gjQRIQfKn}LSgThWNPx#IgggSp+*p@Y>Dw>Y zJ;(M#1+G=AW?)6)qjoEk9TuI8*24pUTP%#*mD6_m*3Q#^xLk(=r#z~n*WsI3$>_A` zF5|X1T^(qZP+g;qhz{>F@C!%3ErC6kyR|hWq<#6^>`zI%L~F|WXrt{u{C1F~EDrZ;oXb7-4t?-gV15bfxc;O%+T#qp4Xb$G}2t9$e~vNRY} z6slCvppJ3Wk}ip&fq;_AeQypt*0x8am0Plt=P~;>k?yWBzTFOWeFyG5!`DFU86+wC0?=h-gW)+5T*H`={jq*I66lb1qq4JxfCfUi>H zJP8BUm1?NDslK!^ea*rXlcyvO8yEla#FTLpPEQ+=I{CeXaeZUQ4^E!@X2it4 zho?`>_rg71qeYoq>zWe5MPhQ~~H^=kv>@HEu-Z;GCwVexJ-?C`HuFu}xvU2^E zl&g}a3_rF6fSS;A9A|D8d)WX+R)s;YmDh-52pz6K;c>M(t}Et&L_Ms)&?L@A$vvZt zIsY$-Jj+lV$FVFcKY;R+$RKS21VJ=q$fPLBU@*vBTk<*==C9PMHZ^!(VOw@q3 zPor8$j$tv)2B6YVNv7gJmssF<0oy8Is`E21VJS0u$xB-{JrY@0G~J8*dDAxx7WosJ zrU`<0!31uReYC`S>TrwBf)2+l_! zzWg#8D=#a8&MSh>wlLv1imU&Ae%$Pgzck8A3o9N!tbF!NM``eM6KKL9;HQJ-%K?0r z9#zbU?6dLgT}=I&RtL6=bDe`ShpgO-h+zTxED!MtPIjCdf0ahZ3>=VJq5)vjvRHvM!#CZuJIZN-fkZO48e(|Ji~=M_hC zIaEZ~2%y8ITxBY@y_>Wt^);#?}`}_dORzIxISQNQrjw3}DKEYdu%R`c3{J?YTfm#)c|H83VjZ z)RQvjh`I{YbtI)2h-?||@tS7ST%+U?eUyI+@vouMURhrS&$9OYGYBr3JyU#x8R zM;5g~E{3YQI5}baI|EiIY)^T;ai`;ZXKgxWwDLZpusPb=KBHaWu{Ji53dQ+0jyDu` zj~)CoS~#8XY`@*r{m9_=3y&QDZ7o{7zNQS6%IhmvZ}Vv%;^YE1rNg>zzS_iT?2S>7EZ?ObBqToe6$lG}P^__*h|yJT5gA9|(vdjGcD1`ZKY z^Pol#S{?=b<^BR5psaRB&v*B_v^&z$InS$Ys)uv3yIX|9F)^_3(T_esnP|a)u5e|M zl$X2Lvt5e4|D`rQnF_~aw(i?}eV&Bvfcg?#cfdixv(#llJKA@Oa`isr=ykEV!%tQo z*)3g;T6^wn-(9$PU20V6<)r-MC!wCcC*6FL+BhXSxhA@L$2tbwnY;+plu)k%17^Zw zNZ<{iti1E>sskRjX|8q|b`B}_t}#wNdjmQdPMyN3e;U^Z;yw_@*t{UOE&ShVo`0vv zIBsT005guG9&U+6%xr`XRJS$PW9}T;oU?vq+QJzbW5#C<{Ur0Fk?F$*Cw@F2ZrG5M zQzm3D8x%cz=+T8=-#ByyY94_8@T1(Nhc}Ho^tJo;iJenc_Rd_}?$CUn9kaWIFMsp! zSFi0^`NrPQdvE`2QtY0C1vj1ohl@Hyb7|Sbb${R7`AdMSrc^)lO^=s~HGdLOy2CY`x*x1+<(9JeEK@bLm z!TcvY&&!)Ni}}c9ES6!nDPGHmWZtG;ucs)g>G9}vI`i(#hb>7GNs{n8!f~8Zsr+ju z*560u*~Ur6wN5BAj!Q-y=do*C1F-vSQQ)EjR!h8i*)+>%!d(=&H-E?A?y)& ztj)Du8nZGszXaey9lZMKffi#TM(!;vz!fdPAx0M!z>z{qF*n3<&8hJbSDyeXRO|KW zy6!8YIxPx+fZ-Lz95_*KzePG$Lc}jS^Q&4cNq1O#IT=G_wgEt;2kiO`i{?b;zmLvXWeH$pIAC9Q=4VZEO=<9FDuY9dq@$I%5G4 zsFhCkiC9(#>N4%w8L5sErmM086D{E=x*)5yn9jPr!x*un0a#I==2WQ9ygq0-844R@Sk|b${U7ZfmN|{_|v=Mo2O3B!ZB$~fM z1yMBHs8pLjM{8A649fqoJVmnvNn=t;_{A^~lpvQ|&}`Fv$t!Bfn>Bx;H;}&w9mudQ zFNG-^8%?7J7JvMoi>ZVXfe3A?TxH~*VwB%R^O42%T0he;dTW~FtOL!KWf_5c`9%cf z2+i|Rh1-e?ie+aMK{-YoUz+jHd0>7M$4g7g8%j#5o;|ND(=j?g09urPcCdgCZ{W`s#rH(#?wL-}|qNjDFluBEXG0czaeWyDZ*sKj{azIbjnHT`9&rVs`;vU7xF1oU2%M+3T|uw^@7M_$;n(aQI^u zX@Ei&7KbKx2|D1l;<)Ro)Giy(`^^u1@AHF?81(I#CyiYuerdNT>g_$ZALD*yV|NpW zNVc>%GC%^Ok!Tgb;p=+8PcsANq#nt8rZqk95^6Pq;8O*Ti%%)$r@yhUVBnUseZM@e z7{1YS-qC4Mk8cWcun}tm0T)Hn%7$w>Pmk@}{dUhi{(k%2++)3blUzJwt!xu)oYVa} z?6$InjI5Bi-@g0(k9R}D;=lR^>NQB$2qK5YY$VHe_;1fE39|;V8Yn9*-m-g_e~;}> z0e7a%;|?5x>LO@-2D+!vcvrfVbZ*Ji-2oo4?ymW^4p*%0G94YFJ>53>dE8$2B|N!} zz>ZcHok`8zzv)`|)?0hOf3$Doz0F@Fe)v|BheM8&O{!h1lMYs~PS(-BE)6Re*M9Rw z#nugvcW=HGvh!NhK@{5;aEF>+3pelH9XVl3EBjDS|Ae>xadzT({gE)JE&$DQczzvj zoYrprIwjEWq(X78nQgwJMUso>4mYno-QIwbN<*kHVs!e!DsIy`hI( zJi=PENb~T>aPW?33eTkg-vG7G#Oza{e*Q^L?q_V=(ySbgI61HPaC#KF z3H0Sa)M>I(Vuuae;^3a_-1d@Vz=c;_E?arUDy+}F+5f@vRS)-vfWZKwh)USBYIyc! zyT4Dom*;U?>v&h&7*D6e?jDzB%>j)PB~w|s%ZYfD8XYn6{qL+5i4HCE?b=*uZJXD| zCCMJ+_=yx$@XxWv%F(7c{&xm(bN@ImllC`h8%G!fj2?(Pnx8jkZ=N4DcVY6JIq5S# zIXU8^^uYtu2M$j8@S~H%K8hVZCVKMxlPlKdZu=QZib2zWT0=o+Qi&D7AFH}PC2e!J zO*6W0oBxl)Yq}r$(r52-x4p|<_OA*&wz1>BwJs}Xy}#|-Z5Pi}V7~z4xL}5IGk=3@ zpJ(M?IhvS~boxwEcK+eSwA72Yj-9@IIPFs6nH$GW<;16E^8h+Mf#?ee9Y-1DQd0?D zkoZbX;IFBV-&9^&AsUQ8EF&pF(&qP#N;Sue6wT`Ngqgzuu~HC(k(G$!`4`5KY0+xT z7)fxPfo2ReBfJdjB*oB}IfW@TRBXD6QhPJaA1alE9ovZkWEw6LVGSgrkkag@f@wHS;DfO`P; zt72Mym8qDzt?QQ&o#uSgeerki?LL0ERw$J%XA%O(hjd$z*>8CUijX6hl~OY5GJqo$ zV81xbdVa{%@N-XblX#b@YyB4nxOG9KR$$;AbZk^G>>dcYR_~&76dy)oCTGkKZcB$McAU$(y76 z=kN7g9yd6;bY`Y%(TOMP)9#nyrmAyK8s1v4*?wul2S+7Fx8oc4un(WGp zB;wM+mD&_$?$*Gw`;GBOqsM-{{nZX%zM_b0>z~u9({XE?XoVu%-sy~o=W$!xct0QI z7pve*&XLi>@9o)h>%hUtm0zOJhJaYk%}FkEe(g8sl?Z~4RkN%L7(%#r|EH~cAMXi; z2M<86#G%JJ9N?(}zEby7R??E0>)ahrv}$(Is%4I?b&8i~h_}~{H+sOuvp}d2w~C-+ zbydLBq1Jo425O(?2hBR>Y?W!(GTF&G&du(KuY3GI-hgWtp{f+r4JfNl8#rY>$_h!W zfhAF2HmSV0W!>KKqaTLvgR%nT?CUE*TLe-SFh#%?!{hw(Ge(9v*{0dpow0SwaQ2Au z^4a3=56_+;_@hyg04taXh-%bOtD+)fvOXFb>f)5>=9bjT?v%54n2+Cg0sgy&4}z*f zD0u?c&hPhdi*t0&baFlA;27=czBj;E6}}f5%AxT7#YJ=Wc=^OS`{vsDdxb)&K4|-ejSZ z7u{YGW(y^OQ-dz0AZ^~!d6Oe2Ej%-S=Gp0^GDeO(J$B^jiDObH4UZl->fprXCq7Ru z$*cvH8Yn$#J2V!~k(`m*widXb#PZD-69#Ts*5%vTJww0j7PY}6Y>jKgT8EG?eL}zU z-~2_dAJ%-lX~PYjK`Y}pW{5T8xctoOG4=hjwHteW@Nwt9gSzw^;u!e4ch3P1ufE%^ z|0f;$kLuFzqY+c)u$YYsLm4_5D9CL5is2()Ak<+KRSd1dM8Wsx#0!fNKr#-scAc zmmC?m{rnAFCMQ$35jYu90r1gxk)CsQ`z||@kL{2K6GICPaJ^jr-pY_xllSymclvAz zOVA*bkt39#F^Mah>(xL$2Z>3${=D=2$d0qa6LPLfh&GG?L67LofZG^>!*MVMF9UFaR*^-z(Z|-n*2(h=xf8+I|R;|MnicDLZ zpS*p}*x4qxY?f%>W_K$^e6OyBU#);^`Nw8X&HU!u{GEGJcI=@WRc7VT^eOwzdBvla zbCCfCchvGwQ494dWR)3IT4fo4j%2DyeJOH!NF{mx%(iY_W38KAb+$=s`AV#{^-(Y1 zAAJLa%xtKu2dorvh=LLg4JbrvP^HeAcFfWGv~A0DH^&%Hmk@v7eZAj+=f$AWfm(x? zu@D&sm39z<%x}gcE0u2meJ!#j8tXu(LVSLl1|5U86qyG_w{Ndn66)mT5O0xK`5#k>SG@tUvhHU%+#5ql1C1RA21?&^oZ2SA4ZKIesuDpl+Qx%9KNi& zp#%*HRHMF8lDYC|fuW2`@aQR;LVi6{2h54WpJv7G?!GC=bIWqKur+q!Yi&Z;dLR1U zbMqJ7HmrGf?bkOAXaOA#FIt2TOy*xUHjL;nbN+;dE1kRawhrjgZQz&=?~Vv~XO!rCO#qmMuQCR0PZG1(9j;2_Z;If+9@t zjs15~elOb$yvc;1IFS*MeWD{No)>jG9nbUT_&-h4=I8;-vJ^!%&Ak8B6YM`)aK(!O z5qIGfc@rF$@LE~~&rt-fC|el+(0O6J^O{Qt$FT#h2+n&2A$V4cWv5##JKZYybn~U@ zEtVl1Z@wHMd#hFF+OJOjQ#k&(vg%Gl^~Ji%{5thxwO*v_5oa1wnV;U03PaL-1?|qi}&^aGUf`8?154WmxU8TEw+C~Y&q$-G@||L)Ty5e{FX#|FE|vF zca!5O-1Jd?A2-GyDd z({}E@nwwiyRb`IXneFG_oL3@91j8dPG|?1;lZVEDV4dNRpQ9$=c`ejY@Tewz@aRNW z`+P6Eq}I*i?Hmrfc<=G=@_b7uRI5=(wgfC*BLz{u5FDtO+^KU;Ik}#-w#smHigI?{ z<<)j$=N?c{4z)U?og|ugXe49ZUv{S&zmL8WJ{jb8eZH3oSj9n>nX;em!HtIM9|$&`<$&MbN0m0RS{7%2n{_*_O7x37#G& zty`uzwM=%kN_2F-H)RHDMJIV8|KX9*^H;QRiL`R9_3Cg#p*Y)Gk>k`R$Hp$*&Nb4- zcYFJ;^=auSOo7?}q!&?IL5}zSMmg5sN)TB*D&3RUS1_&9%AiH`3^mXYQxL!4)Z(d` z(?3f7sCQiN!5PDb#!Mc4bbfI9x}@^lYS3sAYcPlU0t8@`TBcDi&mzL0Gmwb+O)}_2 zQqSXf`$f8bVOC7%y=z_fudxnWYZtM>`{-u7^~*bcvwFbVZ|<}3T+3n{XC>pJV8#F% zft>{%!1yI!`t=$7>fi~Rqccw4D2lsM5Ow+a{*2oJ{l|9xU~K^M z5ZO&=TJUBr$g%k2|6DMR>+yxXcInZixHFC&)n!T^(euQ^c3}-@kX;-mqHWc4IA3S&8=%LE=oWm?2imx8ckYllY8KSd$cGU@w)Rn)UPVA7lRs-|imPXKi`FTvY~pO(j`(!m z+w&dNBZk$V#G(FdhBGnVqp%ah$h~*E2JyUyL+eI z&h3wTbWL~coT>0Sqj0}GAQIs4pj3&>Dd-}34hsc4?&=zhxD;iR2YyuD+bwfzO(j_Fozmt8v^SF}FmV4vmT zdfLW5%gQO!+9RU1%cXHspx_DcDjjGlfviHSzM_&O$xL>r>w|#<#Z<4ijij!5E zi}eXd`)3m;LrpE*d3b2(l$EXhP6WPn*17F1g`&8b)!A0fvYc$PZ0*wQTw|PkcLf-6 zT=vI}tK14Q)4oKTmdE|uihx0r#a_8_u`s--J*PoDN2;j8_+bY=8F6yl)N8W`=MH`M zjq{P%6`vvWtc1VVM`|1osbn}ddZJaPJlT_Ha|FQoxe@-BQbea_n-3=KIJr$Lc8&?25GxOnsauyIrS z4I1{&;E&Pbj*NKwap92B05pKkDo9p>EsFQp^E~~ z%50F5_}g(mi^yW~#|`M3NygSQxzbW%k=ZUHIxp1E)qC;oS3gT=F*(F}QH=AV7?*`H zZVRK_7ant8c+_LTQICa(y%t5fEjZ%7@R;Y4ShvM-&WqyQf|Gizh!CS_b`3yk9Sq(a)p6NIuleg-mhM(e-O*~+!9MHq zwq_vq6`cF710Wg!4i-Z1AJ4fjh;W*=!*|*by_fFlGGpEAQ&z>~UXyuR)}8pN%d9OO zr~i0WkN!&nXmnc4S&Ce<3JD(ZFl^1?Uh}rTHg9M51tDJJHguY?DR9CU*+pax4zthM zo6>gHc8_`C_Hz%mT^=1UYfJZ8->pA>u0%u|ECks440>(-x!s%{oo27;xnzy|thHScYaJB3>q2=oHX)Swc(ed(6Yh4J6XHL8_caQw2*cv= zFX}=S@dD*2D$BviGlzX%JLS|i&(SBXg>|m2eU`05j*Y|FHg@?|b{AXQqJk)E+Z0E; zcyE^-F4mc&2f?}Y@`F1=CyltgW&O?ld!m9r`#CbH_R5;zVfg)(m)Un8zh(s{1 zqg``|>zpAleY#HWgrEud>GltSJ-=_|p636?3H!E3Ua?K{4LIuIa@5Tx!Lj98Z?|L{ z+ax>p7{`DJzg~yl9fKTa3bhW=#ue*0v=Kd#@#*}dF79~_ZdolI^6Y&RZT;e2e+P<6 z+uJGL!TOYyeTtoDjFV54jq7>Wb{UE`KfC!{Xk(LS(<-Hv zBB4dIZ2y3ScAXzD3WDke#8bjDB<^`ci?a~4F^jF1;7-K>-!~%NJ4QQr#M#&+I$Gxh z_!Nx#7;-XW-g+}Mpwm&`PLZ~rCtEl@a&323(Jb4lWsaj=maW5S8`oqT-$UMAwaKZ7 z^M_^;S+2~lj;0r~N)4z==C4*p|ANTGDR@0)fqD^b!2CHVeWE#dKYB{i!jDs?y_YD!@qm+t@Az59TOTlVDDva|xYcY3?~2jktl zf6%Vq7}wVZb$n+`r*}sA^>}~U(yxmf89l)1TLm6H2J{{__0u(59yg-Qf*Rm@abws1 z!@3O^;n}UP&+Gl?*1qrXVROHf{gLC@*I(^7v`4=o-QRxi%!MnpjY>Id zhZH+nR+17(jfKkfp9r4+tlXt&E~=D$D=^lwqg6<12r=RO?U)M>cBWnn&3n8*@9F-$ zr=fX|n~XNi_(i#n2SEYSkN0q9C+6qH?HCb0pHdYg=S~ME# zh`Ktms+y`S=PL>g#g$||B~rXjgV2DNdoIwsy~#;YmoFX6NSBxSMv+_W7V;c}3M5U9 z+fOJsb*J$2gYlmqP2G6%%Fe6@x3tFfO(dWU`VtAzbBp!3RxSL}y&qG~tv(e0WkmeG z%=7WrZr!h`mA7-gpdvE=;r0_3s_}fQ(jn_qL$h*Nsg{9a1026_KjG@reQDSBXWTq= z?qSU3XCY~qAJubp4Ae1@d$Z(l=Iw|xkG7=V*njrH_SDOvr?31}p;6+ZHZ}Ijf6_w2 z^`fou>EDFMY=}OwFY8*=)yGx%*_0u&frsmrx??v=cV^wbTdGlNkR>7DyQe4M&NJnS zy!)rlJ$YE7=L8cEpJ}Z|bVt<;84`EIt!tWNz-b%zOnb+4d%JXdhYUN192=*zZ5;Aj zJDjsZ?~@&!b~RT(=$<ci!6>aw7PPuuqr5(^8;#wq6OM zym)w1+5v;X+DsAa z+%n0oMYgNMiB{Ih_MXR`0uTE1j2JKms`NmMyeJU3`5o6u`~!+nA%SSzIXZDI+BHs#H$H7V9T7g_txdiT#{>M*ojfv{+h@0S&U5pP zc65pM_ucF29OmjCY3*{Nx$AwG?)Mx!XS8-ZV(YTET>#|gfUXv=E}}=lE8uEtD$s;P zDN`PCbvKeFTlPn|w2f_TALC$m+^*$CFUNczr)>&Fl!slqlgDY7fCQhwnONc5$e? zv&*n`O|$kn=Gj>**SV2s6%W}-l-H`l)b0NTIF4o>0g?{Ip)ii4oC?Bm0(9Z`VkRUl z9+EPn|EW&~r;Hw$G+{to(A-lykeSEwC|ScAG2C1>0HQo=C0s#(+dYsAK;R9cmb9?v zkGgE#X!ZU2R=akz*tXO5`>n5jzrE*@FP@_H;1O4@iQ8H>nnae9bPQVfxSoR^?~m`? zZ@7El8&AvX%9jO z@~_VM`iEX4W+)swbb4>x{O|TPU^UWn_-w~+?>oOX(68_4ZbN4zU3)Gs6!^*V&2734 z^yxp%{TA0j-wN z(dcvndJXY^dsOFvGu|2#^!mufeaA1i>F};yyS`JGt=D6%8+G=s?>nP?|1olG@b~oq z4>V9n!q}koZm+-JzW>Pf{fD>h`;iIvt8Jz{oX-(fBt zd&i`mEv?fStK4{oC)6l=C=&Sfw^Mi)!6LKP8`qwbSLT%qED45Y1m3(}P_0r!iin6z zD}qWwhTySo)AF2yNrp_B^6-JL)J0fK}80b)duxO<2JK|)A? zxZ7lAGA`Ta{?_yCN#LCKe|viVe|_&c=l#3aUbCjV!=A~^-p_T*bzfJzC$+kbhtE5f z>hx3*txO|U19CBwwKc73RfM>WrKb7hpI3?1?MK=>z3p9Ju^OF3OoLnpd=x4q+w)Vb z(MThjk_Mky0U+W)hCc+VG^_L>x)Kv$n}P&x1Q`%?oaUUwROwX?%R%YKPHhXk8g2U%Gq_3jyM z(kaoTOJv6`ahBa5SoQI=8x*+kd#G;(ilKCL8;+AeDM76Y`}OA=b~aH~)-j!oQ%vn1 z8`}kq90#@K$gow1f=|GPU@Dzf2Pz<1nWV_a)5l*hFt}}CkZac`vrG3_1M{dZ-R^d_ zxM*p8!KugPA^m*Dj=I&Yhi_NwG*jmggD>JcTHiOd^%&3x@^b)9JRoi%i}bZXsaEmQ zzGx^?t^IKQuJ?#(Hw;X&dkv0o?B#1|=JlCDTtDZF)?I^#^a(Pw28xDxvWqcx4zp^8d= z)wLeOZ#(q!vvYW8YZYqN^+D&)(;V%CyBKM z<5lAyZ2K3;^0MTW@f zMGcN4X7m{O)wE?Bq!{wV0NYP_^qDk!z_j__{I)}amzQz{B>@P2^0vpsB|RoCaTveo zwEz)bXRY7MA90?#ymRjfPE(dWepgTss;j7BbToV==1gHF;4&};0R z9uwv}Ph0uuMXlAC#XYC4vKjgHvFrXyo{y*0@<9#1Ksk+`+u3RS^zZkg+(!pbYngFN zH}xF5VCAMmGPH6+On$A^=y_J7=l*c?3NK2zYL`p5vGeT5%(fme!)fvY+mT-hbm))D zDQ~eG{k7qMuT~zoaxO5v=j3IU!)EoFyx1@LiMp*Ph{GR-C3x-@{|o$;kN?5;-{N>X zI1(I3>EP{$(yAuGhnl*=>gKoAg2F1{pL(pVs!_iSf9iQ9bl0`0?N{S}_lW=Pa>6FJ z=wHu-{(2^K^O?t6UC_Si+~Z$dL)W{6tv?pF;dIotD{&{TJ~~q`Emae(yy!bGG|Xp2 zYJg@HB3&T%qe`Vh?v&Uo5(_CY$P$v1DWojoRVmv?C)5<0T2xD=v|NU!p*0lfsU3Pm z*6Q@HRB5?ZiIOB({sp8?r=d{2f}#kHB?+xUr_+)exef&j{M&t;sg%&$LHogu$TujZb z4;%Js?;gl~`tJOtQxm4B9!HnCUv-=Gl_D}W#pQggy9W?7Ar$hZ*-s@g^|1t{0~HGj zM*lx({5ln>EG+$gz{q1`zH%8j)^F^Lpy3l94j!F8WrmN5S-hE1igA}jW0OQ1hx_I| zF5C7^{27afGmI8K!ErP|hj84}-X_AvGQzNHg1K#osg3`bG0;$=LnJngeR9O^CDH7p z98{8=9b2z;=$LEMGo!P0MhDxhu1=4?unq4yG<(?^iT5qYP6BBI)O~ofebdcu4kcH$}OwDjk#?>_LoQ?=)JF9*xpCPs<9 z`bJtfKC3=Mxmb@ zBpRE<8d-*#*#+7_NYtt#(x=WaaVW_$J12bFC9(|hP!hvc< zUT+NYcGcrJc0~VA=ehB!hW|J*bj9?rWs@JS8WXbR z+Xy!iVA3B&0mo_DaGbY2#S;#w<3M7+KcX$7787W!Q2?}WY4)(wo1ESETAtr;;&#Z& z^_bnky-r)V#R+A64-Qkx8I~bfhTu3P-oiJ+9%jF@89Ard|#bQ=O+Sk9bi(YUnZteNltw-$Xo3Ny zlx-7v#564cl}6oGq^7Y^p?<(r$M8yuoQBZyCl;$!Jc_E78bk(G68uMG0qVpeu?7K+ zSfP+ek*6D}BJ|o094HA|t|65Ktz{5phk?J@Ne(nLrzRPS!#@oNYLX)GXcba;U^%4Z zKr;kM6If({KaQRDGwgUX@uh{b;K{fdfHn>*qDcR?GkHg8E9_dGjid-@I@p$ZNLNeeWV*Sa2e z?P?s?qkouz*%LFTN5*!S%q#*{E|9)T0uZS|CI-0-G+LHK3IHV^-1|FUb+ox-Z4zZ; zl5S<1@c9=RT}3?Q4|`@4H~>lA6zG1Rj2Lrc>jbK5IU z&UJ~QX!?WIU{MHEDA9w{e?Er@&zk9RTm`%x``_dE@`qbzgl-uBXyw$&X~3gWAM5ITT7d2|>`TJ(Q*FF~6za{9pon@CH}}x@qYnMh=g@{;N4NAp zalm=o_A$E-#nsD%0Idu^(#J0v49zlfnibLrLl576Y(H^{&A5fD_nxa#L$#ci1C**E zqgv8`?rPgHGY8FG)qqo40f618>Eo7s=QMG4nS$ZVeU)GUWBR{p!>vG zHWR+?GGe;HfJydWuW^|B?Zf=4w{qqqhgL&MG^APwY565nzFF@)W%2h1F7mndTQPJW zGtYVA{8_7iRp8hACck!={7v^sOE$UQiF{q%WAb9F;WL+QJ6R}Z$1VNIar_+HkzetV zNp_jQVcguF(^i-cpJ!k_bi|^K17>}jSA%>XL^Q5U(rCHkiL}T;hSL7eSi}4$Z~r(S z=lAlO`WCsewnhA|vZ1J|;az3ZpLxu$f7b{F{zXTR$F6WmTX7*RH%{ZDq-Q~sNb9t*ga(_D;_Nxr4)X+)*EoE80(DbTB z8uh01R!mMvR&lL{S3H9jg_ciOTQxLaQRh=v8A0=jwp2^<^>(ow$pP{bODqQ>8Jd6M zlM*dfo6%x#Zj!)LMl6V0R3e!MQ$|sXL4}Lj*z5pdg;uL>5efL)U!+u1ZKEYBWT*km zCpof;)KxT#?uJKtJ$O{q*sN(A(r0Mi2l~IviRh5k*xyZsavabsDl#)zgRlLO0alAf zJ-EL+PNUN^h-X_%Ocw`I2&`|c0BbclB}3pD>c$l5r_+Wet~d6=1bq$w(}hniUh zS=!vPwoRBd2V&yj#T$rCj{a%O{=TE+J`YshcSDygYq@=^_TJs+*RD0Cr-P&wy#vR# zGb@<(lpGf|P`Q%eS_(dtXFUfE_Vz*?I8seZft4fSR&f)wwn9#xyN!LMao3cN9g<8; zL%N!JbT#)JGC~#}i3~?jQ61qp!Q(ig1*JCP=S^OAR#Dbwk%pZUEX;$=&3(p=gr;{C zl7mOTl&+OTKL*EvRxOE1IBI1VX>A*2@Ojv0of7PwZ=2e`_+cXmMWB)ZE2Fdxw6X#O zg|99hy*{FEfP-yB7vqdCj6%QcdZCYlG$RUl4>O9?wciqGc~=w!d++LQ1tKU_(IR;Zd^_G!BfR+2t8;zJ_Iezht_&fmyK?(1E z*rc+XvcP!Q)L~115a3se0LCp{*R}5`+u@UAUli97AV91SXkwsT14j(doaraR(x4GS}W1*6OC*@-6 z;nVs~p8xflUnThUq0dT8hR$%9uz1ntqeB<`&~wt_KGT=y*2u*G179zM-+%-1}Q zXO%YFkDh5ZWag4>X9v#y-eTy?fiqVRpY!drvKD1q`;u-;$vKwR;lTV~eTn^>Z+{BM zX@LBq55?8BuiuxH)i(e6{e5$BJrv$AJ9j4iN7tu6oO-(SK>Do1IdhJ`ShzoH?*7aL z`=2a2@MOV(%(;g$XC2P`>Tu?iok^p%$BaFhu=GmGRxuQ-L4v&>(52F#1J|I)_>zW$ zHy`??7T!-Qsn$aLtJ>I?<<%Ml`N;)UVc7*zfMSs*IluH_%CkldWE7Moy(mn1^{!4y zmxTa5~yh@!KyiUl9&Igxcqrhsff}&|4^O$vZ$z0o?cif28b&te_Go7x=h&6 z%9YeA3M#~}E5*mX0z#h`J#Uh|lhLmlWC3y6p-FjK76>hai1rN26Jzy{9IJoMav1D6 z{c$}V{2%Nz60y+o&k;rWb^h&vBYXgNK#0GLZQ?C#l8kBeO9k5 z@Ve2IoP-h`WMqx_C!Fphj_XC4l`^1I#JhLCyZ4=6v9>t)AqZR8hDzWR94$mQG}{Vl z5fm4`-n;*bt$mECSz@P7v8E^*E<=6S#%7uH4k;_>1Jw{ z_xolLiJO(W2TXDuDMZ~ zrBS%Oy}P6H>pMO`XsP;2P)SP9U$|)1EykipdKc?BgN_;2cAmyxKAJtYHqZm4Wq@=J zumcLMg0g&%LEZ0mHw!fUJfm}mH%7)epLKcC)h5!m_c>$R_opu)jvRrxSfEP0deYmr zORD*o@g|+o41yWT$7>QXjw9kKrRFi~e=UylYM-!=?x0DNy%sc{2s+9@BoW|gkj%o zFrU28e(L;Et&T6tJ5HQxH*T8c_*r!T{g!U{Z16|G zwOe-E4;^PSY?5E{Gco?R1wyUU#M%9(%w4i^tAIjBBJ#=x%wA(YWV*%Buljzq!gA=e zoGPghH{$JvPqiO0t=oucd|y7VTHIso?B3H>j9dQui$)Sukb&)7dMxcK%sY``@xuv2jaimm$Yn8 z3c~K)84C{NtT>Rp>Ol7DLs_d2Wv@7#{mtR*MMrbyxaQA4mhsiKXX_JduS=nnK%k1c zovk|57&_?XF93Lu`@WKdlipF+!}A`!5#G(MeJ+KJCb*VR_^W&H3n^^A9Gq042!2{w z58!e?F|$$;{-QcGuRN_nl36Fek&xXCa5w!$(6gdnT(1iNLY@`Y0F)8%q_VM|gA%zW z?)BRbBH8m=K~UDasJBg#ZyLPfp6$DGzd@((TX_V>zi3dt6)_bg+=|V+mGCmDROTL$ zTR?$J_|xoW2!AE;ig?V)w*1Z%KGAgn+cNcMUX_vS$!R zuoPZTP^(UV1Q{1HI!enSZjzq2&*`-l(N1$(3QdU8c+nvVT1C(*EWkjJj2agL84!sf zHS>=15Wh~ANrskBj7(!Yf0km|HQuCif^p{*L&G#f!}KnODTYR|#>S!M=Kl6Jt^0Sw zleF41XS`?4IXQgPv7` zQ8YY>4c)!{_{h;4zUX?~q4(Q^N8x!cG*^JA4780Psf3Ecl9NY|8k+@l>y>D0A8TwJ zW@UNP+`@b4(3EXkkmMTu5yvS#j#HqbBRBr;YiW~iYM%OKmrP^JNF(#$QNy93PzMqc zJM`(vj9B0K`PG{jhYq`AW0>CG=1wOAUrUo4R@Q-|#zAxfw6sD~BNP`sJAK4!(%4%L zwxQ5vJI7=h_ z*oyMYLr2~+v5qyderf9%W$<}|t>rbNFXEQZhV*a{Re`)&$EZ>5qB!sBz-|HE&B8i; zk^4o*x1CHg47$V^*<7*c_T={+$k|OQ#o$a!1$D&%cYQ65vW+??cQuSPHVrkgz237= z9gpM4w-n(x$>TU``~RyKq5sd@ALFCvVU!RyC7_+ez=x*>kQtOz^R zj99L?Y>U2PR)$Gw_-v@*&S0%qG{?x)(xo1ftZ${sbLsT2*u-IwI0(`Ps}l!na=)%m zTU?g;b3@^|=5k*^eoEymSwn+XjixVIKAaZFCE=-Q$FAO*`QvuW2@9>Kt?V&(-OuOm zu0L^k&*j@2Pr9u?wa=c{d+0XXUe?3ljm6v95Zs( zH@i=J>^ymC>Be0HrZ4N%YfSHnOOD?Nk>WIG&bPlgkDA_Z%=9KDL$uW-QBIA0rp7E? zZ#!Xb&&hME)GSZy?LBUa!|2JQmVDQYjT#s4KHa6?nEun}_ZdGmzp{qJHAYV#znM!{ zbRRUb&-iI0XD_Kz>1s*LRV!<>8Z_2n#KiA+?C0sb4>I1MuJ`n%&QliK44vxvIE7y) zr2ze=%pWy-MbA-R2{~w{A-_iKJa(4t$eGKwoR9!KtCCGwwsFwZMb>>s&G_cK8lh57 zwQ-4cZT-RjMmO@Wt!?|q`8cW5we#Fct7i_)yzOk$UYVVicI~KS7K-^D9QrDfz zU3V()hl80b_hzixo3Unp`r7^JYY(KaIgq~MQ2Nrt84FHk&E69}(Ia*JYso`7avD)F zZ9LBgEnImVpHf_REj&5yO@&uj#EGddcOO z{5MM2=<17RyF}pjIMX|$@IgVvkM5qe05`K+}8cqkLtUhqDy>E5mPGmjScdg>!OmOP$wD-?j;bQ!o zhb4;rK^Zjw(Z#A?&IIkg8tI)$N)$j^{G%4&2&hXC{d8U-?^GbMDu0rxjEY7%5 zfgIQN2$DlOCKOsg+K=;(i1emBtI^{)q8P!aP!24`RJ@Kkxao+K zy{oBtfU$jmfoV`jt2n2DY15{^TEC`v-{$8VzYQ5Z%*)I?$j~Cmw&(pXI>kEnxZkat zo26yUn$_^?1!!cTk>H_VMyA8sa4d)NaWxbAcC?H$w7%ug14QK< zE206@4h47;0DTfhmHTpwx#c|@!!RR*aKq1{jg2BrY{D&iMLLa)A2B2St0jJYM|c?7 z1X|dq+w@2?==j{gpwZYW|Fh3unVLNQ^2?hhCf7%ge7JQBGX0dd0-=sPcJ!!I@4Jq@ z5^Zhc3=A?14D!u8BpDgpwCMQ4H;43m z$otsfBd`^?}2jYtGWrKXewF!i7npi(x&Q>N7%DMted*q)uLXiol(Oqma9Ga-3A z#14X}J`g<^;>JV5LTSWmanb=Odj#rIEZwTY69GKM9qH$dG~Ay_3qL{>rnX-mxd zkF^{$;nd9_DL`2(>if$8M$K8~Gm9_3b^3r2jtM?}_Ka#Qb*pu}~Gu9nV|NeN!cPBGe zpGaGFE`7Oc{Hl<=W7V207Bz@y1~+=;Bq{;6FmT>4c-Q$$4^p$mI*54s!8fNWri#0o zR<_wI=5B8N2DhM>GT7%Gd;eK=^t;v?fL&LELtoZ-#pR`zw4Mow4S8L%=g$2%8rJ1; z^m__6U%Dy)ICRT9=50|xdPd-rObI}vjydalHy|}B^!dx{(K+{@R(Qp~%xxe}-ir_b zlqgV~x$olL%yMB~gZf5v&ZE4_#FEzdQfW27lA~8sTe!?7xEPxIMhGEUl@}i5q}Px) zGfI43*4%zp<@37sH;)I8@|$ia6lK2`>2x3y3Nd$`BNWKr3N6N3Eq_EMk?}`>VcPyL zrkT(|1KgYQVgR*!X2NHSdxy!yihDMn>Ju`Ps{lYZO*dp7;Cb2_@ zlrO(X`@BQO=U=3K{zYPk4pE&u1siw1Y1!4QxBdA64hMVNof$hce%o)dhe7Zv4=O%T zA^wlnuk~8FH2Ub_mM7_`t}c^e9M}C994Fq#`n$~^^XnG|e)io;M@}xZ?vr9*m}Jm3 z#@O@=&nu=40}E_?ip(87}~`q>T{!%&$?tAbbMl9koo23 znMPd`IvWOdHo0!!hJhMix^R-v;+!--n|X{cEw3c zvp_rR1WT*Ljz%$G7>1eJ-LQ6uTmKXKhBXS1383i3<-QI+=4MHzR%r%?FO0iC=wKE- zVLD`I1Fa@dI*DmoG=PYxyWsV}%r>K|=@V1?$WB)AR{hSKIW)#aF$w{2gsvUOv1%=c zDcS$gD`h*56CZIL_m_|)5FrQcm4dL@0eeOTZ5|Tz+o+IDgZ(!4z4y!40s95mHI&mK z!g`5DT+S#JZG34=)#gb4il$4XY2R}x;~{w{BoBb(zK}2gVuwN0BsyXdle`^X-+|_* zpcbH;g1`nXmIpagc&x&COk;bljCf+Q3F9SsVg>Yb{aOm--wBm<}SS!7#*Ek z)QZ*G#S~f_54c?V;kTU!Pr0dR{pUxY0f}RwvckH}`@h?CaMSj~NT!(N#3I?Q-3Pu| zz5bV7Cxn!K@V2m8dg{FAjy*@${_xZ09lJ$JbyQO7yyYubZTRJJQmO`^Swr(fvhV5z ztA5$Map!*58@H4k%J<`*z1_Iq<=4Y!cb~hO_NH6`(25;llmNdTII;MLpMTu3Uyff{ zE|4t$>G${$A$W9e&-q^>!ZwDNe$iW5o8PQ))g z6|vGQd1q#szk(}6wNXxgU(qbIYILZJ&9Y4d!T*Q$#wHi!mW9g6MW2BbSs1S(LB-4KI<8$tB zc7*H!aUO2GN`+?|Daw4Th{9y-i3rmwfC+i9^7$j_0n@QryLmCKY0DOZ!Wtv zJPOXcdppP9S6f+ugs_l$+uz_g$D8G`jpWOy^ljgJI@sJWFo-nhko~!7Zb!3pGph(Q zQ-AZW{?;ZB?5!j0Y@=|z1{Mg3%#+SxdzUY`TWbo6mWA1hS@_v^uLXEmSv2l#E z>T%P`;qlU?AZ-M?6*Qu(GskcD8W`5KTdt8^R%heTP6nP|8u$(D-f;B{Xq$mkkSZB& z0Z1fi@we=|C0km@8g+~{>l$fecf+>3(8muHN?<{)#&k1MRr+ZNr^fBFqsiX+iHlu~K< zn?=mjob|k8ZXa!7o7BC}BNK;5=Kb7l2OvrV(&R_Cxf*M+;>t5iqgaq;;6IoT3~k=t zZ8*-hHH>6g^_t-nuThBf zOlj1@VsxOSK=fRdy@-0^NTk^?88(pZ2-*FawBgExDU!rhP;?&TPk^dKmj|r@nqgTT zKe0t4<_JenY8JSihmY6~8aa5@H(oKB1yabYl4O=N71W7~Y8wiw>ndd0w=K#dk@{tw z@YiE!2Tq;SYt)p~*Y9~W)coxTDgj7hUEMabRwGmrNb(c~a>W%jydJWy%`k;;6rg~H z1BHx+PkdcLhpw;okvbCi0TFb(RgQ9DB|)oMR9FzH^;}{FjV4O51|5>aYEi2BgBpN( zIn|=o2Nh}nF^M!W2!KYJifogmRbjUmH6FIDX+?_DN>)E$+oB+4T2?{olmw%}-@S%n zKU$gpwf)id{{qMViM_P3SOCTTug*Q|xdQl_8I{`y4b>|^P3kEPB( zp1SB%%A!*#3r;4@JstPW=?6cA=Xo}$-k_2UM}H(e;E7J9j@7j3v`9#nzXI!|>Pn&P zU3DXWJtREIMM{<=EhibNmJExIHULfph=DwC`Cw3>ON|}(E2BQ zIge7)dZ|f`)_>zBSH~e&O`Uv9dqz49^|tBmWozeSYZqW`7ieV{WN8y*X%k>=b;r); zs-w+WXWP)V3oCBAX%ZhZ*@^Hn6N+9z$y+FU56`p8g99==+`V@0xOwPM#nb1YR^v`0 zd?KulzY!fpC@X=ghF58MJ2wUN?Hgon8*OeMVQd*>W_I7s`d%+Pub$RdZB4IQ8sD+9 zyzSWY`nZXihmOLt=cw(jQ6cc6P=S-A37)x%c>0L-$I&9O_s+e0?3~=qy5BPFcCTx< z`!>Bprq4po=Aa_60W2>kfrBmzeQVW~FLrKzK0Zd1&-v@;+7}L2aV0|TG;z`v%79# zdfC+Cq)oTldv`&jVzs2cT)>dfT>akX=DoRJpRq9awy+Pja=K~M-Oapb)OSDgO09@s zUR3Bda?}wstDD`NZ3($}rexQfJNY(tOmTFc`&W^~i&?9~4z9LHGHo{y7KATQ;IPxsw3)NgCQfGxuU zcMSFZeY)?yO@VHxdZQwcOo5VCQ)o_He=Ct6#gs7o6sa@k(OC}KC*9PUJ(OAfjqoe5=Sm4WdL~st{X}p?Hx)E%)ghG{*E?1${hHdv9YxfV;C$MeC zVZ09s#p-85HLVI-D%UC1?Sr=jhg1n0L`Z#upwQL83wq)S9hyI_Oihp+NR%30h@+i1 z#b6N+s!gA{eV33d9~fwL$PkTxrBtofU{g{`_fb$w%Yjg?rTAH)Pei@+lfo=R)9hb7 zw|}(#b2wgB*HBT5_R5;ZKl51H^j-+>0$v|?PhRJeu-GMKmRt7BW2xg#=S)AIG3`jo z^y4YBPG`(No3Z#z>bx^ab6gWv+(zz+ z6?#h`j+HAFDvg>KL17Smg%b(|e6p%g$oP>iRGlU8Ev~oS{e+j_b|n!SkV%jf0-6NZ zYLKuD8lj-klnNro@T&zDk>E%qJfu--N#f1>qSA&63Qw8*d-cAAUD8xTear&F$Q+p2mt%_p|olgIp#8C%!U)CQ{X*vGG zH-0EOxoXX^;S(?QAA7}V$lXyB&kY`QX87PU0|uPyKj1>20T=u9ztpGi#Xfyq`}aOM zsP85x+bzR-@0c`n%jA*2Oc?&-sG&a$8ML}zpPxn!Juv@k*L7>JZr^&~+i#Elx~U*5 zi~p{4+(!h*PS&UpNq`y&P7orHw?KMI*48baV@93t*ZX)c`@?;^?d@y7&DnZ)pKj;I z4}H99X~wP{koyc81t>5;rt<_p1x_(EtK;~QT?TQ(Q2&=zD&p?lJF{f@tp!ViXDp1I zzA$d~lDLh(NXrYPbSwWa`QH>*3vpLQtpZ`A>~Ub|y0s?<^*?BBbHc{O z?wt8I7A!1%;19w&z)KlgFB!aa3I$dEeo4RmesR#qbG-)aHnTrDWX$93`=F`@xt~kK zn&&V5*KfSJV2S^drFZAfy)}RSm1WDrUCseX)0Ey$3oW%sZG`*~8t(bcqFZxj`psY9 zJ7eL4uT})D{;e=QLnsyTZsS_49F7)ugyRJ9zZb`KKuUmg&ySemvuB{sw%&eQ2M6pN z?7gk;xgXcvJwxz5!FbY%z@#iKrY$i1Sy+_VBRL~Up)z?XWQ?G*#>k#bY)GA6ow2O$ z`JTptt2)thoQ7jPb`mW|d~(63neCB30P`aMwg2NV-|)CvB{EN}S8+VhQyL{hsFfO8 zL85opu<$JZLs)F;qo@Qyt5T{W_;{Y*5oms5AkI6N@wR1Jno}s%pIUp9B+n56lBDG- zR@Xigiu{ooAQ(bPvMd^IByf&Q@v_PUubTmFnGKSm(6yb1KcP~o)@TU1TuIX`gJsxd zYJ$KMzWkaj*O2X1aaPA^2sOVN^PfPWkO^8uG{f=dS8E9V5zPXNB~qD!AlnVm(Bh)i zYX8-j*uVMqPvdx59daeBsBQi;k0njT0w@f4eat=idzZw8r&DLT=FB*jHs*BB)MM$B z52Z{ynmWtn$zqrE#m5rnoJg4Kmh?kHSzwK}j6&6G8jCNq!7K0i3{WKzsR0_5NPkJH zL5czR^5*1fjfx=IPa?V&sg%cOv0TMRl6>OaBGF5}Xf^r^TPD;r*UR}^Uqc{G7$itW zp?ivK!+G>B*m+v5k^#_4g@mEC3`+=v&HUTFEP9{$@>M`oXhln%3dI_nSkSDaDT+h{ zBqefk=ddmrhi$nz9mgn?S^}#dRA8@x29>^}B-P>JVSpwLG;2Z3=#Mw3bs}u)B~t5a zRw4o|GyHQgi3}I`=R9Xsi28E0wyqi~>Yzpd1s~vT5tJ4|V+GXLLTx=%*Fse_au}(s zLZT=&6$oOQtDwFNnyZmqiBb*{De?hF=BIVgSdVa4OR}vJ#CCbI} zR?OT}gIEX^B~V^0NDQxu3MmN>sEi4bW+%gkx6oV<3I!@jPlD%ohN*F zzxdjvx0lbsi!AO{Hi+tglHs8(qzTekQvvmLs-!e|cwE(;fR^Yu?YjctdA^)NS63xV zNE7%zYP=mxCuE`ULqnr=5PN{4^@>Jy6Iv@lZfMOiD5-~f0b5=H%`H$}fkf3fq@s)R zED{eX&@^&0ud9c$N+LB~7#>;ZeNUL0PM4OUWE^RGVj=g6I`oq@)IviQ2pgcG2K~hp zj`MJCg|&##jUucs1xYPb7eRd$RMtUZEtCs*=}}%hf#4^sQT|SG2*-*4bvRBVMra$3 zUw9op>F%EXcegqDY#rpktKXgNBSVg?jq@zy6dKT}SrF-v)j}mUFXm^##Q2E-GqnJ! z?41;^=~9v66`nF|O4Vt8Ob| z%W>Hat-UIVeyS2z1@Qojp4>&_yp&-$r9w+mOuGZAhS0YAd#Y3_g+jrbezqmx&<5Xn z9M=+zKHyj35m!Q^=ho^_w5`A$s1`MdRY*9ny`87g(i-&NKv9fBCMVSzT1zkl*)}2j zao6JN_b1hQ!0K5*QG{45WHED)V+l&DkhKapTBENg0!O2o8%GkFkIh0}=~4$YMIakl zo!&9xUww)Fn{WRtjyL{O^Wz_yN}J(>|Lc?IlQ*17Ty`pT_PLy|kEBjKl{521=GTYP zW*<#mcrtC}@x*0^VwSk1uD<psb?B>08JJW9xj&whFNUZ5J_Rat#v-rL)cqA&SAjLyk_S=r(pp5$>qys%Mu z*+0_#ZutG!=V`C1-&C|-_I~91AR#O+>;B`!hf(P-iyK|8`riwG;^CiAD1hsabIZi@0>nOhUm~Hi z-q%a;^Mu!Bg^kLBCgrm-flq9v3@<^gl#Hd6Ad`Vog_eC$BPsyu6e#Q_Nn|9V)__uj z{;yJjd^AWEVg{)tpq8WTSfPPd6^P`Z)uJOpArK^}HH<=u-I>Wx%jxYn&LI(6y%Yv| z69u8q0<$W9M}C*j_nwJ zY}<&NrySk)4!m?|h}(gY=MRl`KRo2Zz5!>qk9Xa>*=?09WdX$Zhvea!)TynxD`dro zIq4&SA~X`MqxHC?!(~9wFbLB14hsxTa-@bMHGB`QRYmccFN(Yv7FmI4TY*t?N-eEn zIjv4d0jt3_Ih;N`(=%sCQms^JG%7x{Z50bJD<99IVjW9{CN&z(r|MB$TRfmwSf$&< zP7!@i3oNC>MIjVa=sucOqkE9#2(6xz!=R##u8o|->1Ss+j#MhK4*=HAp&5c8)LIqA zkOZY=P^}XQ(lWG$V?Sx^>-Z))U(%#N$B=48`(Ht-6>^!F(x|bE0jEFC;otEu9RCN~ zKaJz1bHQVaX9 zh1BB6`N*Bf%vw!AZuvV6T#Cx`%dHN1)tu1`q3`AAqw|Xx*ytYgLIwqDxRv@Us<1Y< zQPGU$fH2al{*8{Za;6>=b!G8_-@y&xVSR4N6hQ&M((6v zLQIk1m$TkE4YcdStRgLh7fG%r6&>_X%aXw6o1s@yUR7bwwa6Fs*_EndC0vbqn%T^_ zMrYr8R{HzRkdT6gYjJrk0N$}L@5JZbP0HJS$tSH$7*|kRDAhIS;I)wQipmlKob!*) zYtm#^v_5?LA?aOXprB)x#aVT^rC@qC;L{M-*YY_0M)j+CAAVom7qT~2%l%9^rk!oJOjKLzG6Mu|pNDV)b4)come4}vd&!a@N4{Ppj_Y_Fr+FO5`8f9GqW#1@`!$k!2`InIsZ|&`Sd%NS^ZM_5b*!b@>jyYm*`9CpGK4*`UYdwD!W_<&3eaYBSvXptUmphpT zAK+dC)FE?GTE#NF;j@+l8N~{8pi*izjIQ0fl;LpKnRf!!GAMH5^m0!mYR{>}AA7@k zhXPKYp?;eAwk55+D>qAOv`WONq%?@AqgE;K{{@z1IS$G4^MXt&wYFVh8}+J4^hp#- zHQz@_t5My~EZ=$~$}hJjzM!R6hSv++5@2Zths^lSWOQ1I6k{t57@9R22_6gJ?U`^P zidWC!2nw;*}@5rFG3^wJm?<5#x9zkK-p2 z)*Vk?btZe|!Ib$YvX&lyvg%OMnxpX>PA6`4N!aa`BsdS$F#MX?rrxch zl>~4nu3eS@MC81Wf6*vm;Zb^hdIfPZFu4JHdFM&tLQLL|ZvI6qTuCjCuA$Dw6nLap z1in`vk1BWv@WaIil>qes=RygHdrgIzZw>H#8)RhQxm4+duL^-GDU zRGp1}R*egEaqlHjZ-rGHTnK;q;BE7%@a&*>g4lX(S~DB;vaS&z@X3c$cS3WjL?^vN zd=hgbUzCb4*FCeMH6#lOByK+IB?KsxFemOjy!`~Ekt;dHnp!M6RZI(-kR zjpfK7AY-+-vd`e)yzQsg-$?vd`the{+yAux?CozZHI84_(6=N5x(4yw;wO3T9q7Hg z`t@{ps2q{yY4F_WS6QlmB-cj%rC%C15oKg{tjhfRF<5DzDTTH=Yf- zm^1i%&IGsYnft@m?F$Ki@PTOswN#E`L=?<(K=8aYG|j3|3mFuMswAX9MM)SIPsr*x znFbNnSrlt(c}*(p9*#|tbXrC$Z_C8_h!c|!Q0PiYXt@%Nd5DG3Dn|myGCA9V$^)zl zMf+Mpr@|eGzi|8yx3*>N@2?ra`~-$WF`SCf);Bj**4EVt1QoUaM1TB4b8!>A5BlJG zJm$L-iD*3hXxhBv8S{>$&UMRPeLQyAkw@Qp#P5lJ=T|O&semRDlmtrBXxtjds}PDY z_;LXwQOWLw1gil))QfKhMIUwdxpF_Y8Q@G{*!hRCmm-oH0e*A8nIqJ0^Srf^)*S#JtNn((~BVkz=-NqSSZ<!g{5XUtEgKcp*2#?VfX7Xxo?v5OY^G5k2CY70KXl(a5pmL?CrqhS08SKM0q`m zI(ozVX?^n@WQI-T?Mm!|ARvit+Onuj2- z!1E-yRE(lHf(9v#Xe?+-3>P;4%{COlsWg;`L3JoJ9_t?WdYyOba=#a+D&UqDk^tfX z&Skc2x)S3b{~k|m(kv*X@+JnsF$xwKjwY~eupAVP&?LpC19)bSlhaCMD+sbOO|<|w z;grarNG0P?B}fCLTqo0@>`W~KX&qJ9q;1rqMgyAAuhIyFpe{$`8<7B7o1jq*5-qg0 zN*hoeLrt{R;{Kwn|IzmMacmou>+3T(Y$O=Eu|-f>TT|1}Sl!TE-5~grdwENl0188j zTwLNeTzK-+g`9O~GFP}{EqBdYbtrOyYutB!Pmet*53EzX#zsI|T%2KX83pG)?KrMu z`T3(3iJT{%HEUR2A)yr;^738-rE)qT?RgWxgPek56%?x=FsF#mxT~@D;P2-=5mQvA z;i)DSEz(M%LPQ{Cbs6pu32CU75dsnwLO(RiYo!DQP~Rw5VYe-XMjx5VDX0^xHCQnA zZB4V3!x}Xda$T=i(ajVZA&~$S)Cyi!)rnd3A(hzQyivo}sSy{eT7ha|O=_x9D(AaL z8f-!SwpzezGVof9$FF$T$Z6i(@O_;?pkgmCMu>BFVq_^7?E0Yx^JBxKE24Z8*+=PKLD6!S`L(^b5NNx^5bJ_dt(Z zJFGl^x4X5&_U3k*8#}D8@3OqQ%fe%i`Q`oQmyTFmI%#?7oYC1chG$%i&$@RwcDC#3 zi!(h>W#sIZz1a?e03ZqwC6dsy+;KIArco0~&fxKA9WIRjmkQOtazn$YI*CeNqsCE< z=gXR<*TQ$k6huj(0@o*-(IZs_^ao%vLE|TUb1}`gP+3yXiR7sB#5FRAjn@KHk**=& zUDVFN^z>$M?lw-WlS$#sAdNxEmL<1D}%>1<>G{ z?z8#+$)nL%e)B!}`~4%A)9yVj%NJ@T1%k3;eix2Dym&bL!pYc6M;@O^t<8`kPYsot zl>snHxdJinROG+a_xW$Q{V|T~^tPBxgP^&jqP(oCy0ogcw5sk;?jPztv_NrC-uaUc zH@e3BdOCLffzTDlW4?7y`}NL?L$MV%KB$vrNPJbKL&X;C@BB#t^V6<9!?7BML7D?B zNNA+|k8DhpIt^AGR8mL=;c;wkYEH3A2NlgEPuqA|+}c7Qj8*^$2#CpguSAn;AkcFB z3)C1i)c^vGuKftVE8F~VRg9jfQC=_MZ(qI>id=(PR7aCzRV5*l4bc9-XM||B7`V6&@5gije3)i2aP@fP{$U0MR-5EtGy(K%;`t{55y^*Y^L9P46Vc{ap`2*P=#3IXSZ0-H~@@UOh1U()NMZ zb`0}9XFCXdQajM5vS39@U7A~jlT;0r1yV#v` zpYM6*&HEc%-7O%Wql!93>t{h(#9Y8VV}eH2b&AvJr)B=F4Bc_vUd?eDIY4T2>+eC4 zN7G;B0@NVmGfEC3xvpFa#SKvY3<}SPLzX8U{@P{rQ^i{WB7@Rm;2MxYJNND$2{NYigTXYMX?Aa<6Wwkw9(Ovzr$l z?7bR&=yKeC_t@QcpSnbqdY5q7&G23c4FuBMRneT9p=g%o_-@YM;W*E`lVXuUbsHv1 zF(8sShv#<++hOs~C3tpBNnp(ZPXC<1BVEWnkO47=&LHLx{x%bO?0#1#;-56B86GQ} zRcKVCPKq$GR)Qwggal6)#vcP?aSNpva8R_l5b_?rGW;lDfH(RP0aPoIcd(Fy8m+EQ zqbnB5Q6f*EDXnT5f#i!>Bpk=@3XJTnG_+DE*4MUisA>GjH<4Q;3are)5iF=k#9Jk> zce+$X@Dq9e;>+u=?XT_s{?ZrWtfyfhIUN*BaQZpfe=8hE_Jep{RSFRL=J~M)H=n7hn}ICV)ToiR zpg;qSQmA^yrR>VsGS++C*c+1~gt09k6@#jRY?cEf2Tly+5g)hJr+@Z;^SBb(3$?a@ zq?&G2ql8`i_-*KN*VQgr9`B(_0ChrWs{B9gUHNwu*OmTj=9f8V=FI$-@yWhU9LHO{ zW5;Bf9NUQ}A$aTe(emm0>vL*|VIPzfchQ&eg-D&oGICo5vMoL9N;&2nHQLFciv zK(Wc%aGY#eRUs=|v&$=&5|8V28exIYg`S2J&HGCbDnei|*z&s#zv>BhWgy#`>st2N zYu{Y=wGVIpt{>WhFmpZ76)}?$J;fuBYopQ0msh^A@!Zx))0aZi-&`Im(+a384BR#E zmFG4*`+ocS=0Zn*uw^jXd6mC80YMSs8l-=*@2!{jEboo948~e}^4GgdHSYPY@t|hWzlOeYS#x>((Rc)p6G9BjP84yXP~c0l zPRixPiy1T}A{NDPNs1FFsYs^+EqIVc{PtB56xE^yc7!dSrLRIJzl-h`8lZRf7v zs_!24iEy;z_PWCj9k*j8fPH5=w;pc1*6;VG&EpL{`%kru&lGFUwqI-=uDjfG@!G(S z1NH4a_s%rk+y`k{HFq?$b*m_%qC|^Q zT}SWk^NoFhc-M5W=IZqiw(lED7WSQMy4W*(=)$#A*KV9??cG{acj?CPo>L8HTKnoc zhtG75Y(L#}`ugyd!KwGQ96Z+2zvaZ`x~|cIVD8}MuGPDbP3H94YklkXpWb}@(*BF> zNdpcvbVN1yVEd7Yw0yYnMh4)>rOuj59UNU?@Wk$dQmB-=sSr~kM8YyoJQAnR)U3Kd zFQZP23m0E@n5>MZx&?zc19eoeS(*`95{wy;Cy8y1&Bkoi$b!AGHA|00z&$^S3btS~ zgkEV#WUYs^6T#3i7r1nJTm_4!1c?ZR=H{9kEe8Pn1g0}E@${OfUqATna|izL#JXk6 z_O86_?I@v|L+*HY&D)#a4r?(U<+Aj&TDUnm^u~M3Ydeq6LT(mo(qbao5ebGVNx+@= zUHI2O{l~v-`oXt$Jp1H|@BVDL^o63nP;8MS5Deq@fHAZTcDoG~SQDhOfU#B9EFik6sg-8-DjsKN zPsxCF+xKrfexcu=osr?vo#@UheTO>7@04ImL(kskTm4DpW?VSYJND+9%~!|$n@(Mh zgKZanw52O)!kMnY3xiX))7tyHP6QM<*E4puYvfQv8%N!F4%J_tie+lfUO004oJ^ZZ zGK#*t{?h)d?GX!lLy03TT`M;4iWzX=Qi~@ijm2^&o4fM>drx0VYw+30h9GD3&t&#p z?p}ZR+;j=2f_FFW^YGvm;8^=mw>RB%+yCF2_WNbn+tArCI6V-|?W}9=_h&cMoZnV= z?UUMu+P1;d*GF6K_%|G^+k56R3&tavoFm6-G0|aWiGoMeKyxmbz&umfkw}Unh>!W_ z<-*0^A7vh&pIX-~v@1X{Gpg^c%jJ3)17Myg85@S?EQ4(!G3OeM>6Y4>-$E!cL0oS3T-|<`sX2Rh8#%Hg5_vG>`*`}^iTQ7{9EjIZe5P|rxKK`8#pZfZ$ zpS*eW_fLNE@{?;{e*KgGsvo!{;sz;_g`g6S`ct?({%9;_e_T|RU^Fr@dH>$Dhw7`x z7de8V2sL4#GJvY4@G^_LH4SAfm{g#n;Y&{l&>zO*=nG)M&ZBjQ8rnvp-2TR!wOx0+ zBI4ezJI8PPjt)=n>KN)u%YQm{VW>p*wDmSlhu_)y*%+s!0TKW^E?mw6)U@9?+|r)_ z_{ExSJu}&c{(Ga*BI9w+f{X3FpYA;nOlNzBMmZIKMS*m7%gMS8r_cH|SpL!am<4~_ zvNI2`a`Vo#0Rz5BUE9rsY}L2-c~jiZqxG`}^h_s?x8B-vqH!uu@&K>?VQo}{uF2S@ z+Dp6ZTc!)v?)sMdv*g2_M+Za2#-ZtLry6esX5U%A<8X6d{f+UVFn93sjg_D7za7bK ztF2EOrLEpnl84wmu`Ci-bgYCG2rm3}%h4xYQap}Sj#4e6Zh7x{50801 z;ot;;YXbCg5D1uw+xhH_Uasmf`KxKmFEBxq$Ndp5X*`0* zRaIq5xduQW5)MWq{&3`BJdRyvp_n%q4MdZHXwnzLo5kZvRJYctD+w`dwFFNH|>|uF2%niY5XVbmz!oW>oblLb3If6uk#b-31miE0{7|p)?Yt|NdHmycM}_KWjlv`lb!zFXq!?d zkHO&j@Arw`2(>lQE7{^!%<4hOHaeAa+%7ez&(p%J+R_XcoB3htsH95uHSXOFhc*XJ zIokVZysp`e-)5%FV=OUlP1%;(ooD82DL&M_dL1123EQ53Q<}|L;bk9Q6!&KQ$(6=J z+ss$u2l*!lk7yiu%{;UC1Hb=&fD_Kv55;lfTKiMDW)k6=nTPF48DWo(Ve#bpZhxN0 za%PI|`bXpFb&RG>WpHMb4stPziJ@r_A@0b*39HKPZ|&{G0xh9pidm7twD;D&VvK|` zyXfDKxGr+HyS`@-JkysD$>-~X^IK4@e;h*4d4Bz^{(L-Non%9(WN*3*Qt4jakWUA@ znO+{X^Lo8cw<&Lak;}s6Y$`YU+x+x(tJUsvsltOL&h326_VqZb1Q86M*`m|#T36&! zbU9I}iBty?mfpSkT+WxhcI>AQ9*#8v(^GzoEwzvusw$Jb*E{XL1QYr1&ZB zkMx_2i7RBd+-6Xm!)b68M`I~L-j+FC?P!Qvc2`7VfRRa4yvSf}4;4X7^Q{9}dVisO zkBI>WW9S{G(%0hd z91IIny29Rz>GP=eUg}Cmxic3vY_YSoJKrd04u1l%l@CPf4PiCiiV}_eXXIl*t9>n| z@@~^9$7D&F`%jfNcZ6w)a^wbMrRjA=EiKjAl@C*}Q_e(!BAY$`u$z{?28rbL*VM~Z zBQXSFH}gkx0$4KLNc(OGc9=sv`S6Ml6+xZG>Cf%#?yj3`H64wE-c&t zC5mXZ^%>{=)W&L__QQoI_=-vko{P~y=p0>1mrnclW7kTVW(?fGcRw=tNi#5#Q+E5EQySS zb}n&LaOT6b4qnRN;cu}WlyIZU{SDm9;wQ-%LFLH8K9k263*+mL9v)w0C%dp2&|g1v zm?N`Y718y=PYo_eC$4ls!K1S?wN0Ejv6jg^fc5b6Z30FcmCrd{))%0U&y1X^6Sdns zK~X!NYCol(aOl<7Y>KLuP&d<9tXbB%P3VFs?ug$b9YdlxaY2@K;cOYtZ*>(;^N6}| zG0r2^V5ftbGCC|N)kwm3D(Y;IU#VVZl=(vjuV9rD9!qQc-pyL;xU*~5-^Wqew=Iju zl?i|y$)d2}i zQ^AfsBPy71LF`gSUmu!x|HroR9(hhMAM(z|if39d#d<{%vH<+ocV8q2!a-*R+p?`en{IePyGz-$F9qdGAru8G)& zf{26dPh_p%g{uSFi~_SVP5Y)KRa!;SrV`SgNXR15a|%Jhc%&$|@p;rE69=R!(>E#> z(b;yvVj?Xa(!z#(7%s6h_?&}%7y+mDoL%`Df+bHSgX+2ti%{Vfr{KBZ;*rBxVpy=3O>7MnTv$T3oQP(3!ZxvE;bb7Ym_lv8>D zpnP5hwyzKnJ~mCiVxw||sSMBv0;W@s#-aPfhZ|1Cuy&0&<<#iE5nal7 z#g0RtC|Bn+!baan$R|k76g2)bL>x`4?Ripb56(n2l??MZSt=OxnbVREZ?q$CV}zaQ z*lbwq=ahB9YahLyonQ59e zdG1<5im_5?Nr2kmrv5wiU0GVmMxlN#le50DRV5`dUBqRZ8)z2={*xGTWEaRx0be}i z;2f9$Q6hVb^kkY!G>Z*B+n7jLk;(xM*aVJL|9o<33ME2PnIzaf?;ec$c9jx_iD~t( zUuYo|hrA{eCj~<|#58;9vv5&lr_NC&WmV?Fq(!pRkQ1sZ24Y7yP_J-fly_as$|Cz< zhY02x!3LOZxhLQ=)PR~i0=yP#07f~?KoF?LSLUNce*{XEj@ zjV`72l5C%fkls?Iwer!-EyiYd9nwnCQ>eI{aECLcJ1D}{ZT69Nx-2aJ`P0-)#n zP*wnz4n-0?3SkDMEdZ!|Kx$F1g;;hNf}8}-6*Ug?NZEOYsztyu1574D5b}YI(yU4E zZ0dZXaHxrjW$udFXcOc{>iNvG;n@O@A7nf3-+lKW^Jv7>KPk2Kis&-ATTV6BF%j&JcWP-$u7j1lU7`OGJ+i)!ku433Xb*#mV z-V)sVGU_~qLkIh;o{E%jLWit$s#BiNm8x&{%h_Lv{x>H-15B+3WFldhiXd60hEzjc zXzM4Z&fP?|8c;o`0;r6jC4v2msM_CI`gC9y*8l(XmiqOP@!K6i%Q32th25H6Ue7kTJ!91fGE+*d-zyY zH)eDOX0opEHtG8TCg-qYWW)t#<#A(BNmwDX8Rn?TQV13XepNt~d3~#_JzQ9$DYOiM zKA|mQ5MmT&xQ0e1N-jND$m9xr17opPnlyp%@KfFnm!k0fQ{0VpPai8+qrRaZfy@^d zRaD*9y<_^>dlF=*VB$^vc@#;vehEDi78IE`;$M0s2XN#8VJj#4 z?^$%`aO6xG)L4(K%x{9_*soDw#Q`c_oC$X4Ij4Z~RSB~Io=~W};ecITkF|}mHac|# zPlh`_tYX&cQ%~3Eb2L?g9XqVw3v2F}utyDb8S}4s-7)@GzplP$ODNda{(!>EZq#mHUDse7Nz4_BQ#KaU$y!XbQcza8jU# zl{li+#2<$0$M^o(WZxhkKEmFOJoPB$?9oNcn_#VQQxBDK)>i8OTEU)sFhLE=H938X zaelD@H>_M)VC297<6qsX-8SI9L>NvXfJX6#68^IzOqQ0GC{Y*#<3SCVJgoDt&I|{O zUBp22b?K8JhUFtkW>G=cdW`+rVl)C=OyjS4;a91uBRRC;b5m(1LsQm(}) z*T3)3jqq=0D~HVCx6u_e)<6gK+iMZbmERQ+NFdcvQO?Aq*tHo?7aeB-=Ixwjhz6FCI&YDDA^fWLNl@u(i8rpz|Bpk>~3#DNGD)x zYX^X)Q*t&0{PVZ8g{>7dohTtQG@YQGqp^u2p%(r3G4wjnbc!ZM075NBCPGFAR$4}8 z4t91zMtW9SHWorg#_z9xZ1}DvK=|)%8v!irY`+^Pq*GCpfd0n^A%!^rVDH39M`vPX z05Ea1ur+jcG@~`PvoW%^FtVa`bfz;ha5ScKGO#w$(=)X;0O;v4(zCHLb1*P5GX3J^ z{ca85=xhX#H*hqu1rRdOf4^A2H~&w7tp6PV8QAG*IXM0Wke&8>&=@!vXqo@9;r|ps zCN_2!dM1wl0wCLe0Lb>=0+5;Ip8{iJCuCq{_=gA?SpFqbw*O-g85!8vSQ!2*8M6Ne zi0uC@5Efu=|0uE$ zvj0!1{(rhm4QWjP24)ttMs_xI-^#)o;7-TE%)!dW#z^;{BVnNbcO*>z&<_8mQA91Q zzo#@Io#^+pH4!#3vNJY;rjs_YH3OIvGP1CL<0t$#b>x<@plK6<+lutb+bx(4QdNl| zLE3AWa&p4*Vvo2*L!yUpWC(df>OvcvO>jSJ>HHM!vNQmpi&-SLp`${{qw-MF(1U!J zEf8=B2jF9=d$~Tje<^?z5FSW(G|6YPX7CMV|G9s0oz! z_&%~e*XOWMa=IqQFmO;^OIK#eJvMMH$GHmrw@pA+EBxv*_)JYOaU7?g1vONGtS&-qY zy6^Y{IF_uwkE-`I?}c`k(wZw8WPaRDL?~K-SPo!(sqx}4rV&?fIH*nOy5rjPkB7;W zo=lo~$sJLaua`Nyy64U6W_e{AfaFMRHV zV}Onl$5WyIZ8|{%EnhT(!5}$x?#ff9FXpbc8e1KHTJ**u4r8DeZ&OB)HG!fm8vp{w zDAY3O2#U)z%kCYqNnTqci@58ls&8lK4kAMvK03R{lWaNM+6jAe*z=J?g>?(F?t!3l z2Z9fPxN6&+7g{xzi}()S?lq_ZEJ!K9nXPQ5u_3An1C|a#<%RLIhpl|VL^a#dt4xV5 zj7kWhQ5Pmug+7mwgGt;%c$s?JuczgsJJm2kuA&O1C>&N)jR|KVF8*~=m^gs|%nI6H zYQ7|rTK1QR^Nh>av|BeBR8@7t4<_=K*e#g^jP`)yk`Z?aQ7h?>?Xd4=R*)GGTtZ*Y zBv_(lkmmNz+l0n!=Z{}DikI316iP%8GagaAyl7Mkg>#>)7gTRD17U?EO4SPx10B6)u9Orq(KlC4BX$!OJL)Z|e zs>=Gz)>%rHc!~9OTb=R6@$ZZ|e}@+=s3>2W!H8Kq$vZ@>`9CrXw9gu;u}eEeV8kFc zX*fU{vZXaZBrCLP&R{MgXTp=z&DA`(OF{%W(Nc52+RRUu+QOgT_UkC@f(g-UfG>LK=6%x%B%UN$ova;GlefSDEAip$frzkzGhC#@Co2 z>5WI4%lA&#Brb!bK%2wJpAC^F-EgbEpWvP|%?mw{hiw=iowOA%OO(O|XI!|vsqT4` z@E8SJ!Gs|50NrB3(sNAK^TFbq@s-%)I+Sjq+w2hs^)-g?cH1J&8ZXDQ`Bx$s@FX)Z z=DJiT6)(mK@maCu3S5wwSzROPcF!R2Gtuq>lzRZvr?R zt>9}PD)>%xJrsMq#!9vVZ&jmonL7INc-Z1_UrJa2$csIkw##|yjB<8DC63+owh9bI zIEyYv*MrL0^w__Mu5%&eiA6C;fJ4v-ov*;l&ro%|^c@V_+nD-cQH3-ABjZW@Eh#yK z$FB2`v%3&|X@S8C6RnS5pFwdr4P7kBMb{uB_vdL)2GL_WaoGjErEH#Xf)VU9WBBa5 zc3SG-Ur<~dW8PKOcy1KJ{Qir@u3`yvVH7PNFd0qGv^&DYRtEEYqL>EIEZ1}%yHXG|Dx9{$o zu|*^DKLVR2craDN$AjHhs%5Bl5kvcnhP`q&R$AdvVF89>fn2i9tbcbkiY7c|PH_MKfhT06mCqg_9`+c0|+8Z7mRGe^b zOn+S~ORP6`-Zasc8;XyjiiZ zy(KpFULx>=QJ$XN)Ls~I%(PG`M@NgjVMAew7@qK1oo8%&v#7`?MFAT zlFPL9$&dA4*E&usor){Rh&ezlbBP^H`hqUgl;S^JcHY3R&ycTQR-a2RrjAa(Bz+~f z`8W1UHuarDd@x3RFBwjs#17gMF#+PgGum8qeNK=sfC~i(mjx;>9NH+4Q7U~%WyK(n zsASc2Zm=@o%Y?#u^( zH;lnI9RhCSVlSTGL?5YsT^Ek`Y^T<|E!ATK%V9d+t$XPnu_ePfzkdCZreTd9xoGFr z%7&m~E$QXS!h1qgmreRh=R1%?@#Ln9W^U%besg7ZeJ+~$vfZn~Up=;J(93VGXSFL@ zwEBZVee_GHW^A1R`vXCnbcFeTH(Qw)|D9z1%WPGbGqn6RNB@K2Dq&+__Dwg{ER4U| zCKC%Zow$jGnK|H}MIk$DJ4YpZ1EX()SJ=eG!pKBXOz_*lwE#HDn>Y&D+1T6J{==GN z|F(Sp-#9EQy4hZJQQp;EqWh-@>yq=#*Lt=Aomog`t z!{u8(DeYejJEO@r!+d+o4yg6!2{YT%h`lgrMa;gG@<3WpmQ2h#OU`I%v#@y3%vjDq zEI^H%EtJqA6BE15-F$D2Yfr7ge;X^rww9!-CJQesBdXwrGfw2zjUtw|g4MQqM%^o} zw}m^Wj?ic!XhOc^m5*%aUl5Mgk^-o#K>aQ^tRd`Uilgy@oEOqD^4g2 zNy4E}e?0UvLhtoZikL?2SZqzt2h;5pHanPtJ*2_zM8@j{Kk^ZdOoNROqk_dx%~sc6 zP~N6wOl|%Cd)|YlL^IR+n1Hzq{I|tYY8=(i<_GG+NVO8;V&J(X-2+*4%UiLb+Hp)r zB#e~&GjWT1B_tSi8Yxn)({CZ;C*o6+Yi?+h^UPQmZWbJ@zstnqs3n@OZcciB9o#Q7 zvwFqOlrIL*{ius0dgOo0HqtF3vYJTA1GMP4?;#IOd(n57%NUI+{Z8d^5dAoX@e7HQ zpd%1?>&Q8?EF#8>VrOAjP%YI3S*${v!O9nX=aJDWiP+z!7xnUGXO814-d_-W_x&Ts$ zKRH&ixE=Rw)F~Omm)ASVN=R2l{nX9rUX zE(#Q-JaJb1Q*CEjqC^A9oiN7G`*qCD?Dz1vDxD@UcVn*2bB2+=>7C3MgrQ`t`?Uxz z`?Iawdj^$GGYPGqH2&t{Q6*9$a*o0DYrOki=>XjGG3Nbk&`^e^Mvr4_-KU4+St449 zp7YD;{7Q~}mGiyO7CT5K-f~eb!;H%KcKCDuW!UkMiCUSstvWGbjIA-)_Z7mq)=Xla z!WQLacs`6$P1qc$iC%A3^W@g+93>o((f<;+&ET!A`iEr8L$z&v-J-{9uvu{7xfri_B7m%;U z@KQcMuH~g^CI}F&o7c^O-#GkJQOTXUea}*Y5gmv1Mvq+~%$;K~S%J+-f^>juTEqt+ zcchtV8-+1bZ*ap=r9){=rKw7JpJc+BZ=Xf;pfCcMMP7E0%GU*BPqA|%mlf)eP;ut5 zI4)_4J!$=+25W4!o0L?cL^~!k}dR7-%m z^eazZ-Uvb15_NnKQWHgU=Mm*#`eVOf`lA&h z9C|Mx>#=~!V!cD?@j(PB6_V%v3evT^?|`uS^R&KxU%h9+K) zM6UkWJBvGJ%V`8eT5~uf4_$+Z|s} z#?GD-wXnv2fpN;L_N=jUrgm;)H1FqTPOP}@AgZ7h@?wj$cMGdi0yRg7+6GSXn&RAs z&|NPLIae@aXZjtF79$>x?8-zzU2)f3;P}LN zJLtWi=HoOS*?Rxr((4ZisgdVzTAvUJt_qbe)4!us<>3A}9L)<=0XGGf_t1W5MgLGsV!y6^wnzKH*g}#82eM4OU-0jYjoIg5VKCX4{Rx7=IscUcvArJ4R8Xu5QUCOgdUU9ed_V4y$x`IJCc4bV zT46DjHWFJbE|4;e&0Hhh-*RHM%-0|8v66GrMTb`~!f|xn+ViaNwC(A6R^i(JOX^g5 z9HZug=-mh#MufVOKb{T+aNmpf)pi1Z5@uFwMi7lR^vUynM~A=ceb(oNU~~)0Wtf-| z-4;C#MpPe}KkV?x9LPOD4MP+&8jzA==%`|O_i%u_4?aH*`hgSSEM)(ma9yVVE4VHL z2jllD@4v6tRwij#qb^|$cV}jH;siupJp6VYu4k)WQnQ8tK2%hQQ}vQ~n}$@eC@hlH zR6$g3to{X7s+gv1af_HmTqfximVhimSwK^wvdWAG4BV@2{Zkr9h+$}RZQ^_)gM;bI za>ylzD2~4Leo4~f@%$^5^TOTFn*Q z`|;A^6G9D0i2bf!N;_Oem@XpQ~nR|ZBYdvuuD0zq`?m7E|RK}ZxY$B ztWbqjjrZx{eI%?e#L}i>v&ujUk00}p<#~#AwDHq?!fAe7eq3{<0T%wa$A8b<*TzGy zjDHa3Gbc#^9Tu$uNT&DP`XG@_4#DSx#Kg@wLY5;UJk+)g`}{*n>1lA|@9wk0F%8bn!}0p45J_L##xv^v}abk&A2#1?zzmV=)oHFx;oWMmtbbH00I zH9_m~)w`L~ZGWwe+mjcyvOyUb<%7@Mxs zv$Vm9OnElQTb_U%Y6scy1H6!OzACuAoaUwUG0SOBZZC6B{d-_a*Ah8Xpwh9DaOUm3 zR#;E7D$_!2e6^Cm^8H?ct7P{U*!V87_@pv}mqUt>(q{>wx|mVsLmm9p-@)rNb>H)LWk=O`5hUIE^-efSd9w*gK&^=<=#8vm;I278wW! z3)D&AU6Z!*<$~!r_yBi-QuKnA3J#`MrcWX81~q>(G9b-LPoq@_qZ`hQ@FSC%H|5^e z(!S}Ol9u|=?C#&4KEq-SpRyDYjX2b&v!!sg{-k90`r2@Vjq;vg37`^9^6CZaQRZLY z!6~D?LeH9W7GRBX;hU7{j5sWsG}Fai@F`ie+x(ZdUfFrwxE7V{C^@XaTlw-8(nTDY zF;XCA{h@eL>;ntLZf;MShJ!hsleI+Unh|z7yIZ?X@5r!Cj?=gbZHKTWv7QcVqUCN8>&or_a)ZrqGt1p@&3vZL zsyW<)H0zpf)RbW>(WIXQ@4|Z*29Np}eOY0=x?~m5HbimoY81<+D_*;O*$EKRTV3(KwE$>eMIGH**Y(zj)zqBON#h46N& zGJ7K>GGmUpE{gwEz(Gm`;F>Q~WXe|+X0&C3v=B;wRWKFIYEM9>_*;r5gPfPjC{k=QAT^#>XJ z$K&#$&7WM`AWj+qRvu8#l?DF{llmtCNqQ}~aZ?g5sm!Ci*^Q$|Tv?Ov)ZPQQ!0v$_ zxRO7o?=W)`Rb2((4;J{F(BoBzG@=fRHGdywuQ{>PZdja%5!xw0&*+9IMzaN!1Md*U zqK}jbw2EFFu6E(zfh-W5dvMKZ*>3$9OPLQdrxQQiEUkkMk9ejQ$EerjKQwIqUa=Xj zyW4u%dGj)Ink2Q81MdZXcYor3aU_)Ayf$-I5G}|7tD7Tgy*-cl;(XqphueY$`0ns5Y_ z4`JU&I`+<;P$vOz3xoaEEMpj~GK24_T^3`*>D(ap!jHXhXS^c*cIBtJMfCb3dVwgt zYv&13Y)UN!oPjeTt$5Ox&!&7fe8qttcqxMKdbu*8k>aW@PiUCMVKVg&uec77Melke z+VpuE@!fb4-2tdcKwC>oLb!_g$?0H_92F^6UIE1HcxeRM!`0=Rk*U6=*Nv_?BQYZa zptbt5$hOIo&5cCEun%b$arfGJJ$ZVE_Ek}~0?=M+eC2)9sk~+EsZX1xG{~ICv9{!A zKZd#+Lwgvph6>TRHgBp#^;8+Us$y9U>hz};-{fi2C!uNU6u-Laq`H+Y5LdiRsh&%| zJTb+=zYZ-)UEMGaHKHIgbVBp(kV{NfDxXdFc{F?XCr1B=$(OGnV;~T-9q0l7%fd(} z2fMPqpa8}OtGs_zS?;?Hg9ni|`{ttS!Ao}5FYi4`6iTUFe5FvQq+ytr#0v_0Pn7jOP_ZH6r$ryg&= zERyqT@I8idZoLj1H0~uYefw9gc-npxFL($ zA1Z(K{wFkn`Tq)Ucj~bM{_Cli9>YAlh?V~LX%|qUxruArFL~Jt=K8lc_ zuQ6tiK`N-=vOfy21Zg0@HooE?2})_wL`wQn=s)sMO!LM)n9w+(HWE#wQgtL!Nz_`F zjq`6;-B;tOziH&!bk)?>#3Q{#?fqOsh>k5%nf0&x5dEal7WiA&?o_hu+GZm4 z?!ni$Ou`P828GiAH@&E@WlvERc0SBNQPl6NHFW&4e-Wc?Z|6?V_Pmk>fo#_mBCYuQ z4Z#c?p-YakuK=m>je3?ArCUNXGd{~a%PwVJ`u;o&&mAg4p@1~yev~r@DA-7e8w8-y z1SJEEz~Rr=74VjwIto{-65zA|^0oGfkd6BWMjI)!{`N3ON>dtctNe&lfZuuni2EU4 zpSaZ5rd6%%l4X86I9RSODZsoVj|wJlpfsdBmPB?_G&<`-_U+5X%Or6MP}3tRHYzbZ zo1LR0Lhtwae28pjQ=Ijyqv0%N63@)MYQEK!pEmrXnW~H}0#sypX5kw8GNn)<8EdV? zAiNe=2N`WNLm*l}Q$|fz71;eeO*#vy#y66r{7`i~M`vh?owo0J)wpuX8{9z1wjHav zzZ3xmr(FdBCPQHZvCZ*7;o2}&!7lo)03eYSY*N}GD6Hx573I?8U{!t)E0RxfzyM_vU( z9}1nE$|FM+tMz$v0_IG4tSZdwom4-BVX(+qSCjpV+3@&rE$C84fiKmKK z%3SUeq-tqNg=K#k9chcBlH#Yic6{)kz4SE0tSWF=Ko!w}p-w_(Pk8KCXAx}YIwS(U z9uRK}N42qm)Ed)nDT0e|n3*p*K3^+k)0*z`#Q3PM$OX`e8x*%%1=u1)ozr}odmqbd zg<_uhrg(evhxoSG2Nl1V4>XBBC2lK!K}FHo1}fa`X%)GIEc)VQ+rPY zJI6PTUf3keO*zuxge zPXi1s>hjai+NJj*bYn+pbE6=a`b&uENlq4d;Bt(^6hPS3<5J>LCLfsl)0) zp^~7*>ul>d7aHK#z_UemevH?C;lG`6V9EK%#epjNnujtA1ws~yqUgOINwqpl%nlre z?6P!Hxo$#ya@O=wDqzLSiUmQ<6*)uY{8-6h!FyE)d;YQj-f%I0a6wlLqOOWjfHOq4 z`?9e4%8iR^ym_rsQ5!cDx;hVt@zrsTo$#$CoMkANLPV=@3=LIhsVV!p%039*T z&SLof?smRbT|(Cp&Bi<6jAX^g$Y~7H2C^A=-cyj4d;;WuiFBdRj3l!=-+Bgd`Pos! zs4&+gO{vDMbBLhZx1a$@T?K)h@SWhf{fxUAn=b>ou++_chYQm5{7A z{0y9_iuFk5yt1!WyIBGyBkTsYq)H38z;|XVe*aL5NI#VNcuu}Dbb};@Q2?`==?oQg zzigbZe3G_1O{23mVST*DX-|#Pu}ah;r{oIJbQSHo!JU#L?yt(W1VHbMB+v(p89QSi z(P}SqyA`^e`Exa>|HQDXvB1v zY2!-xWydAN>ZQAs+j&iio?H*2he4xK3|wm1pr5+MljlX% z%Nl-fIH)LuU1}Q=P*TYi3rYOq%-$Xg$jLix1gOofSTsTqFY3Go2O9RT1qrO%4|FJ< zaj0MfPn`gFCgpzWXrGk#;-jKl%c!xY=iqIYttqP~o~TgJp`y*j*uw+J8b}dv1l}-m zZ*H-7!5Q@WobgdR*Kq$s@NCs{H0W}6#o# z1VDw&wVW!z5dklE7LD1StZoHO)=5D>$dVR}Hr$Sv;Max3QSg3-Z~Pqfw@>&x=gh^7 z`+T7(q&!-R8UBOO!6; z1g}Vj67MfQMIPYAtn=dsxhY(3WgVGZj<9M;=C|o-RT4=Coc9IdG=vJI6o^Xq%U?5F zLoT?QH1H`LaK8oq=+2k4oyw?zKzmZau9Ens^^(r=USbWL`3xOD>$z+_W;HuI+)aIZ zc`vS6@cEz${n2-$h^MJ#W~AmXGP4a4O|BHIO=L#Jk63az=R+UoLYuWd1U->35^5Lt zj)DCPsaj(lkLHp$lOW~m)+i-xVDsaO?Frwr+V0x=sftK0CbN4~Y$}1r8$^ zW8F+KNO&nnF!V+Zm}KsRktbQ#RhRU|l)0@q<+?S7GghmOsRH>axG6L+IZXOd*DVDv zZ%Cvt$i?1Y-77ryrqPJ}?!IgGhpr)zaG?*o(>&P4j?{oW8;&M$B|ppAYqZj!;^dq2 z+PJc=`T-0Fo5_SLb=pg;U$$QrAB&}8SpzFbkle~>@!+a$pY3~leDA*wla6tZ{=lQc zr8U_~|4e5+8X-VGq^6oF(Xv72eY$2TLr@;qwi6KA~S52_HHnXX{Y zd55-wGAW!l*SLHzc%WF;TlTPz#a;B?Oah+N9TRCzFo|h7ihh) zR!|^}wLEkr^U+;1T;+K~zsVa-2E*)|1X~JK2wVuNLM3K>r?MKGOW6&^Tw?hrNL?gq za5wz*AGKBRtta%w)Z z_^L09Zy;tr5XfDzQN`HApBG#Z_GMEQhjkB_b zB1n}ejTy^$k@+)qjX|faclOS+xJ@{AGY|g0Fn=MTFPms8s#*ILTXx+C^7!=B?6Ly9-@$= z9YsWB2^1C*UJzMBb%0CiqG9Y+SSQ{JrfH7l3EaD~xI?z2Dea5MCnn~ga+I9Puk`~dENrZ;MY1!8xkQbSyyAv2)c{BT zSI2BzxAr@#uHBjZG$*;BwOn@pE~PFzXDSE1jW~?X&pIBerra4+LTRKbAN$UCB z{CVe@%fy;u{$a!?<}FK5acZO$JfLdUwToqP0g{dyoATXdap@A1(A!|;KckY$)+f-D zRTF8Cj6?v0a8%H_YIYYr*89J>&qkhKDkWn@`^=KPeDtlQHU(2b{Zi%Bk+^~|3 z6eJ4q%_h~FN^C<{!&H1jtW?~09m*}uvVPz}>W+OGNTX{7(KhuyZ&?sGdS*4m24K%m zdU}&Q)3+BUrAoQBGsl@k!|^`nj`zGBE~-4YQ7gG})e4%ktC&i^po=hyn5`sfIbW@w z-hb(OeGFuI%^j*|zQ^;@%I9>xImBg*C;iC!fUveTv;}gqQs2J5r=of^jOwE&(=0l! zApK3LJ8+MCSY?IqzHpb}rQAj%C=;a+CP-to)j{hrm8A22t5h9~Qh&$}D}kw0b6<)& z2!~ka#9{cxR8x zC34rjE1&dzGLKMBAiwwW>sl5%Qe>)%m1Ua`hVCaTdbPnLW!KH^Th)7mg?X*jmsni; z%@j!zdQY`rOK#Td&HO;`S(AF$JNE(lkrUzwZfCG+z?zWdAbJB5R_BaT_wLe%+!668xmHQU0))%z`O`;x%h`VF zkH!oHm=|o4ZtwO19FPCt*8EdXyy7pFTv&X!+swX8FrBsPNUvrZksRSDtP%}q+=slM z{prNbfUdG~`y=rq;F7+99$_~}DAO2A1lEyK zdGUgj9D;#Y;qm#xQ{rnlo!qR56{w6?G)om5AT?Hp z+jXob`ZbQc)$lqGw+O*H+NxMN!eqnSa`fzytC_l!S?+`D>8;Oh;TFH40M?{sM zlkwiw7fQzs87sz&Veg{D`Nqk_QOk63lT46A9o@+;sTB65LW&~sLl0))uN*8w5mc|X zvcIKz?_R`*tP047dD2j+$k#H`480LX5cZEcHA_UB!p<;Xk4lf1!&6EPi;Y)#EKJ#} zYzI?x%k_zmIcU(nP<~K7h~Of|UcZN9t?<2fzYr}vgrSb-WT5jr4C8*&nOqJ1jm~cc zHUV3Qj?PY*+-M&$M!U+zlInUbtlnv_-WkOhLqX6b7EA0~-TIXmk8r4KW0QJc^h@on zehc}R4Y9_VC2X5`fIr%)Rt#RB6(7X7<2m=f%=!mM-4;0`2}w9VK>$OYh%K)-g7-DPD!a0l zx&1m0UnVXWU@rC0Ss)22qdtV8JqIs|1U(Vi)_NC4%(7|&XFsG7(kPoB|3b;+SgU@2 zEQa@c>{k`WQV=Qf=oL}~sW{C}m=N~*IVz;oQLiIbo@Spi3-Md-YJ!tS0IL_nvmKsJ zqJntmoVK=8xSSn_naers(jv!ms}-ec`mbu0tz$p2XDrP`jd%TNE7Eppped!*XFSF> z;t&j5OZk4I9;rFpj)lZ|*s%}I@C+z53&Vq=5OA)$?QqzbQQ=T*4M3R5w!PWDxI!&< zNY`?<>d$O`xrj{m$8@KT{B2=cJ2W3JYYllkX&x4i=-xzHwkKZ{Y+ZQ1wsdriTq?HMaIpYtI&Q1sh@NO22fkMxTW)dPJR#7FT5-mM=C}yp z38#UU3cj6&k7t`CwD)qurvWevMr7#JBe0-6eNED6NlD(l>DWQ5{J@?4_Y3mu5xA)Ut>lfX=RcC(mm0Jl}$DLM; zI(4Lsw`}i&7Y)7%S88|FEzm7+*V|#9A3pGkQ(LxC?XKXwfrXb=+0Rv8@_NgdIdftk zIm&_;c%_v7BeKRrMY+uz)wbR9q)bfirPPhmOS!+ zG(CDn^H-ghs->?Ahxdzf>-U52|NUE4YjZ?SNa2-=@lnl9RaV?Hb)L^Y>DEPbZLa&2 ze{E}M3y)57d(7RE+_m7vwo2L27mAhFEWFqw=#E)*$d0q6>#ALQ2J6M7ZS&C$ zN&a@wrt-VYB>ueRfk#Hz?;Y@J@sInS!yN`4GtyDCQ`;8#_1K}I3qCyZ9+7kRl~MS* z?XP+)j@mu!KxMhP)_`dV{{;l5JsQ*E>By~fP0zjmf*<;<0%!flTECL4wsdF4%c_1agZ(+jit`Nj+G zjdW5g*Et`VempM>0U$&cyWwHBXo-PVIdHnNa)7Hg% z15Qqx7&y+?v)zv3`0=mR`{dLPtQ_n#+G!HUCHk-TI+Huf^in=I(spUi<4?ycT(A3% zF7yd_Z_G`9HfeFw?rWQ7ZGZl>lj~fQdzk~SHR=wqG#WI#qG*D{qmbcx%bZ+$-ZV46 zQa#c@DPQR>SJvrkkH1&GUtN~D%Kg$<`P9n~AGCQq)61OjxX!4UauKyH*9i%{&cmACI=o%ce`!t-RDNc z>M!<*9YbWjOBdf(Eon_yoY42#{@alb?opEsHoSikGJPk

Pj@xwsPQg@@Q-ZKvO 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%0DY7G1VjT#|G_j8a+GAzx2PLGpk|HA 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 literal 0 HcmV?d00001 diff --git a/tradein-mvp/docs/PTITSA_MEETING_2026-05-19.pdf b/tradein-mvp/docs/PTITSA_MEETING_2026-05-19.pdf new file mode 100644 index 0000000000000000000000000000000000000000..1fd72a558604f62db11706f0509575478f5556fa GIT binary patch literal 134301 zcma&M1B`A@&^|bR$F^}OKN#>$A{M=qfq6D!C6&28mi zFZ!PVN>OfRMrL+KHYP464kkuMCK^UYil6qwC+A@L|INbB4{c^|`k#F)|Hn=fBSI!< z24Oiu26+c(J0siw!^Hl7n8dAYU4Kkt5dUuxqGl!zre@F#vS#)cu9k#Mj2z7D{QQJ2 zu0N}?gZ9k2^joh!;B>z9@ej=bFor$DI2z`8U+aBd2myZu`fb?Zw!+E2e+Px++5b(F z!OB-PTW%czZS_#1ijUqQYc&>A)Y3TnhVz~s=qWwQ9Y!sT#^Vp@`1~veI8;K1z&r|U zz30_4IK6xd*nfYe?)EqY^l+Kkmgc5^V;j7FTownzn<@6;@RXiJ;(a~c*D`#3F0UH| zxDV8PySTX5uEL8;@L`tkr)DxYzX+uxPUHY<|VEU+)@(IecFqRXQ)N2!4J%1pvI`&OtL(Bgid!cs<`Sw{OP1EjHeEKJ9!B zRjD>ZS~LlKeR0-NAW&K^naHQ$<{wAIX|i2i-R&eL1I%_dCo`))vZFcJA2np2k=gsbmV)t$r#!B*l zDXW^-@C8tmE*t9QtCIJs{;BNY(XQ$c>B(itHJFaCTc$3fKXrC^2AdCtJox<5eu%Hm z-!IH;90!(OpMuGS0KopiIkUWM4bnUPQaB#Xt(x{$@jK`cw@*(W|9Z#3a_WPdI*{eH(_UrJGioy1gdfPmopqnP%k%HN#do6~##>j^_Q|35H0vfV0 zM<91ysu%X~B8<|^l-qQp@%7*JQ_#_J0`kp}=HsH*MV*{Cp~R|lLS?%J7lU?xLan~O z*{ZJW%C-0v)h&hWN<9|rZuVr>ZEi*H&h7ZAk6)M4=_E<&Z4jm9E0dPj@0HXRJo&h? zGwxic?J;k2W##8w%4#i5q2fg6%=R!cq>h>#DBNzjXQuz4k9QljhD*;=CX`5rFOp$Wfp~iA&!Kcbcd&bzaof#4K5wD=4o`pGJegf? z4rBUW5+A1 z(GHZd5cBj6jOQ{F>!?IpFqwJw9^fiWE;BShB{(~b8ik;){i1`N$6C5Eg(zV?KUwuF zuPST^*eStxy>Z-^H~Rf_G=tHwT1Y4h@L&ti>qFD+#_H9ByF8A~Yl?N?F!RMyy?dw> zZax>V=yazLH7RhWVomU+QF(Te#q*7LrYh^LY_`cvm%Q&jBr4r##=W{mpaZd%kYa}& z56ddE*RfV{4{c?uqm+>JWg*R13kt)>MyJS|vJWsy7jm$AQ=iPRdKaD&=uMK^n+C8@ zVz}TYwa}|ZTtnv%j@cnmbm;l;G%-E}FZkR_(_a($ zg2HRQh&Slgm2}HVr&c}b)!xhEgyl<(i(QV}FEHt+mnKG;+iYdzJ)qZoTltTW*)*&} zErKQcI`i8mC#p)$of^07G07L5upR5%>$1q3p~%d8Rp4dJ(VxbFlwik}3w80H$Y$8w zs`Dh06s9n^(Dj|}`S}ZvN5$(UIW1v=il*q$b-e1(pQK^O%bgcPQ6JzoaIB~J`F4o$ zwHByh`gepDlvl7XC3w?fmQD^K-tCNf;WS36rnp56Ein@qyADuv;WbPx{hLR%N(w6o zZYEz~sG5%aZe-bzOfn`ui>uKSlN&Ppqu%4c7>P`f* zd=S%b`6Dl(VX3$~SLik2ZZSxTScof8wz29Um|1MSJW706==8+*^QZtWK*GjI`RuqV zK-Mot3I(I-hzshXULO@+oj^y#Upfbv2;fVe~_uX!7`bhVib$`7<)47@fuHnSF zn&7D_(4|@qvhbIM+5s=SyQON%{ojc!3BBp^V!*kfrh#6VoX!|`@6r+NzN6JGxBhx{ z6^Rd8KR2klQI$&(+BtWHI(Sl7LCV;x*Za&mL$A0btNot9B~x4McQ3zn5K)Q&J_>Q% zjIKXe2yq`NL@8CEHGa6LJ-E

m#S@XJ9kwqQrYyuwmsi$6~x5?2Xuip;`siNynqH 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

!Quk6wVF#%)ayv@v-NfBwE$N#snSU!!bv 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⪙qw#vFNSAA9H}xg-b`J7>H?9pcr)cR@@0 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 literal 0 HcmV?d00001 diff --git a/tradein-mvp/docs/README.md b/tradein-mvp/docs/README.md new file mode 100644 index 00000000..73f8bbaf --- /dev/null +++ b/tradein-mvp/docs/README.md @@ -0,0 +1,35 @@ +# docs/ + +Референсы для Trade-In MVP. + +## `BRUSNIKA_REFERENCE_EKB-2485.pdf` + +4-страничный отчёт «Брусника.Обмен» от 12.05.2026, объект Софьи Перовской 119/368 (Екатеринбург). + +Это **эталон layout-а** который Максим хочет получить (см. протокол Птицы 0:42:04: *«главное, чтобы выходила околореалистичная картинка как у Брусники»*). Структура: + +| Стр. | Что | +|---|---| +| 1 | Hero — параметры объекта + два диапазона цен (объявления / сделки) + блок «что важно при оценке» | +| 2 | Объявления-аналоги — 47 шт., источники Я.Недвижимость + Циан + ДомКлик + Avito + Росреестр, диапазон + табличка top-5 | +| 3 | Фактические сделки — 12 шт. из Этажи + ДомКлик + Росреестр за период 10.2025-05.2026, вывод «сделки на 5-12% ниже объявлений» | +| 4 | Формирование выкупной стоимости — сравнение Брусника.Обмен vs самостоятельная продажа + 4 преимущества | + +PDF-генератор в `backend/app/services/exporters/trade_in_pdf.py` уже повторяет эту структуру через WeasyPrint. + +## `PTITSA_MEETING_2026-05-19.pdf` + +AI-протокол встречи Максима Басова и Антона/Алекса 19.05.2026, 21:12. Это **источник требований** для MVP. + +Топ важных моментов: +- Концепция: сбор данных по квартире → подсос картографии ЕКБ → парсинг 6 агрегаторов → PDF-отчёт с PDF-кнопкой +- MVP-scope: **только актуальные объявления + исторические за квартал**, без ДДУ +- Монетизация: ~1% с каждой подтверждённой сделки +- Срок MVP: **понедельник 25.05.2026**; демо: четверг 28.05.2026 +- Sales engineer обязательно (без него продукт не взлетит) +- Серверы арендуем, не покупаем +- Доступ только Геныч / Загайнов / Паша Глухов. **НЕ Рожкова.** + +## ROADMAP + +Связан с roadmap в основном [README](../README.md). Phase 1 — замена mock-формулы на реальный парсинг. diff --git a/tradein-mvp/docs/ROADMAP.md b/tradein-mvp/docs/ROADMAP.md new file mode 100644 index 00000000..93f53051 --- /dev/null +++ b/tradein-mvp/docs/ROADMAP.md @@ -0,0 +1,439 @@ +# Trade-In MVP — Roadmap «Максимум» + +> Решение 19.05 вечером: убираем привязку к срокам, делаем максимально хорошо. +> План структурирован по архитектурным слоям, не по дням. Катимся сверху-вниз — +> каждый следующий слой требует, чтобы предыдущий был стабилен. + +## Видение продукта + +**Что есть у Брусники:** 4-стр PDF с медианой цен, диапазоном, аналогами и сравнением «их обмен vs самопродажа». Один white-label (Брусника). Один продукт. + +**Что мы делаем поверх:** + +1. **Парсим больше источников** (6 vs ~5 у Брусники): Авито, Циан, Дом.Клик, Я.Недвижимость, Н1, Дом.РФ +2. **Кликабельные ссылки** на каждый аналог — Брусника не даёт +3. **Real-time freshness** — индикатор «обновлено N минут назад» на каждом источнике +4. **Объяснимый confidence** — `high (12 аналогов, разброс ±8%)` вместо «качество данных может быть не очень» +5. **POI окружение** — школы / метро / магазины с decay по расстоянию (переиспользуем код gendesign Site Finder) +6. **Тренд цен** — график за 6/24 мес. в этом районе +7. **Map view** — карта с точками аналогов + heatmap +8. **Multi-tenant white-label** — PRINZIP / Практика / любой бренд через query param +9. **JSON API + iframe widget** — для интеграции в чужие CRM +10. **Похожие сделки в том же доме** — точные совпадения если есть +11. **AI narrative summary** — короткое описание квартиры от LLM +12. **Прогноз срока продажи** — median days_on_market по выборке +13. **Score breakdown explainability** — почему именно эта цена (как Site Finder) +14. **Photo upload** на cover PDF +15. **Shareable URL** + QR-код в PDF + +--- + +## Слой 1 — Core data layer (фундамент) + +Без него ничего не работает. Каждый последующий слой строится поверх. + +### 1.1 Postgres schema +- `listings` — объявления (id, source, source_url, lat, lon, address, rooms, area, floor, total_floors, year_built, house_type, repair_state, price, price_per_m2, photo_urls jsonb, listing_date, scraped_at, dedup_hash, raw_payload jsonb, geom GEOMETRY(Point, 4326)) +- `deals` — фактические сделки (тот же набор + deal_date, source = 'rosreestr' пока) +- `geocode_cache` — address → lat/lon кэш (избегаем повторных Yandex hits) +- `audit_log` — каждый POST /estimate (ip, user_agent, input, estimate_id, ts) +- `house_metadata` — кэш данных ЕКБ Геопортала по координатам/кадастру (этажи, год, материал, кол-во квартир) +- Индексы: GIST на geom, btree на (rooms, scraped_at), unique на dedup_hash + +### 1.2 Geocoder + Suggest +- `app/services/geocoder.py` — Yandex Geocoder через httpx + кэш в `geocode_cache` +- `app/services/suggest.py` — Yandex Suggest для frontend autocomplete (proxy через backend, не светим API key в браузере) +- Fallback к Nominatim если Яндекс упал / лимит + +### 1.3 Scraper framework +- `app/services/scrapers/base.py` — общий BaseScraper +- Retry через `tenacity` (3 попытки, exp backoff) +- Rotation: пул из 5-10 User-Agent + Accept-Language +- Sleep 5-10 sec между запросами (без бана) +- Поддержка Playwright если scrapy не справляется (Циан иногда JS-render требует) +- Дедупликация: `dedup_hash = sha256(source + source_url + price)` уникальный +- Каждый scraper возвращает list[ScrapedLot] — единая Pydantic схема + +--- + +## Слой 2 — Парсеры источников + +### 2.1 Авито (приоритет 1 — стартуем с него) +- URL: `/ekaterinburg/kvartiry/prodam?radius=N&geoCoords=lat,lon&list_view=1` +- Парс HTML через `selectolax` (быстрее BeautifulSoup) +- Поля: address, rooms, area, floor/total_floors, price, listing_date, photo, deeplink +- Edge case: «частный риэлтор» vs «агентство» — фильтруем спам + +### 2.2 Циан ✅ ДЕПЛОЕН +- URL: `https://ekaterinburg.cian.ru/cat.php?...` +- ВАЖНО: Циан банит httpx по TLS fingerprint → `curl_cffi(impersonate="chrome120")` +- 2025+ верстка БЕЗ `__NEXT_DATA__` — парсим DOM по `data-mark` атрибутам: + `OfferTitle`, `MainPrice`, `Description`; адрес из множественных `data-name="GeoLabel"` +- Multi-room scrape: `fetch_around_multi_room()` по rooms=1/2/3/4 → ~108 unique lots +- Cron каждый час: `45 * * * * /opt/tradein-mvp/deploy/cron-scrape.sh cian fast` + +### 2.3 Росреестр сделки +- Дамп из prod gendesign `rosreestr_deals` (6.83M строк, partitioned по кварталам) +- SSH туннель → `pg_dump --table rosreestr_deals --where "region_code = 66"` → restore локально +- Регулярный refresh: weekly Celery task + +### 2.4 Дом.Клик +- API: `https://api.domclick.ru/...` (публичный, без auth, JSON) +- Поля: те же + ипотечные опции (мы пока игнорим) + +### 2.5 Я.Недвижимость ✅ ДЕПЛОЕН +- URL: `https://realty.yandex.ru/ekaterinburg/kupit/kvartira/?rgid=240970&offerType=SELL` +- State в `