From 21ea3a2c8128f088b94b07c8dee7e4f86774e111 Mon Sep 17 00:00:00 2001 From: sysops Date: Tue, 9 Jun 2026 10:41:13 +0000 Subject: [PATCH] =?UTF-8?q?SysOps:=20deploy-all=20=E2=80=94=202026-06-09?= =?UTF-8?q?=2010:41=20UTC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 8 + cockpit/app/main.py | 2 + cockpit/app/routes/admin_api.py | 142 ++++- cockpit/app/routes/agents.py | 4 +- cockpit/app/routes/agents_api.py | 135 ++++- cockpit/app/routes/marketing_api.py | 5 +- cockpit/app/routes/packaging.py | 241 ++++++-- cockpit/app/routes/projects_api.py | 197 ++++++ cockpit/app/routes/retail.py | 67 +++ cockpit/app/services/agent_approvals.py | 193 ++++++ cockpit/app/services/agent_souls.py | 34 +- cockpit/app/services/briefing.py | 198 +++++- cockpit/app/services/herman.py | 68 +++ cockpit/app/services/nas_folders.py | 104 ++++ cockpit/app/services/packaging_agent.py | 232 +++++++ cockpit/app/services/packaging_nas.py | 93 +++ cockpit/app/services/projects.py | 234 +++++++ cockpit/app/services/social_publish.py | 32 +- cockpit/app/services/ui_preferences.py | 82 +++ cockpit/static/css/agent-characters.css | 210 +++++++ cockpit/static/css/agents-mesh.css | 40 ++ cockpit/static/css/clients-crm.css | 93 +++ cockpit/static/css/herman-dashboard.css | 80 ++- cockpit/static/css/ops-topology.css | 199 +++--- cockpit/static/css/packaging-studio.css | 205 +++++++ cockpit/static/css/projects-hub.css | 63 ++ cockpit/static/i18n/en.json | 118 ++++ cockpit/static/i18n/nl.json | 118 ++++ cockpit/static/img/agents/sysops.png | Bin 0 -> 252039 bytes cockpit/static/js/agent-avatars.js | 109 ++++ cockpit/static/js/agents-mesh.js | 107 ++-- cockpit/static/js/analytics.js | 44 +- cockpit/static/js/briefing-charts.js | 64 +- cockpit/static/js/cockpit.js | 4 +- cockpit/static/js/dashboard-layout.js | 97 +++ cockpit/static/js/global-viz.js | 57 ++ cockpit/static/js/i18n.js | 80 +++ cockpit/static/js/ops-topology.js | 222 +++++++ cockpit/static/js/page-viz.js | 27 + cockpit/static/js/viz-engine.js | 218 +++++++ cockpit/templates/agents.html | 270 +++++++-- cockpit/templates/analytics.html | 2 +- cockpit/templates/base.html | 72 ++- cockpit/templates/clients.html | 569 ++++++++++++++++-- cockpit/templates/dashboard.html | 196 ++++-- cockpit/templates/documents.html | 142 ++++- cockpit/templates/herman_chat.html | 15 +- cockpit/templates/marketing.html | 76 ++- cockpit/templates/ops.html | 279 ++++++--- cockpit/templates/packaging.html | 438 ++++++++++---- cockpit/templates/products.html | 274 ++++++++- cockpit/templates/projects.html | 344 +++++++++++ cockpit/templates/suppliers.html | 250 +++++++- deploy-all.sh | 37 ++ docker-compose.yml | 13 + docs/AGENTS.md | 7 + docs/CONTEXT.md | 56 ++ docs/DEPLOY.md | 2 + docs/PLATFORM-AZ.md | 250 ++++++++ migrations/017_retaildetail_food_trending.sql | 15 + migrations/018_agent_approvals.sql | 45 ++ migrations/019_projects_ui_preferences.sql | 56 ++ migrations/020_sysops_backup_ops.sql | 58 ++ migrations/021_locale_preferences.sql | 3 + migrations/022_projects_nas_structure.sql | 11 + migrations/023_sysops_activity_log.sql | 16 + scripts/herman_daily_digest.py | 25 + scripts/herman_platform_update.py | 46 ++ scripts/setup_gitea_sysops.sh | 58 ++ scripts/sysops_daily.py | 99 +++ tools-api/Dockerfile | 4 +- tools-api/app/connectors/config_backup.py | 144 +++++ tools-api/app/connectors/gitea_repo_sync.py | 248 ++++++++ tools-api/app/connectors/ops_maintenance.py | 179 ++++++ tools-api/app/connectors/project_assets.py | 83 +++ tools-api/app/connectors/proxmox.py | 335 +++++------ tools-api/app/ops_routes.py | 51 ++ tools-api/app/packaging/generator.py | 463 ++++++++++---- tools-api/app/packaging_routes.py | 278 ++++++++- tools-api/app/research.py | 19 + tools-api/app/retail.py | 99 ++- tools-api/app/retail_crm.py | 34 ++ 82 files changed, 8906 insertions(+), 981 deletions(-) create mode 100644 cockpit/app/routes/projects_api.py create mode 100644 cockpit/app/services/agent_approvals.py create mode 100644 cockpit/app/services/nas_folders.py create mode 100644 cockpit/app/services/packaging_agent.py create mode 100644 cockpit/app/services/packaging_nas.py create mode 100644 cockpit/app/services/projects.py create mode 100644 cockpit/app/services/ui_preferences.py create mode 100644 cockpit/static/css/agent-characters.css create mode 100644 cockpit/static/css/clients-crm.css create mode 100644 cockpit/static/css/packaging-studio.css create mode 100644 cockpit/static/css/projects-hub.css create mode 100644 cockpit/static/i18n/en.json create mode 100644 cockpit/static/i18n/nl.json create mode 100644 cockpit/static/img/agents/sysops.png create mode 100644 cockpit/static/js/agent-avatars.js create mode 100644 cockpit/static/js/dashboard-layout.js create mode 100644 cockpit/static/js/global-viz.js create mode 100644 cockpit/static/js/i18n.js create mode 100644 cockpit/static/js/ops-topology.js create mode 100644 cockpit/static/js/page-viz.js create mode 100644 cockpit/static/js/viz-engine.js create mode 100644 cockpit/templates/projects.html create mode 100644 docs/CONTEXT.md create mode 100644 docs/PLATFORM-AZ.md create mode 100644 migrations/017_retaildetail_food_trending.sql create mode 100644 migrations/018_agent_approvals.sql create mode 100644 migrations/019_projects_ui_preferences.sql create mode 100644 migrations/020_sysops_backup_ops.sql create mode 100644 migrations/021_locale_preferences.sql create mode 100644 migrations/022_projects_nas_structure.sql create mode 100644 migrations/023_sysops_activity_log.sql create mode 100644 scripts/herman_daily_digest.py create mode 100644 scripts/herman_platform_update.py create mode 100755 scripts/setup_gitea_sysops.sh create mode 100644 scripts/sysops_daily.py create mode 100644 tools-api/app/connectors/config_backup.py create mode 100644 tools-api/app/connectors/gitea_repo_sync.py create mode 100644 tools-api/app/connectors/ops_maintenance.py create mode 100644 tools-api/app/connectors/project_assets.py diff --git a/README.md b/README.md index 43ec7e7..1eee8c3 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,8 @@ docker compose up -d ## Documentatie +- **[Platform A–Z](docs/PLATFORM-AZ.md)** — volledige referentie (start hier) +- **[Context voor Cursor](docs/CONTEXT.md)** — korte import op andere laptop - [Architectuur](docs/ARCHITECTURE.md) - [Deploy](docs/DEPLOY.md) - [Apps & pagina's](docs/APPS.md) @@ -31,6 +33,12 @@ docker compose up -d - [Agents](docs/AGENTS.md) - [CSS thema](docs/CSS-THEME.md) +## Gitea & SysOps + +- Repository: http://10.4.7.18:3001/aissa/foodlinkk-command-center +- **SysOps** pusht bij elke `deploy-all.sh` de volledige codebase naar `main` +- SysOps-verslag: IT Ops tab + Herman dagbriefing + ## Belangrijkste routes - `/` — Herman dashboard diff --git a/cockpit/app/main.py b/cockpit/app/main.py index 691ee93..ca3fc16 100644 --- a/cockpit/app/main.py +++ b/cockpit/app/main.py @@ -36,6 +36,7 @@ from app.routes.admin_api import admin_router, ai_router, herman_api, voice_api from app.routes.settings_api import settings_router from app.routes.agents_api import router as agents_api_router from app.routes.marketing_api import router as marketing_api_router +from app.routes.projects_api import router as projects_api_router BASE_DIR = Path(__file__).resolve().parent.parent templates = Jinja2Templates(directory=str(BASE_DIR / "templates")) @@ -74,6 +75,7 @@ for r in ( settings_router, agents_api_router, marketing_api_router, + projects_api_router, ): app.include_router(r) diff --git a/cockpit/app/routes/admin_api.py b/cockpit/app/routes/admin_api.py index 59bc07e..7e835dc 100644 --- a/cockpit/app/routes/admin_api.py +++ b/cockpit/app/routes/admin_api.py @@ -168,7 +168,15 @@ class DelegateBody(BaseModel): @admin_router.get("/clients") def list_clients(): return {"items": _serialize_rows(fetch_all( - "SELECT * FROM clients ORDER BY updated_at DESC NULLS LAST, created_at DESC LIMIT 500" + """SELECT c.*, + (SELECT COUNT(*) FROM client_supermarket_links l WHERE l.client_id = c.id) + + (SELECT COUNT(*) FROM supermarkets s WHERE s.client_id = c.id + AND NOT EXISTS ( + SELECT 1 FROM client_supermarket_links l2 + WHERE l2.supermarket_id = s.id AND l2.client_id = c.id + )) AS store_count + FROM clients c + ORDER BY c.updated_at DESC NULLS LAST, c.created_at DESC LIMIT 500""" ))} @@ -199,6 +207,79 @@ def delete_client(client_id: int): return {"ok": True} +@admin_router.get("/clients/stats") +def clients_stats(): + stats: dict[str, Any] = {} + try: + rows = fetch_all("SELECT stage, COUNT(*) AS n FROM clients GROUP BY stage") + stats["by_stage"] = {r["stage"]: int(r["n"]) for r in rows} + stats["total"] = sum(stats["by_stage"].values()) + stats["active"] = stats["by_stage"].get("active", 0) + row = fetch_one("SELECT COALESCE(SUM(mrr_estimate),0) AS s FROM clients WHERE stage NOT IN ('churned')") + stats["mrr_total"] = float(row["s"] or 0) if row else 0 + row = fetch_one( + """SELECT COALESCE(SUM(d.value),0) AS s FROM deals d + JOIN clients c ON c.id = d.client_id + WHERE d.stage NOT IN ('won','lost')""" + ) + stats["pipeline_value"] = float(row["s"] or 0) if row else 0 + row = fetch_one("SELECT COUNT(*) AS n FROM client_supermarket_links") + stats["store_links"] = int(row["n"] or 0) if row else 0 + row = fetch_one("SELECT COUNT(*) AS n FROM deals") + stats["deals"] = int(row["n"] or 0) if row else 0 + except Exception: + stats = {"total": 0, "active": 0, "mrr_total": 0, "pipeline_value": 0, "store_links": 0, "deals": 0, "by_stage": {}} + return {"ok": True, "stats": stats} + + +@admin_router.get("/clients/{client_id}/detail") +def client_detail(client_id: int): + client = fetch_one("SELECT * FROM clients WHERE id = %s", (client_id,)) + if not client: + raise HTTPException(404, "Client not found") + deals = fetch_all( + """SELECT id, title, value, stage, next_action, deadline, updated_at + FROM deals WHERE client_id = %s ORDER BY updated_at DESC NULLS LAST LIMIT 20""", + (client_id,), + ) + stores = fetch_all( + """ + SELECT s.id, s.name, s.chain, s.city, s.province, s.postcode, s.phone, s.email, + s.partnership_status, s.halal_certified, s.has_halal_section, s.manager_name, + l.relationship_type, l.notes AS link_notes, l.deal_id, l.created_at AS linked_at + FROM client_supermarket_links l + JOIN supermarkets s ON s.id = l.supermarket_id + WHERE l.client_id = %s + ORDER BY s.chain, s.city, s.name + """, + (client_id,), + ) + direct = fetch_all( + """ + SELECT s.id, s.name, s.chain, s.city, s.province, s.postcode, s.phone, s.email, + s.partnership_status, s.halal_certified, s.has_halal_section, s.manager_name, + 'direct' AS relationship_type, NULL AS link_notes, s.deal_id, s.last_updated AS linked_at + FROM supermarkets s + WHERE s.client_id = %s + AND NOT EXISTS ( + SELECT 1 FROM client_supermarket_links l + WHERE l.supermarket_id = s.id AND l.client_id = s.client_id + ) + ORDER BY s.chain, s.city, s.name + """, + (client_id,), + ) + merged: dict[int, dict] = {} + for row in list(stores) + list(direct): + merged[int(row["id"])] = row + return { + "ok": True, + "client": _serialize(client), + "deals": _serialize_rows(deals), + "stores": _serialize_rows(list(merged.values())), + } + + # --- Deals CRUD --- @admin_router.get("/deals") @@ -239,6 +320,36 @@ def delete_deal(deal_id: int): # --- Products CRUD --- +@admin_router.get("/products/stats") +def products_stats(): + stats: dict[str, Any] = {} + try: + row = fetch_one("SELECT COUNT(*) AS n FROM products") + stats["total"] = int(row["n"] or 0) if row else 0 + rows = fetch_all("SELECT status, COUNT(*) AS n FROM products GROUP BY status") + stats["by_status"] = {r["status"]: int(r["n"]) for r in rows} + stats["active"] = stats["by_status"].get("active", 0) + row = fetch_one("SELECT AVG(margin_pct) AS a FROM products WHERE margin_pct IS NOT NULL") + stats["avg_margin"] = round(float(row["a"] or 0), 1) if row else 0 + row = fetch_one("SELECT COUNT(*) AS n FROM products WHERE client_id IS NOT NULL") + stats["with_client"] = int(row["n"] or 0) if row else 0 + except Exception: + stats = {"total": 0, "active": 0, "avg_margin": 0, "with_client": 0, "by_status": {}} + return {"ok": True, "stats": stats} + + +@admin_router.get("/products/{product_id}/detail") +def product_detail(product_id: int): + product = fetch_one( + """SELECT p.*, c.name AS client_name, c.email AS client_email, c.stage AS client_stage + FROM products p LEFT JOIN clients c ON c.id = p.client_id WHERE p.id = %s""", + (product_id,), + ) + if not product: + raise HTTPException(404, "Product not found") + return {"ok": True, "product": _serialize(product)} + + @admin_router.get("/products") def list_products(): return {"items": _serialize_rows(fetch_all( @@ -284,6 +395,35 @@ def margin_calc(body: MarginBody): # --- Suppliers CRUD --- +@admin_router.get("/suppliers/stats") +def suppliers_stats(): + stats: dict[str, Any] = {} + try: + row = fetch_one("SELECT COUNT(*) AS n FROM suppliers") + stats["total"] = int(row["n"] or 0) if row else 0 + row = fetch_one("SELECT AVG(rating) AS a FROM suppliers WHERE rating IS NOT NULL") + stats["avg_rating"] = round(float(row["a"] or 0), 1) if row else 0 + row = fetch_one("SELECT COUNT(DISTINCT country) AS n FROM suppliers WHERE country IS NOT NULL AND country <> ''") + stats["countries"] = int(row["n"] or 0) if row else 0 + row = fetch_one("SELECT AVG(lead_time_days) AS a FROM suppliers WHERE lead_time_days IS NOT NULL") + stats["avg_lead"] = round(float(row["a"] or 0), 0) if row else 0 + rows = fetch_all( + "SELECT COALESCE(category, 'Overig') AS category, COUNT(*) AS n FROM suppliers GROUP BY category ORDER BY n DESC LIMIT 8" + ) + stats["by_category"] = {r["category"]: int(r["n"]) for r in rows} + except Exception: + stats = {"total": 0, "avg_rating": 0, "countries": 0, "avg_lead": 0, "by_category": {}} + return {"ok": True, "stats": stats} + + +@admin_router.get("/suppliers/{supplier_id}/detail") +def supplier_detail(supplier_id: int): + supplier = fetch_one("SELECT * FROM suppliers WHERE id = %s", (supplier_id,)) + if not supplier: + raise HTTPException(404, "Supplier not found") + return {"ok": True, "supplier": _serialize(supplier)} + + @admin_router.get("/suppliers") def list_suppliers(): return {"items": _serialize_rows(fetch_all("SELECT * FROM suppliers ORDER BY name LIMIT 500"))} diff --git a/cockpit/app/routes/agents.py b/cockpit/app/routes/agents.py index 08310ce..131bffe 100644 --- a/cockpit/app/routes/agents.py +++ b/cockpit/app/routes/agents.py @@ -12,7 +12,7 @@ BASE_DIR = Path(__file__).resolve().parent.parent.parent templates = Jinja2Templates(directory=str(BASE_DIR / "templates")) AGENT_STATUSES = [ - {"name": "Herman", "role": "CEO Briefing", "color": "cyan"}, + {"name": "Herman", "role": "Co-CEO · Takenverdeler", "color": "cyan"}, {"name": "Sales", "role": "Pipeline", "color": "purple"}, {"name": "Marketing", "role": "Social & Content", "color": "amber"}, {"name": "Ops", "role": "Operations", "color": "green"}, @@ -22,7 +22,7 @@ AGENT_STATUSES = [ @router.get("") async def agents_page(request: Request): active_tab = request.query_params.get("tab", "souls") - if active_tab not in {"souls", "mesh"}: + if active_tab not in {"souls", "mesh", "approvals"}: active_tab = "souls" events: list = [] try: diff --git a/cockpit/app/routes/agents_api.py b/cockpit/app/routes/agents_api.py index 433a41b..bd2efab 100644 --- a/cockpit/app/routes/agents_api.py +++ b/cockpit/app/routes/agents_api.py @@ -7,7 +7,7 @@ from fastapi import APIRouter, HTTPException from pydantic import BaseModel, Field from app.db import fetch_all -from app.services import agent_souls +from app.services import agent_approvals, agent_souls router = APIRouter(prefix="/api/agents", tags=["agents-api"]) @@ -20,6 +20,21 @@ class SoulUpdate(BaseModel): is_active: Optional[bool] = None +class ActionRequestBody(BaseModel): + agent_key: str + title: str = Field(..., min_length=1, max_length=255) + action_type: str = "query" + query_payload: dict[str, Any] = Field(default_factory=dict) + + +class RejectBody(BaseModel): + reason: str = "" + + +class ExecuteBody(BaseModel): + result: dict[str, Any] = Field(default_factory=dict) + + @router.get("/souls") def api_list_souls() -> dict[str, Any]: return {"items": agent_souls.list_souls(), "count": len(agent_souls.list_souls())} @@ -33,6 +48,15 @@ def api_get_soul(agent_key: str) -> dict[str, Any]: return {"soul": soul} +@router.get("/souls/{agent_key}/events") +def api_list_agent_events(agent_key: str, limit: int = 50) -> dict[str, Any]: + soul = agent_souls.get_soul(agent_key) + if not soul: + raise HTTPException(404, "Agent not found") + items = agent_souls.list_agent_events(agent_key, limit=min(limit, 100)) + return {"agent_key": agent_key.lower(), "items": items, "count": len(items)} + + @router.put("/souls/{agent_key}") def api_update_soul(agent_key: str, body: SoulUpdate) -> dict[str, Any]: try: @@ -92,4 +116,111 @@ def api_agents_mesh() -> dict[str, Any]: """ ) edges = [{"source": str(r["source_key"]), "target": "herman", "weight": int(r["weight"])} for r in edge_rows] - return {"nodes": nodes, "edges": edges} + return {"nodes": nodes, "edges": edges, "executives": [{"id": "ceo", "label": "CEO", "role": "Aissa"}, {"id": "cto", "label": "CTO", "role": "Platform"}]} + + +@router.get("/approvals") +def api_list_approvals(status: Optional[str] = None, limit: int = 50) -> dict[str, Any]: + try: + items = agent_approvals.list_requests(status=status, limit=limit) + except Exception as exc: + raise HTTPException(status_code=500, detail=str(exc)) from exc + return {"items": items, "count": len(items)} + + +@router.post("/requests") +def api_create_action_request(body: ActionRequestBody) -> dict[str, Any]: + try: + req = agent_approvals.create_request( + body.agent_key, + body.title, + action_type=body.action_type, + query_payload=body.query_payload, + ) + except ValueError as exc: + raise HTTPException(status_code=400, detail=str(exc)) from exc + except Exception as exc: + raise HTTPException(status_code=500, detail=str(exc)) from exc + return {"ok": True, "request": req, "message": "Wacht op goedkeuring voordat query uitgevoerd mag worden"} + + +@router.post("/approvals/{request_id}/approve") +def api_approve_request(request_id: int) -> dict[str, Any]: + import os + + import httpx + + try: + req = agent_approvals.approve_request(request_id, approved_by="ceo") + action = req.get("action_type") or "" + auto_result = None + + if action in ("config_backup", "maintenance_scan"): + tools_url = os.getenv("TOOLS_API_URL", "http://tools-api:8700").rstrip("/") + path = "/ops/backup/run" if action == "config_backup" else "/ops/maintenance/scan" + payload = {"approval_request_id": request_id} if action == "config_backup" else None + with httpx.Client(timeout=180.0) as client: + resp = client.post(f"{tools_url}{path}", json=payload or {}) + try: + auto_result = resp.json() + except Exception: + auto_result = {"ok": False, "detail": resp.text} + req = agent_approvals.mark_executed(request_id, auto_result or {}) + + except ValueError as exc: + raise HTTPException(status_code=404, detail=str(exc)) from exc + except Exception as exc: + raise HTTPException(status_code=500, detail=str(exc)) from exc + return {"ok": True, "request": req, "executed": auto_result is not None, "result": auto_result} + + +@router.post("/approvals/{request_id}/reject") +def api_reject_request(request_id: int, body: RejectBody) -> dict[str, Any]: + try: + req = agent_approvals.reject_request(request_id, reason=body.reason) + except ValueError as exc: + raise HTTPException(status_code=404, detail=str(exc)) from exc + return {"ok": True, "request": req} + + +@router.post("/approvals/{request_id}/execute") +def api_execute_approved_request(request_id: int, body: ExecuteBody) -> dict[str, Any]: + import os + + import httpx + + try: + req = agent_approvals.require_approved(request_id) + result_payload = body.result or {} + action = req.get("action_type") or "" + + if action == "config_backup": + tools_url = os.getenv("TOOLS_API_URL", "http://tools-api:8700").rstrip("/") + with httpx.Client(timeout=180.0) as client: + resp = client.post( + f"{tools_url}/ops/backup/run", + json={"approval_request_id": request_id}, + ) + try: + result_payload = resp.json() + except Exception: + result_payload = {"ok": False, "detail": resp.text} + if resp.status_code >= 400: + raise HTTPException(status_code=502, detail=result_payload.get("detail") or resp.text) + + elif action == "maintenance_scan": + tools_url = os.getenv("TOOLS_API_URL", "http://tools-api:8700").rstrip("/") + with httpx.Client(timeout=120.0) as client: + resp = client.post(f"{tools_url}/ops/maintenance/scan") + result_payload = resp.json() if resp.status_code < 400 else {"ok": False, "detail": resp.text} + + req = agent_approvals.mark_executed(request_id, result_payload) + except HTTPException: + raise + except PermissionError as exc: + raise HTTPException(status_code=403, detail=str(exc)) from exc + except ValueError as exc: + raise HTTPException(status_code=404, detail=str(exc)) from exc + except Exception as exc: + raise HTTPException(status_code=500, detail=str(exc)) from exc + return {"ok": True, "request": req} diff --git a/cockpit/app/routes/marketing_api.py b/cockpit/app/routes/marketing_api.py index 7141ccb..4b6dea0 100644 --- a/cockpit/app/routes/marketing_api.py +++ b/cockpit/app/routes/marketing_api.py @@ -35,6 +35,7 @@ class PublishRequest(BaseModel): image_url: str | None = None media_ids: list[int] = Field(default_factory=list) channels: list[str] = Field(default_factory=list) + project_id: int | None = None @router.post("/upload") @@ -91,7 +92,9 @@ def create_publish_job(body: PublishRequest, background_tasks: BackgroundTasks) ), ) job_id = int(row["id"]) - background_tasks.add_task(run_publish_job, job_id, body.text, channels, body.image_url, body.media_ids) + background_tasks.add_task( + run_publish_job, job_id, body.text, channels, body.image_url, body.media_ids, body.project_id, + ) return {"job_id": job_id, "status": "queued", "channels": channels} diff --git a/cockpit/app/routes/packaging.py b/cockpit/app/routes/packaging.py index 3c2fd60..e243c21 100644 --- a/cockpit/app/routes/packaging.py +++ b/cockpit/app/routes/packaging.py @@ -1,18 +1,21 @@ from __future__ import annotations from pathlib import Path +from typing import Any, Optional import httpx -from fastapi import APIRouter, HTTPException, Request +from fastapi import APIRouter, HTTPException, Query, Request from fastapi.responses import Response from fastapi.templating import Jinja2Templates from pydantic import BaseModel, Field from app.config import settings +from app.services import packaging_nas, projects router = APIRouter(tags=["packaging"]) BASE_DIR = Path(__file__).resolve().parent.parent.parent templates = Jinja2Templates(directory=str(BASE_DIR / "templates")) +TOOLS = settings.TOOLS_API_URL.rstrip("/") class PackagingGenerateBody(BaseModel): @@ -20,68 +23,226 @@ class PackagingGenerateBody(BaseModel): width_mm: float = Field(default=120, gt=0) height_mm: float = Field(default=80, gt=0) depth_mm: float = Field(default=40, ge=0) + bleed_mm: float = Field(default=3, ge=0) elements: dict[str, bool] = Field(default_factory=dict) brand: dict[str, str] = Field(default_factory=dict) - barcode_value: str | None = Field(default=None) + text: dict[str, Any] = Field(default_factory=dict) + barcode_value: str | None = None + qr_value: str | None = None + design_name: str | None = None + project_id: int | None = None + project_name: str | None = None + client_id: int | None = None + created_by: str = "ceo" + + +class PackagingEmailBody(BaseModel): + to: list[str] = Field(..., min_length=1) + subject: str = Field(..., min_length=1) + body: str = "" + cc: list[str] = Field(default_factory=list) + client_id: int | None = None + + +class CopyToProjectBody(BaseModel): + target_project_id: int + + +async def _tools_request(method: str, path: str, **kwargs) -> httpx.Response: + async with httpx.AsyncClient(timeout=120.0) as client: + r = await client.request(method, f"{TOOLS}{path}", **kwargs) + return r + + +def _tools_error(exc: httpx.HTTPStatusError) -> HTTPException: + detail = exc.response.text[:500] if exc.response else str(exc) + return HTTPException(status_code=exc.response.status_code if exc.response else 502, detail=detail) + + +async def _ensure_project(body: PackagingGenerateBody) -> PackagingGenerateBody: + if body.project_id or not body.project_name: + return body + proj = projects.create_project( + body.project_name.strip(), + client_id=body.client_id, + description="Packaging design project", + project_type="packaging", + ensure_nas=True, + ) + data = body.model_dump() + data["project_id"] = proj.get("id") + return PackagingGenerateBody(**data) + + +async def _post_nas_export(result: dict[str, Any]) -> dict[str, Any]: + pid = result.get("cockpit_project_id") + packaging_id = result.get("id") + svg = result.get("svg") or "" + spec = result.get("spec") or {} + if not pid or not packaging_id or not svg: + return result + png_bytes = pdf_bytes = None + try: + png_r = await _tools_request("GET", f"/packaging/download/{packaging_id}", params={"format": "png"}) + if png_r.status_code < 400: + png_bytes = png_r.content + pdf_r = await _tools_request("GET", f"/packaging/download/{packaging_id}", params={"format": "pdf"}) + if pdf_r.status_code < 400: + pdf_bytes = pdf_r.content + except Exception: + pass + try: + nas_info = packaging_nas.export_packaging_files(packaging_id, int(pid), svg, spec, png_bytes, pdf_bytes) + result["nas"] = nas_info + except Exception as exc: + result["nas"] = {"ok": False, "error": str(exc)} + return result @router.get("/packaging") -async def packaging_page(request: Request): +async def packaging_page(request: Request, project_id: Optional[int] = None): return templates.TemplateResponse( "packaging.html", - {"request": request, "page_title": "Packaging Studio"}, + {"request": request, "page_title": "Packaging Studio", "initial_project_id": project_id}, ) +@router.get("/api/packaging/types") +async def proxy_packaging_types(): + try: + r = await _tools_request("GET", "/packaging/types") + r.raise_for_status() + return r.json() + except httpx.HTTPStatusError as exc: + raise _tools_error(exc) from exc + + +@router.post("/api/packaging/preview") +async def proxy_packaging_preview(body: PackagingGenerateBody): + try: + r = await _tools_request("POST", "/packaging/preview", json=body.model_dump()) + r.raise_for_status() + return r.json() + except httpx.HTTPStatusError as exc: + raise _tools_error(exc) from exc + + @router.post("/api/packaging/generate") async def proxy_packaging_generate(body: PackagingGenerateBody): try: - async with httpx.AsyncClient(timeout=60.0) as client: - r = await client.post( - f"{settings.TOOLS_API_URL.rstrip('/')}/packaging/generate", - json=body.model_dump(), - ) - r.raise_for_status() - return r.json() + body = await _ensure_project(body) + r = await _tools_request("POST", "/packaging/generate", json=body.model_dump()) + r.raise_for_status() + result = r.json() + return await _post_nas_export(result) except httpx.HTTPStatusError as exc: - detail = exc.response.text[:400] if exc.response else str(exc) - raise HTTPException(status_code=exc.response.status_code if exc.response else 502, detail=detail) from exc - except Exception as exc: - raise HTTPException(status_code=502, detail=str(exc)) from exc + raise _tools_error(exc) from exc @router.get("/api/packaging/projects") async def proxy_packaging_projects(limit: int = 30): try: - async with httpx.AsyncClient(timeout=30.0) as client: - r = await client.get( - f"{settings.TOOLS_API_URL.rstrip('/')}/packaging/projects", - params={"limit": limit}, - ) - r.raise_for_status() - return r.json() + r = await _tools_request("GET", "/packaging/projects", params={"limit": limit}) + r.raise_for_status() + return r.json() except httpx.HTTPStatusError as exc: - detail = exc.response.text[:400] if exc.response else str(exc) - raise HTTPException(status_code=exc.response.status_code if exc.response else 502, detail=detail) from exc - except Exception as exc: - raise HTTPException(status_code=502, detail=str(exc)) from exc + raise _tools_error(exc) from exc @router.get("/api/packaging/download/{project_id}") async def proxy_packaging_download(project_id: str, format: str = "svg"): try: - async with httpx.AsyncClient(timeout=120.0) as client: - r = await client.get( - f"{settings.TOOLS_API_URL.rstrip('/')}/packaging/download/{project_id}", - params={"format": format}, - ) - r.raise_for_status() - media = r.headers.get("content-type", "application/octet-stream") - disposition = r.headers.get("content-disposition") - headers = {"content-disposition": disposition} if disposition else {} - return Response(content=r.content, media_type=media, headers=headers) + r = await _tools_request("GET", f"/packaging/download/{project_id}", params={"format": format}) + r.raise_for_status() + media = r.headers.get("content-type", "application/octet-stream") + disposition = r.headers.get("content-disposition") + headers = {"content-disposition": disposition} if disposition else {} + return Response(content=r.content, media_type=media, headers=headers) except httpx.HTTPStatusError as exc: - detail = exc.response.text[:400] if exc.response else str(exc) - raise HTTPException(status_code=exc.response.status_code if exc.response else 502, detail=detail) from exc - except Exception as exc: - raise HTTPException(status_code=502, detail=str(exc)) from exc + raise _tools_error(exc) from exc + + +@router.get("/api/packaging/{packaging_id}") +async def proxy_packaging_get(packaging_id: str): + try: + r = await _tools_request("GET", f"/packaging/{packaging_id}") + r.raise_for_status() + return r.json() + except httpx.HTTPStatusError as exc: + raise _tools_error(exc) from exc + + +@router.patch("/api/packaging/{packaging_id}") +async def proxy_packaging_update(packaging_id: str, body: PackagingGenerateBody): + try: + r = await _tools_request("PATCH", f"/packaging/{packaging_id}", json={"spec": body.model_dump()}) + r.raise_for_status() + result = r.json() + return await _post_nas_export(result) + except httpx.HTTPStatusError as exc: + raise _tools_error(exc) from exc + + +@router.post("/api/packaging/{packaging_id}/duplicate") +async def proxy_packaging_duplicate(packaging_id: str): + try: + r = await _tools_request("POST", f"/packaging/{packaging_id}/duplicate") + r.raise_for_status() + result = r.json() + return await _post_nas_export(result) + except httpx.HTTPStatusError as exc: + raise _tools_error(exc) from exc + + +@router.post("/api/packaging/{packaging_id}/copy-to-project") +async def proxy_packaging_copy(packaging_id: str, body: CopyToProjectBody): + try: + r = await _tools_request( + "POST", + f"/packaging/{packaging_id}/copy-to-project", + json=body.model_dump(), + ) + r.raise_for_status() + result = r.json() + return await _post_nas_export(result) + except httpx.HTTPStatusError as exc: + raise _tools_error(exc) from exc + + +@router.delete("/api/packaging/{packaging_id}") +async def proxy_packaging_delete(packaging_id: str): + try: + r = await _tools_request("DELETE", f"/packaging/{packaging_id}") + r.raise_for_status() + return r.json() + except httpx.HTTPStatusError as exc: + raise _tools_error(exc) from exc + + +@router.post("/api/packaging/{packaging_id}/email") +async def proxy_packaging_email(packaging_id: str, body: PackagingEmailBody): + base = settings.COCKPIT_PUBLIC_URL if hasattr(settings, "COCKPIT_PUBLIC_URL") else "http://10.4.7.18:8600" + links = "\n".join( + f"- {fmt.upper()}: {base}/api/packaging/download/{packaging_id}?format={fmt}" + for fmt in ("svg", "png", "pdf") + ) + email_body = (body.body or "").strip() + if email_body: + email_body += "\n\n" + email_body += f"Packaging downloads:\n{links}" + try: + r = await _tools_request( + "POST", + "/emails/send", + json={ + "to": body.to, + "cc": body.cc, + "subject": body.subject, + "body": email_body, + "client_id": body.client_id, + }, + ) + r.raise_for_status() + return r.json() + except httpx.HTTPStatusError as exc: + raise _tools_error(exc) from exc diff --git a/cockpit/app/routes/projects_api.py b/cockpit/app/routes/projects_api.py new file mode 100644 index 0000000..3a7e5b2 --- /dev/null +++ b/cockpit/app/routes/projects_api.py @@ -0,0 +1,197 @@ +"""Projects + UI preferences API.""" +from __future__ import annotations + +from typing import Any, Optional + +from fastapi import APIRouter, HTTPException, Request +from pydantic import BaseModel, Field + +from app.services import projects, ui_preferences, nas_folders + +router = APIRouter(tags=["projects-api"]) + + +class ProjectCreate(BaseModel): + name: str = Field(..., min_length=1, max_length=255) + client_id: Optional[int] = None + description: str = "" + created_by: str = "ceo" + project_type: str = "general" + priority: str = "normal" + + +class ProjectUpdate(BaseModel): + name: Optional[str] = None + description: Optional[str] = None + status: Optional[str] = None + client_id: Optional[int] = None + project_type: Optional[str] = None + priority: Optional[str] = None + + +class AssetCreate(BaseModel): + asset_type: str + title: str + ref_id: Optional[str] = None + file_path: Optional[str] = None + payload: dict[str, Any] = Field(default_factory=dict) + created_by: str = "ceo" + source_agent: Optional[str] = None + + +class LinkPhotoBody(BaseModel): + project_id: int + created_by: str = "ceo" + + +class LinkNasFileBody(BaseModel): + title: str + file_path: str + asset_type: str = "document" + + +class PreferencesBody(BaseModel): + dashboard_layout: Optional[list[str]] = None + global_viz_mode: Optional[str] = None + viz_modes: Optional[dict[str, str]] = None + locale: Optional[str] = None + + +@router.get("/projects") +async def projects_page(request: Request): + from fastapi.templating import Jinja2Templates + from pathlib import Path + templates = Jinja2Templates(directory=str(Path(__file__).resolve().parent.parent.parent / "templates")) + return templates.TemplateResponse("projects.html", {"request": request, "page_title": "Projecten"}) + + +@router.get("/api/projects/types") +def api_project_types() -> dict[str, Any]: + return {"items": nas_folders.list_types()} + + +@router.get("/api/projects/stats") +def api_project_stats() -> dict[str, Any]: + return {"ok": True, "stats": projects.project_stats()} + + +@router.get("/api/projects") +def api_list_projects(client_id: Optional[int] = None, limit: int = 50) -> dict[str, Any]: + items = projects.list_projects(client_id=client_id, limit=limit) + return {"items": items, "count": len(items)} + + +@router.post("/api/projects") +def api_create_project(body: ProjectCreate) -> dict[str, Any]: + try: + row = projects.create_project( + body.name, + client_id=body.client_id, + description=body.description, + created_by=body.created_by, + project_type=body.project_type, + priority=body.priority, + ) + except Exception as exc: + raise HTTPException(status_code=500, detail=str(exc)) from exc + return {"ok": True, "project": row} + + +@router.get("/api/projects/{project_id}") +def api_get_project(project_id: int) -> dict[str, Any]: + row = projects.get_project(project_id) + if not row: + raise HTTPException(status_code=404, detail="Project not found") + return {"project": row} + + +@router.patch("/api/projects/{project_id}") +def api_update_project(project_id: int, body: ProjectUpdate) -> dict[str, Any]: + row = projects.update_project(project_id, **body.model_dump(exclude_none=True)) + if not row: + raise HTTPException(status_code=404, detail="Project not found") + return {"ok": True, "project": row} + + +@router.post("/api/projects/{project_id}/ensure-nas") +def api_ensure_nas(project_id: int) -> dict[str, Any]: + row = projects.get_project(project_id) + if not row: + raise HTTPException(status_code=404, detail="Project not found") + client_name = row.get("client_name") + try: + paths = nas_folders.ensure_project_folder( + project_id, + row["name"], + row.get("client_id"), + client_name, + row.get("project_type") or "general", + ) + except Exception as exc: + raise HTTPException(status_code=500, detail=str(exc)) from exc + return {"ok": True, **paths} + + +@router.post("/api/projects/{project_id}/assets") +def api_add_asset(project_id: int, body: AssetCreate) -> dict[str, Any]: + if not projects.get_project(project_id): + raise HTTPException(status_code=404, detail="Project not found") + try: + asset = projects.add_asset( + project_id, + body.asset_type, + body.title, + ref_id=body.ref_id, + file_path=body.file_path, + payload=body.payload, + created_by=body.created_by, + source_agent=body.source_agent, + ) + except Exception as exc: + raise HTTPException(status_code=500, detail=str(exc)) from exc + return {"ok": True, "asset": asset} + + +@router.post("/api/projects/{project_id}/link-nas-file") +def api_link_nas_file(project_id: int, body: LinkNasFileBody) -> dict[str, Any]: + if not projects.get_project(project_id): + raise HTTPException(status_code=404, detail="Project not found") + asset = projects.add_asset( + project_id, + body.asset_type, + body.title, + file_path=body.file_path, + created_by="ceo", + ) + return {"ok": True, "asset": asset} + + +@router.post("/api/projects/photos/{photo_id}/link") +def api_link_photo(photo_id: int, body: LinkPhotoBody) -> dict[str, Any]: + try: + projects.link_photo_to_project(photo_id, body.project_id, body.created_by) + except ValueError as exc: + raise HTTPException(status_code=404, detail=str(exc)) from exc + return {"ok": True} + + +@router.get("/api/preferences/ui") +def api_get_ui_preferences() -> dict[str, Any]: + return ui_preferences.get_preferences("ceo") + + +@router.put("/api/preferences/ui") +def api_save_ui_preferences(body: PreferencesBody) -> dict[str, Any]: + allowed = {m["id"] for m in ui_preferences.VIZ_MODES} + if body.global_viz_mode and body.global_viz_mode not in allowed: + raise HTTPException(status_code=400, detail="Invalid viz mode") + if body.locale and body.locale not in ("nl", "en"): + raise HTTPException(status_code=400, detail="Invalid locale (nl or en)") + prefs = ui_preferences.save_preferences( + "ceo", + dashboard_layout=body.dashboard_layout, + global_viz_mode=body.global_viz_mode, + viz_modes=body.viz_modes, + locale=body.locale, + ) + return {"ok": True, "preferences": prefs} diff --git a/cockpit/app/routes/retail.py b/cockpit/app/routes/retail.py index 8b5abd0..1469610 100644 --- a/cockpit/app/routes/retail.py +++ b/cockpit/app/routes/retail.py @@ -25,6 +25,48 @@ class CrmLinkBody(BaseModel): notes: Optional[str] = None +class SupermarketCreateBody(BaseModel): + name: str + chain: str + address: str + postcode: str = "0000AA" + city: str + province: Optional[str] = None + phone: Optional[str] = None + email: Optional[str] = None + website: Optional[str] = None + manager_name: Optional[str] = None + employee_count: Optional[int] = None + store_type: Optional[str] = None + partnership_status: str = "none" + halal_certified: bool = False + has_halal_section: bool = False + halal_certifier: Optional[str] = None + + +class SupermarketPatchBody(BaseModel): + name: Optional[str] = None + chain: Optional[str] = None + address: Optional[str] = None + postcode: Optional[str] = None + city: Optional[str] = None + province: Optional[str] = None + phone: Optional[str] = None + email: Optional[str] = None + website: Optional[str] = None + manager_name: Optional[str] = None + employee_count: Optional[int] = None + store_type: Optional[str] = None + size_m2: Optional[int] = None + partnership_status: Optional[str] = None + halal_certified: Optional[bool] = None + has_halal_section: Optional[bool] = None + halal_certifier: Optional[str] = None + halal_certificate_number: Optional[str] = None + organic_section: Optional[bool] = None + alcohol_section: Optional[bool] = None + + class NoteBody(BaseModel): body: str title: Optional[str] = None @@ -88,6 +130,13 @@ async def _tools_delete(path: str) -> Any: return resp.json() +async def _tools_patch(path: str, json_body: Optional[dict] = None) -> Any: + async with httpx.AsyncClient(timeout=120) as client: + resp = await client.patch(f"{TOOLS}{path}", json=json_body or {}) + resp.raise_for_status() + return resp.json() + + @router.get("/retail") async def retail_page(request: Request): stats = await _tools_get("/retail/stats") @@ -153,6 +202,24 @@ async def api_link_store(store_id: int, body: CrmLinkBody): return JSONResponse(await _tools_post(f"/retail/supermarkets/{store_id}/link", json_body=body.model_dump())) +@router.post("/api/retail/supermarkets") +async def api_create_supermarket(body: SupermarketCreateBody): + return JSONResponse(await _tools_post("/retail/supermarkets", json_body=body.model_dump())) + + +@router.patch("/api/retail/supermarkets/{store_id}") +async def api_patch_supermarket(store_id: int, body: SupermarketPatchBody): + return JSONResponse(await _tools_patch( + f"/retail/supermarkets/{store_id}", + json_body=body.model_dump(exclude_unset=True), + )) + + +@router.delete("/api/retail/supermarkets/{store_id}/link/{client_id}") +async def api_unlink_store(store_id: int, client_id: int): + return JSONResponse(await _tools_delete(f"/retail/supermarkets/{store_id}/link/{client_id}")) + + @router.post("/api/retail/enrich") async def api_retail_enrich(limit: int = Query(100, ge=1, le=200)): return JSONResponse(await _tools_post("/retail/enrich", params={"limit": limit})) diff --git a/cockpit/app/services/agent_approvals.py b/cockpit/app/services/agent_approvals.py new file mode 100644 index 0000000..99cc8ac --- /dev/null +++ b/cockpit/app/services/agent_approvals.py @@ -0,0 +1,193 @@ +"""Agent action approval queue — gate before executing sensitive queries.""" +from __future__ import annotations + +import json +from typing import Any, Optional + +from app.db import execute, fetch_all, fetch_one + + +def _serialize(row: dict[str, Any] | None) -> dict[str, Any] | None: + if not row: + return None + out = dict(row) + for key, val in list(out.items()): + if hasattr(val, "isoformat"): + out[key] = val.isoformat() + return out + + +def has_pending_request(agent_key: str, action_type: str | None = None) -> bool: + clauses = ["agent_key = %s", "status = 'pending'", "created_at >= CURRENT_DATE"] + params: list[Any] = [agent_key.strip().lower()] + if action_type: + clauses.append("action_type = %s") + params.append(action_type) + row = fetch_one( + f"SELECT id FROM agent_action_requests WHERE {' AND '.join(clauses)} LIMIT 1", + tuple(params), + ) + return bool(row) + + +def create_request( + agent_key: str, + title: str, + action_type: str = "query", + query_payload: dict[str, Any] | None = None, +) -> dict[str, Any]: + key = (agent_key or "").strip().lower() + if not key or not title.strip(): + raise ValueError("agent_key and title are required") + + row = fetch_one( + """ + INSERT INTO agent_action_requests (agent_key, action_type, title, query_payload, status) + VALUES (%s, %s, %s, %s::jsonb, 'pending') + RETURNING * + """, + (key, action_type, title.strip(), json.dumps(query_payload or {})), + ) + req = _serialize(row) or {} + + try: + execute( + """ + INSERT INTO agent_events (agent_name, agent_type, event_type, title, body, status, channel, metadata) + VALUES (%s, %s, %s, %s, %s, %s, %s, %s::jsonb) + """, + ( + key, + "agent_request", + "approval_request", + title.strip(), + f"Wacht op goedkeuring — {action_type}", + "needs_approval", + "agents", + json.dumps({"request_id": req.get("id"), "action_type": action_type}), + ), + ) + except Exception: + pass + return req + + +def list_requests(status: Optional[str] = None, limit: int = 50) -> list[dict[str, Any]]: + clauses, params = [], [] + if status: + clauses.append("status = %s") + params.append(status) + where = (" WHERE " + " AND ".join(clauses)) if clauses else "" + safe_limit = max(1, min(limit, 200)) + rows = fetch_all( + f"SELECT * FROM agent_action_requests{where} ORDER BY created_at DESC LIMIT %s", + tuple(params + [safe_limit]), + ) + return [_serialize(r) for r in rows] + + +def get_request(request_id: int) -> dict[str, Any] | None: + return _serialize(fetch_one("SELECT * FROM agent_action_requests WHERE id = %s", (request_id,))) + + +def approve_request(request_id: int, approved_by: str = "ceo") -> dict[str, Any]: + row = fetch_one( + """ + UPDATE agent_action_requests + SET status = 'approved', approved_by = %s, reviewed_at = NOW() + WHERE id = %s AND status = 'pending' + RETURNING * + """, + (approved_by, request_id), + ) + if not row: + raise ValueError("Request not found or not pending") + req = _serialize(row) or {} + try: + execute( + """ + UPDATE agent_events SET status = 'approved' + WHERE status = 'needs_approval' + AND metadata->>'request_id' = %s + """, + (str(request_id),), + ) + except Exception: + pass + return req + + +def reject_request(request_id: int, reason: str = "", rejected_by: str = "ceo") -> dict[str, Any]: + row = fetch_one( + """ + UPDATE agent_action_requests + SET status = 'rejected', approved_by = %s, rejection_reason = %s, reviewed_at = NOW() + WHERE id = %s AND status = 'pending' + RETURNING * + """, + (rejected_by, (reason or "")[:500], request_id), + ) + if not row: + raise ValueError("Request not found or not pending") + req = _serialize(row) or {} + try: + execute( + """ + UPDATE agent_events SET status = 'rejected' + WHERE status = 'needs_approval' + AND metadata->>'request_id' = %s + """, + (str(request_id),), + ) + except Exception: + pass + return req + + +def mark_executed(request_id: int, result: dict[str, Any] | None = None) -> dict[str, Any]: + row = fetch_one( + """ + UPDATE agent_action_requests + SET status = 'executed', executed_at = NOW(), result = %s::jsonb + WHERE id = %s AND status = 'approved' + RETURNING * + """, + (json.dumps(result or {}), request_id), + ) + if not row: + raise ValueError("Request not approved or not found") + req = _serialize(row) or {} + + try: + from app.services import projects as project_svc + + payload = req.get("query_payload") or {} + if isinstance(payload, str): + import json as _json + try: + payload = _json.loads(payload) + except Exception: + payload = {} + pid = payload.get("project_id") + project_svc.register_agent_output( + asset_type=str(req.get("action_type") or "agent_action"), + title=req.get("title") or f"Agent actie #{request_id}", + ref_id=str(request_id), + payload={"result": result or {}, "action_type": req.get("action_type")}, + project_id=int(pid) if pid else None, + source_agent=str(req.get("agent_key") or "agent"), + created_by=str(req.get("approved_by") or "ceo"), + ) + except Exception: + pass + + return req + + +def require_approved(request_id: int) -> dict[str, Any]: + req = get_request(request_id) + if not req: + raise PermissionError("Approval request not found") + if req.get("status") != "approved": + raise PermissionError(f"Request status is {req.get('status')}, approval required") + return req diff --git a/cockpit/app/services/agent_souls.py b/cockpit/app/services/agent_souls.py index 26ed20e..3044260 100644 --- a/cockpit/app/services/agent_souls.py +++ b/cockpit/app/services/agent_souls.py @@ -10,7 +10,13 @@ def list_souls() -> list[dict[str, Any]]: rows = fetch_all( """SELECT s.*, (SELECT COUNT(*) FROM agent_events e WHERE LOWER(e.agent_name) = s.agent_key) AS event_count, - (SELECT MAX(created_at) FROM agent_events e WHERE LOWER(e.agent_name) = s.agent_key) AS last_event_at + (SELECT MAX(created_at) FROM agent_events e WHERE LOWER(e.agent_name) = s.agent_key) AS last_event_at, + (SELECT title FROM agent_events e WHERE LOWER(e.agent_name) = s.agent_key + ORDER BY created_at DESC LIMIT 1) AS current_task, + (SELECT status FROM agent_events e WHERE LOWER(e.agent_name) = s.agent_key + ORDER BY created_at DESC LIMIT 1) AS current_status, + (SELECT event_type FROM agent_events e WHERE LOWER(e.agent_name) = s.agent_key + ORDER BY created_at DESC LIMIT 1) AS current_event_type FROM agent_souls s ORDER BY s.display_name""" ) return [dict(r) for r in rows] @@ -25,13 +31,27 @@ def get_soul(agent_key: str) -> Optional[dict[str, Any]]: ) if not row: return None - events = fetch_all( - """SELECT id, event_type, title, status, created_at FROM agent_events - WHERE LOWER(agent_name) = %s ORDER BY created_at DESC LIMIT 15""", - (agent_key.lower(),), - ) out = dict(row) - out["recent_events"] = [dict(e) for e in events] + out["recent_events"] = list_agent_events(agent_key, limit=15) + return out + + +def list_agent_events(agent_key: str, limit: int = 50) -> list[dict[str, Any]]: + rows = fetch_all( + """SELECT id, agent_name, event_type, title, body, status, channel, metadata, created_at, completed_at + FROM agent_events + WHERE LOWER(agent_name) = %s + ORDER BY created_at DESC + LIMIT %s""", + (agent_key.lower(), limit), + ) + out: list[dict[str, Any]] = [] + for row in rows: + ev = dict(row) + for key in ("created_at", "completed_at"): + if ev.get(key) is not None and hasattr(ev[key], "isoformat"): + ev[key] = ev[key].isoformat() + out.append(ev) return out diff --git a/cockpit/app/services/briefing.py b/cockpit/app/services/briefing.py index d459859..71df946 100644 --- a/cockpit/app/services/briefing.py +++ b/cockpit/app/services/briefing.py @@ -54,6 +54,74 @@ def collect_briefing_data() -> dict[str, Any]: data["pipeline_eur"] = _safe_sum("deals", "value", "stage NOT IN ('won', 'lost')") data["pending_approvals"] = _safe_count("agent_events", "status = 'needs_approval'") + try: + data["pending_approval_requests"] = fetch_all( + """SELECT id, agent_key, action_type, title, query_payload, created_at + FROM agent_action_requests WHERE status = 'pending' + ORDER BY created_at ASC LIMIT 15""" + ) + data["pending_approvals"] = len(data["pending_approval_requests"]) + except Exception: + data["pending_approval_requests"] = [] + + try: + data["recent_executed_actions"] = fetch_all( + """SELECT id, agent_key, action_type, title, result, executed_at, approved_by + FROM agent_action_requests + WHERE status = 'executed' AND executed_at >= NOW() - INTERVAL '24 hours' + ORDER BY executed_at DESC LIMIT 12""" + ) + except Exception: + data["recent_executed_actions"] = [] + + try: + data["project_assets_recent"] = fetch_all( + """SELECT pa.title, pa.asset_type, pa.source_agent, pa.created_at, cp.name AS project_name + FROM project_assets pa + JOIN cockpit_projects cp ON cp.id = pa.project_id + WHERE pa.created_at >= NOW() - INTERVAL '24 hours' + ORDER BY pa.created_at DESC LIMIT 15""" + ) + except Exception: + data["project_assets_recent"] = [] + + try: + data["ops_maintenance_open"] = fetch_all( + """SELECT severity, title, body, created_at FROM ops_maintenance_notes + WHERE resolved = false ORDER BY created_at DESC LIMIT 8""" + ) + except Exception: + data["ops_maintenance_open"] = [] + + try: + data["config_backups_recent"] = fetch_all( + """SELECT status, message, commit_ref, created_at FROM config_backups + ORDER BY created_at DESC LIMIT 5""" + ) + except Exception: + data["config_backups_recent"] = [] + + try: + data["sysops_activity_24h"] = fetch_all( + """SELECT action_type, title, body, commit_ref, files_changed, status, created_at + FROM sysops_activity + WHERE created_at >= NOW() - INTERVAL '24 hours' + ORDER BY created_at DESC LIMIT 20""" + ) + except Exception: + data["sysops_activity_24h"] = [] + + try: + data["sysops_events_24h"] = fetch_all( + """SELECT event_type, title, body, status, created_at, metadata + FROM agent_events + WHERE LOWER(agent_name) = 'sysops' + AND created_at >= NOW() - INTERVAL '24 hours' + ORDER BY created_at DESC LIMIT 15""" + ) + except Exception: + data["sysops_events_24h"] = [] + try: data["deals_by_stage"] = fetch_all( "SELECT stage, COUNT(*) AS cnt, COALESCE(SUM(value), 0) AS total FROM deals GROUP BY stage ORDER BY cnt DESC" @@ -204,20 +272,85 @@ def collect_briefing_data() -> dict[str, Any]: except Exception: data["regulation_highlights"] = [] + try: + data["trending_food"] = fetch_all( + """SELECT i.id, i.title, i.link, i.summary, f.name AS feed_name, f.url AS feed_url, + f.category, i.published_at + FROM rss_items i + JOIN rss_feeds f ON f.id = i.feed_id AND f.is_active = TRUE + WHERE f.category IN ('food', 'markt', 'supermarkt', 'retail', 'kant-en-klaar') + OR f.name ILIKE '%retaildetail%' + ORDER BY i.published_at DESC NULLS LAST, i.fetched_at DESC LIMIT 10""" + ) + except Exception: + data["trending_food"] = [] + try: data["food_market_highlights"] = fetch_all( """SELECT i.title, i.link, i.summary, f.name AS feed_name, f.url AS feed_url, f.category FROM rss_items i JOIN rss_feeds f ON f.id = i.feed_id AND f.is_active = TRUE - WHERE f.category IN ('markt', 'supermarkt', 'kant-en-klaar', 'retail') - OR i.title ILIKE ANY (ARRAY['%supermarkt%','%retail%','%jumbo%','%ahold%','%halal%','%maaltijd%']) + WHERE f.category IN ('food', 'markt', 'supermarkt', 'kant-en-klaar', 'retail') + OR f.name ILIKE '%retaildetail%' ORDER BY i.published_at DESC NULLS LAST LIMIT 10""" ) except Exception: data["food_market_highlights"] = [] + data["activity_log"] = _build_activity_log(data) return data +def _build_activity_log(data: dict[str, Any]) -> list[str]: + lines: list[str] = [] + for row in data.get("pending_approval_requests") or []: + agent = row.get("agent_key") or "agent" + action = row.get("action_type") or "actie" + title = row.get("title") or "" + if action == "maintenance_scan": + lines.append(f"⏳ SysOps vraagt toestemming voor update-scan: {title}") + elif action == "config_backup": + lines.append(f"⏳ SysOps vraagt goedkeuring backup: {title}") + else: + lines.append(f"⏳ {agent} wacht op goedkeuring ({action}): {title}") + + for row in data.get("recent_executed_actions") or []: + lines.append(f"✓ Uitgevoerd door {row.get('agent_key')}: {row.get('title')}") + + for row in data.get("project_assets_recent") or []: + ts = row.get("created_at") + ts_s = ts.isoformat()[:16] if hasattr(ts, "isoformat") else str(ts or "")[:16] + lines.append( + f"📁 Project asset ({row.get('project_name')}): {row.get('title')} " + f"[{row.get('asset_type')} · {row.get('source_agent')}] {ts_s}" + ) + + for row in data.get("ops_maintenance_open") or []: + lines.append(f"🔧 IT Ops [{row.get('severity')}]: {row.get('title')}") + + for row in data.get("config_backups_recent") or []: + lines.append(f"💾 Backup {row.get('status')}: {row.get('message') or row.get('commit_ref')}") + + for row in data.get("sysops_activity_24h") or []: + ts = row.get("created_at") + ts_s = ts.isoformat()[11:16] if hasattr(ts, "isoformat") else "" + cref = f" [{row.get('commit_ref')}]" if row.get("commit_ref") else "" + lines.append(f"🖥️ SysOps {row.get('action_type')}: {row.get('title')}{cref} ({ts_s})") + + for row in data.get("sysops_events_24h") or []: + if (row.get("event_type") or "") == "gitea_sync": + continue + ts = row.get("created_at") + ts_s = ts.isoformat()[11:16] if hasattr(ts, "isoformat") else "" + lines.append(f"🔧 SysOps: {row.get('title')} ({ts_s})") + + for row in (data.get("recent_events") or [])[:8]: + ts = row.get("created_at") + ts_s = ts.isoformat()[11:16] if hasattr(ts, "isoformat") else "" + lines.append(f"⚡ {row.get('agent_name')}: {row.get('title')} ({ts_s})") + + return lines[:25] + + def build_template_report(data: dict[str, Any]) -> str: lines = [ f"# Foodlinkk Dagrapport — {data['date']}", @@ -272,8 +405,30 @@ def build_template_report(data: dict[str, Any]) -> str: ts_s = ts.isoformat()[:16] if hasattr(ts, "isoformat") else str(ts)[:16] lines.append(f"- [{ts_s}] {row.get('title')} ({row.get('client_name') or '-'})") + if data.get("sysops_activity_24h"): + lines.extend(["", "## SysOps IT — laatste 24 uur"]) + for row in data["sysops_activity_24h"][:12]: + ts = row.get("created_at") + ts_s = ts.isoformat()[11:16] if hasattr(ts, "isoformat") else "" + cref = f" · commit `{row.get('commit_ref')}`" if row.get("commit_ref") else "" + lines.append(f"- [{ts_s}] **{row.get('title')}**{cref}") + if row.get("body"): + lines.append(f" {str(row.get('body'))[:200]}") + + if data.get("pending_approval_requests"): + lines.extend(["", "## ⏳ Wacht op jouw goedkeuring (agents)"]) + for row in data["pending_approval_requests"]: + action = row.get("action_type") or "" + label = "Update-scan VM106" if action == "maintenance_scan" else action + lines.append(f"- **{row.get('agent_key')}** · {label}: {row.get('title')}") + + if data.get("activity_log"): + lines.extend(["", "## Herman activiteitenlog (24u)"]) + for entry in data["activity_log"][:20]: + lines.append(f"- {entry}") + if data.get("pending_items"): - lines.extend(["", "## ⚠️ Wacht op jouw goedkeuring"]) + lines.extend(["", "## Legacy goedkeuringen"]) for row in data["pending_items"]: lines.append(f"- {row.get('agent_name')}: {row.get('title')}") @@ -289,21 +444,26 @@ async def _ai_executive_summary(data: dict[str, Any]) -> str: for row in data.get("milestones_pending") or []: ms_lines += f"- {row.get('title')} ({row.get('chain') or 'CRM'}) deadline {row.get('target_date') or '?'}\n" + activity = "\n".join((data.get("activity_log") or [])[:15]) or "- Geen recente agent-acties" + prompt = ( "Schrijf in het Nederlands (markdown) voor CEO Aïssa van Foodlinkk (halal kant-en-klaar maaltijden):\n\n" - "## Samenvatting\n(5-7 zinnen: wat is vandaag belangrijk, pipeline, retail kansen, milestones)\n\n" - "## Actiepunten vandaag — korte termijn\n(minimaal 5 concrete bullets met CRM/retail acties)\n\n" - "## Lange termijn focus\n(3-5 bullets: groei supermarkt partnerships, halal markt, milestones komende weken)\n\n" + "## Samenvatting\n(5-7 zinnen: pipeline, retail, IT ops, agent activiteit vandaag)\n\n" + "## Actiepunten vandaag — korte termijn\n(minimaal 5 bullets — incl. open goedkeuringen SysOps scan/backup)\n\n" + "## Lange termijn focus\n(3-5 bullets)\n\n" + "## Herman documentatie — wat er gebeurde\n(korte chronologische samenvatting van agent-acties, project assets, backups)\n\n" f"Data vandaag ({data['date']}):\n" f"- Pipeline €{data['pipeline_eur']:,.0f}, {data['clients']} klanten, {data['deals']} deals\n" f"- {data.get('supermarkets',0)} supermarkten, {data.get('crm_partnerships',0)} actieve CRM partnerships\n" - f"- {data['pending_approvals']} goedkeuringen open\n" + f"- {data['pending_approvals']} goedkeuringen open in approval queue\n" + f"Activiteitenlog:\n{activity}\n" f"Top kansen:\n{opp_lines or '- geen data'}\n" f"Milestones open:\n{ms_lines or '- geen milestones'}\n" ) system = ( - "Je bent Herman, AI co-CEO van Foodlinkk. Schrijf warm, professioneel en actionable. " - "Focus op halal kant-en-klaar retail groei in Nederland. Geen vage tekst — concrete namen en acties." + "Je bent Herman, AI co-CEO van Foodlinkk. Documenteer en vat samen wat agents en IT hebben gedaan. " + "Noem expliciet openstaande SysOps scan/backup verzoeken als die in de log staan. " + "Schrijf warm, professioneel, actionable." ) try: return await ollama.generate(prompt, system=system, timeout=120.0) @@ -327,10 +487,14 @@ def _fallback_summary(data: dict[str, Any]) -> str: ) lines.extend(["", "## Actiepunten vandaag — korte termijn"]) actions = [ + f"Keur {data['pending_approvals']} open agent-verzoeken goed (dashboard → Goedkeuringen)", "Open Retail 360 en benader top-3 halal-gap filialen via CRM koppeling", - f"Behandel {data['pending_approvals']} openstaande agent-goedkeuringen", "Check Marketing Live Feed voor kant-en-klaar trends", ] + for row in data.get("pending_approval_requests") or []: + if row.get("action_type") == "maintenance_scan": + actions.insert(0, f"**SysOps update-scan:** {row.get('title')} — keur goed op dashboard") + break if ms: actions.insert(0, f"Follow-up milestone: **{ms[0].get('title')}**") for a in actions[:6]: @@ -354,6 +518,18 @@ def _save_briefing(content: str, data: dict[str, Any]) -> None: ) except Exception: pass + try: + execute( + """INSERT INTO llm_memory (category, subject, content, source, metadata, updated_at) + VALUES ('herman_daily', %s, %s, 'herman', %s::jsonb, NOW())""", + ( + f"Briefing {data['date']}", + content[:8000], + json.dumps({"date": data["date"], "activity_count": len(data.get("activity_log") or [])}), + ), + ) + except Exception: + pass try: execute( """INSERT INTO agent_events (agent_name, agent_type, event_type, title, body, status, channel, metadata) @@ -361,7 +537,7 @@ def _save_briefing(content: str, data: dict[str, Any]) -> None: ( "herman", "herman_delegate", "briefing", f"CEO dagrapport {data['date']}", content[:2000], - "completed", "dashboard", json.dumps({"stats": safe}), + "completed", "dashboard", json.dumps({"stats": safe, "activity_log": data.get("activity_log", [])}), ), ) except Exception: diff --git a/cockpit/app/services/herman.py b/cockpit/app/services/herman.py index 0cafe8b..1e19b8f 100644 --- a/cockpit/app/services/herman.py +++ b/cockpit/app/services/herman.py @@ -5,6 +5,7 @@ import httpx from app.config import settings from app.db import execute, fetch_one from app.services import ollama +from app.services import packaging_agent AGENTS: dict[str, dict[str, str]] = { "marketing": {"name": "Marketing", "persona": "Social, brand voice, campaigns for Foodlinkk."}, @@ -14,6 +15,7 @@ AGENTS: dict[str, dict[str, str]] = { "product": {"name": "Product", "persona": "SKU development, launch timelines, shelf readiness."}, "halal": {"name": "Halal", "persona": "Halal compliance, certification, ingredient vetting."}, "design": {"name": "Design", "persona": "Packaging, visual identity, retail presentation."}, + "packaging": {"name": "Packaging", "persona": "SVG/PDF verpakkingsontwerp, stanstekeningen, drukwerk."}, "knowledge": {"name": "Knowledge", "persona": "Internal docs, RAG, policy answers."}, } @@ -82,6 +84,72 @@ def _pick_agent(raw: str) -> str: return "knowledge" async def chat(message: str) -> dict[str, Any]: + if packaging_agent.wants_packaging(message): + try: + outcome = await packaging_agent.generate_from_message(message) + name = outcome.get("design_name") or "Design" + pid = outcome.get("packaging_id", "")[:8] + reply_lines = [ + f"Packaging agent heeft een design klaar voor je: {name}", + f"Type: {outcome.get('type')} · {outcome.get('dimensions')}", + f"Project #{outcome.get('cockpit_project_id')}", + f"Studio: {outcome.get('studio_url')}", + f"PDF: {outcome.get('pdf_url')}", + ] + if outcome.get("nas", {}).get("ok"): + reply_lines.append("Bestanden staan op de NAS in de packaging-map van het project.") + reply = "\n".join(reply_lines) + + await _log_event( + "packaging", + "packaging_created", + f"Design klaar: {name}", + f"Herman-opdracht: {message[:1500]}\n\nDesign-ID: {outcome.get('packaging_id')}", + { + "packaging_id": outcome.get("packaging_id"), + "project_id": outcome.get("cockpit_project_id"), + "studio_url": outcome.get("studio_url"), + "pdf_url": outcome.get("pdf_url"), + "nas": outcome.get("nas"), + "for_herman": True, + }, + ) + await _log_event( + "herman", + "packaging_delivered", + f"Packaging → Herman: {name}", + reply[:2000], + { + "source_agent": "packaging", + "packaging_id": outcome.get("packaging_id"), + "project_id": outcome.get("cockpit_project_id"), + }, + ) + return { + "agent": "packaging", + "agent_label": "Packaging → Herman", + "reply": reply, + "delegated_agents": ["packaging", "herman"], + "routing_reason": "Packaging-opdracht gedetecteerd — design gegenereerd en aan Herman gerapporteerd", + "packaging_id": outcome.get("packaging_id"), + "packaging_studio_url": outcome.get("studio_url"), + "packaging_pdf_url": outcome.get("pdf_url"), + } + except Exception as exc: + await _log_event( + "packaging", + "packaging_error", + "Packaging generatie mislukt", + str(exc)[:1500], + {"message": message[:500]}, + ) + return { + "agent": "packaging", + "agent_label": "Packaging", + "reply": f"Packaging agent kon geen design maken: {exc}", + "delegated_agents": ["packaging"], + } + if _wants_image(message): prompt = _extract_image_prompt(message) try: diff --git a/cockpit/app/services/nas_folders.py b/cockpit/app/services/nas_folders.py new file mode 100644 index 0000000..a978a9f --- /dev/null +++ b/cockpit/app/services/nas_folders.py @@ -0,0 +1,104 @@ +"""NAS folder structure per client and project — geen alles-op-een-hoop.""" +from __future__ import annotations + +import json +import os +import re +from pathlib import Path +from typing import Any, Optional + +from app.db import execute, fetch_one + +NAS_ROOT = Path(os.getenv("NAS_CLIENTS_ROOT", "/data/nas-clients")) + +PROJECT_SUBDIRS = ("photos", "documents", "packaging", "exports", "briefs") + +PROJECT_TYPES = [ + {"id": "packaging", "label_nl": "Verpakking & label", "label_en": "Packaging & label", "icon": "📦", "nas_sub": "packaging"}, + {"id": "retail_listing", "label_nl": "Retail listing / schap", "label_en": "Retail listing", "icon": "🏪", "nas_sub": "documents"}, + {"id": "recipe", "label_nl": "Recept & productontwikkeling", "label_en": "Recipe & R&D", "icon": "🍱", "nas_sub": "briefs"}, + {"id": "marketing", "label_nl": "Marketing campagne", "label_en": "Marketing campaign", "icon": "📣", "nas_sub": "exports"}, + {"id": "halal", "label_nl": "Halal certificering", "label_en": "Halal certification", "icon": "☪️", "nas_sub": "documents"}, + {"id": "sourcing", "label_nl": "Sourcing & import", "label_en": "Sourcing & import", "icon": "🚢", "nas_sub": "documents"}, + {"id": "crm", "label_nl": "Klant & partnership", "label_en": "Client & partnership", "icon": "🤝", "nas_sub": "documents"}, + {"id": "research", "label_nl": "Marktonderzoek", "label_en": "Market research", "icon": "🔬", "nas_sub": "briefs"}, + {"id": "general", "label_nl": "Algemeen project", "label_en": "General project", "icon": "📁", "nas_sub": "documents"}, +] + + +def slugify(name: str, max_len: int = 48) -> str: + s = re.sub(r"[^a-zA-Z0-9]+", "-", (name or "project").strip().lower()).strip("-") + return (s[:max_len] or "project") + + +def _write_meta(path: Path, data: dict[str, Any]) -> None: + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text(json.dumps(data, indent=2, ensure_ascii=False), encoding="utf-8") + + +def ensure_client_folder(client_id: int, client_name: str) -> str: + """Maak NAS-map per klant: clients/{slug}/ met submappen.""" + slug = slugify(client_name) + root = NAS_ROOT / slug + for sub in ("projects", "photos", "documents", "inbox"): + (root / sub).mkdir(parents=True, exist_ok=True) + meta = { + "client_id": client_id, + "client_name": client_name, + "slug": slug, + "structure": ["projects", "photos", "documents", "inbox"], + } + _write_meta(root / "client.json", meta) + rel = str(root) + execute("UPDATE clients SET nas_folder = %s WHERE id = %s", (rel, client_id)) + return rel + + +def ensure_project_folder( + project_id: int, + project_name: str, + client_id: Optional[int], + client_name: Optional[str], + project_type: str = "general", +) -> dict[str, Any]: + """Projectmap onder klant: clients/{client}/projects/{project}/""" + client_root: Path | None = None + if client_id and client_name: + row = fetch_one("SELECT nas_folder FROM clients WHERE id = %s", (client_id,)) + if row and row.get("nas_folder"): + client_root = Path(row["nas_folder"]) + else: + client_root = Path(ensure_client_folder(client_id, client_name)) + else: + client_root = NAS_ROOT / "_geen-klant" + client_root.mkdir(parents=True, exist_ok=True) + + proj_slug = f"{project_id}-{slugify(project_name)}" + proj_root = client_root / "projects" / proj_slug + for sub in PROJECT_SUBDIRS: + (proj_root / sub).mkdir(parents=True, exist_ok=True) + + type_info = next((t for t in PROJECT_TYPES if t["id"] == project_type), PROJECT_TYPES[-1]) + _write_meta( + proj_root / "project.json", + { + "project_id": project_id, + "name": project_name, + "client_id": client_id, + "project_type": project_type, + "folders": list(PROJECT_SUBDIRS), + "primary_sub": type_info.get("nas_sub", "documents"), + }, + ) + + nas_path = str(proj_root) + client_rel = str(client_root) + execute( + """UPDATE cockpit_projects SET nas_path = %s, nas_client_root = %s, updated_at = NOW() WHERE id = %s""", + (nas_path, client_rel, project_id), + ) + return {"nas_path": nas_path, "nas_client_root": client_rel, "project_slug": proj_slug} + + +def list_types() -> list[dict[str, Any]]: + return list(PROJECT_TYPES) diff --git a/cockpit/app/services/packaging_agent.py b/cockpit/app/services/packaging_agent.py new file mode 100644 index 0000000..0919dc9 --- /dev/null +++ b/cockpit/app/services/packaging_agent.py @@ -0,0 +1,232 @@ +"""Packaging agent — parse Herman-opdrachten en genereer designs.""" +from __future__ import annotations + +import re +from typing import Any + +import httpx + +from app.config import settings +from app.services import packaging_nas, projects + +PACKAGING_KEYWORDS = ( + "maak verpakking", + "maak een verpakking", + "genereer verpakking", + "ontwerp verpakking", + "packaging:", + "packaging ", + "/packaging", + "maak packaging", + "maak package", + "stanstekening", + "verpakkingsontwerp", +) + +TYPE_ALIASES: list[tuple[str, str]] = [ + ("folding box", "folding_box"), + ("folding_box", "folding_box"), + ("sluitdoos", "folding_box"), + ("doos", "folding_box"), + ("banderole", "wrap"), + ("wrap", "wrap"), + ("rond label", "round_label"), + ("round label", "round_label"), + ("round_label", "round_label"), + ("sleeve", "sleeve"), + ("huls", "sleeve"), + ("pouch", "pouch"), + ("zak", "pouch"), + ("tray", "tray"), + ("schaal", "tray"), +] + +DEFAULT_ELEMENTS = { + "barcode": True, + "logo_area": True, + "fold_lines": True, + "cut_lines": True, + "nutrition_panel": False, + "ingredients": True, + "halal_badge": False, + "window": False, + "qr_code": False, + "glue_tabs": False, + "bleed": True, + "dimensions": True, +} + + +def wants_packaging(raw: str) -> bool: + t = (raw or "").strip().lower() + return any(k in t for k in PACKAGING_KEYWORDS) + + +def extract_packaging_body(raw: str) -> str: + t = raw.strip() + lower = t.lower() + for k in PACKAGING_KEYWORDS: + if lower.startswith(k): + rest = t[len(k) :].strip(" :,-") + if rest: + return rest + for k in PACKAGING_KEYWORDS: + if k in lower: + idx = lower.index(k) + len(k) + rest = t[idx:].strip(" :,-") + if rest: + return rest + return t + + +def _detect_type(text: str) -> str: + lower = text.lower() + for alias, ptype in TYPE_ALIASES: + if alias in lower: + return ptype + return "folding_box" + + +def _detect_dimensions(text: str) -> tuple[float, float, float]: + m = re.search(r"(\d{2,4})\s*[x×]\s*(\d{2,4})(?:\s*[x×]\s*(\d{1,4}))?", text, re.I) + if m: + w, h = float(m.group(1)), float(m.group(2)) + d = float(m.group(3)) if m.group(3) else (40.0 if _detect_type(text) == "folding_box" else 20.0) + return w, h, d + return 120.0, 80.0, 40.0 + + +def _detect_project_id(text: str) -> int | None: + m = re.search(r"project\s*#?\s*(\d+)", text, re.I) + if m: + return int(m.group(1)) + m = re.search(r"\bproject\s+(\d+)\b", text, re.I) + return int(m.group(1)) if m else None + + +def _detect_product_name(text: str) -> str: + m = re.search(r'voor\s+["\']?([^"\']+?)["\']?(?:\s+project|\s*$|,)', text, re.I) + if m: + return m.group(1).strip()[:80] + m = re.search(r'product\s*[:=]\s*["\']?([^"\']+)["\']?', text, re.I) + if m: + return m.group(1).strip()[:80] + cleaned = text + for alias, _ in TYPE_ALIASES: + cleaned = re.sub(re.escape(alias), "", cleaned, flags=re.I) + cleaned = re.sub(r"\d{2,4}\s*[x×]\s*\d{2,4}(?:\s*[x×]\s*\d{1,4})?", "", cleaned, flags=re.I) + cleaned = re.sub(r"project\s*#?\s*\d+", "", cleaned, flags=re.I) + for kw in ("halal-badge", "halal badge", "voedingswaarden", "nutrition", "qr-code", "qr code", "venster", "window"): + cleaned = re.sub(re.escape(kw), "", cleaned, flags=re.I) + cleaned = cleaned.strip(" ,:-") + return (cleaned[:80] or "Foodlinkk Product") + + +def parse_packaging_request(message: str) -> dict[str, Any]: + body = extract_packaging_body(message) + lower = body.lower() + ptype = _detect_type(body) + w, h, d = _detect_dimensions(body) + product = _detect_product_name(body) + project_id = _detect_project_id(message) or _detect_project_id(body) + + elements = dict(DEFAULT_ELEMENTS) + if any(k in lower for k in ("halal", "halal-badge", "halal badge")): + elements["halal_badge"] = True + if any(k in lower for k in ("voedingswaarden", "nutrition")): + elements["nutrition_panel"] = True + if any(k in lower for k in ("qr", "qrcode")): + elements["qr_code"] = True + if "venster" in lower or "window" in lower: + elements["window"] = True + + return { + "type": ptype, + "width_mm": w, + "height_mm": h, + "depth_mm": d, + "bleed_mm": 3, + "design_name": product, + "barcode_value": "8710000000012", + "elements": elements, + "text": { + "product_name": product, + "tagline": "Premium halal kant-en-klaar", + "subtitle": "", + "ingredients": "", + "origin": "Geproduceerd in NL", + "best_before": "Ten minste houdbaar tot: zie verpakking", + }, + "brand": {}, + "project_id": project_id, + "created_by": "packaging", + } + + +async def _download_bytes(packaging_id: str, fmt: str) -> bytes | None: + try: + async with httpx.AsyncClient(timeout=120.0) as client: + r = await client.get( + f"{settings.TOOLS_API_URL.rstrip('/')}/packaging/download/{packaging_id}", + params={"format": fmt}, + ) + if r.status_code < 400: + return r.content + except Exception: + pass + return None + + +async def generate_from_message(message: str) -> dict[str, Any]: + """Genereer packaging design en exporteer naar NAS; retour voor Herman-reply.""" + spec = parse_packaging_request(message) + + if not spec.get("project_id"): + proj = projects.create_project( + f"Packaging · {spec['design_name'][:48]}", + description=f"Aangemaakt door packaging agent via Herman\n\nOpdracht: {message[:500]}", + project_type="packaging", + ensure_nas=True, + created_by="packaging", + ) + spec["project_id"] = proj.get("id") + + async with httpx.AsyncClient(timeout=120.0) as client: + r = await client.post( + f"{settings.TOOLS_API_URL.rstrip('/')}/packaging/generate", + json=spec, + ) + r.raise_for_status() + result = r.json() + + packaging_id = result.get("id", "") + cockpit_project_id = result.get("cockpit_project_id") or spec.get("project_id") + svg = result.get("svg") or "" + saved_spec = result.get("spec") or spec + + nas_info: dict[str, Any] = {} + if packaging_id and cockpit_project_id and svg: + png_b = await _download_bytes(packaging_id, "png") + pdf_b = await _download_bytes(packaging_id, "pdf") + try: + nas_info = packaging_nas.export_packaging_files( + packaging_id, int(cockpit_project_id), svg, saved_spec, png_b, pdf_b + ) + except Exception as exc: + nas_info = {"ok": False, "error": str(exc)} + + studio_url = f"/packaging?project_id={cockpit_project_id}" + pdf_url = f"/api/packaging/download/{packaging_id}?format=pdf" + + return { + "packaging_id": packaging_id, + "cockpit_project_id": cockpit_project_id, + "design_name": saved_spec.get("design_name") or spec.get("design_name"), + "type": saved_spec.get("type"), + "dimensions": f"{saved_spec.get('width_mm')}×{saved_spec.get('height_mm')}×{saved_spec.get('depth_mm')} mm", + "studio_url": studio_url, + "pdf_url": pdf_url, + "nas": nas_info, + "spec": saved_spec, + "original_message": message, + } diff --git a/cockpit/app/services/packaging_nas.py b/cockpit/app/services/packaging_nas.py new file mode 100644 index 0000000..ed020ee --- /dev/null +++ b/cockpit/app/services/packaging_nas.py @@ -0,0 +1,93 @@ +"""Export packaging designs naar NAS projectmap.""" +from __future__ import annotations + +import json +from pathlib import Path +from typing import Any + +from app.db import execute, fetch_one +from app.services import nas_folders + + +def _packaging_dir(project_id: int) -> Path | None: + row = fetch_one( + """ + SELECT p.id, p.name, p.nas_path, p.client_id, p.project_type, c.name AS client_name + FROM cockpit_projects p + LEFT JOIN clients c ON c.id = p.client_id + WHERE p.id = %s + """, + (project_id,), + ) + if not row: + return None + nas_path = row.get("nas_path") + if not nas_path: + try: + paths = nas_folders.ensure_project_folder( + int(row["id"]), + row["name"] or f"project-{project_id}", + row.get("client_id"), + row.get("client_name"), + row.get("project_type") or "packaging", + ) + nas_path = paths.get("nas_path") + except Exception: + return None + root = Path(nas_path) / "packaging" + root.mkdir(parents=True, exist_ok=True) + return root + + +def export_packaging_files( + packaging_id: str, + cockpit_project_id: int, + svg_content: str, + spec: dict[str, Any], + png_bytes: bytes | None = None, + pdf_bytes: bytes | None = None, +) -> dict[str, Any]: + """Schrijf SVG/PNG/PDF + manifest naar NAS packaging/ submap.""" + root = _packaging_dir(cockpit_project_id) + if not root: + return {"ok": False, "error": "Geen NAS-map voor project"} + + design_name = spec.get("design_name") or spec.get("text", {}).get("product_name") or packaging_id[:8] + slug = nas_folders.slugify(str(design_name))[:32] + base = f"{packaging_id[:8]}-{slug}" + + paths: dict[str, str] = {} + svg_path = root / f"{base}.svg" + svg_path.write_text(svg_content, encoding="utf-8") + paths["svg"] = str(svg_path) + + if png_bytes: + png_path = root / f"{base}.png" + png_path.write_bytes(png_bytes) + paths["png"] = str(png_path) + + if pdf_bytes: + pdf_path = root / f"{base}.pdf" + pdf_path.write_bytes(pdf_bytes) + paths["pdf"] = str(pdf_path) + + manifest = { + "packaging_id": packaging_id, + "design_name": design_name, + "spec": spec, + "files": paths, + } + manifest_path = root / f"{base}.json" + manifest_path.write_text(json.dumps(manifest, indent=2, ensure_ascii=False), encoding="utf-8") + paths["manifest"] = str(manifest_path) + + primary = paths.get("pdf") or paths.get("svg") + execute( + """ + UPDATE project_assets SET file_path = %s + WHERE project_id = %s AND asset_type = 'packaging' AND ref_id = %s + """, + (primary, cockpit_project_id, packaging_id), + ) + + return {"ok": True, "nas_packaging_dir": str(root), "files": paths} diff --git a/cockpit/app/services/projects.py b/cockpit/app/services/projects.py new file mode 100644 index 0000000..245152b --- /dev/null +++ b/cockpit/app/services/projects.py @@ -0,0 +1,234 @@ +"""Unified cockpit projects and cross-module assets.""" +from __future__ import annotations + +import json +from typing import Any, Optional + +from app.db import execute, fetch_all, fetch_one +from app.services import nas_folders + + +def _row(row: dict | None) -> dict | None: + if not row: + return None + out = dict(row) + for k, v in list(out.items()): + if hasattr(v, "isoformat"): + out[k] = v.isoformat() + return out + + +def list_projects(client_id: Optional[int] = None, limit: int = 50) -> list[dict[str, Any]]: + clauses, params = [], [] + if client_id: + clauses.append("p.client_id = %s") + params.append(client_id) + where = (" WHERE " + " AND ".join(clauses)) if clauses else "" + safe = max(1, min(limit, 200)) + rows = fetch_all( + f""" + SELECT p.*, c.name AS client_name, + (SELECT COUNT(*) FROM project_assets a WHERE a.project_id = p.id) AS asset_count + FROM cockpit_projects p + LEFT JOIN clients c ON c.id = p.client_id + {where} + ORDER BY p.updated_at DESC, p.id DESC + LIMIT %s + """, + tuple(params + [safe]), + ) + return [_row(r) for r in rows] + + +def get_project(project_id: int) -> dict[str, Any] | None: + row = fetch_one( + """ + SELECT p.*, c.name AS client_name + FROM cockpit_projects p + LEFT JOIN clients c ON c.id = p.client_id + WHERE p.id = %s + """, + (project_id,), + ) + if not row: + return None + out = _row(row) or {} + assets = fetch_all( + "SELECT * FROM project_assets WHERE project_id = %s ORDER BY created_at DESC", + (project_id,), + ) + out["assets"] = [_row(a) for a in assets] + return out + + +def create_project( + name: str, + client_id: Optional[int] = None, + description: str = "", + created_by: str = "ceo", + metadata: dict | None = None, + project_type: str = "general", + priority: str = "normal", + ensure_nas: bool = True, +) -> dict[str, Any]: + row = fetch_one( + """ + INSERT INTO cockpit_projects (name, client_id, description, created_by, metadata, project_type, priority, updated_at) + VALUES (%s, %s, %s, %s, %s::jsonb, %s, %s, NOW()) + RETURNING * + """, + (name.strip(), client_id, description or None, created_by, json.dumps(metadata or {}), project_type, priority), + ) + out = _row(row) or {} + if ensure_nas and out.get("id"): + client_name = None + if client_id: + c = fetch_one("SELECT name FROM clients WHERE id = %s", (client_id,)) + client_name = c["name"] if c else None + try: + paths = nas_folders.ensure_project_folder( + int(out["id"]), name, client_id, client_name, project_type + ) + out.update(paths) + except Exception as exc: + out["nas_error"] = str(exc) + return out + + +def update_project(project_id: int, **fields: Any) -> dict[str, Any] | None: + allowed = ("name", "description", "status", "client_id", "project_type", "priority") + sets, params = [], [] + for k, v in fields.items(): + if k in allowed and v is not None: + sets.append(f"{k} = %s") + params.append(v) + if not sets: + return get_project(project_id) + params.append(project_id) + execute(f"UPDATE cockpit_projects SET {', '.join(sets)}, updated_at = NOW() WHERE id = %s", tuple(params)) + return get_project(project_id) + + +def project_stats() -> dict[str, Any]: + total = fetch_one("SELECT COUNT(*) AS n FROM cockpit_projects") or {"n": 0} + by_type = fetch_all( + "SELECT COALESCE(project_type, 'general') AS t, COUNT(*) AS n FROM cockpit_projects GROUP BY t" + ) + with_nas = fetch_one("SELECT COUNT(*) AS n FROM cockpit_projects WHERE nas_path IS NOT NULL") + with_client = fetch_one("SELECT COUNT(*) AS n FROM cockpit_projects WHERE client_id IS NOT NULL") + assets = fetch_one("SELECT COUNT(*) AS n FROM project_assets") + return { + "total": int(total.get("n") or 0), + "with_nas": int((with_nas or {}).get("n") or 0), + "with_client": int((with_client or {}).get("n") or 0), + "assets": int((assets or {}).get("n") or 0), + "by_type": {r["t"]: int(r["n"]) for r in by_type}, + } + + +def add_asset( + project_id: int, + asset_type: str, + title: str, + ref_id: str | None = None, + file_path: str | None = None, + payload: dict | None = None, + created_by: str = "ceo", + source_agent: str | None = None, +) -> dict[str, Any]: + row = fetch_one( + """ + INSERT INTO project_assets (project_id, asset_type, ref_id, title, file_path, payload, created_by, source_agent) + VALUES (%s, %s, %s, %s, %s, %s::jsonb, %s, %s) + RETURNING * + """, + ( + project_id, + asset_type, + ref_id, + title, + file_path, + json.dumps(payload or {}), + created_by, + source_agent, + ), + ) + execute("UPDATE cockpit_projects SET updated_at = NOW() WHERE id = %s", (project_id,)) + return _row(row) or {} + + +def get_or_create_agent_project(agent_key: str, client_id: Optional[int] = None) -> int: + key = (agent_key or "agent").strip().lower() + row = fetch_one( + """ + SELECT id FROM cockpit_projects + WHERE metadata->>'auto_agent' = %s AND status = 'active' + ORDER BY updated_at DESC LIMIT 1 + """, + (key,), + ) + if row: + return int(row["id"]) + created = create_project( + f"Agent · {key}", + client_id=client_id, + description=f"Automatisch project voor {key} output", + created_by=key, + metadata={"auto_agent": key}, + ) + return int(created["id"]) + + +def register_agent_output( + asset_type: str, + title: str, + ref_id: str | None = None, + payload: dict | None = None, + project_id: Optional[int] = None, + source_agent: str | None = None, + created_by: str = "ceo", + file_path: str | None = None, +) -> dict[str, Any] | None: + agent = (source_agent or created_by or "agent").strip().lower() + pid = project_id or get_or_create_agent_project(agent) + + if ref_id: + existing = fetch_one( + """ + SELECT id FROM project_assets + WHERE project_id = %s AND asset_type = %s AND ref_id = %s + LIMIT 1 + """, + (pid, asset_type, ref_id), + ) + if existing: + return {"id": existing["id"], "project_id": pid, "dedup": True} + + return add_asset( + pid, + asset_type, + title, + ref_id=ref_id, + file_path=file_path, + payload=payload, + created_by=created_by or agent, + source_agent=agent, + ) + + +def link_photo_to_project(photo_id: int, project_id: int, created_by: str = "ceo") -> None: + photo = fetch_one("SELECT id, filename, source FROM photo_imports WHERE id = %s", (photo_id,)) + if not photo: + raise ValueError("Photo not found") + execute( + "UPDATE photo_imports SET project_id = %s, created_by = COALESCE(created_by, %s) WHERE id = %s", + (project_id, created_by, photo_id), + ) + add_asset( + project_id, + "photo", + photo.get("filename") or f"Foto #{photo_id}", + ref_id=str(photo_id), + created_by=created_by, + source_agent=photo.get("source"), + ) diff --git a/cockpit/app/services/social_publish.py b/cockpit/app/services/social_publish.py index 0b6ec00..27f5d39 100644 --- a/cockpit/app/services/social_publish.py +++ b/cockpit/app/services/social_publish.py @@ -244,7 +244,14 @@ def test_connection(platform: str, integration: dict[str, Any] | None = None) -> return {"ok": True, "status": "ok", "message": f"{platform} configuration is present"} -def run_publish_job(job_id: int, text: str, channels: list[str], image_url: str | None, media_ids: list[int]) -> None: +def run_publish_job( + job_id: int, + text: str, + channels: list[str], + image_url: str | None, + media_ids: list[int], + project_id: int | None = None, +) -> None: started_at = datetime.utcnow() execute( "UPDATE social_publish_jobs SET status=%s, started_at=NOW(), updated_at=NOW() WHERE id=%s", @@ -310,5 +317,26 @@ def run_publish_job(job_id: int, text: str, channels: list[str], image_url: str title=f"Social publish job #{job_id} afgerond", body=f"Published={published}, skipped={skipped}, failed={failed}", status=final_status, - metadata={"job_id": job_id, "results": results}, + metadata={"job_id": job_id, "results": results, "project_id": project_id}, ) + + try: + from app.services import projects as project_svc + + project_svc.register_agent_output( + asset_type="social_publish", + title=f"Social publish #{job_id} · {final_status}", + ref_id=str(job_id), + payload={ + "job_id": job_id, + "status": final_status, + "channels": channels, + "published": published, + "text_preview": (text or "")[:200], + }, + project_id=project_id, + source_agent="marketing", + created_by="marketing_automation", + ) + except Exception: + pass diff --git a/cockpit/app/services/ui_preferences.py b/cockpit/app/services/ui_preferences.py new file mode 100644 index 0000000..a8078de --- /dev/null +++ b/cockpit/app/services/ui_preferences.py @@ -0,0 +1,82 @@ +"""User UI preferences — dashboard layout and visualization modes.""" +from __future__ import annotations + +import json +from typing import Any + +from app.db import execute, fetch_one + +DEFAULT_LAYOUT = ["kpis", "executive", "briefing", "retail", "analytics", "approvals", "feed"] +DEFAULT_VIZ = "neo-bars" + +VIZ_MODES = [ + {"id": "neo-bars", "label": "Neo staafdiagram", "icon": "📊"}, + {"id": "neo-rings", "label": "Neo ringen", "icon": "🍩"}, + {"id": "neo-equalizer", "label": "Neo equalizer", "icon": "🎚️"}, + {"id": "neo-cards", "label": "Neo kaarten", "icon": "🃏"}, + {"id": "neo-table", "label": "Neo tabel", "icon": "📋"}, +] + + +def get_preferences(user_key: str = "ceo") -> dict[str, Any]: + row = fetch_one("SELECT * FROM user_ui_preferences WHERE user_key = %s", (user_key,)) + if not row: + return { + "user_key": user_key, + "dashboard_layout": DEFAULT_LAYOUT, + "viz_modes": {}, + "global_viz_mode": DEFAULT_VIZ, + "locale": "nl", + "viz_options": VIZ_MODES, + } + layout = row.get("dashboard_layout") or DEFAULT_LAYOUT + if isinstance(layout, str): + try: + layout = json.loads(layout) + except Exception: + layout = DEFAULT_LAYOUT + viz_modes = row.get("viz_modes") or {} + if isinstance(viz_modes, str): + try: + viz_modes = json.loads(viz_modes) + except Exception: + viz_modes = {} + return { + "user_key": user_key, + "dashboard_layout": layout, + "viz_modes": viz_modes, + "global_viz_mode": row.get("global_viz_mode") or DEFAULT_VIZ, + "locale": row.get("locale") or "nl", + "viz_options": VIZ_MODES, + } + + +def save_preferences( + user_key: str, + dashboard_layout: list[str] | None = None, + global_viz_mode: str | None = None, + viz_modes: dict[str, str] | None = None, + locale: str | None = None, +) -> dict[str, Any]: + current = get_preferences(user_key) + layout = dashboard_layout if dashboard_layout is not None else current["dashboard_layout"] + gviz = global_viz_mode if global_viz_mode is not None else current["global_viz_mode"] + vmodes = viz_modes if viz_modes is not None else current["viz_modes"] + loc = locale if locale is not None else current.get("locale", "nl") + if loc not in ("nl", "en"): + loc = "nl" + fetch_one( + """ + INSERT INTO user_ui_preferences (user_key, dashboard_layout, global_viz_mode, viz_modes, locale, updated_at) + VALUES (%s, %s::jsonb, %s, %s::jsonb, %s, NOW()) + ON CONFLICT (user_key) DO UPDATE SET + dashboard_layout = EXCLUDED.dashboard_layout, + global_viz_mode = EXCLUDED.global_viz_mode, + viz_modes = EXCLUDED.viz_modes, + locale = EXCLUDED.locale, + updated_at = NOW() + RETURNING user_key + """, + (user_key, json.dumps(layout), gviz, json.dumps(vmodes), loc), + ) + return get_preferences(user_key) diff --git a/cockpit/static/css/agent-characters.css b/cockpit/static/css/agent-characters.css new file mode 100644 index 0000000..dff29b2 --- /dev/null +++ b/cockpit/static/css/agent-characters.css @@ -0,0 +1,210 @@ +/* 3D agent poppetjes — full-width portrait met headset */ +.agent-soul-card { + display: flex; + flex-direction: column; + overflow: hidden; + padding: 0 !important; +} +.agent-soul-card > *:not(.agent-char-wrap) { + padding-left: 0.85rem; + padding-right: 0.85rem; +} +.agent-soul-card > strong { padding-top: 0.65rem; } +.agent-soul-card > .agent-meta-row { padding-bottom: 0.75rem; } + +.agent-char-wrap { + position: relative; + width: 100%; + height: 132px; + flex-shrink: 0; + overflow: hidden; + background: linear-gradient(160deg, #0c1929 0%, #152238 50%, #0a1020 100%); + border-bottom: 1px solid rgba(56, 189, 248, 0.15); +} +.agent-char-wrap.large { + width: 120px; + height: 148px; + border-radius: 14px; + border: 2px solid rgba(56, 189, 248, 0.25); +} +.agent-char-wrap img.agent-char-img { + width: 100%; + height: 100%; + object-fit: cover; + object-position: center 15%; + display: block; +} +.agent-char-svg { + width: 100%; + height: 100%; + display: block; +} +.agent-char-portrait { + width: 100%; + height: 100%; +} + +.agent-status-pill { + display: inline-flex; + align-items: center; + gap: 0.35rem; + font-size: 0.68rem; + padding: 0.2rem 0.55rem; + border-radius: 999px; + background: rgba(0, 0, 0, 0.35); + border: 1px solid rgba(148, 163, 184, 0.2); + color: #cbd5e1; + max-width: 100%; + margin-top: 0.25rem; +} +.agent-status-pill .dot { + width: 7px; + height: 7px; + border-radius: 50%; + flex-shrink: 0; +} +.agent-status-pill.busy .dot { background: #f59e0b; box-shadow: 0 0 6px #f59e0b; } +.agent-status-pill.active .dot { background: #22c55e; box-shadow: 0 0 6px #22c55e; } +.agent-status-pill.idle .dot { background: #64748b; } +.agent-status-pill.error .dot { background: #ef4444; } +.agent-current-task { + font-size: 0.75rem; + color: #94a3b8; + line-height: 1.4; + margin: 0.35rem 0; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; +} +.agent-role-desc { + font-size: 0.72rem; + color: #64748b; + line-height: 1.35; + margin: 0.25rem 0; +} +.agents-neo-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); + gap: 0.85rem; +} +.agent-soul-card.selected { + outline: 2px solid #ffd700; + outline-offset: -2px; +} +.agents-viz-compact.page-viz-panel { min-height: 200px; } +.agents-viz-compact .page-viz-body { min-height: 160px; } +.agents-viz-compact .page-viz-canvas { min-height: 140px; max-height: 180px; } +.agents-viz-compact.viz-mode-rings .page-viz-canvas { min-height: 120px; max-height: 160px; } +.agents-viz-compact.viz-mode-rings .page-viz-body { min-height: 140px; } + +.agent-events-link { + background: none; + border: none; + padding: 0; + font: inherit; + font-size: 0.72rem; + color: #38bdf8; + cursor: pointer; + text-decoration: underline; + text-underline-offset: 2px; +} +.agent-events-link:hover { color: #7dd3fc; } + +.agent-event-clickable { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 0.4rem 0.65rem; + width: 100%; + text-align: left; + background: rgba(15, 23, 42, 0.45); + border: 1px solid rgba(148, 163, 184, 0.12); + border-radius: 8px; + padding: 0.55rem 0.7rem; + margin-bottom: 0.4rem; + cursor: pointer; + color: inherit; +} +.agent-event-clickable:hover { + border-color: rgba(56, 189, 248, 0.35); + background: rgba(30, 58, 95, 0.35); +} +.agent-event-time { font-size: 0.7rem; color: #64748b; } +.agent-event-title { flex: 1; font-size: 0.82rem; } + +.agent-events-backdrop { + position: fixed; + inset: 0; + background: rgba(0, 0, 0, 0.55); + z-index: 1200; +} +.agent-events-drawer { + position: fixed; + top: 0; + right: 0; + width: min(420px, 92vw); + height: 100vh; + background: #0f172a; + border-left: 1px solid rgba(56, 189, 248, 0.2); + z-index: 1201; + display: flex; + flex-direction: column; + transform: translateX(100%); + transition: transform 0.22s ease; + box-shadow: -8px 0 32px rgba(0, 0, 0, 0.45); +} +.agent-events-drawer.open { transform: translateX(0); } +.agent-events-head { + display: flex; + justify-content: space-between; + align-items: flex-start; + gap: 0.75rem; + padding: 1rem 1.1rem; + border-bottom: 1px solid rgba(148, 163, 184, 0.15); +} +.agent-events-head h3 { margin: 0; font-size: 1.05rem; } +.agent-events-body { + flex: 1; + overflow-y: auto; + padding: 0.75rem; +} +.agent-event-card { + border: 1px solid rgba(148, 163, 184, 0.12); + border-radius: 10px; + padding: 0.7rem 0.8rem; + margin-bottom: 0.55rem; + cursor: pointer; + background: rgba(15, 23, 42, 0.6); + transition: border-color 0.15s; +} +.agent-event-card:hover, +.agent-event-card.expanded { + border-color: rgba(56, 189, 248, 0.35); +} +.agent-event-card-top { + display: flex; + justify-content: space-between; + align-items: center; + gap: 0.5rem; + margin-bottom: 0.35rem; +} +.agent-event-card time { font-size: 0.7rem; color: #64748b; } +.agent-event-card strong { display: block; font-size: 0.88rem; line-height: 1.35; } +.agent-event-meta { + font-size: 0.68rem; + color: #64748b; + margin-top: 0.25rem; + text-transform: uppercase; + letter-spacing: 0.03em; +} +.agent-event-detail { + margin-top: 0.65rem; + padding-top: 0.65rem; + border-top: 1px solid rgba(148, 163, 184, 0.12); + font-size: 0.8rem; + line-height: 1.5; + color: #cbd5e1; + white-space: pre-wrap; +} +.badge-sm { font-size: 0.62rem; padding: 0.12rem 0.4rem; } diff --git a/cockpit/static/css/agents-mesh.css b/cockpit/static/css/agents-mesh.css index 6846d6e..ead1d41 100644 --- a/cockpit/static/css/agents-mesh.css +++ b/cockpit/static/css/agents-mesh.css @@ -58,6 +58,23 @@ filter: drop-shadow(0 0 12px rgba(255, 215, 0, 0.6)); } +.mesh-exec circle.main { + fill: #0f172a; + stroke-width: 3; +} + +.mesh-ceo circle.main { stroke: #ff9f43; filter: drop-shadow(0 0 10px rgba(255, 159, 67, 0.5)); } +.mesh-cto circle.main { stroke: #a855f7; filter: drop-shadow(0 0 10px rgba(168, 85, 247, 0.5)); } + +.mesh-exec circle.ring { + fill: none; + stroke: rgba(255, 255, 255, 0.15); + stroke-width: 1.5; + stroke-dasharray: 4 4; +} + +.mesh-agent .mesh-status { fill: #64748b; } + .mesh-herman circle.ring { fill: none; stroke: rgba(255, 215, 0, 0.35); @@ -80,3 +97,26 @@ color: #94a3b8; font-size: 0.82rem; } + +.vtab-badge { + display: inline-flex; + min-width: 1.1rem; + height: 1.1rem; + padding: 0 0.35rem; + margin-left: 0.35rem; + border-radius: 999px; + background: #f59e0b; + color: #0a0e14; + font-size: 0.65rem; + font-weight: 700; + align-items: center; + justify-content: center; +} + +.badge-warn { + background: rgba(245, 158, 11, 0.2); + color: #fbbf24; + padding: 0.15rem 0.5rem; + border-radius: 999px; + font-size: 0.72rem; +} diff --git a/cockpit/static/css/clients-crm.css b/cockpit/static/css/clients-crm.css new file mode 100644 index 0000000..c65dfc0 --- /dev/null +++ b/cockpit/static/css/clients-crm.css @@ -0,0 +1,93 @@ +.clients-shell { max-width: 1400px; } +.clients-kpi-row { + display: grid; grid-template-columns: repeat(5, 1fr); gap: 0.75rem; margin: 1rem 0; +} +@media (max-width: 1000px) { .clients-kpi-row { grid-template-columns: repeat(2, 1fr); } } +.clients-kpi { + background: rgba(13,18,25,0.85); border: 1px solid rgba(148,163,184,0.15); + border-radius: 12px; padding: 0.85rem 1rem; +} +.clients-kpi span { display: block; font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.08em; color: #94a3b8; } +.clients-kpi strong { font-size: 1.35rem; color: #f1f5f9; } + +.clients-tabs { + display: flex; flex-wrap: wrap; gap: 0.4rem; align-items: center; + margin-bottom: 1rem; padding-bottom: 0.75rem; border-bottom: 1px solid rgba(148,163,184,0.12); +} +.clients-tab { + border: 1px solid rgba(148,163,184,0.2); background: rgba(0,0,0,0.25); + color: #cbd5e1; border-radius: 999px; padding: 0.35rem 0.85rem; font-size: 0.78rem; cursor: pointer; +} +.clients-tab.active { border-color: #38bdf8; color: #38bdf8; box-shadow: 0 0 12px rgba(56,189,248,0.15); } +.clients-tab-actions { margin-left: auto; display: flex; gap: 0.5rem; flex-wrap: wrap; } + +.clients-kanban { display: grid; grid-template-columns: repeat(5, minmax(200px, 1fr)); gap: 0.75rem; overflow-x: auto; padding-bottom: 0.5rem; } +@media (max-width: 1100px) { .clients-kanban { grid-template-columns: repeat(5, minmax(180px, 1fr)); } } +.clients-kanban-col { + background: rgba(13,18,25,0.7); border: 1px solid rgba(148,163,184,0.12); + border-radius: 12px; padding: 0.65rem; min-height: 320px; +} +.clients-kanban-col h3 { + margin: 0 0 0.65rem; font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.1em; color: #94a3b8; + display: flex; justify-content: space-between; align-items: center; +} +.clients-kanban-col h3 .count { background: rgba(56,189,248,0.15); color: #38bdf8; border-radius: 999px; padding: 0.1rem 0.45rem; font-size: 0.65rem; } +.clients-card { + background: rgba(0,0,0,0.35); border: 1px solid rgba(148,163,184,0.12); border-radius: 10px; + padding: 0.7rem; margin-bottom: 0.5rem; cursor: pointer; transition: border-color 0.2s, box-shadow 0.2s; +} +.clients-card:hover { border-color: rgba(56,189,248,0.4); box-shadow: 0 0 16px rgba(56,189,248,0.08); } +.clients-card strong { display: block; color: #f1f5f9; font-size: 0.88rem; margin-bottom: 0.2rem; } +.clients-card-meta { font-size: 0.72rem; color: #94a3b8; line-height: 1.45; } +.clients-card-tags { display: flex; flex-wrap: wrap; gap: 0.25rem; margin-top: 0.4rem; } +.clients-tag { font-size: 0.62rem; padding: 0.12rem 0.4rem; border-radius: 999px; background: rgba(56,189,248,0.12); color: #7dd3fc; } +.clients-tag.mrr { background: rgba(74,222,128,0.12); color: #4ade80; } +.stage-intake { border-left: 3px solid #94a3b8; } +.stage-discovery { border-left: 3px solid #38bdf8; } +.stage-proposal { border-left: 3px solid #f59e0b; } +.stage-active { border-left: 3px solid #22c55e; } +.stage-churned { border-left: 3px solid #64748b; opacity: 0.75; } + +.clients-toolbar { + display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 0.75rem; align-items: center; +} +.clients-toolbar input, .clients-toolbar select { + min-width: 160px; background: rgba(0,0,0,0.35); border: 1px solid rgba(148,163,184,0.2); + color: #e2e8f0; border-radius: 8px; padding: 0.45rem 0.65rem; font-size: 0.82rem; +} + +.clients-drawer { + position: fixed; top: 0; right: 0; width: min(480px, 96vw); height: 100vh; + background: #0d1219; border-left: 1px solid rgba(148,163,184,0.15); + z-index: 1200; transform: translateX(105%); transition: transform 0.25s ease; + overflow-y: auto; padding: 1.25rem; +} +.clients-drawer.open { transform: translateX(0); } +.clients-drawer-head { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 1rem; } +.clients-drawer-head h2 { margin: 0; font-size: 1.15rem; color: #f1f5f9; } +.clients-drawer-section { margin-top: 1rem; padding-top: 1rem; border-top: 1px solid rgba(148,163,184,0.1); } +.clients-drawer-section h4 { margin: 0 0 0.5rem; font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.08em; color: #94a3b8; } + +.clients-form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0.65rem; } +.clients-form-grid .full { grid-column: 1 / -1; } +@media (max-width: 600px) { .clients-form-grid { grid-template-columns: 1fr; } } + +.store-search-panel { + display: grid; grid-template-columns: 1fr 1.2fr; gap: 1rem; +} +@media (max-width: 900px) { .store-search-panel { grid-template-columns: 1fr; } } +.store-list { max-height: 520px; overflow-y: auto; border: 1px solid rgba(148,163,184,0.12); border-radius: 10px; } +.store-list-item { + padding: 0.65rem 0.75rem; border-bottom: 1px solid rgba(148,163,184,0.08); cursor: pointer; +} +.store-list-item:hover, .store-list-item.selected { background: rgba(56,189,248,0.08); } +.store-list-item.selected { border-left: 3px solid #38bdf8; } +.store-edit-panel { + background: rgba(13,18,25,0.7); border: 1px solid rgba(148,163,184,0.12); + border-radius: 12px; padding: 1rem; +} +.store-edit-panel h3 { margin: 0 0 0.75rem; font-size: 0.95rem; color: #f1f5f9; } +.store-checks { display: flex; flex-wrap: wrap; gap: 0.75rem; margin: 0.5rem 0; } +.store-checks label { display: flex; align-items: center; gap: 0.35rem; font-size: 0.82rem; color: #cbd5e1; } + +.clients-empty { text-align: center; padding: 2rem; color: #64748b; font-size: 0.85rem; } diff --git a/cockpit/static/css/herman-dashboard.css b/cockpit/static/css/herman-dashboard.css index da1e999..f803724 100644 --- a/cockpit/static/css/herman-dashboard.css +++ b/cockpit/static/css/herman-dashboard.css @@ -179,7 +179,27 @@ } @keyframes hmPulse { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } } .hm-chart-head small { color: #64748b; font-size: 0.7rem; } -.hm-chart-wrap { position: relative; height: 200px; } +.hm-chart-wrap { position: relative; height: 200px; width: 100%; } +.hm-chart-wrap canvas { display: block; width: 100% !important; height: 100% !important; } + +/* Page visualisatie — vult panel volledig */ +.page-viz-panel { min-height: 360px; display: flex; flex-direction: column; } +.page-viz-panel .page-viz-body { flex: 1; display: flex; flex-direction: column; min-height: 300px; } +.page-viz-panel .hm-chart-wrap.page-viz-canvas { + flex: 1; min-height: 300px; height: auto; width: 100%; +} +.page-viz-panel.viz-mode-chart .viz-alt { display: none !important; } +.page-viz-panel.viz-mode-alt .page-viz-canvas { display: none !important; } +.page-viz-panel.viz-mode-alt .viz-alt { + flex: 1; display: flex; flex-direction: column; justify-content: stretch; + min-height: 300px; padding: 0.25rem 0; +} +.page-viz-panel.viz-mode-alt .viz-cards { + flex: 1; align-content: start; grid-template-columns: repeat(auto-fill, minmax(110px, 1fr)); gap: 0.65rem; +} +.page-viz-panel.viz-mode-alt .viz-table { width: 100%; font-size: 0.82rem; } +.page-viz-panel.viz-mode-alt .viz-eq { flex: 1; min-height: 140px; max-height: 220px; margin-top: 0.75rem; } +.page-viz-panel.viz-mode-alt .viz-eq-row { font-size: 0.82rem; padding: 0.15rem 0; } .briefing-loading-overlay { position: absolute; inset: 0; background: rgba(10, 14, 20, 0.8); @@ -252,6 +272,64 @@ .hm-stock-chain { font-size: 0.65rem; color: #64748b; margin-bottom: 0.35rem; } .hm-spark { width: 100%; height: 36px; display: block; opacity: 0.85; } .hm-eq-down span { background: linear-gradient(to top, rgba(251,113,133,0.3), #fb7185); box-shadow: 0 0 6px rgba(251,113,133,0.35); } +.hm-eq-purple span { background: linear-gradient(to top, rgba(168,85,247,0.3), #a855f7); box-shadow: 0 0 6px rgba(168,85,247,0.35); } +.hm-eq-cyan span { background: linear-gradient(to top, rgba(56,189,248,0.3), #38bdf8); box-shadow: 0 0 6px rgba(56,189,248,0.35); } +.hm-eq-lime span { background: linear-gradient(to top, rgba(184,255,60,0.25), #b8ff3c); box-shadow: 0 0 6px rgba(184,255,60,0.35); } +.hm-hero-links .beurs-mini-chip { font-size: 0.75rem; } +.hm-dash-analytics .hm-analytics-panel { min-height: 320px; } +.hm-dash-analytics .page-viz-body { min-height: 260px; } +.hm-dash-analytics .page-viz-canvas { min-height: 260px; } +.hm-dash-two-col .page-viz-panel { min-height: 340px; } +.hm-trend-list li { margin-bottom: 0.35rem; } + +.hm-widget-draggable { cursor: grab; position: relative; } +.hm-widget-draggable:active { cursor: grabbing; } +.hm-widget-dragging { opacity: 0.75; outline: 2px dashed var(--hm-cyan); } +.hm-widget-handle { + font-size: 0.65rem; letter-spacing: 0.1em; text-transform: uppercase; + color: #64748b; margin-bottom: 0.35rem; user-select: none; +} +.hm-widget-handle::before { content: '⋮⋮ '; color: var(--hm-cyan); } + +.viz-toolbar { + display: flex; flex-wrap: wrap; gap: 0.4rem; align-items: center; + margin-bottom: 1rem; padding: 0.65rem 0.85rem; + background: rgba(13,18,25,0.8); border: 1px solid var(--hm-border); border-radius: 12px; +} +.viz-global-label { font-size: 0.72rem; color: #94a3b8; margin-right: 0.35rem; } +.viz-mode-btn { + border: 1px solid rgba(148,163,184,0.2); background: rgba(0,0,0,0.25); + color: #cbd5e1; border-radius: 999px; padding: 0.25rem 0.65rem; font-size: 0.72rem; cursor: pointer; +} +.viz-mode-btn.active { border-color: var(--hm-cyan); color: var(--hm-cyan); box-shadow: 0 0 12px rgba(0,229,255,0.15); } +.viz-alt { min-height: 140px; } +.viz-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(100px, 1fr)); gap: 0.5rem; } +.viz-card { background: rgba(0,0,0,0.25); border: 1px solid var(--hm-border); border-radius: 10px; padding: 0.65rem; text-align: center; } +.viz-card-label { display: block; font-size: 0.65rem; color: #94a3b8; text-transform: uppercase; } +.viz-card-val { font-size: 1.25rem; color: #f1f5f9; } +.viz-eq-row { display: flex; justify-content: space-between; font-size: 0.78rem; margin-bottom: 0.25rem; color: #cbd5e1; } +.viz-table { font-size: 0.78rem; } +.approval-dash-row { display: flex; gap: 0.5rem; flex-wrap: wrap; align-items: center; } +.approval-row-scan td { background: rgba(245, 158, 11, 0.06); } +.approval-row-scan td:first-child { border-left: 3px solid #f59e0b; } + +.global-viz-toolbar { + display: flex; flex-wrap: wrap; gap: 0.25rem; align-items: center; + margin: 0 auto; max-width: min(520px, 55vw); +} +.global-viz-btn { + border: 1px solid rgba(148,163,184,0.18); background: rgba(0,0,0,0.35); + color: #94a3b8; border-radius: 999px; padding: 0.15rem 0.45rem; font-size: 0.62rem; + cursor: pointer; white-space: nowrap; +} +.global-viz-btn.active { + border-color: var(--hm-cyan, #00e5ff); color: var(--hm-cyan, #00e5ff); + box-shadow: 0 0 10px rgba(0,229,255,0.12); +} +@media (max-width: 900px) { + .global-viz-toolbar { display: none; } + .app-topbar .page-tip { display: none; } +} .hm-highlight-scroll { max-height: 220px; overflow-y: auto; } .hm-highlight-item { diff --git a/cockpit/static/css/ops-topology.css b/cockpit/static/css/ops-topology.css index 6f53a14..69c1a3c 100644 --- a/cockpit/static/css/ops-topology.css +++ b/cockpit/static/css/ops-topology.css @@ -9,122 +9,175 @@ align-items: center; gap: 0.8rem; flex-wrap: wrap; + padding: 1.25rem 1.5rem; + margin-bottom: 0; } -.ops-header h1 { - margin: 0; -} - -.ops-subtitle { - color: #93a4b8; - margin: 0.25rem 0 0; -} - -.ops-kpis { - display: grid; - gap: 0.75rem; - grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); -} - -.ops-kpi { - border: 1px solid rgba(120, 170, 255, 0.25); - border-radius: 12px; - padding: 0.8rem; - background: linear-gradient(150deg, rgba(15, 23, 42, 0.95), rgba(17, 30, 53, 0.7)); - box-shadow: inset 0 0 20px rgba(36, 99, 235, 0.08), 0 0 20px rgba(30, 64, 175, 0.12); -} - -.ops-kpi .label { - color: #8ba3c4; - font-size: 0.78rem; - text-transform: uppercase; - letter-spacing: 0.08em; -} - -.ops-kpi .value { - font-size: 1.3rem; - font-weight: 700; - margin-top: 0.2rem; -} +.ops-header h1 { margin: 0; font-size: 1.55rem; } .topology-card { position: relative; border-radius: 14px; - border: 1px solid rgba(56, 189, 248, 0.3); - background: radial-gradient(circle at top, rgba(21, 43, 77, 0.35), rgba(8, 15, 29, 0.92)); + border: 1px solid rgba(0, 229, 255, 0.25); + background: radial-gradient(circle at 50% 20%, rgba(0, 229, 255, 0.08), rgba(8, 15, 29, 0.95)); overflow: hidden; + padding: 0.5rem; } .topology-canvas { width: 100%; - min-height: 520px; + min-height: 560px; + display: block; } -.topology-lines line { - stroke: rgba(59, 130, 246, 0.42); +.ops-layer-line { + stroke: rgba(148, 163, 184, 0.12); + stroke-width: 1; + stroke-dasharray: 6 8; +} + +.ops-layer-label { + fill: #64748b; + font-size: 10px; + letter-spacing: 0.12em; + text-transform: uppercase; + font-weight: 600; +} + +.topology-line { + stroke: rgba(59, 130, 246, 0.35); stroke-width: 2; } .pulse-line { - stroke: rgba(56, 189, 248, 0.95); - stroke-width: 2.6; - stroke-dasharray: 10 14; - animation: ops-line-pulse 1.8s linear infinite; - filter: drop-shadow(0 0 6px rgba(56, 189, 248, 0.85)); + stroke: rgba(0, 229, 255, 0.95); + stroke-width: 2.5; + stroke-dasharray: 8 16; + animation: ops-line-pulse 1.6s linear infinite; + filter: drop-shadow(0 0 6px rgba(0, 229, 255, 0.8)); } -.ops-node circle { +.ops-node-circle { fill: #0f172a; - stroke-width: 2.2; + stroke-width: 2.5; } -.ops-node text { - fill: #d9e8ff; - font-size: 12px; +.ops-node-title { + fill: #e2e8f0; + font-size: 11px; + font-weight: 700; + text-anchor: middle; +} + +.ops-node-sub { + fill: #94a3b8; + font-size: 9px; + text-anchor: middle; + letter-spacing: 0.06em; +} + +.ops-node-agent { + fill: #ffd700; + font-size: 9px; + text-anchor: middle; font-weight: 600; } -.ops-node .sub { - fill: #8ea7ca; - font-size: 11px; - font-weight: 500; +.ops-node-role { + fill: #64748b; + font-size: 8px; + text-anchor: middle; } -.node-proxmox circle { +.node-proxmox .ops-node-circle { stroke: #f59e0b; - filter: drop-shadow(0 0 11px rgba(245, 158, 11, 0.6)); + filter: drop-shadow(0 0 12px rgba(245, 158, 11, 0.55)); } -.node-vm circle { +.node-vm .ops-node-circle { stroke: #38bdf8; - filter: drop-shadow(0 0 9px rgba(56, 189, 248, 0.5)); + filter: drop-shadow(0 0 10px rgba(56, 189, 248, 0.45)); } -.node-service circle { +.node-service .ops-node-circle { stroke: #22c55e; - filter: drop-shadow(0 0 8px rgba(34, 197, 94, 0.45)); } -.status-offline circle { - stroke: #ef4444; - filter: drop-shadow(0 0 10px rgba(239, 68, 68, 0.6)); +.status-online .ops-node-circle { stroke: #22c55e; } +.status-offline .ops-node-circle { stroke: #ef4444; filter: drop-shadow(0 0 10px rgba(239, 68, 68, 0.5)); } +.status-degraded .ops-node-circle { stroke: #f59e0b; } + +.ops-monitor-box { + fill: rgba(13, 18, 25, 0.92); + stroke: rgba(0, 229, 255, 0.35); + stroke-width: 1.5; } -.status-degraded circle, -.status-unknown circle { - stroke: #f59e0b; +.ops-monitor.status-healthy .ops-monitor-box { stroke: #22c55e; } +.ops-monitor.status-warn .ops-monitor-box { stroke: #f59e0b; } +.ops-monitor.status-idle .ops-monitor-box { stroke: #38bdf8; } +.ops-monitor.status-offline .ops-monitor-box { stroke: #64748b; } + +.ops-legend { + display: flex; + flex-wrap: wrap; + gap: 1rem; + padding: 0.5rem 0.75rem; + font-size: 0.78rem; + color: #94a3b8; } +.ops-legend .dot { + display: inline-block; + width: 8px; + height: 8px; + border-radius: 50%; + margin-right: 0.35rem; +} + +.dot-online { background: #22c55e; box-shadow: 0 0 6px #22c55e; } +.dot-offline { background: #ef4444; } +.dot-degraded { background: #f59e0b; } + .ops-meta { color: #8ba3c4; font-size: 0.85rem; } -@keyframes ops-line-pulse { - from { - stroke-dashoffset: 26; - } - to { - stroke-dashoffset: 0; - } +.ops-panels-grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 1rem; +} +@media (max-width: 900px) { .ops-panels-grid { grid-template-columns: 1fr; } } + +.ops-side-panel h2 { margin: 0 0 0.35rem; font-size: 1rem; } +.ops-maint-list { display: grid; gap: 0.5rem; max-height: 220px; overflow-y: auto; margin-top: 0.5rem; } +.ops-maint-item { + border: 1px solid rgba(148,163,184,0.15); border-radius: 10px; padding: 0.55rem 0.65rem; + background: rgba(0,0,0,0.2); font-size: 0.82rem; +} +.ops-maint-item strong { display: block; color: #e2e8f0; } +.ops-maint-item small { color: #64748b; font-size: 0.72rem; } +.ops-maint-item p { margin: 0.25rem 0 0; color: #94a3b8; font-size: 0.78rem; } +.ops-maint-item.sev-critical { border-color: rgba(239,68,68,0.45); } +.ops-maint-item.sev-warning { border-color: rgba(245,158,11,0.4); } +.ops-maint-item.sev-info { border-color: rgba(56,189,248,0.25); } + +.ops-hardware-box { + fill: rgba(13, 18, 25, 0.95); + stroke: rgba(245, 158, 11, 0.55); + stroke-width: 2; + filter: drop-shadow(0 0 14px rgba(245, 158, 11, 0.25)); +} +.ops-hardware-slot { fill: rgba(30, 41, 59, 0.9); stroke: rgba(148,163,184,0.2); } +.node-hardware.status-online .ops-hardware-box { stroke: #22c55e; } +.ops-title-left { text-anchor: start; } + +.topology-canvas a { cursor: pointer; } +.topology-canvas a:hover .ops-node-circle { stroke-width: 3.5; } + +@keyframes ops-line-pulse { + from { stroke-dashoffset: 24; } + to { stroke-dashoffset: 0; } } diff --git a/cockpit/static/css/packaging-studio.css b/cockpit/static/css/packaging-studio.css new file mode 100644 index 0000000..09c773b --- /dev/null +++ b/cockpit/static/css/packaging-studio.css @@ -0,0 +1,205 @@ +.pack-studio { + --pk-accent: #00e5ff; + --pk-gold: #ffd700; + --pk-panel: rgba(12, 20, 36, 0.92); + display: flex; + flex-direction: column; + gap: 1rem; +} +.pack-hero { + display: flex; + justify-content: space-between; + align-items: flex-start; + gap: 1rem; + flex-wrap: wrap; + padding: 1.1rem 1.25rem; + border-radius: 14px; + background: linear-gradient(135deg, rgba(0, 229, 255, 0.1), rgba(255, 215, 0, 0.06)); + border: 1px solid rgba(0, 229, 255, 0.22); +} +.pack-hero h1 { margin: 0; font-size: 1.45rem; } +.pack-hero p { margin: 0.35rem 0 0; color: #94a3b8; max-width: 52ch; } +.pack-toolbar { + display: flex; + gap: 0.45rem; + flex-wrap: wrap; + align-items: center; +} +.pack-layout { + display: grid; + grid-template-columns: 320px 1fr 280px; + gap: 1rem; + align-items: start; +} +@media (max-width: 1200px) { + .pack-layout { grid-template-columns: 1fr; } +} +.pack-panel { + background: var(--pk-panel); + border: 1px solid rgba(148, 163, 184, 0.14); + border-radius: 14px; + padding: 1rem; +} +.pack-panel h3 { + margin: 0 0 0.75rem; + font-size: 0.72rem; + text-transform: uppercase; + letter-spacing: 0.06em; + color: #64748b; +} +.pack-tabs { + display: flex; + gap: 0.35rem; + flex-wrap: wrap; + margin-bottom: 0.85rem; +} +.pack-tab { + border: 1px solid rgba(148, 163, 184, 0.18); + background: rgba(0, 0, 0, 0.25); + color: #cbd5e1; + border-radius: 999px; + padding: 0.28rem 0.7rem; + font-size: 0.72rem; + cursor: pointer; +} +.pack-tab.active { + border-color: var(--pk-accent); + color: var(--pk-accent); + background: rgba(0, 229, 255, 0.1); +} +.pack-field-grid { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 0.6rem; +} +.pack-field-grid label, +.pack-panel label { + display: flex; + flex-direction: column; + gap: 0.25rem; + font-size: 0.72rem; + color: #94a3b8; +} +.pack-field-grid .full { grid-column: 1 / -1; } +.pack-elements { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 0.4rem; +} +.pack-elements label { + flex-direction: row; + align-items: center; + gap: 0.45rem; + padding: 0.4rem 0.5rem; + border-radius: 8px; + border: 1px solid rgba(148, 163, 184, 0.1); + background: rgba(0, 0, 0, 0.2); + cursor: pointer; + font-size: 0.75rem; + color: #e2e8f0; +} +.pack-color-row { + display: grid; + grid-template-columns: 1fr 44px; + gap: 0.4rem; + align-items: end; +} +.pack-color-row input[type="color"] { + width: 44px; + height: 34px; + border: none; + border-radius: 8px; + padding: 0; + cursor: pointer; +} +.pack-preview-wrap { + min-height: 520px; + display: flex; + flex-direction: column; +} +.pack-preview-stage { + flex: 1; + min-height: 460px; + display: flex; + align-items: center; + justify-content: center; + background: + radial-gradient(circle at 30% 20%, rgba(0, 229, 255, 0.08), transparent 45%), + radial-gradient(circle at 80% 70%, rgba(255, 215, 0, 0.06), transparent 40%), + rgba(0, 0, 0, 0.35); + border: 1px solid rgba(0, 229, 255, 0.18); + border-radius: 12px; + overflow: auto; + padding: 1rem; +} +.pack-preview-stage svg { + width: 100%; + max-height: 70vh; + filter: drop-shadow(0 12px 28px rgba(0, 0, 0, 0.45)); +} +.pack-meta-bar { + display: flex; + justify-content: space-between; + align-items: center; + gap: 0.5rem; + margin-top: 0.65rem; + font-size: 0.72rem; + color: #64748b; +} +.pack-library { + max-height: 72vh; + overflow-y: auto; + display: flex; + flex-direction: column; + gap: 0.55rem; +} +.pack-design-card { + border: 1px solid rgba(148, 163, 184, 0.14); + border-radius: 10px; + padding: 0.65rem; + background: rgba(0, 0, 0, 0.28); + cursor: pointer; + transition: border-color 0.15s; +} +.pack-design-card:hover, +.pack-design-card.active { + border-color: rgba(0, 229, 255, 0.4); +} +.pack-design-card strong { font-size: 0.82rem; display: block; } +.pack-design-card small { color: #64748b; display: block; margin-top: 0.2rem; font-size: 0.68rem; } +.pack-nas-badge { + display: inline-block; + margin-top: 0.35rem; + font-size: 0.62rem; + padding: 0.15rem 0.45rem; + border-radius: 999px; + background: rgba(34, 197, 94, 0.15); + color: #86efac; + border: 1px solid rgba(34, 197, 94, 0.25); +} +.pack-modal-backdrop { + position: fixed; + inset: 0; + background: rgba(0, 0, 0, 0.55); + z-index: 1300; +} +.pack-modal { + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: min(440px, 92vw); + background: #0f172a; + border: 1px solid rgba(0, 229, 255, 0.25); + border-radius: 14px; + padding: 1.1rem; + z-index: 1301; + box-shadow: 0 20px 50px rgba(0, 0, 0, 0.5); +} +.pack-modal h3 { margin: 0 0 0.75rem; } +.pack-modal-actions { + display: flex; + gap: 0.5rem; + justify-content: flex-end; + margin-top: 1rem; +} diff --git a/cockpit/static/css/projects-hub.css b/cockpit/static/css/projects-hub.css new file mode 100644 index 0000000..44183db --- /dev/null +++ b/cockpit/static/css/projects-hub.css @@ -0,0 +1,63 @@ +.project-type-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); + gap: 0.55rem; + margin: 0.75rem 0; +} +.project-type-card { + border: 1px solid rgba(148, 163, 184, 0.18); + border-radius: 12px; + padding: 0.65rem; + text-align: center; + cursor: pointer; + background: rgba(0, 0, 0, 0.25); + transition: border-color 0.2s, box-shadow 0.2s; +} +.project-type-card:hover { border-color: rgba(56, 189, 248, 0.4); } +.project-type-card.selected { + border-color: #38bdf8; + box-shadow: 0 0 16px rgba(56, 189, 248, 0.15); + background: rgba(56, 189, 248, 0.08); +} +.project-type-card .icon { font-size: 1.5rem; display: block; margin-bottom: 0.25rem; } +.project-type-card .label { font-size: 0.72rem; color: #cbd5e1; line-height: 1.3; } +.nas-path-box { + font-family: var(--font-mono, monospace); + font-size: 0.72rem; + background: rgba(0, 0, 0, 0.4); + border: 1px solid rgba(148, 163, 184, 0.15); + border-radius: 8px; + padding: 0.5rem 0.65rem; + color: #7dd3fc; + word-break: break-all; + margin: 0.5rem 0; +} +.asset-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); + gap: 0.65rem; +} +.asset-card { + background: rgba(0, 0, 0, 0.3); + border: 1px solid rgba(148, 163, 184, 0.12); + border-radius: 10px; + padding: 0.65rem; +} +.asset-card .type { font-size: 0.65rem; text-transform: uppercase; color: #64748b; } +.photo-pick-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(72px, 1fr)); + gap: 0.4rem; + max-height: 200px; + overflow-y: auto; +} +.photo-pick-item { + aspect-ratio: 1; + border-radius: 8px; + overflow: hidden; + border: 2px solid transparent; + cursor: pointer; + background: #111; +} +.photo-pick-item.selected { border-color: #38bdf8; } +.photo-pick-item img { width: 100%; height: 100%; object-fit: cover; } diff --git a/cockpit/static/i18n/en.json b/cockpit/static/i18n/en.json new file mode 100644 index 0000000..d187741 --- /dev/null +++ b/cockpit/static/i18n/en.json @@ -0,0 +1,118 @@ +{ + "nav": { + "herman": "Herman", + "crm": "CRM", + "clients": "Clients", + "deals": "Deals", + "products": "Products", + "suppliers": "Suppliers", + "intel": "Intel", + "beurs": "Market Live", + "retail": "Retail", + "browser": "Browser", + "documents": "Documents", + "projects": "Projects", + "hermes": "Hermes", + "telegram": "Telegram", + "agents": "Agents", + "marketing": "Marketing", + "chat": "Chat", + "studio": "Studio", + "packaging": "Packaging", + "reports": "Reports", + "system": "System", + "analytics": "Analytics", + "voice": "Voice", + "ops": "IT Ops", + "settings": "Settings", + "gitea": "Gitea" + }, + "common": { + "save": "Save", + "cancel": "Cancel", + "delete": "Delete", + "edit": "Edit", + "add": "Add", + "search": "Search", + "refresh": "Refresh", + "loading": "Loading…", + "none": "—", + "yes": "Yes", + "no": "No", + "confirm_delete": "Are you sure you want to delete this?", + "saved": "Saved", + "deleted": "Deleted", + "error": "Error", + "all": "All", + "actions": "Actions", + "language": "Language", + "dutch": "Nederlands", + "english": "English" + }, + "clients": { + "title": "CRM · Clients", + "subtitle": "Manage clients · pipeline · link stores · enrich branch data", + "new": "New client", + "tab_kanban": "Kanban", + "tab_list": "List", + "tab_stores": "Supermarkets" + }, + "products": { + "title": "Product catalog", + "subtitle": "SKUs · margins · client links · launch planning", + "new": "New product", + "tab_grid": "Overview", + "tab_list": "List", + "tab_margin": "Margin calculator", + "total": "Total products", + "active": "Active", + "avg_margin": "Avg. margin", + "with_client": "With client", + "name": "Product name", + "status": "Status", + "margin_pct": "Margin %", + "moq": "MOQ", + "shelf_target": "Shelf / listing", + "launch_date": "Launch date", + "client": "Client", + "status_concept": "Concept", + "status_development": "Development", + "status_active": "Active", + "status_discontinued": "Discontinued", + "calc_cost": "Cost price", + "calc_sell": "Sell price", + "calc_profit": "Profit", + "calc_margin": "Margin", + "calc_run": "Calculate", + "no_products": "No products yet — add your first SKU.", + "drawer_deals": "Linked client" + }, + "suppliers": { + "title": "Suppliers", + "subtitle": "Vendor registry · ratings · lead times · contacts", + "new": "New supplier", + "tab_grid": "Overview", + "tab_list": "List", + "total": "Total suppliers", + "avg_rating": "Avg. rating", + "countries": "Countries", + "avg_lead": "Avg. lead time", + "name": "Company name", + "country": "Country", + "category": "Category", + "rating": "Rating", + "moq": "MOQ", + "lead_time": "Lead time (days)", + "contact": "Contact", + "cat_meat": "Meat", + "cat_dairy": "Dairy", + "cat_spices": "Spices", + "cat_packaging": "Packaging", + "cat_logistics": "Logistics", + "cat_ingredients": "Ingredients", + "cat_other": "Other", + "no_suppliers": "No suppliers registered yet.", + "filter_country": "Filter country", + "filter_category": "Filter category" + } +} diff --git a/cockpit/static/i18n/nl.json b/cockpit/static/i18n/nl.json new file mode 100644 index 0000000..670c424 --- /dev/null +++ b/cockpit/static/i18n/nl.json @@ -0,0 +1,118 @@ +{ + "nav": { + "herman": "Herman", + "crm": "CRM", + "clients": "Klanten", + "deals": "Deals", + "products": "Producten", + "suppliers": "Leveranciers", + "intel": "Intel", + "beurs": "Beurs Live", + "retail": "Retail", + "browser": "Browser", + "documents": "Documenten", + "projects": "Projecten", + "hermes": "Hermes", + "telegram": "Telegram", + "agents": "Agents", + "marketing": "Marketing", + "chat": "Chat", + "studio": "Studio", + "packaging": "Packaging", + "reports": "Rapporten", + "system": "Systeem", + "analytics": "Analytics", + "voice": "Voice", + "ops": "IT Ops", + "settings": "Instellingen", + "gitea": "Gitea" + }, + "common": { + "save": "Opslaan", + "cancel": "Annuleren", + "delete": "Verwijderen", + "edit": "Bewerken", + "add": "Toevoegen", + "search": "Zoeken", + "refresh": "Verversen", + "loading": "Laden…", + "none": "—", + "yes": "Ja", + "no": "Nee", + "confirm_delete": "Weet je zeker dat je dit wilt verwijderen?", + "saved": "Opgeslagen", + "deleted": "Verwijderd", + "error": "Fout", + "all": "Alle", + "actions": "Acties", + "language": "Taal", + "dutch": "Nederlands", + "english": "English" + }, + "clients": { + "title": "CRM · Klanten", + "subtitle": "Klanten beheren · pipeline · supermarkten koppelen · filiaaldata aanvullen", + "new": "Nieuwe klant", + "tab_kanban": "Kanban", + "tab_list": "Lijst", + "tab_stores": "Supermarkten" + }, + "products": { + "title": "Productcatalogus", + "subtitle": "SKU's · marges · klantkoppeling · lanceringsplanning", + "new": "Nieuw product", + "tab_grid": "Overzicht", + "tab_list": "Lijst", + "tab_margin": "Marge calculator", + "total": "Totaal producten", + "active": "Actief", + "avg_margin": "Gem. marge", + "with_client": "Met klant", + "name": "Productnaam", + "status": "Status", + "margin_pct": "Marge %", + "moq": "MOQ", + "shelf_target": "Schap / listing", + "launch_date": "Launch datum", + "client": "Klant", + "status_concept": "Concept", + "status_development": "Ontwikkeling", + "status_active": "Actief", + "status_discontinued": "Stopgezet", + "calc_cost": "Inkoopprijs", + "calc_sell": "Verkoopprijs", + "calc_profit": "Winst", + "calc_margin": "Marge", + "calc_run": "Berekenen", + "no_products": "Nog geen producten — voeg je eerste SKU toe.", + "drawer_deals": "Gekoppelde klant" + }, + "suppliers": { + "title": "Leveranciers", + "subtitle": "Vendor registry · ratings · levertijden · contacten", + "new": "Nieuwe leverancier", + "tab_grid": "Overzicht", + "tab_list": "Lijst", + "total": "Totaal leveranciers", + "avg_rating": "Gem. rating", + "countries": "Landen", + "avg_lead": "Gem. levertijd", + "name": "Bedrijfsnaam", + "country": "Land", + "category": "Categorie", + "rating": "Rating", + "moq": "MOQ", + "lead_time": "Levertijd (dagen)", + "contact": "Contact", + "cat_meat": "Vlees", + "cat_dairy": "Zuivel", + "cat_spices": "Kruiden & specerijen", + "cat_packaging": "Verpakking", + "cat_logistics": "Logistiek", + "cat_ingredients": "Ingrediënten", + "cat_other": "Overig", + "no_suppliers": "Nog geen leveranciers geregistreerd.", + "filter_country": "Filter land", + "filter_category": "Filter categorie" + } +} diff --git a/cockpit/static/img/agents/sysops.png b/cockpit/static/img/agents/sysops.png new file mode 100644 index 0000000000000000000000000000000000000000..9da40b4f8e96cca091fa0c400b77dd4267227c3e GIT binary patch literal 252039 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
|DOE!tC=HBdF)~cTJVUFDNV-IcN#QYu!4{}% zUe)o#{es$5Jsz5s^K988(`2A;<{N#^2>8XyEod0tGm*@O_F18#;O+v0*2)~5#8t|W zB~oI=ObQnsze9fgyS(wuZ}8F2-=ur^gtCQ@1N5B*r0G>kcBieL?vLKQ)ieT{~Z~!hT1nPd#J(qvN2G96CJ1C z+|7njG5qV=))@3a*Y#9Yt@Pah$LCH;iMp<-t6CkG-G`-UK{|`Qp3@Grc23VZ*o*!; zwsHD06~>vtnBdLi|7SnySDQ5VG#L5nUt`z*p_6t|c8kOu`qRE5__2K_!0= zk|zOr7uUTD3bDERrLX#ga)P9Uz&`umpt2ORms&AC0N!Df!Bo}q=uw+lP|u=)hm}+%p0mIQrC%?RBabS zB-9CFqy!;_#H^Wd?%X*(@u}CiaqBsD_8W?9>AMY86^M9H0H}gG!H|3Ngx9P~5scUr5vW}&Rn;%~srA(-|6CD#dilqV0 z0Ovp$zp7m+<}fFHfv!h#G4FFt``Z&JAyQJ%oZzKsra%em>{@h=5CeS(%nz@^;*i(h zeV?y=<6E5cnfbvX7tUYc@bFMWDF>*nZfz*!%FF~EG$m4}L>B0xCegv7R;jXWoYUj` zsE$5+OzhlPA5K0G8ZBF3>bN>e@rp>M`HEvqieQOpJcfW0WbJP)+dkW~L)1AN22+7v z9&Fp72EH=$n{w(p?&4!VI@7sLd9X3tqeBqeRb%0r3#6p61Y&exnU-a3oE*VF8!C!z zMbhVv^U(WDpJ`f!p`Z0hUN^r_zu0v3d2RI&v21u<&t43y-+i68zWoRM{CnR+PB(;Y zCWV?h&MbIJAOy_LZrd$6XR4}ZHlNeXbkBP(gK|Nv398vmA-?r+R?ZGX~-lF?)RmB&QkjZ3v0vhJGuF_y9 z(ybv10-~aiE$k`56!l*B@tYcCUCroRua6lnajE?tdmg6NFTHxYO4n0b_2e%>$T5;7 z&?%owFX~`KjB3AcRU4oh8aP?6s1`dc&OgVgH2nCDU+^!!^=;aisH>WTX2$b3ZgAzw zCFZl5&3404yMa22yex;r5GL1|00(=2{veEv^&EiM>&nPbC~zC2;Ti7?Y*i9-C!Xp0 zH76d|8VGt_RDzAoe?(M*t7~G^)YdtV?H<8M`6QDA?rU5I(4A1)g%wg;3+4E{E*1YLvfwwj5Wx2X5k3KvmhmXJOA$D((Y+;RU z8<~IB**AHHl{aiHvuD|J{Jrlwc9u&nUb@K6&XS|2Pc>zEuM%X83Ks6?W3zwk2ir1d zV(H-bqm1a}@MoIcY^!df4;C)s))9zw8etf{a&hc=* zWjr&5`015eq*CZCI=7Vms^3Nk8Ym}JfyM5e_da}=#jN4AS6}9(n=kV4&O=Tf9YZeE zDM8L!KND0G*o`I(hk|+)RmiN9I`68Fm5x^oUQ0%1-FhL25NFT*>Q{vcK{Vnb=yyG# z9X9l**dq0x(8cff=>>uW4KAXpO10w>B7Ig)D1|~DdJdKqr%xX;Tg>?MXFkQ>{9FGf zzxmt0!xz8wt33bwEe_8evbVp>&fX5CWVWsD*Khldm?EpyimI;I-`{68*U+`wwxtxP zs+y`wU@9nO7CKT)q!7SBOmb!!6Q6tKHLhK}$gD}kfNsSzRldg+$Y2@qtV4_Lx9#$l zLOUb_ia|8cPJxtas#HS>>aiY`Bh*DI=76Va_b$UWca#L{c0<>8~f%Ldp92*s#=Rz{_CJ-O>BU9Z{-(L@cK zl3DdVErL`t(tHUil10b7>w0ouh()MFq^fJSCDVn#{QPrl(}M5*@Xz?x_y3sG%!vXu znX6YWaqH%Dym0ddZP#+=!2@y#bO>1@DMQQ}%%-mbIT;`pO)TS*t%HkBOPjaDT-Sv# zy=I*Ac72cme2OS|#!B-_#1tohuLvG2G_FKl2ZIK{*Ni<|FL#jhWn*j3uE{8f>vscv z2mEZrUX0Nj%670dfSuUbeGO|lx^33mSydIu)2f;(QOk18hh8_Fn}YMupWa_%pZcNo zK)0o5aq@nYV2stk(2nH0E`@W=jMbeFdE;BZ&%K}g30L>`i5)%&)+&Pxd)MtTd5U&~iLc)$rZki)dERB1&&n!=~4YBqT&6B&vGGYP02ZwdUyf zl#|mn&1|maAS$C2keDb4x#%XZT#UIjhexF^Zn_#(3d-OPlE_5W;PG05)y0yk1^=#@ zF>@JND4XQt{q}iE+s5Zw9YWN+8-BfC_Y8Yxi+fVeq%4`V0W)QbGVUSTE;dQ@!RSEI ztaZ*?5n#Tv;PKPPG)>~lmCL+*>t)tYx3nick|Ac*eoonm36lB}Lp+dARDX&XP1~C_ z$c{$a8}A#m1H)e-&Yt_SO8C>o>5p^*;j0XL^6+kFy%YSTl~+VeN>D-%5g`PcdBep^7dU_6JoCkTP!Ddm zTXkaSb$7vHv0y%5(7P9-sW)P(5D9d-XWJ>qS&636rSC~1T-w{`^RK?f{;VMe-S*?^ zdqpXf1Mi6y2Iur$iDB&X9|yQjC>)>KC7<1A$iQO&8>3BAY}%a?>MQtlu2< z&BJq04PB6 zjM@3C9Oatt{_s!v;~)MRv-wiPe@f5(?wsxMQ?6b(~-Txn*gb)@FlwML{c9KEV)Tg<|8DvXXEyIBa+BO zpDJ1bU2~(UKy1Da>ubWmIcSEc-v_VwfpJi93^x8jl=&F;%sW#UonUI2_uRdA-jj%XmS-7=Pi_8VgA4!bXeKuD_g4hH%qL|Uqk9i7y) z^6~R}q~W*D&q>9W$cD(4G&$mMY>K|OlGqfxR;Je`S`u4Hv?bBzNS`BJj&vo_c5mNP_BRXK)OZ5^d!Ih zx-3I1Jhe=km@~cJ&-*d_F3J#`xfYD^(aD?<^8-o73@A+rXwn;rfoDDZl3!Z!K z3a`BI8hIr=y8DFV$H&mZyk0<7;nCM(863QAc{p&JPfzZ9-I8e90o^&FOhI%rs%r;a zvv%;S|AzvW>dzM9a2OqMVuStc#G*KV{+49*J zpX2ZR>wlRqeCCtPYvH~3Kjikk`+Ri&0d3n_1iZp*UQvo}*Sml39&f(>bMD-}&C%1R zCvIz8g#_$mF#5lhJ|BS_n^NQqBeyUxG% zgTsj#HHUuNy5j+7`b=qimF`W`kj;i4OQi2Jw~wCk z=H1)8{@w??cl$ouK0|JqH-T%HF7nFFo4j`G78iGRXi8>FPge=-?y~#h7x-Y?@c;M+ z{|*23Kl~rqKfJ)Q3GB@yFTM047cO1q`irk{epZjvg#}(!)e)?dqkLvn|wO6v*U!yS_6ll9vb3jnc=05_mzk)GAh%$SnD8OdV#~rkM zWtazQLz(Q_@$$qgWM9OkaX&3ue=+7rB{pR=3hFSYz9BaC{1z+BHM59={s{1@3icp0 zg}rUZrms+JyI%4B^4d&C&Bw^sxG_{y(?rpG zvJ|?~k*Y|6K|sQcn z_;t?|I+>r-t7UThIi-C3_3Ya8;;lc$G^K4ww4owMPen(fV^&~>APK02yASViW;UdyhMJ@A2r-eNIk~*tA<#+bvljH8Yy|lEu8{#7hj)Od}cfa9usC&*$N zCS7>Xq>MFZIQ>n1N??>+F~HBA#k-!?Q6_#F7%?@!6cN=jCHK-ddutJO4%51xZLyeN zf;Pgv{i8-JL>ciI)VatB_pqLAZJ#M`^4U6XI5~ioN#Y@x^J36lBc-U#)219a7N04@ zz-*B8{U-wz1G9t8hI7X!{Lw%9Z+ZKV{(x}*J!YX{yB21%eNwXvajs*AZo|xiZV@e+ zSbCF`A_bSu9C)2bqKzC#;+fX}g)f~yzN(CA@!t&bM`Et?Z~D|{UxExyuhafwGFOLl z6J|;YyRCV99!1A0OCi-YC1<*>SH`jwf`xc41rxY5uo9xrR;N1^A~3B`&RNHM0x=(d z{rSHPzYXB-6J%skCRd%gWyGDyv;BkpB(}@%|DO@`@p*Rcs`Z3|Vjf5SkIz8)8hH zx5x3+>Kc4&ZSE=7C!XbY>aQh-U;aN0fInGUW2w^)^(Pt^U+~2+tcYP^7u0^%nG;7a z8>p%m3#D6g;c$oF`SmaHzy7!X7s&R6_kQsPx8HkPo!WGYBbI!inOCG**xOsOn9Z0s zHBkcJ`o=f-(GPye+i$$#o(Jp^``)qP0)s{})r^ zcUd6TtTsJwz5gLU`0-Ep!H<5-2Y2r9`01Klpst`YOa`{xjJo$IP{*2Od|1O3lb(qa;?0-f3YChB=Nv)~%FY#Sx*xdo-vs**PV zvT@2qqqHUSmgZxCuf!re(*_Y`&_&n#APwZK8i^>XGS_Hgh7@|W5`sSm@SR-f<>E** zo)m4bdXYyYikcvlqS;}q+@4ts^okhZi<|*`QIjY^gmdc^yZ7(&jsNQZ#e0AJ9qQu; z)Y5RW5_Wbkk!E{PEl5?Z&b?R`O;MF-GA*3tnS&BExmR(vc+$3KKL4v;+BfcdVUq9k z)-wF3FY9A{<}=s&C4>57QjaN<;GvKwFEPA?N#s*(E2O9f))~@ZJ{%+C2UyxweQDX^ zUi9X_1ezWl+ctWpUH)=fYb8kz%Zb%ZzrB%mG2YvU^u`%?%5Tg+~X>1#(K(VZ^6wTzC^E3TdAkMG<+E=yH zv|+=~ws;5oVlefd*$4d|mjbYfI!Fbg`P_@`5%z5urF8V|hD8(k+-F|n-~G4$Eq0a_ zZ@uw4j~+gtt`f7R(OB*Ri}{@0ogHSgn!Wuc=Pw?zyIioC%{X_k&y`D;c<|9jtWHkp z+Kz`0)eNv$%vmfJ#1J?=J%Lhanp(jvXPPKBVR)7@RndEx36F7516hquH6QBD6w_bgXS3dO_UV81*Tzl~)4$mL*^ymq1ym62B-g%4C6>i;pp55JD z0CE&Ul~lS9YGVzaAK3sy7;U1Xi^aGbUq@UQZNWj%Z1<%Qd}l$I$z7)J3SD35O5yRz znt$+L|3m)x&wfh1cfe=)8o->n#;5eec8sW} z`LJ8VBym576JRUXC3;;mlQmZKzhKuOwuZze(!|EEblw)aJxfgq`ulj^RQgsYOpJ-i9$|B+qdDvi^%}bKOuu;lirEQ86qScQH%*Ar5GE96?0@ZpN%=lL zUXFvks3&rYft|i1-@VNn-~J}YcRyq)nJ6_~sfo=VRC7A1Shqa{b%t~2w=w#BplA*` zJSSZ#?!|8oX%ojT|NIvnZucz&RnKN2XVG%A=uzzZa7@1oocS$~vpLL}!>_;h=y~-~ zu=B<2>?I7pPn`qZ$*zP%SJb{uj1UuT&a{1|NKpHF(Hs@M<%H|U-Nn|QUbcFv>vbPL z^f}XGw2`Zmq}j%&_V;4ny?u7rz9zB+PYwC(QH_~#vgJUBi+>rgqK zcNaT|^s%9jjcP`0%V^3_6)e(XX4`GJapMNBz4i&t?Of*MqYcL&t;r{ax}T9kR1X4U z6o)l6U4!;g0ealcap|qj!QTZ`0>SqYn*;LL*r zVoXMOHNsYkLLk#`PkH&poBWl({2P4g6W96qPhaQVcYeYBdv|&C;2}p(pCG_;G2`&y zfP?*g7R!d+UCko5vzW89qlss(T)ITbJ;z5!JbLheP;iid4a4v|zhgj6B9 zgRUh6B_c|ECsL!S+o$u{+duY&&20x`15Z#Jy7s4nZ=ZW&j4T&R7K;Vg^9Hs2Gt$Sf zp713$(Z8NyBqmIPFR=*&;p0_=K}y#4`SoX+8vkvoJ#dqRKQH*h@BYd zdZA;6R7;36vQ!ktarBJuQiR-Ql2i)pS>qlQw|_Dj7ag>5ye5YW-D96m7(`{aN56`X z-##4v($C`=|D@M>|3@(Y03Gu%*~tN2Hr4#I^&Dt`vRqk;Iv5Av?$?vC%yB^v3F>#z zm6j|T#VW+2cInVlq^FmTOh-?vW&Dz(SSs1#WlMMF+9JKx!F(PxiGaE+i<-+mcBtrP z+YmqAsoAzLPOr=8z4>2tpuQY`(IKeTr4)1Y6pK!nHKA9`nW_|G0Al9k^oSQ;c!^Ja z`qNZ-&gx-D`vk%^(&QQe-GUu$%xvC^YfVIBEktMR2Q#Fu&GE4BmVHmx%(%5L&aQps zs~C}z!G>j1%sjkB{JV3zMkxIAGw-eyh`!|_V5+T*DFsX*RngG^TKmiIX9otltM~S z+4ibf`8F#HdXm&ZOar`F5D){^q5DFp77}LQzRr_cv zVqmY`a`dyGaOa1AOm}?5A_TfFki!D0b|E$c;Nx?F2q6(fgMo=j-DDqcQ-My}?HZOL zdmt7e(XR<(Ukw0b4Bp55Gp4ViL|uX07<3;eEBfrq&!}mHQiw?(?%EljkE*Gg)M*0t z*#Lh4-_RQfJLsBorIaCqPcE9xM?%q5ly+X3gw6oGGf;N`@3m|zcL4n1Ig{%q*N@j( ze_Q|mvcsW#7@x^8y=E|0{*vo{+2M@AUvx-;Py*ygCy6d3)$x=b$sH+YY6>9~+I~aZ zZ+Z3A*Z9OIJ^|~*`e9G|v=Fz6CO1S0q&kplUE8{*UC>Z-p3W0nhc+KP1+Y9bVMNTt zIhjwY)3UEJsIL6btA@EF*lqgz0QSSRcHRjA4n`^!g%FUEDP7C;E0=ib)(t8O-}|FK z;@!93;nAZfJUu$$(c`B)eDs)m_wMojd++h)8*lN!?c1cPVt03ky&bjT&+3|aQzK-q zT)oVTFFw!p>(6m;xKCYIY&L729zA8fUQyQ-J3C8rG{NGL*Q91fY-W@YX>+E}x&#Xr zT+RrNn>Tg2+vkF#zNF ze&etFHI^4H@yCDmGd{fkP`5`FSe=}3dU{L=g|>9`ITK4FQgd{)p)Zk5*YoJ;F^?bJ zrvh#q?s0W*hn)Zo=9!<>c14Qx;$d&coKbK> z?+QC#@lkZUwB2{Mj~pl%fPC;h7>I!qQ?0W1p@H(CT@q`SGYVS78L}}PPB%;{4&rtX zd#vVU*Szw|T*p#4dGrWbZ>Vx1W+4>IMIp&TmYT4bE&n^3F^;Uh3t~b^is}<#+Vt^| zLJ7}+ffTZ2{(r3f*Yhn)cIStE(p1%UKW~pe=X%q(4H_6=3|6kMufOV_Cmw6@I{0`;a$T*-$x-3%h zPVhH%%_nd%;$p-`(a^bkJmso^3Rux%qr(M;%1_xrTyyuS6e=A{#R`#YFKR6V9)|m%!|~> zXA{5#R`rsqD%su|(Jw1WQQp)L8mtL8mvA0>y^^w&40^6(l%?9DEHfi(0*MgFNuT5| zuSsbgdCLrQZjd?kyr9=aN4O&8&UK}VBh>mF;Yx)PWUx0X#e^87Y@Y$=B+ac&f!FWd z;b3Qrmroz_%Rl=mDJ4c*+Z1JwHb@`5FQ`{FpM3f$fBL6C;ra9D^s0*CpwFOJQWg@P zW(^Efntc8B*F@Dn7!X3sY&K!Om|>k^G#cSmJz_Od!1wz2{($5PnviIM*nLw{=_%;~ zR7igX^!0yZI;Alw1$^n5*GoQr_ys@sv!Bp<%Ll*pZT{Xr{)hbb@BB6?1^(#Y{A;#` zJ$~!kzrlO&yp6L~QhEXd=Q-#P+3gP*UyS+gcYnmic*@s*>#y)1{k^}>7cbBF@XJS> zPbNg;C6NYJE5@yvkz7hKC(aSZM0%b7Os3sR1oMv#;s7FXo{}`jx`H;r!^cng{ONP< zyzv%){qOuej_=%qq9h_tKchjPo_Bou(MNpmPrl1?xngT?pZjmU!*BoY-{QUB_$xfU z9P`hdKvz^!e^jh!ua3Qv_1 zHZwQYf|pEx$r@FS>wMK2FA`7wZa0#DDA0RpR-4Ij^&PmarSO;%b<;4N&$zt0;_B*3 z#sY@6Y9e(AA(6!eekr9Ji#TFgW8Vi;}Xegsxd5sxNIxRCmHKX-f`T z0xd0V3IwDib=32dxC4;9A!N|cQ83C#B}4aaaE3r6q$t}B)${tk>oHVIA{H=F5{7xC z9Jpk^tZ^|Z=qH@6jSlR!*(4>PUGM_VQGnSg1F!~WgG&ydJT5uhUjW=LgLVGhuU+HS zV}EIT<-A{SCYV>6fbXyGfAyS=-$!}o|1}z_p^>+x-U+D{z^4Y&fSNAqdcmMyu{|16 zc~7$vt+GiGXA{mzCBIkr{cg>y_klR_ZK6;H`VNbfK`=T;WQwU7+o?t^QzenwHvr)) zV4t^}ps{(L^5?RMt)(~ULoOa-Mg3G3p4T7ThqmRjk3SOoxAi=G_LAo>&RMP+R!v|! zowKvM$L`)fXXh9E%YXU5aD8=6RTT7l{VpSzbB+*NPEL+_`<=Jh-q~h*XItvjHx0Ad zjJ9bQ^yN2188qu0zU<+9158oSro^gk39JR>Ux&x_R-RYspApqlL=wO}dj5<*{l(9D zIUe(^zw+DsoqzBT_^W^IuTd7B-~X5Yl3T~e{9pc${|Ek`|BwGW|Ji@`zr#7pY&K)D znA5CQq|nmy1zY_-PrrP`&wl<3mTk*F{HOnfyKlY0hYvsJlZOv!W0Fi#%5~TDrKLWGN}F;CAfIJj|>|NZ~zJN%#jum3mx;eYZ^ z**`pDGMlnm&ha*JxVKHcn(?bY{}~_t>d)EQ-o}?b?!WdX-~6rL##Mbj`|>eOD)Es#0*FZA{lJf zD@Z%Zkr5&(`(wbHbOKLa%?l7dj9TQ&e<;73SnX-sm*5V65Mn?1Z$>a zvp;#*_M}(SE-F4S>427 zDSUHK{#kxo;>rSBNF)wU>M4j$Py`9^o@VbUmoD2#+?Rld?* zIp-C=YTbwK+PY0r%ter^BezQ3s1Bx%h5{q5g>o~Y~tBq`n&^#Kj7NcO40 zq(&ru9f&rx42DAn{Q)LGyIA2OlvZjt7#m3`&@?OBrXeN?*X;m5qmjPO-h862r+Ww#tjbkcbQKo zoWFd@)^Nnd#TCXDl+}P_3JH_31A~BoKn9gPtg{N0mSYwDyD*~_cn6if{Dq3ThYb<c!?!EOEfAx2Nk2l|W7iS$`eDW#3_{mTBt#5vln+FH%9PIPp z!F^6nj|nLd4J_&vg85=e=?huF zx=;|@euV&aY>P57`cdBdnnCP7+pq374(|(IUR?70{F2sq4o+`U47O+!tm=l2_XDp+>_u1tabiuztaU2coX0I&OAId7wN^g-vp?(d}dSDG>^`MeF9 z(cLq*d`}&MOsF#0=g1K$iUiB~oXPlFO1B!T7jqa_h$nR?c*r=o!eRRauCAO$= zMTIRYj4Pz5k1uh)6ehu!*rLSgd8RBez9ba|6cx7YVT)2j>qLnMM#@6tq$P_<@>$k; zo*;SkC-IR_v1?*7&_={+cw7glL`VX7WH2S4uO`k{+WK5M|JTnEW?+4NX&Y+tzn~dv zj2ILD!hOHiOe2!_f3V59ueSB^?pi9nXKEp1&|*`INsaX1NaC9|1h%$z=vPBhlR93& zV>KC?Fa|LOQk485R_DG!)boXNRAot3mTQmuPUE$y{n2%k8Ro8lk;6NS-H=lSw7XCG zePd;2;7ym(1#9pC<) zzsA?T`7KUv-eNMD^4UipbN2KpAOGSP{P+jo=lg&7ulfG>zsJ@13cRC9kw6lVNSXsI zMXoN-dGzEFtI+V9fAzOHym7*8wd8s{#`{7zWaZGwal}SIEg9hek|uKySQFSYtfl)7 z=yevDBw>azL<|P&OU^IHJbih_FF*N=|K`8{XZ)A{)&HA6{5OBh^A|4!OiU!SOPp!x z_Z)_XCyyU8n@%7?uNrW2dXsnG`xQ%?t2Li1LB%5$1VcHrK1F3Df zy1Zn$SP*LHmj!$M0WJhQQ5-Qfxr#_qn`&pBqnoOB1))45^4`S*I;8lO_b*|P)@$J; zjRJ_O*$FwRjML;iR{a8m%~s$MDO9UflKv}T+`V|&k~zJNecG>0@V2iw;H?>g9F35#{Z(l{Z?jXHtQXyO=Lo=OX`CE7 z+U?5{X%dMjM#fiH%qLS(PumRm7UK$$x;M=W&X81D9&I9caQ%X6dq}x8zz$1XzrvN3 z0Cv&C6+N7$mX(|qQp_tEPw3LfZlsb8>unP@(#neLw{9Blw%MALG`(!zXJ|DfE&ncH zFjYlsEj21cDQ!*0O5XVdYQ(@KF}>RSIjPxCfnQ#=`uA+GxEZ)RlZuKC#(Wi!Gbk%) zZvx+6)Kn87_gI@2@;NB(&7B{_0afOC(n3YAkS19dK;b?8evhruh^^5` zsxw*%Pxa2pXKV3BsyvD`uV8PbvSV&m7D`8bUa`-US%8gGU=4J}=me4#tNYgAZ>*!J zDx5EfI(?3hPnb@oOve*q2+XE4N!K0{F(CyZtZ>x!__OIkbV|I-3=4QSez@lxSTMZHyj+_4vZ z-@$py_4SoZn20!%WbWOpbLgv!hk}JbSkhN%k`nwio!2J+Cj?}&m%`O}%*FMXk3Rd1 z|LVW~uldja^Zys$|L*s=zPdtWsz7KLKtov=yo1$ZM!Q;(V!&C)?$$1^-FuC~Nu{T@ zZCEVlG)*njD~i)#Fb&BxINL&4VPZ=Rf%$aCa=xTq1PTMgUJqvt$tKC*XQWQGH(GH{ z-&qGr9k{MP3;UygulQ+fG=q+-Tt}pORmtaAcGSCkW4|;};kGf*s$YxDtGwm}^rT

6-cxOQ0WCCpWo6HETnTC!r(RGz0-<{Q{dCfE!+m`e5Gv>>MFkHEyl5-^I2-Xs< zAv!~J5WS%_5!?3+54PDp-s9;0O%CtfVDHW`ySI+myL-y+-BWhH(q!Ka{eFYpyEoXm zbHetW6SnUhvwi!Rt=q?pZXYweb;R)2A)}jz3~wGXym7$b#yhx@j8ZUu&D^{H4v4{{L(-ZC=|Gll!%MCY+ReC#wc?O7gX4 zG^sx{$+EkBz@XY9H3l0COlxsT9ZZeu>a<9Rw@T;6;Ea?e?q~nCzQpVc;EU8Q<(c*O zS~A#M1^^mt0(pv982e&u5=~&f~{VXj<_cPpV0%+kkbRd-l8l^@d971m@gI>Yw(2!vj+TREw(5+z+W|uq>5y%8qa``E!;-ONQNgv0wf$) z*K>@oxclHu-hS`v^oQG&<$&2_!PVI%l`EM~=KR6G`UC#E|Ia_;2S52KwK2r9B=&o( zoMRGN7EO&MvfZob7nbE>%Gt#Wdcz*K@7-oF8nRf-A!VDGz7GW8(1qNA_J(xWp&F`9 zk_Uw>^yzP`v3T!EKocU<#gbJBOqMHt{>wk-M?d;8lko)0y6B3$mlb7U==VKYAa=Si zDqpg{yT|U%F1=olM4}G0M06wrArYg*^+sw)H72e|u_3fA%f*t#WX^KBgaDQI6soF? zUL;Rvq%>t_M)Q2!v@3V0k{@_;UTaH6-sQPNlxKt4rHhZyO+-f!`NiDmoUDe%BWQ_})tasI^Le^LaPa_X@SB@!&RxcTPFFdxNdh14bwN?A|)!;NB_w_inIv z?fzIHhT|l zvU~pqJNHi6zI(#fog+p!4=MMz7#{61I^LtVHzf5ewP|T>62`_suu(x?L*LY?Q0fGT z7Al$``VQ5G1!IH($OU>0L^V+*r*gc4cgGNP3_}L>d`y1-DyYjny4Hbu2KrwIeW_&V zUuls-+E>6lBq?$Hm$nY53rVB=A8N@HqqgLP5y;;+_mh(&3E*en2CKAG{G|=X6zuFA z&?|?;+TdaVt)(y}g)2L!VQ;0vsz~W;5EsxkqW+IjB={`d=a!{>Yw_9lMc3LZ>r|=C zn(A%Xc~Zv+WQr)?J0jI_{aNCDRXea;)hw4aP2J#(VKnShl%5b9=8FZhc?~%Fy#Xdd zYFkoU)6^@#Q22_r4P0Gba`y6!t?gZ&JbTF}pMJr`=2rovTzs^!Ae?R(TN&0{N`+jYX6K0ryfP(TdG7rBMmH~ z;J{`#OW_Sg>G6f!tFW-utJvKdu`}ADa0PYUNWm9h zP*}^>V95PDcj;9<+P0+);;3Q_5?v6ZIK+gO(A31Xp=lcCtD42KW;$E2m@f!*z!^!I zoHN;Of{(nUHNa<}dIfAZBw6gHihK?FIW{*->qdVs>s-e&N{UhWC-X<9$GSgBtJ@hX zbr~}FuGQ??zs!i_zOvRZNZ)md>8{+Iceujh3#kF&3TdL=Upx18zt<+0T@wW%7W#by zu!UdxYM=G~8pO~I>&ADh4n`d#kQuQJiQnjyMZ*QHQ-%XE2UwMSikNWACCiHoOkHDR zg5(GkL@R;?8xBpaNlcoC-u^x}?%ZQE*y7UKRLt}ZXL#_f3mi-SyJehIPFRk8AXq5NbD(3JLElg;hcKyd>^@&ChpRM z8`DWt^!K5x zKnmfH7^%UG!(k{bc$+Xbu&8G&o0e8pEwKfkj22<6@kVOYH+2xnu&H_W_z5AvWZv-P z**Q<2y(9#~YSmJ&8tP?DTQ?NWakO{9_Grkk-=``IVhAi23))7s0M-{;qg~YIR#QvP zR}Gir8BIV`Hc?+V2^387Ko-V|+E|l$U>%W`;a17c-iXo8klwJu6kv*kbq&TWaAv_) zl_=tZK8cYluyw=+BhEFhko@;Vw)&o(fnzl6G2Gf=Yv%xL#m??A`+EoUtCG+zF+N~? z0H2d=2-vFy4`U?;xd>1;!huF_XdToh(jtW#Oi0*hXzP};>|vZ|)wV#wn?xBK1}3my zz<$r-j*2?0uAw;C|;JqlZ~yLZUe?!MR?+m^m}ob2!O=7ZPimwhP#X~a=a zD!7SgY?7g{5?&SSNYh4EF)^zf#*-QI*+MFLDS;sb2(8%DItf%%*+p5>>-F$O_KsK3 zex->zKHKNJmYv=-?tKk(>tqn*xDCafhyvEO06!R5+wjy0kFyk5V{F?UciuUCd&GU2G=NBv-!@#mlLKHyZqu0zsrYz^nE`0lOOTPcmI?R zzxyLT`{~d4)t~-^4}bAj630&zvmokmpYt3@6M@3#c>fr&al_-C4aYuFE9wt5Zah~tNJ-zH z7zh$Ai58ONtry2QdABZajU@gxNkZcc0b>Hzi0?s4EitxV@e$Z?D9kscrB!;A|p=z;dx*Fzhkf8h~-si--vYg{^Q%)q6O%+hLMzgG>nMG0mR{lLm7ZSds0vHzI~)F*n--zpikcy- z4_Ol~S-SG{#yO0x`k2H9pHh;LC?k2H#aRS-`2=FBS%oF5wxx-d6g>nfYbr0W#+slt z?lq(%1QxRy@q)99F=yx3%w|g#^CipqlI3Day<8ESmYvavt^S}JtPleAYDHZ) zDq)FdYtk6?gxCR_1k>e;CP3WCZJllTA_cEi=%PlKXauam+Qjbeki(;0M%zP-gJdJN zfUWHwJ3A$*olu&ZoysxvmMSEwWa+ySZ@fsj28P2vCkNZ?k4mZB8`aHGfqDg%_Q;7PR5+C*z4F=k8w6VMPRdGA8aRV|cS zw)-W!m1El{_WPbuWhrc+u4`t?7H8pTcZ7wRRvBs~LLsW7mLUakhN@#?)dnWh8I#G3)p8|;ezb5-wtX1|%6!elhOOF&gJo8| zcbb3=uw6UD>9saO);8_USqoq~)mhGQuOP2X^QIIl#3J`azGMdF)dV@2;n-kEax_7f zvNlz9Rw4v!@#`UX#)}i5DdZes7&;zbJ+aqz@=i+FxVD_1fj@)&8uasVxn>RzQifrZ zQ06f+%8;rm-`GTQk>sSraF!ws4re`uFDSjIXd3L*746G2`mM}qf+M6J*d8P!ZoleT zjy3r0UF`NQ^JUBU#T7*j{p6^cL{%pSbz&3@g8;oIQPqKJ)l#hjgC^0hBmFwiTQ-#Q z8go6Pm@erp8hY~@Kc3^q3yR5-V!EW5F0j`#;?+dklyp6Xt10PfO1vBsF2=NHS2Qm# zg_$_JqGJZq2~B7B*=Pc?s<@wNN203ku%zRBP=!uq5M*t?h%=w+L| z|3M0=VUm~|l6+6uTR%#(QKV$h)Vr@(_5)76;T_p4UdtV?GyX#gq|}l+kl);HwpSwt zaz8Uu{wf2YF!OrZ30 zw_@{OqO-vPgea=YPVJa-Enms^ET#TbWt&9x*#@cfr7UP?CzWwtdzI(?Z3tXlUo)9Z z7>~zXUtcpGkD1RG%x7~J^976foaJIczu%|d@6)R)ymN%MrLJq1tEE&?)5i!wJSaPV zYy->XiZ-;Jf=F!M`q16>*W(~_4D8YFA@`1Nb7Sj(vNrTXK^Y1TcTYJ!c|a3O0u{Tv zM;wf{8Ic$@bN1UghxM4F=9)Wh!5aqyPL6glRmo^)hdZ}#addD1ZOgE%*xBA@I2uZL zm(@;eWLnzvq|FOXo>61&W5Q^ze1frgPXl2A^%R>{^h>cE4`&Nu z9<7dX&@eP(s7;b`w@piI8fJ?bSFYuycY>Q&nZ>82lX%5ED&SthB`6> zZ(awvZLWpYgCV^8A2G3 zwO!wC*z)o=1Fo^cAa&2W@mu-*+WE(tED&USdnPt=5358dlYmSZt!n=AqYG1^YbOth zxC-le8jh4DNs}a>fVW~cYHAi&m&~rOu-0fcJJD<Vvny>Pv363__n(r`4~a$)A*W21UUF2)QbtP=Rk}_N-v!UD z$Cf;6)if7Uq>Zg6FB6&?LSVUCGM!GD&*zlBzf`s@3o-1(%=&{3Edt82CELlnBTv%O2{ z3u2IDX2ux2(p6u0$*xy;in73Ee;d`{nXEwe;5Je@s8Sm5Ek)rd3Xk_r%z0ky`rTZ# z7GoUNdTd@~BFXCu>4==#HFfcHgijZI9>fghRu?}CrbeA_WHKt@G9q>68p?8LJp;ss zo9(z8Ekx$?18%5t!CgM0Vi zrR?w1#)9qLLv9`&b2=KZ8*2{RIXBaSH+qQ=4tl(MbB~>2#iDIFI6C6Jci(4gXO~zv zRNk|I^u)V8+`N5eSY(`xA^+&Z*j1*&um$fyyw^L9MxA5byjF1f>R)C$H`e)@x!oWgX2TAiui0IDV;y1TTw`7Z`YvW(wFs}C zv!Piq8$iFwBy{Unn}Su=FvuE~WL4Rl-#VwDy}oAFWH>7-`3!EIBhUueXV2oz`xqU^ z{5dO^g&^vyup;?q3EvvA2@8Xu%!0{28Gx07R&BjtetE%ie2sPLD24)l_wE(UjR+&X zs*<`MIv(D8)$|EHiYbYSPgIm0Ju*NFl3F^3pe2Q&CnFDF4M zxkGmWsWrfNdq4p+OZ_g1DnCo>S*k^u=9Gjkt8b<-3 zbv$H=sYyFZSaWDvjt&ngeW`Ouuu@EbGPflpPnq@XSi2Eo>%75hD~k2DC>&)et*AUj zsbH`5Had-@u0WE(ZW0b5VzOA)#A-ug$&N}fQC1bB(TJ_BZF>Da###mOgmsQyuM*p! z)67}wgyWo7bw4E58h~zMzA~u76s$QlAwHpPSxMwp2hItgFqpNJguxp?Ylu0Kzr&DoM^z0z?dbcr_9l%>NHSYDrV@#GOc zG_4e&e+}{MOsA^BZs6=jQ$n zt9nT)9B;kzHoy5B-;#Xp!y)y24lyzq^r@Rhz@&3DlU|F1#)djANv-6(cnLyyOo*D2 zvnAH8l*0{Tm$F*9%vwv`)a>r>@Qts3jW=I=jfbB;!n8~FMisY@54mx4gm;ds*_2P8 zKIY)|4gT8S{+slUcA+v5mo$?zR+BUOUe#VHQMiJt7~owcBdg;|GK822#!$x~6%gAN zml81rmd%Pq)6xKGBSV?2ptTo$Q5N+2JqE)8y?&oU?f58=W+pXDYaP+h#hk}0rYH$- zRC4G}%o9NutkV!W0h9Hyd~RM-YY^AZod>;DhTt!e{ud!g$SS+ zt#R(XS1(`<-Lr0OpV#bsS!x&0;WglACcXpdS3a*j>euTegE}%VH-<&j#p`PrBLJ9H zl-^q+fi~7)BVjqGzPcim8JUoL556jPJ; zxUwLDFg#wO9jx~XJo3+2iz~dO)QyogNi>fu3uU~u*jDK&sZ<<juaC0s%AEuF&R%J%x^MfGMO+LPgpH$NK&rWS=YU&wrOeG zrc=R$D5+8-DD|-{YsuV~?-^4b26;1U$t5QTQ8lGa6n)FQz5?bH%z5$fSDZcigtVIA z3d7w85BR75>3>RpZJES`B{MidW`TTR*~s zH%^XWG9kWr!Tjoq!oX-WR8CRL_gb~{WCAO%yUU?1XT0}2zscYE zr~im|zx{PE4bAmS#?QXs>iI+J$r%G5DNQ6cHHGzT4R;w0wsf8)>2=Dv84`79X`2Q@ zz*!?%{puBqwq_m^t@Gdttn-=&U!CkaX<0$B16d=}J=>o1dCCz>TZ60VroXHOxz=X5 zTy9R@#U|Ki!jzYjRpv}X`Le%3ZduJQ049A*C}B{?Q7P5D?pp?YVTkjMlo;h>`M5IS zxzDa+G;+)1vhlmlrmw0-o7aKPe>LxAV3#pkKb9;X1$uSTTHE>c+DJHMPUGrLW}Xm2 zXd>Pv;&M*7y2NYVhE~JKxNP?-R!6Zq{VvyzGoueu%ilUHnT9F#%xJu@mK(*fJZuw%!D*c3uVuLp+ zTd;*LM(t~`5`LGAhU;0Qen8M#BcYJusGhMgqp{`*0V~yb@zLO;p$M-wA7sCe1{Y12 zh)b@smas|6g5~eobeDu)m@X_$)!G}hFaKuUGCTL{OoPtc4ZPRBAg2j)tu!mOq!>WM znMLCU-g^%A4l&UXnt;*J(lSfqSs=Dn?r*_5M^SppN@#9bxenlSD@#XNSPHKRbuyjW z&@@RuHR3ELLP)sby}$V#S=?feFh+pS7*Wkm}o>3G?Y3qiS>Ekg~mbJz*roLz;J%&@^msjW|9!WNS2JrC~2kBlfxM znD^qvOD--hxVpaP`ubWb5NYh90ampv@PxsnNQw=TsX-{bK3kfJP@FXl|LYO-xuj;~lvC(I^eCgU;l z5P0K*ukm;P$$!E(zWrO+;Wn$QYc8HWBhKfPv{W|WT~cQ$)1_L=5|$%rhO8iyH+xv= zgw3i&(*)uM_i2X%i0a>N3HAW@Vhd;5FbyMLSg<6VY3L#pAB(as*nw{PbZAJjF1GTIX*kB~`nlO6ZU%QqzVWP6%MFx2VdZUtR2g0)c2E|X34h2`N*iWtUmpmXW#n~&p-W?ekpYxqU&R;5w7TAtnZv? zv7-IC^WZhclPR;yF{y5Gg=6n%pS`1fc6ayK+TLMjZKdro}nW@BYo-V^9rA3xjJs1KXo# zN?~e@I=U+88MC(E3)ZO8GDp*7Gl0?u8FuxVQ=kvo{G<-&V!jln$PMoON8ib6dm${Q zTaYNBNa#e!TcZ`_)P@yfd?n*oRrMGRN21b7S+yK+Ci39k9jr-Aucu5W6M4`maf?PJ zeONn6X0SI%TFts%vAey^>B$LOg8{SYl(t?8;5W6{-(%wZ{G5x+ORg@j7++sY@)0X) z4@fj^OA}SG`(dDS3n zUPFK1ttH(jzm?w`r$DGCv{&w!QNmaeli9vN`a#jkxOgT2lGHoBO#Qn|aG z>Rnq0@VVdl-kZR#eaz1x`{ev}L$n~uV64X#)hIdvc0|ILBrkFeXDnVx875(Dq$r?o zVe*S#@$^rA!1dE7^h#k0@dI2r>XLIMG`hhXY*BFQ&Rs4qu9%Of5E8a<>>eMmdwjso z-X2@KyNq^r*gM>3xU)rXYe;`v?$X=ep})VwV1Jvz?lyy+Ek?WB zV5PdKIDeV0oUbz$pN#lBSxYbm*Q*%q?Xo-C=E)ZiF>RD=`6}I^lDNFz%{eJHbdv!x z&p`#={JUrk!HIg_7y&e^;d(Y1d=lqFAJ=nSa-&LL#d}|)K6Do5d5GRqv;}M1{bnXU zvHNG5r7HRSr(Xo@Q4@~I2iNmYZ%4}70SzJl4?(`p2jE#Zlv^ z@m4k6ZOd>l;&1)#-^K=ySs2P#(W9g?r4&5d&~!=vH?X%`^V!Cq*Q7H0Dj3I@#NR1I zLK{WH-YU=sJ+5K&BH=4l5dtF@*GH7$$@UoCACt!8W-i>w=L8hKWP5v?qoX6{vpFf` zq6t#f=+3Ph462gpWXkoGq=roj_-LMGd7F8T$`?z*8ADUA*x%db){Rq!g8|d=HBDX9 zHjWa&&D=s>~*Wv-rVvtg}ZA?Urgztm~yIL|#aQEntouLALRp2(%FOtPb zrLFwpwY-K&5*uop7T>m1CSgO3OD)UAl=0+><#I-UQ1SYk_ql)XHamOUxL(2G?VH?u z;|=bA@D0BHH-3-5{g3|<_uhMxLsPO+_`&~dw1@0 z@ANizPH!^s1+$9_u3tW9esNB?x@IfEwzX_Ki%0wiT4OQ20exolC(*WscO8_cy-i5&)0Ku+cXp8`x>*MKG(%9`}I7tA+2;^ zucm{Juqo52zgrV0edA{Recd(b@472_9_M=tK@nm@M__~?N$UuaG9IrGMD2_8Ypsp2 zGCk!#D<0}T$u>DDLu(Z5bDxaK-pJsa6&FAL8PC7_L+Yz*in5S=AAX1{M;Ke;tYn77 z8BAgEWy$G{TU?x9GMh|EA(9-pK`Hj;oHo`%(W^+#lAOU+1-Fw=seE$vycW$tKdc^L{6Atg*i$kZZBUx`rnY(Q3e#pz8dM zjU0sQU zKOT1~eP=~-Xkw&Q-omB;vBfS|jDUNG2keXn^b1GTDm}s5U>5V zX{hTJt7awD-KrAn9n0kkUldYaSf!4Buf#jcYBpmzUC=CR`8>YHHZ?vp^bPD+J*pV- zO-o!XFsmgPN5EmL0d};<%T?gde)cmSJ^V~;x4x2!iCP`4EIf5=Fs0+*^cKnW=pUXk z+u7&2FB#VXD6qy!PJJs(U($+AVyhOg&T}~#<@#0PX9JwqPIVc01q7{LBfsmc(aHos zm;$4=IMYe#9oTo8G+j3R z>nz@ZO)V^@oc-{pod4*jm{qM#br$1?*kXvW;>VGaA$bJwtBReSea_D=sFzEsvZB8| zq;-jBmuEbE@q!l@=bT+%^2M{qeE#e)pFerT=T9E-#gj*T^!aCe{KaQ{_~|En^yw#j z`uXR4`0+_nxiB4do7>jzIM;Bo`|n*6~A-=bs(Q5dy~~2ItKs# zKUp7H!WUqF^>f}fb;D}8Al3_Ps;PX!+eleh!2xTzd3uZA`OUx1a$I9pmVq7MqoZd_ zO6$AS*JV`+ea?Ab6bIdgGoDp!7AN)%$vq@uNVFkoM2URQpW6^=+8`NE`*;85cZ5i& z#M2Fme$L;!0Tn4pM^G1j=JZ8^tm~Tbc+6_GB*vhZO~lZ!H5zerbVR*ca&d7+TQ57% zPe~*?XDzGcQsT6ogbbw=uqM$qHOGes+`4&#vha+rF4YlFLT9p<>-BidcrxL7EWlrs z1TL6?nvP5kqMmeQW6%LytrmYFx8~)rz!QVO9;ciIRCQ*7V9mSsE(iD3ifODcew3 zr1YX`_A$jDI>4LSarrSx^|2nw;RBouVwYx3Z$DLjsms- z=(;a!0)#j!b&|S%S0>e21yZw-SZ5R9jRJKBejTEYfq11qnJmb&ug{a~y*j3O#ae*TcF=Pzkzi!K*?20EEH;tOEQl2vFK z?(MLBxW{5PXMBE%X#*ySTAdBw08sj*jBe8DYBHW#2}vZ0LnWoBb`VNObVi&DogsP4 zBDMr?NL4{&p|Od!v^4#Ky6*?Atz{*=STwLkec#)xU9 zscV+YCG~1WY#S^Mm5Y>K3W!;gSS%Mf?|ApE_xa$RZ?K#+*xJ&!eF{_J5#Y8OO=gXw zuG`MB-Kx_eh;v{{8fqAHs}6%nK)gv-}+P$!h85pVApBx!^(0)pNb+_`<57-}vrUeY$J&N0sdCK{r8 zV;eP6=$xhSmbR@q+~4Q)_?W_4rjrRVw32r{G%B(irqdbY$&~ByHP=^HltrN-f&%!f zx*>>MB0dJOrD$qKF>&wki2dym{nAksPEwX`NchgkBrvE}B1S^AG||yUFJ_F`$~FW{ z2-uMD5sDb;k*HFniVa0Gi-2`eRcPR1kg9aKFoux=7{*FnF(K(5 zkcpsEUM5XYJN>d2uwP}sZ!v8EwU--2I%u1kh=f==4No#o7KBBBBtd6CGbu`$+R$Lz z8rL-Vy1_OrCMHtQ$bgijuDEeh(|c!^iF17Z#TWeKM}JCTJ>FNuBr3{YS;>Mf9Mx#Z zVDE^*{wbrIcR4G1JZdAYDX>W*GNK7Y1$=`p>~5~E0h|t)*55NR5lLnZLPi0p1HW!P z=rxr%bhmN(S%05_TJEF3sLr36K@bqnkpdf90juM?Daq$+g1UIzOP^mTs*`z-a#!$`{QEa7KWgC*;z)=W=f5>?D&&`f5muBR|xQ3WVgK~nXuBE_P` z%^Rv!q*%82S&f}7vGWyv*tEkrXMOz*B#wOCRWaXi^HDd4hklo`0hWon= z_IK#-?ojQFD0hZb+avsFK-%sTM-{Ph_+Ag&E1_4ADo-j4V(AElrS+E9NjmS=Lh|D9 zn5>a%s+!}#BzgZiH-yB(D~?BDTk;wZ64BXyUwOXul3as!Zo=bq11xhD)qra3y|o(4 zZe{Rdh_r1hzG5rM+A3cAk-{{Twxuk<5U@@Xxb=D!Uw`kL+`sh(tLp|+TPoATBFqurby1L@}daTJZL^T3Q zLhn?E1R*a)#CtFe_$J}o2G=&ic?T(S zt!bWB&735SB$DsBQ>8kY=*}376A9j!NTG4EhA2$XM)^x&rn22Wd*Mr1n@nT@d+L^U zz921Eq*aTl1F3F79e$jXoCOl!>!|CRrfD(OQuTToM&{NF$l5M5mS|TZDbx^ZOjto^ zAV>k8)<`w#q#BPP;sw?h`0YKKqU7n*=Y02%{sdvsZZR`^QCiij5Y-FNlt-Qkw_Ewn#`&AIuBvirO3z_ zE zYXHVDnM}C6yks$-5tb{=swK>qEUzXkuExwRu9&>MV0v-Iay(^vdCm0lnr5-YCP_z~ zLX-#~BlBFQxC~ALB0>Wt=Ru~k8{;j|BU@uSz+TT=N3@pY9lJ*dlv@K{K7YY-I+GZB zrAgrxr#-n|zEMIY{ER0m2IssAwS&+vDEGFw``|ury!9rhH*a!u>eGke{#(3$syav;^(k+v@cGK2YU<;_ZS}RGCbI&x3?qv z_IDWU?J(HerW_4uEz~B_ddX!VK&$3C<$$7^Ev&T|P4JdK8-32rZAY(UFhzJs!Z-+x zP$5?7Q_@H^r^RW|QtEXrMc|sIAq4S=m$jMjrlzzFmDe?94Xf3P(P+ePee-uX+&ZD2 z1Z?A|sIb9yfZsNewhlBZ-M6hKZ_>nIZ5t$Jh`PRMBo)0B`q2!4 z`aErjl5+xZTd)7!@8oJgy?$TqHF=QMgfbIP8KgB6pcGCfrOCr?gh#h><2>Q4akNd# zjT<)@4SO{8ob#8@@mB5lQBtj1V+bm-8*3zeEQzLG0Fm3bZgT79P1>gB>hdD9Y|06V zmSVnKG9FL3yt-mCo^&ex4ESx(ggYro{^QtU7Yp`$!Gq&tb=oss79*d%^i}<7G!%ju zHHi%rjiG43g@6kI8#F(35Y2@N20|n>jd;X|h8P>-D>q8z1cPx*Nx8txN5`9`!^W^4cF{|*yivWk=&&_D%~r(b_|04CWCrL-)>(H*VzF3 z%mf&vXF|9Y#7!=UlYg@Y>a3-**}+PO!EFF}cc1)w6uk4bx}nQ}t$pqKxA}eDCpoqT ze9=H8oYkiB`eM$LHCLs`wlO^Vv!C(s`#)sy=n?(0$1+50F~F81j2n>f5*lnRwGFsI z$?@?qi}9R#vDEOlKx-3s-nh@3@4d}vYebBRo$W1d9vySEy~kdE$W~FYRrVRWf_gG% zdU3`4YD_&_FuNMFn$0mGQ7An~LDEv^d5hJOvq=jA0SV1JqM%|Bhh=93u!OdDGgrUs zJayusk9X`IA5shj@KfE0=1jBf`9iV?qSw#Y$sh7Qk?!d-O*-#My@H8pdHw6}^WOXK zbK~@sqN*6~ZmaX+j)3|89;3Zo4sV>Yd-H_-8z&s!xy8|~Qx0#Ra(L?|hqrHXbVu6p z-P@epyT$SSJDl9R&B?tx9NoUj$-Ubg-@V1*ty6BlcAwT6W^K(PiQtyn0F6Wr*)Bt3 zP?fukOE;Dq&$qeNMFdD_E}LVTHK8d9z3A4UtkoDJZQZb1tyryULMsxv(Q~aa7$SwK zDP2wJ^Sp=EYQ_Hk9)I(%{vK5t(o7SswG`2l8lj|DIls@=U6RgLMYTTI;EDn zUQiZ}`*-hh^TsLj*@UahOAO*5VK6jp3m6v5C0AEhTwGi-o6o2!NwaIMgi^Fo{PR;v zBH_mtJD+pZ>v8|+h@C;7o-xnyb+fpcpST_yJreXW^1Y;y=N#@~F)Qo*i3r&k@8(dpsf~fIr zOj7nYBHq-h(l?0RKVnG35pghJGGFqq|MefUT*>5YV*qO?`#qW%aibl!PHwSv_W`2^ zuk#`qE}F!`dW_ph%bP_QQ08Z2N@i7a)>H{~T?4%y%My3q=DFV`tI_BbVFuLHvC-r@ zYjBt2x_&Z1=WXtTS%WtjMD@Ga^EM>>SAc&F(w)Sv@w%Pu-iVYf+YJf7bKYBneFkNx z*Ou#VNcZ`E9RncO76PcpHkl0FC%~SsBfb^ZfG6p(h$G>7q#WIHB4`rh|= z_@_UndHIrF)o0m8d^Nu2FS!~TH%om~c1#d0o5aAJtU^m{MrUN7OD##y3for|pN$YT<9vmyow zTP_MOppmj!MZ!j{(KW9V)fkoU^#zE7oWm9+zE`n*xDTc0>EkE(kVs8Ss2hk8=llk+ zWlAiUHu=2?VG$tp+47%=J&)TR@y);fJH)!-2Y>V@eE+-O<-?CY;^#mA1;70BU-IW4 z{)&%&^&y}9>O(&M@I!w2%RlE=zxowle)c(Ee*76Lly^>RgtWaJZ27mZJr z`q6#e(B&nsf0+i#Rs>pMgk)}sRKK=$u*QK0|F^4i_X-0`;M=WK4 zWW+aG-lyD`^Vyp@=iV*|ZRGH9o1?>R7PATS$+cv8ik8@_!<&gXC)WsCn4noL+1=gZ z?w#B0Y;SRSaY0kBI=c%f7#RV43Cp`=wOUbDCEk0C%^3kj3M5IDKH3_$T5)r0i@OI0 zZ1pR8-cnWm6~GsjzBs_4p0T2$Pm(l9(rb`ROC%78gcJ!Fk%mdCcGu94s9vNA0qib} zMViSK#Sl;CkYi-6*uM-?s6#?LgzyRjhiC-qntD28b$yLlt?+e=Ya+Id;-nWMDH#oy z3(zz$pA(ywRnxGnSJWY}e|SKv_AgXAvmsJ6k)jC{b-*_*Hi&bcQGO>zD=Pe4H4#w(JBcQ7DY}0>L!dHM+E%e$1kO5nUE+2pO zm|Q0VSl*YJirn&jt;yP*%%F%=?@gp6s-!RHc>{$p3}a-ttog;i`6C|x;^(Bvn4;{l zY7?#+VTvKq^oT}0!=o{@MWWp9bGU!N^!%D;wvr+=*5Ipx!OoDXS3!u>ixso^jM-|z z<#fW!vooGPf5x-t&v^FY1=rIt$;f=n@!~nV-lA=&Q=leNr$B2Zqu#P!3WK4(F`#+t z^Se;KRK`*#tl-frU@vpYVVuL3C4=p4hPyi~V#|{+zwAogX6>Uux0n<%RbDR+0YQs0 zo*Gdi>6JaTH}sD8x&8WmrY|pe@~cmX%bM7<6vh(Umic7H{PLPOUC>Sz)RQUo)s*J! zig-3Ayttx%e#z?DIrFDyOdr2s{OB21Uq0pX%cq<_e8TgGkGXz%#^cW)^7PSTQc7%X zZ?jk~ag{JN7cXB@L?{%jb3&O6*2bz(qmQPmy?bEUbcyJ37wpQyr)Xw`j06h1qUURz17ob(_u=-P+x(5+`dubxOTx@xYG9RUYr)sh zMq(qfVT_{vi5scpQKw;qLa2W=nJ63d_L#={DRA?D?$kB2`bN! zqNqy1Xi3HvLPOcq+}qpd*6uD_y|PQZ;|g(7D~yB@$@EZ2=|Ee+9watC5{Tr~y^@Ps zf^2kgN0E3tk6c~s=mby6NQq*ks+`pjmexUV;&c;@q#?CQQj&@WMfxTLIuVyOtMQc8 z)ip)aVpk1l{C#XyMHI4~XhmEuX%{P+<%&hUq6q<0II687$$PD6C*x2w5#K~y6LEDA zkNhAhaM9An;wPbjR(YlAJc-tlMq8NC7K=9VKmN-<;OuHlvJqbiks}%Qk5AaU_ZoW- z-eUCNO`cDlBd1eT-PZ_wnl5^ z{PYk0HP1f&7}G3qzMzQ?uYezHMMUOIG?03ZYH!HSXq)rL&!G+?#U?4gd*jYccK3Jb z`HFr~v442T!RayEhkNYo?XtVK$Nu2~`-cY{ot$uVa?EIZ8{-@|?%d||_Dv2>j@dgp zWdHP-qnoGfpB}S+dc#TZ8Q{)rEU}(r!2ts3xv&5=k|G_Qx zZ=NuJal!S&rxaRT%VQY!2kdTbv(p=}?R$(|!N8UDBG}22aY6lU98JO zXAZl|i{5lgZ2gyg7Zj)Ru}z%nq~NBJh_9fatH0}{dDL8^!lf|=L!fdsJy%OsQ{z~y zYRaQlMgAlb&McJt}H=0h&?(^n%)d*NGS+7zuVhXU1 zgr#YtB*d9cxN-9a`v?2@LTs?!6&t}76DPl5ZP}|*QbOhM4>>y~L&VDSY6c0( z2c4OMAk0PEVA>kn23#9)ZNh39=NKbRY^A71NDvJviWj~lrZ5C;;%Tb{-sC8JEu5oH zP$mUv8^Ur$s$1G+&1$}2Ih(Vb%NS0lQz*m+xJwA6I1y2YO>y^(zQ>$dhCC=3)xR-;ddAT+o>AFjZ@9(5)((f;I~?uoaj?D1&Tz!`V93qm6Yk!+!|V4S@aF5U z^TvY*y!rYYy!pl(yz$!W+`D^^(_1$=x^;v5@4m@{ci-ah_9>=UNXlAGMZ1|^SCxDn zVyQSGFHixyZd=uQAqlcdF=a(1+GZoUlrWNOZEW`^L{R8a6DTzo0_qI6yT4D90`t{U zQjdE_YZJxxh@%I0c<`OqWwq zlWAJ#aOoaX{hI`u^`BQSE*u-jGyt(+*QZM86$n$mOOxTq3*x7Cb!o1Zhtx1pucYKv0h z9mNe{3POyyt=Ipa7N*eBs3=YBY0{TxBhpCz({; zc&HY@BIJXyBh|N}0aG}rJbpN!+8SYtLc$p> zv;=~YkUoOcv93*|v7*h0MxNZ^#9zP&BZARXsznJ~+nB9gmcj5Z{>R_vVlpGTL~Db1 zx|V&u@r~bP|DE@k@9y(>*)p*O3s=z=j@FAB)5L(!2xsgo32}1EbGnnJjRN=Pc^i`U zdY^)-Q#-!Z#3Qe)i+p`m?d$K!*Roda`ttkifxcd2>ppg1t|0DnIOGPHcR;_v@V)Zc z${Z9XaIL0yR_5R<4tlz8^B(J#wE}uwj1;-aQaWNjkomrGUha#{zd^E88X=Z)Un%e4 z9rR41XA<5Sj6)pul0?>T1-SnBbAI{g9^iw8AuNft%TMM!i}|t82AS&*=@S4zw1lCD)U&RJSx)M9}$>5!ncV z?m*tEMo^Q}1mNh#DW-H>&8Mv9a|$d)f?iotx`Ghe&a`CpKHbIF{DgS)uT~7JK4n!B zfx0l<|K@wt-f;HiW5!R<@KwQ*$bvUTf(YIlq6;{*0?9CLF24#oD6hhKg{ zywcTZHwD}^M50`^p#L4y61a#&Df19 zUmao9>GPL-j>+JQl4zi5r3|DmDzH%3Gh%8uK0M&Hd-qu`mYhAm;QHbU?-IS9r{DK9 zP0i)yIrG_=zx8{6oxAsLF}}X!>66DmqG=>=Iv7njlUOd7jK|lUU!5^uOeiWZYE=bZ zm#m~4Oycn_@#8H!*7DZz2?te0zjRbyYY~@X!}r!v0W+Qu{7gOs$j#zNh&nk`sNW|)wu z7b}*_nx+l3>K`H53Du?_BdfY5ISaj#;4SmivUPMoe|H<>tvb{}G%~S>5fhV`F|s-l zBTPZ{A@(*x@3; zvM6avvE3)s7Mi5El29{=?2zHlfGcB-k-3}=(nco5tH<&S%7CmPbRxAYGm($${W_3# z7VFo37_w1N?|^Q7oea1#Hfv^ky)T!em1QMFT)}cfdN)S2J8SiPCbH}1vn?Hz`BFxp zbDWdUxphoJ_nS>Sy!0hA1v-4M^eOL`YpX+^<^k|pcGp?~`O-jX#9_~X6wlFo^20WA z@vD#cvw!n%8DE}Jl$Ivs40|Jt>wzgnP3uJZ@9hlf?{7nsn7+IuE*sh?+Cb+eS<9W< zw|MW}_jqvs0ad@p>uT<;j zZrB}e@!Eq2oL!uAad|Mg44H5>Kgw|QN*2X4Xi%M4YKcxW}3Rggawr!~Enp!>Y zQD#+`bnzh*ZTDK5m$k29mmsQl6EUfw=Nl^95JSKh6|?Dr)6*Ng`|f+(+`r4^;~8o0 zFipZX2@|1d0x5vej9oFb3f7{&mn1uqF1OpKQhLmqW@Txz)>^a}^2i}3bvUe9)>>l* za9eNw{qKm*QE}R?Cz%jCNv$X=QK~*=)tP{tIx210_=UiU_jEE+87*0>Wfha8*>n(7 zU_PC5a(v3pXos!Q2yfx~>Wu01lFQ2%%%)fDY!CP=zx7SN{p}B!j4yfe>@nlAdE8Hsg9aW42h3VxsV#qR?>2lrU96 zDhuW&P#2c%8^;{pK84arJh4@qM$(j?DPoWXVoA7^aM5Cu69Q(nbg8PgleJKkq^c)? zKN_*b@Gt(CKVZ73Ax7e|rdigMy@KuI19tDfP5Q`F&e>uf|1ei zMR^x8=Qihfw!P;*t=~yTtIQa5Xe#r^=)2AuFl7q5_igC3Jo#A144Ad5wX+N6%WEGp z(Ggz(*`HPJo%emm1c*vL1H88)d1sYt_mWh~;P6tL-GKF$e%tWT zcfZT0Kl&l_*%&|WV z_V;L-hUI)AOs8fK^cYF7(n4hmDm?9?#wAPX3QYj!03$ihtyfK$fW9+^&<0@&ih`Di ztqKlr91+@<>x&E8*m8RR4sZU(2OK=OO>wlt@L-oOA3vt4Yr#5I=eAL*coxaxH5Z5! z$+3jO5lV~M8t~3Z0Ba2Oe953F39}`i ze)tj27rg(iZ}R%r-{<752i$z?b#A`#8mF(_kf-$tilHuJ`9=!HC zU;N@D7SAq;>R&XTPPp^->(rHHKA*D~PsML28E9GpNu8E;$;EX}eoXd9(S@$KR4-RF zt6E~&8}Wwkz}^Uwivlt;4Vj@=HT#ALY)r(Oh%+sfZ78jl6~{51&UpRxH~Gc~-=dec zn7(MRivr(*4`8GoG9=A4pc1)E%&b+=C@3NC*`mA#_*~vSicu)BR`2KX^hvKR4t=6M za9eNvgYU?o$jBL$Dny#s5Imtg0y;vSl$(+PHEJ)V1AD7wDxG*@E8yb{$t9AObBz(| zWliNPcD8mo*xTV?Z^Xg=7CYO0cDDN5zjupoe&apffB$V(^^AvKe$M&%OPbK&tfy^~ zxXj{6(Xd)AxxT*O;_^AO1iS?T%z?*E|=^^c;oPp`}=#0Orj{D zC`BT5g~M7Ud|haUOp;Couai%RUIqvqA7u`*CI$7dk51B2MrTP*J#n4G*#hI7Ncx5A zfLwqj&p8co(~MIoC-_kH4$0tzgo;yJvdrd<_!wA8YiV+AX6NuustG3VSeiuJD=?!z zgQGnTZk;mN-6Cj)zs?}9mK3oPNoix35=9h8LYpKJP*SGIsMMOQBl?22C}3*~wnvOt zE&s#+^sg9CmzXwD1OYfx8T|H;y*qERed9G|7-lxHauFXbWfUnnIZM#BZ51$62lSZ> zScAQQIbaONs^@$Lb=?YskT1x3{PlVXy+?lWIwyqEZZLQm=rcGfSex7*U3c9!M;I!Y zXP}ke={`f3H7~2tGq`6dKdaEQWWNUcB({5%`a959z%LZ+ZI;e8X-+mn2!EsR(`P8GE^xFpU;NksK~s8C#bqmkWORhyR90Kl>TW#T@4x zZ7eZ<7gz3x(J0a7*oX#(hkN+#Ev_%FXl6@nkhPLYoz=9>fkd5J+9U}~maCfCe9mMx z<#K$@#pIgn#fq|;kNn=MkCs~VLq8sB}bYq`SjCIiG^eP#xZtx#HwG=Rvt6zQ|@fz z`+b&e&C8ePq#%mxxI1ES{{}aYPI>s_KZlE%j8jOA>m_lw&+h%3cr4TNE8?QYw-M7u z`Mp!YCJ8tvqrw*m!x#k^+ic@rwWL-Y@=)*;u-7#$Xe#Tl6Wnxn27BEn(tV3JEu{^V zHpqL8iF(!W_M7kV-a8+_qF{L*vC9${p^OrGPV|`MNJL2%mePjffl*mXC3tn{6Cbs; zznZix*>BkQgPN^btNFz&k#NJe|KWEq3gphJ`q*Q<@3O0*V3e{XNHV z<1EHYd~cQ>3-5(j0SfQrgBWlyM#3(Psv4yQot}|oG((j`z&u1sUr?5wqAc)Lf$tTV zsvuScvGlZ+r}h>*8nAVA!0yR0!`&Tu|62Ca=yttmWP!-5&MHI;tP5nw^CgT;Brg#L z(RtkN0gU!|aXIII{Ga|UlUYlu`oyhmOuvsa4sT1`!42%u4Vvu{mo_mk9Km^l_k^w> zM`pD2eulL~ty1qRDs#0%3vgvARe||0v1iMBmgf~dAUjB|0okBokr~W$2}}#du8&zG z1);iQ9f-?PR35qWeXvqeXhR*Zs`xCqv$56u4TXZbINBNcuKUFc-cTBGsFLHV#WI@z zAv@?9an|#jJ^;dIt2ROUCRyLsOhnQB4sAxH`&Tpq5l6(QgpUTF96p)#GmmHd+5i0e zy!`MJ+PbE2o)8O)-Y&)u$#S0YUU+|R86NE62NhQ@&R|jFLbfdnbKInW?^P7TKE-8thXaaUh3{4PVV_V~ z%&-w)pbuiw2-S~U#&eX7xbYBZqS8DU2~Chd}C(}<(RC`;JF4u|ns-7>IPo~%itHqqpAALzN=o7tV zQLmWJ=S;>EX44s~#gh4S%J|}n*?5d;#P6rKzs>%wQ+E3!KK=PGsTa#G_3k{ioX@Vf zarZU{!!6>n=IZQBl9{E{g*#{ZW68Nm*5S@6h@HM}H4Cds^pF`;+3KDS)&=A<+HW40 znT9dqLY-O(Cv^h&2DW4w24ZH-vY=RExEGd}tFA?If^tm)%Z zL8`@mkCwBv22$HFo6dOh_!+b5ikJ#~F{0;(l&Qc5Lz4n4+hBa8bO~QC*-eSNTRXgU zddeUr%7m!#3y&!ZC<+07t&o-_8)0UYh%3Q&sv+rsKc`ULPy=`1uJN_vi7HVIn+ZL< zvlPC-ihf5z8#~ESCabej6e2|N@-$X*xhE65JOIfhyz^8=N#VS_7blCnHyTik`j~!6 zTRNJ;Qtj<9*xzHgzelyTCGR^Kv8!TLQc*BdpqB+C<05|+j4+8w3u}mKJ*c+Gg0H9! zZxDz3eD>uT|LR};JK9*%J2}Olo?v__(nyn-6a$vqTlkYBuAE_36tvFK6pr9Ui+~YP zHn|MG8i$@e-8YivY-0oa(Y0=|O2g7_Nn z*T9}ZKl6dY1IoO1HcQP}+E%G}Q(bPXg1DA&-c;SQ_KYtT$V&vsOJgXFqcm22o0$bQ zUkO;}925%X>I~>o>VV#9@s@n7P%}d3!EZ9)gEx{sIx|q#DAnOul>q0ZQu$lob7alIscMX+&KR47jpj>tGL4dd{9c!__T5LYo3j3g9fuwq~@u z!*Fkx-qw(6YsAgh?$h7fVQX)fy~6_zj*qx~=MG25$DEv;aP!7ZZr-@T@zF5{2L}uX z1In^wI2v*9!2@pGzQz8@5!?HcMz-ADVtBky>J`v0*t>N~|8R$Lf17e|3%@g>*cxJc zQmVJ;l{oL1t>$7{^Oj%|ZHiENwvP94{fg=JnA!D&qF-@x>n6kPErz2ZMX#b=u6X|R znK+_(ha2|j?Qb(U+T-Q)n%QD50AYn;_fE{UWxvPKjT7#@_JEIm^&uBepA+kbP*`rg z^9G?;P{%;BhSGT^SJ#BP#iYb!GU3^?XYAj)K{*~e7H27{`{qt8AU5BSPM>4}Bqaz4hDp4%s<9PID&?8`?|=`$wkwxMlXWj2N8 zh|*fZ9ccr!fhGvU7DC8YJ=L@caCaEneacLL9!q2jr+_aDTEeg!3LB{u@BtRfC4>Hu z55D#d9^8A4tLIbF)Zv-}pJaWS9MKh12l&|zo5+AK-?C($HloTfD#5=Z^^57Illqfr zHS+H}bMWAufAk%r#8SXVBztj)5_K`wVV%c1J%%i>&I>==Ky;g>Tjy*yuvQ03ekV3+ z;|i=7ZNlaCm^MbXc6T{EI^_KPj4!|Vg0q)r)OC$B1*6_Jv|`&b&QtaK0{BEiQ!|}h z^Wxsdcs5esv_$)yh_2w3^-!zdZbysOVhn>74-D{#E>xJpSiVDmau~R!Q=`%yl zo4sN0$&#pWc&&PU%9M5bUTk6TmB;r>TqW^Osq~m$AvL~tw(0F`Q4agqvcP#y)hi|a zW)j&cUZ%F9bE}x}&BcW|wQ^~$G5+%|}_}#I54Y^LCVR&NW*M2Cgp8Yi}8b7bw z+%^H$Nn-b-q$7pYdWDRGJpLUfdlQTqbXo-}gA=7%vi_3E!J$uTRk00~V=b!WG=b!WN z^M^eA{0p9Z`H1o56;B^N;_>HS@a&5(xqSALv&T=FU0$;sPpD^eQr$8vE4;B(zF^R+ z==FN^dKEj{+w{wdozWH#?%(ImojcrraGwXSy~b;AzRnwOyutC&AxDQtoE{x9sCryo zUapO{R?^;@(y@DbL`!0#X?|0POvYnQj*i*e*=2lr$@l;5zvIy-pYh_!GoC$v&iVBv zfyD968=PO9Q_tpj@je6$z9^_&!i{>|ymyzq!+n1B%RguG@|+@p?Umep=M6&7Qw|4I z!vXW6NN>dA~3Uq0g2?K}MTw||STz4Z=n-F?6ZZ@m#*S=7%U;FE%{f5->#e}kJh?r`z=8nY@o!1rPcCq&W8N{qJxe9E*_gp2h*?aWtt zlY=@1;I*cS0zRF@|LXPK=)HgZ9jr*3R#o>#!9L_U=R8iENa2}SD)H>>lPU#kr6cQ% z2ztgKuSUQg>!rB@oJi58ELgS;v*m*RpwI0)x7pp@WjGwt@AVl~1GcL^qp}c*bkI|q ztzl60h_T_~>WnX+e#tU5P)LsW(l`h~D(a<3u#w~w1Cwx*F-Okv#^DhU4h|Vw%fNdo z?)w+#G+Fac6O8VyF4ezcmv z#}ow#Q3+Y=B?vG|sEvt|F)uZt3;%QI1k&sI%2D(Sik`<5LY-~TQw@9cw?-7h9=>1V zs}ffgxXKevq;8kAu_2j=QO&}7RjA9N5!IS#e?-mR=sx2j&PxS8jK`D%(!njx?U3(% z{)i9f3l6^hEruVwPkZk+<#5FO;+n9mIeq(0-u&j*Bn@wJ)V}JpB?XoWM=wbfg#e*| zcYZe+ywPpStKHHa$EZ0VGxXU!U_^`KH^MZ1QAnz0)%dJ`qfDQ^*H?jG`=B82HGz>+ zhDE~NHk|0xXQbGWxW(4K`F#!e8MwWI_g@6|o+KXen$#vIw<(f>em<{@zt_GXkq{Q~ z9kIE+;@l_adSfV^O89C9@J3blM#~l_BX&~VR~RWDUE(l7GzNu(cD3N;$Di`ufByf) zP8X8A3rCYmTyK}wNa7`Nc(pVsGT0h2+#b<}mdoeQ#cmoSjY$mlwt4p(AMoba-s9lL z3H|MD4o^?`;G5s%=*W8`%+TR zo%;`tTDL|CuT2)bS|IR&LK6y%geoe6wUjt(;rYcx?uzMr!z4;o>IX?aHBbJxf z^l=pZ9e(4Z0~cRD<=L-3<>`l?^7z9~c=G8N zTs(Qki_ahN_|wn1eDWNpwLB;sPMPLppcwYV#4_s99}YO!-)Cz$#CeacJo~$QeDU!o zEGIK!XdxtGD_Vw>lg`8lAz_0gH52D@#j9+e*X1f8m;p5};e7C`P%nQO@U00r8}K$z z=+*#}>4e+2@9^HcAF#iB#Kp5QuC8!RAzCoSRB@zBoj^usA(fsbM60`o{Iv&u2J$u7 zXQw;?epJ~n>nnqOw&B0`AAd){Dod7j>5oogv1Rhm4nFQVFJV^jtw1EwK@>$3e7#U|M=@%}(3$*4`ekADwVA z98v<<_xPwjg$XT7MT`*?bI zN>x8Qr+xS9P&t|78I0EeoWF}^=GFaHC35Es&RbFAJ2lN@Ng$I93&x6HMgHyjUOG37 zNdH+vmpLUG39l)OH^E*2)CpstjDXn3H?Dz5^TO;1XlJm`;9ppk>NSx~p8*k-$KKltIk>EwDm%R6)bx`SE&+k?O`yj z+W#%Arc=K7>CgDd@BblX-C|uq!Vye`t+oa5tvJ0VDckQXFaBgg!zhQGQ%tz$|lllp{yfr(NHyDXEkowP}Bjp zYGJV=%oe0&OWj-9PwwuI?|Mge_xb;bDnlIx30rkB@DE-sm0Pgq<}Sd1q$ zbE(2-6F6(}&ST4hquV!_E#@@i8Fta&+k^{|I9pMVr?k@rzLxBlr4iM!bDo{8ZSLH< z#j`ITQ(ug!8UeQGEvZ+qETKHw;f;6RW<46$5VPq7=n`rcS(biRC+>bv6}E_ z)E~h0g4N@f#PNcvO|%yin)5N?V#4xb%=qOw*DubvesRY1;tH0HFko$D+15;^6V5Ns zd2;@oN9QkidiI=WXU}>0@f&$)bY#*52yX0c{(cb6|e`IN==m{8Z4HmaAh#-=L> z+L*+bgbmMq6-h*^r0X{2|1w+kD%k%;klz750dFJTisPO)!UjzyQ{I029o~B5J^Ix) z;}>)Ms>C%8t28<#O_8g)SM!wxp7s74pq{}xGXkBhenYx{<(&Ks`7!m}loD?1{eSWu zQA2Ca`%XnE%{eEqyRZ&Ro$Xf`#M_ zz7S4tGMzAXV(JKd3<$$v2;ao*o_OZ5*lC#E1VxbT_HEfEJ z(6rq$k(nxsB^oW;tE#IUr2$f;s31z_-BjRqj#wSv<8iga&!#hGhlkAfcA5E#mF=xWuuj`j|rExxAP8>%7Aj7AqpMYDXlj)Ot13I8~{8i}m`s zP-)y5jF+u-Mvu#R!Z74_soD#*qb0||fZfT~n2K%Lf-x`MoS1dt_KXj5eGaG%0^W|Ikv@t8`hKgPo0)nDa$wcv6-Wu*m1R&~w1 zshO^p%$5sgt0jwir5Z|M+>=%y^M#`cLIZu_^&Cl6>kFZiAp~5e2QvM;80rusbt|#p zZCw+Zny{*A<_p4dg;QqP2zMxRuwQa?`zB}Cmn^O)(6o>`y{QoRm@pv{n--%n@2*#| ze|W&&!9I_lJYg}O;xsnVSc@wPLgg5p?DNhWZ*l(kDK8&BCd?KT66`}!me`nZiv~BX zDP}cQ9jWTX>iGrZXJ^E^1!D!URE!P=mQBrUF=w@^rHD{Wk}fwULQ}JvOc|eFaQXZN zm(N~u{qzOnr!TmE`jYb}&$xK;lJm(mvGUwHKH8GEJH(^0wFe(p<&M%ZjZM4`rQXSI6Prg_9U;pQ2@|zxon%y#7&5y!RD|unI zSBX#;cwVF(cxToAD=Pi9v@d1@ab(NP0ahq!hyjw(>SCVDi)%jo)h9fA@`BlT!F;ly zT?JP2hIY{s>Og8CHi^^-6JVkxCPN*fWaqO5g)PMU-FU3=3h)KScmZTB%n;f@vubEo zD=sfCIeYPv`E zS;OUEK;!!aQ&H3{TfoJWN4V5*b9alqTeo?c9P^$4zA0HdQ+h9!qHOS1QB{CkK-}o( zHRx{wyngp8-Fry@V|2(k>(&yw1dNh;p?yIJS4U(E(;RH&pWlsZ!Xw#&lZjKDy6a-}x4utqrn%mv*Pi zpg&}|waLQOlz1xdDQ(57DrvP_l7=A~w9&h&>uMd%aS?Eug;iSMdW?<$;^aN5nGag8 zmtwppQAz;S2T9E&iL9tWC|wQ@(Zhd!{F3E(N^TPJB*m2#!CLU5ci%*byqDuhS~*+0 zyChl0>FF8OY$*)(Ao?3RG5A(We}9|T9>2oT7hiF6bc$Q8FfQO~%hkmt=P!>KKRage z{FM3e1!iTLoL+MC@|4B(IP!_4agoe@kq&k$rVbEC0p|&IjrN{QDcU6DL7}ZDL(%ez z!YOjE1kimDgJgf3*I#*sPk-`r78loqRfVn{!CE5$u~i*INt%XjNlWO==v8a_At+d8@MIZ~f+PbASIa^(wHssnKPEDitc~ zAB2FkOe`G8)5rFkEgXzBidmr2lH|sRP zq={%3C&~ITO2wjn3(>MoqP{UvwlG8sOHf}F<3w;LlD8UwH;NEFE}hCIHG|Rs#iX)o zhg8b0rnTky_ctu{$sph7~ba(wBjDrpL%f+y2~ zLc><4&8vrpeCLg~xWBnW+vImV4kc}LQ(>}$Cr!*Z@{}fqWF<^5$Kj1ko#$@O%}<;|S4 z>nZ0qQ%){!I66J&*^48-`s!;w{^%3_yMOiH@dy9<-}3zFa}M_R=?(e<`owV?J^Y}; zdO|g~uC^q>lPPd2BNRQ<#y&^gO@6#|{OII_S-VZ$>WFHZ&*&@7&?wHHJ|V~QaA!p4 z@E%7PrmdF5s*Qxv8>30bp6WrzR7hi-t=aRkX?5q)tWSMow6O*vxik^L%s0VbSpQ8m zg(gi5X`7_p%g^~`z#Xr5&}u^BEAzt_sxAdp5|EO`x{c{yh%w-DCgofL5m^lGL&1g$+)CQw1T7X~^bOA8NP}`_;9z(7gsXNEI z*qlpCJJujkBb_B=t%AJQVYs!y#l;1owxnp5^Ep|XN(w2;#n!b&Yc0YoM$sA#*uQ^| zMO|`yeonbsiSZc;!@+25JEgt9&BOcmdH(4aOi$18Wle%;dRXW1wIwVn{Cve~I_Ko% zl=00CtHn})D@n+EUC2|cQIyJ48}NyyRzffH5l)LD$JRB}4&ywbw)mjG=Z9e+Tzah+)80$!Ck;84UrvYmnbLA?^dwYrFM^;huCqUU4BkR9- z-tU6_oflyZ_!dJ=YCMVd=pYSi%ChEne*5pRw{?%@)KX6!YNgPXq+W?F(mlQjib7=A z$Gg!6kjE-U0KZX5bVoNuHM##d#+s76;3K6kM6izsVtU{ECm%H4wvQfp&|=1m&<~|Fa?zTQbo7F~5-YTkRTU3ja??JR^fiw|s!?eSou(2tH3pJIkt7-u2cp-Ckf!)N z$L9qu&+tWo?(``7L)x2L9yO^ z#ppZVLpgY$^Th^%Ch5E7#oDz>o&@laIb&NM`=h$?qO z{LSMv>csttL=zW0I!R(FWJ1s>PhTGM$roQ?iVph^U!k|XLowQr&=9b7PolmQ zXHU4fykUE|#jpSRZ_w>`!AKZZdIiKZ&Nn8C!YG6Co-_zKtWp`Pw2Rt*$d^TrAFXPh zE=xkYgH8)_3JMCk-qZ6n=TE;N3l;aahhzu)9Hl8Yt%6_z7{87r1+8K|x5!?KD2{}~ zq<%iu%PZt@3{|U09Ft*xo3d%V*rqH`?6g>xXEdqNLQYE>f|>wh8pGsi^r%zByB09@ zq(Oe8!3#rO1rjY_Dxvs5szM~pL881oj$3l)R=!V>DNmt1MFjF3BESa8`7X~1vFXX-8bQTVl*J!DcOskad#6IeiH$R*TzSgXf$|< zW~j2{<&)3&(|_{^tggr8I>91v~fX;Xj!Z)H+jP5&NlUO#rXUZTD#pU%CCugFke|CDp_2m`w`HaP4E&@BVDbvM_MY&>8uDF`q zFt1iZV2k`3r-WQrhX9G8ayH6j%UVGb>emt}QZ(EM@&1gD#$IDY$EbzQQ-+%((llip zjTjxG*BbRstg|>LrMohC4K`7vy*4`!4sk|tH5-c&l4z>nAvL%};RXerdpjKL?(x}A ze?fUI6#yy-r3@1_Re~scI;Er(HZu&iHn{irArIboo%?UU&i?DK(B0d_jJkC9w|M8* zzQ?1t-{9ckeLBMdrK?!kN>Zi-DgCpxj4cm|7vUo91F11M?D;I1r1(D3cfq^Ty$j5G*|WoaY{WGOz&aCw0%T7-5BI$cz^ zN7@^Z3*bF^$tx>^wyb9@N&wl;bDt#|3< z9SMK?I8wYUV3 z)d^+ddarOngUMJ~`0JnjlF727ySYPqV~gI-E`$9;`iF<~4i0GV?a|q9wq1(dU3!~) zj5ZD!4iD%IcW94xXm9M&+T5ks*dZTnQ*7+e+1jPIwMWt4pwr(V&DvaDjrp^G|L2S^ zZs@gpy!Yn2{N``{EmR_U`VGNIW=Laci#;t~o_H}?5EZr3w5WO;*u8svWODwhthrPg zleNiAK^ihLpEA&jman*c_9YoL2b+DedxxCl88_`Bp86mpNn^k$0Yw5@ME)RBBuwL_ zE9ti`04|_oVrV*v+6ReggkqZKnzAza8hKrwll*nuVic$W=3iyQXUK2M8VTFxJ2WvY z-h562{9Ziw_?ek*3<=q?W;&_Ze8ziPAw;hpiU#bJ+275as zofaFrJ9P6FsWNohZHA*Eolcuxr$fKrXE+>E6oq*2vEj8!4Ni;aU35FN`aQB%fl3W& zOGI}}mOx_AS%S$kROCK^L_3;ppptVJ11V`*Z+qDD8OFuu5=UX_ym zF$R;RpcT$Zc-SO~sL(|{d!Hxd{SN(|Es}OYZ#ZDEy~%KUlfmW&ozakde}m594uejY z&wumQE$+Sg3ilpAq`$R6nJBL93foF)?QJr6uurzp zV-YMa(Il;m!N!p7gI%s?6XvT0+6OXa(9PQ5gv@7r5WyyG@B}&sTZ|sxqm$-5`N=O( zvlY5>m?}2zia6OUL0Xm}6kwGYD5`lr?jw8OzOh-en%92?dZF>gm0TZ9O=cVkHAX8` za8z~8=Ef#J{I%bpn{P0^T484%zwji|QdCl(h*pYDWUL44vDV)Hy1+U#Pl!>87}8fr zB)Q=RDHYR3UV5V3?E%nW)EbWf)BBD8>H}dj8&sM^Vp9`_Z@gGpP}gX~vwCW{(IVDsJ@HJIkqK)QYcb`WOALG2Du5D~Z z8)&7eOgb;*ByD1jCxVA~lMQ$qv@(*HjaC>j1l%aLaTolRkN{~S0PE-EzU(iLb!;b@ zMCp1dRWkJ2eSZ1#k9hg~h~<2V#!zG}x}6@w!HCV#7MmNJ>}~I|zq`-=&OUqFd+crR zv$uCoddu(bFxuN=Yk!Z8-Cc&;+tLqwXP4dGJ+`)YXcsMX2wa|?@{_;*5g&i}3tUz5 z_|biS_-jAlo%i0Pv`aiz24%SITOEUC>wh>WDH9Aqr7T)K?CyQ8hueJU0w2~jRbD`v zqSJI;BHB-&ZEjccYecc-{&Xtnj@gs?MSl> zm8IxBquuYLvV^QCFtxO(?qoT`PM2QRqMPM(vx073keh^5X_OBbrD?ZX z=jU8rU9nn~^oIjBcDArp&Bq^q%=qS-#dJoJBs_TZkR(efT}|z3Y>-;{CZ}x;xHYdy zgp_&@_8C1sMAwd|Km8@ivL>lLs*b4^u8_V>w6pXtR4w+OHb7$;_N2trI>N5!4T+eQ<= z`E9r9iQ6>!twAFWBoMh0K7`n6SNL_}(MMZI-$t852$<2|{g)q@EJJ4rNiMfKZA!9a z(`n4*XDKF=+U({zF%o1Slcn+f()h(BDJF@}WeFw|wzNr`oTnyBP0T|H*e7{LQsn47 zN9DQ5t9CmSoi2I1jY?9i)|4n#7;2N@vNo>W#rOMUy$+pD!F+s)yFMqMU1RDcCR7xe zCJ?C08t>u#@BRRl73-63fYd{V25$*Y7`Xu_Jphd8H%kOW!g59#;Q%Owiu&zJ#Tn!(`OV+>H3p+DwJQlo{i%+}Ev(^4(ou0y_a37RJ{TM+tKJss;cGli z3Vu=5e5n<_-Hw$D;QnHCSd&?4+qXbGPecf#xiik1?uycNCk2J8!<4YZYb<;`sa_VQj$p%V(N$(5l{ z`kNbiowF~9#y~8~Tj%hDA`M{;&Cj95mo-g zZkAAGBK0H~gbCToV0L`Lr$71;KmW@gQRr00kZPfl9!c892PJwQiD=?mJR7?^q)KmshM} zD_mGy~ZE^V4t2}=9Es}1VqtjD9`{WajzJ7*6(d~9wtyXvfm3N$9oO6D5MqO8&o}6%e zbWD<^eCvDPraS7hC|6ueZ>XHb*3zPuEQKtQ+`SR<_U5bi89hE=c{S$who6$KEXI1M zg|HVQc~&6sb_-E%w|PwzOYeC0ci-_Jf&HCV*9JpeomC)Fj@(Ed-)Kefj=HkE{m#3* z_13!>TQE6a;THi_f@vD&Am!%{kM&mC-#W>&M+)Ei_pYN0&GRulzix%wgzclTVXcjX zQAx!(@8sMdxqa_F>aG9nzYPLLVkODy9rLlxK}X;U5uCKq-^dLBXszSkx4&8iQN@zD zshC|pI6`o@xjUsH5_KAtKW`FhrLo4KvJBml4py$JBRRo}X1tfMlQ`Q_Cq2ZmjiY+@ zB^Q73@0tAMN2Jqhy2=xlb8I9?=&a2@`(OS`zW;;YM9r66Jbi|q&&jI_wU}W-MM8!3 zOH}GmsYfNCQz73NlaLxI0nAJ)rCqr~r46}D*xKuIuULks8bP9H6xtFr%lrEstf+TOzYIo@l28=d0**`d7cW;lK-EFpa zwi#}3W7=)fcAGTM&_=IGm}OZqpU#-vjJdhI4QRpbnCQ6@@FYh;{IB!A)_x&FbE(xOcw8A79V-%ev%~ zR?bqTBq{-`$W=n2VS857efpFy{_qb-hArOw{`<7vc!Q@&#&w>NdB~+3DjMUw+$#j!liQ_p$qXwkUG{pRK4E*Rjo8-M4U~Ilern7u+ z^nBy{g#qy&e@3$f#28JuB>*J`@Bili!A5_8cZOOI2>CW9@8L1%G{+~J630pfUj6nvcnvqtkC`2xlWT)PQPnk- z4umWr9rgIm@BAjMVV|}#)RQ?czkWu!TG8!xP)1YLHKnbYmn(u&%$5rlt0g*3qCBmP zFRcwlo-v;kQdK48ct$y%5y~3lAXA259lmyCk!|m5yN)7|XiD!0S%S|~ z276n)`|2A!|M+tj*JEbE;#w))jUkU-f0d)-W5&nl_}NOz(PDkN)rycMB&~vFU81z; zIq0UTj0xC8aqqitv-jTXgySnd`&WNV=W4muX-XtG%`TF^D5|i-7 z7f+}cD_(u@kneu?dwlfCCp>-rjQ-v>hp#KKYcVUwp~o!9JTC8yxKI z({2@lh66(fB(ny=0faaRYByK zNoCL-z>dnJOLm<7o*By|HWAdAS0`hl8a`f~eRZF^QMdBAEiNV$t^ZA0`|NVc# z4}b7m_-Tvd&nMWcnrx*>>jWPXLP&AS;dG6oCUJ_y$?TP%BI}e?6U6V2w-JRQayO)E zND+JxDdV~pLa3Lu*E%QHF{YD305kgSfAK+6HsYO>28ft}l*oh-yYhir*krGgk`OSU3)#5a(MqCJ6l`iSx#M5SX+znqU8d3Bxf&9 zxRSE0#*0-lxz##U-+)Fu_B-cc4eAK1Jnp#uy!C$TKzJ0Y z+36|$PDeD-orC3y^7@9!@d;;NJ>{!k{F0CU;z#_=pZys>`HTO+U;Mj2*)!~9LLMABjzR~1_wW4{ zzxKUvu`%kA7$AsngtQ$MX-O5kf{7(6=W$88R^D|*1bdAV8~1xtTvHI7R5E<#12{}`8UXe5$tcT!)<`2 z0d|^8_^V(a|8Ccb+i=_6i{AWe#zq6;>Kn^NL!G(ZTT&g(J8!pJK$pG62oMig9yhml z_q*MiU)Q|;Ke*p|Y_5leKvQt=#Pf|0L!P2r8A-dq zY9LJ@P4F5j0xpRyv-5;v*kfa3gX0%3ao(c`9X21|74CCpnX~iND zg49SAQ7j4c)}pPKZk8y5lBme`y#ofjTa1s-xP1B?Z9R1YWdf^0lWh-q>({=6Bk=i? zFPM%ef?g{oiFY+@_qu?6RVs zS+ZczPU9jM%WIEQ4v&jCD-$rpCU${X*>Q(_*F-WrO$~peEa;?C#7i@wW^M%)tCynT z0MQX`efOVyVC$N?s;O&>jayw=Y*k|`OI_9Symh!*LI=%$&boCt!CHs4BIoE_(}&mL zyu~?-v%<)9R%#Z#k1hRzL=PNL`#|kIXibu(7;PYU>dFy<#@T?kHP{M#4WS~0YE3e! zLtqj-6Q!_uM(7VHiZ-bYB+HWEOA=Lsg6ruVljiL2?yf4O7NTdU z!X1MqB1ed;s|>t2wALVhXQ0LRG_S2ee!X8@mK6jg1ET>luN2lxKC;zrp_StNACjAR5@QhTAnguA_j6k6}6azPr+yO~sf6C>_DMg-REqL8QX9EFzC8Ag&?1ZSoJ-p9&He)fK;w!u6(l{?(QKAjjIVOu4 zlgWg|ZvPj?!7_U>Di>%erP| zD>{P#MYluJDlpv^y4xb(=+oO6(c2i&84VciY|$AF(XE`U*WuvN12*?|*}Hd0XE4Bp zz+^ecrv|Hqu-6{;84ZV=9iLEpNB?k_o!1|s`)$5Be#XY(KKMqrjH{9$I5M1$%EiBHQfq^(UWGonDiztkmCok1{&OBARh6 z_wNqxZ>-AeC!bWHg3CgKBPjswkv*ILqg^FsWw{uI>^ct4E%yBs<%_eJ*kSeWrkpppO-}sxGoIcU$ zGwt{O@dv)P_*z0tzIOP^;VX-)EUv1hPSRRJEml>it=w9VkD)17iGI7ca_g)m1b+wU zyU{>OhJ6t;bPZn4*UtAFaJB)c_P~U0Y&<#Ul+~l-5}1Km|JOHr;lcU~8^U&oJK6 zFA6r=ZTeY8&m`=0y6kkjY_&U#+AaE7K|jst>VzC=C}Mn6O^bv{6O|Tqmf(T|qu4#% zYl2@qPnB0#-8SY$Qv$5U>Gk2-py)y)@;pLD&k;E9`pWYPk(MPG*G-8jHdPsFAG- zfyxIe4|RYlXsQ6EhZTw?une&Dfn~VeWW2&E1WM#q9?SkKG@wlV$WEIp(VTonAAy5;jkAF%v8edyum6f){?%Wwm`yQhM(q_o?V^eyI>`Wu#)z@4 zNLmFuhX-7YZ&*!cC@Twe2(j!brci8fEXpOz<$`K5qnggBmMd0^1&is7>D3Lh%Nu4_ zH_R_(o1R^=yu6{F%$c2DGCRFubungnF=l>#MR_&BRF*JbQIF@?@f_wW(nU>c>ByIk zbY9c(hQa}hiqtFiMw|4D4#RGbG{AB?V=^9-7-6XAtro-4h<>}n^~o8*TDI;Vu>J6m zX}RRt(M$FY57-=TNDf~qHa0gYIvt9BkM^KXyW4?C-t)BsD+Z$mTCIY;$M-S)7EeC@ zlF`T+2M!Z{{fdrr_xc+Iod^wLK&WZ@r1pdU5Zx0 z_2nhk7Z<$y_S;M*V@_TkVSqOuzs6pFgk6?gET*_l#@nyG!Nu1vSY1!>wIzv)eJ)Yt zgC4uDKScFgJo)fr!u5<~C1HOexXUIBPQ%Ve-FfcLdK_2UUs<7>mH3-~w~u2;UB&wf z5-h2*B)AyK4D|a$e)k{zL%dVWE-IEc4!>|DUZb60jtd%#!>SsOI7!NbYp^hav^c|e zjQcx{ahk_&?d8Y&(Q#JfoJAMwqgOZ#*!AtF%3*sFI$zF!&saYSQI08NRgGMM)4^3uOr zMP7ikdbAj=8TAJ|x_6Js zI!Q{Vl<**;_o(!(AV(b>m8;m?-Q;)wv)|=+{_by+6o%4O1RcoI938K_(~eqMl!wF_ zj1{XJqQ|W*y3@vQ9x&}}@M#tJs0y67+H!0`q(Eygi%@S~qK_}Q{Ni&K*Qazw9rVM8 zEO+-& z#v=glqp{imzC%$5FEPT+U0hjboTF$^z4Xy%t5aJLIizy~Ek%C0c7rHU$DEq%MafBHoLtc=P!>qT}&`rJzjnI znDNmW)ALJ0?Pw)ZtyAJ@Z;jY~^#Qg>_~K_DlFUldrHx(YV&pAGsP5uhxVzr|%4^?z z^dAHMU86y6#H5hEFtWZIESYvBDwfnK&Hlk5f9LP~U6zZA@!68qI1tK!u>l>!`Qi{* zEENuiiVKwUvfkJRxFeAJAm01>v3KiM=q`w1;DVQsew6F=L4I$RrDSPBViE#KJK@25 zzxROvwZca!!+2Z*^tUEdjBm#+RuJ%;RlGVJ#u4;k<9Sp9Le7{3e1x;C7oK~crHiO=fL2pEo z70l-gYG*l}PPti?Z0#TL=+)O)RW-J%WU(k~jPudMmva*c>kzxw;I*tMM%^m*-3{BX zO|856{Kjr<-1}b{bRJJ-E7CkenMBeh&XH%ibS!j^-~)qRk2ha?4ZB*gn$JiAY!3(Q z3O~pVRIX5}fxn&WpkoL0a>=2nX7Mv7l_@Ez2TbXDNDflf}jX&rOS;PnMkL9mXb) zigq4vD+;CPI8SzZP5H$$PM>|v!mZeR?GgIXW2S>4ix8x&Q7OEZkgAB9MDkfI14Bct zJT)Hg72au?R3V1IT!<3FK3*#kLJ|W)JYK8B8&(LJQjFA?Ba4ellP_y-?-~~}T>?JD zNDvyYG#)L6ffAsuky`;sF(PZFsI|grEnwal7$}J#ps-5Hj$B-lBtis1$#KZoliSeb z2;;uDzwC1P;*X}-6@;hAoonC2N+=9~aGn;6F7!`6WMu3gS@6m){ zkX57F=|>x#-+>KHbyt);RS=e_*OsJ)@J zh9KM~V-nIN#h_@VDTPVMlp*s%mJ79&HMLQgD{F9``FKLLT#=y2G6DOts_2Xc^tU#s z%aY0YC3aP^vNb9(9PI70G1}n8*U$LnkAKP+AAZc$$vH2dKI8Q0n3peJa(Z@(vyT0} zJzhS4!F)0%LCFzn7;FyNcz8&e!e<|TL}3G|3)C7q+Z(*`-n*=pD?a<=Q|9wID8u#n z1;nmsHlZ$896o#??Dtl&7pJbfS6m=rOp)G9O$3=dDC;g9on!%e+LrBs4G5%;McQ;r(0Sm&ehiQqhQy`v$~XF^OR` z=+o_V$nzYn6?Ii(dhh&~ALtvJf_z6NA@Qfm`)olOavXsSy(Tf)&U{y>zD zO<06Bq-h$#NIoSv0dnoZIHIPs)SY7k!3Mnbc&G3-5Uj#m@HR*~!FtK%M3YVo2=LzF zy+emUrnM+|p;0D7cLo%j+oYorb)GW`n)CURm#634yMLdZ%`FO@;1&y%wXu#ohC-va zL+q-Cl7V7W%qhq7)DVS2TI84U+$6`0SaBwACXX)I6Eok8&xd)`Xx5$`Q1~gai{ZX*P6+Cm&EarKxnF7VAz*A_;iq z2~ojMu1_H7n1jYks4g^*B){Iw%I4o)*Tb*9ZZTk+ITaA8*jfr6q%I&xu1`C$Hhd&1 zHCaU(l{#2Q&tz*BK-pI!6EPncrAKemQcZqc(i*jDQWKKKsENi23QJ5~#3-ErxrqQD zbN|skm+&NV{)3VG26CFOLa}61}XsJU!#+) z^Ch{HPJZK1vG?jj?(Od3#|xhS;$!k!$~bIrGNzS`c-4UVoj(QZ&Ws@QHHK&J5cOpJ zZf1(i?WkdJ$2p5L2ThHp62ToT8qca)(rV>==l$>T=IifpbG~45R#HyERY>JhP!f&s z!sd~@dgCyOf!Q!}py3C};}FC6ax3eDc=C;xALVr8Kad4QD+M9oz3}X6TVV$8{?iY1 zQ%6oC)E_}V5*pS-vUp!>a|d(;_&gF$P)bVVL^3vZe9Cy z)_c5e4JobCP#Lg^jKw4Ze$XDT8^D*!1c%2dk5g6%mPCo^+shPxlgyn4?nC2UM`B=z z8$mw5))E~N?_Gh{n9%%|7&*|*H%Ny$eRo_Ta;W0b-x{EDikiob*MIBj%Qh0%QV@kf00*FWO? z`7_!{i%^3h$7fw!)&?bojY?^14YYCwqY;TVj4!XK%L=VD*1%jjuBruB(=p@OgvD~f z)tTtZPkhORUoo*OywNPJW#UTeETO%#3H>$52!7f|d+w{6!bZQvwY%uJBTEyuwzo)%louy2 zvE_=?XeumK0z0qVr?olYYBuKhi>LHzO;QJzgB<;Ehuz&hp8o73@};N0F{0@8m`-N6 z+L5#hii2&^!)?-To8f3cu#U^;M@(LvvYO7R%93v0qN`K%qLR|b%@L}dQw6`~0`&$1 zPR`C)-Au_WxKuM&mV-B6<*>g&IG^zH<1a`ZcxMIZ;w+Qd6|uaTU$U&;0)Fh`8B~b# zQ0Ag)O5fJG==Cx#Q8IMw^61gn*fgiaP&aNHRlTIwYw?5c{W|ydUSWK`Vti3jE)>Bk zv=Tjp5F8;0X541Eg$v_uXP|iZ5%`-NzA)`&UAgPcuV0HsL1Qe4;b?KzQrnukuBhu8 z)BDyx`9MX0LL7zYjmAZ4?VWz}K8Pl%)Re~@cC3X@vUI(LJEZ|Cezpn{h6uia=*GK= z7pt*wnuQ`DdFG}xusI3qCG4AjDryBZja_1LVQm$8L>11YIeB+LI@mxDhuBt&&rXgB zgC3pT9rBG07QwM{F4h=}C25RU;=x<7d9+wk#MdK+-&uZRx&561DL?e~nB`CQZ8jal z(=zPt@Farl8{a}*S5gmL6!ZrJHbxt?+HKLm)-mm1G$kIFDC(A`E)>hmW7`@!hW2)s z!&eXa_V>QU-}(E$&7;TnXcZaORni#@xn{DOi(;B~fy4y?-(a|@6wj_#e0nnGv-1g` zoK5)o^HZK2UGe3!bDlrHVs*KqMaHn-M+ZxLKBaSYMf&oB=_gOQ{OXu1=dky8>3r)= z%)LG8c0o`E9W>fXE|zHiBtd{)CasJ^ui_OC9_=BqsZA>rJrdeYKl1=jjv!(QH4o)gOU>*RhdMFCWIIWsldEkay7YO zZmmW3rgDs7lJZX1-XkS}n0Eha<2ImZVd#cmI%;t2jP8!BsVx(v+^oC7MTX zyh^v#;pXg;o2M^n)nKecwKDo!BM!EDeVOzWQ2pDc0QyWld5|>iOaxX6Gx*Fzy8DDVq>t!)%lFc)rxv9sd61H=@1>JHF*}I;}Eg2 z0rfS2H=Y1-CO4QU;lSqc`Zd{Y{k)5fnrbVXa~9Km|DSw76H>l&1_E(mxU;C-hNguz zu4C7?paMG4WUY*%Rgf3C0DhjudiFI+#b`kUk7jXd7P|PO<%dfSv@r}q5CUC9|Ft(v zB+E%~M&8`y*n*1Q1%V_69ggswhaew;4XTkL`8%?EHi(P1t(yfbM8S zS&MwEMv(@woDG2@OGy(W=gzNvsd&~Ku#eBhV+=vq|IOKGezu(Ec;O?sOPIO=dKIlv z`S|s%f}&MW)fHt`p_HcG@6+4bVtad=!RCmf*MTfWwK8-&$8{2H$Dju}?cF|G4|jR| z_G8}v-n+c>z4z$%TY$sXD*<~2i7^trZ~obX%lZpmlMH|MUstUwqE$#TB8}s8{Y`e)tZ> zn~#}k#magT5;`g;@wXOu;vsXwtpFhiHo65N1X1|&n#84O-vEA%H*Q_$t8|D0LZYM? z3@9Bi+LI_x5@gbbpdd)DSxKQkI+oN3;A=tz{NQ8iB}NS#Q36#3s<_!$PwRZs0`=D7 z)d95Eq*lomB!Z#h+=xF#a@TS2=w>`LAJc$(d>&#NB7TRAQaMjP8XZkQQFsD(^Z61{ zSc82u1lF&q+o}c|$w#+FO!IzqOM;B=lSqJ^Bk3gOrEL8Bc!k3(A`@c~aml z7*i0k4#Bh_2;duIs7ye23bwblSlvunO{UU&T^rJN!FPY-hio3~vj6A-hp#_obAJb~ zVdr3v!S*KYewTK)E5cuCMo0{+y5{=&n(@^oH|G~z9-VUb;w2}~Uvl;GnB%XWarW#5 zS1(1G@BHNv$Io7HaeT_n`32YK=PagEuFlU{T-{JkX3S?ZX*dQ<#uFx!Nn9HviLwEt z$PGxdl)>&6rpP#ZafB*sOb~J{TCYn3SGJ~hmJnSV>l`+CN*r0Y!@`cP-%GMy|-zZl&k2K_ed}{P$@^N-Qw`@kaoYv)pE+t!9I^)d5o=V&d$%7&Zd-$ zCCi%$H&0)3_VE`iPA*v0CHdx%*WP`b2d})0KWeJ zC*a3Klva@q6CBQ2c6WFA+rRz0B)ZMz*+c+;p-@f{B(Eh-YY=RLxc)?OHlwwamfw-a z4GjVBPAFd<-r~vaam&PSurnZ-v}X55L&LPc^?M)4J0mbRr$G?tS3G<9K&2r`lc>2b zb!vG#r_=9Jv|Fe|iN14U#OrT}Eh_$)J3m;Ko#yM}_rwM1_F$xRO@2p|a8**?rgXe* zE>a|PiC~X-`bAOD?R81B6d%cO&INRuQ@Y4{CNQ@(S+~v3;Q^gq52ZC*n_KK{?TG$B zRY})3V}v8%9Cg$$R><$W9VYQ8f|QBHD@X|OIOO4-KSA;4eJbjas|fDRx%h^6AMe#s zQc-DXRcxK3E=z(|6x}w1tqnHzHW}@2uyJpT&HFp-JUZass}H&V_#s<++w=xKvMj;X z6|>odvRdJSm-CDC*Tx44D$Ufj(2)1Q69fBWzLg3n%FlMeRi?cQgwcb|iM zuduVZ$M$fWt-%&OopUo8Gp`q1U7mCL$)}ur`Z>$livGqf_ul;$?Qg%y^8Pjpr7$`p zLjYS@&`E-gM9CzG{HKzL_j74_6}_w z!D^f{l3$LwxaRaXd3U+C@!G^R6wMrO!rT6iW_a^t92+W*jkTxJpIBF_Pe8B|`kEvMB*yONbQ(5|wBGUY0un>$`w&8}Hu}na0tG zi768QjT-$}0@#2(QhOgFSvYYHR!jc!5C4c~pMHi~m83eu)?m^$Diy$AFW8BuHj1R% zVsC4Qo6~dbY$@kcD{2MjvoTLkk2t@+9V!8&GyzddwYA_ zzki=c4yBOENH38^wZetKaC?)D!#$p!9&>$jjRrP0H#xh!ASig}jW>Dk^*5=fb8gNrXt!JR zwl>&*^nlmic%6?v{)Aur@{ti#6a!NR%q7ZzP@LUo$^qS~~DQ4)9eFmWp`y7KKNv zfcF*%+`o5^zw6nf7b^Zp7hC>)XHg!R<#jz#eyMy79!F<#h?8X(MfMg9_+WlXqGqS%M3m zRb8>FN<0B=G)WwcA@)`lPrdn_w};Xkz#29ihI9j@jqt%5{BLjX9;Jlxg~92)fL4|! zV*fg+Ff}?MIHd7RyG^&pdC^u6ZV6j}IOl4IJw|tE!}`Ypl1_ zUh3d0RS{Z_P*})hp)@8Tc!gbgY~^s3r(D%C5M%FmG)8!AlQGqDMeRLmW5DRGH|f9q z7V6=B%8fpYG=W;t@(C?6l$Oq6E9G&C0KSPbv0)AP#K|e=U86)RKpPpt27-}@kO`s} zpo1b<#7ie31ckN=Q+ae9@IJ?r#JImg#ZaPT++yB8G~wu`v^B0BK_UaP#oy$G7hrrK z@zP-~@lqaUn&A@xxJfar^#h`?P|z~(AYkyAsCX!|LiU|$ z`lCPM^sBE)tVgQ^>!q8bO531wP;#6;_FOM|9kvD|E{;wKRSn{Y;8R8aaEIQ`23eZ2 z98WkqK1ONHWIpBW{G5}cV@_WlaeZ>m@zZAiFj(Li&z^5Uvdmy6e|H|*0H z4Jm`?`1FJ{O{l!ZBEn=Sg-H`=Iuv^FrIgjBh{B$=ma3}A^PD6x47+`{Ha6+)Y+ySX zqX&DG;~5vvUa%TZ!O0ryVno*^n!`6=;c_+O?Bql$0M5^tEM~m<&Re|p_%Uu-^7&U! zc=tEH&nw@3mxFuv$b#b8ldpL8)mQX;JzjtOn9a_B(U_@S>4f>X#+4c!%&k!$CwB;9bc+Ws?0oN~ z`OPiB%RjgU{q^DyG4u8#ZvkH(#&@m>eYYu2)BC|c`=I$~@eps@wJIeVqXMcCV3C?v z@d`Z3DAFP$Z{;`yY*ux-RsfQ&c&V^Xy`!#$v><xpr}a$Mf!EZ|-GXv8-0i{hT>BEYy_BRZ%H1V3(eH;c!&|rv;c2 z9i7=mGFRMH6DJndQ9Dn_GR|i!{`&Lh{PgJwRcO<0ZPM>-p_E~{Tr!_dSsJbp;Ex66DqV40@WXi{tF_>{~lDgvbep9vAmn?MqT z@EKz5x7TtWo1A;IfQs6hoX`++-O_)(3CAl4iFoA>bR7ZTf(x0D!iXpw>e&23HVH{9 zv=hRqc5(6XcZNZbFING{$vf%$t%HDd>L7EXXAxpuyjQW@O-ba!E00w^YR@-;caI59 z06!1|j{^N3`79rYUTA)P^L%9bN*+E$@|~30xd!Z`P|$67Ur3V;$P0V_HUeP7Z3Msx zmdR(Yy?!w&BDM>GFTPIn@Kakee)*EW`IA54>g6$6K&qZYg2_7Qq>WO!kPfwI@i!gt z`t1&vM<-B8RgLnZ72m(NLuY$LVG>xDc;|TV$|HIkBL@9G!(N|ZyT?YWOD`?xv2u&+N9`pnO7xe7iR>c818KG@bO~~?j4e*DOFj<)Rm+g)1bwGRI>hs5Lhf1 z%olSO^Eu18G|joOE6Q%d;BcGO)tJjKpW_xHXhsOqsvO0nUXgAM$hQV`ix#;y6zvwf z_YQgMy|*zg@ZyUvIl4Y)=j~TmwGGqDYp%aO;_Sr{lbbOQA3WfdgZm`4=fy8SC!JTY zs3^9Ej9$G@-fHo)AN`oc)eQ=1`@7Vhd~3*S@4iJjp7P@JFRABCwDVHZ7`w|!!=~GH zQr6I0XQ;uE#>1E8_CF2yAp(9tK0s2bP5?eM^(jKw(;CXvl74T%+i$(iyKjGo^Wz&X z&t|Nq7GFsviF|bQ(qpPx_+-*V#|Mjdah;6-A3~fYYplEj0qgMo?X9eAw@iKcj9Y;o z@8xsM#^3t=4@7e}g1W@YV+cUNUUcvquU`NvAhqZ^HRP?FtjMUHWmT6{&I-T=N0Oyv zSt_;Tv8#`e^&*JN75IiXFPA~KTO&a9l^f)jHB=_OggWJZ#9(xyNfJ$(NDuTxc~Twd z3U1CRPhPTo@r;X)KVtIa3G?UASR5ZQe))oNX*WP@*Z2 zoL-Ol@aapwIK76f5N2zlnN?G+=NF8ZV{VpH7QSR@E6U2UP>L%J!?)jL>oH z_3Iu3DnSJ;GQ~|bOJlXG82a~j#IPWe18>VVW$eY@7vdt(*q!lvV-|AlaW`Ri0e?jm zVi1?+Oq#M$qkRVEyguat)f#R#+F-24zxJ9Dn*LAO45GU~+Lm*3{_h zoFwa_lLDnORP4AHoJV(CB%6J7l5lx^in5{;(Rem_lA^7{FIKp+LL0-@&NkgnhmCfh z?e2h$!I1uN$Y67W;npVI;eeu5&>i&Y^?S72ZPGMFDMhc}qdVx)8T3edEqrb;y*7H# zMh)7iVViW&C28f6`yiDYR!c)0uO);ZfYc=5V;(wIH3g+`1h)5gF-6XJKIP)(8q+R# zXE$X1 z4*LiD)MqzbefbPsT2dP%T@f9eoL_6Hm6^oI0%J$j=)!_kPVt4qFo`jpvh zO5y@n&yRWe)z_Syol-h!hO@h~!*FYpQh8pUosf1~6r&z{kM6UvvBBlb6TbfBbNsR- zQ<^L&YULRm?r{J0SD2q)^YV)?31x+fdMrK&iMxq{YJn7)T@eFhHHfQgbPxqfBH+jM zqJbgV=g!(39fxn^??Wt3RUV^Zu~@LXv&*;Md!GmQUgPw|71!r;R&x(FU30Hw@-<*A z^CdtdEG>>=1oLLUI9p}Chhi$hIaxq=^_Q!9#E)D$p%bwgx?RhJ7~sU3w-ke(@C-Pd?`8!=G{V zi=T1%$;Z@3FELkFnCTQXo8cF8QmweSJm>3YUvn|JVfSEA?%Wg4ApbSg>V#tZa~li#>+K@oI9lD9Y;Px$!7DPLbr*MMK+ zn3gxp>j^ILOzH)d4(ky3%ot|94#W4}A$j~N)8Qsp+OW)1=6Fodv~@ya6ier*5``)f zNHx}0q$<`h$3fiypb3p<+>G7kB*{1kcaEh2KdVIDt@N?Glyl_1q8lnY!QzQtsIAx6 zMaXTjauNHkbP5n=NeD`uF7C!;Wq}V+`mnE z$a}=75)K3Sps`-QS9u9bCuPZ#pZpD9{NyJrZzg0I90rmWI`5)Q0VJ59$d$%hiyC!N z+dZ6jj8D%owRkfs$Q+oSUvcsLi1GC`%hig>Y{Kc;IWJ!xiR#_aDK}TwOqO%Tt0l|2 zqV`hfoficg8yoEG?6SMN%jWhLJNvtA?d~wx*`&QOARBerd3>Mk*B-L*_>keleRl32 zu)Dv> zH7`z&dE>ozP({ksY(f&tg5)`al&DqOimM0giPA)_(wUgsi zysk=747#*72EzW|+v5IfkJ;Pb$FE90|M`cM(>ca^;YU;!YZN=LK4jY=1=KdWACT}$;)eQF6Yz>P+kCkO*W4cu=#v3yuE0H#Pvj87a(tbncTTEk7GKc0rs^a z5$E^q5jBr*@0rct`sW`cNg_E?Ck*n&izb4Jj(KsVg#?FI(%2?VAP(XrPtl2VrgGxb zkY*WqmXV~Xl$jt0FCKn#QZ# zb(n#mMfGhxK$>f^K6~<~mGC1}5VDTcmP4u&@-!te3CcmPbBd%*mbXdr0+Xd=t(>%# z3CJ7JNi-@{T)cybrs$@O%>{z>Sm&`yq4E}AU(fjb?3yYlk~EX%LkW;7mcirlf~C?d zEzBy%GXCPc>3}=U%q_K^XwHinLQmkAbKTXVOI6n;4O6z{aV7H;VoHhlCKgyu4sum%R4= zJD6^p=P#dga(>2eG~(TN-eoizvA@5^y~BI#$ClW;ySr@dY%?4UX?HsG`hBt@C(AOF zF}OtW%G+;p*Q((OlCoF(lRgBLrID7t*o9k;XFE5$T=j`q7 z^5Ee^RAp%e&7j@k{_C&u+WYUYwX?&Eqa&8(imy+PcyV#Y{^0@N{qA>h*7Eez&-v^p zKj-S@spv~Y-b1Q1s-3g*`XfgBJKP+da`NPBY5QASk~NMpA9lFJc^WzEQt0i^?+Girh7KG=) zoq5?rdwp^>|Wn*&cU5m8k3WkTYWB-0BO+CG>Iv#2bqPZ~gDiwOs>G{4OOG zi{d55F|3s$(HX`R=%j!&Aw;iUXP}aRijtA?A+mTk3%?jAQva&F!vtwd>5~N2>T(?n zN6VVii!nMR7*a~-m{m2)kT7$Gg(|4?9?A9|-EY0i_TT;?>ASB&uTM}3N;P%$0WF7& zHBcuCYno0~0TZNDPB&J4oYGneb2(^3h$KqkSTt>&y@c_diGUxo-H}qS>ykk^XU{Hp zJ*;>qEO^7tIdm0!k<``Bqn*dh z=lt~F{UK*hJ}1qY<^#^S9hkX9ak9qOrOD1QRl;bJobS`-*=PA;R zPP*w#n$#VuRVA~bu;7hpZtQ; zFP`DXb9C)c)?1bG-Z3dwlDi_i>fsC+A|FaK>9=u7@Zvd~4 zR)dP=ZH+OYliPNtQX&*{|60QQ%E+nGT8lzm(>6CYy)h)zF(>WA{go>l^`Sz zr43rAQLoGq%5hN zqiD5g6>ZWa0|&OU(!*TqNL~`4Yyg#}`A~?>f|Q(#&rC$aR{Kr*Sx$Y z+>u2mUH&!6Y8LOsoR_+eY987Q``wLOa}pCr=vcE5rXPG*jZfN-;w37tU1*mjIoz%k4*9h1Li8M5N_n}$Ze4O|}rg&TiW#Tu(CoVQI zbsq5{vi74IUZdOZ8zSHuKa|O63hnYlu$@v=oIBwB)B}JAr zGGRKIGMmp?luH&>$=p^<>yo9f*?(}4Rk`Hy*%9-zOHrhYYfnfN!DzIHA{eqdh%9%| zvTXQ(svY%m$!b1lRaIQC7M#r|oL^ipy&6;E@%>>z zo@}xGl?qr_V~pWj@4U}jZ@j~D>bN+bu$WkUtlZ+n#uEfGKCgz+ZY;Dp6 z?$iZi6go>WSt9QjjYzZ>3$ZB;&`OggDM=!WmA77+!c_J8KpX3-v49l9Hq|;ssYJrX zI$$zG(n_g(MOq{nqX@yGykoQ9V`ng+6#~nv3r@cLg3IU6u+tmdVnJ9f2-Ot3yu>cY zl*@{$tnoIkXhA&2BuUBAjJ(Lnvka5O+J2-yx~^)Jha$_^>-YKgtB-l}V2{0amsVY~ zy1F2>6^XA{mNRO%ByXir!qJl|$h0C&G)XF3NR$x9wZdc>XfYTPEqVsVNYfA#g^xt$ zw;@|bQsteAfQmz2DGABLZC+V7Ip#?0Ac)sz16n2GHT&io3b9Bk9~ASf&AdBAA3o-^ z-Q%a@IY0mS3CGV*DOVPs8caJU>+~sl8+10d$wnhgugkobGU;iqwMCbn)N6`Vl*pRj zO4Q1?M#|A-5%;lcp>%VM@rYZp+M0|f#%fcFqI@i)@do8Ha7voIDofCw+FOcH^GZ44 zEx+VFQ?Y-2%t5_CVel^Sv(5qkeRjZ)^KH>$Pzsvn9Y$*Wow=QCcu(RLDVjt@Z``wP zUmJqV4|E_T7H4dX9HgYAB-&tzu6>=kZMT-m>3}u&*YZH z+|c=&=T$6Q`^I7!giO~MmJ+dQ)||L#$e?Q0Ah{p+Z*H5jK~#c;&&f9KVUrF?(4J?!x1$Dfj}EM`?pxK}B>(YRC-QcaR(BuT<5fq4>G*%Ixb@QTV>LYBx_Q<^kQ zNKHZrfp)8fQsA8NgBFo6r3|p4y0Nr+nZo7?3464(@rwJ{Sk}89@jx-Tw z{p4nhtu4d6%|}1_3H59tcDx3k8d{@1k6wF)+4&VmUwlPvV3{d;yPIrpY=ZL~KYNZ} zNrixSPC_!Osh|Sq9H2<^OgK(yLda5lW=Q*O{%8O6A8~SW%(K7z88;t4CGm32y!Uu5 zYl;q#1ch4nEQ!jBalDJ>l)@TC$Wxpal4+tedB4lvqx+=of{sdHUU6}9%JtP1tJxg0 z6wUu&{cU79mFPy*&G^Uvn}5z#Ip@h={*>cid`e+~MTv1S=iQ9ob=jK$y^mEpq2ap( z6$9J?tZSvrH3ufF*TE1yd~p!OsY&&{%?X((W*>S@>Yw~BzW&xtyb8&mXMQ{z-1!^iEcc5VaQAV zT*P?L^664udP@LNN|B~1X_HruF^96Oq*t@|fQaT0L;fIj?k34FCX>)*0xDIKE7e}| z&c4PN*clCZe6Ww5%{c%1DQ91O#q8{aq+Fs_bL@OdH5s#2|slc}}V|-qv{QP(gC#)>>?3<#$_;u1f4=%)1XC^1I*v0pEZ1HL|M2&nK{& zvn;37ZiPv~x{Aao3S-E%LJkR_#OffDsD9k~pV z*r*!oHimal9%VdAIbneN*cC43W^3iC2$7xVq9iRO4pEUqfyq!sfo`{$4Y#llUga~d z_$+w7&NHg4h4otcmIJ|PjLOK97ARPFm|0i`i^>%~32O?R0HPQbsaK>yWPzO)z?U3; zY=0Z|{F_c}M6eGYl3I~ig(XnpaLS>*$KcT+LHi8vlyvx04j%!(6)N7TZum}^^PZ^~ zo8l__N)@8@tv$6b zQN~MO?NEYKq`DwYTe!?nX;5}S?pL&er4@1tmtu9BRgz+(JODBcrA;*sjk*PTrPe^N z@aQ1VHIbk-*ds;&G%JsI;?3jrOU=%Afjk0*9K76F8}RX8xZ~qUy}Bo;6pO(+=&L}o znsfg1AM=0xKmPBr$1l*N7?rc4O|kWm6$QozQmv)xM=MmGGJJS|>!f_~;m7p7LCr-p zD$O#oPC@A`X{W{Z;|Fy2x4B-;sWi-13+(j_Kc2I!N~B@$Ru$A10^}yegn+9m z>axUFmORZwPz*@5A+}z`C{3CqggnFL8K%>sQ?zMiIZ2W*7!EN>!g963c}F+NdGg`M z*!i;YHE@Y$=ixoJ_I9{=e$4rkuSwDb7fWru7sL2gWJj?oODb2BwcC&;l+J<+BqkwA zQk?g~3CauCh{f+73b5PdDQ^^`n6jkppHg&^LhjLjgfj=1|KkkU;F(Jl#=B@ zy4#5tmm~tr#u!gXjm$Hy!$ukiCJVYNV& zE5d3)HJvgWU*pPBI`Mf0Dj_Y}3^%sf*x6&Su}RVHqK(0M&#GKeRVB8nsLGQ0d`?|g z1Sb)Ux-1FKvYgM@=yur~jh!l~>kQmV7Du&38 zS}U&IB>{#Yy^v$ogO3*8dPqb|alO|TB5>~Oow(OFA+bf2p zctk4_s#K%2oC8}o7hM(vxw(aN@epK;NH{T87{pT(noQ&Re9G98?voARH(|o&vshOI zg!r9u+ZYPBK@27sn@3YUX62Mv0NTbN>*P z8fF*QEU(67+MsQqm1F{VmGq5QwZoMa!3RttWV>ZmQh7(W+hsHw#Z+WYtKBB=w8^?1 zT7xc+-*}a$Up-}dbVjnYcqEOcx-DFy1$<-IMr$N>>QMo;HoTPxWCQY-+iB_&%Wm3=}X*nA$>cX ziYTR2Xg18YZ(T z_a8jqJKy>~yPF3bKfmPaY>r(ils7_jCP>Mhh-}DwXl_C3uv8@N#bbywSbkP~rTL#b z-g@)b>@V|l4ZH*|*dnjXKBoVJ-~Zq?Z>}MRB(>HgX|f(fKDOc$pDdn~NIpWV^$8TY zQV}~Lux{(BV#!^zSjhLtdrbs(@tQ;)RyYAMv8{#495j%KcZBjJi6Xd~B2C!a++cS! zBrI2)J$uIZ_=NK2hOiKzH?}4Xj&eR@e09O(`Z|hgD2&eObOvl~?y|A5LtbtNe#SuaKPShz~%8v<~NsAiy1yxOrps1O!^F@ zhEyd|jw9g`LS!vh-eawYW}Gx2*K8qbum>Sp`9`v}$-k{z1WSlEcoBH0f}~vTwDUFMZwpOvM#(7bw^HLt*BWY0b$^sP1#4=hl?o( zl-$c4ZyU=ye#vWg$$@ojRuuuuEcHxNgIkyXITR8>2l9FpYzQd*5g>bRFuX!x!xV6aMKA-fBqAm{N%4_1&dax zG$BgcB<&%V1PJIzC|dnMDzM9v`PB`1>;makAjvcOTN~^=IK*_@EXoy^mzRvk zW9IWY7Z(>?o}4oqPgyLNOr{fVuCJMlC(Nc(mWw5Uz_MJCb=qw0?XrFEfWg)VgY7ML z4-Ywf_<*gQo!De&MF`?m%b##6R4wfD%p_nPuB>CEMN7?lE!-5PMexcQ#onX)RNgVW zxT2cQF=15SliyaV*Bu{!PFaq+AQ{{KtT=z6tmU z%&PUC9_4Fr6*^dw2+)(+lsDgcn{U1K9eS-1CoitJI-5bA3RwAuIM<{gnja=x2%wY$ z6|1`t3~0=2;yrmLtRM3$^I2XJY-SD3a%3T<)0^kb;0OQW1J!uyMnaN}H;5RT934vH$gf-iDat4??{5#-mrpNDd~3l!9vN?PZcTDyJwR zTV;u6XEb8F-^WY$rWg8Sxm=FZmzIpg$agKXS7;9hJ#Ip zgDvu+i}w-i>p^O*657vQ|I?bwF(k@b7zju$rjSZI9SGeVZP_I~( zb5`X7=N;O}c}lb)(M#R3iw*Iz_B%^vZ%5`+knyqS$l}xIAFZ7&)2OXzc4NSN@aZH6JDAYS4oSN zE^r~0O{D~#N*K+Hq3BHzDO@MbU_#7l)d-Ml=Y;$gmFh(KErNYxu)07}M>V?WiOTC< zq96{8m1A9J>tbF|MOHr%%mnP^{2HfFHFT=LTejlex?)t7bdlyjK3W}DX_u3%%duCK z!BQJ=#!#ZL%7`brE=`jO>Xeg+N~p+HO)v3mWs3bG;Z0NXZ9nJT`6Ump&p14N!Pe;s zhtn~Sea*epv6s|5sKz{+U9op_L1!|hJ)g7Ej;ogDsugg$#OYe5laG;xW;Kj|fxF}4 zmQdF$GCqQ~JSW#D&emu^G|Nm}AAEeS0rmK~AqGy@(MBKFk~kilFY&SL6b#;Lv{$r& z^6HY$|K>*=efkSpxF~g;V6rZ{=wr#GRcQppQU&^3o8&sdPUn=fIR->h8_3%&Hurbg zef)r=+oHCXL}~6F9xxaT>2$gbdjtC29!Vm`L>fcX-pL|ty<=%Bs^BSuV`*#Vwq{x` zS=kyJJXKwBc6!EqJ_jE#Xq?J?F16)^&S$P)G*KVZCE zu(-U&FIE_(qq?JLojCkDYLuD;qB>vD3Y8ijy!x2DD45Kq%vUQ`RmH4aaa}K2m_TdL zqrWlWvrj%@d~`-qI(%kO8$G%Y_Q*E+!mi)wlWh$sc1HB}x9K13(!IY+=l&j@2YU=2 z>@j$F!0_QAgZujo@9ndBZ=cP>J%-ytSnO?#=xlG&+1;eQwLyE>r`_$)&Rb;0V7;db zu}Z~gTHOx2_YQdF&DZ$sv(LCWI>oGN0sE*+-wg2($EghE=JpQYH&M}V0Qz0Pj~{gB z^(HDMhz2@1l&?`<2zy4=1U&QAlJ9=^`@H_@J0ujGzPRG%Vu|rZRPdDQwGb>p`E{xG ztv*X=^eZ8n7$IWfddfA=#C4Fkwn&7s*(dH9`^+>Bd#lJH;<-c_!3=)*zxtqI!=n`; z5}g{NoigI-OO1WB)|H|_+>hZOEf8jfJ6;cOe5%|QJRV#E5a;N zO@2B7uRO*mv-t z3Tm}lbO(Jpy&g%COP(ys5fb|#`?|uGE8J>{uS(H!wie}^0D8c?8t*IGx#6|_eI9IW zqN)|fRwUlCEa%MTQ|egaXX_eVZ2YiJi%4G5H;P-)of1&@I3Fi_jJ8OPyj(9AS@a=t zCe~=_d<>yV3|v_SHF)cBw#L~SYwK8Z4NH|V%Q}p^Bd)ggIo&$GTNTiv)uPBVunu3K7Ke@Jc;T4~0h)1#dg6iG_E zXvN+U3g;YERZ}@j?Je_i#iCj?MkleqAHn}OKvW&7++oE=1cr| zfti=&rKhmaio#gEBxjhl85M0dT3vR!Lw0*3_D5UnZEmx_wZq}=K6^X6Y#!`Mbm3r^ z(f$sbhkI=8?~-=f+)O7d7YkA?x-Lbx!~Ituv3t1BC!c)6N?zJm^&8l*emFVuabACx(an`*gF6$@w{F&z@6FXN2VnQ^^3KEb&!I zrq#NE&Z=B7pUr3&IsIObR=11E^4R=Cy8IaJ0W-_DLTs_O~uIZLbhnE z)c`mm@CT1|c5MJO)et@k8?E!C))DH+gsmY|0be_ut8v!iycHus888{EyvK61!+hsH zM_YS**zWOHwdZeY$J4A}ns+JF7ArI^5#nESJ)Q9Vq@p6WO%A>$2^MWjY|Qmpq!f$* ziFagCR&w2xC6E7Hk1@ImUybS>=UX1sc&yh#Oxsuj9cs2C;)A>gn$6^|KV zuzFiFG>Uh_inr@2ooa@r0$<|o5?sk;XT&F_%h#qu9So2XLP{Vbs0@duR-o~;bfE1j zwyGr$>J@Kk$9FTuw~gghJ7<4(#^CaldOo2>6BRwa}v&r4yWxt{~y-=`&riQyzj(5E4-n@&f(;9GcGOy0gxaVAxfl8iyG4^ z*Hn3uJ>{t>+vTyVT>cO6XZWXa`3HMSF1tJqBf6vsB}*d;APJBJaB*?t$@}cQclYk@ zH>}_vp0&FB+zXP@Nbf%DboZOz^{(~g=lfjLV`2E-5M9>BGcCwkfw(U+BNm^$jHfh_ z(|i}j354NWt=Sk$Jc9G$+VVkSd}2(Re4-OR*Z5u&0$$xGxm{8qRHnqSSJ_z>al-MbJYmlqe@%x7XPEG%e6+jm@F zUvc#K8E2_F+s*Zaqo>b#^66(h`|L5-XP3-wW=yZH=oc-q?Fn6vj*3xLQ&>w?m5jz? z_74wu?aepX+TUgW?rrw(+-Cc5pY6jv4({D$>u`_J-VW8)7_&J-Z4R+J8x$KO)SyBY z7G*6#Aq7*SVBTl2nVwMfXQY2LSehu5MV_d0U; z;2sBeZgF!x<>KUwN?UA{LQ$P_6m`uTuf4{2FyNE-KcG9kV#ABYp$(3Ut4m%!d%^M3 zr<^=~&e=zgIsV{Np1l8a9{=>`JpS2-JpJ$!jy`$B%g>&0^ympMKYhyeixX~+FPL6j zF`M4dEn1Wd)Po_##u&XZq}Uv>b?1=7hYz^@;67$p@#6Ul=9d!&rl2QK3OMp<07^7)0xZZdk;W|j{gQ$tW`_{HfRtz?tt{p5+p@rxCALf^s;s#pzI#f>{D!v>}+hX zv9m)x8WXjl4-);YbEISFY3Eb=#SQIjN;jX05TJD`kt_FCs6aQnWN%dSKm4`dKX6z4-t3rRbA>XV5IfqY!MmOh58megV{h>%)h!WLlqHzdw8n=XA9_Z8 z!$vpfL23AMrTJ2+d7vG8{SEc>oc`vFesV@PnbTY@*c@+C+#bT7p^BFBCK4wdv)P>4 zY(dw|sI6kSImU0_W;Wd6{qX^Rx_O&Vwr+`4NTu?{X;GvsjqKV@L{jKo9&c%$BHUSm zpTyK`jit7lTYJ#XVKNEK7YiA)sVd`2!(RyyD?vXIk0r56gx8BX8>8?l;<|vLqVSsG z;+p4w@u&P3|EK>0-OEqdpeHgyn=OisJIv#dUJudQp_G8xP?o&)?z^<}IY&>Q(Y6i7 zXxg?#7nY6f4R*G6=$ZzjrPAEI??mwQp6PrJMq|nn=N$cfj;$)m1&@J%K!htJ07tqi zsYU}-VbO(^bltk9E=ua6#41f~OLT-qvtVO;i|w5qYHd+IVmw^EJmtfmywA%QNAzvS zP+2N3>6>1Is!K+9_j&V|zs8^b^e?!1cFd?x767HhU6CTMb&Sw^0m3ngUPVG_dGA-g zK`|O|{Mj>(A3vuyg=F2>f@|#=+}Y>1zWdu$Wx+rBNB@|cCokEhg340e+9r%DyoQAr za2?Y+LetUpU2>O13Dk=oN0dG^7OO3;cLbxM5Z6d$3jkbYU|3=YHO5-XvY?6@ce7yj z^q6rIDH_jJXxV-J9)IwMe-CXn|LBkYA*UZbqHY4Z>m~o+dt4MKYn3xj*2X@fAISQc z@HkXL!c@Yqvg<4HP7xpwp&*1P>Cb=)9_1TMSYT)|VS)B@Ty&J9n*YWB@;~A22Vdv- z$%IdSdc^c3pxsE!`2mbo_}B`3Zi>){6(|_=DAfZjktspuR=Tq+l`k2;%-LkJ%zGv4 zE?JyO*79Y-Z;3;{Op{UpFU!8 zaza0wL*GKzia9h0NQ{nBnM^BizGvRdnOGbL*)fcDMTlg>N5Cn zNR^*5q#0uJR@#77=+a`WrZ$#=v6!-e(h8KZ0;>gsHE0QpGrGc<0lFOGb%EDbB1~08 zp|PeSB6-Q)Di%Z*G16E|x3xpJvBPmy^I3q?ddQV6xiTf8s00nq6v<_fCYqK(s})$S z6B1%_M`%fPQNd%7bjF|(5*|hnWzea-s|Y|b`yrD+tD{KghQ!RZNboLMB{FPnOyg8s zQZiwb0Fo0uV5FR`^F3u@AV}$3>lGWc)QfYzzEkpDcg-(fK4aL=&?eIKEsZm{Sn!k0 z2mF!Q=g&vCB=TO7(EmIpI!0cC@ot5VH%rUgwdIcQ*qu+P7E|ib&`-{|o?Os0QwmeE zG1y^eXOB2GEKG-9^o&|XcRt~Aa>=4!P}em(J3CZ^5uqN@nv$Q^xB0=~As-BH)0>Xo zx&*;2;6s`;-VQ4%>GFbq8Kw#NP)P8(hMs@aM1OVe!8wftQh_pu}#*#e9fh* zkHk=z6!+qd!6}XJ0!1hpqA9PQ^V#?RYyRl}@}E-9FDaeFsclqwfF1AC>6)Gbi^mdh zMxi%HJb3F3W|!9-J$iz2p3)ZdT}Lo5-r3^zy}LAh$Iih%qpeM_nnl|tmz@N{O>btL zUtLmE6-sN-n!Aq0VzFehJ_Nj%>&Tnx&pYige&zQV8WoQZsXw{1AGP3d3eSYun{4O`=7yQXT`(v(-PZ{ch zVm#!Vzx5sV9^8ehU=e!y-VwdW^*ycY=~8R^jz!n9Xj|I86SHyeXxomq@96qo$`q$` zMPeF!xy6X`nyQc3dCyj~C>OZ2p51rf;1B=s-{R)%f`9V={l}a>dP?mg)&)YU4j2hU zjTHHb5_GIlA{YU|houM_L9Bx*oJ^>Mj87S>2uejdR;*Z(KQ9P-4fHpZs;9s~zo6|K z?!Wes|L}kQA9H*AEgpS%&Zj>+qQ9}Iz7iT4V$$%_{jR3Na<0kEMuGkoDLDzs>BbVX zC%Z9XzW3bn{yFO?J(F4!0#e^Az-)c{-}@d&sK1V4n$MV;RZ(D+!8;Gh2d|aXx6d~l zV=}KImH{#4g2$&0PLx|MS-sqi%A{evrJGL@OO|HEPwnZwBRJ1aJ>u4Qi?R=#J$lB? z%QO1f4BD31wcxu{($J%#M6pVifB|FCwx+6TVhGEe|A+)AT5H99vFvY=_LgxD$@k*D zBLtWHDFGclu9F=fq)g>S*~Y}sV|s1!@@@zA6YoXw27QvEqHn{ z<{dA@gxpOphX8*Fe|H@P9uQI8FqJ6qJ7n?zec=uzE_t1#e<1FqQ-bD>^< zN~ZIeh*qBXGCY@rhA6~F`Zj)UTe9q>z`ou^`d%_Z1U5HsPY}9@rl0B3vL)>%oABj( zL?vO-DfbkQ0@}T5#AWQl4$lK2sT5xy+O6J zK|7l>znVynevo?fxhta4O!|gJ^ejTpP1i74%xJxnVn-^{MNday|NdRd%?+x}F{9mW zwh#8%zkQ4Cy*+mK_SoOsXMb;>z0GY7w|6<*-erHh#a21MIvAUZT3IQ7>?5Xk^wSxO ztH}}xZ+d=-pD!pPlu;3S3D^?a0(Difx3`DYhV!#?+O~zlVuk~@Zy&OCcz`V|u5*;i zPzFs&%5E|mT~)mK-n*P%Uokm8hnt1C1e_>7eW@AU+2hOayu-z_BhH?_VBWTZYH1b4 zcu1!r)3#yKE|^D0Q^2A!^uq$bIY4iZvAdhp2Rn>z?Xz*`kj=Zd*tm1Z*8SV;-oMTM z{kt68yTk6CLvG!>%k8^&xN~^O-rgSDd%GO&A964lG3W#S`Uc$x6tEZ=>emi=?`vP> z`0+EIfAWa-W|kuD!FwlTJ!#`hrkSc|np9Xyr{YqPobD|Exe=30;vSu8E-~3qtwf(G zBLXlEt$S4Lh+%=I!zv(EeSPb#xA^8aewk8jar$D;`N<8@8OgDaY2wLLTk?&VCWbOm zQp=S=Q6SM`Y4W6LL=vJ!(9XPb^_jmfY2(_FkrX?V`YHc5o8SI-zeg0QMw?Vq-3N4G z*xcTts%x6AmFiJR0~4ygO5@ArLS((<>H8pPZ3ZL3Q(tHbjX|eBwKQ`m@KQx8^g)^n zxW1=vTMDhXv$?}|HRST>nDgf^Xs##tt^wzWz8ByaRs~B`lBkrD`@;x&-Jq5#emT8M zC3s z@zQ-IWHf`uD$$Zv0x;4_VM4_80o^%#+taoQ{G(|JZHG%~g1RVZbjh>nj30jXh-cFU zPp&4sm|k&oGvWDU!sCleK74t^j~_qcFFyT*pFMrXlk*FXr#DQ|=+P$Q!`n~~=|b|M zBY+zw$dH79(qN647?;{)Mo7%d`XEf>OXbx$L_B@Z{$+&-METelWn2E9*M}fh5%Ep0 z(oV8qkQtduj@}p@AtiO$04B&yc|4 zZtqf-1w2o9B(yy-6=)fjC4-`*G?uz3 z84m|+Z)~tJ9&HnB#d%L@AY;K|y+`4m{z5RWL8)F6=BewT@5`O)DmSJF3{db4crZ&aN)#`ks0?VE^779=`Vux88V&sVk<pnRHdJm-xwz(cfAw2@=c~WO?Tu}^^D71}P;@=k zNP5Sjo1;qbu_t;jHD`TFA3-X;IVBRJ#-qK*x=7)X8s%EymBQ*sp%oMmOBfyQa;6Ku z|M(gIgQsM^_({X;6GRV@m^tp29kTgQc07>sYf06)ISZVY! zre%Vx&LP4enX#{~@(MT8L18cupi>>rIx1aI^qK;L*O3m#n>VNYkG4y`)||2B&)IZm zl-^^b!F7>Yw6wb7(fBt1w6FQJ*kI%u_KL{sF3T~;M@q9vgc}BdxMBUuLe8yt7 zplw?E5GjTuHg@+IZf#=f8b?nb8!6s1i@2+n+4Kfe7&dk`D7T0BN@4?|?`fNk#X{3{ zmiIUA^Jj-|^YiU{c;oQKBcmq^&nw?#>h(0mQ>aoRLL>noCUgI4f7wr`^DKp}&o7ZB z;gNBW&HAg)d=1Ibb11+mOCK%TDXfECYq|L8Kj+W?=s)8x{(t`!hod2?5484xFu0Ra z^2AM8AZeV9h1b6E6*{Xpee#^^7bgtMic%Z8q_J)u?(y*5x7aw?qd~Cmqef^|3@n<4 z-aDGE<>qpNo3)sf?cseg;|Hmwk+X{mYuVb`5^Isx)K!Hwmif($yLav|91O%or(if9 z(kvF32!pc5M#bZgKjqOUpD~+Eg~e!r+_icg)=SN4hzUSc1ZQl9T z*QpM7DYwRirsMHPpYX$f`p+2$Lm9vk&~?e)-P`=qcYcNM|KJB)efErc?xF3Zpip6G z_J-_#<4gSRcYlX}@kjp^Pe1sW>Ffqu7F5H5)UgPj-iwJ@TSL>fpc2|=av5cJq|D!l z(wcfSp!Z2wDk_Fmg-M8jgH&XQ(&9@^H5w9b7F;|%;^fgYsvfMdG}|@zzWr7H{vZ4y z|M>s*|K|D6KIZ29lF&5J_Y_8>Vx&)Xb9-~?m4bja|VSx!9mC>lar|Vn({r})U;Macrw^>}3eDD`9c>d@D z<7!7hRSgH;w9(LUl129s_%(T2%|~`&(*RTTIx7??3CA^m{$k_ z^;=h%q9l-fWif)1AUJJ|4CpMZAg+y~D5z5*oe(0SZKxD{w0Nr%TKx=ID zIM)$EPf-_3YA7!FHS7W{0!h%4cBn$207|8)bqeZB!IPD>RMt|I1-7tkA0BdH3_m_Q zml4r&+-G2>0l#s-uXPHEbxz?M{_4RkfcV{sVvZ{0=PlHdcqOMos~ zffXq=LxQK zM#0xMO1@l0?zU65E{_>qpEF+EFbJOh@*KBV;6p$c6&u?-9NfOkaAQ+~J$)d0N4vP8 znN3+-+|W-uimGJ)?k$G9n?z&jdZ{xppI)MBwUKk zn#~8dxqtT_KmC&*vbeeiU_2gi|K5GR`ORz+@bc)0r;i_V^5hve z7ni8sQ=lXeacjuIn-6&VjW_u7|MmymoL=G=jcE5uNg3go+`ZW^t`gr0!k@&jCoyP2 zr^>1-qhOL^ni6A$B<5xfU&gEC1PNM53>{WSRP-37P%)sj;k$q9ci7)MWO~_i{9?jv z(xNDmxGcU#nKS7cO6FXqS3>6`-oOU|^GOo+aw5sGYi`X~C-Cxqm-BM@Ov1%wj%SVz zX6sk~{qN-sBKXTiLc-EtEEW>5lMc|y^uHnw;zzMoN<2c!4fn}xMI@-OY;o;-Kq4*C zk$_)rk6Icg3M6cB5FLkmJKWycp}U@N`uHi$Bb>KKEyQVQ6XCFP)E^WcC_ zXLG*)>T3D|kV)srKp&yJZqIb!4;gApm^`K_|@PK;{AMo(?*SK^49=Gn^VK5$Xb#cM;;u6z)Y#(6J z(NAaid5dyhSWAq=%*c$!S&iKqb9i{j%csu>U5~PwjqPpjzW$Jf>)6=bVsC4kLTS32 z1+}(p499G3ZLzU2CWOG#CyzNlK0(b|s$P8CDhhsu+1+60;T>-6?D65B{W;9q6nq#d z%YxCy7*klP;ehe>CR=;E>>Tc~d;5^X2Y0yp=4(9s(p$Xt-rGF*@>|?{=S^z}FX>W{oelw$=SSb;+7`M_>MA7bU9TegaFd-cJ>=HmEq?UJ zKcJt?z$fKRfp<>Wyw&K!VhXdg#)^Yj0{5a1=peNKtTD@&A#p*<`D7#^nr347GLm0q z_=KK9M*-kLg7NBlz~A{hzssN=b8)ud?B$eZ?$9JW42f__6Chb96CYYl5|Il;_sIgt zt1UC^WlQ%bH=Z^7%+Oc+$b4H_TSZs^vzZuv2#MjRiKVp`DJleXLg35HUHE!T0aapN z6$WUr#vsAlBDE^3UTM0}Xe+5X%A`U#uk0hgO)1~eQXQ`@EU(|WOX(w%mnTeKp5SLQ zbk{-G5}o+&qu|6QEkF5D5J4m&keg!H1hTPHYcX4wCB_ygEtv=*TPzR@g%m@PD0C45 z3aO}9)l`Eax~@^SWZ(i@KC+=B#x1CgBiewoj-Wy!xkduWC?$o?=q0m9d$f)c7?-Q# zX~|TGDbKhlEM-|zRwcvHn9=SYKR!F-pMLfkXA6%qBa|6|El@>?9gLtHpvnQ-6a)ve zSwrsv8=KpV$JZ20A8zDfNYn^xRJ=K0o(!779r3M|Mv%Desq<{_^~{Kl=-g-v4vrVnKm{s0qcGSZ$!Rm|AtJVipyYgPMmA zU*qiboSVrs2|k8-aFkmc3=Vdv_O{TYnrd^zXls+L;h2r0rtV?>;uL>+O+24sE@!Ak z&wP5r&1A~#YQlUnWpOiOHoajsoie$;=K6ZVWHRCM>WZuDYi5f%i?(6WO0@b-GpFfV zrt=x+Cnxw>LmjmEpBEjpeTpHGj?+p}7_oz*6t1!qyBln8Z*%hGIof$Vpi9GOYm-~| z?ornRrdL-yd-Q~}qhoHaCNwuQ=JOeo>uXMqk2!sLLN{+HT2Il36te=3NPV!w&g=Ks ztOk7YXMc%a2t04_4(~nJ(`zm+FS(dpaXz`?^!kE}n+ccmDc9|s8`m<6J#*z*m`GPB zTx~Feg28ym*6udOYG$(=t}ZW#&PiHv2w0a=3BAKa36V32pBQUs@f3G<*n0Z`TbrA_ z|NS4qtb>?=wFE@QT2auH)sSL`bc)uO^NMB9M6lYRQG~uvY2&2qn#>GIvqQ$DQfe7Q zt#J^0h&_c4XeAj38ra?0Q zd^3u6rco5uP+BP~sg1@~7F`-_VKAxLR7N-d)}=ug8e3XyDF8dRG?ar9Q)qNyD5`?( z(U=FfZZSPM8pJxRBUnecUs)ra;6P&{J9bIrl8&MXDQqTi&GSGEQp4KEh2wbor zh-nisTD1FI0@oN3lvG&|s{&OQn95>ni>V8Snm*9~p0MG2GaqsKp|ni<0gA1I%c^oXE6W5DHB+MiMRp=%7=5 z`CM~84ZvIxE|1wf*p_24G55S*VlMK2)&}izUGfvIX_7I)@X4+#x6SHW(u6t0@b>I`2fA41(Yo zdq?Ox+S!7|WXj@d!tCObixFOdCZ&=}kZ@@WOzI;wswj6i8CNxzPhU{>iOD&se7C!?#o}_x(I=01_R*)@ zyga43xMp^C$<^68SEpxOpIzV&G zZcx(&&BcV-*(HmssUTs7KSwr8(R4-Tnce2G?T*SitLz+i13mhr) zMFvE=l~<;j{8;_JetiC(_mpuJ`J7OYwnidm{44*?_wu7#ZN&UTazP}9Np|?7(aEf$ zNjbYwv@jCWw_1r*RY+5XL0c^hzO>lVVoH(FOlirI3oVIna^DPO7u_t-f>&$HH2 zlwzhgsSt+HFzIHMECSkCRBoz3QBqf9dIA@VDbse!U|3MtNbEXH*E1|CVvKT4qls3d z3}_uODq;;37OXXrwvkW~M<*J%np#Hd=bA%eo1 zlJRJh!j_nza81Yc^#r92o7+2#Hn*vUBTQLi%8K#!Hg5~PiG&W--F`LBLmzw;F;inNV=6tca$dV)Q6R1qyH^+%&W+dZ#?ShHfNal!) zV^Um6L}UA&w{d*a1n&76!}gL=%|$&>5eZkb5&{=II(Tdh6dIIwaz9a_wIwP;AE6Hs zuM((C^aP~xk;^N(P)#+{R8w? z1y#V8nzQndb9KNK117p)W=pw7NJxs=Vzms&$rL2L0ig`b{#i2O<@dFBmKpgg{`+P3 zE?b%y%lDmMV_d%5L~xY63m;+AG^kmFnRn<; z;J2+dRA}m`DU;?&kUsGQDGjR(k%-+MQ|@n3M8)LUF||jSRo^kYp7P22A9DKmIsMfQ zMeiwHWT*@kO57tMVxz+NNQtI&0o$#tv>k!%2e;X}f1CDd%EqFM;}ny(BRp9>j4MvzJXixeEg%IU|NAdj~bNK=(;49mIa=^Pz?8W*tv7a zcxRial~fAsdyKWjV~@5M~(JYCZ;pUqj!=X7l= zF#yei#iCiY^gG7~ESiR3F_h z`SLT~eQ*+0AA4z`?+9Io?>Yzpmup-*hfQDz!3l^&jFGA=+1cG;YkQk|Fa)h>oTqVK zs-)S1Sd>syl*0||a052BX*M=F3W`5{_L85TUvsHS812wtiAsbFV-(tgE~J@KQIv+N zC>T^F!@+>Tu%a52*t)>f7F}sfZLmX2F)Ap>CH3Y2U1~}NLmyG|g@9fp;bkxwFdPh1 zZFVb+O0wmth9m0Hn4+#gD?tx*j&?Rfhrp<+D3W03J4fgQrLI&(s`QtcL}vPF00xod zqhEmweX;ph+AEABy9=`U|8q@>7iD21!wKgceOZ^IRHdYVMrjGC(ZRE$BlnbJIG<3& zo+vV(;NdH=tYi+Rk~tY4vC3f6dD_m=_MV_LSS!$`!4plCG{90Z993AWnNBB!5ZT_{ z=kC4N*xcD?(e*TaN7pqp(+St-=c29Jf_gL{+Q@u*&1^E|X5O*r15H%4Nx%@HN28O* zOw>zeEAEiY#3i69ua|g>Rf}Kvlt<4&n9-+wmvI+~Zl+`MaT2I0V?l_}`fqU+LV^_y zLT~Ur{d`Klm@n(e$EYP=TF8^U|25KVjG?TmRAfsc#H}{q18&~HqNnzXZBwydjyR|` z*wGc^Xc+`e;i0w#DhZEXiC}GvPGC>R=SrQbWG8um&nrqihu0aHp88?EWuhCx}Pe84YS z=z3~2rH|O&qnjSx^c0zg)E~&hdtfC+mm*^!>S{ozfZ@V6&OyVh; zvZyF*Nr;i6tk~M#VK^LdaeYZS8c=SHFdG9HmiR$ITWW5!r>za+`?vVoZ+(Z~`NKcp zxBlS2$9uo}E%xr+K_?jFs3dPc`aqHD4rG3sP3)OPt}hu|MZl`WZy#d{kV$bIn_F8b zW$3#=-}&Sc*DJi1WwAMlWfNweza)AoI=Qgr1pO=Dg;_5JZOCTO)g7nfE>wRu6 z5Yx82F1SG7IiicW)?u~f-rgbY)r6~~W9FCF_{Bn^^ZOPZJVY-=3R1vc3_bzB1e8yK zeBKj+;K&Cj80;}w0Cbk1)+t)5pDfH-g5-*#KpR6y(wj%>yK7@GR#FHBC9g!6HH)aY zY8^M7r^iy(L&~B=dr1^8OvGAHMMM{h!e~lkDT_jUeAZGFa&Bcbwkjy=lBzB!QyXp! zQHA07^qQk*r(9jnafL+YtI}ZVg2Cnnlm$gyo-C17c;k22vz zfJknwY>Zyl8nad5bH}qbsZ}!ZMKqW~G~nJdik`0(j<2XW8d?X%BI(mOHKrea)fuu+UDl*RWQu5W3k*UT?2 znJ+qu@g~*I4n;p>vc86fDPZD=Tv~E^#kp zbSQGvbQ&v3c$9}jEG21sMuAMuU7|_^HHEQ+B~cbe5)oh^X9Vy`ODNKk=z3Cpc_Fw0 z2i*5m2ipv8?b6@OX-}>wx)j(P#iE8!wK3M~WOxDp3K^dwWxFU4CC52bA<(<64(z^m zkJ0TtPG1~x_2L-ad%S{Rq{^PMCItqI3ojbUYRcJ7QL%)vmfZbS>@EqXB>-L_6)&|Q z+$p38kG|niC@S7VKNTa2W@(3 zsYx)aScB%)OUtDr?-D7pR60So6W>azv znHqA<%sZD9E6RT=G5S1*ve`acC^G|JpLBW6@_X8k#EbJDa_NXxN`MPu!jAS)2Bnw| zR)3P_ASYPm_vQPQbvdY_cMjKkLLZ5p)IgU8v0H0B#7+@92yG;GK(C0M!Yu-!jnFG> zEEw3D=4L_Hv_vNwJV9CrJ;8SbC!bl<_kD+NTU^uNng-uAgtj4eg2?CECRM?c?XGF) zn+DhBa|o=Y_X6drt)Z+d>d}yTIK&+i%2F1kKy(%bgTgYX3I>CU;izUfEE&`V^`M|07F44G zT`4f0t-9dBXoLN#rZmtiN3an!uuvORnar0&oL0oLpd1ge;~`XqxEBhIva4W09U`H3 z#Li(nQiQ`RDO{5@L6+KPYD?3;Oe2-{k(L2-k`}(E@vk)Yq}3(nvphZ~rjpyMWB&^+ z2c7x|E*g5T2tHCN%~(f9Zibp&VVn~Ng(fJQU}{rfj{>hXK@~(@6B!U=nX1%@iy(xQ zsu)+yKI(vv4i_9sDaQ4PQ8A(l1-el%_cS+it}f2GIlF{e%cvYM*x4a&4C$1oSzOah zr?{!7pJ}Epa$+14D}_=^@6kcYy#z}LYNe@rc_;a|X!c3#4=ZcPx_rCbFZmr~jMD9E z!j%YO>9|Y+@->&)8n0Rp@-g0r<$Z)y=}`Ng#q|a4Y>JKnQl-S8qz-l#_7rNFwL$_e zF-kP@Jl>48Xe-duXaS^&I>9v~3~BWz%wMB0F|E^5AWQ_m#L#jiQAH^hFl&+v)KFA4x-1Dw0CJ)= z*s7+g2I!!;yt?LecFl1!;mj|%);+Tlnt>(mjHvGHQ{UaA8x{Qc$tOI$KE+p-;r6B= zEJmRmwl6af!GG zZ8T+BP?QqWCQ~Id-y}53uoM8H%xlwlTW9b~vX*FKdW0ph%hrLv>MtZ7Znl3drRBwx zGNVMBUwxOB;(?Y@tw?wXaZJd2F-gDjnavun2vO3sN&*E-pG0;mNWZTry0w59uero6#$bw?q8y^NrRf4!vpH>yP*>=|09#im zW5rBqtfV)V8VXHWSLni`D~qWuMO~&^1D2|^)OA5s6_lkVIM3vK#^m&di>BuyDsBo( zwJ~D2y@?$RFlCJkk+x5G*U__cu+MmF6I+%joq`bSitU2~s-0~X1dcB+=oCT-P~sQU zDJmro@T_63Yvf68UNV`iL8W1k1x=y|j56p~i)jCO{~SFlwF{CEEAJ$k$?~ko?ztu8 zbJVC{upwe%V7E}bXBWKIpA#k*)Yf7#k}V;q=3>Sp3Nca!6oQMbJR$ZXWJbvdQ6!>} zp55v~V1z?DU$mlGh9FSL{eq^QaW%PSI=LZw$9OPgYk!YwJOT}7J||pHIGsC=%Pl?| z?(^|rk7wmJZ4_&T03qd3x5N`(_RF$A)`%QQ`;+&U`)o~EODl8VtMyINouAY0g;2`x z)iu{|fhfd`81T+Z+EUOIzNPGEJo@nuIsNn_;`AD8D>|=HQ1XBWPnK=}c)Z8e? zBZhlBoZeh7%i^j+OW>A@c&iA7Fsoh#sV0|cPtss9N|;olRXSzg2(?dRjg=X8`N*;r zl>~@Hu@mi*ePikq6BT6u8^q79(s5CzOeLitMvAIre0v`?tT}uB5;gCrlo94CDwvS& z$Wrr@>%2wim+|dAh6lS04|b?`Hz{{EDR;&c zTN@PHWAw%VJs!ZYA`DBypupD_S6f_Z=u0iFF!Y7SX+g&A@B@|yFLDeXL+q@Kf`J?$QV$0dm0t%6JDn0@_4iN8~@YqX{}I3CqhnwpG_vL{F&Dok$&^U zQK?~s!DS>nk_k-aPiE!`IZw;PQ%cZhl#;4>N?`5fP{A;ys!BFDH`pEyIeGGw`NgFK z>h&G;9ll$D?})((glb5I8WMK5PG(KP@fLHwbDdNX>YbE|b=|TyeDH#%C+UWw{)AM% zRb@EDguJB_IFGdj)@s^z1}YGZ!D~anqD_sl19VXnike<&&Sp1Ey~C6x!O=8RZe|zEn>k(QDeZur%`NtJb{TArad_HhPMl6r z(;Hrfl1Jm){Cs?yXVo^Bc9Wp21O=(EtP>zw^curYb6`mY^18Hr*-u#jh%8+xkmrmX zv)lw_gT@4Pw&PSrO7nX#)DLM_a?@?E~y+!11#e zlwRsdbkWlj5^~(iM9cD9vc#lMd0zpOU}SXiBMZu#qE98Y$D3nbd-ok~zw)-+PC9UwVr>Z@+T(1f9Gw`n)iS3XXwd-YTn@{ zH#C&p16jqbLf#^w!(lJ~-s=;cXUI6CQv32^Ytw#NJaF!Nhk76Gn+X zDgC!pI9JSG{sLMBtO^iXqHoYDV00ve9<2=z9z5hXfBkn@%st0P*IZr9=^BMrHYqid zb!Dth6=sDFIp+x3dZ6P{f)>6a41e`bW!pMEi%FnQcb?`|n)_?(m+RKHWqX2p`+xsO zF>B|ZKupY825z3((lM!LWHu*lKKr#u`-=p!c8C&2pz@DoF3YqX#nMbCf`NQmqw(G` z7!KLr-{;nFgO9%dLncq3(_df0d`4_;2#YBuc0!XNkn*#VmS-`>Vr+pi5#KlTeM{paT~L6bur-A#uqvX1 zr|=6*J4MYd*y`uJHY)hqgInC&C@K8{TSkgn0wil&iVxgIq7>l5psCA>sub8??>&Qh z!1dJ)pMG@Chd(>!Pfo7+$1jdq+_}g0tpn=qO^m6~s-W*YSC?0~-f?(%$oB58pb2J_ zKU=VS=MH=K?sKgoCtX7~teF>+*kbo|UxXnW; z4@{!;eI~S73zA)AAEi_xyjn_dhLu|>GojT45UE#NBd2x>8!f}q5`D|P((?!Ah`-f* zg1I`U2aM`1sse}(7kd^srp=6QI>XNvd@{VvPxjvC=i~canK2W) zDP@OkFJ)pe2#kyP4q4ae)2C9BcaZx@OV=-%vsP(EV$7sG1&vs6gwe~qG&zNJ$y`=O z(d9XR;UWYs#)zUstBTEjLUHzp|K=b3r#%1ZUovRsXfvb<1B&qhx*XtBzlI3f2=ZZ2 z5Jok7Z@$LvgF9^1BeV-Nvjy#ZP7IOONkF9Qd-^^J_)UjzI$YZc_)`kliwcZNX?;t= znX%5-qPx>r^f|J8%|);zvROC^Q2=F9-n~w9BPLV6H{c5q4y+by-tBkaB5cj^ zFwtXhSmlUrO7v5#b{HM#UBjRn@tyDdI{(rC>_6ejXBT|(^OwAQdQCGGeiEFxER}Lt z8!3tsFtnWnZ^j@QSxN;_QiJeEt+fc;q&SQ;k0LTh^Lin9`E!lYuOE}>UQ>;1;FCe*tO#*SWWMGIv;RBqQi5JwgC!d zsC1-^9_t!xJEiJpY+KK}ceZ)+aEsmAFjPIIi5LR5(CA7-DP*T{y_Z4j??mNh!gskm5=fg#`3zT@ZqjARwg)!BG^N z7(GopqwN+HX27W0rnCbH9j=?xb{(zrT+bJrc0E(AdAj|OpNt;x>EI46HN75!4Jg|Z zRR^-ZpDH~x@RJ3%kP@Zz*bW?Gc=(jqKOJp;c7pqnq7ia4s- z*xzMT)>OtasA|eWfU~@cM58IHlHN(ZaUCKmXK=Vc@0^r;4GteXuJ5Gmch^bj?~JgQ zf)}OwU+Rx_%ho!USL$b-;GK0!Z&Xo8Z`ORh%>`W|&0@j5d-pkb?H;q}`00=SoT`ru zwFRy5QHqDjyG!Rz*A{}GVy}`(SVzE1(6Wi*0ueuc#1|TueDk_2Rwnlpcr3xkA_VAE zIaC1260lk+nFKav6qE_>+Y|-1uFPU z+P(WsZ*KU}U;G8{|BF9mAB&ka;3ehTM=1cL>jH1(If}YsFdPzNq?^p>CNos;D1sFH zipjdDjae!Q>kL2JtX^gKJ(iB>rVws0+GBK}Y3A(i?(^O6{%!u9fBQe;gC9TTlb^rj z?B$$(E@j4INZChpDD6do2$~RbtQj7FP256|LfSghozBU4mV6>*|TE^oIZr{4at$LG>{`rrXJ$p%ebwQj@i0uukpQA&Ii%trS zAo=vcN13d>fbnDmzL)~4K%ryC`WJ?;*YW#P#X6NHfzlFiVu}Q%TMGWZv1Q81H`t;~ z=6-p$K6*OuaNeV%#;Sr+TS{#(F+gmHenIIb?3Ru zHHM$e_*s~g-}xAw%IL0f3DUShun&wDNqC*%%Pul$!}`Ei8joN?j6z@-0!0Ku;BF1S z$1{Fy_5oa-QP&$(#elJ?80i96MCO&JvqAF3qsD}QZ(CGw1m)9sjcAjFMMD%jEk+f@ zpoGK)si$tNMrm-N$Kxo?fINb2j%MC7Z39p0ilgy}C!6>AS#_7^)opaJ z7)q3NMB5N`gYiL-+b~1~7a;d(nyJzqNWZEKAiBoLUuF2R^D9Mo5<|}}68_dl4#6sD=Iq0olH2&k6Q;y?5{l}=Vs%H^gy5g~Y? zA5K7Na>Ge-fr7zCt}7^78zQ z7f+s|dPhkz^&;3OAlXDFir}vj6NpiK)FBHdF%rFBS~#<{OF}0U(TaGor1NP8%G661 zgETP2m6enqBYZ*>Iq6fIGM6Yz)SyO{1+}%*w!qXSYFMBL6=hXYlqIUNn7YIp6J`yMKK_)CKlqUDS^g{4#q@C{Dlew1KR5T%ZQxEa>ma%;>zzn7ITu*TTe zgn`vOmUFF+N%Q#DfBX+334tiYiIIFX!oX!)UJnrgsuT0SX!a}L zK4}8PL@5*!)hNDu`R)3Sjg2vP@80G9);=Hp@ehUJU!N1_6X@qCHwV|y`4$&?AhK9A zgbsN@!*|z*uHz0iFdqMOgZirbW!1>LA-^_G4@3Q zvZmoft`e2vAeQf5q0o}T=~ofrdAz9-GFFDDG-XjxcMT)o zu~Q9Et!FU3=sCBW3kT6!Y~f3}5bYNf=aO?!wsR>EsQiXU^~X7cu)N7g=Zc zC?x`F>Ia9#>x!NBlB0k25Bb@D`JXd8KV@iO-WT|4A3HjvP!{C{(5M4+A;F3&B>%Tf z0I3PcMJdIiZP7(REF>eP3m#iYY1%>?$`o@`6vBW^RiaCq5IsxLXsy8}!C)CP;yuA9 zVIY47k58B#&h_}@r}aV1x_v8H7%`dKb7a5x;#aPOt&L5-^wwKUt|vVH>=7;%i&0Ks zTy+v=y%M3>KMn%mK&E)u;^OIAW z>5N(#!eW7Sf>3CeDY~LiX5l3(t9{>N0u*Qn0%&B7ks!{b2x!E8`!_QD*r7v13{!NN zqqPL>-OMJu_ukj|{ont4eEXZf!=L}jCw%tNDbvfI*j1>IaY;NOcAz?xGWa0=eU#v2 zc;5p~LgA3I@GJj);!W#}eaY-ef`PmPv6rkE{wqvBANRRq)!u*je~wYfgqMk)2t^tQ zt9P0QMczTAr97cydhvOn2;tA@LCcdanSR#pV_F^8O9m!Q&^yO?Jm&7byS%Y~ix0p5 zL#EG;Xs^!*^9ib-gPRljIjw8(u}5jmVzB@eRv8Ly1>i;n33AFN{U8iqKt()02uMW^ z`pbkFpsZ_bAxvEx3BrhIv?(acin6LH%K=qAkhGve6RkoUDJo=*L4}BK9ZlDx3QIAl z(51mEkLni;qC?N84BMVN!vWvAx6LozuDLgk#9Gs7DPU9=l@I_g7K=(5+_d4vi!=V@ z@j2grbi&V08uZ~?uzhz4m)rTCMY~`y98i=cT5Aez!9{%AQ`RNQYL2ficz$+Fy)j~c z|A4){1Ge_}dE-m(vU~3?*E;ao^*N8uFKA3bZweVq) z$-4#;!}m^nq%ooEEY_?hUzFr6VzL0pohU*0 z^ALPYfHUBHM^P$f^C|7koPOSM6*f3G`&%S1+H(|wwx`B_zBK1(LQcC9o3NraNTzif%oN?^hJggmDb^A0hJDOsgRjWv3|oKI_X zJhLA1SWi|P@;FIM!$(j`OKdj^Z=lhhUS*$i8Y>9B@1vOZwF?X|7#AqD#VAeNHFy>2 zT}R;~wX#w$sA+^TSCYZhIVaW&?+MOhP!zVHX&a2ScrDhO(w5Lm48&i@@NIOM*rEI! z!VNmk(aK>hOs5mR{j0ymAN;*Pwf zpWfh_IlgZR!Qq3W_m0kcf`X!|**mz!#`ZSjjSU9F5!Ikh6Vpm%rNUC!lA@?6iYob~ zMB=wavDENYVqAUiaL&>9ImIs(bcvA|9IoqVn+5Hnp=}$S?}!9RXdp_Zs3^}_RwWok zAA*?sl@i1)V=2lZwj9#*iqq3$y2YHqprYE?z}5vJq#`XTzg$d+igwX)aXsT_#}|BX zI$@$}%AGst(YBb;B6M9#Sr*j8f%JEb-~-*fp(+YO^qgN@^8CdM#+w`L?CdbG6*h?5 z;QI8OQX96nw%FO;LIKm+43`9?z^Wu}Oz%A=;;IwzFj|BllhcusxnIgEN2waPCM2*F zLbL9gOw1_&a9t?N15ahEpArD0?qb}6*M z%E4mh)#9hskyKbiOOU5TQ%D}~ax#guooubd7^EOc5R}O11F=td_a2%>%k}hz>7r%Y z!wn_ZqXRBC@AKGh^D#r7nN9p)Q!*!1#40J^5o07oMTinOR_kJn zkP3aQ_K|HWy}vw1v(O_1W<`L6dE~?8{Ob$?p}&1n3peK^5Xdmo;`42MIuwzt{e+vC>$AqTs=+)O5X_R+^o&#$P^ z5@(QH1Xc;ivkxAO5&)qPC9U`sMj+V>nFxm{F$z&ZRo8?dzqK(G))HgH8Y^zH%-qRt znl&`c;AJfM44@#_(`g>!MVk&?pTKTBs&~-!guWN_)(|j0QurwK1zeyEP)+Lh4qzHfQs&3E|9SAL1Q*y72jCtRK_a6M=WVvOj70U+t$At@}` zlrM}~r`Yv8Ut?UQ+X*d^*|Yk8O~_jQpZRW{Y5BO-+!Gh)dN5zWRNwf+?}>zvG%+Q7 zIh%+w@eQPHTJVVjVU_H!5|PV)OY=mOa<{}JzpR-plx%|(xt+9n2sqy-$_;@)QJ37> z-C=rm%HsNprd=$VeB(XQ7HsYxa(MqWb`I~L${I{b)RvIa1(#9vwxqBXMLEEhlACU; z0k*7{zjaZeY>vn;P}YjiFM{_{+urpp-gN}uLFgekLhSKg(zc@S!S|?y@F&)eY!;JB zds-V}VgM>CG5OiG>jEQI~))f^zy6;i0#}b)OC!AlNGnq}%MZxyY4)tJ&)g~3k5r!O6 zx!|fO*xA{lw2Ho)<6TcQdf8tg;nZqUUUPb{T1Tu+`Qu6B=~I9sG1XwmLpPbN@?tH8cC*qa3>AAQQ=>5=;)gGtgL!ONe`MBKRQ#0VqR5YdrCG{-|B^oW(NZM!0sv-Ck1ulK{3d3J(uOQ52 z!6}M)93-Jq0+-~MK|@BXj4Ap&37Jc#k9>-pE<{DCoSh&HB<~ZG0uTbCRYeWgr+o5* ze?q)`iHU(CMxv^*!##o?$^DSVZ2n7m%P7I37X;8X>Y@^TS|fBSXBw5S%bBI#u3*DTI1S)5)nKfPdf za?b4doXPPSlb0u4ADytcnuyPT$-w14g+fL_t6MTIbjs^-VaR-4q6jNzCC<^+eG zpIw?f>$1O=R=0G@OtaIyk>2U6$7N)vgmID>UW^%FNia{8_si@7mf%aWO=7Lmap{S& zz?~VoSRB?}$?JE@`jZn$a{`HZ5W!te8daJLXyh6BIT-}!3ZK5C9wUh2V&6d^skJ1Zy4z2cB zdk=Y!D8KS~U_CgR#NPvE^sT@DJ*C8!uQZT?&T_u}5+EW4Z6vi-a`2Z?_3}OYXSGSq zO0+vBrTV4w$acxK*IGdH|Ij4_zz}8lDJi@I0zM+S-(vRhQPD?@vju%M z;#v>52nCDz6xB}IstYzNiw*rU3fOg#$*ke$pFQX2CljvJkaGVXZ8fH|1)-V3;u>Q> zS&R1()pwY_BX%wAe8$z~8MDO#Tb1nW?^6wi5|coJqYP5)$GINg_vjcI4=Ogt6&lCF zwalH9y5+hcL=hCUS83YGq|sX97L<}8Bfs9ei_X{hEMi)SZXJ$nZ88%*C|y#p*o(Cpfh%@D9AqOHf9KxZQ@ zDcF(%6%=O4@B?0XVf5M&RFBm15*!Hcy`b1R2wlW2I^4X&&0G3KLpNWrXf1u*W1$Z@ z9`5saW1ml|Eq-omo|H8UQxSEEj*`P|qXe%xt#GOGnGa6tiF+|slK6e5BJ1B@X~`HN zEi?ZmcS+Ic36^@9+n>n^iF&P;CGAg}Rt7*3{>2IqQD|{%h$N3Yf5D?a{ioR3xm3;z zk)Q{d!9HFOMJOP-bjan7g>rfVQ76GLlena)$bDvEQJB0=*3oolORI)T=M`qP#?+D) zo12MXBUr#jg$+_%vB;XLj~Ev)y~A`4-8xjlp4amZHSgf2ftv+kI>%3E^eL*mpDj=> z1z)C)%+C~*z|)e3c^1CHn(sa@Dt%o(clyhWJiDTnFY1*6^0{TnH&@K&uWDkNW{EqW z2bfA$W3j3POpqcvDoVCQUayyEfpKkcCM$3D-6!TA5FdVK_FuU3bl-UtD6+ti&O`o^ z-@gb%Ix~IcfQA?rBCG%q@S&lq3%>f5Z}H}vUtx0Lc=qU$b|%_8NRccbyu>^t&0d&& zx|b!x&(_J+-A81;+VVN--dKtH zwQ?VVoF|Ok7A0j_QPvezU1Q6VvP?lfR-QrY1gjds`9S9+8s7ym#f1=(H9*k+g7=~& zMbKJHE^iDNEfBlWccM{6DJbHa1*HNTJ&W0dtJw|F77WH)C{=(eiC%Nn2A*Cv{NUr~ zJf17u=56fOK8s%RWBb{J=H`mlIg~B&Q4w5E-!$CJW?Wxi)Al{ZaKPs7E?YZ0N$6We zdy{;8&U-r7OA9^q#)x`6Bt}EK=jR1QyFeK=g)%tb6HLJCAj~Gy4X;pM5gbwv!UcTW6I+K_IP|oo zpR_EdJ+pb_A{b6h#fy5Aqs=`YjW>8Qs(4lwoM^*k)HKSXqQPJi+^h#YUPxJPdWDXP%n>b zjkqJ!8gp4^#0pZm)?|@L7M7K{cGX3Sq|vYcUTgWk+mw(Cg{o>_| zNB!$8ulB=|^QZn$BKV@vsz=3^5L$==$E$Uu@8@i7Zt&Hwe2drazr*F(oTI0gvP6>9{NaNP0)H+|O1O+6ZKA zRA8*3E(+?xa(;Ts)%6v|8eV_>b-w%E-+~Z0J3i+8^n`9Pm&p@lk{G3yxzd^0Yh%Pr zp8#}B%CWaL<&!3VzA*VpqI#=x>E|zsDh2S_Wi)sI`o2&2?E>Swln@gWbG@VOTKdij zqc<8A16{ko_bsJWMBlTxnQ(J?&h-2Q6FlX3L{|npfo#sd+Zz>FxVIqQU-?7 z;{IKKi_;5=qQu8Y=N-L@6jed+DL^F=K#5#U z!cWu`sWx_Dq;#er^W}+?xr?}tA_7fmjlv>~p0=e5k%3lJ3QX_}ddHr&go|s=pS|Gv zrKKufXnV$Gg-rqy7JBXJR4=Zt#OPJ8p;LGl=zEFS z4qcC%&Ea~1y=w3?&tew2T0~yzlH>6fN4xucFsS+Yu;O`Da9Ua>wxm%7K^0<62#63! zAmZ^zWPS`{YSvL=PZdm|sNhfrq7DQV1Op)VW%j)zh=LMtlbFI9PC+IPtZC+P zsR;|3UJOz~v@A-jwQ^Vru9hMra?Hx&nj)Js$xN4!&vccw@1k)?v8#$mm`yqTe+|PY zo%gTb<6nKr_x@Kr@n5|}mdx$dCHKI;nI)f1!7B_ukCNQSTJ_0?-=cyjj9Nu*rkA|= z#v6R?tG~k5<{?i$JLdG|1lLJ_XU4kvpCquYTqJi8i8`CAy%UD)miuOA zzB*^@ofI-izeATl1@_Rlz0_dtdR*H}#iza(q&z3bbxnhJJw<7G@bCfm@86?u8jfGQ z;Ogv*zFDASNB|!xe>ItcmwDd_^Iw@%1~q}{$oC`+h~0VFl$P`yZ6qK~XVZU1+bb)I zs-~)Is;Z=_%0x5;^-N6rV&3;o1R&9%d1BvT_+lLka2Aqk6m~|)8o3HwrS~_1%1;H<{j~-rJwg)dd*oe;KkN1pY0s*^U)5E z%qBPS)y-HaEDn;x|dg(HVYGoLa z?<*Q0Z!_(qm5_wY@Cz##@i9c4^Ripg>NB0xS`Z8~@?i)W;a=WRNI_A7DA^86Porqo zgXrIv_>+j_=iBn|SNbu}j9;|mJ%p8f{%>^;d4S6^WEY8!Ifydt7nLYeF%k9UeXQ~3UHT?LjXls3LxV~d zVntv!yXLE3{VMOh`whxsgU6q~?MG7`9_zwoL^AF;aD4MWX8OH+sPud+`il| z?HJ{EZtI82uOt-Y8UcCD(xM=A!3@9j_r51pQd(0lr>rS&a$9^B>ry?Yp?c=YKf zTwk2ynuh3lRPxOvJ9yNNa7-@^%O2pS2Y`(8}!~W zcY>826`)h_N+xI_`F3-_Sn?SQsELdv9dnSU%%-R#QAad^*tLwU<#0ISpsXqTp4rI> z^RqLW={4Q#27i6c&CyHTWV&SZF`4LMkYK>5tz>$HfYU~T2s;7r7#fS|9kK6Gt|JDI z^F6-rFms2Q2`+onwlr;vYg>HNp%xB3_uws;gE2>&n|!jl%TLDJ{B*F*OSQ{{1FnlP z)2gB|2JH(9S73XMX(Of=pKeqV9OzA?*YaDUrKK;4Vwm<(%=yH0+!~Sig@ibYNnWi7 zaxJx)#O!;Y(*2e$>gD;CdENsQ8i5nPw2SswT5l7)cP z|M?87bs$W6{krQdO6SNNSgsd=bM-z~+q3NkQYJ+z_xwf8KGilzrxD3|{TbF-!>h}` zG@o2Q-Cwb+^}=%b;`zU@;;&h9AN|eCzsy-*Ig^mI<$I9c&bmcUjPu0sMF@z|(RB-c z<(Gejx8D2;-dP@hdc@?ifl$1{%$M(C85^?R4>F0C^K)%k($%zcX4dO_$VALXrgOdW z|LWK3bG047jK1{uzDG7kMY*6NeU~qCRF-1aL|~Opra%~F`jq=lQj{E&4p`0{k$lK= zM56a22_7$<>#%RDBufIm6HK#{MynOnUc6Nh}0h}ZBy=Z_5qF0del6J3k zO3h1*eW}$aY;Yx638LXCUVD($`s5nO%->o=QAogHQ4T2UnyMa94~A6r09!~I z+=#+CFFCTwROww$GoPViq-_>xB6kjN@k?L(GLIfT;n~qknngodC`g4+TOXM$dM@S; zJJ_TiZ4gzU?_2P5a0@O@p0iPwyz}rr4_|+S4?g{j#s|j3F{9BYK12cvWi1#Z#4idF zTulUduh}mQNnMP>>)77grW#a)7+7?z3fgs9Dd>G+nz<|SoDs@1*TDRr3y~%h?m11 zo^Rjc(e`Z~jrMtLH+i9lT-za?sc5aCF+uYDJycFpI*kokvxkstkS7Kj2?=2>Vtk6+ zPrh=35}f#$Dn;i0%~LJ+d46@t=P39FuLj*^q0~7kFeQ9C5u&&Xc*~MN3{rnx{NY(L z5Y1fl`c-;XjDlcLG&jtSp78Yjza&hrsDMBLrluT@MF>|BgF_>TlH!LK;n*aGFIQU` zN|#NgS{%`v_DSGCE%W?7!=Z&>~%PM3Gd{S@ObI%vHU{`w|IulM?2-Tr0H z3@hu5ybqzheBl}$F$lvqND;G;+>*cX>%YOhyKgg_I-Wc_W;W^3tQdY~&@q|dV>b0? z&3)zbNnM{=@#lZ7#=}Z@Umqi@^~<%d!~~@6OTSTmIE5L#^LM{TM5ayhnacLniDloF zY1|mefnL9b+^HlJf=KkTVM#CYnPU`^kkd+(Oj0om3Z}mJy*=JL6tKBD=4)SlkIm7L z<7dx#^2sN}w#7FM%JnGkunMZGAja^D8DFVn%3o^nNh(gvUA{|hUUzjBq2&k^*yv|GYsHRDQdp+G^4k56+ zv(2x3`&YTVyyVemk2rn#g0iqF9Wg>NAe18(UeUBYRas&T1mDojujv-oynObUp@#Qf zd&t+n@lDQWbIzwToQr5>>0P9#2Pj)4$j^we!r+J^-D)yceln@*D1<#k3YMD#hKc zZT6}frZcXdJ?HG{Q*_%&?!5+_LwiqcEN!!(b3Gy9J?JP^%y0qKN6D{Onx^gKW!ntFTPbwY`$!u#Q#;_Y+~DQLF2}cDlAEU=@$6?m#cksE1=o<5dx(gyE~00H=~QOeduvkQsMUjx#w-^dzd! zGk9U_vR*!OBP%TM3i;1OASOniY1rqtFX_Qr)8bQ1WFw^)s_bu1>y=t!2}G7MLSiB- zMjvvZ;OCZK#N2<;y3a2$6YbC4^B3FakNm}p?6&5DAian$^wqz7OK15T7e#vUf6emB zxn42puU%0^l#YriYJ2%;@dE`#pKDNyxoDF&I6ryG@zZB4CKKp7bnxilv6AjD0zxXpLuU3`wD%m0CQT-x2w6aSIl(zL z#v{J-?QcU2eEiXeeDu)=1R_pp8V`LmI8~ucLAzK$=;^vS&0lB%vUy&l?Jg-VEDwVV~AJ9=u^Ga*9)wtkk znmNHc27>{c8=FL6wrKDX@!4yWw8~^vGEy5{MxIpgmhMb{(G#7+_&^l{V-yF25$)*( z*Uw+DIKRL+PoW_8J-%&;-eHwU=P^b)*U`BSMU-z)XVM{`Urt1XZt0hrp1u!dXw|f4yWT?jz+tDNXe6GldIu2v(YwvJtPz* zSVJfjz7&RKg2Fn<>DE34b;cl==SDRAsAR^g7_nYac+g%_-DHlhld|6t^6^1`O<>tvpy!h~a zs^BRjcr41+42HwR?4?YpQ7&cOhzn4PMu}fPkoqSJ7jiR8nv)4*ULtvJ=ch@N9hH8` znlCPC?Q-6)DG5oqNWH#ns}4`|WjUVn?{$EgHA0`5k^B~>5kBWid*#mZ!~PBH)|a^C z_I%-d|6P|ap6#zbuh9DRV~z3tqGk1l{^};<_pfiSo-`e>jA2>5e@%~y4a63sgb#Vw zGaT0Z=5PEqTbs8yIiB+3*%@6Eu&NZrB)L4-1+^8!UyZ>pF6mw%jg>rl@-gc|fV6z> z)$b%ckePlu@^k+C7$Ro;&L4a)cN%HHXA@$Gf^T1x1!YxI*5wjA+LlGCAFc@r>QJc! z!jlG^R%-}GxkX+H1XGBK(HLO_#01t5A$mulHMjTo`O4dGv$(qA{KXMB7Z>>XT#8G0 zFTVSnrlZ9@fY#!xPdDlxZA95Ml0cB=f&0KGs$zaorcO)6hD)`S5O1fo)s zrk6DQSDLaYll}gsMD^DL>cN1zt{IQVQtTly*SakE)nEP=qq^kd&pzS(58r3u9F2!X z4_z1VUQ+w4mU4_uJEv*ILNFSPB)8dncDFY8`Y-=7)#etTJbKJ@ItNwY0w`1BV;W#d z_|ZzVJ@F@M>6IAq-T@w^g7it=Zp2^f5jfcpJX&dnbn8SU|; z-r|L>xGHM8vI1k!DiD1~a4j)9@p0=k7Xpy5*FBz~rF^Pa5lJ9S49J5CA|RNA%9uy0 zBZ`k4F|iBN%`=`A15Qn4Q~!!y$h=PkVafEBzzqlQhzTiD1Hm}~qES*-XldyQQl^)n zP{E*r1}CYDl9p$29tv%Umq%QF`aUP0eayHpR9X?W6c-_SbnNl{9347T=<$73dGWOA^mAGCvBD&+ds84fqAik|@iv?Ao+3er_MpuyS1m z5lEzyl2DR!2!BC~Drxpn5-~HwXPq}>`ni5zOFEX9^?{I?fypR75OGL)CoIc9+mcl}ERng(y4OR=9XGmBo_wV25 z+u!~UrQPD_`4uNemqaHP%N4^-S6O4aAVIF{$d4o;PVPf^o)7-j=Z)zHz_~qIN09d%?A(I-`wQIXP+@WJ)^t1A$A=$Cgi4& zplcJ#p9I&5xjjePi|JmPNsK^@5=qWi>G|_`OZSx*8J}sOuJ4%#uhv9mh+0aNikWcT zY`9|nN?WweAV1>w9}ETp$dml1r8Ru#Ti@hxcZ+8)pYh3)Pw>W~${|5lgkbPqqgA9V zz-Wikk)qIyhhz434zSA7w{wPd!Mk7kD!1=H;Ik)BIKQ~2cM#BMTM?9K_OHyt;6+4J zLez!f_r&NiX|kwvf-n^kbFYq2Ys+{zW-u7gcDa4lWCAi4y-+IRAq%V9@p#2%uo z&p<`%%szLB%-Z!&5dgCY_4#@KYIi2`s^mYBPuFO`I`vSIh?DA^q=3uRNbgGm9OLr) zlHq5pi1dFX=2x{wG1u=j-{CJ_*0;#53!__G^RKlt9@SWx8-s9 z%jX#9zxEP^!6p(eE7E+(d`HEW80J_bbr^z^RPuMf^d-Lj^>3iUkQdJ`IX%8YMGMh< z?l$u%Nh=e7iK`sfbX~cyyj!7FvVYnq%DGfx__Dw7=ggZ|m(AbOxzcx~6-8mif}Vij z%;^75+n+y6mSp*T*vH-P65HEf=F7D*Ys;$Y?&|5Do~3)bXL|OTo_#>dxXHMfD4J0+ zijs+vQ4(bu{SW$)H2okM2oeT>5C*`21VIuc2w*Uc?pb=PuBxu8tX$syUaWU>cl~gV z--xUkP@n`wT4cnFxDj!$FXwxf?>XnSU-})RCz&ksbkfEcX=kWlAEKx2TAH@*K|ga2 z=d?v?&>u1qKaW;>K7aC_ZQOHt>`WkL22(hqgVr|`gMtSyKj8M=TU?%rPU=q1Nnv^xzgD8o2Sh_1yR_&>RS)(d)bkH|st8HpLHnG9<6 z%a9ly}P$KnO^hw^a3;3qTD{j4JK0T$QY>- zS2&7NSp0*@9^;(@##?&?49ocp3p{-JW!`w}5g$K!!tu#Di&dw60tzrrV)MeH(_Hr` zJYgdXI>x9CEIPHKRAVw$KrAitwBVv>t}z-8_YNqs4DUU4TZ>|#3~n^T!=mIf&3h#V zobM=NV9PoViveRFS)QCxonPP=3w%@e4E(ftM7E2^po@`c#0!!eL+o1W#S$AM&N{G$ z)_20uFj89}7{p^01FiS8KG23p)fvub4Nn&xC*?M?-9x66UCvy=EGww3qtmdDb+Rw4 zkzD$=^>l3@1Vh9TO)g#q?=im9N^9zAkR>UWcuHebMOj8zT7xD}fSmIhfb9#x>@+3) zhamyJVqmgzHjfkBiNvlYGcYVm#={Y1UaV70gLY{P5Y_YHqs40{KaV{3#;F1<>tSF# ztEcaA@!p?MUtciHGwCiCWl1?3iCs--S6aJ6Qi6Tg5xb6{wJV4Xp<5BU6?7HRSJ2hq zYfNbM-e6;g2^}`H*eG`wJ8bO8(6B)w25KRmwUUr5{|FoJCk4UCuGiSF-c^Z611w{i zh>`32njaxkkoLMvHlKlIrj;?e7G(bO4F zKDyxSbc&5qRdjvZaIJ%EBy?ZNy8_5YJke3TxgkcuuB0p^SG;ak!;5r?^nEY>p4`)K z02D>eWHQDYOWU+`zQc`Q{Y7!<>lYYVC9)u_AulrWvH&fjvZ_}^BW)KUN}uUGmq}Ht zKXW-*nPUcWcV&Sq3T!FQZCT(31$J0q^f49=TV}XHjx8+S1nxb!$Ag#egEhSO-S4nE zKgX|ZQoi|0k(I^iw0$MRAn5}rtOEMpTNz9sY9fX@=mlO z+(49z^lkKnp`_8SGXbJ5!Yt2-MCztyu~-t?iqE|93XfiW$W_(y!RaN988F;Aq!?{8 z84lPUmW+o5<6%iz4lsof`N*VsP#0h^y(YE|ckbNghkxX=oSmKX@zWD7ua{)ykZ2si zSd22NiGDq<+8HiJ3A?myL-5i;O2#%*rn4+IgDQG@d@ANN84S5~a08b)7ON$V?+DJ& z#GqjwL$j)|#*k+YXTW%m>sqq5%{0BX;Lng?Y6)jGNP4CI24_czu3pb|7rP3x5>bjw6wHknR7?)#QK`RiW#Cpk~$k$3D5l0|*sWV_w(nYbiMwC)(0?v9uy9B=i zUqe^Pqpyhy{89flq1E>qZD`eCe2a-K)=NJOq8CNetN~xZU4GXZo!1`h<+v0MAjsZH z#f2bon8cSPfUS>z=3V(KssxC)Yx6T{6{ta_q9n;Ld2drfv3@Rt+usBa^i!LMfASXT z4Zr_SxBmB4e@sfawNmBO*d!186Zj|I{%MZ+|MvDG;Oi(DBl8^th8klk42^`&l*s<& zpZE&*?ml34-SPOt3$8B~Seqd#`Wj>fu-Ebk)P3LMfsAJgg@+*WE6bd=&D{iT-Mc!i zQNL?*L(A{2kL_i#F^tD!wzs!2#!xp6!3XR*ex)Bwf}sDP41V;1u5D==DHgM?5#Nc6 zPr*LVa>_z#(Pu@0E44_?#$#SewYt14$Ok#D$S8*;+&tj5*I&Uo%SRu5 zz~#jmv1@TLlB*C;RrTm6QfIO!=4}$}P^&xPa{_xA%(PWx8^{Z34AA*Y>!cqWon-my z^xORp==0>CmcPZlFXF^Utt}L!JFsy%HZQ^DR87m(^))_viopn1PN=#_7v=NLS&G6^ z6u>i*r>7l4$F z^uEJ)()LmsMQBfe#OgPqF9+{ws*2V0n)8o8X7>CU2ZNGF_wF*(^0y{PcQB_QXJde_ z#RX3p19|7UwYAMCM4F3B7RM)av$=Ho3$j7kNZs_xE>C+xEYLvPw6sk}krf>7?lT#V z30m>6i=NH|Iv41Sx={^uA<}k%Hdxx2v4}bIVnVfZgJ$QD#b}FpR#LkHZ!;jnMN9PH zyGZAuixzJ)OkUu!0eLo{uq6dKS#&z_Qj5X_Z6B-cL{sewB{!%w5T%QBSoa%1Yg$NJ zo*u6XgFIh{kdp-;^|R6IV}D=Q-ylfXBYIE0TrrvV&l3L zak`6UhjJpMH^F)>=mJm1j=FkH$^zKjyQ(nua&3b@^-sL%cPBOMpZ3;+-3u>DEIDdM z&YGzBXWt_F`~UyAsdGd2!Hd5kBN9p69;4~q&RUTh2M2&Z;#E=ixx68t4x808)gz!PffixXG2NK2q!`TSbFQu~nayT2jd)hw z_?4euTljIU&83ezXEjcbM3j`oV2$l-%^PFHWuX0!#j1#OK}w_=@B6BG=`naO@sZ9; zHM1bC6Jy(8z30tWUg2PCi|N@JCm%f~E|%D)!FsWX(uD$8XT^o;1mu%dzjo>Cau;OA zsJ7Hwg&Y4F9S6DV%Q4}&fc9E{*i|nLfMuC~@-`qZHq?qKlHEWRexLsqCr6k=9^S*Z8i+;B~BJJQ5L7G8rVVIbA12sTm#v zuE-dThm6J}F0L*KK43h=V92cW7065^4}qb9!@-clvZOvcXMTK4eRTz`v>uK@toxwM z)+7W)F_SCkq7Va3h{R67EVr2`Bq2zl9q(z01gq&$MqIX0I|HUY(HTQy45Pz+1~(6J zJ6nXjz$+BlnBih3hF(NMIM(5+ex4aT7aHDx#co44rhf^bPoi*wsYesFy%GV#Y50Ev>I(kYi2gFzVYd z(c|#)`zb7=#)(Cmd5O)xeza-bMpfG4`m@PnB^sL$08N^>-k#HSl0<$FW@%K`cac{c zR_=PK$gTIbtZ%)H`yaTaHPo+R5wbnFM$`gLYflxE&71sg`d_~5pVcjmlbl<+Y&l!; zpF|~wRzQWb9Tw^OIT#H2*`NMd2IZL3=L?=cow8as!Ug-}kMyvcenaGk?8Eeq0=LQ* zW1!PMA88KLkf-b@`CbVxY|e+^nEY5;4QUN{?`fJwJhMU4lHKH$pX&i%)`^Tp(i)7W zm*JDsa@|z-2Rh`%OG*;7ban2ai*8k z^Yo#9BG$_#y(su*)Fr3_$j}4693}uM6S`I$G+h^i#K{+nIjhAL5ANRN?azLSnt~6W zp7Z?dl5#we7Q-skq&9s)q`;eu&SqNW%#%Bas}=2Rj`1}=`onLtyFKRl=@lP6JHwMn zjMZj11^kp#Ekf545mzoiRaf}7!o&{iBnED+kRUBhjT|?mvBMVzu#z9$P<_qS}k6E3c6IUy86GcIcsb`&Th=|5UxoB00Iq$zrb7 zeUuosHFQ>T!BK_CMuY1hwqEv&TH(o^ufrxA*K7#iD8S%?K6(XvAIbE((kEZI=>j(N z7_n9YBC?P4M@0EtA8%C&kTF<8s~n+1oS?NCJcb5BP4p{Fs3^0Jt&wAYtK|01kXH|P zxwkW9FZYa$bcZYkL$Y#!bE5Eyb!7-X(gtWd=}Tehh`yF0Oj>c#q*B`A4Da`Z0KU59 z39`2P*Mwo9KDKq9KcOf5*`5Q?LJ)ArH+?JY=xf3YN`We&8ZwAoOYFQ_@ksSg^+*Z0 zYZgh`DXQeW0Qh}4C*5U%q|sj^_Ii#tRt{_FwEl*4e*wThv1I!7wsAB4fByqFU0Z8e zs4s6S5E1#JPs-!|cV)Bbvizq~H2z25^xO>k8~s1c{)jc!)Ho|Gt}T|m-F?3L)t`Zw z@%-tWljjSnRg1F@(~oz51#;^zLbwfyWuM;ky3W_Je7|P%tCC=>QTF~CLz0ppdvfzP zWjFSZM)(tLCp|=*6T{a{UjDh?NgE#0LJ}}cUy+DNRy*e9nWW?yBW+&Wx}~X`bxB?? z)>Dk?9!x%Kt!hSJt~XifQ7nnJVN@2p{_;a^9~^M}@nbHYKc`(Rh-%q|=!qsV^2MT* zn%+_j2#{`gMhow#g}+|!>*4uRH`!|n_^J@3MH)BuOd2NHJ}_uN$llIAt7T1Hw{+1+lbFyk%nUnu z!M4qCtBUEf=QNj>_|+1+7GvoP>7+SK(_-1E4#dXKS=EGx*2lTbjE z(!Q|~VeNb%(_Y=uuqNV%14ei6GrIQ@X0lC>WQMj`(uJa1`GoROOUVzDa_^dScI45YhniJ>KSjVb{xp_4RB zg4AS>zLLjKX&1Jd7%O6||LVLFVF`0gf}rWLaWe|_wyd~MPH>D$Ja zq}!h%64$r?!8g|<+Aakjx3 zF-Ryrii+oD%H>D>lAV0OSRXNqE|it9bl8Kui?=scj=YsTOv4}Z4L!(UHCI;sAviD^2lAO;Zr^Y-qH4d8v7Vywty_1EpGKOtIiJu=@5V#z(#$TCcXs3fpJ zMiZbjmZ+}JGK&m;R=LH_SBr0IxtBOb6Q^Ox#U$WoGv2u4z~VpN4OL@BE)Ius~xyfx5T0e<;- zvXW$N34m`1rA@Hcbu44Hk(Q_H+(-I$$?La7@o>?T5g6bxs~H1dv!BC*-63z^KjJ6e ze8^9{^)g?0`G7ZXjJdm&b1;Ja3EVo^=B3-Wxckye+<)aYUViNnZ#;U$r{8*uPrdaS zUVZfu4<5YA{fDn}_oY|4ed{I%ds{TsjH<0@y^LSxN+6S-0;!php8IA6y(AXa=$t@^7HmaOHGT+)UoGZ_|}a<7+f8~2U3K!#xxp#I0+^jCW(e)^^)1RH1=@u&uax~PF0N>gU-+G3{kVlW+;PapRVXm(hJpK5J z%ku{Bd$sbb|$e^dRk=6C%8lS+hK2vNge4OV>%aSdcO3L0vs3QhGco<_Vb- z;LDFD%xc@zsa5z^#3+E@3xl+1Y-)^=vQqwR9r{&?c}~n zuBsO%*Q65+bY08-?lvz!xX;bKJ$~@c_n4la)2^1#wpe8zMYUy&x-5+TVN%f_r&aY* zIWS{-OS50nCM~GVjgY`y9}|fwt|zwtt#R zr&=vpTwky~$oazO-e$PH&GWNUKKSrMihLj>Jsgl>vVxci;3lR|7Cg?kIJMTBre;37 zOlK7Pjayuy`Z+64GExkzQ60x3;M6uoM-q^%d&(2%QzFJ**<2LP%4 zt*#p#1DA^>9hAc%b?c>GfXi~)&eN^tOq}6pYeHVv%%7dGJU@d~h3%w-tM{GQ^;UDB zqY%^*0Zpb@$2mko+hC2sJE*iqyfaq9p{=;=Z6=`!V<9u*#+Gi5V)@6iWOTUC?t@q9 zwhx$^f;NIN8OCK=x>e>c@lc%iWU@ywalMXWh}bSjRXt5z3&!;!9o;Y@+_lqSOmSdM zxwAo5lz>{Y@MVJw=%|25z}>Iue)Y@vB#G2NSE11#;zZd)`>ShB1V_My7T2zD?UF&L zxwk*&t(T7Y(YIdVi=Td-&%buSgM%T5rD0-V43t*MgUMBG0OMFS9aYmp2sk4Z54X4W z7*BRMxN(a+_wIA|&Ji~ccUi6GG;O2fZCI^Znx>;}I-0hnX*-&>lfDefJqS_c1PVM! zRwVsCDFiPt?St>j6mO^y7!XB1@kKP8)HC{fWj|#S1e^;v8?jcD24@1sdaUsp2I=V9 z3g6X)pdo_(QNjp>h8QG8QHo26@=NUGJE9iEiW>!pdd`BLr-m&y@4cKt)~SlFUS_4| zM&;Iv|6VZLWbdn?1?wfaRy@>o9fi3shlp!B2@83;K8t^v+dth=deiSVdc8#Tuo5wJ z>S?L4rokFd>>`u#HgCQ88Qy&KY0gfjJp1^X>#I)WuZ~&2w)$`10OMr*W|=~O0RCt+ zQe2IcWy${jJ~0NGwxR1fK-O&^zShqMC8;MxK*ld^+BMjVya|-0R05P3zQK(i{`Bvp zkLWq~AJnzJzI%y-hAt3WanoxZi5GK-^|JeTl@hx^wHy^xUM-VApeQmPKDf{QySJHN zU-A6o$JEO?U9}>%4bDpCJrjjJ>@b`0ysbbcG-q!LjCn~_;k zA&{~d(r07;MQNeyx38ZkX1=oWMW}q@8&t>}BXOIgpm^_DRu#+H6fs-iPGHh-h*`pWkeW;-!?09DEH6Y!0s z$N6eStd^AZiW_A?Hea$lJ!5fxj$f|&3VJ^EcQ;BR4D`9pGWv4GGL=!vmKZI35(3r- zvJPA)>}VgQLS1Wu049;#Wt6VK*i5psT|s_u$kx3F43F-zawVcAi`R_vzXjsb8v+vFC8{FYXn9V8XK)JwblI}5x2UWNNOmf0zY;= zuR->JQDsoqUW^)!kq}4-M6zQU`ozQKcsFLUqyOWeD6kE7eS*xB8cz7>-(Sy2f4nMmh7 zO(P0Ht4e{i^m`E``N)P8=JGoHAvM3I|wa~4ihVEs4yuDLHQEKufSKtZb|ej@GFe3Frk*(1IXu{S=Sxt4YL?^ zE$Es^x+h75>iUiAG{HWE($^ADshXCqUS$Hpv|4+akW{F&MmL}9_s1tKKV_ImSrSHms@@ZP%(5ub+;hrmul~{VSlJW&Q3Kj?u8ONo!K& zMGyGsiO7lRN$Pk>Y&7NhuJe7RlAc=hs`ClxrzN4*i81}=3nmhsmEPVak`)#Iv9Wx?m){tSchkdxEr zy!YY9xZy6HEwE7tOe8G9^&1&uqzasG>6TM$wV)^qVxAK+spPZ{pXhieiy#^$7dvc} zEKuJGL9B6njH+y#U;y&3!24TO6F=A%7~r{B2*G4%A<^VG_t{>h7zLb z2y_@9$y;eUV>K(FBT}146TLL3iIEITX)=r}iTMCK-eGv_4uhjRbb~D_%`ac?Fi`|E zD@|dH0)EO;k@aPCoeKK0-RuN;*ejI02Cgsy2hJ2~fj-~Ar%zWW{@KY7l{`6U-u*IZuBIXl1Pd37bV!D`#_~Ze@h^5O~h)i5UYJa)}e$A(8ufE zY{^W6iz{5LaG}D+8mkI`WJFY$P+?=EWr=G{kXi)dDcJbids!I4^m5Ot)??C|=#^@b z>`AJNdMjfmuS@85y)xzElV!gif%WsWjFZ|UZ>8s{ieb8^!Cb#5@2|l=5nR=-e&H@Z znZ9hTI7?p!Y0_knj1ppvH67N1ZvzJhH~7+z|1?|UBc49K;`sTL)k28I=@(Kz3z3`2 zkERB5+FY!Occ7dhwbn!MG<8MO37cMI$J*O0zp)1Y7gm&heFFOaxAjrLUc5OFF^6CM zzv>wGE4J6l(u$S$l7{q&!Ds#c<|G@W_=tS11LN>Ov=*CZv{CY%N8=%@YRM0M_H7>A zyMu2kK6>vR&YwQPv^B0Y{9|q{WLh zNRV7i@7Ey$q%8y4B~wcM?W1hOTS5y1e52qj%V5 z$^Yu#{8xG7?a%Yh2OsmF{f)nk8EoO*5N{m8N^8d8g$F>8!XLuVP#3p>>+2~`-~BfC zc5?pRf9qf8=G{Ad{SUv%U;nRuAG`a2ijfEr(|}ezGgzWGayQbhwXPPdPM^T+g5lN{ z49CR5kSs6AGKuBOU0wZZDW$QH@k?tY(seCWT~XB)_`sc`+xWJluBEN6QBtEY#W$9E zL^gJ>xvs}_tp#`L`t+D!vEE5_GbG;I+CXapLCc>KJcT!u9#N)Tftzeo+_^X`TfbW$nwp)GD}ukpd`A_!V8-;*7yrRpfgw916G{v<*cJ46I>PI`+1P z+&S3hmHS6LxV6LKHcSdAB#KV6Z0VXt>Kjxw@4xo}-}vSqa(a4>wK>D#5Qq#01FWX; zwr#`KWQ(#Wsa7kRRmE^PlyDJ-;c&=!JR;9BI^XqGJ&iVb60)wP>pCeL>cq|3wyltf z+m^**LEQ+?Xf~TMy`HjKEvZ%&)9E#f#geM7XzH4#swCT}UB^+|w(VW3AxOUv=`o^Y zVGYB@xXv2Vl_;PfOI==5p^eJS)J;!{yU6F{<0<7)6$y;YuX=7sASt3te^1@xMyq4$ zdufYAkvJ*~gtmF^UDfj6)Duen-wrZn6&3Ej?cY6E7Z< zt{ud4W##dcw={<97yi@}xow_`5|CvFMJ;sYCCow#aY^)ZVpx&c7H0#oGdz0jP5zC4 z?SIME=r-T{`n$aIohMvgG?KEXU@EdG&8=GVFTAedlV13z^Gqql63h3RW{n6q(9g?b zI(9>Gh>?g)aC(2e*ft39`h5{FhhP02T~!L0{leP>^R!6Pq$kZve>p7>ea)z)XA{_J z4fz1tdtK_UM8Hw-M>Z1NBC?=Fj)`yzUy?X zB~~XEzI?YahWTQ_@ejVspqcUS{#*YVuYc-IzVq%o{H4G7-x9}ns2E|Xd%zbtlK@}l zDOhOgC9Bh?#Org4(Fik|V9Fs`o=aCimq{68r!9gtFW+V28a1i}CUVMjdd+M$rCP19 z#&YZEmH?+NcB5Vbkq{f3Sph$7DoFDv&tr^QS6u)<2C-O^TbwBM=f(c-@Q53{=%Dl# zn-v6CQ0^TtcyJGYu+RCbroqvXi6<%1sEjn1%A6wxPuny?ehX3OTEk6pmNGHcVzWSA z23#Hq9@<8#@fqXDU4e5s1ZbK@OB$=XtsW`yT&jmkEezSeNfDBmT?(hknp+&oWl46_*#65*mtP=@KG!T~lNkAq2*wF*k4Cbx4j2pu?C$M~5}_$lP1CSiE@^fD)=fhUfjrM?+m@zj$g`ZmU_jH< ztd>ivs>XL6tL1`=i*pu>12xM3va1#I`JAe%h%r#DD&Yxeqo@S<&SkO|GErD$ z&8tl4L0pPl$r{!5+-K`3+1SV$PGU;tQ5zQ}nWiq~sOvp_U5pX$WnGHQQ-xC|UVl#H zch@&;(RG=gr@I2X)h?rkq`aqd*f^F9D2OpvaVOumRsiJqUNPz4Q$-=Boh-*j{JO!= zCvItGdd9xDl^Jsx@L`z!{H?4TLq|=b4AtklT{aefEd>H~!WC1=TX+ zAOFGkdH>z#%%@QrMnzE^QbD2qX4sHT$wMjfpg*Mq;z0}t@gl9iBVB z@>(9{*z^s`Dbi7mAm_UV{InnvAf-u7leczP8=Ic5kBbUsa;6ISR)w`%e9;2C*DvOf?7l1;Cd=LOu~F5_q{x0YAC2t%93&c0#}f|!j6Rw{v`pAkJLD(EL= zB4Dj$RaKmQ^e)xuNBrCW#=p!Le(Xp2`1v#bm)8L%r@Wu`D zTw!jx`_ctSAvXoYK{70bMKBJ;-6X>Yo`gEBZ= zR#F8+vAfUc)rWBBh-vFtHIiSCQ5T}hmb}Qtx(q=8KY4{z*cz(>7uie3I&2;oj36MD zySm0hbU2%1O-AN&tQFu}RV!I9D*puRH=YM0u4yBlG^f_SP42uX7NoUCa)+&W6jGrh z8$G^WVM5E!WXSEq175zh%^P=jxiN7}hC>ErCS`WTIl*#PadvXb@$+NmvpLRYqSQxW z_s^Frx)3?Pyyo(HN@gP4qk^qrNeI$Cv27ZjK6%2)@iCX@7fi3Ona^g-rZcRyjD|zT z;|Y`Th_Wn1`RO`}JZE=*kFqS;-q~SqcbD;GOy)9%!y#Lf34_6aL0K{!juZqHn31&M z<#O3`7J{Y-6C-WgNS_4*D=qh&6otB}sj7$E~9fVB(4*3v}&@$!MD|{@9oJm;c58 zIZq#7^Np{6pC^wmsaH<;NKs^LN-y73S<){?)MK`JdNSJr!(Ck^S#5p(!c{})9Eoscvsx`@OrC4Waf##nJt_E)j-nf_7nu0Kv=+Ah!O zLcnGYmt_nFB|rPqU&Wfp@yCyO_VI_*^BLAlook~-TWn%xtA%LP+7}CZ4YZqp|H2|L zs(i3s3F1m)BVMm9R=v1pySBl%0{Bu7TC98L1k|h*OCKZM`Faaqy&+<8rD0l+DLqKb z`K6)@22n_si#gX%-={hKkbm=E`RDnuulx)rS9AW8|Lm``3KzT}dVhASID#%>Mxk^?U(Qe8B(7%6Y+!FXvs8nvvhw<7qn4vOf= z@*#D!3=VHnzWRXf)*;iXrD>6@1+_XvaEgWRoK?VArD+rJ)uj)Jf@&-#Hx%QXF1EB) zMc1@ABkf}?mdq7oE++(7tZKn*B;{4&t*MZUJVtT?1tGe=E_|kzVM-B|=lXZ>xY&~8 z8Ru|gd&u3JyWG36&(Z!iyW@#?pXVvN#AtZgNH&~-FT!*aC}Wnj5vHk+|p zt*EMs<#O3826a`@b&^RCRRPiE3@WBfIuDmD{=|)vsCh4Uq4yYwP?Pm2&*d?yv=8d- zOEO3bk8Oa|1{e!C(<=d9;zAq0`^iTnqsK_6(Da_jUyc2%#~Aeztie|m9{qj!i~%wv z!k%PY|EyPda~+?$X-$#bgtoY2-7??sq}AljG{tvgxsLfG2``_1^h{OF5XpWZfB zf((pK+UCT0>Fb`{`jYCDHlu3J@}G=PAG_Ze1|64}MldN%dWfu1jrpa`sJE``Xckwr zi!0uK^EK|i^fHZ)eCxa4rwL%S!<|HY^|$)-6A)DOp?Bwnddc+cIj_ESmj@3Y;xfy( z-uVIZ27)Vb77XG^K{ax*9(A$Fx8SP^=v@OPbVwQdrhU2IWSSzOq7|@3zE78uE3jI zy>SBE&O|a3$*jQ=g-zZ?VsJ{@6U)LNN{xw~#2_&kQxakdpGdi5XQj(p${diYZyn>p zadT(LgQGp(dg&&gf9(#Rd-;gB?(FdLUe3YDP}-IlYO2MYtMfBXo<8OH*)uLq&pAK6 z;PU*6>D5d~kZquAJKDxm*ELsHmpp&=l&-1C^NhA$F}=Ft^74|?(^Ecv@`R5*{D|rG zH9>233x9TwZW;a?JCSW6sacxxBpK z^z4-P-+PZIPoD7j^);g3B^8 z=O~JDttjm7aBy(I?%p2T+dJ&;?y-Mxz`?;GH*X$sbaacOTSwf!bBDWk@9O;?_wL>0 z&Rr!F-n_}d!6AEl`;5k8#-lNVfqKg}lx45i+jUa;EqLvt&XcHP;2uUxl3&UsWCuoL_bmgJzG;O6o$hd=p$PE4Qmr;VZqd_sWB>&6MuBUvpkfWATB(}Y_m zuge7sSUYW%dT?;SmwxQWn2d(J`@QcfGk+<$_gzD7#bR|a;BqM$8 zcRed3i$VU{_%Cgi6#r0nesbyiuA^&e+PbDyf|KwDGIi-^l2@7B`!)l$@G%-ARab5r zGgMJXV-z>i6@!A9oM5D`DyGjqVE*(S{-xji6@K#Pevw5Bf8j6xF4H<-2NQzLX`{?d z0#ebN<+_X!Yu8vuh>`m8gb)7YAMp!c`7wU=*S^Mhd&HmrEB`q^IBf{UE?E{au@!Ap z0pA8NU67s#HUfdw`6-Lj=X7nyc(OxQ4n;WU1vZx=G;0fA$vy`1EW;WIK7jYE7IW&A z^f~XEn)zzQjXQU6YT+9#ISK1}3(4InO45s)rr%^K$10@Cfq|Ati^Bu;`X1=o(8gd}5$$Gz^p!I+RzEW>=M> zm^o~jV~ZSOhwo})kao10HDty?h%~DX-$qPKfNyjQ%X~znzBfhfkuw?%shgIj5dvJ>G%S}(+NL3R&(?U%pe%dN z&u}nv zcj(hdll%c$uRa8tT0#SLU8{0*#cH);u~_uiyId|=smGvh)YIt281Y_vk!bwbti?5` zHz%zTljNWtkmMdnKD^m*eCij-ahtE0MD|PawEr>vthQ-J%4e@-t?7?Zh+13xBuvrg z8{cV+B}NCPknWQGZG9c`Sy4$6`Eh;j>ATWRWv;OTmdVN|2-hbxlFArYKuexQR?9g* z^!DfZ+AsYopLy#?`Nr43$G89ZL#{3xq8}2y@=kioTk%8$lRnbB?vren+lw+QJr|=& zj*;`!V>R5<<5f%~z%=hV+vz;ia1}|BWTbxQ;ZObtswyOKT3heE6`KZE2Rm8T^lq92 zXzR&{2BH(dw;Q$Y#SL#LvYh+(?(!p_{~RBG_#q#E@B!6)is?GKdI`QIcal0`h}g_Y zK5@_V{wKuljnM)41mLGt-GhC)3%MbB556OMsq^196-`yqwT+|!S_wfom*X-4eVb)i zmt)^d`C(miBn(<_tybzauRuq_AfnGsh+y)|1oXcc; z#t6Z)oXzR#8VmTQ;c7PH#@)MQgR+lBu5Y@L6;KTFotv8_{Vjm6*1d8+IwD<^vd-3P zZ3PAV5T#=q#*n*`+?M!!0OKugK6(T0+~jPjf4aO>pJ&6;9CX!wk32O1bJ^0 z@I%l>IL3mr*dnJGmKbLU>Rpj^EoqPw+m>cgW7>cX%FmBdo8Kd?f4wnyi1s9%DkY+a}3hs;Oz8-cfR)>rqfG4{i!#(dGiL&S$u@Hi*ym% zre?WVaD8>fv!_pa{`8r0M-0owg5h95S(L;Wsj7;qs+f$&Y;A8-mckb)%bXYki^YuV z>uZ*ar6?P#6|>ol7^NS$(@=mhq9j^1I?m3{dZJv^PK0GSps8E3EaULT4IVyxKnQ{P zY);+Oltsbb{vM;zNWut{2?qxUJbd_&+qZ9vp`anLEX$;`s9NVq@epO);+)D9Cv1ON zDNLZyL$!+kTr?>uI9)j=E)yq-a_x+8rYJ$?er*sblj+4dUA2#il!oYbhrCv2WUikDku9`{y# za_h@^>2T{*r`eZDNdrvE?+yv@1?=&j&@_@4Sy!};bVah(;D>^lNxm@*n@@zsAM9))>A3zLc_6 z9)Mc-L7OFn7_df&bAEQgyWji=eE!W>_;Y{mH+b;iE`R0s{u{pe?kT?5#br@lTRL*l zkcEKlJgx8WHsYM2y1Za|{G57K3E<}?S-H0GO_uJGnURF82;7wK3(MJ*&~{|j61t9y z>udIpj<7}X0^rNC(~YZR)RUp&CpKJMSG6P6$5$)JYbZg$Ubz}tZqjIKmoWu{!2~ne zAwM|e;MLct_qI63vshM`R@#|HwP@11Pk?U{;I|tVzQ*t&F>!SdSqUWCJj3P=n>p=I zAtkG$-b2-r1qnBZ`%;S_8$)L--bj<4EOwNkg<3cfCc>!9xUoCorCSF)x_iiLcMiCJ zP_moDke0#(3KIxerpubs%NZB574te!x1Pt3pK^9~$$U1aQj*^N++FOB`zQ~bHnNKNH+V5Ez`?U;}=}00pVUk>f^qr8{ z@y0D-3&_m%e=Cx2yuW^K3q;ignJg$wD|DlR{QQaKxE7)?eW(}Bk< zC=na&-mn>i1ssu^IipRjuDj1s5x#GipEnM&FND9d-DpEh)Pv69zA71aAub9%e7U^C zYQ5^}$XNc^{ov_ox$}I>)p`9UVE$=_ts**~q|97+d`s(1xt27oOJ*$Ow<4^?Hx{+8 z@=>q1Wgbp5d9ZTyjB20YJ3ot9lK|4ZiqE-n_$@^;VGf4R6?(<6}kiL4g z;qz*Mf4bu=kAN!tA$kEkx@I;H3`EHB%v_*X_I1_9tA9_tl z2w79@?achx@ixO`{{yYny`?|;j7q{sCx zFefEg(bHS)a0={PBhGT+1c7bnQ@qp{FtxgK)E2n#`+qY6d8(u^^+%2W+ztr|swZrj z5TF^W2lSjgKTGAS=GHA(u4>l~R3@qnJ91hyR!Fq6O5L2Be-cOWV8MCHs<#;~$BaAJ zO)q%$MCCL0WZwE&iP--W9S+Tb==#obeSdp9YtLCy6&uKTscGz_-r>Nv3GR)Wwi>W$ zJ)SJI)6)?#kX~urW;^V_wToAgES6Ik3DDL^P^{5rOdH>KwHx)JA^BBSRnkzWx6+^n zSSj##N^xqiez1hS}~ZBG{l?jn&E_Ruq9 z1(*H5!P~(hOS4ysomgQKzrFX8fLs&$%rUR*ztQFBCsbf#Ln8h9E8QWKN3*Zo*w@i$ zqHUERrjO6h9k)*>M5pK1TkRK4zFtx#3??gIX>b3i+o-}g*JkYH^mMszIcUc_XPorL z-N^YDY0JPMkw*fGq|PGU@Zi;^iWFqc8@{eH{7)ZSu)8PcqN~qeNG`MW7OpnNN*jkq zQlX{O^SHqvIF4O?P$IC#ZuOd&z3>Y(0<<=pcz%04!%})LwC_t7*Doe9pY1X1ls-ol zbYCI%Xa%6C>JLG*_3JnD9sC3PWg#N>E8QcpuZIT@?cMLRFXP?M(h_h!q+N5&JEk-{Y=ONhX}6v+!|Xrekq7&AYA?BN=?1_`XMlgx^%tL~QKeDi59)grrPEru+qod9EvP|Ydo)_HGSD32S! zd@-XroY&}maFds}AZuU(eT<};fn+7#&|mmJ0KtrYVkpGvY-S$Lu##*8t>kI?>O&uP z2{!`5#|}7vv>k|aEGb9si4xNLiK!XKbmq75+_d2fc?v|nXdd)5F_sprOsSViyvG+N> zzmt-aps1zTQ*Wl5xL#V-MjAC zzIg8x**-OsUD!|K#b!Y<%=mTde4wm%t@;SlTfLz??ZO$9IB(|lE*bYu^*d564yv0L zuIS?HSJLrMteLE+X@M;7r1Q94x@d6_d4uxTe8@fzd?sp*;v`#0nodYNR-LNsN+Y8d z!*N@mJF$cRllp46OQ;Hupx?XiGFYuG36v0Gsn*OF`KuGk&%}{-%E)M#@YMWTy`!KT zyS1=a9VV!zA-IRy^Ii?YJfR$cYn0?KR9Vv`o!J*aEM6ef=>bX z-}p*PKy6@!X^d|J)5e{Hs8C?hwglTXJ^*Xt)g`%YuPqkEOBq1QuUh47T05eXHhvJ* z>`tfADh6ktp{MgN!z9n8HD^*;`(6}*HJZKshB?k%ZCGyP^n)OV@_?i`28XlO3=VZ5 zkfCkln{2~w5r5#yoX-|hWL>zWG}Ty`Ir@*;S2dxn2^>U+>m^Ykd%HYP&smlnnY z9ZTCBBbuUa#&>AhnHmwgy{Ezwo|;lo7_ER5dW#wyeyS)X*y7vMuh$NYa^hA#iZ>yh z;Ui2%^cXRwjN#%;#!OmwZf!e{B+^cLzMT>bd`&mUo>1czk4K}6z<}_Mh{{$`*F@ux zyEwb`4U+l~+`5kRryA|gpXr_cINR2jQg3DiHj7eaG=@gXe130HiHW9ncWyw4`s;kM zLYk)je)^^0a?>7=g`uIbQ(?-UUenyHtdjyXIX}298}&DRDZw#qF<^cDB{r$=v&u9< z=)8P<(7$clh3`A<^s?%)J^wtj{Kw5dJGZD$HVc90^tCoAW$Zk@ zm_5O{eY`UKU(mQKO(f4GN7qxL(RW+k?Z=%#A`!o+Gkz<9OJeSlCUbS-cu<9K{K1ER z3*Gcu*UB(H1RoM{#j(H2(Ce@tso^F~ZDkT}aE%o&Fj{h;U}BB&Fg;f+LcL%Q;`Jz# z<#u3LuO{%A__lRsEOe*j0OQ+E;k{w^u8B$iN9jkf(KC~jz(;_Wx#M|!*u@k`L${M+ zP~dlJ89*qtj`8~g)s+=^qDjg#fo}1L`FYH3{hfHHXHF9}5w(>6lbxtR2Iq zw-Oa=?{xW8E?BBLmfg?$9jRHdoUAHOb|F<3w`+gPT@h9ovvY7MiUMn0PD8`1BdFhI z1A}8&aF_`@osuUc?Ta9MLOJRI`-tFRNQw%}pB$$KjmyJA%5|?tlIr#L;q2FhY%zpq z(Mx1gGd%-CE&%0B;xw3iZv5-}Mc2kKhJKc;jlSbV--72!L1`84}%r3mv zv_nTnY+ADnGGDJA8SpFachqQ_rVwgjls+O)V%E1noMGqRmlHWCq?x_EfV?6U(OAo1twXU7l_sF!c2S5;N5!;Fi+_j%~T#$4j0Mzd#` zf7GTm&)P<6$4MD`ZFzaSalvrUMdTk}j)=F?<!*uSpR8&Ju4hhU9lD7T&a{>GckWClH$Nry1$_e}7f&YuPU5;b ziUN{qmvuXs@;Dj4koO9fZ3n2O0{{ zr3wB}YPb{nHVh+TkSBGQj23-)`w!(#|3c}+Ba$k;^GP63`I5RP$I!Nl0Pv_6~F3HuOl0? z>`<|*AbJjuroFB6DhYQV&8h8OUyi~&U{Km=@dO|w948=H+sbdGf%ZE6YEWSy_+l2r z&G0DAw1E3?RZ4?hf2E%E%hZa)EK{n_zjbeg$qA=*(>5iSi$a(r>^f+6WF>|m>o9Up zl7yx-baj%bqM}1^F>%FYzHShk$9HwqhJ!p7$EVFI0vMik-51yw%sorFEf+=>7;_KyDTr~8|L%L zajk#suo<3PBdx{#GCNLwHBJsnx5e4!sFSd$!kBDjEwKM!}R7B>%1 zez7!|Ma)W)4_^)%ySTCE`8G7*huW&Edf0YK#j`|D65m}$#DVy4EB+Bk_&!I+^UB^S$35+a=2Ga570M;W%3uK_J*u40TYtu?C z7tuhzu5kZVlsx!M@w2T|o7r+KRZX7;(@6(jyJDO!k{q=5Ke2iNBOvfU{2f|(#sokF zW}KM!t|)&&ijBI!*2UxQAL7RQn*h*mI=bG#oAaGkPAus!9+J!CUM!tvG?f;_h%J2Q zR3e>Y!2VTGjw4BaBV|^ad>NrHce2jgA<759uQ*x@S^*6z*`n|T3D=W+v+^_8oFKn94xQrJ`=g-OzpzXmduKnt z|Bs&`WYp*=0ujtQ|^YzWK0w|FiMf`pb@OND{T38dFxnmF+8heLB8Bc zVESd!l?FU$x>9v(SC<8Udr=v6!-|_&Mik-p82d0y&AiDlVs_z}H17d|XbTe?e4WBj zh;SH>j9C?7K!h|5+{tku1iloGtU}L3AtDII72RGc1&4?<_vWPgPVZ$m)jwz0G55mf z1h(t767AAX^dEHyH2Aj}>x9mnizb6A@3i4Pl~~L5oCH#JFCd55tKd<45=+_^oUSmy zMjYEyHBuj593>w(oDQCO59uQFNR5fbaM@va_e;Wye_AUk?})`Lnc{+Z7&h;Of8?C< z`VHgn2+zZa|3i7GfwYb7@<_Q8Ja5(qzBv$lKcrj+!yE`T-7GI_&}_&&)8%o*mF|~= zB`_Ch_e@`Bhr9eSE>YQAg9;ui(;xrXT^Y##o3XAcXQ*PH)S0kEr?S^9pdgc5=CJSY zn{*i$z=JV>c~WE$iPmzK@8q@Eu2YPhEUCGkRnPIg$n-gK$=y!%du?76X&W_q?d%@+ zj?Mi(ipX2pu;3rfT%nlS)d4e~0K!>N7Wv&JxNqBiiQ~72=ND0YApb_{|LDMRLv6;_ zi$s88%EqSRiW=;I_`&AlN~Zb&JQr1;Xvr%WD7G4ncv;^uRRO0O5Hv-X(R$S0i0Ix& z7$~Zrpg0>QnW{GO&6`Wp*>bjz>zMqIN5bnIYjHH6c18-L!E;vCweRi>MNND|S1jkd zfoMGHl0e7s{F--5r@_QZN@5$ur%;qS%+E}UYnyYDUp}i(upo{oB5yPkr^kEUPLI-z zu~%Z_<$Ytu%0?ljWNyYbC%3<8D$-$MGmy8Yz_M&@<=UPTknZq0fWLP*cWTh9>V{9VS+T#THPn{zWgsQmcE^A`3f_O(}sb|lyZCE{1*RaoVfjLRl?gkgl7 zc{KSHcbMId2ulbeacl#=y5g9aRMug%z_)GjJ;8t21+mN)z~ zGz#4>O8@+2lC|e(7;zL#gaB+{qCfNSE^Z9+BNlQ-bN04&U^ideXaL{+qvecg$0?4Z zgZd@p)(0s#KZCjLqJ@Vi4@UB~I>un93!%|M&Bsyp3Y;0ESx%v84|f3h^B8mGHWki1 z;*aA(H~q~h-w63!(U@dTU$w)S7#DM4mD!X^8`vB7C+FF@@fSk>7L+Yh{ZbaA%eQ27 z1Zdq2HhiSV)+!s#IXM|OyHJ-H{JEPy_OHOF&YK}0u)hj333N1q&DhB&iPMIFtE%JQ zCN(4WFtadT*|De*d;t}gGv5q^|R!| zfb)p$s6o|N7Di})6gB-aG`%lV3<0zO8$Ml#yPX3IlZWjrFZNN!_CAmP)dAHXSV7SD zo0ZL0RNWmPm(0#+H>0IQD7Em3R4jJ;fy3c9opVzY&CBJ1$mHV@;-tt^*wGPvkzK6; zE#C&)Ci)2pZK?b;K^{!k7PujP05`Y+>ZyJXc>!9}j``5V*5%s2T7 z<=9d!hU-stmSnkb3v7 z;aHz1kl*8if8=L((#v-L|2JJ|!jKeG1x>Q!ctfWsT~T?)mlCWjlZV#obYc+;rzf`V z2M(j{1;3->)-?B*jrZ*fHe2~2mySl)a5_AgUz)4Y`#AGk) z!NfW@+8vD`|MJ1O08dMOVy%`~dbq|6h(Xg1{DbSjM%Tq@&WX#eC1)ay370X20jON9 zGgB-YO@!MmyqtPZk0Yjk8v}UkS~f9!KY4a6eyZvxDU=Y?YYJ0V#^KSZx}jQl%}6+) zvL3Ts2-+n06lCt_Q4w2Vbd24w}Xm+-QvgaJdLw zrtAbxj*eu8jngvW&Iz@(x*AzIIZhxD)7L{G9SZ`~kH8HohN7Qk#F`m?87k(rfxasPss)a9p75c*TM-Lm$Ge^Dh zi&#({9T@6*#@d0CFr0@9=@6k_j~~`TDZ&iy7XF(CoNuzKI3FEBG(^J0sEY?8Q`!+& zWT!obhfj(05m+++nLGa}sVbux9l~uA1t>UkQw`gcQ_Ou{t_EjvjlDBFJAIp)nrfGE zSZ5U?Ups{$iA+_@)kDtTffiz@;xApeA!N)3S7L=bujFJM@i@Npn5#!?E&^aSxN|vj z$8{L-IL9OAoFP8UYp5$tlp%nfPlMv9mEiv2q09;Chm0m1hj?60n}(xrD~+yp#o5XN zTj=yG`GXkXq^gsWvXFLnqwQwDXaBzbX9q_=;e!?bYgplz-dZTXp+iDxRa}LpP|k6+ zI^v8XElvqx>gMN+R5BdBL^Jh;t}c?iIAyrVL=6_O`)=bR1A06v&pT~}ABOyO#w7xU z)$dG%{Y%<6ccINdsHB0+#wlrjFlr<}Teoar;XwGCT2$|f%oveWWoq`C-T7Mkpq_*9 zw)e&x_av!Eksh;?L8zS&bC`e#2WE4u($h*P$t75=$%Z;Y;2q1@!AwW?C&FA(0wi%r z-Q5lCY)!O z&2p2!Xj)&A$ZMGcSVayV1vYj=*FA<7fa|*Tb%x<3y8G4W=Ima$51aCbA<||!cX9oO zCHDYbQoPyLL6-&SF6rce^x8$_G5-a^^3Hj~4MGRadkHpbya zT_+GR5YLIJsF@;FBX6cklH>YCxq`%Hwj!*CDhjj}X|Pg8sTXGHHP+baT-OHqkHsOsAxrBZC{(h@+yJH!GaldyQH@Lv$Qt(=Y_$Mo;Nf7?fIEzMdI ziFiZKCq6aD#PGIxCT5=zU(IXFqr?~4Yct|`Ts+q`mTQ2wqBBoV&u1Hm?bK(R6yL*& zIN(^wQUhEH_AH_?XkO;_xPXW6x``U3l*nQw zFWC#%%o_;-S5kDvdU;<;C}skAxSq}#II-~X@U%^bucH_fQU0LAnDZG65@3k~GE)h4 z80toq8LDdSDowy!5`GWrU?8C6qzsRbTm0yGKN`#@|WHVO0UD z^U7319dky}QMgOrt>eqsA|n2TDYY>GYSVF2sxyj8sLEr&uo)lXayUe%Yynd76; z(|rOlqXPl0;%CffHs4Si%HcZYbDNWd0L^kWC0RKdUWEBLJc4F>;;W@ezmRFi9{0Ch zr8IWaP$WjWGmkPY~<^ zFLZrYrsf%#CnvSXs)n=73yfJlPjo_EpA1TC`L*PwAu1z)Bl@^5+G9d|3Iw9Oc6r3dV;qUv%7VlH#Riq0M42LqRuZHR5HU z6%T)R(C_R^v*{J)xR0~#)cLiGy>ZUAkcMobfz+KE0+>yppJ#!F`R;73xwAW#Zm>=x3GD9L8Rz7El?Jw4XtZ|{76 zdlvM20g#E|bzn%`^%j;5+({q zIuk?NJO>?o9a!u)Bm8PBD74pDW|nizf}_e(okYZM%!lm&68-sq>gn~>mu5$H1A%t5 zAp6qQ3%m!0o6Hs28lI)q&&iedX`>?(TSM3}s-Ru^tdqk*5))+ldq81nUoG9i!2$0A z_Q28-xaZZdx5xhnny<`&CuTVad0wt9%T1fnov}c56^miA7yzH#HTQ8tX(1ZXF-1LB2VdtJdiZem zmY+0|NC3qgxgtR#5?b0rK{11|r1x^>s@PGqrZg*9Zuj?#D=Vge!`9lG!MfK8QxAz~a(EUbXj(5Y&!~AubU6?A`KA3~$`MTpS&iL9v1-rMDn~zGyp@n?b09 zu4W_-5ZDN$Ry%=w!Ap+>|FhuUcTqcuSRMDP{zv59kD2d8(ttl2Gyl5xJ=@09j{9)E z-SNogSio2`f+0cxBgRcOA`)DSY`qJWD8jc&x3SC1bBsP?RPSey4-m_qL9 zC>V4Y80glu5Wu*$`x#aE_SyhgOZ#W08hQ_GJPEuL`@eLOeiiQ9h3jHbN-X+DqqPtF zs3gHRA};RhG;$<;aXrWKitc~D;1{BOdP({==$}2y*8rKaCNw~S{wx^mFxU?#<1Xl+F~`4NDb!((KZ;=}7%plI4ymkyZ%*#DWrywq59()8d( z8aAvIK>fS<3~MNI5%_mXs$y;57PCZo18GLX&TKPI5zDXzwzAp{!8THiN^z&k1J9#83e`x6KZ(#pBy1=Rlv^(c80_9 z^H=_-@dH2eu<9_Mshb5rYilqlDJ$~|2${S2Dn=1YH`_bzK*-w#+LOQm_+%Ue^Srn> zIK{=5fJGF&h{rqZCp3HGY;*41dVMDFs~|~jXZ`s6Ja=H7u{L%TJS<#NkBRWk)lO^+ zuSmZAmyx6&PTcVj|{LF{-7a9O-}^n4rOp4N}%InhNJ)Tk!AiRJUfwaJLcpLvG3L!+m(#p>&g&`>&-ZT0edQyReyeZlqa(IZ-T= zoV;U5=-*%5Cc`OvUn^k--+G~esHn(MdEC)p#-zhPVQi>X7Qx0AXNm<5V}43mw5BJFrpXQ!a(C>{4uosfwXW?pATf(N1CuHS^Un7{xSl$ z&XjEUEU(E_#-jmBMgy5f;|~-wT^v+Xx=>0f9tYMgrw@rtF?bBPKf8!6@nGh4uGwi* zQs%>K7aJ0qb31T^5sXs;$%ES_Gc|&*X1+5<&e*O8X+Dh)rd-vS`8$NRhpq^E9dWzg zHMg{O_rJMK(81!7MH=e5OOe0vDk_2t6wv$Yi)n$8t0RCS`UqP#mZcdgr;qP{W2mJV z&D(t0{#8E8Acg|OTubfLIx-|3=G&hQ?A5s;a62;L9&&z25Ap zh>p#~QahubFsVurBfuGTtsj9xjUGdIp~zFsC0X(FESs2~VfF8~^5lWkWLCPy#CTr! zAVC0(Su3{RXd6AHfu$#5g5Y=W(O)9)34G~w>PguQP2YUT74eCaOfAe(JzwHWk zFX!iR4Hkf9V$c$4@R?yspH6(uSV=XCRkV4W4MG$xjGLkM{X9R=y|?CWl3YXkpV58h8E*$6_uc;lFk_PdJx7hKQGV3! zZ8Ewkm5XNCU+5KJWjknE_IHWiqa)mdHtG;?O1-)cOm$?tJ{AAIKijxH6D!(){TXf* zi(@0gnCtVdU@i6@ielf$+t}>yDKrU+qA(~GMFj!HExkjV3WuZRh&hvqe@~bjT)XL< zjjWI`%Rl#CG7&l#a7WMzgGvT>kg9wd=VR+U9z$^>l0hi2_E?+v)Pv zmd43M%R!%)f7lA2G*@V2JzO z&^vEDylLQrG6w(k6h=NcGiqM@7;0TxKWwq+j{%dFmOOhwnluG{-T~Fz?f^)+jE$;Y z60hV76~6w$%a}WKA1cm*V8j4U&jDO z*TDbXhRu?#vnXRS%&!0Tk$@YXrk}ihMeo$^BCZ`K)ai-gSGt05u z_T83!>+RKhwGH(D$O-uB0uYylt)PV(L_8iOQYUcMpfP;8}nvNR#=qn^10UJkvP9HeY9@CoFMzY z;>+;R;`+MDZz&xOjpIkTGf*L;iy_MYvSUnsKzFs|Lr$dq3U{LK!0W{V#g30s5I=4F zb${SERUtWQY(FY==6peC^mdL*kqJcF)?~_^$)2giCnB=5R1X9|-X+Z@VgYC#b5JK3 zC~XIQ-m@>9d|sjeidZQo7mxr*HR{fQh|A{^mcE%hX)tXeWFo~8Y#FsE2$diakn@WT zSqns>5&w)~bXRDC5UukLwEnW0Q>~;}NJX8@(RXob$}{9cp@xqy-;P(DkrIsUW5FzB zy`~`3GcB-=pC^*h;P*zCF^=}gRiksk8rsu&QtlRiPuh@|{?Sz>WzS!}%eMBq{a)03 zsorT1?a?SWJ4{~@K}}ChY>NGz1yn~1U`d)F>I_2*o!}H7!OhSOzf9@sjy~`e8)^4F zN%>LIp+99!@MV6!na{|NufTam5qcj*mCCdMw`v_+aet|KRgSWGw{ zI#&}_>mx*>t|~uMk?(C&$nW0`%gsvno%(9WJ^Op}`=Q9*V`DKFbvAJV)=(Rcj@40K zzw}X4*Rd|EiW}3|fx=`=x?xsadH}=xpBUjpQGtW+6`1!D1adEtu5+?`OGLp?A1GsG zP|2WGd|i8u|LS1{CJo(6sIqfqNwBsY*6?P5)KttkDRLFkR$G3qt$p8OEUt&k9uB9W zMZ?7_2;s+FB^yLzDrcOUBW^;{W*d6?rJ^maT4C`1rxXz+`Q12+pedAq#~sq)d`}Y# zq?xZ*8r(H~x9VkquMV9mqqB$QKi(KjYJSZzW$Hmtd@XE0i z%yB%JFtFd~64yy-sBD?ahDn`kssoDcn@A2NWu-JjBd3E2;`8-(TC&zM4?my2y+Y1x z>x`nw6SrmA3BuYQEe3MKa1bL21n5=SQ{xZ#=F_+Y^kxOI1bkbytpwZ6IEmOufGXi% zIKm>jqf*7@Y`uEfoSd!%ZD;letaIl*Qp9hCux}P9wq9PM*|XB`1sp~&1@r!N_ED9KP+*hn(JWBF=ZX7b$2UK z`_8R(Ha3C*5EVe#y_`pW@SA(vMxsmbF-QDb>+~%H;&22s8A?lYTj=ao;`x?1RA*n8 zn|ks4t$!>vv!qjyQ^+Sck2ip3$haY0N*g7;lZCf{SeUm{Z}ts>FAbek3i(- z6jny7>|P!cb;&HAWet^Yk6FX^3I~ zJ`0b>w>ZjisiaKi$ET1gmrS+A24NqS1Y*K@cFns=PPcd(jV`Qmw$Xv>5tqlR332lH zPsdXD`x68?!b1BG4{5Q&PhqjbUSn6aAt=l&NBonsrc~?m20nEO|NEk!EAkd zLv>LA_I-0O`G2pEhj-9mHww@WqiCegfTG-ycffnnr?%%~DGw=ShONKoN`t;~HDHow z!j>z);XNLU2ZdQk_RwP{*jupAp3%phIi5Cd5rm#()g+JbbJ$~St=+xV{hnmw>8=_0 zEwfte@@YP&Y9swDtY0nZ)PHIBoWv2ZC3~l*72B%zwzq#xxF<={(>sRkW$p1z=pGjp z5}}lo5$0310)BAk=bxmdr5Uy4{|DTEaQ82P2n@FjWz0K^N`aS>6SOwC2xrV0`87GF zyqqELPpSb>Pe>>Vpp*&fFz8TC$YvDQ#?0Qh982}#N&-^qST_8s>grO4VFn%uD?SQ! zCQQE-74u_T3Q7>Rjf-w2%cM)0+~TzkO^_a9vW#75ku|Gk*r;a?miXrJlddfSewl`% z!Gc=AAizM&81DX1r1BD%X5N)TC|mw5dF55X7m6y+8*>jjRaf)B-G{e zi>pvy@7u;OO{7)#f7nH{;R0(IqnSANFUF0%gj(SL6L8$4>XrgfEVIo`X!|QS+E5Z_{`(RnVf zc3BK`cYYowE2yOVCAAR3`(+PAK)J^QH6iEMygK@fq>aYZsHEsJ~H|2FkeJuCmm8*8{p5$=9%N-u>u@JUdwEUs z9C>jf0<0^3?A9dSruprP{4(mn&bhx8RkrCY`@1?59_;(Z{<)bv4t3g$yg~wryp4@X zy5yJF#|ePrPMDgXTNk>6tSavIs{{)E0ecASu&;9M1yBXFRhieOVI?;(WM9B^;atym zdf(T~vjWG)B=tsD>E~oT_CXNSfo};8?1`q@EM}mPJbjgD8QLeg@r7!eB0yEv?i~f$ z$#DljH^oY(Ak#RtMa9{YU=}2ezu4Wo)?`xb2lz>_TZYuZj2>Ajgeex{#tqCcawE5L z1NHN@?e*m(*vbo@29Zqj0kPXUz4!oZ*Q(EspS0TMn;D8`v_EmyzS{jB@Y*S!HEMl~ z>&Tmmkx$nr%pKK?B(?MF|0C7GXD3te@qxg>f8Paoqf?7xCm-&b*LSXcWY1|n5NrrGZui%_8E1GOpO~CCqu4(Hu|C%SqMS9@zWRt zA~3~IhnuC5RY~)|o=74uko{VFO0jSQ&zEdQD+_Hm@)-8wh_An2A{wYTgeHyy`3zpl zZ6E0S68&ZZP=89bVgc6t<14wIfRpJxU%R2Bk8q)l5M)oT;4}`C>zIT)917D>uI`^* zzlm`0;jM|Qlxqxk^_W$-4*K5T-|ZB6E={$DfgSgKgy%XBBUaI>eNt`HWE7Px`El#m zyb38>A=HnKeP-`*YXbKrb-xn#A|%5aJjvIfYq!~^F773M#s5>W1p$J$d7ecT(dGaP zseL>m6sFj7qRZd~lFJ>3&XL&8E2LaskIawHuy=C!gpS1Mx(L|=F9;H6TyagzrR{0c zT$Q%PTA!xb$VY~3@EOlAmhckZlJ6o_XDSg8T1)A4kdaJ>ocZRL)a`#kIA)!+pi`Zr9vUG}7Z&XrK2AV-BS^uUBl4L4C)0Ezf%Xxw|QLA2rb0(u>L zvRB-P*|(fz&R*G?9oA@m6kI+kIaij;P0*H^XH85ph)!77mR7OsF$Sj;1fK^mj(S(c zxg;6ciD=g}}tFn>Gx%D__WTxpBJ zD>7(WW5*pYr*y>a3w!1aJ4liTSC!#t7|ep4h4ThPbMT@<)P#9PT_W_$(CzIU=d3k-0 zd4Icj_w~DcLu1|TcskBJ{jsrmZ33(X4;WL4CsGCuRkk~a@UVi*%kR?Jq-rE0f5m?# zBtVAtp&Bd35t((8lIS30J0YYLvZs$JY`s8*TI(#mjCo5FJZ5?=gx+~ecAc<)8Bu=w zBr8Lf`Q_&asgu1?S|bl-^R|HSwvu2U+G;q8#7e~Ku4^QZ$*cO}vFd8-yX7YI&H-wi z(@KnuLdF^q)R&|6cl)GBoJwnM%Z?jVJdItWv^{>WU$i&ay9Ku_=Dj5Q^GdkW}#qi94ZZ>J>R(AN$$2#4c$$r&6U4B$HV6r`fFbMhY zWGFte02UV}b*3O;$LTmqV}}tU9-GL?isQbF#L2!3)-6wdm(<@eaO?bE0a99*NA1b{GZ$hDm zppYWtYYqHP!ISY7Eyokr$o#;?T`YZgK?9s2$IpQ zx$GGVEE_w1(Mqu(Ii_@Q)U>yc0?U`xR+rF^Xe5^-pmnD zXRCjL$Bbn{x)w~tY}C!;kN#Sh6orvzxBxOH8@Q4e=P<(8dTCUV}Ba#N=C?x~}Mh*vZ=81{Ws6=G0rmxbU1)w3_5@%22_ zzL&v5M!NCh^74MNmf=plgMSLox<}yaE37I)MZrBB6A2edEIrrF*AC&!hok40v-j)! zhjaH0au>Mj&L>8w#`g<@uV#8adqsU zwCCqsQw|9IsN^(d3vEMkUR}aGN57;|U}U-i$zuQ57W(WqEY9%{$Y% zVf~verP&U zy%3GxzE=)T^(PN#6jwk~`ZDFU!zZCs80r%S}J( z56*IU{i4E9R-GFozBK1@rrw=}LocSJ@zCOt{aLIm0p;=&XM`3-C#`tCoQm4|j#r21 ze;i$9RFe%GRvILvo6#lRBc;0=32Bk;2I=l@>5>+ZZjf$iMmLP^_@4Lszn!zQJ@@Xo zik3QbU$?E zbK9Xi`k$*CZNE5XRg8AZncJt3p8nDZ8oi9}`Pwa`KGj-n%9YI1DycfvwAE_JoYqkQ zNYVg-h3fl?D^f`oUv4=40rRu$A3;7!V1Yrl9L1-7(Kc)Vc}+B*ajlupei@dC-1(_h zuS6~S1yVA{{bSyVhW%u&Ks#$3Ra(rDbJ^k#JxXXH1rXxNl%#-5v4xv_MB0+8^mM^F z66El2nhT~@^+_MlH%b)(aw2pbv9CN??^WmpK;yHM9I9GJ6>612+k4|#KqV%Cv;=z$ zngJbiWy)%rd}<|4)NbN~noRbnrsUf19o=Do&+{;5=@;G%c_qOBb@u)<%c@So(Vx29 zkt-mLLv#U{w0^_i!BqXBAfIzG$kVz2fs>)%eK@b-8&i-|*bs>9Y7=oX-LT3*s~+#N zz1v(3v-Zjs6vrzS35&cz=b8NHhVt4gNZp7j5@zkij7 zdJZc4?0zC4A>ruwv$3=tr>j)MZh&YT#5se+`aO-(x|n~BKh*vop37yS4xvrKpNAiv zMHMN?j!W*)ClV*33lJ|=B-|1+3g!y$Da^L3j zc`eYN?+ivMzqwEwsW{?pO-+84I7&F&0guO#9psbrag z7yr!ofv1WKks+Ic7xUQKq@l?Bv2Rn z-s@2}Hj9ua|JmEpu7A`IIiTB!@G-$rgWRg7vm?E%j)Xqitetqy%z|&`H|!E^;zNwg_Bu4jH{ZDl zPPXi43%2xMMnO6Sja!oY{#{J7E0d9`GraKoVm$fo*fs249!26$8lCT^b?rSw;kSFf zWM*Z3v9q^ZwBflnkk(B7mCE>}m;U&6y)*Z*c949FSn9@eqBm`J+XB~9^>3Ky5cL}W zsL~<^Wv#ddz*LXyVqy$|XwC<&tbC~r=GI+nhd`xETUNtLY!^Yd8s=b&+^6eVWzUyK zZa||o(iLm7`vYZk)pikj$2Z!RhsC9+xZ;*(zco zO@HaMHOJCnNrAaPIQUC_mpak=XSAL~9r**EmzZuXBq~ByR+zf&CAYB9RQP@a*6+^! z6}{{2Nd$1%wB$3@qj5mT>6yJ_RJgt$rizW#YWH}hd0X?pn{4^Rw;zPj*#~)QeiinA z#eWOTd#&u+%4zQG!{~f#yS5$fy1xRxS8eqziAG&Fl+{~Pl9?Rk|_hIvyWY(vLWE%A^MPBk= zCc$%v6Na5zd(VOS<%h?xG#dtL4Em+5cWT=r)c0bE*caKntiUBL09C+5UQ z5^!`dtX7lM{?T>4gVs<inV*Y~c_2az|U*F2w_%SfdA3bSyb zdnOu7R^Q~+MHF5>It<4Jw``%e$T(q--n{1v`>Tm&;f=Q!qZh!~hSy~}K@7e_&{G&3ohKYBJ)~utLUC6|Ybv$WZt%D#v$Oi#^O31M8Fc{SMA|TC-0$ zt`r5(c3#^qBwfGiJJDjKY1;Nkj;2l6{7gNg|4uH6Jm7t;k(Lqg`%Q*t+w#&l(iB}ged*YWxAi)bSL z?r>CdCk^(kLH>HKn9g{q(!*&rd4xFbLPYi0q3v@S1mYRR?&AF9jg%IjP*W!bt#ty^ z_ysbgp?s6|hw)=z76EH8-O$=g{vH4_o!Uh;EZ*;aXHd+-r9Nz%Ko#J~!wC^P92tq+ zUVObBygs`XxP21JS`h%)9Dn$_Hh|l2)Ri*}D@#j9i*egpJ!II51$}SWfPS8-+o=w) zwnQP!f+%M%&31UMj~dJU$Aj?kHPVGtg)(b_k&*f}G@+F>rDbGJ@P>+0 z@qA=({e|a#igc%yZjDBM4bvxw*uKr~_@dW1b|*d(1#y)?A=bfw?QLu_A+P?mHD*go zOH_77xSCn#jwB5s2}x%&#m{06Gq*V=*HL1waP<)sm5rx@``H|Kjm(m&7n@iBl#xUccHaqpq1i>Ggxdj)yBd&>s6Nw1bCcf`Wa=diE$%CG4n z&wV0$^Tz;|$LmsM*>-q8&zkG(+ENOBS5ECAX<1B7cZq|zHIb^A4Y4Tdlrjg&N0uiv1o-up#?>d^2)42B$C37rWF+HXWY(?OrS| z$X(F)GJXEL=t|S-`g+}(onxv0a~=(*){28O#b}0f3ueix{z!#;3VRHL?xNn$IL!9_ zD);qG$bK+e)5pU_#K8;`oOt+19=;PqnF&aEcv6p)D4Z%m8`kbAgln7(O{ZDk&q2=)Nq=m zp9P9SMe`Ob)s>U-ZrgES+f|vW?FcQM<=NKrP7s|&EDgP@8t+D7p^PCTS6aCEC?j=l zPWAo7O5FXK^R6i>_$(=nRyo$R&CGtPKt@}L{l{4Qs~e{XR5E%?&7er#&^mh8@px-!Z)lB zquE_@TgzotJ3me^2pB}m6>PWfUtb3Up3>F!)rW0Lu^xD0ddZaiCME;HfOz`c&qYd~ z1t)M}|M5!JJf*VUtWj_FPN>GPqhEJDXm)m%UH{C1?<4aUGrx%hb}>Esn6_j7dN*Ec z*w5ubVTMGp$%$Z5xweLtQzWg}I|sfgcSbl3oPcU5A6RJfVta^>#C~Gp9nDEXO+dMO zw6064E^b&NmFMK}FftGU#sYcRpb~!AX%qCkOvPmz&HY@G%Tv%|$Uql(2Z+Wd@?IYD zF8tpBDUavX9@_Cuq{wrS$Ohu0Yyx;6&sh-&D1gmFpt z{WOuk981d+J0FoFEDXXq7v2=#I`AmJ9ABy8vfc|y8mA`MP8q|Hbf}pU49LYioaTD^ ztd_@)?Ku=n)c)Mow2P$tE~;WjTI7)e;`!zac!StQ z4UE>5#R}T{9<%Rm1&@oKx#4cE~kmC%G5F3N$8J_qSF zdU2&L8QCvz<5%kM^0TY#kD9@QG^QwteWthPAAd3$>u#pXA z?}UPq#6hQ@53n_zG%#g^%w+^UUHaYEeaA|nU43*Azd>(hEkQ%?NDdh8y3_L@Dr!~_ zG*25b{Ru+4$i8A5O3tl3iDlnJs$%Deoj?VYrnJ2$Yq-0*rBD*ymuH(g=|G~S9W-RK zL6dgL&hm!HAS#Y&a0bN``)v1O!`4r%qPDf%HMi1eXXHo~2Opm?la{Zlns5#Kv`LBj z7UpB`IniZhrI>PTEsekF3S}kajM5?{p-RKp`e95*#?0LWtZAYD$Z8X~>h0RR)!Jg2G)~-@!AXg{`ZKd?v!8C*P&``VA zLt<-nN`?!n_${C1T@38R)>6=b4SuoMeQ5rWH&~IMV|$NY-h95TrIQv6eh~6LW>$(- z{?pcG+N@rXo7}HYQnkP|5;<{5A zkLtwmxj5!r2Wru|(Y)*UqPhUpdM5sbbtgS7!V}`|;ww&s75h1I{kaIm0k+b$XV$Wm z1f3hud!dLZ$a>6dFb;|ebl>K!k0EUJ*0T83MS6{g5ylGPbmJ5k!`PJ{Q2 zCdtV?FND033cuc)3O~(T>gO1-aiRIDZ-?f>V2@>=D2Qb%UF=Zx;9myXd{OZ*An}rq z`-I%PL_4MjlgDdEvIym|f!ZBrWol|-%5b#_0h@~33Yw(xf_Yt@)PUW?s~eIYV7Z1HHs#h4z#?z1n1Cp(W9=_;gs9RwHqja`(m-+F{x+&EuM_oc*Vak9v-QmBTb zxv_kd>sMd4Rjxet!@FhT{YIYH+`leYQJ0_4=$5e(wj7Wcq{NjXB8ziSBw2j6*2KXz zSZEL-8FVUqdI^C0rEN_nqJ^26$KCDr0suW75= zYPV77>Hu9d13T!BN&9k+bu=-A##dI0-M(Q-5A`V($jAZ+1}*J>cDA0g0ZM{f8>u3v z`5tj-z*pV1&-e5qABy(Iua@pQ=C)`%ZufrdcYtzMD&$(;@npqdsyO@o_FQl-6%(kO z&wO zO5hV}vqH`-{clc%aUQM znq6p8nBRKfLrrx~xTh36Sbxd$VS{g0Zh#(pZhICxSJ2bMdqeE$`U3P^ip(kj)o+S~ zD7S7)Asc1s5qtDoNF;MY@Zn)2=q7V7!u;>UfIq9w`{xg5)zuLO(l*2g-YCUmY0@ri z1qW3{HWcMv5(?jv5-8atk5AijJ5!crzjKt!CORrf>ed=EUq~Fi#IEhd#$%xh-PkF2 ztZ`hEN}@Ng#RS@%>yGduuUpElCk{mqyPZ{D=G>_lWMuH((66muN&X#L?N`~AqZnICh8Mae;lqN>7Nc>@PHavZc!~2H7fGx&{V1GhHQ5m`#a)-t2hXc9&x_jb@lo2tv{V zd)eQ0WEnsl_Bl*fduBD8&v zM)HBzY==gA&}voB?#AG+V$C;Mqh%>wD6mn6`3fzIh4Ga=7Kb#HYgD21GU2J+3G)lV ze?8DNE4Cu$aVG|*DUXXw8eqoUdVY=u{3z927kIz0!`Z@WQSx9n7trf4rSg>$UG}k^ zpDZ=7Lpz?4lVi?jl|_oJhzvVD0EyW-=;krinj(seqDvfUI5((unS@^*Svfjw>C$1nVLfj zd;E+EQ#nrr&6c|})K65QDEX+N^A~ZJZ!!Cm{pX@%f!Nr8sO-~oBL*q}>xqm}{`KnU z#u}hZ2|ylx_+Q7pQuyCNU)kwOo#0Md@ub-fg{NK7A_C?scCN3(3tX~|vM*-yfcwuD z>njaV(a0eGYlb%4(V8xgVY}JOLePuwjo-#7tKs=`<${X=b<2;d;-Z_K2u#gM&P}a< zJ^dHMne{F}soFK~*4l?pZ_sPr#Uv{YNuvy|6+)8{81Kc&s9%nXHNBBzX!d*#oh4xWjwCMR$ z->*CE;xi^E7JFH)AIMdG`GNU_xnyo4l6H<(w+ksT%{2aaaphaY2s6!#THO;u6T$tW zvMdNTIdULCBuTMSZq7jRgVDeI^9|WyHDCu_YUhKRT5o)C34T$k(#)rbjae8W)Z&!z zF7zBbuEz1?o!d}n4|AEYD3@bvEEZ~0lybqP*mt@{%FEkq!{Z%UzjbgB zUbs#5ud;ADHP5&&W@#2R^a?OPgV#M`8{)-65gZ90pU7*T{vDr0fhKkDZF+mE$&0v@ zHO@43*MTY1HXZI7 z4RU%Z@F==?5fU!6odFpQGIu!5)g1{_B&AuuZb3Reb$V-mo>LO zZ-`eMLal1tFYt5q3!BJsi2%r<_i zaN5We=JQZuMrL+WhNaTEdNkbrfnJpn(o9+8hUHcekF8T;KZkLqy_xGocz`T;Sino; zlm$Elm}cPlzd>JoCm`7uj|1}PZKT(c%5Fg;eqN;#j(%f%mPgOO$QoC#w!h|3U}n9` zqp>hEIzb%GTXpBMRh%VZYBQ8>fT-Fx7gZP96PqlQlhmm1a*};~4omb&$9|3%zfiz7 z?ibph85#|c)eEu#{r0xB63$}(Gx_eoAn0beTunC`wKJe#APkqCE8vQpPlzWZ836Vk(K`s8c8ye*bV-~d6VyFzXU!~5+hiUi^2o6k?7r5ry zn4iW;uStu;K5GbyD0pIies>oAE(V(PxI(cgUqYI|vD)4y9)W>t-tt35jWo~U`kHXG zRGH6XQq%Wq9;H>wSI2e>nFL=0appj%nkX;1YZ38z`R=#Hs}-owCggFNj%4;DbiLNl zL+d!P-ihhI8LY8bMu?~~7gsX?prOIJOhgkR6oHXrF~8a$J#R2G4)}aRxH4O~&BVL| zOXjKeDNH~c2|41o<9bxFV0rxzDYDCajxwh9A(^eJ%uj2vO-Z)yb^5BwYAM?D$s9bH z*u`JJ>{<@_>D-|ean7*W`+tETDvSj)(MhB`W`#SZUR%OJ6yC8%o}0y8$o6K;m3D*x zUg+hX&Qs$OyurG4_-!oM`>j@dCwC(RmY%Rc;~E;0wrT$I3Uq_ORxRBP8`^J~7G~E; z8O(_xa3#r=r?T*89OH zU>P}0Z5tPy$n7a!;oWV9a5y18rKod4TpeZd+S~otLa^GVMVx4{R3z9irWAjgeA|E zbsuX;+Iov^%8l_RtMD_b&|*n^)0ih`WtLVxef{Aum(6E~*nDj{GyBcUvteM^lwJO! z2n6D>g!AnV{8c2)rG||b4JY%$>O^XP>p^@ThP;?|K5oggK(ePvZYl2#qT*C@HW z*9F8F0`u}dnPl2-l#mU7_vf|Mw^Xx=hDq$<2nN$}tDI>5`(0_RNA(Ci(*_3Wo~0Z` zJfUG&uLs$diEVd&QYVTbQ09{{YF~@*em5&~j~R=Wnw_%xncAi>T(yqXLb)6ompr%J zog@yO1;=tGOg$VTxD=R$autbAje=&_PS`!}3?J3X2~2M#v`5$FDH<;i;)~9)!Ax1f z%7|QvN~Z8uqWeNIh+XYg?_CLtIjX&^!@>fkR;n$REX|-B}Qn#3VU)=Q?pT4LgsE$tNP)`CWTBxA8+1N^Q(e|fieT*S~ zk+bL`U>Sw#R@uY(e{?)-^P_$ghs zN3?cod+LiSAjoGiLd-TLdzNL;+`J*+oXq-*oeppu{? z0>DYxI2;g@GB|$2t++CRzh<(RqfNmImXH%$(6@qk_r3LMS`;|SJyMIHZ6aA7>o-Tv zzP)RK(! zqo6HGS?UMj=N&4)%WcU1Lf3P2R@A4~R$4T*LvJh=bPtS>yUbsd*a{8X#GBWJ-&c`J z-6@S!|Js~LqwmUPsuYjnc*&LMx%G9Q?$Y4f8#=rDqKQjy?(po|j7<>sv1{+PFGT=T>&PX;&)((Z!o5~RqA{;Fd2`lb3+C0`66?> z80+@LzNV#3uyn;fLNVr;2=kS`N@>C`e9evW9ve0dxpPnX(9!_u-bqxI8F>^pDoHw9 z(Dy^LUIPeg;R!b8>RM8k5rzI!r%?2bUakH72b4fO^Q4O~QR4$fvh0 zh0dlL`7~gJj)1=v=PsnYWQhNMYyvTON;En4*JbgCHSDzObU z01HF6!XMhkz5~JU(jA`&(K+okDq;+!*4SXIN7^;2X0SStLc5Qe z6fA-YE6!@=Nl;`r4(CI?l~J4ZJEg01dX+tY%I1#DYv9WyVbJrEr}@RGFovXREs(y- zD0=|h=K*coW2bfrpSNwZ01FF?=A(OMFMk|a&SjL*b0VwoTQ-n>Ub_OdSzSgbgvO0a z%UPNAlH~|f=Kt~m-~clFt|xTBA+i1Cc7=o#*$`_DonpxhaGV1SCO)ned~9gJK{vsKMflC`gaB<4bZgc(dK0lgW*SvRbnF) zXV3dU46|F(c|K!LP=D$9Z6+J+q>~)a-<9Y+nT3Tk?(Pey;zLHSyIosd&#bSXgr80p z+TUKoe4x#K{lGi=zdQD>o#y7foM^ZEx%P~Yr#8hfRd84CVk&Y@-Hed8=(7-zc5xbx zW`2JGEp(q`YK@9w%1kg6J8I>7(>?j4V_f?&($g(2SVSx}j}b(!+C&a@6m(Rw9e*oM zo*x*SDtt*SS|a5%*Hc2Y5i!@_WNH>Cgqg^H8VvWoMtt)&y`hzrM^YU?jU*`)Zr;4s zxbfmeh$x;Tvu<@xp6zimiAKc;nUogIaCR?Fs4KW{L(RxUwvq*Laj7X`!> zC|eWHI2{$W=6WgiBuJ7i>?u2ADQ@dQ8E{<{a{n|3jGc!bju+bfE&`9Qc<&eGZ?Zd% zr1u3pH%67-YN+l_RM;9{%l5kHrbWmvLz6kh7D}4A33%J6Bn_m$nGeO~evB=vFeTrw z5LQV!d*8$Bk2q8I&mHh@)3~IDeE!y00$ZeT&d%-SRPTu_0L!crwb2m#dq+j%B<(}% zK;SI!_{?KL+-<5^79sl6Hg*wVLe)?Q-?%tfmOYKXFsmd|w1MOslc?&=9z-Rs#V@+ShJ`auZsO?aX#Gls?{gr(<*ruz!;;`7TRu8~r43$QoH?=A zX^q8zc=o!3@-AOZdK`%kpmy{T_nNXyK78(Sp! z^edy4-|b#6nE=+^_ffYRpqM=30Z%uzy8jTpVh(4yePa4J#c&k885|F))6A#?lbOYG zakM_O;uX?Wdfrqz=ySO0aiUOPLX4B1u5#Mo`@=VGn-Yop5|Mk{??jXavh19ftB& z4c3dbw2~rX-^+e@skS1f3k;n6N~1R-*M&-IVvwNI3^d9djjcvEvW&S65UU@ z;@5a*@69)5>R=J{8LzSAGMCQT18cgQcJvCYgU1TQ)?`L($$3PbDZT8>ML}Z@q@Xhpzi&xB@p|=CgR7n*!=ZR8Ix@E$NBod9d%>k!i5PMGN@=G z)%yKf3i$ag9GwD{ zm`Bu1L^T(!E7SR<^($8E*S}Ar;{Lr(YD0E$|8`$@sd?QO-voW9f6dXr&w-RgF#1qMD z_LfMf)x9l?vg-Bb+PCrXFh2(JBCmd*`a(OCtU^hK<2s$SZF0*X!!R?){W9fT>+}9; zjZB7wl=SKJ=p74hPGmg3L zj2m;pgXEKb#h33aR|w=osv%pW5Q<} zSv{ZIV4gsRXu2XUve|yK6AD>wRS#C_(0ogOcfg?IQ}v`#!-`$cj3mOSJlPn7itl-F zJy&DLJ8F%Tl+qM~*{o$Q>}#f*sHtONlXqv>KKq>clQJ4`MtW&uT&NOWZB68o6gsl@ zvB_o_F2mv@KbTEwGGs1il<`7D?Ypx|W%~_Ea(z-%Q<4?x(+obKV8Pq!VuFOWRFYNj z?!Sv}!j7MPKJq%?S6lh)`*jiOXbWo#Yf$*-f)3SY|;(xPCbl_6vVdOghIJKq}jh6{)8Ich~tS~}Xa zb_eGg6e3Kay7&RbcQ`DYa>_b5Bq{Kp(&!5rky9yD;KM9`l4I_?kYms29E-B6_M;HACY^Uo%U?Z z_G96AjpHMG)`OGPxe)8uIqq&o2G|J_y7qrr9;smZn6j`V^K!oX2mQsPNO)_Cb5(ho zZs{t~*)nOa8T)-JWS}cdU+mu){e;yUsuluI+`RXi$kUw+8k4JAH6paCsR!s^&CQI| z8VlSj<5K-^N}32z9(Taypk@I_QdE6mRsR!O4d=X*rY6wPaiD_D&CPp_%#`zPS`pQ0 z+e;>O8^cLM?N<{k0Ea7hdz-3f_q(JyH;hR%5D{eO|Fvu7KXZq*Q)Yu2AG8@apZ>e9 zJKz5Zq$6q%Nc9<;Dj+00UX~$A^ZivjP3{Ya#n~HXcF)M#0;UC2A)B+??2eYrfhgzo z_D+*FD*`V>hV+>!LUz2P=pdV8-E+s#(i{IkR_Vbui+YY8Ef{kP1ZR_mU)=s?A z5dk=bX%y0I`#CvD^%cV7=j~RN>eRXxI%|{R{$fu|(5`6h==X{Uv+A>d(q$jESsAv- zUS9pPi^Q4%MUba9J>0l?glTw@aN?tAvCLIbLioh=lLR)RRw~|1ut4M(C_ca{TD0Slly%W*ON&7z1`}U+rjG9_r*=b!O9z@ox_V($oCP@-% z0|krZj^$K5Usxs$oo*kw0e~GQR#TIKN>2_)Nxy-!Mk||+pT-9{iYA!+4W2bi&Oxr3 z5 z_;WSXu6>BBd;;8B-!I|?WYBR*${I1B4+OrH(7IuYNccntchb3_RhM7b##p0AR&s-2 zA-BoC$+U$?DscL`oA|hXExpXzMNT~%f{F@UzD3G|gQjYQH!M=ct}K<2y9NE2hndTa zvE}qKnyDl;apx1WO{A{Awc|Epn|w;(m0(I>$5V>xZxvB-MI71CO~D%A3TSgmAw`dN99mfgVosXykWQ zH5R#t4xHs?VHs>Z#FPd_cG>!Fb=+Nou3XBbr`|7<>wCl7bU>Z1$s`ddSQ8^=Af$d6H(2;rk?i4Z8{(e$T=UExft^X~;Osh7 znPz`~RGFr4us-cBJ8X}X_?x}`8{E>hDRt7|jpqn+5<|dtXJ`(pyJ~NEr*%kn)h3Bl zgAuHhnY2D5wE)�)x!IQb&8U364HVt}r>PhCz!PbhCBr90G0~3%8l@J@28JyI61e zu9l&$H&7f_XEr^#CkDmPz!!$5^yCeb@MISHV_hu_&!KATvZvUiZv#&NtHu89-2MLY zs%CNBh9Fa@yeeW`6ke{NA_;ftEN65g6h=FFk8huOJpZ5tX;1$<&z7*axk`NO3Q z^9wJwk1rW!`TKF-K-Pl1h-WTp*hJk?qCiJS=PcjJAE#13aebmc^Ls1nHge^hfSC3w?3jARrH3zx7qeh?NUESm=NgjBZ*5B=!rq5hyGn6{jm1(S;5X8!_WWa zU@m$cuRa&5gOg=~b;p(?hz9~hB!Rd~3gH<35fdh8cN(!b*V?cx92Vp<;_Mk$iR z*{bd~iFJ%E0FHVwbL$KYLe9|~ySm>`dx}CgXy@qTvk7duO>t1?qkl6|rJ+I}#kkZb zkW#1=PzIfeBi5onOD9dyZRO_N?Wl95&l>zj&DI@Ylrjz#tTLzTHcM0q4Vw=Bc9q1W zZlWjsA^go*4V#fdciZlAFkH2!HT!2Z+R*pCA1GB!5u zIyxOtZvY`$4$i(YSB6Ad*n*~dD!lNMM*0`K_(qpUy8zOVNy&tiPbn!4k!-;!hFHRkIkdwYZ~Wxzi+b^Y;yYNVdb01YMAb(sgUZ|_&j0pegsY{v!gMW zWKuopH_Qwn=fD~>7s{p16a-nfx98{!&p{-GXp}#6z(Ds)FSi$kB=ue*!?7QU&lwuW zIJSq4BkbVfGgc^FnmkIg&#SG!wl>q&58&@SU3YCFo4Z#FHg-Jy7Rol(tuI=!D&k@C zlx32d85P1Zy?K?_9U9TP#d)L;d*3f3_}1y}DGOQ%mlM-IngxP(B2EL=Ec*7l9%)zs zf@9%s;Py@CNacyiUpW4i)KM&>)DgVBZqNA)E#CTI`=cj_%(q5-kV;LCQ-Yz_YS_CTG(DB&Wi<0VRSBgs zwVbd8eiY=pRlB?dX4!Klk>X)_P`5X0mAvj!+sPD_)8v>cEmDSVcl?=8%?lbc&FuQ_ zOXiU6UGiii)@Jauz?YY?hqD}Zb745}(9KNnZ^gc~HBxQuNP<6Y9or6kDmd`K9#iV` z`e6BdZS;~nDf|>YzNb_kS>^TZR!M{e9jBQ3vFUj66oYU7;T0eiio6cJ{h#G;)}lY7 z=e5}@cZn{pywa#)KJfT$+^ccWdlK-3HS)c|&1z#tpDfTDVW=&mA4#k}_3(8YH+nny zz{0{~!z=J;_Y(=%yv{6~?K&bE2PD$}jqE3atFx>Kwjq`ryd%ceSx1zTQfy|+ZezN? z`)8sYGgl_*&?1|`tem{3l5NUG-A_B&;M#4oGX+|Yte^&v?-Ie`7j(igg{m`tdj$W6 z&eCKD;3f~Ei;n7l$K)w}t(HQ^l_re*o*{QpH6*YUAXu#fmKgWbRJmQA15pb#e}qmv z9w%0wcj)~4$LB+%8a}l4DK)KlNz3-%F!zfxxJ6+_TvT}M*{DCnBbQQ(W|JT{nDJuH zE1V3F>`Y#jKsh!2VbT!PAS$@^OVXo%?~Wdv0W?ZRT-hpuFET#qkgq)rJC!wAnEO48 zz$5%|TF64U@gqWD-jhu@Lg~OOQ4d{OTw^09E`f+8%#B04-gZP~Lm^dQ+d`+CjfKd} z!iC{cCPibt*~<=tUB})8*iN1DF;QG-iYv%gMt4w-ZZI;R>Laq|#?GNBa2qdb+IMKk zUpt|{2tF7yC1>Z8zBa7U*A~Wpaby7ok)-5EwOdiBg832#pGGzvjp?(^ECPt>c@U{H z07WTJoZ_&R37^Cb&30w9WfY78MPg9J4UpW_G_JKKT=rsm$yP^%{~)eOnH*R+b@}H= z=OMI$Nta2(XE2MK{VCxOHSNF>*}RAXcbVgd+m7!a2zm{eD(bw}rl&J+>PQgMDrqVU zX*!YaDWwO=lhYFl)lXp-1oY>!k@IPaskj440+LC@<)jW`kO@wU-B6KaJqcmJ=#OM9 z9F!HNl$n7oKKl8dshhS0gD2i7F_|a#41`o{{HL;%iQw+~G^?54p!($;v)hUAhU}N( zs!@XSWaf`jJKV3x5ubd(mD`qB{_En~`%lb9B9NhB0+c7op#lYT@|ZAZ6})0AE(wx) zG;pz*$LO>k1z9#RAv`EK*0oKuE+4q7p8;2a&es3*L!(h2?4Wk#7~D^N0XS5)3k^Cf z57%vwUFdTTWOrLxcr(X+U3E#%8XQbaWoJ$UN+Fz4==f`Gk%+BLUs1Eflc>^Laxss}_GO>_OnO<4>4=hVtE(`n-k1B71pA4f;5Z1(fk^XyONqWI! zy3${<|B9MQJ6C4xZZ+T{sT*Xuw0nA(9FIbPuWJCg42`dmCd3RyJ-~av90L(dL%5|u zBal{}vLPhzlPKG1>uu;bh#?O-K!Vunw7!h5>@l;J7G zJ$3^j5Q-#RPhXs%qe+wEuCd<0_#stPFGy2Y#fzQ<=dVcju9{I{V+Z<@r5 zb=CCL0zG<{NmY8yc{p*(iq6)CmzXS+$_`s zX#O?0swaN3M9td}lNb@+$WLKu5>;m!C$*rU9ZFd1vPh2OvovEvUtOhCn|-xJFW z%KlVG-#)OWeTU?0M@7ZaxnlS`r~Gw-ch3h(xRm~?@Z@FocnWq?^h2lh`1>%WfcY0w z<1X&*Tr~7_wbX`kMtLyaV;}*e11oiaVrDKz6O>#7M3Dl3F+gr)r&R*wTy9E(uCA9j z0UBZ1ukOjOp3f^yG??Whfj3?uSFvk$Lu+eQl0?5P+%ZN1_woA)7FW+aUycH`YbO4* zwi~;b$)>LvfN-i3`gk}cIYeNHuY>;%K6J$OsSVb&EVTj)cz(vivY-*aeLErtxA*M7 z66#Pc`BQ4D%-eRR7}HmBujFhSczgJ#wF!YWx9Hz_!g2f#)1*H<=ai6 z_qF%i7Xe#J!C}<>=>%LVS|H3;!z}7%8Z%A_q*|S-zpCFLM6%e7R=Ld$d0EHsyz9X5 zcsYu0tNdW%+l|ItF0}E8U=IgUSLSC8ghpanMtI=7HdhNk-IExWa_+0ZZBJF5|8>wahM2Oq9s%^xmSr-Z`V;$3#?cY^%sR&Iu?c!x*Vl%_A`4(+q{k5NQ}E^DZC>-*osZm+IS=)USrd< zbgNr@mDabUTseh@SZnVRe)M56gTY4pSnPbMaY{O5Rryg|D?)3xp9!mit1zF#O}?3) zDZ54D{AQH2jg%@v1AB!$YDA%gm6mIoN!GH~X_$L(+lB2JAaTmKSoAfM%sEZzO}kFH zso`2%{-CNWldF)MuXwChb>*VEUwW_MiFM-1J}poti@L4~KM62YJ){%7@TmXw)UgQ4 zW0a0Yri7XQ&~#u5DnyB$DX#mddCkUmP`}?vK~C|}^p~O&U~U-_0>hH(^!ZD*7D-zS{ETuU~V1cEfI4({~DUD=JSSCs3M9G8qF*>!5LHeA5_pc=mn% z8TC~&Y{zY(oXZmR2q;?L`7<&-w7JISLa-ttoD7}L8uNIS4bj%!o;Qb~uzc?)e<}i_11|q@GZlC~G`m?2Uuf!@J1aw(P2>r1 zF7Wm{@6ivDwyEj6R>;2VB$YVX^|HOvX2&@H>7nY64ve(V-u1y|e%xTQ<2JeT_t{Cr zm`1+AM2cu+4Y&E zOk=QX{!Q8(9^4E`&y`ko%MAGQOTGpJd2HTOE-KciC-mO4Z9AH7U>IN+AX$v6Pslc( z5-!@yIjV)6e?oM`rYClCs7oo)$2i)XbAPiMK3S}^QuPYxh4t(+NUiTB4asId5!%>i z@6`-CrYf1=3-yDf&FX{H>qFO*h7Ok$dS`|Pib4)m&N6vr4ZyU5)93uG0fisBP!fEJ zcLgaXn!4w3XxY^*n|;gOuIBP?&*kR8^{(aiFmT&BHl1fP6l_w(CROZX!G3^&z~C1o zUolXUd_|~MgldWN6^TG7D%y5nx7%}jbI0}7E$45}xw^Qd-W@1?V6|Mc-S0TmHBH@6 z*9}eG&^E2g)efr0<&x&W6DfS6@Q%_u7QwR!PFWe_hVaHcr|&w~%sbn+h zZuWfj*Bd>{ zhx4&~?g&>CZpbYY;C#+K7<3t0$FoPeFn%}q5kn(5UM?1R3xCX-%=`=i^Vi3kTORrR zNXo-O^Awiv{k{==N$mpV`DF&g8E{Q9&fU(58xqLNIs_7tAts(YeVb5}^j%9^*UBN@ z&*GG`>LW=4GKe4FW;?|;#Qnw2-*OXTm|vsg{Ay8g^5_wL2yEJxx>gd5*aJxgfLwwq6q>7;lxEj?ma7$2 zQ9?V=?`qmZBS1HGaYE}-gpwjBKr+pe&zy3SSw@+!4C&gOd#`x!q3`9iheB&e32)(G zE^B$RbHHpfFge7$aOMarsK`sfnD8k zXgc;S)Ptvsp6Dx*ufSC#SK_Qf-!Mp$SyW5btCj48!$5GJ^nI?-#D`rMS z?dxQ|16o4E8D`qZYi9^_0$MGy?A}OfvP@>mLtn96E-dlOQd%LikLEDG4C~$tW-{{E zBlS$-6x4U;M994%>RB7nLe`RvusZGYj27~Fa@NXw&hDM1`KWL>-P=q>M%<<8kjBF~ z%K;IJsZg0QvU%RKc|)d;`%FjIcUG*ZBM#E2r4%{Tdm~a6N5|6k_I=NrH*fgz%P+aS zyrwJ`1Ybh(I9IY-p0M3EJpbwqKl|Ai{PGvS=JMhW@0XP28b?7tK#GZ?P`(3~LvPJ- zG&d!(F^Al|-t(4GWwJlXa6mqM@5}h-8*o8p9B1bkJk8IE*?BHM*X8p^wlH5g-ajRo z4^xViWy#6O3BjT+hCxvP!=T6=@09vX_qTi5voeE|pER<-Mg%`aN#qW%HO^s_U*8Jb2wVI|*j*Z||~(!X|UHcRRcb6h07Kz$NI1NI%G$rttLuhn$w+dxHuYHy*wFXJ)E_uxMqsz4-tTGa16`{UqsbK{CjuXW zm~2&569etd+0{AoO4drMMLq@)U|%f*7OYbmRe)6-*)j#ftK&v^dgCD&Ki z^!-3lRKx+wa!FAvY1_o}=V$z@pZ=WBKYzjH#T{*zsH!y~RAV_@+2$Sn(3|sQLGb2V zVxe%EY07ly8=K)f!(R63{<(9A$@iHulo~|+h6NRF(49s6(R_NNLAHP?P11Spuhw(I z{|?7$wdB#GN8lWFUDI_P-Z@Lb4L+C#$6#T+|9H>bN5R3=Cwq>Auz2_P{&XZJnaF?b z;z^yKC(I??AOnSF)DSKrdF2cPzoh^-jxe@pAH49D3YA$m)$&yx41f_s2R6jvku;jRu%sxfd z?wH-mhrsERCs0;wyPnPV0MU<23}OxoM^3vUHMoPKDsUcB-;ufw=U`El%2D4dY%_QV zu_q3_d_FL{lsT$71hXW0=_ay-F9hby!#&Byps5_^AWxc^2}U59Y-QMb$&BNOo$9S? zZYMkQTnZUtV(6pRC>e|;XBiNkDifL#T>1HOvK4tJj5g6YL1-SMG-Fv?A!dWrlTt^F zJ$;O{5e^CVF;NeRT^G5n8*cVBH@gGZy93wT12_8vcZZg3+q3T?O>*?UVDKfa^E8&D zyRqtPxeV)OyJNT8E6r=$(RMvCIfiJ8eHVxX`sir;MBNP>nt^@OQ#T!L({ecMX%4mR zeKE~dQLrfG6k7z#cIlm>8=T&i%}}{6JP_Q(1dL93Y1+G!s$aPl6uFQy$5n)&MW3IS z*L=h&V>5WLZ~3RZC-qF7;b!<}LICsEh#toKrP;l6OXHv1a)0gH*hjl^j%ae5e|K`i zX5K$9xYIleH)NbPskW6628SHSTw=MbSg%(kBDc3Uyn6kH>#JM#`-XmqI9E^P-`TR#8%1;6~omt0=lvEO%yjupxtnw|2-^s{q&wMoI|labdLqfMjF(Y=@U=r~yh zGbtZ;(;{YCm;F^z#{Kz~r*(EO^=rbZI%xOBq6F>U)|=Vi-|#&p`mU21t!d0xNWV>> zsPQGNKlbcQ^ye*2)NOo{5qx{zy-sM9`L}%G2(NR%nR+8aV1T`^TaHgoSS^=$2Tffw zSY;n#ROYdiZK@i`oCDJlMr4==lpi-TB_rV#$2aer`aAaC-XS?zU^OKf!1L3!OqxVp zr3_}O0M*uw2!6V6-f-rvuZ?IMas-Zy2quE>oQQl%>YDc=8X{l1Cc}1~i@c`e8X3^V zlt$;NJn+#m&{K#H2zp z!;p-~8_^#L{`5*H&1^#JlO@L-HYEZ-bNC~xuY1+(PL{(T(>6F5e4q;zy)Wr}p%;OD zpV+k>+oogNwA}7%ZubqhdlCNIL(Qh{*fbrRrf1u99O?sYy{9?sI9R5>-R{6{YZc)R z2lo4h-J#~tbkt2p(+_k*qKl4hfOc?ngQJTwA@ps_&~>y;L)W#qlxXXkyW1NMhaG*_ z5&M2L+jwW8jKN-Bp^$}l@|p0q$Fl0%o5Y>>pY6S}Dn;yTcSatLsbNoS$)Xb4y)!cwbT!72cKfJ#05MFP@+A*=NuB z^2^s;U+?I952*xK;#@H@(3xn><8lBoWcTdl=ADkll(Jc8#FF{C{CT>Lbf4JABxF?- zf#qt+a=oPQ`g?>t!&2^FzC8E&{>sn4P0vpg!Vxo&HIn&d6$qQAv0^wgjlqLu9LM!= ze6wdeJFH8mc?pYme*CBRPMUqugEBWblio3a883SHFoosRP0MP%=4iE|3WY+JT2&m9 zYHlL-&Is46m)eZhk+I`hQnTkJ1KHg7{5|(o$Mvq?^6i}vuglsBEo26^EJHiQoOmF` zNZ+;W_d9J4OPb(=mj^fKw|Wd1IAnKm7H z139z(d&RIvOT#J{Go~?bS_~+%#BVT|G7+#^1=&$E_HtCq1YhuBX;Fm%^sG493dQux zmqE`TXW8^Z1Hs9u&AUVzI?`ZO_)HTfoNI8IbnpDam;y2bB0w|Zr}a%{LP#h*b)TRc z;Lr{1>Wz_v|{yu7zzA+0-3(`<9!# zJ-3@3cN;MU`@=yw+D#*(ohG$Yit=EVM+RJ9UGeMBzu?u2m)u-k%M5U+X$}YawuNC( zNTY>8ir`BN;4Mm~v`TRbr4u8ojC6{yI9eZ3nd&~91_=4B3E@+xa zS*}UZ%Uf`C#$=r9nO)_M zf9F3MS%?g5de6u5!94l;G7=q|`DEAWyCeEQmmJmVh)+KLgm>P4+q{5x9QHf<`atTH zeT|{Rr9o1RQ@wKM6&mP^f>7jSJUQK{Is15p?kRjv-u4*hnx)$ursu|Y5z6F(Y?-qV z3}-5=?0HOzs_xeJ1QJ8na(i{ftLI7-@!k5!i&v@zx=CT;{1|CiHb={8kiF>=OU?a zRF97FRY`0+`a_HFBb5tu`qj+y0`vM+=0#g`bBGy|#oy=TPp0N8Lm+lNLnqbwVA|K_Y})zKtLpmns(;h2cO zHcJFIkQfw3Sg3GQ-}f^@nGtigZGOEO4pQHpY^-kPz!id}U^T}SXP1KqZN;iR-7CyIa-z+FH6cG2fflf^1am&@D4Fe-gC5Gvs^C6+VUX; zuCK3o_39;u{T}ZfWfADQjzv{*WVPl`PL4S`KH~UD@2k~{qFUgJlH`NnAV&JGr|ViP zm78tUYH~!&arw3b%wbB*?X({rw#@uylR;4^1XJhhexuZ7Eg=En|EFz)so&geCy#&C zg!AStnKr5@3gmjCJO<-_FgWmD4DadbDc-99&-3RmIKQ|cB_&St&J$zcX#JSBOPmMwpy4 zloM_;fyAyIH}}|Sz0alp@jZ{#@VmO8{u*Qh;7Aa6`C{v#4rO4;=gi;l17GGM zopU4~peX5L;@Pve_|E$uaC&^gn>TMb>~^&KJww;v(*Ruyu`|`Bh3t7F+@VlbFjGPM zAQiM9nF8gq&xGGOF$&H+Wo7>tVIP?kV+4}D^29qtZ@n{Q7!_mIw+*T9=-Y4RTLy8s-k4ITyog$xxKxC1gqtevM8yFg7?1tZ5Hpm z!`Y$c&;RnTNNxeHqK}g2%c3x~^FXrXJ44|pPuIArV5nQ#eS_}?iZ0^1VWz1F^u4L@ zonr9wz8ArlvtfF{|)xtC7TP~%Xz7Ry?2NwbjrUF z6KNRehe+3{Bx{T+rJ0$toaY@(0?+$s6hb8JCpUoW!3`9lkme;j8TP&GsmT~sgs8NP zb2!lbk~v*Q(ikO@o#MRrN=(!D%Khz?Z7r{}cV4Pnn~RiR!gVqSp*`V|Stc-0xJcn5 zm5UrL3l@cAT?LL7CF^CydQq}ks)*5|Dk#l)Y*AI3SA*HU@06@1$+@%ZT4^*)be#qH7l?K#z5P2Ci9<&=HV{8exBoL zKM8y?kr(0~8H;?r&F7p5&9>v$o1xUd@f^698vL8voQVGGnqu!2ir0x53^HG3NqA9~ ztkx^M_gr0Fa(;fv-Q9-Xd{hRDofZ7AxVt^@#TPI6>Z_MrU)|Dmi4+6F;7BRpC~!`> z1W0*<7@>Ej{mXYUS@<(>t%C3&i#D6`s_v;Xy0wUv&qbvX_cH!cIN-#t*%Tq z1v<3O(kvP?;UEeT>8YbB&}23v5<)VGN_9Em!4bC0Tl33d|GIX0Gj{dm7j*e8Is zYttyA=QnrqcmAU!0w^_e{>6>N+=l4%Irk~$-;Ha^6Y55S?}%1iuBw*2{my%Q`pKu< z-EFzKx}n+ch+RwUTj*QMLEeivpgPo9E$J=khY#{P4VG_zl&I~y2<9Z==kl`J_;Z`~ zoZ#nCYI3}n=P^mD;MjFEhaGKQ({~N^e#hO-jY61g_=TyuoN>gHb|Et!>T5Kou3cU8 z^x0cHdG?IOa!sEST|W>}zcA;)`64r0=%g=SJFaHHb^mQz@cGxgmiJE7$7r7Lh4(_z z&U1NwK1yG!#ga03-hTI8j=%M7F8hH$`0?*_^~;d|p=v)V0hGABYA#{wr)%GV(!FbO|vg{q<;0DaRM!MBZ*|&F znwN>DtV%nkf5G4)Z>+u_Xj_Zg@PV=@@m@Cgp*Lrn2b#vr001Nxi9QjX@}b`&_+1X+ zvpyQ4*D_~#ok2)mMAIN>-$*mzgS0hW-xA?<@z7PJb3>a$5| z!D?C*%2HODT7R*qSS%J+UU+Hs1{PxkfX{o=G+zDCThbm&$%~M8Mz{&h%lIv6Z`h2e z*&?T;-}8C*7C-;~H?@Dw&x(Ax-|k~;qg#&QKId5UsDN{;=$=KSJ@SFg@_^X7`X+YN0uQ22_JJaLe-s>@buXdJNc4x9 zDnA;82Qv?5f~fTuq-5q)nlMTEcF$>-+1KfMh4yLOneHXB1Fp7 zD7eh4cU_;v0yj@5ES(=>Elhr_WbOM*w)+AR6boAWE$rnebXr-O4M z_=u1vlm<2|DqImPW7>clB1LleIC%``ImrDc*_>vsI?qMAPg$LF3K>gE9h$~eqy`}N zIgd~9J%L9y9YJD!AeMHsUX>Btt>JgB%+7tP*El? z$WtD8OHG^1EOc*AKZI74m?S!U3=}C42zZn%DBwtgG!vM!V{qQ~cT!CWBdE!IEg-6d zbsQ+7A|zZ=IO3@GcdCDZFX>Z3n+ocoVB0xv>%{dzughKJd^>QxIk4I8*xYTo-5j{v zHEi}R+e6E)?m4uPwoCMbV@QhUz!geN6e?U;;CulT#N_CQMBQ}Mb;EAIXLGmZ=H`~0 zn_F&g@3_6Wty8+Dp%#y%6y;zFN@a91AP<)b~Aicek9M zpY!I;Ir~FRiXQJ5c)tKj+QxBpwdMI&Z}|N47rcCN&UV|-4-V%Fa6vw{D31n6YpMNe z(x(ypjP33?q8vd06W*LZS5MNhiCj%gWp0_IPQT@Ey2teG-TrqNDW{S!IVHE+NDE>*RJ1YM^(C->QWj65wi51O?M zAk&=W+0DPtS3Zu6RgQa(td>hvC9`TyIaG16tXQ0!GK7MQ%NusPTB(C^IJ`=%#)vmF zowvnAr_m;0cIcFuKy+ZH?v$dO6CZ_<^{pRzn*Ib5C{)enqSNwDAl?v8` z9PN!HW>~8vkNr_HN+um;Es7szuLM33Q_qlkC7m&6phVthHts~`##h0^}i?hQLAw{cN0h4s|lpIvOHyTEy{l{x{o-U;F+|%{{nY&}~QU z^83dhT>tQpX-Y!y#_&ZJi<0BxBX-*@FJHdo#fukgH(UBXQuqqzDo6oRN#8l1fAxl+ z|Lik9|Li%NO-07bdF`~%lk7CP3p}%!d`AJb?96*!M&#U{&_l<2d0DLE%JR6 zBeBdG`^E{g9?2)b@GDuXnCDb4Id{sJr_2eAifj^*778Z~ukJY~?)Iedz(nlxu%^@Q zk6`?MZye((_eY(^JIvdaf=m=?**kdPnMNVy8@9iY=D477F4VZWz29Ed~Ddbwo1Ub0-swwqE?#<6Lr5c0$Y+0>lS?Y;K3 zohvoBAi}o17D1=m+G<=GJnVhc(imts-KOt*A-$Bn;^Fl8m^ef>cXu>(!|`g#qAWOl zbjsroKcZW%_^V%h!Sk=qaIV7n5(uMuR{Xt~hruVR(;HHgxi{ zz)>z1EJ`^Y4Q)r)wD<(24|tR)NS@C23~iQa-`Ms{!XiZT@-HoWW8ZaS=&F+ofp&OS zgWjVJ#|f$4;Bgh=ym(mFVlj#o~y(jt_>QCRP?drN2o&5%r z?lLmZJf3rtMrvGmYiTwof7|9TmHzCyhbH~J*Y(J6e!zH55;I(ez{$xGtJRXjVaG3j z`3ug^&*;rm6{91B3hye)a?Q{O-n_Zyr$7A}FJE5Jwh>&(5G@CW73k4=nE7R_Bqtb> zHf!Ey1Ih5`2Anyyj^x)&apPth;VNHf@0JM=lXUapz8}U7MWGmoLm-cO(5+1PBh9X0bQIq@MYqjJ2Jw`12_;EXC~l2gTOt4pRdp2gPk?w z1Rgr#VrRPJ-~M0g{x*-A4^4vb$FvwpGbLi_m?kfuYd|N2lO&CJhbtDiuwY1m}_0v%d^*X^^Vvch;2ja>(Q%wRPQ@;e9Jka&7q6zAeWu?>{wBjM&NTrI~DxU zg2;(a6#>mpAWP;6h_WL#hduk!-vL*!t82PAXhD2Iaw^#>y7z$Ke?yxu^w?~p zjbD>ZCB}i;zkKdJut);9?8WVIltsa6v1Gg5vc21|T$HS;l9SUDo__cd9G~#Z&!6+z zXD>*p!26Pvf^6r;Aqxlx1`mtVBZ}pM*z~mfT4_5C*d@_x+&)-kC<~J*%){J)Lgcb4 z&4-K=@ImD!Meyfd`V*oM%F$fdN0L3Ss4~HiN-G+BlJg9B3Jd*mN&W#{-B36`W}b_K z(z0svY9~$llDw@|O`Xf$=04jfvNWUz1A>qFcMQ>u-E>Y-F}|c5gg`Tc;7zlpyaJKn zAq~ByE|!0Q-k}U$Hu`G8x^kQ>J?qM`TrSM+ycomsjF-3m7#>OLzYzP386Y!c32#{% zgE0XrETl5StJR976&>=0<*K*LoFKmrrJ>D^n-8TtCWJn=Nt5uf&95DCD;apcq0M0H z8*u^?oCoJPIXNZ`J=^V;>#IvHFE7~bcUn`E(n+4OT*>?X;*RIf&v^d)jP0hO?;SA) z?Q`#?K{Cyl{4SKRCm8{BsC;j<=#MCfpWEAv)i)WZRKogJ|da9NlB*OiQwy%ADPGm zKfljE8=QOL9(U1Pal%f@2aF~R^xDa_c>_@GO5s17|bY3R@ z0$}gtco)2fP!e6i5FJe)IXZpBJ8!?smBqh48qwiYk!-l5b;=E^hbWFKePMf^>1t-fDi=w1(j?Q_u{lKPaIqYgSHyd7T8y4UBm?s~9kJHn) zAyw@6J7Q{0Ix0!AkON4F2DJbBmVp2!>FOH+MyHIx_7MGGYw19$s=;FMo#*)Ih_-9l zZng}4%jwCQK;zJQ^))J;c&jdfn&N=4cpT~NSS4>xr zYn+#tD2*PaiV^7D~~1Iwt2oOSYsL5`i{p-I+-zct>F&fR$CaTUc_PWmU1LN>+=CWmT}K z^ji^>tS2~UrpD~MFfjlz%10ybA!qPV1XT_!i$c#@R7&Pkl`Iwu%StKd!4S+J!!j>M zq;(jE!Td8+XGG7`Y`JXTw%N!Un%q)iWLlg_r_&so&x@AI;CV*K9D)vGybBvc2%fe+ zaD8>f)zvkd&6c+74Nn$|t9J!4dakbSxH!Mz_3KN{&aP#)bCojWMMq4c9SO^`kC_6; z{bg%z<Z1O0P~)vQ=*(9$M}y$j%@!rmGhqWM~~C@@!9re+)7M@e>!m*%XE&$kw-N? z#;$QQSV$@1PJZ+srXi|K-<)WVbBS$Qd&iuJm>o|U(40tx09IuZy%%>sB*%~(T>^Z; z$>}L?z5On4z4aEm?UwD`9o=Ei(6*$uA+|L>4yvP`WFv9GkqjwhLM|pCm(n%DpKYQ! zl+WvxiM=yZ06~PmK#oqNMAI}h^`54_g;-M_tqH3&u3S(g@DYpQFYrUlop6fy6#<3avdWV`vaTH4R5}D#ee(N8*ZPykAMHW94()b`igqL#Zgm) z1aUzeDs3De6~6ViXcG`k2zvZ21MUbIc3eL`JOH|jNvlE>ILCUu#yiiUKCs=~^61eq zi$%#h-}->lr*Ct9b<2PMFaDA~2BHg0HRBS#@Rqt)wl7yoZ6A@EG<5^9?ddIbu|tk` z$>L!35~6b>q7%?ZgzW^YS;CjvT|`;ZEh(vDTi%40a+R!Au#9!S2$ajEvLIUYiZjmy zpDg`t-_x~LG|D)8l5F~Og!W)5M&c@ZtA81hc<;pUn9l(-MEd@%{qTwL*ZT|%rtewevE%up&3nGjH#MD`@rjyF%@@oF-fW)k6Ei#0`XYorF&pDJ zoT4ZSi{oDufmKzoS`@6RlA~2+gx_9eu=KrRL}i{3q>i@bluR2C&7skJCrsNQtxTY* z3Kol!<)V_gVYy^cRfMXds45uokr+`kMWrB_>BvF7dv?`--l2?Drkl*IS-Hf5Z9t zHMe&=+BOnGiTA}Ug|?S(Na|TWRU6_op>zG}WIVig< z1l=b(1@I_L&od-PQ7t$+IpOi6$GrQ_J8U;w4x2mL!-4Lw#}6G0y%O{cJylhxM!DJE z{3yYj)E@Mn3H-)hL__zQ5AM)(Yo5LR9;Z*S1IVxKu&3wy*#3M|VCm!KUP2u7mqP!xu< z+VB~P#B3EaqVEc2AM=HZcMPp6@8v``(e_OUc2~1ij%J2$z%3Y|&C)$C;jJKz_bR~~ zbA9n~ybo_OYqJN)li3bug70O+&jjDQ90NbQbawxIY<&L>T8ar#{S9pL0-*Lb>i z4kHsz5Ft*+y!(s;@4?Oero$6{1PFf0r=P|!KEbyEt`i^?Lg{bnQvF`yR_<18( zys>jq<0|1smipxYmsR~bHrez=@Fiu2D9J6wMBB97+*}ii#PP|BqEsfYvZ|Cgf`X&M zQM6m)-5Edr@PvQ+Cm-{}PrgH2A1ED^&QUq}7PK+4tvk*(1AqPNGyY#c{fzyS_oQ#b~TSqPkH>-J3M;wHojc)pZ~Le&fUIY5Y@zoKsOTn5?^@w*sJnjippeH z7F3}mMCcBU)msctm;DdZZ5S`(6^dB~Kbg zN#Alj6bf^T{Xp!eijZlRz$4EU3E3}a2<)}nTX`XG5eFFeai00uh_uB}Ah8i+LWHvVsTSnfwX*jb!%n)6M zdEp-m22GYQ%PJX81&8z^=Mb=b{AH=s)61&l*^@^cnZ5q__=uzRimEClH6sUB^@^TT!z2Fx@!{$}u-=Th%>zmd7g zWXaLB-DpCN=ImRRCC>b6CW1U~6Oo>#Pksg(RwnqmK2N@^K9jj(PVBMkrtun{9mkNL zt=X9dJtO!@vnJ+pey^#GV@a6yNnhsklJ|SwhcQLm$&dbnl(PXPQ(cOPk8JML#tl4w z&m6qn*x7eyoKlMPQK5M*6u7dKdOs$TyB`vc{&;P_;1iDOh9 z&r#z2f)m#gub%V%iRT~u-lzQ04?kd8B+4>S_(Vw302JOcv>m%c$1krM{`~WE{@Y)@ zA-wln?3YihnwcDZ3hxxloq9r)EiH#a{cT#_6jPh78#l@WAk-z(HEsknsjZ#G_yaUe zLrRI0lM{}QkLmlCtIKoN>ot#`y~DG2-eY<6h=2ND{8!v=YYX4<3@PHx1{%r$KG6;L z3BE4^l`mO@g09wj$H6#T>z_C2oV>Z5sqpe9%FZ!nyDp0oZ-_uDa*f+rEP76CQGCs8N_C{_*zqzKil7PEcF|@@=Z;1WQ-c9P|57M z8I6p$AK`D-W^=8k`z2!_gfz`h#7RVPnII=6k5Y=@i7?B~Yfh1-@e2-I?3J&-P!9g( zV!>*;F=ZgljLnofk~Vb!d71$SlFjDL*7!?X5WD9 zfLIwbuvjcuR3)LP@ImE^qa_9F`i|Zhab;GN33ItvG7JMv)3V>~xxT*P^5T-+Zbv`J z2`*7E44$G`f(slDHE+%?`Sq92Ils83ZaPT8av#`pji=EoNjo6X-n`TwLX#HuJ^`GX zV_M()_(?5maB`an>;2}PW9WM&Us{xOZAV=nCc+)_Lnh{dS-%n%mWpVK`eWzAs9l%{ z@;CK)e$NME&V9CLk0Z$Ek~IODaN9B4|9T&9Ft%|n^0Q`hqv1{jUvn1;)muOMQ{7b3 ziHP=i%juPm%{Yef&ZCq+ZA^y$)isV@| zcPw^i{J|%0^TQ9{Bs`nYf8(a>zG;K-0Ccqe(+}A*o*BE*_q~A7a{RB?EBd}8#VGU4@hPkI z5zk+|;!roz8au}@D4na+%eGB&*a||_-Z=t}(g$MSn}b>Ax<&A^_CZUV`!xsn>AQ1| zkkyUos|G43BL7Y0$l#C9m;T#ZkRffd9yahH)J1-nM0hir)9LPFj>nDDDz^Hd9hE> z4~f3ltLX;zb;oYsu-P5B+w8f%-Ewt($JO;6*EbukZZ_O*c5HVw`?{rWdlb?i@I^%^ zl|ooAa~Q_US0vYB=zF@Zr)^p#5Zdk8+-;OJ==zSk+l{@p+}&-c4>e7FAjL>o7AzOa zh__f)EEg43S;+Bo=()YQ<^1fNH?PmQyt-z)+0k_aB#-ljh1s33+Yh{cbIBK9zU0d< zUvY79LtXboD{zydyyC}gL|$?^=xO@1liCBg7~AwY84Tt{)%9Or+=So(1QYr7usO8H zz4sg+A8~wqj1S(5v}vwWN{XgPBO)=V(r0HIC%=n6%+J%O3~-r7j*P(A?3xVoxxZt# zGb~T{v}v$E_s1tHXL#h^FZuU}AEuVc__RH=CqnV`hku%E(9?DH>EVs+F3x^S_Uvu9)#of{&l?`WHv`f#8sOMF?8e2~-~2Z|IaUBE|J9IpA!vgIHA@Y{Unt;bZ} zu_!He-Y30WBE*4yv*qUUmcM#^%P($P`sy*EdQ3Nzv?D?D?~ZRQQ(Eqtu-9-kaTCvRp{LFWncJnyj^YFz95T^6({`q^J?>x8j4x~AAI6G#89A7$T{yCrb8(NyiIbkAW z0&)+gKV!@AoRB1!>{e5Vr@d^3RF+t;ND$#Si@$RP_=4mL(@uH10qS;Oe-Hz3x7~Ad zx8wG1%gxDr#AZmACq z`(4d$t1N=IH@Do~-Ll!-(X}lOM^zPL3S&9s!O(YX?lxRrUT|@K$<56jP2I}=?kl`6 zAbGmZv)T51`TT+}e*JQ zU07)9R9~+9NKm1eYB&CcSO;_hD?AT0v7~l0l zldr4wQOC8k_ca2}Y0!DHGO{azr><+Z+btmko;`bu5DLq1rhMaLSfx$sG^TvNOr$0$ zEl<22X9PbcnFa={Ej~nswxg+Q`mSZMSm2AmVC2@PD7$=0gs$PJz2Of(e#VbKdW*-W zM~WRzaukv(AA*Z8BzBvc7jJI(SLb`4wTP6*b*}gp8;{4%lpS*stK=)G;iKJdUIA=Ef*Xg9hv0sS+3R`9iMV}b2q-?96xc&@r7(8l&XQX7Xk_-@{ z9Pd(2Sd@^nU6S*kcTRS6Q!9FJ@#=AcAu>aP;At3o`nEGz-IjHC20BCY9Iem(5+Z)$%NA)ohC{Z=2xF^tcj zos%!h_r2Fg)VEye%;~BT2N|AnNa7evHIpU$*`1tII#B22qY)D^S`RIMhI82zXfIc& zcv2s!o1X2y=JsyG)%6XRm)D$MUh(GqlJm0*wwpbh&7R%9rD-DF;8aKkuZ(ndzm&jv zIk*;OIok4bjDL&+UEgy!95~c9ZQCg{IQQL5l|zg)b<5pm%l^<%*Bxy)FhoyLE~%Stf@tIxmU^74khkNBdZ?<2TCQC5Vaw0r_nWR`Oo-_PvgNuTF<{+nA~ zXT9gO)L(=7`7LH(^$^CUXH6@b67+p%HRY88T&I1LL_Xaw z5BYe~uj6_5U|#*6AamC2IWFVr{IfQWoijf)T|Z8v4K1%vSibW+e<~?Pi|R}bsO>Yo z=6AZkt`kvrGl|~W=F0DR(@xHTnJCKv%Q-pWb$!R>^))fU>66DSS1Sf9R$_Oy$EqWG z)4gT4GXTtv7CFu~OF6T1hQ7rUVTdZ?($qMMi%woIQlbn6rE`S#Kv8da<`4YC-}!)V z9ea+}OUgw>*EFn`6+T5`-!k+qae&=E^4Y6vesMQ&?vHV+$HY|74T+Y4-itGK3FTXN zJsz`ly1zZa|JyaohBbbh!`Ph2WP)#N8Z%(eC1FYV!K(mKQC1wEKH~On%jNa8NfpLI zT6QgOSq-Jxk-bsA5l(B+w!}_m0%yr_WH&b{eOx=!LW~4I6LkG?nYlo=z3F=0FAl1n zR|L;;vA~<@LE%g0{hhBdRr@du46T@vJbq`M@VTbCH)bJk_zdIs)Y@eDoW|hu{vm4% zv=-Bt)b4G&ueIqJdE;j@K_>Wl(@%`>bpCv9r{8R!{f3qi;nxu2yxH~otNY$N+rB@1 z%5?q%JY>Y&EPIeOF!r3O`(nhhf0BMvje<$-pI>>n(j+Q;F1vVo`J*K4T|G&J$vluy zkr?Eg)b)|3>AAeP;o|(3H)l7zdUM6AR~NiKyX5+M!)ABjP`5N)j}L{$Vj3Ce6@Hx1 zCUC~U%IxPU%LS{|n$_A8f>jGbQ4kX}O-J2y9QFP;OWUYSHBK77m~sS)BBhED2!%Ngx{0xxxBIa1O>m+$ z9-Fgc{LQeJ&vPhZE5=CMw(Jjknp*xwqAS9mqBXkaH@2_A@gz`8fI=DF`JnT`%Bv}7>P=Imv^+wC~i4L$_cN5@oUB?pyc8{MAcG%_22 zA(WY9Z;v2l#F5WUku2te#OEJtjscDS?i`$s64pf%8t@#3{M| zKM;JihpQ{Vn0|ADsPWifDNq&aBEr`9ox+>eYjAReJUV&AcDv{L`j)2cNJ)qSM0AE> zAX+Z|(PljibZx6m+S~6Yfok0{v6}iyhSQ`il>0qypfSg~vbPjIJm%c9`u=!hqe zA5#|6B&kS_U?-a}LUzhB#>1P`EM{arrmTWjpGWh^gN}AA3@B`;kFW8Z%=|of={jS`)eE#Yr)PYV z-8ZlMH;vF41FA1h#6E}S8o`+)MV+WQyf+lX8}pZ)nG@h-O+d2VB)c->H0$N~`%Dv% z5Oa_sst)H$5`jKCnzm=RuerI~a(R8j+4&`}-kkCJ%{k}im)zXmvD+W0+m5~;h$!=B zQC1Y?f~s0kgvvtwR#b}>Arw|Ev;;i;0Ed0c{?O8Pk-m4doe}!azT~sdzv9iCOLm8j zAq8Bha4x6@L9e1_0H#1$zc@GUbLY&v+n5dshSHEl!?Q7IA2_RE`OPi=Fr6^M$^5_w zANjz;CI&6<5fMAt=tt*mi(b%Ax?eQm5~kaV3QhOODu2O4W(4h;abO1T2IwO^j_~`i z{e}tojT1FHp2vBwP5nqb`2B0=+EDFJN{LWC`{AGF8*7~N4L5s@8+ZCu$7U0lCtw`) z#0O2+W1Y=NM~FBd*SU^v7-&07QRy6&g|uL~ic`MMF$iv2D)bg5ZQ)=_NWM0sgH~*ei$MOph#kj0iOCFt`s(ftQjwNKt^O5HY zX<(Fu$TS5rb*6Q~`f8u&b3P)G$xmV&gPFBPxSQGVb;AAYbMxP%;V{lWB}DMe6cN)5 z?$gX^&+av6O6HH5#;AVg?<0a7kBO;sPD9Jc)j361s9)yh{UF3?_O$W1e#zsqxwNCB zw!|swXSrUpUawg!mVhdArrA0qOX=$DTCJb7F3$Fy%YAiIc-wr8Bu!FYgHbh{G?^o8 zTHo`WIG0og*+mHk4D?a2t{-SRN#nai!)DiTw>@xkyXW$H%jMOMo12=uO~+>2v)#3H zU5?pTMZvz0bbX>9pc%~zJI*eyxwyLJ{6g9Bp1(NbtLJZc{pOOJ+dWO2#Dp*{TC_66 zxSYoPJ|Von|1{40U1Ju^{Y@>etmZVYuN@iTNNbDTUtO5!&!{Oh;+~r=o6Z{r(h2w3 zQ*?ZK==l36B#v#?*ID25eL>eu_(j5vOo{p4HimJWxi9m1u#dCv`H-%?KkxIF48D`) z*U0mcY+UozNH*Uh_|xI(r1{xs5@EXOIM?>>@H&Bp1Oi`Q#+=<4?cE<8?`3z!jcQczjYgo{t)5-$%~&@Mm9K@XNc%e({KS@{Ar& z)6|wWQlr(i5kC@HN%pc&PKzv9xxeW1b|1LE;n;ZX{jHh5>2D_X(`HaN>{@%voc__# z5mmLMs3e69L*(VF*X(wCNj~rZDPr0cOI~Ay$iY2gZ##W_{=C2HO773Rk9wEMKx#gc z5PjYp-brdsre!FrlDa<7)U^n{Ni)u6$!@xTX8sZxIj9eF1VggTHT#_h{U6WG>+ewV z5_67}GwC;;=gyu7;5@}*!O5dXoSr^nxmXh8K-;!5*(4Em#==cT z*i%BW_(u2*OF0t~^n~1}%xq3lAC`GBpEoVZwD$Tf65YVy2BJ$uCv#e|w7Yn79;7hm zKu6OicKd<5P0QU~!|iRu&27W=ZO!$KJoWE38*cA*T-|KAyt?7y>V}JpYhJxR=lP3Q z{Q9ex{OYqW`Rc`M<-LFLh8M5Sxw_i0Kggb+T&emV5|ymaS&A1dXQDBhsAg-0!Qy<2 zOncy)o0e|6c7hT8$$RGh-pk9La9G|I(-7y)knfZ4Z>pJj7k%nrV@h$jq|=C_{ip6-G7yxHCD+x?UBHF-}b!*vc_D6wE_?&y2} zzUaz)yN@4DrDz1(*(#4WnAz#|8%EeMg5_pN-z1nk`21Zwzd6OI;$3DGRNPH*)m2&X z`1BDcN5_=G(=`p-yIcCEmSh|w3_YpuVd$lDO_oF45^Z?nUS&3bzOTV0`XSNvA_9x5 zpeO^;ds6U(P*Q{i?6-Wc+VBs)v*J&F=exY~_?T7c2#Y|m@RXsVq`;+u)^h0o{5JA` z`sY96#c;%M{FGt+m~QCl>b+71o4wGZ+U+huL4K&EE!WamyRbQW=O##(zo7zizjcr!}{nHd`UAT{+oaPXPlj1TK2Aql4QiHCm90F zOd$^me*Q3lV{R$Qxi0rB!(cL|Gk6s~iDSkxNtY=lnQW|7u>)31m1=I=mVW5LK`3&? zFWnC>_*aVFulEN8_xbqO<~iSI)?|NHwm?6cAiQPq%N6&uhThvo8E=tiG4CnN|3G;U zFrSGKg3gSJR+!2j>+<~BWmtJIwy%%E+JgxYp)j?&Wr`zB`7uaxJey&TZ-mdW8O+>c zMDw|}#)N{!@d?k~d6(0ZQ%I4k%S$fL&uQyg(KksI`IK&U=1XCczCA48R74mv4b1k0 z%P&K1^WOx)`J)}PVn)e`d>+NU_i?VX=|yujYLBvZDl;PtI9h^_B6=3bUzEX$b?Lf( z7})I&%G*CU3#(I79SFEln26&`^I?vzmQp(z6Ib|PvHtU>aV9bn%JVei0De<5AD+Q- z735U4(bh(@qYRoR@#Ga684_#_Vv^R*Zfny&U)KkHoT;+r=Z@={*Lxhs{QNw|d|dOB z&q*0anh7+S&>4aXq3O5Wm+_{vulf4f3F9;KF`X~CnD4JN^HrK@KSstmKPwTcr$6}9 z2^r1aM<}+1oDubD1s?o1-onna&u&KC$CL6SX6In{(A+EIQDM2xyRM~a8g_?0xWviH zF>gJ4Mo|txx#maVd}}X?@AXw&O3py5xU&vtzexJi_TW?z&V*jgMef%Oa&ntI8>S6CZc66}!JZhc zK#C;ZXv`8Vswy=LQ>Ulqzi%*1Fj zoi>Rnu}FrD^X7FXNo8pwXXs0DDqNCplJ`L}C$-W1klCzzgb$m`e7(KK1)0BQFlGG| zBDUW%p&D;3RsQ&l`7<9r&(?8-m+_d5-{v*}$vLXUlClU4eb0WoWxw5;Q|6R($H>?? zUT-ic(ZYVSu1s*A=R&G^F{{?cZ_uoa?{+-z?(c!z z2VEgrn)kHM_s)%(8@*Q%E)2qK79b@;_4NBQmA+2Ni;_3B9iDxewK=iZ)%U)W2|E+w zod1R)JB=#$Uw_LYsIrq+M!e3Pqx!z1sT;bkqpT{5q8zzX9~93%I-mF;gc<@ND2xTK zJpbP3LMT=Z&53JLN3_91inz96ojSh%bjgq2K4M+w-25W=&Lunr{oo)hxNRN3dUL~n z^UGIUgcIuZQz%M?exRxMI5(I{!K0+Dd0{X#q#XZFabWkR?3>yM)W6|-ZrLd*1JQVV zeA&1S>7_V*CYoott)usr*{dj6uGTD9Ys#{sZF^q6dSwLP);t4ddVnm)W5%3}Kt12M z6X4HZ(|z-~c`Vv=Qbo#{NNbrTUDZ#|cK&Q0a<=wj5M|TM&vDryEQidwyk6hj--j)4 zRs(lH&kALk&(QPHnDR62Vr_79Wb~#nODR!UT3GKr{m>f{$c(`>_p+(qXWGVQ-F5b? zdGGI?cdyNT3MNJ?rOBq4kLAAprn%AFJv{WFkMm=haWiDh`;&Dl>%6 z@LO_T&b&T|a63f{;G`jyNB#nQ0VugpR3MVdBo9&VvA2qJ=5T6z0K@yIX z5xD2)iW$gwTD29-r@)eMc{3x%q*pRr_cglrfVr_roL;#b%<;;sWrk^Fdc^#%S1T5a z1u;hUhlBEjJZPbM@`FDeCpBpxe^a|p%=1dl5Ws`Q)yE7?Xc@`6lJI(c??U59s`qNpg#%0w~?)3Fkj$@(P~vW~c*-}<4K3MN+!oZ0alP{tm& z-|+6z^Mkif`S8&ZMS{W?7CWu;B7uQ|nu0H`5B%lxD}Hvdr&&LtUmO$ro~}NShK}Hq zqA0Io+Y>-#LYrZ2Mm%i;O0_?8UWCyL zzAQ^iD_gNxE?KRQXu6)4FJ7_T?s69^jZ2a??F&g$9}wxv7Eqdlf!BD_xNL&X41{khj3Abb1&pxMe9Z2Dr#ye1Xy zT-va)niM2;T|S(1mn*a}C7CEz0_>e}6;Y;C1AYDH0xA?@nP_==L*$Yg74OU-aJGvrM7bXV1P$;=2qKh8N0M`Tv_ zaJ?$NjKJ05?r?V?5CGenIYa(7r~?jdWpuPpSMa|33X!}wMYJk?FaJK%;eNntvW#gv z;{tzXsM!DwU?>}uouc^(>Qjbsk*|7@&MQ%?iIU~KG#RY!Alhhg2DBThQf`b+Q#)Id zdz0BZmf=0NfH;_*Qz@9{REO&6G?mtJfMm@jcRsk!xW?NuMVZVIqikH~=>bh?T~E>Z z9_z}ldm6hP*OjGyJWu`gpoo+DfuB{wE&O)UYH@Dn&qUg_)?zk%UAgfSKY7k2X-dDP zLdg^&MS-A3&PF>FWErsuy_o|_PR|TY_k47RlY)b2yvJ!eU^~5FJH23;w5Y5=uK{f4 z3aS+kK*#Im2!Avtdl3OTPja{qK`C$tR;-nCgn1fYv>K-N<<%A)268-*U-N?F-96sE zeTQ}3@SA`9pLqK6gd$HA=4Dq=J4Yjp@S8BtalI7`@Km5Xj}5StPm!}&B>ZSi=b-bw zf05FmVW&KCAyzk5O)|rg73l;U{3}6Myr4%XMg=4%LYt-3ZIjXWDQMlfsahdTWk6_J z5$tkWtynJ{;adrG$JuldF?%r`q)7LWjneH)aw-}I1iw{A7SEYA^ z72A5@;aYXGy9|Ih#65pfF>YP&b6pYd!2QFxvEq2g+_UBUGWOVXaRH%vdP>V*${pLy znK&8nrqBN@^Pq8W$lKjoZ^=2(?s)2Hp$B=n5z_By9D1ltt@7)eMQ1x~+h%SUQ~f9P z_%|>MN;+LcfHcpt?04Mr%(X1eFo;XkE*hnXuq%;L_vx|o)a9G@3}<;`y$tVZ7%&tX zux=~Q?l>$Q*?V?LeUGm`m1#hYGBrGZrOu#z{E@wknM!UHwr#w;Iof0!>+%~gAHMky z9O0{979%L;Fv9mqS!M9E6$~=B6!@~p5qXwr>m&3w>wcrc|DATM3Mmni()}kGGMx|98F3)&4f5zYa z)qDKwkMHqrK47ZAahfnyD(ZEsIMsqvS@8e<)1UCG-~EW+JOS&&N1W#aPV0(#e#Kl@ z9A>GcR!|zZ)wEiu;O8&}UaXgx&z4+~UZJ~x*Wu&QwzxFf9^vy< z$TU$Yl!-@z9`7IU_~tFP2K@ThzrmL;Pbh^a%-N+OPF?D)bXUOcnJ^Y>o#2?xOGT%s@kBJ> zR-Lj*gT2pbk~2}bEjJqFYnCI;&p-K^uK0BfRU}|()RcMuXb)_Q(hTHL*RZWbVgHQ; zS8XU!>I6C4DSrW-TRXXN?04<600n&%UJBO{utMSQz9Wb>G}oU7RN@IgU#{8?mzgaq zwKiNXE2dKL{@n+>dGi)iDR_Q<)@gw(hxMk4RjpGDkOB)#H)@}v4bJ>Z3b{Q)LH!|{ zM}SfEH#-M2uz%-}K1&whO52`~iCL-U?k{n`c|08O?Kj`x{rmSgpUzmf3znH@ur#H) z)e&7)#5D7$<1of`D0(FV&yr{j&$_N$%hsA~qe@Xh4KnzdS@cZ!YzG!Hu6=2=?JuK?V&*G*DRr_pDGJMDL6aIR>;P3wGJ-&N=kp0uz2I)5QX+3@?9nFF zQet0kj|%iAFLB1OeHASh%siEFnim|7N8H~( z;O_nb=gW%!@$28<%a>=Abm|_Ad34UMFdHx-KgMGRvcc!Oqg++PqTMz@?`67P3yi%k* zUADY^Iw(x&Dn}eOJAk3caLAy1e7>znQ7}3_(eK5Buhbju7%uoJQrF^cA_))AeK_1EqOQ99Q0hYbpWA&DF%b@+3Fi5by?A~+II_j>j)n{e8AuQ&A-K8|Eqt6r!Qad{Pd(f4SHLy_4BUm z=%}e+-|o|@JokG?Phq1er$sa*bvqsA!^gk-dkXVdAY9?Dg%PvYY<`ZSdgYeDrueZ; zB0tY_Oe+DLR-(?MkTvZVR`l+h`J7+bO2M?yv-& zalY_mDsFu7ind-bSAHhPLo{YixufEKea8RxQ1Cb3yv4h_2OP=~chiJ&Ib&{>JKvWX zU&@SM{p0WP|NQAEd|w~%a{n#PnDFxY!aep;G3$6x_8E;53K!y3P1A9#e^G<pO)hhkQkv6DWGg2dx?ifZAU6B1*la&~tZ_RV-yND?*4YzmBvlk3?0?X9C9Os*~ z_{Peus57-qQ~EAPzhj5KhM={e_lu5CZl9eMfCkJPO$BX)b1s*P-V|_L|FkkwpVPz1 znD1CK#O>f#xa->M$-qs@J!r;A#`WZcFtkHKq_e_ksu^y&d7#iL2MV6fY=MV$mik-> zO{ZCZ1>kxemyDM5npkm-Kfp9L>a9QbHo1M|4HtOn$X$ueE4YV71vg8Q>cg;*X;Iwuf4d%wyF6q5Q}r}=Fd`FJ~>(-Z)Z!?j*6I2^bm>-XP( zkMsFVnNr=0c5A%`;j@<^Kd5~<$gph{%fdk}z;irW<)^sjRo(bSQuKWN%*SuiD*b3t zLQn-D3=i)eRpg~H#KpI+(7@lxqj;6!PHO@50yqLqpGt}lYJX4v8%Ve&7rGPxt>W8n zzr%4^Xy~7wu$|9XPiJ6V(N>+#*H+ZJV%i#Jouh-z(`_qiyI@*h(N53!@a7TkAKv2K ze8gOV)9V>^T5viX@x!*^zyIkc{I@?n;h*aRUY9qxlmjl8GwS8619doxrRSGMrxph7 zw8ss2pm*-Nc0xfK<`BYF$AE-hvK5z&yhrbv0`(~0#=ccK0-HKkBfsZ~BMZL2pK&8CIF{qO#Om*-ci5G3-a~C6OK%uU4@~YQu55+(-^E1c-itQ&VR47F@2VI-Go!M zC$1o`QK3VnDqUyHAhKPHw_;7s1p6J+=XQ4*@#3R458KHnFXv@}{vN;ep?wgaDSLy% z5eW)V?{)3y>3*PSmZNSS!86QlRBoV?Beu&0FJHa@bpzHFrEVzdAhm2LQ^QgV=4}F2ZT?a#wtB)^ zUs2Z+o<9AAWt#Ev_=xY0_n1*oYXO!!{IG5Khadlp|N8qM@ITjke7gG<>vZJa?3WXb zxZ4h{w&mwJ2^#C1WbCJ=cKfYUQm9=(1WoZWP7%HDQ0bYR+zBd55J935oVL9TDfBYW*{Lg=i)AG2XhVg3N+e=S$t`HqC3w@V`QmjmrrpdYM z8D+pZRm~B-)Ul18oCFtLGzHwBJ#w>wl>(Jv3xgk1>@xONOeA`eUDub}r*QGX#=Wax zUd;;%b%I|nKY^ZIZbReh?KGX&HtsJ0%|cA-!!;H?j)fK$bOjNVZp;lnU6dwhKH=r{g^SBgLnXdy!w{yvnefi3d$Yze3dkSg%CN_WN8BCnxRCvP*6Y2LK`1(xOni>i=%%$Pb3Jy&NqR?f)1s9y!1?zgk<#NXB z=@rv7@!92Tz7zkk5} z{Ub`5@!Q}24nO?)M_ja6rM0Yq)IQ-?6x8w0?Ptex-4c`@r*y@CBnPGRMR!e`iHHb2 zJqzKp40@EEWQ$^3Q1s5z8}Be*%2QQ0Sohd%e+G(qWS*$**!MoG+7V(9nZQ$eMO1%UB-crEGK{YFlqmY zWuDPg-?A*YKi*-zoa5D1mXm=8a-Mjf(m5b5*S~9v9>;uNht7}v10M?{!zB`oAe~rb z$9gzIi0nvUFrFRAjxH;~pVse-%oek&kUa9<)1g-nh*nqsuCoOAs~<#dw-R5|Dn|{R zm16^wOlkIIT-9@fUW7e9y**vN_s+`*MQO)0Y_Rp7ZG) zK9CW2GEe!C0woN-nJEP#13(5TZ%|CXQr^CIM~Kq+2*^teI$OphSiuJ|JG>mIPERwT z;BYwL;r z_~VbCP~X18%l!lX>+gPtUw!{Q{uu?^;|H9}0p|;}mv?`6++r%9ZAkpqPdCV+__HvA z0v@#TZ(J$Aztw44W$)+8#dtMF?xcl3d5jUgMwPyg^il>M;ZO5~<-ji@?(Xh!|G-o8 z{=a|tANc9hXMPT6=O7t0?57)3BehPg2bK6EIqR~}<6TBCsG#r@=CtVy8g_e3bm20k zgZ53kj5o!IY5Zy-<<}2i9Vj@rp)q~FdVva4zv0Dq_E`pY#OQaqDN-i$ESJ^o(&D`M z)Kz7~%z+$DX4qfE4Ul5CW7G+-!;i3+(V^`Fj0#=79z{;j*P+L`J@K5Zm83?a`2`TZ zr4$?%E;NmSie|1Z=W`TK6hw>8xPYihwAsf4ZpSX)b+WI5>nP1*u#nV9LA7VytoVrD zQ)omy=LjPEZMKP?A*UXFO)Ce${gu39+MIzy^Q(+zY;)G(7H-E`s0w9bxbjb+_+OO4lqwp}6>)6^&&p9!viQeW0VtwA0X^ITHYIjY(ek!UReOplyln z!e+#S{~UJ9AO^m`pnM3TxAQ8!qcW5sY$PDNp1xL?cv2*zDG!`|Qa)$RZ8rXHo9as` z0$5C^(J#W#p4|TZNapK6Gc5PinheZgS+wESB)z8mcGMC- z;QpsZyB}w{V$y_PT>iVq%zetvs%?#%qP)90uq%nR^fWm&QSY&VUn)Q2X&CAZ98+r| ze{^#FNlIZ?CL*ZUYdTxkgucF%-QnE_cMcKq%*w8|0n-SNm#{xakB`5D{g%#m_w zsM{G+sl3{RsTHr0<*NBf2B2{B+twy5(*cLW1GZ_wr5tcB3!b-v=M?~Eu6^;zZ+XOO zV{g3SPGkc@WfYx5^dxQVEO@k@jC&aQblGV8J{j>ap#4C#Qpsv&X*Ox|J@((Pyh5sR5>>vb`b@>FYAjBOmGn9><7Q+}-P>+o|USjz!vqJ;Wkz5C4j=Uuy_ z9jQDiMAN+#=rbv;057a(s~gt!f-Ppb`pj4~UfA+RGSrAf*H;6%IS4letY)5Q4V)>tNMb3#d7wiz=d?Wxlqfa@#LtR zaW@GN81=UI;`R<=PiH;am`t&`C1bn%bd5p6FLbkO+RKU(4zf5xgl75#aS{e8yW1KO zK|6&utvO0iVrJO}U%-ub{0`rxn~ePJimd;#(-0a=;I3dYgpqLSVMI~FTfYS%%Dr`5 zx+hew)ew#TG)?Nr4a+j)&Eq2`fID(&I8DTl&2N5-r{@=x!t)D8!ofX)aN?^k8mAreiP(*k3j8B(2{l?n||IIR)3QKw1ANjXG59uSt5RmAR^6ZjDblj#v za6~eI{YYU-6S^&3Jn~q0H>RHtAMyx4xUOF-fo$|40pYG*#>s-Hn;@^hvmSN)=n2pm~fmH)bkld2X#zEoz+{VidQz=G|V#6S0i*^jVowX z4vl>`UipeVyAiv?YOTPwp=})1*Sd0qUpKAF@8!oLJ@F>jNnUaXyLnk~yuU-4XS}|i z@u%;9z#snbPx>}guQ32D3r~$gnu6nxWWl_Qkj_&lpy=fVMdG*){PSO290#Bv+P8HJw*IdmgAa%@)~8RxGSEO`Lw=TR*e?j>1C z?P0y<>rhzGF&n|X!o3AQ7uOq^cqd>!Q=>=TGQxdyox-3UG?8dkxTyGWSlC{*-|JF} zXRkoM71(H{V)lrdHu04B)Pn}NqRCD^T;5Rb%~_mG8>Ti-p!NZh|1=V2a3hrpfWqIy z;Q(&K97U)M>VcsdAwQHUZ{y0oZ9ZMoD&q&RZr5=|mjTy3jA45o_!{$z&IyO;r%3%} zSGLP25w%Mjbui7ojr(VXs#fL?2}nuza^$kjN2elQ>dR>c)_JJ^jC0S|8Za*(|9y<` zGXt74MgbymDe6f44%?k9H?ow%J>os8BI<#F@i8)r-9c`sF6T)NNh&iwb-An?_jw0! zKArIT{EUZ(JKWtJvCK2-w&LaWMYtEVrXy)FpMY&J_YPFk2-|7U^1{2lQSVpXI9jQjM(?Zc>&A^O6z6m; zUv*rmkJhv;WU9lX+;na`rYVjBIi1e<{P_u=K7GdFaEt?Cir$xQ8~3x9vw6*9h1nR7 zf-e~gi`0!*PigJOUy7?#(B5H@l5}Z)23TY$Ga1Zgd?b5?nWQ+F&-X1&aT-E_>KY8| zR~&=ld~CoFek()tlSZei$qDrA5w?oFOv1ddbrXgS&)4)!8l~xjMd@*;f zFRD^oa$}r78{HgF=;Z6413TYT=!G?Zm7v`@AMWpiug%V#7M~IShHcehNh-ae<7fFW zeXe=f@eE$%Yfp3Wh;6=(yA{T&EL*uh5I^GxJE4pjNKEpOMx}6Iq*O|qW($pD<4&iR z$!2G`ZtVRnF(v54%6h+2`2#JSJ|W1!z(;zvadyu}n~l2r z&{f)9S-Y|o+S_V<;@~SB1yOd_RS-W*;cM&Wt`?h$`J5Qd=IQ%?@{RfD!-v1^2H!@V zA|(xs7|lm%TEH=BUwR8d?-&xdD&uaH9j}pt1#0X;ig#-=NTI28Hb%chjU8d0XReCZ z@vg0ISmp^Y&(AoWUeSEgn0Bh-lI}u-ukZXzqp_dm0Z)@ocAD6l83j{oDBFg4tK4sT z0=Ae==fXV%Z8T~RA=ka){M?$Hgw(P4JvD!0I^OrO;I8&`9-Z3IYZ||VQ{m};jqY2E zUmJQ(cXCIs!*am!c;uF|5~lOI;?vU;4tIB0<^#@`6`wzUp`$eEJzoLV^%4s#_v|$6 zJCda=q^*GY<3Thv9i2~#$#T$&I-tIg7$DCUN&aebzCxBmezli=?-rf6cD$r8b33ov zvV$(q^wL>VkL&AcZbPTtsK|1z$y5`*#@|Yy(;_24`dW64l^s7W-sG>H!oM7-_^v?? z3j(>DG$ZI0L1S43OdNd;bW*v~W5MNgLRCLqq#rm7BBd@q_vW+y-mX#a^h>cZ?c0C9 z276lll8kid`Ldj3urmWhLn5yC59wGfSZ$v5@PI`9HCIrSe=N_Ahjp3L^j45Ry}!12 zy^{LLfT!u2sd1yFDJb(ON3d8u?{Ft1bDM7ld^#2*HvAiW_^SLTJ>@i(tubMTtNPt1 z{KrnQ24WMRn`SecPyD>mFXzLDzm3!Kvccbro<~_$j)wz3ZJB4TfVKA=%21uRmzW!X zD?3L!o@A`^Zy0k; z-N(p2zn2eVuUUbO2EJ*tj!0`Kq0#6QZ%xxp1ykX^@~t(j8&@>1+lsALYyjTAe~;yG z#OvvVAAkIWX_6CFDA?h30^`UfvH!LtbYa;4^~gIzXVQsijU$7t5M6%9ofk{4p~MZ>H0ka6nz2uiUNiUt+CXZC5l03DGvk**+#|kj{nJt= zks%5_#fYXsg@O8kmW+cGM4iSlM%3YiCJ4OpMQEZ;80cLaM_^oU_cf>me26-GEVDAq z`l*GnC+-f1%DnLf*DCOz++Y1h{5BnR(wZ*((FgBv|zrmI8!>ji49Y4$0%T*xs_ zIkMScbO77xb6m!BEZ6iyl9P^|)Ax{(mc5lXATdAmkTW-ysOA8o6aOc^IUJ(JuB!R) z;oto|!^}vfXe_KDb?$WCKiuQ~{vL;AL9G?*<)XA*nOTsF{sbd~@Escyczjm=Tn^a4 zDAVXBMl^kY4SBqGhXcO(<|Ep+;r00$&re@)I=x_9SDj_t1(_#FN~@QKHZ`;vs1uF- zI#twC(F!-{p~P~7m(3l%86z{HGYy`0m7=Af%FFiRy12G@J>Zdf9-;R|eA(FNsd%MV z8cyM-k$rM7yud32Rc)xPVXHN^+H8LJxhz=jj(GRs1D550=a(1!@WYRo=YyIo;WMjU zu3+p?{5y8)EE|c@n$B`iDY-6_`6I!3&(84iHj>t z`7C!R-5HP^?aQ{v?7{S6d{*3vVLQ4FbRp8bjp{lbhGYSZ&qhCRbaeVHrS}ts#LS3+ zI`l>Z6OfL6%9ZqdHe#yO%uQ((V*Y3|CC(g3kH@0hoYRfDo>3giZA@#vFwDndD^=@x zI+6NMHom!S+%b07B*T@nnEH>5eV4bC#`QJPju?nO-L92FDZMeJ4^gETJ7g+cnf&

#;zV%^SI*E6>5f~{WAz%6&@StptmA8wae;zr0f;Cz7U&cf!lB!kmh z>l?c?DW;fCqoMZnf0I$C;qJ2lVeFfKn`RRF`+nx36JW;xR(2Uj;n5%mL^C$)wqael zIH!UeyBrQj+}+)4!QR3V{<7ftnFgN??xu%^UPMv||xZs4Q+Y1*`=fy|h{;}bm1v={FNVQyj&OrS}@&YBuGDP7U(s`Tc z67}<4_B?Cfg(Q~+-PoEZ10U2@r=_z;nWtW5vf|1b5?*`A;k^>JB_4MmU8MUQJ`^V) z3Z0$~BQQ@(gJOp_0Q2$v-^MEaF@eDX=LYl0)8pZYMWg%E>4fv;3`lX7qN7A_6^DIb z8v^#7I=QW#D3PTrm9hDVGK)s|-+lWnUZ0#P5 zyj}Q;zfW|dXhGiuo+UjMz6RLR`zZ>Xl)R0%jOl3HIi+4Ta`*fB{%&5=k)GmD@8!J^ z@3NjzwRwoIVIiN&_0-Q$@3vuEH*7kDqi&q7h)-t<&#XQicq-oUc*Nmwz_cu=rQqSs z8%)!Tm*-df_|s3Mj1*M!=x^7%u4RHF%P#bLWj+da(R<@sH#G2+sCj0+d^f8#2r+Hm zWw8NCxmup&a5d)hf<36NQn)+a%kwk&m!zR%ma!kfeJA=*gz>?O$+${#rOqly!F4d{bv!cf z6VArh#TWBo_qu}Ebbj_=hG)KzmQD2IH7_%kWzorPqnr+MaU1oqP6q)ToG3n(7wg$#TBoqiLKUtG(tyQ0H;^`+KJ5mHdYuul zyYKm3?O2~?qKZP4e_lTPyEq;>kC%xZnsxrQO<}x zLo>y02z2g1C~n){gUa@s%KL{gfnMLmz32byaP}&{Wak)|L0CxB`y#|7CEi$T* zvUPpEo)O&7BOeku60+pbZ7}}+&Ef7(p;vPH6xRFASdqi7;+V;y43hY9>uA36*u1{Q zxTwvaZnZ=@ZSf%mR&C*ngI%Z2J7{S+@8GRB=({Noh<4Vi~@gkr+Ic33v%k%rK~ z{x;O7en?|aozPmty3%3nNRAlgP@>%XKQG?c*=X?ed4goS2SN_~;JS?%fCUMAVQvQ+ z=>g=irT2SD?xOfXG{u`;{n6gk4^yyi^-%JC!YjAeRSYEUe1!CY(O}C{;t-CG&wTjs zfBt zSe65g`*Og1IAC5DD!++orfEi*C(QGLIRnhj|1H(X_UPy483MlFNkh z7@C}pUxH8y!Nb(q%P156HSXp)2Bn_U?j7ts6x`k2;dne?Dh1o7K9IK+PM=lfe2Eb^ zp!e3U^uCt9m+cgJ^jWf@k3#jQ`~L~lcNBPqX$rpz1R`cxW*m=4(q^7x_6^00SUFwn zwH}?$sVq5dMFw(z0e)aS4cv&C^(PWlqsQj%prSgjO!uAf$hyUugC;w}x+}jm;^%=2 z4W8Pkk-c{;%y^Hm3pX!^i%>w?7>lksN4x@>)}rXKHk}dgnU0|hmf&)_vDdGr^yi72 zaLqH<1cmO^{`7%|h|K1=j$K;=)J`%ih50t$>rVuAU9so=)qRjo^(BzOA1ELpzF8E@ zN}H2x?hKNAo21YikyB;w%gy!Xa6K89-2Uifd%<^|>WuD~cgF+XK0f00@snBXu^c0%vdnt&}J-c;wO8;Qsx%5)%Yxr`%Lq<>XR)i4<4kG z-?Ph@d!#Lc%xNja6#V{zMwwi&N5>f=el%+HJYzo4OFtYBILO$~%Yu2C zG0!|4r-4Tlm*Tw_CSc|$|Mm5Z&!4~G%jYMYPG?MopFxG5-n*;;^q%?8L8F3XP!u#U z+dQ`1aSEQJ`@4I-die6?DMlxR(GhiiI}ldVfN9>;7Jc5;u1DAeBbHT@fpOh1^iV3& zj?XoiV=C31ApPw7K!@A)GOXa^$B%gT?j4q8#`%2KS1l@54zT6YG;v zkzo0zVG$0#db;={NcgvG3=yAUHx05p03aJomtI3Q@VO5b0L#po&ExTaWnM7(^F`@u zmf+*UtZeT5eei>G}K^2ERd_Sw!J9>{y^b z2@Yh7yxy6gEOA#ekC@A@>6w3Hxwo`Z58};!EMrt1OJtPZ5ei=B8HZ)Y`E){EFJWls z!uRlV{{9|pKaCuB6kL{t)7;a7Wtw?f)Lc-O3799eWkQ)JuCfoF_7Ogfyo|jRNNkAX z`}7%}8#4PZ1f&lk(y^v+)I>g`Aj)FN-^dB&ns?l@I{;O}9fk)LN2eLru*UJ8wU zCph`A)rv1q&-nED3%-1L!s(SKjd9Tz4{K=}9S22A;#H`Rd~cy1WuhxRhLvzQZ3N_` z@!bqsZ8%>pIG;~l2WLIBvsA4aH>SvCvvhT_q@)d0>@1JPj%B+UG+upC(KHp*x?Po* zAsfyi-B3?b&N~pbhWH{}zWw%FynFW!rA&B!rnBby*nOzvuDfP-dNidd+LZy%Ob3VN zFx8bp;yx)=28z#vk`AgfOhuaqd$j$$5AQ(dVp$G29=J}WloI>x2QMTm?Az?$4ClyF z;wXoN5xHFfnJp&r4X4JA0qgA9uR%tiEzvK-Z^JKBWB?ZTj^)5OwHDG89{Qq;ku{|M8#W(L!oMsZ~rG zy^kw+3$&;D%zc<`*qGFt_qVH!L(J&t21b5J7AiJ1MIETH`8FW@Z7k0-QyOL37#!yr zZyz6kT50fCebTncK|#|(k%~5v!fn#17KJ~M|*kNSMMcLY#rtdkzN10GX zQ?5U3SZl@8%L^{+1`ZA<%+sQ+b-O{{wv8JW`| z3>nK9ftszieWY(GlvC{J6GrbV1IVno9US3~uK5lK-yh}C9Dh7w=@8;k)QOH2^0^p!S(g%TONv&HwG;4Wnd4NGKb88w6EV^hb};$&86`AS-&FtUltK#KaUmrJ`K{jjzmn z82NG3=>9v5UTej=Rjm3{k0as24`sBG3k~Qb`g1#?kw<`z<>5m#>IP-3^aEF5(>ujI zA+tf2o5fnQ%$p%enbcat0g7bGTSR{ppl$i}0Kv4RbH@@VPygq1@H^1{x!1PpyMAQF zJwi0`sv#pVdROB>pZ;8ulUFoa^^`t)7pOelk#}&#rYj}1!$&-18^;1~8N%YxQ_pS* z6>go@Ez`)*ZYf4W!EJm2;iBV#{GDWR7MI8m2-6ge?2Pb4qMMXV9%3E=Q{I+S6h$ zi}N(0ZhEazm?sbJieIm^Zj@Y4FUsMKpExF7+@cNh5&sd4FMma0t{)J7rEvDFwcJ0I zy+z?Fhj`oQPbheJc)(#;jCjH6bmEsR8s!5(kTmwgw#Eq2}pIMsos;&;B zQR{4xu~*uu@VoHy`4rzzx7M(3eWU`AaIMMc&)g%wh?xAej-~tJ4tkspi4G(~Utog| z8vO~Vg`4tB0H&(=o6uY1Deu1o=)71#N8s>mubcmEpu8P2!~70j+B5KR3WV6$x#Iei zD)vI(FVxD7c-Y~Y-d(S0_QJ9QAbI}cw{Xn$I*xemW85yb8{#SNjW^5ZsED&0uruPi z-I;3jI@)HN9~r)ie+-FMnq9NY#|tTidgjNcB5F})p~zzO`@4gCI@ zjv4t9iymA51WuL87~iURC|E>vKi(@dr|r|#8FEQ+ulm*UpjYRO|9k}!T@8DT-L^z6 z%9K!Mdd^Zo!wl=TQaIuT8u#m87EIF=U%hOVGlwjf<$N9Zs;#xO$420wStbfs?3oVi ziyV5GrR(c;x2D<4XxUYK2HOGh7y$UXXT%e%tD*N(I|bU`z^@^{Hd8kC0n&F5&R3$H z%-8!XhIJ`w*gq1=EY)&|CwPN#8%BriOdyOu}_~yUx;6$_uiHiY2#z!H6 z7n8OfaBqa$2X7o^wUofR<)R9lCj&@HqK+1AeAx~Zlymm z;i^yqjR?LP4;QV`da4x-{x;m$H%_AuMafxnSYsHb2|zyOu)p?@PSM4w``S1*cSB7I zI)RNxYlc$NN?DUC)y;)1Hr(B)I{wD3$r=Ua=N(H3Qea$npv0-8w40d-#qV2p@mYQv zOa`l&u@N~xsg>hzLlJ{|wR`;hybr$(xr6WN>}TU{mI!gtRrTzv{mZHsWP_if-JW7h zbiOs(AAt#sayVAOXFr+_-C-ZO6$w*l(Z3;uo^}qGM_*EzJy(DI)8Kc*zt|{&jQT$K zYp_Gffo?A>pe(Juo^7G|pU;<^=p>$FHv&3hyV463I^fn#ih z8DF5>|L^~?p^#Z9dN1#3VZE!WwU4M8`m|1l=(OZ0pb=szb|l=cJeqR4Ye^4<89z*4 zH%_Cyd-o3C{ncOL$3OoWpFe-b`FzGSO*kHpxOkgi5F!6&&=@v7r?iP#kPwWyO@nc^ zWAC}{9S+hth2`hHF%<2JMuZAt(#eJvogY_ql^|Z12ZlKxWauM}S{u}fzL?!33Q}pn zn>UZB8_yQ^Cx5JZG@yMM$IjUI(67V3U2;;4&k$2=)Vf0ix7F>u(J_X!p#YLoW%<0q zg^NvZ{1HN4KAYF}WVn6lez0 zY(V)Y>`|CXFRsNO@f(d&d{y18FhSe*v=o)|Sw^72k7*}^Lh0;jeil-6ZvVfO-iCr) zW*{8#0k?>KBiR6hn%*ZaSmp&=SE^ z=C1;l19y0Oetzca`>I7Gnw0>AyQpZ4@*gKL95D9G#ldg<~>cm=d-8fmA6dtI<>uT)aMJ@8-Tp6{;s@MY*h>E^qZ%vxb}!b z7@b7-O;h0S-@QWtxCQUV&;IhLtF_cAcB~B8b(&uSbBjt9Hw$j!72G))_%DLJ0c>EK z$?hxzyr+{fWVi`ANx@#uMC26mb@;is9qbj8a3+0llZF`5-B!te8K}==ufaM*@c;ix z0!%|Izvj{S&p-p)SRh4i2vHuGq_m80&aetzqMl?3d60dCqXS^cPN_W%F@ M07*qoM6N<$f^%r76951J literal 0 HcmV?d00001 diff --git a/cockpit/static/js/agent-avatars.js b/cockpit/static/js/agent-avatars.js new file mode 100644 index 0000000..7430891 --- /dev/null +++ b/cockpit/static/js/agent-avatars.js @@ -0,0 +1,109 @@ +/** 3D-style agent poppetjes met headset — consistent team look */ +window.AgentAvatars = (function () { + var CFG = { + herman: { hoodie: '#1e3a5f', hair: '#4a3728', skin: '#e8b896', style: 'exec', accent: '#ffd700' }, + marketing: { hoodie: '#9d174d', hair: '#1f2937', skin: '#f5c9a8', style: 'bob', accent: '#ff6b9d' }, + bizdev: { hoodie: '#0e4d6e', hair: '#2d1810', skin: '#ddb896', style: 'short', accent: '#00e5ff' }, + finance: { hoodie: '#14532d', hair: '#3d2314', skin: '#e8b896', style: 'glasses', accent: '#22c55e' }, + sourcing: { hoodie: '#9a3412', hair: '#1a1a1a', skin: '#c9a07a', style: 'short', accent: '#f97316' }, + product: { hoodie: '#581c87', hair: '#4a3728', skin: '#f5c9a8', style: 'curl', accent: '#a855f7' }, + halal: { hoodie: '#065f46', hair: '#1f2937', skin: '#d4a574', style: 'short', accent: '#34d399' }, + design: { hoodie: '#831843', hair: '#111827', skin: '#f5c9a8', style: 'long', accent: '#ec4899' }, + knowledge: { hoodie: '#312e81', hair: '#374151', skin: '#e8b896', style: 'glasses', accent: '#6366f1' }, + retail: { hoodie: '#365314', hair: '#2d1810', skin: '#ddb896', style: 'short', accent: '#b8ff3c' }, + browser: { hoodie: '#0c4a6e', hair: '#1f2937', skin: '#c9a07a', style: 'short', accent: '#38bdf8' }, + hermes: { hoodie: '#1e40af', hair: '#3d2314', skin: '#e8b896', style: 'short', accent: '#2aabee' }, + email: { hoodie: '#334155', hair: '#4a3728', skin: '#ddb896', style: 'short', accent: '#94a3b8' }, + research: { hoodie: '#115e59', hair: '#1a1a1a', skin: '#f5c9a8', style: 'glasses', accent: '#14b8a6' }, + sysops: { hoodie: '#1e3a5f', hair: '#4a3728', skin: '#e8b896', style: 'short', accent: '#38bdf8', hat: 'cap' }, + packaging: { hoodie: '#7c2d12', hair: '#2d1810', skin: '#c9a07a', style: 'short', accent: '#fb923c' }, + }; + + function cfg(key, fallbackColor) { + var k = (key || 'agent').toLowerCase(); + var c = CFG[k] || { hoodie: fallbackColor || '#1e3a5f', hair: '#3d2314', skin: '#e8b896', style: 'short', accent: '#38bdf8' }; + return c; + } + + function capSvg(hid, c) { + return ( + '' + + '' + + '' + + '' + + '' + ); + } + + function hairPath(style) { + if (style === 'long') return 'M28,38 Q20,18 40,14 Q60,10 72,22 Q78,32 74,48 Q70,56 62,52 Q58,38 50,36 Q42,36 38,48 Q32,52 28,38Z'; + if (style === 'bob') return 'M26,40 Q24,22 42,16 Q62,14 74,28 Q76,42 70,50 Q50,54 30,48 Q24,44 26,40Z'; + if (style === 'curl') return 'M28,42 Q22,24 38,16 Q52,12 68,20 Q76,30 72,44 Q66,52 54,48 Q44,52 34,46 Q26,44 28,42Z'; + return 'M30,40 Q28,24 44,18 Q58,16 70,26 Q74,36 70,44 Q54,48 38,44 Q30,42 30,40Z'; + } + + function svgAvatar(key, color) { + var c = cfg(key, color); + var hid = 'av-' + key; + return ( + '' + ); + } + + function paint(el, key, color) { + if (!el) return; + el.innerHTML = svgAvatar((key || '').toLowerCase(), color); + } + + function paintAll(root) { + root = root || document; + root.querySelectorAll('[data-agent-avatar]').forEach(function (el) { + paint(el, el.getAttribute('data-agent-avatar'), el.getAttribute('data-agent-color')); + }); + } + + return { paint: paint, paintAll: paintAll, svgAvatar: svgAvatar }; +})(); diff --git a/cockpit/static/js/agents-mesh.js b/cockpit/static/js/agents-mesh.js index 96c7472..d2f94a9 100644 --- a/cockpit/static/js/agents-mesh.js +++ b/cockpit/static/js/agents-mesh.js @@ -11,12 +11,9 @@ while (el.firstChild) el.removeChild(el.firstChild); } - function curvePath(x1, y1, x2, y2) { - const cx1 = x1 + (x2 - x1) * 0.35; - const cy1 = y1; - const cx2 = x1 + (x2 - x1) * 0.72; - const cy2 = y2; - return `M ${x1} ${y1} C ${cx1} ${cy1}, ${cx2} ${cy2}, ${x2} ${y2}`; + function linePath(x1, y1, x2, y2) { + const midY = y1 + (y2 - y1) * 0.45; + return `M ${x1} ${y1} C ${x1} ${midY}, ${x2} ${midY}, ${x2} ${y2}`; } async function loadMeshData() { @@ -28,63 +25,103 @@ function drawMesh(svg, data) { clear(svg); const vb = svg.viewBox.baseVal; - const width = vb && vb.width ? vb.width : 1000; - const height = vb && vb.height ? vb.height : 620; - const cx = width / 2; - const cy = height / 2; - const radius = Math.min(width, height) * 0.35; + const width = vb && vb.width ? vb.width : 1100; + const height = vb && vb.height ? vb.height : 640; + + const cx = width / 2; + const hermanY = 280; + const execY = 75; + const agentY = 520; + + const souls = (data.nodes || []).filter((n) => { + const key = (n.agent_key || '').toLowerCase(); + return key && key !== 'herman'; + }); - const souls = (data.nodes || []).filter((n) => (n.agent_key || '').toLowerCase() !== 'herman'); const edgesBySource = {}; (data.edges || []).forEach((e) => { edgesBySource[e.source] = e; }); + const agentCount = Math.max(1, souls.length); + const pad = 70; + const span = width - pad * 2; souls.forEach((node, i) => { - const a = (Math.PI * 2 * i) / Math.max(1, souls.length) - Math.PI / 2; - node._x = cx + Math.cos(a) * radius; - node._y = cy + Math.sin(a) * radius; + node._x = pad + (span * i) / Math.max(1, agentCount - 1 || 1); + if (agentCount === 1) node._x = cx; + node._y = agentY; }); + const ceo = { x: cx - 180, y: execY, label: 'CEO', sub: 'Aissa · beslissingen' }; + const cto = { x: cx + 180, y: execY, label: 'CTO', sub: 'Platform · techniek' }; + const edgesLayer = make('g'); const nodesLayer = make('g'); svg.appendChild(edgesLayer); svg.appendChild(nodesLayer); - souls.forEach((node) => { - const pathDef = curvePath(node._x, node._y, cx, cy); - const edge = make('path', { d: pathDef, class: 'mesh-edge' }); - edgesLayer.appendChild(edge); - - if (edgesBySource[node.agent_key]) { - const pulse = make('path', { d: pathDef, class: 'mesh-pulse' }); - pulse.style.animationDuration = `${Math.max(1.2, 3.5 - Math.min(2.2, edgesBySource[node.agent_key].weight / 8))}s`; - edgesLayer.appendChild(pulse); + function addEdge(x1, y1, x2, y2, pulse) { + const d = linePath(x1, y1, x2, y2); + edgesLayer.appendChild(make('path', { d, class: 'mesh-edge' })); + if (pulse) { + const p = make('path', { d, class: 'mesh-pulse' }); + p.style.animationDuration = pulse + 's'; + edgesLayer.appendChild(p); } + } + + souls.forEach((node) => { + const weight = edgesBySource[node.agent_key]?.weight || 1; + addEdge(node._x, node._y - 26, cx, hermanY + 48, Math.max(1.2, 3.2 - Math.min(2, weight / 10))); }); + addEdge(cx, hermanY - 48, ceo.x, ceo.y + 28, 2.2); + addEdge(cx, hermanY - 48, cto.x, cto.y + 28, 2.4); + + function drawExec(node, cls) { + const g = make('g', { class: `mesh-node mesh-exec ${cls}` }); + g.appendChild(make('circle', { cx: node.x, cy: node.y, r: 34, class: 'main' })); + g.appendChild(make('circle', { cx: node.x, cy: node.y, r: 42, class: 'ring' })); + g.appendChild(make('text', { x: node.x, y: node.y - 2, 'font-size': 13 })); + g.lastChild.textContent = node.label; + const sub = make('text', { x: node.x, y: node.y + 14, 'font-size': 9, opacity: 0.85 }); + sub.textContent = node.sub; + g.appendChild(sub); + nodesLayer.appendChild(g); + } + + drawExec(ceo, 'mesh-ceo'); + drawExec(cto, 'mesh-cto'); + const herman = make('g', { class: 'mesh-node mesh-herman' }); - herman.appendChild(make('circle', { class: 'ring', cx, cy, r: 62 })); - herman.appendChild(make('circle', { class: 'main', cx, cy, r: 46 })); - const crown = make('text', { x: cx, y: cy - 2, 'font-size': 24, 'text-anchor': 'middle' }); + herman.appendChild(make('circle', { class: 'ring', cx, cy: hermanY, r: 58 })); + herman.appendChild(make('circle', { class: 'main', cx, cy: hermanY, r: 44 })); + const crown = make('text', { x: cx, y: hermanY - 4, 'font-size': 22, 'text-anchor': 'middle' }); crown.textContent = '👑'; herman.appendChild(crown); - const label = make('text', { x: cx, y: cy + 22 }); - label.textContent = 'Herman · Co-CEO'; - herman.appendChild(label); + const hLabel = make('text', { x: cx, y: hermanY + 18 }); + hLabel.textContent = 'Herman · Co-CEO'; + herman.appendChild(hLabel); + const hSub = make('text', { x: cx, y: hermanY + 34, 'font-size': 10, opacity: 0.85 }); + hSub.textContent = 'Takenverdeler'; + herman.appendChild(hSub); nodesLayer.appendChild(herman); souls.forEach((node) => { - const group = make('g', { class: `mesh-node ${node.health || 'idle'}` }); - group.appendChild(make('circle', { cx: node._x, cy: node._y, r: 24 })); + const key = (node.agent_key || '').toLowerCase(); + const group = make('g', { class: `mesh-node mesh-agent ${node.health || 'idle'}` }); + group.appendChild(make('circle', { cx: node._x, cy: node._y, r: 22 })); const shortName = (node.display_name || node.agent_key || '?').split(' ')[0]; const t = make('text', { x: node._x, y: node._y + 4 }); t.textContent = shortName; group.appendChild(t); - const role = make('text', { x: node._x, y: node._y + 42, 'font-size': 10, opacity: 0.82 }); - role.textContent = node.role_title || node.agent_key; + const role = make('text', { x: node._x, y: node._y + 38, 'font-size': 9, opacity: 0.82 }); + role.textContent = (node.role_title || key).split('·')[0].trim().slice(0, 18); group.appendChild(role); + const status = make('text', { x: node._x, y: node._y + 52, 'font-size': 8, class: 'mesh-status' }); + status.textContent = (node.health || 'idle').toUpperCase(); + group.appendChild(status); group.addEventListener('click', () => { if (window.Cockpit && Cockpit.toast) { - Cockpit.toast(`${node.display_name || node.agent_key}: ${node.health || 'idle'}`, 'success'); + Cockpit.toast(`${node.display_name || key}: ${node.health || 'idle'}`, 'info'); } }); nodesLayer.appendChild(group); diff --git a/cockpit/static/js/analytics.js b/cockpit/static/js/analytics.js index ce0718a..8e7342e 100644 --- a/cockpit/static/js/analytics.js +++ b/cockpit/static/js/analytics.js @@ -100,40 +100,58 @@ window.AnalyticsCharts = (function () { } } - function render(data) { + function render(data, mode) { if (!data) return; + mode = mode || window.__vizMode || 'neo-bars'; + window.__analyticsLastData = data; renderKpis(document.getElementById('analytics-kpis'), data.kpis); - barChart('chart-deals', (data.deals_by_stage || []).map(function (r) { return r.stage; }), + var useRing = mode === 'neo-rings'; + var bar = function (id, labels, values, label, horizontal) { + if (useRing) doughnut(id, labels, values); + else barChart(id, labels, values, label, horizontal); + }; + bar('chart-deals', (data.deals_by_stage || []).map(function (r) { return r.stage; }), (data.deals_by_stage || []).map(function (r) { return Number(r.total || r.cnt || 0); }), 'EUR'); - barChart('chart-clients', (data.clients_by_stage || []).map(function (r) { return r.stage; }), + bar('chart-clients', (data.clients_by_stage || []).map(function (r) { return r.stage; }), (data.clients_by_stage || []).map(function (r) { return Number(r.cnt || 0); }), 'Klanten'); - barChart('chart-chains', (data.supermarkets_by_chain || []).map(function (r) { return r.chain; }), + bar('chart-chains', (data.supermarkets_by_chain || []).map(function (r) { return r.chain; }), (data.supermarkets_by_chain || []).map(function (r) { return Number(r.cnt || 0); }), 'Filialen'); - doughnut('chart-provinces', (data.supermarkets_by_province || []).map(function (r) { return r.province; }), - (data.supermarkets_by_province || []).map(function (r) { return Number(r.cnt || 0); })); + if (useRing) { + doughnut('chart-provinces', (data.supermarkets_by_province || []).map(function (r) { return r.province; }), + (data.supermarkets_by_province || []).map(function (r) { return Number(r.cnt || 0); })); + } else barChart('chart-provinces', (data.supermarkets_by_province || []).map(function (r) { return r.province; }), + (data.supermarkets_by_province || []).map(function (r) { return Number(r.cnt || 0); }), 'Filialen'); doughnut('chart-partnerships', (data.partnership_breakdown || []).map(function (r) { return r.status; }), (data.partnership_breakdown || []).map(function (r) { return Number(r.cnt || 0); })); - barChart('chart-agents', (data.events_by_agent || []).map(function (r) { return r.agent_name; }), + bar('chart-agents', (data.events_by_agent || []).map(function (r) { return r.agent_name; }), (data.events_by_agent || []).map(function (r) { return Number(r.cnt || 0); }), 'Events', true); - lineChart('chart-timeline', (data.events_timeline || []).map(function (r) { return String(r.day || '').substring(5); }), - (data.events_timeline || []).map(function (r) { return Number(r.cnt || 0); })); + if (mode === 'neo-table') { + lineChart('chart-timeline', [], []); + } else { + lineChart('chart-timeline', (data.events_timeline || []).map(function (r) { return String(r.day || '').substring(5); }), + (data.events_timeline || []).map(function (r) { return Number(r.cnt || 0); })); + } doughnut('chart-rss', (data.rss_by_category || []).map(function (r) { return r.category || 'other'; }), (data.rss_by_category || []).map(function (r) { return Number(r.cnt || 0); })); - barChart('chart-wholesale', (data.wholesalers_by_province || []).map(function (r) { return r.province; }), + bar('chart-wholesale', (data.wholesalers_by_province || []).map(function (r) { return r.province; }), (data.wholesalers_by_province || []).map(function (r) { return Number(r.cnt || 0); }), 'GH'); doughnut('chart-sentiment', (data.sentiment_distribution || []).map(function (r) { return r.sentiment_label || 'neutral'; }), (data.sentiment_distribution || []).map(function (r) { return Number(r.cnt || 0); })); - barChart('chart-words', (data.top_words || []).slice(0, 10).map(function (r) { return r.lemma; }), + bar('chart-words', (data.top_words || []).slice(0, 10).map(function (r) { return r.lemma; }), (data.top_words || []).slice(0, 10).map(function (r) { return Number(r.total || 0); }), 'Count', true); - barChart('chart-opportunities', (data.top_opportunities || []).map(function (r) { return (r.chain || '') + ' ' + (r.city || ''); }), + bar('chart-opportunities', (data.top_opportunities || []).map(function (r) { return (r.chain || '') + ' ' + (r.city || ''); }), (data.top_opportunities || []).map(function (r) { return Math.round(Number(r.halal_opportunity_score || 0)); }), 'Score', true); - barChart('chart-promo', (data.promo_by_chain || []).map(function (r) { return r.chain || '?'; }), + bar('chart-promo', (data.promo_by_chain || []).map(function (r) { return r.chain || '?'; }), (data.promo_by_chain || []).map(function (r) { return Number(r.cnt || 0); }), 'Promo'); doughnut('chart-milestones', (data.milestones_by_status || []).map(function (r) { return r.status; }), (data.milestones_by_status || []).map(function (r) { return Number(r.cnt || 0); })); renderTables(data); } + document.addEventListener('foodlinkk:vizmode', function (ev) { + if (window.__analyticsLastData) render(window.__analyticsLastData, ev.detail.mode); + }); + return { render: render, destroyAll: destroyAll }; })(); diff --git a/cockpit/static/js/briefing-charts.js b/cockpit/static/js/briefing-charts.js index 7962809..ed757a9 100644 --- a/cockpit/static/js/briefing-charts.js +++ b/cockpit/static/js/briefing-charts.js @@ -242,7 +242,7 @@ window.BriefingCharts = (function () { { label: 'Actieve klanten', sub: 'CRM · zaken mee', icon: '🤝', color: '#22c55e', pct: Math.min(95, Math.round(((stats.clients_active || 0) / Math.max(stats.clients_total || 1, 1)) * 100)) + '%', val: (stats.clients_active || 0) + ' / ' + (stats.clients_total || 0), link: '/clients' }, { label: 'CRM partnerships', sub: 'actieve filialen', icon: '🏪', color: '#ff9f43', pct: '45%', val: stats.crm_partnerships || 0, link: '/retail' }, { label: 'Supermarkten', sub: 'Retail 360 DB', icon: '🏪', color: '#b8ff3c', pct: '88%', val: (stats.supermarkets || 0).toLocaleString('nl-NL') }, - { label: 'Halal kansen', sub: 'top score', icon: '🎯', color: '#a855f7', pct: '65%', val: stats.top_opportunities && stats.top_opportunities[0] ? Math.round(Number(stats.top_opportunities[0].halal_opportunity_score || 0)) + '/100' : '—' }, + { label: 'Food trends', sub: 'RSS live', icon: '📰', color: '#38bdf8', pct: Math.min(95, ((stats.trending_food || stats.food_market_highlights || []).length * 10)) + '%', val: (stats.trending_food || stats.food_market_highlights || []).length || 0, link: '/marketing' }, { label: 'Goedkeuringen', sub: 'wacht op OK', icon: '✓', color: '#ffd700', pct: '30%', val: stats.pending_approvals || 0 }, ]; container.className = 'hm-neo-kpi-row'; @@ -257,11 +257,16 @@ window.BriefingCharts = (function () { function renderRetail(container, stats) { if (!container) return; - var opps = stats.top_opportunities || []; - if (!opps.length) { container.innerHTML = '

Geen kansen — open Retail 360

'; return; } - container.innerHTML = opps.map(function (o) { - var score = Math.round(Number(o.halal_opportunity_score) || 0); - return '' + (o.chain || '') + ' · ' + (o.name || '') + '
' + (o.city || '') + '
' + score + '/100
'; + var items = (stats.trending_food || stats.food_market_highlights || []).slice(0, 6); + if (!items.length) { + container.innerHTML = '

Geen trending — RSS ophalen in Marketing Hub

'; + return; + } + container.innerHTML = items.map(function (r) { + var when = (r.published_at || '').substring(0, 10); + return '' + + '' + (r.title || '') + '
' + (r.feed_name || 'Retail') + (when ? ' · ' + when : '') + '
' + + '' + ((r.category || 'food').toUpperCase()) + '
'; }).join(''); } @@ -289,16 +294,17 @@ window.BriefingCharts = (function () { { icon: '📁', label: 'Actieve promo\'s', val: stats.promo_campaigns || '—', link: '/marketing?tab=reclame' }, { icon: '📊', label: 'NAS documenten', val: stats.nas_docs || 0, link: '/documents' }, ]; - var opps = (stats.top_opportunities || []).slice(0, 3); + var trending = (stats.trending_food || stats.food_market_highlights || []).slice(0, 5); var ms = (stats.milestones_pending || []).slice(0, 3); var html = '
' + items.map(function (it) { return '' + it.icon + '' + '
' + it.label + '
' + it.val + '
'; }).join('') + '
'; - if (opps.length) { - html += '

Top halal kansen

'; } - html += ''; + var pending = stats.pending_approval_requests || []; + if (pending.length) { + html += '

⏳ Open goedkeuringen

    '; + pending.forEach(function (p) { + html += '
  • @' + (p.agent_key || '') + ' · ' + (p.title || '') + '
  • '; + }); + html += '
'; + } + html += ''; container.innerHTML = html; } @@ -325,21 +343,33 @@ window.BriefingCharts = (function () { if (longEl) longEl.innerHTML = parsed.longTerm.length ? parsed.longTerm.map(function (a) { return '
  • ' + a + '
  • '; }).join('') : '
  • Halal kant-en-klaar partnerships schalen
  • '; } - function renderLive(root, stats) { + function renderLive(root, stats, vizMode) { if (!root || !stats) return; + var mode = vizMode || window._dashboardVizMode || 'neo-bars'; renderKpis(document.getElementById('briefing-kpis'), stats); renderFoodHighlights(document.getElementById('briefing-food-highlights'), stats); renderExecutiveSummary(document.getElementById('briefing-executive-summary'), stats); renderRetail(document.getElementById('briefing-retail'), stats); renderMilestones(document.getElementById('briefing-milestones'), stats); + var actEl = document.getElementById('briefing-activity-log'); + if (actEl) { + var log = stats.activity_log || []; + actEl.innerHTML = log.length ? log.slice(0, 12).map(function (e) { return '
  • ' + e + '
  • '; }).join('') + : '
  • Nog geen agent-acties vandaag.
  • '; + } renderPipeline(document.getElementById('chart-pipeline'), stats); - renderSentiment(document.getElementById('chart-sentiment'), stats); renderWords(document.getElementById('chart-words'), stats); - renderAgents(document.getElementById('chart-agents'), stats); + if (window.VizEngine) { + VizEngine.renderSentiment(mode, document.getElementById('chart-sentiment'), document.getElementById('viz-sentiment-alt'), stats); + VizEngine.renderAgents(mode, document.getElementById('chart-agents'), document.getElementById('viz-agents-alt'), stats); + } else { + renderSentiment(document.getElementById('chart-sentiment'), stats); + renderAgents(document.getElementById('chart-agents'), stats); + } } - function render(root, stats, content, createdAt) { - renderLive(root, stats); + function render(root, stats, content, createdAt, vizMode) { + renderLive(root, stats, vizMode); renderText(root, content, createdAt); } diff --git a/cockpit/static/js/cockpit.js b/cockpit/static/js/cockpit.js index ffb9853..e7f597a 100644 --- a/cockpit/static/js/cockpit.js +++ b/cockpit/static/js/cockpit.js @@ -40,7 +40,9 @@ window.Cockpit = (function () { } function confirmDelete(message) { - return window.confirm(message || 'Delete this item?'); + var msg = message; + if (!msg && window.I18n) msg = window.I18n.t('common.confirm_delete'); + return window.confirm(msg || 'Delete this item?'); } function openDrawer(id) { diff --git a/cockpit/static/js/dashboard-layout.js b/cockpit/static/js/dashboard-layout.js new file mode 100644 index 0000000..508ed9c --- /dev/null +++ b/cockpit/static/js/dashboard-layout.js @@ -0,0 +1,97 @@ +(function (global) { + var WIDGET_META = { + kpis: { title: 'CEO KPI\'s', icon: '📊' }, + executive: { title: 'Alles op een rij', icon: '📋' }, + briefing: { title: 'Herman briefing', icon: '📝' }, + retail: { title: 'Retail operatie', icon: '🏪' }, + analytics: { title: 'Data & analytics', icon: '📈' }, + approvals: { title: 'Agent goedkeuringen', icon: '✓' }, + feed: { title: 'Agent feed', icon: '⚡' }, + }; + + function loadPrefs() { + return fetch('/api/preferences/ui').then(function (r) { return r.json(); }).catch(function () { + return { dashboard_layout: Object.keys(WIDGET_META), global_viz_mode: 'neo-bars', viz_modes: {} }; + }); + } + + function saveLayout(order) { + return fetch('/api/preferences/ui', { + method: 'PUT', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ dashboard_layout: order }), + }); + } + + function saveViz(globalMode, vizModes) { + return fetch('/api/preferences/ui', { + method: 'PUT', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ global_viz_mode: globalMode, viz_modes: vizModes || {} }), + }); + } + + function applyOrder(container, order) { + if (!container) return; + var map = {}; + Array.from(container.children).forEach(function (el) { + if (el.dataset && el.dataset.widget) map[el.dataset.widget] = el; + }); + order.forEach(function (id) { + if (map[id]) container.appendChild(map[id]); + }); + } + + function initDrag(container, onReorder) { + if (!container) return; + var dragEl = null; + Array.from(container.querySelectorAll('[data-widget]')).forEach(function (el) { + el.setAttribute('draggable', 'true'); + el.classList.add('hm-widget-draggable'); + el.addEventListener('dragstart', function (ev) { + dragEl = el; + el.classList.add('hm-widget-dragging'); + ev.dataTransfer.effectAllowed = 'move'; + }); + el.addEventListener('dragend', function () { + el.classList.remove('hm-widget-dragging'); + dragEl = null; + var order = Array.from(container.querySelectorAll('[data-widget]')).map(function (n) { return n.dataset.widget; }); + if (onReorder) onReorder(order); + }); + el.addEventListener('dragover', function (ev) { + ev.preventDefault(); + if (!dragEl || dragEl === el) return; + var rect = el.getBoundingClientRect(); + var after = ev.clientY > rect.top + rect.height / 2; + if (after) el.after(dragEl); else el.before(dragEl); + }); + }); + } + + function buildVizSelector(container, prefs, onChange) { + if (!container || !global.VizEngine) return; + container.innerHTML = '' + + global.VizEngine.MODES.map(function (m) { + var active = prefs.global_viz_mode === m.id ? ' active' : ''; + return ''; + }).join(''); + container.querySelectorAll('.viz-mode-btn').forEach(function (btn) { + btn.addEventListener('click', function () { + container.querySelectorAll('.viz-mode-btn').forEach(function (b) { b.classList.remove('active'); }); + btn.classList.add('active'); + if (onChange) onChange(btn.dataset.viz); + }); + }); + } + + global.DashboardLayout = { + WIDGET_META: WIDGET_META, + loadPrefs: loadPrefs, + saveLayout: saveLayout, + saveViz: saveViz, + applyOrder: applyOrder, + initDrag: initDrag, + buildVizSelector: buildVizSelector, + }; +})(window); diff --git a/cockpit/static/js/global-viz.js b/cockpit/static/js/global-viz.js new file mode 100644 index 0000000..25aa3e1 --- /dev/null +++ b/cockpit/static/js/global-viz.js @@ -0,0 +1,57 @@ +(function (global) { + var mode = 'neo-bars'; + + function getMode() { + return mode; + } + + function setMode(m, persist) { + mode = m; + global.__vizMode = m; + document.querySelectorAll('#global-viz-toolbar .global-viz-btn').forEach(function (btn) { + btn.classList.toggle('active', btn.dataset.viz === m); + }); + document.dispatchEvent(new CustomEvent('foodlinkk:vizmode', { detail: { mode: m } })); + if (persist !== false) { + fetch('/api/preferences/ui', { + method: 'PUT', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ global_viz_mode: m }), + }).catch(function () {}); + } + } + + function buildToolbar(container) { + if (!container || !global.VizEngine) return; + container.innerHTML = global.VizEngine.MODES.map(function (m) { + var short = m.label.replace('Neo ', ''); + var active = mode === m.id ? ' active' : ''; + return ''; + }).join(''); + container.querySelectorAll('.global-viz-btn').forEach(function (btn) { + btn.addEventListener('click', function () { setMode(btn.dataset.viz); }); + }); + } + + function init() { + if (global.location && global.location.pathname === '/') return; + fetch('/api/preferences/ui') + .then(function (r) { return r.json(); }) + .then(function (prefs) { + mode = prefs.global_viz_mode || 'neo-bars'; + global.__vizMode = mode; + buildToolbar(document.getElementById('global-viz-toolbar')); + document.dispatchEvent(new CustomEvent('foodlinkk:vizmode', { detail: { mode: mode } })); + }) + .catch(function () { + buildToolbar(document.getElementById('global-viz-toolbar')); + }); + } + + global.GlobalViz = { getMode: getMode, setMode: setMode, init: init }; + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', init); + } else { + init(); + } +})(window); diff --git a/cockpit/static/js/i18n.js b/cockpit/static/js/i18n.js new file mode 100644 index 0000000..2fa56f0 --- /dev/null +++ b/cockpit/static/js/i18n.js @@ -0,0 +1,80 @@ +/** Foodlinkk i18n — edit /static/i18n/nl.json and en.json to translate. */ +window.I18n = (function () { + var locale = 'nl'; + var strings = {}; + + function t(key, fallback) { + if (!key) return fallback || ''; + var parts = String(key).split('.'); + var o = strings; + for (var i = 0; i < parts.length; i++) { + if (o == null || typeof o !== 'object') return fallback != null ? fallback : key; + o = o[parts[i]]; + } + return typeof o === 'string' ? o : (fallback != null ? fallback : key); + } + + function applyDom() { + document.querySelectorAll('[data-i18n]').forEach(function (el) { + var k = el.getAttribute('data-i18n'); + if (k) el.textContent = t(k); + }); + document.querySelectorAll('[data-i18n-placeholder]').forEach(function (el) { + var k = el.getAttribute('data-i18n-placeholder'); + if (k) el.placeholder = t(k); + }); + document.querySelectorAll('[data-i18n-title]').forEach(function (el) { + var k = el.getAttribute('data-i18n-title'); + if (k) el.title = t(k); + }); + document.documentElement.lang = locale; + } + + async function loadBundle(loc) { + var r = await fetch('/static/i18n/' + loc + '.json?v=2'); + if (!r.ok) throw new Error('Locale ' + loc + ' not found'); + strings = await r.json(); + } + + async function setLocale(loc, persist) { + if (persist == null) persist = true; + locale = loc === 'en' ? 'en' : 'nl'; + try { + await loadBundle(locale); + } catch (e) { + if (locale !== 'nl') { + locale = 'nl'; + await loadBundle('nl'); + } + } + localStorage.setItem('foodlinkk_locale', locale); + applyDom(); + window.dispatchEvent(new CustomEvent('foodlinkk:locale', { detail: { locale: locale } })); + if (persist) { + fetch('/api/preferences/ui', { + method: 'PUT', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ locale: locale }), + }).catch(function () {}); + } + return locale; + } + + async function init() { + var loc = localStorage.getItem('foodlinkk_locale') || 'nl'; + try { + var prefs = await fetch('/api/preferences/ui').then(function (r) { return r.json(); }); + if (prefs.locale) loc = prefs.locale; + } catch (e) { /* ignore */ } + await setLocale(loc, false); + } + + return { t: t, init: init, setLocale: setLocale, locale: function () { return locale; }, applyDom: applyDom }; +})(); + +document.addEventListener('alpine:init', function () { + if (!window.Alpine) return; + Alpine.magic('t', function () { + return function (key, fallback) { return window.I18n.t(key, fallback); }; + }); +}); diff --git a/cockpit/static/js/ops-topology.js b/cockpit/static/js/ops-topology.js new file mode 100644 index 0000000..1716320 --- /dev/null +++ b/cockpit/static/js/ops-topology.js @@ -0,0 +1,222 @@ +(function () { + const NS = 'http://www.w3.org/2000/svg'; + + function el(tag, attrs, text) { + const node = document.createElementNS(NS, tag); + Object.entries(attrs || {}).forEach(([k, v]) => node.setAttribute(k, String(v))); + if (text != null) node.textContent = text; + return node; + } + + function clear(root) { + while (root.firstChild) root.removeChild(root.firstChild); + } + + function statusClass(status) { + const s = (status || 'unknown').toLowerCase(); + if (['online', 'running', 'up'].includes(s)) return 'online'; + if (['offline', 'down', 'stopped'].includes(s)) return 'offline'; + return 'degraded'; + } + + function flattenTree(nodes, parentId) { + const out = []; + (nodes || []).forEach((n) => { + out.push({ ...n, parentId: parentId || null }); + out.push(...flattenTree(n.children || [], n.id)); + }); + return out; + } + + function layoutNodes(flat, width) { + const byType = { hardware: [], proxmox: [], vm: [], service: [] }; + flat.forEach((n) => { + const t = n.type || 'service'; + (byType[t] || byType.service).push(n); + }); + + const positions = {}; + positions['hardware-r340'] = { x: width / 2, y: 70 }; + positions['proxmox-host'] = { x: width / 2, y: 190 }; + + const vm = byType.vm[0]; + if (vm) positions[vm.id] = { x: width / 2, y: 310 }; + + const services = byType.service; + const count = Math.max(services.length, 1); + const pad = 70; + const span = width - pad * 2; + services.forEach((s, i) => { + positions[s.id] = { + x: pad + (span * (i + 0.5)) / count, + y: 430, + }; + }); + + flat.forEach((n, i) => { + if (!positions[n.id]) { + positions[n.id] = { x: 100 + (i % 6) * (width / 7), y: 430 }; + } + }); + + positions['mon-sysops'] = { x: width * 0.32, y: 570 }; + positions['mon-research'] = { x: width * 0.68, y: 570 }; + return positions; + } + + function drawLayerBands(svg, layers, width) { + const g = el('g', { class: 'ops-layers' }); + (layers || []).forEach((layer) => { + g.appendChild(el('line', { + x1: 36, y1: layer.y - 28, x2: width - 36, y2: layer.y - 28, + class: 'ops-layer-line', + })); + g.appendChild(el('text', { + x: 14, y: layer.y - 33, class: 'ops-layer-label', + }, layer.label)); + }); + svg.appendChild(g); + } + + function drawEdges(svg, flat, positions) { + const g = el('g', { class: 'ops-edges' }); + flat.forEach((n) => { + if (!n.parentId) return; + const from = positions[n.parentId]; + const to = positions[n.id]; + if (!from || !to) return; + const yOffFrom = n.parentId === 'hardware-r340' ? 38 : 32; + const yOffTo = n.type === 'hardware' ? -38 : n.type === 'service' ? -22 : -30; + g.appendChild(el('line', { + x1: from.x, y1: from.y + yOffFrom, x2: to.x, y2: to.y + yOffTo, + class: 'topology-line', + })); + g.appendChild(el('line', { + x1: from.x, y1: from.y + yOffFrom, x2: to.x, y2: to.y + yOffTo, + class: 'pulse-line', + })); + }); + svg.appendChild(g); + } + + function drawHardwareNode(svg, n, pos) { + const cls = statusClass(n.status); + const g = el('g', { + class: `ops-node-group node-hardware status-${cls}`, + transform: `translate(${pos.x},${pos.y})`, + }); + g.appendChild(el('rect', { x: -95, y: -36, width: 190, height: 72, rx: 8, class: 'ops-hardware-box' })); + g.appendChild(el('rect', { x: -88, y: -28, width: 12, height: 56, rx: 2, class: 'ops-hardware-slot' })); + g.appendChild(el('rect', { x: -70, y: -28, width: 12, height: 56, rx: 2, class: 'ops-hardware-slot' })); + g.appendChild(el('text', { x: -48, y: -6, class: 'ops-node-title ops-title-left' }, 'Dell PowerEdge')); + g.appendChild(el('text', { x: -48, y: 14, class: 'ops-node-sub ops-title-left' }, 'R340 · Bare metal')); + g.appendChild(el('text', { x: -48, y: 32, class: 'ops-node-role ops-title-left' }, cls.toUpperCase())); + svg.appendChild(g); + } + + function drawNode(svg, n, pos) { + if (n.type === 'hardware') { + drawHardwareNode(svg, n, pos); + return; + } + const cls = statusClass(n.status); + const g = el('g', { + class: `ops-node-group node-${n.type || 'service'} status-${cls}`, + transform: `translate(${pos.x},${pos.y})`, + }); + const r = n.type === 'proxmox' ? 38 : n.type === 'vm' ? 32 : 24; + g.appendChild(el('circle', { r: r, class: 'ops-node-circle' })); + + const title = (n.label || n.id).split('·')[0].trim(); + g.appendChild(el('text', { y: -6, class: 'ops-node-title' }, title.length > 18 ? title.slice(0, 16) + '…' : title)); + + if (n.type === 'vm' && n.vmid) { + g.appendChild(el('text', { y: 10, class: 'ops-node-sub' }, 'ID ' + n.vmid + ' · ' + cls.toUpperCase())); + } else { + g.appendChild(el('text', { y: 10, class: 'ops-node-sub' }, cls.toUpperCase())); + } + + if (n.role) { + const role = n.role.length > 28 ? n.role.slice(0, 26) + '…' : n.role; + g.appendChild(el('text', { y: 24, class: 'ops-node-role' }, role)); + } + + if (n.url && n.type === 'service') { + const link = el('a', { href: n.url, target: '_blank', rel: 'noopener' }); + link.appendChild(g); + svg.appendChild(link); + } else { + svg.appendChild(g); + } + } + + function drawMonitorAgents(svg, agents, positions, stats) { + (agents || []).forEach((a) => { + const pos = positions[a.id] || { x: 200, y: 570 }; + const stat = (stats || {})[a.agent_key] || {}; + const health = stat.health || 'idle'; + const g = el('g', { + class: `ops-node-group ops-monitor status-${health}`, + transform: `translate(${pos.x},${pos.y})`, + }); + g.appendChild(el('rect', { x: -72, y: -30, width: 144, height: 60, rx: 10, class: 'ops-monitor-box' })); + g.appendChild(el('text', { y: -6, class: 'ops-node-title' }, a.label)); + g.appendChild(el('text', { y: 10, class: 'ops-node-sub' }, health.toUpperCase())); + g.appendChild(el('text', { y: 24, class: 'ops-node-role' }, a.role || '')); + svg.appendChild(g); + }); + } + + async function loadAgentHealth() { + try { + const r = await fetch('/api/agents/mesh'); + if (!r.ok) return {}; + const data = await r.json(); + const map = {}; + (data.nodes || []).forEach((n) => { map[n.agent_key] = { health: n.health, events_6h: n.events_6h }; }); + return map; + } catch (e) { + return {}; + } + } + + async function render(canvasId, metaEl) { + const svg = document.getElementById(canvasId); + if (!svg) return; + clear(svg); + const width = 1200; + const height = 620; + svg.setAttribute('viewBox', `0 0 ${width} ${height}`); + + try { + const [topoRes, agentStats] = await Promise.all([ + fetch('/api/ops/topology').then((r) => r.json()), + loadAgentHealth(), + ]); + const flat = flattenTree(topoRes.nodes || []); + const positions = layoutNodes(flat, width); + (topoRes.layer_agents || []).forEach((a) => { + if (!positions[a.id]) positions[a.id] = { x: width / 2, y: 570 }; + }); + + drawLayerBands(svg, topoRes.layers, width); + drawEdges(svg, flat, positions); + flat.forEach((n) => { + const pos = positions[n.id]; + if (pos) drawNode(svg, n, pos); + }); + drawMonitorAgents(svg, topoRes.layer_agents, positions, agentStats); + + if (metaEl) { + const online = (topoRes.meta && topoRes.meta.services_online) || 0; + metaEl.textContent = + 'Update: ' + (topoRes.generated_at || '—').substring(0, 19).replace('T', ' ') + + ' · ' + online + ' services online'; + } + } catch (e) { + svg.appendChild(el('text', { x: 40, y: 60, fill: '#ef4444', 'font-size': 14 }, 'Topology laden mislukt: ' + e.message)); + } + } + + window.OpsTopology = { render }; +})(); diff --git a/cockpit/static/js/page-viz.js b/cockpit/static/js/page-viz.js new file mode 100644 index 0000000..2f43de0 --- /dev/null +++ b/cockpit/static/js/page-viz.js @@ -0,0 +1,27 @@ +(function (global) { + function init(pageKey, renderFn) { + if (!global.DashboardLayout || typeof renderFn !== 'function') return Promise.resolve(); + return global.DashboardLayout.loadPrefs().then(function (prefs) { + var mode = (prefs.viz_modes || {})[pageKey] || prefs.global_viz_mode || 'neo-bars'; + var toolbar = document.getElementById('viz-toolbar'); + if (toolbar) { + global.DashboardLayout.buildVizSelector( + toolbar, + Object.assign({}, prefs, { global_viz_mode: mode }), + function (m) { + var vizModes = Object.assign({}, prefs.viz_modes || {}, {}); + vizModes[pageKey] = m; + global.DashboardLayout.saveViz(prefs.global_viz_mode, vizModes); + renderFn(m); + } + ); + } + renderFn(mode); + document.addEventListener('foodlinkk:vizmode', function (ev) { + renderFn(ev.detail.mode); + }); + }); + } + + global.PageViz = { init: init }; +})(window); diff --git a/cockpit/static/js/viz-engine.js b/cockpit/static/js/viz-engine.js new file mode 100644 index 0000000..e0e66f3 --- /dev/null +++ b/cockpit/static/js/viz-engine.js @@ -0,0 +1,218 @@ +(function (global) { + var MODES = [ + { id: 'neo-bars', label: 'Neo staafdiagram' }, + { id: 'neo-rings', label: 'Neo ringen' }, + { id: 'neo-equalizer', label: 'Neo equalizer' }, + { id: 'neo-cards', label: 'Neo kaarten' }, + { id: 'neo-table', label: 'Neo tabel' }, + ]; + + var charts = {}; + + function destroy(key) { + if (charts[key]) { + charts[key].destroy(); + charts[key] = null; + } + } + + function colors() { + return { + gold: 'rgba(252, 211, 77, 0.9)', cyan: 'rgba(56, 189, 248, 0.9)', + green: 'rgba(74, 222, 128, 0.9)', red: 'rgba(251, 113, 133, 0.9)', + purple: 'rgba(168, 85, 247, 0.9)', gray: 'rgba(159, 176, 196, 0.85)', + grid: 'rgba(159, 176, 196, 0.15)', text: '#c8d4e0', + }; + } + + function eqBars(counts, cls) { + var max = Math.max.apply(null, counts.concat([1])); + return '
    ' + + counts.map(function (v) { + var h = Math.max(18, Math.round((v / max) * 92)); + return ''; + }).join('') + '
    '; + } + + function findPanel(canvas, alt) { + var el = (canvas && canvas.closest('.page-viz-panel')) || (alt && alt.closest('.page-viz-panel')); + return el || null; + } + + function applyPanelLayout(canvas, alt, mode) { + var panel = findPanel(canvas, alt); + if (!panel) return; + var isCanvas = mode === 'neo-bars' || mode === 'neo-rings'; + panel.classList.toggle('viz-mode-chart', isCanvas); + panel.classList.toggle('viz-mode-alt', !isCanvas); + panel.classList.toggle('viz-mode-rings', mode === 'neo-rings'); + } + + function useHorizontal(labels, opts) { + if (opts && opts.horizontal !== undefined) return opts.horizontal; + return (labels || []).length >= 6; + } + + function renderBars(canvas, labels, values, opts) { + if (!canvas || typeof Chart === 'undefined') return; + opts = opts || { key: 'chart' }; + var c = colors(); + var horiz = useHorizontal(labels, opts); + destroy(opts.key); + charts[opts.key] = new Chart(canvas, { + type: 'bar', + data: { + labels: labels, + datasets: [{ data: values, backgroundColor: opts.color || c.cyan, borderRadius: 6, barThickness: horiz ? 'flex' : undefined, maxBarThickness: horiz ? 28 : 48 }], + }, + options: { + indexAxis: horiz ? 'y' : 'x', + responsive: true, + maintainAspectRatio: false, + layout: { padding: { top: 4, right: 8, bottom: 4, left: 4 } }, + plugins: { legend: { display: false }, title: { display: !!opts.title, text: opts.title, color: c.text, padding: { bottom: 8 } } }, + scales: { + y: horiz + ? { ticks: { color: c.text, autoSkip: false, font: { size: 11 } }, grid: { color: c.grid } } + : { ticks: { color: c.text }, grid: { color: c.grid }, beginAtZero: true }, + x: horiz + ? { ticks: { color: c.text }, grid: { display: false }, beginAtZero: true } + : { ticks: { color: c.text, maxRotation: 45, minRotation: 0, autoSkip: false, font: { size: 10 } }, grid: { display: false } }, + }, + }, + }); + requestAnimationFrame(function () { + if (charts[opts.key]) charts[opts.key].resize(); + }); + } + + function renderRings(canvas, labels, values, key, title) { + if (!canvas || typeof Chart === 'undefined') return; + var c = colors(); + destroy(key); + charts[key] = new Chart(canvas, { + type: 'doughnut', + data: { + labels: labels, + datasets: [{ data: values, backgroundColor: [c.green, c.gray, c.red, c.gold, c.cyan, c.purple], borderWidth: 0 }], + }, + options: { + responsive: true, + maintainAspectRatio: false, + cutout: '62%', + layout: { padding: 4 }, + plugins: { + legend: { position: 'bottom', labels: { color: c.text, boxWidth: 10, padding: 8, font: { size: 10 } } }, + title: { display: !!title, text: title, color: c.text, font: { size: 11 } }, + }, + }, + }); + requestAnimationFrame(function () { + if (charts[key]) charts[key].resize(); + }); + } + + function renderCards(container, rows) { + if (!container) return; + container.innerHTML = '
    ' + rows.map(function (r) { + return '
    ' + r.label + '' + r.value + '
    '; + }).join('') + '
    '; + } + + function renderTable(container, rows) { + if (!container) return; + container.innerHTML = '' + + rows.map(function (r) { return ''; }).join('') + + '
    ItemWaarde
    ' + r.label + '' + r.value + '
    '; + } + + function renderEqualizer(container, rows, cls) { + if (!container) return; + container.innerHTML = rows.map(function (r) { + return '
    ' + r.label + '' + r.value + '
    '; + }).join('') + eqBars(rows.map(function (r) { return Number(r.raw) || 0; }), cls); + } + + function renderWidget(mode, spec) { + var canvas = spec.canvas; + var alt = spec.altContainer; + applyPanelLayout(canvas, alt, mode); + if (mode === 'neo-bars' && canvas) { + if (alt) alt.innerHTML = ''; + canvas.style.display = ''; + renderBars(canvas, spec.labels, spec.values, spec.chartOpts || { key: spec.key }); + return; + } + if (mode === 'neo-rings' && canvas) { + if (alt) alt.innerHTML = ''; + canvas.style.display = ''; + renderRings(canvas, spec.labels, spec.values, spec.key, spec.title); + return; + } + if (canvas) canvas.style.display = 'none'; + if (!alt) return; + if (mode === 'neo-equalizer') renderEqualizer(alt, spec.rows, spec.eqClass); + else if (mode === 'neo-cards') renderCards(alt, spec.rows); + else if (mode === 'neo-table') renderTable(alt, spec.rows); + else { + if (canvas) { canvas.style.display = ''; renderBars(canvas, spec.labels, spec.values, spec.chartOpts || { key: spec.key }); } + } + } + + global.VizEngine = { + MODES: MODES, + renderWidget: renderWidget, + destroyAll: function () { Object.keys(charts).forEach(destroy); }, + renderSentiment: function (mode, canvas, alt, stats, widgetMode) { + var m = widgetMode || mode; + var files = stats.nas_files || []; + var counts = { positive: 0, neutral: 0, negative: 0 }; + files.forEach(function (f) { + var s = (f.sentiment_label || 'neutral').toLowerCase(); + if (counts[s] !== undefined) counts[s]++; + }); + if (!files.length) counts.neutral = 1; + renderWidget(m, { + canvas: canvas, altContainer: alt, key: 'sentiment', + labels: ['Positief', 'Neutraal', 'Negatief'], + values: [counts.positive, counts.neutral, counts.negative], + title: 'NAS sentiment', + rows: [ + { label: 'Positief', value: counts.positive, raw: counts.positive }, + { label: 'Neutraal', value: counts.neutral, raw: counts.neutral }, + { label: 'Negatief', value: counts.negative, raw: counts.negative }, + ], + eqClass: 'hm-eq-purple', + }); + }, + renderAgents: function (mode, canvas, alt, stats, widgetMode) { + var m = widgetMode || mode; + var map = {}; + (stats.recent_events || []).forEach(function (e) { + var a = e.agent_name || 'other'; + map[a] = (map[a] || 0) + 1; + }); + var labels = Object.keys(map); + var values = labels.map(function (k) { return map[k]; }); + if (!labels.length) { labels = ['geen']; values = [0]; } + renderWidget(m, { + canvas: canvas, altContainer: alt, key: 'agents', + labels: labels, values: values, title: 'Agent activiteit', + chartOpts: { key: 'agents', color: colors().gold }, + rows: labels.map(function (l, i) { return { label: l, value: values[i], raw: values[i] }; }), + eqClass: 'hm-eq-lime', + }); + }, + renderFromRows: function (mode, canvas, alt, key, title, rows, eqClass, chartColor) { + var labels = rows.map(function (r) { return r.label; }); + var values = rows.map(function (r) { return Number(r.raw) || 0; }); + renderWidget(mode, { + canvas: canvas, altContainer: alt, key: key, + labels: labels, values: values, title: title, + chartOpts: { key: key, color: chartColor || colors().cyan }, + rows: rows, + eqClass: eqClass || 'hm-eq-cyan', + }); + }, + }; +})(window); diff --git a/cockpit/templates/agents.html b/cockpit/templates/agents.html index dd70de8..2d1d4d1 100644 --- a/cockpit/templates/agents.html +++ b/cockpit/templates/agents.html @@ -1,8 +1,11 @@ {% extends "base.html" %} {% block extra_head %} + - + + + {% endblock %} {% block content %}
    @@ -11,6 +14,15 @@

    Animated team · duidelijke rollen · soul.md · live activiteit

    +
    +
    +

    Agent activiteit (events)

    5 visualisatie-modi
    +
    +
    +
    +
    +
    +
    @@ -27,54 +43,41 @@
    🤖
    Agents
    geregistreerd
    0
    Events
    totaal gelogd
    0
    Actief
    agents online
    0
    -
    👑
    Herman
    orchestrator
    CEO
    +
    👑
    Herman
    Co-CEO · takenverdeler
    Co-CEO
    -
    -
    -
    - - - - - -
    -
    -
    +

    @@ -87,9 +90,16 @@ -

    Recente activiteit

    +
    +

    Recente activiteit

    + +

    Nog geen events voor deze agent.

    @@ -98,7 +108,7 @@

    Netwerk

    -

    Communication mesh met Herman als centrale Co-CEO hub.

    +

    Agents onderaan → Herman (Co-CEO) → CEO & CTO. Pulse = actieve communicatie.

    @@ -110,11 +120,82 @@
    + +
    +
    +
    +
    +

    Approval queue

    +

    Agents dienen queries in → jij keurt goed → pas daarna mag de actie uitgevoerd worden.

    +
    + +
    + + + + + +
    #AgentActieTitelStatusTijd
    +

    Geen approval requests.

    +
    +
    + +
    +
    {% endblock %} {% block scripts %} + + {% endblock %} diff --git a/cockpit/templates/analytics.html b/cockpit/templates/analytics.html index 7e46d0c..66d69e9 100644 --- a/cockpit/templates/analytics.html +++ b/cockpit/templates/analytics.html @@ -71,5 +71,5 @@ {% endblock %} {% block scripts %} - + {% endblock %} diff --git a/cockpit/templates/base.html b/cockpit/templates/base.html index 731a183..7d29bfa 100644 --- a/cockpit/templates/base.html +++ b/cockpit/templates/base.html @@ -17,6 +17,7 @@ + {% block extra_head %}{% endblock %} @@ -30,46 +31,48 @@
    -
    Hermes
    - Telegram +
    Hermes
    + Telegram
    -
    System
    - Analytics - Voice - IT Ops - Settings +
    Systeem
    + Analytics + Voice + IT Ops + Instellingen + Gitea
    @@ -79,6 +82,11 @@
    Foodlinkk +
    ·
    {% block content %}{% endblock %}
    @@ -91,11 +99,15 @@ - + + + + diff --git a/cockpit/templates/dashboard.html b/cockpit/templates/dashboard.html index e62b623..cd8fd5c 100644 --- a/cockpit/templates/dashboard.html +++ b/cockpit/templates/dashboard.html @@ -2,14 +2,25 @@ {% block extra_head %} - + {% endblock %} {% block content %}

    Herman · Command Center Live

    -

    CEO overzicht · klanten · briefing · retail · alles op een rij

    +

    CEO overzicht · trending retail · briefing · platform links

    +
    @@ -24,6 +35,7 @@
    + CRM Clients @@ -32,29 +44,38 @@
    +
    +
    -
    +
    +
    Sleep widget · CEO KPI's

    CEO KPI's

    -
    +
    +
    Sleep widget · Executive

    Alles op een rij

    -

    Executive samenvatting

    live database · geen RSS — zie Marketing Hub
    +

    Executive samenvatting

    live database
    -
    +
    +
    Sleep widget · Briefing

    Herman briefing

    Samenvatting

    +
    +

    📋 Herman activiteitenlog

    +
      +

      ⚡ Korte termijn

      @@ -68,12 +89,14 @@
      -
      +
      +
      Sleep widget · Retail

      Retail operatie

      -

      Top retail kansen

      Retail 360 →
      +

      Trending food retail

      Marketing Hub →
      +

      Sales milestones

      live DB
      @@ -86,72 +109,153 @@
      -
      -

      Data & analytics

      +
      +
      Sleep widget · Analytics
      +

      Data & analytics

      -
      +

      Pipeline

      live deals
      +
      -
      -

      NAS sentiment

      documenten
      -
      +
      +

      NAS sentiment

      neo-bars
      +
      +
      +
      +
      -
      +

      NAS top woorden

      corpus
      +
      -
      -

      Agent activiteit

      laatste events
      -
      +
      +

      Agent activiteit

      neo-bars
      +
      +
      +
      +
      +
      +
      Sleep widget · Goedkeuringen
      +

      Agent goedkeuringen

      +
      +

      SysOps vraagt dagelijks toestemming voor update-scan en Gitea backup. Keur goed → actie wordt automatisch uitgevoerd.

      +
      +
      +
      + +
      +
      Sleep widget · Feed
      +
      +

      Agent feed Live

      +
      + {% for ev in agent_feed[:12] %} +
      + {{ ev.created_at[11:16] if ev.created_at else '' }} + {{ ev.agent_name }} + {{ ev.title or ev.event_type }} +
      + {% else %}

      Nog geen events.

      {% endfor %} +
      +
      +
      +

      Projecten Alle projecten →

      +

      Laden…

      +
      +
      +
      - -
      -
      -

      Agent feed Live

      -
      - {% for ev in agent_feed[:12] %} -
      - {{ ev.created_at[11:16] if ev.created_at else '' }} - {{ ev.agent_name }} - {{ ev.title or ev.event_type }} -
      - {% else %}

      Nog geen events.

      {% endfor %} -
      -
      -
      -

      Wacht op OK

      - {% for item in approvals[:8] %} -
      {{ item.agent_name }} {{ item.title or item.event_type }}
      - {% else %}

      Geen goedkeuringen 🎉

      {% endfor %} -
      -
      {% endblock %} {% block scripts %} - + + + + {% endblock %} {% block content %} -
      -