From 8c727dd99e0adca834f701dc4f676f9a0e5f7567 Mon Sep 17 00:00:00 2001 From: npeter83 Date: Fri, 19 Jun 2026 19:52:02 +0200 Subject: [PATCH 1/3] =?UTF-8?q?feat(auth):=20account=20lifecycle=20?= =?UTF-8?q?=E2=80=94=20Google=20linking,=20passwords,=20suspension=20&=20d?= =?UTF-8?q?eletion=20plumbing?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Link a Google account to a password account, and adopt the Google identity onto a matching email account instead of 500ing on a duplicate; set or change a password from Settings. - Expose has_google/has_password on /api/me for the Sign-in methods UI. - Mark Google logins email-verified (backfill existing rows, migration 0024); stop a routine login from clobbering an admin-assigned role (env ADMIN_EMAILS stays the bootstrap admin). - Suspension login-gates (password + Google callback + current_user) with a rate-limited 'suspended' notice; shared purge_user (cascade delete + access-request cleanup + Google-grant revoke) behind self- and admin-deletion; single app_base source for user-facing email links. --- .../versions/0024_google_email_verified.py | 31 +++ backend/app/auth.py | 254 ++++++++++++++++-- backend/app/config.py | 8 + backend/app/routes/me.py | 18 +- frontend/src/components/SettingsPanel.tsx | 125 ++++++++- frontend/src/i18n/locales/de/settings.json | 29 +- frontend/src/i18n/locales/en/settings.json | 29 +- frontend/src/i18n/locales/hu/settings.json | 29 +- frontend/src/lib/api.ts | 27 ++ 9 files changed, 507 insertions(+), 43 deletions(-) create mode 100644 backend/alembic/versions/0024_google_email_verified.py diff --git a/backend/alembic/versions/0024_google_email_verified.py b/backend/alembic/versions/0024_google_email_verified.py new file mode 100644 index 0000000..7b7af53 --- /dev/null +++ b/backend/alembic/versions/0024_google_email_verified.py @@ -0,0 +1,31 @@ +"""backfill email_verified for Google accounts + +Revision ID: 0024_google_email_verified +Revises: 0023_user_suspension +Create Date: 2026-06-19 + +A Google sign-in proves the email, but earlier Google signups were created with +email_verified=false (the callback didn't set it). Backfill those so the flag reflects reality — +matters because password-login gates on email_verified, so a Google user who later adds a password +must count as verified. Demo/password-only rows (google_sub IS NULL) are left untouched. +""" +from typing import Sequence, Union + +from alembic import op + +revision: str = "0024_google_email_verified" +down_revision: Union[str, None] = "0023_user_suspension" +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + op.execute( + "UPDATE users SET email_verified = true " + "WHERE google_sub IS NOT NULL AND email_verified = false" + ) + + +def downgrade() -> None: + # Not reversible — we can't tell which rows were flipped. No-op. + pass diff --git a/backend/app/auth.py b/backend/app/auth.py index 4139b4f..e3fc79a 100644 --- a/backend/app/auth.py +++ b/backend/app/auth.py @@ -4,10 +4,11 @@ import re import secrets from datetime import datetime, timedelta, timezone +import httpx from authlib.integrations.starlette_client import OAuth, OAuthError from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException, Request from fastapi.responses import JSONResponse, RedirectResponse -from sqlalchemy import select +from sqlalchemy import delete, select from sqlalchemy.orm import Session from app import email as email_mod @@ -16,7 +17,7 @@ from app.config import settings from app.db import get_db from app.models import AuthToken, DemoWhitelist, Invite, OAuthToken, User from app.ratelimit import RateLimiter -from app.security import encrypt, hash_password, verify_password +from app.security import decrypt, encrypt, hash_password, verify_password # Email+password auth tuning. PASSWORD_MIN_LEN = 10 @@ -25,6 +26,22 @@ RESET_TTL = timedelta(hours=1) _register_limiter = RateLimiter(max_events=5, window_seconds=300) _login_limiter = RateLimiter(max_events=10, window_seconds=300) _reset_limiter = RateLimiter(max_events=5, window_seconds=300) +# At most one "your account is suspended" email per address per hour, so a suspended user who +# keeps retrying (or a script with their valid credentials) can't be used to mailbomb them. +_suspend_email_limiter = RateLimiter(max_events=1, window_seconds=3600) + + +def operator_contact() -> str | None: + """Who a blocked user should contact — the first configured admin email, if any.""" + return next(iter(sorted(settings.admin_email_set)), None) + + +def _notify_suspended(background: BackgroundTasks, email: str) -> None: + """Schedule the one-per-hour 'account suspended' email to a user whose (otherwise valid) + sign-in was just blocked. Gated by verified credentials at the call site, so this can't be + triggered by someone who doesn't control the account.""" + if _suspend_email_limiter.allow(email): + background.add_task(email_mod.send_account_suspended, email, operator_contact()) _EMAIL_RE = re.compile(r"^[^@\s]+@[^@\s]+\.[^@\s]+$") @@ -190,7 +207,16 @@ async def callback( if not userinfo or not userinfo.get("sub"): raise HTTPException(status_code=400, detail="No user info returned by Google") + sub = userinfo["sub"] email = (userinfo.get("email") or "").lower() + + # Linking mode: an already-authenticated account is attaching this Google identity (a + # password account enabling YouTube or connecting SSO). The marker is set by /auth/link and + # /auth/upgrade; when present we attach to the current user instead of identifying by sub. + link_uid = request.session.pop("oauth_link_uid", None) + if link_uid is not None: + return _complete_link(request, db, link_uid, sub, userinfo, token) + if not is_allowed(db, email): log.warning("Login denied (not approved): %s", email or "") # A denied Google login doubles as an access request: record it for the admin and @@ -206,14 +232,49 @@ async def callback( return RedirectResponse(url="/?access=requested") return RedirectResponse(url="/?access=denied") - user = db.query(User).filter(User.google_sub == userinfo["sub"]).one_or_none() + user = db.query(User).filter(User.google_sub == sub).one_or_none() if user is None: - user = User(google_sub=userinfo["sub"], email=email) - db.add(user) + # No account carries this Google identity yet. If one already exists for this email — + # e.g. an email+password registration — adopt the Google identity onto it instead of + # inserting a duplicate (which would collide on the unique email and 500). Google has + # verified the address, so this safely unifies password + Google sign-in on one account. + existing = db.query(User).filter(User.email == email).one_or_none() + if existing is not None: + if existing.google_sub is not None and existing.google_sub != sub: + # A different Google identity is already bound to this email — refuse rather than + # hijack it. (Near-impossible with real Google accounts: email↔sub is stable.) + log.warning("Google login email collision (different sub): %s", email) + return RedirectResponse(url="/?access=denied") + user = existing + user.google_sub = sub + # Google verified the email and is_allowed granted access, so finish activating a + # previously pending password registration (otherwise current_user would bounce it). + user.email_verified = True + user.is_active = True + else: + user = User(google_sub=sub, email=email) + db.add(user) + # A suspended account can't sign in by any method. Block before establishing the session and + # tell the (verified) owner why — a successful Google auth proves they control this account. + if user.is_suspended: + log.info("Suspended account blocked at Google login: %s", email) + _notify_suspended(background, user.email) + return RedirectResponse(url="/?login=suspended") user.email = email user.display_name = userinfo.get("name") user.avatar_url = userinfo.get("picture") - user.role = "admin" if email in settings.admin_email_set else "user" + # ADMIN_EMAILS (env) is the bootstrap admin list and always wins, so the configured admin can't + # be locked out. Everyone else's role is managed in the admin UI and stored in the DB, so a + # routine login must NOT reset it (that would clobber a UI promotion/demotion). Only seed a + # default for a brand-new account (its role attribute is still unset before flush). + if email in settings.admin_email_set: + user.role = "admin" + elif not user.role: + user.role = "user" + # Google attests the email, so a Google sign-in implicitly verifies it. Setting this also lets + # a Google user who later adds a password sign in (password-login gates on email_verified). + if userinfo.get("email_verified", True): + user.email_verified = True # Default UI language from the Google-reported locale on first login (if the user hasn't # picked one yet); unsupported locales fall back to English. prefs = dict(user.preferences or {}) @@ -223,19 +284,7 @@ async def callback( user.preferences = prefs db.flush() - tok = user.token or OAuthToken(user=user) - # Google only returns a refresh_token on (re)consent; keep the previous one otherwise. - if token.get("refresh_token"): - tok.refresh_token_enc = encrypt(token["refresh_token"]) - tok.access_token = token.get("access_token") - expires_at = token.get("expires_at") - tok.expiry = ( - datetime.fromtimestamp(expires_at, tz=timezone.utc) if expires_at else None - ) - # include_granted_scopes=true means Google returns the union of all scopes the user - # has ever granted this app, so this correctly reflects read/write upgrades too. - tok.scopes = token.get("scope") or BASE_SCOPES - db.add(tok) + _store_token(db, user, token) db.commit() # Multi-session: remember every account that has authenticated in this browser so the @@ -249,6 +298,94 @@ async def callback( return RedirectResponse(url="/") +def _store_token(db: Session, user: User, token: dict) -> None: + """Persist the OAuth grant on the user's single token row, creating it if absent. Google + only returns a refresh_token on (re)consent, so the previous one is kept otherwise. + include_granted_scopes=true means `scope` is the union of everything granted, so this + reflects read/write upgrades correctly.""" + tok = user.token or OAuthToken(user=user) + if token.get("refresh_token"): + tok.refresh_token_enc = encrypt(token["refresh_token"]) + tok.access_token = token.get("access_token") + expires_at = token.get("expires_at") + tok.expiry = datetime.fromtimestamp(expires_at, tz=timezone.utc) if expires_at else None + tok.scopes = token.get("scope") or BASE_SCOPES + db.add(tok) + + +def revoke_google_token(token: str | None) -> None: + """Best-effort revocation of a Google OAuth grant at Google's endpoint. Revoking the refresh + token tears down the whole grant, so a later sign-in starts from a clean consent (no scopes + silently carried over via include_granted_scopes). Fail-soft: never blocks the caller — used + from account deletion, where our own data is already gone regardless of Google's response.""" + if not token: + return + try: + resp = httpx.post( + "https://oauth2.googleapis.com/revoke", + data={"token": token}, + headers={"Content-Type": "application/x-www-form-urlencoded"}, + timeout=10, + ) + log.info("Google token revoke: status=%s", resp.status_code) + except Exception: + log.warning("Google token revoke failed", exc_info=True) + + +def purge_user(db: Session, user: User, background: BackgroundTasks) -> None: + """Hard-delete a user and ALL their personal data (subscriptions, tags, video states, + playlists, notifications, tokens — all cascade on the users row), erase their access-request + row, and revoke their Google grant. Shared by GDPR self-deletion and admin deletion. Does NOT + touch any browser session — each caller handles its own.""" + email = user.email.lower() + user_id = user.id + tok = user.token + google_token = (decrypt(tok.refresh_token_enc) or tok.access_token) if tok else None + # Raw delete so Postgres applies ON DELETE CASCADE / SET NULL on every dependent table. + db.execute(delete(User).where(User.id == user_id)) + db.execute(delete(Invite).where(Invite.email == email)) + db.commit() + if google_token: + background.add_task(revoke_google_token, google_token) + # Confirm the erasure to the (now former) user — GDPR good practice, and covers both the + # self-service and admin deletion paths since both funnel through here. + background.add_task(email_mod.send_account_deleted, email, operator_contact()) + + +def _complete_link( + request: Request, db: Session, link_uid: int, sub: str, userinfo: dict, token: dict +): + """Attach the just-authorized Google identity to the already-signed-in account that started + the link/upgrade. No is_allowed gate — they're already an active user. Refuses to hijack a + Google identity owned by another account, or to silently swap a different linked identity.""" + # Consume the companion marker up front so it never lingers across the early returns below. + explicit = request.session.pop("oauth_link_explicit", False) + # The marker must match the live session user (guards a stale/forged marker). + if link_uid != request.session.get("user_id"): + return RedirectResponse(url="/?link=error") + user = db.get(User, link_uid) + if user is None or user.is_demo: + return RedirectResponse(url="/?link=error") + other = ( + db.query(User).filter(User.google_sub == sub, User.id != user.id).one_or_none() + ) + if other is not None: + return RedirectResponse(url="/?link=conflict") + if user.google_sub is not None and user.google_sub != sub: + return RedirectResponse(url="/?link=mismatch") + user.google_sub = sub + if not user.display_name: + user.display_name = userinfo.get("name") + if not user.avatar_url: + user.avatar_url = userinfo.get("picture") + _store_token(db, user, token) + db.commit() + log.info("Google linked: uid=%s scopes=%s", user.id, token.get("scope")) + # An explicit "Connect Google" lands on Settings with a confirmation; a YouTube upgrade + # (wizard / Settings access rows) returns to the app so the onboarding flow resumes as before. + return RedirectResponse(url="/?link=ok" if explicit else "/") + + @router.post("/logout") async def logout(request: Request): """Sign out the active account. If other accounts have authenticated in this browser, @@ -313,8 +450,7 @@ def _establish_session(request: Request, user: User) -> None: def _app_base() -> str: """Public origin of the deployed app (OAUTH_REDIRECT_URL is .../auth/callback).""" - u = settings.oauth_redirect_url - return u.split("/auth/")[0] if "/auth/" in u else u.rstrip("/") + return settings.app_base def _hash_token(raw: str) -> str: @@ -381,17 +517,24 @@ def register( existing = db.execute(select(User).where(User.email == email)).scalar_one_or_none() if existing is None: + # Without working SMTP we can't deliver a verification link, so email ownership can't + # gate sign-in. Admin approval stays the real gate (is_active=False); mark the account + # verified so the flow still completes on a no-SMTP self-host. See email.email_enabled(). + email_ok = email_mod.email_enabled() user = User( email=email, password_hash=hash_password(password), is_active=False, - email_verified=False, + email_verified=not email_ok, ) db.add(user) db.flush() upsert_pending_invite(db, email) # admin-approval gate - raw = _issue_token(db, user, "verify", VERIFY_TTL) - background.add_task(email_mod.send_verify_email, email, f"{_app_base()}/auth/verify?token={raw}") + if email_ok: + raw = _issue_token(db, user, "verify", VERIFY_TTL) + background.add_task( + email_mod.send_verify_email, email, f"{_app_base()}/auth/verify?token={raw}" + ) if settings.admin_email_set: background.add_task( email_mod.send_admin_new_request, sorted(settings.admin_email_set), email @@ -413,11 +556,14 @@ def verify_email(token: str, db: Session = Depends(get_db)): @router.post("/password-login") def password_login( - payload: dict, request: Request, db: Session = Depends(get_db) + payload: dict, + request: Request, + background: BackgroundTasks, + db: Session = Depends(get_db), ) -> dict: """Email+password sign-in. Wrong email/password give a single uniform 401 (no enumeration). Once the password is proven correct, the owner gets a specific reason if their account is - still pending — that's not an enumeration leak (they already hold the password).""" + still pending or suspended — that's not an enumeration leak (they already hold the password).""" if not _login_limiter.allow(_client_ip(request)): raise HTTPException(status_code=429, detail="Too many attempts. Try again shortly.") email = (payload.get("email") or "").strip().lower() @@ -425,6 +571,13 @@ def password_login( user = db.execute(select(User).where(User.email == email)).scalar_one_or_none() if user is None or user.is_demo or not verify_password(password, user.password_hash): raise HTTPException(status_code=401, detail="Invalid email or password.") + if user.is_suspended: + _notify_suspended(background, user.email) + op = operator_contact() + detail = "Your account has been suspended." + if op: + detail += f" If you have questions, contact the operator at {op}." + raise HTTPException(status_code=403, detail=detail) if not user.email_verified: raise HTTPException(status_code=403, detail="Please verify your email first (check your inbox).") if not user.is_active: @@ -484,7 +637,8 @@ def current_user(request: Request, db: Session = Depends(get_db)) -> User: if not user_id: raise HTTPException(status_code=401, detail="Not authenticated") user = db.get(User, user_id) - if user is None or not user.is_active: + if user is None or not user.is_active or user.is_suspended: + # Suspended/deactivated mid-session → drop the session so the block takes effect at once. request.session.clear() raise HTTPException(status_code=401, detail="Not authenticated") # Always keep the active account in the switchable list — covers sessions created before @@ -506,6 +660,49 @@ def require_human(user: User = Depends(current_user)) -> User: return user +@router.get("/link") +async def link_google(request: Request, user: User = Depends(current_user)): + """Start linking a Google account to the signed-in (e.g. password) account. Requests only + the identity scopes — YouTube access is granted separately via /auth/upgrade. The callback + sees `oauth_link_uid` and attaches the identity instead of creating a new account.""" + if user.is_demo: + return RedirectResponse(url="/") + request.session["oauth_link_uid"] = user.id + request.session["oauth_link_explicit"] = True + return await oauth.google.authorize_redirect( + request, + settings.oauth_redirect_url, + access_type="offline", + prompt="select_account", + include_granted_scopes="true", + scope=BASE_SCOPES, + ) + + +@router.post("/set-password") +def set_password( + payload: dict, user: User = Depends(current_user), db: Session = Depends(get_db) +) -> dict: + """Set or change the signed-in account's password. Setting a first password (Google-only + account) needs no current password — the session already proves identity. Changing an + existing one requires the current password, so a hijacked session can't silently rotate it.""" + if user.is_demo: + raise HTTPException(status_code=403, detail="Not available in the demo account.") + new_password = payload.get("password") or "" + if len(new_password) < PASSWORD_MIN_LEN: + raise HTTPException( + status_code=400, + detail=f"Password must be at least {PASSWORD_MIN_LEN} characters.", + ) + if user.password_hash: + if not verify_password(payload.get("current_password") or "", user.password_hash): + raise HTTPException(status_code=403, detail="Current password is incorrect.") + user.password_hash = hash_password(new_password) + db.commit() + log.info("Password set/changed: uid=%s", user.id) + return {"ok": True} + + @router.get("/upgrade") async def upgrade( request: Request, access: str = "read", user: User = Depends(current_user) @@ -519,6 +716,9 @@ async def upgrade( # straight home (no YouTube link is ever attached to it) rather than shown a raw 403. if user.is_demo: return RedirectResponse(url="/") + # Attach the grant to THIS account in the callback. Without it a password account (no + # google_sub) would get a brand-new, separate Google user created instead of being linked. + request.session["oauth_link_uid"] = user.id scope = WRITE_SCOPES if access == "write" else READ_SCOPES return await oauth.google.authorize_redirect( request, diff --git a/backend/app/config.py b/backend/app/config.py index da51958..7d454a6 100644 --- a/backend/app/config.py +++ b/backend/app/config.py @@ -119,6 +119,14 @@ class Settings(BaseSettings): def admin_email_set(self) -> set[str]: return {e.strip().lower() for e in self.admin_emails.split(",") if e.strip()} + @property + def app_base(self) -> str: + """Public origin of the deployed app, derived from the OAuth redirect URL + (.../auth/callback). The single source for user-facing links (verification, reset, + approval emails); dev and prod differ, so links must always come from config.""" + u = self.oauth_redirect_url + return u.split("/auth/")[0] if "/auth/" in u else u.rstrip("/") + @property def session_https_only(self) -> bool: """Mark the session cookie Secure when we're served over HTTPS. We treat an diff --git a/backend/app/routes/me.py b/backend/app/routes/me.py index 9631344..6d05883 100644 --- a/backend/app/routes/me.py +++ b/backend/app/routes/me.py @@ -1,8 +1,8 @@ -from fastapi import APIRouter, Depends, HTTPException, Request -from sqlalchemy import delete, func, select +from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException, Request +from sqlalchemy import func, select from sqlalchemy.orm import Session -from app.auth import current_user, has_read_scope, has_write_scope, is_allowed +from app.auth import current_user, has_read_scope, has_write_scope, is_allowed, purge_user from app.db import get_db from app.models import Invite, User @@ -78,6 +78,8 @@ def get_me( "avatar_url": user.avatar_url, "role": user.role, "is_demo": user.is_demo, + "has_google": user.google_sub is not None, + "has_password": user.password_hash is not None, "can_read": has_read_scope(user), "can_write": has_write_scope(user), "pending_invites": pending_invites, @@ -88,6 +90,7 @@ def get_me( @router.delete("/account") def delete_my_account( request: Request, + background: BackgroundTasks, user: User = Depends(current_user), db: Session = Depends(get_db), ) -> dict: @@ -105,13 +108,10 @@ def delete_my_account( status_code=400, detail="You're the only admin — promote another admin before deleting your account.", ) - email = user.email.lower() user_id = user.id - # Raw delete so Postgres applies the ON DELETE CASCADE / SET NULL on every dependent table. - db.execute(delete(User).where(User.id == user_id)) - # Erase the access-request/whitelist row for this email too (full erasure; they'd re-request). - db.execute(delete(Invite).where(Invite.email == email)) - db.commit() + # Full erasure (cascades) + access-request cleanup + Google-grant revocation; shared with the + # admin delete path. Capture the id first — `user` is detached once purge_user deletes the row. + purge_user(db, user, background) # Drop this account from the browser session; switch to another signed-in account if any. remaining = [a for a in (request.session.get("account_ids") or []) if a != user_id] if remaining: diff --git a/frontend/src/components/SettingsPanel.tsx b/frontend/src/components/SettingsPanel.tsx index 954f675..465e988 100644 --- a/frontend/src/components/SettingsPanel.tsx +++ b/frontend/src/components/SettingsPanel.tsx @@ -1,5 +1,6 @@ import { useState } from "react"; import { useTranslation } from "react-i18next"; +import { useQueryClient } from "@tanstack/react-query"; import { Bell, Check, Monitor, RotateCcw, Save, Trash2, User } from "lucide-react"; import { SCHEMES, type Scheme, type ThemePrefs } from "../lib/theme"; import { api, type Me } from "../lib/api"; @@ -353,6 +354,125 @@ function AccessRow({ ); } +// Sign-in methods: link a Google account to a password account (or vice-versa set a password), +// so either method can reach the same account. Google connect is a full-page OAuth round-trip +// (auth.py attaches the identity to the current session via /auth/link); the password form posts +// directly with inline errors. Demo accounts never see this (handled by the caller). +function SignInMethods({ me }: { me: Me }) { + const { t } = useTranslation(); + const qc = useQueryClient(); + const [open, setOpen] = useState(false); + const [current, setCurrent] = useState(""); + const [next, setNext] = useState(""); + const [err, setErr] = useState(null); + const [busy, setBusy] = useState(false); + + const submit = async (e: React.FormEvent) => { + e.preventDefault(); + setErr(null); + setBusy(true); + try { + await api.setPassword(next, me.has_password ? current : undefined); + setOpen(false); + setCurrent(""); + setNext(""); + // Refresh `me` so has_password flips and the section switches to "Change password". + await qc.invalidateQueries({ queryKey: ["me"] }); + notify({ level: "success", message: t("settings.account.password.saved", { email: me.email }) }); + } catch (e: any) { + setErr(e?.detail ?? t("settings.account.password.failed")); + } finally { + setBusy(false); + } + }; + + const inputCls = + "w-full bg-card border border-border rounded-xl px-3 py-2 text-sm outline-none focus:border-accent"; + + return ( +
+
+
+
{t("settings.account.googleLink.title")}
+

+ {me.has_google + ? t("settings.account.googleLink.connectedHint") + : t("settings.account.googleLink.connectHint")} +

+
+ {me.has_google ? ( + + {t("settings.account.googleLink.connected")} + + ) : ( + + )} +
+ +
+
+
+
{t("settings.account.password.title")}
+

+ {me.has_password + ? t("settings.account.password.setHint") + : t("settings.account.password.unsetHint")} +

+
+ +
+ {open && ( +
+ {me.has_password && ( + setCurrent(e.target.value)} + placeholder={t("settings.account.password.current")} + autoComplete="current-password" + className={inputCls} + /> + )} + setNext(e.target.value)} + placeholder={t("settings.account.password.new")} + autoComplete="new-password" + className={inputCls} + /> + {err &&

{err}

} + +
+ )} +
+
+ ); +} + function Account({ me, onOpenWizard }: { me: Me; onOpenWizard: () => void }) { const { t } = useTranslation(); const confirm = useConfirm(); @@ -366,7 +486,8 @@ function Account({ me, onOpenWizard }: { me: Me; onOpenWizard: () => void }) { if (!ok) return; try { await api.deleteAccount(); - window.location.reload(); // session cleared server-side → lands on the welcome page + // Session cleared server-side → /api/me 401s → Welcome. The flag shows the confirmation banner. + window.location.href = "/?deleted=1"; } catch { /* the global error dialog surfaces the reason (e.g. last admin) */ } @@ -388,6 +509,8 @@ function Account({ me, onOpenWizard }: { me: Me; onOpenWizard: () => void }) { + {!me.is_demo && } + {me.is_demo ? (

diff --git a/frontend/src/i18n/locales/de/settings.json b/frontend/src/i18n/locales/de/settings.json index 24d1ab0..0f7bced 100644 --- a/frontend/src/i18n/locales/de/settings.json +++ b/frontend/src/i18n/locales/de/settings.json @@ -61,7 +61,32 @@ "deleteTitle": "Konto löschen?", "deleteConfirm": "Dies löscht dein Konto und alle deine Daten (Abos, Tags, angesehen/gespeichert/ausgeblendet, Playlists, Einstellungen) dauerhaft. Es kann nicht rückgängig gemacht werden.", "deleteConfirmButton": "Alles löschen", - "demoNotice": "Dies ist das gemeinsame Demo-Konto. Es hat keine YouTube-Verbindung — du kannst die gesamte gemeinsame Bibliothek durchsuchen, filtern und sortieren, Playlists erstellen und Dinge ausprobieren, aber nichts berührt ein echtes YouTube-Konto." + "demoNotice": "Dies ist das gemeinsame Demo-Konto. Es hat keine YouTube-Verbindung — du kannst die gesamte gemeinsame Bibliothek durchsuchen, filtern und sortieren, Playlists erstellen und Dinge ausprobieren, aber nichts berührt ein echtes YouTube-Konto.", + "signInMethods": "Anmeldemethoden", + "googleLink": { + "title": "Google-Konto", + "connected": "Verbunden", + "connectedHint": "Dein Google-Konto ist verknüpft. Du kannst dich mit Google anmelden und unten den YouTube-Zugriff erteilen.", + "connectHint": "Verknüpfe ein Google-Konto, um dich mit Google anzumelden und den YouTube-Zugriff für deinen Feed zu aktivieren.", + "connect": "Google verknüpfen", + "linked": "Google-Konto verknüpft.", + "conflict": "Dieses Google-Konto ist bereits mit einem anderen Siftlode-Konto verknüpft.", + "mismatch": "Das ist ein anderes Google-Konto als das bereits hier verknüpfte. Melde dich mit dem verknüpften an.", + "error": "Das Google-Konto konnte nicht verknüpft werden. Bitte versuche es erneut." + }, + "password": { + "title": "Passwort", + "setHint": "Ein Passwort ist gesetzt. Du kannst dich mit E-Mail und Passwort anmelden.", + "unsetHint": "Noch kein Passwort — lege eines fest, um dich mit deiner E-Mail anzumelden (zusätzlich zu oder anstelle von Google).", + "set": "Passwort festlegen", + "change": "Passwort ändern", + "current": "Aktuelles Passwort", + "new": "Neues Passwort (min. 10 Zeichen)", + "save": "Passwort speichern", + "saving": "Speichern…", + "saved": "Passwort für {{email}} aktualisiert.", + "failed": "Das Passwort konnte nicht aktualisiert werden." + } }, "demo": { "title": "Demo-Zugang", @@ -87,7 +112,7 @@ "addPlaceholder": "E-Mail direkt hinzufügen…", "add": "Hinzufügen", "decided": "{{count}} entschieden", - "approved": "Genehmigt — sie können sich jetzt anmelden", + "approved": "{{email}} genehmigt — sie können sich jetzt anmelden", "approveFailed": "Genehmigung fehlgeschlagen", "denyFailed": "Ablehnung fehlgeschlagen", "addedToWhitelist": "Zur Whitelist hinzugefügt", diff --git a/frontend/src/i18n/locales/en/settings.json b/frontend/src/i18n/locales/en/settings.json index e679450..91c992b 100644 --- a/frontend/src/i18n/locales/en/settings.json +++ b/frontend/src/i18n/locales/en/settings.json @@ -61,7 +61,32 @@ "deleteTitle": "Delete your account?", "deleteConfirm": "This permanently erases your account and all your data (subscriptions, tags, watch/saved/hidden state, playlists, settings). It can't be undone.", "deleteConfirmButton": "Delete everything", - "demoNotice": "This is the shared demo account. It has no YouTube connection — you can browse the whole shared library, filter and sort it, build playlists and try things out, but nothing touches a real YouTube account." + "demoNotice": "This is the shared demo account. It has no YouTube connection — you can browse the whole shared library, filter and sort it, build playlists and try things out, but nothing touches a real YouTube account.", + "signInMethods": "Sign-in methods", + "googleLink": { + "title": "Google account", + "connected": "Connected", + "connectedHint": "Your Google account is linked. You can sign in with Google and grant YouTube access below.", + "connectHint": "Link a Google account to sign in with Google and to enable YouTube access for your feed.", + "connect": "Connect Google", + "linked": "Google account linked.", + "conflict": "That Google account is already linked to a different Siftlode account.", + "mismatch": "That's a different Google account than the one already linked here. Sign in with the linked one.", + "error": "Couldn't link the Google account. Please try again." + }, + "password": { + "title": "Password", + "setHint": "A password is set. You can sign in with your email and password.", + "unsetHint": "No password yet — set one to sign in with your email instead of (or as well as) Google.", + "set": "Set password", + "change": "Change password", + "current": "Current password", + "new": "New password (min. 10 characters)", + "save": "Save password", + "saving": "Saving…", + "saved": "Password updated for {{email}}.", + "failed": "Couldn't update the password." + } }, "demo": { "title": "Demo access", @@ -87,7 +112,7 @@ "addPlaceholder": "Add an email directly…", "add": "Add", "decided": "{{count}} decided", - "approved": "Approved — they can sign in now", + "approved": "Approved {{email}} — they can sign in now", "approveFailed": "Approve failed", "denyFailed": "Deny failed", "addedToWhitelist": "Added to the whitelist", diff --git a/frontend/src/i18n/locales/hu/settings.json b/frontend/src/i18n/locales/hu/settings.json index 5e682ae..77c5119 100644 --- a/frontend/src/i18n/locales/hu/settings.json +++ b/frontend/src/i18n/locales/hu/settings.json @@ -61,7 +61,32 @@ "deleteTitle": "Törlöd a fiókodat?", "deleteConfirm": "Ez véglegesen törli a fiókodat és minden adatodat (feliratkozások, címkék, megnézett/mentett/elrejtett állapot, lejátszási listák, beállítások). Nem vonható vissza.", "deleteConfirmButton": "Minden törlése", - "demoNotice": "Ez a közös demo fiók. Nincs YouTube-kapcsolata — böngészheted a teljes közös könyvtárat, szűrheted és rendezheted, listákat építhetsz és kipróbálhatsz dolgokat, de semmi nem nyúl valódi YouTube-fiókhoz." + "demoNotice": "Ez a közös demo fiók. Nincs YouTube-kapcsolata — böngészheted a teljes közös könyvtárat, szűrheted és rendezheted, listákat építhetsz és kipróbálhatsz dolgokat, de semmi nem nyúl valódi YouTube-fiókhoz.", + "signInMethods": "Bejelentkezési módok", + "googleLink": { + "title": "Google-fiók", + "connected": "Csatlakoztatva", + "connectedHint": "A Google-fiókod össze van kapcsolva. Bejelentkezhetsz Google-lel, és alább engedélyezheted a YouTube-hozzáférést.", + "connectHint": "Kapcsolj össze egy Google-fiókot, hogy Google-lel jelentkezhess be, és engedélyezhesd a YouTube-hozzáférést a feededhez.", + "connect": "Google összekapcsolása", + "linked": "Google-fiók összekapcsolva.", + "conflict": "Ez a Google-fiók már egy másik Siftlode-fiókhoz van kapcsolva.", + "mismatch": "Ez nem az a Google-fiók, amely ide már össze van kapcsolva. Az összekapcsolttal jelentkezz be.", + "error": "Nem sikerült összekapcsolni a Google-fiókot. Próbáld újra." + }, + "password": { + "title": "Jelszó", + "setHint": "Van beállított jelszó. Bejelentkezhetsz e-mail-címmel és jelszóval.", + "unsetHint": "Még nincs jelszó — állíts be egyet, hogy e-mail-címmel is bejelentkezhess (a Google mellett vagy helyett).", + "set": "Jelszó beállítása", + "change": "Jelszó módosítása", + "current": "Jelenlegi jelszó", + "new": "Új jelszó (min. 10 karakter)", + "save": "Jelszó mentése", + "saving": "Mentés…", + "saved": "Jelszó frissítve ehhez: {{email}}.", + "failed": "Nem sikerült frissíteni a jelszót." + } }, "demo": { "title": "Demo hozzáférés", @@ -87,7 +112,7 @@ "addPlaceholder": "E-mail közvetlen hozzáadása…", "add": "Hozzáadás", "decided": "{{count}} eldöntve", - "approved": "Jóváhagyva — most már be tud jelentkezni", + "approved": "Jóváhagyva: {{email}} — most már be tud jelentkezni", "approveFailed": "A jóváhagyás sikertelen", "denyFailed": "Az elutasítás sikertelen", "addedToWhitelist": "Hozzáadva a fehérlistához", diff --git a/frontend/src/lib/api.ts b/frontend/src/lib/api.ts index 313c4ea..1220e1c 100644 --- a/frontend/src/lib/api.ts +++ b/frontend/src/lib/api.ts @@ -9,6 +9,8 @@ export interface Me { avatar_url: string | null; role: string; is_demo: boolean; + has_google: boolean; + has_password: boolean; can_read: boolean; can_write: boolean; pending_invites: number; @@ -199,6 +201,15 @@ interface ReqConfig { quiet?: boolean; } +// Set by the app shell. Invoked whenever any request returns 401 so a session that ended +// server-side (account suspended/deleted while the tab was open) can drop the user to the login +// page. The handler itself guards against firing when we were never signed in (public pages +// legitimately 401 on /api/me), so it's safe to call for every 401. +let onUnauthorized: (() => void) | null = null; +export function setUnauthorizedHandler(fn: (() => void) | null): void { + onUnauthorized = fn; +} + async function req(url: string, opts: RequestInit = {}, cfg: ReqConfig = {}): Promise { const method = opts.method ?? "GET"; const canRetry = cfg.idempotent ?? method === "GET"; @@ -251,6 +262,10 @@ async function req(url: string, opts: RequestInit = {}, cfg: ReqConfig = {}): Pr // 400/409/422 (validation/conflict). 401/403/404 are caller-handled control flow. if (RETRIABLE_GATEWAY.has(r.status)) { markConnectivityLost(); + } else if (r.status === 401) { + // Session ended server-side (e.g. the account was suspended or deleted mid-visit). Let the + // app shell decide what to do (drop to the login page if we were signed in). Not a modal. + onUnauthorized?.(); } else if (cfg.quiet) { /* caller handles the error inline — no global modal */ } else if (r.status >= 500) { @@ -470,6 +485,7 @@ export interface AdminUserRow { display_name: string | null; role: string; // "user" | "admin" is_active: boolean; + is_suspended: boolean; email_verified: boolean; is_demo: boolean; has_password: boolean; @@ -599,6 +615,10 @@ export const api = { adminUsers: (): Promise => req("/api/admin/users"), setUserRole: (id: number, role: "user" | "admin"): Promise => req(`/api/admin/users/${id}/role`, { method: "PATCH", body: JSON.stringify({ role }) }), + setUserSuspended: (id: number, suspended: boolean): Promise => + req(`/api/admin/users/${id}/suspend`, { method: "PATCH", body: JSON.stringify({ suspended }) }), + adminDeleteUser: (id: number): Promise<{ deleted: number }> => + req(`/api/admin/users/${id}`, { method: "DELETE" }), schedulerStatus: (): Promise => req("/api/admin/scheduler"), updateSchedulerJob: (jobId: string, intervalMinutes: number): Promise<{ id: string; interval_minutes: number }> => req(`/api/admin/scheduler/jobs/${jobId}`, { @@ -624,6 +644,13 @@ export const api = { req("/auth/password-reset/request", { method: "POST", body: JSON.stringify({ email }) }, { quiet: true }), confirmPasswordReset: (token: string, password: string): Promise<{ ok: boolean }> => req("/auth/password-reset/confirm", { method: "POST", body: JSON.stringify({ token, password }) }, { quiet: true }), + // Set or change the signed-in account's password (errors shown inline via quiet). + setPassword: (password: string, currentPassword?: string): Promise<{ ok: boolean }> => + req( + "/auth/set-password", + { method: "POST", body: JSON.stringify({ password, current_password: currentPassword }) }, + { quiet: true } + ), // --- onboarding / admin --- requestAccess: (email: string): Promise<{ status: string }> => req("/auth/request-access", { method: "POST", body: JSON.stringify({ email }) }), From 3f9c395b17e9d948cf26839b3669a83f18f17941 Mon Sep 17 00:00:00 2001 From: npeter83 Date: Fri, 19 Jun 2026 19:52:12 +0200 Subject: [PATCH 2/3] =?UTF-8?q?feat(admin):=20user=20management=20?= =?UTF-8?q?=E2=80=94=20roles,=20suspend,=20delete=20+=20lifecycle=20emails?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - New Users page tabs (Users & roles / Access requests / Demo) and a tab-ified Configuration page, both via a reusable Tabs component (persisted active tab). - Admin can suspend/unsuspend (migration 0023 adds users.is_suspended) and delete accounts from the Users & roles tab, with guards (demo / self / last admin). - Email notifications to the affected user: suspended (reactive, on a blocked sign-in), reinstated, role changed, and account deleted; the approval email now carries a clickable app link. The scheduled/manual demo reset also seeds sample channel subscriptions. - Hide the 'unverified email' chip for Google accounts (Google attests the email). --- .../alembic/versions/0023_user_suspension.py | 30 +++++ backend/app/email.py | 62 ++++++++- backend/app/models.py | 6 + backend/app/routes/admin.py | 101 +++++++++++++- frontend/src/components/AdminUsers.tsx | 123 +++++++++++++++--- frontend/src/components/ConfigPanel.tsx | 28 ++-- frontend/src/components/Tabs.tsx | 62 +++++++++ frontend/src/i18n/locales/de/users.json | 27 +++- frontend/src/i18n/locales/en/users.json | 27 +++- frontend/src/i18n/locales/hu/users.json | 27 +++- 10 files changed, 461 insertions(+), 32 deletions(-) create mode 100644 backend/alembic/versions/0023_user_suspension.py create mode 100644 frontend/src/components/Tabs.tsx diff --git a/backend/alembic/versions/0023_user_suspension.py b/backend/alembic/versions/0023_user_suspension.py new file mode 100644 index 0000000..51f20fa --- /dev/null +++ b/backend/alembic/versions/0023_user_suspension.py @@ -0,0 +1,30 @@ +"""admin account suspension + +Revision ID: 0023_user_suspension +Revises: 0022_password_auth +Create Date: 2026-06-19 + +Adds users.is_suspended — an admin-controlled access block, distinct from is_active (the +approval lifecycle). A suspended account can't sign in (password or Google) and any live +session is rejected; the user is told why and given the operator's contact. +""" +from typing import Sequence, Union + +import sqlalchemy as sa +from alembic import op + +revision: str = "0023_user_suspension" +down_revision: Union[str, None] = "0022_password_auth" +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + op.add_column( + "users", + sa.Column("is_suspended", sa.Boolean(), nullable=False, server_default="false"), + ) + + +def downgrade() -> None: + op.drop_column("users", "is_suspended") diff --git a/backend/app/email.py b/backend/app/email.py index d1af768..8e1e653 100644 --- a/backend/app/email.py +++ b/backend/app/email.py @@ -74,8 +74,8 @@ def send_access_approved(email: str) -> bool: body = ( "Hi,\n\n" "Your request to use Siftlode has been approved — welcome aboard.\n\n" - "Just open Siftlode and sign in with this Google account, and your YouTube\n" - "subscriptions feed will be ready.\n\n" + "Open Siftlode and sign in, and your YouTube subscriptions feed will be ready:\n\n" + f"{settings.app_base}\n\n" "If you weren't expecting this, you can ignore the message.\n\n" "— Siftlode" + (f"\n\nQuestions? Just reply to this email ({admin})." if admin else "") @@ -83,6 +83,64 @@ def send_access_approved(email: str) -> bool: return _send([email], "You're in — your Siftlode access is approved", body, reply_to=admin) +def send_role_changed(to: str, role: str, operator: str | None) -> bool: + line = ( + "You've been granted admin access on Siftlode — you can now manage settings, the " + "scheduler and users." + if role == "admin" + else "Your admin access on Siftlode has been removed — you're now a regular user." + ) + contact = f"\n\nQuestions? Contact the operator at {operator}." if operator else "" + body = "Hi,\n\n" + line + contact + "\n\n— Siftlode" + return _send([to], "Your Siftlode role has changed", body, reply_to=operator) + + +def send_account_unsuspended(to: str, operator: str | None) -> bool: + contact = f"\n\nQuestions? Contact the operator at {operator}." if operator else "" + body = ( + "Hi,\n\n" + "Your Siftlode account has been reinstated — the suspension was lifted and you can sign " + "in again." + + contact + + "\n\n— Siftlode" + ) + return _send([to], "Your Siftlode account has been reinstated", body, reply_to=operator) + + +def send_account_deleted(to: str, operator: str | None) -> bool: + contact = ( + f"\n\nIf you didn't request this, contact the Siftlode operator at {operator}." + if operator + else "" + ) + body = ( + "Hi,\n\n" + "Your Siftlode account and all associated data — subscriptions, tags, watch history, " + "playlists and settings — have been permanently deleted. Nothing is retained.\n\n" + "Thanks for having used Siftlode." + + contact + + "\n\n— Siftlode" + ) + return _send([to], "Your Siftlode account has been deleted", body, reply_to=operator) + + +def send_account_suspended(to: str, operator: str | None) -> bool: + contact = ( + f"If you think this is a mistake or have questions, contact the Siftlode operator " + f"at {operator}.\n\n" + if operator + else "If you think this is a mistake, please contact the Siftlode operator.\n\n" + ) + body = ( + "Hi,\n\n" + "A sign-in to your Siftlode account was just attempted, but the account is currently " + "suspended, so access was denied.\n\n" + + contact + + "— Siftlode" + ) + return _send([to], "Your Siftlode account is suspended", body, reply_to=operator) + + def send_admin_new_request(admins: list[str], requester: str) -> bool: body = ( f"{requester} just requested access to Siftlode.\n\n" diff --git a/backend/app/models.py b/backend/app/models.py index 4f12e9f..388ba36 100644 --- a/backend/app/models.py +++ b/backend/app/models.py @@ -37,6 +37,12 @@ class User(Base): # Admin-approved & enabled. A pending password registration starts inactive; admin # approval activates it. A deactivated account can't log in. is_active: Mapped[bool] = mapped_column(Boolean, default=True, server_default="true") + # Admin-imposed access block, distinct from is_active (approval lifecycle). A suspended + # account can't sign in by any method and its live sessions are rejected; the user is told + # why and pointed at the operator's contact. The demo account is never suspendable. + is_suspended: Mapped[bool] = mapped_column( + Boolean, default=False, server_default="false" + ) display_name: Mapped[str | None] = mapped_column(String(255)) avatar_url: Mapped[str | None] = mapped_column(String(1024)) role: Mapped[str] = mapped_column(String(16), default="user", server_default="user") diff --git a/backend/app/routes/admin.py b/backend/app/routes/admin.py index 176c1b9..1f7d3d8 100644 --- a/backend/app/routes/admin.py +++ b/backend/app/routes/admin.py @@ -8,13 +8,14 @@ from sqlalchemy import delete, func, select from sqlalchemy.orm import Session from app import email as email_mod -from app.auth import current_user, get_or_create_demo_user +from app.auth import current_user, get_or_create_demo_user, operator_contact, purge_user from app.db import get_db from app.models import ( DemoWhitelist, Invite, Playlist, PlaylistItem, + Subscription, User, Video, VideoState, @@ -132,6 +133,7 @@ def _serialize_user(u: User) -> dict: "display_name": u.display_name, "role": u.role, "is_active": u.is_active, + "is_suspended": u.is_suspended, "email_verified": u.email_verified, "is_demo": u.is_demo, "has_password": u.password_hash is not None, @@ -150,11 +152,12 @@ def list_users(_: User = Depends(admin_user), db: Session = Depends(get_db)) -> def set_user_role( user_id: int, payload: dict, + background: BackgroundTasks, admin: User = Depends(admin_user), db: Session = Depends(get_db), ) -> dict: """Promote/demote a user. Guards: can't change your own role, can't touch the demo - account, and can't remove the last remaining admin.""" + account, and can't remove the last remaining admin. Emails the user when it actually changes.""" role = payload.get("role") if role not in ("user", "admin"): raise HTTPException(status_code=400, detail="role must be 'user' or 'admin'") @@ -169,11 +172,82 @@ def set_user_role( admin_count = db.scalar(select(func.count()).select_from(User).where(User.role == "admin")) if (admin_count or 0) <= 1: raise HTTPException(status_code=400, detail="Can't remove the last admin.") + changed = target.role != role target.role = role db.commit() + if changed: + background.add_task(email_mod.send_role_changed, target.email, role, operator_contact()) return _serialize_user(target) +@router.patch("/users/{user_id}/suspend") +def set_user_suspended( + user_id: int, + payload: dict, + background: BackgroundTasks, + admin: User = Depends(admin_user), + db: Session = Depends(get_db), +) -> dict: + """Suspend or un-suspend an account. A suspended user can't sign in by any method and any + live session is dropped on its next request. Guards: can't suspend the demo account, can't + suspend yourself, and can't suspend the last active admin (that would lock admin out). On + un-suspend the user is emailed they can return (suspend is announced reactively, on a blocked + sign-in).""" + suspended = bool(payload.get("suspended")) + target = db.get(User, user_id) + if target is None: + raise HTTPException(status_code=404, detail="No such user") + if target.is_demo: + raise HTTPException(status_code=400, detail="The demo account can't be suspended.") + if target.id == admin.id: + raise HTTPException(status_code=400, detail="You can't suspend your own account.") + if suspended and target.role == "admin" and not target.is_suspended: + active_admins = db.scalar( + select(func.count()) + .select_from(User) + .where(User.role == "admin", User.is_suspended.is_(False)) + ) + if (active_admins or 0) <= 1: + raise HTTPException(status_code=400, detail="Can't suspend the last active admin.") + was_suspended = target.is_suspended + target.is_suspended = suspended + db.commit() + if was_suspended and not suspended: + background.add_task( + email_mod.send_account_unsuspended, target.email, operator_contact() + ) + return _serialize_user(target) + + +@router.delete("/users/{user_id}") +def admin_delete_user( + user_id: int, + background: BackgroundTasks, + admin: User = Depends(admin_user), + db: Session = Depends(get_db), +) -> dict: + """Admin-triggered account deletion — the same full erasure a user can perform on themselves + (cascade delete of all personal data + access-request cleanup + Google-grant revoke). Guards: + not the demo account, not yourself (use Settings → Account), and not the last admin.""" + target = db.get(User, user_id) + if target is None: + raise HTTPException(status_code=404, detail="No such user") + if target.is_demo: + raise HTTPException(status_code=400, detail="The demo account can't be deleted.") + if target.id == admin.id: + raise HTTPException( + status_code=400, detail="Delete your own account from Settings → Account." + ) + if target.role == "admin": + admin_count = db.scalar( + select(func.count()).select_from(User).where(User.role == "admin") + ) + if (admin_count or 0) <= 1: + raise HTTPException(status_code=400, detail="Can't delete the last admin.") + purge_user(db, target, background) + return {"deleted": user_id} + + # --- Demo account: email whitelist + state reset ------------------------------------- def _serialize_demo(row: DemoWhitelist) -> dict: @@ -270,16 +344,35 @@ def _seed_demo_playlists(db: Session, demo: User) -> int: return created +def _seed_demo_subscriptions(db: Session, demo: User, n: int = 14) -> int: + """Seed the demo with a handful of catalog channels (the ones with the most videos) so its + Channel manager isn't empty — gives visitors something to explore and matches the landing-page + screenshot. Idempotent: clears the demo's subscriptions first, then re-adds the top N.""" + db.execute(delete(Subscription).where(Subscription.user_id == demo.id)) + top = db.execute( + select(Video.channel_id) + .where(Video.channel_id.is_not(None)) + .group_by(Video.channel_id) + .order_by(func.count().desc()) + .limit(n) + ).scalars().all() + for channel_id in top: + db.add(Subscription(user_id=demo.id, channel_id=channel_id)) + return len(top) + + def reset_demo_state(db: Session, demo: User) -> int: """Wipe the demo account's per-user state (watch/save/hide states, playlists, preferences) - back to a clean baseline and re-seed a few sample playlists. Returns the seeded count. - Shared by the admin's manual reset button and the scheduled demo reset (see scheduler).""" + back to a clean baseline and re-seed a few sample playlists + channel subscriptions. Returns + the seeded playlist count. Shared by the admin's manual reset button and the scheduled demo + reset (see scheduler).""" db.execute(delete(VideoState).where(VideoState.user_id == demo.id)) # Playlist items cascade on playlist delete (ondelete="CASCADE"). db.execute(delete(Playlist).where(Playlist.user_id == demo.id)) demo.preferences = {"language": "en"} db.commit() seeded = _seed_demo_playlists(db, demo) + _seed_demo_subscriptions(db, demo) db.commit() return seeded diff --git a/frontend/src/components/AdminUsers.tsx b/frontend/src/components/AdminUsers.tsx index d3172b1..20165b6 100644 --- a/frontend/src/components/AdminUsers.tsx +++ b/frontend/src/components/AdminUsers.tsx @@ -1,21 +1,31 @@ import { useState } from "react"; import { useTranslation } from "react-i18next"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; -import { Check, RotateCcw, Shield, Trash2, UserPlus, X } from "lucide-react"; +import { Ban, Check, RotateCcw, Shield, Trash2, UserPlus, X } from "lucide-react"; import { api, type AdminUserRow, type Invite, type Me } from "../lib/api"; import { notify } from "../lib/notifications"; import Tooltip from "./Tooltip"; import { useConfirm } from "./ConfirmProvider"; +import Tabs, { usePersistedTab } from "./Tabs"; // Admin-only user & access management: roles, access requests (the Invite whitelist), and the -// demo whitelist + reset. Moved out of Settings → Account into its own admin page; the Invite -// and demo data are unchanged (same tables) — only the UI relocated. +// demo whitelist + reset. Each section is its own tab (persisted across reloads); the Access tab +// carries a badge with the count of pending requests so it's visible without switching to it. export default function AdminUsers({ me }: { me: Me }) { + const { t } = useTranslation(); + const [tab, setTab] = usePersistedTab("siftlode.adminUsersTab", "roles"); + const tabs = [ + { id: "roles", label: t("users.tabs.roles") }, + { id: "access", label: t("users.tabs.access"), badge: me.pending_invites }, + { id: "demo", label: t("users.tabs.demo") }, + ]; + const active = tabs.some((x) => x.id === tab) ? tab : "roles"; return (

- - - + + {active === "roles" && } + {active === "access" && } + {active === "demo" && }
); } @@ -47,14 +57,37 @@ function UsersRoles({ me }: { me: Me }) { const confirm = useConfirm(); const q = useQuery({ queryKey: ["admin-users"], queryFn: api.adminUsers }); const setRole = useMutation({ - mutationFn: ({ id, role }: { id: number; role: "user" | "admin" }) => api.setUserRole(id, role), - onSuccess: () => { + mutationFn: ({ id, role }: { id: number; role: "user" | "admin"; email: string }) => + api.setUserRole(id, role), + onSuccess: (_d, vars) => { qc.invalidateQueries({ queryKey: ["admin-users"] }); - notify({ level: "success", message: t("users.roles.updated") }); + notify({ level: "success", message: t("users.roles.updated", { email: vars.email }) }); }, // Errors (e.g. last-admin / self) surface via the global error dialog with the server's detail. }); + const suspend = useMutation({ + mutationFn: ({ id, suspended }: { id: number; suspended: boolean; email: string }) => + api.setUserSuspended(id, suspended), + onSuccess: (_d, vars) => { + qc.invalidateQueries({ queryKey: ["admin-users"] }); + notify({ + level: "success", + message: t(vars.suspended ? "users.suspend.done" : "users.suspend.undone", { + email: vars.email, + }), + }); + }, + // Guards (demo / self / last admin) surface via the global error dialog. + }); + const del = useMutation({ + mutationFn: ({ id }: { id: number; email: string }) => api.adminDeleteUser(id), + onSuccess: (_d, vars) => { + qc.invalidateQueries({ queryKey: ["admin-users"] }); + notify({ level: "success", message: t("users.delete.done", { email: vars.email }) }); + }, + }); + const onToggle = async (u: AdminUserRow) => { const makeAdmin = u.role !== "admin"; const ok = await confirm({ @@ -65,7 +98,30 @@ function UsersRoles({ me }: { me: Me }) { confirmLabel: makeAdmin ? t("users.roles.makeAdmin") : t("users.roles.makeUser"), danger: !makeAdmin, }); - if (ok) setRole.mutate({ id: u.id, role: makeAdmin ? "admin" : "user" }); + if (ok) setRole.mutate({ id: u.id, role: makeAdmin ? "admin" : "user", email: u.email }); + }; + + const onSuspend = async (u: AdminUserRow) => { + const willSuspend = !u.is_suspended; + const ok = await confirm({ + title: t(willSuspend ? "users.suspend.title" : "users.suspend.undoTitle"), + message: t(willSuspend ? "users.suspend.confirm" : "users.suspend.undoConfirm", { + email: u.email, + }), + confirmLabel: t(willSuspend ? "users.suspend.action" : "users.suspend.undoAction"), + danger: willSuspend, + }); + if (ok) suspend.mutate({ id: u.id, suspended: willSuspend, email: u.email }); + }; + + const onDelete = async (u: AdminUserRow) => { + const ok = await confirm({ + title: t("users.delete.title"), + message: t("users.delete.confirm", { email: u.email }), + confirmLabel: t("users.delete.action"), + danger: true, + }); + if (ok) del.mutate({ id: u.id, email: u.email }); }; const rows = q.data ?? []; @@ -90,8 +146,11 @@ function UsersRoles({ me }: { me: Me }) { {u.role === "admin" && {t("users.roles.admin")}} {u.is_demo && {t("users.roles.demo")}} + {u.is_suspended && {t("users.roles.suspended")}} {!u.is_active && {t("users.roles.pending")}} - {u.is_active && !u.email_verified && ( + {/* A Google sign-in proves the email, so "unverified" only applies to a + password-only account that hasn't clicked its verification link. */} + {u.is_active && !u.email_verified && !u.has_google && ( {t("users.roles.unverified")} )} + + + + + + ); })} @@ -135,10 +228,10 @@ function AdminInvites() { qc.invalidateQueries({ queryKey: ["me"] }); // updates the pending badge }; const approve = useMutation({ - mutationFn: (id: number) => api.approveInvite(id), - onSuccess: () => { + mutationFn: ({ id }: { id: number; email: string }) => api.approveInvite(id), + onSuccess: (_d, vars) => { refresh(); - notify({ level: "success", message: t("settings.invites.approved") }); + notify({ level: "success", message: t("settings.invites.approved", { email: vars.email }) }); }, onError: () => notify({ level: "error", message: t("settings.invites.approveFailed") }), }); @@ -171,7 +264,7 @@ function AdminInvites() { approve.mutate(i.id)} + onApprove={() => approve.mutate({ id: i.id, email: i.email })} onDeny={() => deny.mutate(i.id)} busy={approve.isPending || deny.isPending} /> diff --git a/frontend/src/components/ConfigPanel.tsx b/frontend/src/components/ConfigPanel.tsx index 9141265..b614eec 100644 --- a/frontend/src/components/ConfigPanel.tsx +++ b/frontend/src/components/ConfigPanel.tsx @@ -5,6 +5,7 @@ import { Check, RotateCcw, Save, Send } from "lucide-react"; import { api, type ConfigItem } from "../lib/api"; import { notify } from "../lib/notifications"; import Tooltip from "./Tooltip"; +import Tabs, { usePersistedTab } from "./Tabs"; // Admin Configuration page: edit DB-overridable operational settings (registry-driven from the // backend — adding a key there makes it appear here automatically). Edits are drafted and @@ -35,6 +36,9 @@ export default function ConfigPanel() { // clearing the field, since an empty secret field means "leave unchanged"). const [secretReset, setSecretReset] = useState>({}); const [saveState, setSaveState] = useState("idle"); + // One tab per config group (persisted). Called before the loading guard so hook order is + // stable; the active id is clamped to a real group at render time once data has loaded. + const [tab, setTab] = usePersistedTab("siftlode.configTab"); // Re-seed the draft whenever the server data changes (initial load + after a save/reset). useEffect(() => { @@ -94,18 +98,26 @@ export default function ConfigPanel() { const groupKeys = Object.keys(data.groups).sort( (a, b) => (GROUP_ORDER.indexOf(a) + 1 || 99) - (GROUP_ORDER.indexOf(b) + 1 || 99) ); + // Clamp the persisted tab to a real group (the registry can change between sessions). The + // tab pill carries a dot when that group has unsaved edits, so a draft in a hidden tab is + // never silently lost behind the global Save bar. + const activeGroup = groupKeys.includes(tab) ? tab : groupKeys[0]; + const dirtyByGroup = new Set(dirtyKeys.map((k) => byKey[k]?.group).filter(Boolean)); + const groupTabs = groupKeys.map((g) => ({ + id: g, + label: `${t(`config.groups.${g}`, g)}${dirtyByGroup.has(g) ? " •" : ""}`, + })); return (

{t("config.intro")}

- {groupKeys.map((g) => ( -
-
- {t(`config.groups.${g}`, g)} -
+ + + {activeGroup && ( +
- {data.groups[g].map((item) => ( + {data.groups[activeGroup].map((item) => ( - {g === "email" && ( + {activeGroup === "email" && (
- ))} + )} {(dirty || saveState !== "idle") && (
diff --git a/frontend/src/components/Tabs.tsx b/frontend/src/components/Tabs.tsx new file mode 100644 index 0000000..7871c3d --- /dev/null +++ b/frontend/src/components/Tabs.tsx @@ -0,0 +1,62 @@ +import { useState } from "react"; + +// Reusable horizontal pill tab-rail for in-page sub-navigation (Configuration, Users & roles…). +// The active tab is persisted to localStorage so a reload (F5) keeps the user where they were, +// per the app's "persist UI state across reload" convention. + +export interface TabDef { + id: string; + label: string; + badge?: number; // optional count pill (e.g. pending requests); hidden when 0/undefined +} + +/** Persisted active-tab state. Validation is deferred to the caller (it clamps to a valid id at + * render) so this can be called before an async-loaded tab list is known, keeping hook order stable. */ +export function usePersistedTab(storageKey: string, fallback = ""): [string, (id: string) => void] { + const [tab, setTabState] = useState(() => localStorage.getItem(storageKey) ?? fallback); + const setTab = (id: string) => { + setTabState(id); + localStorage.setItem(storageKey, id); + }; + return [tab, setTab]; +} + +export default function Tabs({ + tabs, + active, + onChange, +}: { + tabs: TabDef[]; + active: string; + onChange: (id: string) => void; +}) { + return ( +
+ {tabs.map((tb) => { + const on = tb.id === active; + return ( + + ); + })} +
+ ); +} diff --git a/frontend/src/i18n/locales/de/users.json b/frontend/src/i18n/locales/de/users.json index e115bb7..e45c288 100644 --- a/frontend/src/i18n/locales/de/users.json +++ b/frontend/src/i18n/locales/de/users.json @@ -1,4 +1,9 @@ { + "tabs": { + "roles": "Benutzer & Rollen", + "access": "Zugriffsanfragen", + "demo": "Demo" + }, "roles": { "title": "Benutzer & Rollen", "intro": "Alle, die sich anmelden können. Mache einen Benutzer zum Admin oder wieder zum normalen Benutzer.", @@ -6,16 +11,36 @@ "you": "du", "admin": "Admin", "demo": "Demo", + "suspended": "Gesperrt", "pending": "Wartet auf Freigabe", "unverified": "E-Mail nicht bestätigt", "demoLocked": "Die Rolle des Demo-Kontos kann nicht geändert werden.", "selfLocked": "Du kannst deine eigene Rolle nicht ändern.", "makeAdmin": "Zum Admin machen", "makeUser": "Zum Benutzer machen", - "updated": "Rolle aktualisiert", + "updated": "Rolle aktualisiert für {{email}}", "promoteTitle": "Zum Admin machen?", "demoteTitle": "Admin entfernen?", "promoteConfirm": "{{email}} vollen Admin-Zugriff geben (Einstellungen, Planer, Benutzerverwaltung)?", "demoteConfirm": "{{email}} den Admin-Zugriff entziehen? Wird zum normalen Benutzer." + }, + "suspend": { + "action": "Sperren", + "undoAction": "Entsperren", + "title": "Konto sperren?", + "undoTitle": "Konto entsperren?", + "confirm": "{{email}} sperren? Eine Anmeldung (per Passwort oder Google) ist erst nach dem Entsperren wieder möglich, und jede aktive Sitzung endet.", + "undoConfirm": "{{email}} entsperren? Eine Anmeldung ist dann wieder möglich.", + "done": "{{email}} gesperrt", + "undone": "{{email}} entsperrt", + "demoLocked": "Das Demo-Konto kann nicht gesperrt werden.", + "selfLocked": "Du kannst dein eigenes Konto nicht sperren." + }, + "delete": { + "action": "Löschen", + "locked": "Dieses Konto kann hier nicht gelöscht werden.", + "title": "Konto löschen?", + "confirm": "{{email}} und alle zugehörigen Daten endgültig löschen — Abos, Tags, Wiedergabeverlauf, Playlists und Einstellungen? Das kann nicht rückgängig gemacht werden.", + "done": "{{email}} gelöscht" } } diff --git a/frontend/src/i18n/locales/en/users.json b/frontend/src/i18n/locales/en/users.json index 47535f3..a5f955d 100644 --- a/frontend/src/i18n/locales/en/users.json +++ b/frontend/src/i18n/locales/en/users.json @@ -1,4 +1,9 @@ { + "tabs": { + "roles": "Users & roles", + "access": "Access requests", + "demo": "Demo" + }, "roles": { "title": "Users & roles", "intro": "Everyone who can sign in. Promote a user to admin, or back to a regular user.", @@ -6,16 +11,36 @@ "you": "you", "admin": "Admin", "demo": "Demo", + "suspended": "Suspended", "pending": "Pending approval", "unverified": "Unverified email", "demoLocked": "The demo account's role can't be changed.", "selfLocked": "You can't change your own role.", "makeAdmin": "Make admin", "makeUser": "Make user", - "updated": "Role updated", + "updated": "Role updated for {{email}}", "promoteTitle": "Make admin?", "demoteTitle": "Remove admin?", "promoteConfirm": "Give {{email}} full admin access (settings, scheduler, user management)?", "demoteConfirm": "Remove admin access from {{email}}? They'll become a regular user." + }, + "suspend": { + "action": "Suspend", + "undoAction": "Unsuspend", + "title": "Suspend account?", + "undoTitle": "Unsuspend account?", + "confirm": "Suspend {{email}}? They won't be able to sign in (by password or Google) until you unsuspend them, and any active session ends.", + "undoConfirm": "Unsuspend {{email}}? They'll be able to sign in again.", + "done": "{{email}} suspended", + "undone": "{{email}} unsuspended", + "demoLocked": "The demo account can't be suspended.", + "selfLocked": "You can't suspend your own account." + }, + "delete": { + "action": "Delete", + "locked": "This account can't be deleted here.", + "title": "Delete account?", + "confirm": "Permanently delete {{email}} and all their data — subscriptions, tags, watch history, playlists and settings? This can't be undone.", + "done": "{{email}} deleted" } } diff --git a/frontend/src/i18n/locales/hu/users.json b/frontend/src/i18n/locales/hu/users.json index 2a8713a..d65554d 100644 --- a/frontend/src/i18n/locales/hu/users.json +++ b/frontend/src/i18n/locales/hu/users.json @@ -1,4 +1,9 @@ { + "tabs": { + "roles": "Felhasználók és szerepek", + "access": "Hozzáférési kérések", + "demo": "Demo" + }, "roles": { "title": "Felhasználók és szerepek", "intro": "Mindenki, aki be tud lépni. Léptess egy felhasználót adminná, vagy vissza sima felhasználóvá.", @@ -6,16 +11,36 @@ "you": "te", "admin": "Admin", "demo": "Demo", + "suspended": "Felfüggesztve", "pending": "Jóváhagyásra vár", "unverified": "Nem igazolt e-mail", "demoLocked": "A demo fiók szerepe nem módosítható.", "selfLocked": "A saját szerepedet nem módosíthatod.", "makeAdmin": "Adminná tesz", "makeUser": "Felhasználóvá tesz", - "updated": "Szerep frissítve", + "updated": "Szerep frissítve: {{email}}", "promoteTitle": "Adminná teszed?", "demoteTitle": "Elveszed az admin jogot?", "promoteConfirm": "Teljes admin hozzáférést adsz neki: {{email}} (beállítások, ütemező, felhasználókezelés)?", "demoteConfirm": "Elveszed az admin jogot tőle: {{email}}? Sima felhasználó lesz." + }, + "suspend": { + "action": "Felfüggeszt", + "undoAction": "Feloldás", + "title": "Felfüggeszted a fiókot?", + "undoTitle": "Feloldod a felfüggesztést?", + "confirm": "Felfüggeszted: {{email}}? Nem fog tudni belépni (sem jelszóval, sem Google-lel), amíg fel nem oldod, és az aktív munkamenete megszűnik.", + "undoConfirm": "Feloldod a felfüggesztést: {{email}}? Újra be tud majd lépni.", + "done": "{{email}} felfüggesztve", + "undone": "{{email}} felfüggesztése feloldva", + "demoLocked": "A demo fiók nem függeszthető fel.", + "selfLocked": "A saját fiókodat nem függesztheted fel." + }, + "delete": { + "action": "Törlés", + "locked": "Ez a fiók itt nem törölhető.", + "title": "Törlöd a fiókot?", + "confirm": "Véglegesen törlöd: {{email}} és minden adatát — feliratkozások, címkék, megtekintési előzmény, lejátszási listák és beállítások? Ez nem visszavonható.", + "done": "{{email}} törölve" } } From 6db7014b081de543f7a01f47a8ea4f63384bb9e8 Mon Sep 17 00:00:00 2001 From: npeter83 Date: Fri, 19 Jun 2026 19:52:29 +0200 Subject: [PATCH 3/3] feat(welcome): landing lightbox, prod-served screenshots & session-end UX MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Serve real files at the SPA root (e.g. /welcome/*.png, favicon) from the built app — the landing screenshots were only ever shown by the Vite dev server, never in production. - Add the Channel-manager screenshot; the two secondary previews are smaller thumbnails that open in a custom full-size lightbox (fit-to-viewport, Esc/backdrop/✕ to close). - Drop a suspended/deleted user to the login page on the next 401 (and poll the session only while signed in, so the public login page no longer flickers); 'suspended' and 'account deleted' confirmation banners; strip redirect query params for a clean address bar. --- backend/app/main.py | 7 ++ frontend/public/welcome/channels.png | Bin 0 -> 159539 bytes frontend/src/App.tsx | 46 +++++++- frontend/src/components/Welcome.tsx | 137 +++++++++++++++++++--- frontend/src/i18n/locales/de/welcome.json | 4 +- frontend/src/i18n/locales/en/welcome.json | 4 +- frontend/src/i18n/locales/hu/welcome.json | 4 +- 7 files changed, 180 insertions(+), 22 deletions(-) create mode 100644 frontend/public/welcome/channels.png diff --git a/backend/app/main.py b/backend/app/main.py index 77c2a5e..220b1a5 100644 --- a/backend/app/main.py +++ b/backend/app/main.py @@ -107,4 +107,11 @@ async def spa_fallback(full_path: str) -> FileResponse: # Client-side routes fall back to index.html; real API/asset paths are matched above. if full_path.startswith(("api/", "auth/", "healthz", "assets/")): raise HTTPException(status_code=404) + # Serve real files that live at the SPA root (Vite copies public/ there — e.g. the landing + # screenshots under /welcome/, favicon). /assets is already mounted above; everything else + # that isn't a real file is a client-side route → index.html. Guard against path traversal. + if full_path: + candidate = (STATIC_DIR / full_path).resolve() + if candidate.is_file() and STATIC_DIR.resolve() in candidate.parents: + return FileResponse(candidate) return FileResponse(STATIC_DIR / "index.html") diff --git a/frontend/public/welcome/channels.png b/frontend/public/welcome/channels.png new file mode 100644 index 0000000000000000000000000000000000000000..31cf1e9c218126ddf26fbb07aa320bc9a534186a GIT binary patch literal 159539 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%0AL^i zO*d=-7)>yp-}*c39f6;W2n?;@`AlF4>Gee7tjIH?A$rEJ+#~#v8^qhr{IFSA`)}j`BWw#yWZrV{4b!+abSD&)u&5 z8(Q3*bEa(%M1IPp1>G!nlxYA8M9>{iPX`AFZx9Ew?F%io8S;*fle7W2xTR^K{Cr;f zebYkTj;)^3q_wCAh1PJaAhK_Gbh(HYGr#ETYT}X$iIdX zqI?OpQ)DM_*u>@c8;(YI8BwY;5&0%wYLKa4P+a`Q={tE-PO6}{&9V>0>?}_Li(dcm zAkMxqTSH8Ul*D{wWaI_(zENH7rIIN>O+^x7<}7)bX323NX)^@Iy`&)_XtU_OJQKNc z`I+?hbWc>k$3a`1H!S_QADl%TQ|NWxReCl}6}&2mPkx0vp2^9&daW9;9tF3Q9m6rz zfIUTFNG)O4#C;sQJ(75>31i&ct$87|gS+Rn$|y0VV1ZfEos2|`?JgDN)vxv)Z2^e& z4y0c?J-LYOGoq&MUynU!P_wOXYBWbwnjB2YlFo;b;0u@-U2P1gWoNSlR6}krNRPaZ zRYXONk92itWZo(0>ZYehCD}E!E`2E!LHEA(RKZY7z&iN({N59rENFZ3Y;%6Q40_u& z)>bNaWTPw)6f}+fUO>R;`%>{>D(ZjsHA<4L#1C1M01DZje*jvwdG(ud@QVk;8+|Fp z@v46?NT{>0u!@7^E)t%llCH(EO^?%yEW;^(e@G1mHm}O*>kC@V8C2qZx_di1N*9Vg7Yq|^MMFilYt2$g#?mC+Akx-6Q& zr+Zu)9s}AKM8{}!m@YewwHo#e>onco-fC&8YH7!(q~N;lv}Zj>E7fT+uq!;5*({{> z7=eJHciL;!c_88bw7|eE|CvO^=Ug;s2;ZYV#8&Xqxz*oDy^p58wJ`#baO8r0P;b?> z>z~17fYj4uh6~x@8YGau{7&x=4vMj1g{c}@OQ{&^6nVBC1S?Y4@>uJdAfE}wv zBm3|7uO(TL$h70;@EPK4zR`^`Pv$RX0b$feGIF^+#Y2B1tf66^vh0)j_0e)VdJ}ru zdK^ZId}8Pg64hsh<3Ce9Xjq8(59{GW^Os2-bf=k{pYJ!STwRS$#IRpt(gYok+9QGM zOrqycF(&*$FV#7V$&FkU|FFFP-cZ>7%Vc0;y;A?**^xXKJ&G59t|lynJ|c(wPfHef zQ~uTPISA=7{-+iCQu{r5hsD+MFG+Ct4LEqI{jiA&mU^ClpN(G~i=GeRN+ZaeTkRq@cA>pAAH|`9KZ*QLPFeBx4Lt ze_^q+CtXzjFSo=&{F<<^`YO)+g~@wFuz6>0*NdkZaO#&hc(0^*1+?j=%4~MjH93nd zF6avf)Ca#(OR=lR^6Sg5AN#x{2YUWpwRXgb@Eqg z7s@1&uKPZ!6#c%d{ZBQ|4$R9}|;0IS<-kWT25(MwJ*;wY9p;TNk3=(vBh_TXewmkS=LuDpY z@bF3_vhJV$IJhhtswGTjp4LU0r&@`-Nd!4WoITP@Svvtj7 zq2v4uKF{Kl+O5W8chY!WA;rb~j=T;CLGL(vDWWH!Nb_@F$)F0!j>3sTebxhFf~JPl zNMN3w3ar|RL4!D)LhqkVZuYbHJR^3;zDyKWSOn^-PPO^`bfA0cB1@d??DS%>&Xt?` zi`Ad6YHD>zE9eJN{~9JeLeHPnZTgadlTXx|gV9B*yO9$=1ZZN&$|OlpWUd+SQjYe| z?)K>x)7diEo-Rqm+6k^`gs9B{`iUj}I9wikTt$gnTUkA7Kg=ifN>lJa)QX$8Q8jvH?GG1s432UWT;YlJI{P6;{rs2ppu%Dqn;o1YeI>O3-b7(_zt<+HmG^f9Hoxl>NwCZ-XbFYw_J8({qxy_EsaMq^~CeBy&7X zO$oI!=h63w@mi*SSv~fqRFjW@{0eRY*tSWu zdiA;RFB(IA-hV%XSg3x7s;8zZ6PQ8O9T7~V_UF`kL(smzdf?<_ApSvHSvhy-10@rp zsSNt#ctxC6HXXFqjj&Y1Au^llbqe{)mS@e*7*#RHI^Ec*kFY86uvXUBzYjV72MbWm z+RqZ`vMs5hA(E1M5h|swvXE6d=gsM=Z>IE*5+}cBdp#LMoDwiTOJex@AnV*{#ydOMUqmliHtOhV8 zu}sO$-TO&sM;pmyj3Ff@>XvLL=`x^G(N~umus$W?{Zq)oGq5j zO>!xQ$JHzxo1djFw3Ky;vl@PNdqr~n{j?^e%OCTq4}<Mj#%KExR{KPMzN;7^L$`X8b7)6TOYPo4c0ax*B^NM&q3<0F0_lImiMke zW7YVV;d`$jYWnwRUS}Km+@*R)NZxxUD5i>yT~0im3K2ZqilifM_^i7JiP*{Sc6yHf zW*U)%lR(Pj(>hmsN8`+kV;ZyOwDR*2q~&AB4gu!r_R$+##95d`7`RJaz`O=39j>!I zXyZ*nuYmQwW8k2P=DCHm?z zhj{eT_+z2uNs%RTH}5iky@V}_!n2D-5i@BW!C~DSN}740ZiL#UnDMh^9-=!imv!1V z(id58{=1T`yzfB$UZ(@xw*7AAWzE%hS6mhIQtL`v4xpBE7gU?<(907ZA=>wmNyiOAEq(pMIf{KL58*HDq1j^P` zILuzZ-3JB+swyjc;q4v2umnLz z)~eWzP6x8cHb=L+OvxFBm3yEPoxE{PK72!&1f1K1hlkt3?FE@Sj|gr9_x1m zz9wzk4K%`am1AMS$qk5jFC$pNE}pOKj@E-jrn4HsF)2-2`a=4;x&qI`uqx=NVIWnS zq(EvI55DE$pX_$F>wd#c+(tY>fz0(BnRqE|4L_9F;a#n}E-XuXJhm~eleo!m74+6n z$<+vc`x(IxcIQ{-LP7`ilLfC}0b%LO%gf5DsxBK2@WKtjo^NTMD`D8b=Bq=#xX{(> zpt-yE>=zGm7CmgkOT+`ivuI3A)XJ!e)f<1OLYgBohy@H%b7I(&s;by8_h*_fjy9sL zF1Ja!Ojez+v2EEMMS=DweTHb>T6fm=K-RQmm!;xG{a0) zz0jegq3B@tSh_^u-Eq)Y;VK0Md)qG7IS#N0PVKR0z6Vvn@{|N`qT1vD_q&~~j|IFJn)+lZn%3!7Q5Af&h}?|1JhX0g>PJ#&Q&LE z6?+V6s;2tfm-h<|Y%8k}mxTbQL%^PEEbgzTaZoKW4+`&*Y7^XdyUENY9i$#!BAFS9?oi9xE1M6M;FxM^CcfI znci}@t318cIzYxtGaA+2jGL6b8zznNZlZ#vZk?ynS$XL5(17Ip$bMrX1 z)%DtDOv=6qIpO7(mEgDTH&0lqhdsq=js#*)6G4=+mY37t)bxXM46{qc$0`b`Dt22C z7H|y>71gBhJu=%=wY8DaJ*N_L*rcoM{(afV@vYw!IRBNoZl<5z6+SSPOlKM>Q>_iI z*-$XkycdH{d;ZDw!=T-X3$^QI32k=QRG(G!vERbJy>eZD^@dwiXQ9eBxzuhflg{ra z4s#VwkLHn(X2|p(tzTEqdJlGPXeL4;WpoJb$U>%~Cz6#H@i}chG;IN(XQm+A*wxS1 zh`{Evk2STftF4_fvf5R`S~!v7*kP{mTua!=$}pN%W!{~Y#QTF! zLm+u<8hvq$ZZ=VU89hv<{`h489fAxK`d1fuK;!1PCk;2$5kG=0+QCv?qM}&g;ceFQ zbqAwv=U46yRaH~>Rq**~s8Yh=CH!)x#}+DKJByEgHk<{>&XH|uatB>sEj;$dART?a z9GUGTZ|_JMV)=NiLcx?)x+$VLA?}l02EQZ)l33z*xdUt%8G(UBEK4Ibx>_Iu2I}B zF?Q#yM`PRJj9!xaqNP}Y((zMVPbmQ0jJJ`p{&MN_hRd-f-fA(swPS$R+tDfOrlYIN zruLuj87$pT7kP7gAR;MO5Uhm&8tQIEJpM+*Ce^6fz9IKxKUz9gex>)PMRTJol7ns5 z1AXvT_xcBpdiQI~fbIpprt9LXO*aQaYil`OwrJex$CJ0DSQ)%!j|G8!O&JBsB@;H% zcm&C?a;kXS|Bs&?U zTyDl8FMiMAA%3L8L3X4A#hMXUUA6An0H5-*5b2FV>hNwgHFau!HYFMWRW|S2RMy5e zy)}?&&*Gr)Yr(;9W_(eUh9roZ4nR{u^mtQf^ULI)uX#1PRFmT71b5?Eazz(-#2aIO zXlTnMv6V({#&*Tz@G-RILbG&5{0A9&n^ax`VicCF$}Sk3nESg%`{Z5?eccXimIL0< zWaYoDg}rsquc=9510;>_Z$hTmEZjK@*rTgY;9-fpaynggk|LHEgxv44#-)N!JEy4y z0tYnLf`vK)s!2}p2y0ju_dlr{1K--pHtY4imME|P?7wX^*+kZ`Gj58DgOJUkM;u$q}fArVW_JgJi(t%qRakZsSpFX`omzTpG2l-~(b!sf1T#&f1 zbV-qpM*bWJ#ZATatTR;n>K+XKQl8FTIKbM|6)1eUE|V>j@7rvwXd%*wMFX8+bas|& ztRJ&Wo>$sOcVsYJ`01~#K+vpNv(@rT&jfL)r;FDZ{Ey|M6};i90rFBa6D$zgrBOrn zTs~D>vug60kQM?*U@uWfxOSg5hAL`ksLuz_Lme^nPDCLp@{C==_HH-+MiBABSbk6~ z)qurHh>dQu`vq2p5OB&F5UagS$4BNx@sq?kWZX^Wv%$65LB2FH!v+ELQH^FJSH}@= z93DDlfpwG4;Bjx`97{sEW@*=iDEO&Gv+0fnd-MQHgg?6Y-4EcU|9JGrM%ObGpJr(T zxg)|u@hRSPK{vE9MuK}+??srK?ztYMx|SLsr;T~vE5jTTY|Gg!+aj(w#)`m=^~KM+ z)~4;0;O68NZJUc+F0IYq_M17%Ul3iQlr7h>SI;2)x+VQq{c}(UVdu)4qUBXXNICBQ+;ktN93phtv5VCVOljTMW!~b+JB)%yXCB zUz}ZHk;7FK6b=uzY@HlaAOFDu^!0&@eG7TckCE&*2MY~d%KB3^?zTXSsp6Y8a6b99 z^$EA-qlVX^lb=6WG=w1i!B;4kE^6xHNDu1$(6$%SdUc$pmX1`x@oFb0XT<4gOZ2

^PzTIsD~gYbzc+Mb|zClmb8Hv!d=D0yFOB>hPy`CdPxsv5;*(_F-#X|y>+#X z2vG@ArFv8{bLtI!p##AjdcGe{Wa_&ESYevU1kWtQD0e&j;9AX+ zcs~`M23N+l>-Bx3>E)7~6VtRTaB=>WEZ4h<437q%Sdhw{Uj3ArSp_}5oz^y*xhrH( z^NxsufSxy937RR7zIC-Y38$WnZ6AaWG5DxGW6@8ai(dVB82T*ho!dvm1SFUBSok|V z<_15D2N}YbY2XU;wte>bI%Dp@SNf;==TfcPR-~HY>BMEK1H74M7qW*jrclSnD!nn= zyI*BdOM9A(CI(1imA0o6w2)<3`dhx>Z5Wuq+CavyBe-77v~3e$^Yz& zCM0#sQu9_O#eu$1sjer2(=VrZN@{915@#(&c6F5i)_9xTNJ~+j^FVWjmvAlroEm@2 zvh&?(a0IXR`KTkxNkSe3L1>*+n;4rbxwV)Y;7 zJB9~jx6DVK7bqjzyL{*8c_l6>Cg)r`Q3{G)?KFM`R{kO3uQ8>+(8Q0;9dy>4H@1Lm zsLH(|U))W%$QfN$;ch);<3n?8Sy1ZkmvpRx{b0x*_`r@MT)2&`^ZEK>{Em&m9@vmq z{mNfXG%NoHW;162S!v-shP5IcLEh0+SqoLt;XGJ+UX!eZv`Ti8idlo^LYDA4I@&;2 zH5z#?po8TuI~GJ)T3zqMJi$NI{`|SKG)OwS`RMIZb0WpG$XlnhljB#s6{a=IVw2fU zdbpt~0*yD2^t~Vo4X)h!a{)hzTgbX(S4#B*1BtgsT;^kZ{$9F@VM-JpArB2pbdOYA zLM($ynu0csN{e{US$@GUIDI_v(L-!);j^+8NpKF+j{B;`sJM*-ko4FDgkwObL@?!o ztVo;M;te}jbLYni-xjpkg7X>s4X(a(lXMbvUt%rn?yA&c0$#=zX>A$J^&Bf&CJF80 zHx-$F-`Lpv_U%0hhml$SFl#=g3Ibp=zTSB?;K5#eoJG01w$>X~l6HR;6f^yBdE`H{ zUHqb65XdvTwKl_9`{3wIf#g_M9>9;EI`gaX3znMXg2rBX^R2WvEBI zPNt&y0Ko@--upO&+RvURPCBr>3sHxwSPjH^=kk%k1nd z0C8vO_;^V#sHLoKW@1v>*btvUTjUaCKt-<-uZBlRs4FF%*?}ya9q8|umRW!BZNs_< z_rG?tC(LeG>h!y+99JYEApz1q`#Fb2!d@XWkEJ@rwMjt0&q=1+I+0t&2D?0ff2^Od z*f~7Zx6x03=N)y#>%G<=7aFRp#_cNUsjrY_)JZ9zybx>yPi;wzN@nDaN=f--lV0%f zrq3Mzy(CMUG(Nh?lkKfYHc4s?E zA==bIKdnw3VGT*84^AohYSibre521pldb{-Zy{;LUgU zBB0+@au>p8M!gci-0CqBQH2T#*oRg~MDrGp+K4J#8{eGsQdyn~BAs+!`o=s-ac6Z* zQn644`*G5tD};fML4`e^{-9&nez4`N>##3+wM2j{5)$~eAz3u5NS3<#h_%>qiB;Hs zOwabQ)_4OfoLDTW_!g~~X>Y>ee4;*ns`M$qI~SPjv>PVH@iNPZR{M7*6yi-`Vpb=JdiuLzc( zG_yq26bnkmr{WL>P)OnAajtkGd3crTgeX-~#+fksOh z8I0LzK4A_Kl-7(lw112j=q+9gR$#ibe6{t-V?_0Ust@+fl%X&15;ne&3QkkEcvGbOSVBlgCqhEcvHF^Rr_^_{wWvT>!OA5o?fbj)-zo<=TgjP{ zl_q!Zd!rbTv>;3KgHSxWj1^>7*l*Q%Jj5qntE1#~@cMLfDhGvrapAd>?jPq^Di|HX zipwV$tHjiPqH_VwtI4Wvda1a&eo3d2ym)pbr0f!IQ&*XP*h`^n;P3jq)7Lq< zE#!#w&MW^BMEA8Fb3;_y{wF)>^ozCFh*GcJ<@G!SsQvYTLs*wehsbX+!8mOQ9V>w< zs@|-VIDNy$PNV7Mj0pz|RC!Lj2uDx0jP{%RO`Y1%k4CScVO?HtX}sUk(`Wft_QDd5 zVXodQu@4OR;!;{T*;BH=1RT^zx<=FPr*!6hf=6$(#p_CT`v{%CR(wAQLSdy*_^_?Ja3TZ;gqNNuqGnW{~AAxlGJorKibB|^sG!EXx`?K9QKi^(_s!;A-tT|d4|CqHoP~Ug5$_1b>Pm`_h2)b2{d^Ocr&3@J z%WH|NQ88!-4-Ps-*Eu*;PTjYBgf4H!TR6$Jyz#7kTwd8tI#7v3S5?STCRpN+9=MwN z<)K;qCh#iuO`5;|#;>Z36HC%JuB@AX(hr!Lo81wlKVWHdd@Y!7B9v>?`!{w`=p3Th z8zTAbLnmRXLkU;%2g1xiS|z9~#+^Yd>1ux?aV@#d&fW~IjyazkU@GUi5AcFc$Dx`M z>&PXiB*ZoDOHDc%oMtl&(E~S*Y&&t$i;EBDok`_el#SbQUMnb+_gAtJ`$|Zu-+Ke? zSHdTkfQuG|c_JZIEDkI@6Ds+uqjXBO;Wi{{jJfLDZvz*v?4jqG8p@IG3@Vz>im_f)j9Pp-p41Z2xFyS$QoWn^Pb zfUiQ5!L9TJw2U+k-c5%hbVN+|^GYss`tegPiqP!u&eT9#ls-SvkGvvN(@jNPrL#jS zmY9VNWh)kuaiD`Eay{c3A={s}8?s-(HU3I5qs2}-)6`6Ap}Pt&ck>$riT%=yyPkBD zz1vwoOLczprfP0ww!R`zC|z2s=k2BB^D_6J&sB?BbB-iG;+7g}vdAmt79pH=b_qrcX#rJzNOr*zPdf9lmG7nZT^klY2erAcNe}Yrdskg(u42d*ftmbJ^^V3Qp3&MMJ$DVZ{wHOA`%C`4I@zhfUJg12Jxnx{A13v6NF~8_tlJAHh$QJNZgMDD) zLKD?#WhZxdhRLdVaCw*kcA`xSo3o)_$OXkCItywB%;LvMznMf%GHKl(8cQGT&|?@f zQ-p?xXG0&|SEv<#*Gq61ZNIeH&4=Jpt(M+^e}#Kyc4&n zr#4r~V7mKSPRP~QXn%jxgrU0?k32B)fjj!X%4g+wqsA|>oTINE{Cvfo--f;5rW7-C zTJg{?{7aGwZKizDXSS|dyc%l5+q&9Jzf-2^Pu}ACksaF26r6aXVKIFA#8Yj%wGmR` z?|;pudd}N^x}1J+=W6tLIC$=aXf$cKlBI5(TH+5?b7Lv5aeVo*l_zJu3|YI^{!y?j zId}e3bzoDVnvKiU(t!81dso@!CU?S+sc|koAwCap!)s#D-aLvXQx!XGKx#m<2J0hJ zC>B7g*2&qCr6@B&ZI++a#3Yy?ebI?N(>b#po;_EiqTSm*S^bpZUbWnbgzgjln~_`a zC2b+MU{c{FjvLR8fo<(YDKQ1BJ&cZd5XK1;Pat%bECj4>*W-lfDF(rnNl!z~fLUB- z`_;BETe8JAkHd;7jvqJv^12r`cVJCo4jdp#*Vdb$j%h{}P%pbei%nrXCp|OBdGo;A zvc$J>TbTz;s5Vi5@Samju?mPJDF)7`Ax}0Ix~Fz#4!yr!nybjKORIl_Fz^+VF^SuT z4X6(t=!B$LCggl#c{l*Y$HjGLs98Jb*XUN$EQ<+qG*Cg$JAo!lZ+FZbRM1qW*{p5O zl`CF=A|zks7|Dy#@kwi)W$w#=gjgSk)70iON<5o@y+rtFGre3$8ebgRv-=yx- z^CZ%qztv$%H7{{$nFd>^g{CkU35{%!#IxjX-~AN9lq|2^F1QxfXViVqid0zw@Rjj}lax#l>k2e6D$rE3q0042x3lu@ zLm-psBzBp01Kw<{l(z{-p~{P}RaK8$exM-Ip9Ybd=Y>tmH*+o#+dR;=^r^ZBtco|X zEYC@e|Cy&2ckL-Q)Jk^!UO~{ESt2$Scl4GNwmp7Fj6ZOp$(w0w4YoW7Bk0oEf zMC6bKEB;dQYBNxbkzD6qc^c9Ahp{R-xF|31jn4h~l)k+}X`32XT2!#DTL8SusfK7M z@FRNg>i8fhJ_@x@F!l9~sD4mJuHmlNL$eAa=x9u{8>O*S8D#U5*d#1_?DkHnPTU52 ziHn&@GmWPfk=IXySKo%8wbxL}tJw&QYoXGU#>qJ}J>m-d}x7W zJI18S>8&Od7B+AQIB|HLzCIO&9=|n=>yPe0a|wY7gH+v;#;1nuJ7@Yvpbxr8 z5{bXy%#;#&Laws5BI#sw?a_TB&2$rba+n{|s|#aeVnT?Gt33K-))9K$t~-|TU#>pG zmOGLnG{D-Qi+8$5N2t1DkI-hgC*gdZONBrn+FlH^Y-3uaE1#K|{B6DuGncY7KRo2_ zV6&}JG=r7{S)*>#;F>PmJgMXXi@r~~I`;ZDxmqSkgWkpjxtK8x zjs%4WY?92xxl@2JlV}n-TY5W>1UaxoU&U*v&#J2~R2xlR`r%_y6H)y7zB#J3>bqv* zSXJ^112Efb#0&d+)XG?Fz0mSZ)NMN2gr3eAs9)9wqf*e8`oe-os!@By^^M)q!>gvw z+uanw@8KXV+OtGR(0D1dK@=?YGIc9FJ4eD_AiKz)T_>*8US}NCwaiSK zrs6p79}YBe7k9;VbPP_7=CHnSZ|1<`@P$8hrbC+??x*LzGxlm4 z72=jsR92WDsRewDb0T*TIdsM^tDluJfbhl+R4+Mhj2kEj#_Y8E zSh4`0+a|o%A+5riq+-%iAS@z#Cm4x5|I1gmEELrA&i>w^I$y55C8P&2FsAt|;eXNg zR?%4mOBZM$MjWEV6XH(Xowz~V-Q8UwLfqZM7k77ecXxMpzrz8}`S0sp>&`>+kjYGU zPj_|ouByHJ^Cn?#QP(|<`uwD2ZS3PLizIuQ+kbBVDoj79Px}~UAQ&Vu`g=d8WM?`X zAk9Iq<+8Y?*02!1VB^PYR&&bOG9e{+n8H)zG@?Y$l=L+%IKP)ur*=IVk21`770=!! zB`PRng(t`J-n(l5OW9vJL^S9OzfOH(qhlTJ);yv3p4Sj+WLL{2-H(ptDdH=M z&Pg};Y=fkDmOg2axH7Gn+ZyL5Tet}LV@{U;{F<`@J~%Scl5T2bFB~Peu`QuCQ@YaX zMkUj))%vV&YC2Q6nxXj&#c&YdvqaSBa=pGf{0;vCF7`pS`XHRd5LW25 zz0>XLK1tHg|U?$#(V@T=Lnu)?qtd=)T}IDuuJ5+Taioyq8Cybqf0&I2>Bws&`YYchk1i zM`BGW62V0OC#PGOnXSGw9TU2EeCXBl|*FYO%#sAh)nc*qT z=rr+?&uI52W@O9A zO6{6ih=zjP##^3Xs~M3-L?$%Y?7nX#Hp;QPV2P8h`u%_}#^5|rLGfM*$rpzM_Kk<_ z%ZEcDGwe-InIkQtLW5|OfpmpaIbBxQ0_C?PD|C5gL*q08Qh{n8=x(H_c(!xHPBew; zH-&6&<`j9r;(YUS0qb$EXrgqwydhY;yfo00S)=rWqZ1|Co}@vdm7eRY?ovb{al>f3 ze{8y=9$PHiteMuNSvPN!1AV~?M**Fg(zR;4x^3~JLl9!KaEwAsq*kJiAH^3D7<4D@ zfk^B5Oy}Cy$KtWHZswB12C`;0d0teaeNM@#gli_kVhr+%)u&mbUxqCNHMx8VuEg4+ z{3bMZ4<^Gz^Q)q4GI7U^es=L2f*Q+m?s70_9e~rA$r=;#fYk-<&&i*3v zx@~EXR$AnmlW?N;;|f;YfKD8H((7;*2+^<5vNv#$7J4x6AL@22N)ejbCPpyh$!~P` zsZZ~0vo=S3mqe%_rc!e-(^I7kOM9-EC<(;QwQemu7a%LCD|n2&G5c;aC}PH&onCSn z=%Z3nUU$WXw|9^mm1DLRD;4shrWyJli(+elUZR}@lTn0*s-LX3@O53ZAirl?73LP-ogBV)e2ol%VX9*hQ>0Uyj6Fa&h3E6=U^G?!Rz2_bv%u|zUhES-vbL|^sTl38yx;w)td9*Qp&I1uOycdzvK*AR2Q^s>gNiYmfQ{PJ!QpU$l%ML!JP}&C17iBx5#V)u>WrqOwoJ=Yx zscyRmZn}~b_DbxrG?^v3w>=P+M5ad)e-73|pKDNfx$w zGiLnR8d>4EBd`A#0Mh>OhQ#7!C{|?14~dPms^AbPnRdx0T%Q4n2a<6K08~LAam}zF zBPU;tcDL{_9Q0RnRu8xW)Of*#d8ZmQ=qzdFD3Q!n(DCimk!KU!b{k!)rJM0;zcEMS zN6VNA=R92X4ja6wzHr8-^jPH8s!TS4crb>CG!VUokV*?{7LLG?Q&%p#KBZ%nAM`z~ zfU-_bK3~>U2V-J6So90YQlmefm>y;X7>EwSKNx9?#l45^Bd&-%%TmLtlnh5#=#^Kz zcxNL5@h?Zzv=M9UGa18kEPE z0|CdimPb}h%e+$T!;j)~)SLg7AdJO)K1c~wEh1v#(gYI7X@zrD4ffbmY2iaK{yh+^ zTEkj7K!+KETAS&PWw+K2Z>Bh}5Z*zy@X85Cvi84a4-f|}VP!m%{6OnS{dhux2?6R5#t4`M5F|ooN)$}$@QVok4JptY zl#}}4c?;K3gZ`Tv-00V6Q~v>YfcKPC=K;pooEvHc$<|VFDWhto*sHs>Rpo!r0!yNC z!2F19(yW6EN$po}A$kjqqyF|N<>@HZ9TV)6Edz=jBTB^tEx;v^L)}l5tlF>Kip!w% zOcp)lQn1qDFd&9N!pQ&Mfd)H4W%!R}2vNPaIX}Q*c>u?5M281!-r6NSUA;4XxE3`m z^EWu%N^xaYHTeF2_^_Bs5ldc3goOM#;`=#oT#812LhhhD!h0uuO<1h5WcBw=k1-=N zFg3l>)iF_sNG@UcKQHyhaw%5lY^*(=+O?@)@_nQIaY~ir+M}bp5{1_n{=Z%IUXX=* zGdMMrwc2-!309qZ`qRn4meG>Mn)2Vk0bd{&{jDP0s;1)z4RA~ENdMwsYv~*m!~gDp z2cf@>Ym^}e&nPjr;H{tpDzE=u-iVS2P6r3$k#D{#UDe{3=wRMu3;g>d7!#E#q4qrc zJw4b#5aF>%LIflUocGR;j-?X8(_S2nAIIuXxGB$=V-k+S?v}3ZhNeUHM8UBn^?xce zybZx%Ac2~rAsTZ`Fo$f#V-aRTIJ*ikW2icp0K}BL>d zw!bD0ac%qFy`lz7f-gx+ zZMbq%rDfI0DEYeY0F%7CGoAP+Ti)79_wI8mKSWVmnB0<@<6^n#O)MN|y_D|JP3r5A z$#{jEc5gpG;zl_61{{pZQgVnID&$pww0A1=LBL?nYiXCkg@)ztS6sW1dp&pi0gpF? z8rPXa=Wu=SC2RWn?)hr*`ZW54rV%OmJUKrRvJhHH*Xij(lWJWgK;LC&4JkQJN+}Mt zY*9i-^I)L#@q)=)*l+0bN3b=-_3hQwk^cBMdVD1NC~UtOae&L3tj+@5TCb&&hIXLd z)kaCv@e{AT)qEiVtIJ^!bfRk^qS9$eE|SNn%sfY4S`7{Lv5Li9g|OG!RXv{Ro`jXn)~)a{VQP`GIn@5Tl0i? zVjyIt;x{L97oeqkT$ul{8Z0xOU9VM2<=7Q*UWQ%ZUJj&X1TdB?&Ap$hHH=D zmUGzlin~&=_H>@T)H9MFTikqmJ@|+TwidRrGw=6i)92#P;7Q^Af>Bo4w*hHhW1UNj z);^lqyT5c*5UH&Y(}mF%C%!@5$rcu&KIDF~;BTJT8t}t?oZ*r1M{nWo%%xeUy)E(J zIXNnwNj3I3iqgQ;vf_8 z*5PDslrfFlX7$OgCXA=o$z$kPtU0TdE3YQ=_EhCE#Ced0AsS(RQsrWAXF1k~Gqj^) zBwOem=2EkuNtL8OJ<{{$tYcm3uTfu-*?G=GIcc&Gd=!_9HRw~C_iCPJD{7ComdDGL zoQxlBB{lnq7%34@i+o*1xjs1D%yrL+KI{hu4;<{RFK;QA5%w-&Jjc;Ke=97N!hYFC zG*ttI!Vc``{{)wRTO>V|DFk!Il2PbvMdn}@inc8-$9RdAI_{@bwV(Mq(~37T@^f}G z?Np+VZgvVAiQFYB{8u^@Ty=Ia-tyg3QoWC!z~TP2#p-Nu|s;Sr(H5J3S%(ddMU+F@&0T} z?=Q&uS&9^3swd`;FL8euvq6T8O{TyVVXuQ2)4G^rxzdC>VbXkg-aoyGt=uNf!J~1D za_O9)fEib_t1KzGcTtxX#xcX066uc6{-P87B{2Z6$?13@)TceQ_4%YXk|-dEg!0Wq zCc5WET4-qXoZjvTF21uii%ZJu#$hT))ubd+KW$A7%aW9)<_oq}(@+w0k}iJU2idI0 zkO%Ftt0iA`K!WPql=2 zeS^)86GQQ!iYR2H$7;;(KjxHYN8%D%pw~E9byzG>u11n4K_>-7%}vh22-> zxt7I@_`adGRG=KTpUnEFOk0K`;ja-q%^_ujr~A-jH!fYBZFg?V(P{~|lI~N3>t9Zz zC+Y4NnoHXdtQhfaeABXB!5Evup^4Nyi&=i+OCfBS6gPDyovlmFviVOY=cUB+?^s%2 zTa@2@DH|Fc^?FPVufqe8DI=Qjg%5iwXMUAT<*<3W8|QMjG45LRdhKPVD5skUk9(;} z;Y2s0VSb+Bitp=V)Y0+SqgF~~L*l+-lY^5jV!3;G7+dY?DttPd8%L2Nm9cgz6l$G8 z>NoXpE37iij7W4%!bXF0BA|sR78+g`D))LNJV_9EFRsAWt#Px5_weFoCEFhi{-M|T z?CcvQRr^kUeYjj=w1ka@u~f~+OwYuI=H|x}ktpgjW#Tvim4=ME9H(QDTCke|!xJtD<4R5V$GLZjNarJn&21 znj7?LYZKE-R+}?H;KzYneI6TbEDSd4jdtUqqLXvnW6VAD-j$RbB5!9!M#NvP;d>^O zPm~#p(Cl2Pa5!s0Zv3(07_nMcS-6kE<6twmc2-ms49(IM{9}s#>!Yb zkwpC0L~s5$RP3CJF6-kmpYm-N6p41N_8Mg|@dfd@+}(t6)J$2^Ws^Y8Zrs8r zok=~n%9HmQF*o3ReyOynoas*0BAcmcv*5GTT_G{YLwji+O+Vtb)PY+~+YNv9G<}`5 zr_{aeEsykigh0e%J1=z8`iXNnb`a)~7SS)M{7g{qqo3NgHiE?Ud2wdOzvsTlR69LB zUgqYCik4#ihkFjXtF5hF{qy-xInY9co@|k*jF_}^CLhFg(2K26?x-;LYin+QVwyIj zD9HJ0ydD)5a;`)WsYK;y70CEJUOe?Ah7qpF2*3LE^z@xpgY&WzkGnDQi|vUd>h@kw zHFlBb*SD&*7btK#5GD$s0ub@+Qt|=Vc8OeoP6$mXe;C(VC8Hj&TU1Dg=ipz zE)e>;JFe(utYj!LX{+jMt;y`f3kt#)=jI}+L`YD8Mzs5mIHsFW-Ryab3q;-`2Ee!CK85|f*0W_B@@6=Z=0Mx$zG zvxiGqp`!T=uLIqw@xNGc=NkwP`bK>;auzx76=LFXmtR);J+y9cZqTn?&D=^gUb!L@ zUHOl`smPWcu9BhX)gq)_Jm)8 zVPWLZcE~UXuRqVxnr=YH;rpOb2j1D$ZP$rRcXC~{I$HVejuAARo!kM=hdf4FykpKA zkBRBZ$?H48#TQro?%m9Q+9nm%D3RPCI7TE(ca!_vRHv8AF9Xx>oYG5{1Df$^Kg#t)=I4}OtL~Iec6x<)$&@IViIs;ET;!J792jJ?{f*%t z#lBiQIwCif-dl0A6MYktDRYgu`y>{;1>gUjhjubzsEZj$S zyOpI-e(^X-zu=H)L{Qgs`7N(rnN7cV)Ke)Ug$S$Beob z18e=^I$0EJQvj3}M`|OJzp*Xob1B+S7mMa(zBHq36w_TFz|!3CxLSX{I}=uC#lHM* zi!^6`-zI*v^pt0Bn?=KD?7H6U)o4&0POdcVy&I?#)J60x?6Eg%_yukiPopDkM7%K} z7He}U3l~OqHg;8TrXZ*F6#-_IF^zIfiX!?w3}!x zAziH{FN=NKD{zpIEfvWl{VDXMb9%&klt%Ifm(+fbxpA})sbZ2gD#XBIwqvrjbZKg+ zr(L9)c4CH`#Wp*;+U%7cj)JaTBj*tcq47g&>t{MKMzO!gFkyHTWuWfp`}akmRBi+N z>!4*JH*J;qhULp4{ubfz#WMpB*QT+rM$e@vUM{7vu4Xs0deXE;4t^^^r^?I{KRMhF zbp7h9%Sf8?J2R~I+y0ZckWzF#j>kR_x+{VJpSnU;+G08F&Vb-GU`v{7@OoltxV8HNM zHQ!f+h9WS6^-r|w^%4n(;XFK^2KzaD2Q5b|FgP51(c#AzQTi6V{MA^{AO7n4dVLTN zaMw7U&%g$-(5Ul0W9Xu6Mca_$1Wn_-edMBV#SCj<_DoHXZ(}}a z@~9duV%9RxV0sGC(Du!pk8Vajw&HPZL)*crMWu*3b5vNod4`DBC%Q>UMAlIGR&!h$ z0D+CE2e@9uG$dW-&Cae0jt|{gPsv&x)n&F9h#yhiZ0`q3U8_%-8>MF5(9mms&j(@{ zg&4p`o3B$-=Aa0^B&TQJkKYT@SE<&B|78ZY90+R{P2wpL>o;$LVau@b@>J2tHVbQ~ z_CI4n-zh9*j5`Kc6Gz+zUj!UOdxXQ14`poNJzm1Rfh4P5;+GLjq!UdLZtI)g4NJA~ zh`H(7bUdI8;pNwOV$G6#o5~#(YtDRfxa;Z4XK3hkeKqp#9{7>v`rurOE{n)Z_)>YWNzBWM{kwRID@P%^7TadgPvQqziDABp z*}6&T?ESc1nNXdI8Y9QyDc(P*KK%A=e6uGEi%UNPFEP9m#hPnFe$IRSdz@0CzJ#pM z1-Vwa@jIv*Cc(F?mS#mr(liT>`>#tc4zIzX%Czduojslh+xVn)nHVq~5|Ckm`S%g| zyzKSWAIyh_j-`)Yww}tfaUX{ES&Tg$U6)?2={`?m=})c@t=yP#9$fiYNgqA1y(}$c z-ach9L-_e|n}Mk}H(cSr)+Z)T59=i^bqsuC6q~uh`?valTH;P&>A4!0;TkD3;m~9b z&kM;4bC8=hJ6k@>Lnv?KjqpY!me-c#*<0`OJ!F>AWlkm{_JgN#t<9{NT1(cjF3MIG zBD&NU)}5}?M2d0$Jf*I6qF&>lE7=m&(~iV@dsww_j~p<;BbEz=xwT~l%Na8z%XzPA zZt5aymmXbvu!_9MS`8Hh<~Lu&rR)}9@Y=bx%8m5yYSu;%6} zC>E5!YZgC*G`xFqH9UqFu0PEc0DG^zNP%tPp;kb;|`LAC}Z6-`aeZB!jV zYCX?(x24||8y~k6)Yl_K8m%I*Zv77nFe458gPn|#e<)P4uQOR*b#t;JLZC8V`)tS+ zLi*cEM#)+eUX;=d8cy9285J*tk%|Ki3*w4>g8e;MC^$H$BvWlw z;|DMA=_r8W83L;2WvvrPIU_{iyq8m_7<B?Oe;xCMW;oS%6qv-m~)!A3*yS zubn~UyfhD8r#B;S@H{$!=|Hul z<++M@^AC?Gm)a^=ImS^SM*PM2nVS@abBL|>IZ!OHVj zBv4NE@r|~$@Ka4}C2gvP-A&(yV6xWr)!`=Y=ZFzi)kali_FQ#tJdX_|*&I<*CG_3n zr^oVOqnBp%S~}ZTR(dieV=3gnnBn<2fHsu7cB{0ycDHa-B2axM_r-((^2%_ywjaMQ zZKV|XVrg)2K)>Vs0j7;=3{sk7B_g_4=PxmJN;{0dom{p2p;bUm*BI$sSCiTN@bEpR zYO2?Wm&+o_^prSTwtrS125}^fQ%3JGcc;K`9*4_4ru6G(LywwOi#xqyHbn7ina~(f zA7^cDhG_WSL^et-Suq)P(P)Rv3K609R6_r0%i}m%debeizunKbzP`vL+=7^u>DBiW zI2?4R=JmL$>00hM{CYf04EeoFV}E_V@7a>1(fnM^!k=jq?r$auntivAv4O^!VQ#r_ zM(1RAuB&cgM7dAM$QW$;B@Y#kK>;Dq^*eWWA1nW?+|*llkL(QPd{$05)8#O6_-;{T zgOXZbFEQ4ILbF^JK3$K4yf* zNM*m{h7rbn{9 zNhjgk0eW*xWl82+yRMA>)zrEB@s{e*{;eGT)Eqy=G%veCYPH+2=3Sh{^ObcPE5!8j zsYzb*y(_IS3pb}%j%in6k=qC!qLuOg9R`W$2~SFSJ$Y>8Ic)ToTd8EDqb=22J3@Si zSc$pF7(3tR0$goTZ@wY{RNK|UtN_VYzS1uR(nLvfI=yK`5+n9F7E2PLdbDklC+nvp zDOwtVC}es3QvGXTMKq$-Y4Q`>?;m0@z_4J54eRUcBKrEU5&-mX$otzmKJp*al##Dn z1@Krc*#uq4L0$*dAy@jnkak%b0KzD167S4XbpP?r)TXOa6Atx@mO0(%flUQgVH?dK zZ*RSnZjM?F^w)KPfpI7UyK+l2P<)!^kRwdS$-UCvo&JU>(v>FauN4I41N`@qSU_}Y zDsiYv+0iXBUtVdmPzgY7kgz|eycr{|lcUmMlpPUlWB8Ovv5WcV{34a~`_0mgZD4s+ zDipP9KxlB-eV2ogLa4rlJEp@KO54VX8Ufz8QE_2`DbtXCfVZAqe% zYSjP!>x9a;Unxuo_cip*SL_koXXfnzdSGxqMIj@mazCMfUvEzNSOJLAKlGa8U--t2 z0DK-tl?in33kR32bexnWQ|{%Tv3)alPpYL*xA z#<*rllr7T?(Duw!6UK0d!VJ>6NJpRTNI zbTWeS{yBA+J8AiaRD(Mb)hl8e*^O*>s&JeV1yF2BLg4WcT=HnBcX2WsufPU(6|2XJ zbUp40?IN0`JJ$L0WG3tbTJ1Mu@Ba^FnYZu4@&A>GX|sU(|B2p=-T;h=fmY+E{-3t| z{;BYrSS-vtW2E3!pP@WEM1eCVrFf@IC!!yV@_)DOK})>*Gu3|o4{rnnX^R?^a(DOGwoT1a z7M}oMaREiLouSm-!(B2Q%jG5;fM7{KfkiJTymnQF*ApP>)pIrm6eKDQdCR?4@nC%g z9331qDxAkd4`=_*|KFXdYwpvxg;tVTj~FtU-2il1Ah7jdm6scC6W9!r@Sr1erAySy zL#AWp$ihn>>>x2Y98Ne)4!HH#uoSuP*BeW(Qh;((p8!LPmAZBNEwO)#8hCO@XsR6? zO0?Q1w8VZ=vS)v7J;^tRUFUif`4kUE+5kt7sw}`=VzE%e81#Q)lR#7x7S4*q%~hxTRWce z+3j`>40CYjYL(7NG<`*PXf+z6vt{$upKrwhc4>gXd~*HD?G&F?XCkUQxR1;121RjZ zMgaAX)BAfsz?g`g4wc@erld_Ybw7rUR=eTe_#)+Sfmjg<))CK-5}vLQ+=% z;wHTA)~z$2`#r3!`&hL+T{j=DHJcw9u93Up%Evp91ttdZ+}thAkM0$`N(e49&aD5> z_#F6D)Dch+s$BP3 zWt7ax$;s~1`H_Bs{!b78^8+hvkrlj9ZnvaZ4cdNh&g3@i`0?h1mX1!Z`nM>IyN8wz ze|z|=8CA$4psxVyP|HKl+jW!x zbAaC?I_I{MUI;#5^ATByuW*q{^Y|`l&{V4L~8w3c1jsSIo%g`#(epNuU zCP!EpCIcT*nj`+@>VKUB`$b?>8(CB|^!lRVaIRYv9BjsS2xce`UFqLiV z1H(&8)%B2y0C5RFKR^95D_p+T?@v#$UN0Y97`|i177a;CV4Hcp&Vcw3aBxlzcYEXC zGh8pU0h6Pyt{!);QBCIECaDy_`ai^KR$Ehn-jtk30jQTGxJJ!poUIRfJ^Bp+w7c+2 zseMvI9zQxfzISMFEhMY4CnYZ?B_vfE3c4g#fQV~BpQ*U_m!^X`OVsDSeJjyN_&L-u z&@;6(u(Tv=sr!kQe!5BAyGIc6o2KG7O@K6n7Dzaw9WpBVyK#cG;dUpyRjfVXCY4Ui zF~N5^*cw0^8~_v)sHl(t!fT7k9-uVS&|K6R)^gGCq4{=_j-JrRvm+mSw$#XIH-Z$+ zW}`0cy=|pkofD~QiKwTZ-Y612J4exLTdU&Jct>$JP->)o;87Pxt=ZMK><^sA0Y}K? z;Tm*apRdA*T-=qAKv^WI0R&KRG=S_vT%j!4iEY7LME7XdYY0Y4!<{(A8tFJimTX^H z6;)NmZ&^h}dDzcl6&{2Zk{4PmLEm;ie19Yf8PT2D_!ai&66P~?20bKiCjz{3SX zW3XlwjJLFd3kJ9*Nf8Yt+!2TXcF9=S{t zPU)e!qak{uAUrTt*7se0XN@M2G2DBfr`N(`6@0EWo@-T|Fxbq>SIt^)?iug;dnd3%)8ZHll7VC0?)n zS;gKt0r~kirCW*Qmh+ox+8Gp+ULEnpi!w|Bt_l*U=reCpNpG<)ZHnFJ+1>ik&;j-x zcqWs97;!nj>{L0pe`dCak94+0A~102%V$9EPAblk+tB6lwzjN74`2>co^z?io2yy; z0o71j;lM<%5JQ!z$qY9TlTDhl6IT=VZ%?p<0~lH-yZW0glE)I`W~AY#(5TdEYnJh? ztzinrvjY?B>tk^h5m~5WNJ!8XYjO->|GoYFs>&}_>+}WRy%p8?= z_EdCKdKrnpy0kpp8~JOvGS&eC)+B-x8aK8E$m9fVOHmJcdU`w44;wqn3gOs{b`tgZ zm?oI;OqlGgrT?%1#=HrsAymU1AoJ(Xh4m32GliKTIZ}a>fQAb3@$>W8eHq=i(Kgui z?fx+w7qx**rDpWsCWcUeXP6MO(%+sPTh=``o27?yHYO#jIVCV@KN-2=q_f|30_g_p zlX2uj#fkJ8bI~Z_AwZG=l^QE}^H(fs+&fbsD?y!$qipeeyp~ns5U4`-5QhrTMv&5! zmJam+wicJAu6|fX#`c|o*e()Y8szj)9xqE^(y8bPh~9)9tKFV14_k6Z=d5fVZ(klp zb-TDQV^nwt1k8dXjdIvq^Jcru=*iU8)xEqNMgb&*Lv!*mu_~Nw`nmLpA%9IXU+0@Q za7@hZKRO1*gV9J0nH%KeP>+kZ z(VP?F^PB}pUS*1boQvMEaEAhp3L7}{!vCr(JB#P_++_$VE`IK;G;F;(NLE*7cO#AR zEQ;i37|WyI1hiBfL_kz}gn7QIFxa2-B;v;wVD)vy6&mXoV^FvMy6a%ZpUZsTGcj{L zKT=VfBiJM+W2PrNWNU;6+!5|8E<-h2b50jFLi+iIDjmL2l}Sugi=8%kbc~W{dAXRp zx~lr7*IO^2Bjx%?W7Omm7DfPnhKBR7!uox9LYyl2;4u^w| z<#Zm8pi-|bdf`;=$r3>kacmjoQ_tr*iSrJzH))3A`ma7eD1-@rARBEMByizW5JFl{ zJ~({Wqs#{UhfZk3cP(AP@BJVy$z87whJ&yC;x*Ub1O>~R$yR?=$uIN%=ers!11W+z z{`KvPwb5WxELWbgsSq~3??pwC6>+1mgmmAVi22=91k|*!Th4G`gd>8;DPkdu#DUtg zb!_BH(QiSVwZiXwKqQ0^Hfv;#UXmLaf#T{u3yn7}45Q9BzRLWK0zqnMprm8X%c?Sb z^m?**bwreao>Z5I+iJUu)yf^r0p@L`6cAQ(4exKir2$=0H_1V`%hNLXYY96i82&*AGT@n|vcK*sjwsf%u**Z6BBR8i65L zEE*aqXHmik1g;e zXO*pUsv|KrloL}_;^OL9$Ujd{qVX!ZSAop0-eGaf&F_7kh?J^R0&yK#HzoVIsE%eq zNz9+@B~-t%WKNPI5F0Biqb9N{Tl~jcF-3FO0TZZHUB@QWfaD~&{;>``el05MOT!|dX6774t_-`hI2drK4iO$a zlE#4s92x6Oo;mR7{MHU~3_3jxO!D7j^~<`jvkP26sR~2WRcICi ztsX~MNPg5}`ER$|_5f%=Ds*E*-3(hvQ9^VclhtfFtQB8IhGURSb{bapI}mrmSk*iL zrkF5qScGZ9mSurD7vfqnE>K_P!E5+?MiZeAV+~JVuq!JV+MR$|Xz<%Z= z5(12L{9i z)pN*Fxtq3W*3Tvqr$Nv_mN3;&aq)4}2=1ebN|tJmgZpgnQ?iG`I({g7c}VhpOthLB zV6K52*LP~h2H9Hr3dzc;9A{|V9aE1ALL$_q^kU!LCSnn-Jc0$@E8ZLAYDKZdeIb+% zFFB)_`^n8ZD;mX@L(O0u`Z0DFfWlN|Vo@;|I>puAQV_}TaEE^(@5jNPu*?~4N|y<- zwQ*op$ZM&~T_|WOv!0r>S(3U!`q zrz@x-JnkoQ`fPXv(XI}CN2~e+D&P_%>-cbmu&Ik#h@z;dC;&y`vi_5VaiF>^A|l@? z<(oA4kMCmr6DWQW2DA|{H*t!J?*3TY8)=ERb`letlGEv&Ob`nH2GH9d0?;m&Bf4J* zoWadiR$iFin;7VM2AqmLZ&@=;^`Mld+4LUz0K z9Yet6?F76gsG0x;tuE`?O2n3)8WnfzDwV6Ar$h`G=;*M6t36UFL$%cdqB0m(i!s*s zwk9SNF!~)Kpl3Iy#)f*SM3z)fd*^NO4gYJigGyiPewpAqSx(P9Gd&9MOv!9wl0ZiC z@s2#4w?BTkJW!lpp-7)&8iB;bnCM{G>)8cv{I-3zvL)ibwy4@or&BF0FEPWZ@Deki z>l^(WQe#p5Kg{az-aS6e(RK&Z#<60gD2s#2)q?#h=P>nw8}0EUgHk69Hi|$Rklyrf zTM1<;?!cK}ly`UC$@d_$D5e6pn$cu_bfZDn0R=x%O%dx85d&13oAkvg2=~sk6H*Wg z8-@SHV7!yg&ddrA#O7fT!rM(w|57nBtO>KMZ8RR zbYAM3Q#T&>NlC%M*=B0~wTW0*zxUUON$6I)TNvirJQp;=yvV4iCLr>$Z}T-F-Q;vb zB}S{Q%_6`{HUeICR&NDrh=$sB;(*QU-{}M%fKvH4vtA_L-FxZbsUDw9#`?HMr#PEW zR=8a?+SppD08oXZVh^8P$JCG{t&vK;(m%9v3LJR*aQu&CO^QA#oeWRZogAEnE7i~u zTgGT9Df-mPc^zHTr1(J1zh|2|+}{>Fx@cVjJgw{#1bPJ2pW;>< zd5@4x3Q#i{WCPUM`~SXzCDGp)!cbm9LIMx-sh7oq9}c_wURw)yE|ClxD(V$JQ=Z48 zG=O(1DGGGH<@gg%2oF8HMH8S0@@s)kmzUovD$hk$4R|9C3`*EBY>eW((A%!Y7nJ~~ zAGzZMHPvql@`~~dWAdNrnd#-ogWzmoZO_(K|BSIWeYwLJ`zA5(i71M}Iz zv0_knb2NFYy_TO2&)rm>0miQQSX6-Okdm5)YJiH8icoKPIUylQRas@CF#w3w8_=`F z{t2CeeN5ye(e6L-I*VN9bW;BrioO_!icu+!&SE^aqQR+hoCpx(&%s1j01|*v(GU`{ zU8FLJo+nF~+3kn1022PNH8~0>5(}krN(2B<`zX)r1Ryl-q52Sl%S!>$2ter#uW0BH zEHok*PJu!$`?=8(B4P9*)nYp}Fw!~Fo|~mk5zjh>ywLdbf+1Uyv=OiMbgf5e1m~#* zL>`U#0|31@zAwodMArLdSEn|smn>MykjBeh^NpH5ef8*-P@}fSgWu za4`|nR5aDGgqrdG+exgqf)Lc3NNXAZr`67m$$oxPZr?=5Qb+$h3F9x?$6RvMpg&|} z7q)h$+ctnqp0socz&L`I2*5%h{My>;%5?h6_PM!BU<+KFtJL;J%1O;J@gCOuU{J)u;N_V1eZ zUi3SMq=tr`W`(}AwPTh6_!!2uL_~TUV3aXvyIkE|!g078cwD1N^C|M-nHVXl22u2C z#zw8_7~nS!VPkP92n(9a+ce%`@%)*E8T8ujZw5O$qF&I^%v9o()w3$9%Bpl7vIuyc zUR$_-_`@Ghu?r^%kr)EQqS4^Ey8{G5qDKtOj9vkiZjB{*xp5x#J4hA0xmu^0BQo+7 z01MYItEj=_v1RhBcX@tj(RnV_lz2Z?4g@CdAMPXh^W{qb|ExQ&cW0UvotTuETB{}| zYZB{S`5#K(GkbumT}UVu^Rw|g+??E;a~Smv>UZD%L5YCs-%cnn0wN;Q@I{|29!>LW z+GVB2ZM7ZzATn4i7OzjRbMlWOxrBvJnjS3pa2(1{T$|y z_v=%vpa>b6ih+TuYLIqxY+^ri&cex^G!X5PE1=#Ki2BGAES~xGbM@P7-uJ9dto)%H zfI1;;Qqoooa7dY#3nSM8G{pIU9K-*OLkJhR+1%MU;DQC*oKA1Ajrn-YC@QWCij=vQ zxoip}dp}&`6V$|r3S5IS%J{O}rIP8RrwXUNN`Djm07}h@ss%-Y1P|-@^q@9q1k8t? z@3+3wVgGynFeZQ^n_^G!03tICT-QgJ4;qLcnTXdfwiEWq70E==7Ro&a0TBo^SU5|d zMPhM+z{tKkDK08z znxzzfyFXQL_BGk@@bytirs+?pMA9XboV-0T@tX3}f1Bc+;{!womr_zRIBUumyBnBa zhmxLstwlM;0Vx_y54|_Ms8&P{+N&!nm4bUy`O&@o>Uw>|LeE#5PT|}l+Nq;Sa5WndW9Xx~dC^bc{w4io3ULkpaOmEug zrr%!biqZJ3Htzo`%ACQzxjw5nn-B6$);eRnP0NkDQ8*j+Qp_4R#!l4{3OaYOA`Xp`od%uCA`3ICp!;04*J3enmxA z+fJS4T(`%PFgIE<| z`b8aI40R8uzV~l2kE9EbnUYRrT71L>Ab1nxnbOguX|Lne#%iZhJl)5URF0G7>iwts z&C4C`{K3;9X#Cfs#nrph&QS~}m}3j0)4K_5{9)%cddEdfF7u&9e2>HJ<3TJa$_Op5 z=k>YqW|W@r4~uGQYNhw5rNQNq_)WKQU4y&no*#kQwx`|Q$olkxl-H$NBZ%j z`Rc%wVYeNaKqt+Fbk9opyKi_ZcG(ifrK~IWOUl=3qYLiW)AzmM$3#X((zq}7>yKL! zjMez=H_=~h^hvQb0zceh4G=Kv4F}~^ZuzU5hVF%3)h$#2HA3>bQTVZTRJ^Ms!L6Kb z59GMAFs}_;kKSNjfm)R7teS3-2ZsVf6t}Q+xEbw+$fugy6y2K3@9;1u>wYpkPBQ<=kR_-}^F* z(77lq=uP6Akuo^ra?g=VB>$a&okg zKVfGN2YX|ehOQJ6mUipq2)0I}y*xSU{r!DZW%!6I!PiCYaN?*E4bK0EthWrxW82yQ z@gM<$1QIlOaCe8`?(XhxFCN_8-QC@TySoQ>cb`7@p8HMJO#h_{n(n>VUhC;c3JMCy zNJy%*>KNF5@|m!^*H0-;^cCKHoUSzbmITQtnD7X|crDpZU6#8~dWChqCofu}BnG4KOb=NMU^!jRLqa(w$4N;GJzwr?=~$y$Y-DY+Io zOx-&_2#=G!qNR1Pulvcz$q|2Q(QlNS`UGDbrr&KKiVmA1+=tIBnQCIE2%~ zC0k>5&vvx5b5^GG#*$+)Gx0tlmtyHXSZk5VU}eRpU(d>P9hNeP&9#TbZe=WH?O@`d z)@8aMS#7ndd@5$aceC6GY$&^RjNtHR2STVg8!LB8a({7fwt2qvyMOjEhQxPC(OCL9 zMy=|mW@iTn38pBgsA*|rrdL?4sH#dChEUu!#B_fyOlF?>ZH5I47TD$`Tj%Hdhq_%Z zo83sb0>nkaQF!#GQ$De%1tB5#EkVc=pwb__A8C`DUoD-jH74isP!@Kx!5h=kMr+W> zJli|cGfIu39V4!G2I7+}mQ$)ss;s4@r8%8XCuo1#RyVB{Q5-m&n9w(+ zTWIobc1MtbIp*iKxY;gfhDOjXNHPxddUSgVReG36XZZ+l15|gSVlC-Y)#~%>6DB$y zM9BxdypszHqzu<%7hP4=jg3IIHM{0&$3^GS&Bue}Xd(}47e7C^v9YoH{i!z~kNkv; zbqPrAT3cG~&zCz44v;EdU!^lR-v0R24KIiCCORI?m^}vD;^SA{etCcTjECa>ZYg-u)sQP$GBzS=0>&g!YK%BUb(XFw(=)Q8*9wt}jU zmRS_Pz|sY%f&x+mKb-T?`HFx(ZQaXi`n&<@t^Mcr;e)AQi^pI%$qpECd-I8%sHNpq zTwc8CE^nRT5^z0FN{SI8>C9HO3GO!UT)BxlyiOgh36+(AdcB5UDtIMp0&Nc{s}|HW z*V2N09c_*N$oNIFKjGo8y`P;45HSNdKsOz%`C@W8-)X5pjcn@3J*lZR`$wok6 z7>Q_V_He~COVo_f^}zT`v_e8(FDcxV6qkH!SzcKQ#F1UcU2F17!c+RL1a)Dj&$@e53+nLIg4u|gi`(oZ9pA#u0nk-jKqyyo-N{fq&V*$fyQC2@T2bxlq zDm=v@tv2WL<+3&ak-gd>E2hAAwJj9T!$5P7;Up3?HO1uB!FLGgnONBG3xU-pKQPem z?fuknZBdf)&8Q^Se!at_3rz$WJ_$uWlvXEnPrt@C0=2e^T_~ms4V?qwLUT0foz3pJ z7m%p3T^uA6F483-4sh*0}E z=8m7r2vixvl%ym|O>N>u!U|aC{?bsb>Kr;UY4_~>;;HH7fC;bXae2EAuqj29g?6Cw z?Ag1C(Zg(jnHK#jVPa%0%FLxA$oLJ%0nLFjHP3>D4wRgh%Y`)BPcSf4IyJRYX}T3i zK>G`Sa|49vX`{yd4-4o&g!hF}Vfvi6g%d$yx{HGb3XDp>xpvTTeI_Wx^FhRB=Kt1Y z;Usg@24XGuC?ar(Apds4{F2}fA z9#LMxbha`tdkCogG1dZkoE5%|PV?Bw0z9U>7S7Gs3U|@9zI4?rL4n8&jLZZXd*$kX za=ZQsLt|uRH9-ttIRBAeK-hY*MW#QIwdG0d@u*sgUi#z8M@KVXQVSD3k}k98vIOI& zhxSV9{786T^_JkPhv&{V?Z?Z7dX48~=6a!I=8vSb(~Sn1?Y%S`FVn4k7PFb=1aBH6 zik#z~p2<#9zk&oMH8nM9X(Sh67!G0y1P2EY-`L35{{4~J5zu778imVBA4aV8}ldtGY(Pnk}YS_I2!dC=%a^=;0EwXNQVPx013=%_ckD86Cqe zu&{XO;a1s|(w1u4)81zD=m{p%yMFiu&`e1C!QA1q(S;)+KNE@p&h45+BcP=0vbV^Qd$J^&#; z6@U{Uej8e=C^B~*8))!$V5Mm3n-;4*vQZO*i(pL#EwAUiajHS`2@K4Y0KFUD>wHq_U-9&gB=$BJ-L>(zC&dVYTX`FVDls>14@{zKbE{XwUSI`;erdRub*F1DnW zW|_)c<@evsqA9Io2ng3tT$p(8omv`dPQ!spRmypEKgz2@LNwPn_qlI=0U8PK*LR1u z=*Evq?U$#dP4RZFx7&2P9bq!EB6(g1dweb~O3E7`pz$|ktG3$mQfyCu=`M9GO3)uC4DDET+(YxR)@O#{pOw^HuE_ew zSY)gM5waC~dwUECw~ezuSGhXwk6){+d4OXv3kV#4I$X+J7ZlUR`Cr+elycOo4V3#W?L_>(pj)zbp#e zx^KSl8zu)l3+XWvtu zV$AmLTCT$z8y|nUOEPMW$3()1Je;X!V32QE2}?4bGF3}**GnVQODBztpJ;7ua0QM- zDEArhL#a+%Q6eiWn>gnw+b~WDh}SGP5Yo{h<@>7$*C*fEk;x{D#R)*+{Rs(Y=D5TA zqce)<+NU(#yCNrDZ9bNehcyB|T3DI*RZVR*x|)QFb9?GJ~1uN)>k|yTLi&zTo*j!R~`C#mP=5tQxASj%PD= z`{5;Cojfw!j5>!{`JnJ`7}|2$ox6*hACEhwewXi;;0?dxm7W77`>i5!a$*(f<ldxI2Vs#xuh%V3pw~QNXt3GjuNh@D$-_&z zBc4atBr6jfboMxD0%qRMn+c0QATQJ zHScPmwdxs>I`0%aKZErl5G9Qol9B|djo-oeSb>FD*eV3?n7c3O_PqfSNSqLq=>Z(A zQh9oV0^D7TS>V;KZ(M%w%{t&0u0j+N!*d2>n59p6C?$K!z{JC|E|v4}cQ!mxYokIL-4%nx=HA94ny7Iy+fN?2(ji(2MLIwer`<~Yw`qqg-J zRGaFV1FIF^^S~Q3NqBJ}6-0>!s`&+#>AbCLwJqT`Fu@^w-5u(TlH3HP#PBo`MArg z*VqfdP`_|;YRr^w(+o@#e08@M4~=Rn3JY_P)63DMX{xT@r5XOCf&@f>Of&ixBz$cG zu)dhl-PSo8f-Yj|t7~?<`c&Iq6O>pUp>cVIjqUWPP~w6p99V?UB&9)_v8?U1b)`|* z*Gb^{hV#vN3K7jswoNrP(&FL-ccDmP^&=xA_m{RV_U#Gp*Vph^0~i=z?UZ6De#6i9 zthECJW=P3!TfR2*CtOavn!jhr%~0h;N&+WJ8EyO*~KnaO1lfS#fe)MKYZo zAagK%5srK_k;y|){+WT$qh~0U`Q+(BG2gu9%iDUblZd^z`Nak|5Ik~!KHG8xWV;kW zby+Cxd8jE(1Vx>%wTQ^%zc^bJgu9$9Cj~YrzNb1M)-ucl1V}@`U?gpsVo*genoVsK zY7Lf`OTHPH^(qVSqhFcjq%;&MCZ4g>?O z{fM}=C&TjidT%|r^ThLg*h3=i8^Mq42t%z3M?_|d(a~MUQ(r8M%#V#sZBpYNx(=bD2s+Yis}fR{fCJMNuf{XfTgPrDeZ`S z!4I?PfZO>4dnKiW+(wujClKu7S#PS;X*}Q5+4Ou7 zIu=3T1sRM!?|HvIJ5loD!<^$$P*O0h3R}^ZHb6jNm_EO@f!1F!buhh#$<3JNxZEhN z>n6)QSu--Po2)fwa}=72J{|&f*$tOepO4_xxHht52CC)Ij;Vyx*+9{OOlU%zNws;I!lR`<`{i5RHSMn`H- zb1%tjxTHjJ0uVflcgoQE+6*!1UczGa#{`P*ZIaYu@-myPKzcaosoSF_P~#)UN@Z0O zFk>Vs*PCm%!Y2--F#WQetyG9$BsEVEfFGZ2Bbg*pLn@BYRi^~jU=kWCGA@U{p5E1A zc~Ix$tHHB{zJ9C2VkTD7Z-xeSek>@=cUM|EMrH$H0nIwp8ks2(r1MpNAqvH9V8%!p zup|QSEt|J(bvh9z6xEZPekwNYz6N}Js&tw{;cx0>cptBVsx+Qm$w)Pq8{9XS=!pPi zPp9r#hT`V!1vv(S`DE+U(6|VG$Iih?Ty%1?!{GTDr!&wCIUmn$Es|``MtufuvC(Q> z?CvXm79Ri;=3aDtWBN%&LgF;KZv~ne813HZ79-@fD}I>%T5i+T-MY(Ft7w%!Z$rmE z>zG|ef77DHd~b9fK)bt(q?%yZdpusb?kv^+VfApMCvhL&_FmsnV_7)1(+F!(Tx_9q6nqRpF0?uw!j z;+l_#2Zq)aE&!za9oTn=}9lv zm+5kLT2(dm_m{=(kR3!2S0cLf`bv1FcuwRWzc-tCRCBsH%VrWGaXHpTdkj?4nuCh< z;Ed-;zkhV1+lqZ#%@Xu76YfuSHr_idW+lU$-ghy0v`n&YrzKASejV>E)T#BtaUL!q zn9A#=)#sQ%vCZiGyv)X0>zli%?$UW!30Sm1zux z-G!jT;o#izZX0?Ww+{b6sd(YQ_KZJ_FO$BU^Z?)v$#XV(!I>31`*Ezw~)QfFbOA%XJo(%l5(LdRxh7H`=8drwkN_ zUyyeg)Ld@g6< zod+FAJkNfk&g6qE%S$W}z|kFmxUD-)Y6=IC6|?i2seFUDgv4Ze#PjJ*l^98mf{y3g z+geN1-PvlI;@_JC10L;1=q55qGx`jU#-!0b^mUgmYFLKv%H_Em4X@~8i3r8sY`wV zQ-B2+gHZ(>_Ltu?w$mBzg!t%gus`v(xxWbW*Uio*w=BrqdxVf&IOc5L=EU-PUaRWb z2507G>xw<0I+N^ln{(s=D?+LFtRD8yx^&RJm3Aht%ahKB=k+q7UMRR$@nmLR(ct1h z)c5=Qv`I>d&u=WF$INM)pa;f6JiQ5!EywpqJq7)@LfqT3>F;LXHy^AARo)BUAAZMh z9zFFUYJU87>%0y#fl{1U_4QGBQCyCXebqT{sG7xo`LAWZ0R|9#x_pkHfJvT6;GM=_v1R7_UqG> zx@o&BnDKbbXB0E0NiJqeX6g+1h1nBN z??99c`6-I~YODeg=y9>(x^JSr0>Z>(7|Ix@gQB=%ww{Q2TnpN&N4=}HSX zD`i3fGS72)Ny>69iH>yU`%*wy>7|sERMN*iwbNn>GLMpW<;6~5EJMz{%*<}>*D?#G zIz`%iMz70h)>!SlvQAM_i@gKEd+SOXM7fDTBC}zEp77kwd3Y_WJfvO|8DC6Q6*}fe`E~9=gSVtO39J5>&3V$P2EGWAYQ`DA=WU#G1 z9-sfHWc8=>&PvWv_H;Q>Qc8>hn{Wx>y+!(fgPp5`oG!KxfZ3t!!Xh&?vV*Bj{OV|- zp?BKg4vTMQ$Zf_yW{nDv$jBCB91Zr9z&gYO^C<)p-V6^}5+xSP!oqKzVO5oHWeD1$ zvKH$rGN_nO$Ln>J3MWVsUM~{gSR5oWSI|(3$SZdSWn3;QS5Qu?5-bM8@kWGjD$%EW zyvK@dGj;KTqc_QnH)SB8#NZ4DKcfNAQ~y>T88o*jj=C4WZ#KUvH6IWN-|TuF8!JDj z^JM$?2nEy0UK~pXhE_0>mO=~`1Z4@h4P&nP9qQ=Z382iZzWi zh&1o0>K6jS%~{&J<<>a`4U?E4>gpy-=f}|l(%En6tQK-%%}x(yx*?s@?DF!{uqrRj zc2m7UBr6%AOoN6TMKzGp8#{ER)zxVjLQ2RAi;b`TMf;v?4c+`fxDxZr4RV(JUM3HA zh0^X!fH6Y+kfDBz+$_CJ`xMpAHkzjg7gX1)rJY<&7O0LcXYuk2snjla-)lPk-gGx{QG=&>d1t~w8oDQDH)1u3*9jtAI zD3|noDxoY9$oBAMN!Di#!+YFDQVC zF5_`mNwtl{MQCVfSQ09e%-;S!KCfNshjP`j{kaEq=TY}uuhs)b8@Wcy5`Rd$L%Dln z?*248t!9h*O_8+Op)`^6`NqmXDgtFsC`GN#(_G2tl7hzU>gd(D5kaEkjkiI3 zc4v7Uh7uOyT3PvFZjv-q8MSPFhJfgV1Sx`O%n)I|n%U?y`JNl;X}Gp0*qrI**Vi63 zWT^uqfdFBCvDiKWPxJ1!EI7NX-3A1>cboOZsSTo*RN<0sAt^xZ3V}6`@B)A3adpV! z`e1~b>#N&VeY=!kBf`qJhZfQ*zUDFz=g zDTj)My1e;LolYntQlZwSbV#en56C&nLC6uI%AVN+lZ&gDx+RgMk=Q5>1er})Q&ZB@ z)0l1qMZ`r{joowOA*oC@(gKY8vRl#L#8FX0K(|DYN1VI0jR@)u&U&cMN9YYu=YgN+ z=!&@yk1r(WsFJ8ZL{5`xjVtM1%!cj9wFR#gY_oZ*G_kSE)Q~6VBr}y+H9K+_CM3$6 ze+?&;gJ$?NS^(7`n2-6TOwM%GQHjdgwe)hJ5IzMI;rFEf0GLi+L_}T=lO>Fd zjGi;7pRQ(87)co*lbQ60H$7Svf*L(wDV9k?Zqc#aUCxW2f1WW;b`6_wO_SH&UfPn~ zRCnvCRB0d75l7-hQS@)(bSPZ1l8b+vBij{JUZp<0&$dh%P*nf+f$ z2$(XZQAwLS=nzHHiMeIJU)S#K;oBXTSHoBV{$rw4uoW{%uJf0N*9h>3R8au}f0+q= z+i;k&S>GOSDeV$UdOn<>RhpA)Q0)2P3XlH=2-n1^S;|;Nt!v|DIbAgAD5ni117?rn zgREIyocfP^-K3P9gX`n{(O_=8+q03yTrDJfa;C@m1J{lG<}b7AC8QVPs?-G zGd>>>81uUta2&08dxVWEA&Y`dl;l<{)N?Zj6~3#QmP-p7!7H3#j?@z(F_KVcgz1wJ zN-M00l787gjXu=};2QZDsLCX>Tq-5_b8-t^z2Lm;+vwcg!bZ%X0mT3t zp?egRB8m6{V9KoB%F;r+9v#(5cSSw@$&~pS?ss|-{>;%&sOK2|x)E0b)305}A#9jy zYb-x~^e@)y%BEU}sEWOsBCuKIR~q5ym^&I`Bt_%1mo>&6lQ4I+M%6*65&?UB6t(-9{&Uh?rham~@^TN7)Kh zNS*`*YH!fqZrE-ShmCt*7ugUd_4T?(ayOy0XR#IfYn^9%A0d(r#{DtF7x@$U@KhrH zA|lA7(9b2cfjg0>?j)r9JtQrfc<4*V?VyYw2R;3dWCtA>D-8y!n|O{(JjBuO!h@RS zN<)g%y)Z#n!2iD@cD1$nWw*`Gj#Uw}^`7nECLz2Qveg*V*c{Gv%4dUzxf{#>+n9y@-}Me@y7k4=A~=64iY@VxGdeLPhNv_kGy)2muw z$HpUs1m>E+e8HzfKt(l!%IOe^jc0KlqeBJ#T+VUQdLJkvI#O|9`bS@bNvv^u&daks zrzX#o+LOrK0S7EWSjrkv9Jg*fiWKZUK8t{wFVy}!-ziTAc?Ko>jJL9Ryb zfOgF7)@xh=g>2H}X?$`n3eWqNC)ORcLF$|lil<*pb&Z0LgtR>9YaW#n&GVKELp#F< zxiYV#lU|{9TuMqQbKM-+BS@Y*k|cV^Vll2|6WERsl}uvdfij2&5no|d|J`ueQDJsT zH#Z34;_;JQ52PV%Oh}kn%*@Q5JM(TCoB{1`8wcfym*b{^h-Wf8!dT0J&PP9}{GOld zT!yF?>^8i1+&cZEOE59uMv=`f#RyDcr0=_^pJLOX1HvF2?H&JehQ+yr%AE>{f+5Et zH@b`5ycep}KYzqrLPODD$+d^v2Cjt^lhk{IEcsr1z5dR(# zm3?`IYHw3HY7%cj;;$g}@vWK3My;2A&dx9d-(OHUEd34T2yY2PU0y>nPNw){m>FXF zm`U?zyAe&8NQavz0PQGgv_Ku|LgZ|2y%AloSvHCtfjWGHfOcE4B+BvuO-Nd{d7wj7U#e-@#G7h z2)?3xh#T(!%9{V_>}V6H*x8xSuM?`eTun|Ixp`^d7)e27<-Zx8sa|-yDr@whNkM-#Awm>I(D3 z>Q9?5t{Ny@vPX%Q0#e(H-F%4Q}~IsW;3H2ZDB3JuujE%oGR0gBhf&F5rH2%+^7L5-ZmlIS}GTlDx$aW1dd+cH|- zx9&DtMyH%B*CW~^+_kVToNZ^C?T$}zlNjS4o9Q$eE3~ir)5{L@U%!5JIu{Xec174_ zf3sP~pfEHyn;R?sxzeaqA(n4n_}ck!FR_jB6P9ld)>9o6Qw4OTGUw1%5E$HJ-jrRQfY%n@XenZIc>q&1#y6FTku`gZ~g_s!_&sLI-0 zo*mGMgG)vJ|5;>}v0HvKtPOP}JC2OsZD zZ+Vc(%93hEa5Jt#fH5~yhi_vjD?Gpr-nCEJ7f{|FcALcIss2#xgHz`HuT|0DcnBQa zKiY!-(NAGW39hi-np7A?ZtSuz|btQQ4@k zU$3B``zyfsb!%b&AB*-IKqytQlFTviC7>g;>3CVTQhkHM3ckK(&?=e=!HQpXGZ$m&^GXlQ_+4BVa6)EtO8**mys+#SGMi)|}MB|6iL5E>w9fSEERr)U6@F$J0FGpLN>6n(x`Ivzx3NQ-?)ACV^rByl_L_pt~l%%4p2)iE|DsG+Km5|VoX|MoDG=fYfQIKBl@MTM>!lI&ff~?Q2 zCAk|)v#YbER-GlOjRTNzb7&UQRMj-D-l}1ckT4sk?CtFVTfToTALGx6GS{`SW~bS7 zO~t*k&_1LvcM!)2`NDff1>cs40G2kKlPUHW+n!{ z3puMu1Cgh>xw+$QOYC;+Yx`^Y=@o#GDeQ7-Sqa!`;K0tzO}&$+2JEyyV4H zYXRJQEMZdW$_uL5rd`Veu9>m7_jlg#}FG zQwCc2b=|B@;L(4Pxp4kRfG89g=?VxmKKr!l|9|q8!u@^YpiLjG%yxdnrNt*DOjp&` z;?#-p#Rb7|FrEhz0)HulqbY*pa~AjO$}va6e@gc&Jb@0` z<5mytXIr(a#n8>kOrG)oz96t{J3a%(=af`(bPN{2Rj4K8ccArWfLHJ4rUor0HPX|w z_PcflRhbufQ>X)0*mr};)JJ_+dABMwRcdBLC6s`F)BpO7UVvc#d9$XVTv1KA)F3AG zoR5O!1JZUdn*NPa0n3XWfkVz<&$&J#P@}_85}cBi%w#dr>VF0F+}dzOWZFZw&&b%u3E@Y|hUocWX~y(ztl9|geMj7SJH!$y3* zWBh-6Pz0WDvz)C9IMsSgNawH(3rN*)hya&Q8kTtsn5y}d9q@y~8TB@7 z=IZ}E!N102@q@B4P}cSlky3wum_MjM_Dh44^b!?1_`fq~+L*ZA&rrd%1qwMhoL^SIZ(Ixm|NVtNd06TL zf@-*_N*br!xS!-kO})8Ki2i+-Q<|5~EI!!&ez0r+5BT59Rv-3%3k}RiA?^`sfWpG! zyN`pdol{xmPlnH0I#P;#l~v513VEyZjyAAs08&>X>zRdwIXR_()IT63LrSpXBIGpV4wSh{Ew4?SA95 zlHz+Q`^esMCbiuqBbAY8lw`u%tPsiCpMZ-{wi&568+ZK1GH7R_RK){{uYRexuQ!jv_S~}AuU~_P*G`={!3sAbEyMLTlMJW8&Fy&(P#mvkVyCKu2aM>-usXVa zwoRmRS1IT(3a1AjLfkIJP0r6RY`BtcE%MaOS3CLc?2yT1DamUt)j!QX$ zhuho-@6Z5%Hocc_xlnpIP$tvWeWLtP>$H;!A}fRt>;f0$1-Xa`xsh8aUC??)tS?c# zJ&rTLRQR7u6-j2@_1AuExV{$&IR&36Dl4Pnppu>{v=T&yL>%ZOXuy2o!FY1ZKpv9jg+L5pBnk{O{Y3Gl>BtG@jC zeIFQ9Kx3TcZg55T%;vhZ^e3CH44f)^wGZa2(BXvfaM>h0{@a`1H@>ulr2==ajfCdN z4CIT={&1m~Cxk5Wu}SymtC!>}N&Ay>cYB(R@S@1(N2mhv;pF1{{BJdZFgcbx=Ud(B zV0%{k9;Ft*+o4QWU}*c}t6(?rDye9$#P3A|3Fedd8w{gfkRpNMYz~g6-DT03=L?Eh z!E9Gsn|rZh>E5QdoT_brcRJJAy%%JV*W)Iu|ABN*JX5;8=>@Wmw|=7sNRip>`0UjD zu9DS^FUMBxb{pH5pP=6M{ci?lU_ii>0s|JK&AX0t7RQ3iAK4a7uPsf|Dh~dr>C#e) z--11+&YgVP`sn7rFPAH<$*UlRAbVyc7o&w|AUSxztH?;gi|Bp32}F=D0Mm4ZU1DWF#W~ZefXu8hO*`&}v%4oJa=2$#zBstIoiu{^xlA!_hUpLcneg>K%$*hC4Gx3qt96glf zgF1A3Xj-o^$xbrvJO64)^~ow8&m^ymK+ZlV)O!XQ`Pq(Pg;?4wq|5GJVT87&V^IzE zzS#No@uZZbthDH*0I$^h=4wv=49fhXqrNs5%cF%3%rmOcHMo=y(-GgLrN~0|^lKKQ z#?le{RH_q8tUCTjYVo*>&R5rox2P%cndH9w^VdH8)-*}7MlR~9p-mMJ8|I8Bn-rz- zFU};08v7huy7b(HhfSs~qlWgZF35GSmMMGwB$t~7g9NXJkAHuYMHS%SFj&^_nWZyw zpG|gN#1QljzISeG=!GA3?!yTfOyp_M^RyePlg%tM&-Wpp7yVhMhWLYKW@en()5zepNK z&v|+BLzxocCLk@7{t$u;$JFDbQnS;PBP^qj^<`m#mZ5FA6Iz-UvE!%4I!Ym#$@@tn z0=rgXQ`t z{VJ<^k2NZiWSN5czC&3PVvqW?oAGL)Q;*edWQ8~U18>?wMLL(~LSlr)6Jqj?g*Aw~ zp}iqnB3#Y*%e_s<13^!XapH+7Xe*S~61{6q-Pm;$#{xuCphQ7UQ`;VWWmUgsy9I%Q zj${4-mXpBiwX3V@8o%>31^mzVA3o4$h*}6Y_Oz4f%s~Q*0{xV&9uqAe)3_S%YqfSx zRXl!$6YLFyng7EAvMp9QZQeE!l+(VDI-b)=vfo6yA8zK6zxdl6(RlP7hP0#f?V1gH z7#8(a3JeFqQ!_+~l+07ihDhb9 zoT}TJoRxlkHHhMYd>pS=;>ciOWetK*RaDNW&b2Dygbam-r4(jGbW9>$OPEQW)xwk! z^eW>IF;JfNJ0Cl&42bB>+(QzXw_nZ1UBG9}h+S<0Xx=&TmRTSCIY2bgnD!&Vflq7HWO(Pw>718347uwA1 zwV{5hvWE`rmFKJw5Sa6RphKG~3`t$Ze5+CTJv?udIU{DF`}n<9GqqaZgVLX&VlUp2 zqn3;2rwRO%zj02+kYzFJhsFe0hqI=N9cFjc*mb9 z#$cn2erok|F_xPUMM;6$@lqG8k}m#7!^;bBnyO-*RTX$eiR^K8W0O5ddlGdZn7^Mm zyXd&@cW-*=c%PD~m+J{K_d3##0@E@K4>eZ!2>J}1#LFJ+6PpkVSJT`{f~4(ksWZ3_ z`G53>m~!F5&MPTB4cwMjR5;s?SDZ(J7$F^emT`Mnbv%CTa`5;rr-=M8bj=iZIN&yB zuQJ=6s2*HjOKCtzSx!yXCWO96{*tr84C%uHZA0Mid>B;4n*%!+7luKrea-(XKL-L@ zEBQ#Lm0mwE`WHya$w*f=xnh~zv0qS~$w*BMVA(5H=TPEz)o8p7!t?Mw;J0i3dQf#l zmU5vGIN@qlO-#bLabu>KA8?{Ps+Dq>CW+fjQk~c!uhH=EAf%PJiA|#`AgA~|WMr@1 zS1Vohp?h@V$SD-n@-z1rD_`M`j+e8ZkkEI0eiggc=^X6ai>~M7%3JiE>=;MNeKV?- z>2c8W(GHW>9_{AU(bF4R)vyrS>}4Xa%4}WvpTA$!(MeFKDc)}3$|!|G1lt5f1y^iC zeO_(WD{}&Fpz`71Z|nn-W4=@L$@>g1^8Pt)uSdEgjzJ+|SjSSAGMv3VAW>b(>1k5@ zQjl=)68XN@l%oid<6S~GKvr2cFIRzkvf$9`^cIuQMW6M3U31x{dWkF{)qg`8FLM8lN{YB*! zmCv35Ib8(eXQ`#)oo0zd75iWIFNLp+&evMI9T_&hBIwBQ(4To`8c>t581V+J3W#0Z z6*JWN_Z$Xb) zULW|x`^7jBw?mK7$pZBI0wbP>rYFbi-2**%V-m-6V^FOWd;Ov%_ffd`&emJe<>#u7=;!PNL+PJ4*oQpFU!FZS478r0Vn>Hcq5OiFBg;z-Af3G9nR!|>5P`1IAl%onE zL$TSNU=20SH)3%dKk1k@XR6D}1J_`cGxq;H8QvB?QSV5r$3hF#w$MDCE#wqS+#%=l zU{%jgup~$%D3CslFwE82p47m`yYpes#IC7 zw-1qgqVm)H{`{ca885E-`uC_XCG#1c_0~C84#MjO7Y&;ipwPk_BqSv)k;BX)rxX&9 z1iZcAm6`QVTYcev%{MUxOl+-}wf$H`3Y6(TO)>JV=l~~rf>GR;m3yGyn?@?g9jzhy zG@dD=uEn}?LEF)&_&6kiRj7dVI|{y+(Ss9M&3G=1*hJ`9M+b)+Dx#`&^DI)|pPe@9 zgT8AtB!8v$=OWMcld-D8b}CIoT=N~i>pSH!e&#{(UCM-aE@3O9mUZTU*d~v5-fLxVyKXUzC}xxILJck+?IqGVH$?Y>0R;)KIA1^UT)CG)jKt zVdSj&`1qW5_Jb2E<|9BNXJx?Xw{#JgQi<;A*$!EF(Ym3!-g0~fqaU#L_GD=9wBvD? zQIs+DS(5gk_k`CTzyHCQy{m8kwZgG5R_OR}Svz(RPjx?u-A>BPt)2U2Y2dDGV3Q#u z@Wd0$pk-gmiQDP&;B@WRGT~ZK^0>r_+C|BH?3+aXQB&bE4A=@GRCP9Y-Zy1iQ`LjY z^&5w(DbHSan=bR`ig^>C!Yb0;v-@$U>>~v#|Ix*tzyJ#h@d%$*p?CPHsJ9F_1cxMxA zWHkiJwiNNgr%t|iEuSs7bqQ?glieLI)S=kO=6XsMfQ;Kw+EewyQz9-LM}+ECMOw{S z)?J*K8xY68HNuh$o(R&5XnRh2nFcQSt_0+FGcpK2!GZ8B^@~$&ZEeReHT`y|fqt^*M=i{R7X`K|xDFYlXsc{Q%(oO9+|XYWt!ZDR+-p_Y7U>~jgVj->bab`z4@QZv7X z9`C1z)9<=|QU3Z1j|+peIVOf(E@AB0o>(|(DC6>VhVs=>T)6%+o~4{T;3GHAU?x)bd$`OpDX65lHGB5F%11s^zuuFrFKX`vKUz+x1-|S4 zSL>3uVK7c4D?Vqmwcj+cOLWPK7Tj4nEjDk(>DWE-i#S{llzvHea21HANm<#txJ|c3 zf7g;hrriikqxWTM-yIke;@IbkyujtmY@%;aa7%exzReId=?#<(aP=MiDgW)08S&!R zua}uWdrocpUn5mNE&BX)UvVhkIzjF_>#}WwJZS0#qV=vxyJ}N0)s&tX7k}+|>LuB1 z+uR;YAlGfCp3dg{!;5>MqujWby68%a;}|K6!B82gM&kw$duA@^c(gb`(TbB)a#HoY zd?HMmkaHYRvwi^CcbeUio8IWEuD)9LB-@xPP^qO}beUy#Z>jp2QB&;vk?(`0`&4ud zZCD8AUe25WB8nK!RXu^IEP5MlYfJw~u`bHUvN=r1hG>bes!kBKe@Vm=akoVEqlg&F)Z%Tybm4NupJ!Y^+e?$$ly zRpRBu?A|+zWkc{MH&(!9|rF@nM1r^;AD`4%C>1w0=FFz19BDuZ-CBC2G_dKb zl=J4t;Hk=<@JN=F7WX2&W04%rQrQ;fRW=*R@O|5=srSexJ7icXi7L zxARsxm>j0z>;0zB4aBv=*=y#(&z`8s;V1l*CSk5%remDwe;KD2~`)p5s$m7?t9SWBh;r33QXP{J(h*aisssdm*J0{l~!|A^jf5`pfS8 zxk%xEBn$BQJvZ>g|Ni|bruZLOhNOh?A4~K9!7buAkj$g0u~XESDK+c+*HJ?iSYzJZ z{w$j?uO>>6D^_QKa`*AUGzL@sb(d+~PO(BI5@@bj4>DUnzw-7z2;#co;VL+N5DJsX z84cwsgL+`!azKu4a;2pPhS>Q9=-)ZTAAnw}BJIe$lvT15ykgA@(L^w8~U(jFDbpE5nsH}0nd>FuF9bKHV)qi}U zpz^lex%rFU<>=nrF0C~gCCG`T;TMRxoBvHjE~96dx5|-JUe3eLx##2neP|~(iew)( zcBK~csChiD|EN_>DahQ1;g>~B>*r-KUYDgwhJLv*56x;T=SPv0`L2F8Ey@JY8-+ZL zzmkPduA)V$9{>;Z2Vm2T4Apx*ulKs1&;S?jK=^)$I^Y}AFk?K(h?f4SsJAqp$O&fd zt{~BLv%_5abdsxE^S$=lZ|tT9l%HxfC1vl~(%J)YQ$GebT9oxQroO|4{H12ixz2z~ z`(A~(s?>X`YpQQK!wj@TCqGXHPWA{>7l?AN;+En1qcJk|g7RSL+yb67i84Nq+x6xJ z|6@Oq9x;D%_0QF`#Ow0jN#@Ks2SK?J!AjXAk%q-PmZ;_F;yApw&Jab=frniiR2?9q{0+e`*OM`NLbCB}S`~zVK5m@h=i9fkO*77$gTPJKeTM3Hd<)U-y^9&%PH! zLd(X8llh39GC#@x-0yxnE?W31X-0;q%5cyPsK;5s*B`IbZ9R8%>K}4g$%lq9!l7+E z>e;u(YE(RM!c;sU$(;Cw=%`GLHl~lv`^*l9Zi#4#;rMX)fxIbn`@FH8N&CNB#d3VQ zFd4WizJK=e{;17PJw9nnn$2!W`r%|R=f0`VT6Zu6IY8_xo+0D{aa2P=g7b<{5MYip z%XNLZOvoQfG_yqWx))Anq~$H9ofF&ro1+)?+LH!?q$P$8t|FS6Lbmxzb?*BoBdyGT zmo=Q?#5J;cJq-5q&J^GdPfl7TV$hC)2`O z$S73rqbOI(Idceqp^IgFgZt{=on@^Qqix8$5=4W++j|Y}H`&|0|fVdHPsuWRZlgBJHu( z{WJ9ZFL*xRKJSz;5*5%-+y(h5D+?ZXuSo7eKI|SB>U$sVYwokD@bwjDd zxFis5ZP8UW(=45nohmLzAe7|#z9hfTArB}HZmzAid zB?+^UevNq2n}7s2TeZ0D&h=V4%lr2D`2*_NWz+sp$oAY*%q6D>!KyV!ZC_E4t-f!D zYK`fjso|o5-wieO`y+z~#D~84%64XNZ(VCHjJwvIVNHF%o*hT)iPJF)E{=xqb$75{ zr2eJ~b(9hKQmA5NaBvkKy?AnT=4m-<^a`h??u@&ipj@9@pimJ6*>+C3X&31w>LNW8GMF(gk2nfXOz#)rCRP~SF-tM+^>%I zo?$wporJ}7+l9a+^hSU%iSTpP3+O##y=cs&PDoONc@-EFcK2$D)_AELC=MOmJn=px>LuBD z9nf;}BFR_^Iw5C*+J6i-3BnCDJjWSq@cUd?$Rk-k&Im44(sSm!PwHPB9B#4ZEtV?= zx*Yuex@>$cEjN92)md6)(caTn5>`mwW_OIHJk|pwt=Csdp?W-JICa0#5a%g zMEu?Ox>G9!EzGRZmSb`ZsFIqOxQX`ag<(e&m|C`rggX z?|A|C0{11w!>1q0LRY{L2cwg7I`qK~+wLJ6rl~MOg}e~lkX%wx<15W-gI2_up6LJ! zLDeuyRl0z0^3-(h@4Tjv=aQ-B(We=i2`N9VT+T_~1|kH#KVTZX+~;;>X_ft{wrCV% zdU=WYy~c=ZP&2EQNx_2mb{5POhKh0cabUQqT{B=tnJA{H`c25+xTIR`51N8=h!Rfd z|8m*GNVXtQ^UhgUKAmgFz^yVIFNtE?G*i+ddZr3iLO^5qKsF zrEs?GN=qI!3TkjK4P4QV7QDU-BX2FbtgE(6(4qw3?g^9uSb4 zU9z^7-@r=`5>n&|%8SZaMs^%aV`Zp`YQ`L!(+cgt9+me=SgL1?T+AmO4+!~ub=5P= zy+8}V-3yU*$jQ*A&*0>QTNtS96$5A9+&fs4?`O@qU3TMLfhrIA@bGa<@eEq{&^fpS zT9aM^Em62VAy7#5B3q=tq?+ypyt0->!stdW~D}%Pz@lp=bWqC z+kmJ?nx0IKKge}A04;NE)dNPK*<@~Z9E1D$1_6yGMR7P`eIRH%qGtIV?9pS%kurY? zp*=f0b98IEvFs;r)9$_Rj0okRP|P#C9!}50q?eiw zTV`>1{TK{QP5FYV-K(KXKcETUwxF+!X(5vXjp=bMW|x!4ai-&Qnc+O_s~LpHZSmq> z9$$@yl{zf7q!j2Y91q2nj||Bkj9#itO~_D33WP;x$zY(o)IF-mxum(_;h>lJlY%{}us2%OEl(2%TPHIK5u?edplB7pRmeN_PSDIEO~E`K35g=sCK*|6u{M9!u#AKvX_@n0dPuXBY7Jj@SFrJRVUc!StbQz`ac>&hG;U&?u+S*+e%#{dNy4$xcj-nL3_l{Z&^D=3L23@~ES z^iJ}=Y?f8CBUlvcjR5E43thMWk?@?B>D-4~L|atvhM<%8FNxK=PM}g?9$f^OR%P)y z1ePbv^rPCmqreTdWCGx^KYt?pG+|0aI{K;uNa+D}S$;ohjI-vadN?KaZjOQn%|q^O z=`SR-g%q3-8Co}>Bf}2kWjFm~X-h*Lx&*ig(Ly_jgHQ+Z9 znQXAu7qtA@aXIfd%-o>c9YI>>cfIdeHT4oQWCU*MU&bwCO<0%Y%b1*W+$mwwU1&jf z**){zm~W@b-DLCbzK4*50V&_g?=4f~c_V>X z>HU#B6l)nyJlAbBG(m&aANe0RLau{4&Bs%v+M+5NWWPzM#vZEpP=*=sT6rm&tr6gA zgCN-;roYLY$lRI?j#zUL)@<6QzDHFG;=V`tVWItjuZ)^ahc*tB{)Lwu!US|!+0#0c zqfUGx_5SRc)NjGo1YBLQGt_^^Vpb54vTphlX+=UmchxPhQKusEN@2!I;>$aI$v_r5 zcgzPy<-xRj7y*)b7YH3pWdogBHO0>yT@~f;1s+LTegLqLA%Meg7Cq2M94z|QfG48b zk}6WZ&|vepU6!1z?1VkbGNg74Qi4tHx=_YU?|7luIihM}DlcV^<@Q7HcK-I(5lIWF z!+JdLOb=04)7v1%VohKG5)ln3+=A5ZkxPPD;Ll)v6;>0ECA_r992Tc}%UHBqX7hbn0>3ofoO?#90THj%7 z=U{uEoH0>`Q63H27cSuaSitA8g}0=IsEbEsh;nwJ@~35ESzi}P6rc5uO5|`q`!zcKyg(ki`}Rytj-kMiUxK9PJ+7@+jMN z^!TSYrpg_D0xDEL_?)4j^E3;Lju3#Oz88$~ylwAVh!eu!G*F+=xP2$Zr6eiWrF-ij!=p2Sq_*63=FLy0_(Xn0KgCu z?8(14pt&n$jKskT|+yXq= zPF2}CUyoENW_UOaBq)4-BCn)W1ggRDY4X#*&&5U6qR$q?M6KE|{l0W!`%DTw!lvd$ zPz8N1or}Xn2^g1D1i7p>{GgP=a?5O4DKW`wN|c~w#v_#9I2zKD08+L9 zzPpA>FzFfJ#}_K24oF5A*d{I2OS^yrg9j~ifaOiKmHWW&>|Vqog8fXOv!88j=nOBP zV4F3!`AQ7Yg{=Ag5^pnOti)<2ax^?y_kdBY{ugc;MY!u-dI3m5~XNEk5dN zY;2r`gi%jU%$uj2JtMRX52Nv=0D<#^Y9`i8O+s_yx)YOdIgvJh?{6B|GYr0UzUS8I zEE5)-ZO+vp&lQ)D zI%7j7rq6kCFJCAlSDxB8)=11RT-$$UH>>U#Ol^5`{}KrarbJzk9n!AS^}?l`qWadJX^T%Ajsi-D`43RdpO_U-u5IFMpT9i$Wt>a6cieP*RA ztz1LJydi#%$RBDs)IVQG2O*Oej;tYaMypx-Amddo@dr0sp=pKW3omguO?Xx;KJqI) z6v)wR%I4C}9|90Nb;N=er$jkP=Nz_bu0;m(r!KTHZZLS@`n6+{lBSyW`p!0h_@z}y zEU0iaFu`|c-Oj>Bp2^V%(zr@gx`$1R<|=r6qB6Sl1J4D0J(!+@6h zs^z!IGID1xWO34g@-F!Supcun*$HM`)BD+%XS50rR>ioCZpZc?JvWterS{wa zQi0JZ=5_x3v(eo%qZlVVczW9#7V~Rt?jFttb;>4LMqwN8f@A4G4dW9X#@+;wQ}5<6rI?8$|EELsXJTl9fo0;CxbR-+g?24{Oe7Q;lN z=m;-pV^5&mQOtiAFG;%eXQrGxDbE%bMLdmjd0%a^$)G`6C2ZuVTeaJ3f~Qo%UMZMM zP3bG|j328Q+quss4xIKnjR+}v+1C{DX6c4Xjv^nj*K6y_bmB0M)!?KbyOkIhK462sE2Q$-EbIsm zaLiS_%HyM<_HEsxg2%**#~#*ObqxzIx{uBLnXr*4kN_ngSNow!L5eB?(`5 z>gSNA+pU;@2d$>inm2H+kG+-l$bS-i+BenEG_x-OI9b!D4v@Y&wZn&nLC!DS=}poV zelk=3>9|$Ljt$WIR=1v`dSwtO$HF4ZNXm?3ER7qR%X~|vio8V>H$m&fFC6A;!u@+f zz0(MI84Fn>CHUMGo92Tgo*E-o8$u%jqGxW8GE1iHg$-`((+ z$`X2Zeb+l4{|>{=`7R#bD_^ZceI1^>OJAK!n zVA=>eYhp~`V`f%>=HSBp9`>iaeau0vt-h|7VHP!zlyG8bHFkv4+xx-f+FqOzq7=o| zgM;HvgDfFWuAr&ds!}7<+UOfh5^AoFH58Yl9|#2UGt+N{0A?E!+wS}vrC3u}{cL?R z3uqRvbzn<@VUg>M*+};k#tG>%%5{`g!TMziJy^j??(<*604pe23^80|Ht<@*nFOzo+A@+W7E>)4O7(=IUm+fhF4aM%(F`xZvao6-Ff36SNB3kMjiXN z2D17~pk+*y^ByiSHi=AJhQdtq;g6W>XvD%$G@^A!+0+^;^MG(V)+ybdE)O*6|6_Cf zW1(xlr`?bFOJn)DpflLETUnzRjJg|Y>c3Btb&!IaM3D)b0L~EpS_H3aJJ)O#V}fND zrU8lK44XF-m&ICJZ*2?w8xVWKeit-!lQEH$JzR>F)h& zzW2|4kGFfk-~_;d(c!cx9({ES2oFo*_q)Kurgay1_rE~vS->cx9; zys0L(de27ABn-@af{UEAY2hc(2bGa;#qa@2Zh_>J6SQGqDJ(tw5buzR09c3@8J_N% zY69LW>RPXtiq$0C*L36&lABbiU2H$>7ji>`VoZgl+b9DqhzLU69GuWzV&vnkw!9f_ zt0uZ*>R)1EV&TScQb^^n*}Q;NBif~o-(pFY(Rr9;0!K%XE*zUlkO>)EnV1d^TyJw4H-$~)+u0= zNs}N*3Rds~=V`^ft{x*3)c1N&MPu!_;EYon_ruC(MpRBbJbX1IrZ*#5&nwJDV3WFy z$>OJ|Xe7d}Pb52C4`!wN*Em%L!h0%8bIEf}3JS9F$#V@;O0`i9M1STePy?2xuyEz~ zX)%p!;Ewa8zB|si!<-c^wiHcGFpI~zkSTN6sSG}6Vx`$YV@T2jtTx)p%w0j$oK8ko zG)*Dq#q6E`-Mq)?!*|mOM|edLp`2`(5g^9tNgeMmM-)oe4XsLJR-u0Ym4+eqCwq>v zeP%))e2tcof%?{2e&=wfVId)lmDi{rMs*pam4$AmHd8tjU+|K3K<>uixS{U%k#5>( zxgSY{Eu;XfS<)$R;2PjoE3NpyJbOt#Ego%w6We%fLGQV~aj*>7pB^!zjuU154%?W2 zkn!9>L2Vd&Voaw{b4L+o160*Gi|h(FXYHHz{#EVgVQsY?o8++<`|=T=>vs-}oK1k& z8Whuf%xB5hNpp0L>-dr-M_iY#pQ@Lu@Yp6^f46dIr+n_0OVsbDvW@Hb-A9hk{TQ2p zV+WPI$9ZdH1fNcQ57DoS2UwMeXfH@vassJDOeMOU$?~sp5>?7J6}yfk#Nf2*-19v79Ctnt^5iH)$x39 zAx%j2bvPm)+gDN1MdBmZQ|Tx&#pQe-$jj&^wP_jJI1gQexvJvviE)5~e{K*myF-LJ z^1@)|L2vOAKYDKj6>h2a`iq~-h4r(pPk}7??9RdK!iHvw^g%X)=ZgD^ zs*Uz%BG4NYq&^dqndC*cYgVI7a8G#Syw}f*EJU$6Oo?zdwdQNI*)>f~u1y^aEZ7WR zp|bGjhH7@Zam+KN9UOf6AtEQftSa#^N!(&otM=(Bkv$YmnzQQf1_@F!fBW_=Vk$A$9uMR8_GU!HMiDl$_VpS4?=CAn2i(t& zE>109eL|zZZ9B1U0td{Kr#Exj7#SLxdf>qbMWSeO;lWfQ%;&fp>#Bsw2wxop26>j} z&1<~d?K!|urn3BSiMMoeY^4dKXRc4B1)Rx>!anH)nQ3`G=~X%VEwN6ZFC!q;adk~l zeCN-Z%^|Od;jUDou5bS0k3ACTf96Hc?{0328yrVNr>xa`P2!=N<#Wvr@S&dpH;8*X zH1o$q!$d(wTK#@{PG%=us9BX8(vPx}^mT3~y$l3z$6_OQHBK6RO;h5&uK?CK1{~Gi z&|HWB&q-}1Q9{@u1CcDdgzs>Amf3sGkxsE%o_y8ftq}K9<*+Y+K?2aaDM>$(tZ}uz zkJAj!HTY&6(tWB;?=>ApGiq#YDClOpAo2isH?#1gvfJ;Pe}8@J>Z6p0mpzevZq}VQ zF;vb&!D#Rzqgx#eE}pQ2tEL5*6L=rbNYivl;#PawBl6Cqk`!$)VielOtex9-phMpWVymamVWI0xs}2aL#tb0d?LT8tc~UbIL;2RlRx za8&M$wknpnz8i~)`HHsQTb9MQ*Ot)pCnLl-yPxIQW5cL1E7`;8=T6A|>K{Ib&`)*{ zD20j?OAL!_F`=qKYDd;A#3+bS(NSDx-d8OQmh)lkw+(18@+M2vOdZNCejl?Ynic66 zluVMX8e9gtWHLBhRrF0iPv5TNLL2Pe`~G)zGSJfxwL0^@qy1iAbhSbweQ4$%@YuG^ z1(j2(R5dCcOP{nz!^$$Ud@0`@XTkibm&eJk`qWuIA_H9r{wp#fQan*(T+|?}yA?nf zlboY+*>;;XJIfcUwYOtg<+9nsB`G;wTr}~b?0^iQtb;Jq-raNBWOO2f z)pHBpDw>!C&0xECB_>Z_3Ee+Kqq4v!T4HUQ+?cb1_=QQ!x_9O*dJqUyetDK!yyOrj ztC+#zdsn|4q6kTT_WT)OrN3K(4kNNE^~)v)y^oWtWhh;=RH^jw>s={ zA(<_=w6ru6bG~0yP@xl(#6P*Y?ui2@uYsPn)osZ+n`o!>#6I4a8FdPCGJg*5cVUFc zg3S#16J32DIl?xQ4;+AnR(6g?>&?}|F=GV81aCv>-}cPOaIC_~gvOkm%tcK1t|GM2 zh)&|2(=+}+Z2M7&ug4SCxJbEvq!ETF_p01R9H^2(K~I{z>eWi+pm5ODFYCt?s2kb- z?JGcQn$zy!x}oGwVwUd(A8zo)9^rjM4iI~Oc@p0pNvI0>23*Oo9WouBtM{5Eo!Fw^<`B`N0<)c|B|W6;@7jV1!oGpoqfd}lZ5 zPfrdgqNEEV!8RsC5#w<{8J>gL7B_RP&RWG??|Wo=VYsv#4<=b+?t-Xa{HB4YjfHqs zrOB`wu8R>y E5FPR-ghKb7CgszZVwoUUQCGpjk)WX7Gj%KYP(44t;M=HX{38w?Y%F3k=XC)B*uc!F~j z9M}xE(zog1%Iu0zEPMR8%*%wr&Z(zK%c%Q8o3%SL7!Wm`feEw3j`~EawGeQ{_MOAb z!QK}r7^}O=ObXD!Ie1Egy%5xH$rn7qeg1Cj-4l*@7mYSci5t!iryTz;M>31=?8mn% zO>Nc{Mq9J7i0}93TIP116xg5uksDi5f1~R@Emv`sgjaKEbA)gFVIL3@uIaZL)i$ND zV=%lPhczwJW+L*>KAu-5$VJLi%E#lD+1fT!P;_nZxhi12D}4AN>Pd#=czN^-+SNt_yE;o z73VNHjD46=6o{~1zlm6OU`4e6aebC^Yj;Qe97ye*P)$fk5j|$UNfc5w@8$|=Ydfp?BPJ3O8g-^f4D=af zQs!0NA9~66WsSqb!T}_v$^)4NOuip(U?xg=Tf~RRP+8vv(RO1yV>Qea6DVm9;f|rt z#W6va-~7%f6QH547EWT@14DN_IHW2|zD&nBc0GuV8di!sR$V5n@svJ>NrAoAn-hkr z#`}m6s>D6V!GR@K`-O=QSIAve?mgneZFh_b*9`Q3()JGNs12&Dt6ezm-jz+)FfP4^ z=cuqbdWMt-xfbsEZ@5C5$6PnYt_?TE8Y$>c=3cND|JD6CSDa0!vg5>!;f3Vq2x&5} zyU8_v^Q-73zja{cF*o-Pqd%2sZuX&%03QyAb{ffozza0xC$9TJ!SO@RIr;X<_pB{K1{X0EOabEJ zoSdA@Zan$RiwjLa^hFn$W3D+lb7Meg!IVIhB$234wLX7Kj%A)nz zjp;OMxNF!)W18X6t)drU#mDanx+>^nyH?fCSQM$)_01HM_GSmzD3+i4E@r*N+mHq< zTRo?-4@aXoS3Q6~>xiH(Mv$K;L{cJ>%&&%l2IED?e(cPJQfB5rL<`kSO8(&|igP8n zy3pO#?p<@czFO@w$dj3JbD}buy7V-z!Xb%~*x?2LOYWTUX2Qgdeo*ru0xXlUC-fV|pQ&>w{ScTyNgE7+daVX0q<5R8|hP zs>S=JpuZ=}SN(F$dM^twqpPt5CCFQMpy4#B8WNfDt2>$$q*GXJP5j<^OGH^Yx+5eS zHKByQY@Fi85}X9YG0RM-!a)BE`8*A~`R0zD<})09{meV)=}eMpnF}O7KK|=8LsTZ_ zwsYg2d{T#)f7K9i=F5|q0hRC^RV~vNYR87}jqMtB(dsK196pl-{R3%OCvI84)=zeJ zN>-&`x+=)5EFd2TD+$=v*uZDY1aDLrQhAIxb~*bs+{AL&GnnM&6neDuTU#3lN`({g zW54LNwZuzkECGvIC|xdp#V(@?GSMr{RolHx=C8r}P?}xz5s~Ld(5+&>(_ltkUQ*(* zyiNnW>+;OUt;(5E8z$9{fQ2)4-w@QTt_eP^!w|aZZNZ%P+DvsxGw?kZ_SVOAyYzV; zmCOo{2np$_{$=cUO~k3B$r~hwplTA+J>+mU(O%v&_#g1+ zu5@R4u0!C)#-r?KBJL@Rv|(Q=y}Sd_(^lYdt);bhxO6=|vnn{-^hxo%9Gr^MMIpib z#m#HXm_QGOm4DP3$UQ&!!xg<##QV`WGmZIS;e}2N(e11v5)@^@9SI6^68JQ6;*QkM zQ8Doz__)P-$Fl17(h{df5AAuyNGN}`xLMTweE!3|@6XUuUT}PR9bOBi%LE=ke5$4> zs4eMCe99{tsZOZ_Cno7!AZ)uwa$@z(gu_6ZdIvkp3v1iMUS^kP7l_qM1JY3a(YUWg zMO%Yu@2b7eb|8#1y1(8fNs|7<$$VHESo2c16fYFRNR^)`;LHA2lfQ+nuY*4HiHAZ# zS#Xrq;9%zD4`pDnZl-qNcVK<0SGSd0zf)CwQONMC=`~TDmbOOsk4Hc^2d4^~T4XOYL|hFG=uecfUmVMT461jg(i@=RbPu)-m=9K~?e{W>H} zV(cBrN{2CS`<$rpmC+!&;){$16vJDr*Z7*6I=cg(0Zn96eIu?uZ%?ZKU*D2>9c$K7 z!}^qT+Qrkl0e9H!iq=_}c|7+zO+%(oa4-bj7CoOL{~HDCsy*&1KpZ~g$M)q6!P138 zi7NlHYTzV-e!Rh3{H}srdxv6HCL<)9ELCl)M44oqya_c%ooZ>lKc?@d^qTwdDL(ah zF3~9;i9&dMlJ3>X`SkqWvonuk(By_mq5L-^g1UloG}qJY@i>{z_}G`-CQo?4H$1Ef z>AaytEx_%5cx=@`aQTR&sK*Gg2Sd%dOG-|}f~-zkDYv^vi8SKz&1+y9Y6?(LxCD=+ zEkUTHCAWUVVspB%{rt(XQK<3x4 z5RnqBw2ZMW{rf&_0h(nPsj34mo7&Y~5ClX9#p;Y4t%?o5tU_w&aEFrmJ~}q&7O2R4 zi%soY=^J}IskP62pY}E(ojNqt6~OjBabn4T3#OH<-*-sXVlD{(t^{=`DbOOqlVmzO zSZoDEA8Q{kLBYP|)YzJCmpdozjT$~n;R?%ggqf~nR)-%s2qkw*HNHyYv=`(~S)6;q z!kdyb@(hPUR=U9Jl8VzZ?Qpu0Nloxn`^T+LQd`t*hNVow)_LJ?R_-AbKS9X!$@y@L zX79Yc0acJ=C~M$)*XHT>OM`}ry7!0iN?zg%JmcV`DUGE5KfTs6Gp4uE#@8cdqYC~xHtG}XC>dc+SXUQUVQjDCY}NrBxx91 zkvcapGWvyuVr5|p75Cg!oL5~76AbhC4am7@FNJK|#aZiyV4z?~Quks`nCJ0=i) ziQLJVCliH5HM#Z6A)NQN=XfH1VgIO`Mk3B2FeO-Q??)clhsj7P>~Q+fYRmk^U!L|M z&p=Sigo$+^`N!V$_0wII`KAhp*Gyap^()|v5J92o9VVcs%HPX0b6Msqf!<#AU!|DHDTkHJi`wj$@^g;JggWYePVH80KOyQ= zelN8NAV{fL|5VZxsS>}g)tAXli|GBe!^b;!gOvO~duBGf?fbngbi+Jiz2}|!IVJ$` z@Xu{o9_8!ue|>MGskX-tvXc0ox*;9olGBy_Z`%fQissUAM1?}m9VYDnhd7*!q1R%h z_CMPu3#v~e8di%Xc`A!Mzt@Gxv*5%)+Q7d*XH4b5L?-ZJopwI0_s2-P3i4l{DCFnh zd^#4*gX?xd3FM0aIt%81^TW-f^BS!Saj{PuYDhsW4h3HH|6B=@qC#d{9^{96Wk{N;!$df?*dM=f4-I;4|`m78u(1*+jE^+wby9Z zBuyF`481 zy8r;*n-l|sj2HVzOayh7=6`n9*=J7*e;3gFD~|=9K?(ie#{@qAzc9@Lf;=Afzs5G} z4=OJnwAA#f><%X}tbC^|xf9id&bF4!0sroU8c4q{HLIzq=bObZy~fLeM=>($IyzNu zn~8!=wXE(&uY7Jto8%#;+zOEZ;Wjot2e^bycDuRJv+uDmi1-}Wl4V{thUYgQ?8c zNTV`20n@)eMF`FXGHh#Q-u_BIzh$SL=kxe%4Kaypk_Lv7hX+VEmOU)sS{1PcK25CYR)5f=76 zKH&D7szn`{k5qKV-p&jO}N$A$*U)dyg z-%JnDU6`MpxnCLFsO3LU+?kDgJTr(3%C}yEd1a|BM5POPbWU!%ma#lByyaq;&n@G`Gmo7-xkdOUoXTFhaUyhGsO1kJN8b)~Y;ZLBr*h1B?ncn*( zLK32ljSW_AYN5wkilw!+o>Lc!nVI@r^Uy;ejXD&6?m9K8&XmyieavX`n>`QOkn}i1 zG4cKG#!h1L_<}D||K7`QL4e-=8L$nclsVjN=R|t0fBNu~d+ynlPy~(rhXs)0G^%vY zmi`85eZ9RA&N5{I%5Dv$bNBT3xb@UVLj7)I*jtY9V6UCz_-jj*dFy)+TwRhu=s&KV z_eZ4xXXC@Vv>As|T2$fH%coIu+U`N&yVJaH-p~Uk1-8WdsWWtVJL2m6`Hk^@I21~Z zXJSp{^5B0y`vZWo1kITN5kiuB8Uz583` zL<~&gLg{h@Mb0bjlx?5@*rSA^kf_)4n8td#x~Hd(epffEOi662hF+#8f-$3&jt%K` zJi2WgJgFHx-qTf1PM4YYK*=khxT^-@rsJ6ExqE^&M16J}=Z_WW&3*pf>5|X=t9&HR zcWkLHQ$Ff_`6zN>XnqFAdQ!8p{JZH{Zb69GB6AWw^@YPOqsu|ctynn3!|00cw&d)d zxs@61T@+N^5rjNJs4RRLtiqQkeFkm9Nhv?exY^{C1(hx*oxhA~``f-RSn}i{b#R9C z^2H(GmsvnLe|UU{wBl=STMj|lg6N)TG9y@6=IAdx$N$6ITYp8}cJ2RgDIy}Eq=0~c zNP~oQsFZYf2}pMg9ipNVf^-kv9Yez)DcxPt3>`xb1K-o@zMtp2*7FB^_|e634KwdK z&%KX*?AI~Y=ISYlybc;7-q>sg4w}A*j)4I*Sa=N!+fSdcil7ob1lAktv)0z1bNdaP zxe`wq=wmD518y&8cnXNWr}3SX?l)gG*4H0tB?{NtXS?DnsvBrLqD*tz{f#MPo$xCB zgy5n7Sq{Su<{JnE)+QS^=oNEp)~%cqledY-7*3PB1aWre(Vsm&fF}r@3@)PYjd6~C z01#9?_=fhRf{d4?C}z0o%7^T< z-A8FE>YA4e@ic#_Q;SB{XMPc3X}q7qt#0msA-YJwpn5hP;%u2TU$dz4NM8v&Lgj<$jng$E(A&+QU zF28W3yTztB&+Yyhb`tU%nb-_fUd&LVwY3LL#-D&DKfeW05nJ0r)*_b6ggT{Q;zlp) z5i=0^(e~jhX(uj7i3;%E?qR2#jERqXNG@h^W$#h-g77gpeTM6|W#otEgyq$psj8um zXrCH&W`^gyVbsgq684ezgF^edU~s>aOYBz@6B06EJEP5HX+|uuNCf{EC24R6s@Byh zLF0CJXr8gLl$y1HBM2PC(w!Yjsm|ZZ1D92)YU~WqV4WGk>(RZ7z2(g7`r7TAryTj1 zIJV_oD|YO&z40A4H&wXhqL~|Hlm2{f0qQ3fdJo)>b2Zk6y4FX4^36n-HDbfm>$G+# z7UDKk?-=;A84*rPSJ|FNb7Ki$(Oq4TB++w|hQr&#Q%2PJZo1l0sw;K2{*Y5jC2vz@rEmA7IBQWa>Wqfl z{hF8M?L6e*`uFcAvrMy#AR9#}bo3v`RET3hQeCF++y+F3fF^zHzVSa&k79ZoI)`pM zD?d{UspC-!hCiV6ad#N8;sr@UyZk>Ve~_#Bccr>*BG>Z{)J$4D(gNMOE$XXrqAl>L z`L0%i*pkAc;=j2h$$fAG(%IGNrXwPTi7>QVF@>6fTB?ZOyF zNXEH4SCyK{SiKyh98R9~JiJQ5s0wHILmPg@QKID-{2B=d#PQ5Ln7V};VepnlzXJ^|cobM(4*AD^z-S=g%ODK)$_>%e z+n+A49AB!9>k*fS-(WXWf2W`pDJM8T#rb}-1`o@t-mu{`Q}|Is*Mi_CEhmk!chWn4 zapcP=4vBu8^n0YOnl3>ram=-<&RgS0^llm_k%$6DC7to8tp&^1z*P0iuhIV!!Fu(M zzk@*Ztaea#0pTB%Iko#0?B>|;>UqoA+5Q95YhFQdZWTNh)eHDDlJ`l1UPPoBA;OSS z__nRBdx@J~;Q1~RM`DwLF7o0qaA8NQEdAHVkIx#|bMubkImxL9Sv3na;Ws}ae4=!P z?O@&X!NZ3+*k7vyZ!j?fN^c;jN%6$xm`zdlw($$4R9(MJ(-p8AiB%QpmVDF3gPZ@e z2O~wT_m?QKU6M0um%90CB(TXACEcKr_jG!JnU=XhVm=5rajv#Fi_i>wN}%#+F#s{L z6{hkK&GqjiL_X(~)$S7v7X6#x%bUK1LuHP}CeSX35%+Bj%N0p-dB$CMXMuG1NWf{> zDI{jZ>oZLP^1`+w|ET!Y@R|R~C5p##VGL}t3R{Z5^j*71gQLQr=hUW<>V^> z{Oe7RB!+zAY(n`aolokzB1lw zkq>a2>rNUx8?Z%05R8?Ltp@)5`BItF@xdDlbEu&6?j!UFXQ5^xJ@z?rPdwq%GjQkH zS<&dk^)yR-!l|>)TDO;~yx>`1z?~+lbz2^TyER-<~ zpeHhyY+46(pkdiq*_K{aY+S>Z8OG7dr&5rS(XbN{?af)n{QD&zS8MG%wlRnF)Fopv zf@Xs932~GM!#C;(E;Fj3gz0d%=B&Py33VAjZ9-6ew;tkgmn-xA=YbFU8g1!D*w;58 z3y@Bd8r5^E9zmhF?5+o;18$r$9#(oKae|njoP3f>VdRgd67xl@1c__iJok-Fv(2G% zwvr^qO88=ge1Pl1+S?1-G6MqxU82bEoi0J4C63HBv5t0YB{Cb2b$TN|yB9 z^HJl?wej(_D_363e`0;sqnuTgA735*enQqcp_wy-i+h~7ES6pj@E$B#KJ0?_&(M~= z{lW-ko$vHHZ&;ee(HDLX(@QcowF~mX@yPkS$1j+(x|N+FuDAA=5J#6o0JF7{GVzD1 zNH+O0Cx^3@*_LUgFB6)atPu zhU#kd?nd_=QBc%@E#1W$bHCm|(PG5K1y)#^0DFsiR8cZz>h?qzhbj-xD2q%C0gYg( ze#9cm-Ej_#=o-1=dgK{OZ%aNeD7=$eH=*xVefHTRs&73;vVVF_F>CT~zDM3rU!&>f z$h%|NmAVZk-vSZ!?Z$aZ(=?8`%_yIC{Y<8w}WxPx*+BEz+Y-?Rcn|*X|GuJ|Y|O@8etA z67(~CV%ODj4DX!0WM2Hf)C_=({2Z?D3v8aFg37v`HxsBYhscG2Yb=9uCo+q%k}_SZ z05PgW=4ql}Ej!Yhk@e)YaL$BHK5qilJ?a5%Dq$nw&{R;W7-(GdMHoMzvfp-VXb@^Q z)A#;TG-W8-t}?INp;!OSv*Gh4@-u(lqBp;2`u=3q5Q0dCDn(T?@Wi&68GXI531VJ< zB)(+GaGk=hpo+ge#7dLSvi7b0NEjTG=$57|6$uJ+X5Z{Fh+(RiRTzkIcI8;)KCS5( zT-dMkF*5LNJ3bJ%R1Abyb3J=`aWV24dtEp*JTh3xnE`oOVK9X8S!Zy z+)JKcScq;o&CZ`sM5;g3yF+q6p2I6q=`nG8rU3WC*H~gQfJf@?=s;a!LxrHGS_ExT z2ngoW?xkl2KjRzyPP|!qhEiT>U-a_IBD`LTl5DicX%`W7>(%qfVd!rye*W}__odD5 z^DCmRu?4-jii5rlF~~5~`9r4F1ACmUnE(L?gS)78rFE57Q+Snv-EcAf#p|4kth_Dfl5@B_c z`PzGsnp9WK-~v?4>iGN46^1^2kE;Wb?|)_g{% z@@{$%v!-0g2iXonmfocBvf^TZY&<5o559^kW^MFYIcnBk1zwa~EHAY+wLCpN0ru!i zJL7q84!ApWDhJ!gSf4)+Q=XwMjaJwv_Df~ju}R3l2!O>gP~9|jnJd^e&Gd8}=+T%w zj^u(u7puX@e4Q|OZSAQ2;2M=y{B*wzByj9B2$li#l%#-n1f^4d4E-yUjbej*K`{SpYHiW>;iFy zEHwJC8vbUAqh*V;;71OUQrR}>Oi~L%mG4>v6A_XwTP)UU$P2_LI$yLpG<;9CnA#Ub z*|_OtoMw`Td>ykGl?_pP2E-CO3G-u{ri;o~h*&uW(WrEF#sxOjhkf1MWw(DGyHN@H z^)9Mo_SU*3_@FLSTT|cMVQ@#3PT15s=vDdk3B~GlW@&($*&=@Scm9*$7~^57IBizp zzU~FK>Qc~{wY1#0Nx;n8lN5KfN0#=fk_(#1AI}83xJW2d{a|UPfYR^JRCs}&X7q&6 zyOJ_ZB_M#C9Rq|*QSAO+_G?Dr?F+xZZ}e`z`x!qa$Gg`2y|s zUge#N)9<0BfaO2C)rD^U*_+oCFroE74oET#rTq-709R*7qm@;2Ct-BMCHCD^A+PGX z{GS|WNT*P_sC{ZE%EM9I+w&H5Y6oez9YBgf3~!AT1(=xJv^2*x$89N73qK_x@<64Y zcXlyq#KcK=x#brY8(j8zfD86V>PyJvE_S|w+&4`|Gj^!fNV6pzC)#mfs4*qYC$Wv= zDD|P?7pSbTrk@r1hDJ6xJy&L`5CukyVs6ya4b~-S7-4V+@^$KY)>6^Z zGnPlxi}1$GCZwJ8c6vq@(>hSY6o>8zGrY)26*IZS?W0gcy(W zon`z(B8Ly5L=Xv%l!NW>1Bm`F-f7fC-TRJRB;QjCKp);F( z^72fR%Jn%-nPG53UV8M}#|(OFev&og9+7AZ53Vb;kH>t{Q^*dLD?&uU@==3P@eQa5 zEjR89EvW@IDc{oG1pWdGE*ssPRKztLFgJ$ECcPP5v3-jS$jB?ho!Gs_&01ab$0|UT=G8TA-74F9Uxc$!x44Rayz|@4wAxhK1$tsFrgu} zKnWIdUw!679lgxQD+Y0F5>OE&`N5tKs zpWMFvElQrerhJnV{yRaSf$@D8Gy{Kk;i&sST&?~S$C<35x3siJx;|z|ww;0FmXgnK z`3Uig+^Dsn6J7YtMeKyFplBYUd^WwbGDt-g2_j+X?c*yomR&`VQ?M5*!)b{Va@#M5 zZw!GO-lQa>u<-43ZX}_7{#J%6+1e)gECcz{ix&TZvf6=$__V)kVWMCJF-9Jdy}L8b z9Bk?fgTbm*QRjAfZQ?-$(qV}LdffH7xfV1^M$(LF(AaKsTsIA9fX63B<{u@+ZxjvZh$eS%MuzU7Zwn> z?l_Wo8&5j3$uo6*GZsVcfuwvH6E*Jgt;Wy-m0wrh`pcKDJV`)9dY!CMRJaCI0}zF+ zmF4A$c}zB;J-dav7eHy0>SB2=>W$2)J6udn4m!+{E-5T14f~-Sc98IH?wxKbb*H+; zA4it#fi*NLDKi=SYPB68>*zjCtg*2452Aa-aWuM6Gv0 z4lWm!%>P~(bT`jGhrG`%F+li6B}Pieqd>FHf%?PVrw(#^rW@{9OCnUhy0@FXHvptI3I>i^(Sef1a`_AB6C%3O5%RNcJV-?-^iSv@oXkY;bVZQtpEhtMI#(37zW8_)`=Co9#mlEV8p)UdAp zi;UzF*XFO?lSJhEneHjLOqst>$=UFYR%rq86c;TM@AcY<#Hn=IMe>8tP+T=-p{so? zD+j~IbHsd(kBSr1dMW+4bN$J%&!jJ1cGrMAJaypRME*p@5f0Ug(E7TOnE6OQDaI_* ze+Hd@Hq`X>vqtj4G0hU&TdimR#%TWv2Cwmc$+Tm4)fYEw=JpVs}BANW;;26x0_T2T?%R!-;nPzL;V7=YS5%Ykzp7wQ>z&mVnhdv%_5enU0K<$TtRD@phC z)qj7H9oX72i&g6C#EvhPV0wGq2kbaFKhn9(b2`)e9jc~q=HJb>vGG}!fIuu@k@}0Kzy|B&j4Kx4-XKSR=@%#c8`B?0XyqsGe*UFb30GTcT!S{ zZ~SThn<(le_y6Z#{zV_(Q-JdBuSP7g6y#4g+BX}~PuRd(Fqda5U9Uu>AoWeT4Y`?3 zO@)=knU#gNts@gb4Aj&PftV)Hed=Z(QiUYmv)F(e%bm&Qe;$Dhy z&+zu<>*XbNb6w^brA9n7wMcg$4f64vOlzf`ojIm34&Lg|8Z0dA&BYp8sp0_}FzwqT z)sFKe{}ZCWf8j@qM-&v57weW;ne=0$JZkDgzNe?k2!v%wNND01?&0~tykLgwrV^1O z`N_C?gpokNQD?x7vDo&(osTErJC`ozoeC|VcoX3O_%RizscXnZ8&>B)o0W1d=cF$p`0S@5eR!lY(59`;Y1%r963_~5B<8OvG2*AM;|$` zz5RVX)b-jN@bfcUy&p-ix?i8M#m-kw;#~(nqzwFIU1O;To$bsURjfq)naRBN4c`A) zo2OmN0TXI2O)q~bEY8@Xe=h9MsGnI_P~5b(LBby02eW}G(T`Y70I9kpfOD{~Z=uDH z;NN#HH{D6qw_>+hy#SHbrC_%A)?)JVaaNwlZ3LJmopuup+=i+Zd{B~R@rdj(1Y9C3 z0RfgbMXCjwkco8$3fNc)3kEN{+Y0_*r>u}Of6mlSZ=alGX0CCipUE=ql0T}TsAy%a zfT%Cv#(7{HVjG}qq^i^3F{)=yRaEjF@rX6*`+?6zSwsV4$8Y`QF{K$O1a#^_YPrbsV$FNh7 zLEJdZ!`xg-Rn^2=)kM~-LaD?;$j{*n3p6UJ)17m|Dn-%t^|H3MyqA|`cRooxKW<2! z`wtdvKEbi&;(MkxGjq4DkK3i(ek^N!8Hd0BdM~V>`N@7a%tq5(H$z&}(%Z3g%GzsK zF4qb0kF|?pN=7~ZNv}traz+fuK`+}QSicg`91q0Ph&TMnh@}69efMH0(Xac?$p$_p zpTPR>iqTQ-NgcHUHeQj!++4k~u?o_^+_!2?a2oB56|MG+$&hgK2N{Ssv~>XfcFzY6 zFu+vcRI?t3ut2mnW^jn|m^HVPgv=qDu}WE5ljFS|gpS7Wg6J1`l-$R^kIc9W-m#dQ zMlQ~Y>*&&oy4aN&r-L3y=j@X8-%pidXR+P`DyQgJHp05!`YYyWReGRB_!32?y80o&a>dG_ z&JdSvC!v$q71y2d#;DUNO+39^uq4FeVAK6&a5<8TFj%r^#Gt`*S)r={M1I($u#tvQ z==?EIxfANMad6USD-WQFD?3CSaUqP0+=xFF#01I*l~LU7gUd^;b{?N3M}p?$K$p+PzOvC)seZH-G8se zVWx}>TJTBk|GHEzKXceDZKi2LZOooh78Tj*umZsU4XrA}CGu(QjUKH=!c=}t7v|&& zI}=9I)Rrp!6%t4hX4h?u(3?N)=0QPHVq%MBEyrzVRE};kuqF0)asgu(9~of=Y9P@No1#cOHK?BeX) z8uQm^qmDrt+pLmEqS1jWiXc z#Kcd5LLaWfmSMu_NF&sFTYtuXZ%^+({*AguO6oOI(ltNiepJZu&i*~HJp{HqnO-t| z`C9ZZ=Hjn$>}CS2BAg@mr(K#3OW*;+D0yQuewv~J8zD8PWrJLE!v9*^E)N?f;Gh@D z1ww{;?$DL#On?{Ni4@7k=EA$2RtLQn`c*0!+hjlnjqWD6{hJ3pkiOVH$^C6w zT<`KO;NZrE+C;??AJ>;t?CLGnqzJ4J8=(Zdx9iQ9qd7Y|y2d`r<>>v#--c_fORbWd z_sZQbX<9e@vu)c6+<=3BuB*oCsBcK@@I5NR$eBO{d9f0Id-U5Zz^p`)E;g2QeH%j2 zZ5hdGU^w5*Dt8Q&>d^wTro6mmFb(-8kI?YlTsQ}wByyfy|C`QQ4Y^S(Ue4xgJvFrz z{ab%@&6;31(rC(~b$G3DU);rNX?rQ4xS&9b$p8#=I8%l+3Sxw79P0K4eQuBY#Ssmz zE7PLKRPE6J^_G|<)7)X{yqK}ksb8#for;YGlup94#KMje?^ za{%t1NYeE}S(((7TthF}_4Xg5jvQ_iQ?>IPd81r4njd*>c`E-9_d06WnDa9f703mj z99Q86S?70%0c<=-@V4XQWY`4*Sg$rcLxI?4YtH%i$X?#?Kff>TWpKmMrsDJI-UM@i z#jf%)|8Q1DSjLuT8I#$BL9n+$!%pYAE!yp$jH-?>-SZeyGF7c*T_MrayRkGEVbxJJ zraHWDe0^7vH2V}~M(+VQ(V=9zi8rA-*d68{p2P$o`j*>mv#Kx~OF{fnoFCcsfO_<~ zJ2lAugS`r<(KOuF>QBg~2bS$N>cdl4+S=PWj2%+Nm>!mq+5Mrsr`fB=34av%u6U~U zt+p7(z}mvO*#4quaESHwYP~C2ezt`WW@q_L^V(h++-S1O@;oLc>nvVcyIw>ItWkr(ArSW&WiL#yH|xc{hYW7|6v~p=A^t*yjkaRx z%ZO|{wv3y+8y(~vJzjASS%_9`b+7r19@;N1z`A$uE;hE@^Ha%D zk_SNwEIk7Q#)n(c%Hk&?w*Ej_SH9ls1RV8{+vdytc(8psF*!NhW2mW3MzTOFy7vL1 zN%HwDTu%2b4$mpF0>q3~onVmA2jRFoEIf$Rbfdz&RhUUa+|`UEz-cm zm?bs*J#+pdZ}nJmiHA8k3>FOfNp`=70o%malCkdf$O9oh$LHRi?c{x87s@7Yp!BQ1 zW~PVU6Z2=ZhLjWSJuMlq1nxWHpWH>hlFmhcqqYGxskcABpip7gv~KqdFw)DOpygR* zizq-)T#-Gbr+R}07Gl9qB`f~?ZWG{yn0X6TdcXGa_O9385&u2u^3<3}sFb;`pFbsh zzpZH==sJ}(1+J!V^}MA&TLdd5JR_84>n2F4^IXK;B=Q;Jqf|EAVhsu%`ZBZRbqRUT z-Z{w$RZ=_{6%2&kt8Y`Ji_}H;&P^R;bVDm%nRz*vz6%@WsAgrBiMTo5p~1#~x)Crj zq3xqTmE7cYqG3aUrX(WLTxyf79cti5wFy!;Klt&TLe$|nDOOzk7D=DXUkv3Iotauv zv3@^rAU+~>0=xu?uCIY^kxWOIl{c6GyGC(_=k7M57QY2GkQ66kVPARG`K-s26p7By zXZn#FR&^431QkiXP%q@AYvya6W8^61Aqpkuc#YrYFhkJr}qi)*m zU?_b4Q#RX(7HvNJiCWZ$lq6P5JJz5+MLloSZD)>IY;olM(^S%(?QLEg#fl0l$Po3y z?eUZh>TG{~B{RQB9V+6rz2tavK7B;QldJ4?nPbV^#cSPb&zp#lS$yVv5@+x1T){P> z3V}h2w95RBa;Cm~4WSb5N*xezKidU*Z$fo-7n~Aid0) zn;^-qGh`_Ug4$}&G3yS?WKe$}O3rH2eB6r*{9plo$20zD)O^6f?njIO?~kwh430O{ zggQ@*MSL&b`F492NCGWIMPFak^CCgWd_m@*g*GfBuOE5vdxWT4A?0kj(J}0)AMWR5 z0+MOqO5RQl3ke|ZVPS8X)k;&MAXdY{$1&?VW-POG0~YOvVQlIXHVb$bY=rvKFa_1Z z1|QGi;G_i%>YMV1kESU&|KOD!pOg-_fJD?~`{J#Qh}t1;TecqCrNb*uUJ-z6syA>b zLMK_%bB>XIcxx|qRnm^_?tz$9x011*Rq3G!9|%Hk9h;N^!6yIvTtHV!n!)Efr)g;Ix*dZD^+j+eJW zqE7njbD&Df+fjASCw!AD#QRW9^G+=|7;oV1lRj%*F@dZV*rjS#8*R;F__p zurhm}9?9JL?d*9>m7>R9=4MuASF`ax@3_g_a=yQiQ*3lebi1`_d0#tK%vqzLSYFi2 z4XC%gUyW(N(8~3E{@dqI61c~%y0$<9YRv_CIX}+bQ3(|eoxs^09I9*;*su?KRan_3 zqG(TE)F1M*h{QBiI%{<5chefIh1!%;J2;{nYpQMULGYwz*ZlQ!>c=kib<&JSqg=YF zl?pkfqw;0Hi>i40+q+Aaau*m030Dzf#~r~M$^>b8kb%I@0pl!Gg`#Ww`!}skK7>M@ zmZ`$GsDmQm4oOaEx058}I>W3ge9l|m+(C7BcaMam!hZt)0lzZAxv0+>0i~Gd&F6D65|V(!<;pK# zl<2<_=py^0+vHxnaKE|^bzHjrLnLfV`Q%B8_m$`5jN4e`TOT@38GQ!#~U8dhOIk9}_s|AXjs6<~(k0EE;l7uTxXdzo)K}lt$ zrTQ56Mt{p^aHq^`=8f@Y^1HK4u+EEUz$PB1H~+5pWngAj1*|t-?Zz*Cy+Y#lS5(Tk zd%+%y{$^)}zz*%zIyM#^qPn>w*bfW+A1%Ok)t5_n$7Qf{Im;2)$zJ-gF>^h=XqW!6 z)MAbX`xS{tkvM5C$U0`rp=?13WC++$dN1Q-m2j9pye;a$Q&7qpw{gq&s*+7mjg5p^ zN{#cyNzvm@@83m0v5+)o)iREhG|4LswFxM4uHwp;=*MSP;)lj7e() zTkKTc?zI`*(2UU}MYp(QDQqm}$mC0EA?Tb-JYGdbTOL!W>27i~-TtcF-rhcP-QRjd zB;oP0YE$Gj;I5g8U%$6Du=|$Clc%LQN%UA=z7GI>WUT*yN`Ra<-PpijcSU>Yd)WPh zsXQ`K22YETP^9Kt)4Ur$pL4`Q^glX&-se$0=Aiw%Ih&&qDsdQY^>6zymaDkYXHajm zx8O1GfPjEX#1jLn-1~I5RD(qsDj;Zo6(f{$yq9xOVpIh+b%K{(aL{p^UX&M!PCXU( zn)OHa7CP7VKM}JL0o(%#+wk=^^E-yzVCIBH| zfBoWMP#eYf z5)xFggBs-7d*%p+{>KRGPODSTrm(4J(Xu7AIdZ$Ep4%3ikNzkoj49J>TAS{C9?25uJEE)5C_U7eym1T#pi}$dcH5SglH5_b z9kUP})rYoA-tBvMSmgbxm4JU%~@r?6B z^j-Fluh>hbIVA2j+ld^qC1YR8GkKTTyw_Gddb&%g))^9i!MS zq9;a9Bg{hkm{x=Z)(F!I0osgJ#F%y4Z)6w`!JzSUnQ>ZVJKi3c_$y`xC^D9>e{&S` z+CC_INX6xF9+@ul7mI`_%4*xhLuG^dPmvYXRI0@Mtc%T#d z^Idj@^XIkMREDIjuwL5wAWfSeHPyum{RUffit*c}!DEd+x6GVNx(1YPs4>Q$$WqNb#$jzY}bI;#|SaM?FHoji@HMv5jP z4`bscF+Xn(^bmXz<)rKOAv-jb?$nJ!s?6$Bf4{4?%Sl`NTY!w&!Fz95=M+g`&{I!G z{oGxZi7juY_TY6IfNQwPZ$BbhsCRwq?A)`zaCU{0IU$hZ!pl)A5zisp{*53wJfz82 z@O=K#PLGDhv8?v?g!5`uT}xAwxfD%Tf?=D^%(K76ZzT|6q*{7-biz}Vg0=UgEUH!B zL&FX5C4y=Xx&5+8N&YFgKVYi^qH*FBm34gtZIemNp^#N;syES zzaMJkFDxmYZ8Bl)e00)n>UP6j@ukqe9&F0X_4_ebp0P|cfI?L zeqFG&J5Lx*5`Qu2GPTwMLSbKi$Y+_N&+Ol+Xgk^xD*VsEA`BAr5630Lzr<737QGKx z{pB)9jOtf}L+DPuh7O-t9F&$&5k;|`kl3?zj&G%xpJr(p2Uwqe+e!jJ_X1#Rmo%uZ$P;^vyk$Uz?^0F5DBXJWF0HtbFQj#*w-ZHH_Nt zJ$_oyCSm31DQJt01>IRL0XF=@*V6Qdn-3_` zQfr_?`A#RNxN=SCk&MOK71~hl5gf_|5ezQQVk!&yjbx)XoGW--)>FvYT}&-`o@_+iBL@ z|IKEY{xGY4hm*aW^fA?J<7k$$YWT)$z02S*c4`L)OiX|1eh6;-g9Xv~6Wrd)%0caj zC;3gD?{-Ewr}>?Rpr6I4ojWbvH{vGO<7^7IiEXs6D_NtKEIqKZr6-yd=3MBzTs1ie;-!yOEoS;v@SndL|~ z>qqRQa>>~Qp7+m9Mev6bz3^QBaqe}}Oe&_Qn8nBYnr7g|pKlUyObG%2ywo?j+K}rd z;Ho%^dqWd)t@bjeR;c>JWTD3U&5tYn(8U?OaC%!)ct8ao<16;h(CWQP&;GdR`n|Wa z4YKFgO=qB)s~&fqHl7UdvCJ_$dZt~A5yHwP@oY}cUNJrt zcEycu%qE6HNkvaLk`K1rrkX#fv&6Psk5(--dL#>Y<$jiz7c5V1({bGt<+JH$2RlE^ zEG+qKoLR0AZ5B+tr&{{js3m@~O{4mblzZT~J-g2?)_>(?ujRsD5Sn+u-xxxyR&ROA^kOx3Bp<$`mQJO6PJXwyG(brP&_K z=1f4LEsGGk*xaZ=+t^qbowK1qtgKW*Sd8+J8GW03J5_Oh>A-9^hea zuXm(`72kV$ysRlC4rB(;Tz`Y_*(rfafu=?j!2|qtB9)3XhkA?WL(J(u6_XC~(;7^f z9t@kAy7pw$xbL<{)$d=c+8m0Nd-}1CvGA~ap7Mkom}k1`B#3Kqa95cYN>|8RRzC1d>HAk%(F?bhn7s!PJg^%b z9dz5Dw~mK-uY9YymZwvlM{CF#+FxEdTEvoB3Rb>;@O<4+$P<;NKT$Z_K(Rv=N4EA< zcGqe_(_V-%fo4?uwE$ZHcUS}-7o#1@59 z3uZcbkPGB{m|J@}DE;b6*)t6mdB(&fBqGUq1SGx{;jZTTHO<8@Dp@1B*-s7O{;Shm z^a%V75ZAbtS|=kTwZ9PHv|b3SsNm{k$ccQs?ATOM2Y9I-Wl&S>MSTT*kVf}e;*;3T zVXAuG*y8P<=ooq#nF#8|BFppnrY83AX2izU2oW-cmYF$HX^D7<`}v<=?O=AeA?_9s zpFPOHkV9-$R9w8~$YOW*hu)8^3B{eoZ_w!`e-h3Tu<+bp3Mo>^F=h!aF@$9GOL;r0Vm7iNvaHl>e0^Smd|5tag%VNb#^JC?E#|cC(#1KgwHORd3q!mB7(9Z*OC@ z$=D-@sTo*taqKmr>DnCOl9=BwsPt@Kj5sIk|%e`=gySaz1M-7m6CJxH`8_dSf zOy<~bifffvmb@t`jP5avf#L1K=Qu!ZvHe-T|iVU)e!;1T~-C;qSI#ql$|sV=WaQXWnVv zj7*8A=N670qdz~5O<`t}`c?2(85hfaI&1sNq~M*xSatFf(g1U69_vbel>m7OJ9u728~9#kyk$=>kkbLHSo+m7i(y%T>SHrISm7tqH7n zD<-a>II;`7-AsRzXam}0ZnE6*nUadhP{&9=AHXXryZNl-H-RphaJO)AD-Q%5|Wu4dX)?n zI>@z@-zy=k;tp)*XNQMpXXbQVKX{8jXI#R=_wm!}3=xRs`iqmwSv^I^;G4>Cj&JN^ z-?5yYp2W&`xD@m+@f_OCBHC6eG4G({66?y#FMQ9WXpCvJ>)qx%deQ=#<%%F(Ob-L9 zOg_SCq6qR-kGk~ot5AOv$O69~KsB}r z#+@ZE-chXWZ6KIqNi|7=$9L0iYmpP1H)^hH(><#N{f8D3!J(m{8Z2qt=5kW8qc~aG z5hB;G(-uYB+unLrb>LCfj0^W=N-0Ca06;tR^z`&{H3Fsx$ZCx>_G}z1$g`u0>+Rne z&3Ve>OM+z8W?-G2fuZxeQQ*m+JvdMuo_RxvDsNW?lU)_{x#_6(WY7<&)F?KqfUswG}$9DiKM!WmqxZZID^ zKi`_3-bWYwwqP#VIWSmKE^;}FjZ{8i@lndC4KGX&lDLtnms40$f{TwYRO1@^_60sZ zKJxJJ{{8#N^AlYB2l)5zAD$f>91q6#U%ty3ee?O=uzlBJGwSb^4i1*n!IkBGKHrO< z4YLieY;S$nCvxrn=<4eFzdvxl_x=Zh@)w3)sC7I4*SJD{u1!Ju1-s3z>+80mmWz$c zfa|@}0Q5JQEhqfq{9OFHIKS>y^6nOF_BfLjgw|mRCgOKwOS%LV$?2MT;?ZJMbN<(M ziG@qkVykjX&6_^91J(xzLN^DkVZ?c({Q-w9uXgy>HaFF;Sy;FgUPKpa$gOHO%nD_W z+CXmnTTCJ|h^LRwkMJHoe2DY#`1tG?oa65&GwAc;{pvq~U?PmxAD0_DfD#%o^Gjl{ z#^x+N5DjkM12h5K2c?g-bi8+Skly+p8z3l*+6dFUvmV4y&;S$rIxOK z9|+zIEz*Ys9ii3v{V-Tp`-2um37?y4>8d^^-U?veR5MH+?Uag4PL?-etB_=i?$Ka@ zDB=Z`jPs_CSV4qdkcL{nW+M#xaxVxATSiJ+=Bvy-EG*Q8r%#=ahSp@$c@KdcqYpU? zc(Jebs~ym}Q^tPFy|MFs@vgd!5+g-2WFm*a8MbAI%vfymM7<%?Cb%7bl50r;iz4^= zmNVy8pzsSG+vpubW;{~pT!uS*=6Q8@_NuUOcbl~kFt;{8VZ?oGQ^->rx_8--lP2iO zjQXU(a&+u+e(03u@v_{a0k6z-rlAo9kVQG8(?R8R<3*?W@3^7 z-fAN#l;Z)G;qsEsm6t!Qjlo~;6E9|oR-^kumo}OBQi=R#YU5d@``S9$t(Zms{Sc!O zSM?2rY6?wzNYK0IxmzSyB_Qu}p&2bj7%Z)sH?=ciC3t_>LXfZ(tj}VcreCN4>P3XwE~Uv#oG603q8WMC4PT0 zx`!;FX7&cArg=m0=yNoIxX=1T08d`_m`w~U*0(P6c^YP`;vG!3kKSLtNcGnT{3;-l z;iY(G>)frBc5-yqurtXu0kMhIlTc3DvX0g&nxv%D@dh)M97a{47m>XrE+NJ}BoDCg zde$E#YREaW7JNr^5+^%FAzwQi8z{+R8c(yH`7JBf+N9dL4shhWro-~l% zCihVDZ!m9eWMxx9CGLipO}r6}juiCUNa3s4z;LPpPQca~`z4>^^15qIf~Dp4jv?d|*b7_Q#HEtIFu!?beNU3luqc6qSgmtRhRq4WT}C47I} zx-Kn^{BKLw^ri8482>-s-a0Cd?(6p?L?Ho!2M-n;f;$9vhsNC@xH|~}0t5)b-D#k4 zx28#gJ2dVNjl0WKo?o8#&b!vkT6f)> zDzj^0-BU67UkO_ChU1-z2lz4kVZQnj8fgD~XbZ^^vg_FfFCqZrR{$uh194T0vXxG^ zx9R)J0SyjAubg%SLwU*dWd!aH_d(-Movyd5-0O&r{;7JXVmWq%gf~8zO> zwj6hk4hhcb-<$!H*Y z(LV*yNdcgk!?P1`^ievWaKn;=E_dmCwad%DZy$(9b%gRwV`730Fd$sn2I;Gqy}=5T z?;^UUhwWE)cOrj`bod5%Uw3qPkg|O&k!Ri+fh+ z0Syp%r36-$xew5fLI1(L0Vja-zwl)LXVm7gY=P(NAFqx79o0aI+NOU=J^+#1Q|M}M zEg|?SPVw*WN+11~?I}`Q(Z8rT;Ib*A0aN1d@xQ=B`(IN3j{zjiy$S7$zmjq!D{9qe zNOe7H$D#Pl;o(s+eK>&mHt)Yz4KMW1wd%nQ55>RNf0sDo2ySQg81(x7=Me@RA0qx# zb@{>#m^@ds2`|q!%Mpt}kGIFiuJ-8*=GS44K#2O!QA3N<@sBKC^;8xz?ti<0RVyoD z+AABe7;tm8HPz6FAuw^x$_Q1=(+txt{WAXbES}=p6xUfh-@tI-l+zn3TR!=>>mcwP z`G1JubGPCpOYtN@afz*f@R%IvB2^*Lf{eUb0p-{fsneMdz8h72ufT{G)?tEbBO@-~ zK1KoRI>q(Yr-s}9$Fvve!)&PH+@q2ym?hDjc2qedi*A)CrY(t1r8G6BwVO8~*L{~V zraVj2d9Cr6?#pOtB{FgOzSDR^L>s$If&o4=lVoGs*BG1Sea_hef~~#bluti63ek?m{m*P1Fxu!ZilvFtXlPP?W%clr z($N1zP4b#xLXwKgJ?AS?$9!ib5#Um+3$CzCkIu?$xzLm!<6A25ie-~qinNhI*n)ov;g(11N zyW5BZEuTuSzNnd|rZd}wgBh1UwH{uAqBPl888)>)LV|L!0B3G9RLxSIQn)n%QjPZC z7KLV=H&QBiS)@9p?{0hxq{mLPE4{beuw>@P6M|Zr;+^tXlW?<7-n={D&AX`>Hb9x- zk!Xa0z~39#Jz%JQ@nisgy#R;aQ1H` z%1QkXTbbvdSGxm!4C!I|&lqnm(=mkaZ>K6_`>j1apEm&ZS_ycEQS8So7Q=gG;uLVi zD~Cn*i({bQV*KRU3#2_oJ-yKH-@gOe16Hv}bd^waR+RLW-+-vj%n-dNrFw zO*!h5eue12Xok&dWT<9CMyg*V-^}UaDPC^s#XzKs7<3Lt{bv0Y@d;*yZQMG!f(gCf zQ^$AT{c{)0A%%%MuWXgM6F}MGW4zy!7YVx{n*h{86#!6LDrt8%n6~c)L}`L8x4q%c zfRG>XV)k0k90F>=F1(Gk?4~g#Wu0>cMB&P^%yZ*m_uN#Ek><TG#Y-;7HCT!94t*vY6 zV?fji-TyeMb4&o!{%UJ=sNy`T?kMPD!MCKgUVVRMe;r@Xb3IKFQhBDA+&QTpHwJ)t z^H84+E2;mtL7(MXn$mIrZSu_eEspP2$0j0eIZH8nsvi6Od9?l#swlfNikN8o zAw6bNsVJ`kwiUM9P14VEA;98xIDZ~{+^5-kGYm#_g-ZZoq-I%FRJ{;v?W*JCU6JhI zeVtvbBKCV{d6wXQ+tXoV2GE_BijL)O-~1G10y&+VNf?9e&F9ZzmW!~g#kOUDm`5V$ z9}Wg6#^mr_G zkryf)#i9?r;};H#MJr2jFJY4gii#OMp+H~QIzwY-!2KD9aM_Znzy6WFme!UW3(Wlh zTFvja-LSUkz|GOQs7}w&TRm6+SNpt$PVyM}GoWWC_z;U4{WSx2NC4<_2$}!OTonYv z)#FLLx*wg~?U(*JA*1F1eiScTyAt|GPiV;vY2FyTxWLF+!|I$;A_f?$Pn8%^U!fX@ zOxmh5`8*8t@lFF2%b~XaxD&!|DV1)2-3q{|`4zRE{{VUwqZb*g`KAFQ!$0OeXG}Fn zeYcbqDKY)%TJXoQc;n#AY}_R4RyN%wKtWvUKixgHw7WngCguGJxKoJ+tI=^ipnU29>s5HQ?RtGOP=L%a)wkM4mrj^hCp^irgR>! z@8xhuiz=#-MlpRdXow02f)(b93Zz7w7z|?Nz+ebWv7O`FI6VCD|49+PNoujB2*D+_ z9Ets;YdMdNi`^wWDyb~8vYR}{L(cKrw3$g3d4#q{bTb`cGV@o8V1zZ8TO+HNzBfl*;EyUi&dpi_a2N#FG<*fc zhd(bkQYOX4qL32E5jV#*M!tckX7>}5WlH~K={piAlv)-rrlNlF)ba{b{lL0dM9y9b z*kaP^=@W9ux&HbRVac^~W_QNvRmRM$PA}xV#$)?5!~@HklfI9o#qZ8y{;my7)?$67 zq3@O->hX4nWvTrDsc9bA zm}Lxj0}80>1F!e1@&$>BmgO1qSC`rz{UjV_{RIQF8*?W{505By3a-bOmQA5U!QdTn>b?aOm_io%Vdgle74lx7l) z(`WB`8t!|CXl^M{d{BMMSR|+PY_J`4j|sTd86+k4v5x}6aazg|G(Pq^zQn%%%sFMA zqQ$^$9QzIadDm+T(f#Wja^Rbkw#>Dt}#Moyn5 zSVgGY;NGPnq)GP_lmsj7&sc!HcSQ8aL6QvqjU#tF(rLfz08EC_0&9HfwV7 z=5C3kk&)vz0-#aD6{Ju{AaiLEgq%#R_l3l5ky)Sh0B^hT@{bx~@6%&Y-PBR@J@Lq7 zXkr22$L(Fvl!9boqhyD(u^AApivBRa;k2k9p>PD9DCGhj0V?W{noFA@!Wt=BBtl{=3pW$g34!yq6X(V` zklgRio+0*toknYpGy(=))>WC#39SBtdT}Q$zN~(GqbBMWj*OhK_Gc(Ec+^*YI@~fE7)03vUIR)@=Y9~k=UnUS|E71Lk7b@ke(ggWX^G3e5$Fz_71nU=Flkx z6&1tTOS2_%vRf0xhH?QYR;K4|%ooKY?ajf5`9wcZI+B1?ZXqfKUKnVW)7Glnr#d0hZaW$D3qy-V!5~9V`NW>}6H5BBiPr zkMO>73|tucrA_5OXZk`AaRfNY=CX2RAd?AtKO6*~)@U^atwrP$SYxM9F}twm>PzxR zfp6CkJ^fmdUjx>+_m9?cH2)~dvO$~@35f1>jO3>vO7Q+ZsVgI_(i3x!5mjbLzBP2d z0g5eP3^Irs$9mOZ3IwXHG!CjwFe@YOSu!#ROdA%D`D6Zc_AXe9{%@ z3~oa6_S~zlwxKVrDIoTmy;&v+kq>aR>&ozuPr4)NsJ2?$T2uP9Dw(9Xu}{Lfnl0>A zN^8I#5e+rwWgRTJHgeHL&sWny~j=T(#wB8o74|;DOK`@Be2nh(rMOb1q zwq11u;f8z6eXk#zhLp{^Y1(>CC#DI+daP%-?f<$VV}z8IkqU1{p|i5OK4M7E+Aon&|SW~(Dya5j?^ zWyMT^-kmwlQ88jm6_!xB`VFWUnfyl?yx^G+l%{>|Z!$Hn%GE>!-&47+A3I!0U0dra zyoBAK>I=2$hK^_iSw;iRnI|7V*fyB%WO8&mSN_uM#^V0`!)c&+9ngrU0)a_OF^-bF zYyg}&|4VBbvqdHmtG9{dwhUo`G9^hJ$aZR^Qa)PdGH1&OtW68yV1^~1FL&6|Csz@U zSLH4su$$jxbaI+#c-bms8#`b#Hr>Yi*3{34^*|VD^)CS(CnA{8=so|;Xp9#JDk=%kV|ZBqn@^|* zJfEL8a`YC@o%nd8`?a)O&f%B4Wxdu2&FkR++N%?Uj>8Zhntoi#cvF^Z>^S}5yF4NO zpYbGq2RT%ZqNdg*)}_>jg#Qqz_V@(H#93q=d7sBUx4`VVvh7s!A5r8<032~vmLU|M z{}hneODo9XM|7Z|kSJx|FE&rY*#`x90*qk*D*>H*PTzGWMf@Q}(Wnn&(f4?4(U5@8 zWDa1b6{^=dT-0S#c8-$y)gp$3J*92um_mxRG6SmO{@E6M%<2C6x@`r}{`L(=crD4c zGsqI;Du%pGaQY^zou1rv8bYJOA-cb_$&~Q*%-c`G+DXFN%SroO_~C43>64*S#_d=6 zV$WTc^6`lxE9P`35k4{eeeX)~4QYpj|972laN&Q~`341jrqzo-df1(RZiH=4_UtrL z81io};E=l+u@IE7uYbOfyBqnKm{CMTdG0X|j)eMaVHL->Ja5pSsC}f*jy;|E+t^LiX7)-rA~zX%#Tq>hoN7J+q@&sRFfY#YsvA6mSd)4DV@^=Y=_^m zVcNSL0P~x~Bq;{kW(@D%A|jru1XGVM5}W=W$N7-7fUC&Nu-M2{<^jv*^($XAPu=Mx zw25Pr4+tQAs#GKXd;BG|m1~kz!6Cle$wkld{)&i3Qs%$7r6=UxFMA}ov3wIGwC<}D zd=|a00f-Kuo8{0ZUZg8JGw-?GIZNyNqp3=4O?cV7vpuhNGDMS!=xWR}UD3npp{zE5 z5p4Sj`BPxobRIbW*z=YY`uud8e{0fwQCI0H@)Ip2yksuFU$sNOw!dVQQO{ovDaTh- z;bSYynt#pIGA}CWMe0??9v+;X4I{8;EmV>l0z9O~@?-Ry6Vz~~rfMyRq)hlr=c_g; zU{y>^P>?O{_xwrg8XMBRoBElXSQc;#Kiu)d!wiH)=wi2lS)b2fsKMZbN@pMvc|qjU zBZ|tx5Y}=%g`4x){7x|7+b}+p-~Q6jpX=pWMHcf&4>`3mj(m;vVxzZ^su=4NIEoUn zpq9r|UNVk)-QM_P5mb_E_UZiJ>nHUFPxypJ{wWcy#w!sAHN0BG_b_h?KKZ4 zKCb^&QweAQCx(fAaO;UPSKPuEYz#9ZertG_HlA*!4>bOimTti@XKthD^6;a7EuGjB+tPD8Om zIf4Qpt?Fv1q^07#<_vUZ-Ufkia5vtOE*xjDzRdNEsCusx-t6Eah0l&wCLtx!PD53B z{q~1+a5!q|xguc=eRpdw5@7=3p#R$PjtpJ^6$-ddY)U;qXTd?WgbG8os|)U)3##@t zrVDrnnv_&x8|+TowuPBKKRI#flMRQq5OG@1RM~}=IS1cDuBxlc!0eDu0RH7&XUO~Q znj=E79!M`vge`KPa`tyAgob$lN%=7d+dFEEx1Bp@&vW>~-vfe4=q^GA33^LL1gIn}AR#tMxZMZ+q{j$%LES2_thf61o+urc^O&+bA4Fb%76=cf338aJO=~vt1IW z9PoVgP840AyVy%NJjW< zjRar{-Duu7u%4+d?mVAe)5Wm%(SC;KbUrykaR%`?d82a;lI8L$t`d(Xz9fgVZv)E+ zeiS3g`P{n{5HrJ6jqek4gP_jRFnjib5*{%F`wd!#cl5U=zIRWwY~n@DD93y4`P){G zE<;lBA8|0sBr*rwA~p{c19BB037Nip54(*oaZFWQ$BQ*0lGztf(NHpu7NnBv>D`U! zS7+i`HlPpfTbtLf-dM~$T*f>ODAmrct1|iaq5_F=2EX3zSDq#y{qwwDTh?7z*(4oh z?~Qn+@eEC(GR%a9IWBo zDk>kyJN(>7*U#nr(fZeAgr)ZdQOeXcv0w6>y&N}MMm~4wf*nX(a$_XMv^-CbZ323H zczo|O&`Zz0TpUD@%575LGs%*55ooN(4~kPgBjHK2rC(4s0=M*QeGe5<1HdfX>#ojK zwqo07>P8<$?RqwF~hmsEJ)7Kn?k;8&@4+{;Yg~FcATcxS* z5%G~bnsD8e#8^8{!o$Cod1e%I|fgtA=>M_q}PI?D9n^>=(JI~%>K z8f0BOpQ|mO1nY5xIlT@BF$hO+3FQyVQdP;pS|HbHK=-aGAJdhe2$2N=$-Uizj&Np! z4julBfy5maI_4Sk>=_=CWADpnxa$^HW3tbND@wGEW-Co;HV4w7*UGm{%7SrRe%e3Ix#DRr6G}S6hRC%5%=Q)0&{0Rmtc~ z`RJCpT^}FYb3&_HU+9NENPmTWP3zz)%17$hPWNOE@40cNhmyvI1h59;ic5dC!?S^Z zv?E^*e=s8wW=7l4ku){EIQe_zeKN>xOWed2Wqpk4Ph7K{YHg(&>iPPB8t~ z@Fy|Sa<=0;F$Nh{ZE#uTcw)C-{aEYLGE-OdS9@>E$pxMIz4m#gPo~$@?ujn;@0mMk z=+{s|n#B4+&mwgxS%wy?j%DOl#p?*it(Vd+u^Ae3v@VF#sSFz&cet_-p37#vBFBm5 zAB2YK8925763H4{(9X@?$wQUX{P2j>DlAOqcZl%v;uH%#eU6hU%%N2`CFy%yj2F?< z^5Wb#5v2W1N60xoi8y%gk#?5Wwi8kfu68_6q6Z=ivhIEC5#TNVJMr=L=*(=JtjG|} zWL>9vs=V7?$W6Cfro8KG+o=1~^=dh;ZB9NPkB0-ie%pD0jo$cgnqcTGEcUQB`6UDc z@05gd??xM&PJqvE_p%UW)eIN6q-ri6lsn->fVUcEM>s#Jd3vfwx!}3F4zwW2#2Pd? zpONbIx;r|C+s};l=+(9ZCJYgqialm-oBytQxT$?^0J9lzgY>Ci-j zz-7mYpyl?N{JTr>1ILFpfmZe17oXwFV7P%GMrl=V{tg|UK}_LG~b zlROO`#DNiB@sUWsZ4Iwn_)NBI^xc&(ZrYsg%7iw)knw}TogvIW74IQhtUtnKBieol zWES7#BPHN&v{;KP2NUqHcxAXZlE?gK7b3RJ@ zQH*#oh^~R3K%0*(QJN%84~lxi#!=h^Sw%s*5Vw;xB5y<9`Ha*jO{@I!Dc}CnqbuLi zvc!cw?Fn|hDS4*C*Yt`guFb1jSFh4r+lFW2%im7z zcnl2;d~-wIM$_QPa@agIq;+<5W?||rYBA?V5-@sg1aSQxO$3~J$4HYe5wX#F&ATC=HN1VG2K`z^2IU-M_+tpqc-w(h6sshV6bjzi zas*Wd2me2!6pvDgh=PFI^VOFu&|2F`KWjl~>*?OS%g8S;%8WM-8VKA_^luU-MSzsC z5ND9I^;A7St}pxqp_K@n-IsPoj|93s1!^Vx@rz!$A-Q>X_IkC%3b?0@IIs^5QJ+3-UOo?w57S+r*P;In=>=7M!Scw{{Bw3LdXw2VDRXB1s;&HC zLV}AK_m6B}Zw#d}RbuMO4EzKVOp&Svoo@J>=4?owR&U#o8=ht>kJWhXu!Ezjyx%I@ zii>8abkREy^~2R@^K(6AyI#fMXfh3d=(^v#_7Kg;UWzBL9vw9=?v-&vj)8o5`wwT) zQ3-lEs{1?S)uj`Hq9~F|h#X<^i~2e>&NEE#Ed|Bz+*}HioL2$ssOwEG@RyuA@79VueL>TN{Lu*dJ`D{AVwL=Va{(5hZ;%gG zFKX=7tMZ1!HMOV0iL`hzw#SZx2SsE4(GdpT7~O?1&APWsNJ*(a8!JgGutdpqr!R_j8&Qq)1p1X3D^H_@E`43TM#-h zass;<5C7G4UVDIra{WA1vgPF7^8OKd$-)cQeh{R7l1-Ncd;1JIJxU4#ngO0XB2X&K z_Kc9}Fk#7VPaneni{cG@PKL~g#2!UF=fX?pzrDi_ct?K|6#GSynR?vWc?K!V&#$=d zSUvH?B3+E3aovcRdt!o-J*D>c2@f4bTOJAul`& zqoRj&9-j?QX)ASr%qL-@0C0;}YRfpz_tan`LJ(o3lq?I>`NMO=W zN>3M=2l_Cl8}>2&{Yy7=>Wa1|Ee#Y#kXI1Q#ZvLm>lQ8G;a__0l7ScsW1!E6qVEoR z(N+K4OTZYFbP|`DsqTur`Sf1{^sR;>hfPNCI&8Kk`!V*E)i^7I|Jl$0Md5zBGdK9(J^kR z$kgN6@PjjN5{RaK8S~vuN8QdGxd2u7@A>gAxIXO?J{~SU4xTNlP~oB;9rqx8c8EIHGEz5lwl&)V$o6gyl3CW4V<-vmh< z>eGBp!rGas>Y6;O5qy^xqASjG3=_99yVL}r4Bcw}`vB_Wre@9I0yhPIJ+`z zhF!VrOkks+Ahc0yb--|tkgK4N>-6oA0|$!2zbB8>4B0Z;C|_?7sU#?J345S!!z4^92Rr8nr#UHM zjssV7)xjw=GhgZsJ*+3DIzUuw2sH8pEk>QAlS#N`|J6ow=6}{!GI#g75fw}omE{mv z%yLJ*Imv9jG3XB$OEC%^B`k3T`v(>lv;H@wlEM#H&yXr4fr(x+6QTC5|7K0FOt&0x zp1-D)(ZrxCupQ%zNf+xgOCTrY&LEMg7WpMJ-Kp>K$8~HvQ{xYGg4P zM$!TCY~}mQlk$Hi<9@9aDFItyfJ4|=2wN6qm*QQEiH7P5^?Bgeudl%EkryKkqbR7JjO+38{S+BA)&a?( z)ipB(Yp@ru_C=(s%}*>Q8uFP49|=*HYAJ+S#w9Jwf0(tx?b%}hsj>Qugb zYdLE@;G~t0fA!QbAl^KWp|AHTR%QFhCl;LJr?>uh-ga{}(29z(*~32ziq&_Wdiz$t zzL~}o*!28FE;2HrfcZEPEGU zKd(_<^3{kp<+OJ;+Y5pz$EvLfG&S|HJiOD=RL0~Y0VUd9f6nmIzOwh(t;^7>Hv()- zOzE7Anq_%@cY7FQewX&%k{0fDxaL~tiu>ryq~YOgkvbAe=G0Gd0UUF@Di}UoS(Tof z8uGdHx`_Xg<0ACBH-b`1;CS}Hw#jX$Wo5I2MLu~dSBe`@N{{4bc)I_ZD%0mr7jP>m zEKHiG%T@;HFNP}QaLt8*lBjGiSNi&LId1y4q@N6tJd{{Do&Qnl&pKpy- zNyNe}ng3DEH>e?hGU^yw?BLjGCoGeRHB|UFux|wfKZOjv5kPcm-&7+%>B?E$8-Tdf zJQ$&E;1QO~|IQj1@|EkJ1;3w&qhfKwjvp-VCrC~n#^sx>JXPQZWZnwwZY|Gzsy9mX zoA2v3=n|v>*gF;;=K3tp_txneLWS#ENa7FXcDu#Ak-}uofA%{dE##fWrxVsFB`h05 z=ol|q_j2Kg@Ln_LNYD^AjwbE7A>G)~7tx}i_63Rj1oqOVRB+pUC~wLyUnZp?(~uoS zQBtMC&FRA@#VxlhaPWGO=9fCv?M*V0t4ThNew07=&L&>K2@IH_HlF6?#Xt`GbYn-2 z+hO|WcKlT5;50O*q~t5YEdjl+2&O|<{yqN1C35LR(_qu1{jjNwdEI&&OguckvvqFR zmAj0AL2Gq2T#9UPuKEJW55Lslq&_-&=w)o?Y@MIx9#Q0xEiunkKH^jM@}?p{U^9DI zzH_4Mk+F%d(v9|K((#a1P-J8&&rJ!V{q*$kgR^7B!EAH0H5t?ZY}usR2u!6u4QF9Z zDgGk$(p)(e~11I;lH7-ld@Y(%0csgpsIjDA}J-Fka@X zNo;G~?g0ZkTZ6AkP>dWdi}~MLo12UR-aaSyCA=deF_{79N2ZjLwzc*4xMd1A%#;~~ z0o#|$K*VLBLLMvqQJ}@Q%s>WI6z8*ACwRWrpt*3pbb$-(<9G*49s>akL`(|Bq;jez z+Mryss1`L+GJEU=H3b=WSZuCZqvYGya;|)}-w`Hz>bq@tBIZ3Df=Y`G=Bb#5enoEX z3qFTSVPD$AcZr4cV^>bRHV0b>XLBpd9qP+Sxb0^Kmn;DPZ@NV6r^q57l#`m9Y5e@y z17%zNAH^25#wW(!oqguj@Sd5TPL1;7sFJKd1msOiuJ*ui zn&>x^(_aVWi!s>d6&TOzYZ$q?hv*G?YNsFBW;~{;J6Hm0H*+T!T`AMk)9BlaH$S19 zOMBiv*UyES^&9M@(nPb(&OR}(vdeL#bE~isth^h@Xd^n~prgnex;W1FyuRMYoLv-tOUt_4 zQqq$4NPQb`Hd@i|#C~7K@I`fj5~ol;`x;8D0dIo?4MgDW6j6OVKT+ECOg~U0Dsi5$ zbPvHG^6mmED^QnN;Zw;G6vqR9u?W;-ge$a{CyxKkqP*Jav(Z^CY84xJD?2qN4q;WZ zvY>3>^A~nW(pdt=XCIkq@jB`QYAU1q4C4|aOqQqB85*7u6pqv^S# ztNIsl8yDT!C*r5g?$%&~hpdHnN;an0BqUzjW7;5$Eqcai+x22p8vMx^CE@1N)T{C5 zbY|w~iliLtb{z&tp#3!jJdv4Zb90mE#<8??M*)?{;Hy#=?9-?FdejQf=xE|Zcg}dZ za^Krq)0>dY{9-U)OVMm)=SqV}2(|7ooq^h-v8Mr+-STW)hcty4H5IDC-;^8H-kl_~XT5#Gd z$a|#%EgI#iKw@B^@nXQkgp`ZW)f%>Jxj2PNDwo~$DFO})cz6^~417WXgKCD{=B$5n z0RJBOpkKBk_jdYh4VF`*BE#1%X(fCPahYGgWX*>-233{sA}Qi zsEu%8K5~v{%t!b`o}ONC>xI3+il4bj<)R?}mBMUfbg2F$dznNh2ZU{qlCpDnvV8h8 zxu#m|-Q&*?UnZ%p8d^GfGmlRZ!U?`7!oD9cC}v1!>JCK1Xgq#e!>>7OB1aNH<{WTn zyb0y%vpN?0R4poWlt`lsGP_yoj$j*?$W>=+%*1jPq1ulKQD$X18O35+mQ{Cbxx0ZJ zj}Q5v5vu}0ghF>;&xQd%6xVB7I~}MTmGTZZD}+kcgxW70()e_XO9azU%}E-6!J9X* zo4wH|U6ddBgnnnKl;lNSHC{-6SA>D~V~Xd3=qw`F_BDhdA>mEtckxOR2nLp}PfWM3 z9&K%mHwZ7YBnsUl;)Lz=mBx!~kz_ve(a{6^lyf>JhTKz|BM(C~!m$U*%+ab}IVNNd z2Pu{k&sBiT{mqKKI-0wi8yJQ^ln$cDJ=#D_-1Ery!fuSaU zD3H$OuzI)`b85bT-j13nDMg2ehXZ-LfYT$(F_^@OMS07$XfszStu_NQoqoOlDotkp z<~tx+uTrG`^XI34`$lFVR_kBvroO%{Uqs0x&o7$LICQ$s?SyYWqL)4ZtnX&mZ6nHB z83pKd&)kqwhCsFR)sLj4LXCiu^s}E`r}Kh4cOL4p=85)xww{rsqz1s8EYMTr*t3=| zuVO2+9;@L)eTE^(CkALuE`L6Diu*S9J|%wzg_tjxnSlXXN`MUU)!f_NdoZXT-5uUZ zo=mB?nJns7sb9n?&dEkxkQG7RxbAUJaK%Aq{3!(eA!MoVNahncJ@RDX)zT$i3|`E6VrXlVd$Jw>-8`LOrjPd<-3Z!97;td_n|)L1nrDt zFI$=7Vn^$s0Yg##L1d*uV;qJMW||v5)B2H2jc3i1qpFaSiqupZyU< zopo8Ynd|JN8VGaZaW@z5UFB`fJ(M0d_z)yd=H^l&aAa~v9Q{;P%U+S3x2HO^+^*xh zNC|STAV!Axcz7C`cnlkzYd5s@<>az=F6K?1r}4Xd&cMSXJg+JfyxE_w&DX{FZ5?;i z#Zfo3)R&0m>{6A4`vHX!DWb)fkRW<*Yb~}+P*rwdUl`o$+5Od|Dc+AHPek<)Y^MGoE5He9EU9tILKvXhFePq^X|H3&X| z%1c_}B(u7%s%dD8);_-vFQhF^51WEI;#&S8&O-@(le} zF^?V1_;V-zm-VY-1;U{(-66YrH8?ZxY`a_Rc|$|>)Xh9abCR*N1X`6Tpmg^Ir^VJ? zo7|0MX!gk zOgK{Mj;6mwG$6GmRoZ3g8cvLy`)ovQdnv@(Wkc4->1nGKrs+Zy*xsIgwIoESUWBR& z(pr3`g&fi4sWY#j!7@MhCn<|qp5#$}i{m_h`W=AdN#(w5Lubx-mGvl0NjeX^iGI(3 z`klVF{iu3)nPMhaP2_k@*fQHfM+8cJ+N=XZtHT^mmfVHVn1bbpP>kLEQRqeg^n>ku z>q%7UgJTR{Iz?ksQ~CX#lm&@0^2;^~ctq@+h8_qgrsRt|=VE$5m!ExULamhqZz7U1 zhD_^BVm{|ErnkzOT5BCApEwa+eUmahITg@7ki;Klr@PKZ5x(A{bYh^s67W3ie#z1*d57q`XteCA{W#(} zTc>}@!OiW^alBYn?NaEo;X_6+Nkc)=;s)7>(^%gmXca?@-`$?{8V2azZRLttw%#N} zM=QY#SYdaq1-g@iaVZM^{-TfxCKi1~gT`YIcm8J>0XcSE_IlnDna$M@+xTDFhmI@T z*LO8*kQ6CMhH7O%#JDf!}#(|&>qgV5^9$BwoL$+1Ig*X5 zR*~fk!;!kn1AT*0Jy)dX=!CQ`043A7;S~@Fm+Sk{|5U5>r#}CACe&#<_t;sCGBl=C zihGa83m%TS-a%loS#7ze-dln0;1%5zWE!HSlU71S$$zJn+oqTwtSNA(lg@j{Ik`Ar z?`7>Y)07|LEf)9TD#UG5lsU3WV5j#dp1uJ+o%Efx;%f2rlHjhd61m=sXz+Z{kOL4_6n4F06PreR8ulc8@pJo;eo#O@XHGU9edRz-p)N zx$mJiN^=tro$#G}^g(lp##dR{JOTGB!7qt_Vuuewzm#_bl1U%&xi8XAb- z`X~PzV?E-%uR{&N20V3uRHYvG9W$hM#yK7Y89%w?3zKG?+^XSwhkFw0WmB(kqnZPc zpq*Y!SR?8H@lKUlzT z9+y~lMH2{k1{#_Q7e%7wf7DxO2dI+;r{R1J6S-x2GP%}8l>FTFPNs&R0vEf%tO{e* zmi2uy5BgdOGYbuX1O?=OxfOX+?T#2lBv&eRwTn+r&&){Mjcq^32Ewh1=t3rw;*+Uk zHC_ZG-}Le_8s0NREB5Wt(J+mF1L;sh~W2#X2rCq;GfV0l33NN zW8@M04GHoQ9=@^)gg@Q%JJ>99-Q?e3x+@ze11Nm?lW+%>HVeXdU29B^i{Tz@)%#@;0056?iOZeQusNmqPqk zXVI2WKs&>?GG46yD$6+eey}89;(^s}X6Ixxpa?$i8jYN-%(HWc7)asV6W)r^8QfbN zd5mKknSN+8Wbjy#m_I2qQx~Kv-$kRabz3N=*(iEHemku_2~QsX5cpIX+Y}l^KVUPb z$=m3)Z2XfuV=Gxce;iTkOS&k@sA5GsG&&phg;~|WTC$jtKM{-h`6uc8$y{~=k>pIWlJWd%;-3U#V`7-1Am1U)_7_%7POz{CA4%bl2Mq0bCS7u*VS1%)B zGFUgcg=^&E>N=3=3k2Se*5@kJho3kx+WCRuV@ibxZP$1V#%O$2kMl{UO++!8N}7g+ z5U}qBfTFB`lC=Q)#zHTVA<`h)0d+btRhX{AmaqhR1rWUXEH^^1)Nfmqc)bIio~raD z!OWHc&C2%YT)6+i+s&uf@eK&UtO}Xpr(e z5V$dp`jiNP=V{jtSZsbYQjcp9VWHXw!w_h}&*qPF-#vG|IF7`0?fg#kLK+jSw*A3! zmR?oQKh4I-tX@Hd2%jCsR=mj?({f&O@9%v-{ign;O#|jP2%hnb=c~D=l+4e|KrKiWIEoQ2%AllVQsF$5qWu0u z86eqSYSmosXD2uET|v3v5U&H|W!W0bKp>eI;EAY+;aP$Yg#CKD3y4=0@<|sHzL~2w z#GGCeq$h8(e~dA`S(3oHtT6JM>H>efrK`7tr+IaU@|iW9`8^M8dYSX)G}ih$oVRC^ zHph_1nRY~=eo?(t;q=kT5!X|!^{7YCSWdF_$L-1&C1NINCztf@_`p8x7YN(_WSqTA^MO? z6NacMi<#<`*;q=Pr~L0;5}U8sshIO15U}+7_s(`F5YsUs;R`KRW_y{k(<(bVR;H%N zrDV@f-vv{==cjr+4h{)`9UjgzUSXY;^dwS*X1H6Qt{8R%rc^<~4-w-Wwzmm2Q=)x55=S~q4^Lm!2cm2`tTs^@i?M*1dkdgdWF zuqkHKEJ)77d(S0=nBU1c)V0P1fTk0@jA8!Id6nq>$z=OGBlUBW|>5VB} zeB_FV^-YV(*$du3Cis}Ej2RA9VyxXp3+`AV+wr<1 z5AOxJb8>P3r&E>X_(l38`*fA{=K9B?>O?g2-8tVDf1E7z2Ia;ZnR!HCpB%>_jdY&& z%M9gFlM(GX;7VQ+09Nn4;>W`mp+-=0ltTy3_7FSUTK|n*-_|MhixwR>(}NkrO};LE z4Oq9*@wLjNO3uz|rSP4+l&ww|5+2M~bV)f8dEesC4*Hlk5lWxUx1O$$`!$Db>c86Li}BzjM^;0@PqV$i|ceg#DIhyMD05#I-2J4&7jDi3Qm4$=nJvL*OWkVBbVO~_UgW)w_J+B6q5997CfPp= zv&6N&{VJRvm3-wqtc(d4rLG0aQS$l`T?KEmh9l-l%5}dF?oY46kIQIsqU=7&8#u{J z+77Z{jd~&12V1yv=(t7FE88P&d}?7aF&q|W1lQ23v@~i`?i18%ZD!y@$)~YZ3VV6H zK_%-=1!O?tHg0RG;S)uVu;Th@XTwzhy%b3>cCE3bAD9lGaTJmmA}Jp5M>JML zNt9GPC-mv^Fsq>8e$V6~a~wA_J)=gglh%h1@`pyUqylV5XPv{9QS3$a?8g0`0NY+v z$Ik;aDq^G7%vGYH(E{wJj~*RylLKAgu1zP?CX1j|OD4H|ibkGp$2)1DM6j+3be?h~nRSTj)9m}2{NAg*D$>NUa5 z%)p#h`y@Fhj8RR?)&ZN8!wOo*@7>)+%M2x$G*im{WWNY1SPs&gwRbRaTWE$`n>h)| z-!=Rzb={pV*Gka33fCpp*73Eu8ynKmpkAllHpYM2eue^EhkLF#W_k zGPs0QsdOUal@-9$70v^j$5QI|LC+sq%`f2Vq^!Ns5YS=zbx0UgKCcSbEU`FC56#TZ zZUmh0wNBe+gK2*9bimF$MJ_uXO*(zBC+X0&S6b)dirU(`UpgAQH>A>Ju%IM)7ubq< z-_(ENd~Rq+BZ0fEi&oV?+?`!qjD{qdi3MU!6H}Ap*7jO^uZtZT+iDU-S}MJ+vi?W3 z7O!4THNtzgm-aRHi}UX!QO9nWbuMONmea!bfgFw0$4`zx#yLItyVqm|Xm^V`7786` z=@XBNQc%!*Sy7ekr~vCeqfQ+eQ%P5{cygV?#X7G3+(?F2_b$24fNrm~s#uzCi+?ns zD!g=gagpt67T3tTE@f4$|H{E>UQl3rdmE_?^!Z%s0C^q)v%7IWpnR*A)qF#Y3$os! z&x76Nco|3%D&Aghj12)_mV8}z>cRZ_5?mprYceZUROMj663+V;;YPG-Xrkn(+ChM} z6F3F?A?$O1?Eana;n@MG17${jk2K*lTwY_43Z`*#B1{E#r;mgND=Xb9 z{D&9=TidghyVKwrZEg)d`)6E>KA*0RJsN(9Z!9ieZk6>9d6Yw1KzypMuPb-;KNJCn z2Aqd7<9_ejvyO~2eb&08u|loW%;Terp(^KoF|0MHi(Z{_rfQE(JS?cLhcH}C$~H|#TQ{ulJ}a*)q_gGfr;qD?3pqw zgip+H*eW3T;IFOtpG5W6Hff0!y)xGhU6ROoB}Igvy-2r6NId87DtL4g%m9={RL!5S zZ}DvM-n+#CT~ZQx>; zo+ITl_z@~iB54UoFeOO{SO(`aTBWz{;Nd-`ASc2jFg#;ar5lIOt2M$a(a~c3fU=aS zs}d_|H}SF0p;?F;KBN+9q9zUOD}DV?o)V$aq>J00R>FB^rl3f`#`e~;=9YWHpODM< z{lxT>U2S)-TmIlvp~qyE7SnhnmaD7B*`yNrSJGLK1C%YJgi5D(!9tR!R!6D2MQlcIjwc>(Y z;e&;Vd{TA%7Mfbn%pwQgS=Pp@^J|R511!wn!m=6Ae}QvfivUR5OZ?b^x{K!k8Rv$$ za@F=~%D3*j(4EXvXP@5~&d+B)9HEcmg^O!ZS#vn#=X z9!So{)(HsQgKioG(9y4EH50EW$@|t0gM*}o@L6?arRQsyt(LO3+h{WX1|d`40~_*> z?cu)epFg)`HwfwjAmJY(H}UcUAaXYt>)99>Sk8~Dgpf^tjs}h5uEztk)yoDu)2S#} zw01IbaYGy=(vqGOe;_^+B8zdl4e-vtU-AL>`Y4*D5D9nGFvxP@1swAOZ51NdtQ56K z)2LK#sLO7GfIa_9jy(JEIiOzEwYw7IWP7H@miZs8rh7-zWXn*>!J@90^Yr)d13t@#7Z~3Fy_I*57~sy<`VxK}o{?Q&C;rXP{;2l{hX1J# zm}e&juT`mV)}XaC+m-xS5fpU0ff_*ZdC>ce1*mK}78 z(BH5a@P-t@6ilkW-}t`*2>%xZdFC^8@S$ z|NBh8O9T*SwBT0!&O^m{;y|$xa*C&i%j;|ZdNU93-&YmfI9FDXBPA!HD@UibV#)Ud z#6n29{W@B-|2`k`+46pme>@6=Ivhw_1AuN@@Tx27Od)wO?Q>D%nG1l9w+o^cgD4w; zt6gvnq~e^nMmmMwO0`%hLq3HBx_sM@k!l^sjN!kMYEDJR2$GiieZvAKR$m`r;`s(l z%ydLSl*Hbt3i(h0Y3U$h&o^s+s&l4Wln%_yexm^@aEN%t*3QOL!e5)DPZyC3H@sYu z|HJ}}tj%8#W8NqHn9B)42q)^il$J4lI#%aBcMSVdhLTIZ)pP!SQP=>)XwO?aplmkp zl$DV_iQAntAD3B!!+hQ|On7Z3+gx<~M3*$_7x?|T|4~HueK9{Ge^{>=!z0@$rxRxi z(iKMCt-ZkKfsxjSIQ9L{=A2f0c>W=QZy(ruXzMeX(wi)ymF7=JYFvK>-aS8>Rb^T3 zI$#`87U#2p8=S{lNR`I9OdMl7dZPRqNS4^Q5IehtgJ$URP8Sf0)NmplQ?IEQf!6w zz#f;GhTW<(ue7^Z={~CT&-OAiFixGI3wXaoVeL!@y1uktJIsr!$&+hcleL=8$&D8ANZJYI}H5MK! znUB;uTj~Ek01%W6wamVhFW=!yu!d4^mQjC#V@}&P4+%BZR^re0m>E3 zn~l-r(+f6ZgBxPfM`w6>YSw@?HS@lSEOPW5JnC+ndv1qa1jde(9~omEaWq5uP`tNN zoZ{M{+~GCe9rZ;V*oIad;_M9NIgw-tb5Knop%|5?+RCy;4o5GTmmRTfNJmFD2kD%>X-njc&no6%O2zD)I@#mf z^^odI8RFzu%li$y5mb)0PiFF6vnLk*EDokX(!`#Kz1m3H{!;(-iG9U+k1_{jL{Ut| z>u0#CFv8U=okBY1%iRIBqH!}Nx5N;#wseK!iT02?9HROi{8xSDSr47{Zg+}d zT1Fj7^%&2hCsGC;Y%T9vydbm@pzp7V(P&r}Z4ZH^tr*)mWf2;7E4f`kA9gEEIXh+a zgkqQ5TRp?W3x~k~;2XFma<>E5@2u57PTMwwf^V`4)UN;vJv*-AEYMbXWw^EsfkhUM z=9%X_p<-oKQGo?oZa;m8E;fA=jkT&^QsFq=N3W;@`tV_B^H?~wSay?`-B@P&tbgOw zs8_w#>B_QKktzIWgZ(8Fbyt}7!+Q|utE;I|X-SgBO6#E!2@zh-cSOPf?5*avcMH%G zHEW}b}C1uOhxkTJPIew7u@9$rmoYeNqy2WxjpiU?+j213s zH7dIehzgPhYzyP7ymjRs3~yTTu#q#ED|L0@sI1BQpv~x%08OH;MyZ*Y95%YGy$-h{ z>gqgdW>PSXQs;ZoiA8m}iu>hJIFf_%A{&26? zUn*ht$Q8QcH(vR!DaqQy8WH&AQe0aOXyEPy-shXWOGH}#;RnfqbzID=Njrp%ZsWi< zN`(B`R(DsIxi&Nq@KqkSE&-Mp*!pm3S68?5)`Y-S;;H&9q;d;Y3D;mzzc^IIYScef zyhVP_mqj*QPG{A%0VZiKIVmcN-DXdJi{&5kmKzpf?_igu;|Gtw*4z8FcZ?Ooam>ue z*Wxz=)O+s|_c1clv+<3ro0%PqW3AfEf}n{bHI}p+^0`XpUMPBQ+WgghO0Ez&7Der( z)dgg)KvZYfAHWn^ll=$mxk8O43c9wwRkoOKLJ#2YbF}^grULQzC;S%6AnAt1tQEoN zx`eG-SAB#dpVtvu@BG;j1hTQq`2BS;PPsP%;Tm@ZgOW)`ZFhjZ<*+qyWG4hF8*Nc_ zD9*KprxT6SHph5zT-N%UBEv;-fX3-5x3KgTGjsXHv@(i(yLHev%bhX%qH2*j+9bhs z`b5ht=H%0B_pu}6Wb-p5(b{AnYj4tV-!jSk$79jwghVUGNXNJ-5cT&DmRku@SY^O1 zflp!dHZ(n?ZJs5iXoohLf)zi|AD8lA3B*Vc$zsY8cWT@l7!q=MSr$r3_NImlK3-uu zZ`i811R@uzTiBgvWH7)Fga$C4f`o-(v zM7^R4B*KnI;rZix_xupG?nAqGd@-a%9fs>|H4wwnyu)OC3u42OZ+N2;f#Ci=eWHw9 z%uyGRfkI?E9IR44=67E;&oVaQ{B~ml&R1?^(a@xkNQs>O{8@7co@FHk^weAWjLssV z_S*V;=Ce-`SwJb}jG>!h9IFpe+E2UIVS-k@H!F=s0ZzM|KGTIVRg}ZmM|km8stHyl zS9FiM^iN4F(;VD>c(M;L0C|P1oagfnBq`SZKi7@2mWE#?KJgCeqpWTXQc0>|KIX2K zC#B-xuv@wq%@VM7mWV$cbQrE!#MhR72%Dr~iyVM9vz|Q1+B-eOHA!$=VQ_z|DJO@G zg}Z-j35#`29L0b_I!C&u<3uxId^K)|E*_rDn3i|=>4;e%GX?5LNcOerY~Z>7g1T8o zBIVI$nX3+yPD6%Run{dNsnFHRAqCZ%V~o7GD6}M7M*>a)w{rP_Q-DHC{0O3YXKUmEk=$cP>m&YrH8y}(7s-nDMIE1j|Qd`XN6NGMIRX6 zKe%DxKr#vpwo22b=;&QFMbb-q2`PaKN07&wM8Z&&=y0veZB~q6X~rYsoqBNI$g5>l z(ExXDoNooX_g{hHUZ;2`UtWH8Hujh(y4j;@NlKBZqPR*76 z+H;&9xC4{c3JO%t)KY7i4hJVdW&Nmp!w-kcfJk58^hAV_)Vct7Qb6)sw_;%xISjRe zgOMu0-QsBOm77ZV$nRTu`mC&*SoRJfCDZw;H}1tlClRsuJ7Ua$UBezQDwMr&*cs#7 zUsSj1U#z5@8qeWl%Tm{NA|Ce!Xx8@apqA}2$Gy~H=jPH(EQGZ`Y&j$7fDQ6y7?0xV zo2-m#`77)A7eMVPkg!(vUnR^{WRp7&&%8Dwkt$LGVAe$$_qpDXcIL#aQjX7)G^8R` zy=2!0xYa=Kt}m_A=5id*(H)>Ksyan#k(FI3r|0^Pih*n|NV; z=}vU@R*=_@sSF3G$@mzqv*bh7B2jpK48ZreLIOLkyc>Dxi#x*ZxT+{@WTvtkibo2< zWtS0>a5t|S&^20~a(;ew> z5!F}-x#@pZwj`7A*6Xrb0mwNL_S3$6*&E;J)9?;a<7M2RWQ|Xt1#}oVnP&I>jGisy z)z{sv2vym6tdkdhObvZ@JKi|& z>W&2Zg5JCPURQUJd!AXg0VZ>pDrtf(OEQ)1+&@X#S6)?hbG{a(<8fY*>9{!pj~327 zvs%#9r>qH+^>%MP*&X#>ufke8`AYud*BuF37em8LBMfDFt9Qm3ot=T43D@cjNobrY zii>eC8nfHwO3SLUSz+9)cY2teIoxUi zpc^c*&nPXOk*)cL#VvO04iLS|J6r zoCWt6%rx{9YZIKCU7dE<;%xGbAU>zF9pr`hj0s0{6cC3RIT+MzR`OFgX;WzX)mv)R1t~Zki8-4NS!2J z^;{(&jvX=Uej*|IMb>?j6Ii!w2O*0E>F8`uIu2``c4;HN>cp^x3l{}5~)Lz_9WMn#fY37ptC0hW!()lx1tq1ett|tmK*0II+Q>24 z*5=y%-I6mywY8;X(+=#>wIaIIh`$u@Pb?rkEo~-7+t5&RI0xxLi~+{Y(?}}59gnm< znQdajbMf6#Kl8n^EGu1_MLy6Ghq@WD)r%!xTHii2@g*ZbE|4^S7}n>a~{a2L9xKnNYT@eKAMSpa20}Tjnv~u*F0rr_&SZ0$O#Ed8 z_W7Cwexd|qvjCn%=dQgmD7`vm)q6)j%j=h5B$$&DXCIKsfhOuPF_itV;e>g;Ou9 z7xb#ek+Ymc1Ot=M^y++#S4G{Xb9h+4Kj|v+6|X3((CS&-(iMlO2H{ z*o#4LIj!e7DveL8XWe5B+2>I|C&=;e=4zDfyYdbWAI-xFE&fL&^*ixMqYfpXMy|}O z={nbGpyJEx%+}A>*Hhjn)~=F$&Xt{?e+y8EQF=K{8}b5{vpKl24okhBe-K4JXB;2T z<>!mGsE{|)%Vi2tF2RiGLkM?DEBwM<5-FN**&P-1jeDTYrq4M*{v}^?_g8D znNlPFruY7WiH`rmt?60eLkj(LAuu0GPD>v|A>>em*%spn6v&|-)7z$iUIU8B=2&^g)0|Otr6xS{0Tc(WxVr8a7*8Vl|Vd`b`SYMJb_utH_!e5(ni=Qbj9JmT~ zWaFP2W@+Lv><}z4;9lPXwZ_6acL|woBLNYkK&6mnvU6p9Y~_OCR578S9`HaZe;Q+y z4kH*WrPEuQs!vl=dPz7s(8xQLvu>u@dtcZbk#5WDys2gXa9D$- z5Dkvhx%d1wOq+B2?6Q3&R2deVn^Nofw$w7Lnr{J)g)_M*xm0 znm8M-F_oD;pIw5ah)H+shtXKVI7Ez=*$n_IwS;BUfvu)3z^=IrXO5jhaOQxom5X-5kV zQQs`MlTOC0qh#JLmDQlIrI~H)++!o5+g={0!J*889}LXHg_^RpHgEQmu{9DBp4B?N z5mlmk|H+CF$;ach-v~lBK{d6tB4Zvc>S z)aPcYPs8q<9OYcGqxQvkJRXPdOe~T8)o2qho;lP8n5uUy!ul5Rm--dv-sfU)Z!>qZ z@_zvuur5(Pwjh0IOM8CA6_>2(jzH|v;H)!o@L)!alzYP-dQ#V#}- z;F3u;jWG`s1IKI#^}pn5iNU0wXu zq_D!V>?&VIZW_PdY)YL8F0<{-v7{xarKxFNjcR3%o+v(l;JiKIebR0i+SQGHivHC? zpvJVLGhXEz9c$l5XWFZS!mlcz=qQ7~XinNM{A20e>0RPpA9khovJ-%=q-=@&H2ae9 z0G*>rP93$-^+bQq0HG4YRpzznLyhW(G?grcN#UW5k2?gSEE}vge?>WLaBuYW^J_p1 zv=-8V>gk~Xt|@tz@*#GCP+8Y=@yB)hyUOm1m825s=Jj_QeC}{OU+dSYv!S}qBuP%b zY|dAHKrZAJK~X;0c-GtsG?50zm{T`mFtl?+xm#S2Q#*T@e5%oWo3a}TNqP4?#heRi zn#)hoD6xB|{sQO1aq`qCm}?yCmOG41%C`|?P@5fK;2?zu!}`3fYQ8$Wsx1JzB_V1j z9-et5&VfVPBEK^4Ov!QGg{ow$bTUK3BHS{ot4CU9;fmQOgdex3D&i?x06=Ic!>j{u!2C6quxJvbr@5B#w z@*l=ygq-USA9T<|%m$C6m>H9q^0g>lRybyB2J%{L_moeGt1Ex#k?$%l%-&+(_BPl= z9epL=7ckTyRINaAYQ3ynvdd=(vX8u*_CUT*Y_=;Xt$C)kMPrWLNSDxh5Oeqs-Wr3@ zl5}u5YdgEhJ=s~`(1OJ1yO}!gH_C>%q5hqn2D9|#Cr`h+J0mnaAA8(?A(SQS?szCJSQjXR+{`oO&Abg+IWsH9!arNp@C4s8f|Pk%o%BYhT@h3vXR*8c!c zcNcMTNW`4sQ3%8X`A@O*XExW zK>Z)^NE1nM4y&j^cvmj6LCNI&)i;qKLBRC67+ba`6Og5efIuLtyYp%c73w96+(zmO zx+Q8%IM~<=N&bET6VuZqBqWNb$30960ZwlQ6=qTd>)mUr-!c+*HK*kPV+V51eWJ_| zg?t(d#L5BkLt0vz@@5MQaM7Y)oElc?nZ73?vcteYSvP7(g~skSaGH$}a2#&jQBhFX z_roFyz#%^xBV*NROj1TY+5|89u?oc-3aB#tYRJ=`@iFI~DyNPyweQAt-M=SY9ei)b zlsz%Xc?TcW`#CiKC5HXMC*bJ*+C#`KpaLi*qoqya&4~SXvlqxtv7m%zc4ZRl$DP{b4^0=x$S3 zpIwUxUPw2w{Z5UPiV=r8P46dy%5R^FpWq~Tq3tLqQ)n1W9$=te6ewnN3iA03i z031r4n~zw??uF9xF#f9xNxwRS?x1j*`}7sDRQDx;M?Qr&RS3%)28JGPwWN4khSK90 z-~F4}kN?GKtLKk@cFh1ZcHv_%J;G3 zDYoWm)8FVB`@*8*d3*vxf>I_zMhP0;r3}xVh{^NHeD9We@~$P~_Q{p(b-i;0oKds$ z&g{efq}q3Hi2oabZA&(2*Y-KNVatKHZ9S))i@z`+a`SOHAQ5nNxm1OjSt=Vph94M1R_-_* z!ji~0FreJX+TBw(muHC86?J`XOyE5KuI~tG?XWr2+1WYR(sH$&%MPq{H^z&i#nVp? zPA=!ylB;WL0|NZkkE?Q|O-QM{6IGX%n^ zN3RsGhic~sTF2IMrYEF$J$YSuCfnocj#RiU=lqAnRn|-f|Hf_5kTnVZ!<6C zqzF+nPrhYx1S2-6>(qCwD)>0@v9*Ktm~xT0O4*37cgR3qRnd3cXt$X|) z4lq$%QsmR!+M4KewKp!h*1xY650aC6h>J@U-1cu!_o&jp zLEV8N9R>j9Mgr`km;5j zG)^-s_8p+k6Y$<>Q#eJ;CBC4~xUjsUM}S3maQba5gLW59_#9FWAqoK`~bGu&Q*7nYIKP?2P?rvoUsw4{P z@M7_2!>8Y}_u@(*AACaVnrpaN=9H=UIWNB~JQRic4lXva+k~MQk~%?)TqeSA$(N zvE*k|nnp1>EDI9B!kFCi$@WWC{^qVhqdbt#g%{$^8>AZDqrXUhr4K~T*2Sy+L4AA2 z=d7G1(ofaX!J`9S^S}!BBOrXQzrMiw?msm6?sDI7YwrKf{Q{;i`!&zD4d1jhC2xBH z`t*p!G%ezj=e+z*Cnid;$W%js-nk7URIB?eIHO`W{cK{=yT%i>L86|5qpKu>Y=MVa{;foVXQ_NFWYpc-t2zvn)>01ZU zO)m1ogWmG}EhN(Z?AH#t#@HK^$N%BmO~qrZM%Uc2xm>?9W41>Tw9WUHH%n|*^{ULs zu`yG?V)`Uvm)PUvym=Wm&4S!}9`yB*yW_^8Vpc=vMyUMDu^j7khDazpeWVHTnh(wr zx^U;0)!999byAq)al01cHvhjdAa>R~Q{F-gzVNTvX;jg>sFj|j_Y0yYBWR=`oEz%k z`7zEp(BJ!3DSH?W>gl9YIC;3Dpy~LgN;9)QH-xHp@6ykFGM3&kOdFe$3*e%&G#e5$ zfehr%&RCYLIb4MVsBSb*IoX}l4ohBJ-qQ3O$XyCxN#biuN!>d-pl4!w=XT%OKc6Yk zU4BjjsQ)v|89%YfL)9h%3lmdU*`d-nydmNR5RiCUV;yvxJQyrM44Z%K0eP<`(z1a98g z0A#;v``wP#c|E7d?p%8br^@G#8X2x!R+{w=WeTyQ`2+--Dzh4aNumJvt5wf>_%)Oa zFxlUz`EqU6R{^EQ=bobwm7!Wr^W<&g}EFIy7Bb~0kzZ8qMukQ@APpga?{X&MGdP_5=xtI-dr1Y9wcUPn*!t)*OD6$*nwEU*LW-0Cx*bdNPn&JEUAKM%h1PUNM{ z$zLj6E02EgPJFO5%#7k*bE}sA7@n}H`sL(W_Qj>=?DnY^^O$O(NQtmLS9XD4bbYYW zmca|s$<|uXSM&bo(GuzWI@{|vN{ZGRCGzl5FMB4>wpa_nC2V~(0@uwEsG z6>+PtA+;_89w0mpdMiCOz8f0Oj`q^u9<5J0(B8pv?s{_22T=Zlu%{mqvcL|m!d$wo(G4hH(51c05W5`TbXeOCOQ)! z@vSqg-71h#Sqs9%640WdFl!8qOE!i&}8n8uG77Ir)DrQF0 z^%+GMLi-cz*QE3sX2P`gA8l7p2c8#|pOTR-Uv6FyWaC)zyI=eUA${DxuoXCNa&cO1 zp?aIoF>om8nLK`JR0n^11oY2i)u`N#JM6qE$k0S z!O*n4%T)g9z75tK^b)Xy+bzt{LsuK-5k)n#wUr8V&Pb`9cmnq;p3=@Ea(bXpqWa>d z798xPLr?tB#Up6}90|!D-+0tGqv;?@qxF;3flH&(A6_X2pC zki=S{i(j(?#lM301NTV?mIxvimsnRw_|dq#?VRm{LvTVvg1(yKi+Qus(BQfo9HE!2 zqU{ymR+nu%?aqwxvl<5`7VDg5C3ie%H-uR>XxboB(nKXcMQJN2g35``rZ!3&P{jmOElrxkF#Cd+fq|$ll-V-i@9IK8@8) z!91JuoN8>WiPc@S0z#nn2;;|OnK9c?(MlHX{(<#Wk;YN8S867yr*OlTiJPrdc$%7( zN&JsN@h4k)!*l)g?Ja$hOmCg3uDW*tL1&Ucxx0ui-p)7#3HKp(Z~sQsrj44?S5=vqQ+C}#{1SOO zju}f}#-fMCHAftXpoSJ%jg2*Bc|8pdM;TTBMm2w+|6?BB;rn>Tt>Xm_OE#Ypdds1= z2;*+lczX(gVCLh}cXl4x*x6akmkc9Q=w1~MZ}@qnVq*`P5_)7Ak*c?ket8jq8}Wn3Db{=BlBwt*76VvH=bMok6u!qyZCfRsVUeQrkPDX|UY7G9(^0yEZ z_`0}v1kus#y>t*9+frT9Mg0!8j_KK{3kv=IR~ zLSpR+0LS)fR00A0s)(k|BBt>!+-S1r|K?B8Y-%fKfV_sAfEJ}#Q@OJf4E^!05SXfjcET% zM&Z9d?!P&Ue-Q(1G(tn3wfy}DDM^1lMN@l)ADo=b+bi^3o+;vTe>(J^Gre)E5>|Wp z{Xq!57|t$&L(xBr0JyW>m9ZL7zS5_?h@`h%Hs2hd zV0j)!G4dXioBd<%)4t2!2b7X}3nBeq48g}=to8MmRxBwW(;XiXPEKOI#Bcb}x^#$q zPksb*lM>+HLie?(t26mGK`VT!w=@0BGh}iz{ zw2D5BI!Xqj4&@7YL{E1X7WxXbwY9xGguy`F=h@lIjq2}7z{YGN0g_1=NHdDcC$!TC z9=2%av<^0~YQ(+^f4#OfsbC2K#<)nZ7L3)6xZ_ z`O{wx3C)fd81X5RB^ILdisiK+&9@irm*C$1ev*KBjrY5yFRdA8XVTr@i=<@gU^?}P52W+Q?0F)2fYgN7CKCpZ2^l*@8l8!N`dj*pxnYFy6WH48W$dJg&ic2`R zw=?~z<@AGuT879s?wE}xua2lW4F42(?Bv?&Cwmyp4EM`<@Ngb8xDUv8Ro?udazDJ2j^N@&Ex3?e(1d_Kq-!tp$te(Q~*sP1wEY>F*|KSLx zYpx0{Ns!9|-i}AfYesl$f4>}SG!Y|Bl;b1UySY%6+!1q*KLqdnK&U|*XugxEYwcCN zCQwO6;Q>Gl-QRDx4CHSBhSGAbR3v}&U+!N^lcmvaAz`yMx`+=IW)*VAj`^5q6%w@d zfIxQ!yUT^YK|DR8TPoO|UABME^>NYmHF1X1?Ang{W^Wyi!)lK?XqR@b~WXlNQl|3hNmT$Nq^0 z3?h9+G{LOVT?Ro$aDFY%gsQDBtP`c8#^s{XLr303es;woh2LKMYCf3u)!vn=4$I}v za%WjVlj(Tn=typ4Qv6vd&^th-Wv)}pY*$GImY+jsTu>TvFBHdDj5krdXn2yRMj1w; zfPrrERap3QU41<+1%D4iKM2rzy=WHk^d!@gt^NMHP{6bYaqWwK zFp+(7S`rJTNCj)DzX~-jQY6B1soS!M)$ZqjwCq->WJao*jAAAx`u;L;`mUYsd|1)h zN7v0blGJ_r*M6PgYYzREm39w7oyFCxpPfdx_k)eI7o>DOxTwK23`xY}bUDI3&jfTs z2SU{{x+*@bgh-B!po7KI#kzPF=FMXWH19x%mt)MG1Cyn%A53p^Lv7;I9^zW#m{05* z5VAf7Ka`;CFMW@5Y)CfY}_a7ZLDIpLFAPEML0Y<)Y?fUYYZaI4^&7M zi+hxa(nWy-%0z)MxQ=6`tvz?Fc#_z>eD1y<1S$s~GY905gWQLQ&Q8Vl&h|JK%TZym z@Nh=OAvU()1I8dFGXx90avs6g@mKfx$s;!mY5T(`F*CqPY6VqUjHb6=5jO$2pXweb zPsk55_6_ROqE3)J8%Vsy>q?+Fy9An;p07H0tdyvtpR0H8xQLD!)-5F}{1DwF#f0z1 zuBq-lI?8gk(!OhCoB%(94gs`svV>H{@aRvqd#f~ZoA*ssY+9Qq=>=w}CR6F+DKtRQ z@8A8Tk}lckbPOKytKN?1Q2B09JaFfK)%7UVH&i;J`%wpqr|TU%QNHp)>74|yW8iME5(n$J zT22*e)#io*cH?i(a|!3y&oaT1Z-}9$-#dU+99!fX;Aof_?0aJF=l$dQp|CFB6=~mHD$NELoXL+H{S<&I$ID zVMGclS2XgoyCT+4>=Q*{X|o;~Ek^j~jP&S z$Ka3^%Xsc#gmCnsjP@GNa_r6&V!649-<|XSm{#0+s0TDOOY17JzLA)2ZLc*SG|L7hshry_z)lv<)klS-Bl(>^b z^?9<8`ywDhelin2wI%w81dp zbqk>3-cTb>-62L`rCfO4{l#c;byeN)eU?To(xP_(tWm!U~neMHH zy{*=0qkcEzgJA1oH(>-If~lCwR{cj0oHqN&M83I2nEctJM)KfBt#>+uAVC4`m-yI} zg3BGrDz9E?4ViH4_QwJK+4FN_N+B*i2g{uw16iKYcp#{d=zqjynGnB+??2U5pl zDPY2!A*E!?bN6YwR#k5Z>l=n+$;=m z$8%nroCr;z3%rW-i(%!@5)vW%xQ`Z+hET$^ME{4jw~mUcd;GRB5Jdrl5D-w5E~Ohq z0qO1r>Fy3ixz%*hEI4!aKIiQH z`CL~VOY7!%O}dz+4=_x(eBK2Zpj);sOHxiFd--j-DD@c-+Lmr7X1DzOs{31IH3(wc z=6-NYM8c82Anld&NN7dKvt1O;S=Z>*q1Qp#K=eoEaHMaez&tPV=d8=iPmG^IeXdI*}n>x&;!Wq zC?LUU;EbmO1)zq~mwqpf1oQx7IJiPsyX((x(0rfj2SuHIOmmpyg92K zW|~~E-FS4u*;SNAo#Eyv*Hvw=>>nMv+L4>4ebRfj;)h?s>Oq5-xKm@mg24c_9hfoh z%~&1^zCuew`cnVbWcPys>9oiDYa`M=17`RFWMHu~Qs>5zry!NCCg(-9$zsmD5F^Q1 zM|5Utf>ur5oJ1GZ-_&6+tY&j{8PBJX-9pKy9Ar-Ayw9pQl*nUlS80&3$TH8n@9gm^ z=La09J@d+aT){|9c=ume&X89F*Yeo zRF7s*4*J?$vl%#%Sr_b@2W2xqa{$`~xI@gwr+)kx z=o@J~IoeYp?VpCZM0%)71H2dIJkljr=Rp^rsRlDny0rui9aj4O2Z+fIKEvPX@8Cl} zfGjn7_l7`(rs?cV8!{*WP5z=j+Pet@$-?yBNri1H5)B2dJWex*mfl{(T0DO9*w_Su zlP(TDlZXRXfM`IzCM#vr!0%Ksly{{7T_}fpX#6}`@8D6jZbr8D#T$GA;;1k2N~hbJ zjvm!kn=WpiY$8~^duajyjMkx&S+JKY$o}477G*QU5>fJ|s6LKJT^)#fzE) z%Bb+MHwvWri%qRgh2IR3GY$6y-Vz9#%E_b(o-dC3M34*o5ct4K?9wj{7q=R_yB%=L z?fQ*#8xFR~+2`#5Z!$l~Kp}KFD(J^qa%$L?6zyU?@zQnlHW8Q0N)w2nIL_@Zb(Ht; zUfq~Pyu)t<+@pYh_|Nug7sHJhM!njILYGRzwbH!zC5(#`9GvV*>hf}oRnZsaM!Gu?d>4v#YiZ46n4A1~_Q1uVQ>->~HIc;! z^QhO1CHk1LOs9=jtFe-?7pPL3&9awo-{d}cPEP#tTYq5XBCgMe+c@KmhAyYh#b}h) z?#|9K?`z9`YwddHhr#cF;51Dk%Y3?r%0p zb*NiC%-gA(JNvY}yp)2CHU19_#-)Qy1?`(F#GEvYAa7y_d0?2A$5xhR(*_9mlhsQisuL&aPvkeHu+9w}h82COuq%fmC9jVEWJ{#pdF zga3iKj$2xyHEOO?Mk%VQzSVNtMww+RJn*@2Z2H)oFDw619~nAPzP()D@8NztxA39- z=@Ml>z5f`(e_YKxF@ER z+n+p9YqmOE81P93UkUJem)Bssot^oqspM=X4d@0pgtnar8(Ssi&*s#}+mFL{|6k(U z^OfYI|Y%?@k3#0&L?fQc6QnKKPs!R zeSlyR13>h$#b-Wz-^2mFE7U(IvmA6@#@gB#66{%7T5Rf_7}snL39#0w@7r^^_{sb< znxBVqG;eiK@15^1NcICKu_#Nr)hTnONn?%PB%>yuhqYwhPY^F^O8}ztaFu5aJ|9}* zS7zC9Z|Cs*;`h<6;bzU@ISjCUFx+Q#Dd&^O&q%3pvWWs98t)vg&+dAhXy8L8#Z8xL`ot$7pw zKLUVR9ljG@g{Wnz%3Q;8htW#=gS}|b2mMM8<}gg*XGm$h?3r@lOxMWL;{ zwOEC8sSztSb^4jY3|~}Kp3Nyw7H`I0K=tGi3)0|q84ykz4ljI^?GM&?w!qVU%fZ^k zcJd*B>%V`7dA!0& z3@6kBq_D}+^<5t-92S|&G)Vc+g7?%Bod2u^)R5KNEfb_bx$Emx=#nvQ%)q@P_Ed90<6lNfuwXyws3xHq0rqz=BS)*oklkWzw} z=%7!EV2$`*-D+4ACZ6SdkW$x{%J02I&Pgj8nxp7=vSw{juxlb~YvE)&C4*-}f&F}` zIa|!&jHfbtU5OsN9XKI4MKv|{*Y%GF{k5=+7zpN#P%QEQ@<;c4wjh1rh&}p8vuK46 zm+GwfmnLLU^2=oc2}%;t2~A@c=2^LtWW&V`FR2OB+$#UcJWUz3U2C2B=oRvbG-Ge9 z2~sc5aL;pP2?C?gwS}5pT6{?vnXKWGhvOuLE%y0Tq}|r5xEN8d0t)ShRUxtOKeE7u zuBxO2kBeAkAY|*Yvs3n95C9Oi!4(MmKlr~p{O%-U?v99vXs+VN@;b@-&Vn8zGTHZ5 z0e>=&kJ~sXyR}n-wE_{zfxV`r;o6EQ9ZtBR>u`?#|07BruboYGcl?2H^F5c5oG^)g zLr|LS+n+i*ED*4x4$oWJSHN1V$k4j=OAaIq0PHU)s4SG|QJ4UzmH3^DGow$RjMn@0W#LkcqO(10+<$!|)4ZIfEEc?RPo&)Y%==m; z?v+P8BO1rhSESv_X@uEz-sY9;cSGKTDX?PGZ80-D+w+LW)R7=NTiOrZPorCIN5E{?7!*~3u zs$|NZxU;j<9jCCg3}G;He8=$nZX!ppbLQw&=XU6&mjs?QJ&81Blv?6q(1S?ZL&_{3 zAPL(>PMK@UGXSKRL@A-qzS)RVbGrWOK?;D&Jka|A7csdoh~lQZXvlt0OQMr=I5#u? zB^Auc$Zw}vag#bw_v|qSRjB6oMg2;%a}sx&WzX6!uU`eIR#|3-DHu}(YfEw?a`WiI zHwVZDq9sc=7G7v&DoyU#XKNI*lC^`-|EE6sq<4@B)(RiPL<=+HjW5#C2q{p~vM_}) zvwR=AR>`LdvFwYV8fX_Act)iN9(|v%TfW12G-=OOx+9Lp3F!}0zJ1tgmH9po@OD4~ z;BmbOtB8f<>2)NtCQ}oasT4`tL+Fa1ludC5l~+~NW0$lQK8@a4q;W8wU)UU4^${oD zlil{5`AEeVLm8_Knks_oDvo#+4FD@hsUe`P^7UEFDCsJxan4$Hwp6^^JkZkz=Xz(? zh6pnQZZ9fKvBx$!mcnPvWChfI<4$s^ET^esM(b+bMFlT}pByUH9M={5sSf5(U`9~`7eQPi=F>@c`ukT)ZXLif?9)%Emh#JjU5YW*;)t?Q+|3O1pLVGY z8lOI;oLd>Th{Rp@m=Bz)@@%a>J9|kXo1(J#d!GD3{%FOk`IhqacHHjvz2GG@RJzZ^ zLS~N55SMyxm0l@>G_+QXwwZOp)LlpCVunfx5*uSLJ4}M(^86kjAD>{8`Ml8v^XK`B z5D+RF%E@QUlnf?nJhLQR`S8O_*}?2OZ%Ra%_0|1<_IBGY*T%hQzQr|E@nJ|>quF~N zVRWATwr~9*v1)BjSG?Aq+-}N%xu0aHX?hMMdP!U1~*t)n!!iCgQns z%VCU_yw-3I(lKf@qPw_&woe*6h~za7krM+$2)4r`JR7(Ecz^i@5%tGRt!OALGc+M! zI3u%}rEN;Ie*f^xdrAU&`l@k0vtI>IPw9amG^dGeHErKVD(T?l>{xfjk&A=qIX<=t zTnMgSnRAXMpwJCV;dl2nC;~>KwK0qDKnJ(DI`vYaRpox?QYyhN|s(Ud5}x9ZMY zNdl%VbAzI7`M7Z8Qgr}IBAr0o{}NLT8~)OIGd(x;F>_V*fH`{~?g4$csA=|jlF@OXx?AKBj27X<7oun?) zJyE@xbJC$j*bJ%E!}H?t*O*}@w~c#5+XYaT2T7O|ni9kSgpmbx0cm2GBcpS!_)W5A zVEup>(`y_Oh&%>DA7yn4Yt4+;Kh!S#KgpNiFqSkx%o3^thK>@mQ@VrdxjrrPy-j*& zbgQ6L|7RVFn9eM_cT_Di`qXi-L`&yz(Wkc#kt66i7r#Q)tp*GxP(R_iqE+JIP>X~O zb>(>UfcfL5SV>DgV51Zf@lV1j>zH1rh#}POt#huTEv>)x@s{Dew96l z0lcO+h~RCeO=ht-cwW4~6z618eOcR<%Y=SbqBHkF7qmj#IH2z~1Ij6%L74`y9hd~1 zBG>!(bEP9{#Al5~y{=mGecnwQT#|f5@EhPXR@j}JyC?hsDgg=*Y28ucc z;2KVn{=FP$W}{E=mW<43$ue6gblc3|=8a80j6gVL7VEeQ3@KEvdD=`wL@i=&I{ff%ZhkB_h`Zs*? zHU-=F5fL(uC@Ka920A*0{35%l|G{-8wO65GCm=AOq45{}O{u)SbO>ejQP^rBsTSO5 zapTgg|6TT-Z97gxm^@7u89Q2YRC%C~pHg4gp;Dk|5#vwQ3d2lTR;MW;u<3|0cjIz) zNQ6ZCHE2=I5z2Q%#_FuZ3S)cy{BEQqC)Zd_DR<{z9JW$My&rAznYuW?SBybOKu~&a z;RPOb-@SY6)wwZN>9f(mGMXY$pD0We*!(<6iDK?5hp8uk`b|vol8EaNa1jus(RNf1 zXa#?#;y&5o76^M=nnUda*TWT{6?OCJ3%|t@-fL**BPPH$X2~|F_rX(jxgJ^Nt9d28 z(SOpr#>Lhui?4^a3!tj5^syS3#uS#;Cbg2F6UyD#_KC0F-c>6Hz%ihT9gmaY!#d1D{b|UQk>3dE>FQnSro^=zib$E=j4`=LRd8mI?!E$ z-RMUbzA9f5ktiNRXQwPcov*l842dr-J?-m`3r+Zd`u!|j|D!NP=_cXD7x(#)=poK@ zwJ%v)FB?@;&g@ZHT{v;1tB&sK}aDO;1&Hu_e2PIF3l_UAivnx)wfs2JD)9mzYS|Cmm3>cjr$k}>zAfCZDBp~i3Ujy9P>g>QO-uWvYzQk9uU3u1gnXWo_4@Ygc6 zsJ{fv8@MbvY$JUT8*=^BKBde*%|*}lsSqRg^oen}M7IeT0W<`6t2FlUd~8zpS6c3h z^=BF7gaxfrjacAWz30qPrEGL|eRqQ8k%U;Q-U-1vQBYD>?;LpR@%Xg>*hl<3Ry)$H z;8hYB80YfbF#Y{+)J|gvj$ZKoDjZKx{rt2aZHQGF_#M!?a6LY-7Yezjl)SjCOOn;I z7TsZDp(mwh*>W@Y54-l-@9ICmSiz9cvpb@UD%LezF`c4Cs$`9&7@Jlp7tr}Yp*EYT zDW*oTCF8EoraxuIy(=9Md*?A{9LF$k9yKbTOH>z>73plP`+d=;_C(2iIsEk8X{S4# z$o6HkWGS+njm>d|4;FnF14AtsdzYbonA-jY1k3R4ZKM(VXDvWnTZg#q8$`HNowwoun zfi*FOJZ(v+%)rKx?N-uAsgH!e@92NeL?5@RdGjcCfrv@1NqqI8Xg*OmBSFE$5k8|J z!5ehqj(rv|$>Z^c6n;^=HdG2}D$*(Uw5zWvjvy0iCCQ5*8^3ky#OG+hqz4-y%ug6% zN9$ZUm|6Pb;)tg5o^{OL@qZYu@q;MD(sF&bLSdg5<$3>`{zGn$n+)^zxAe%sTv{>M zHGv_30!cHO^!wuzY>iKIQ427_IK|K>bM%dsbuYNTMGc{;UVIm0R?U53@-j!2j)Pps zxsRDsojBW_Y}4LYB}mtBs_b`VCl3`#aBlG@YTdLs-KWs>C5eP2Mfe@5tG)GF?Ih^h z(NSgsved-L*tq;w;9wz94*x0GKXe+2!7{5hcXJD#<`m`6L6|2CkN~^r&duu~&^_K_ z1)Yc++P=5$T_aQ@x~X-f>AL?xIs%Uj~MGoV$9Kq|K`;MzOC@-BNUqmE--lExN!{PB=tr1{^< zaE@Y?db8bwNaKD}l1J4xm(NCgd)znIb>MZ1?%4xs==99guk_&(s%}yst&zzuX=J*M z4ZFhcV%#kXCAg&~oDMLj&S3AlXk)p`y;#Q7B6pCuOFulQuHeH@I41d>z(~Hk9FytS zm<%bOtgS1Q7{@_WP1!ZbXSr~lceZMfD>3QPR(E&0XQLr^s8R_?9>CeUK3z{4o_b6G zPU7!t!o(wWPDubje+~d@H?Sh{2?e(f6@vb2g0^4{{4hWlts3};*Pb3@!4D3w5V}cu z14FV1d0{NE;3QJ`%V4>Q=TG^5!Oj-h(hX8da^uX0^1KJuH5O=ewQF`tC6Ua*m}ec- z8xMoORlSp^R@9be4pqgZdxz@|*GWh#rDORUx=7*bUgxv-qaJj-h-M$nvQW3tyl8FL z?P77o=&MAbQQ$2kGn3LF@!i0bqGJHR zD~2fnwwq|(XshzlZ(BHuxezrX*PYhht;byWaEO$p)lHmTRqc6rOkC#h7Dqr0L$z>J z#5TvgQP)r5fSIYQ%lVKZTWD_->=WDocx0Tb%&Bntd&;Pe5A(xVJiM@&*rB(px7<@? z)W4L{GeG3Rj4UkHO6TuLIDUEv3u5pTm1WqZ=>ZQY1wXH+)J;l+|H(^YH7#r&QOJYv4Z#m0wc}6Z@3`VHxGlc zUk?Z6gsZ;}eEYXRK=kEo#}9!wKc*FR)5@1ZdD>E+=|}a;czeyBC<7*j+WFvW^}LY= zd)HOw7ku!ru6}3p5F&{v$!gd;0bM9AcM=lveN+tBjI$+gt<7KBXYiB0y#Fnoe;mNf zPCiAXnj`)T5C8yQ z+g~3!3eY0?P53`UudiHWW&a7GVvI<1kW17Y9LNv60*jTxpM>EJ@X(OZuPnNCsZpsh zF>*?39V@YRMxLa{$45tV^YhwGsp`56fAWhMdRBjU{-e!VMoBfmjsUH!9%g&{NQ|Fc zwzO#=>#Is;@I3x9*Y8 zAoAp`W%>%Hd^)>&^bQpv5b^p%4RCavit_U9{ap(74{9mJVf!Er`seg0^DDVLn-k!3 zlhD)ql^;zLds)`T_5qTxz7)>p0kVwYou2wi) zb~>K}n1EebH+#9IG6(Pp2%iW!SCy!=g{Vzv-rTz^@M<(Mp;R7A0g>I-L3Mu3h9+ zuo|}ytnTO2bvl)?s$gCt{QI~VO50^9|6gcCrEJr+>})F1k#iB*8=pP_ePw@&K&Bim zec)>36P~BlQJhvIpHiQULKjycLn_7N?^@aQ58pr_uPR(@UG0ZPMZLXq1U3)5{u~xV z4HiiCePt-S@by!*{RtL{>}TcJ_wHphiHirfJ^1<%XPp`ICZ@ft>iI>eM)t;FHK6hp z6oo~pF#>=P;6j$NUU+H$6W_*Qp!tA@MX@Q0d3>y@@D-MunyRyR=x$tR_xTK^RV+HY zyxc6nL`N?n)A-Kr;a>-m*MDhk7&h+=!GqKr=W$b#{<7Ok_ViI1q14ZrR8Wksv2e z1#V2}b9U00+IrG97RHXh?jBcP5?(@JHuiM2h1rj1>2`cBD~}0@VSS%^Q}};9>U&h56}SX%1m3eim)sB# zaJ5YfZ^_X#n$96)(u8@`rU`l}q|1E{@Q)aaHcgD1e0slrO-EuMoi&Y=$kf~W zqq&q-sHv#bvlS8|p5ouZ!t<%JR%t8vtEqJyP?EIS)?vssl{|oglh}m0`fRx#TJ-%H zk#cN0uN^nP{=9zhs|*a;wQU;8OhZRrD=;7{EAJ9X;S&%5{qAl5jGnMCp^GC97QQ63 zPYy$LTAHl9#v7fI=;+YE+}t>*Dp_e5>u&IX5+Tl`CuTK;b5YzQi1 z@W3fhtc{=N^mZBY&tEk}r}XUR z%eMy4Q_cn_G>V;p(|l6UdnmUy@AoQ;U@B_Cr~SfHMc@&v|nFzI{EzBMzVNCC2LSxs})?9d*Z`cDD6?LoR`0 z*1enun;b%y-;k3RdM6f-I7m1Og(8J`KP=Rj`m;MD7Sr^_h02G9`HN9&@$RW=6#Sov zj-T|yTjwn>9R$_4kag03=E>h5{XyS1Q5@`Cd6Y@4S#wq^z^BGxBf z7P`zW-JuZ+{M;f55GHr-#4)$gs3>(1WBC5%9vg0G;P=)&_L_*5uX{wXCF9eBurTL& zCYx)(gEg8%KE8lx7vS*2%_8?P5Z0G}b#+dFeIrUN;NHrVCS`T{J&-<96e?AN#JC0v zJf);;rnAdzZUr7Jh<$57?*y_`?AQyVj2A4(TZ@z;9;x7c7M`|YAcR^G7ESSn8MO`z z!dY2|^7s#7f}3g+f)=Xhbsv8J%H>F$NWF9QPpMJfzul;tR1!5M7kr>DwdqdK?C z>on$*^JrJ($nGfF%%`v9VTV8qJq?+SqbNO6+QRE6`#S*iEgGSP_K z8md~gM9y-o*8TEFCJzs+r|WjBW83d2Th)+fa zNlpE6kEW&J_wR4G>k|h{lf%Qk%GpYgSV(yQZg{PqQ~6I()TQ?C^TbLjxQCPO;Ueq$ z0C9su8v4yxA^jfzN5KVxH@TNMK4-+dwE9;k!q$Zr?tTF?p_Xm^f_Lip#b8W z{-OYQbp6m|ei5yzyu6H9ZGaAc>g%V2%k1vpU2~xLshhxyf7Svr8iIHqzka(njm4$` zHGk#06l9I&1@B5>qK)Bm_97Az=B}=JYK($j3#dI8x~7fjgT*({g3e$?zDu_40f}+VbQFL z$n-$*?mp>qh#2a27#nUHn}-A(l-2U=fmm{eNUpWt-|xDZA79&U>|Mkgr>ObG;`=aC z){#|S_e_7EE5C~=%v;Ur@u38{x}J<$BhwDutyID$zF}%h``sK-H$OiY^LN&Lx4u>A z#fujMu`Kx56IIr)9NMaW|Nj0jb{srk{K1Yx?Vfs7nsFrVS*Ws5X$MU-iW?e<6OLcS z`oZvhLEWR;WHjR=)Yo|KDiHT7pC+CE;}spJGhB zH1KLt_|FXgavke`X840lpC4{-p2ZVxx zfY+W8OscZmY5hVz?ly+{tP`k627Zyfw+Gu^bt@d$DqnlzW5--yYT9_|H(bmGo{Fd7jO)#Z*xDH9A73Z&8M9qHdYx>fH!0MvRKj`RF7s?QDhd z2|mGtxmrMmZYou?-w3NtP64SP-{Ctrcd)k(5mxRSO?wjkuGUOAWUbg50MPMIj5CecNTe2}#S4G8qJh~ZP{w)20Utsu|S*L0Ov02f$ ziCsOorM{e5zGF}xUk4Wb9oVK-mNhi!$(mo~sX|e(_kWn|^mrS{vjfC(wAg491ts*3 z9Vr3yM_Jc-xzmKq@M%(CnTMrMrQe3Ho!y7s0HN6$n<7DB!0rmOu;%sN7hl3jc)1J- zUsZK@jx77NGQ|UO{bL+3sDtVIwKYqu{mt{=lMY+XaDj6_ia2Ie&2yP_xr&q5|2@-h z%;tOR!*oV#Z=y(=phLt}E}Mgrvd8gexajU!14}H6?qG&UWi*W}k{=qhlp`DF9$S*L zIc}Vn!e+Y^L=L~Tb?hn8SYvr+(cdTC?W4wi6h#B}G+>tUosbyG9_*{&0k4<43o=gI zFoEx4bsql>GSxA`V{h!#&6-KAO$DAJq`M;W_K4i-vFdB7(t(uYWkvmIsZrNPvFY1>5@1;5sD1o;+mNDKV}G@xRavHE z(Tg2D+Ux(IJ(4`{tCrm56?fgvT_oCNW8@UD^F>xo(bAa2?&Fx2nIy>%uuH%{xrn2#Xvj`Gu((f5g zC|$@4ww^OSc_O4!uG49x(JNk2S=OB2Pf33Kkq$j0$aD(`5LM_<2C-}&u#fq6Gx+bz zLJw@zyiiD*NPO`$W2#z`Z~p{qpVLi&G-+w6Lov6n!u|W~wwp$H!a54@wC520%;(15 z`){z-6X4NU(r%jNM7|I{x0Ai>?#|=m<2FGQ)7?F4e;k$;(iJw$TPIWW-)95_?X|{- zm6+i>+q;qLY)ffP-a_uCHqg-vFh00FPH4Rf0asi3gAxK%DbA;I*%An9!!f$i6G_)l z{%31gn);AVvPsBp+m4W;7hYv@REYhib zhdxCYp95|+U95zHs4UpENd(4hkEER8FNtWl4BDM8CIlE5I1bVkX-_1Vl}j()HfeK1 z#nv!xjr3NrzX2e2wBae@PSTiEh|IdwE|Dw?MfrOzuYk5)0f2b4wobiAKNa1lZBS~W z^XU9Ef`^-Xd~6)aPhbSr7Jw8%`9!hfJ#34N$SPCn2RDTLnINi_Lw>Z1;i4NB2BXn4$ z&7@iPWi=;TH6~7^jhzkWuYKjL+FzZmy`zDR4A|KAh5aEjoO~XqR8wc0!MW{~Bm)cz z`N~z?h}69rxuI^a?g8vyr=ob0+X!@j`p4i9Y}xm<;XiLP)xk-|_oDXZ1WwF3+(Bxe z3~k)=7ZMWfs7E+v9#d)3vMivx=eo8E(0dF_4Z9N|Xu{y|$}uXiY%Fi7%5p8XWh8Zy z3sRAB@-#nu2!S}Gqt`|;^>zPZQ+oFK*8dd(8!BP5bO^XbUVl>9E+-!UC54TLsW!xB z-QJelE-2g7vgjJ##<3R%N}`brXd7zfHT0!3j>GcFb_bXd`R3unpi)SE)-jl+xJ`4N$cm znet(;hX9*njp>->)^~4!!W)B@uBgwn1kbidlFn~z--$dH6XmhJeG+FeF1g@I z4_iNS>z2E#YpX7QlKpYcL)*4JdWP9VQEAm)f_vmo2r70eDhBBV=+H}iwnsm1*nyOk zH4hdq18`B(7xM3ZkPDVUMn~h+-ywTHZ2!=`pUyE)=PZOT?F#EYWs9jZS}f60mc&q+ zaIh#bDNnASjN%Rw_y8%}z#8W?CH+>L;31*eQC&4e^3y;A0xj`LZFuMH2i7vI3CoRLrd*U*8aw$^In zNQVt?T%3C%JYo?k1@j%R)~VmIQ^54cGI_0rPh9@(3#7~|x~v)e%yzc2K4)_g3bL{^ zYCVPuks&n3&KgGjYnp#|@5mUNTrUN9>S&MCpi$tCP+#VFP zwSnf9^;oS=*!0>PNh&?!+!y*sQ^j%LvcnrdV#(TtOkiHKl# z`|vJaA^&W75#mU)wUqgmf>?0w40iX}Z2?dE)7yJo4gjbZmR+IB(bL=9EWk?X+243$ zeWDsTiPb;2KK5GP44FWrdueJcPB-7m&QTK3addFN!NWtBTX0D~CM0Ba8@%bhzUOkZ z^#eQG9;^{^J`}Hawi+c{X47+prh38lLWr67OF1tNd?A%F@n3-d^%pUVKd$n1#{86X z3&cI9qG6-sUMyUfy2hDYn*{nW!p>;ta`OId6M! z={P$d>`}dRsYx&AJQ<>Og`aY+72v;^lX$L@pVOXh6=`v+TftuA#&`*^dR^*N4px~! zvNpZ@)2D+&?p?aI7Ob4Rd8Vt)e2cj}WO}!(jELyB(YjCrHG>R{|5Gy{8@tfA?fD{L zkxNg|3W^4@y!%PZrp_|nK;cdVb;h38(&{XFt~q4_IY#=vD%65gVmo~O+F!Ddv)Z_> z+Dssk_;$tL2c%xJRXVRfKNCEl@T z^N{lt9%M62)!YBr?y8Y8vgbSUUy;>nFOZj@5(YbK`lR7VJUY-?SwtImjU9jcPOzt- z5GCc>OzTa<{+2Ase(A*V8mm=u^gZaV`S^>(i^K@MP8)_spYwIRddE!%y-i$R0Ul31 zm$(i1@*6*A%k#j{s-?5m;osa+G?!>Y&Bt~}_b9*g>LQX4vlJMrp;|kT)pAo#p^zX_`5esdyeagx@RP(`^&@4eJT>K5DUE% zAUU+(9LezH$=YIHN-<(tCQb14{7`7%Iqfgo^!N-#!;%03wJ69qNj)3X|N*BV;Ylw_3_(Rj1QMyI{^bA_cOL5M|j)iZuXEV_0uXm7>zCSp5Wd@MZ3 zfw8{$UMMGh9f@j^a&~c4&FIR5E$}QeO~=e6DZ#Gj|BI{EqWz+hi`hd-$J!MCRmJ{N z4jGM&#;c5m(X$i>+VYu|Re3H^N%tlH#k`L-?cYRRz6>%Rt!vk8e1<0d z56=5EBV5OQxJWRD&{!4rM3PUKmPlhcAyq74C;Z%WcB=58#p>J!@J?2Khhf|$`MSHv zqEmbSaxk=C)_Z!G-Y?CXaC<~bZKCsftV4HamloW7tRuG#aXg-WUO#eC zo{XD)^ZK>(x$NBR9oI8*IM&_@-xAVjYHFuTF6Am;7iBi)TB32S@DUYN_Qoet9M7#i zUgNJi%dLGzN;I3qY4z}- z{VZhUCA6Z#o;gFIV}1{woB}!pL8-=BCR@B!1Y4NHaYo567}zAK3-4oNu4_Q;o$cwF znBca8sic8AIRz$M&U_h3HCcP++p1~C+FVb5)>u!`(Q-ezHge;~9<`$v7A{w@m{e{l zcvZ3#;?rA8QjstL?2GCWwmc)zsJ4lB1vqM|N0|=VA@F z1eN`XP7}>C9@TR#ccYX11gpS2Y(!E;=Z64YoWBV0mOniHCBWw*ProSrtn;Ww!DDQq1{Wvw+Gg&cXCcG8q|IKrS>+QYpsDub&Ua(8uDQTIY`OU#9^%b6h;4{7WQV1Gn*TklY)&Pns7d=ZWEvK zrEjkKa8XnMW8d_Iuku3u5=%QZP3TfGWh2J}|F-{6^-Wouks`CpH<3g3)-;ji-yU16 zeJ1iaAhDep{c(1Ns`zTaD`+N6!$MZqMX*!4(BD^=+E;W7>|KOP^()tA>=en&%`Lzt z5^Q|^j`0u_9)XMaZIAd!PM5J+Dk|{bs&3tu=n6mIhqcF#pwJQPqzFp2^|L)h7iY0% zwGFavZQ+cWg(Yn;Z_vl@Wwq#A^P1 ziTCXG%LYY6XzlGERtm*W&(FV6y%q6xBYcPl1T08Gciuf_7@|1Zk^clUV$Hy`a%ySW7EW@aZfLmh@?o%B`%I zt6+ty@DVCb9H{zOOR@(-0R2KS)#!gs^AkWP$$+5$!rrE=~v;q zOf5t(8G##oIgg~^*+M1~m@`Oz ze4ux2sAcrNC{xmKEe+838JuMl9wH@C`{c!L;0ER^7T@tgy1r()O&R!!Ca633`q(@+ z36RESs=Y);r83mf=R4h-Ab&m(^*}4T)q!Y6QnLH(oK!NK6Ht+nqJAlW(c^axonp#v z?{S$T;aCagw9>@H1n7v9RU{M{NYQf}56^3@JRMlT%*>W&)4V=X6aQ+m>18N0*}S-R ze#&k&K3B}8n{eqi9HLPbG?6$#M$5>YG1uMQ>{lXSU)&vd6LT=K#j5vRrpj};xoZIm z8P?}9)@$*;ofWRG-^}FkIx^tmsj^FTy+c2)Ig|@oQ5OE>i9rL!}w(Wmrq%1dxk(T0qhI}1enI{ zoxR)yW9~gaj-=ZJ!Rfp6-1%Ox!XVxG)9?Fx4IzlRPX0kFPr16^^40 zNv0aGB0a>;gBUj)5-4?D?_)_Tz1DaBx?!bh7?OZxZJDJpW`(8ZsIFRyeC2y9Q07Mj z86S_$#@et?ksNIdxSctEr6LRk`$j^pOC3W)6ODAAg+YFESs3`zGczBZmvwb@Nl1h! z74S73_*`BseVXc`M(#xGSOGM}a&%yQ>p`LAFF3O`uGd=2@@UQ5{jh$+%k!lbw8pY# zLo?qQiEQbxhtuzEo3#e_ltd#E3Ex#RVKAkagx?vq|&Gn z9#O2`Z5}?88$mW9bUt+Z<9E5m2+HEjcA3wgZ%QX}3sUnIl$Fu4v)2|CS+?#>8TYuJ z{>w#I9EU`w>~8Scj89CgkHbsNqD`^mOB9A;Qu7D$;0*$ohsQJ<8yooH#45uTUZ=Ph zKly+u`x)paa2lmcgf?TLP8!L>fOD4yJK>;_V|)K zQin#86U%!N9h$lbGeM>FI~<+~_HQ0~bS1IRAJ@N?G)4*wx%{(+?*-Fa z+7v!`;BK)KrtVlfK(0BKs(Z*$r8GSaHuz7K4j9i50<|Z97No!X+U!){M?R8GFBEBf z%YjrC8)o{TR}o*s>U5>a;URYMJIYKC7nvAchXiH2syHg2l9Cm24*XFve$QkMOm*?{ z*R%y&`KaWzM-X<>+(*I|^$}xc!S)Hvgg>vX&{9&`pMB0>pBSsJudlH%X|g`g3EJvt z$s$o|ppP_Q3?8w%@AwE1@g%4wLxo(ZZ5JeWm!eW*2fsm$ku?^F7kIG^=~essop^vy zaQ%jIzfprC%U0Idiffzml8*yXZu!|@8*a_ps@aE-hWPE9U2l?HEBIA1oT!R>^%~W4 zeQ$`VO9NDOF4V=v1&Srm;|opATc00bTf39bT>nX(nEL0fBU}ro^{qbXPqx+z5z3PZ}vQU@8`Mi z-*sL0tKE^25fK>Aur5xO-8=dSo?d$UCI&C09JD+{w?u+Ge5It((8^~bhd($uoiL+< zmKq;KJ{>~#7aQV0dUu&T9a$P-Ln6I~1SElN3 z)wsFsfN5Nx$fk_kJN=RO#Z}HEFkfZY{bs7E>1j?T#t9`3^^jbvw?4ab8s@gTfW|OK zL+ktRYso^_;GFu7)b6&s#==Blr{sI^9)5v3nCi0F!ot;JFX=o_f2XV{VZ`S8Da(nv z*#$b19Uhr}YRaUrl0LbH{%PM($6~IsGkG7of~J+@ep*aY=$wxU*K=?*ZtNNPn%W%` zpPN&`BH7CJZ;h^M9(z72<r}~3=x@(jStj48b-i=B6@?Wgcs;L%P*M@Uli)gz0-6#u zDVX~e9a)~TiL$nBQe+=_G|RsDoKmQx)-(~id*XO`YULPcqFf%Xp%kV;kGz=ShM}@_ zTGS*PslK5XtUpzcz6?5OS!T$!ikke0OyqT*TaheXR+8}nAItZ*{(!NwvtK(dZZ9>1 zZD$*N*83fbeoSb1RqfUoD`-`|%Qu&f*2Yo15nb#TP}|qLDLUPW^g%(TN-ccPp2%8 zXE$U5(?^6rSgShWG;Omg&RSQ#x-9IKyDJA@j=rk}|G_Rv*w1^tQb`NLdE{kA?O~U` z5OPMh?a8s0)aI6e`ystrSJvihAR8HcagL1@@qHlMejf&uC__X0q{+0Rg@lE9E^p~j znIaW-YIJlGKa{4s)k#H1EDxv-Of^KJ#bqP+!W(cu1@zRTB@V363Bkk%bg>8{16;6T_<{&5%ZKCBL9HdY&6G z>6*?^X+XJ2!fe;XorW}O`TS#my{LcA?@fNw z5g1dL9Qo0%w~jwflvZ9#pT@V+W9>Ju>&#E<5EjFkfqw{p|Ay^3xJ}#btn+4bpKd;s z$G3GO1ZuyCZN?|AWII#n+W0x;+sfw@G^Qt>0vXDT2{M;r(V>YNhHizjp~*Ops^lLz z+w{b&7^9{WpJHKRoXGOqf>$0F&omyD=*^$LzN1%Kj_E=>d}me6Ja=`1R&ryuvmcRM z^B=%4zjAW2$}3bR@A2by%FO*GI~9ci=}RpB*JZ1z?!r?Ar(v|X6)T_hUGoS9a@Bi> zO6;%{7(E^Z6lZJasK?aeGxPInYN6Ey_NOtDg;IGcY*Z;PEHuj z$0;9=tjElTQG|l_4f@Rg!Mm0Hrb-Mnw6!nyy#}GelleZ*sn|-D@LqE6`i}y^;ixYCAbJg09H_-6W ze6|~GKYKl`ci_z!%Qduv2JG46<;3dDcz-C`TM`J7B; zHj#91o}I()zadVG8``zf-v0SmDKV+Ke_+U5!Sn{&h#0G{ytyo=M8n#(G2s{)&w=Df zGJxqh82C9j_?dX`1|y*ts3bs6!as_iNvs1^d%~h+G{=UA=z~nl!`*i2YY~p$ixxk> zj=h@lxsWuMN;-FurkUnFS=MRY82EDeddh`1MNH@~d8vdgWWx$01DsAtg3@z*>af^ksI9C#0U6OdltM#8vwttd zY~Rsvpi|fI)==GyvQawuE;Dgr2lM^QfJ=6YELVWzGr0+$8v|EfE7z0&aIT5QK z0(%I7^IpqD3-ZMB`@_py9p`12tu0$i)BNuPBPl}oWt$HFloAm|LN*_H8|zfSXE#$! z^pNqXDekvI%=GLrUe*_p!Vb#~V=X>6Yip(f{=z03;ls?Z7e;U4`juHGG>=WPR(r6W zv*Psb?&n!B(*p|P`k9ia2EBYjO=uD@HWlAC|K)KlU!DqR#zZf)TuIIE6-T>}mdv-AstbDA9BySepB(L9ThL_g}S$%3D&YPlnp76;FXz&5?C zpxhQc<7*}2X-B-qI&09v=Zv?tdh=EF;Io%ZnSushzLwFr=vN~G539#H;^Nd=DYWJE6Lm~%D2mUkKQaC6#OPRTjqk1Sql*zCQ%=9r|W zOOb`Bby%wVbpOpf4xa}Ym}8Y%V%{Xp+)6B^ii*PmWY9Ep91O%ntsg_UX3mL#WmRv< z>`+Ild3b1xc=#aLGfkd)HCL~;JTyE4aM57Rr@2NA4)P@2eoJa8)(e#ARH8Ek4DU++ zi5LpAgbu`Lqd(lwoEORV2?#V>PR`C!y<0nv9}*r5q&H`l{{0ehvV#A>Eq?*m}L>D7=8+%GpX7NfNI3a=7XYa*f-3| zGG(ojZN%chXs>eRhBz9wX?BhceqTSBwdnx5nD6@!q8?4(zGD8OTA*HVTWScAr}kmJ z`;DZMAEz4n1->vuJiR4~fcK8w+wZ3lPx&nOx3>>A!EGE`vIO5KNDvm0!0!4LhOc2OEEiJtKJQVKg@su}@}O;xae9W+d1NBl_^l>dGez@xLR-A5{aY@bu=4+|$&Xqcwez>ueB!D^-LQ$6ySnkv!pk&{!Xtf{G~ zu3VK;kpG4ifmv-abF_J0z3gLWZ{NLc`FDRvqaxcJKV@a=mHZSG6jDx z;rrU#EEb^~)9K}TrjlYS3PCe#b66VhneW-O{M#`(=M5_voP{DJe5<(Y8corNMuPkp32K z@v5C)s>83gO=2}o%IVh-UCF1!@;jlH&a8OZ@s6yXXa)FA69n7(H=e5;^O?zU3Gig z;oCVe)BoqOS{c9Y`il& zTLN6Ru~G1BxZ1v{ep3z3gc5l~wByr@-OA;7X zEjni?f2nvRe<`gIg{K3R6)MXVtdvX;WOebyL;)s1d-2|9y$%{ZBf9gp?ZmPv(V$i^FV z{9*$prZftkk$)98BClSsBju-jP&$AF$<4Wc8hsV|u+)fgqTu1Z^_A2&YSN8H0eH;}B#`AU|-%_Emz`6_fl0*Ni@ zoyxRqFY$@PCvk|DYm#&-;M&bW`Fv-}! zLBamEEhrABU789+u)_R6QpOlE7 zf%12Fh&Tr;E+Er?I$Dqc$3fGe$(2r5FQ>Mi2-F8C_pcslV?Dc)4ak?EAn4P0Kl9(y zlwL2Eh%Yi7ddXfcq8WY~CO&|`$e}`~R$KA-GZD3q zsqSo-VTlF6dPiN`!_>n=-BMdZ<&WrKRFHP`(H7?m5R4^G4YO<8zn#S=L!QdQ$yEE# zh`{=|(&>1gb=!%09fxetSDdBXQ(%kAeor2?McHVXnOU^n_7fL-W)??~ zd7VG`l*ORs&F*wrrbW=w0gTCKK(h^GuSxxQ6w4ex-s++qE*@3$V-@nuk={;8OIRn0 zJ3z#8dFkz2=3p*nGBw@T9OB}SHT|4Uj!&q>@b;Jf9KA9*_M#J0MDsFo}O-S2#6JUEfPLepw`1}HhgV z{L_)s-_qjp!Gq=h)dG$$8^@~mKNn7&2C;*dqYs)IFBR1VCxr>ZBvScYiMWijTjVv1 zpZ{lIWoezi234-2$OXX#L4)kd6nbmFAAPT zt49(%m5|Lzk&2LK3P-QdkX;BQ*3I37CXZE0*On_OkO_GFv=|Vos;*>Wj_>U31ma#1 z2!uha<4*I1aA-vHfHknRtJ-fSiNbrui-^+K)hxhuvO+v)(C1dvxDNK!u|ROy z{o}v7-5+R{o|1DMA4ad95HO?TL}inLXmP<8yEUgBRLD1O-lu(=jqV2}V|-_w#>>A~ zQw$dO=6FYWlEs)?6P^>`5x(>|_1Eu-VGO9RHj#1kSu+1T&JeBq?m2ov%TA-;gv^3O6>7IDFB4uz-W_GK#W8s*CLzsBH{>+5m}-Iq7Zb&i2>WKzgPuEKn? z4MA7802dzE`Oo#19}Yk=S59z1QQ+F#pT7#Mrk8Z84u55s6w4qG#EE*d_!|}+kcx^4 zrzBa-=trXmMNW|;=VL&P#KGrV8@szzhiC3ncb95la4_JJZvkZ%biHQuA=sO_ zasb#7Q0m2TbQVoTMMY7);*A^jiJ{j>Ti^OrwOj&oTKy+#R%$*~Y9>Mf7gGR-GRdMu zM?X#+&fgR(4$D(4y}Y$PD-(Ya|CJ`D&#Z|WK~5~ZI&|)1vN0Corkdw_hhWY_MMMfQQeQI&*ErA}}+z+24BO~2SOyC5m zrg-``$DiB@fK1YnGR*V!;h=!_7Ib-I_WT5ybk4m66cmTt%^8#1CScW1_skwb*Eujy<& zt~~46+$pw}8^on87#N7J4U9(Xc6a#)4eH(ta;=BJp;~^yh>?-KS-HikFT<>E_7CgV z@bEb$9o;$gni`sjk+0>=*O>aP=4OWWZtw}K{vVDbWzxdq`+_%sW5{{}v_(nwn+5!` zrx07MQu71^a^k(T{WbQ`(um(uJ=r!EiaI`_+TS{7ovFp|*WvkVQIxsoTESe(v|J%`BJ_adga z?fRQG`lr-pYv^x=$Am_!YI9V~LrQo3OE&PUmp6c#brnvzd1r6$s9zlDqGvYwgQ?{>Jqtq+a@8A~Df_MQuGQ-Zy#-5KpnX?V zd5#%pV#;7C&tnipe-ZJQH$_% zyZ1Ti=0a6o1|IJ`>$5swFgPd(<;-_Omk{}(6>5Q=JU%{Nd)v@8J$*4VmNi$In3(K$ zH#E&D4p3gD`Yq!Hv8xTPJLd=Ur3NKQ6v@bs(QFsWRL-_gXfv+85Ny&6J{;XWU4RSX z*z`(c_%c0nJjwe{Ke))Hq@sgmurdR7;J;u1!%=k>}wPIzALjP9SjnBtL+*|sg-0U%AyZ}?4oKk^N%{Xu6VlZK2 znyq=&TaGORp=ArgnBl2CA{0{*RrZeB5*5Ns6s-eR^ zFAOfFF>G$2+qL;Q(m4x4T7ng37?>)dayul`er8~61b=xR26!3A7B zhpWxaZVqb((*k|Ge=d38Sr6;ke0!hDF{$thF3DHDau?VIPO~I z0lpFVh+ll{Z@24YH3BK36xl|nFAhHeqAqHiN88Dt9h>zbMpOO9{oiJjr%LD_;<8zn zX9knvi&b_}(pO=Itz@n=e3X>p96^m{0d6`h?-*0=`QBIg>HBwinfGHHIhN~#;ZrTm zBcC389&QP}?@vEMRZM!6T08~c^K(%CT5erfXavNWE zNt*jjzI(?v;ma#zG)g4N=ey28#p2^(cF`thTZ=)6V%M_;vtKqE=G zj212nPG1YSOz!exXs0rH@7cL49pDJ*cW>)Gw6(;%?7QXyIYnXFXi-y9kGjZ~dP@tQ zttPRAhljo9WTt0TlPL~+q<2MFN7wq$&?4{o1Km{}5FeW^!v{8JUqxXgZ_S_mx;KC) z3VkdCNo*-F-(`IEaWej#Y%%M^uQgdJ2bM&!4SVdXdl7LiOxyep{e7LWfM6uq!bBki z<<5rP(&aQNEzJo!kA=OvsH3heLIBjXG|!CWW;Na1;&V|!LDDwj$?vb~fsl;Zj$uc- z(TuxzFDy>^8{u`G;#0XmH*RK|EJWU8oC#RI54WnhAYNwF2m07<32AGk;$4x6jYSKj zyXKePu%r{MW=Sy1W7O;2*()z+rP8mBjdC6ySoD-G#JA=wtvDXH=!Mv)q}AS2!o6g>>Km6K@{P=oqt~wRyuoV+PSCdxP*Ea4N zEglF!#oN<)(^{Z{fv~m&*tf%zF`m)9!L3bb?QO;S1^W&gJG<`b#%D*RD>af_b^6$t z1Ba#C`Ey}+*n?v=^q>rA`7Y^JeKGfP>yGO>Xo`+Wx}OH|r=@YWnDj&%mm4~&9F468 zKpAf`%gV}t==gyIpP5n+c~V+@d|Dzz!9tzi{k~{1sWeMG68nd_UKCAacdS zWq$hg>cl(&bQRA;>~*&5dpgr6)a<3JtDBu?QLNM0W-;>%&_jevWcKFsLmv)`e*I$5 zXOOecnhV#~(b?EocUWxj*~1~WWN2yWz;C_dGeFAt-J5SoY{TH=;|Ry1FDcOr30nGA z|0+XJCDw3JNgimqsTO<@HOXL~|H}4iI2CIRJrvJ$ECbPVKI}}Tnsv-%A8VBy85tR+lAS=?`rK$Y=9n? zO{i2}u)YnQ0wp618>8!a6&{Qm9qT5-yD+S<1yap8F}aatXYfpDXSO~$mo#UCPO}y@ zYDgU(Vwc!23f!*ORcI@JmEi2;sB+&WkGFs~Cd;EuXv+EWH^5uYAHGI0RpO|-Az6?1 z%oL4?D4Z4b3_r{;jicrFVI}kP9o2ahGz4LfELG|^D$cf=#i**(+>z!;n#V^r`kwX; z6yDh#5KCKns5>0k7t?Jai19Z}C%t)dN6Q=YkS7g{RVzY5h#_5TPP{x+)EoP1t9dOa z=R3gZ{*P?L9g2TiE+%$O>Y}KW3#h8F2Ab0N=s{UzkmVW-s~rb zmPa8EsMUZHvK2W{e{r!6DLkfFCN|G$)9!DHis%Qsj}*UG$Yd2RQ0Dtv!Af+nG*!=i zK`}JjEX`uCUHM)hK)1F!=g~`^6ev`B`egxaJCR{x-SFfjrvRe>9UU)+V3yr{4M5Qu z8Z=!#5hznhLpq(CU zt}KMUWDff-ASj55i3yngE66K!U0*jo%*xS?e*>hck%x`1NGlyzSx!*|O?!V97w@jp zz-EBtqaldjki9)KK7I+UEWe*nT{{oFudlovGNFd6jzzctJ+38NrVSAFcFlFT4_9!tk(xw+@R3H_#6Vhte6Thlo%VMdA znO2FT<&)Aso7j|}{eCV%-(VAyD|8oqaP^4FIEgHJ3o=^CMBT9hqj4mE1yS#EhowhcLP&2_m<5U2h-0}khZ$$<{;!??e|Sd816g?pxS#4U%n`o$ydp7 zxDW2dD&Tea0mOefjk&)xT?nv-@GIMS|M7MJjhXCja?E+5U=c&^9j{O}nzqPqnUeu+V)DrJ_#evLDk(^^y_XX?~*;);># z9+$+b(Kgp7f?k&MoVw1-Dg%N|&@94Xa{VM|@`oK<1mU|yL1{TFO$anrTVGjJ7Z;!G zYQ00NPm6Zqj!iheZ6+`mvE+^`! z>X#sCKy0j~wK+QaV2vUvA=ND4Zd7V07=lgqA7ZeM`-?Utw#DSuN`cvb#8VXC&GmO*8yYVFlfFzkO6eOfxBdPh zZihBv-wx@n?(VhC_3^Ukj4=WzQ;^R;$DmRU z;0P<%?k;GTGi<5Y*rJ_^5;g~~e%;}Cd;7%6=Crg3NvbcG-rLWNX53utwYncHC5JCL zxw+;3$O2qfcxW~g`(h84TU&1@)_G@VlN8he-#r0-m)dlV; z$5EH8(ruh=*EO664RZlo;IhE`rS>zQk%oW zoe4^ZN%^YsUbR?Q4Cmr}T6?;zl;8uD49b&U^BY;0`UV1uF}DxS7~$-Y%5+gjyKvtt z#0}BVPdFYCtLgiMH*ttzRBI;2Q`B|#7lICsM-f_D2f#dYpYAc`>V2R$E!eUySLSp? zy6YfHSPS}7rLD0-;`n@sLEqMed8^Jfxkegi|FS>+JAXe~ zeUkEeV`9-t8IxL3{v?JQy_0t1$e@WeBwY;C<&<90BUsDMb zg{ONYXlKOL0v`vmS01@u*w_nNfX|ZMKklr3PU%FS77xWU($lLvb@?oOJ0Z2bTc?{TDh=QttHNU684A@hJZF@|GHmvUPNt)PbRz>*d&z} zy77|6@k_EdM|{Xy7_3@s7QUH4_rf-?owoYGZvmQnQW6$?69s#toqZv9ki-?#R2;{S z^7tC{(~1}ap4t(un(wHi-p^LQRP@R1GL0N|RyJvW6sBi*c4A`fhI)tnOUi0Blhj#UY5SYgK5p)5=P)z>*$yzDQk@*+duwQwyvySJB> z$6bl}Xa5H|VHc6bA6wgy0l-=!mo+?j59kwR-Ss5>c+Jn}R#8zt`*2_{TUysO@+38r z*Q$B}cl22Vo`cmm!}%de0v9^o9j>tLiiLv%IRU|Rv$XrQE*l3&__wdS6SX4cWrv3W=c5=69+2Ib|e zrZ;|#E)5Qz-roUoeG2!3?lB@=ogd2);W*Epk#m4OER=B2+kp=3J1Q!)G|bGwovTd? zkBeP%b8G95mWRI{msjS9b8&H{ny0Iv2WK91#^IE`rw~+;4#D0&3z6EL_xo!2Gd%!@ z&m8t?odm3L^laPVb|sVIx*zbOs(Xc}cKvx3k@ftLA>Xc0=Zm2d*qpjqhf+Lnikll( zOHxW|Oai>!JNC+<>7IVwrFc%D2{3G}{(XaY5euhj5xhA)*xLGxR5YfHhMjt(i#<2REdL90&UeM8z(zA8yi#Q+%Zq^s&7mk5ue%UN>$8c zoasmQ%vCQVjH@_w9P=izd6b*6(F zQAt6+VF>=24;Lo~q)J593wPORPTK zzY3J2gx!fc;sxn%aKo%Zw;w4wsz}Y`fUNv;i$IkTHr|(k&aCA|3>d_<7KT`BQW!YY z#7R{fg+6BQ76*&AP$q72+=r4r2Sn?r7{SgHcY=ZXz+=0)xuLY$Ek9_J!SB!NFPo42V-AK2&3PTpoPv2m>a#vx z|Lt4V?E(qk;lVvI)X7PlEOyc1}**@GehYEXWf)`~ta9ToV;S z!wJ;ykPXc^5eQV6soItd00utispjP6S?8Ksn1!BxQU56Ae`Y$a&zeVpoO;ZycwVfk z^%MO3W4&kH&CLy{>C@Q~P76(@2Sdr&KxeCmXn#lvKy`@tf1QY3^ zK;x&OojO7?uNh5k-u$sh&Hcy#V9u=XN{`*F4%VnLan`}3vYacAD+YAcmjKw*ReUede)70$@5+}E+U=6FK#mFkro^|E2(`X~57g#XpXt!w+ zp2Ucr5uv41rL~^O&@h)Jd2Fdek+py8&^1lobW!6TwGS%Rmh2*=Csc8PXGz!QkTbh& zuU-C@hEh>cYxxC*K67t1xH_6lWWga9H1xV&54U)jt=Gsk0ZpFae}o)RHDH>U#71Y` zU3uRFcmacc3LJS|ZEu%!pQ_t2%N0>qm|sRKOkSHm&7=TNW2HSjEUtHOJD5GVhGWdR zGg@1sav{ zi=S<7G1Kc}+sMp}klgPeXSP)JIX8HcGBm0sAOKQ*eJmunzP&BR!o{^0?f;&OsyaP= zbgmn`Ff*o4RUAo5x>dx@Ainr$>-Oqb+~nz0iQVo)4M~P7{Z5$ZXldqiKTr3ICMpqSj(yu~EjFj~jG^RG#1D`W7Z?YBxzq;A z(Mc|W%%*twxarp#g7gzOJRwDyTt>%(oDDy;OI`VNb#$MdSx?>9wkW@gPWhos4f&;8 zZF69fq}2zHzuw22T}n-?*aO4gFquF(Dv!lAiua z?|t4rX68BTc=76Ub?PZ11^$SrL7vL^IO0wbb0|SB@@coyxK_+Tuh<4*_vzd!mP9WZjxN){~zOv2-WLenxpA z7tWBgfOW+FOQI=Gyr9`h5)ZpT}o-p8k+YFJF8XIF{ zW>y6HAw2dAWH*y>Gc!cXxMHgMr}Md70Fwr=a;N-yKcLX$WF|;F>!KPISmZ#%RO z4QWhMH1)&c?K8Wn%8QE`>-7QLeTWC-2MqT0l?9obGA=GQ-<_c#@eu5a+FEC4SH-#n zk6*uD>~+!6G<+AO2q1yUV(Xg39N)S8pve;H#>|EDAJy8Y;GI zObY&@AN5fmw4uMewBQ0Wi_fiO)tpmP4X-~V_IZjZpi83m)z`A@iQ3Il`Z%?~Lpxf0 zZ3on!xj4D$V%HJ9W7|MQz9?TD4E8)FqP&lY8jLE6z zg*#6mJLxzN|No_T3j6=mJN1im$Ywx3n7SMchaTH7SJFqGSFDY|mx`VK$er|8eF_YF zWy4U~!*ukW2u$k zE(?l}PZNlJ8Tajjldu=<_I6RR$iUQFxN|r{<%%SWN;sNxVQF0WK`}4_!7YTGS7V%^ zquMZ(|3G-k@8(<>hg7I@^9TzQ)7B2IWy!(LEuw4#?hZq zTVDs?Us-@I>Eb(batvx-aUCFs;}Q(=rAQAov@d( zJ~1*`+Bxkoqx}#aXSp02dF4BVsvvz}F#>wc=aR0?h~1Li(nF47$nSQ4b9=&Z>m8Dt zlLNwR5wM;4Xg>__8XTOg=^uMr_j=39z7q2|xbJL3l0h{lDqv)1kmuc=WGNOQ`&TFC z>jhca>~i0v+2hzNRpPr*z8C+HX{9fpcSlN*Z$W={wZToaqIT4v<=M~-Yj zkEX6pW(Ho ze(v^JNJYLJjJh}_5mSBDGb`8F4k?jdb$W>AY6$~!?zJhdhNR5IVOhNhN5Ri3&qY9_ z>rmsNTSJHSF|UkoF*^!S2${bAVdtcQxIk`Hp=P|MB+8Z9IQb&4E?w$m6N}~?a?XZk zOj1IRfnt&Q)+!*LYTO;qb=9j^*A4$#v&|IG8(GDl?cgTXLGiBZ<&?HO6W?`fS!Lau z)zKO&$k6K4>g>IV5Kd!7L{XT=0RZ=Z|K77aS^QS{Q4V&-)?l@MM99iYW;i5;i12mt z1Vk%Qef-DfAyNe6Z$k>fnb(4a%SELc;z0TFy%3BopL9cg0YTA7 z!^KwH=1GZNF)#)B_U+p+R9M(-ZW2I5gMx!K%Zugv5_-Fe(@u9Lc8W?TC9~X@4P>LS zZ1e#iA)uVqzclOyueI@gxMRufFqenkp3egbB4#70H*<@1vIEW3)aGP{i$nC*wm)K1 z@xVJo5OqRMI{q7M4p7p=P3cauNl(Y9>eaW`^F<>+x21`hFq?hCu5?uuwcPcitP%o8 zxOG2FUh3KEuJ+tq9PBi&-6_q!`Uvk|7quAP!+GDH^fXG*eJ_PQ#<&oKXOQiX{ases zl{7u5V5IRm{km*RJ~wi_{@YTOV`XX>eH2CBaY3wGsW!kORBmGoZ2=53ryXihrSGT= z)AqJ(sMtGPb&cOw9XLWi&W?8%`Q5FQaGyS*qN38s)7tjJ?YEhN)WK$}9PN_1xmDaJ zn={>ZrgBo74L$(bQV;tUe8HK`Q9@uAN)84ts;-&NI(G*LO7V_nFC6t~LpIk3uKKo3 zCALu`?vioFRO@Q*1tSy4YxN8dR7^{^ zM_i<|EEI@_qf>2-S9BZyRF;Y%22u3<^&i@HQU^#{z}Of`<3CWC61!_Uy5SPOb=h&F zogf4ocW9Q(t0YN=P6gtB7D!X3jURaDozdGlNYBErk<&SZhOA5dUqX$oh(^HmVM10& z>2BG?LX$p@op+qU<4a3`kz#jNX1rMhUO4i{9`A_8$a4ol;e8VxNjS6&v$u)Yk^DT1hS@^4~nW zAAd%=FWqV9jWguhw@@-L_pXmUV~Prkb#k`h7mw8x2oTX!EmozM4a3l0+_%R;YAC)B zuTY-^a4x5M`J6(|tK2+GRNievQRg?fVRiGwTtaxSKH!2Of^s2BqlgLP@|mfr8oj7} zQPDhzhM|3?#u)m4*w@KeVjlZO@M#*S(XJMV*@UU95HipcNi1_9H$BdPy{<{sb)`?) zmU5b19C!J7w~8JRO^zB*T99k&ddLO=p7-dNxDiD~CW24<rKr{rkN29eb`2Bw&y|HH$NJdV8-Gz>pgcLf-#m;;Doj$A{0~Q86~kg2 zHBj)y5QC`J1M0ZAI0>SbPy6aW(^~)0{hWM%1dy2qkHfX7+pQP2wMZbcoHul9>X=;(7rov* zF4!vU923|QT88Q$Z z&sWIE_*IBkj8oUvm*@+B-XtTbC;=1u`1$_;w6m@N literal 0 HcmV?d00001 diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 009f5a3..b1a03a6 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,7 +1,7 @@ import { useCallback, useEffect, useRef, useState } from "react"; import { useTranslation } from "react-i18next"; -import { useQuery } from "@tanstack/react-query"; -import { api, HttpError, type FeedFilters } from "./lib/api"; +import { useQuery, useQueryClient } from "@tanstack/react-query"; +import { api, HttpError, setUnauthorizedHandler, type FeedFilters } from "./lib/api"; import { setLanguage, isSupported, type LangCode } from "./i18n"; import { applyTheme, @@ -264,7 +264,47 @@ export default function App() { return () => window.removeEventListener("popstate", onPop); }, []); // eslint-disable-line react-hooks/exhaustive-deps - const meQuery = useQuery({ queryKey: ["me"], queryFn: api.me }); + const queryClient = useQueryClient(); + // Poll the session so an account suspended/deleted by an admin is noticed even with no + // interaction (option 1): the refetch 401s → the 401 handler below drops to the login page. + // Only poll while signed in (data present) — polling on the public login page is pointless and + // its periodic refetch caused a visible flicker there. + const meQuery = useQuery({ + queryKey: ["me"], + queryFn: api.me, + refetchInterval: (query) => (query.state.data ? 60_000 : false), + }); + + // Any request that 401s means the session ended server-side. If we were signed in (cached + // `me` exists), reload to the login page at once (option 2 — also covers any click that hits + // the API). Guarded on cached `me` so the public login page's own /api/me 401 can't loop. + useEffect(() => { + setUnauthorizedHandler(() => { + if (queryClient.getQueryData(["me"])) { + queryClient.clear(); + window.location.reload(); + } + }); + return () => setUnauthorizedHandler(null); + }, [queryClient]); + + // Returning from an in-app Google link/upgrade round-trip (auth.py redirects to ?link=…). + // Surface the outcome, refresh `me` (can_read/can_write/has_google may have flipped), land on + // Settings → Account so the new state is visible, then strip the param for a clean URL. + useEffect(() => { + const result = new URLSearchParams(window.location.search).get("link"); + if (!result) return; + if (result === "ok") { + notify({ level: "success", message: t("settings.account.googleLink.linked") }); + void meQuery.refetch(); + localStorage.setItem("siftlode.settingsTab", "account"); + setPage("settings"); + } else { + const key = result === "conflict" || result === "mismatch" ? result : "error"; + notify({ level: "error", message: t(`settings.account.googleLink.${key}`) }); + } + stripUrlParams(); + }, []); // eslint-disable-line react-hooks/exhaustive-deps // First-login onboarding: prompt the user to connect YouTube (and resume the flow after // each consent redirect). Derived from granted scopes + storage flags so it's stable diff --git a/frontend/src/components/Welcome.tsx b/frontend/src/components/Welcome.tsx index 3bddb6b..df0daa9 100644 --- a/frontend/src/components/Welcome.tsx +++ b/frontend/src/components/Welcome.tsx @@ -1,12 +1,14 @@ -import { useState } from "react"; +import { useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import { + Expand, Filter, Inbox, ListVideo, Lock, PlayCircle, Tags, + X, type LucideIcon, } from "lucide-react"; import { api } from "../lib/api"; @@ -25,6 +27,9 @@ type Mode = "signin" | "register" | "forgot" | "reset"; // backend); errors are surfaced inline (the api calls use the quiet flag). export default function Welcome() { const { t, i18n } = useTranslation(); + // Which screenshot (if any) is open in the full-size lightbox. + const [zoomed, setZoomed] = useState<{ src: string; label: string } | null>(null); + const open = (src: string, label: string) => setZoomed({ src, label }); return (

{/* App preview */} - + {/* Features */}
@@ -60,13 +70,27 @@ export default function Welcome() {
- {/* Secondary showcase */} -
- - + {/* Secondary showcase — smaller thumbnails; click to view full size. */} +
+ +
+ {zoomed && ( + setZoomed(null)} /> + )} +