From 8abf40338adcd23a3ad71ad273787f20d174b9ab Mon Sep 17 00:00:00 2001 From: pierre Date: Tue, 15 Sep 2026 11:08:59 +0400 Subject: [PATCH] doc --- .github/workflows/docs.yml | 54 ++++++ .gitignore | 3 + Makefile | 8 +- README.md | 326 ++------------------------------- docs/contributing.md | 76 ++++++++ docs/index.md | 47 +++++ docs/logo.png | Bin 0 -> 151161 bytes docs/setup/configuration.md | 45 +++++ docs/setup/index.md | 11 ++ docs/setup/installation.md | 61 +++++++ docs/troubleshooting.md | 45 +++++ docs/usage/automations.md | 173 ++++++++++++++++++ docs/usage/celery-app.md | 33 ++++ docs/usage/index.md | 49 +++++ docs/usage/mcp-clients.md | 26 +++ docs/usage/metrics.md | 31 ++++ docs/usage/queues.md | 28 +++ docs/usage/task-actions.md | 56 ++++++ docs/usage/tasks.md | 89 +++++++++ docs/usage/workers.md | 91 +++++++++ mkdocs.yml | 64 +++++++ pyproject.toml | 4 + uv.lock | 355 ++++++++++++++++++++++++++++++++++++ 23 files changed, 1368 insertions(+), 307 deletions(-) create mode 100644 .github/workflows/docs.yml create mode 100644 docs/contributing.md create mode 100644 docs/index.md create mode 100644 docs/logo.png create mode 100644 docs/setup/configuration.md create mode 100644 docs/setup/index.md create mode 100644 docs/setup/installation.md create mode 100644 docs/troubleshooting.md create mode 100644 docs/usage/automations.md create mode 100644 docs/usage/celery-app.md create mode 100644 docs/usage/index.md create mode 100644 docs/usage/mcp-clients.md create mode 100644 docs/usage/metrics.md create mode 100644 docs/usage/queues.md create mode 100644 docs/usage/task-actions.md create mode 100644 docs/usage/tasks.md create mode 100644 docs/usage/workers.md create mode 100644 mkdocs.yml diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 0000000..8da1800 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,54 @@ +name: Docs + +on: + push: + branches: [main] + paths: ["docs/**", "mkdocs.yml", "pyproject.toml", "uv.lock"] + workflow_dispatch: + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: pages + cancel-in-progress: true + +jobs: + build: + name: Build docs + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.14' + + - name: Install uv + uses: astral-sh/setup-uv@v3 + + - name: Install docs dependencies + run: uv sync --group docs + + - name: Build with mkdocs + run: uv run mkdocs build --strict + + - name: Upload Pages artifact + uses: actions/upload-pages-artifact@v3 + with: + path: site + + deploy: + name: Deploy to GitHub Pages + needs: build + runs-on: ubuntu-latest + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 \ No newline at end of file diff --git a/.gitignore b/.gitignore index 798061c..105d964 100644 --- a/.gitignore +++ b/.gitignore @@ -46,6 +46,9 @@ htmlcov/ # ruff .ruff_cache/ +# Docs +site/ + # Database *.db *.sqlite diff --git a/Makefile b/Makefile index f66f475..f5dc69c 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: help install api consume mcp test lint lint-fix typecheck check migrate migrate-create clean +.PHONY: help install api consume mcp test lint lint-fix typecheck check migrate migrate-create docs docs-serve clean help: ## Show this help message @echo "Available commands:" @@ -38,6 +38,12 @@ migrate: ## Run database migrations migrate-create: ## Create new migration (usage: make migrate-create MSG="description") uv run alembic revision --autogenerate -m "$(MSG)" +docs: ## Build the documentation site + uv run mkdocs build + +docs-serve: ## Serve documentation locally (http://localhost:9000) + uv run mkdocs serve -a localhost:9000 + clean: ## Remove caches and build artifacts find . -type d -name "__pycache__" -exec rm -rf {} + find . -type d -name ".pytest_cache" -exec rm -rf {} + diff --git a/README.md b/README.md index ac360ae..a94c389 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ # taskowl +[![Documentation](https://img.shields.io/badge/docs-github_pages-blue)](https://kalvadtech.github.io/taskowl/) + Modern Celery task monitoring with MCP integration. No UI, just data. ## Features @@ -9,13 +11,20 @@ Modern Celery task monitoring with MCP integration. No UI, just data. - **MCP-first**: Query and manage tasks, workers, and queues via the Model Context Protocol - **Event sourcing**: Append-only event log for a complete audit trail and state reconstruction - **Real-time monitoring**: Capture Celery events as they happen -- **Task actions**: Revoke, retry, and recover orphaned tasks -- **Worker management**: List, inspect, scale, and shut down workers -- **Alerts**: Slack-compatible webhook notifications on failures, slow tasks, and offline workers -- **Prometheus metrics**: Scrape task and worker telemetry via `/metrics` +- **Task actions**: Revoke, retry, recover orphaned tasks, and execute tasks by name +- **Worker management**: List, inspect, scale, restart, and shut down workers +- **Queue monitoring**: Per-queue message and consumer counts for any kombu broker +- **Workflow automations**: Declarative trigger → conditions → actions engine with + webhooks, retry orchestration, cooldowns, rate limits, and circuit breakers +- **Prometheus metrics**: Scrape task, worker, and automation telemetry via `/metrics` - **PostgreSQL backend**: Production-ready, async throughout - **Broker-agnostic**: RabbitMQ, LavinMQ, Redis, or any Celery/kombu broker +## Documentation + +The full documentation lives on [GitHub Pages](https://kalvadtech.github.io/taskowl/) — +setup, configuration, a complete usage guide, and troubleshooting. + ## Quick Start ### Prerequisites @@ -46,11 +55,9 @@ make consume # Celery event consumer make mcp # MCP server on :8001 ``` -## Configuring your Celery app +### Connect your Celery app -taskowl listens to Celery's **events** stream, which workers emit only if -enabled. Add this to your Celery application so taskowl can see your tasks and -workers: +taskowl listens to Celery's **events** stream, which workers emit only if enabled: ```python # celery_app.py @@ -58,34 +65,23 @@ from celery import Celery app = Celery("myapp", broker="amqp://guest:guest@localhost:5672//") -# Workers emit task/worker events (sent, received, started, succeeded, failed, ...) app.conf.worker_send_task_events = True - -# Emit a 'task-sent' event when a task is published app.conf.task_send_sent_event = True - -# How often workers send a heartbeat (default: 2s). Higher values -# increase the worker-offline detection delay. app.conf.worker_heartbeat_interval = 2 ``` -Alternatively, start your worker with the `-E` flag, which is equivalent to -`worker_send_task_events = True`: +Or start your worker with `-E`: ```bash celery -A myapp worker -E --loglevel=info ``` > **Note**: If events are not enabled, taskowl simply sees nothing — no tasks, -> no workers. Enabling events is the one integration required. +> no workers. -## Connecting MCP clients +### Connect an MCP client -The MCP server runs on `http://localhost:8001/mcp` (Streamable HTTP). - -### opencode - -Add a remote MCP server to your `opencode.json`: +The MCP server runs on `http://localhost:8001/mcp` (Streamable HTTP). For opencode: ```json { @@ -100,288 +96,6 @@ Add a remote MCP server to your `opencode.json`: } ``` -### Other MCP clients - -Point your MCP client at the Streamable HTTP endpoint `http://localhost:8001/mcp`. -If authentication is enabled (see below), send the taskowl API key as -`Authorization: Bearer ` with each request. - -## Available tools - -| Category | Tools | -|---|---| -| **Tasks** | `list_tasks`, `get_task`, `get_task_timeline`, `get_task_chain`, `get_task_summary`, `list_task_types`, `list_orphaned_tasks` | -| **Task actions** | `revoke_task`, `retry_task`, `execute_task` | -| **Workers** | `get_worker_status`, `list_workers`, `get_worker_stats`, `shutdown_worker`, `scale_worker_pool`, `restart_worker_pool`, `get_active_tasks`, `get_scheduled_tasks`, `get_reserved_tasks` | -| **Queues** | `list_queues` | -| **Automations** | `list_automations`, `create_automation`, `get_automation`, `update_automation`, `delete_automation`, `toggle_automation`, `get_automation_runs`, `get_automation_status` | - -**Total: 28 tools** - -`list_tasks` supports exact filters (`state`, `name`, `worker`, `since`), a partial -case-insensitive `search` on the task name, `offset` for pagination, and `sort_by` -(`timestamp` [default, newest-first], `name`, `state`, `worker`). - -### Automations - -Automations are declarative **trigger → conditions → actions** definitions that drive -workflow automation (a superset of the env-var alerts). They are managed via the -`/api/automations` endpoints and the `*_automation` MCP tools. - -Event triggers are evaluated by the consumer process: when an enabled automation's -`event_type` matches an incoming Celery event and all its `conditions` pass, its actions -fire. Every evaluation is recorded in the append-only `automation_runs` log (metadata only -— args, kwargs, results, and tracebacks are never stored), queryable via -`GET /api/automations/{id}/runs` and the `get_automation_runs` MCP tool. - -```bash -curl -X POST http://localhost:8000/api/automations \ - -H "Authorization: Bearer $API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "name": "alert-on-failure", - "trigger_type": "event", - "event_type": "task-failed", - "conditions": [{"field": "name", "op": "eq", "value": "payments.charge"}], - "actions": [{"type": "log"}] - }' -``` - -Trigger types: `event` (with `event_type`) or `periodic` (with `schedule_seconds`). -Conditions use `{field, op, value}` against event fields (including dotted paths) with ops -`eq/neq/gt/gte/lt/lte/contains/matches/in/exists`. - -Action types: -- `log` — write to the application log (`level`, `message`) -- `slack_webhook` — Slack-formatted webhook (`webhook_url` or `ALERT_WEBHOOK_URL`, `text`, `fields`) -- `webhook` — generic JSON webhook (`url`, `payload`) -- `retry_task` — retry the event's task (`task_id` defaults to the event `uuid`) -- `execute_task` — send a task by name (`name`, `args`, `kwargs`, `queue`, `countdown`, `eta`, `expires`, `priority`) -- `revoke_task` — revoke the event's task (`task_id` defaults to the event `uuid`, `terminate`) -- `check_workers_offline` — scan for stale/offline workers and alert (used by the - seeded `alert-worker-offline-sweep` periodic automation) - -Action params support `{event.field}` interpolation (e.g. `"task_id": "{event.uuid}"`). - -Safety knobs prevent alert/action storms: -- `cooldown_seconds` — after firing, wait at least this long before firing again -- `max_runs_per_window` + `window_seconds` — fire at most `max_runs_per_window` times per `window_seconds` -- `circuit_breaker` — `{"failure_threshold": N, "window_seconds": W}`; skips actions - (`"circuit_open"`) once the automation has fired N times within W seconds, and auto-closes - once the window rolls past - -Skipped evaluations (cooldown, rate limit, or circuit open) are still recorded in -`automation_runs` with a `details.skipped` reason (`"cooldown"` / `"rate_limited"` / -`"circuit_open"`), keeping storm suppression auditable. - -**Periodic triggers**: automations with `trigger_type: "periodic"` and `schedule_seconds` -run on a schedule (evaluated by the consumer's periodic loop, checked every -`AUTOMATION_CHECK_SECONDS`). Their conditions are evaluated against an empty event context, -so they are typically used for schedule-driven actions (e.g. a heartbeat webhook). - -## Examples - -Questions you can ask your AI assistant when the MCP server is connected: - -| Question | Tools used | -|---|---| -| "Show me failed tasks from the last hour" | `list_tasks` | -| "Which task types are running?" | `list_task_types` | -| "Which tasks are orphaned?" | `list_orphaned_tasks` | -| "Show me the timeline for task abc" | `get_task_timeline` | -| "What's the retry chain for task abc?" | `get_task_chain` | -| "What's the task success rate in the last 30 minutes?" | `get_task_summary` | -| "Which workers are online?" | `get_worker_status`, `list_workers` | -| "How many messages are in each queue?" | `list_queues` | -| "Shutdown worker celery@worker1" | `shutdown_worker` | -| "Restart the pool on celery@worker1" | `restart_worker_pool` | -| "What's scheduled to run next?" | `get_scheduled_tasks`, `get_reserved_tasks` | -| "Retry task abc" | `retry_task` | -| "Run myapp.tasks.process now" | `execute_task` | -| "Create an automation that alerts on payment failures" | `create_automation` | - -## Architecture - -``` -Celery workers ──events──▶ Broker ──▶ taskowl consumer ──▶ PostgreSQL - │ - REST API ◀───────────────────────────┘ - ▲ - │ HTTP - MCP server ──▶ LLM / MCP client -``` - -- **Consumer** (separate process) captures Celery events and appends them to - PostgreSQL (`task_events`, `worker_events`). -- **REST API** serves queries and actions over the event-sourcing tables. -- **MCP server** is a thin wrapper that calls the REST API for LLM access. - -## Configuration - -All configuration is via environment variables: - -| Variable | Description | Default | Required | -|----------|-------------|---------|----------| -| `DATABASE_URL` | PostgreSQL connection string | `postgresql+asyncpg://localhost:5432/taskowl` | Yes | -| `CELERY_BROKER_URL` | Celery broker URL (RabbitMQ, Redis, etc.) | `amqp://guest:guest@localhost:5672//` | Yes | -| `TASKOWL_HOST` | FastAPI server host | `0.0.0.0` | No | -| `TASKOWL_PORT` | FastAPI server port | `8000` | No | -| `MCP_HOST` | MCP server host | `0.0.0.0` | No | -| `MCP_PORT` | MCP server port | `8001` | No | -| `LOG_LEVEL` | Logging level (DEBUG, INFO, WARNING, ERROR) | `INFO` | No | -| `API_KEY` | API key for authentication (optional) | None (disabled) | No | -| `ORPHAN_GRACE_SECONDS` | Wait after task started before flagging as orphan | `60` | No | -| `WORKER_OFFLINE_TIMEOUT_SECONDS` | No heartbeat for this long means worker is offline | `30` | No | -| `ALERT_WEBHOOK_URL` | Slack webhook URL to post alerts to (disabled if unset) | None | No | -| `ALERT_ON_TASK_FAILED` | Enable task-failed alerts | `true` | No | -| `ALERT_ON_WORKER_OFFLINE` | Enable worker-offline alerts | `true` | No | -| `ALERT_SLOW_TASK_SECONDS` | Alert when a succeeded task exceeds this runtime | None | No | -| `ALERT_WORKER_CHECK_SECONDS` | Interval for the periodic stale-worker check | `30` | No | -| `AUTOMATION_CHECK_SECONDS` | Interval for the periodic automation evaluation loop | `5` | No | - -### Brokers - -taskowl works with any Celery/kombu broker via `CELERY_BROKER_URL`: - -```bash -export CELERY_BROKER_URL="amqp://guest:guest@localhost:5672//" # RabbitMQ / LavinMQ -export CELERY_BROKER_URL="redis://localhost:6379/0" # Redis -``` - -### Alerts / Webhooks - -> **Deprecated in favor of Automations.** The `ALERT_*` env vars below are -> legacy: on consumer startup they seed the equivalent built-in automations -> (`alert-task-failed`, `alert-slow-task`, `alert-worker-offline`, -> `alert-worker-offline-sweep`), which are then managed like any other -> automation via the API/MCP. Prefer defining automations directly. - -Set `ALERT_WEBHOOK_URL` to a Slack incoming webhook to receive notifications on -task failures, offline workers, and slow tasks. Alerting is **off by default**. - -```bash -export ALERT_WEBHOOK_URL="https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX" -``` - -Conditions: - -- `ALERT_ON_TASK_FAILED=true` (default) — notify when a task fails -- `ALERT_ON_WORKER_OFFLINE=true` (default) — notify when a worker goes offline - (via a `worker-offline` event or a stale heartbeat detected every - `ALERT_WORKER_CHECK_SECONDS`) -- `ALERT_SLOW_TASK_SECONDS=30` — notify when a succeeded task exceeds 30s - -Payloads are Slack-formatted and contain task metadata only (name, task ID, -worker, error, runtime) — args, kwargs, and results are never sent. - -### Prometheus Metrics - -Scrape task and worker telemetry from the API server: - -```bash -curl http://localhost:8000/metrics -``` - -```yaml -scrape_configs: - - job_name: taskowl - metrics_path: /metrics - scrape_interval: 15s - static_configs: - - targets: ["localhost:8000"] -``` - -| Metric | Type | Labels | -|--------|------|--------| -| `taskowl_task_events_total` | Counter | `event_type`, `task_name`, `worker` | -| `taskowl_task_execution_duration_seconds` | Histogram | `task_name` | -| `taskowl_worker_status` | Gauge (1 = online, 0 = offline) | `worker` | -| `taskowl_worker_active_tasks` | Gauge | `worker` | -| `taskowl_worker_processed_total` | Counter | `worker` | -| `taskowl_automation_fired_total` | Counter (automation runs that fired actions) | `automation_id`, `trigger` | -| `taskowl_automation_skipped_total` | Counter (runs skipped by a safety mechanism) | `automation_id`, `reason` | - -> **Security**: `/metrics` is intentionally unauthenticated so Prometheus can -> scrape it without the taskowl API key. Only expose it to trusted networks or -> behind a reverse proxy. - -## Authentication - -Optional API key authentication protects the REST API and MCP server. Set -`API_KEY` to enable it; all requests must then include -`Authorization: Bearer `. - -```bash -export API_KEY="your-secret-key-here" -curl -H "Authorization: Bearer your-secret-key-here" http://localhost:8000/api/tasks -``` - -When authentication is disabled, all endpoints are open. `/health`, `/`, and -`/metrics` remain open regardless. - -## REST API - -The API server (port 8000) exposes a REST API for tasks, workers, orphans, -retries, and metrics. Interactive docs are available at: - -- Swagger UI: `http://localhost:8000/docs` -- ReDoc: `http://localhost:8000/redoc` -- Raw OpenAPI schema: `http://localhost:8000/openapi.json` - -| Area | Endpoints | -|------|-----------| -| **Tasks** | `GET /api/tasks`, `GET /api/tasks/{id}`, `GET /api/tasks/{id}/timeline`, `GET /api/tasks/{id}/chain`, `GET /api/tasks/summary`, `GET /api/tasks/types`, `GET /api/tasks/orphaned` | -| **Task actions** | `POST /api/tasks/{id}/revoke`, `POST /api/tasks/{id}/retry`, `POST /api/tasks/execute` | -| **Workers** | `GET /api/workers`, `GET /api/workers/list`, `GET /api/workers/{name}/stats`, `GET /api/workers/active-tasks`, `GET /api/workers/scheduled`, `GET /api/workers/reserved` | -| **Worker actions** | `POST /api/workers/{name}/shutdown`, `POST /api/workers/{name}/scale`, `POST /api/workers/{name}/restart` | -| **Queues** | `GET /api/queues` | -| **Automations** | `GET /api/automations`, `POST /api/automations`, `GET /api/automations/{id}`, `PUT /api/automations/{id}`, `DELETE /api/automations/{id}`, `POST /api/automations/{id}/toggle`, `GET /api/automations/{id}/runs`, `GET /api/automations/{id}/status` | -| **Ops** | `GET /health`, `GET /metrics` | - -The `/openapi.json` schema is the authoritative reference — this README lists -only endpoint groups. - -## Troubleshooting - -### Worker not appearing / no events in the database - -1. Verify workers emit events — start with `-E` or set `worker_send_task_events`. -2. Check the consumer connected: - ```bash - make consume 2>&1 | grep "Connected to Celery broker" - ``` -3. Verify events reach the broker: - ```bash - celery -A your_app events --dump - ``` -4. Check event counts in the database: - ```sql - SELECT COUNT(*) FROM task_events; - SELECT COUNT(*) FROM worker_events; - ``` - -### Database connection errors - -- `pg_isready` to confirm PostgreSQL is up. -- Check `DATABASE_URL` format: `postgresql+asyncpg://user:pass@host:port/dbname`. -- Verify the role has access to the database. - -### Broker connection errors - -- `rabbitmqctl status` (or your broker's health check) to confirm it's running. -- Check `CELERY_BROKER_URL` format and credentials. - -### Port already in use - -- API: `lsof -i :8000` / MCP: `lsof -i :8001` -- Kill the offending process: `kill $(lsof -t -i :8001)` - -### Getting help - -Open an issue with the error message, environment details, steps to reproduce, -and relevant (sanitized) logs: -https://github.com/KalvadTech/taskowl/issues - ## Contributing See [CONTRIBUTING.md](./CONTRIBUTING.md) for development setup, code style, @@ -394,4 +108,4 @@ MIT — see [LICENSE](LICENSE) for details. ## Acknowledgments - [Flower](https://github.com/mher/flower) — the original Celery monitor -- [Kanchi](https://github.com/getkanchi/kanchi) — modern Celery monitoring inspiration +- [Kanchi](https://github.com/getkanchi/kanchi) — modern Celery monitoring inspiration \ No newline at end of file diff --git a/docs/contributing.md b/docs/contributing.md new file mode 100644 index 0000000..787a4ae --- /dev/null +++ b/docs/contributing.md @@ -0,0 +1,76 @@ +# Contributing + +Thank you for your interest in contributing to taskowl! + +## Development setup + +See the [Installation](setup/installation.md) guide to get a local environment +running, then continue here. + +## Development workflow + +1. **Create a feature branch**: + + ```bash + git checkout -b feature/your-feature-name + ``` + +2. **Make your changes** — follow the existing code style, add tests, update docs. + +3. **Run quality checks**: + + ```bash + make check # Runs lint, typecheck, and tests + ``` + +4. **Commit and push**, then open a pull request. + +## Code style + +- **Formatter**: ruff (line length: 100) +- **Type checker**: ty (strict mode) +- **Import sorting**: ruff (isort) +- **Python version**: 3.14+ + +Guidelines: + +- **Type annotations**: All functions must have type hints. +- **Async/await**: Use async for I/O operations. +- **Error handling**: Be explicit about error cases — return `{"error": ...}` + dicts from core functions, surface them as HTTP 4xx/5xx in the API layer. +- **Documentation**: Document public APIs with docstrings. + +## Testing + +```bash +# Run all tests +make test + +# Run a specific test file +uv run pytest tests/test_queries.py -v +``` + +Tests live in `tests/`, named `test_.py`, using fixtures from +`conftest.py`. + +## Docs + +The site is built with MkDocs + Material. Edit pages under `docs/`, then verify +locally: + +```bash +make docs # build the site +make docs-serve # preview at http://localhost:9000 +``` + +## Pull requests + +Before submitting: all tests pass (`make check`), code is formatted +(`uv run ruff format .`), no lint errors, docs updated if needed, and tests added +for new functionality. At least one approval is required; merges are squash +merged to `main`. + +## License + +By contributing, you agree that your contributions will be licensed under the +MIT License. \ No newline at end of file diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..9c2f0b3 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,47 @@ +# taskowl + +Modern Celery task monitoring with MCP integration. No UI, just data. + +taskowl watches your Celery cluster's **event stream**, stores every event in +PostgreSQL as an append-only audit log, and exposes that data — plus task, +worker, and queue operations — through a REST API and a set of MCP tools for +LLM-driven monitoring and management. + +## Features + +- **MCP-first**: Query and manage tasks, workers, and queues via the Model Context Protocol +- **Event sourcing**: Append-only event log for a complete audit trail and state reconstruction +- **Real-time monitoring**: Capture Celery events as they happen +- **Task actions**: Revoke, retry, recover orphaned tasks, and execute tasks by name +- **Worker management**: List, inspect, scale, restart, and shut down workers +- **Queue monitoring**: Per-queue message and consumer counts for any kombu broker +- **Workflow automations**: Declarative trigger → conditions → actions engine with + webhooks, retry orchestration, cooldowns, rate limits, and circuit breakers +- **Prometheus metrics**: Scrape task, worker, and automation telemetry via `/metrics` +- **PostgreSQL backend**: Production-ready, async throughout +- **Broker-agnostic**: RabbitMQ, LavinMQ, Redis, or any Celery/kombu broker + +## Architecture + +``` +Celery workers ──events──▶ Broker ──▶ taskowl consumer ──▶ PostgreSQL + │ + REST API ◀───────────────────────────┘ + ▲ + │ HTTP + MCP server ──▶ LLM / MCP client +``` + +- **Consumer** (separate process) captures Celery events and appends them to + PostgreSQL (`task_events`, `worker_events`, `automation_runs`). +- **REST API** serves queries and actions over the event-sourcing tables. +- **MCP server** is a thin wrapper that calls the REST API for LLM access. + +## Get started + +Jump into the [Installation](setup/installation.md) guide to run taskowl, or head +straight to the [Usage Guide](usage/index.md) for the MCP tools and REST API. + +!!! note + taskowl only sees what your Celery workers emit. Make sure + [events are enabled](usage/celery-app.md) — otherwise taskowl sees nothing. \ No newline at end of file diff --git a/docs/logo.png b/docs/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..d0dadf181c88a7d864f381dabaa5458d06f63519 GIT binary patch literal 151161 zcmV)fK&8KlP)DX=7n*SO79HGBCq)al`-s01b3SSafV}XK7<$Y*_#? zFfuarRtA&+000kkMObumV{&C>ZU9I`O-U_5Eio?*pM?MbAOJ~3K~#8N%zX#AT}9RC zy7!*jTY3UX=)EZ*ib@d`=?EB5EJzc7P(%@=N);6m5%gCdid01@p^Ee(Qlvx#1VTay zA&^3n+k1K6YBOtQ&)(+*ec$&M+?>6qu32^Zt{NK~8wUWWs;a^t7$2wCe5k_zF|DLC zKjZlCxW;o@mo2A!Q&I-1#;L>r@LkKodTa^|*YfdK(-i_0m=je{hOMg-uw})09o;bA zk~UNSIM^zS+NUv_$U4|?eop*FF zc{z!pmBfcyk`HOQQhH=jqOgb`YpVN!k&|C)rL(1#LtrZs5X)<&a*B{_lhPJ{qxfnL zXJXKw)+-4yqoRrFd}AZzoxquJQx}(S8*R&q5=TN2)MOYD6DE&Pgm+AA*U&Q3mVi9Q zW71f9T4$1rMn*Bq0JXJ< zo<25}Dwa3%5+*DF%}2k9d>B$>7Ob3?wJ8e9_Jq7zXIqpmaQ0F8Hf`)U;&_UxRQ3ge z+_4kYkw*$#Qj;mH7khj9$senA3T>Kg+BBqVg zSDKsBMZH(en`-ud19IukkUqqOPG z6y)g#g_qHXvW}x%<07c2skQ?&Iyx$H>~kvO-up>hmG_2@)e_};6%ho)F^@&Y$9wK@ zu9J6~ok&@@5IxRa2QvvM+mP|oON%An+qh#|?19LH=- z(@sY8G>ur0&cx-l&xX^pk!dnM$_wGO)@#dg`Nq?u;+XdMt9es+$2`(!hlAs7#Jebc z5N9COeqX0IDJdL_@ReLrMxqUo46A(S$&#}z4xwxuC-8AZBWsu9_G!4`Q%vUotPL=b zp##Z4NUxH8p=VC%1<417t;;~#=#}f~g-A+Dd`yjrf@1K+5Gb#X2&b5lDg0a*HVGYO z1gZ2zV3jWyQqwOYG}Ka;)k_lNDVg;LqhmfK&?7~0M3J&$!9qv`1rV|!6RxzehRQ*t z6d4{CkTq5o8>Y`G#g3IKLvs^{5XTqEvT2Or7Zs9yE--%9X((jm*6VVzj8s^XzZw@a z(%Ekbv$H6MZ%MgTa0tf1As#UwV%c;`U?8{70`SfvMNfWLxlx=l{1-e@w6wA=0fn|9 zh|7q+Da+`HJS6osBb(7kNNt+NWzq2PQE(u=0OURnV#hx6UB5h2w}ncABE@2 zRXAj4r1eD?My&@c7Jdh|zL+?Qmw8_kNE$efaDPntoHPYtX=Tp}1SaFOoSy!Td1Clb z7L=`)wyGfbUk=Tcf9w>rn5gY3S+Tf9csiL8pmyfbG?uMIQ7@7?{SlCxv`D1&$)bLw9A5PL%FmSlo!({mirPt6MO4 zgov4v5V(qr5`rd6;2kh87J@*!yf9`J#0aY7i*ZYZ1t3v2O)L~CVY1~~rxMdh4MrH} z|IL7*nM;p9u4g1IwkTrx3FD!7dn0df3TSK|1y@U1E{5eIqcDUUm+o?;dZU!i2FUKa zSU3W-jEv;a%cZe(hGLN`x7e200H+Lsqod`qBumL#D!dYKw0FGbh9vE4p3a!G0sqU% zbV`0q+L%wNO$WX{`ZtJ6;fJ8I#sB(gD<>|(OQm_%1~A05%Y&Hb5*iC<7K}_K>nay7 zp!EkbW-_5%%bZ! zm1|twkaFoglr_YuqD+=l{*>dezb-r)y_AzBt*cx*M!H-YHN?fdOx2aa!_p&eBfgW) z2f-Taf_=2=KpL>Pq!EwG_eo?r1$#-ZjbUQfo&u63>r8}a>6q6N1Ih<^$T*G^MAZcK z+F6BECu$9V`4pp_>F9u!wv^9WZPVo@ZQ29LPYptxIIP&wi?uGCOb3X@XuAZTkM&Nh$2Vm@2m;79>`l!-Mw zmnPy=&?yN>#+0Uak!5^mG%X!NIpyM%PCl*6?~^7wH%w!TqeMpJ33w6l(ivJ`Oi)hB zCdE3LbR3a0;Gisi4mT6$ zf+Hg6YnkD&f+|@>;IbE`_ry;5ABRIC&JjTVBfO-EDJ6Aa$iS~z=F+qL7pIqmp+egE z{Jg5gsk~npPb|_?jX4g#2o;LPv^H;?I%rl$@+s1}zzAd#i;>9~BIb1-hL*S7o)DwJaYRJ4j)i_w zWXgaM5GxZg+D5)pHmZ=H2^_4n1agxR$$VZ~`I7+AHLlPa>=<(Gl1}l(@#fV!93P!e zXeT4KjI1(Ix)K+z)XWyDm0PbE#|81`IYSr&PLZu=%n(UNLB_Cia>12e#`*NF!!KKB zswWZ{PaSm>;OpYdH5h>$CCZhISrFesIh+PXf@PCabG6MrNwVk&48xO2`ZAfln7#L3k2x5_C0*RX#K6f&x9g z#2jRzIGemU_4IWX+5n4>WX{S#MBO;r1)Gs=88#Q%n@Aq%-4HvoZQ96sejAFRTzaif z+s6y$u43)USGY(QJC8_`V&VjbrU0y`(_wZH7UPl6%d+5%fH2z{g(SX-bQ~XMk(A+)5XH2N%CN;28oWfDcPycRrqeN2j{Z93mTH%RjU%DY$IsC+PGeu=Y9iWX zK$OcuQHQ{m6XTIFG!;M~t3~zZ#9Qz@j>EGwv+YUgYD#YuG^R*LE#3^AD{euMUm~qe zDbIa+j1XBAJ+cm+bxq~U7p-xcFN3vdbKEZb9@9osVMvgV@N~(twjzr`2Hzl^%D!}t zig2=ySiw1oGBTtP+bo1~HaR6X3OsG);&cd9vbd_tn0hc|`Ip;v7M%;qyxW?fDeY`_0v`+<~xEHk{BfDitmV38Vk;mZ# zjEJTw^12xVY~twAb+3H-z}wr%sGbb*bxNpA!x750(X~x*VFi@7=1qxEfWgw>5uqtF zQJR2bU0Jqw7WLEupfa*yPRN3vusuN*%SWv?=&8}aL3)af%Zh0h#^%!8^`dM&N(v(j zao$W@G}?(&&OCn(gl*2R%f*@coIF?oFosg|2kDeoF^^rjp?rA2@Cb*1?ooPMz8yUV zX?(oCD~~D2q<8gX40i>@j(DWFwgez`gSo2tbdz{9G$N6lW+zb8w!T0(y5oy5iC=L;_M2>rf{w2|n1i>m@V-B2@K+qQL zN$P8g*|O-Jgq&a(Wty3(*S;6=$PQac!E=*2$m_k>IL?|8W}}{wdm}YRD-7*i8b_LJ9X5R>aZX3HlWb)mu|8W)h8;+<>^TpO zufSVdf>2}QBrz@)c?~MJi0=56zxb5|B9_N6C9nt?f>lUA1XsGWs}Li?m%Kp4=REUg zz-7(yB%p(&(`Q?9tk7<^h8m%S(4`Q|Gqj2e6^{(4O@EZ!Wl`k*qCyF4lp=c z_)5x)&LgMfDH{E;GjhThrnPAd1oZWZ_=o5(sWeQJnKs2i8Xi0+_+;B8q|E?FM~lU& zh4msst5b>b8GghEvGmy{E07D0&N>sDro4TnyRGay|CfS{p~@tX-#otLgu45Yt#DzYKK8o+ZCO>cF8Qn2@0m;^NjS^*qHlEDuJNput|+R%xlI#ns_p-6)`TY zkZE~I;bJ8>jLw6iHd!dA1i7*y{0aUrZJF|lfOLpP6DH7=&A+69K^>7KMD1X_7U zl65&5<>FJ%<-i+%4|(}ha;5plRlaFCHW1b%gmucZ(#FJ)6U-BoA}EuE>aUzk0j!a2 zit$J^I}eDisYDTp%aubQD3>ycwJlM2EELXzP{@YIIZzBoweLtgtz zmO=E4m)uq8p_4+FH@{Z^mS{vUd{jCYF*JfyI##4ia8{fC3s6*KG8_@hj9Ajj!9P_{ zU5ytZi{rq&qoWjFQ^VmgBpDwGua@Tng49XK<#Uc= z#>dA9*XpWjl5YZ`aZ!Ga3*=rObF#%cYV+ngQ_Yl+?Mw%&fd7SMR|+0US+5nR zu8?`wvQQayfj5J@^ytM?li(%rV4df+4lRc3P?|BgdMz2G3?5zZ?~OOkh54^8fGSk7 z@o^ZXA^xbF#?tiEc2ia$)XJI)t~OxW@O#XEjgR@C;#W$kl)gkInO<{cYTd?w*m5ln z3PE1^FC(uOHA9CO0-cCtAOB+7=`*!S+a)tpnfg@$g|sYw76+CWuLlZ75M|B8Hb<** zxM&#^uE>}SG0lkHS>9=$q+v1XGi8}3h4d3y8N+9ph8-P)noMGNV|BK~X3F&0XKy@au04azS+ek1pk2Z!HU<)^L9z5&2eT{Jl9@7ji z0*70sZK9N#E?|r<)|hONcAVX_Hq3dhp?zm$I;R(98kEQ86!2aYjc+X_PTCItstM z?ANgSo(I4!b8n}Nm>#RecwGx2U_CJf2gOzdRuL3bL4$OL9(fQLV-(ch z$A%*SVVhI90^BUPdW_Pi^g|(ugA`#TCxDO^B12->@K40hq*E_r%aDJK@>?KWydaAl z#t3DJLLrKPf~_}p#ub946Up?*D2$AbP~lZo)llD14?W#I@ZA$nfn$z27G8Mn-;`EI zCS;FNd{A0Pv{%{$5G7H%rOI`@cf>1(*ofyE^r$nmCbW#}kid#%TOk)W({A@}(?;?` zBM(xqcp*2f$SX0vK8T;=hGm^YPPuBKC3`tq2l1vjXM_?3 zWP%cCP?`!2kpi}Pbd-B${e8W#boqO*V#P{0{K#YB^fS&S$5K;ML-F|R1X7Dqg~?Ms z14T*{KwdFXon;{*J1MYAR*~bdpzYV)S5eZ6+gtzvE&(!Pk~y{s>hvU>!a^LhELBtl4GVBF!+9I8;OUzdydt5F<0@$%K>;uIIR@K~ z)SvPrE-zJ<%8UwCs*QR1{If_f3raXGB~C1 zP!tyfmg}cg(IN0V<*%-S+wZ&!KJ|%x;F+hMg{d=Uz}VV=M~ z6`on82%$5#jpFV37m1o`O1~!ejI> zI+MGgIAW~`=<1G6=;`j0dE#McYi)%`{{9&3x%Yu^_dWMPZK;-~01#ARgQ=|d36&TK z3vmad9K?!I4%QT(N+4OLbP6mK)$QZrG$MD#DE+q~*N_%LLHaf2VIHuvP&s77fdAn% z)zI(|oO|wt@cB81K}S~yv`uJ(k&$5-92|h&ehNIUY+Ioh6FO&wwz@%7i^M z=Ejd^cStNi7@m?q(&JuRP;La3DyQwW zIoU~+XCZJBrk=P*$zkd8QoY3@z%nXH%WRT#vFrq+xsZP`1a)cRg8HSeN$FG;lI1IE z@?d+gu1-5spnz%OpfxnaDgG2eSgxTZ?y7<+sIRMs7hie_PW;ZP@X&(~LfgbiP*V*s zJTxF5N*kkR1g$NuHG>CM5a?WGyyt9o#=wX3uU`3Y7?Z=(n65e^2;^RO+ZlWv&&+gv zVJAxR#${8KU8@%77RZc32DEZF?c+(SWjWk!87^570lXF_WKGHl zhhLl}57`icn#*Z?3_+b?8!~POUyJ24K?Yj}vo^N}gTeSuRTcF0_QLqsh;cYoGy-X? z$KyKHaOux}0Z;tnX}I*_3t;PQwx;=FOp9$89vPuJaC)n{I$c-F!Ng(Zl(7h`qbUdc z>D&CYd4|C$ZluVW-|(Nzdm4BY7>5UMs?1qiR~1YBTu>b2(0nQgEiqx zrNHYHI%Uf3FO_Owcz6`9z4|&h{fx6<<%;)U!jvhr-FyT)MYw~RHi(SC@Zhj1Ej)*j zi)*5pls2dNzML!%om!I^Rz{l?9aB!ujS3PX9`h++>D)umsL{;}n6!Ap7?)ItJT5D!)v6g#x}8 zg2xy4zjGmd{r%K?BV{54P?4%dz{a4dwHcm%>S@?}--F@$>#m3D>Kbwu7(Y5PBBK#j z=pv_JpUVnv4iqVQUR_zpkBiHoKic{k&X40S&$0VyJl=pX3Zt?Zi*)gS;XCed^Y6UK z%YUQvhheyLNb_nPyhDi2?9qu=#!2v{-mFfE$$FXmmx7Ectch;Ky~sGakp2oH_Z0}e z(wk_9GDmA00JWtOEO}=s9QKu?;h3*~13J6Apmjn!j13RL81A|fp7GRH6%3CI2Td%J z8F~v;IkH8O|48XChxtHCU(RM2*|YDi{-}4)36$kd7@}xXmOKZtq0v?bOc_?^GL9of z8w&}!3h*(G1A$MNyR!U?&7_2|Nh|{HS$UU**52*bI4c^(^w;h`ZudN0mHF~LOqHU=$CjWE#P566A$ zB)I$DN8r5k&VY5-n?*(rD^gso&<6r%jBXxi^89vZou<+eA7GFNaRmm@gHO>dNpSJ!tcefevxvAH8@jVLp4U;^ITYqmJICH^3zE zMkxhJ`A_gM6=orh=W@N=#1Qg;M`t*?MVi&smZ%eR`<;J1}-D{O(8&Vtw% zXIH|+$ut#1WV5*g6H!iH9c`?RChE&vj97?NDk`eKFu#H*kz=Ta$BrWh3>~8gvnZ~{ zH-UD3$^RX&M)E%cgMAfHZw%j^ZKQ_q=z|PPRTbc@a;dHsYM}vc`^%m1_|s3rY2P~$ z4nO>hl$=hb(_VYs@gfGVfZl0X)Aaeum#NzdN2K8Rhq&vrDk&?6HPSp1q4Lq<<1m}1 z>}sH<+%6%^Pg5vbhqLw$F?Q;d*l$u$T--BX6+%)dBR)D6F4Hr9BZC-3tOLsx=fkCP z!y=OWe*?(U@o_w)$_>{O;&|ghZEYC{n{ zw6U&7<9dLmp-#~f%{AUDpBNIaWk$V)BBk&(3r<$)EtAYP*cf6%5ir-p5v`K#PD6gr z+v4#4)t>F3=H&%dmLMO-&$^wC|G1Yt2F;Dl(Am)mC!Kr>{PnJT;DR5X0h?^RDLD|F zR#4n3HtInf|2mv(T=15Kn8r^2A{p}hlpSZ1hSo#e>?xmv(YCNNtl{69YMS!Hlgn(1 z$Dyxp09LJ93CmZkgca|tB>MFB^gvHn>?`1$V+XL^3=V_@GcTb+fHi+)bV6YkFG5w@J@~1LLD$` zTNvzU!h-Lk)ajYR!eWB=Ouca%6ApztLtd#|ywYd2@5LC$EJ+G}sXg4bT7b1?5LSweH}t5&Uo-kyFK8X0BBfG3!7V}Xps zuu%TxyTfS2K|i_x%p*U(xDy=}qQG^RYHFaNp@AIA#7Pri^5n@defl(5d*<3Od)92& zXv6hkqm4Fz88fEQF1hL&G_ttHBJC9;jCEDZxFgX~KHqzjCw;$93H2aq#bD1@x~NN|LZsJ%^}a`Y~}eb#&h>GCZ*138bB=VW3= zsbdRZ8%e_@Nfu}pCt4cQvrM;y0fzrR;})U1q)v1vJijTZBz@*&CM`n%4Aq)-Py3=MjOFa zTWkRz+WrHu@x~iMQ&W?xU+;9%!*mKM$C06bu5fWWuWkl^)dy3S4f8zWFvblx9gI_l zqp_g@28IUU=a>EpF8k%LVby!9psA%Ds&RTs?q>5KvdV%hbVM0LK4Ez^H05Q1Bc`&gFMf8NA%z4>h_3P4Ln58Eu@)RpJgT{n;%{88 zw~xi;X&H%+L5cS@ZTDr$)QG7>iAKbt;Bo1W*^DvSO=C1&B25YcBPMxlTj^PhPC%$= z{UfVzS&D_mvOM?_)p!eSbd-Q8lu`0u%p_G3uN<5odt-R2yru?c8r5+K3B+*u(IW!) z+_4lcYYgh@s$s0A5gvN@QFwO$L*STWj(`)teLS?&;Vjt#EOl#7(Hbk?9{RUf!ZN`0 zjg_8xg|V_r#aT9KcXbu@=xa(Ws$JbZ@Q0YaJ_WF!`VfZC7&<@L0$xlLL$uCHf@6e?*G;S)x?2Ib6Eq<}3~W$8^iZKGvyhPf4$X}+%aJ|WJ@#@sVGaI|H> zH<1klDiqGM<1_$?rYzF3pmI8A*aSp$oB-3bOEo}Sdov6T4#6cCUkdl#`yib5z3;+j z58RIoE8ozIb>f-`gZA=WkIK}NZ=|wqboSN=wa%BjVyd{ly81dQdt__`=D+$nJpR}} z;BSvS0?)tjGQ6|oT{?w~vWDv!IMde9SO*P_^(+TeyxxbT#*446hcW2@Rmt2tYaDYb zLrcy}xFNj}S8_CrzszV6RLicRal9r59nB~^-s&nepg6Wc%Lq_gg`=N3sA^E2jKkpY zFue52e0br77vTCoUJp$z%`j`$OxSL_ZQ+x@F0ITr&{(eA+l5z+Z;^LhyC{ZJ@x?d4!)fHy3 z4unOx*mhZ&DA(3XfliofBRwu*kJx!R`X{V3NGo%KOizQX#Bp{>Y|F9b8z4on0hlLK zze^k_MxFvCap4!S*e0>YJHmMOB+K{6I9y1GT>FI9wp#O|Oy%@UN!y+Y6WYnB@;fg8 z^NaKfGXf!|p6DiX_Oz2|9BON;p;X;OM(fD0e-l1?=bdossVBnbn{O^>7sjQRF1X0N zzb!e$Hxg*aImV4>p~hVB)OXrOTvbKA*xI^U7#bLadC$*-d+vDv9)J7^csfqH$a>51sPK=|G;3H#BQL`}`F;1F1!J?KD?d-dh zsa&PDn{?dqjr2YTq_}jP*i5R+YzcPtYP$;R$;4UyNJo~^h0F;c)VF+y9Y-F-aj`9p zai-l?N+~5+NR<4_2vW(6u?-WdkXzQ6G(}7;$8a$aNwAhdAjQ}q%vloe5Vf2l23Sx* zw!IL2*6(Av@h1B0Woj~*+rjy}~!=|xjPYRts&(Oh*cT|{@&&2!;z zfBQRp<*+ZpamOA5GiFSu-X`LKb)k{sE3~s)dqaG)^x;KeonGNIyeQ6cP+P~>t-Sc$ z3vlc0cfkD*J`4*Nz6rhk{j^3=S6c`5^*oKi_JG?(qa!Rw4wg~8kuIhN%7u>7ln3S? zCPg5|mWtYc#!$*l-*M8#T-|2cFV0xvD1z2EaEhuH@fm@+x7-RpyZADA=AZw9Qf)Pz+d$glbvfgsIK5{+=%nSU zyvHK1x3iM-U`K^GPnkT`C&_RnAFO^6m^NEI4D#gJh8!8U5I8HLab7*zzHEfHF$}A) z$poo3Wa`VJlnXXrZrew3tA{j-`v zV~;r+jyUQty1-5sZutsro>tPe5EU%_BmB7$^sITq1#nJ_qbR)W@s8W?f*WtV37-7N zGtkk|L5uqh^$k#}!3_d3WyXy%4p$wb?a_wqjX`R5?-plO)|9O9)Q}nVx>1bzj=WZ> z#o;uP?0$3E=)8%TN|y~sF*4;PqeDHFPRlapR3ge5(h*O_*HqWQI_u1W-9P)|vZkdije%ZDXjmW`>oEtfed4+t&jT(r@V~;-pKl$;`;GPHm24iDG z(A?BWcsSjsLmDdQ(lZzN^mOu_JiU2&nKEn>E1dHS(&KN`?tB7s zxQ+FSY8sq~rznc!^7T3lyi5-3-(#->;i+eygQlitavqEs^T>qaQ*c+z)d&Z3NOF>3Qb+r*VR!R8VXu3s3|#v?&a>FR>U#wL~<8vSCMy>nuEYGXwglrJKafswb)qq-V~hlZi0xdCpy z<=V9Mt-Lg9B3|_)+6xo859YL^$G=@-@9p$rW_0`}TgVX6S z&_gy$1{_^Tb~#H?n=NG8Zxkutc{sr}Q&{?=hOms|@CMUqfCtse0%oR&X?rd)1j3TS z(WKRHJr_ZYw`*IpzLLpfz^3r@DDM4G8fgpmBypz=UAJCc1z-8f(Qw-xcSBoSJB*Iu zWrxN=XgTpaKZLR>ZD6JM3$6N$Qx`)++zb5Zjvs;Vo^(9yvhz;VAUq$!_^ELD>5*_s ziw!fT!9R?9<&{_A*O&he?zr=A+ER-hYaCV4yuF;4Aax_7CuLb)1$2@&25nEb*>Zxh zGd!^PnjpXW zYZ3hNm%oJ@ZoCPWFIxt+4fRkmSN;oPp$z31XqU%CaXNLTeENTAXb`4Pp9~M)cNa{X zJ{1NAhM=Z|JLgKY>n>Slq(54}wFheTQn;n`I0eqe*%^jF!eq)U!bRyCgWI6vMr)ZQ zWu1q^DKUeg??Id8vC=lPerqNPlvm@*^@ks9WAYkb4l;(@D6=gsrkOH5KwJQgzJ}xp zDaA=0PVu9(aTtr1frL;ZXgiV)Oe)QzR3W~(BN@gMd!wbQ8rWdN4S2_mX`_O39JU-y zqzYw%ona1ur{PeM8yaxe%sBl0?@z$IXXn9gpV|$+aoo}Hk&k?s=GX@Y2S_&TolNo8 zQ8Hj7!?5s;MR4`i*TD^cnhWnPeV5KW;7M(q{h|{bZiF-j<8;Cp6&=f}$?_uUKs-3Q z5DuZlyVg>D^5%N2p08}^I85`{Z`5mP(rQmfxqgJ7U67fk3fI51EMk$Qp^M86TlCo% z%MODLHg03Cp|zorkuiAo+2`T7|M@mtbM5u;t>ce{PwcWQm5sC0T#lK>)Y9nGJFaPz zpuV;q-d(l~e)E5R4}ZM&Pw@7V#ZXt@KqK98E4zqLX7oW+Gf?PP9wHrR~D_%&@fSVtvI zg06wR=7&r=mgSI!Ds!A5#3g`05W}dlTXj{%d}XE*Yee;#n4N=23QQT+fM$$oh2>hJ zxaWjm6+#8|q|yXV7Jt^T+LQyqFg~Zi(*!$wcze3L%J(D@d{0u|f-*QP0;Rb=yWX^< zmebT&XI*_Q^bHQd+?#KOd+)gyKE3-V;rQc^gAecUAzG6e8pb=fu;<8&tJns0DCj(H zz5P!3-pQxI+i$-OtrI3e+XTGdh;O#lsT#X)$*E_wpi6H=pGY~}yOmH;#sm*oCiKbl z_*}8tLpJf!3CYk=!al)b#A6SE{4-rlc&*}dwCmhU0n?{ zHnqag&@kM0_x4_?Y8214XO$ADYn9Wu!>Pp4GlJ zc-IL1gM)D64Y$C3_dW!B?z1PH@Qts-cH4iDz5qu~gwmtJkI`X0oc{XMZl8d&&pivS z`298T%u~<6VD%uhwzqL_c?j>1!jT8}-U&@IE_|L`@nzgXJOgH_DDsnp`!trWd``os zj1@6(6PgxjX5`7qoReuPS!-Yw(MO{{RxW%Zt;S&D@Krn*FU1Bsas%mT0ug{qB)K%7P&QZ4mWl&#D_l5U3iabqlC49jUYy=2Pd$%G^XEqF6= z76(_aOXlkj(nUg;YKQH~;~#!WaQDyb3(r3LFFK^mGPIy{1$P!y`k`)!9Wm z@OJvx$KZ=!Iv75&+s-g`@>E`Am-P(%;1Vu|<7g1mu6S<+Ty@oTaQz=|fcXm+^0w%@ z1}M>bioGHxyedZ992!uw@xbxJQ$LVTE2lbgsm2dQ@nZQkS6vC8{M4>=-o+hImC<($ zszWJTVD(Fpigk|CIokSsHr|HYuz*J{QI_RJpmm3~Nq!?c>!d!%wrE^Tix_VUWOt(W zR|-|*QbWpcxkQfnhA`SN5p0#4T*^hpm6N6orltu5RNg6E4PZiG6ch`JiwGE1vb;ZorKdT_8oPG{mcFCpC);5v0)&{~GHpv?(sSDo% zY$#qwi$*A|(30NEEwDN=!Flqr5f~gEq3<%ZO=ySRKCvr&dRxcb^_;g;L(g5~eL3r$Up(A3;ac;KzGn2%3Q^H$KLBD)v)kwpW? zk6?PlNrY*tEt3OXJw?ug{)wp`LWagEIX8>)mfo=;p)Q-!9#3GGN;DcB=}& z`=n(3iV*Wo!x|zBgsI4orJW}ZOC#r#vSP}Sj#k6K;2?bP16#vAci##1^|kJTM1`ab z6zCR0CO%;gtj@-I8D`Co;{?%rPO>5hY;9CmCCg(%) z1q`$mjavBN8=}kS2Rt%XF0*YHs+kwdW210k27ZiKWo6KY zdAe#`g2z&KkX!KylJko-l&*X^*^fBmG!vrI-PH;GeLb+@#+$%b4m}hO{=yvCVEy&z zl)3_r^w4>r!@z585T1PUDfr#*uB1bl%a$$YYhY^Ypd>rn#^pMA4`xb~h@S4IC^c%xHO-9$Ssq-j58A!ZBYv3NE?iLc+bCuBh=-wkfDYw*pXv1e~#^DEbM@f`TZ{lKI#&=t845`sZAfpMp%8bJzRwZat@od6VR8x#{RXQ4STEGb-U?=?{_I|Iu~4=FmO90i4mQsoIu9-VAB zAJXHK<-L6au>0=&!iz7y2+hrnZhAqf#B!nACtZl(poRPJP+0L@+T;FV9Oys2;zW!9 z<(H8G291pJCvTgY8er=!wuFN}KL-w)^I4cabt>h-5eQAcjSSPtc5Dx}YjwwJxaY6; z!yo?iCpwHaJTM6D?GvG?1*hh4lp|{(ZVHF%H<&tLI)}2TX?Q-~&?#ca8at1KjQNCd zzEJi&uydsIHnyiNqhH)MJA&&Ot5?Cu&@gPj{dRElkza+q_SplbPMt=(q;TT`eM>{m z;2^CrAFdd%B!w}C!crR3g^#U1a#m=3%}BQU|Or-Xs9Yaj|jA3YB2aBK%Vx% zE(zj=-`bctdlu}!@7{3u;a`UJ@m?kX`tZ^~{{WQgO0?4l@3iV47^GA5&;RR1m^=3t zxb?Qbz|y5lp}n<@od_LZ#M^)Ufk?(N#6w!lbat3aL#SakT?oEee9331S)Rd;t`r=~ zV~`^u|K7N0KFsRRZr~q|25`dx@_hBGm2}u|x1D!|qmKG2?7ZtvFrlp->Kgd^lK%dF znhL~GTU%=jlxk~XaA*kr^rt_=b=UnFo_p>E7#tpgYP=V$3Jo&jq6WdshHsnFS9$Iz z9kfT99Lcv5SEZfPno*2#BK#SEap)f$fgL{h0eJACdua_v*ZAz|_&|nLeiQm=68W@2 zu*i$9>?eTA647$`bJ9|jtvjqP;{X(_J%}NQbK)X+JK2lU#Q2%^2l6UW_Bn=(Z3`mh z2c1WT=w-mBc0~)ZDNYi^6{n0k393z}J@kb0a1a^$K&TSNo$qbU_)71@;=>T(kss-E}wU?CODrIy?*}_){LaawJeX_`rMPg z*>sv#4S)?3F_yZpN2_ZUXud~qv;kExb;?B8X_t?|!E+9Toj?9Dn#RH@Ed)ATh^IPg zYsp~ZcRKJ8;jMG;fInRSXL$Y1H)v-NerO4=$-?is6Wt8b&Jntvo#na3R+152M3yvN zoI%4(UGDBC9l5HE8F1xMgxruN|8S6msr`}zk~)=y*URHoEzQmKu-Be@!I6i56}H`O zYiMq6;VC`*8X?{k?3^^71~0+F*WQ2|Z@vxgxcyF;|I&OI!O;k=c@S@K^OTGp1rwx` zmouSSKn%0qVV)I;b`lgAHB*Kpb|*$={%k1-3;Uh?ik4 zQV!{b0vqb6<9E!NECizk4&XL0nwjsRryx}~KSp`&YlMFWB3r2R^3mBTG6xY3gdfte z%vxPJpmKz#xx1}W2GgpemyM8#0sh+PgmH`wKk24qw&@8EP8fux%82vEUf$EhZ%jorfc%(pzbbzwV2GY(#0S=;RF#Q}R^O;J^@ccXz?m=~Liy2OJ28 zANFO~e9KMgzAr2THy^03AblDz9LC^pk3I(1|M4bx_@PH&>9S=oUR6U*25CjTd%0@g z^Ie^$juO0_c<141;T(X}>&%`7kNxc-Xl-kv zJh;At<%KsEgjFJhamsAZ30J?SS6(YmBR<7)W9v$p-3)F9k}~9^#Ftl82FAs9BPhej zwdEs|*XOH*hSuh1Y*kb?1)=i@GN@M(q2hd=83C9cSE~8B#!{s}K^$VP{L4whILYL~ z_|*$TPK^wv-eimv4!Vy!eE~qOgPoxz2rIeJ;J1)jS4Lbhn z)e^YPcLYX;hoDpxW3vMQ03ZNKL_t)lhM6NUg=D?w!KNz;!ax?c) zB;9m?fSt+vbGdk_A4*WEC8?(OjO)AOLGw;O6|YH8XExAF4#S89u~7`=S8|iM=_U&v`JltEt}anILqh{_)|qF*si%C0rr+>tetW(nPbV}! z18O*JBlOXv&lu%kx=z9(%jTV)&!hEOo9S?nXO}+`%D~Ph7S?@I+v$;XiS`A;SpZ2H zw(-uMO2%Q+@wp^O5P!h zBSpzSj+pe1A(je9BzP(3QBKgy(Im-8`p3^1>qUb&#c|86cf#R^A4NU%w)S>XI$W@( z=DM%hF_GgQi+3JI4z>OaxlCSFpor3(Hy-&2kEAf3@*FtWaR~(;F9Vx4mf_~M{+W@m;ihz$h>OVO0B4J-c!Qn?7 z4hJ3ZS(rV0Cf#O?&K0Mbw0vwI);@3EKjDTO=hBC~@FX}M&@9!~)5Vf{c_3~w@TxBV zItRjGwjGW?E>^-NCCQ7>gTo@n>I;&0Uy{#@>3QQrNk)~cSFM75_TC$A_|qStss?$? zQ+GvMbSc*9-7CEw7IIlc}S9S&cl6v)|8d&JnU3^ksZO{d~y-Q zWfwUQEl+K-h3v>9jJCA!Pp-{j;~XRmy0b)49l=|Q9`q<4y-rgqH zTaUW$cT1zZV4IGD=c}ik<*r997Fr`2!Q!i#GNUq0kIZmDaloBdIIUjKri4G6ueIuHIyPqFYtFZ|Ie^qqL?Esiw0J66I58*Tz$ zJL*U{;DG&L-SyU?5d}^`;+hW@+S<}gP6NMfa`#{Fg`01>1s;3+Nm#yoIXP6m`Ie`r zyaUL}p*LjF$RogC4O-Yn+mRzaEAN!=zBD0|#Y3G3-^GO+BM?@;x01GfANAEE;oJ+( zhUwEL!QkL9O;_n!M-k-PEDy1M*|dcQILhk-`NtW0D^K_sCAZGO>aUBB`DL6(CT*ZY zS^AKVu+2;ZiqXlCSsD8Tu z6vbHs$ub?aCm^IU(khw@&Ooxg?zIdpqunkxPn^$Z2^|Rj>2ej${jXZNik!#KFa0Gv z^^d2>sNhHh=h1bcoy+wj81Ia^27YE*IDEn%so%VChX z?!E6mx^!{kq)AjBj>4ScsbXc=tJ5+XZhPn<-z->};?Hi#NRRAZ$WQ!3!--Dqy%j59 z?X}l}uYc`mIOO1iVEWoK=#V7l;L#YL0>{k(%a$*P8*Z2jH{X0Kyzs({^aVdWBv@O6 z2mj;-Vwtt|yc2m76v+59kwe{b_{*ru1%(X_44*MV^v5q58DQPzXT-9)wnXc8ovT*U zMVTM}*vH}IlfDDHeR?-?kT`lG2dMSOdT&cFqbm}@{Eh5^LQ+Qyrj0mI($Tt5RIe8% z2X;~a{WuRzZ{zd8*@qM!2}hZ1Uj(*pYk#zojPr295%tnjtMuiV7@!uF?+f-RZSTlu z)3_{X`9a+Yf@pl;y(8hG_*kF}BT~ZV%1xDF8kmtYx>F+zOVToERwzK2#(v$8J`OcL z4l9b1irgUlnaX-FmAn;m||oz!$!B2sAb{K!5)L_0ADTTo=G! zTyV#!oS*#k5_tC6dC)#_B7J)T@6RHB$D-lrY}CRv%r=ryBUN(p;9HE}?a-oWt%+Xv zjEx@b#B~ikr-2t59&y-VaNMz9gAF!XpL*lCmVsCAqjPL%Y@~(m1+OiFYp(qR+;Q9O zuwcP!bi*teZqkypEjyu6Ok2@AVv*)K^^5hAGCw`9}*J^as5rZ>|3W*-IeO4Lc=a}gp ztWL-J9oiK6i3KRqi5LQ%j(K3>Q#e{Y;!b?Xq68hJu2lJ%_9-o+HmHsAj!Qo0EO{ud zlDn-^kTRx8uvW$gn!WalTvoVQuq6n8{b2?lpTj%EFC-}AQr3$LVY0zlL0BWuEIIWi zoreoB@g_eSCc4UlZolP^1>rOb-m1ECu6z%g8k?cHwTbA5 zJ^V5HcDOa{I$AK>BLhKII{Gkr6~hsv#KdOgL9g`aM~iHL?7=a+Oa9fdRT#s=cipUVH5gxcu@f;MQC3gf|zxMP=33l_;JZg3PZoULIfK zmuF_ia0P9PRnkl?I*ug_AJv`V8PigqaTLsVV*%|N8yf6}>QXapia7enBVm`_K2BGz zE);6IP>ToJyOtw!7ooTV#IFAr7^JLIh1Cr5n!{e-?c!Pt}8Qd0M2B&8yf`8aH z?7`x^cx_D;Y_rvtaKw>^!J&tKo_1vQ_u)&N=S_c<`Zzp{;!a ztqq`KWs&3h_^W-9aYeA`Qj`j1*bbIKFURyQbZcmAfbPx?nvy&I_;13oU;i3Ro;r#0 z>8%QAJaOc-?7jEkSHJo#{P~Z6hBw}PlT1}ZJ&rVR=MnCj%BmY-A|&^`GP*&a(qX3N zqNZ>^4i9*WlqYnP(gh<$d6vx^d^o-Y{R6$w-`hdy*I9RC*k{kZ;gB!Pfz3AE7$#1d zNKONJfK}Kt9L^xca-ulrs8*h_&wwXKHpB~P@z&L)%a+4a zk3R+1|9LL_?eWLxQoWYeCffRmZDUbj2g2XL_KF?Q%CuXZtal&+f~-0Y78$Q}M1SKr z^p8e|ff3_&(kD+P4_?tRI5-0J^(ENxBOiwEeEWFVbFa_P=77$wE=rHrqo4y_y{ZF# ze9@)w>t9_C)uk#rWT&UpiKF@*6sliP&$2NMvHXcp;rR<(Yg)Q&32eT}X7Hm6&WGLi z*o~$Z@iaJnW4yW=nwy(pcytu5zUo@|&98n7FTVUT6@$B`XbPta4~ODa^;oQaA3Q~7 zJ8Bf11UG9`0z>PIaQT(zHh*kbt@EIc3Y}4@hW_3@=Yia z08^(>Ww-d`Y%0*Cg@*(wK~6*Rh_OZx4f|6(Vj?gL zGjXD0qlsv0Rx-_Qua(hxy-O#k@N4)=gP?L3Hc zR0m-4>(%#;-;&=xbAdWiWM1)(zG3L;>4xT}COG8aIdJ%qN5BT_%_b*}YcylH>y64` zj&hk?Cx3Z3yF)G3;e6*2>Y5G9fJx#yJkj?1INs4y!`1}MXq3QI6XP4`ehT+IaLS?D zqQMb8Vp-7oq^`go#ki3@$d*UHnFaGi+6TQhI(jgZKX{OKe*sRxOwiaG_6=$*FXp3kOp|>MagNI?9g!P zpzvLdf?-cTlpzVsm^O7fY`gsjpst}2I#zeVi!c5g9)9Ry zc;Wfyp=0%GnQJEvcfDDiQo>g%8`n#4!ISWnn~?=)S~3>r;|!3)Q+vUD(pX0?RyM3` zae!|n)7D8oO`Bjjg99V9PO$6FJHctEodVl`=mT`1u&z|+&KJD()?)bX$)~~Gn{R{m z_6bl^!rn9P#^PEnZ<0HIi~-U6sZi38jw_Zgh1qM*go}UrWBBZW`$1i8Ev?g_^T6vx z&}ska`WxXF|N9%5KYsxo62!xR*s?J^5D9$M3U3V2TCDI{xl{+n0p#Sxd2k!TwlI&v z(V_}ACZiEgHGVA;H(u1TJC!f_Q8BV4vu4qj+nKXx z!n(89Ci&>;=^_5$^kIq0F(VsBF)6z-RIE#p$zbvbeI(H8QOcOdx=D`3D`qC2#%G*I z?7%HpJ=c0o+Mvz^VJH&6d)gJn|5Dt|fWA-&hoJEy3u zl36ud;N_!=(`%79UU}c z@z#jSI!^X=E(RtwaG~QbB zHk@_l`S6#&;H|O4P~XtNTW+cSJblK~iz2^XO(aY_3SDg??T=*38D_g%j)}@J$)C|j zi-)UU`DDs-({Wsu2}^5#C$BTi02dT>E{?J<;bMhHQ^l<*Y@LP~%wvo#(U zTG4T!;^JDy{SQ10M;-BXSlQJjJF(E%<87=Znlfo>X`!AnjyUk#0Uo}?sV<%lsUid0 z-P29R1bgzhFg-dvNaq*o8}O7f-|9+Eg+?7>aAc~)azg**wGQmzM$QA1M$=}FCT6~# zBYZmEuFUCaM-Pm{9=q=jKl<_cFnjjeFpS?rp#|O==$j0wy)WPy)@4_xS?+QP=L`VeIcKaY(c1ttc|jWr%gxJQ!CDD*jFs0>UX8a9<6-RurPp$cY+wQ^b{<(oRnf(O z{XcUaHr9WKLlU^3HFX|wdas1}#8alK^N7=@>PkVS&LhJIRRl^D;;CiwX>xULJRR}Y z;>ED{zMq4|i{GJzO#E~$tyR$V*!-)sLxCEK)%o*b<;s<`aEb@P(0P<<>Y$F!UNrF6>Poe2)8q} zaM5kA*qxS(4Yh4zxOwVG4UVINQ9f_v5pPU}mja>_86L)OUG%_)8*T(Y{?R$G`=>wY zcB7%A!-Iww{^+N0(M3N4C{;mIa|?`);58cjVJ17x!lXw!jq$bSfG5W5VA;EG!ycd6 z6E6ALPwDns?6vDC2c7h9ueb`%J?96|(a{O5?GvdicVCrjglyZj>m0_BD&KkJAdCCD zQ9-88=n_iWri>qX;v0H-)Ti_wAty1=-w(sMRzZBKr|q+NqwUsPZVlUha2wcci_Ktz zO*VjMpL!N9_`!uFJNTJfbRaykWclaspyM~{*|_5tYPum{Xpjy&qHo13SoYaxFZjcC zzbD*j-9sH1-ni_h1-)ZRK_w1^#b5L$Fd3nq#?Hg)G$*gnfI9h0NBd4k4&KDHoN#L+ ztf`2cN083sE$2KmOks`NF5sPqBYZ$v5!~{!Eiso>(V+G-`B|4M}wk z^)3&b^CfurZ;#XEfp~>E8f>0&k?%T?F_N<6<2=|?#f9^p?rypU{OBW&hHrlB7}#jT z4amVD^!D^YS9ce5bacV$&JK9%%_Z>K!iDhiEAwH=l6T;pcb7uP>Xp#Z*-a;;u@W5R z&?uz=7m3+XAwFc(>D%Qzmru@suI0A9)dcOLQG))_kv-g%1>?}&-3{$6EpYC+r@;|N z97aYOZ>gM1jsyE}Ntqi^pJi2yZQBCq`#5s_^7`Jxrc53D#a~Cakyay0HFw8^BiEYzZ4~ zupUfbYZ|mQw?J!K3vDMRjK;>{rGLK!=brZ?n0wo8Fn#KD!UgHY=T2n1?l_LtSRQ!W zEjn>}BYNP@H@t@Ayz|b4uI_H)Jsze+-dg98()rjx7U^E_Y(>PRBcqFHtnwtvjct?H zZ(o<=qXeb!PuUp<31><8i5*aU^_k)mj>x6c5laHM6j*#UeX4wg6m7Fxb@k0wtYLa* z553z`(tQSpj76%P7b*u9+X{+egO89Uj3fGgij#mEa00e~nRtq_mO|sKU}mLT6Xi0P zbV8u7rjSVycBQ$Uq6-}Kn4!TygeEAAGgYx5xFChoiRNu%~!^>I_{>%K)4h+i^ zIhE=v+GW<#+z7w<&HuuF`|V91dgAYl*e$wd8pf!Mbsj~u@!)Y%upK`a8LL-fD$B(g zXF|U@yh<747>XPobqs-LB=HU&chjyn1MbIJtr2& zD{&sS99Kp}BNmdd>>!^$o81X9fwJJKZUw0vBOL^f(WoR~o{Y|9BY>fpGqAob>3LU$ zO#PO3CQhH&8E^0BGWb0TlIWox}(Dr2O|7-JfO90b_94c z@6g}?oN)aA!0Bh60xd1AWZZCS4X+6K-f3sR?|%DxXl-ey#bPwre62n66M9H!X_JS44ZDUF>J8@ z2DH92apDB}zCE6EK}VsZMJiIRdqKL=f;~<3=~w%Jze*`nQ?v%wKLEGhb_bkz;>pm_ z*$ERSPKLpOevw&q+VcGtY(upD8rPRL-*R)f{gxZ)&>&XA-%k(qi^~yRu{xblZ;fVk zumzb}5;J1YGl2B!_VMzM)oW)HoxItk>FKsSBdl?88*N=&q=d)z#)fmnW$Qw)?Fs7E zX50EBi0ijF=3h_ZrhV8WYIcsYjEJ&Z$B<|kg*XE%=@JG!E?3_w@{R~`vV;Iq8VOGs z?@H)Ag4u+oIL8!-`FCNw+#;am; zJ-T3xz5E*dobBKsbaZyXnP;31#~pVJthLs3IV-|bAmku$;ZtxR=Oe4UuKl_Of!}7p zv}%AO!1~d6_jLEtw$8kz}G z^|3U2wv;j)yb9e>&|lL#KvU!FP0Z!T%h0JluTq?R2BB zc1T%icyzRK)e4wCWimOA{r207u93%47A}mx{PKMG_IFN#d+)g$+9ymV!^_ik{BbTm z0LYsOXnn>Lf*H&T=X3<~Y}hb2+DGe_3y6Z8HkUWK}oc|5IormAww$+%X1!{Ic$_9)W>C* z<}&){Jm-;MP&o&Zm(M}m1F*@;5C&mQoCiV*UrwIA`oVz|r_8oJh>ChI(ZZfht9LYz z7X@kn03ZNKL_t*Hl*aJTFdTUBm*8)YJ^>RZ;A!e1v8ht8@KlW}8h_ksIXKVmXh?OWf(x%W zH@J3Y>h(iF7v>p1jA)3h@N`R}Mc49{JnjFk{*ba+;K{4yU=gVQhE^F23j|aQKn9 zb}|Zs1B1}q(hM)W{4#v|TPMLo4?F;E6WZxUS-mEPFHF?Cqx6}mX5oHvii?0FS8O)2zY z4)8VdN>A;GIJu^E6I_F;fhQh+5{^Iq+wknXf5F-_XVKJT4NhChI)}@H|KU{F_$ZZ$ zQ(e_nV{qAJKZmb=^-Iu;XJ2aZJP8|n?Fa-8Bi0Lfv<@b89;!=`{;SS~0YNzgsh+$m zHh)WNk)1#YZD}zCJW+`2_o@@-5uL-}3aZMKQv^xpF*-WxJ_eQRA>&G%hDPZW%&5hN zaZp~S5C|9ijg4i_lozFmhM1Hm5)MZMGo-cgnKtEBX23hU#QZ76`LL7_x^P1qZohxm zw#ClF8%d%T&0+uKCl|vx=UfPF6Y&y0UdwO@xDf}3>D0{N@F491`rlvt91fmy0Myo% zsF$kWSg>={RvFx%!<0c!E@#qFLO){RUp7=YwSv2{Y_EKEM+dwz|5fz)qI8BllB}{=%PJ2*>`<(Uc#JJ?AtaQfTeH038$QV5}bG5Swx?{{sA)JOWt`GPWaAAaO=%CK^u)Y zs%e`pjWDz~O&9L+!ZwdQ_^v8)EW(}YnmRg5gI^Y0-LVSRnlS?oKIj0LGv^@KWYdjd z+SI9Hq#1CH1xI2e=4OjA@0LS)h+&RK12Gya{SK--|(8ky>)*lRu z6;t%VKYE=ri^?{O(!=SN)i*OW?&R3$P;3tH7Cz^-O~D#vW%4Vp%!lK@^*vI0bR=w9Owmk8w~c_&tA@Vb zF8JTeegTJmaSrW-8O70vx!cOhNZei*9#oM|6Qq~v8=M}Yd3`z~!VZQ7dmNe?8)5dW zned?xZ3lbp^BLG+gAHN+s|(@HMQ=bOE^aqAx*KQNJbK5dQ?BZ?m`>v~-;am%hK7gX z(Z`;Gt+(C^Hs5Sxx_@eTcof!Ke>OBWG{R$#K1QRI=C(F?d(j(k$eho?4}Ng2yK)3a z7egb%aQ^u}gzK)k23p%D($(qcgp%~4&V}G;=z$KVR=yy(eEGXDW7;(M_BW4%^UpsM z=FB+|Hr`|-`Y;qvo_W4=*-SUy*c=ffJ&S>x8;ZMNA8o_Tg2 zEP8V>v`?5wQ)1SMGpO}uJ;iOrOP4OE-E6pcj_t)=ZEC3fH}7rzM)pm(ZIebO?Xk;h z%C%t$aI{U->%fGmEy>f5N`bN|$%^VOz@1`(DC4|ru;7`(H5dPgFE!_!bIv)LL^`E{ zg-GX}@=4=}SjY==0y==mm;~Ya7X+sp5s)ZyNQ{#Y(K7Tu&7C5$t;;e#5%v3(kd2H`|yNfYI^bI>#@5 z`D^&;PcET*t8h0GZj;7Eaild*-SJ^bna+}<;#{sOLGI9@QrW41s9wR z`|rOu%$hxmZrH`eeEx2W2c@C@F`vv7p6YBLzirXu$<2Pzb!P;G+WR3Nyr4p~?kqKm`J!zzQC7RSqr})s=uCy|ro@Z;WHvwiwW~ zoIX*oPnZabrUyOWlMKuXknlpMfn;>?^fU9|j5E)r6TfJbUC}PTI(vRc!}Z>K%i&wc zegjTE`P)!mk2`~`@}ko`jgY!wqz_54Ox5J1Xwu#6&M~HgB^GLFm1KPEwK2FjV-s_ z5}tVSNm%ge3vk}K=fHmZ?@gl?bY{4l>DF8CfKyNVKJ@kX(|6<1(djf4H_5LPx%P-7 z(;I(#db*&irxOmI^EvqW#Xo_A4>=HK&RmN|FleX;@hgaC+7SEyp}b1TT(nj9z*uHL zjYuT(ng^#}GY&|eb$w;S_1A}4>#PHFZ=MS!{Em8!jC3hqXlPUpv0bZIcS3h(FU&dk zKyn^Db>%+*rupoj7ManB9MyA%F^UUiSP={3Gj+S9N>7guRbPSKs3Z+Sahv5mH+MjK z2Vx#P&!rwtX0$n3fS@rmbASkv6P^j<2%laBk|R75^K7;W z=Xy;Z3e2V}1h0(_EZ$64rGrlsr}Ke{pcEYnXv%TgNZy)z%BiQrzn*&$np<1kXhhrZ zXeR~-9S5EW-{C{s!KIg61QRE;z0K$Ue7Z^m4j=6r2cIzs*FM<5bB~>O@kqTi zGU1&+YP`|W;T0LXeR5ZrIB_C8@x(vqN(~$h@H{)7b;0_%9yQ#8jb{{nw5bv1J^c)< zx86GN;T=9i>2Q1M)Txu9yQ>=}wNHklk2;)oI`#MULsL@|y!z?_qWAol7tjf8zFZN@ zrc2H8hhbOmoA0bGiSjMe{epXJ=tWF4FP>V8dOG&4Ju7b$p}rShNwl3 zp1QW6-((TPEhp}o51|kfSH(aDzXsg9WMv(ab0%m!YHH{sPo=6_xZ|$7puN34G&1fN z`N%u&Xv^{VIJ~puZP;3l`#+zcl8hgyW z=|xS9N$l8rM-c=pi1ZEzIKBU$X}h!g?)M$|-RJoaeCK<=ciZgj?9A@$?rcCnjh-N9 zvf;x1Bai$;XH+(;nDFuM_?a|(fi4QW7*c=##@Exo5Ac=uDQ&Os^ji3yuc{0 zsHCm1W5aPYwg(vC0O_KK&|arYX!@!(xZcv({!oPYjBaQ!cDhT+Z4)bO_Lq_|zvq4HsX0Ar0{_V5O;$Xq@t9?gcUZ?W$>C(bmL4&xeVNP0>t#YzHGAIvmRo>7jL+>C%$fxT6 z&)^wy*C2?Wpr+-M7~Cu)N4Tw5pg8y;1D5c)1g8(r@TG^Kr4!-#Ac{{NSo~MvC=k~= ze*4?s)0qjhk@J2{ERbE0SV4yWaGhhvjutro2j3&bL5IZ*qlKTaY=cGcOXIVGP;-%2 zEPSU(pPUzAq2hLAIsBCQefb>TXl`yMfsQz!`;LF#cR$?q zw|_tlU2R)J<|T4x;ufuChG4teM;Oi!^nE2TK(J=QOLzpDa?fp%MQCkjU(3fY1* zK!|7h2SOY-&ND1W2#^PNO>2pyh0%@`*NZp;#rIizJR{sRo^8;WY4bH8g2PR|Gs>Jp zef@A&LSLfdXcQpIPH=J4V`CbMr_8iPRW~ve7Q(u9>*1nHenLus*E-AsnWH(EkEVu> zwjFTb{`pdG61v|a`e$h!us_a;I&s@p;O|xZI;4CX>hwU z=KP3)kWFP3m6h=38w+6HefEKU_nA&hht1jnrLP7NOYM1a^>ghZjUP1ei`Ls!!zxeBYz)HX^bD=PvZK? zT#>~VKjs#u2$+!G3p1pIvwr6j#-XMUE1#*XV{Etb!>_|gK}Lw1!;6tMF=b}LH1dKr zL1g#d*{r2*d6bT*h=fus$lfs`pfuIA96KFPKe)RH1oM;weV=??p-XoZ zE)^9ObQlru7MU`64^nFAlL-YM9#F(xO*raztw{y>_H+t?4j6XBs8J)~h8wPh^3pQ+ z-S2-7RW-FFkWn}V^)Vd+7rD{HZ$))AUD12@-G754j+jNKw-E=j>=yQtPo{?+nG4Uo z_%bv!H1f%M8VKOsCf+kKWskqn5h4uGn#!iln_>Lu(QwrjSHNdK_bIAPXJ9N0KH@FU?efOk`%yNw>W`|f{0 zQ4za)aP1=hZiIpNde1yEgG zNoKS=@45#bc;F#e@b+TZw0NT5QMnc+O(&>NW7Md+&$st!*%B zTg1)MN6^{hmX^&hX5>h?`l>78w9kDSdi#2a2B`R1Z}?qCsHoVCD2E?qjS9_ZxLAMB zJ%5A8pLzz~dFOrDvUw}CwzUy$_~I|#kw%O1MaAUXs;RLNCQq3JvyVFlKK-drkZ0Yt zHeOr7b3l&WM1h5}f(5vo^mZtyAiMoUfoQCq17AQmF!l%Z z6jHOA7?Q7}eCc}#5$0reB2Sw(rz}f=Q>^iVxvh9G(o_bDMnw5ESR7{KghEcz>;&$d z7M~2BiFkZ*yN~A@5P#AlTeeYsV)HHG!6;%VJT2#YE;Ql(y`xvqlBTtzve?fQuOHwk z=Xq}~fD=#nr0h)cJ8)b+Qbqxqgz&o7{vLSbf%{?RLHj{hC)(NB`5g-aQ@#bA5t;nx zjo7`_tb*H0tMN{Z{(ku5pZ^Mf`Sai5t+(bw%k~|VM=7pVl;Y)6e3Dv~2O^ICkMQgT zUf2YKc!^RKOr1IzzVP|a!dK5e(_P?17f#_yzgw>JxM<_zMNsG&ck9-zaORm`g-0HF z1nSYNFuL;BQ7Lq2RbfbuA0?!ZRP|o_7Jh~=dZknfZ%u}UJ5HpYWl-_M#92zL$hiG7+BUQzy>hwu9wf$?^09{%HF z#mp2amPD=T%}#1B3%ja3;ugvzb3}~d8Qk3SP-UjVcRG!XvuK=N>SA{CHjqq1h55X4=#65h@xqVb#~y!yyM93eP?NBCJ@x zoV@f(1?2QRdbnjlCR>jv7=2wWS^O>?6g=p_nIsf9ZrTJl+;|HtT(ku08yeUQ7Vwl{ zAe{{_!0PGkCWUzMMHj+3=X`~tkm7JVi^4kS8UhMp#0!0Gy*6(ioOkYz;P-#{3oKu` zlEU%yJDU4&a|F_p?;hbg(KhEobj@Bu3IqLt;Q`C8?rvE2!E$)=iDzK(q9w4`w5ep4 zL#L1^taX;-*pa^ZM?Bk>mjPh;IA}mWUyTh7aOa(Wqk3XKJV3O-$_JYe2SVFhx5G&v zKM|USq01R|$Qb7xk!q(PC8K;`7?zDG>lP`Q;bIJpki$I{dx+#I0iRMvoPAbtNCN*d z&p_Wt3G=7#gyKL@C(8U*G)|l;jWnWynV~|a;5S*&^ckV1;qp&^F)oTym@deJC0JOf z;GQhYwT3U#{Y&f$Nj9!|r?m1kV_M4CilYYTO8$v_EsgY}E#q29-s5N)?bdzWz3}K` zPeE~Mg=-Htve5d_B0X>G#2enuI_nH5MiUo}z**?T_5m72aYbBS8b;xQ2PzH}hTXlr zByjJ#>mE4gYu|+XA9#QkcZUscpbLgjpy5bZJ@cY~(Af%|Eh#L3(vo7HnH1y2Mdfs6 zU|16h=>d4)!N=jW)6RrH|Mjml;wNvl=%U>~+!h!Q%`=my?hcp!_)=&dISO{Pw$Xwz zQB?g-iPF&O_6_us;O!qAgoo$Og%6i4qw=15>S=i8mDi!Bx|aPsX*j_7$H9(mTWQlm5~Tf+C%0_c2v0usj3_b6 z(G5;QPzmEDjmOu=b^TFjOU)GY(-2%AkbxP;7xqsQLIw%Ehr=m{TtK`L_irN@GPorc z#WkIMXTiR)X%r|u;Vh?+@+c0Qo4!lo&At;z=(u+TxiWVZ(03}ZoP5~@t`jh#R&sVN zm$Sh+YApEV@Ki2klgh^PVTJ|{Y&wbKaMJYDBH4HrQgyL3&47!VRV-NVMen==ixw=V za|gHv!e!b9mH`1?%G1>b)28kX2Om09%HwUmgj1&2Eb}n)^KVrE2l@y$Ei<{kK%M`jAq3C~egdAu0u&&9t|7kgJc=zj!*~gC;Ff zp4bk02$5YExT{=oiz{wFed_5K;obK>pg4~`_7rU1yoKsYZq}t9G5ce-cmpHORAwJ{ z9L$;XBbt%XY(kv?s?zdQroXs2j~;ZUH&%bEOF??=- z`Ok_Neqf1_kXJrRoRA>ykNo6iN=ONdk37pq`%^9;{`8V9gK4U+x#V6>Stx+vIrG!< zljk^umZCs+24uxdMn9%nPFwPi4EUmD#3el_jo7XL7AENp&*jQ7ZhB=9u2vpAFv!^Q z17+ZO*x-<`pUO{-mLZeP3&G~AkH)^3!NsPtqbrIw2v0rx9JIH$L49LAU-YEuB`?hd z1yz4fADnvfNi@<#^OiDamKpVYbSN0`Nfie(Co2wI$o=CV?u4KJ^eSlU=!C|GM!r&3 z?hhebJSS$ieooNh;wWC_x*A3dYlbtv{AHLtX?HR?ty{MaUVH6znD_b{Gz-ApSi?rt z!}hJMaOtIUprWD(&ODRXLC}mvW)5-x&N$=3v5YNbsrG^&ejnbP_Xe4;h7GG=Z_R^j zuCi^9d7#ikA-;a?Dpcavv{7kc5}tu^I#e!LCN6*@EpNK%W~ivDrAx8;`+9(`J(tlvZ7rr^2VhXH zfTjDv3kPBI#`WYg>W4r09vpJ;L3D4%)|M7nv}g&;o%=XE``q(TQB?w?M>WIpoh%E$t!FEoe0qzQ$IdgxQK4S(fUHT!^)>ir5ZqaqiUQgYeXh5K`^JTmE|6BqsDa$NHeklscGsT48^bh=GZgV{os048BDO^<=z z;cFc+2I+?&h=lu{o0gFbj`BLg^crUf!dpnk4Ov)-XbbV7@o0w_S)*lf;op2`H0^^Y zvk1q#;rd%(=?BZn_U(7IC^PXh=822ZXg0b0^2=b*1?nU_F4=<$aX3?yIf|U>E`TA2CK05+5t!!Ao7G}>r9`*xFxT9guX?w!ki8q15HhhbZ5znFT4aDC?v~yAv&Og@`@~~(_P>LgLEhRqJ@jO!xXXkDFjYb zB->xxc5H`pzx!?Y;uk+}I-bmq%=(hj6qPNSB9X2)-gpaKckMM$URgzJG?(> zI{_=4gT4|7UyoZH9^`5ISt>u92Yz-|aoF&D_{C+}GE(^?P#)1gimxu&eLqhNQdJyQ z7U}`LRQ%wb%R4`~W;VMz+~^=xF=7luyv#$MvYEgCpCHAKIaxHuMIVKBnXqIv`6bc> z1q64bRe4!Gvpo9G^H+ZU#>m6sYJ{eDdVU01-j%zHr`o-(@%LlCS^J8+jij z&x|_kyKUQA;2YogE(xEST3!p#+lYLVF?C!KI5I6Qg-x3_!pR>$5w5xV7jWpIGik(* zbz_HtrL<*t#*Arj_+hhP;ev&6OA@;jWN z?78O@czeMjSorp0sI08=&Lb5$Q+G7ql$MplrY)P{!(|_mK*OC)q*pV_gUdj->YFxi zq+9+jy?72ZHr11vOg#r9t#wyhz~h61bb#`o|GW?8Tznask7{chXwhGHU@?kzmdbB2 z7(aN%(lGa>5rBz&^%AM?8xL_DxSK0s3#&LHmj$3LLFjNQrWh znY2rcjGPGpYs3VXspV%{o?|7tl!uh;%Dl-fSZ!FYILY@r5jWNE@AQCZC<80(xYZof(<_6xMI_KyF%uZz_o$^Kf(diP8rCw4>H+_37*qe@ zK`xyxi^(UGpT$ixi=Xi^(V5%=vpnk}HG$@9^H6PWan$FCMqbF!4_e5@sw`W!0yb{k zL}neXwb{C=ZA$&M0D617VCH@^NkFlS3(i;b4*1lV6?}L&^T2Q133SbMzoa`I@MJdb zs-jDmIELg9GA;tHRp2dhqehH?OD?_;_MSc!cI?;zZRqB_rH>8Vk=q`!w8n=iSiR*-4{zQm%HJvhXz0lV%aP8?34dzVM~f zVeGgu(B9EOW++oz_YXm5G-yu3^#EFsmNN~O9{d@A!s0@@o4u-{98N#|G#EEw4Aqkr z4d24YTa$&Z;z9<`$Kc}jyYIaZH{X04Y-`y94R}X5&NyTsMRg;|Oc;da78b(x9ou30 zw7uYxITyglkX~r*>7R$qo3=nD-g91F0{8vvA^69? z9;P)YKJCp5+I;FeYX7+ZxIV|BdKb*pDN|tL#68HgiVNqs%!95;NRi5JJKFJ9R7CD% zmb~+h>usvDUBv91$2ie;80%W@MT|AkQLM5y}kTH{!HGyhv8suoP~& z-VrT!A`jbcUL@H%`M8;U0=eM2loKzxeOn0x1#x!_5adFl3QFcX3&Jl>K*kOBe+G+> zJZlHY5Xq!*OgaP#q)&(jl9y{MZ7nG?L$@fS2wZ2S^#Zm_((}LoEL^yVgcXgRrD0tM zcKNcBN0ZLsM;z)d3Q93u1|rG`dx)y%- zhdbee4^~imT4y1*Eshw{hWJ=W`J+-g_L!r|EQZf|gP}vyH8mrTGd(&5f)^IyKg?hJ zWLbeq@d}GzOUo8G;_xHj_}Ry~T(nIrrHPIr(9r~m%J07W?}ry(d(nj=+GybOZj7()(a8^%Tvc&`0~9Bvxpx-w$Y#RN5HUj_ zQ=DUDdGBTi|1UV%#)@V@1Ur!>l|3*BZ!cObTSg?1GMcP#2b69d z=CcYcROnjP&Q3ZVz5hP@&|!I;eKa%27hv z4;zm+C1ZcVK?>GGIx-PR`hpt|GOmBQx6J59<9eI;Q zw58qfB%4zVsGQKZ+D}as*QPdIo-P;mlicC-tS_+)Bgb;3Pw_)Of$rp#nQIgch88^P*K`E3-IdGtlF5nYm z>yux=V+5qUO!YlMvm=@abip70$-z2`n~I;{Gh41xJQ`Oz0>zQpkj29_x-z~KB!jSg z#Y&n1czlAW^o?=RTr;wH6pR@=nsYRY!!f_*fr$C-GnP|STms9ME`vuNc?^n6@m>m6 zW=xXoH{qpKHVePFph|+q9Zr**@o*$+4ld#|)&WgpXv;^zgA3W1O=(#P-2cEsuy);g zap@hkrF?OnQGgbcus`wRC&2XS)1a%flh0XjB1y*|UPID)h{BNe;g7r5JsjCv4Wp3WQ8H!~Pp?Pb2+IDsQUn-{U zqd-rF?8$^TbpO1UtXjtflO}0XLAraR!i+Q7xL;mC_0)z9Fo(YRz*xxzAoPrSul#NDJ zfw!xm^-D2^Cz5jVG=|6rq|;6;z8IO4{4cJ@K} zr|{KgO9Y`g>A^?l!p4o8jVo>DhmeO1E{XP7vwAHZVne{$5!%_2$=M!`qgQ`95avm1 z1EpnjC=O=>xCmTRR|_w{G7lEL{SMWGT#XRUUYKxQSsCGicYkj`9X_0O@PX`n5!W-w zUzVhiyD@N00!>S{Ls{46T4yW{al_q0=u8n$ZX?ZEDOzRi^TFS!IB@*|*C$?n>1F6> zYlrg63UX`W&#Dy3UFSLqmj)p;_<$t}>TTP0!0NT@94-6gra#XQp76AmfQ~D1=F^LH zmlN&9MKlw7?WI@fc1Ci)LOZ0$c%`=4fGJ`ga`Kr>eq8SOabuvazLs`dk@Cne73Yg% z5M1|KwQ99HfgjV2WBdBBGEZb@9xQw7V@Q!GQm#I+ld_T067QuU7WB#wI}4-?A|cf3n@w%{ovBws&+v%a#@zQThd3 zZ%*;a3dl9~?z{8(2@JBh>0=6~xDMJ*SSFqZM#0Jpz{<#;jsd?!ltZCXRZ|C#J@pK< zci_mMU3TaWCLVDM2Z?USXB@$=+qjtoCi>&*>+glKk`icd+X_qGd5=cy>ViC=0UeLf zdp5+WA^_cDH*(}~T5!kB2D*;GXD__qb-UO|pJe+2(x9ue0~#BLi7S&*-Yul2Fr=Fm ze%ir>p3BiY?tAak84n`9bJs70N*;6`#np(*M%O15<)yH3^JaMI)mI&_(&0Q;rfplD zJr=^Y?b~3%+ly#Ra9=;SQE5pb9nyUH)z`?BNT>e+KYBlm$x8A~2_34N#2?Yz3?rI{ zlWCEZhtkr?7VTd^=R8)fTrISTGBxA~Im*4v^i!=r_i6rUXjq$&-!uKl%BhIIUAT>l zf2^E}^2!Cdlt`*C#^CrWS9?TqEi;JLJlr5OOp7t_ES~V z$h5ryi*ytkBbKJC2d!Of57jV%fVt#3MQ|6#+QTV+?zjqApP+$7ab!hl4sdlbG}F`5 z1qHBe+cs#~wq49?*rfe-AIQ3|8?(uqzq9|v0o;(b=xf2q*4y=qD%KT-y+n=tU@+$@XpZ)fM2@}RacUQNZ*ha;{vp7^Fe&o({O$h*OOT?wKvmGW) z+zlpA+JoOqT~$cxWX94&^INriC9GJvh8#H#k|~NXcOUmpvZU%5+VK6~gYej6PrwT= zy$X#Dygk_0oq`Sm<{@YOBP!HX`J$%}~7|n0n;H~)!U0PS`fVD#2 z4nYSxJZnUg8eS8Ovm83p;V!Py4E-~D8>ShxGq2^^iiwKd;_E~MvfQ`d+s@vM#JdR93$)Y zRGtNS&f`2)sp)&QxfhbjZQ9;@(jqjP)$qOBY3if%HfwyOo4gpQ4?b81TUuJ6w7iV( zVhO z)z{rjhY)G`gf=|zOcI6sD%|zt&`%_Gg{993+9%@YAl)tq`A{B&y~gz@S*Nw{V$i$-*^mPik8mer8gEY*9n1&8 zMk06!mWnu0u!!y54rj{a=KED3TNe1c?{BDPKQrq)*gH0dcHIQ(_ZC znh!CI$2kL1-cXHbf7@?Y=NLDkPpUCv+Gre`mjxSN*=9&<@|8gfrp%`$S)+S2PpBa}ZqKy7e1KndxpYUkTIlhIL#!NgEPg1wgcW^6{tOTi^N~ zy!!eZP*YP)o_A4MsB%VH-gD2t;k@%NhSh6ULv?L6-My~6o7k*02wOI9rZo|2W0^J$ z+20HhUJ?n{#p)XysLd!$xyJCV+dQ zlv(uIgs?!SyDxCm&7))ew!j^nTL4Gyc-<+@JVZ8W?0^gbZ+b>?Esj|Z0&Lp6g>3qG z*ES7X5iJbR`q>U@_=UfDL{2-VdV6Vy(7N>-;mT{TgJ)iR9zOQ5qhQ||Gf42^iRl%~ zSHMG$JPr>%Fc{Ju4v1(9t2DQ zA@6xR?y<-NB_(+JeGnde;9*$0bQzp*!fZI`zyruFJ2L1~@4)2CU$4qEh`!N^DZov!>*~Ln*?c z7)c>!j#M0la0HR#eFQ<%$hjJ~cuPC+eH*aA@*@aT8hGaeh3lGtc1&BOo3`3_zF(JuBwNTX5@Y>&P|6+__J{^Uu8m%_D}9nF>uVTer5r zmaW^MslYA)|u$~V#bAovhC;}b0XqEX+&0#A^NaFzP{|_K~Pfz zk&;R&fqZ4#^e&c@p}g@zfyv{4t5U%HDHm&gHrVof!&sQ2`exEZv~y2`0L6JL6G4!% zwv1%XNJkJ9tc;M8^m!rdR@#Uv6>`T;21f+V87aX`8OXzIc_B}<>_|sCod|5kRcPQC z&YGlHaM36`YnB#>I+V;F-0y%fO_Cg>%1><%PAJer0gZmqu_KyQx;ne*Zf;!EBE_`s#)K!5S4^0a~-%;uYY1V1Ao_?`)UE|rSIZnikAOB|DiTh$^|eq~jEC(8q1c%gITJs) zz;Bz0-!0?|B5^_j81K(ehlnIhB@LFLhuAEE*hW9VK9TzR$OMD-eFfjNQmDMpQ5OsA zK{8d<*46S%gcL5@{3)*TJN?O?>eX+=t*RQ=7jUbs4db{<>sa}qpe!jUCV`GFTWDJ> zC9>3G{QYwbe%-_NPgEReIz#gx){Wh(pdcS0^PkU7MyQAzUd1l2(9DT$@X;LTmqmR$ zTee97D+b0F*Ozc79G`3KhyFpFwOZ$p9FKi>0SzQ1mrR$kZQw`7+^&51oq5+^2`jc% zgRP}&+}8HlwwHU3XBH+bB`d6;*QbmuFrfWge$ZD&#^f}83-8$c<LoULB z9O8K)W(tuEQ}w2PD0HXRD8RE2gD`R8M5wH;g3k613Ss{6G)}d-ymp}NMlorDn%6=G z2Kd09jmO#I42r4d+l@_f1ATq4`)(7-{6#U{jxzn&5+zS|)IpbMp&1AB!KltHhV!>0 zoygEl@zFeS)Qqzxoc*Lg6^vKdoF^SX1b~SXC(xQeXID4h>W6DLPGCqTDRwc8$kDlG zT4z45f-?-9jp+R?GAnZXetD3F>u7{0dJZlwh6&@w(d?tAXHf2or&5CAJ?|%5+wnN= z`r5i}EAtQ1fyM!mX-X6zdMm)YMHE<8MvKJ?h9=sFy^Q1s#Zdn$gcr z-@<7>lmiu`W$8_UtR%Su7QnQy`oNn2G0_fb1;y=Z%D7Y7F?qX1PaFw zRh1hgk~EC+ummf^(1&`0#0?_)inuqnJO%U2xyg(v#e^0Y8hi=iyiCapu7+A)lYc;) zJjz$YNciACCopYQgqev@%r=@onrZ54YuKD)6bGL|7PlBwRkq>dsbNiv-~P@90aYS- z>aU~n5yP5b${v$RdC*dQbeWRU+_snFlR&v(nP}(sv}79awoN^(M-&JNLuKMlC%W;k zvI=JGvo|g7@_p#m{fgE(%lteN#(O?+mliwcBVikPeC2ON-PO#c!sw-!>bxi+zsp3ESD=uK(;{EUh_QV`?4v zmCY+kV#;yKBSpNp!&&SVamO^KAeSr`?KBU02%0lj8et6gY~S-k5IqS)FksHIBXA|z z#)~7xExl79x%dL)r+7D&?Tpn`mC#UMPi7<@EsJMT^-?OMO;VvnMX+M|a?`nOOL+*| zK!Pb3*WUaaU0WP__@U&573Gn7!sR%kK)ked8DvYe5Hh!Cesw>t9e~e?U=`53g6A`K z8$TBIn6x{kqa8$Uup)Snl(J3^xeOd_D7d>Bh*KWs<8HR|6zl5hBnO2E z>i)!bh@_AqlMbG?Z-D*x-=DVH;x=TOEh?^L=3!G$rZ1X4m>;wsdnL>R63=Voo<+9O z?z`VUujpFjW{}L*Grc`0h+&enKK9*Hg2Zv-RL^Tonwi3kj6NJgERmbH42?I zioZ7DSLUlBnTQ}orx=Ec5ej1WGL$gvDdiUi^iZu6HX88(pyb$lT8Lgj(K4?p5?m^^uRXx+Yz zlp@a(bhe=GJYt?!+WNM!ycPqejYgxi?Hd=%i|Ej4Lv1a5?C7Iu4Tla=Do?pVfv-9K z;bsaI5k1pY0eBd+7v5X?KJ;|8K}jh((R76HsB2~bw0U8|ZsXm7LVsv73%Tlv5cRMy z%mi9GXaM~+dHa6o+b)%v=S|Ncv7C^Ij<+eg33Bxb`i|i^_dZ`63y?)uB#uPYP;O7n zGswX|#rWB(NLXIw5g;=ZSS*5P5r>Yy6sdH>OQ0ii0P$~2WZz^C9AogWAS?h!+=OsX zG_Y^P2zG^D3KnfM<@evVepmz_j2l0G9Iw_oH`ji2J;xIF001BWNklgC)dGs_JA(X(MMJ{)Ya9&r#|&bT4d#`R?RHPGzH5|C+%pIjV0oU7(LRe zYjoKJBvH|CRWZ3LufPRy+Pcb0Lq);qn^Fb<(3icHE_(tgoq?D;2uzBGAo_}{J#)VJ9G&V9T=p=Sr!BwE*}wUzN)!tKp{HNFwO|+ zy$B2v#{+n-qYO5zTLYi@%%|bdL;3y;UI+046jNHoM;9qkfS$?+Si5#T?AXypH1dEa z#EZzG-(bN2Y}&jD)~sCvJ>6YUQBek^C3qtq*8}N`_pzf*fAbbr&Q2jK%Ox0yoD|~O z3o+%OOO}&QJ_*K+9|tX4(Zo|s^|XAzbkMaeejT*Ad302c1O$luFl@vya-WW#3AnrY{$>j1Z|SNy7Gb5qvjzO1V(jeffJKYmfuiC{woPdkgc_Rx z)y)n589#OmImzUiVSsv&HYX$msJ4ZPA~f{zY?_p(*d!`S6O*|eh)E>-i{nJSz&)pw zf!ufRfVU(DuTo0G0+~T$@C;&p`)A8nft1&DQeNgVD2q%6F=KvEMr0XbM&o%ZVu>^4 zNFV|tx{jRiIW99!t0Oi7j~D*6r=wkCMoBG@Cf2l)kEOrMIY8aA38!`qq45HyPB5dS zWx9AAks7fbSQ0K!2`=i z;j-U;)8VYMzYN`dowCrZ_itp|&lRIQAa&HLl4oX99{vdjbF54de^eY>w{9l$#@E08 z724iP=DEURr|h!eUH&^I0stR=xEyx0Zs+xe0bVaDD=Vi#&DyoAVcV9iFnji~aMsyp zKy6(OtXjDOy1P4|jQm95*5!Vh*`bfFRjbxYQR?M}cpOh}YAkaZ?bO#fWq zaq%Su^44d{pP-;DFkR#$sdj0%l~o)Hae4N4N4 zg$Ie2WO<#MONU@a;1N7+^DHcY>C^Ut;W$bp`!YA97ZF}a;0a&c#q#X)FFT} z%1FehGK1xzxZ~1xP7!!0FwkEA{d2z!M;v|#bhfoZaj`$=;4sjI8gWGtGH=MON(FWt zF26BYe0QOn47$9jw;S48cfds#{0R2nZy&O&(@X-_DU9;)9nlI`&KNxcW11!JybEn@ ztx#50OlBIS@Wzenpk>P@n0?%_aQkgH!7p#P2Clj4=kTlBZiI8baW=X8ShsF1nO4w_ zUtV59CZ83{SMnk=u1}HD)_R6q!5xq{HE28FECU@ue&^fYgd>kS7B+2I1*PQ`jt1KH zOd8C9Dr;I!l!gF_jKnS2e36y5w}X5_ z%UIRu2Ek%nL+OQiZ_I~H8#X{yRXMx#mjjFZ(ZL9x&p?GdeeW5R9bf9DW#=h(S0EHj zLEjJLR6-`CdbDzHF6?#%>z#?4D$6R-T#yMG>Nj(T%QGBySSUc3>~<;8OAj4sx{sh9 zY)O<}krfKjJB=3bwUurcpSBlHQQ(Qsu+uoTw=Ji=#}I zux_`Q3ugvH1z1#4N(yMp#`SRScm5O3IOB^XcyJAd+sTf$B)wCT%2P}`yt5m<*)Cb~ z9&h)psDK?iw!_w~TVUq?GvT^xuYy}{z5&ks%9mib3FD!$z8;R9eGFWC?GFJ_%r1H{IC@C%^ck%1iZD41DYFf~K6VzMVit(hwe1q&WZ1;&1;L0n13e)zU z0qfVTg379DXSz@>QJvv;gIVRs=UZY{7xgPo*bc1tI=eccud5Tj{4W~XwOxz22up9i36coQ6U#G&+DQpB@J z-t`t282)rZE@rL(JdXL|*}QVf1OFnZGkr&L%gGOsAx_4|U}T;`3I~lxk5N8eu7tni z=L~2+Hy`Xf(+Vi-L=lXeLC5Ojx)QMTj(}G%CW6 zJh40AMM)@qwr*SxXPx;~xb(*tlewz9TNcTqcF1k+V4FP7z7{Na8`iE}N5XCW`c34v ze$ItIg4=Ju3BLKQufuM;ji*@+Di_>Bi_bOH)o}93ABXF2xSA9Ux^!Q&W-XnM_;BS4 z^2@~vR%U95mGm&@F(YOL5%xG!=(SLqJ@G3`l-xYCkCJgt+P6m0V5Cc(I z3gCv)t5n&ffN<1NAEm`rba(AW0W#8IGlia$7@)O+zy0l>(AL^YaUDujhz@7v%h5aC zK&XsxbV+9|y1L+FM|~9T_@7&0^3+MNdd*5080>?xQrw+{sF*FMdiYOp(=DAW;JmG# zwiXuPnUZ3ttgMEP&UV7pgR@Y!00FgL7f}KGR6i>e&m*f$Av&LXgLII1|CV#*P^SM||Wk7(03lypDH> z!yp{uXZFuDeC&Z9OM9-2E=<4Z$t((?BZB0GQx!^*$=;8~Z8SioL>Lha;=BuX3 zfPQXGBa#u)XZQ>e&oEH|tzEYcescNGVe6I_S|b|3nFrBRaxwI!yXebG;oJZ5AF$_M zQ>gyho^gNjzta6F?tYe6ZKRkph63Lw!gopeVu1Uq@2~bd)29>9mR44_T2r^BC8yxO z6kE#ic$m7&_UH^q97fa7POVDP=osdeheir<&kb?rsVJ^O`7&Y{Do&=H98AEBzw=;8 z9zPPRC+e5XKPMfu(WFBv-K56;NpbhTHM#qeGITp69_D&$!9tk-##^+tln=^V^pu#=~K=4u$&q26*rNrLb=8 zhtS#817&3;P+D3-rY^E&;}&E3F5+2C5ehd{7z2(lCp+=uABRgXo&(?d z_BkYo@RA}FhH5i+W)>sYQoKPU;{jA2rSRC}Pr}lrAHsR(eh1FM9b45^(B9TT67kSqf9?}JUyl!~nZo9#ym&~F1(B)IcYk`F%Ybu^Y^m~dT)Q|JF1A}}p zRCo$Bh3n&q{$roR0XV)3ts$0sRGw(On6Xk6;pkDrrsC)m{m_V}Y~m3)daN2H$dDrB z&`^e$fmSrnR(Yrp^MRVcSCZ1YdW8$gsfJUg%s~SOcD9i12oY0~@D-w&4&;N))=SAO ziCcibf6CC(A>_ZqM#s^lFo!4(?5KTxJc@qsp-14XGrk6u)ivV2+}|=tibPB`wD1nN zEwmRNdhnlczySx)D6h1*h|EKQpwp6Fr^?cT$-umU<>7rBI0LDvse=B#0eI?}=ip!W z{u|~#`Y0@2x)hypkgzW*E+Y@LcvlCdr>(>TwEY*?6;SYv8aV7)Wmi&G#x7~7paK{~*XzAK?6<1`=%T7wha3zioNzqMKK@u* z&%qn}cq2lIEVAn^Jj2{hiSRqm0yq`n@`wi5c0GM`m~!QsHSnb`oei(O`YJRuHbF0L z=#W9tpw1|W9eH~+ZumI!%U^_>Z@C`Y+S<52C3wb!+ktt|Z-`LH_IYK}kXM~-Nu;pA z{lxaWJV5AZ-!MEESzc&#AHT~1S;dhBtK?$&Xyc^%feZH$-3ylelAFFy4!~qhm*`7Q zTSa-e6}>Ql3JCok3R22LeubF_JSuscMju*v@Dx4DH3N>|`db4GadHwV0Xw5SY$NY7 zP?EUeJYiIM;36ant=86dIQnD9!^%~wpsb_}`sBhL?sF{U=t3x55y60vIUZg?Ty^jNh{0iKYk~&Ch%N4S4aTm*I`K z=EJfNmeG!+9ox6NJF;>1R8>_2BS#H~Nt4j@wLeVXYfqRlV+M>KGm6SV0gp6LWx+V9 zsmd!>MKh+m9*o4gB7S;t6mGGlg<{Fen!q#t~&Vv}FnL8h*|rDe`prEF_hOw4sqKL#TQ!suGoSksELgAr>gpPxx4VPrL;1?u4kt%tHAqe=XYRirJp9nV=%6MlWZs+*nhRa| zWLJdS*zT0M=@2e#mnwjum0$=N)x>d3oyJu`al?3wbBGU_ZDjWl3Y9N>{xrD#mfN9+ zoY|$?3v0v+-|Tv$6n=5#b#UmcSx{G30|S}GKdz5$?i}QGBTFue+X0`+!Qa3j2`m(x z&BKPl$mS90Obp;IEUX9LRf6XNbkWnBJVIP_1{$_O+?m+rg`Zg!7Yn{LXi(m_xw3A+ z&d!1_R3^NW%I~(pY;lIcboR=W8{Kn)zOqfq*=L0{)k^$_(Mk0F0lF0ul`@)l#*ZIM zpL~Fd9LZ67nRxF_uLDwz4|(g96gdufwUWm zW@wrp(->dl1_0#YlTJ7us;et$hZe4V@zP7W|M|f~*tR@)@$nq3Z5?FhO1~+Br}3_K zcg%-cG~mOSmI#SXlcOIwK6Z*Bl!2BeR%Ydcl;VjYkdKL(5|t&ggQF_F2BBb}ANR_6 zg79=)m^lXXN(f#Avf|nzlXI#xJiy6fjf>1V%jY;{NQHzTk zHBM%vV?dkRe$jUj)hZ8zkJcxbr1lXd$d5+-C<5RMUpfo!yYE4A7Km#fuAwOk`@kZB zS5QEsSM=F*#m{~UKRo}t-mD|SRr+JZu z+nAxH@>Y2$K=EUaz+P^pDFjdGQ8H1HXaQV|4wr)8#AfkWvcd|51HE8!SZ zJ`{_bEvo4wcjHM@}Z7gFbLoJ<~Jxy9GwP@K_&oul%s$~^-YZpaKnu^!n{{r4@?9s=uO+x zqhgc=*S^97y6uECsW2yRvj=775uDFChp| z$h{YQgaq4-l@<%w0_a7Po(^_QR=n23FL~FQ=T9pXBuXIEg0>VAA-<14{scV#{EJXj zgy(Qj$ooZbS`^m>l%Qi;V47q8n4g|$QMwY1iVC2pq}bE2km(t$T^XD-A8K!1V2}1m z*dELL=G)%(1?{7}?$!!dU3CL&+OQd_YO8582P;p(l@l;86$13(xsQPX`1lDY!i0%q zX%>Q>lC^GnM@jz{FF}0m%~Sr48|AdOykjorxwDmX4IKLJF!dY$Yt=Qt|UaOb~p^g@vH$ zKPIiMW+t7@-*viF%n-DkBuMfUlf*D|N$C!t?@%xue%LHH^5`R>t!;-nUl87mhf@Jw zctx{KDYUk=!TA?lLhBIto)w4g)}j*Vqdz&^JNKmG&7RI|TiV~;7EXvcVP=_L^GbCD ze@8X_asuC!EAG~@4%}aGZG+7!H~sP^_|JttW?%30=W9TQn+R%p7x zyf<&&0@q)EBbh7B9)W{$6N$)iXuO~T;8@Z1lK5H z*trNYW%FKZiaNe7F#cLY2*8Isw7=szCgSaVAKn zDQK3%Fa6k4XAk)Cr_=eo29KP5IFn09Zl3l-^Av(Jkqz)@zr4H*9)IE~_}R~{fnWae zc38DyHMKJ?_TqXGZdc{@GJKY+xg;7zac#;t>g)pR@X$k#!0T_k1+TsKCj9*8SJOd1 z+;WTOZ1jYEQpiW(_%$H1MN-dr_*sRU%~_gie#*j<9nTU|13h`Bazmo4l0+*3=KbJ< zbK$yce+dmuP0%j~Q(cL2_Cy<%e3A9`LqY!leD1TS!L+@n(2h5pDRJ}qvRr?()v%ASlc%|T<~U{0T_!%2Fp;DUA$68S!FNT!yN9OB&O8!Hgye}tF^m@Hz+(7erH zOY?P+<8QUB(8u6r`OLL_Zo(8@e);9WAwfb$8_lK@`?FOj^yC&a!%-AhE-K9c5zSFK zTJUyx*fJwN;!GrtwwG4c#7!}d8Lb9*=IO{9&(grs0>SR2u*|@8iRi=u$@s2Pt^=n* znTl}&m^fiPy!ZZcnE&RRP+eWayH^T|TqkyJWhiStaa~ti2QR+-G6|lej`|1*KooFf zFE=w@YORPqz8X9Wux!J$5@&}bOZbJFR6<%<#@EVeAz@nu^dlj~9iQ*I%7Sqw&LL9Sju}<)lE=eF+N|c6DLvW$BpM;A7g~fDevwCcW`uFUf65+{;O3ie zpzYlL%#NM?cs|X?{{aZ&dESWnRPtTeUvteWw5>AlQ@jzq<0cCGze{WCXTyT@iTdcP zAhwf*Ihe*JN|cd#qXDL0Q~qI0I$`eYpFzUtcZygEWc8A$;GHsqrGLDKFCF( zV3WZ293hww(zy1OC%QBs2?UJ?pMB!BO^7g zi=5akD1iO;odI{<{dYPWfv2hQom+pfg4nEeVJCj>>F1%kwi*tbbqIBKI;}3{aJS+$ zDceAvALDxIwXRZ{3ud~fAxB+RAV?dy*TUEeWP+0Q8Z=u~S69QMk333>W7V4V&^W9S zP#@xMpo0%Q047hFOnKk|NncdhM5`q4001BWNkls>5rqyawO>&mY3lWh>}PS`*L9fH@da+Lvee(}XR};$3O2F<(qMW!AVWXrPDrW=bA*?Mt6PU#> z1f%3^9FK=;1ld_)!d;x;OY)1UY0|l88$r|9-xRDJRm#JefmI+jKd03>oI04~5pO$9 z;iq-7A7mQ5TfDNm8vcFXeNb6dE6LDwU^9_T2DrdJ$cGKF{3o7y2FglG;IPAIQB-uh zPW7Pes)im;py$SgN;RjRUD8x%%D&2&A2gkIWbPB*e86^i-i}*YRRxbc_%M9)yFY-H ztJc!(c)i{1Yiq;W_0ZkZ1xFu!6jW7Ju>!#SXyZXxFJ=!bbp#+;tj{| zPJslOcz#MLfk^HKjELX_nvd^57$vAftT@c?R4IW-Gxg#x{ox0!&bO6IWU`HknNb*F zuzAe^p$#)8jDZ{t8l1Ip;g&dwcl1++h6Y#LxiTQ5fSln<3n6G=e>7#Avu4a65gwia zqXyA76(K8f(dUalRFK6WmKy{NM?r?J+TVSDDZKT@TToL|4+8^z=CUBM+e*j79MRDq zjgotM;EBhdBv7k?M6zwRU)QPZ5wN(VE(U|>K;28$5 zZ{RZuw~ERNC@wC9zyJMSIPV8@VD;*?Fl=}e4B&bWDvAC9sI9Mq`Sa()v^}T7KKsnz z)A4dAh!tSz?&X2;}O)>+8sc2#&~!uDHNNiLkCJzVSuqaXBB4B4GGXysVInBZ`}Wp7N!vCtL#y!liQ2yiPm_1S#BpQc)?06)0S>mAo+1zXrpJk1 zWt69n8}!2{pS-j7MBV9kN>fL1wSIB>V6a1933)^KMN%5c9MCOD;PX&+u+dEZ6r8~+ zcfSmND@v+>sK0C9<>wGR{*h506r_=Lv}qEm5>SESK+Px_?dcNASGFNCpsxjQ1n+Jj z8&@kC5GB!x^vMfv6WuJ{CmBm24^Jj*W6RIrqKm+u6840;Q@*AxT!ZSCM!TB@X@Tb@ ziukUN2Of9;TDG>()v7v5_OW@hD0^oG=*D5S}kS7{mDM7U}5R&r_I*icViWifvhW>kKJPr$d%Y{h~VFPD0M*#~gdRoBC^ zr5{3lT`e8VLnVOu;i7z1bu|nQ6u^rwz67gRt$`UcrbF|{5wvjM)79f`y$*cdF`pyQHNB`j)C}0)Pj`youBuya`88aA`4#Z)(hp$F=#k_;o)m`} zQEQ2sH96$$M_K^<^zzH$m}8El_EK}9wy|qxT_2HO!umm;xxlrZQ5;?d=qxVc&-gb* zq95jUw&3`k%8!g(j38(c?cNCh1aDuRTUf9M=F(kh* zY0|~!ge*Q{r;J}`C79`)(Y@so0Zm2N=^N_nVdBJzaL+&Ph5{(1a{zj%i*E5o9Yv?E z`NluY4h13lzrtJQUViC$Sn|$N7&&|dOxbfXd1&RuUN$i(C|xXLTDmb-79_q4%uPIE zY}rji17UYC64UT@TlCL_UU3({^Dg|?<-dTNZoY%g5i~T^^KL5fT}8OzF01~2sI9Am zw-+sfF{4Mp%$fVU%>isivRg%^PReldj;riVW@yT}{n!5scmDYOx|M>9je2HWL~_Nokwm*kL7nmQzLXOy){OTZYrQk z+?xGJO|jCE-D7x01w9$BUb_x{_S382>T9oumTlW$MDsAh*SDluo6vmmQ3f`hoo#UX z=T3u5F1~=a=F&B@X5eA(2cmQl{oSwJtg_P(^Cin4Ph$nEcr*N*Ld3jEhHIEToatZk zmrG}bOBlz+qZvyWB^Si_xOzwLgHrS4t(3{SWEXIwUg0SX*8@2C3CvOnWP&hZmUu@4 zrE#qkBdt{RK^#AzBz>hii{>2&+$g!Dm?D6gnw`qPkExBlrzW*~ARy0EyAc55wMI3Heq^)+&< zK56pqWXDGY(1uSbN!DMGE@-ysrQ&b%QQ=9#O-I7+UJzcmEhs922OgXY7hiHY z{2Nc$*VfW3gw9+Tg6WzKj^c6DJJ8<;D^{$A!wx?T#*H0A!cvtYrVB^;p3Yil{O;@P zB^;K#^B!D%_4Tl3Br_J4 zOSBb}oKwuY<<-zB1;P6qacqn5>`6Bo$VFYWZUp485)X4eJohoU^wOWgpZ@e$D6c4m z+PWI@ZmcJBiKdtUUAzdsH2x-~SqN>d+u?wH_k|m7_;0ALsgyo#nJr=EO{u2^lTtAjoEm`IDmI19j$JwkTDGYx?`!M}{7WnZCLOf!cGR-07==_6eL+RiMycQs*@bU5^oORsszwq}v{|2@7^_)L?7N)dJ6Lt-QC%+4M zwg&|?GsMG$Pe1hxeDJ}Cagn6&M4#S&=QM>aRm}En^X}L@%wpQSUUPaKl zV>^s)ZiZWKxe=yM-wS%W@ycYb2ZraZj~SeEw4v*+Kus3p9j4`W&E^-do#|WQ>ml%n z`lsuo5)jNfB(BTTA>gG7ku{Hui))$fO=;kM9>?~$x^)<7*8l^>djL;_We68VmO$-H z*+NaY6%rAVQb1{Jc9v@99V5vLyh9O4m066ZEi0Y@DUpT(6|h#R>U#^+IF?c3upBfD zz(jFo!Khq%Gz_g?axpfJU~vI?&D!o|6ZxqxB zIMRRk;YZ=_yYGQ{Z_Fp9SXWm|GXWeqQ@-x*4b9ctqfvmPf3Mc|R;a12f#3e-4wyar zXmZX+Epm256M^DEzgx89fs!<$EufMge9tT14Z4?b$;X$B$d zgJmV9w2-`U^ClQSZXBHUnN#7EQ%`~e51vW8v{0bq%mmZwc@#{ki}XW*3Up5dZ37Yy z^iLPAals#9`SO+Uop;^?&p!7&y{~VqCr5|mGfifK)NG<)nJ1ZZ5J$WPvaO>X z%F9aN)|+mE(?0h}=;&x?$A`|{N~k(RT1KlSdm6?yiZ(g2 zH~n29Py+IuOSA_#N}F50&(uLc-&(x6?pa85DS3_-@Ljn>i#a#rO~@LKAg@!(Bik?< z5Gsh6khz#a2^Ta%M%(5GCWd7!W`IoN=EA`e!{BUQL^xV9OX;R8`kN@r(Z?`~2Rl;B z;+9ls9O&{>0catvGYVZ4_@pET2Iv~s=U#dV&N=5lVA=c2prH|Ocid6(Da4wOz<8Ky!2GtS(z5}I+Cx+B}+tWEulDZKsm5_sXIm*9c>9-;eJTH88c*oa0b zDk!A;;+-N^bDC_0B)&Dm1}~<<`$Dj+tFOEQzV)rI!S?Ojor2O^AOoCLurk8@WV)fR zo3tv~`+b?3F7A`5{%OG#kw9bg z=w{0BvdYUA8bVXn!=*W1kc$vHH@VBG5RjL zHiX2F^GyqG!)OMA-A%3&@E==htUO#qQ%=APhFSQ1ZpDF+D=i0VfMJM4qX%mbgM-lB z)5E5vL4fL-YIykZ$Kc#=e-A!bwvukU8$d^aSccGrZ<)i(g814at%GShTC1h?6bcK@4fc{3?DfHdV6s9 z5m%089m>0C-*>!hcn0x6KU{dyy##O88-T5ww?bcECp3>510Ox&a5(bF!{NXK4uGjs zr$Bupt~q%?+9Hj0eZ=++eMEAwyAr7lK z(AYpb$Z&RrvpLL|*P4is&OHqkC4vqApvkbUvx9D{y!^*MhBH416Wt4dGD16gAa%@%nL+qA%a8?3NiWS$}gy- zL=PI;@qi(;X^1%Ayu@*W)g+)xaD=!rCFiyYM{}-BiAMrZ`M~Ax-%)&d!Qq&nHKPc` zCc>zGF{Bt2(6WD$2{KZm2}?P*#0?Jm9 z8sCwJfR6Td*tUH;tY5zo)~s0#Z@#qTbkYAg-*s9pt}9w z)+GBBl}&epNIZ6t&g(jO4QhFL1#H-`4i21oApGVxx5Kn)dqPKNCzKQy^R{QnQ%|rf z&!I59;KEDbrd#iz*$;7soET@C;fL?!#x(9SDE*5Mm?xT{aM79;l6jVg@mt$=Kv!ow zl$BS*)X9@z|NZxceGk|Vrc9m$W5|`RuL)%~&PHv|XHmg+`{2N371_A+K{Z?O^)lg=^Tah29x?#`1=K`OcbCd1Pgg z3=TM<3-V8XkQnyS@WI^^<5T&%Q93UJGBQq3Nsx_z@*?@ezc`{pz|oa{nMr__Lo}5^ zQ|cOWMSmdgRF`o`(PU_V;1K#!aM@aUmH&?<3i{g$ zUx$n6W?e`}?$orn@IHu&Lv}mSXr2`vUJ;B=BT?|TwzolVcMq9_@MgeqW5>eyabscJ zxUn#L^k^6{d>B+#mh;&O+*}~#;ml$C_8oMtWaWz0ux9OAqV1aX>!7P`2hp#px|S3? zxsLDCopZLYc!AA$6XJw3{RZ59aNtmUpxmcIR8B8?Czxea2qn7s9&{u6}&O; zEjan)6NA1PA2JPjKjd|Z!Tr_92##aqhvCz#3^L}^R6onpAOAnz-UMFHsyG;*d*8dS zNp5a(LqfuitRjl+2uN6}RI9kPYH6v}PeqhnM8#Td5v>c_R;%LjZ?TAiML|Gz*}|?Y zA#5QD+4q~fZ~xz{XU=)f^S(FK@0;Yg@AI5>&di*dvmf)@Y2!iTZ2abRo0iW~b5jAL zOLH3tl`^i#5d=dd4JrDQ3n^(?@f;orKRg&eCMPGS$^t5rjX_dTqp*R;-k_B#;v6z% zpvth8pBKhzanL!C(yLph`{SU~BaJ3qB2B`|4NW z@~?aa&i&-asrP|l@W4Ra8289SkHW>5TmrY7#)IxHK_gdzDZv%LagrT3vu#+r7XJKgZ->|H_Zqn7 zXV<{GwQEV?V!Ei5`}=o5@2pwyAK(8sSiJZ|7#tjiCNy@qCqX9fX$fw9g^m_E`xEEG z)jzuy<}a8py&yiKWO!r zS60EkqU-*a+Tu&q8 zQ2^(kBS>ky3}{F-3TfQ5H4)*>h!lX+%D9)j=OD!e-=g^Hm;C0+UPg~H_Y^o7hef>j zvLS9Y;!w#?etI>$@WOJq>z@0dtE&T!Ir>OmDKtJoLt1<8wFew|)RC}a`3iXAi6>|% z2q(o^4zNY98|&y&ZdbRoY>Wf8J+%jc`Qs|3wzhWY?CgZDu1;#DqjJD}u_cVFcJMw2 z+*Qp>efdspY@K2Y9-of(c3QE6dl1l|Oib~-O`td{7nL=WIqgB!)zNVpX!ka5S`Uqt zMtJwT&VVof<7M#YZ+k2J{+@f_4^KV~t?g}8qfmKvbale2l`q54&=?&5reo+{byU81 z)V)<^*%0`PUtACW`fuN-IUwBh$9qI7)LYoNejO}+^9gX}xBi6=nSAN_7vbq=o`w2` zIx>hfM=^zW#+lw`E^}At-``XACbQ8?H$B7bVq;Oh-jw) z$ea$Ie#_yzprf;slzC$XjfT)x78fW#Q#~5XqsjqmKh6KJoPH|Io;{m(;Oj7>4k`M4Jm^>Tx*-L~Xdf=0 z)Wug}I8^Fl$2gy=xFun;?wR77E))Ihf$M28)!5CIG}V2X^lE|WTZv3N%)Ju!NSTtB ze?G$qdGDSwK9gSRUvRUshWz=dMhujL*cDSPhOVGDot znlW7(Yys0tw@5SdlfQ; zuuMXk1F2r62&_()DR=eOU#}mgp({Liyscd1Dp+KaBe~D$So*A)zwhyCJ zW0Rv$VUu7MDet6Z(eSxaJ21qwo0;h~_&n*&b?tomCgv{hAo{U^3(N^%71O)9cP~s) z7>8?Q01XeRa5`+IaU?s>2R{U;;c_&Ox{0Yje)>fUbO97A1+0uOy!aAa`JMm3^*FSg z6czbRzx^F;t~>IG!)Yi7&$1dA9E6^pS#Z)xC(xbJk39S+%@5czRew~62p}D8LS@j$ zgYG|29`i5N8N z^ZMW~-}fH)?4_T9x1N474&=b#&@iRB_dff;i!Z(eOCDT8JqI*4*b731hc_|4yz&(| z=9r^tz6P&YrD3J1DH?kF*0=r@{_DT4ftj;$zpm!}!D~_sHZROQNaL+Z0AURIIZ56*oqNz<1gUg9cZwyCpZj zF_0tEJeJ)@9FCY_F;#=bE=*%NAB&k`dE+qU@W=@HfBM3U;oNgS0o%51A;W}?0_<^M zkM`X2E{1D<{!7?pKJMVhA-5qqjPmfq52MBl4#|1r5jQTqVl!Yh(Ggi+0JGAQ9a?zuGbE*WK=IG5>%6jHq!Jmgm!o%F6w&Tym+dm($F!S0gJ?l4y+ ztO~hMg?vhEu}R zr!SX248A9qrs1I=2#BgbvX?_ef{SD5bc0}BJv{u#qj2?q{tQ}Ln_+Tt6q=h`Y3KtD z2r8;04toPMx3$4I4qHr2z>My0c=MZ&hga6Dfkz&B44PZoZ0OEC!f3+F1p}+IQtX-htFXe z9;Ue-Y?af>t4bZMT6*xohiGUIho}hi$qDG1F$aS)~uQE@I#Nl zm;dRjuw`pM?Fh#?4BjhI2mRZ(z(+swAvo)-Gu{2|07JvW)SEl>&_m#;qYfv7`SQyv zVD+li)Ov4{RY-dHAjt4eFdyt{&v;UZ@+Ub0UapmoMeCpjv&m`W88{TP*J4CUnz=r8vqH z!Ux5TjA#9HNV0m=e>TicfW}dSLN^JPC6p>Tspn}R^N$FUZsO74WqJAdnvZ+T zKaHLqaNP07z#X^W1#8!Dq&Wwpt^Fz;+&At4z*oFlRo#m8y@)%LCC3 zqlJp#_AC+$$5pp{rScktp1FToK<91eT$y(dqWPmIGCzjQg=cH5mWXKo)% z;)E|QPH1kX$@kMvJ_$a5*{5M<&rCAPsIX}>9CdyH*b`820V?t4#R)hBiVh#yi_HS7EWI^vxLx9-%Ii=nVbZlYBWG~i^}mwKlx91?9s<*m`a5o zTYfml(AL=wcinLpY}&X1UVrGJFuRvq=EI{SFlTlzEZB7c{Ll3_0G@z>%8!dLo5D0B zGgdN8C1IF6-oOaK9SeW| zp%1~QKYan5aKdq9G_hB}Lqfb9ly<7iybLOeq2UoY_}~Mn$8yg-4-j%lFPu;4>gtA< zUVIU{XLiFeM;}3x)4%@h&2Z(F-vyYgqg7hC@(B&{h7IdspS|~juYBbnVc&iCro{j( z?|8mb17CzB^unF#_;$d4uYprfT?{k2XVEa(nzid-`}Q5Qa!TWHUBE))uXVSm0YOHC zEQZp=(NgK;>y>*cm7}QYDc?ApCWSP_3Gv2yfb-5j7fwI@G}yi!_o6h>+|k32J_Z+_ z_i4E4x4(s57cH_A4)~b)IvB$<#X8#IJ@0x48FRiqpm@d=f9B-exdjxRcc#p_lrnX{ z=#m)$aFDuqbc}a4BH==3(u)1088ERJ2T(BjCP(E3f=_Sh;cyG&eUIO>hY-4t3zZh3@W|aQ8j;!m1T3;f;qK z20gvAXy^wO;(o8$7gnrzg$`209o(X|Sc&T-HYs!&no@KkQu+@rw3frOl9fu3A?~3B zEk-}|$0;*exz*m;32#2}P4JNq|2>?4!FhB~1YTZ+!y&r-69E-6eajIc+CtaUfDb<8 zAXv6+89edCQ?xpadp&%xAMU)kx}SqYlowcJ_3$A_GnsRhR3g<5w|6~PDXgcqZ$pB zMNO|GXy7K&Nf~ss?*H@tfxaebM1ooc%EI`9=L`iAti)a2rjvgG#BdO#0?Ps7bY1xiEj)4#X+_@p zuHGrG$tR!N#I(TSC#<0B*KZ)>fs^650*9ihK-Je%9|Bu^vuDqN2OfS1)~;R$r<}4F zI=ed9e{vFD_qs#i)?06Z4eK{Tb7KQ7C8eV|IvY)HV&WgMnqi#8uk%{Y<04;j(S_Ox@W-dd+rYR zJ@_E3S-qBybjNeD@Cf^LYd6ByZT)l%$?dn@MFxdVgRQTJvB?P-*xnE4o%;#+o4@%0 zO$g(#7q0g5hJ$5;4@9IQ%U+6+(GfBhxXJIhN1!=SeiZpg4e za*?B;P$NgHonae9Aq9q1+=Lx8lv1fc|Bimxec=N5+Sjgt-FDxV?Hb#&W)l&drfl-RmtuVk~=*qVe34jQJ5!6k#Pb!j9qL z95^jyob(K$9!nMCrl9eB8Uf;T%7~Q9FP~mqUJpi4=Z?vS@S<2PSiB^Tl$Q)Ws1l3t z%FBMiU1{#~MPxT^-VB>JZzUzCt!zI26qOkc8C9raqXOP-;cjs4uYLvp_U}KSG_hrj zMri*0J~;pUbD_R|N{$9+!y#D&UU=R+TycUxQB1kA-Qb*M~1etY|ON_q7O=QbNMmdNwT3-jF!^6-3 zb@1MIzZ(vF4ZrDRV@*S49GjW-b#!Rri!Ut?c_k3& z#E-qxkuq8&FIVo}$!A=zr7TJP_hF*?>(b9wN0nEv95Qi3J#l%-lfIYcpNu|ex+&h~ z$IQ*@i&PIq^~0A%Ws5vAjFR+2ldKFRjgT2999bpHhyO)|)#Y9Z0*I^*wN!(YIC)45 z9t4btlL(Ek#A&5Y!-xo*yOvRo`P0xL4azPNQaQag#|SN74hIX9t!9aQh(NDivla%2 zaN`!Q0-~0#T)xAb|5&*pN+V;VFt4uY9Yc= zaTQ$jPOu1zv zzH`nR@y9T@G6;uIa2GW80N($;cf*}r8=ObUZS7x(dKJt5o(1i=%W(7Vfram{v~v(re8GAf)OH5ej+0+jYhcuvLxZM zl4h7`O2v=0X_#6R6DU*U2zevo3&f8v3%w=lu~VW?8(f(QkCHN#(Xz|{c$hX$xunGH z`RAX9326l@J#_~!)rFuss3K!)Y;0s0uDIeG(BD5mEqE$u-4uNC6KBKB?oQhY&W(UD zgi;e!Hx&$s0z0U4Myw(q{EOyqYX=5!NU14I4}f_O--<6%NF?IRX>4^o43+cz;scRALsXM zM`eTa9#fNaz7_(~%Rnozi|4C@)LQ$B`I^9V>rn!}{-y8JuA7O>)q-jv3ppx{5|4th z*%?UE${LUq#M!L}RQJ%j^Z}DVHX&}`R5?Ooxs25Sl(n|=27*Bu=pWW&p$o|Csoi>c zm#($QlKgXz&(k!TFpknn8YCJgjw>&&LKJB0AcvFYNhe#Tw9(Ft#bf7Zo_RLhV5coB zw{IYnkrfhNHq_DCMTaHcefNEGtVJDNYIMY5hrzMO9StMnxN=G8XZQ+9MY;L1sbtV2 zFHxz@1}WVHf1|ftZ7LBtA4x++4vz|HYJ{6^ya`sXUK@6*dwt~Sg?SiKBCEO|LvP5N z(cJ|XUGOQoqXc^wY=m&W2j^0n=_n3N=i-abhZ9dc&d$2hD`KmGpE^}u>4fpK%btUK z?!K3eJg#tyj*<_=_Wg8|W9^eT8tF254QFzz&PrOLJIRF5L{C$uy#X?eiL^Q4#1r5h zfAKat0}SUmuxI<&V~@iPH{3{vZQ^kwjE1Xg#x&lzsF~x520HwwJSx@;snfJP-J;sV z^z{)%+{(Z!M}=%LNb%=9#GAR1g`L7F zV+e5rTD=@69uHZm;Br*Wo@JYNDF5iHAH&cPuU5jzP+XV)fe(HVI@{amL|%#`mC!Rj z2(uw(Z?Ss{R6QK6SlPtOeM3kF&W|?qb#&44(525lPd<7a2hl{09sS@RHE8(?k3&az zsN+8S?hT*2^wZGSHyhTiM+1UGT)0wb47P0D41fQ3e+%z<_dDb;LA=9)Z^u*2w6vk^ zZaIbW(qacT90(6Q_z*nx^in$Ac0#Yvl{+(dnQov@wgIC48A7XkdfuB~f*;WW|A|rM zLm-D?Zf`Gq@PqG%h9>S^wYRs@K9y^)y$&|x#>^((q0bq_zP=!c zDSpZcX}z!|4J{dO1+8!?_jVFAA7xOPbq*C(KSTA6$}85N&?>ax`JLP?nPPrsIFgn~ zXgzD3fDcimM5wCyrJ%Gnx~sb@4;l#EW3X=RdfG`%27`JXjFSg9Jx%4uir?1W4tL*u z4=jE9S-zsS4wsY;!<&vh77jb?4RlTw@jGZEuH=~_aOY2rm4xGrEnDsgD7T#aP=b0z zsPIe^Hd^zsAh=w%e_%U2aQ_3eM49rGiB(ow+Oozcw6aq`C5G+|O^r0)v3T+EaM@*- zLVIfq-7kVim~7g(9^QWX>F~*OK2A%5Y1uQbyfRW~IkXqWkMY@MtKPV=4)>}&aQ}le zaZiUV>g0@t#ec4c;S+JcG%MtVKCqXaoD6Xgc~LwAE65iYPw0^+$Gz!Tc=L(J(-Af} zuY*SKrI%i&6AQY#yXC?t%ZL{}xH?Q;ST5v8rH)pWtzWkxTHrvB!+}ymq{MboPe}Ne z*1_mK;jb!odt5P7J)>!)^*=6496r(|326LC=5lTZnY4@^I^v-9`vqg0uc-k6dL1* zP*G8G_^FX9`WU2&CkRFo&|7K+M?(u%Qr;B5Tnofpv|`Hf<9IyBh7FtOwAXl}nf@rR zRA?|hAO43UFSv8~y6b;MJq`pua$*YJ|Ng(C31Pl{kB4bYfURt*yjYGBc?|1BHN0+( zc9Y@ioxV%*yvb1F6a6NqXvNRH_udO@*RG?m>7`AXlmwWvERQ_w#FMP`)Y?AlZ$1c@ zTyh~PxRuM7!C`MW9KP@mm(of!G*nt4Nv>p`kLwU47}3Y)>f&I2&n|rq9)J8vXl`kt z33)t&%L;4|WIK{_lLtp_w=h57r_SCSYCec1054O6wWwZRR)zKJdnqPw;0@c_J0IQ5j1;DG)2rJ*a5 zi|8a&#>Y@E6rTwcjjhsah?@fY#Np$RtZ?vD+19o;So-X9W;~Ei*jmE^kc2G|>30l1X#om1`lFL((YobW)`%?=fFl zIPI%MftTqa57P-#3W5*S;6!F}=@Msia;3p?g-AhYl+)D)wlv=F%1UG_RFNoOnlLXF zeofdcx>V$(wUr`QR-ww={DVOG719X8;a$9-s5~iyw8x=fZ@Csqrn{FEn;%>#ph9aE zHLfHo%=AyrqcWP62w*P%;29L27Q(JIH6>988#dwn*Avt`Fq&!t96D1*#$Qi|UAlBB zJhEg7x#RLwyqpQ|13Bg7#nj`#((o{kn@h1=m`cG&sY1}kh~oj3iIqtdTptNYKT3;4 z$)Lf*J4o;p-Q_QZ<)0zA>wV~tGZqT?7S1x{c??`2fEy0azu;3ewtw84j;8!{rB-?e zML~|Gutbxn;Jid#S6kr;$T%F-hzc7o^l~+dS6boquK`caQ)NS?J;A}1P3dKH^F~FZ zQgGoNEhMPG@aQP5{5pB@NzmBH$ELKjv{95tAA1}ge&jJa91!&tx&(S;rUTs zQXHkLzGqO0(p7)YcO$HORKGYmE$DThmO!>oXGr>xwO}WLP6s?)T)p!@h4&QFG$^bJ zl4n$jKqyqpV`m^&Nf62evH)TXD0pla=^K?O9YTk9vZ6zh9mz_@aL~UA7DnuCTz~xy zyeY1!iN4Vwz2z-$q2;l>gf(3EYKAc<$q3o9DPmlZpb-6wzB-v;(9CdQ{|3?6rD zuU@@I&Qao{N4)H2G4oj>xZ`y2!4@_eRNQgC>#n;{J{XCY0^^3n;;|al_~>b_cw#Sc z^($*+*iaD)h}D$yJgM@KJFddeO}cin+7367E?#^R(HrkzX=`hR?c2A)uYYqR-MiAz zz!Tntgvd6NfD??!Ff%y5WdRhxLPY6=Z|@ET`K3C$g0=JOheLX?hum`6ZPW(0FX-BSZ>4d`*uZ zGaCNE(RLgLYHfu(?z|T^ZQMi(60bTP8y$gz589v3y~3+wiC;DupP{|Ye0u(QH+Ij- zl!=`fdBwf((ABMcBOl^~Lw2}38}TX74sncdO?fNw?OL)3RQ`!cYAMUziiDpeCrQUW zj`Z=u$7BziW4CVIM$1;QELaYlQ&QZh2o#qo#d&Jkn1Z@nzmTuXRO_PeEz3(*#&o3} z-X-$d*B%JFESN_ND(D2<`Z`#?d?lSM+&yz9j87omMgA9E5X7M4zM{!-ShsGyxR=Q~ zmpgt)$pn3*JkUBpQA*@R>ZUn5zZ^~xUz2dDn?CfNxTXFI$~&T|E3*2LvrjjZ zw+H2o#x)x0lZMaMWudnIlHjmkyWAP~`!OZS%KD!8EIs$5eiWvnL4a13f zKDr-y_pKmSwwMy`H^8G*Ft&!but_29%l9Chn>yx{8G^41&M|&+kerFMY2#MduzoWc zW?mttw<;peOyf9TO~&EplvYOD zun_A3^9Oj$ z2bSMt&m-peribhq9?U3~m(oh+I31&AJn*ug%D;uh`5O7e{SHIJgN*a!IGC&BaA~@a7~Xt1N=w51B0QB*eu`;$nJDnbL8P-%#hb(_OGClxYFR@h9jxLSDySiK9l~-PYC;#{qDKy;)jVo^6c*GlNi7YKE#q=UAoaa$>3Lszz zj>vfBlux2e=^bE7He~ZL;5q~$@g+dmJ?eFJbf5h2&=9ZSQ`u2v`6`HOHB@y+E{xX+H72SNyy5u23DYTY zLD%jyxEy?DX~wB|rCGY~Qsa@fs8ht%O)GS2AtS3O80JWnV+_Sj_6DdyF+q(YM3KEu z47rwrdnZ~Y*4+HakS1kJ{!twNIHl@A)1WxQATE=pQPSe50=PPAU|=X1UrU4Y3-9_J zB*XYCo8|D%4BTD((2|F!6^b_yq9Va~#~gbsw6rzT#0LI(-ZIt zv{8IBDFuhDys2CK8_S;HV0gzor$@pUj5|B>L%LlJLTKN4c_>7bRwn{xPeXv(LzKCk zh*wS)BK}bYi5qw-L!pki<=q;N9xosG&YKf4&5_|DnB6lAjym#4^27NaJc@q#iWPAC zop(W(4qH;5(`(%uZo0WtPHx8I^zBqz#no6-;CSR_W%RlriQ@fJ>8RDX)G|bPIN1zN z)pehKr?@EHRE~1Gi6AXgqHj{rx>#^ezE!t+Tup}ky5|IZzBT7O!mE6EPW-;8x=RP##+hoH(Lajf=P8&sHf2I_di6%VZ=(b40;Bf<6$g1$3DwH3*G zIe_lfesIY{)DyvbFVLW1%l^BZ8YJy)?S$D=Pdx)GSFELtfw=n0?%DRnDlsA< zV`-R(@xX=%_7n&D2kmf5#zl>ziy9?V15_b<$SD7sP+~X=?9HT?Ex(6?e?Gh!QxB00 zm6wIt8~Ybdz%7F+d8R;TTSY|ht$W{kksxJOFSfoSq={diu*HpYQ68GFi>s-ti^YxQ zFr+K~u>!Kl^rUH4gRIeD5BDBwf~B2QvZ%skGS9VY$^a`q?%d_x5$>=Ka~_1TDRF#M zsdL>09smF!07*naR0}->2R)vH_IR|l!P85Z!uIXkN#5}sC!9E+-7^zjv+q8nKxoIg z32Hcd$r@E$Xca2)MLFOnCz-yy7$c&yB&w}8{^6BKIJCwMgNO;qZ}^J!OvultT?SSs zNQW1B6mXU@x=+t$Jdy-k_Q*SySNy}injZ5^`R5ag&$Bt9s+}wv| zBzbYVnui;=M(@cfXl`zSb?eu|i!Z$F=*npwc+f!<7xT$Uu{Xu^H)#+{-HX!HG(t>Q zNz|8_WnAD0tjL?1o9Hk<7u)4n#w2m_Jdk)n?!8eIUN`~L3B_C`Ocyv28~G1?ceJ-d z8=hD^F-GxONrlSFJd6rY?w+0@wM0%uj+wWyzZJpr0XGJYjYDT=8@%@5*OC*?Z6T~% zzX6s!_z)fBh|6}lVd5JO0T?&;&&jaXMKtnQ4m=|adm)UFPV#a(wK{%Yp%s+1;S`Pl zjg&(b<*x6VedOn*%4k_$Kht#6MoI>~4?(sDjV6i~!_78@~}; zMNC%0Op|k^pp^~(DUA_k%88z~rc$ut1s0=Rt88LKoufw#QHkzyHN zG)Aav*c<5SnGO5xzpou7g84rG{EP7X3ok)yYcn6cPDl9jTum8qEZ@j@sLb)OGB$Qh zDLGN`C1V;C%bP0T*fZ~(8jaX1_^HC(8Bl!^eeYyi)PPU};fq^jbuo!3aKOA6OJM1p;^J&FO zK9omBx})$BVH^#jMmkkjfv!1$sRnds0=5dVwTjDE z=~p4}NfoHICcL87Jf$9BMSuF~rL-zYhgZ;e?6dbiFtd9GtY5btPl7U~$O!~P9*F>lQ@P`Y z2==&QR5e*sgqd=%d+ZVE02kMsrxD(R;+XT(M2Xzq+543tUI3OiZBUVm*OMw+ag@+Y zlc16D(+C9_bdZS`>_8IM(Zl@p4)b6eU4fk?txg6E;*Z{afRY!!N+|I}D zvEdN^QiE2~5-3Pc$!BT0MWN=e^6=c^3hbeWaL2>;Fa)*+v8R9r#O+qD!wp$Mr;;#; zlGl}2v}H@?5HLycY+co2%*I7e=BAfU4Y`XFH1d;lbB;|k23JBQ9*!m?91<#8mEd4c34gW-=t)sW$G zd5gi*y}qFWV-piFYt}5-ZMQ|ZzD@2>VMN1V%LJVzhF9Ry1{|V~G)hzs2<2cXRXKCn zodKo)!Vh}%$P+xzj4!7`|Gs(iU^d>%j(cY6>tS$c2v)9K2@?~eNM@KA$5nQ`??WFR z#tMxkFVS2Ylr_PV9-eHUpcaY}h;b?|;Zf#IkIvJ9|7}W9{G|S}Q_-yqxO5@KX~)%I zWrb1qX(s0(G=R%OFf@c#bhVJAVzlj+U=+u-?wYkm6J(OYm__r+h@k7cT3>C=`aH-f zA$Y_LO<0@=1s6WHwi-y%Coi?|JTYgN7%3jEOu3c{ov$UmnSzzqxN`EYCd9PM5X+$0 zWyeocN_f*7PafC9q^&s8C!B`sm5u$%^bjg3JeIqqtsORO*kJo7xV1P5GiJ8KqD8yH zBM(0c4V4DII+f7TArdtjp**Zy)KI9=@WUPzz8`?1$T&Trq}s#_2=f4s#=r-A9KEx9 zpoum!j?2}%oVUprBN8X0<{^?3qxaBFQFKc)=HyT&@;Y11WMz%oBr2phI6lrqPWRKF^5} zuj>KE#wY1Ata*KNp|Jta^up7b`GPS#?jHB};1MNs8B|?`@S+6@lBed)rLvfVXDQoyxGy*(zJta z5gf^}C_8~fiLfO2TKSAfK?kY)d5FR%Nr!YDO?{vwtpeSqWY}tFAY_%eyTt817cc`x zH2lG+nu#+U2!;2wzyf6IB1JC5D_J3t5-Qi45J`y(CHVTh^j(FCTurD$7)#cKFC>cz zYj!zQJiaspB2Jq(Z-s#!TVZ&pg@>^S7gjQQTOLnP%3J}>8}I}s0{)OYwnFRc=(O6G zUU-4-a_H#nkd-lYP^qtjIdf;j;Lre!<7BTKuR-|uW7@5f`5uPraTq_fHO*yWg%~bp zA~$KRYKoXA9@dAEMu&%B=FD#PkrNXN712bD6VVkzk^EpBYsWB7r7}|HW?rH3WaSij zA=!|~yDeHo7bkRT1M-g)TY^XV`*5Xz^P==ZDI}q(HRFg~H9e^nWrPmi!Ks8%Q6}C$ z7u0ZOf#u+tfC|2h)szDHCw>X>({R-c2+=YlycE4eF!)E(OUXhmI_$tc*phqAfd@cy zV>7+;CO+NF#o2zvoaN0BPPd$t?sj4O;^!MoAxSn2HhntkB)haLjs zbfg9zb~nzK{m>*fA;e4j6v%DLfJ!BeXTQz@pt2 z8g(>|g7U#D^OWu}xOuOfe57t_5M-gs`=e*5i5eib~DetZ(P z^>2sSb9Ie|& zTr1t^8Okk%BR|x?I0@X@)(*3JW=1_Ajho{~P6i8ZhJcq#6U<RlHdS^g;YdcI(LjYiKco?>A>nD81M#pKXE{2_$kRw&dXw*SN1sfM=+;ATU^NjIj zToDHhM}~275*q3opl8l3XlZPs!xzc;)HZj<2>6EY3co0N|RHqE_r(r;{1tgDRMXW|_ z4=E9A0;ZD-?+8afiYxummY+fprWA6t*=fkp!+WYSKpbewASef0nS+06Y+Q#kI3DW= z<%g!HdAjcmgzH8b;z|@#NWax^h!zXJ6i3U#{>8Fl9@>I67e`x;i=VVS8O?|cam8s! zc!#3Ti(AG;T9+G-R6asQFYsORvVV?pc|A*$_9SiUn|l&4Sq~HAd>R3c9#$%70BGW+s04*iR#d?!%k$FO zm4}_t0a@LZhDpA?{?WXqt6Z%#PWI9Q)-oR6pT3hi=-*SnAh$;Ja^vA3Dzik*>F>HJ z`QkqrW~P?13i7Fcj#(*a6q#YF<)UWF9bw76+G4eyAhF4Kfg-X$yJ8kJh+f^$jnF+QGT zOBX^>8X7Pl&BH{xxIoJjHviQIR`|YALU`NIp%#2fc+Cc2ih6Q#^C8JK-#tU}Hi1Xt z;CW|gJaBkZhf(7pD5Fn?ikMeAWaZ`4Sdj3CaLe!{C%>t#NOcyIRMQW7!V@>E2NIxk z3&ET~nM){3uF+vUGR`RdGBWELnz6jgvg|8G;!suhO5Nw*lQpuy@Qn@mbt}Pya_@@eQitVq_;GqeJuFN3#tjdZM^!AoZYjTL z{sM=c=n7t`57Yyif~m?BG|*lHL;{yghdH=c!;2hDM`lg$Aa<@!U z(nmyGjisC`0@2VyOb=4SL2fz1n8+n*J7ib{N_uNG3ZCltAhnr_5G!u_TN*|a^obWL zk^|ogqHx-67KVC%i4cb`Nms$+RSmLfC3%Koi?vUBqA6WSK(qy;!(LKG{%}GoiCAyM z!iYQJr^7pxpvx&hT+W=Z6`cO};7OL@M^w2Suv5leTa-JAEGw-HuVW@j;N)AuSe^?Y zjPZD9C@tkJb2H>urK~gk(8nM@cT$jfmmLxUWxEl>5cpLkevT0lxv zClAWPBt&!aYkV;g_jN&fF@jex9I^7V{|D+1Cx%>n3M+ z@BgG!WY9H~or#E+6zv6@Wobj;qkLDnxOL zg1IxaOB)H(0#_$+bZTl+Qpshf$ts#wWLYVgfk12d#qYABBt|*$a_^c}97fR#e093A z7Ws6uh$mguI8ntEC*N~KE?{}2p=ZLEm!H&dSlA3iIj5{nzZ0lM27|J6%)Pplsoseo z-y$OSRJ6={N>*EGVEQOg4B3iY1*%pmNh)ng@DIPFEw?oPDE%C2Y4)xK%HA%Ylrre+ zaOAAym<7Qj*U}Y_P$Z#gl5{A)Dj;-3cjssR;>IXsXj-N0wOSlm1?X|`t-BX#$8!z-8PbPQ`vaP+57S4~3@ z*I?1!bDrcrQt(L1>}kkB^DBLFKy_E!1BJCjYU!k7vVH zKvR#HrXx!SOGrOj049Hi)bkq;lfZ_2DR<9~%jOwY8!>j9l_oVpS|I zOf9fRmKO|Wj-eF-C%@ALPw$*k^LZpREEo==gMKAk$|Ri=bZ!F{Wh{#u0^*QEJ68!j zRO_(__7M(MlBx=coV}`a(m48^@+PIaZ_%T>laZ`Ka({|hvP-V9kwT8{DH+sFfp{Sf zBHc-71Wu(S+W=AYYH6j2xrDu;@yIzjjgocm*|Pcucg7fzyt1dp5RW7vM|U3y+NPJ- zk={!PW{oz%tt?y_s6Ik`+%k`Ne3wHCB1vgH0%dOMLrF?>`auu!6s4gC6!VhFFte&I zk($QKXXsxg9iq1r4&SR#X81g4gH2QjdDU_{QAk@lX+=uEvkcSph33>KF`CA9Jw)M1 zcJ6-~CNr|;>Fmqw%Vk1XMG=Qe5z@)g#NSC^{vJ<_D=TJf+&b-$+7KVR1YU-+=kN_^ zYR@j$%M_YK4)G^K)r#iQEYz7yeg*JJd%2TuqbCzAtI(Ogy8k82Uqoq^lp`qdK(uQ7 z_h5Biajas*sk$6eVM1z_z z7jTM|Lh7FlFX@+JLLMrD$ zro`U|7DxI)k6b=#IAn95Y$YiG#UYPm=)#J@X^^K25X$RxSf=c0_$==-jT6(VJ({(NcgfYF8P8v~C^R)7|Be5++ zwh%S^Cg?`3T=C3RrmW)Da?~2OGIZs|;bAh8=>D-HQ>ui6X&=|PXr=|PM`rkdQhd44ZDMb4$QJ6Y|4yc8Lb)0 zCuI>VPV^JYm&!^+Um5-hkkJL`@7(g~#8Glkt<3zvX?nVnx67ZsB>$@P3Q%lBiu*Ks z4?Z0Jrm~-_8)2RBYjtRlrA?3IbhH!E* zf+~O96`ngL1Rp%ukoqZd5@r1qpJAoP^5-B`X0f8mM5t1%vZXggS1%u>iN(4{!c+a2 z?(*y;=`y9A?a{dGbM-m4GUk|lH792PJT7Ghp$M5ot3Wm0}BwD{rkZ8TiU1pV@Ylo!7^?9LGp!80f|9wY}Ejw*97cveYWw*1O! zK981s(B?1xF2mZp6{u5E>0>&JTP7^|yPiT+0rlPQ>P;Z3sF`vGr64(!toli5=_`K` zZ`ssVQg#K*o5d`oohm_fSIAXTYa!wz&S~5t^nn%be$mE6$I2uk_MGRi(6cs%{R-ggs(Fcp=Ee@j~Tqr9;5u zzXu10_^4-fm+lk^5VfM>JSXJu{NQjZiasgnVPA#b+tuxm~MPu7nL6H&ITkOZCcHmI4G+rg$v?};KLMokqT${o}|l~;?R1J2Lc*^?c4idU~muy1_of$md&tX z!$#P+VUr!p-_qOy-7~vj&YWK8nKcVKIyy*Z+uPcqy}gz4Lm9_9m?|vJM_2u+Y!-Rs z!5bN3YdBavp5pSl$jObiXx}LfM zbrn|1bT0)O6PG-u$M-x>!X(}?;D*6Gu8I3v#hao{D?mzXWmXw8Js_HT)_>w& zUJv8eULz(^D-LYcf~aPmg2mf@)7uSAKJHot4H7VpeJ zXl!aQQQru}u zS*GGAZjnLq-cE4M%@6fdsVu7ee3)E%(}H5L6W|_~Dn_o0N`IDcrb>}sY`jBn6>-BM znTCc68IuMYZoznybO$&Z5p-{CY^FwsUNwsigZe7NE7dBXha8O}`nxpB(<`~dea~e zTVeds@o{+hl-f{}vAc$A_@n%oD;>Ce{Tf zE-v@{c1lzvEH#icK}{e@$M3meV<7b=%9C0^MynWttflpU^5@EBVMHkTGh3)kZL*$; z@-t>CfAP@K@EFp666z{AL|-vFT3&Va(1`p(S)Y)`tI)`3<@JGO67|#gZ)RAyx^A|v zP$(mdA&2!kLJXJYDih{fdoz6a6M$ysjfVcVG&jTCzIo8l(gEF_9WaK6g){*x2qWKea!V|)S? zzfPEQs}^M)ubOS?>Vg?Fx(Scb(NTD2=`wiakw@XX-}@n)cG_Y%>#V(St7D|37T#{Lac4?*b zMuV>`75DK;7#SLYk)a_Ntkl8y_=E|*84h8C#1K+)g<<6`ik`04llz~oj1tcY3mYRz zAIBA?vc-brhOnpwi(`-gqhn(*Habj0CW?)+ASJ{)eEgwUvh8DpNRgIu2uFqcAl&4ihr(6XokrqjJ))-V{s#Hncbl z$~^WodU|HT@W?Ry{O8xhZ+?9RT z@k$(~Pg(*Wye3z3cx39DmsxdS`3<>w`OAuvq#F*jAo?rB49kF2ausgKuZ#&G^KF# zh>yC2uE_wgI24c+9oE#QLD`|s^d!QH5R-IAd$~CBIs*(K2L}Tbp23r0< zDK~-Rjo~Y0qFxWm3a@g);U=8N!Pe@}e|{~T{M@Hei3oeE;&-^ev`P8#e z!QMH|op8@Z4N*u>%glZ;B=nBiVL@{8PLOlq)YTp5?!0sdRt2Coa4xqz4HQ33%NhrnuU&#$?qYz_|E&z?<@sjc+jxpM#nUOHcCf{W%l4BHFTyGgOdZ++*IP{-vO0vbFlI zH%r{ zgsue^#VJBs%Z$TRE=KQRg!h zoDpNC!->TB#8mXOs7aTk0@i{w3=gyNV@gcsWoYGCr4dF(M&Z)We-S?OnM3OZx>ko$_hC1tdGFW zH{AwJP0dsWTw#a?WV+IsDzah#`Sr-@ckaCm#Nec|XyE4OYC<7cdAzi2s(5t~528-I z6a(UwHCF@HY_>m5S)FZYu_dV~x7Fm;$Lc=bTk!G$!udUibIA65HVtK*ImAAg3 zp2l2}c)HO}R&w%~s(WbP2d&~wi~{ytv;yhB)NnWh632JQP)o;6z-u{7K{0;1YC`?e z6(NxkAlzfwi)iRtDHzT2^^b#^6)}O7A0D#l*vgvV7s){`J#8gMYra*P$7zIjO(*b0 z`Np^SU=d&BY0SG#s+=6jxP!``^9`|MInOKxbDsR2r}sGD5#-Gh~xD(G1U^;&hnb)p zkB^SR$QT+4T+xGm)PG>P!R5Af<51Ty29Y=i-*T1rDXB{$M## zb)ezECC44@ZSeD7{ttZVAO9ID^>xtJ(FsFC1JF>{Kt`vIHl6A+<*<|)bVPW4w+Bv>x(IS{Lx0j9~X{fKj$nY3!+_VW+zOoWtUa=C^tXWG(nqa(!#ujMA zy(BWM!l-i|p?IvQ(NMH^w!`w5SHh>xy#%hk<|okE)kzI04C@Vt(lnJFtM|18Sff!m z)jv+2Oc`e6G-6&XK7q%XO60#Y_~m4u6*T@25u$p<4i=WT4@mEbWIaxc9@&to*%fqmyisij!9y8$VbD&`>) zZ>0}K3dho@o1)>Xik8{SnLpqYdkwfmmZm%87tH; zP*7>~DQ{3|6346T?)Nfm{;roALfcUlPLiyk@ep>YtzZfm2N~Pe!iv}z(xc)lC>C-YhpX_6n7TSTW?|O_yU zRfD7P@ULwD$NaiFI$_p~E@-UO(Qy_rUZKEDV98f&hG2)r1S<@t$FA}>QS|Dgij@Qr zk+qcg52Zs&eEorGIhr#L62n!@GT}^lr|}hM#FrZdVIvzpE(Hs#;Z>k8 zS=!}Hykj0PLlU9RKmlK&HBUb3j_hDSR1R6ZU3;sf+=xJ+l~&$R4poTaoB@_u>=k1} zgEx|fxdWENNtooK!{qoRG&VKEz`zdp<~Of|M<0I(`gYk3h6lFs5^!4^hV<6+rEn06 zvl<>5g0|KsIPK5=0?s+-6L8=G`w|w|Q^!g7{vEP1OR=MUYEyi^RdW*@f9z58Z1~j2 z;RiqZ3H;Z8{)~F%5^Id+S zC#6Wor*ImiyybLR7T%BtE0{D-5>ZxsVobTR#!OLsnXYk#pN+rSM7$0W3b?a96m#=>tPCDt$uwdbQnirv-xmW~dL!hIS z${JJjCGRRb1!b2E38moq$R}QVUhCo>Rm{AJH|Q*uqXKxDkPj+{ZB7+GJKb0LEb?9G zMRA_Au~K!BiCV~v%aY7Ym=y`abY9M)* zLN&h(AfkGXPpZJ;N~}swmdTFs>7VF^2gB)xFs)1!Pty`IE3vh8fRl&VTS0~B6`#+O z({bHTBW$kK8s;p>jixg2UIjkjPFw3J%y?|}(9jUgp$w0VkaEDI>CvEJA}y^g(9zaT zC!S)3#it2}*xb?Lyut=sesOOkWkQJ@6@YsUypvb~_aI>UxZhx4V33AQwr<@9TQ+Zo z{{9`LkZ?l3y}cb~&YS_=GrFO@wS{_gI3&{C(oFM3IH8LM1wpqLX-m8GBBG>b=x_)Y z$j@(Z`Ow|9K#9>lw$edrup1V!^riBkf{!%aP5{QzhKSM;zfsY*wY9-ZFD{2`etta+ z4-deczCPLjhz%Mi`Eu?R_G(#CZSUU#uRHh<`1Uuy4zGXXA+Wu_pUz4``qGLmcP|Hx zB4dLBG10S>Om=x#4S6;=G79_bwHN&8hyMIXlD&h8mdX{e_Yime^&hEs^z zwH-l)j_zi5>F1E4%ogF ztG7yVmyg#!B3Fn8*1MfmY@r-n7B(!Ro4i1(QsU5QGUY%t2y-VQ)ds99y-Ny-!Oa*E z{~duC_6Ds_95m@TQOm^<+80t=vf@_ga%mKk+%Wm)yrVE$;1t=^BI;0*SLB2%eQVdB z(}?IJzg{`&@$6NJZIv(NNg-v$R1}ReXE*H?R4P0cy<^7!Y}&RNmfZgcJht1^>9CO@}aKHik!>pMzp{1pnkGenuh3$2sRcNv1A*tN- zpt97V5-0Sot*Ww6OhUqo0ud=OKU93nSFC^y>o-6h9%e@?m+(ABHqJVPMDkV-&`{q9 zW7vbO)WO1C7m^W0`e9p>`Qc2|)D+zG+neFu`|g9TnLT_ww@iBKF(vqi$$@_=uzAxa zIQYN=;oDb!9bW&2LttRXfSe}GCk(4hYQw~6DwUeaihr0^c+5LZztq>!dm&6;KWvAL5-P6PcI6{aZml2)#Ig>cs! z7IkPC4Jh&q!?d?|z`{ifEe)+F+LNVhSR9OBTxQ(UG6~Nudw~}$Anr5-CNfc94-MMm z#DiW&hp9o((cVG0)3CMB2qK59Ux{0kp1e@8OLUO~HHHeIpIJL@&T!;(MNTJb zKDgXM|BH`yuR`UrM3Z!~2^;4%kaPFAk-IWa3SFYSqe3a8jqG9!EP3RBC^Z8`Ld%!n zC{Rt&dc#5ACSd%{sOu0BAH9qQ0Pp|69mDtC{{UQj&2{j=Lyy4fHS1wYhTX8&#lt~3 z|I#Gsak~9G24KrG&%+asKMmLZ@>f(D7R;Xqr=7YO-uJ#U;D7@TBxQ|C+#6jbqvDb) zmxK^w5f&K`K9vf!Zts6!3H;y(KZ09sy#uyw-VAk>254<-B_q(;(a!g3C|#(&;y!~3 zc;%I~@ceTx!Eb)^8)&$q8TQ_D4|wMpe-7_D;|$ny&)un4g)5FowlIHXO<-bD0Yas) zweXR=Xcyn{OOBBVv0Z)9@ntGBJEB2rX=#NgpLz;D^3hMiefK>8U0vPM6XT(&AUC|A z0(piDEw*jn3hy}mt?*C(^p9*j(5Rxa(DTlwrl{AkX7yUQ`M0-GZvz*1;DLm={G4|o zV-9-G)g<-!@GgjX^ZMYjFMKu_jwY_MjE0sh9uiVFA*z(06&Hr%VN+bT+d%t4T3g%T zbDy~gR;^kEx8C$SG9bf4LxQ?4@DSO;UGWoB(Av@rYuB%btA6@l@b#}>4ugY())4#c z&9}hEK6W0=o->Drlxf}uN@mRL(IXL;$ zx5LEPIPFPea>@EQW|Y=)b`fGm$lT)M6+1(AjeZ8S&BduOs^+vQ&O5(&} zU4?G2Ys1ZCFoTpY-aYY;U%VXt^*cX=v(EYe{Qckm9qhTsZoHe{^_)m)CzmV<+k=EyyEgRu&r~VmSarr;Pyan^*ewQ#@<%bg=eCT01R=vHm%ajW3%D_`q zDSZrw_mwn|VL`{UKl(9v+uPm({oDJgk%7Gwx_wUO&9wC#2`;^goAV0B6&na_FwxGT zf}J~eE_~?=pM$5LdKxxt*g{5dbYz67rUpb9fIPzn#^~q(+U0O#qGJ%$hw5dgsog z{Q$IU8JCHUvTC<~L<8Z|lUxkxT{&V=B8*VT~ z%h&xTG9qK`jH3!KQ$}Yte1#*$B*P&Hq_D+yC~x`Q;fyz0QV*~ZMn;F>-19GiTWVE`3w5s#FO3x zLqq*^tUDSzRIt=jvohihiA^vvIu1`g`3&cvN=k-L%j5ymK$_ft-x6qPX(K~OY16_c zK7wA;L-(=qNxDdj%A+l4rvyzJOg8u%gWrGugHTuBM2$15TS5m4g*u1Qs?cf2#~ybK zw6)`fcDXv2faz3xLA)H#s>JnPQfq9DIg4k0dADZ8wAf$3*g(Da{ z1x~uR!p5y-*FV>Brnlz7G?P{=we0x_fBHung#DD$7@hb|iYpvU%kxVd?!t>NgR8Ip z1MAd6-U-e=lkx_FkqRGPpG6{ zS-lz_d*X4*3->rNKD18D_7Wi~s8F}<*baSt3*ZCq|4W!VcNU#^OUt8C0ZXe_4j5K8 zNSmmZ#wr4)i@aB*eCo+3!<$Y#0oJcyC+-~16ej)fA$~Y7wqsxr?zsIfsaHJCKV#-h zc=L%Tz*HT|tICO6%8h4d;ZQ3~(PEMN?_WZ4f_zlP?u`Y{#W62*F~X`9tKiW`o}i(| z30$$p8^8ovDV*SntH|!U^Iqbe&bRPwi*mwuYHZ2q)Wf!I+sNRfeCnwHEDIv%a(@gq z0-G8taMV#pP|rzm4C+Jarr#-!qJutS$WT&nsSv?^+5em|M^-F%cC69m`u3Z7I^^cIyBDAOJ~3K~yluwQ0)9 zW?C+qUs!Y(%1Oi1S`HClUoI1Bhp4wLSP7qh{snmNd;c1~{cqoZ-nnz3v#S+`cI=>u zG(2C3QAAvLiK#B}Q(IxuV~|Lgm4z>l!FB)G>YCZr1s7d>34HH+KOl{w6W_*yA}gHm z<7%*ac;XLF!dV|a8>Z^(Xf@5)@CYA%X9hKNQV|GMTSXFn71yA2W1PoE2B5v89lB?B z!G#xG2v=VD9U9B0v46cY-Ww5RXbOygjgQ;zb0H}1+V=dRDAJ^3W5RSo1^Jb)d=viT zdq07Wu6COAN99K8$bp82Ks`_kbnAw-aOgn?z}LR^&#?DCdr}Vz5z-!{9;2hn$`O_= zTL#OPJx`|_r~;;NYU~JS9=1b6d;FV@gOeAZNUQR2p9YqvBG<}_fHPgQ#6b`~6zV}7 z3hBrDcF>^J!J;}z(S!AFKiVE+7F zVE+U5Cw`z|w26B)?8d7iErY&ux}XYZx~Y6e{;^B)%b6+-QlN6F{#VUwVS{_UDb^4* zPDw!vS>j!)pb7;MKmRYS1bXP|%)vb{Tx|1Ahzm-1mE!)3+<_CBb1H&f6(#f9yLYt^ym3H7g%hh*~HqhQ(6` z(-PRp37FN>1D9O#1-SS3_sQxH4J&u1n^ZFHnip0aJP!PvbN+wg-UH67;#wR(+Y7tw zE*%vVR75}oK~RdQ*js){e8$){*2Eaii@qd26OBFg`1Cy!OJaXXG#X>qLl=hfHBdCX*Nn z-d*8v;`?4lp7wDNd*1Bhp@qZeDxib|M% z#9`30vL{Vd(s8=danp(=8;zK=lQ;nRKnB0v8xjkcZEI^Y-5)b%e;7Gx1XR~l)55*R zaT5;Ud}*2`m)00IY}f$r&wZb!H&Kz|h_-M4zA$;}B&gf5oxHHPIF)yn1H6f0RJLy3 z2=C279>^D$S}$A5PxwuIDM#qO_14=w?IxQ=RWU2gSr0Iv@v7On72bV!F3X0=8^H`x zT`keby!-CEv@S#Z?)ZU~AmJn<*T#lAIB?u}=v7q#EzLNs=|@OB^{mHat88eeQ3_Um zOVM*ND6c8f{x`E*_I$il#yntuJN@K1*#AqOw;n+4#jhPQ<~5 zW)9X0Sdrn77uPeIn;W6AvB7;X4?Leb>>Q}@c_Bo=brDR5^Sf95$1h<=-40?VOHam> zr>y8&7!C#SssDWj7JR&rlqnlnWoqpi>zV>i4*@hZA&zy>(u{bbmrFA=H#I^-eLd9I z@1Wi$dcBa4$aD&QuuWq6BnTpDuE@}a%=XRxkv>2NM+qQ0jT?gy}ciw#m z95m@b+V`Tl^VCzg-hs5{eHfjveB~+{MPTooL;fppop22U6&5aD?>}-BOg{Kvda4Wa znl=FKF$JLQokodRF>?mmTgLS`^zb_3=;_efq8?OEO{oQU$_qov)Y?q%K8R+_}x>k#)B!0j9?t745fZ2M#&p z5Nba*es=nm9a0pxga-S1pv|mCLwno#+Z~6nWp?Gmu%PC>3f?VMaM-(+QEhqs*7uekyNjK%z%Uz+nn_n&P;lj)Gfn zy%ny!@+#!p|}k&!YV5N`5(@MXa4jTIOp86cuqg+3F|xB zU(1W7L>5ikiRaBX!k$Biz+s0^gOMXfL1nL=(B9fXuDxs4dBuQ-5uG`Cu)TH@oPXX0@ax-ef{KcA>anUPj`D^E12h>pL3bL}YqkKa0&;>ZjgM}# zvu4kRpZ&)#V9S;osO()y>qwNBl2mvUX^je`rltleD=OjcyYGPMM^1yrh6Y}Lkav8z z^HA7u%4A#ZHdy=Rml#KcruW)(Ek|qS6f1lA3?H>G>^ou~!dbnKtXyS^SQ>|VNRw9! zn4-146)G!w!a)-zLS9}WwF~W+5PPS1a66#8Do<6dSg}fS>7YFzC<7A?oIqY&4UG*n zLZJ<%%7ZeRz7Y6!?WHK76bN*yQ!Sx_cb7pnNqLHlnOC#vZmqwz83OyY z*_YDa4+vbKMP9e4a1PW;BPP)~ar{C)&hq?kOMazos(-ne0I%a*N-w{&7Wk=gj5i!^$7 zl@yo2uwi=>?(B_*Qzq)2=<`m7E)!$`_qf?I;J6KyGnO@U$RHRnpg(NgS`8HyJ!yK9 zY46*K+bo|H=EhAMiRQ>BOoL7sIItf~JZJ*E{Nii0=Yzwe*s_^OxQ?{?i#4$Pvz4&V zh~eB;vT4SMfnZYYYZkrA<2w%dIPnN>iabpNq z_Mq0N4}Pi%-&weD0n}92KxvOMcF>lQy!&419Ehi5~XNC7gIR$_rAKKcXu%sBS{OOP3jMLAed0g!6a9}z# z2Cw6^hlG#iPqjr@qN0}2ZYVBvxV6b6HPah`r!e`kPla$vzn3uyWU)8cQ}UZfoO zUS2@~3CXlW4uQMx`88Da;{6+_+;H&{KeT5+eh=8CA6$O<58&N*-h|UmKb4d-33+ZV z)Yfc)A6#$={Q3?y9C{v065kMq(#Mk8D+V7#QvazJyzlK%TA72!UL-2HOE0?;K3upM z`tZDC(XeiK&?Y3Xv45xngWN2)}jeTB`JK9Q{gvOemZP>UO)~(+_ zi{5;0x$osNw!HY<)Y3#9i#-PK?r1=JI%Mi9QMR)AbsDg;%uYL>rvJdcG-0o zF|6VGqiY|UR>LC$a%e|>b@etVD9ER&CEWi|Sy2IpAAT6`z;_N8VgDMxaouBkZ7sYz zXFiRx$+O9HWJpovau_3=*2BFe7*gJk!tFO!#-*dz&gWP>>WV2GyoOe^T$IF%+*gOU}Z zR`QK%a*xwU%peSfaOd5>hNF)@9%{C3fsUM9a;HVFkQ=YR8J>LN5g0ylZxR9=^3vW3 znG?Xe>Vh859phRE4zcgJ{Ra5%X{SORu4TxEGu5e%4TMQhz;OKp-5>F(?mMu?(<-=C zt5!jKn>VBP@P?wVmJT;7#2{tn8vz#xb^0n;Qa5M4UJ8>>zWk`g{hFL~j-M6oAB=KUo0&XDCuO1SQ# z5IZ~RsDu9f2he^Ox)*2(vq)Bj(Cicpra+E)5HlA$RMJdI=RWZcZ_FT9Bbm6GFurYAWRiSn@LTf*Iy5Q1_E(O1?5Qz7Z0 zRnMkF;MzKc7m~p01$(Vv`G@3|Q)cMGjKuWYDXK7Cw;;OZaLyP{Ts!}g^Jzh^s4yRHzx7tQ{ECa9 zwsr?CN~$pHTz9j3!gbeQ2j9Qsd@|&=XGx=_1ch!{LuuSl z-vCVwjr1Oc4|j?!tP9cvL!$KR<-=$=G6Zd73Q2?%22Fy55e>E_Zg$&k5E?P&Ro;;3 zq#za$asJ>vEw=YPXt#l|&+uWi?vaf4Ssb zGIQoE*s*OJ?Rnu5in4|9fs-A-U`_Px;HfKg4EcQ7XJoK&s*q$u+6hrckGhpBSHrST zmy;pnXUva|FXezZtkd{$M$g<(+K0?&F0{Vp zv3p7#8V{~M0f=63zZ3Y)Ssoz_F)+I5x!sUars6{A8d7^!lv$Wm!74NdLL8faawU9n z`yCQjhZ~HWZ%lcX1XNFhdz{V`XnS8Y2b`Bn3Zh4ka`>;i?uKWdeiClEo3k2jjuYix$U zzx6gLc#XuYyk@7Y{BJ)JX&29~>TNaf=9~YJ3iu8iSAlV#^WJ;pG5rh&Tv{5OLM2&#!e*9vbO9EbM z+#EA$@0m{^#J8{~dFWx&;M}v%BzHzq@)BK>>tR~d7!EFx>x6qLu!oPm`UA%9PxWv# za2w;;rPl2i$S;8P>(+6ZS_h*{Ecwv$D3~`FBdd2XDfTMynADeFehqH8{@1XzdK*P! z#donc7l-7)k8^XSYdl}Oo!oh~ZmKlMSHGLUv9New3+Cs(DSt5{vVcl!DUbto4fSxz zC6~kBUU(5IdiEq`K%*WVDT#|P;))?aaGJ4Z^9H!|`#&V(fq@8d%8raa8B1CC7dz*a z1$|i2Djz7H>Y9rOZvdU)z@7NAZlwDv{Qe3AVivwH#x905@v)F0V}_6ET5cjg;kpI2 z7rL%muRX$n*B4bui>8u@n3F0>>6AF$li-Lt@?gHtvha#PBuL$d~O$j(m)lh+o6zP zU>GqQnZ*eAx1I+-x=(jBs8H_hQ@mUVKdsyf9apMvxBT=BNaPS&OCj5;hBdQq2 z905IpC^#MopByBmii#Lt7q~I7Ub8!+J*=AwE;l{;^y6A`PTM(b_e?%8yx>Bph=LdTGL5_f#%H)bhOXMSzP|o0N4+C?qzk!1CVyt~ zt(J$phf_q=+qRKICe>NqQE;>q1xb`q6@qVcmvJydO#4r}B(pZE3^!YwFcyIx@m9xRG(*M<2oR z-k4hkQQ-d8v>Ku;9(IVYyf$)Q7^(4DlH0?M%wDJ@}F*Q&}&XCyQd ztr|IPaAhP5O79?z;C|4=1EEKcQfR`{;PQBmms1;NrmFLlQIC=yuwe0Gxb%vDhh9~^ zVEDfKz`+MigvpZ+hGD~oLhoKxZXuG5nZ}S(3UUuyd*_N5Lo(AkAe2Oi1L5Ol=N=}~ zJ_maAEQ4EqeFr@D*y9uu1gFnXnQ>Y8Vch6lR6}`ruzAxuIP0|U!nN034V9JU)INFu zms{ZNf_HsglyE@3Z;UkDj0ZnShk)_bbgbBr9$U9=fsLCs!-$c3^sDBJ>CBv1z>o3w zR|B0A#5$l6Tf25G0J`EjH&_OhdHtpX$;cauJ&x$Urs?Q_s$LZ^dCEcX@b4al^0IO~ z$IWF&^dc8m?kp|*WHIG|ysuM|Ir+KJ)Y1ZP&zwn9D!8|#wWF2i2UC@JQM3|6LGdTb*)??XC!+UQ0(Yxk<#Er)XN88-p^Y)h&%89cIr zK2Na^`A+$Zf}meoIj3|f2l?jSsS|hO{~Uw9n`A5$ku>8&_k;4&L6s|1X z6G@N4icG)Xs8KLx%xHLf#!SdBEnr5b7yXn8^O^5mm7swu#zpT|_~3*2Fl**4xb1d; zp5^5*Wa#d&-^h`0&_Uy2-1u>@`|g9?!By6kTiw z@G8{SY=yR#4k)IuBitLM^q2wq848o5D{@WERygHbC&SIR+yMOt^n>j?>Y%6)-KYK3 znq9;VlwZWhflL8FpWeNpPoG|NuoJsKd$y8!7n)YVPR5q4)v$KmddWxU+wrempj5E5 zu~O;vgI;Gsn4a(W-g9GpBdq;$Jw>f$mSag&gRSX!#Mcg`CB>wysRyt5(%z0 zlqvAggMSe3EiNmTZB*VEsTc!_ju?qi2Ye^2Zu<_HHFFM>mf^k&p6((ZRXpVQ+#g?Y z1!6}%1&u^pRk7`JdFtxzcV^IDC^9bM2!ZW8^WAr$v7sIciwdb;%p%D9 zUe<6FR9IXDhaG+>@di$P*-cXpo63;Vmk#b}T2{{PmZX<* zmH5sx#1Kk?Sy;voKpWMBe843@_Bmh@_BlZXeI)&M$_OPx&UD+=x?te)=seKLaUg z{FslaZc@LVl@(A~S;3(?TnEP`rZ4Qhqq`@%yRKZh(mlfZ@Zu~TmYxX810h?7ZI=WY zM#Ut=xK>}R`4UP>ddT{M(wq54WlKjZef##MBZ%2ZbH;S&ldL6-lG7w{N{+mk&@d=D zNjIUQ&4V4aJ7CV7_sMu5e!TxF4^}K+37>zyf;ufY`ONgD^BSolc=}<#egk3jn9)#! zA?0y+K${pbW}0j!6`JH16w( z?YWmbyMtsQ>c}yJD=AdQRq^Aq6kf^#F6Wd6B^}SDB|f*nrH6(n$k*xO5G}1AwU@b{ z3Qmrl@MSy+!O-uY30|Rv8FO)Ja(s0?!(-z~O9sZ$%vHKidbN_k4Xq_#6cjvb;K`@{ z2uB@tBAk2nMey3IuhQB8?#k}fyBGBASq8<$xSO2klhI=17akUco1}V_6+&fIPuj%R zr*{=iV|}vdQ+WNgw`lrC?9_mG!~g`S7dju7^VpI~q*#C=6dV-BN|d$c@ys;Za8Yd&1XJxu|79pxUqbStXl}3d7W^> z^*6$Y^XJo41chKXG|mbUnXP~!;AS~I-<<_c485B*V}3=tVz9`zmSzg|f#h+%ypDKE(vNPH z76S&NV&4z8Z?BcTKu5{9s}C} zFly9D*kwQ;*k{-<3KUB8cAG4fH-O@reevZN@X3OYxx+^;x_Pj5Yb`8Xu!u$-90glF zw{+cujS0GKA9na*(4z;gy|66Wx@yaWnn(;wq(ePTcS`M~C+v0x0UF%~r!P66Wcbgg za;fP1Q~ z^|xaXGcCnNC0PkuunK1V#tm@R85hDu7ybxVtyxQF8dvr1OA1Pd_^gO|KQw_drns7- zQYOXT#>yR$z$pPdosEaVDh#%#qsU}jB!X)H@NK83sQx(_yQ+C-Z@xm_eoyz96a0iyrW zJ*|dZU=n5`k&2lmp-p%5BNKmD9scKKY9nE%WOoF0XAqB~9u z4PU3=NI43-pr;;=eBXQTeG1G;q1wrKv659KOmc<`+89}(pa6yr8R`qi=flGjns8Kx-h~}7|AYCkwR)>t6T^U#|M>emG?LV6GQP_HX!HOkPMko` zh7K7FBlq2x)@@u^9OVTWJ+wBr!CP<5k|{|xK#LYHf-k>Z=cb$eN92H_KDR?bQ9c}X z%n>vqvKxGzEGk{S^$=QE@$^Q+YG0|AK*V$1(U+0eqqec*1SLyet(fO&V??@9??lM10~wr=2xtCWqv+I->q$x~3~v$V#ayi! zB$jU*MLneumMs1hjymEbc;)q1q2Is(wD_&jaS^b`r9BjSM~$fwNLQXg3@@FFu{3%T z82!dQNaOty11`jC&^^qzq_7zN{Ote2ndh7h9qlbpS69bpqf32pt{MaTaR52IuL2c@ z0#T}~f}@C{v|!!|W##2iSy>5hzWF8`eas2);!7`6mDSZ3K|2-nFKQf(>`Q6o#692Z zlaG#0a0j^Dw|ii84mvo81YIp#TVa=7c7-ROc@7?b;*V4xj8}$JO=JuuRCp332{ktr zyKrJpch4bv(4j&&MMjPt(pcnE&%#0-1`H_p*^1BMz4zZI+VBWbjaNn~@~w>O(}>uH zAorMm83nsYj#H_~6BxwtmDk>&(D392?IKaL0iiY)dSl?f@}3nia>PEAA=8)(>YyN) zIkd;3w4@ZKOgb2fOUh`sIgXw%@7Vns4aB;Q>tL>){D+VT8!;sbUER-AD}S5RCGGiSd`v_<2GIM19t8=6}%h$ByR zG4JcT6MMroH8#LrL-&Ny`;8>t;9c&1<{<;Lopp^zXv2z|rA2Qug!!n_cfVaeK{5yF z>M~schdQ(S;9^*_g<%5{$4BW3s4}J}n`UX~x$?PHlB)1TnNq_^+#*%3*@2&HDptn6 zL0o77$xAmFk9>+lJ1JfL)OZK^FI1JtI)#g+fHe14D7QwUc}6gAe>SJo4!8Xo{h! zp&sgYun`fR;SQV9sV3dzMi2FTaQV3NHl$^^m)QordiAEMtM8t69z6ftOAa40QZ7Gw z!_g1H8Uv!C*^y34ON@hiu0|s;Foyop6UBepRuyGsaM#`U(dl@!9wLTAr&Vmnq3fO? z(-vX(J@%jta~QpsHw)T4*x(@!=vi02wHjv3m_;$Q^kh1#M3g*47SqJa^O?=A{NsPK zJ`6`zI+ZwM)_bsc(WlU}qTG3?k@BMqRF-)3gtQs7+itMm=>2H#1iGN}R4f|~3|Fpx z2D=a514fJ(PU||z`&_OW-O}_g@P3ckJavWZXdiv_5q!CJ15b;&k(lpXV3?5IcN+vF zBoZ-pjE*?sa40S*f*guL={pzN<`{r-(c)zkfE1_3&>epEtal+Vw?GIbJgaR)i|u%J zM?D-i^-yvSK{sx{X*JxZmZ2x40bG;mAJKWPjZ*AFz-!W3rnjO7PvXc}R}sj2`oxw= zVy^8cc_!hMa2S*UeIuD8860+pbNoriY5ZREw9J;g{bQLDu^~uZ4mR3V<%l$ z2~&JV!&_s>nLD7+7Sf|esM)p+F1!3EuwvyZI>r=3h&aONu2IV@I2C}QLFyZzcKdeN zQQrVZ%C7bY%qn_BEIx_>u)*oRC>>Q?llyK>@gVX>g%X1%|lt1-^4uf zptQUc=FE8y-ulNoG+n9WRQmAmB>7RniSg3T5j#9EbOL&wV((vrTq59Un2$XCdm1ev zc%x~JmN*(v$oK*{@W62}U|>J$fZ!e_Hqh)HmLtarL?SzR2~AXiF~Vc&|c_< zuw|vZ#%0?^QbHJFs7yr+z>URcjq7mOJmfFJSw>$8u7n6&4jK>ajpspUZZ5q1>g(|O zYk!AbciEMCi=2sK$9d?48Zrt-s4XnWgToG+22&523d8muM#6{ZAfwk(LtP{6*s%jP zZrlu8Yqr9c&0C+f|hlp16lSv+tdE zHk@_#88Ca+Y_E`5`O!@LvYj0*FsrYDF;+UM*=z*SZt5u2iHeadE-P%>Sup`t*0ZS62(_&%`z{-a^u z2k-L~Ag6SH32!uDZEa9h(F>NZSPhRq`6oF1@I%Sf8AH^dQO(W85dycHhe%L`7U|+A z51i9O8-=t%-hK9&=gISKmt61?6nhYvsO5V-5k|Kf#pTKf^zh0|EHV9)ehvUDjdU;a6imsP-ww`a+|3*OMj zb@%J7czo@YDF@Tk7X|FZ!@f$2Ve%o9V9Ao-yC@1Ok3?@`mRy+e?i@Jx{Ig)m(obRQ zR(23@dc^TDzL`sgY4D&yFlOx7ppB^px-Kj{!NyJWr8b1Nhie?ppYjRfx|y`1-?D<@ zn+3Y7w;hT}4@KTI4I7WNd^HEPR*8v>u@ORZa!H*gVCLF2YoZUcq{(Jc)u51fge=vj z&?NZP_1D3E`|}BU4u8Q{aUf=rGI5dblO>B`>ZBu~xP*-dF(@i*O(%&_UKIy|6q?c_ zdC}5W>4Vc%Xl$oUoeWc^PJz1mdiZ=P&c}ZMbLV{kpDbDgU#wXNJGO75GST-PVxa`XIHiKh zG7gAGB{=eTLR(8K^zYvf9(nXh7&Uq{{P5BXC?ix{X-0$dGE7IKARhIg;x8#Fg~^j9 zlNTO_c}L@nP6cW-Fn{jU@bn+LwZ8tw8}QiUPs4fVok8_xMZ-N{G$IiO!7o)x^u#GL zPKV#T&fvYBu-)GJ#|-%OZFfOgc@;mG$N_|s6)G{lI6~Na?|tCNBc{uS#*k;3tRmYI z01+3m_u6wP_4Ip`mXfC)=gY!IhB+@6>T0*c;!l>sUVH5gOP78QCB;RA58Ij!nhwkD zz>^Dct*SpvJZPdDJz<@2?c~TK4u?k`dW>aB_(3Q@mngFfK3M>5?VT`h-iMSwc3dbQ zsxGz%PZ?r7t>&g$ICRQ1=%t=>;+n5CwxGXNw&~;Ai0jIoB9RM~ku0)GU}$R7I`xqd z=1Fl$=UWd+X?%NzY5jt^fdui)4zUbU1A9Tv1Wk}omMXrkh-knyjxA`S-F+r&}PmMxp8$NR)nPr%r*`$J7l zH7jal3`vjmS4E18+`Kuk6YjqA9(eQ3x9LPgisI^uQ|7WC#Sg0}>XzDo(@vUlFibdb z95mL|KtUeHZ^9`|zg9y%ck-{b7aj=a7o z2}eRq6)2pr+9=R8Q|_j%blB*ZV7NYFP|Um5K;dI#P847~w|vL88d7?=$&UTkb?)BB zTS5<$T?Y&?|QNbY|Dhy~$u=k4#m_zp59lm|?iE#IwH^a;sufy|yc?Q09^0%P_ z4~U|Z@L2fVh``{aW#XLl+z&pabsmg8#7$^A0xms=QTGPK&wmI1q>b|PieSTr^>E}7 zN5YLaUJr*)JBSXa>eai7;w*8TFv{6~~8Q4!7NQ2Yj|{IW1=EI#>J} z{!x0-Eq06}KpJ2tVEC}T2^W9@I#rUU=a2_=%EEMRD71fN6|7kO1zi1$YvIHBACn=( z@{tFWuk_Y%(G#XmKb!(Bl9Hwcc3sS78n7cr9=tpIJ$UuC z*J;C_$3xd(Fluru9p!xJq0<;Iip#}k!6WqQ)eFXs8%z5#crPY`8CWXfo+T70 zpbVcCln?Nq_S(gTRJ|Z-PE%t&2`wsbRB}AJ z5rv_QX=xo+BNJqiO%;)DMq?v}f`f^Kp=kz2gExBj5gvQ=cX0m$ z_d{8EDUF^etun1`R~da^tRmb|PXPgK8kdx7K+_h4tDMH?ymh>iV+F_Wtl#hj9CzHY zaPPf$!d`psLA~j-&ioFXcIqk6+|oo-S%{m~o#-Hn2~j{L+P7~%c=grS;eUSj2sAbF zz5(jB3(XYVLNrY!Vjg~)$gWR(o5KC@(LE&zG-&A6)b!`0I1e zL+}0rsLo2qn6CIi6^6>VATJlb_04acP;~iuL38RBWjDV6>x-JsjHF zTlgIfjB5A>cc4G<c^y#pB-kjS7|u(+uAl>%{fRs+KNgrD0{N+SO1@06;p zl7U~!04tmd)*5^3VH!$?;9m-nL)o+}XF!bR%_Iq@#X0*88#hRhAMX6 zt%}|z2z0iC3!11q&2_{fy-@L3K|#P>=V(Me`e*@kv|y|rF3X0*)(v}%n>JX~RuM4& zssWLnOKvXApFbb|^z@&gp|RPYq0JeJym%aun3z2sLEFN|(V|lL&cA&VzJJLDG&hga za%?z!!CEfT4X3xze_o@ZQVpzNNi|S8s&NJlXRe{QRk_LT>$>_{xbVXB;kOUmOXqR# z*uI0`@9czMUH=O>;kcurc3TZ+PkUV?4^hOfqtMYoVK;D5|Ig3-l}DJOpc#(@;u@aQ zQ8uZF!-{mJx6GOqdbd@SRlsMiX`F5J; zCnp6IW-=P>d}fH?rPEUWqwdC-JD=QFTvPxrzW6enc*4o>>YJ}a-~I!jojmDG2gH1w zJV7TN@HJxJVQ}g9FXr`yeBK}8NAw|Ben!AJU(*hq3JrA_Wf!M_G&;1LCP}}U7PuzD z;aQZkGd%(t)nP&3K=9!<^*32Iz~h0 zFgHgXc?6X~ds671Xp|&%C;UT~W@M=4``)}743P=KAt673K(|`nGq;s@vO$t=wP5AX za5DkrF5YzhP6l#vFNWTNPVora>NTPa55y7udi@6F|%u){-Y&itqX$V zqjWQfc_AaTG^4`P^DFd;;2;cvnRImKP#{FgS8`=V820@2S`reVVB!gc5B&CFC@R4y zo~#JeINEt>Psi-uZnh1yOx%0%pVwRm$DMczoOSLwaMSfS(ebg`BV(TA=_|L(9F?t{ z%E#*razGRSOh5cEnoq}GBkc=F=~pR#s9S4>3X)fdK5p6q--|-4V_d6(BG|lnBOG_+ zQE<)Ae+qs3^nr%PMlw)1HHeBAgZTZ&&##0LBZfgubqyb`MR_Qf@CQeMsF+Jj%b>Zr z0q(y0H}Js+A91u+*;%ZcHyH<^t3%w6WOdC475TrN@@+Wfly5_A4bJ8Bv8{T}g?1in zTVf{#r?i;-T(TZlh;3Rac(fFE3R2~<>;yOAXu2mZElNtlWLAUe?+OF0~Q z)O6}p=^h+jhm<`!veDCeM*1~8PoJF54hk5GM?91Fqx7_`eDAjFuCVWjeW0PCUe+$O zLuX{h&QdUo3k?_#^p@+_ryoq5G{KLc#K7DATh!KRJ$T_)Cv%Yjb0ZYVJ2L~XLzA?U z-qZ2}G!pVl!cyN2X<_Q;Z_*d-^GF3jRv}IJ(?E4Om8CMd6Ys0wxu42_Q8J&cY%V0_ z&G%T4Y$mo&X}B0-$-Hg&9yb*-7S8)ivM4`EObV41$D*an$U{XvI#7|}S_pn)53^Nb zO<4m%3a6t3uKd|G@Y%A@ptPjO^?dAtyef+DT2P4UNz5yXpTjHUz{bs+;5+|zCft78 z-L&Z4xBqT%$6a^9jla5?7DLIKOoR>%h3)0??qDttWnBe+M_oNnCj^}f#z;R%XWTW6 z3Z<|>;ug^&y9j|xAI`zMQKg{)rlYbYKU`!+z}_vzND`%p-cIAj><<@Qa2}MD7SP%7 zbbbo;tfetUnW0-WPH*+^Hvs0%{}}%3-uqz7=FN1PBK7#C*RPulGr^1`bMt6a)~m7t zesJ*xFn;_PsIJ~Zp3FQhq4U?xF49zW#!ZRG3&4$=<)1W4bF|{17 z*U)-LGmP193=AH;n^Oe%jCoy0jnR~yUaJf`J~c)Qr?jb!6%QU*rD>%Mu*xwDB<7c3 zD6(}n9hf@0sJg@eYPDqXTCeH32zna0XQq6cTCd&XB*i9)!bafRluB?+!h+Lyj|vSv zLieTNXdp}t*cH|JO%)6Ti$7i?vlis#LGQkOq{UU?Fmv&Lx$XoK)D@q74v#(d1e|-$ znZ(!>w@UKo&Myl91@pscEty}x`L?^@u|GUUAs93UkV8f&=;~=Gn%c`3)SXtpx_}Hi#ky>wVHa(Y_)KbD>j3P8c0Ohi!_6m`5qR zw}{U^}e6Ivqk+NIyfC2sBiKqSqBS!8ES6%gE*%jVS z-`Hv4=;}O`=df{N!3)hee~!~W;}0AMS6+EJ{P41$P_G#GA|Ov-dAjzb?Zi_xs9?B_ zF~m8Z^7qN2#WclOa@!p+Xz=bZeE2ZfWA{CvPoLfta-*@S5jLz}Px~d7En5MbHf^RU z+tME86s(cY0Pi5jjLr@pby|^DUc}${cgK!;m^5KL+<5(Uw0^|m1I)o?hCC128t)bxbEEdvFQrzHaS))Z8-0cMNt_3hMwXs4d-zQgy? zr`$7QwlO^>7CiFo0Dxa!cQcgtD20>%?c0#oswbX#vCwyMis6g3>)@By-3X6A@;LM; zFL#Y6tmy^I5)dDg0`#}sBdR+a42_e8ZosFUau$5NU;$KBRf+QC?oUTfD^ykWgIE9l z2E0G*133Gv)8TvHI}7&QbEs2tAz%7l=AHN44}bh$?%m?F5Grz?R0U7z)d}Md91G>; zJ;X3cIPZA8Lds6*6jqS)_R#~V=V}-P(bDM^tRot39F6?=$5+6jg^TH&l|I-Jpg3e~ zJjkNU)C7B%6+n+3CGeYj{~Jb(904aBe+-Rc$hjEF<|5^WhzUpVJ|k4rG=0?yC!hQ+ zSh;EqTzB0~6v-7AiuqJV8BviDmO7grDdLX`th`4Vbe5LU=x6n+)v)Z-WzgB~PtoJu z_IWh=C@v|X@F;i>r%*|;vM>?iIXPI4C~W%1(y(*GdyHypx5GX|hQK{{-UWU7^`;Gk zXbAaz42jOh)92~M)R97rF)Di;86JJiQSgs9-WFE2+@W=qwU4NypdE+_2abn+{ix=slSt$Z>cmny z9DGloN$bm~jNX^k64ke=lhnXU4h}C*4+cw%Orw!vd<2(7qmb}C$>799%iLiefioxu z5;Haxq{ph`+!t5M5-^5jgyVetw=TfxTq`fO`9}4?jl*jSqBsMH)5~v3=TTtnk;zcR z@N9~S6DC4=c@_1I&Tdbfr!z=-cNm9JzRA0kKmcVyg(z611B6nCj=^sU_in} zOP0ZNe|ri3^z@%$^@J54opGAE!FbKmYqMf9^aw zbAluO`gY3c#GZ94l$G{?y2d8B>z@1I;YS{W1ICSkBc>k?WA+~f0|xY`0D?HB@x`jO z@X^N$;Elh(MTbP?6%;~25xSSkX0t#70CEfRDe~#S{sUpsl!Ivc0$p13@tkm~S30jD z5XC54%OKiPAz-zv@Z$%g$By1_1e|;R+3?xb%V|NoM`;h~$!cU?;jvsCtu)iL(U)u1 zz}RI^o~1xD0By)xzy}{RaB< z=|^cg(*8SyxMX%v^dD{59oKw>;-S9t+UJ7lWdLp*#LQab&`ks+>8O+070Z(DLSUKl?IZ1N>Q9{*;fc_2=#-X0#L$ec0~)&` zJ*0~XK~_16dBK!pjR_k~()|?)7D?~L*2o%^_&tY6GypK@n8g0lT?a!t!^>Hy zqZ_SsGg>ev6&&5%B7G9G=>qJ~8Oz||_mJHO!{n)x;mtSRqZy@g++7;c=2{UHQ zfp^}X1$p_oP*_wR!JK)?R*-}l`IhaY(eO}WvDmeL_&e0=RFd$+fMM*#X<7n>FTJ$By(_S=6H zeDMB!=vmp5*7o?BDpv0O+j`<-p zSZ@g*=`0%+gX^ZgZrI*vq>77mZByGcF3%edt)p9~Q6p}g3AD}V$}OG;+A$rBh{g~r z|FnDd8G?Ntr`I&DZgSu4ug|8O719t$2gx&jEv`H84z%dpMq0K=zs4(z=r;9E+k9z3jA!6JFNqDGUI+u=$8`ms4pcKP+x3uSm09pB-@io(&1gt#MW7UbuW%W+ljK2TO(3HkZBfX}qV z-XMAfVWB*Xoc-QkkaeBxvETFmm-hKMOx#yh?`VlvF_H%H4M#M0B^V zxgzk6&+!|lKqnq}0Q9QrMMpx10-xDVOfz&0X@|Umd zn6{hmQJNPCcCJ@TZ)Tz&;HD%=0!^1quV>U#tt8gVDp04u<>MO7d=!)^L+NEPQ>Dd^ zgfX4qW`=x^4VU&V?Z0H;`}mx^!%?tkp43#D>W7VjiVVFh@DmX$;B@m_^Ki;k7DL6A zP~os?hr+i{J{hXFY^HS(->53U8kWHC&{i)c^e;z6QBqP2rKLr5J~$5HX{WPHG0?7S z3=dLPMvLaC{8TV>F<2Mtnbf{M>>e4`m!gyAbi!Ukhrr{HJ^~~5-3w~AR^t{cX%DSB z=j-kXe^3~27j9liBZd)Ud(jyOdg35C6L4>s!~M6@c?pPa?e?v3!?nL8rOkNB=#h4` z3;itKgohnf8D=GP&3#p%%B#|>j5DtpV7+kq1n11hj2sDPop}Z=+BY>|?^-vEX?aRV zR$h48U{g~)?LL3|?RROxTOA2lzElxpDk(cZ&z%sSj{Mnw`~-gY@cmF!m=85uHD)egG$v>h2$ytp$whu*WG zxLEE``r`ZOvO8+j2y#8Q#)h-Eik$fs%fTR>7!_jwG5bm9!1BE6L#bUmp&&_8j<(>)pND#!*zl`h{y#Vb<}ojA2p0L?AU(5qJ^Jn`u7 zX^{}8TIk#XH^TA@^;D{v`U{nZuM@F-2hbr!&ph{MIOf=+C|WMM){?@~-mS|Y4YM`m zOe;2w##dc7L%H(kzX}D`r;z5|H>_U^H~ivSIOB}(kOzdP`FyDOV0j^+pMN~E0mR#!fm(S0#7~tD6MIsn=l#{jVz#w zF6h+J;u97Y@`wNUyA;W{g%|em$k<(X9SBVgxaiH(h1?{Zk6w4;`Wv9v8+wbC!l8#A zLii)ic=10|A=8`Gh8kX+Mb@#d$-({J^}`Sic<(7(12@Fr#oirtM4# z8D-L4mxk%2vCDY(x~|P?*~}~4q0t=J=yn&<(o%hrQA{v247PspbNkB~52qMZzzlfn z7Ci|0LT<@TXEXSBjACF!G?}M&7lws%bH>9Qd8vv4W9O(^5te1Y^#ok#xf+j%SS%=V zEr0Qz&fg;A;$r!bA%o%ZCm(~o_Z|jYw`?L$6k0^3DR#RlNY`I{C=>jRLu4`{q6BpM z3yo1lc{x1rKlj0uDHEZfFpuH^(TRG}Q|BW;eZavEs=qNDrZ;Ho#pfe*!oa=*;K`>S zgI`?xpHNU#OrsE_2`MZ+lfp5-=^YWhG**vz1{p=A<>ROXcgT~QDn{UKZie68e?MID zlOIw@cXXT8UY%1;X+XljWwCpY?9I^WF?y9lb!eTFW>(@a`Qvy?n!{3=tv925_xCAN=tybhjp z5FJ5~n=7L|BXj)C-2@zQ<9mDTu{#`qF{_Age1}0n+g)W>aX)n0R46GcWBD?1tC+uS z&z~BMeq$UitRF`mkQ(ibR>z!3e4^2ZoBr05Fa6& z9mPdoT!hCn4RHDk7q7971?aI9^MPv%p_?;;9W-5r`wm`z?FBgXv{Q-6YihRA202t( zY_xdV!e?ftKU_OX8M1R2-^F1&dYNtCRt=L6o&vAG@*;Z(HUO0WV_prU-d*`1E6;a-oM z{h&j`soyyn-gx~*xb3!^Vc>4NLQVBH*uHHW87*8y$LUQw1*ZB>D(Zm@CF8Ej5|uEX z=(lOpMv4ag|Gseoy!^`F;O={GhduWiLizHZ1|O)?<1Bf)Yi%g}7Fs*@u;W9^gB)%K z&(D}TbuwUlb*vBW7RPYvI5mX^9!(^osiSf1{21Or!!7)1f%thb%X;m@iAuf z{;>C+L+A$14&aCmM(FicPZkMMBhjeLpgS_e;>=xOV`^&cA`AYun~be zJ$Rw@P&`s_QpJM=r`@wHEiiCEKX~ZD`{A6k&V<|Vx(8;?m6$SMH$sX z@LlZH;PAVpwT;e_K;wW+`=cLR3P&7sIK8L6tAPUt(20T=Q50PqsfR6_y%1088Migl zk+OQ`P=LB?dw&;IE#iT7*?<30@bE+T!?I65hbNx=6TI~DOR!@3N}7|#VLlmV+`A!0 zgsRfPjs!GyPd!TfG||p$^c2J3b?CA3qaS`B4w*KI6tYg!C=D%>dVw@OH2|pIUJose z+n}WpJW})RAji}@6t;zhBMAQ z9o~H7EqLac=V1PaAHv$T>!|(FNYf}c4@Y)BHX3z^ZpqpgE@Y1{#0p{TF`Hf~%;)1&0t zO{u(WV%Zpppr|kpCLhe}9ZECC3uVa~5rZH_n&^PCvT_(ZZVW8=_zzG}fFWiiMpd9V zWy%klVf+CH!ES?gB^;DTF<+}-nbzUd5Z+S*itU0Yf#N|^Xedx#@jkBudqv;Yx}8qy zRIe;c>z#!_*=Nbe%3IR2r296%oDSKQVv)_TKJwR2__)+66Hz%9W&4QJi2;$3j^-Or zD8)TQ1sg6LnR~;=jqu8=Z$N2rF?orgdniv^um=nYK~X+$^2^PIVSDdIi)VapgWntC zr|p!@O+!S4j_IXyuh{UoF%AL4H_V+gAD(^gd6@mdd$4@ja;V+DjSc})z#bunr|4Bx zK`y%o9(W)ebM(=0==8}@TGE41LBZE(p{v)dfdvZ|IVQyV6Xw_p6;BpA@F+hICLKJH zdR0^{6+)${m91zFUX>p9fa@CSVcz@mVaB_&Vd26h@Wq#FVB`7?u&uUMPHn@`5Ii4@ zfNL5!%{E|{fiQT`U|OR&@uU-A-+lL%wIBu!Z9*=gsGuAl8E&9hR&1Ejpw4=KE-YHO zgbu(WMJHZ!lt;0Io>ye_vb=G zeIt~XvaypW9ZXEpg1pAV9%6XtQwtg2;lqZpVU(Cs^osJ9yVhD7L63L|+uJKGeulhI zU0p*#GH1=44WBGp3L7`Brx65h_{4oP9OW3-g_u9e%FCcnpFXh5F1u2jj2tzRc1#Z+ zu{Y6G&rre6j{@@n8>LX1GeKn{t@9r|l=V1nXLdhFoaekh7us;Y2hI@48jg1c(YEV= z;^Gn*HF^}CI;ru+JZ&wWYM*Qx9>H&pV$HkD--rnBniIbdA6;7sd_w>wWJm|T(pej3}henB$ zWR6Z^{H(%5&^dD^saSW%)FwyChFL*yhzx`+I)0|cj~H6gC_YI9=3_ovNkG=FTL)jP zUIQC9Z6*OHMO#?`ef#!@U3MD)y(%hbe*_L~Q5kW_hS0ML%Z^Q0GLE;HfvdP~J4kN5Ombh*zJitr0D#F1Sk@ zPx|B7WH?g5o$lBkc(P>!MksFQJw;{ZJ;|NCqOuZ-3vl`t4FdMq@tWx!j*vX4d|5hq zU|FLpV;Jny03z9t+8ezPK386qUzFDIuP2{JBSL}kmV1WRi1g}xXr{Ed-IVVoy^H3H z8EJmLlWFl`sp9&?^y2p9^ge$@-C@jA+k%uYBa`+<^ZcJ04+NFf3_$wo$Ri`6G>B8~ z_I=6U7i6SVzJlcDN07e~!ZdOWPHAfyuA%%pG}K4eQOiMw24TL~!=S&RfwK9E2C@uH zcu2m=2nx11w+QY$a~NoP3)9-DxskNmgJ~I8tSfU08v}0;Sjn*?06wFUQmm8= z0oizPy{Jx7O}!T{j=Fa&P30elnh^eS#zX3F=|Hb?S(uGFFeLJ$2nIii_(bsZo;AWz zY)KdmXFN1VFAsW4`H;~P{&qZtcX#i7j|qosgx<-+6m??jO-~&3A!mmcc_1Wp}lqz6%Pfii?1`w9p4lTMNfq98r%eu zc-uk}4+Q1otdH&G2N}9HH}_%$-0i3!z3=%Zqp^Hiv9uWqO`Z!*)L5BaPWKFloLvzF zK^r>8BQzX*hY4nIj+02uZ2cV*kW0G9i9M{67)VAfGQEaEk*ASONkO0@a@mt2BIb&M zJ8I*4VO55a`PekW5s|_%FnORP(^F$ixzQed#On!g-ab<1I5$n5b1xtP9vLXlkZ1r`NqOZp>y zen)mYiZbtYQ#UDY+|HS85a?LV${7y#Cj(;LoDJf(SF$Dn)(4mQodr#W490gYuQ$xY z1jt4>Wk_S$(g+$+`It5~L{U|sjgV50xc+)O>P0AU&r^2wYKV9&1?N!= z1PtTqL04{}lJ9F--0NXJ4mgzS6e&?W?|?0aBqKtHb#eVBLwj0?l;?r*Ha&d)W_-QS zYhEUAqZk6Pc%-mVCQq6klv^7~05LX7OA2w3(zKch*+2Z}rY@M)+RIl6gwgdn4Nzkl z8em?!sW=PIc&-c^h^rvyTi`F(Ial1g0q}WfJIJ@Z;f$-M4m_w5kzxo4%?6BaX;Ct* zmyN_s7SBr#TwC$IK=vKt=G(j)=!}GVhajT_TaHWSWHBSB#5}s6u5Mf~U7v!kNzmq}~}! z7`1>?@FEVpiKmUrB1+F5dsw1F}$uh&9&ozY4L zRB!QH>7XOJ$ao|t^@h}eaR!p|vXvHt(!|P`dzRFBwv|iK^t1@6)V-Oh9YV> zWk$~nq4Eou!Mzl5RSf1-4oLx7vPnE@h zWn>%{&@8UEd4ktnm7OBk!7~GtOmQ+*rkhlr>Hfs+M7)%YP@*EI8|FFzANxp?hRLkq zz%*Ux2<@{)btI4%(`(T+IGW+N#!E7E?P3E#CUh&Y7?HHbP9a_roe~X443b}0X@loc zxsEbvy4VpC_uRD0o@OaD&FTaNY6Ay>=;U6=*#W(hjDuy`jGnD|9`{oC=GS8=0*g`- z&T><6vMlCkWioN;66&Rpq%^ao*S1N6B)Y|T#0JMcQ?N=VO|N&Wtkjp~Tlq(Eveiv| zHG3y1e^o=k!yy%9f)vvC}gjVH6Pl`B*D%JYZ5 z<0|8R1{{;p9^C`X%)BdQI$dN76A0Q;D&^Y4t(6&&&YW+Z?D#rb`bNY^cwI2NLB@eW z+z%V0G(p{WZtRvR$Z>+i%dZBQLD1^SU~zJd6V)rt+T**if{mXeq}4YKtvG#vV^B`_ zgp}}1DlZu=_bjPS8Q^3wV&rUj3nb!{1hy?>p48E4TG5Gx$PNAKMm@WdC4J1oYUo1W zj!3R90c+BIe}|HE(X>gtm&qR?r12qwzJ^KgIw>2z6_1WHLFFgFC8-^vc6DIx*~geX zZihtqvq=I%n<9;V)R_c}BVKB{?(p(gf`}dtA2kY!gu^Kf5#bqmuD{~h0?RW2ujoCw z_P&>~rF29TL>-k3$UCm+xX~37>O${DoEP8A#^3=Y;1=Mk*GYBg0=RY&BkBU|&gPY+ zZix;4ReLWP%qBcy+vzK0OR%$bj_B8=a*d#?;+&$>Y?FFu)O!r`GRgTmLd)@w@_2XJ zLCU7G()2xw*^mOB~Mq!}ph zVB+7yd@|(4xO8Vi_v*%Yq%m2f*W}XkmTyZBim9{1kyNj3B#ai+BnT2fhqvzdeqbxvmGK!V%CD1M7o+Dz&1DGaYLUU<*EA%Zx zWb?ATk~tM>A&E!mJ|>p*_L&tLxuGwZGW}nhKm#gfu#qfw@0_ybOi1C=WkTD=d?A;i zF|>+8ZwZeoePhBYUBaIk5YsJGN^&ntoqgNTU%nUfDaaPMCxZjsk7tvjtWzJ0yZ7hW{W%yLvMn((2h|{S&I#9r`AM z)+OmtM9U-w&47d?fx_3%PQq8I9~DJS z`GLJwT!d!sk><8 z!^I438^&epekM1dy@!z0Xjv7kf;>y3V+t~{Ep@L2|IbjrrXJcddz(NAMIWp*dw{Jm;GodZ`F^_P9a4l{VQGhr@ z^eBUu<5w~s9!zI2001BWNkl4noyhBY%`XMNV=|;d3a_NLd$%+8;FM;9Ogl&^ zE-M&*4q#_+w6u(INXy?sG_4iOY@pC3U7$0Q+Rr#iWCGu_e}hM6nu(`T%@n01ck*WL zaodR7xoam&90{I~s5F#W+@iP#%s9hnn8lW_t6(&*?&Oovb5iKyRkgN>AD@UIkvdo~Il6B!Z!ltCxVKZ=ewU&GcrX zANmWwL*7Yiha^KxEJ3&V8E4JBj>f}pPY_N<$fW2YBkG#g&`E-S4U`zAh+k{3Ci8kh_Zxl4YYL(j?tOu$^kh zzG;c&nLKu~kXB|Fyp;y7mP8umFVAD~+DxL{CGwTm5wu_~$)ZFl?O-ZR1=4ZTg3wOX zP?;#{oj?)pM4lD`CXE-E3^=Q+U>HBCY8Fe!>K#0o-@XlD{kRFkNxD(-U!7qI;jSt){4i@OM_PdSI zaBvuH6dpXRC=8cw`8meH@tCVdGOi(woK(5r0i=_ffbujvVmlPc<%M8*1i#bLc9-XD z`XoNj#yd&)CZ*5HV?uxX9^x5vV)R)GpJeC?12I3ld;UivSl%F=8uL?}Zx?!pATG-; zj@##PHikcw^h11)0wc;B3|a7!Iy%62H40J^b0szUzZ|6KnBcD7aebrt-I&1~;H@s& zFctm@fML*cA+Mk?=qza@SR2?+>51PQU{doB3l9`;tYr0mH<}?4qIwd}X~r`F zvhvl}fF!yzDzx0c1<(2%YpS z%RMU?Ny3tpHoiv4*4sfy6S{2e6Q_@99QPpUx6r}WMekv{c&AzdgD16PVjEfor}--$ z89Qae5EwB8?VX^Y6c2}w+~*^L`5H$T_~Wj7{u^F;`DG~YQ4UqTs^G#4zXu0RoZv#| zXXDLm?Q0>GKNPpLUZ+_MxAz>#eSMr(jzWxM68P$0 z6)37Mr}4@_Az~q4LN^&hg*6tg_<46AiJ`mu?$?1X8@CIf*R!D6W&Y;fG&=rEATHMa z?n1x_x}d{X0Vg8~G*Q+F_(TQCrQz3eiSoCJWR6AtB^6AhXKlbOWn-LzHw zAZ!4&Iwq}^wk%)`i2nXpfUQq=hw9w{%j9WwvG)@?ONo%i>`B*O7i?Q(YZu34*~(5+ z7LmkJFGoixCcAh981y7#o-`vIm)?Ez+cZ)TNE#JTKBmqYsN+36U%egQ}8*`=Mn+9q4>%F8r>^t$h7LTO#UllAa z_Fftu!Mpg6hSJQ4_MfFa{nP1CVR+@8n19m1;iv2ag=6YDP zc$v7;hG{cEgh{m#{>5`HFl|v$5zKk-19;=Lzw=SLod7+1R=_vD_5Yw>|9;TY(rV6` z&gEll0btFVFW~XVo`MxCR?#y|Czz9Q5+4=5qf;e(;T69njb6w1?K5+2+sw6zwwbnD z0&mCf#;`NIrukYv%EoK)d)ed*At_B#nHiAfSyyGILO03M75$Rv;MzR?*tXT*F-?@W zW58E5bc_KK1LecGNTiv1Ukaa+@kk;X=xEO}*HkkC?ZFjD-;gyJwus4sN=B6enDk_BcXU~BPF1ieEx#^78Ycwx$|>am{sb@x|xE&#%53)^Au(d9}8-1hkh})~T{(mA*^z&tZXo2_zYX zv~=Bp?xagK82pgGlAor_SD-;tKHY?WmJB1rx++7LMQ+JN7yOwGg%teKf^P7M%2Dq? zUU4PGjS^q`=lrn>59fMqk53hc`pL&1mnH&RPF5x{(A{(hE^RjqNK#|%3?$)XagFPk zP4JTFVexa%6P|S!JYMo!jY!mH+1ihui_xL{tl*jCnRSZm<#x2B_y5-eP+!*odHH#Ac09h3OnU@6K9|brppzUw`+PaPGh-IC zx3yCmJT~q4d_1S_`lD<#TQ))Yu2oR z($Z3BYHkk7&1j<(9am_?4qV`$-FOyahP1zfdnrsFzn^ryGhhY6e(UvD%{L7a z_=F&d7BOVU$1C(M0n;UA!|ad({Ll&&{mlVrYi)zFvNCx7g;(IJE3bz28#h6pzP+F* zzW^HQcK~k7C@d^A0;+GT((=ggD5e8C+fg{%p`f4;UVr`XuyD~5sI07nty?z3K?jV5 zL#Iulkw$ZKGaC;abqG&4H?_cL%U9DPdP!+9bX1nZ3okqmjScm1?|t{e@O_3sU418QN!^9X4kKvJD8jodv+>x(4F`{gfxd9DBH3y&Mo-#59@ zV_L?Kbgr)y?#9(!xmfWw`fle}9d0|{8~!Sg#F%OK6n5s>*MaVq*&XPrPD#+!a|^Bq zvy-D3#VLuQmA~vq83dEjM}A=MtF@(-dh^db`#k*gs{e$w>o!8KK7A7j)x^nm&1aOK7ihRDxtWr7(Q9F80O7e2;;_&husJ5 z3Jr~oa?X8buQZ7c?xO;eWyJAyp{qRpl|0{_dpisN%K9Ziw(^tdfo-pH#^1=J_`wbc zI(D?Rx6#O2`8#|+&d=TqpSkjBK|Ortu1z*M9pVNOWMJ!;RHmktKlDq|(J)8eXQR;p z#l?jg88tLD(VaYWZIpMiRsNp=%zQjQP1;11pKT~cJ{tj4Q2$vta+%4D!w@r^VwqY# zBbRy4)GXuOs0^1*Z&)TuH6H0bIK588Iq5#;&Fsl#U>fR-w6{Y^aWVY%!QaD8H{A|3 z)wR&OZ(nF^tb^^_YT@diT?Lo_==)GwRubTt4F~MlVBR>jgrk`!o_Gp=a^*F&R)WfY zcFWjGDdPisNPZy zW5m`&@iN!i+6uXOc~D61;pTmu!fkE| zq8{+O+2t-9#BvjZo3;uTSZLLq8P8jz_|?d0M9K$+9)+u*AP3%^H3wdK^$ploTMGq6 zg>c~5v2eoi$3TzrGH7gUVBh$TPC7e5nU?bmvJAn=1z%(%4Q1mp<6bD=OG}%1Kb9n= zC*vE7nM);z#m|@(=t;IZrhugpfkj4UDcy6btXq0bq*GdT?X%4HxX!`5q_q4UR)#+9 zS7TsaFC(Rb(@FqjIBvM*R=DTR-$G+c8}#knAL{C>p&&O8{^$PRz$xGPCMjm>oyppS zbK!Lj?5FFTkN`mG|Hs~Yhe=gral^mq>F&un4^faHprAy_iV+nh8P^=xMa+54q9_K$ zgu==$VBR%>x~_r&5fl^^1q75Vd4@1d?CI|NJ?B)ob#LG98PxBO_kG@@&D^d!Rdwpb zinr6!P+wbz_urq7UAuOpMT;_2?AnFXPCo@*yLI8fMfW;X(4eZQbd>0{EMCrP+qNzK zIr9Zvf8DKk^R3rWP*{eN(qjC$d<8DOWIU!m`zTI6ZV2O2JruNvSAM_Zm+HHuD-PfE z@m~X11YAQ7vaHB9qJq|2Szbv}=9?OA>VkNVU1{*rAqSXB84sCfS1w=TWvnJ~hXC$s zG#Gu+BuZKoF!^zUs`%~3^^KSgY_q4 z=Z;;t`<{m|@4XLr^hVPwGLnEVjDE-V#pFjGLXRFjP*qjM(UkINCL$uOyKzC7NuD-{ zLjqTaI8b`@v$>#Yuq!acBLBL>i+6)cJmxnKG)I@+T+y4^28JGiI!0Vd3B31tngk;t z+4b7{A7V6}q>r+iX$rib1#gtnl6q2BG!o&{Ot7N3;ilX1;=f)(Qj#C}g~ixkS%K1` zd`x}v37mTBFfj;`OQxiYYKGtirm=;?5d?z)%$@f>#$SB{s;aAbP*a*;gqi<(9z%~C zgogSCL5Cq4#Ruj{B*L@pU@!$0`}X0UdnaPX3)7L4n~l`eOjPdKi?Z@kOqucsMvp#| z0|)_~+A?{?^?S%g8G6hi6y2AIEdwQY4aUI<<6n*9eqgzpIvg)ZNcno^NpKo~17hvP z3tVj^Y^(`z*})$NXP_~Xn-30N3z;gp`lL^#gCVcJ{2x5}_>9= z&bfH-!Ml->o`%LST~c)}i4vI4?g77v{R=oQ9e~=tVfj^lpP9?+dOX9V$s9aYKVUHvi3n0cx_H@*|stkb4Nw#&bMXVa!+rfE=0BymmJ9SY}KZ`aSNUM&En4>qx^ zfb?IK_6BTyaR(Poiv*RgMmx#LWH@32`{2I)xZq98vX`zk9i_S~_!=)&`n z>=*Yx#L}m@*vFwx^@;3&dE-MU9AaZXVb~C4WM$yfPd?*QTg4@%*tKgXKL30%@(c3O ztJl$7)|V{k(+(p}u+z(ruKtky@!Njo08YK^+m<2Ojv-r9cVlF3>X?$h(it!PaN+9u z?0Wd46*g9{wT|kK07qFf$Iw~PuCP`8o^Yl^I9|%vc5LuO)NjzQTX51~gWdO-kHJIp zqj=7~gx^45er%bT9U~c%l$8v_jg832%*5+&{0BGRbSpM(-NFYl0?7gR{WR#NHyR{i z(ZbJATi1a8{re#`HAN4KRA0Gv<2fEEp4thnzw+5WZ6!yNs&dCNmPF>U2P>~V8c`@T zf1#O0GM{@-!W*ys2XDPS5BbIA@F&yMyg@8MMCk-f8hlAbSiEE@ram(RPd@%I&4GC8 zpAt*~EeMEFm|Pk#=;I^4{6a=yN0vBjEU7X6N@di{QaY^AmY?uEKGKab8}KND7zf=ME}a*rjdhh*VvhW2B%L#f-xAkD3|C1FM=xDoq-e zL8Y^PyARBJnizD1&h2R5rY)YG_7nyW9>6r2GYPest;y#$?e;}G!tv4) zS0I><&lfGmqD4!PnwEyT+B)Rq7U0Aahao37i%&|?&2dGWW(l#4>!-G8X-zDZ(WZV% zN-A!?@p`1CX5j9-?nlMmJt!+L$KHxcTz~T&IB@VFuD|B5{5liTZDx=B>02k=GC_?B zrHA3){AMH{($WH`uW#Vl3@zJHaE$ftsmmAOHuyKRA_muM9qO_Ig4 z?33)XY}REL@+Tz;iD%rxzG$g`O2zEbSo0n={}n*`c6k)>6Z8EHES^buh-(Mua_Y^ zH=73^o7Zo|;A02i@hOwgyKhe(b*nmA#=6g{4Lexqc8pGuvnOMl_uhxtw0R3kii@y& z=T?k3b1eGx>#J$kBSl+P9Bk*_$&6qinfpL>Uo&AG($dm!=iLur=dN8SFDpdl-o3c* zzWb3JjpCZ?#v=+bdtkrd^rkN7YWF1?jvzVU=U_d1)=QZ7!aosArJ258>?6u9YCU(o z9EIBAnUqpPp$txEqS&N#-_Fr`rAx`doUFzH%3+G84Gq@+7z~XmuZ5=hu38nZ>^GH1 zQmN=QzKg-9Acjd{qQsQ~QP$|4@-GfBdh9XNP`-wTy^=2akM~gYz|6VdCO+b{pZM6{ z$-d}lcWq5IHm?5_Ia%3az!sM6OP>~rg!r^yWkn@E`0!&48afc!*;!&Xswj6DzRhOw z=<@BH=ft=Dpm_G%6+7^>L2FRuX!PQWM$9Ke`L=G|hK*acu;GWpAzr6eOpIDI&5E*v zq4nj)a2RXXtwmB&vf;?Y(v)DdP*CkIEt;Cs{)!sS8bO2X z3`KkwAV+CDBCuJjl#kUwCTdzt&`#dSGWpD9WMGrD$X-fRNt?@HZLz2aX&8bq+gUis z5e?gpFSg%0#Bi26jVAhLZiEx4wv?jNtb_REOCsk-&wkX_gz)g>C(wUDKeTDv3ZaIG z?tg6HP{+VUd$bWq`mu5IX54=3o%m+?56I2S=FRHLeU&)(oUyp`j+@c#sIEM%=S^a{ zv`G60f}JL_Ra;KSEP@$WS68lDg+*U3<~U$4!fEmAcQG ze}-M@AV=0KmrWI~jS5wpY(v_wi2)epQ5w}i%lR~mrSf{4TI&hZ-tDJSbH}Ah#vvwUXiB<02iQ|SGhd~4T>7YXc9McF*vk^v3^{Gp+1mX}01(2G$ zS`=p%p>vmx9Dt|~$j|0|k)1ntVg34zqKFI*X1yZW*%y&%)3AHb9&Fpblb6>r(o=ZW z#}aXsQ#PaJtSXUC&jvxeL(fD7GF{~;WwuM&znU5=SI=aPFTZ;ARb)7{TI-p;msbUJ%%WvZX=i-c zK`gt9S-i@Nz=veXX<1NoUeXmslGJ;mLk&Qh4K8^IAEAcrrmQ8%_C0TyD^O!zd+aMK zk(Wq}6?dudqA{AD=VWD~a(4xf!h~+xOlMSix`Z|s!*z8?PfZikeLiL=ab@*_$;zmB zJSC_z1ZE4}P)<1_6r%t&ZM1*=P~gQIHK_!094_wa9OH+6v@$57g@@Iur;=Sdu9VLU z>{LY{)g$RK38w!!=sHzh@LKZHnBA!6c*%kvBpI~Nr1+})MS)(lL8|O%Rt8Ky`4bhF zL8Fa8h?XX;1~k+*;D&3jLs?mgWAo10-Ppbp4&9faGwto#w!_4S?#GR{-iE3J2a%nb ziGutBOrJgz`wkqyjP@4Ze=I7cT)jHfx5EbIsR7Z#*!2#Gf(8~Lmt);yjA`}1`q}kAg$(5yYveg z;)Edu5;YT{nKUg6^AZ%V{D^i1)lvYUQ-$;zo-m4w3V9|iXz`%CSs?o388{^Hk3n&o z5>}juB`Q)(5efWVqAP`_v&db#9)VuHdtmL)Kfxa?Mq@a{hCxcoo%i_=2nMmgstN=8 z_r=|RzYXbWbdk`9B!9AcTcfUD{5X&N7;OqLoV3(QWe5)SGla{+QUOXjN-1w!NnHvf z^v=l}ohy?S4VvM4RAZO1>k;BNtB{gVjf=NfQj$ylJhpZ5fa}%oX0kJda@*f@nok4* zlMi;_a2hJfLc9sqP$ltIkCY-2y6qa~eJ?)2WYOt4KaT9y4e1$aV$VRIx@y`%iXUO3 zF@_Ig#+-%pj1-K&=4R~Py%UA`1*opJFk{Ax*uH%yo_pp=v}#q3+S*zK$QEgnoc2JB zMjX=D`b4w?et!}^{^%2|_;DrAI_QMev3+~txZ?)Ndl+E^0x1Ts9HbgROJ?fg9vvVN zfg?932lL*0AJ<)XD>iT5iu|G?G=#&b-ggjJT{R95J$M)L@^U%&+5y%{Z%j+ZDKg4$ z(V_(&oBSZI9{*QfC6;kch6yeq>#;|!N;mXh$8xT0$Em)uQrqncS=wcoZ0bMxNj>Ot zkKc_N6V`9%Y56&3JyMT!pfTs}Mp-k$xDZUA;us(^qCuQ=D8il{)}aqLh<_z#Bu~UC zFLC%so%r$us$RbDFTx|ysCc_`B*Obwd-w0d6<3VoyGL}-Nt~>cG}3ah-;bnZKffgO zq?1ozebRd4@O?7Lz4f5Mkd&&PS!^s|$v^tXpcL2<%>^z3_?ttJWQ2Y+ghD9D%for+ zpM&}H=VRyg?P$@m6~cVlN-)nK44`t)Zscd>VEmO=V(_4TVxS&}um2DJ&jCYU87SzG z0SKd!M#g`<%v_bVm6T^JNW$r-ordhJT#UQ=8mwFMD@saA5bzh`!w){dCDpZfaprSq z*R~C+X$ImK8{67=45y)-4dsQy^xE|x>g(z;|Km?lQ(cYHvU2PWg)nOLS?JjDa9)Dt zJrs_qYS0m@sOG&3%BK@%G+4^X&cN(BFXPr*?!xZ96(}w*Lw!vRFI(Mq`>nY3sE`(; z001BWNkl1Ay}vQXwyOcDJ(4H&;Nt}dw}F0iH13Vj2Sx; zk57Ia0e>>mGc);kIeTKdL>NfH=8eB##2IJej5CI_F43Te_m53>c(`^a7$fl}aFZfkNkVS`vQG6klHmKErN6n~sv@Ug(PlJU*$jr>(w;zlje;p3i*7MA%Wmzd^&6=k3TUL4?i*m)%Eo#DKAB3MFoOL z#)A(&fGe)L7^x{i)YaAVz>7ZAPX*?T!`&wLNK_I#-88?u@tT4^(}w;Gi0uc-Tj>>L)1DqJpWgStLwNSN83;Gj!Jm@O2a9Nlt1(oE z<4-sl)1I4xP8|>DSuEFVyz)u32NyZCb zT@>W?H_O8JD^}ve59ed~^5xjOZy(>|AOjygas+zzI+`5<8M_*ts!^UT<&&)=mC{&n1Xu74v;N_RPfX2;AvH{(AFI zI)8q5)TXVt{@R-{@4a_WSW=2$AO*X2?m?S&Z87bcCvoyg$Dx4^Y|whK+{Y3B%isa< zfQ5{cUia{~3D@IavtL13SvfXu-HJPJy$Sc;a~nHzI`u^)sXHT1`UL$vn378%G=m@= zuc+9KyYHHa*)RWx*M15L3$Sz74&-HKVe%u7;KGZ~;o#a3YLJ1Af}?R0-k8;!cHp*0 zmCu1g{W#X|4juvwA94slCCrkCs$*WD>U5`>;MI6S9t&Z53%mo^?dE2tgINv4<3x+r=N^gty+lRuHlz~%0ZKHZ^+S> zUYd7#f2GiIbWeX*!GjTvD&hu@1P-0o?BpdrTJxr<7C8<&ZFAtj0fcCFk>o>8ZVoci z)42@4=*#0Rj^gxz?0~BsvlH>24+XsXl!$5Z(*7tUYLjzxe$#sfO@XHzJp=L|1Es(o zIr6VThijjSHOcth7vB4lzwozvcLgR+d<4%=pN{ODJfx@7sioa0$j!o(Cm+KF=Z|H_ zPliO7RNaP2L5W`1zI55Q7Fb zq2IP{#r4(-5E*QyPkobotM8*wr(DbNK-5m@cu#PvxY=+U3C z@enU~sJ{sZTup#i+5f-wP=N}>0uHU-rffBFzs$TtXtW7P+-58=zAU248t7D((n-Gv z4pdd~ArZ0a#V9C3x5k4gE-rGEqxxuxfa~yycUl>lyy-^=ed2Y?ZA9YF?-PE) z;Nfy;ob(6UN(2dwz_q{hM}wDFpZ{o`O@q`}{;QsiHjSkp&e5YLn$6NFlL(&x_&^80 z2x|<5P+VMyNe|t}8^sSkIEjM+y~J?W&Rv*r^|c7q*W=R5F66T;gwF#M?z4UWhaC6Y z?}*wryK+`NbFGm}7b{6+Bb%8nwyUhI*qd(MhvyGVEV|`2{yze>*;2un>8L z`N+t~z^3)WUGI)-`vA!nK3*AC+Hobwc6& z*>=!W5Qqnf%X#qBfoEnmzs;tgxx7@MgNJcgz+oE3F_29GH~!-NP_;z zEcb-LO`{50&NT7YxtF4q!n@H#5sD3+K5U=j#13EdqgRv2W1Q+mb=ogG-nC-`^DqIU zl{0si`yGOpKFkabX5IV|(L=OFS#biXX1t%uEx_(KZ$_fhlrL@in~4k0H!2d54{g)djB7Zxgma_gF4lb9W| zLHm4I{qxVb<<>i~;M31hSX9V2em8B}h!ck$k5^y%CkGDtJ#!i~i3^8PuO!P=KOJ)A zN8_feL4%gxp9IaCcN+5lJ*p62hn#5&&kNrxPxCSc&ynOQOa1qcnN*YDraPv8LdmsF zI`-=1#c3X7%fX8JsQoU-yRwu|GCL&PvM0pI#6Z;bNgSc8;uTR2P@ORutk>TRXRA7< zF!Ucjo+fXIYX>Dx1c>_SA8`SRI_q2yH<-y)+5$Cyc-;+J>1C%hp8I2h8p#{=t2T81 zlB zs8q)YhjHvwqok4P(mAEERV#LTvF&>G&u&waA_uB=jfUele5w-+ol*l`qb%3QefAivOM1<8(Nz2Z zLJ$)?G+}1H)w3ibF36Xx**LMpxT}t3g2a}|njSf_h+&LGkNNBMF+dB($mf^LX>*fl z>ObuWW9!t;*JvZI(t3f%>?dXvDBJT^oMwXRr&fEL#+de09|Um{KNfhVsm_c`JJK~7 zqH+f)$#8)$U*zZvC<0&6D#R|*m{q$4t#%r^1Q?ml^V6p7Nl{Za~?W!*L}5t&3)R1|+fruRK$~V{~1jYMoI1 zRN3zOjDesVNB7Ufck!2bENfLC-CN*|H0@{W6`;D zN3K{ocmf*v(9$s>!0Ye z?IRtIoztZwa=ZbdX<*%wI@Xl>Cmig^!twIr+M%KA%>joPTtc(kaaywN8*GCRPfEyk zY2APvOfhea<0-9F*T5urVD zuoeFg2N(m)eyKKeyN2l0NX4m8O3;o!5{#LnRti~~(-mK1*&+ghchJ@}IyUjdvX7#U zmYuqG?V?}Lz#NnK;%IIPDl04T;Ro|kbFdoOIW4fSVi$(fF9mk#%zF}aTwJd`OFC)Q zRRq~sT^6*cGcnTGw6fmk$K=4D(W(~D4@yzl*U9qcC9mQGW zoq0|W)l2*F$T7Yg3P^lU2D_(&ZtyA;C(j)?=zCKN+!P207~5yJa(e~>$;Ws!913kj z2h*Zt<5AS1SaIr3#BGmmdVs0vUipc^q)XAOMq%p1gBN-|ygbTl;;WBX;__j^g3qw_ z*I)QGA@oX<($dx#IA8#8qSHpaFd%zLNW6DQOyfoSu{{=ah!ch+RXcE~Jo_C-f-Yf? z@jjZd!k+bVhC@b8nSmFnO_XT{!Xd#S1(Z0t(X2Y+p%~8m4}q!Z%~+7|mXj3b?*I-& zrk|3}&H(PL+a26pU!6R21r9F|^$7%ej(NA0ZeK>trkU<)&HdgN0?9M3FXp!!;?=L# zznpaGsBV-q1*K<6h67f8jF~}+!uF%#m>g+M$XvJM6%1rmZb9lcjD9)t=&NkkQwCma zQ)OK3X*s&eD0*2QGSiLAPE_~L{@1L<24^1=l~NdtLr&GpGPsbCwJ95+KWe?#?klMt z?LDZ|PvTa)2q={14+QvC)w5rI1;1@shn&1J9N4!5=U#O!`tekp9=OZL1(PN8kJJZcM+&rlxT1y0d50~#b&l(m*plZCL=Q0a z%iR};uFK%*)_;)|p9k(bO}U%kphNXlzX&ou{caogYR>^?RV+-wJ%=B1w7%F4dx#~W&a1X$IZ9^iI0SP!PZ78h-Lq(uu2_|b1(&Q71zx4&rVYl$b=BkT z&%FDoR+9{NH6P43lIwy-4YDoq$Fxs(D@`%ZRl=dCa=^%G?s}aNPtW=2^3!(mh92C`fAEtvqP?b znu3ssj(TLax$oi5bD+BnBpyF>TRMQpF+|P$*#5BW9T_51bW_OIk;7k%{Srn{?b~?X z>+nv=i8|u!iD-K5-n*THngI~h)Yf9#Z`)8?Q-=;6+w*02ij{QuuBVd zj*Cr<=W>{eK)33|6f_(Z*XzOmru>EeuK6O<&BmpEI_%sdXejV=>Kje>8&xNMEOtj3JfC_V7z~2^-w}A%>!$(Po@%c8g z&Xe=&1T_=5Bbk?(kOfUJ~Jj5b6&c56CK;W~Kil8p%lVq!{VTZxeb z7&y(bN3X%89o*d52DtN@Lz@@quEnpwL7S`Lg!b=2e?06MR8BAjNzYE1yTL0>^~2oaU7WjV3KR;F#^HJaf9QSQBS?DMpbDe!2VNHM&sg zF?a?~bU#=oMq94Fh(E@RL!;R19HJ@3E0JZ_ufSN=q;if5Da}hi$38c?1rPZ>Gsd&r_2sNp;4|GU{-&C6l!ss!n)-CvBP_ncy+wH}SMR zN?8-8z>l4A%7XTzRyRX#UcpTDMf2RI(T(r0P02TbA?elFHaK{x{%T+4DkF7C+lI{b zIW;Wy+2Qt092Zc7?3AfQi6VBmyz^GwM+Ed-RjPy8GbO{2_HQwgRWK z^@fCjSc6CYA<(A4%iv>VVx}29bN7YWZ}3>WYJonwfQ=i6T!*vQ6?!5z*Ftf?Z~&K=TC-Y_6`ji+c2nZB&)xESdiYy5Nw5}Ftojo(f_0Zk z1n&MCH0qjpbSr05Y6Q#a_V;+;a854yi!U0{21B%N9rDs0C#ZCT4@P~S5GT)*UX>?> zlZduM)oBOB>z)f@T5yz8o%aSaSTN0|SX5uM5<0<)C(Q*nRk|(SFn42ejyEB01JLOS z6wE84YkWzWBZ}%j9?LaNDV7I#DQ>)e#NfEvN)$AiUe{FIYqPm&gNhG!8C#@oI+_zK zn@d9?gH-7XC#EjPhIkY07&2F&nl$f#=u_)@vqiRTKWY$Z;uMiyP-}t?0-Lk0bgn{D zXs|=IE%e2ZkCR0CsOY!T_^X$W8fWx%RVJQGBo5~nlPCW*gSeYM%_6%EQcS_|oaZ*Wvr~mX?Ue$_j^D}OJ5>J8I z7ma7ort<}oXPyR0oS`9hR;-9)UyR6*KxkC87gHTVP>){AQgOgbSdM^VBmTM2RDDE} z`7yIxS`gFMM0{+HWh8|788=C8I?C8n=CZt3M z4fGgarPY!AUZ=yi{HypG>_^u=p5;|01e9{qEGYuU?D zzk8NP$sU`8o^*ILl}Ns^Jh%BRnwHgGW!S2LgftQ~lNI_|ZIrrnAqI^8H>;lxJSV3;d*P-nPCK0J6*wGS zlKqLn5Jtx7Qs8VrWFY)(D1!Mp6fpgP`7G;+(=827=V1tmp?P+t2MNZ0izm2MSO+a< zy3SX0BjCtMJ0MGB7v^6#xW$=30b&MRniLmJ zF+tT?j`|Q^1`^`s>ww~&O%V6>Bxa-Wf(n0k>9fE!@RT4ZNjWE@E-yvZif#}dPiQJ4 z+V$xi)sj~+r{K&}IkJc<<*3e)V1wq1BhRfZiOZTij^T-e56@Uik~N^um=yvn-4 z$y-+^TwfjZo1n{@?WoSgxl3Zw<{?U9&KqLEP;LFw=PbP^PNr_uN za|wL})5eLR%F&o{)JfwT2PMp7#=4wBRtau~n2$~wc+P+oj$jNwnzIvSw_bxcQ|HCA zO_Qhm4dCvwY#g1_{V`fI@@#PHn4r}YH3qm;jLyf=AD3;~edm9@iU>%Mr9qKzijo;4 zd8&5zSOgNu&_S&U`l!0iJF}{I;P4e5X{Jw=DaNx*p=GP)IFN*3EO~HUCPQ3!G2pEq zF<>f-qSKq+*o`)4K#QZ0{EwRUsZjJ_Hs8;>u#tg}74&q^KK5Zfn{ zrg%o|mG0)HsXTU`SuVB{%7Kb!fg6to2gvR*&GZmcB*EK0)sl`1BC@Qr-8hVo#~&qX zRhLZn^_ z_03=9gRa7B>rO3k7FlQKco?70fBqhVdV73|CmzZWX#Le&)Ok7A*Pn@dcj9F(%I&D;UKb(6O zhYUt=Q{c9z*rU20pd-77oOOiMLrxn<2NaJMbOdxAWo^pf3C!rJ`pEAuQhBlps*Cbs z>-6Y|PFHD7D}ytNH}7bn0;f<#L3i-5orx}Gl+jqmv!chAdm?_COCz57291i>@jx_V z((Z-j1UGF>(PM&xfBb0Er=1Bytc+EjJt~ePY9n3gRkQeI-pJLNf-afu(le2+egj0= z8nu;_Y>ze^BVXg+#5{}boT;}lGLU&foQdkCJX1eps#?CIXZ`^##cOx@rXgmOOqE2P zeP?+J!HB==X1^Ct5(O4Rof5Ls0}|V(2e@DO>DFaK&-C(@yLN{zntBxXQ4i9Z_IdlbE@3t5_D2LBbNyatn|hT{?#@gzfW(6)vOPw^%0W9z+O*qk3R#$Bxt63n8kem# zgEBi`1903f``HJo{Q{Zj2#I^i64@3Hbp;h#Tc$VDu*&8oUuAV z$uGt+yTPTO-riOHwe!qhN2C`_+Wc=GeR09Gb0bj&D_y^A->cm}NI{bz=!oB6#ZvqH zU(?_UGtNhybAnP1QoQ=2@infg2Z~4Dg9xrKW_+n;(ibS0!?8kdB5l^lPU)iSJ2Z0}t`^q`&+k7!+9$Enno+@De>$0ZW#`0eA z#xA2V?O~_`R6lK}X7k$MvkY)Hoo1U+r#c(?y0=m%+;X9r1oukebKjNIHTo$TrP4^& zKA&BgC~ntb%E^|e`n_~J-KN{=z4Zit8P0O=Q;5!A>t?3WRbkY+Q1bHYjB`k{k*vtyeo_lNT2EUEzwhg>fpU zs2z%BAxyki3QP5+*efRlDZ;W6p{uq^uFN)8KUn~cvS;$JaEkWUs446;UJk_CW zScqQ8lxGhz*i#-Oi$D;ygf1}^=E`Z3uuH9XgiAVwD6?4gOZft#k7?)S4co_x!GzLP zH;6paRpFP-!Aq>~kwc4^THGLfh7-^2dkzI0^{LsoeAeJ1%l-{>wXCE9g~P}ts7Ep^ zwSMag4(<+_*-kp_FQSCo@MNA*A32I}V9?kVKp^OFV9JOZ!(lsN+P2h&tpLKMnGMsY^a2(KPurmqp6x`0!xCdYp(v69iAN5E zlPO5bOsX#sQ2iFXRI*{d(|>ZbNqEuZBqU2mCS)4n-zTSfl-`moXs|)NA-ZJE{4eh< z$lyi%XU8D>pq&62c0}k(Qh;;x;(=k_`~Zs(A1td8XP^ z&YbLn9(_LB!BC#4&tkn4gChaqa3i-93fI z%?{;Qxg0q{%R*{OQ0Gf);Kzpg1~z=*WQ4f|q_g(|3MxGNkVa1bkwG?_5ea~lO&fmH zUV0;F2!&(|Nt`a)q`o!^S+HQ~BSvbJEe6D*6dRm!8ZHP&!djj*Dy0CO2ts7=yk-cb zq}o9(6e7o=WMvx!@raBrAsE3p9;n$Mk49O1HZrwM{SAksNOjOeg9<08QKjkh5&;K3 zasqOuM8>axoC=$}v6f7%iA2LlH3Pn@K9V!(ak36>LZ2dyVV*^sg9XxO)=@cH6;99| zsk=w8q!UCB|Hr!R%qO0x;LU+297bwtD$l6hKz!x8cr5IPj0@J2V$AE!@aMe|p^XPy^EdhTJ zRr~kj)mQ(GZ@*uG(WB48X~R!KZEYR5M}|($Wb5YNFmv`x`02+LsIRR<>sGCB%JAVh z<np#so)M!xz zBjRJlo=UtucP_sEdKv0!YEV{Mf+5Eb#hGWE&h1fvN@fS;$JD2u!j`SuQQy#jP^bYk z`>(04!uc1Rhm%e|K?H1n03R=yk9XhwFUF1@iGhQTWe22!HjlodQKY1#;FVWi#YYRi zV3`r0DL^&W*W>VZt#RYcH=(egkZIVpdpBmzoP|9V6>Q-3^&#ZtWTH=>ei$|SOm?6g z>>|MQf6T!8jaxD9ip$WcQwP-7Hy|}F1)nTfh&eC6f)h_T9-~H$;J_uEKN+hSa8TNg zojWjl)+_jB{V&MO%z)qLX9FR}UsGL!Ze6E+jP z-0?#(Y9!Sk;NL(O`&GhA1Oowl^X+$-^YUx><>y~fT%3==#|^|8BhElcVIezk)|~@Y zm^o_>cJJDQD=xbPZ4Yb1?&6CtmSFlnW@6C50r=bBuH+FtIYtV2=F%CB&WTTNz4;E_ zdG`a189fqX&pwOwmVkI)Sy_o^o|%q46}xfn*<&$i@BoAwLOcT?eo~Kz)5Z+c1rmsl8phcH_yZPocE99OJLPf_0Y4)HT#$?!5Q0 zZr!iA`ma}_sHlkbj)K{|_vhj3ua@EROD{#|BRVr}>wjI3$EQ4j2=7@WA?T-3y@keT zBN`hT(68SBTz>f_A}~NW;{E%oFzcn4@y*h2P<3EGa`JL<{E(p-GiD?*GBd=?ng>lj zmf_TApG8&GLDbgOqPC_M1-ZF6_Sn7{IcgL;WC}=Pna_v0^X6g6S4(l(MHixD=T2M~ z^?C8)FY)hxzloDh7>3hFjL<%+s_Fn9e)uu8C~JXBuecZ~L7JtB6$J`%b+rxn_uKDc z(dUa$v3obNGP5vX$g#NM^2?BtB6O1KQb9xq4?WN}e4!qk$oZu4!)RVH#mg7F^Su19 zM@Vqs=zIzuZlJp#=Ep0YW-Rof4R=SHM|sAHM6HPWaC*eEKCaV9CtL;3O?!c;whn98 z+4^MR7gjhDv1)2-IPa?^%dD)-Le9VbhC4W|s_LLsTU%#E!eQ%&?|-!VAA3A6xMgG& zT16#o$hBLAg+$vXGo=1yggaqLP+YR$dWJ_^p<$+E^1O zJ#5w0)mfoX$f~WaWjeQQ-(hv?(#=9r&?;|vnAM_9d#kvtrBzT=X5D|^{hBXS=E2F2 zTJUFCCFO@%t=e?3%3HRxa&n8U5hF)iYkpqKYzT+LR%2tMwcyjwn9j7cTEFyYGq^=TG_cRt)07eTlMwzRvmrn8m*d|s8v@NwL%SHt|t-+bNd_CZ?w)l z>uk%Pl4<4UmslM-ceQf!O0AZy53_E$?KZ1&-+rr++YMQfaMbGAr@xhwS!A_r-O1|E z@kpyfrz5Sb>|$&B^qI^j>N~-`_dh@jF4p6ZJ;VHNXlP)16irnJ4>H~*mtM*80n)6j zoFXeHw}j>`*2yOgw|4B@q2;{l=bx<(osY8osX11MF5Ru}J^NUNMJ=t8k`~tF$&Xpp z)zwxc8nGhbh;`E~cW|8-UwW0bd(R%`&6dr-Swn{o$9>gwuQ z*EavQ)fzE!j8#xvZnbK2n3a*8XXWJ=TSs&`%4*x@aO;wbF1NO9*~)YsI8enh*|B4X zHFnGeTz~JrgRLcBFJr|eeo)^@Hwgaw;m1~&Zrv>)-8!s&S1Y%m1(*5T_^YkT%Dq-N z+$iL-alO^6_W-M`{BY~bMTVd9XfQhQi3_wOLN}fG^)2T+-OB25i1;yur8^# z4ptqsuDohI*Wa)I5bMX)tF?X-y!D^A={Sky^JQ6+CqE&|96V^%hw9lrKKpc`)vI@3 z#wjQ$vx-YvS;@XMt82IJ*2}NF&iM894a_@&AAee9`2(3&UT%@~(yOm=T4Q6_+Fh~7 zI{EZ7t(?3PYxU}NoUYos^s-B>U`m?x&YSP*^p!uYv^sP;!pbiywQ_R{EngtbO3%!( zva)im{G3AT<{NHhJd#(qF>Gzxu)#X@v{7t}!PFe9Wt$FGl0U=p`BJTmFS)|nzHJBd zgz#Bb+jm$+#-G?)T>Xm+iH#zJc?e zef~Mimy}|4Xn%zD&GO~iKmEG?SIh6uwgwM6+1kJV0P~z|gY|IBR_mgR$63jN6bnfy zR$f7w`wlfr0095|5{e63=T^q|&7O5Ni%H>Up3mF!TJpwwi*SyLMyVd;i7pg9jlc zn1Y6eMtt@4G90X~Kw&{^WTs~@K8+@5)U|8ZE?j@(ZCLWvrx-WxI$U(oc?hNiuyW z&l|;~=y%?ohpA6JgN}!H#AA<6()@002q85y8=;0qJo@nC7}~!-TDEM7P&kCN^b7=3 z(s(3D_~PUhZ90h4KD6;ia-ueAujrop9>m;t|BbWHxfm0!z5=;n~&M=utTBw39LCmDjNFi%)UE z`Iqr5l*eioEhqR9jnZ-z&B(->etBsr9+~tYs;a7Z6nW3R_aR&t!F>^_wBj3`_9|BjXk?}k911~W zC=4VAc{=#@my5A!^A@ye-3mK*ZpYlY^AHGTA}u`)DM7J5Nz+Yo5(__HgwH?w5F^ew z8;?9P5xKcpoZqYGG04iw#swE#jDO8}6=$AxI=5wRjFy#`p@08=j6dwSp=jT}JCduZr38Ek2Gnt6$wMtnK|gJJr}$Fv-HH`>ckWyq zbId?YdEybYXi>^oM*=9FIRoq0twUK^u{`;rst}uuXPhxSMj2=+ODm~7eUj{#o51R5 zrJi03JdztN2OZO^JBFQbyrVv*JW9(-ViS~{NyiTDaoo_soZsb$E_nUlbMeYcGq9&} zFQZk8<_g(kn(#tPGI2z{7a|*WNxT=z~ZAoGekk;Z;&`?*0g`a$azg>Ab3W^G` zWa)Ce_tD2lP0QhBDsk9^_VxT6l-`~9zHILS+;Zy;y3b@EX=y1KfAs{sH0L$+?%7iZ zk4U5uNxmp@atrbE>NU9Y?)&iiOS3pI({dgCzBTK+0|f8YUY%O87&S%ZK5Yc?*w z{8F@RUCwztNQi`yTUdnQ!%xw5{_mrYFl**Nv1?a_2p*C;wSOmQ7k-O59ZBMWPWPjZ z#Qcvw!arxt## zVdzk_YttUDygUn+UVJ`|?AnF*MflKw!B|?)Px8s*tJDE`F5sK*zhmV;@q}RKNMR8?1@I8uaAW21I<-&gJLlbI|?#vrll-O*i2E|9*hJeR|`x(@#UEPKR@S zdh;JiNKZ?{_U$_`?b+#g>#esjZrlXibjuCQN7}IFlS{&n$YWpB4`u98KDJ)lP>)tE zTA*XwHdwTD2^M_zDb79T9K8R*2S`rx;rQbR>HGqw!)cb zoXqJJ6_p&w3knJ_Y}j!)tZjQNU;aI+Yif}uoh!`->g(#!w@*K`Yu66bUw9TXh7H5D ze;o&lPF01)2|*_a{V+$qbdsuANx%<4PV}u3WVW zpMUZN&;By9vh6XKB#Y!P=oCq`Vn9c$L-n;7GwLj4q^IGLhabj?!;VLOUJmn$PnbzB zNQ0ywfBF#z4pd^q$s^FYQwMo~Ckd5%51_of3`2)xB2-_`D*|-VQGw~Wo#2tC?nuSv z#Hk~G;85V5ALG3l{4qbk#6DBrU{nQEmMegm&uVrdsxXf%GNN=MB49YWWwfi4T!e~| zy;vr(!VwG|dK|(@!29pLk5OYr;*Gc7MCY!Zan+R<6z967&}jpB@BRY_1k#XS zl#800Y93wlrfZl+bWyZ!U5;PZ{fdLMdF@k6Kw@Pr9F?1t{$$3jtFK3S%MyIM>{}c> zSR;?yiT;zK)>a?HGfz)LU2TX*{fBpKk5Olg(x#U8mrKRywN0KjyDBaiKI7YG;fsIJxdm?Or_7W^PV--LnwRJr5RmX{!EnSLD z8-B&L*ItKXdL4ta&N>}$z571CS^gac3=p$O(l1)x8#8t!FMGWH+AEm%!H4+wf8N1A zUYvpP6RyGKmtKstG;s=toE$AdZrrp9J9q3teSIy`vNFKq7l$zmcdTxWNP|*YsIIL+ zUUoLlJ?~sB`~G`;{L#ngdCW2R=)(^%a>S|VKX3r%fBZjvRhwns*oggA2auhcgY5h~ zaepHk=A~fLb&6J{xf7p#`Z=C_{0a2$)0dY+!x36$ zbCAxn9;#p6X;B;g)GNMMA%ipp1aX{R-0dRAOZ=~?tK&lsMa2aycM3dI2hH3XlIqc} zeOs1k<-SU>G{$!;MDW?MX$!`TJ_i|@DX6NhLB-C!7(41*v}@Pa5jX^c#eFjRqBpY1 z&La`DYu6qVCq2YVYm*T!MG;Sq$) z#*||a5!YU(iVLQYOmL@>?@=#IWMva~0cdJpTT_kVk`g{Car>>e;Ni)SVe^JfeERCJ z_H9sGQ>oVwiB38ySy+&daHI~~wr@j5MkXpN_n|SFE(m3^L-=*W76jANkd>Xq4nH|L zh-jD;n=Ublv-;#<(^6A;2C;VSdIVE~$jQl;$NdN|g8GJfv^e2Oe$)k}E@nYe|lz82)=@eE|=uI=Jv5S<2NqxB&tH%A`-6o#tK zzLRmL2mN^B(TON7E#r|OEqM?R_(-BWg2}@Hx@Qv-cSyqQkkv^bI_odVv1mlsfJ-mB zjF%;7lup5Y(2#*ls5-hxG&DvUc&)mmv;@DbTaS$!HsXT6T!r=Nn47krA8lr*O2tkGxkOs}z#21xcAJLy7Bb`~~o*uba0c21%Sw=)BXpWhBeKRtEmT)m^U~qn_uPqbS6#`oZn_;oBX#G+N5N0x ziy9n>dn7jRllYo=)bR=9f#$ajK34 zPp1)k_w9{uzx@^)e_h9WCeJrpMvXla7hH4+ z-gx~rv}#e#L5}X230oC2%8c|(UcTDCeLFHT(^;p2fn;<)`bg~9whJGB{64B`Xkg-f zIn-=B1`Kbmv^)NcrD@PUJtk;qBXOiFd$xmzI;XAQ5ffWR5$K3k?zFLoN#{wZp zGq{-hDmICtoHk^&045RmQXAi@wlMsZVR-J@R(Sp8Iq2G@2XB1+ylN$qlA`d-`vi@V z2vSl4IJR#eJkc1!d-LAo4b;}HTWLCGzxr>i_yjkXvH$=e07*naRPH;ReA;Pf)v^@z zb+ufE>Y-Huy0S&fUwOH?jQ_@4@8E~!-=q7{N2ALT9r0C{EIxf28LS4TC zK6lS|Ly~x%l-7jL9y=E2{$(s?Oq+pw9(VvhtXheo!-lXE=8+SzAwo`G>;=&J^n`22 z;k)mbVdkuVAvY%<0h+~-(#laPT_L06x&p)!0Xh19eR?4!JstDs&&Rr}E)H)dpPb6GpL5SS7vFui6niT7 zptM}9brT3X68e>wpUXy{mY&W72z42dWl4)e?pZH81+gx!oRC<06ZCLCJ4tcul9o!p z{(33v!^$65;ma?-=Ghhnk40a8iEqC94yT=b5-)qy)-_<+H{bCF?NQyjqGP9yIOU|1 zx!TE(OvLJ+*XZCu{iP+vl9FOfxcYCXsj0%b=bVixQy#~$1N&oOzrK9LG(fXr7yUv> z#Cto4zqPg1$j;2b=rN-(ciy{r{qWcZ2rFX##KCiGjT`9w#HvQnIN<{7yE z-n((sQAeV5XOIe1mDv zPeXb}CaxYg4u1JgDP|yVeh0Dbw;h=M(rfI9e^{{sGiSaCe;|lkZ@w8>Ss8pfOZ3;` zDgEx9yD;;gvyhixAa1LMBk0wu7uvULE4oLcak}J0x21zA$jQpW#g|-&*|X>1kw+dz z?_S5?*nWM{7!L6rjxbHj1Abw!Nl7Ru$j9SPJchwTj>Ca{yV0^`TRFnB8E6h7$Ng@t?)ZR*si_+iCQIQ7KgXxp~6cE)t#jFvT?e(oRW z)VU+`VB5BB7&>Gyj_lS=za@icrGUG5$r9d3rjuGUBP%H`!oUFo^qMZ6jH6q+v zpV$VFg!&Mjd<()yJD3`TL!ixFzSik6y5boWukNYW$Pf>eaf(~tbSd+b1)t%kAAi8* zS6+otXP$|J)itb-3qJh}&pbN~ixw`#upvWuiE{h4-FSG?WNg{G9#>vD4#)KFjs5#8 z@#W%$$V|`1;fJ+1Xb}5S8ENT!VyauW&baBuTX4;F6EO9ODd;@yIpi1Q@hput_<5#e z&`&^n8bQAg4GncTSXF}|g9hT5?nmN_FBW0=DZ`PIO$P^RxV(=qz|sMfMqc_HJ!%x* znL8JcJ~kPRjSU#ke*oLgS6_dPC!c%@ZQ8WOC6`{PmzfCk;ScGgGtx3}{k2zP**8nD zeED}cvTIkzWkRBo1{gFGB^zbl(uF=>GNL})(bH0$bMH&szo66}M|H>F{yGj*o_G{j zj~|b#uDk-pC8gN1bqk(*_62O(v1#dv?bS*WG~I z?zjmLPMU-lr#~-llIy@mx<~wRZuaxa2fZ4{pUS*HtZi#NaQ}U{Y}|Mx03|`%zC{`l zkuRI1e$YUXmRA3I^?2NS_up~Vl~-ZhU&rC_P93plZzW!w{tp~Dun)mNS`#O&3{d`7 z4zTTX^(S$l@B*&@rBh<^JnA>k@A4U5`JZ{7m(G>b$BpZGF4(yD;h9J0sri10{HSBf zqB4OOj_`-t3^g|LhhXAE53yI9HCvo}U$b_dHD$`v)=w)}bGeu1%;EgM-*q47tGgIf z|C%*xt#i)#3*Sc&Jo541Ze5SEX1@56Rae(wRUfRj4p!Ij9h601en~G_;Pc@=e}*o1 z)KNY8+&$4w=g#R~1GT+#*AA;E4_2}8hs;RBB>g(&Q`i6RI&MPl*`rY?FWHp2ut%EgneD~#vDN{K;JtNQB zzI`X(VW2bpbZ(u_1aJU z_g1xq`oczmMxCJ`vpU_rLS~79^!IzvxUm;dSiT z#oDxKvlVI#v1Xn3mkTBDX$(rd_4D_ll5*>(RjZXkSsOQR=KD8&diS@sZvBmEqVxL4 z9MhBWmoEE;QN@}18f)MFef<6EYbJ31j2CC|cj6=6Gihib9SU2G;V9o*Fd!2DSK^D66zBfDFfS^3uDC0`3#C9Ge+!743nX|-tT0@RMp6@TM zS@SFFQ$Yu?=d zvd*!N$$KS>mn>#EjyPi^f3K|(_nqE;`yFnh-C^ylUAuQ{{XTfG$~yPFb2#sRAAY3E z(7hXV*W#m37I6Nkkz+ZZ^pWy}9t$6^r=rrj<+i_Dg~g?oFG#fJS?~v~^71y;!;>Df zst!~$Zhb=o--+3|bB9$}RAS}kms>k`Rxr=@@2j$g3=#K$-g-;iIZt{_*_J z_&eDW!SgSOJ7zDw_!9S%?zDtMjn<`?UBT%`AJgBe+`CunWPL-(s;Jy+JuvYRtEjk~ zagvfr=V4`L+(W0*~ddykq(C#o@mx9fkH)Fwq zPkEED$I;z+V_58A&~eBhDk}D2{wE9Y!w)~8`d|&(cQ_nF1`gsAM0D3ey)=$SpTBL} z&NtR+hD|r3X`0@myajsq>Ww429U&;R#AY_t-%wwN*WY{#dn@+RS`!-R#20V6`_S#k zqj1LQ!}Y9<*2zErd?AJop`*W|A9V8Rh3Wsm-pc*B?Y0|vra|S`{_->4e)|KQdg`fs zOps53$oCYz^vY{!sH?{nS6n7v$DtT4U%KXa`I@+CUUi@vi@#pNM+GbQ?c+NP1N-*H zz(M^59rCpme!q`zMsMA=6VV9WOK24DpNd$#1TtvQv3k_>?YGPE)i>Yri8OwX5bd4R z)}gSd5Eou}0q;>z+I#Q4k2UKy@Mx8fdh$I3KavAM{N*nf@NIWuDxFrEJ!=k%OG|L- zDW~XHjePdmXDnYjib*GYXgQ4EVHJ%aEhP<~e*PK0_~J{99z7aeyL9Gd1hq^eUVB1I zhQ`J?{YN*o2``!UT0)pR?*o24$f>8C#B1jvdTmEAh&8{g#V4PBjh*InHlLU z19g1%qmMq~`vYf;IGx`TKyA=6>$l(ifDb?T0GrltKz>OH2KFC_6Nep#^vtyXueR?1 z)3Uk}J~PY=Z3c#>F!Vn3B8Z^aTQ)|GCNX8BiN-{eXqsi+^i7N@>LxMyH(8TSG;Z9i znr6ci#R>?5f*>dz1gQfvz;xdKIqlwa?|0vChUEXxJm0+Ud+WL9o_o%%=hB)Ip0mJ_ z+v86@1&8Vn!-emAFP$?$*t}&6{LddAgn`Eoq_vP9-Mg~M3)&XWn-X~X5O?-9!?VvW zge_aP!v+8J9vECx!=t7yY)%BjFJJx|EMBw-&N%%Hm^68!nbu>1yz|Zuc>0-V;Puy5 z5+6*MFagdz>nu9sfg@0|dVngwybJ8uxeFeD>~R<~W;C37>U^RFj<|5W>Y)c8Bs@Rz zv5(M52k}MPV%uB$=G*YW4_pd^2iLG!7wWKcyV$;S2R!=N6EJS{XgK?Fn$_^^v(Ll1XP*t@ z#*gK7lG0Mxwsi~q;ekJsY`E~E_d?f-a>5m-KJgtl6)b&q89cY}dDymfGxYC20Op^1 zDomX;8IG?R$oy$Wl1Y#$B?sm`o_b1+CQ{JZaGE|o<2ddn!9aO*q%{PR%7X-ElvaWA z@HyBi7J3@J<&YKP+94i$@q)6>jmAJ$c*!IMr)6y`;ru$=ufpw~jbbZF6rLFQ!+Gu$ zV47r)h}MbukXC1HB&9%=3caI&I<&Y;rn@t03^cU2_K0Y>U+SiVNMOs%mC}``LU2A= zx25v-$~>D@WQfn0O3?ECqku|>t*K_t#?RjaTF({`S2gc|sN#G$hZQ?iY<*8?tG1cK z4vhaX(e!Kr_Nj0a1jWa&IAx)S+h|_f^A+Ny2jaZ-TCNb~A+-O5f=hu-wD8#gHIit7 z4>fvs+<`>p(G4nUNYI%@=dHvDn76ZSB_=PBw~I}YSo)HEEizzeY^Nzm{$#9Bcvg4q zAy@;K#X#*!QF^$!Lh4T!uF>BrHrLq{b1W&Kom^sd8-r_^wA`vJwa#L&?NGnvrNHJF z(_VIk39t{Em`IwAovGo<|7oUTa=D+&byS-h03voWAQ^~7i=6&YridVHXZ4>2l^SQYfG8!#{| z;mLxK8ii~@rZXPWQ23A@Gpy1L@lw!UQnxcR)Ha1yMPc#droLcTOk<_-X<&xxgGOn;emMJQw1W1=XrC!!-3QC z=Ezw9c$44ur{LMlj&4~Hx8r{O5}eaV!7lW~(Fx&&#v@sw^E|nn#Ub1nUt9pia-biU zfi1DJAx5qG>F3lO_O*mT`oE$w=D4U0~+9)_bZvIxwAUM(DJJD_?HgQO}KxGgB{xShCm zECvn{ESSzX2=1SVnMLwc=W@ zoVB^1Fdk_eosOPk8=Mw?!FIIwJE@X-3it`0R;G&ADx<+ObL7=GHb^BhoaV#v zj6|841@UF<1Y;I};vg&^3Y#3TZP~V2dc}f;J|iJB61$;N~6&4_<&UU?r;cN)ftL4i3aD?HPwyPu{!GTDgK38W!RnQtX#{ zkAW;M(})MZw36|BY>M7;p$`|!sWJ+Nr>GMZ6bn6!PK_A<+(?A=AcpV?jv1ZLN%$M> zw7k6E9!>bF@ZclD|7Rq*7g^{EGf_spvsfQ3xxo}MC zRg+Vids=z{Pw~lFg}pGHnWE7+JR*%peH>TMm-r3=}=nxHS*{ma_#N34E!aLQqF1GQwb*e-vFCg=1X$#~}i( z8KkI{phPwaY6yxNF1*u|rlVzQNu&xteL~bkT%!xq4J*`_#;xxd|FFU51NX9d&fHar zB#q0xhy;BS^QnfT7QsPf&BG0C1uM^_zFbKr5kfK^Tn_3zYI)44gMLz8pKb;vM@#75 z6u#t2p5~G<-+1-pt~Rt3eYo&pugUtUfb_g(!(qBAB*`~X2TF5&*D{k61?O`!l7i%b z^YfUl%!9l74F!<}D=e`$9=c1q^3URHFY^l8hnoV|I^z);(?ipC**KsUaClJ!gRlR(BUeT~VBLAa@3l|1dss(<+KMHv=DbL-3 zw0ng>ofa@o9^|GU$B%1_Ar(E$yGQ|Y((DX4x==@i%~dE9a=rN8n`^{HgaU%?cY_?HGoC}VI|O?oNhZkUc+E*5~59(6v=Y#&i6m9{1nfv{rOAZW)Hr-^v@brQ+m zHV7#@-&Z3T;8F~A>IHu)8>hh??R?qr(0#gK1D5tC8pB#Lx4i_nK> z3Ain4r^9ssG@hVXkY^4Ooz!t2lt+qy(uzAMhHf2YgbLFr5PxJTc#sZN&0?B=Ip zga}Fvrk}iOT+IgK6F(FvYfpE}qny4;SEEn`3aSP5=|>b+FljziS7OZ3=VwP0Y5orR z!tjmMIhT#oz`xB{jSR|YkO4%wn}ps^EKsE_!^ z0qpQmE2J=;BIK24UI?F%PDvm=?0XD4bHRAlO877>$~jov=CJYIjGO?dc z!))Ev&K>mxF_h9#q~K*b3xm8LiUii!7=ns1Pc%@;{u*{gNy$o2*%HQ;#--8)^1?y6jV+6dv zE=m&4Vr0&i$xl0}o6j!Mz8$dOcSPdpiC~V}N1$_7(xNO`sByZy2s8O0UkSwc>6TO* zSHaF@>m0L$qRfM|1sC_z!kG~T@w>x8cZ)Ipsl|UM!z}1|6DB?S;t*c5 zBN+ukM@9wK4exDNN8`tJWWokeSRY|fowDO}?7Eaq(+gDZsI>LrrDgfb78+>gS|2V6 z36?W`DvKSuW!EbUof`CQO0sgG`4nsbkxHb?#N@nD(DofZ#2qfJ;E6x1Q+zp!b&or( zob4Y$gn7#6@6+<>v4PUmJ`-xQI@+Y~a0FHev175RC|d!F3xB183oDDi@`{No|C}G! zh%`5!mwlJiA|8umq9dJ`-i2ut2W}fimM3IaD$RmTY*qv2LLvxNUV^H51#!q3Hx+C? zj`#IRdpBD-g^XeH$d?*^WTYHuK#3Z;CVLK6pldv;5Y!gbmI5o~nxk&MDBzKh9rz#EDT0Lz=!R=3*hmbs5AgpfB4iOQr4R$ths)2+*aKVr>jiD2Z~xWUzer>w?<{X?q|B;Ok2H);ip`--Rxi(j8HH zde|PSR2H&~!vcukb-%hYW~@Z?fFGWjV4)_Vw}?)g6_QY z$Y)G6#?#cn2v5#X(4jKcl%y+VS`mNl@plyK9r*NLi z_m0QO9J{BBBuRCn+jg}Pn(CHsb%}jEq=c)|Jt;48z{*#Rr>t+mrkRo-j-Dozeig+> z_$mb*mBqGQ%ex9Tu4~WuZnx@kNOPBlMhF(K!#Q)E59PRF0b)daHFp3;3Ay&7X(fnY z3vCHu{bN6in=K#X$l-%Ksg zm!lYv05$?&LCsmP5JXes9!EOJXwHDJpwOQ;Qyr!kuI zy?O10Pokr_`xr2VCc3MGt>AL<{%iru!klTI96&tLCK8^CXS(=P(`*eOZ35>X0jz%& z`U;pg-=7@tXuT zsdUK{hDSlNe8p>Il6~@&DLe&+jkC24R=)8DJuy!bY-Ied9hw@O$=Koev14f}2k%zL zTLfQ!V-1WPIur&E9ZaP}J62ex6|cPpO-(H@ecDv$-mOB)?#)|Z7;dX9Oz`5R#fuk{ zLBF~4=8}*l%1Oro4d}i0`by|lQ4SL(P9)`IciL#f->_*5yt8#H31+;<0>dJS)x->z z3vtIA`u6TW0NuNCI%rN}P)!ZpZ;oajP~rF!@Txpiz;gZ7H#86(@p7ix@#Co{i?l^t z-d_I}Y}~jRPMm!r^yyPg7cZfJ+p~8MtbBbn3>{hnwYB4A;8X&;cJC$woLCq5BV|k@ zL^P0D2IIz#qpO6Kch+xM&zFZ)lu`X)cvKoS0|&u`+FH8h&W$3`^i4$t96Wf4j7`?n z?In9)Q>RXKchF#5C)BeHHg4Vmn>X+36RH3JAOJ~3K~!&ps>+^n;ZPZj966GVQgXUn zpGphG3k@GGTe<=&D!Rao>C@?UOBCcp_bz2*sB^={O|Wn8ei|LoXn`ysVEwegz<~py zwzk$OCNyS={NA;^941em!W{vX8rTWw#zq~NzrG4~?c70iHf-onm^^6$jZnE<+(E%K zkq_3cTL(=?n&E_5GlEXa-hKOE{f13YJ8leASL5x6-h7UR`A3yUF(@j#0HN2W! z$Df)X4@|k!vpqX%{8HiUFGEwwE^gYqaIyH-Kbe;;pUKC^)3O@#@nljS{W%PplV(%q zZDcmRt*t%VzppO4{E92HsZ(cVtKV2lX0)4|nzM%=c{Cd~d_?x?Yd=qMFpcKsrtF3r z{w13*X?nI{<0dhPpJfLR9?VWV>)hbDO`0+_8#`uP_V|JY&fL2` ze}Dh|+02=<$h`OV9XqwAoXP85@9xTOzx~JA3A5&Ag9Z)HYHCJgGiIEa-F(Z}vUTg; zCfvxZbz@`J+}M;|@_~_6}RO;+E~K=~qFF%IHS zrn0HdGI~c?wtPi4W7eGPD__1bJJfKP+*+EsJm2~5t=X{Q!?Uk_O#*Le({@L_+BQe$s&%c~~@B^1+y?YO! zodRX$-LliqI3xT0?;ptO>l=u_@QLB;57uYj`ZvUXR5pI>v~1w; z^G37vU-;6E+32z3vx;t2S!K_@+4%7jvs-TYTDE@u21)~Y7R|3CAirO8?e*F0*(YUx z`tx77B+@2-d+&YOwCS_5M;_raa^1I3Iot6%2iKO1n;^H4^3Rhi#biyKe(>Fi@Wt@y zj9)5`j`B_YsEqQgwYjAg*1ffXObInNw~#4poa@DFEibv`V%UGM zo=mvkci;UmbVv<+;L=N=zOD|2j~K@D=YsFS19kBBy0x%z^ESG%j*PRlw?lpXL0J3d zThLH{M2zC`vW7u`u^mo7 z<2;x;X(ENeJIW_bno9Syt0iL`VJv!K30!l{HL!ZkN;vb(bKr#8b7A|=&2azk?t_KT zJ`4BWdmov&Z>Vpf-g#Tr4m)@5gsodP!nx;N1kM6Xg zC8ILL3oq>YMm{{8!qMc_aF>90_l z9fgm5^fI!xJ8akxsOZ|&nS{rSrdF+74Gkk($P76yYT$?f+riGAyWopox)~n+>jN-l z%5=Eu%1=UBX%|@Z@*=qHwp(Gt=FM=|kMDr$-o0fTIF96w!nW-@VCm9jaQhv1(d~eP z1`Z^?-LiEHyuNZ3?B2as_)8c}wgRWtZ{uFRb&JEeJtt+pmpn$=63!Z%ne)a3S;iS1|z^{J&A24acc=F$L#mC|HAKp&a&CF5(7pE{`0n?<4JXW)28RzHh8u4FD*WQ-KY=BSm%{0%o zk(SF*(Y2herp22HeLb>Yw{8{Cv#LKd9jS-gZo3`Ejh_f-oHn1&|_`cMX&Hf@1t7d{8mrk@1eyLE*X z%a+2vy>-yDsypG1Yd?7N;5Ao&lJMNUcR#FJy&4+!*TE0Ie=C%WX?es2r<-VMG6Pap zRn=AA6nRA%T?PHuhaVxuao#x>!JR+;AxxZzw^9OZSib>oxaq6#zylA#>GMyAYp=bE z%)29C+w0z=J5*I22dh`DgWG@nbGY*d-zA#i6j)VNZ>Xp!TpLnwG9_yA#RRa*hm@kR zkmuf!9|_)szZ1yvZ9{ZchS_k%aERq7(F0#(n%d#u=x2^%D1GEJkPa!09fI-4SIR*4 z0g9rbz1-q1z7AQA;?pQvNDG|}XP{#(Ez;i6#9=FyDRJ}m*J~K^(~|{abP@eZOQ;t* zc-Sy_W${vIJkkPNw(NklYu|#i&NvNl1JAN$uMv(fE?Ptv$IP8OhvO=}Xq%wS|94S) zP$e`9IdI@0t)DbCHbGl!Gc?p6q#icjr+l!!o-WMsbLl8tkHW59JK*)#-++~?-h>se zzX7i;|ge*T|?YoA`d zN#SWZbWZv&k3Is8M~=Y1{L5EJaiFq5Wq?sH&`F z6YzAuHm^USV8c7Su?*;k^u`OF@NO9Ft>b<6s0^B#u}*mB5nj8C)`oZO*a^FK?WRkJ zHg4PmhYuZ*ZP%;>R=%+kp8DHUaKem};l>+oAjN@oS=FNwK6T|M;J*9rrO_sioXGSz zS(nCjildOVw?hxPE2Vq)9x!6qaC%o9kp6V>lJFLGTGp@M02g2QUO4-l)8O@0tKg+Y zOPnyKO#^Lhls_tnBZm*e(Y97v2RU@;FxB_rBZui*>lW+1y|o=O9Er$g4^*5D4Gr+f z7E(sz#*Bu$fB9>8 z`kCjUTi348+}I3l%}1!*F?1w6JC<=Br;!I3Cr`L5pnv=;3NaoXg^%(;$SX;p%sP>- zj$RcfG4;rP@hBrM7{}2?;XIV0b{rJG@X%jwC8;K~+O7bfFmC*<3M4K^aZnmyTAH4X z&kdeNX}V#6+}Xk=UGOHovg$t7FmLWj@aSJ3h0X801B;d|gHmXP?|kQ5aMO*qz{`u5 zKudEQtXQ!EdiU)I(`HPU8{(9KW#N~;t)AB@2;3QjcYV-y86N2gPE=2NF%fRl?b;ol zd}<*qd3h-<-13HpQrLg6juxzQYQclh5QSk&YZFYYod6?7kA~m>;eX)^*MAnax9xDvd;rw&Xh8{Rgh{@yq_T9QdW7841=Xbw@x7M#CCHBAf{}HNt_lJ|_ zog@@N{P`{l-0-kq!DBFBKwr4>%8$dIy}RMApZzC1`uLM@;rq^)b|yP6%`KFueAQgN zT1TeY0d1eCJg}qVw%hU!D!fs1)7EX!yUzfaJhhfOJ9vjW(h1WaIeZw59z7biZr@JI zLX`&smIXTsH{bGQxaQi=!8gA7O_+P)V>F7znSa(HRs3siPH@{rmS=3?PV z6jFhEv;?|#D~I=9`hIxmq5pyV?*CudvTZZ;>QxC}yzX;w-SuCAw;LKfk7~NYGi;BF zr}yY5X0!1O3SI}yy<~Hmy#(MFzqlKkjvR*e*26HUW-#1v(=Bl3nWxD#S7Pg_oUx&N zWxFt*yK$ot@xypWTbp3isA2G)^Ui@6o_iX8_`@H<2S55@=v7tatDI<|0)|V3qX66z ztGCQ?ugq^5M!;#CtQ4SkpK2IAdISs^GKlJ~vWl;o)wPt0@~%))T8{hls7$zv?X^`a z;kqw=8MbfR0qxE8P+L0%rcRg$wUcXkYc<_yiRUZY;fV!L!9#!g3mmE63pF((;cH*L z1TGOBo6jO+9i=_J1LxA{?c{polM$T{*OO+8$OA4Q5xPH^tN_F4WT)Tjy z*OsPcx{~&$n{I>~Z}t*a=J^sd(TSv<3oRhH`lC% z88c^+->f;a;Me!u13&#gKZipN4RG42CqsF8DKs^-0+h@3r7~rud+@a+)Sg9%;U!mu zgWRm=WWL~oy;Dk~xfxDBZ64h9vwx@QgrjXoVc&s$FmKN3bZ57{DUQnHWU(-@e4)v8 z6fE@(hhWZ$Ghy1y6X2J3{}1d?*|^u%D(hVg|RR# zUNZ_cyd!+y{sXk=T3uaDbi*=Wxm%m@{`fBN=}%n+BZdv7Ev48~oqx)F=-$1Y7UfkS z#o%bj7(qc-&Y6IE}aNheBvtj$z6AmQaE&^87g{oRhJ1u(90lyxhI&wuV(sGV2~w|(z6IB;Me%$YYEdiAQJX*C=r z;TC7yPW$5G#jtDVHdwo^Cw%C#%Scgd*t8ky4jzVw{`3f3bJgWEHAm|hnj4MSIB%RL z!%;AIwmi+LgF~cLp~tuERg`ywAvJ^G)g?>ejn(Vm>@!cLsX{C_^4zv}-huURZ-A5M z&E+#7rW&zhbm;J5sH@u#S6y{E{Pp37;nrKf3**Pv(qetvQ67Ed$qQ>o%z_oPoq^8E zkj_A?42~5#g?l6yli{txO!-IP($FpZ+%-@~{`v8QKXr|eBB1YKg#^(aihd(dpTsC7 z>*s*FDIJoA07Gd=?a`)U#(8+0(_m3VGEwOaja>P3WFx_9U+Bfe%DYxTMRzQYWomi%u29|;d%a=80fkJx=;`j(_6+*>?F}FM=*M9D zrVY^A(gvTn{GX{VaH^ubTe)LU?U`S2!9PJ|btU}h&O6|hrOTmfMORwG*tBIUeEl2W zg3ny@Svo_(3$Q#Y!8M2SuHE4BkAD=dzy4bI+_j&E^UpmCx|AM;CR8kRn;jEAShq2J ziSA`3WsHX?CFOHex;)C`6V;#j%%@?_?Ah?f8>^t{$RQ}l9d2%JJ)EP)*HY;}i?18; zXed&I(1oTa5l~riJ^Ql>xUpf(m@zbxTDEKv{Oo7HfbBbW!HntC;Ip6kG)$j58IB%p zfu22kLuIcj*Ioi46HAb;RG*~5=M z4pqIXY3JIG9Xnyqp8atAz=5>B_1GhiLBpZLG%}(QnvfIYV>wizpwf!(59xvzELC)) z%^B2LIeL^j5WRat90x!ip8kNg?A%#Z^RSfmlUllw8wnyh)Y>bsWkz z`)*Z;*dNj>@rS$N%0_9P~+zEfEeK^MtWe z903xA;bN~MK?uB9kZ-q>ivjaX;goVqK{8m%QAX%OYNnRnfk9dXXewvy*x|6^mFJ;P zzd>-)oH-O{=)i$6eDGjczI+)B9z25&R>>)1B^NfnJ-hcnX=%BiGExx5fr13L;^H=7 zGTvuUrDRHY3vEkd9W)$lAVCG~OrN&a7N|dP09U3ty?FaXVuak%)I_Jd4d z_rubcUV=$eCc~u36DUkWeLd{oQ%7qV2x?yAtTRu8tFQhv+NAQIRb|dHNX*CsAZw3#cFKC4FgB1XO4J|8Z{iQ{p@F8)7H(fZSzKGI?_buU2rzV z(L$aLhZ^8$%Ry*vY@%;nPf?|g`J;ksIIs(TcGu5g(aSH;Muxh&eK2M6WVrIGPtu%z z+_-Mb2|`qZaj*{dty```Z#yu4@;OspLT+js7OmtS5C`}gjIQ|6yZ_i!V=G~JVB z&~l^^4%aupzJ2?NKIfl*E?jcyrEu>(zoBi^SAOE-j9YdT7A{-}Pd~N*-uM1X;3s!{ zAF6s*(T=va*1rum-E<2)`^@9;$3H&|AOGlwXd^|bTr=C;(geG9zDv98&{h?LcC8qi z+gf1%o_FC;%|J&WZhYlWq=4L+7dh*G0;JWLtgKvNHtI*!k1Dc!sh&-D*BLr>SVt(`;eB~>gRHa!Wr2IW7WAK-&1mRZ4I3@1Bb>ZGcw5-z;xLONxA#{5&EfB$L{#@M@abLd@4V91am zbedc32x%`FM-cdq+fRoL84AY@I8N+S0c0pZ-J*U8^sK6c+SvPpzdXX2 z(W9WfHG?u^aso#ZI9>LyH{S#`H8t?igAc-kfBX|PHMhcX{rkbySAPz!zy5PDV)!s< zZsn<{qtFHV_3IDg#!i6h-qnPA1qyPy%uCl77(1P~;tOMWvjFo``Jo_5N~@QYvk z2mJJ|pTgpom%!pzmO!8CzHt7z=aIr5Icg+rp~W_eTY*u54m|#Nm^^th3?4Fs=+n1v zANax-uY-*n*29uTOW>1N{4?Qwu%RB7tylrmr_Y4XTzwUc965sWME;yTYZhF3$)&Jq z;|4l=#Or3I?n+jSKXm9|sP5g5&gF2&f_v>ep~pMpMvfc~V@Hl8Jla~&s2gt_8C)}% z&T)(zI~JZ?@C5w#AN~MGTiWP^`As+90-w6_a;OsR1z-mQ;i zl44LSp8|!IP>ecARCc7~M8D8|38kg9MRU=MOJMx?aWH9eEiJTS_?^3U!{V0~!?fvB zVf5&cw4jR>%2PvS)RSDcd^uf8G<)_5)JSLqB6(nA!a41iUR(@4D|^D66HgFx;eJ{M z17fdq?b`Ju@bLg1*E3_ji?Xd|0RB~W+ZAS_$9oP^Qj$&<*0 zMr(T;RFqf1n{Tdz_3JmnoH-}JamO78t*tGDGn(aCykrTC95DhWPMSbTvMCgyMQJH) z+qNB6zOe>s$B%%)>$+!gES&zfsoO9!NCI!Fm1+E=-H#Y z6Oe1ytfO6M$Xkdr?$%oK<~k@Z>jt&8qlvz_u7gSr722-ddtmkIH(|txp)h95Xri-r zBybDz8>?5-7G6w`IwrKc4|x&Kw3N~I@K=|=4*mM{fvGgj#_MP*wAF^%>NnTHyL)y) zdrKP(9XtdkOyDygYMfF>RfzktrLU3FJZavE)bUWB-@JJ%Y}~L3CQX?HH8lfyyS6k< z>hOr%BCd$qclfRRQ`qKx>j^=_6qS1tE>G~=FfpXkiT%=YsPNr}x9QMZG2BQOc(+{H ztI9)j)b{6l-JKbJ6|Qj*M9PCSrE!nL=OGz~%d1%Oi}N&4tOA4d6K+HY%G2a-l?NBB zUu)S3ruG8YS7)eyXhOBplBc1gA^blA%=?Km?67{F4lVIN6@4!NLJd=P?cqc0h zdjy<^N1(=MMjWnQH4B3mPc!fiCR8|ReHN9aEiVFxvG;!z-UWj5*GL`6x3?GkPTk4(o(Y1 z^l8GpJOc0hlQl+K7h(J{4eflOWrQ-NfhYw0;hKgm7lM{u>w|t`FHF;8%g@sKGN83O zAD=r9K~#+u8yGG;vfg3S<#b{g7qqeQ3N0`N60T%29UD0d zIcg*(d2A%KBMAi;?cCu;MaqSCzeo=p4~e1aiLx#{{YB2G1|@C@?(X9C1ACcNtUPo< znB(9gytOo|^kPMXUv#27x>ZqWk7ZYrC>V#PgfKl#N9c{Gqw$HO1jL`quX&2#uzVtH zhi<%1hcs%Z#bX?W;MxY^EOBs~E7k$h4h5(Jo}Xbe_DnO*O%9BR^5D3bE-I%oH)W~E zb1*n|3P>0eaGV3|G=0qYC5E91g3;pjI4;3x8m79Z0>9F^9pkg@E@bLe3$ z>eBXJ9NEhBrb=8)$Cib8O=?2$QwzX21<2FcL>{w{stckJ& zEnXZoipx}GH_tMXANu=sGmTGI9qV}zsY9I_vw3hnG6n2%=`6(bEWp>K7yHHTao&0E;^_;oPn*8HGtY+paeDTfZCh#W=g{I< z5cLceA?5t(e@L7n2o@u-bMqw#Ag=;aY2-0O9)oc2OBlgz1jq>+;bHR%@7y;2_~Lpf z1wq2Frh$+f{&Qx#y(`y=`qQej@Kty~k{hMQv$W+mcejUxQGCg_2(AtSLCz5fT|7-k zYi(gTOq*ttyt7Hl2;P|fE<&jr5E3nubsZ$?Mv!iUf(lz2e8_Gm3c)2;oC@VQDt%u6 z@GfbdKp-WD0@Za2M6ha=Nmcpig^HtN2=jJjB)Ygt4Wk6KmT#$SDw(+hNR>-L895PF z0IFak;5_uJu#PO>*_p+ZOtS6B#g`}Hog)VM&Gtikd@|dDCaa|l+kFKnR zgv9Wcp<-HDCXaF8UKtDQ6mDL)c|*oLT_bXZqL@ZwkXBoW$wqGGj=46aWZ0{eH3v&W z;y>~?c-myei3MrInDkE)aCtJ5@{S(s@8g7}QFo6kz6kYPqbQX%5(Pdj&4Hy&a2z9< zZ2j3xIh?6S_ZB)(9!Ah1ecT8XGc+v2*~o|v-$aQ7oA_eU}1agu9 z4@LNyDosL48E9S|<{3edm!>P9RNpGR6C;zq7gFU@zVNavQbbxl^Ufe)N@%ODAj=%V z?h(={L2E%PJt(lR(NvUxND84a%C8hBEalr_W#YxcS>xq_;%@V{;ZqD0gDHs<*N9U= z3_(6Fr^~}^vt@T~xRjDi1=?u`kCT+$P)AMK%XR2-3f zD7_U2>A44u-6~9>7(2(fX?xf35i+(;jh~iF-F>o>TY^8hF>x66&E-!KU?|+Vu3Rvt zqiFKflv2P$OgM+Tt2^WyQyvkY^53TE14V3*s6>mTbELO`mqW2&IsLf!`?3GIKh-a<``yv*@W{q zodv-ICwI7U3i9N_sN_Hkb+I+~F5oyf@UhGMxObhgUY2#*+;v|M28ZOiOm zQuAj4q1btgZn22Y#7kG_4~2$_6LatHzL1rhpbqh+O?g?U2NKJ`5& zQos=I)fJ7QlY}jRM1`i_V<_gAg1C$ptP&{BBsR}<+4JM31%n6gOX$##g@FB$zx?sL ziKD)>@LoV#6EKBI=$0x6O>Gn@g!QxiD@x1wNzszPJ@Lep2nw+d7F#$+PbGz9r<5^4+`-UtZn_tNRp}|4-s*r zI?E}1s5nd@nQkP~(u>U?UFsNI+L|mW^|-J+!m^<4T;F3T)`k@Be~F;7R3+zNvas@g3dLKzEp1hdkk#2VP_4AS=%xT}e~ja`Qm{4)RZdre_skN9E`U zR8UZgj1O`BX;6ozSzvZW){@xiuk89z185qB3t8avukB&E5hgT4mrQ>4wv!OxWzr1YRIJvp z$=AM8rXlZg{$VW^;I31|`jM#L7;JniM`FLcaIp;Xd=pJ$CGep5v70=dyWwH?t@*oH z;w4X|v4;2b59#c{)N=uS-Bykq$YUN0fdD85p4*I5NZ=$C^HYezV0u9Xb)p=d0-KGm z1@DpSdKb&u3>RZ4MiY!-f9h5cC<027{zbiy!k~pkF@f^wnab3<`$SWGlcWXVTy4X$WzNc@-bU;}?RhFN$erz2c%5lB~c>{llm>0@pQyPv0mSWm}`zIGUC* zk$C~GI^^tt8f20^SsYgY^>ZmjJjdbSTy||bSm*;b00V-6@gf5+EiWR3R;BsF9urS6wNI72<`tRYeqZ; z>y9pp3-4G{HVIJHlD8*;64{sE@`=qSRshyLAG~4-;zm44yl2Y8ZV|0DZeE+h;L&tW zy6vUo#}M$puRt5XgpO*|R(gSaF62YrK%>0l%OIb=eq!5){8l}tN4#gFO4LwdILT7pj9C_aao|HWe1%;^oc8gg_z8fyP(~ z9xH@t2sT*OBIR{p+BDyKX#f|D!ox5UM;$D#SSfOkh$N+w>&O1%bdQa8$f zrgvAUOmlFQo@9tdVK0~53mS?~+x_8mg#o*#utkTP|QZoPv-XC~eKa(BCZ{n{+!O z0~c04{8UvsqQy5qVJ9>T_=tRy-`cSXe4_Yq2cW>;3hPAPe~&U?QWu6LTx0oG5Xu7w zPlrgAU3oJFL0(RAXu0{v3Y6X0$)uG?*7ElM1yP&$cXW@=8~^|S07*qoM6N<$f-ZN^ Avj6}9 literal 0 HcmV?d00001 diff --git a/docs/setup/configuration.md b/docs/setup/configuration.md new file mode 100644 index 0000000..aec2b8d --- /dev/null +++ b/docs/setup/configuration.md @@ -0,0 +1,45 @@ +# Configuration + +All configuration is via environment variables. + +| Variable | Description | Default | Required | +|----------|-------------|---------|----------| +| `DATABASE_URL` | PostgreSQL connection string | `postgresql+asyncpg://localhost:5432/taskowl` | Yes | +| `CELERY_BROKER_URL` | Celery broker URL (RabbitMQ, Redis, etc.) | `amqp://guest:guest@localhost:5672//` | Yes | +| `TASKOWL_HOST` | FastAPI server host | `0.0.0.0` | No | +| `TASKOWL_PORT` | FastAPI server port | `8000` | No | +| `MCP_HOST` | MCP server host | `0.0.0.0` | No | +| `MCP_PORT` | MCP server port | `8001` | No | +| `LOG_LEVEL` | Logging level (DEBUG, INFO, WARNING, ERROR) | `INFO` | No | +| `API_KEY` | API key for authentication (optional) | None (disabled) | No | +| `ORPHAN_GRACE_SECONDS` | Wait after task started before flagging as orphan | `60` | No | +| `WORKER_OFFLINE_TIMEOUT_SECONDS` | No heartbeat for this long means worker is offline | `30` | No | +| `ALERT_WEBHOOK_URL` | Slack webhook URL to post alerts to (disabled if unset) | None | No | +| `ALERT_ON_TASK_FAILED` | Enable task-failed alerts (legacy; see Automations) | `true` | No | +| `ALERT_ON_WORKER_OFFLINE` | Enable worker-offline alerts (legacy; see Automations) | `true` | No | +| `ALERT_SLOW_TASK_SECONDS` | Alert when a succeeded task exceeds this runtime | None | No | +| `ALERT_WORKER_CHECK_SECONDS` | Interval for the periodic stale-worker check | `30` | No | +| `AUTOMATION_CHECK_SECONDS` | Interval for the periodic automation evaluation loop | `5` | No | + +## Brokers + +taskowl works with any Celery/kombu broker via `CELERY_BROKER_URL`: + +```bash +export CELERY_BROKER_URL="amqp://guest:guest@localhost:5672//" # RabbitMQ / LavinMQ +export CELERY_BROKER_URL="redis://localhost:6379/0" # Redis +``` + +## Authentication + +Optional API key authentication protects the REST API and MCP server. Set +`API_KEY` to enable it; all requests must then include +`Authorization: Bearer `. + +```bash +export API_KEY="your-secret-key-here" +curl -H "Authorization: Bearer your-secret-key-here" http://localhost:8000/api/tasks +``` + +When authentication is disabled, all endpoints are open. `/health`, `/`, and +`/metrics` remain open regardless. \ No newline at end of file diff --git a/docs/setup/index.md b/docs/setup/index.md new file mode 100644 index 0000000..967a51a --- /dev/null +++ b/docs/setup/index.md @@ -0,0 +1,11 @@ +# Setup + +taskowl runs as three separate processes that share a PostgreSQL database and a +Celery broker: + +- **API** — FastAPI REST server (default port `8000`) +- **Consumer** — captures Celery events from the broker and stores them +- **MCP** — MCP server exposing the tools to LLMs (default port `8001`) + +Follow the [Installation](installation.md) guide to get started, then read +[Configuration](configuration.md) for the full list of environment variables. \ No newline at end of file diff --git a/docs/setup/installation.md b/docs/setup/installation.md new file mode 100644 index 0000000..ab7e8b2 --- /dev/null +++ b/docs/setup/installation.md @@ -0,0 +1,61 @@ +# Installation + +## Prerequisites + +- Python 3.14+ +- PostgreSQL 14+ +- A Celery broker (RabbitMQ, LavinMQ, Redis, ...) +- [uv](https://github.com/astral-sh/uv) + +## Install and migrate + +```bash +git clone https://github.com/KalvadTech/taskowl.git +cd taskowl +make install + +export DATABASE_URL="postgresql+asyncpg://user:pass@localhost:5432/taskowl" +export CELERY_BROKER_URL="amqp://guest:guest@localhost:5672//" + +make migrate +``` + +## Run the three processes + +Open three terminals: + +```bash +make api # REST API on :8000 +make consume # Celery event consumer +make mcp # MCP server on :8001 +``` + +## Docker Compose + +taskowl ships a `docker-compose.yml` that runs the API, consumer, and MCP +server alongside PostgreSQL and RabbitMQ: + +```bash +docker compose up --build +``` + +The API is on `http://localhost:8000`, the MCP server on +`http://localhost:8001/mcp`. + +## Verify it's working + +1. Confirm the consumer connected to the broker: + + ```bash + make consume 2>&1 | grep "Connected to Celery broker" + ``` + +2. Check the API health endpoint: + + ```bash + curl http://localhost:8000/health + # {"status":"ok"} + ``` + +3. Make sure your [Celery app emits events](../usage/celery-app.md) — without them + taskowl sees nothing. \ No newline at end of file diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md new file mode 100644 index 0000000..be2170c --- /dev/null +++ b/docs/troubleshooting.md @@ -0,0 +1,45 @@ +# Troubleshooting + +## Worker not appearing / no events in the database + +1. Verify workers emit events — start with `-E` or set `worker_send_task_events`. +2. Check the consumer connected: + + ```bash + make consume 2>&1 | grep "Connected to Celery broker" + ``` + +3. Verify events reach the broker: + + ```bash + celery -A your_app events --dump + ``` + +4. Check event counts in the database: + + ```sql + SELECT COUNT(*) FROM task_events; + SELECT COUNT(*) FROM worker_events; + ``` + +## Database connection errors + +- `pg_isready` to confirm PostgreSQL is up. +- Check `DATABASE_URL` format: `postgresql+asyncpg://user:pass@host:port/dbname`. +- Verify the role has access to the database. + +## Broker connection errors + +- `rabbitmqctl status` (or your broker's health check) to confirm it's running. +- Check `CELERY_BROKER_URL` format and credentials. + +## Port already in use + +- API: `lsof -i :8000` / MCP: `lsof -i :8001` +- Kill the offending process: `kill $(lsof -t -i :8001)` + +## Getting help + +Open an issue with the error message, environment details, steps to reproduce, +and relevant (sanitized) logs: +https://github.com/KalvadTech/taskowl/issues \ No newline at end of file diff --git a/docs/usage/automations.md b/docs/usage/automations.md new file mode 100644 index 0000000..d8b460a --- /dev/null +++ b/docs/usage/automations.md @@ -0,0 +1,173 @@ +# Automations + +Automations are declarative **trigger → conditions → actions** definitions that +drive workflow automation — a superset of the original env-var alerts. They are +evaluated by the consumer process, managed via the `/api/automations` endpoints, +and exposed as the `*_automation` MCP tools. + +## How evaluation works + +When the consumer receives an event, it loads every **enabled** event automation +whose `event_type` matches, evaluates the automation's `conditions` against the +event, and — if they all pass — fires its `actions`. Every evaluation is +recorded in the append-only `automation_runs` log (metadata only; args, kwargs, +results, and tracebacks are never stored). + +Periodic automations run on a schedule instead, evaluated by the consumer's +periodic loop (`AUTOMATION_CHECK_SECONDS`, default 5). + +## Anatomy of an automation + +```json +{ + "name": "alert-on-failure", + "enabled": true, + "trigger_type": "event", + "event_type": "task-failed", + "conditions": [{"field": "name", "op": "eq", "value": "payments.charge"}], + "actions": [{"type": "log"}], + "cooldown_seconds": null, + "max_runs_per_window": null, + "window_seconds": null, + "circuit_breaker": null +} +``` + +## Creating an automation + +```bash +curl -X POST http://localhost:8000/api/automations \ + -H "Authorization: Bearer $API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "alert-on-failure", + "trigger_type": "event", + "event_type": "task-failed", + "conditions": [{"field": "name", "op": "eq", "value": "payments.charge"}], + "actions": [{"type": "slack_webhook", "webhook_url": "https://hooks.slack.com/..."}] + }' +``` + +## Triggers + +| `trigger_type` | Required fields | Fires on | +|---|---|---| +| `event` | `event_type` | A matching Celery event (`task-failed`, `task-succeeded`, `worker-offline`, ...) | +| `periodic` | `schedule_seconds` | A schedule; conditions evaluate against an empty event context | + +## Conditions + +Conditions are `{field, op, value}` triples evaluated against the event. Field +paths support dots (e.g. `request.id`). All conditions must pass. + +| Op | Behavior | +|---|---| +| `eq` | Field equals value | +| `neq` | Field does not equal value | +| `gt` / `gte` | Field greater than / greater-or-equal (numeric) | +| `lt` / `lte` | Field less than / less-or-equal (numeric) | +| `contains` | String contains value, or list/dict contains value | +| `matches` | Field (stringified) matches a regex | +| `in` | Field is in a list | +| `exists` | Field is present (non-null) | + +Example — only alert for retried failures of one task on the high queue: + +```json +{ + "conditions": [ + {"field": "name", "op": "eq", "value": "payments.charge"}, + {"field": "retries", "op": "gte", "value": 1}, + {"field": "queue", "op": "in", "value": ["high", "critical"]} + ] +} +``` + +## Actions + +| Type | Parameters | +|---|---| +| `log` | `level`, `message` | +| `slack_webhook` | `webhook_url` (or `ALERT_WEBHOOK_URL`), `text`, `fields` (dict of `{label: value}`) | +| `webhook` | `url`, `payload` (JSON) | +| `retry_task` | `task_id` (defaults to event `uuid`) | +| `execute_task` | `name`, `args`, `kwargs`, `queue`, `countdown`, `eta`, `expires`, `priority` | +| `revoke_task` | `task_id` (defaults to event `uuid`), `terminate` | +| `check_workers_offline` | `webhook_url` — scan for stale workers and alert | + +Action params support **`{event.field}` interpolation** — the value is resolved +from the triggering event at fire time: + +```json +{ + "type": "webhook", + "url": "https://example.com/hooks", + "payload": {"task_id": "{event.uuid}", "task_name": "{event.name}"} +} +``` + +## Safety knobs + +Prevent alert/action storms: + +- **`cooldown_seconds`** — after firing, wait at least this long before firing again. +- **`max_runs_per_window` + `window_seconds`** — fire at most `max_runs_per_window` + times per `window_seconds`. +- **`circuit_breaker`** — `{"failure_threshold": N, "window_seconds": W}`; skip + actions (`circuit_open`) once the automation has fired N times within W + seconds, and auto-close once the window rolls past. + +Skipped evaluations are still recorded in `automation_runs` with a +`details.skipped` reason: `"cooldown"`, `"rate_limited"`, or `"circuit_open"`. + +## Observability + +- **Run history**: `GET /api/automations/{id}/runs` / `get_automation_runs`. +- **Status + circuit state**: `GET /api/automations/{id}/status` / + `get_automation_status` returns the automation, its latest run, and whether + the circuit is `open` or `closed`. +- **Prometheus**: `taskowl_automation_fired_total` and + `taskowl_automation_skipped_total` counters. + +## Worked example: retry with circuit breaker + +1. Retry `payments.charge` on failure, but never more than twice per hour and + pause entirely if it fails 3 times within 5 minutes: + +```json +{ + "name": "retry-payments", + "trigger_type": "event", + "event_type": "task-failed", + "conditions": [{"field": "name", "op": "eq", "value": "payments.charge"}], + "actions": [{"type": "execute_task", "name": "payments.charge", "countdown": 30}], + "max_runs_per_window": 2, + "window_seconds": 3600, + "circuit_breaker": {"failure_threshold": 3, "window_seconds": 300} +} +``` + +2. Tell the team when it finally trips the breaker: + +```json +{ + "name": "payments-breaker-alert", + "trigger_type": "event", + "event_type": "task-failed", + "conditions": [{"field": "name", "op": "eq", "value": "payments.charge"}], + "actions": [{ + "type": "slack_webhook", + "webhook_url": "https://hooks.slack.com/...", + "text": "payments.charge is failing repeatedly", + "fields": {"Task": "{event.name}", "Error": "{event.exception}"} + }], + "cooldown_seconds": 300 +} +``` + +## Legacy env-var alerts + +The `ALERT_*` env vars are **deprecated**. On consumer startup they seed the +equivalent built-in automations (`alert-task-failed`, `alert-slow-task`, +`alert-worker-offline`, `alert-worker-offline-sweep`), which are then managed +like any other automation. Prefer defining automations directly. \ No newline at end of file diff --git a/docs/usage/celery-app.md b/docs/usage/celery-app.md new file mode 100644 index 0000000..3d201b6 --- /dev/null +++ b/docs/usage/celery-app.md @@ -0,0 +1,33 @@ +# Configuring your Celery app + +taskowl listens to Celery's **events** stream, which workers emit only if +enabled. Add this to your Celery application so taskowl can see your tasks and +workers: + +```python +# celery_app.py +from celery import Celery + +app = Celery("myapp", broker="amqp://guest:guest@localhost:5672//") + +# Workers emit task/worker events (sent, received, started, succeeded, failed, ...) +app.conf.worker_send_task_events = True + +# Emit a 'task-sent' event when a task is published +app.conf.task_send_sent_event = True + +# How often workers send a heartbeat (default: 2s). Higher values +# increase the worker-offline detection delay. +app.conf.worker_heartbeat_interval = 2 +``` + +Alternatively, start your worker with the `-E` flag, which is equivalent to +`worker_send_task_events = True`: + +```bash +celery -A myapp worker -E --loglevel=info +``` + +!!! note + If events are not enabled, taskowl simply sees nothing — no tasks, no + workers. Enabling events is the one integration required. \ No newline at end of file diff --git a/docs/usage/index.md b/docs/usage/index.md new file mode 100644 index 0000000..422f373 --- /dev/null +++ b/docs/usage/index.md @@ -0,0 +1,49 @@ +# Usage Guide + +This guide walks through everything you can do with taskowl: querying tasks, +managing workers, inspecting queues, and building workflow automations. + +## Available MCP tools + +| Category | Tools | +|---|---| +| **Tasks** | `list_tasks`, `get_task`, `get_task_timeline`, `get_task_chain`, `get_task_summary`, `list_task_types`, `list_orphaned_tasks` | +| **Task actions** | `revoke_task`, `retry_task`, `execute_task` | +| **Workers** | `get_worker_status`, `list_workers`, `get_worker_stats`, `shutdown_worker`, `scale_worker_pool`, `restart_worker_pool`, `get_active_tasks`, `get_scheduled_tasks`, `get_reserved_tasks` | +| **Queues** | `list_queues` | +| **Automations** | `list_automations`, `create_automation`, `get_automation`, `update_automation`, `delete_automation`, `toggle_automation`, `get_automation_runs`, `get_automation_status` | + +**Total: 28 tools** — every tool thin-wraps a REST API endpoint, so anything you +can do via MCP you can also do with `curl` against the API. + +## Example questions + +Once your MCP client is connected, you can ask: + +| Question | Tools used | +|---|---| +| "Show me failed tasks from the last hour" | `list_tasks` | +| "Which task types are running?" | `list_task_types` | +| "Which tasks are orphaned?" | `list_orphaned_tasks` | +| "Show me the timeline for task abc" | `get_task_timeline` | +| "What's the retry chain for task abc?" | `get_task_chain` | +| "What's the task success rate in the last 30 minutes?" | `get_task_summary` | +| "Which workers are online?" | `get_worker_status`, `list_workers` | +| "How many messages are in each queue?" | `list_queues` | +| "Shutdown worker celery@worker1" | `shutdown_worker` | +| "Restart the pool on celery@worker1" | `restart_worker_pool` | +| "What's scheduled to run next?" | `get_scheduled_tasks`, `get_reserved_tasks` | +| "Retry task abc" | `retry_task` | +| "Run myapp.tasks.process now" | `execute_task` | +| "Create an automation that alerts on payment failures" | `create_automation` | + +## Structure + +- [Configuring Celery](celery-app.md) — make taskowl see your tasks and workers +- [MCP Clients](mcp-clients.md) — connect opencode or any MCP client +- [Tasks](tasks.md) — query tasks, filters, timelines, chains, summaries, orphans +- [Task Actions](task-actions.md) — revoke, retry, execute +- [Workers](workers.md) — status, stats, scale, restart, shutdown, scheduled/reserved +- [Queues](queues.md) — broker queue lengths and consumer counts +- [Automations](automations.md) — declarative trigger → conditions → actions engine +- [Metrics](metrics.md) — Prometheus telemetry \ No newline at end of file diff --git a/docs/usage/mcp-clients.md b/docs/usage/mcp-clients.md new file mode 100644 index 0000000..5e85745 --- /dev/null +++ b/docs/usage/mcp-clients.md @@ -0,0 +1,26 @@ +# Connecting MCP clients + +The MCP server runs on `http://localhost:8001/mcp` (Streamable HTTP). + +## opencode + +Add a remote MCP server to your `opencode.json`: + +```json +{ + "mcp": { + "taskowl": { + "type": "remote", + "url": "http://localhost:8001/mcp", + "enabled": true, + "oauth": false + } + } +} +``` + +## Other MCP clients + +Point your MCP client at the Streamable HTTP endpoint `http://localhost:8001/mcp`. +If authentication is enabled, send the taskowl API key as +`Authorization: Bearer ` with each request. \ No newline at end of file diff --git a/docs/usage/metrics.md b/docs/usage/metrics.md new file mode 100644 index 0000000..84bf845 --- /dev/null +++ b/docs/usage/metrics.md @@ -0,0 +1,31 @@ +# Metrics + +taskowl exposes Prometheus metrics at `/metrics` on the API server. + +```bash +curl http://localhost:8000/metrics +``` + +```yaml +scrape_configs: + - job_name: taskowl + metrics_path: /metrics + scrape_interval: 15s + static_configs: + - targets: ["localhost:8000"] +``` + +| Metric | Type | Labels | +|--------|------|--------| +| `taskowl_task_events_total` | Counter | `event_type`, `task_name`, `worker` | +| `taskowl_task_execution_duration_seconds` | Histogram | `task_name` | +| `taskowl_worker_status` | Gauge (1 = online, 0 = offline) | `worker` | +| `taskowl_worker_active_tasks` | Gauge | `worker` | +| `taskowl_worker_processed_total` | Counter | `worker` | +| `taskowl_automation_fired_total` | Counter (automation runs that fired actions) | `automation_id`, `trigger` | +| `taskowl_automation_skipped_total` | Counter (runs skipped by a safety mechanism) | `automation_id`, `reason` | + +!!! warning + `/metrics` is intentionally unauthenticated so Prometheus can scrape it + without the taskowl API key. Only expose it to trusted networks or behind a + reverse proxy. \ No newline at end of file diff --git a/docs/usage/queues.md b/docs/usage/queues.md new file mode 100644 index 0000000..7f5d739 --- /dev/null +++ b/docs/usage/queues.md @@ -0,0 +1,28 @@ +# Queues + +Inspect the Celery broker's queues. Works with any kombu transport (RabbitMQ, +LavinMQ, Redis) via `CELERY_BROKER_URL`. + +## list_queues + +Report per-queue message and consumer counts for the declared queues, plus a +`total_messages` aggregate. Queues are ordered by message count descending. + +```bash +curl -H "Authorization: Bearer $API_KEY" http://localhost:8000/api/queues +``` + +Example response: + +```json +{ + "queues": [ + {"name": "default", "messages": 42, "consumers": 2}, + {"name": "high", "messages": 5, "consumers": 1} + ], + "total_messages": 47 +} +``` + +Uses kombu's passive `queue_declare`, so no broker state is modified. If the +broker is unreachable, the endpoint returns a `502`. \ No newline at end of file diff --git a/docs/usage/task-actions.md b/docs/usage/task-actions.md new file mode 100644 index 0000000..8bede63 --- /dev/null +++ b/docs/usage/task-actions.md @@ -0,0 +1,56 @@ +# Task Actions + +Write operations on tasks. All require authentication (`API_KEY`) and follow +the pattern `actions.py → main.py → mcp/tools.py`. + +## revoke_task + +Revoke (cancel) a task. Optionally terminate it if it is currently running. + +| Parameter | Description | +|---|---| +| `task_id` | UUID of the task to revoke | +| `terminate` | If `true`, terminate the task if it's currently running | + +```bash +curl -X POST -H "Authorization: Bearer $API_KEY" \ + "http://localhost:8000/api/tasks//revoke?terminate=true" +``` + +## retry_task + +Retry a failed, revoked, or orphaned task by creating a new task with the same +parameters. The retry chain is preserved via `root_id`/`parent_id`, so +`get_task_chain` shows the full retry family. + +```bash +curl -X POST -H "Authorization: Bearer $API_KEY" \ + http://localhost:8000/api/tasks//retry +``` + +## execute_task + +Execute a task by name — the Flower "send-task" equivalent. You provide the task +name, args, kwargs, and scheduling options directly; no prior task is needed. + +| Parameter | Description | +|---|---| +| `name` | Task name (e.g. `myapp.tasks.process`) | +| `args` | Positional arguments (JSON array) | +| `kwargs` | Keyword arguments (JSON object) | +| `queue` | Queue to send to (defaults to app default) | +| `countdown` | Seconds to wait before the task runs | +| `eta` | ISO 8601 datetime before which the task should not run | +| `expires` | ISO 8601 datetime after which the task expires | +| `priority` | Queue priority (0-9, broker-dependent) | + +```bash +curl -X POST -H "Authorization: Bearer $API_KEY" \ + -H "Content-Type: application/json" \ + http://localhost:8000/api/tasks/execute \ + -d '{"name": "myapp.tasks.process", "kwargs": {"id": 42}, "queue": "high"}' +``` + +!!! note + `execute_task` does not check task registration — the worker surfaces a + `NotRegistered` error if the name is unknown. \ No newline at end of file diff --git a/docs/usage/tasks.md b/docs/usage/tasks.md new file mode 100644 index 0000000..c13097e --- /dev/null +++ b/docs/usage/tasks.md @@ -0,0 +1,89 @@ +# Tasks + +Query and inspect Celery tasks reconstructed from the append-only event log. + +## list_tasks + +List tasks with optional filters. + +| Parameter | Description | +|---|---| +| `state` | Filter by state (`received`, `started`, `succeeded`, `failed`, `retried`, `revoked`) | +| `name` | Filter by **exact** task name | +| `worker` | Filter by worker hostname | +| `since` | Only tasks created after this datetime (ISO 8601) | +| `search` | Partial, case-insensitive match on the task name | +| `offset` | Number of tasks to skip (pagination) | +| `sort_by` | `timestamp` (default, newest-first), `name`, `state`, `worker` | +| `limit` | Max number of tasks to return (default: 100) | + +```bash +# Failed tasks from the last hour, newest first +curl -H "Authorization: Bearer $API_KEY" \ + "http://localhost:8000/api/tasks?state=failed&since=$(date -u -d '1 hour ago' +%Y-%m-%dT%H:%M:%S)" + +# Search for a task type by partial name +curl -H "Authorization: Bearer $API_KEY" \ + "http://localhost:8000/api/tasks?search=payments" +``` + +## get_task + +Get detailed information about a specific task, including all of its events and +its current state, worker, orphan status, and result. + +```bash +curl -H "Authorization: Bearer $API_KEY" \ + http://localhost:8000/api/tasks/ +``` + +## get_task_timeline + +Get all events for a task in chronological order — the full execution flow +(sent, received, started, succeeded/failed, ...). + +```bash +curl -H "Authorization: Bearer $API_KEY" \ + http://localhost:8000/api/tasks//timeline +``` + +## get_task_chain + +Get the full retry chain for a task: the original task plus every retry, +ordered chronologically, with parent linkage. + +```bash +curl -H "Authorization: Bearer $API_KEY" \ + http://localhost:8000/api/tasks//chain +``` + +## get_task_summary + +Aggregate task statistics over a time window: total tasks, breakdown by state, +and average runtime of succeeded tasks. + +```bash +curl -H "Authorization: Bearer $API_KEY" \ + "http://localhost:8000/api/tasks/summary?hours=1" +``` + +## list_task_types + +List distinct task names (types) with a count of how many tasks each has run. + +```bash +curl -H "Authorization: Bearer $API_KEY" \ + http://localhost:8000/api/tasks/types +``` + +## list_orphaned_tasks + +List tasks stuck in `STARTED` whose worker went offline (crashed / network +drop) before sending a completion event. A task is orphaned when it has been in +`STARTED` longer than `ORPHAN_GRACE_SECONDS` and its worker is offline per +`WORKER_OFFLINE_TIMEOUT_SECONDS`. + +```bash +curl -H "Authorization: Bearer $API_KEY" \ + http://localhost:8000/api/tasks/orphaned +``` \ No newline at end of file diff --git a/docs/usage/workers.md b/docs/usage/workers.md new file mode 100644 index 0000000..e31ed0b --- /dev/null +++ b/docs/usage/workers.md @@ -0,0 +1,91 @@ +# Workers + +Inspect and manage Celery workers. Read operations use `app.control.inspect()`; +write operations use `app.control` and require live workers. + +## get_worker_status + +Derive worker status from the event log: `online` / `offline` / `unknown`, +based on `WORKER_OFFLINE_TIMEOUT_SECONDS`. Includes heartbeat details and the +last event type. + +```bash +curl -H "Authorization: Bearer $API_KEY" http://localhost:8000/api/workers +``` + +## list_workers + +Ping all workers and list who is alive. + +```bash +curl -H "Authorization: Bearer $API_KEY" http://localhost:8000/api/workers/list +``` + +## get_worker_stats + +Detailed statistics for a specific worker (requires the worker to respond). + +```bash +curl -H "Authorization: Bearer $API_KEY" \ + http://localhost:8000/api/workers/celery@worker1/stats +``` + +## get_active_tasks + +Currently executing tasks across all workers, or a specific worker. + +```bash +curl -H "Authorization: Bearer $API_KEY" http://localhost:8000/api/workers/active-tasks +curl -H "Authorization: Bearer $API_KEY" \ + "http://localhost:8000/api/workers/active-tasks?worker_name=celery@worker1" +``` + +## get_scheduled_tasks + +Tasks with an ETA/countdown waiting in workers' queues. + +```bash +curl -H "Authorization: Bearer $API_KEY" http://localhost:8000/api/workers/scheduled +``` + +## get_reserved_tasks + +Tasks prefetched by a worker but not yet started. + +```bash +curl -H "Authorization: Bearer $API_KEY" http://localhost:8000/api/workers/reserved +``` + +## shutdown_worker + +Gracefully shut down a worker (waits for current tasks). + +```bash +curl -X POST -H "Authorization: Bearer $API_KEY" \ + http://localhost:8000/api/workers/celery@worker1/shutdown +``` + +## scale_worker_pool + +Grow or shrink a worker's pool size. + +```bash +# Add 2 processes +curl -X POST -H "Authorization: Bearer $API_KEY" \ + "http://localhost:8000/api/workers/celery@worker1/scale?delta=2" +# Remove 1 process +curl -X POST -H "Authorization: Bearer $API_KEY" \ + "http://localhost:8000/api/workers/celery@worker1/scale?delta=-1" +``` + +## restart_worker_pool + +Restart a worker's execution pool, optionally reloading modules. + +```bash +curl -X POST -H "Authorization: Bearer $API_KEY" \ + http://localhost:8000/api/workers/celery@worker1/restart +# With module reload +curl -X POST -H "Authorization: Bearer $API_KEY" \ + "http://localhost:8000/api/workers/celery@worker1/restart?reload=true" +``` \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000..3dfb2a0 --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,64 @@ +site_name: taskowl +site_description: Modern Celery task monitoring with MCP integration +site_url: https://kalvadtech.github.io/taskowl/ +repo_url: https://github.com/KalvadTech/taskowl +edit_uri: edit/main/docs/ +theme: + name: material + logo: logo.png + favicon: logo.png + palette: + - media: "(prefers-color-scheme: light)" + scheme: default + primary: indigo + accent: indigo + toggle: + icon: material/brightness-7 + name: Switch to dark mode + - media: "(prefers-color-scheme: dark)" + scheme: slate + primary: indigo + accent: indigo + toggle: + icon: material/brightness-4 + name: Switch to light mode + features: + - navigation.sections + - navigation.top + - search.suggest + - search.highlight + - content.code.copy + - content.tabs.link +nav: + - Overview: index.md + - Setup: + - setup/index.md + - Installation: setup/installation.md + - Configuration: setup/configuration.md + - Usage Guide: + - usage/index.md + - Configuring Celery: usage/celery-app.md + - MCP Clients: usage/mcp-clients.md + - Tasks: usage/tasks.md + - Task Actions: usage/task-actions.md + - Workers: usage/workers.md + - Queues: usage/queues.md + - Automations: usage/automations.md + - Metrics: usage/metrics.md + - Troubleshooting: troubleshooting.md + - Contributing: contributing.md +markdown_extensions: + - admonition + - tables + - toc: + permalink: true + - pymdownx.highlight: + anchor_linenums: true + - pymdownx.inlinehilite + - pymdownx.snippets + - pymdownx.superfences +extra: + social: + - icon: fontawesome/brands/github + link: https://github.com/KalvadTech/taskowl +copyright: Copyright © 2026 Kalvad \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index cd7b379..423acca 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -46,6 +46,10 @@ dev = [ "ty==0.0.80", "aiosqlite==0.22.1", ] +docs = [ + "mkdocs>=1.6.1", + "mkdocs-material>=9.7.7", +] [project.scripts] taskowl = "taskowl.main:main" diff --git a/uv.lock b/uv.lock index b7b21ac..1376021 100644 --- a/uv.lock +++ b/uv.lock @@ -104,6 +104,28 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl", hash = "sha256:c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309", size = 67548, upload-time = "2026-03-19T14:22:23.645Z" }, ] +[[package]] +name = "babel" +version = "2.18.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7d/b2/51899539b6ceeeb420d40ed3cd4b7a40519404f9baf3d4ac99dc413a834b/babel-2.18.0.tar.gz", hash = "sha256:b80b99a14bd085fcacfa15c9165f651fbb3406e66cc603abf11c5750937c992d", size = 9959554, upload-time = "2026-02-01T12:30:56.078Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/77/f5/21d2de20e8b8b0408f0681956ca2c69f1320a3848ac50e6e7f39c6159675/babel-2.18.0-py3-none-any.whl", hash = "sha256:e2b422b277c2b9a9630c1d7903c2a00d0830c409c59ac8cae9081c92f1aeba35", size = 10196845, upload-time = "2026-02-01T12:30:53.445Z" }, +] + +[[package]] +name = "backrefs" +version = "8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ec/56/4744bcd0c82184e80c52b0ac4076c261a8ffa1f1b343ff2f6e89ce0e1cef/backrefs-8.0.tar.gz", hash = "sha256:b556cd7d36c3a3a2f256b89590b176b8eddfb73bcfaee3a3ddd84ea66d21ce50", size = 7013081, upload-time = "2026-07-26T19:54:24.638Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e3/fd/9bf53b6a6f6f519ffaac765df2f2a25e5c2fc6d32cfd2b2747099e72c911/backrefs-8.0-py310-none-any.whl", hash = "sha256:4a627b817fd2dce43b79ab48da63613340509381cd8ce0897078a0bce79a2ab8", size = 380377, upload-time = "2026-07-26T19:54:17.457Z" }, + { url = "https://files.pythonhosted.org/packages/e1/29/4bd7ae72a2634da00379c2b3bcc5439e7c94620235c6afea8af15229a973/backrefs-8.0-py311-none-any.whl", hash = "sha256:f0c35cf0102ba6b6070c12a492be3c1c1d3f5839529784b9a9565d6d04569a01", size = 392169, upload-time = "2026-07-26T19:54:18.782Z" }, + { url = "https://files.pythonhosted.org/packages/29/13/232505664e8e2a0c7a2eb0c505cfade9d715538f89a5d62bc4c272968f62/backrefs-8.0-py312-none-any.whl", hash = "sha256:87f0fae8c5f207fe9f4b2887efc71d42f4900ac78faa1af08d675ef303692dc5", size = 398084, upload-time = "2026-07-26T19:54:19.954Z" }, + { url = "https://files.pythonhosted.org/packages/8a/69/47a3dc20abc4fa5486655fde681bd55e63211b46c886d8c02223d6468431/backrefs-8.0-py313-none-any.whl", hash = "sha256:601ce68ca12385dbda06ce264406b4c4210cf5b79fd0fd627592365c92f29a88", size = 400040, upload-time = "2026-07-26T19:54:21.194Z" }, + { url = "https://files.pythonhosted.org/packages/1c/cf/e5f9b68a5b0e939a2fb933a66c20180d0c9241bf8927f7a47fa48c1675e9/backrefs-8.0-py314-none-any.whl", hash = "sha256:9ec96efa080938be92323e8e730e57718c9c88eb15ad70bbef4e1766df591408", size = 411903, upload-time = "2026-07-26T19:54:23.221Z" }, +] + [[package]] name = "billiard" version = "4.2.4" @@ -201,6 +223,100 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/aa/29/35e016098c814cd93de9cd320c66b5bfba14dc6ecedd3cb518fa7c408c69/cffi-2.1.1-cp315-cp315t-win_arm64.whl", hash = "sha256:d18e5ac0f2f03f4f518d3e23db0f0cad7faa1da8620e9c09461d443bbf6e6692", size = 186360, upload-time = "2026-08-03T21:21:13.636Z" }, ] +[[package]] +name = "charset-normalizer" +version = "3.5.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e5/3f/143b048436775b0f76ac3eec145c019e8173ccc2885c8f20319b996d5e83/charset_normalizer-3.5.1.tar.gz", hash = "sha256:6117b84ea48435e5356dc737f5121485c30920ba43375fa7b434fd753df0eac3", size = 171764, upload-time = "2026-08-15T08:20:44.807Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/29/cd/2b812ce5e888f1ce69a5350281e58aab07ae64a958ecae8912f30865718e/charset_normalizer-3.5.1-cp314-cp314-android_24_arm64_v8a.whl", hash = "sha256:774d157f112367ff4abd29019f38f023c24e00e56edc7829c20e358a5a913ad8", size = 212318, upload-time = "2026-08-15T08:18:04.403Z" }, + { url = "https://files.pythonhosted.org/packages/9e/4a/a6ee107430768a5334e6d63f31f148a04a1a491ef161a1ac9415a73f2fa8/charset_normalizer-3.5.1-cp314-cp314-android_24_x86_64.whl", hash = "sha256:26422d45fd13551cf564c58932f7d72b4f58b93b0fcf18c35ba6be12b46bb102", size = 224897, upload-time = "2026-08-15T08:18:05.997Z" }, + { url = "https://files.pythonhosted.org/packages/c3/d9/35ae3f64f29d0179c35c3baefe575904df2913dde519129c7f75995a2b1d/charset_normalizer-3.5.1-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:09a7bba9f739468c8e78c36a75c33768e53cb1959fc638f510454c14683f00d5", size = 194848, upload-time = "2026-08-15T08:18:07.397Z" }, + { url = "https://files.pythonhosted.org/packages/74/76/f2fc7380f056cc273a53af37f50d08ad54b2c59f61078f31432edcf1c2bd/charset_normalizer-3.5.1-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:4c9548dc78002099910abaebc0a72ac58b7d30931869e0351c09b507dff4ece3", size = 198163, upload-time = "2026-08-15T08:18:08.989Z" }, + { url = "https://files.pythonhosted.org/packages/e9/40/095ce62fa078483cccc1fa2b36e6bc9580b85422a20ee9f925341c50e44f/charset_normalizer-3.5.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:c428c6c31eb5f4277d7f8eccaf767fbd548ddd5ce3c8b4f4cbbfab3d96b5904c", size = 341823, upload-time = "2026-08-15T08:18:10.458Z" }, + { url = "https://files.pythonhosted.org/packages/f1/5a/0e58b1c04a1596e0256f407274a92d5fb2ee21324409d1fab1da48a65b5b/charset_normalizer-3.5.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2f06b7eae9dbe77fe1d644ca244dad508de8d302870a43f3c559b521270938a0", size = 242458, upload-time = "2026-08-15T08:18:11.989Z" }, + { url = "https://files.pythonhosted.org/packages/22/95/b4618ce912e6db0b1aae89ba788e38e8a7eba0f3025cc66e8c0699f977b2/charset_normalizer-3.5.1-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6b7430cf5728e68f6c462254009a6ef4086e1bea43cf2f57aa9c55fb4f50ff96", size = 226717, upload-time = "2026-08-15T08:18:13.401Z" }, + { url = "https://files.pythonhosted.org/packages/8a/76/c681192bbda3d55356db5dadd64381d5202b37c6b598fcda5282e88b5d3d/charset_normalizer-3.5.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ab743e9bc90c1f73552ec33e10e3331315acd2c397b36065b591b0181de533cc", size = 266111, upload-time = "2026-08-15T08:18:14.961Z" }, + { url = "https://files.pythonhosted.org/packages/88/be/55127bfca72c0cff6c022488d140d7c5b04c771e3b72e9bdb4836d54979d/charset_normalizer-3.5.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f6f7deae3feb4edfa2efaf7c574fe88cbf055038a6abdb40188e4fff66d5699f", size = 263128, upload-time = "2026-08-15T08:18:16.515Z" }, + { url = "https://files.pythonhosted.org/packages/e0/91/39c3af510b0aa32bbda03374259200f28430febfd1bf5e511fe765282ce5/charset_normalizer-3.5.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:15f024313246a4ed976c60f440bb8d257815513a681d212ff74fd46f7d715a90", size = 251240, upload-time = "2026-08-15T08:18:18.127Z" }, + { url = "https://files.pythonhosted.org/packages/1c/a5/cbe418bbc6ecdfc3e05a0116002897c4b403a5e838d697e64c78e9f0190d/charset_normalizer-3.5.1-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:823f82903d189af463d7df250ef1f7f696f3cee08cc8d91deb565e8d425f6506", size = 245282, upload-time = "2026-08-15T08:18:19.625Z" }, + { url = "https://files.pythonhosted.org/packages/cc/a4/689bb42e8e7cd492f3cb64907c6bc00ad247ec9a3628cd3f8eed126e8ae1/charset_normalizer-3.5.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:01e93745f7f219b703b60ba7afead36cfc4242782be5af484673fc500df12da5", size = 244597, upload-time = "2026-08-15T08:18:21.121Z" }, + { url = "https://files.pythonhosted.org/packages/c1/ce/9962938e179cf9f699d3f1e7b3114b5d7642dee6a893745229f9dd04f274/charset_normalizer-3.5.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:329fc3ccb63ad22d867d84c2adea759a64079a37ba4a343433b02c7a2816871e", size = 231376, upload-time = "2026-08-15T08:18:22.57Z" }, + { url = "https://files.pythonhosted.org/packages/85/54/46000450ada53bd9eac5429a2c8c54cd2d9b39c0c255f229aea9af0948a5/charset_normalizer-3.5.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:bb57753e36e4855b8ca375069482250a6246372331a3e4f3407eaebb007443f5", size = 266715, upload-time = "2026-08-15T08:18:24.235Z" }, + { url = "https://files.pythonhosted.org/packages/3d/bb/618749d70f792b44252a777bf89bfb86823b9bbc1ea13fe8ce759b07f38a/charset_normalizer-3.5.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:fce8cbd4997efeb450bd298b54f755dcdff18d496f7a5ddbb4867c6d7c88fdc3", size = 245848, upload-time = "2026-08-15T08:18:25.726Z" }, + { url = "https://files.pythonhosted.org/packages/7e/3f/ffb64458527c7668031d5eb095d978de561958dc9f5b53f8e488a533e603/charset_normalizer-3.5.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:6c9cdde8becb25a7fde49924511aa2644d6f8081cc8df8e9452724303348d8e3", size = 264521, upload-time = "2026-08-15T08:18:27.193Z" }, + { url = "https://files.pythonhosted.org/packages/4f/ab/74a55fd803916a35ac461daf002708191aac19b546b80dc8cabfedc63d98/charset_normalizer-3.5.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:9ac4444d8d4fd4c4bd08bf451ed3167aa9e7ec6cdb41b648794f1d1103652e36", size = 253054, upload-time = "2026-08-15T08:18:28.568Z" }, + { url = "https://files.pythonhosted.org/packages/a0/2a/6a9034b7d3c60b17499afb482df5878bf9fa20b50cc3887d5ef017a833db/charset_normalizer-3.5.1-cp314-cp314-pyemscripten_2026_0_wasm32.whl", hash = "sha256:f03ac127268b43ef4fe9e6ab6794a6794b49485a0cc0c1db79876d2f33f75bc7", size = 140580, upload-time = "2026-08-15T08:18:30.214Z" }, + { url = "https://files.pythonhosted.org/packages/f3/46/1d362e1a00d035d66b9869e1281eee115907f7e390a16a07824ab5737360/charset_normalizer-3.5.1-cp314-cp314-win32.whl", hash = "sha256:1f5883d77fd409a261abb5dc8ccbe335720d798b1de4abb3b1d47ccbbc76b53b", size = 180325, upload-time = "2026-08-15T08:18:31.877Z" }, + { url = "https://files.pythonhosted.org/packages/7a/7c/4938c329b6a9d446f6a59aa2092ff7118f274209b5ed0e26893d1d30a63c/charset_normalizer-3.5.1-cp314-cp314-win_amd64.whl", hash = "sha256:c658c50ac0c98cd755a2dd50b7977d3bca7df401dcc47fbdfa87db53ef7d4e8b", size = 204175, upload-time = "2026-08-15T08:18:33.466Z" }, + { url = "https://files.pythonhosted.org/packages/ac/33/eeb384dbd8dec570661354592f4f2e1b2fcc92585624d146a000caf53841/charset_normalizer-3.5.1-cp314-cp314-win_arm64.whl", hash = "sha256:4bea7f8ebe90bbd7f0e4a2de42ca6924ba23e3e76418c408ff82f1d46fabd687", size = 184123, upload-time = "2026-08-15T08:18:34.913Z" }, + { url = "https://files.pythonhosted.org/packages/1c/6c/c73fa9d5a85f6ab05395de61c5f6984e0a9ff40bb5ff888d46dff02526c6/charset_normalizer-3.5.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:fbc597639158fd7c14d55e808718848319540f51b0e6746e3eefa59723a4a348", size = 381682, upload-time = "2026-08-15T08:18:36.349Z" }, + { url = "https://files.pythonhosted.org/packages/30/c7/63565f860921457feba93bae6c86fb7746deb4cffeed2f375cb845318146/charset_normalizer-3.5.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e71c909f353863b2b89c83de2ebed71ea6d0df8a6ef65a128193c5e650766bef", size = 240826, upload-time = "2026-08-15T08:18:37.887Z" }, + { url = "https://files.pythonhosted.org/packages/06/ae/7ae8807410dfa33f8e6f1715740adeaafa8a816cc4cb33508f54b1f7c896/charset_normalizer-3.5.1-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7ac76cf9afd34929d76eb7fcb63be476a4853d8a96f0dcf2d0db68a0cbdf9885", size = 227861, upload-time = "2026-08-15T08:18:39.315Z" }, + { url = "https://files.pythonhosted.org/packages/e9/a3/887c1642f0da26000b0e0652d91071113c0e72cea33952e225cf589f49a9/charset_normalizer-3.5.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a3a370082ce34d0612f421e15fe011c53bb1feff21a26d06ad4fb244dab5a375", size = 260758, upload-time = "2026-08-15T08:18:40.88Z" }, + { url = "https://files.pythonhosted.org/packages/3e/11/e6f5b9a3d0e55b0ef7505cd3765cdd48f22db89994c947b316f52f801fd8/charset_normalizer-3.5.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:256dd4d85d9e4dc595e2bc983c980e73f62ddeb3165c58b4c3dfe78c5c8548c1", size = 259950, upload-time = "2026-08-15T08:18:42.351Z" }, + { url = "https://files.pythonhosted.org/packages/1b/ee/e4e10a94d51cd1ee638aa7e00b65399e6b2a4e8376ab6d2eac9f95586671/charset_normalizer-3.5.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:58d4aa13a59c969dbfdf9e6a9560e242cbfd9e8a8f50c2747714df1a423adf65", size = 249329, upload-time = "2026-08-15T08:18:43.914Z" }, + { url = "https://files.pythonhosted.org/packages/c4/25/d5f4198819e6059735a84e8d0bfb72dc33976da67b97adcd3fb5a5e07ec6/charset_normalizer-3.5.1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0c6dfb5ca6723eeed15aa8e564a014d69fcb8812f94eef11fe3631e0508199f5", size = 243137, upload-time = "2026-08-15T08:18:45.368Z" }, + { url = "https://files.pythonhosted.org/packages/a5/e9/e925ca7569cf9fb9701fd82503fee73eea5268fdb856bdd64947092d3daa/charset_normalizer-3.5.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c010f5581d9c612804cc59fcf7b524b707fbcb72828551237ab545bb5c7034af", size = 242820, upload-time = "2026-08-15T08:18:46.842Z" }, + { url = "https://files.pythonhosted.org/packages/34/17/672c251a888ed2aebcdd2fe830ad0104e25ff83c43f5c4f9c15e9fc6853c/charset_normalizer-3.5.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:52ec005752a56ae79547a05c0139ca2501a0c866390b6115008456b9f0e7cde1", size = 230504, upload-time = "2026-08-15T08:18:48.353Z" }, + { url = "https://files.pythonhosted.org/packages/3f/fc/f6a85abebd42ce4da2f1db0aa56cc6a0df1995e318b3875d14401b8381d1/charset_normalizer-3.5.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:2bced4061f000f7187254a02ad3433ae17eaf991747ceea2f478422590a5bba9", size = 263087, upload-time = "2026-08-15T08:18:49.859Z" }, + { url = "https://files.pythonhosted.org/packages/98/66/7c42677e739ba66746b297e2046918d793078094dc239e1e72768cffccc6/charset_normalizer-3.5.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:9eea3ab2597a5e65fe65296e2d6a84570845a6b55532d90333d740d48bbc850a", size = 243269, upload-time = "2026-08-15T08:18:51.601Z" }, + { url = "https://files.pythonhosted.org/packages/de/d8/a50b79237f417af10f8c2a501ce8d1ca87829a22e69117891ca4ba20a69e/charset_normalizer-3.5.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:496846868fea80e479324862fa877f02411f2fd0f83b79ccee2607aa68b2a032", size = 258766, upload-time = "2026-08-15T08:18:53.23Z" }, + { url = "https://files.pythonhosted.org/packages/2e/1d/0fc91aeaeb3c83b748f532399ce67cf84604b48297405d740000f7a9e786/charset_normalizer-3.5.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:85d5855daafc240cc045c026d7a15fd198a09b0fc8ff6f5ecbb5297b509cb11e", size = 250814, upload-time = "2026-08-15T08:18:54.768Z" }, + { url = "https://files.pythonhosted.org/packages/ae/10/3d8c777cf9024615295aa1b808324ad5b4a77855869c00824bad74ffaf8a/charset_normalizer-3.5.1-cp314-cp314t-win32.whl", hash = "sha256:58d3e12c88e0950bca850ae1f7c256055c097639c2edb9eb123af9807d8b15e4", size = 191074, upload-time = "2026-08-15T08:18:56.305Z" }, + { url = "https://files.pythonhosted.org/packages/4d/81/ae557d3c44d1a1d688696d60563413a0866a91b7ebc50f20df838be3d8c8/charset_normalizer-3.5.1-cp314-cp314t-win_amd64.whl", hash = "sha256:acaf604462bf330b0d07e7a07c1d6e4adac79e5fb13e9c5140590542cafacc00", size = 216476, upload-time = "2026-08-15T08:18:57.889Z" }, + { url = "https://files.pythonhosted.org/packages/27/e9/61c01fb8b804692569c036b3fc50495814502dcf13a60649c6055390b02c/charset_normalizer-3.5.1-cp314-cp314t-win_arm64.whl", hash = "sha256:fdb8a068947befafba9952162645dc2fecaeb400e64584829ed5e9b2fbe21a7f", size = 194115, upload-time = "2026-08-15T08:18:59.418Z" }, + { url = "https://files.pythonhosted.org/packages/4a/4e/8544831ef59d8f27ce92c80871380fdacc8076a8a56ed62f82e54f991333/charset_normalizer-3.5.1-cp315-cp315-macosx_10_15_universal2.whl", hash = "sha256:9085f87b0e38a2b92b8923059b4e8789fe40d9279712d15dcc670048d77079af", size = 342048, upload-time = "2026-08-15T08:19:01.054Z" }, + { url = "https://files.pythonhosted.org/packages/7f/a6/e3b46852424246065355644f4fb6dbccc0239a42a2eee27ecfc8957f0bcd/charset_normalizer-3.5.1-cp315-cp315-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2679de311c7946dde5d3b6f44941844133ff5c7cb86099c0061ab1e8901c20a8", size = 242997, upload-time = "2026-08-15T08:19:02.492Z" }, + { url = "https://files.pythonhosted.org/packages/03/3b/0cc9a26777334ab2f2e3089b948bbf4e4fe72ea70b897715ef6415043ec8/charset_normalizer-3.5.1-cp315-cp315-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:baf3775a2635e5a11fbd5e4e64ee69c7e86875d224a5c72aca4c141064589a90", size = 237014, upload-time = "2026-08-15T08:19:03.943Z" }, + { url = "https://files.pythonhosted.org/packages/8c/c2/027335f0aa337a2a2e121bac1ad88c4f02ba6053ea0926802784f3db11af/charset_normalizer-3.5.1-cp315-cp315-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8ac8c94b6539074e0f40899301273ac8402b9b3e01c7b7ba269ff30340aaaf20", size = 266174, upload-time = "2026-08-15T08:19:05.598Z" }, + { url = "https://files.pythonhosted.org/packages/86/d3/e367787febe4e74769dec0f406f2c3c8d1b955fce5aee1fd0f94e8367a45/charset_normalizer-3.5.1-cp315-cp315-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8fe532b3c966d1fb794e0698e4589d0444017ae77fc0b31edea13c0e35bcc449", size = 263361, upload-time = "2026-08-15T08:19:07.251Z" }, + { url = "https://files.pythonhosted.org/packages/af/3d/391b193eb9f3e84b02f9314088c386debdc0debee843535aaea2e2c6715d/charset_normalizer-3.5.1-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5c84bec0ab5ae0c64bfe73a7d2adcb5ce73b467523fc27fd6a28ab2aa6cbe35a", size = 252143, upload-time = "2026-08-15T08:19:08.816Z" }, + { url = "https://files.pythonhosted.org/packages/2e/57/de221f1745a90d418199761967e2776bfe2c275a1194220985e8c1d37833/charset_normalizer-3.5.1-cp315-cp315-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:854066be00447fa8de2ccbbe893e2ffc4b123ef16d897af794c1e18bd4a714b0", size = 252086, upload-time = "2026-08-15T08:19:10.255Z" }, + { url = "https://files.pythonhosted.org/packages/c8/e3/d119f86a01f9331e8186175f24873b1d74a7ee9e2e4b4d68f9947dae5afd/charset_normalizer-3.5.1-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:21b82d8082f6f5e7f456ef0bd16323d08de1266efbfeb476e64b2a91d1471a4e", size = 245231, upload-time = "2026-08-15T08:19:11.807Z" }, + { url = "https://files.pythonhosted.org/packages/26/de/d8e48c135ae480879539cdb179c8d3b50c7879497d75dd899b5763b69cee/charset_normalizer-3.5.1-cp315-cp315-musllinux_1_2_armv7l.whl", hash = "sha256:838648accb3a7fd9803fd45c87bce8509648eb0c11bc34e216141300977244f2", size = 241546, upload-time = "2026-08-15T08:19:13.416Z" }, + { url = "https://files.pythonhosted.org/packages/67/c4/217755fd1abc50d326c252922cd642002758095a81ff45010337b8b3ef65/charset_normalizer-3.5.1-cp315-cp315-musllinux_1_2_ppc64le.whl", hash = "sha256:195ce897c6153c0700078142cf8efe3e6454ca4cf4357499e4078dfd83396626", size = 267033, upload-time = "2026-08-15T08:19:14.981Z" }, + { url = "https://files.pythonhosted.org/packages/b8/d7/34d8e404e358d2adcc5a228c2134643af00104c8fb0bf525f3688d756f05/charset_normalizer-3.5.1-cp315-cp315-musllinux_1_2_riscv64.whl", hash = "sha256:978eab16f55b4ab2c2a745be9a0a840bf8f09a7f227d9c76eb30214d078865a5", size = 252045, upload-time = "2026-08-15T08:19:16.618Z" }, + { url = "https://files.pythonhosted.org/packages/5e/fa/40414471acf0aa0692ca77305aa00e434fcd8288f0941c93c30e9a5f8f2f/charset_normalizer-3.5.1-cp315-cp315-musllinux_1_2_s390x.whl", hash = "sha256:cc0329df4caaceb950d2f580b5ac716a377f7059624a0bafaeaf8a218c6ed774", size = 264866, upload-time = "2026-08-15T08:19:18.101Z" }, + { url = "https://files.pythonhosted.org/packages/32/90/fcc850bae791abd2e0c041847f13e270aa08692a79f3e00de6d2dce1cb50/charset_normalizer-3.5.1-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:687c9ca3035544b113bea2055e180af96fb63c0c476e22a9180f51925186e7b7", size = 253932, upload-time = "2026-08-15T08:19:19.734Z" }, + { url = "https://files.pythonhosted.org/packages/af/af/53afe99068b3c10b4cbae592a52ef72a7c92c0188440e83ee3a078fd8f75/charset_normalizer-3.5.1-cp315-cp315-win32.whl", hash = "sha256:706bfd38730a5ac7a365793269a00f4e988178cec121391f4248d84ad8c972e9", size = 180320, upload-time = "2026-08-15T08:19:21.37Z" }, + { url = "https://files.pythonhosted.org/packages/c9/bc/f46a132041b29e4a8779ed712d3df1bf112e94ca8de58b66d7ec2c0cf8b9/charset_normalizer-3.5.1-cp315-cp315-win_amd64.whl", hash = "sha256:92caef967d287a407085d61176fce4012b1dd62daed4eb6d5ceb26d3d2538712", size = 204174, upload-time = "2026-08-15T08:19:23.088Z" }, + { url = "https://files.pythonhosted.org/packages/a1/5d/9ed554480eda8e447b673648628fdc29574d23dbad01fe11837adedd1cae/charset_normalizer-3.5.1-cp315-cp315-win_arm64.whl", hash = "sha256:5fc45d653ea8c9a20479167e11d4a0f8cb2fa3470737ab6f9c827532313187b7", size = 184126, upload-time = "2026-08-15T08:19:24.471Z" }, + { url = "https://files.pythonhosted.org/packages/3b/32/9b8929bf384061ee1fe5d9c27c6f9776d3d824039ad4e14c88ec00c7808e/charset_normalizer-3.5.1-cp315-cp315t-macosx_10_15_universal2.whl", hash = "sha256:59171c6e45bf07d0d5cab3b0bf81d945035530f6873398b3b531c31184d46663", size = 381441, upload-time = "2026-08-15T08:19:26.038Z" }, + { url = "https://files.pythonhosted.org/packages/96/10/e9aa7923d3ddac652c99a1c5f7be494e737e151566a44abe018daf757f2c/charset_normalizer-3.5.1-cp315-cp315t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9dbdd9205662134957cf0c324f639bdc5031c0ca056e2369e238db75187c0f11", size = 241742, upload-time = "2026-08-15T08:19:27.532Z" }, + { url = "https://files.pythonhosted.org/packages/28/53/a2d249ebddf47b889a100c0bdcb61a2f9dbb8bc24ef325cc062e4f476877/charset_normalizer-3.5.1-cp315-cp315t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e4b018dc5a0eee4676e38fe84a47a427816c590b93b55d9025274ec4d6ffc2dc", size = 235298, upload-time = "2026-08-15T08:19:29.274Z" }, + { url = "https://files.pythonhosted.org/packages/7d/07/469f78af590f7d5cd48e20d8dbfa3d66deeff9ba37768c04d886b5afd45c/charset_normalizer-3.5.1-cp315-cp315t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ced3fdd71aaa83ce593746c2edb42b7a59cb4c19c8b5c407781c72e493aae55a", size = 262500, upload-time = "2026-08-15T08:19:30.955Z" }, + { url = "https://files.pythonhosted.org/packages/55/66/3bb56a47f7dcba014055b1a1d33c6f08bbe9c1e74dba154cfa25f90ae885/charset_normalizer-3.5.1-cp315-cp315t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:19a3dd5aa73cef1c99687c4fc57db016a9c17104ae1185da88ba566a5d3bebe4", size = 258888, upload-time = "2026-08-15T08:19:32.458Z" }, + { url = "https://files.pythonhosted.org/packages/ff/c1/2adc2800903fb013210349313b710a5376856578d9e33e6b9a1d8b36714a/charset_normalizer-3.5.1-cp315-cp315t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cc5d36d96478aa9c60654bd932525bf32964c62a7281eafdf16d85003a8d6004", size = 250243, upload-time = "2026-08-15T08:19:33.94Z" }, + { url = "https://files.pythonhosted.org/packages/95/b5/a18d0dd1157ab655cc2cb14a545f4a4784bbad70ab3502412e36097502d9/charset_normalizer-3.5.1-cp315-cp315t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:04368edf83514385ffc3e1cfd4546e595f4f1272dd23ba437a93a9cc3741d47b", size = 249871, upload-time = "2026-08-15T08:19:35.413Z" }, + { url = "https://files.pythonhosted.org/packages/ad/c3/525f508cd1e58d0450ac55ed40ac75bc3a97482c59def5278456a5fbf03c/charset_normalizer-3.5.1-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:9b5db6052055d34d41230fb78d7c439c23dc536a9896f6cb039e8dd92cfc1263", size = 243580, upload-time = "2026-08-15T08:19:36.886Z" }, + { url = "https://files.pythonhosted.org/packages/7c/c1/49a91fe7e97c8140094ca5c64161ab623a70d9f636bf834eace14048acb5/charset_normalizer-3.5.1-cp315-cp315t-musllinux_1_2_armv7l.whl", hash = "sha256:252d099029bcbea642f2a06c4ed5046bdf8b5a8150b64afa5e027e88b106e5ee", size = 239807, upload-time = "2026-08-15T08:19:38.392Z" }, + { url = "https://files.pythonhosted.org/packages/d3/58/56a48c296601274c4689b864a8e2dfb209b81dfcb39472753ce95eea662b/charset_normalizer-3.5.1-cp315-cp315t-musllinux_1_2_ppc64le.whl", hash = "sha256:6199d5606e2bbf2b096cf64d03f8b6790c91081d5ac866b8e7bb6422738cc60c", size = 264083, upload-time = "2026-08-15T08:19:39.856Z" }, + { url = "https://files.pythonhosted.org/packages/10/4c/dc48409274a1817ff349711d26c62aa0c597df865d4d69ef79160c859193/charset_normalizer-3.5.1-cp315-cp315t-musllinux_1_2_riscv64.whl", hash = "sha256:77efcff2b23071c349402ac1066667a3d011f62398d81408c9b88ad991747c9e", size = 250317, upload-time = "2026-08-15T08:19:41.53Z" }, + { url = "https://files.pythonhosted.org/packages/81/58/d325912115caec62d6bdd77bbab5e0b7da5d234a9f20affdffcbcb530d0b/charset_normalizer-3.5.1-cp315-cp315t-musllinux_1_2_s390x.whl", hash = "sha256:a5cbd90ecf0fc62e64726917ad083b73001f0563657a87ec3c0b504e277dc90d", size = 258173, upload-time = "2026-08-15T08:19:43.07Z" }, + { url = "https://files.pythonhosted.org/packages/34/f7/b13b1ccae2c8ec63980d13be1890eb73f8aeabbfce02a24aabc0908788f5/charset_normalizer-3.5.1-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:4d26f14f041e83dd8edfd61f4cd4fa7285d31798b5bf1f28e70c367ba6c41d61", size = 251960, upload-time = "2026-08-15T08:19:44.587Z" }, + { url = "https://files.pythonhosted.org/packages/1e/25/ed3f9919c5aef8cc818be1f972f565f7610d7b2076b8ebb98839516ffc3c/charset_normalizer-3.5.1-cp315-cp315t-win32.whl", hash = "sha256:ac13b004224fb341e1e25a1ed5e19d32f57cdb2a403e01f003b46f051a550f6f", size = 191186, upload-time = "2026-08-15T08:19:46.293Z" }, + { url = "https://files.pythonhosted.org/packages/69/d5/43c2b3e9d8267092b913eb8b0603f0f71993c395632886bd37a7223f96cf/charset_normalizer-3.5.1-cp315-cp315t-win_amd64.whl", hash = "sha256:35aea775dc2bd5f54cd84a1cd2696cc3207c479cb9cf0bd346f0d343e4300ddb", size = 215947, upload-time = "2026-08-15T08:19:47.853Z" }, + { url = "https://files.pythonhosted.org/packages/a8/76/9aad3e9c8865e5e0efa9a7f6f81c37a67635a985145ecd44528a81e088ee/charset_normalizer-3.5.1-cp315-cp315t-win_arm64.whl", hash = "sha256:fb78f6e7fcd8ad785d28cd577168bc1aaee827b25bb8755638f694794ea98f0a", size = 193909, upload-time = "2026-08-15T08:19:49.383Z" }, + { url = "https://files.pythonhosted.org/packages/5b/97/fb4e82231aba271ffd775a1b4993b0defc4e3059f286ae41d9433409fe85/charset_normalizer-3.5.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:41876ee62a3dddf48ff1121ad8f0798032aa03f2fd35f21f34a4cab14f18d8d2", size = 331467, upload-time = "2026-08-15T08:19:50.959Z" }, + { url = "https://files.pythonhosted.org/packages/9f/2f/fe3f187327aac18e2d54e9d2b08e15d27bf9b642d9e51c219f130fc34d1a/charset_normalizer-3.5.1-cp37-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:a6dac12ff6b846103483683f60c5f8fee205121adc58ffd87e90a90a3af69e99", size = 253057, upload-time = "2026-08-15T08:19:52.654Z" }, + { url = "https://files.pythonhosted.org/packages/d7/c7/9e48cee5c161fe24da823b61bf381921d77cb994a0a4de148e95018c1984/charset_normalizer-3.5.1-cp37-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cee5dd7c6fb5dd52a0fe2a740f9bc6e3593f5f8b1788bde49de02086f30182b2", size = 240930, upload-time = "2026-08-15T08:19:54.163Z" }, + { url = "https://files.pythonhosted.org/packages/49/e0/716601f3cc69be7b198951150c75ead1ece33c3c8036ff6ffa46029659a0/charset_normalizer-3.5.1-cp37-abi3-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:343fb4f2821043bd87095f7b08a1a181febc8e36ac64212143bbfd0a0e1bc235", size = 230822, upload-time = "2026-08-15T08:19:55.807Z" }, + { url = "https://files.pythonhosted.org/packages/d3/05/71bfc5caa0abcc45aea1f6a4d50ac68e59605ddc7666fe8494f4cd229665/charset_normalizer-3.5.1-cp37-abi3-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ae4a097991662cd4fff0ddc74e0fe7874f82e00042fa0ea00855645ed0c79598", size = 260037, upload-time = "2026-08-15T08:19:57.312Z" }, + { url = "https://files.pythonhosted.org/packages/c3/92/de7e32ed05341e7a9c4c877c318418197b7f2d66a3b68d561bf2ac57ca3e/charset_normalizer-3.5.1-cp37-abi3-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4b599739b93b2cbeded49645ae3c8d1405c29ddfbceac1545c87a3f9580a9e96", size = 255097, upload-time = "2026-08-15T08:19:59.056Z" }, + { url = "https://files.pythonhosted.org/packages/f5/7b/ade0a122600319dfa0b1000ab0f9731c94a817904cf3c5de408c73a4ede7/charset_normalizer-3.5.1-cp37-abi3-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b39b69b347e5e47a3b5b8cfc005c68c1ba347474e3960236c4944a8ecd174962", size = 250166, upload-time = "2026-08-15T08:20:00.612Z" }, + { url = "https://files.pythonhosted.org/packages/75/9c/019fbb9f4834491a160951349b1a3714439376f66e5f7cf18b4f18f0c7aa/charset_normalizer-3.5.1-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:a2028475ba855475b8b4d3cfeb4994269c967aea8b9892dfba907f4263a863a3", size = 241821, upload-time = "2026-08-15T08:20:02.321Z" }, + { url = "https://files.pythonhosted.org/packages/2b/b8/11d4840bfc99330cc7fbcc2681ee5a044553a6e77655508d8f9b2bff7b34/charset_normalizer-3.5.1-cp37-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:36047af20e17097c3bb9476c2b7655f2f7aa51322c0ba58c07695bedf755a950", size = 232529, upload-time = "2026-08-15T08:20:04.008Z" }, + { url = "https://files.pythonhosted.org/packages/18/96/2b3a21492d9f65171ac75d872f5018260013d00bfa0ff70ec9f179148cbd/charset_normalizer-3.5.1-cp37-abi3-musllinux_1_2_ppc64le.whl", hash = "sha256:4c4fb141a727957c93edfe5c32a26ceb6b5f6461d67146e2d39f51e16170bea8", size = 260348, upload-time = "2026-08-15T08:20:05.877Z" }, + { url = "https://files.pythonhosted.org/packages/d6/aa/a69a2028e8bd052476c245460ab19d7de595de084dd968f2d75cd50c3e25/charset_normalizer-3.5.1-cp37-abi3-musllinux_1_2_riscv64.whl", hash = "sha256:2f293479cce755c75f1697e87c409b7ae4c555c7dfecb6e988ad13abba943031", size = 247234, upload-time = "2026-08-15T08:20:07.487Z" }, + { url = "https://files.pythonhosted.org/packages/35/8a/3d130aeabcaf3d2466af76b7b141c08d9e89c9016ab4b7cdd0f7dc2d1c62/charset_normalizer-3.5.1-cp37-abi3-musllinux_1_2_s390x.whl", hash = "sha256:3588e376b3ea2eea84976f67273d679f229e24c66dce7b82ae45aef04ff6e072", size = 256917, upload-time = "2026-08-15T08:20:09.142Z" }, + { url = "https://files.pythonhosted.org/packages/80/c2/a7379b840292d0c1ab9fbd17d1f3967aa81794dc95bc74be8999d7fedcf7/charset_normalizer-3.5.1-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:e199fb99720074809a7720f1c0b4d919eea8b87e88713e0f8f602f7bef543d9d", size = 254846, upload-time = "2026-08-15T08:20:10.727Z" }, + { url = "https://files.pythonhosted.org/packages/01/65/d43b714731bb2f40d4053dfa00ecfc1c5a301f8e3316c5db3a09af59fe94/charset_normalizer-3.5.1-cp37-abi3-win32.whl", hash = "sha256:dd732602a7009217f658d5863d12d79d373a4de0eebc111094bcdd3bb8e0a6cc", size = 174216, upload-time = "2026-08-15T08:20:12.334Z" }, + { url = "https://files.pythonhosted.org/packages/35/4f/b911ed898b26a09789eba9c9200c999aff6c61b4bafaf4838e56d1a1e1a3/charset_normalizer-3.5.1-cp37-abi3-win_amd64.whl", hash = "sha256:70055ff39b97c99e7ae40ea3e393fb62aa2e44dbd9b29f8d14f42fb0025c3959", size = 199764, upload-time = "2026-08-15T08:20:13.908Z" }, + { url = "https://files.pythonhosted.org/packages/f0/a7/920baf467bfd9bf689f3b318340f37aee4572a71f162bd8db51da55ba4fa/charset_normalizer-3.5.1-cp37-abi3-win_arm64.whl", hash = "sha256:87e4f41d375c0b9be2fb5251aee4b8a689169e134535aed81bf085c3b647451e", size = 287318, upload-time = "2026-08-15T08:20:15.551Z" }, + { url = "https://files.pythonhosted.org/packages/cc/61/d01fc49b8dea277640b55a9e15960dbca9fdc8c9fde18e572d39c59f4019/charset_normalizer-3.5.1-py3-none-any.whl", hash = "sha256:6df0ec430f9a831772c23ca5a224cba36517a58a84bb32c32bb59a9fa67c47f6", size = 68658, upload-time = "2026-08-15T08:20:43.306Z" }, +] + [[package]] name = "click" version = "8.4.2" @@ -325,6 +441,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/cb/03/10388a42375ee7e4ac9b94eb2c5c569c8b5795e377e701c9ac3ad63de890/fastapi-0.141.1-py3-none-any.whl", hash = "sha256:bfb91aa2d334c61cb35ba9a116fc123b3d3df31640b801cf57a7a78ec3f603b3", size = 131954, upload-time = "2026-07-29T17:18:04.364Z" }, ] +[[package]] +name = "ghp-import" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "python-dateutil" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d9/29/d40217cbe2f6b1359e00c6c307bb3fc876ba74068cbab3dde77f03ca0dc4/ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343", size = 10943, upload-time = "2022-05-02T15:47:16.11Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f7/ec/67fbef5d497f86283db54c22eec6f6140243aae73265799baaaa19cd17fb/ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619", size = 11034, upload-time = "2022-05-02T15:47:14.552Z" }, +] + [[package]] name = "greenlet" version = "3.5.4" @@ -457,6 +585,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, ] +[[package]] +name = "jinja2" +version = "3.1.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, +] + [[package]] name = "jsonschema" version = "4.26.0" @@ -511,6 +651,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a5/54/12ed58d458474aaab5c3d180173e745a4fe131bb330370596876d19ff60f/mako-1.4.1-py3-none-any.whl", hash = "sha256:a359d9a94a541213958742b2698d0a7757bb83551767bc468a74b9905aba9617", size = 80010, upload-time = "2026-08-05T06:10:58.248Z" }, ] +[[package]] +name = "markdown" +version = "3.10.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/29/6f/da4c6aea59b3001f2e8c0ec7497475aadaf3b021c10cab5b2858f0f32b26/markdown-3.10.3.tar.gz", hash = "sha256:3589362618f743188b4d955b874402bc814f4f83f544dc207719f4baa7d9c45f", size = 372596, upload-time = "2026-07-30T19:05:29.005Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/64/69/4a5af2bc115a9a33fefe51709749de8262be3f9ba063d1753a837cdbc49c/markdown-3.10.3-py3-none-any.whl", hash = "sha256:fa6c92a00a4a3c98b22728c64a935ae1928250ae65058a6ded814d2cc29a4cea", size = 110757, upload-time = "2026-07-30T19:05:27.883Z" }, +] + [[package]] name = "markupsafe" version = "3.0.3" @@ -579,6 +728,84 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/8f/d7/6ffba5d8cd5dd9b8a19478875c50e04945314ba5074e84d749283f27f62d/mcp_types-2.2.0-py3-none-any.whl", hash = "sha256:ea476b73ee86709ab5abc9452385ed36cc05907e582355622e294595c9a04f13", size = 69106, upload-time = "2026-09-07T16:06:21.461Z" }, ] +[[package]] +name = "mergedeep" +version = "1.3.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3a/41/580bb4006e3ed0361b8151a01d324fb03f420815446c7def45d02f74c270/mergedeep-1.3.4.tar.gz", hash = "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8", size = 4661, upload-time = "2021-02-05T18:55:30.623Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/19/04f9b178c2d8a15b076c8b5140708fa6ffc5601fb6f1e975537072df5b2a/mergedeep-1.3.4-py3-none-any.whl", hash = "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307", size = 6354, upload-time = "2021-02-05T18:55:29.583Z" }, +] + +[[package]] +name = "mkdocs" +version = "1.6.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "ghp-import" }, + { name = "jinja2" }, + { name = "markdown" }, + { name = "markupsafe" }, + { name = "mergedeep" }, + { name = "mkdocs-get-deps" }, + { name = "packaging" }, + { name = "pathspec" }, + { name = "pyyaml" }, + { name = "pyyaml-env-tag" }, + { name = "watchdog" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bc/c6/bbd4f061bd16b378247f12953ffcb04786a618ce5e904b8c5a01a0309061/mkdocs-1.6.1.tar.gz", hash = "sha256:7b432f01d928c084353ab39c57282f29f92136665bdd6abf7c1ec8d822ef86f2", size = 3889159, upload-time = "2024-08-30T12:24:06.899Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/5b/dbc6a8cddc9cfa9c4971d59fb12bb8d42e161b7e7f8cc89e49137c5b279c/mkdocs-1.6.1-py3-none-any.whl", hash = "sha256:db91759624d1647f3f34aa0c3f327dd2601beae39a366d6e064c03468d35c20e", size = 3864451, upload-time = "2024-08-30T12:24:05.054Z" }, +] + +[[package]] +name = "mkdocs-get-deps" +version = "0.2.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mergedeep" }, + { name = "platformdirs" }, + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ce/25/b3cccb187655b9393572bde9b09261d267c3bf2f2cdabe347673be5976a6/mkdocs_get_deps-0.2.2.tar.gz", hash = "sha256:8ee8d5f316cdbbb2834bc1df6e69c08fe769a83e040060de26d3c19fad3599a1", size = 11047, upload-time = "2026-03-10T02:46:33.632Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/29/744136411e785c4b0b744d5413e56555265939ab3a104c6a4b719dad33fd/mkdocs_get_deps-0.2.2-py3-none-any.whl", hash = "sha256:e7878cbeac04860b8b5e0ca31d3abad3df9411a75a32cde82f8e44b6c16ff650", size = 9555, upload-time = "2026-03-10T02:46:32.256Z" }, +] + +[[package]] +name = "mkdocs-material" +version = "9.7.7" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "babel" }, + { name = "backrefs" }, + { name = "colorama" }, + { name = "jinja2" }, + { name = "markdown" }, + { name = "mkdocs" }, + { name = "mkdocs-material-extensions" }, + { name = "paginate" }, + { name = "pygments" }, + { name = "pymdown-extensions" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f1/cd/c05d3a530ba7934f144fb45f7203cd236adc25c7bdcc34673d202f4b0278/mkdocs_material-9.7.7.tar.gz", hash = "sha256:c0649c065b1b0512d60aad8c10f947f8e455284475239b364b610f2deb4d0855", size = 4097923, upload-time = "2026-07-17T16:21:33.156Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ad/21/17c1bc9e6f47c972ad66fb2ac2568f99f90f1207eeb6fc3b34d094dba7b5/mkdocs_material-9.7.7-py3-none-any.whl", hash = "sha256:8ea9bb1737a5b524a5f9dcf2e1b4ebda8274ae3008aa7845720a97083bef708f", size = 9305438, upload-time = "2026-07-17T16:21:30.017Z" }, +] + +[[package]] +name = "mkdocs-material-extensions" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/79/9b/9b4c96d6593b2a541e1cb8b34899a6d021d208bb357042823d4d2cabdbe7/mkdocs_material_extensions-1.3.1.tar.gz", hash = "sha256:10c9511cea88f568257f960358a467d12b970e1f7b2c0e5fb2bb48cab1928443", size = 11847, upload-time = "2023-11-22T19:09:45.208Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5b/54/662a4743aa81d9582ee9339d4ffa3c8fd40a4965e033d77b9da9774d3960/mkdocs_material_extensions-1.3.1-py3-none-any.whl", hash = "sha256:adff8b62700b25cb77b53358dad940f3ef973dd6db797907c49e3c2ef3ab4e31", size = 8728, upload-time = "2023-11-22T19:09:43.465Z" }, +] + [[package]] name = "opentelemetry-api" version = "1.44.0" @@ -600,6 +827,33 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl", hash = "sha256:d7193f7c8e4e93f444fde0262bf90af30e16fa0ad0ad44cb553c87339b23cd1c", size = 129956, upload-time = "2026-08-04T18:15:27.159Z" }, ] +[[package]] +name = "paginate" +version = "0.5.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ec/46/68dde5b6bc00c1296ec6466ab27dddede6aec9af1b99090e1107091b3b84/paginate-0.5.7.tar.gz", hash = "sha256:22bd083ab41e1a8b4f3690544afb2c60c25e5c9a63a30fa2f483f6c60c8e5945", size = 19252, upload-time = "2024-08-25T14:17:24.139Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/90/96/04b8e52da071d28f5e21a805b19cb9390aa17a47462ac87f5e2696b9566d/paginate-0.5.7-py2.py3-none-any.whl", hash = "sha256:b885e2af73abcf01d9559fd5216b57ef722f8c42affbb63942377668e35c7591", size = 13746, upload-time = "2024-08-25T14:17:22.55Z" }, +] + +[[package]] +name = "pathspec" +version = "1.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5a/82/42f767fc1c1143d6fd36efb827202a2d997a375e160a71eb2888a925aac1/pathspec-1.1.1.tar.gz", hash = "sha256:17db5ecd524104a120e173814c90367a96a98d07c45b2e10c2f3919fff91bf5a", size = 135180, upload-time = "2026-04-27T01:46:08.907Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f1/d9/7fb5aa316bc299258e68c73ba3bddbc499654a07f151cba08f6153988714/pathspec-1.1.1-py3-none-any.whl", hash = "sha256:a00ce642f577bf7f473932318056212bc4f8bfdf53128c78bbd5af0b9b20b189", size = 57328, upload-time = "2026-04-27T01:46:07.06Z" }, +] + +[[package]] +name = "platformdirs" +version = "4.11.8" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/53/18/f3bb8ef0d3b930692343da8aa4d3cbcd6749477c053959395ac81965a6e9/platformdirs-4.11.8.tar.gz", hash = "sha256:f23abafea7dd4276d1f29104b83598d7dcc567cafd07c9c951e66665645437fc", size = 37182, upload-time = "2026-09-08T22:20:42.866Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/e1/5b7b8bbb55084d1425bcb9bc823ff519e1b2be05f6ebb0089e2eacc38413/platformdirs-4.11.8-py3-none-any.whl", hash = "sha256:52f2f181bbfde907966932cc8312d967d02976422d66d537ea16092b8e291081", size = 24027, upload-time = "2026-09-08T22:20:41.537Z" }, +] + [[package]] name = "pluggy" version = "1.6.0" @@ -732,6 +986,19 @@ crypto = [ { name = "cryptography" }, ] +[[package]] +name = "pymdown-extensions" +version = "12.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown" }, + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f0/20/bb1b39c1f487e6745bfdca09625db8e8265cdce70d2bac679d930a6cbf72/pymdown_extensions-12.0.tar.gz", hash = "sha256:d00b32be02715676bfec9183371928d1db44e1cd58dbeb76c7f27d9f72682039", size = 867035, upload-time = "2026-09-15T03:32:18.85Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/52/8c/18eb38daca41f784dd06edc2ef95a75d7c7572e4105f486a5b2cd613081b/pymdown_extensions-12.0-py3-none-any.whl", hash = "sha256:ae9ee9bfd1c1e3d291d6f6ff1883a7ef388594905e80c0c714b9c596fd8a5cb7", size = 277140, upload-time = "2026-09-15T03:32:17.487Z" }, +] + [[package]] name = "pytest" version = "9.1.1" @@ -803,6 +1070,44 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/23/ed/4532e9388e65fa16b46776ef47ad631a64eda1631884488af707666350ed/pywin32-312-cp315-cp315-win_arm64.whl", hash = "sha256:a8597d28f267b39074aef51fa593530082b39cbe5a074226096857b1fed2dfb9", size = 6840337, upload-time = "2026-06-04T07:49:57.531Z" }, ] +[[package]] +name = "pyyaml" +version = "6.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" }, + { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" }, + { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" }, + { url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355, upload-time = "2025-09-25T21:32:39.178Z" }, + { url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175, upload-time = "2025-09-25T21:32:40.865Z" }, + { url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228, upload-time = "2025-09-25T21:32:42.084Z" }, + { url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194, upload-time = "2025-09-25T21:32:43.362Z" }, + { url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429, upload-time = "2025-09-25T21:32:57.844Z" }, + { url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912, upload-time = "2025-09-25T21:32:59.247Z" }, + { url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108, upload-time = "2025-09-25T21:32:44.377Z" }, + { url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641, upload-time = "2025-09-25T21:32:45.407Z" }, + { url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901, upload-time = "2025-09-25T21:32:48.83Z" }, + { url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132, upload-time = "2025-09-25T21:32:50.149Z" }, + { url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261, upload-time = "2025-09-25T21:32:51.808Z" }, + { url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272, upload-time = "2025-09-25T21:32:52.941Z" }, + { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" }, + { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" }, + { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" }, +] + +[[package]] +name = "pyyaml-env-tag" +version = "1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/2e/79c822141bfd05a853236b504869ebc6b70159afc570e1d5a20641782eaa/pyyaml_env_tag-1.1.tar.gz", hash = "sha256:2eb38b75a2d21ee0475d6d97ec19c63287a7e140231e4214969d0eac923cd7ff", size = 5737, upload-time = "2025-05-13T15:24:01.64Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/11/432f32f8097b03e3cd5fe57e88efb685d964e2e5178a48ed61e841f7fdce/pyyaml_env_tag-1.1-py3-none-any.whl", hash = "sha256:17109e1a528561e32f026364712fee1264bc2ea6715120891174ed1b980d2e04", size = 4722, upload-time = "2025-05-13T15:23:59.629Z" }, +] + [[package]] name = "redis" version = "8.1.0" @@ -825,6 +1130,21 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl", hash = "sha256:381329a9f99628c9069361716891d34ad94af76e461dcb0335825aecc7692231", size = 26766, upload-time = "2025-10-13T15:30:47.625Z" }, ] +[[package]] +name = "requests" +version = "2.34.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ac/c3/e2a2b89f2d3e2179abd6d00ebd70bff6273f37fb3e0cc209f48b39d00cbf/requests-2.34.2.tar.gz", hash = "sha256:f288924cae4e29463698d6d60bc6a4da69c89185ad1e0bcc4104f584e960b9ed", size = 142856, upload-time = "2026-05-14T19:25:27.735Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl", hash = "sha256:2a0d60c172f83ac6ab31e4554906c0f3b3588d37b5cb939b1c061f4907e278e0", size = 73075, upload-time = "2026-05-14T19:25:26.443Z" }, +] + [[package]] name = "rpds-py" version = "2026.6.3" @@ -998,6 +1318,10 @@ dev = [ { name = "ruff" }, { name = "ty" }, ] +docs = [ + { name = "mkdocs" }, + { name = "mkdocs-material" }, +] [package.metadata] requires-dist = [ @@ -1023,6 +1347,10 @@ dev = [ { name = "ruff", specifier = "==0.16.7" }, { name = "ty", specifier = "==0.0.80" }, ] +docs = [ + { name = "mkdocs", specifier = ">=1.6.1" }, + { name = "mkdocs-material", specifier = ">=9.7.7" }, +] [[package]] name = "truststore" @@ -1100,6 +1428,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/9e/a4/017a7a6cbe387d961a688ec31364ae60a5c4e22c96ae9921b79a947c855d/tzlocal-5.4.4-py3-none-any.whl", hash = "sha256:aae09f0126a8a86fa736be266eb4a471380d26a0de3bc14844e7821fee3e2a15", size = 18115, upload-time = "2026-06-29T08:03:38.666Z" }, ] +[[package]] +name = "urllib3" +version = "2.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/53/0c/06f8b233b8fd13b9e5ee11424ef85419ba0d8ba0b3138bf360be2ff56953/urllib3-2.7.0.tar.gz", hash = "sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c", size = 433602, upload-time = "2026-05-07T16:13:18.596Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl", hash = "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897", size = 131087, upload-time = "2026-05-07T16:13:17.151Z" }, +] + [[package]] name = "uvicorn" version = "0.52.4" @@ -1122,6 +1459,24 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/03/ff/7c0c86c43b3cbb927e0ccc0255cb4057ceba4799cd44ae95174ce8e8b5b2/vine-5.1.0-py3-none-any.whl", hash = "sha256:40fdf3c48b2cfe1c38a49e9ae2da6fda88e4794c810050a728bd7413811fb1dc", size = 9636, upload-time = "2023-11-05T08:46:51.205Z" }, ] +[[package]] +name = "watchdog" +version = "6.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", size = 131220, upload-time = "2024-11-01T14:07:13.037Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079, upload-time = "2024-11-01T14:06:59.472Z" }, + { url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078, upload-time = "2024-11-01T14:07:01.431Z" }, + { url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076, upload-time = "2024-11-01T14:07:02.568Z" }, + { url = "https://files.pythonhosted.org/packages/ab/cc/da8422b300e13cb187d2203f20b9253e91058aaf7db65b74142013478e66/watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f", size = 79077, upload-time = "2024-11-01T14:07:03.893Z" }, + { url = "https://files.pythonhosted.org/packages/2c/3b/b8964e04ae1a025c44ba8e4291f86e97fac443bca31de8bd98d3263d2fcf/watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26", size = 79078, upload-time = "2024-11-01T14:07:05.189Z" }, + { url = "https://files.pythonhosted.org/packages/62/ae/a696eb424bedff7407801c257d4b1afda455fe40821a2be430e173660e81/watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c", size = 79077, upload-time = "2024-11-01T14:07:06.376Z" }, + { url = "https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2", size = 79078, upload-time = "2024-11-01T14:07:07.547Z" }, + { url = "https://files.pythonhosted.org/packages/07/f6/d0e5b343768e8bcb4cda79f0f2f55051bf26177ecd5651f84c07567461cf/watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a", size = 79065, upload-time = "2024-11-01T14:07:09.525Z" }, + { url = "https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", size = 79070, upload-time = "2024-11-01T14:07:10.686Z" }, + { url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", size = 79067, upload-time = "2024-11-01T14:07:11.845Z" }, +] + [[package]] name = "wcwidth" version = "0.8.2"