From a7439069a2c9e085c66cb24053439919162b88ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=90=86=E6=83=B3=E4=B8=89=E6=97=AC?= <2435040480@qq.com> Date: Sun, 31 May 2026 22:21:37 +0800 Subject: [PATCH] first commit --- .dockerignore | 8 + DEPLOY.md | 29 + Dockerfile | 16 + __pycache__/app.cpython-314.pyc | Bin 0 -> 30825 bytes app.py | 414 ++++++++++++ data/cici.sqlite | Bin 0 -> 147456 bytes docker-compose.yml | 15 + index.html | 162 +++++ script.js | 538 +++++++++++++++ server.err | 0 server.log | 0 server.out | 0 styles.css | 1127 +++++++++++++++++++++++++++++++ 13 files changed, 2309 insertions(+) create mode 100644 .dockerignore create mode 100644 DEPLOY.md create mode 100644 Dockerfile create mode 100644 __pycache__/app.cpython-314.pyc create mode 100644 app.py create mode 100644 data/cici.sqlite create mode 100644 docker-compose.yml create mode 100644 index.html create mode 100644 script.js create mode 100644 server.err create mode 100644 server.log create mode 100644 server.out create mode 100644 styles.css diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..34ff113 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,8 @@ +__pycache__/ +*.pyc +data/ +server.err +server.log +server.out +.git/ +.DS_Store diff --git a/DEPLOY.md b/DEPLOY.md new file mode 100644 index 0000000..117c773 --- /dev/null +++ b/DEPLOY.md @@ -0,0 +1,29 @@ +# Cici 的个人网站 Docker 部署 + +## 启动 + +```bash +docker compose up -d --build +``` + +访问: + +```text +http://localhost:8001 +``` + +## 停止 + +```bash +docker compose down +``` + +## 数据保存 + +网站数据会保存在 Docker volume `cici_data` 里,重启容器不会丢失。 + +## 默认主人密码 + +```text +cici123 +``` diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..d366f84 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,16 @@ +FROM python:3.12-slim + +ENV PYTHONDONTWRITEBYTECODE=1 +ENV PYTHONUNBUFFERED=1 +ENV HOST=0.0.0.0 +ENV PORT=8001 + +WORKDIR /app + +COPY app.py index.html script.js styles.css ./ + +RUN mkdir -p /app/data + +EXPOSE 8001 + +CMD ["python", "app.py"] diff --git a/__pycache__/app.cpython-314.pyc b/__pycache__/app.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6fd91b8bd39949be20df0fd4bd8217a1b5dc8af1 GIT binary patch literal 30825 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 literal 0 HcmV?d00001 diff --git a/app.py b/app.py new file mode 100644 index 0000000..2d46db7 --- /dev/null +++ b/app.py @@ -0,0 +1,414 @@ +from __future__ import annotations + +import hashlib +import hmac +import json +import os +import secrets +import sqlite3 +import sys +from datetime import datetime +from http import HTTPStatus +from http.cookies import SimpleCookie +from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer +from pathlib import Path +from urllib.parse import urlparse + + +BASE_DIR = Path(__file__).resolve().parent +DB_PATH = BASE_DIR / "data" / "cici.sqlite" +SESSION_COOKIE = "cici_session" +SESSIONS: set[str] = set() + + +def db() -> sqlite3.Connection: + DB_PATH.parent.mkdir(exist_ok=True) + connection = sqlite3.connect(DB_PATH) + connection.row_factory = sqlite3.Row + return connection + + +def hash_password(password: str, salt: bytes | None = None) -> str: + salt = salt or secrets.token_bytes(16) + digest = hashlib.pbkdf2_hmac("sha256", password.encode("utf-8"), salt, 120_000) + return f"{salt.hex()}:{digest.hex()}" + + +def verify_password(password: str, stored: str) -> bool: + salt_hex, digest_hex = stored.split(":", 1) + salt = bytes.fromhex(salt_hex) + expected = bytes.fromhex(digest_hex) + actual = hashlib.pbkdf2_hmac("sha256", password.encode("utf-8"), salt, 120_000) + return hmac.compare_digest(actual, expected) + + +def has_column(connection: sqlite3.Connection, table: str, column: str) -> bool: + rows = connection.execute(f"PRAGMA table_info({table})").fetchall() + return any(row["name"] == column for row in rows) + + +def init_db() -> None: + with db() as connection: + connection.executescript( + """ + CREATE TABLE IF NOT EXISTS owner ( + id INTEGER PRIMARY KEY CHECK (id = 1), + password_hash TEXT NOT NULL + ); + + CREATE TABLE IF NOT EXISTS profile ( + id INTEGER PRIMARY KEY CHECK (id = 1), + name TEXT NOT NULL, + bio TEXT NOT NULL, + avatar TEXT NOT NULL DEFAULT '' + ); + + CREATE TABLE IF NOT EXISTS folders ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL, + created_at TEXT NOT NULL + ); + + CREATE TABLE IF NOT EXISTS photos ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + folder_id INTEGER NOT NULL DEFAULT 1, + name TEXT NOT NULL, + src TEXT NOT NULL, + created_at TEXT NOT NULL + ); + + CREATE TABLE IF NOT EXISTS diary ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + title TEXT NOT NULL, + text TEXT NOT NULL, + image TEXT NOT NULL DEFAULT '', + created_at TEXT NOT NULL + ); + """ + ) + + if not has_column(connection, "photos", "folder_id"): + connection.execute("ALTER TABLE photos ADD COLUMN folder_id INTEGER NOT NULL DEFAULT 1") + if not has_column(connection, "diary", "image"): + connection.execute("ALTER TABLE diary ADD COLUMN image TEXT NOT NULL DEFAULT ''") + + now = datetime.now().strftime("%Y-%m-%d %H:%M") + connection.execute( + "INSERT OR IGNORE INTO folders (id, name, created_at) VALUES (1, ?, ?)", + ("默认相册", now), + ) + connection.execute( + "INSERT OR IGNORE INTO owner (id, password_hash) VALUES (1, ?)", + (hash_password("cici123"),), + ) + connection.execute( + """ + INSERT OR IGNORE INTO profile (id, name, bio, avatar) + VALUES (1, ?, ?, '') + """, + ( + "CICI", + "我是一名小学生女孩,喜欢画画、看书、拍照、记录生活。我的风格是甜甜的、酷酷的,心里装着亮晶晶的快乐。", + ), + ) + + +class CiciHandler(SimpleHTTPRequestHandler): + def __init__(self, *args, **kwargs): + super().__init__(*args, directory=str(BASE_DIR), **kwargs) + + def log_message(self, format: str, *args) -> None: + if sys.stderr: + super().log_message(format, *args) + + def end_headers(self) -> None: + self.send_header("Cache-Control", "no-store") + super().end_headers() + + def do_GET(self) -> None: + path = urlparse(self.path).path + if path.startswith("/data/") or path.endswith(".py") or path.endswith(".sqlite"): + self.send_error(HTTPStatus.FORBIDDEN) + return + if path == "/api/session": + self.send_json({"authenticated": self.is_authenticated()}) + return + if path == "/api/profile": + self.get_profile() + return + if path == "/api/folders": + self.get_folders() + return + if path == "/api/photos": + self.get_photos() + return + if path == "/api/diary": + self.get_diary() + return + if path == "/": + self.path = "/index.html" + super().do_GET() + + def do_POST(self) -> None: + path = urlparse(self.path).path + if path == "/api/login": + self.login() + return + if path == "/api/logout": + self.logout() + return + if path == "/api/folders": + if not self.require_owner(): + return + self.create_folder() + return + if path == "/api/photos": + if not self.require_owner(): + return + self.create_photos() + return + if path == "/api/diary": + if not self.require_owner(): + return + self.create_diary() + return + self.send_error(HTTPStatus.NOT_FOUND) + + def do_PUT(self) -> None: + path = urlparse(self.path).path + if path == "/api/profile": + if not self.require_owner(): + return + self.update_profile() + return + if path.startswith("/api/folders/"): + if not self.require_owner(): + return + self.update_folder(int(path.rsplit("/", 1)[-1])) + return + self.send_error(HTTPStatus.NOT_FOUND) + + def do_DELETE(self) -> None: + path = urlparse(self.path).path + if path.startswith("/api/folders/"): + if not self.require_owner(): + return + self.delete_folder(int(path.rsplit("/", 1)[-1])) + return + if path.startswith("/api/photos/"): + if not self.require_owner(): + return + photo_id = int(path.rsplit("/", 1)[-1]) + with db() as connection: + connection.execute("DELETE FROM photos WHERE id = ?", (photo_id,)) + self.send_json({"ok": True}) + return + if path.startswith("/api/diary/"): + if not self.require_owner(): + return + entry_id = int(path.rsplit("/", 1)[-1]) + with db() as connection: + connection.execute("DELETE FROM diary WHERE id = ?", (entry_id,)) + self.send_json({"ok": True}) + return + self.send_error(HTTPStatus.NOT_FOUND) + + def read_json(self) -> dict: + length = int(self.headers.get("Content-Length", "0")) + raw = self.rfile.read(length).decode("utf-8") if length else "{}" + return json.loads(raw or "{}") + + def send_json(self, data: dict, status: int = 200) -> None: + payload = json.dumps(data, ensure_ascii=False).encode("utf-8") + self.send_response(status) + self.send_header("Content-Type", "application/json; charset=utf-8") + self.send_header("Content-Length", str(len(payload))) + self.end_headers() + self.wfile.write(payload) + + def send_json_error(self, message: str, status: int) -> None: + self.send_json({"error": message}, status) + + def session_token(self) -> str: + cookie = SimpleCookie(self.headers.get("Cookie")) + morsel = cookie.get(SESSION_COOKIE) + return morsel.value if morsel else "" + + def is_authenticated(self) -> bool: + return self.session_token() in SESSIONS + + def require_owner(self) -> bool: + if not self.is_authenticated(): + self.send_json_error("需要主人登录后才能编辑。", HTTPStatus.UNAUTHORIZED) + return False + return True + + def login(self) -> None: + data = self.read_json() + password = data.get("password", "") + with db() as connection: + owner = connection.execute("SELECT password_hash FROM owner WHERE id = 1").fetchone() + if not owner or not verify_password(password, owner["password_hash"]): + self.send_json_error("密码不正确。", HTTPStatus.UNAUTHORIZED) + return + + token = secrets.token_urlsafe(32) + SESSIONS.add(token) + self.send_response(HTTPStatus.OK) + self.send_header("Content-Type", "application/json; charset=utf-8") + self.send_header("Set-Cookie", f"{SESSION_COOKIE}={token}; HttpOnly; SameSite=Lax; Path=/") + payload = b'{"ok": true}' + self.send_header("Content-Length", str(len(payload))) + self.end_headers() + self.wfile.write(payload) + + def logout(self) -> None: + SESSIONS.discard(self.session_token()) + self.send_response(HTTPStatus.OK) + self.send_header("Content-Type", "application/json; charset=utf-8") + self.send_header("Set-Cookie", f"{SESSION_COOKIE}=; Max-Age=0; Path=/") + payload = b'{"ok": true}' + self.send_header("Content-Length", str(len(payload))) + self.end_headers() + self.wfile.write(payload) + + def get_profile(self) -> None: + with db() as connection: + profile = connection.execute("SELECT name, bio, avatar FROM profile WHERE id = 1").fetchone() + self.send_json(dict(profile)) + + def update_profile(self) -> None: + data = self.read_json() + name = str(data.get("name") or "CICI").strip()[:18] + bio = str(data.get("bio") or "").strip()[:220] + avatar = data.get("avatar") + with db() as connection: + if avatar: + connection.execute( + "UPDATE profile SET name = ?, bio = ?, avatar = ? WHERE id = 1", + (name, bio, avatar), + ) + else: + connection.execute( + "UPDATE profile SET name = ?, bio = ? WHERE id = 1", + (name, bio), + ) + self.send_json({"ok": True}) + + def get_folders(self) -> None: + with db() as connection: + rows = connection.execute( + """ + SELECT folders.id, folders.name, folders.created_at, COUNT(photos.id) AS photo_count + FROM folders + LEFT JOIN photos ON photos.folder_id = folders.id + GROUP BY folders.id + ORDER BY folders.id ASC + """ + ).fetchall() + self.send_json({"folders": [dict(row) for row in rows]}) + + def create_folder(self) -> None: + data = self.read_json() + name = str(data.get("name") or "").strip()[:24] + if not name: + self.send_json_error("文件夹名称不能为空。", HTTPStatus.BAD_REQUEST) + return + now = datetime.now().strftime("%Y-%m-%d %H:%M") + with db() as connection: + cursor = connection.execute( + "INSERT INTO folders (name, created_at) VALUES (?, ?)", + (name, now), + ) + self.send_json({"id": cursor.lastrowid, "name": name}) + + def update_folder(self, folder_id: int) -> None: + if folder_id == 1: + self.send_json_error("默认相册不能改名。", HTTPStatus.BAD_REQUEST) + return + data = self.read_json() + name = str(data.get("name") or "").strip()[:24] + if not name: + self.send_json_error("文件夹名称不能为空。", HTTPStatus.BAD_REQUEST) + return + with db() as connection: + connection.execute("UPDATE folders SET name = ? WHERE id = ?", (name, folder_id)) + self.send_json({"ok": True, "id": folder_id, "name": name}) + + def delete_folder(self, folder_id: int) -> None: + if folder_id == 1: + self.send_json_error("默认相册不能删除。", HTTPStatus.BAD_REQUEST) + return + with db() as connection: + connection.execute("UPDATE photos SET folder_id = 1 WHERE folder_id = ?", (folder_id,)) + connection.execute("DELETE FROM folders WHERE id = ?", (folder_id,)) + self.send_json({"ok": True}) + + def get_photos(self) -> None: + with db() as connection: + rows = connection.execute( + "SELECT id, folder_id, name, src, created_at FROM photos ORDER BY id DESC LIMIT 120" + ).fetchall() + self.send_json({"photos": [dict(row) for row in rows]}) + + def create_photos(self) -> None: + data = self.read_json() + photos = data.get("photos") or [] + folder_id = int(data.get("folder_id") or 1) + now = datetime.now().strftime("%Y-%m-%d %H:%M") + with db() as connection: + folder = connection.execute("SELECT id FROM folders WHERE id = ?", (folder_id,)).fetchone() + if not folder: + folder_id = 1 + for photo in photos[:12]: + name = str(photo.get("name") or "CICI 的照片").strip()[:40] + src = str(photo.get("src") or "") + if src.startswith("data:image/"): + connection.execute( + "INSERT INTO photos (folder_id, name, src, created_at) VALUES (?, ?, ?, ?)", + (folder_id, name, src, now), + ) + self.send_json({"ok": True}) + + def get_diary(self) -> None: + with db() as connection: + rows = connection.execute( + "SELECT id, title, text, image, created_at FROM diary ORDER BY id DESC LIMIT 30" + ).fetchall() + self.send_json({"entries": [dict(row) for row in rows]}) + + def create_diary(self) -> None: + data = self.read_json() + title = str(data.get("title") or "今天的小日记").strip()[:24] + text = str(data.get("text") or "").strip()[:360] + image = str(data.get("image") or "") + if not text and not image: + self.send_json_error("日记内容或图片至少需要一个。", HTTPStatus.BAD_REQUEST) + return + if image and not image.startswith("data:image/"): + image = "" + now = datetime.now().strftime("%Y-%m-%d %H:%M") + with db() as connection: + connection.execute( + "INSERT INTO diary (title, text, image, created_at) VALUES (?, ?, ?, ?)", + (title, text, image, now), + ) + self.send_json({"ok": True}) + + +def main() -> None: + init_db() + port = int(os.environ.get("PORT", "8001")) + host = os.environ.get("HOST", "127.0.0.1") + server = ThreadingHTTPServer((host, port), CiciHandler) + if sys.stdout: + print(f"CICI website running at http://{host}:{port}") + server.serve_forever() + + +if __name__ == "__main__": + try: + main() + except Exception as exc: + (BASE_DIR / "server.err").write_text(f"{type(exc).__name__}: {exc}\n", encoding="utf-8") + raise diff --git a/data/cici.sqlite b/data/cici.sqlite new file mode 100644 index 0000000000000000000000000000000000000000..6b651d4e40308275e217e6a6963a0c1bab6f74c8 GIT binary patch literal 147456 zcmeFa>+k$}ejjvBc9ZQUEK4b9iIxWkQ7KtXPRF;gJt-;JV~;O0w#WAi4}~=`JmU#Zc+dBDcC}}lgq2!? zQoh!V$76qddw=|SUtjOHP5pcy(@(BVUxni*_(%WPM<0Lu(ZBG?Cm((E(bwVoC*k|O z=}WNi#qa%r-;aM_`S)A=`bU52U;8J%@{jZ%{lu4l>!Yux|LDK;lfU^D^~=BYQ-AaK z+u?ovI|be;@J@ku3cOR`odWL^c&EVMOM!2$KmMh!eeG)>|FS-YQJE(9uwUP1KXEX4 z#^OJ*81~G6^0w-epZ&>CJ~!QyPbAgi1>X4NVn_;O_@A73{}aZxG)aa16<)P|?uYgn z?_-&MV)35!iK@ZZKA-=dCh0Q%!7buG4aYS3MNl(8ccjmq>*qeXSK;l4&h-h$9~t{> zeeyFu^NnwP^o1{d?WceG<6r(4-|oH5nz0!^%)j`#yZ^B6AIR<3Vf8~-^uu>Q^zr9! z>W3Trh&O+2$|UW7@dx_od-VQ34bX3V^Pl^PFMaLnU;p@9+8YTz>@$4!^Cv$?gwIy~ zAyMH+y2)>R<*$77KfFD?fBYZ1r}rC|FaE^WHk*(Aw>ulU5=^UK9MWz|>p1OXwX`!~Ls{@B}-{LBB$hnwr0>%C0d4?kb{9DzPt z`J+C`2a!LVKKWS~NWbt2`i&nRjsMRBI=VN1@PG~<;TZOxZ}a^z`ZGWCIi~iFZ~jvs zzcK7@edxqyuG9W)_G6#B$G27gVD7LDhhc8|6oK#d361We1l^;^&nH(5CowWjFxZM?don?h@EYwX3`5gvOwcJAlPMD76pE!g zDj}dDisRQkz7J_6+`rlXU;dXrg3tT(PJwp{yi?$v0`C-fr@%V}-YM{hMuGqR_VFM4 z=%>H6|K@-HCw}L@`AztI=U@Fdzw__>C%^q){L;7o;$QgoZ~hzK{*7P%?yvrP-~JE& z=C^<2Km0%b_MiXuzx`|9`H%no@BZq41)u-rm%jPkU;A^v{kMJ{7QXZ6{=#>E<*&oS z@BEG5{PutSZ^16#`7LPhEjZeD|MH*x-M{*;f9J3KZ8+?AfA!a1pTGQPq2=%X%6|?Y zSbiP$@BH%b{wsg}cmC?HeD~k|rQiN9|HgOz(tidY*!1nc^B?{8-};MioCIQCKmQh> z-{x(4`_oZ4q$Kfk+kL(z7)CdXKsIg+%jgXJgI|W*5;xH|ZI$y-*0hj7ws;%1@z6k& zUmdo2a8 z|A(ypq5ttwMR3a)iO$>NYxmFSqy+BHvEQh4d##KaQDN*GD>A(7yH4}A z^0gr%f%IIC!Xj6Ep!aJvOzgb^dW{5JC7Xw@d-$xA;2O=>{+A49Q$(?+lPhY9-s54xYjTdSDiVa`MjKVMr!$n(cW`Vwiz|J?3y%iGto({L-%o+ZL(`SV<2K#6*uEZjD>CPnL zLKi1aALN6-$P0ZvTga$bHm>CjDXqiS;AldB>N_pJemJ(?!0`|`PIKXw2A2)GRG%^a z_xHVSq5F&j!_AC);}{dDpYbfS@a&e>8SzDio5Xz>KOZRfVa^{|Mme&#SbDX4>m*&_ zn48YAH$`L_>A<|63mqsn>qp*@GB#5d-8p8l9@|oWVhh7LG^T0}v1kxircki+qVFVE zHUn#TY=oJ^6oYx4>-IX|tL^t2vTz@qWJn9k^OjV?d9Cvn zyFqu&@T|Z#UT3z9HiSosWex@N7;g-Z$PIG{nd%7Fo$@nJORR5Ma}M2J-B=a2@hBr- z4zD>ZGm@p>SZH~2S;;c8GgHWoIm-gSZPfKEtGbFglOTF=Yzvjh=YVF z+A%*jxup2)Y?syev}DmX#J;=G0Eg1tD6>?Hi%HeDi<%$A9cg zAKAbB-~H)NQ=Fv9Ym$755Hay75k~t@=_^8hO2OJa5@S?|pzjj*UE%^0{i7ps8}R`A zg}pU0{3?gJQ9wEx+)QZPLc0R1gtE!k@?Fp5gVLV!VLh2MaXu)8g7}EWAzQsr4=3&@ zS$4))*2wDl_A`k)fJmcNZXpcbAhxHw-d&#b_V4ez{Y>H>Bj)z|NL<~1NxkojvbTlL zB~p2-M6ITX!wS{#=c;%t9oc6k+ny0 zKAQT|pLkaV@NL|kR@!u)hI~G}q`B}tsr$p%!0>O<{MANg-=r-_UO4AX`GM=@54^5q ze12qkl;@>f&W`-=A$c#ZB>8R2+_U?_g#Jw;&pcxohR!lREK1S+B=WAr`LRx93nNH_ zzUYmi&pLbL*aOS^zN}06kxA(ePUTCsFEx$cz;w9Z@3+%QI2{jf$IzuFHvHR%KXwD> zigiYN9r&IdmLqp$cw2F$16)dhHHLvngE2B0b6>bad0-cY6%U5Ka7Ru$!o=9TV!vJL z+rJ3rC-@#D=AJjo>+NI9 z7uVJu{_cAMu#(gFxwe9yUv`pntfV4-9JyP2T4O@Xe`JmgHr?BK-Z=KlW&+OrHvIs{ zUM1eP&mr~Tl54|}O*T+rkXtB2__rq=-@>D7%#*aKr3f%;|;o#jTq@pJK75B5*U zBQMoom(@eazHO59h6R)5VCfm`p1q8q*H-@fD_$#q@GHL>z<~~6J#}C$@o$#K+itK{ zkl{KGO?ErKEV&R2s0vIkL}FFAN8d871KYe-y)NW!+slZ1UG`g}mo4`?(g7?fzRJ|M z6WQN8_M7!q$h}-d?ICU+fr(jIh|Oxw!?&koGXtbz-&?U%U;mwCAH?%N^T z<{0<~BfAzHR?eh{I^6Q~&{Uum%R-D8bDq_3#;AeCFH}m>_k1~oCu8VkZ!FkH_2{pU zYZ4C|*Z0iJHIkfQe!9-_I`0j~agnhqa@tuUwfD9C;%~_Dh?cn89qTOLGMBE)>VVkJ zTz9t3l04rdmwgVOQ+}k9)e)T04l-n_NFNCK;z*nV*(x0CzPu zCNF`R_~AxB^tE0UZ#~3ks_cB|@E2h}dlZ}_bmb`VFT?V)o@0t1AfwGxFUmoGzBY4B zrXKEac=e5t2kU#}*Rx<5p4yO1UA5e_aq+os%!wJny+d6RbB_)4MqwfUJ=JpEp>BF6BfOcNzfj* zhxJSZ5BXSugNnfz%im~je?5rqIRUT8?wWPUbBD9T*|;j!z;@Twc7^WV4R+oQTCv+P ztEC3LpB%1F@v%E=$y#Z&OUvrM&nRSU#<8#CXlHPJPfji;z z{?LcQ^~M-G!L!R3Ls39i74{E2_pJnjT>_ovpZ)^OzW!rh0h9j=U;S@C`s)Am)&CWK z-lum8yi?$v0`C-fr@%V}-YM`-fp-eLQ{bHf?-Y2az&i#0NKoLXzVL;wfBaeDk1u}t z<1c*ePy} zPJwp{yi?$v0`C-fr@%V}-YM`-f&X7p;Lm*FCqDY)|Kz9oKmRsi$e;S+Pki(>{L`;7`b9p3>|m zYJkcI_IU4&XEEN1Ytf~ijaA2LW3|4p+h9jb$%!y6mEPK{{!_z!HmsU(Z6@}XL$Vns zuum+^%IPXn*RGlR)7>1SkP1XmS(Tud1BH}sX`W22W{o?pEq&+QbSk~8DYeIHdzrD* zNz-Si*(Qa+k@@z5m}9SFBPy^I^I|`51uJyHfmE(G7~G@)ZU*9fl38HL^{b$!>YIo9w*WIaN3`W z_JjbG)-Foj0OZjttE0HRKsb<)6#{7amCNzU>d;#UGFZ^z2K@yoD*(I#$c?Hq)eE)+ zU=T=133>X&jPCBCwBB6P?XoqT6|#fe5WgVKx!OMR3kEo$L+LK0d{3Vvx{EF18FQ^l z7nLu7&;`vA9xNK`l+&^j@}`Db+BtYxUuIt58z2TGXbdGNGdE^`(*9M2CW$d@tkz#+Lj(>8PBDp9eYih4gc^dXUnaC0IEVPcwA5Z8hVaMF=x1C)z1#cz#i~^?XxjjeM#jVN)(<&yCEFzmV!X>iEnnzVVk!Kq@(oy0q#|g9Y zK9`y2t_>p1D#oE5(3!YjW0?&0k)X?xdY(-5S>^1SxNI#Lx7&^KN$Nf$c6rp5ao=U( z<{msKI#8-6HOl9>y=WV9LeQ+m9Z@U8gm2N+rera0pTq4|*7}}B57Vl2WI(Ngs_2&) z5}B-7qK+{!x0G)hr|MSSi;#E-!hWF2AiNXHT}4mGsOlzeJ|DL_-Y&Lu8ZLs$<@=cM zq;UehX%TG^);?X+`C*lwYJ19I_%jNhAnEUp)jQg>_j*x0+*0M zJ*~&7MHVt2*!;9=)#Y+aI_93Dvvw8zd=pluq(IK*{>Frgx?o-rV2+HfxHTz==5d`y zq6HG<#o5Bhvu|hTgDVcDJI6EoWNF>IvIX%7*45Z@u4GA)2KifOyyi`_D7v@QsMo;y zkP!BU6nvosow+KiBLZcy0Tl=k#fGsCrmu4cA5e@pp}GMt)M2%$aRQkWH;$|ic@nW@ zrd2_{A++Og+D#qj-L{8jL1-n8L{q#jPuw+7lPmk{@p@SUd)L|4D4fHlQGJg0lKp81 zjLi2j&rz11$jde*IBRbqp8G7=N!Oa$nM;zew#U;pdHP*UoS*f%7H7t@c-+mD%%XR_ zh-(0%&jEeE8_oUbbh|lChU7*haT4>XiRGWR(i?T|G%@6rkUJq%!Lb@f(v!7{NuzsmZR1wnoglrT%9NqrwXFb{%C_zR{dics z6FE#Nw8^bkL&hO-4Fh8ycA{Ys{~!gJ~du& z7WYisMjY=DoLu*mG(x;Q@Vz1?=_&-4x7T9YGP+cn2i#{VmH-Dyk7$98ikeG3-&%1XtWX;jTD~;QV{xk0SPIO zQz~q<^CfY|aU=>prZ2PMocGmwi&*Ts76f_jDtqr84B2$J@Gj;45jz;aeY)kPT{Pu#|t$&K$+Cmr%Kxgf^5*d4Tc6K*tXkLl4>@BP`Ktem?UWS^l8w#fqv zLE;$~I3f$zw7MRWrF`6vLlew&bPVncaUS!hnQgN*RGBO~H4R`W^9{dkI)1Q-JR_D} zj}i0`>;<8dWVwaBOvnla=?W-e07<^(NWPc=e|zHskZ1}So&X2GaUe@i%u$x)PHAS~ z108d0C&^ov_#U)crOq*btW@6{wH>XG&PsE$+9wfM7g@?ft-V!gYFED3sxNp3DhXBqWr zJl&Vny{L5+h*Fw7J&U0N^vdCzj;Qa|p_!6=Pj#{fxw>_VsJ>cF=Ler^%C?&bqEzDJ zVT)r!d(uEqq+V4_(n2>OTlCMB#4GI)9Ze+n21pAs=gZQi)P9d?8x4=BzOPqV+AR(V zynf`AjLyVnnup|}TK0%=!Q?S%y$zB5{dRSq@tr3$WlAq=mX@)GE#>)eKzxls(%be? zUbS(oTiZGEr*JkvUZ=b2pj_i~q`M*W;OcQBH%q>_%PkactSc1Bu{Dg!#^QaV38B#Y zyT0;eD(@!#abeLYl10>cl(CQH^rXiLeLJHg#W-G-v7z3cWdFHWXlX((vOVm20zWv9 zr?15uKp~?Fx@b+0UheC>+BVfyb$;%G-Kt+!ae{~9=-OQFEC-$lP6UkCB5>MDDb84~ zn|j&KNW>;3btu72*IL2UI~V|VdWtSwh=m>S6(<+z$u`H?ohUvvaQ8tN zZ5w5aXy|%wr=iHFjIg_4-jxHrj;K$uctoD$QHf;YDV~r^w99O{zp6}<2*ea^2!h%& z{0Xxym1C5mo-Eu(_o95y3d&e>bs^Oxq8fJ%WyaOmSqEJC#l9Pj1d4-aERM8M{8Y;q z^w1e5dVCaIaJ>fzmmw!wu(-4M7{x%fwlk|eLP9f(Jlwb3?Qj?aNQ4XAoW&*uxXIbtFg4bI&g zb6`o$@=5~;-_jahBmEcy>pA$IenXG~g|r1TgamU)7(gI#VgOsGDj+dIHBv(HJ)Ym_ zRA<(vUZwg4a9j0viEQ_CGX8w!HtptZ>Bgl+jQEJH1lRD)E7oyUs(71Hbi z%(X9!TQ^jJU1QJ{@FhN8{cV*Tkzq!Ba-C{faYO-9BAGNn4n60IIZhHI_r#)M04w4o z;rFwY9A8Z0{W(Nh>JAG*HLV!xm=NF zPqgtKt+}Ds5j8|9V;cJ-*lu2Bara;+VUJKJ0@fY6&OlsG!J{q1xX*BViUvOF`+QxO zhfzU~WC6M4uEi^45}%nzyA-VfHXG#cNczaX(i%7h5}l56B)takQOLl5@wS-h)`6d2 z#U#vwRjAQK?3rN=@4ash1)7!D7298)$0$7Be1riLaz;u`!qR{&T~RcT^y6H_J2$aA z1jf8Dda4(;3CLF^n9<%OjhW&$EttKf>nc((5tJ(49Xl|xQIz>Ddp#i}&Q0bq7S204 zB8~QO%Xia6Bc*S=u5+AzuMOH2ons0X<0*|bBS#u0hS4d&kqmV`dpUWjfw6WX=G z4;LA^5lS5+Pc@A92WDE^Qzc+rjdGlg#tX6xV!UCz8s~U?QZZg>XIaZ=lyv+M^w%LC zL-e76B^zJ8ey=|+)Wt3L3HT3U#~I0fcZywF*+t$Zof92Kv3T+NLDz0Lj!|yC_06n* zqBbdjnIgwa6V$uAKs?Ewi|cp_mHa`R6Wgbds2TiS0~X5p+F{)|-?tpeqa3cWadKl2 zk;n*ml7yEu@0v%lw`yWmk$l@po8Z{{9D;J}1#t_+Cx$7+R(+IM!I;o>hmlw+(qh-S z2ep@Iu+W8^;ihKUJJ(xR(>p`~TWAYOR#l7_k0&xa0;S5awLJ32eG*(`#x^CF$>;Ve z7YR#11{c3PR2)PhM&K=H;fK0LhX0v3YEiKwID_SygW`;L z%oa``tyo@n^F6;T8m-Na870zO7~E6Z(b?sxfm#eTUC@Rh8UJwHr+li|`3(mK z@coeuCOBx}!wpjM8aoUjK}}U<)hGop(HmBiLS(w=Csfz@?dWY4$ntWJSzRp~BiroU z-95@0#(Qq%m97`hK<}MXK%TrqcD5QOXkBRVY$XA%`tE?I1QA};)ToFKa|nZaI#ZR< zMKB{!QMDt75RfsP>?MtUkr<}8G_z1dmAi}C&7#yDpkmg`)nPA0py9g}N-EKIA zaft<|?NE>EBO~I#)3r!;tb*QQ3Fd3h>v?b<>FJ!FNX)dK!fh4P3%VuO$KlMz)TpD+ z%Y08=E!lB82C`m@DJE~O-PBzv^Sn2~)a|>Jc^b938;T$##77a>S(VY(gQaI?UwJM3c#~1mZlJI2EJwFzHB#=OB)U^K8^}@xN2ojJPYj- zN#M`LFl|JL0@&4EzY3s|qPUlBgfN-099vc+-BjQMOpU=gt(WS!DH~y2R-$yG$%BNu z9k-Vm=}C5d6vRBIEp{q}r=7VRT*NYzVynpRZnMri_5K)xWVD%FE~@f;S81L)kx>=) z)q)X9>SuJ^=k)nX_Emp1wXQi}B(mvzVwHBaPwnvMh`mhr*k%Hb6IM;GjXd2}7J9;u zLd{`MHtZuu$pafqwH3{2@(IBk6_szYtEQF&N~U^XuzA=B3{oG)iNcbY16 zi=5m#X-^;HqtY}4Ne+d-F(`d^^Wz(bdgl}q2px6kwhNh2Zv7S0Z(vqv@ih|h6DeXQ zZC(22GMj@IG(yng{8pJ0cMA^o^iFS1inMbp0XN7KBS5h(5XW~>)nc$1Vo|)eYz{hq z#HL+pD#u7_#zGfO4OzDK<}f0AOK#vX*4}xxCdS zClp1`TB7TK+rczpY>Cmj2Ixek49zp(wB6+cDb$2PY{KUm+g$EFH7uIfLVodKAFQBC z6wC?*N|=QOCIh;vDuci8l|T&U!RaWodKtT*xos87KbelCCAOBPxz&b~aFyrmI-m!2 zcmNZ=`v~i01Ng}?#$GALTc6#^Q#6dEK7V#p)bdJ=UaU6UlgzTC@!bivZ=eRdxYu;=g7Fh(XH?2vQC zp%Uh7Fa5r>Ce#dF{P|S<-Lq0;kQr7UIM0moZEqv;ScltVKkSE&bn#)g+}K@~3%x8@ zwe&x7RPq&N0xsUR`+_nnA_!m28F6beliJG`~1o*Fj zH-ObxE?l`2JN3CopUdiMDvGJ2*zP^YMw_HbT%9xMIgwb1`LG@pEwbgrR-)t{lShm9 zyu+xdMR&JcuClY^Ld0eHR~B=`3Y7-_t!o=-86`<^HkN;i z-$tsmxow2*L7O9@+F%pOY$t^=Rd>##QW=lgteY6@i)9iuu(GCTy7t4g<7dfP&7C<` zsAyE60w2K#x9CO5>E>{3>hnp+Wp^x6vb*LG+wwtazse`mKtYQNO>j;@tv@-aZV;0g z1xCB?Q;uCX$dvP~(?SJ7fqf|{-N373RfEo`N%kH+?S6a=uYXa#c`p^3+W!3 zd)kLs0e+fd9jPCV;wgfs;*N=GSs$`{&aTa^>5fmF-8SG@4UR%$l4{_r_bLtbRTpyt z6vseRnJpJ!^KC?Za8A@*TZkLalRb;pW8U6d0*Y9S813d`LuEm@&9=FQTiWw<0{bkD zF^L|h5feeVgy>D3k@Nmma1cP79^SzVgIyn97^gGtI%YMdXH9Sp2Tam2~?@LtznIX5{fw;n;cbf_NY8O>^ODKC7#{Ax_QV|<@U|gg~ zDJK!ek@zgcZ5kUd&_q2#Wa*Ke`AO^}F{IM9&dEsJGnd`z>52^IRp}GL)%RkD!FaUN z9ct2}52FW7w$cf7Cyg@k;6@h7Rt{c*G3$*RoAxY(`a{pCViLKZg)G<6W@cI#P7Tx~ zEslp*5k{!k$d@m7yTd}v#0D0e$;#;zLVT^rbnaEOP^g-=W9-6?d*H&r-`GP3_AV38 zCWNfBT5@K2=V>mugOSj#ru!Y9sSCL8fq(IxK1D=+4{}W07Rrg_c_wEC9h|zy`=*Lq zWAi*h2AT)|`W$CIPFQ8sL(e$M0G7{HQ9PzcdiC)cUVTJi+%{`8F2x<|H?Teuz; zV&k;6yXpN427WsHCNi0h;DSWW86hV5ZBho!Nb@lEC>4=!G|%syuAcRwKP;4yEv}6E zt`>UPQ`}>da4aVan<7!;Mtq(uwKpc#u<3%+=_3VBI1JvR3k9pzgR%)BRtj}mZ<=_U zoCmtSjd^&rfXCTbU5-Ka+#Rm#jeF!RdG^fMe$FUrqG&PAnIIZ99&ZJLV;3Tdw#L<5 zW}>GQdcdmZqq3ARkz-}QM=S7zZ!*@akK(cmclfNGcTLcW;Nt=hB!|tWnj!3_BM;&o zs&qKkX%!xArDgfL@1O0GKOPwF%7kPBf z2uViLJa)W9fx_?9<}g7B@kv5hV1gjCJDW_QQac70)+a(AFRUb}KAKPSVRt%b;2H|c z#nNr6Auugc)x-WN4i`@wcpg-PxZ6W9I`=MIDior1wCht{A@>*rTXUBcF<{KA|E#L z9OEWlvGax(CzjZ~eBSzG(_w*tj-Z|_GdwB##29ZoTTw4Z2dvcd=?WE9D$FD=m$Hr) zcWt7babe=q!E`4{DkJt-Uskhlg6=KaLKJHOA$(^wUvd9~-%m5{Vve%cRy!{r zbwop<=#APBiMq+NaWJwNmq(=FCJw~n{=zxS*pR7Rtn8Ca8u3i>;3A8YmrrxJ zP>~4)%U$tjV6rnpn%Z){D-^YpX!I$dIsFt#!wCW9w-+m!Nfm!AnR7unMNGcdW%)9VTEI zuxGsoa|Ji@%jG_A+PNF|#O{`Fp{%$hfLEd_qj4|nEwT((+}%8#(c4I|1+a_A7Tbex z;e@RxY@u)^>ZCym9X~$1zFk`7l&&s1#Fhyqg;1BsS@30D+G4NWQIvp4>$rck#EIOa zN}G2UCmS`xWuOPLHOq2U%{}-H>viQZjU-_~P}#L}E{B@du^=+EKpoRKMN;zaZXR%} zSqtuMe*b!)o-Ed+K5{!(7}f{eLyT41YUCPOuI%}I8`A}fBC;#jk|F|Tn(l$Op>Q6= zy~R-oHqyo#Rq8X%o*UBWRwbg&V{eEu8+Muy?5@%(_nsz65RANBslMJaLT(R<7j>HE zOzwsbvkL>kdiWY4RBz=%4MpfW2WF*%mc&*svO0`scMTN zYq>Q9fAcS)t#SPO;G?F8zR;E54Uyghz6(s{+3$$xShC0o! zuzY4tb!k}coiFI_#Ixs9n3sahf)jAfPf)C?*}eFKc@$5n4O@L+BFYiGoWML@Ey|<3 zvuvf^*{mAx92(v7k&x{|RpxFu{RA<+F+eTI*6F-&!3G(d&clOeLr!2uKSGmhq8yw} z<%8@2an)gZ7pLp}0QiShwfmcS(4JPEB#*d*r&o0J-I?&hftxhKyC=>fI?l5JrR-U) z%cA9Z5smpJ&Zi07z1nGV71QpUF6)!p&@?bl+pQ6oh25%6_PB)iOS<8)btrvI&;oF8 zK&+|SFq`(!#)^lPLvpkYucc05Rc%q;3Z@21PT^NAxgGBWxW8oZG?;uXZBJ_pxqgwsqCBtnOcz6 zMHYwaMfB5l1H<}y)0!^K#_Pg4A$cR@JAk#A3)E!aT2z0YgT)Ej&?sfzKdFd6`v-j< zX$W>=$}zE?xx)7{qqQM%3<-RkW+$KVz(hD&X$NBI5YE|ex@97qVZn|(OJ0&KsQI*s zVfdg;QMGb(0sg+0WW%JyALxDsm8ZJ5k1eAj6L#&cJMb51#i3uKc{e{zY`^sN(9$>Z zu-{k!j@zvC0`aU0No*{9lx0iE#KxTY10Xc|_=pi=1owq`9fT@X)p5j!Lw9Y6SrY;e z`Q~Bwg(g!51akA1@FB!gf(vo676l5|r%0E8-y_Y?3<()fFcFYyUxp?t$QGYCA|bmox!(}1LJL+!7%%G|cYG z7eoSifbkvQ#O_L-dyVNAfD9f;C?I!L&r+2kddPLY^%#=;(Tb>-gVTwRG(1*f!%kG? znnsCiJ=J+5nBe!>#tD;F>p-h0zvYrZH}GUqV`?U+T@x=9lybjKlrQBPN1Sl+8Xg|4 zbRcnUr%W_hA8f_pu=<3J7ahYWz(pBqNEHtzk_FRhH1&=yTSWs0fImi-N?Q;BatRvT z`vyA7tcyOgLAqpRL={Y8Nba?e0JimP5o!mx(Tle_rw8G+)tGGe4~4wi z?ocO!x0nz}I2g2Lkzi4JhZR5FL^Tm)pR0K=E0j%3rP=HNH1Jww#vZ(L=ta3;3LRma zvv=!_*hdvRIWzPl$^f@X?XTIgRj(SnyU!k&EzT|!M&t%1;ihpt9F*H`f24d3 z;Y|>BcNn;@-@H69sU5r)8xf@C(CD1`DpvUlmTxir7k&ZE|DWO|IoB5F3$M6;> zKC)$$QyaEL6fk5P3A=vkO>_YxAHZU!xuB!SI`egI8*EkghjU*qbX{ubT9l-Ei1YKY zIV_O`u~zBW_dOK^k~?QDvxapyFy~Uu&T=~}JIZylrW4jjqWA{4Irisr-djVqH#i691UmQ^+BDrWL7R4Z+`@j z<8D^8cpnw6<3@P|Wwr_10u5!%0Rea%GGRM7PvJoH7V&VMxnozq>DO#gZ$3yEkLs?A ze3w+|$+=E^4o(op(n)y}Kc=f}3ZQ258`A(ht;$>hSvM}!9r8s?&IWm^sg?yH_@`++ z5>H{3Qj=wf^Y7PIePK;M`$F;C6U7IRV$*^j z87lXFD3SYN@PT9b7QXU0UZW63DU3p>jxU_^@+^YA+GktC-4q22I3mX+g6i0k_jQOb z*Q#}ckqY}YrqS|5`gm_1;5{K6;*xhjv&Ddd>A+Qdu7qdVW~q-)F&kI#?im^oFFC#i zb$wr-uhEI!jwz_!%S)FM`($SCSFk-)WryBLKtzfz#o5?g^QJmqy+Mpz z9CdGk?~nEvlQaMvo2})NT}wMf;2xC4RPTWz#KfrSILYs~REM)qO@6u$bnNtplVhf; z_q7r;UZLUIgclHN8J=X2-HJpE(49DhV3S6o&Ai^FdepnB3?zt=S&w^q1&9d09qv`& z!8$125iT3Z05)UD)M2aO`Ci46~`d9KK%V!`{{vt5!n*^%{Z%O_J7 zu{w8;Wdv;rHLX&>Pz0AAxzAgV-z|ih z^i*%p=4$fy{bQp)5(no+fHxBCVLcHYz(1P1p9rM51C*bNjK#indXES)I^jvsuQ_Hz zffH#XFStyVIvH__UPp2^CU*#6Uf>-xKB>g>@VLq~J`8}2lO#HAy0l>;VS@sT-DWA< zQ^~_gUhl3k_ji)OQ3pM%-3>yDkVr*y#u#yZwF2luMbCjfrl#g2M_?wFpIPFvJe3u4 z3bX~Cx@l-OPJsCG*!olk_|=56uw(n;3f2A&X<~TM`x{Atke~H@WIkO5Pk|rTV#FzT za8PRp$nK!K>$_FeRdjJxh)j2V&N5^i2riRSGsM*3J!SMz=gmS+cr%ISaD`VLtyp8_ zg=%n)!Se!zrJHV7-yTN-&{{q|s>`_NqJ4>2oTlhyB#KpD4KbK+33DWf{RN$hd)_tf zGEOe&=+5cb-eLil#im7K!IacT3T1hB&Hh{`({}Gf+t4}_g_2Z}--+%L?iQ*ucvHxN zM<_y?0$^d63BR09$)SR`r5&FlV5lTrk9hY4IO$Z2$v9FK8?fp+6tzBOAhMx`@>@|~ zK>NSyC<8|Uq5bwX5JYkjz^cEok+-C<4<(o-{RN)UL9m0P9T>}7A#kR34$<)m0DE|S z(2fFBxk^GZnm(%#`j{;6VeV3|nAfVo^Ydxxg#y_n{zh~R>Bcn))y;`Y7(rNPeFgTX ziq4hi-N`kiY)sYoSWgC~)6xmNw=rt2%E)TTf{Yj-2LyoZHmTQB=Vui$VSYRfi`|QK zo96&v&X^0;BPN#C+LX1BwzYslq7M~v zD&(9O800KqPlv;>?8ah%tuyI$5s%@PuM2cEH#(1VXDqzva=otSG7!BhwOv?*a_tek z*wD}C`Zht*6_^a>O7gLXP$%DXj%P{49;tH6$zvMWJex@8;5N;W&{#`S!Cu>Rcc9DN z(7J;R(FmXDdnj!050^-WC|R<*+@(FZbz&qgjnj_m0}$PHqdXZ2oTTc_l^ZXyooLk25>!cuN46P%mn-;mYm*P1K)ltEzQfn`m4>#4h_1 z;@lENa&(`mD2QZ|!x_0Ec_QG|M;&v0|G(#3=6L5CsY9Xn-dd~msSK&khLe`Ezl_q) zH>$pefOwv(RzAO&NNz4f++3sEbHVT;eyqGeC5qDI(2u+~7S}zDE7R|$+%e7ZJ=OAC;KkK=;p*`t zhUbRLUv-6_G4qg$N7;9o5^02BadJ8QYWgMUu-hE?nEK5tWl#w*xoD<)I{a+8;9SKE z)!v{|=46wpZg;W+`dcZ#$8;GkiMLa6&>icWJCq{JYo>Hp;u3TEqoTB3B-Vp>={p(M z?^?$=Do;5J@hAPN>VsrUdPMq9(=C0GBr)}tMK-2p#rLIe?mO}Ki}7e{{6Ex%{?;;BiLF2M{@;W>qKbb(1z76-4nhAy3jT-H@BFJ$ z9Q;>%eyZM36Ul9y!`~Vc;ND;QBzgVJWO*|RPVm{Ag{mH>z|y-`+h=H1y^0SiAvm6Q z?jh;rWByt^1}3O~M1lUhq)ATCgr_C!inyY-U250_Ws8#?UQpt5RqR`*llo;EA;w5$ z0E7M3?ypw=p8C)zLjlGkvD`+3>tkY8aRhhI@V2a<@`+HI*=^q21WU>3akFeApn1x! zjU?-wcb3l2LK`6>n5Bm=#ji$lPeuPTUfegl-Ou4P!q^5h< zAr3+(y_W|sm3sBQ)}pDMZsum~oMU|5p<*$9jx9Xg5>~&j!9R(yE3bi#oxybB)S&3P^T5ID)29 z^-lbKp5cLoUS1u%8UB)4R_#ST_HbIfzRB_>gFHr0817o;e46sMU0-?(%Q0+~w3r(H z4&nvW|NrM*jg>&Yqi=ii6;y%88}W7CI=px68CUmpkLpH!gG+~sJ-ux4FexRGM&OIG| zXT3z@I0RxqP$eO?yssM&F?C)>GsRFzr{Cr7JtCUx>U$$b+zRpjBo_j^#Z`V#)hoU$ z`lYa)Uwbr}dY}%uQC4KuuZj1TAuLvZ z9TJ?r{;Srk{<^%h@L%WTRz4QX)ZrhlZ^JFTJ7RP0FV&`1ccqMj#^xS;j+qn!Xk7RC z4R3~g&2~Zda?AS@mYSNi*Qq3^ogcj+y8KpxiDIjucF;G&QJ@aA&JWiLhpy-GGUrfC z+E&GUeyC}Ea}#xQDA-|%Z=K{?kf>jx{PGA$+e zKN)j5q{H<}p&TK%qlui-_~iwQ6*k#J|Fb@P3|pgOc4#=Bx8U5m{>h#?N+%-5+-dDG z9d;XAKiaCQ)bTK|VJM_Odj4ITA9O@URnN8T9$j~&?(Sjoo$t@uW{4;bFE+g?om6<- zd>@s^C)oQo<(mif`Hm)bSkp0Ej5Je}`D?#9=`ubtp{~C_ITrSlI5$I>;<`J3Vh@41 zxceU8_C$OPdKz=m*ripxHl}>rdQ&`yaWN^@$PYtLmov}NP6p2# zQ6WmjX|-OtLn4Pn5#_VE6#mQu9q|4*(+%pS=_%sK7F07da@;^jC)FtXgQDrj23G6z zb>6v*_~rVN*%r@IE)2&OKcmREurP`J1+xg4^3`EdM>Q949Md9Z#$bk5XyqkVpVxA! z*jCBU>0sl^f+|@U<+PNpAN4HJw(*to9g(wPc2FY`o16ky&IQRS;yThFY~4GRxZ8do z1gIk~5)@g?V|X;ed#Nov@3n!E)U_%N0Y{?2)7|xmrFZbvw91ofbd{0^*Kw_JA|0Hj zMElL))u0lCcFwS@Yj7)^o;i8EF}jUa9lh(0s_M9}EuR}Ak|g0sg)l1W;Yyq}@<&zg zVDz>5R*)NYqTTSxa*jTGk?x#%v?m+E^~2MHu%Fr|4occ@Aw6b}m@bc0?;E2{MYP`So1mQ)0eb_sxeAjmE5BudOJAb!5RNSB6K~0BJYhhFDJ<{wcluPO1XSYgPp&l@*Nk&Z0 zH@QC6h&XwkK)rHp=F|DG?H*QkdCp3$YHzeXzBdsPz>U+9<_BBcA!b^tSh(kFQ8wk| zLvqQL9y&+y!3{p#clDl{tUBkdobrC!T^%wlUH6bXFQQVcs}|oRTyX)+ih_5F{S(v* zNBI#-b9%QdJAv|yFwUN#FZoUPMETgxbTj;Us!B%hbI3s#J6Vc1g|)YlZ(Cm&D;F3LqggU_YDm!Cqg`YJyd z5A*jMya|^>XH!9xW5!WG}xtW&13AB zns$<@-ud|?AGgK|_7BreXX( z5BD~6pG2b0?txHk?>dpxfj~cAp@%L~#jqlmMw+E!y@W%WruiQa2F16eRPb2Pt9_!z z<&6gXlRbFTi_nIB>nZ|T_aYPL;J1j(i@^!>dK{YL>Fb@0G>7S{c?a8=4jISCuc6F_R>aVMky~?jW=W}q+~mv5k(Ftg zxN_9XtpOr>?H;4F5X-gkWJqB4KIJwUcTDCTQ=sT*ErQhatt~f0{65P>$v)`%hv@s6 zXJUdFXZ9)M`SNeF^IF7y?JJ#!^;+p|C-O!$$cMArJJg{ zg<+N!I{+Z`;`!4>S~Z|w8LJrYdl6O-@AFql{ryFt_NSg&bcOzF0O7o1{>5|s)l=qQ zg;iX4@4vGQffC?8lJiiGT`X(Fhf=#gt0bSl4Jct>r2rR)Vj}QbEBGeqJsMW#uiU_9 zM3O^$thy>WU8a&gJ-}ZoRCqDwwBO?AX!Sd1Ve>1)X(#v;OG6}c*i$0S`A=CTN%*O5PdDCSnDS)kR6`QBFR{(LwikMbqR+%76#Lk# z!sJ7BgWPk?E7T8je)`?XmEMkL{-K)eAioaJTQ%k*r1+nZ8GtCnh&f;97#DZhmf2|*p~t?JPS4qWeI;d4t*}7r#){> z^O9cmP^^LN9)y|z{ODv_-(T3=CP0JUsHJaog0`z+!k!M}*g4SC8CM0rpNwviCNJjF z?u@~A)XPtc``kP)?x*$5SKRaa5(PWnu+WR{O>-g3?3(khl?Cap{|bm7Upu9hqjdZ+ zzJV#TsNWTVxMSUli%eJpR}TaEvV6A#*(QFnF36M9ejPH>yzY(;nNB}#Vfpy?847OS zAav>5om~^H+#Z-NH~@J*I-Xl?I^kv6A;!(CeoxDe-Egiu&0M_;!L(dIbr$W34n@!b zb3!EuyXdj4;)~2>ulJN_5L)k^{xb=zUy#1}sBZEPI|}uDI82*CVk5w-S`Qc+98G{a zbiI5006drmLyw5x{j5WMu?dN9UY}>C8r7)`r$MoQPy(6qsA%9jX3E1Uj?*!IJO*`&$^eIKK+J@3g1b#er2aB zE9qTs?~R_IU<5SjhH7IQWlw3mOM$aa1>qb^T)I1=Beyv@9PQxlDIzPLzkwp>&axg7 z`0weI!kRLTsFMC2ShPFpBJ`h83q9}wjIjP&aghJ``U|4Gizuz0@~>DY=)rXN4k2j{ z!dAJn2nV;v1BaGtuIyc}#6ok<1OQ7OT+@N{v_;BUt+$A@3^XOl2*t+oXu0<>cHbvy z5xi%K4g#sHV#_9>fm%?NWdpqg$My&dP(s%Dw+tOaw? zd2OC23#o#3%r;bV{w7ev_^7Wwv9mz*WS`1T!a zIIL2oS>rFyNo&%}2zyjouf*}%Lth&HhItgG;QSbLugOw%z0hH|@RLiz>yQ+@PrDR$ zW#zWbR_gpNT6w1~%r5xEk8L@A4$E#&l-zsA{T^5g2MOl{#J8Rk0%PYuBKW~{R->GE zN;m)Qs_>S#WGl63n~B-|Y`-6mqHD968?3Cx7(ay}7Ir^IrXF ze$2V@4&W9^#<-x#+xx5Sr}Kj5OPQ~qY`nQl{Sk)1_lNlg&=(VCv|+$@INsjUQGmfu zMx%Us1>`al90p~AOp}j~!%GIhJhXg62V{L#4E%r<{JDvI&~4IvQY|(WvvjT=Y4lSN zz_|IIc@ScJXNGc|V<^J-X!*~7VrO@ljuA&~ zec}Sx`P4n8&q1*WPer}1uAd^RH$AuXBFU~rgPOrj?4s|_PV*wzPR&^gds;Ws`1ffcrQqY{WKHEDAmUb%sxW5^$)} zV8#HyW%@he{Hu@tIyQgh(cjtw+5F!kM9yFNey@?UIq%!%zQ1n_DHAvY#N0!AC^MO$ zPG{%*a|jtI@ecCQ;xbi>ZugTFXbPI}-wU-S@%hQUK}Y#mjp^!lJDKI*R}KeHrAkd& zwLIa*H)+(_d%THlV8gMb9r*8+C!H#{n8XkSyJ}M6KGv_)lhlKqNK9VB>Jyr057Y$S z9KasBF>E=XNL=ag5qaxLzyH)kNQad^`-C;$b|f0vUt!cdvi&Xg>4ux;yw5f!nXj<= zw(Pf%%8PK0^1VG;k!j6|uU3HqMBNb>y$(d8n+!}I_37_yt&6XKk9@Gqyn2DwdYS{)t6`ILF=^b3yV(Zv|dU-+}A9L7kS(-i$g z_PZptO6N9_W!l&7Bd8Xm6Wssa?`m@V%_SfE$8#`=_<^fDDZq$eyvy}V0 z!PAly5AIA^|?{OFAg;f3dKdo6$vmVr!8_eDB+5m%aI4Rcfj0-$WV5+2VR2 zx{>8=Njzy513L|7z&8fiH{v&g81NVCpIG!-OIBX)95bGGaFk<}ZZY4rUl%wKJRe1Q8B197~-3yYzzE+%j0 zV(QbYcX|E}NubbEijAk9Lz8LgoIRC%w{Uq9&YG<726KM&36GbQ{R zhP%AZ+gtPaiE$^-oPPTny-G7;1l*1tpG_EG)!=l3k2TDdZ9@Z+<9Bnt++}MX{h4sg zu1@-Q3(IZ592cQBU?K5t_WeX~{kO&B7_R$dh4JCMPa_6m@XsguVh`y+$$RB?mi%i} zIrQ!Lc+jutTij>+iV|OJ_ki4#WcftNN79%PYx!71ZSmtVG9HyTlXh~1Q4zelm=p4A z?r??AUC1i=GDXXYRcy~ixGe_AoR9#-u+qJjUER%B&TF7KTFe&}>~aXDomo2=V!uRQ z+w$9t|D6kYHd%pi*0t7kaBkj{vhbzD-p<0|=B8&U(2|UT#9pZ$kvnQ8Mg_qVUv=V8 zwS5rvP2XsrP!V*En$LmBf}M9B*tRACt(eZ+ES!|j5tez3`+i@Cu)g*zM9E&b=#DWG z*+~jc9Bz~SIP9jSy_L-xzSF~CLsWBf7~wrj4kfH`_V~z%SD?u)z;YlTZ>BkRIzT9J zHS5-x>C-smeTpl7gdQQuxCz!dfp(U-N$azC9K7QbGL7|I6&L2JZ0~7DNZ0;t{#vGO zXJD6~4;i{QS5;r>z_h+q69aAz5zk7O#t5aevc$jyk=aa9ipL%HG%Da|1;E?;s$1HOZ__l~?ZQoBt z3~JJJb(%*n-ywIllgz?1C%$ggF~;=KyJorWVPud6d1Sac05D8Qn#?0DlmI8|8RBq0 z&a5Mp2r0wCnz81nqTz&?1M+u)A|XEQ{({Eqc@#rFDURT@Q4Urm!_n$j#(q9AMk{r_ zo+U?y5#hJRv}EQ+oDl~t;00J4QuhHK3RE-dP#2uXm!xk$SJ2&t-B16bowchnrTJUV zj_ z!vy^CiUmk?%azR=o|N|ehpbV{kR#D`S`td z*Z#)_ydq)Dw?7GNQ@)4qZU1mxY!bc5*p60)!KNz7qPO#0|9!6QEK`1AyW8=m{6aE> z3t;gii=6DD+@V|CvM}a|V$DWp(zDq^)p4qk zcC7EAL?JnMrV{D|hx zgXr=eu@%IOvze`jic;qrn>Q9SZhe#?PlY7cKF{d zMJvA1F@WB7GAgP0lY5(SGhrvZ6S2@=^p^4?m%3gu`SVM$jPR&d|sM(07~Cy_B4K#?0kRk(NH&QTEQH!{(2@fmMdxPQUCvc7(g|C*8{gG7cywf z5GKRMn>|OvwJp#rCg^XFs9$gnEb+V#luXyQx%C}&PMz&G*kQ2?Y5oitgdoECADjho z3J47&yZEf-pzP>@xoq2CcW53ku|m1_|NndbQ~5*$L_ZN6JDoeC^O?x2$2$aqphb#e9 z%a09X94~!EJos`fm18yFQ&jW>7mfvwp&r);ppH&`_emXr^u+kqN`s=dO1OYoSX3^U zi0~Pe7vBvJt6(Re$x99W)s6EfzC{Oy?`}Al_~lL9ESwezf1LBBlqJ8guu4$ZV+E30 zCtg9x_t(ouy*+(x=dNCkYsr4-<37qXOAXuEyvh`spqmN*NGhVLKfoCOL^rAqn;zn_ zF!X0VFhD~-SvvWnxmQLzX?}Ky{T*x+CFzu@IVUfGRzAD72tCG>&agyjYqsQSZqMJe zYIeTVu}K$_e!u{*lna0vyS%h)+PwbG!8O(NH`=}fE%Lx+nA!D793Bj~%+Zp(zOOi2 zNF#SW-iv(S3-|Cd(3dD>(i&S9NjO&gnlbrrDvdl;gkwYdReK7%SLB5EG5HwF51lAZ zTn^Wp++|Xfop$HWf3k)gPM9_2qTV!)C>G&WJ9V)anz-&xO(1uM+(()_3NaR?`(sn7 z5#1sAR@^CXy->f&nTu@(%*qE4ZqK+s$Ot5@^QQ?uiFxiJxDNO)`p?%>s7QUt#e|RPy$Wya^Kt5%)ZKY{FcK^FuW( zyt*984hUJ)ad>Ib82qwo`-0}Q%f zUV6MOaj&SS+wF5d&E3sHKf?PaAzl5u(*m3t%MvVSQmF2&ml;uAxcz{Ty~snG%p_UM%zpwt3)^Q;?aZHf9Vli&6p zcaQ3&bpfp%pVJ|`mvh$>n^PI`fw1$~K0*|N%( zquzQId3HxYy{DX`FD#fD&Dw_nnV?EZ!%G4P)Jm8K2mOf&=E0!6LgkZPh+W|S-Db21 znQdbxK%E7(kKK~KiqgTNp+NQXx2FwV__kOl1OMk^a+H%2>*=Ran5!}M8-rPnNB{K$ zx{^Pg-AOPB=A?L`yKuCu$1o1c#Atk&3B1k8=`yr z+3{+lWW><|tG$LCFvGnMxrIf9ug$*=W^cuj(v^F$I+6ywwB$8^sD-v@U+o#H&;HIE z>{GFKB8j;zrf5?o2gC%L%U45i0nR?}^!y~+8e?fBZv3jqZ*rI;dv5<)n0-RQ@c9IZ z?;GX-DR6^Wt$ow9^hO_ST#Y2s2n_rxYyPGMunM|PrbshO&)2vHll%?I@jdLfpL$;a zKct$)(v+l)^O^C-Av0b_>2rKw3Ynm*C_J@)#jZz!t;<3|8t@*2_FUOusykUzcUMv2 zvoyTsMlBTLj-G~rQ$oNqZ`U7&RQF&PFu{sEg}9lr<-FITy_W`S4VYD9WL{NT%Q(}j zvQzeoqRV3zT#;M?!%>Q+;r^s_3rx*iUG{x`<073+MYf9{OgbFxz1Cngk_{a1B)_Mps?8dOc7SiQcTnxCQ&Qks) zhULkfn^A$Hkw4tKauCD&kJZ1se!ME$vVLbp9bm|^IlV8U%sJTVzS3VFPI|g${(S%T z>jlDvaPSrdMSfk%Rof+hAtDD_SuA^7(?qv(7hd5_`+Vw-VjK0~9jnty%{})Mm>w{> zM|gx8?i|Iw{u1UwYO?L~bmMRJ4XnuDpk|vOwPY$_9)|XTPJL5UBROL3t&N&;;-Ru+ z)LfGC$RWc}hj9>dBW?s@Wky}ON9;sczv&(TlriD?C{_=s;%e1|Q_8>-!0 z_744xN1&9LzLnjDvFH_HX~fg`cH+c$TXEj9_zr zG#a0j_}1?n_jsH?%~cgzaf2mXv8!Ksu%-8L(w4j*jLX4evg=h<#-MASHn2Mo#*VE3 zCqRb2B%FZR3UmokeafQgRN%s2gnX{jYP{2)wov2_t?NnwUIghRx8?g;_SehrAxoC1 z{d9MP1i^=b*f#1neu1v&EbhLV6b56Crtw$lH_dGc=ouOV7RG}wxDIs->+^5$&$p5u z^R^zp+4|Gm)qK0Su^8i(RI#NQ2h=Y43B6-|#r5#MrtZ3tMe=7EMnxG!32D6$Dh&u4MJ9$~kq5f8#Y1p<|h(Cr6n$wu*Z5pj- z)YJBb=H^EI1DatmeMO59LV#o#_l|!FPu5RDGYOWXi8U>fbGrgzK z1x7S=yyXORkw4gU-DGH?FL6L^QuI5IYm&%|>JTT7~*1$uX4ulBx_-G5Bdh9e{oRsO#6tOQX_jP##X zLfBHkJk;Iw2{Otju6FNMzZ|m*hXNZiQRo$p+q9Fqq^mnRoX zX9G5K*hRR&6<^rXzTTK0Z*b|ShAGf}CHJtNo1K_uYjO^UqdA4^G|VS=+sH__U<00) zXpGPB>-E~~gGl2g0FXh2c6=}*YS2|d{r`Um0lKxVoL>C%B9jU6`2f=E-{KK6u+wYnK$LE3qx{z#JAj-u;JH|k|h|(E~gm#|~ji46cya3%abjb$= zOzzWHI;1@?z+g7SNqUwEHjc_#mqs&r_%H8quv|iDzelT&dh>@;Wi6MIJk16Q<|=e3 zbXgAJ!e36vUrV+mHcf6m?&x{O;raKL-hDz)(khCTJo1ki+{xvFTDRLFk?N9!zt0vx zHduapTlBB{exRx~mmZcp+IKjxDDK>LYP*+v9}Q6|_NdcAfLbY(F|Z%|^8m)Y*ldzd z@7~ZDASR%_E&h&6a8%--$SyfCLX68(-1E=z**4bz;`m(1cgkPDoAIRg&g1yBb=@aO zrBqK%twh!cBD!*-)e~FX1I$8$8K8`-ybsIwl{9VlBdn1qFKiGk=Rtv|?mK)ZG}RE) z;+YA2Sn3m*Cq^uZ#2nuF2cw?B?CWSQPND3CF05XI40BtY(^&rPy{fS$YnrR6X^)nY z&x7Po9{I2FxormZamvSVd3eXdG@u{~LSHxF_eK*}NLN=`J;1IW+5iHa<7s@f zm34Lv(QoOxgWTV(-Q#Z5FSy8oz6P$F_BptFUX^JeH_Q2zRgq9w0efz@8WZ8(o<`M; z5A5I!>X<*DSaY5`MY^)zt~=h+clGJGg@lQ4yh*O0dy=E2G+x&eHw*|8!ZfK*2_^bp zileiPx(=(9Y6X_O_=DLB7lJ!?Ol5*5)a0UqSmJFpuqrA#`PzT7#Rd9?v&R!*UzXD zKy~p*mwTE%TRXIXh%Txke;cc&{!Id7{t)2x9UPEo$lszI4bj!AcZxZS|Ee5% zoAI(9KyKK{n6xSNR{?MPMSgeO6zE7(OX|xI1vJ3CtL;-6w1GKdMeKdPr2WK_HL+g=3CBc+Sa^Ti~1@h z$N`q4TVIrTxa+plw4vm1{QZ9RRN!lvZRhfy8qe$s@#kY^daUyN!x8%rNyaUaVIFVV z*(<}3pxO)iCc;&{bWHOk$5K#Y_Fh~L+4qQ;q{92xNPmRZlw(E(YYSp%K+=03AG=?E z6-oU{CTgnQ?``;Ii-a8rK0opllAZx zV0VQ{l|`t~?&?hi8ujP)zL8?={~{WWrtXYE+wW(O!C6r;u_m=wpbRg)!ZL98$iJ21 zAL8nNI%3F$`n=Kby8Q)2T>*ke`eS5a<jmk1$si6!x7HjIc8l(7Ob zDkv;r5S@EnW?0Wv{1Cm2S+R1sc_r3!bn70bm^dpJcLs_!#iSa;Dd>P|4YnD5qG2NH z<=%Q4?@zK6JyER*3AsN68-hF{_pD0!GT49m2&D+*mnl|hsi1|M?K{fjcYSP+qGbh$ zLUy=&>hhU>;eBPjthAWLz|3Ngyn~C}zla1G5myDLcNw}$rM_zeAE)khCb;Lr7;tyj~GWg)`hBoA{={&7)e>NvdU`PZ|#xJ&7HaOMvO;X8Wv7}RR1e*SG^EYQN zeudNhRle3o19%6{j);>Sc>oy>^1)n)-=i+pl<9gnXe=W}YbvthkN?2)pBZ=Tx6AGn zvOYbAZ{uP^A7zq9JV>m+p~e#%MdVO26$B6(FaC6hZr^u#KbEPdh3n6dtSOf)^)2he zd#^u@yLVyh596)0gf>+6*nXL^14}mE_}ol!Jt$ho`2b54AIaHD-R3Jb+(NXaD>^aF zpmVj@cX_6;2U%TLAvXteZ)Uf+H@b+ri<4xcOYK|8d+bKRUsL=+D$UD82>L@r`^GL_>Djn2xivQDeC zHzeQ_-t27Bk-qVM0h#bYCo1#0OqeXzlTsw@9CJH#oUif-;G)x;xT0}%*UkWHJcWtE zjOEPGg(xw$O;ob~d=26SSPGE^!IbpWF+F-;UA9m6zr~AZ0@9oUlyy#IGfAh|8*64$1<5GPjcYakNheK8uqN|Dk!` zXupz6>{O{i*bTG>3?h-faczXdcHTWN02lP$WO8TY?cQ8d#DME^hw5FV!p{-BobF)@ z4VC{TILgHA`(LgMh6ZbTb2;eMmT3n?UFS5v-1P2`c&_SQb6Z{+Qz1W7i2>}<=4u_k zuA*hlbEoT)k4^26+pzZ{*BIkbqAod!6lpfCo(E$@#w=RE>!T}*KFY#YopI)b6^9yk zi#&muNpOgNZCMIQ)olQ8S;R4jBwgzPjT>3fJ2^`@>#_Vv5#P#jQG_R_ykH&=EoP*E z(8GSePVm0y(XmYkNIYL}v;g2-Cjg+m9{L+j2c*oOvmDrRGJfq;crhjQ-rnhtR$k-y z$zdV#k4VT|7u&2`@$M62pmgDPnPg_^6;Pg~pmpZi>xC4#6K|sO8<9xy$VP*WLnT(ua>h7qxalGLJ z*o{z^-?Srm;BeWOs3O_ZC}Yimqjq4#@>l^a_Q4}bxwLo%rmnQqrv{-cIttH!o%7Fs zbM^LbocA}n`)j=8@8@sc2Qnjge-uG+{|~|bKQ#G&Q{?}TWKjP9e;x0hJPQ+Umi2;W z{Nb zq7(4u-`AX3I!Q}8$oNO47c9&^=Y?NwY8 zDErFsDF&|-{;vSTKf&)Xnid{Ccu>YwE#kLu1yp$yuHHRpPYb>pKOgT*Z|~C&zuVu# zda8?qe9!W!I_$4UdXOE7+p6SDb~5kC#Z>{P8?uaXSO#ib0P`SXj-sOm^Jo=rofs;Y z3eUjboAXI^oaE7aDypiGkcsxW0Zyxw4(sTdkUC*d- zx!4+J67jOVwAYzyi=f`T+f6APrBJJ2wp{NFO$^&~M-ae zCC&Hq-^03G^g?apzZVU^rEtHUKNryiBie+ z&EMdi8{%g`yG45&lRuy9^vHyV&?6snO)lpXa|TY9;)0|>*y#pD05%0}*F|BxI`Mhl ziwWEBZ&^KzfaU{-ey%f+;0~s^@2hDt!y7z^N7g%xKt22J{M4MRMvF^pACKwC_K1Q;P>u_3Ffty8eSX7|n_a_6Y@=q`@9Td8ve z$1JXv?)G=xY_IEK4U2!5(&LQ0>E{zS)%oOHtS@hcbENL=3B3h3nw1;Ex^J6|1jdTvly~lr%AL^&&@bUCqfKS39tN4pXJ?h<4m*J>dLE2r8{j&kT+Aew0{#2IH9qcJJQQ!Cgi45l- zUw*-+V+n-a>T#;u!A(yx=348v=SzKD5<}a#M}=&owZxQM;$j@|>kwpEy z^&p(_zKG<8zA@dQ;d1jEpv)h%OPn3{3XV8@Ft#{yNV_kN9dSx6>Xd~YSDKi4jRN3xagrve(H&?T!c-@c~>-Mqnt-ouTKUYjG1{A6r_MSi2NhpmATZ$ACg z!-JXK!Cp+R?MP8b78H}i-cRFK6LAlvU*~C%59~`5BnlqGZu-A70In{4= z@!*bWpIV?qTlQ=u8)hK4KBx*ov+;$-^`^tJ#Q#dvZ{zu|XY~2ili9~y6V0q=k~%_# z&k}3i8Gyow2E!EiMhcoh^qzQJDB|MU@i(Vg9!|?1d{PDvt$-2|F}lISyzbgIbt%;h zzO$eX4zcqV*f5=ic)52umOtb<)*&<7)5B;t#TNa{D`bz(k{gNW*8O4Oi|k}XkHJ-i zDST_+Si z^2gVR2#Ip73M}+Iu&J|UwX&qk?0NU|O3xs#)ZpZIpa11v20`^0WhF$3x0|?dZ~Oe; z9{q1~ddh#R$muR1M0`lQCuukO9S1s)*|2_Kvp)T8>t}vhfa@q6#8=soOKOj+y1lfm zHv+^X6OH{756{T|Jzm+Bj?F3N1PUPK?~P<)xzWZ;|Dk5EkO5%jk5&HtA#)=YP2TFr z$BTcYyCx4KeO*5iceOu!{~|9VK(q#~BIAr^#-}&@pE_vA{xxVt3$EnDU`C+tKQ$_0%LcN%cPd?i}?xP_Z#i>(ePCQ#=x3&aJcu+b0@od zUtmNn^%3IxNbSk-WwyMY?M#dI$+T6n)aTJnZ7rLWw;dbJA56S8SKYigCK$=FSgn&#%L)4raO4f3lv3JKIjbbpxk8vuoO z*FcKSQx@!+D}>wo-t3$p580eUb7G~M#2!dQdLtE?kefP*dYXSY68$2I-61}r3zl5! zJ&m$@(4KoKG`jZ2+KF=&q~EODB2pq@u|AQfEE#&8E3sp7j*{R4ucX{o^%&IEFf#4p z@k!RaL2Qh@{QW64uEcCsc_GP=ni}fpazc}9FY&k86(!tnF509$|BBOADJVU>J zgNyNG>t;x*jN|Mi9NP*eRbu0%dyWW!jphsv`b(2|zYukgl{Ihc9fAJ;Uq753=JfQm zgDV*Oqcb8V9*~4D7W&Qk8vV+rJ0Bhb$d=Nbnh*haMy+RjppBBan@=4Ym>q)KqmhK; z=bj!7<#UZX@^TB0Ib(Q`E?nc}vm5cMIF0f?!$kbRS;d_O{@5r#KA}L(O`vRJyIze< z@q{I;F3$UQpgqORs5;^C=68vb8S|GSewlT8-dI+sm~(ndv^=`K+FqfooH=p!5997D zpRdFD{utQ+9?Bb5>>cX7;&yS%7>u_^o)9N&IR|K(ofnz9W~>efwz+W$VmSB=>MpuX z_OrnWvR&Zjxm=N;J6&QW3E7#SI)1nh53OUajL+03@6>Zwpkb!d*Rx;GmVeLv@i@^& zx(#9AGpxE?&TuN>i6z3I`j{JIIbmsQnKNv&0g#%JVZQY09agu?HKJBeB)ffN$Xq}yc z!Sj5541P8Um+WP+U;p)jtG=kM4CFtsDIqbslevie6TOM@4$g3A@vK-Ew_19ZE`sA?U^El3yp^MM0oiA{XqeynbrJ zkc0u8UQqV$aJ4Brq64-1_*RvNxK$>${n^t$N86~ROYJK`XoP+NY&UfL?PP;TaY$}X zLimc2b}ETvX(a2uo;m6Z{m?zOwYF|@v4wJKT~@{IVcrCa`-dD1bB zh9Q0U(evJHGw@_AIyG74d?ztdZ+&%Ra%`p7F9DeFr}X>vF*3p42avKx3uLF~SK_zV z^e1W2h*)blKyGa{AyF^*qT__G;ws)9w?UaNa%FX$m zF64Y@4LHtN#O9jnEoX#O=ko{SdgJgFJcq^7UOteo6Et808}K2OHkd zEkBGBvimk2d>R&$PU-F<0@cSvMPGZnCEVaPPEN!=_DVIl_QWten|Pc7KL_riW6EWK za-PXw7$1j8SX{;Dfm!ffK4%Cyz5ZB0flgl45%u@oXjVY&>Qj2OPB~AoNIPDD3}J{6 zx$_!qw!sNXx3Wa6&np7g9Zi{o`hLk;+SW9`p3Zv#u;eQhRm4htkvm~j9-?m_;gb@A z`6p~&>%{mGpIlB56|Wn=PA-)tY=#wxqbbJsQLn7%Jstfo zlu+w%ubBK$BcdCbCpYgx1@F3-!(^Pw+beS%p&{E?F#nGa>85um2djDEHD&c11Et ze_RS1{n`&gwklblwwP>{Pq)rAYHK>Hi>8VQ=5hm9Wy1y6O;ouxI#d-yMNXq{l47hK z|B7A@{xeweUe!rC6{%a+!5;&)F*tXAILmhZlCpQklQLu0{AB{sBB%Hd$d?DBAbFCn z?78%}9y@Qtfj<7|@Zdr7>XbOHLw*E=A0MVt1oP$VP&#s+FSP+k=jKu^%W_=B=@!Bq z2x_ytPi1DQP3&4eol_6cTSew;iT3QV(d<{l9jqx2ewp@jHsB3%du+Ms2*Eil-F1I7gi-hJ@miU{ls&#?H zfwY(~kJ{-x%A8WFcl$>D%b}pSKRR%mCkq6{L#{{`NGB64KQY<9hD;&gzaaTTwg4p5S+g zx~l^db#XMU>4AJt>1Q1nZ$OTFdOKrKNPEacU99JmN55k^5@LZ?Xu6{~@6tBWpu{BT z-zgg6mbTJh97LONJJNu#zwQl4w1mnUduD;r6310@ZEnFijIac~k|(QrSvLNV>t9^p z61XQsknQVB5>M9O2W!(ua1Jj6*fv+SQo^i*Xi7q?;?N$!=R?fAxE*ORL=C6T^i$W) zz{BnU!GL~L43Sit%V~{%yv06h|DHRW5KKmxKXrU_E1bg;^fsApYT{*9uz-@K{IeRx z_gs*6D&nVrUCmKn&YsyxEffRtA^V|(q5M~qHhd6Gcki%vrlOdxH9xG2qtOUGL4U4# zHycv}=w7`ATJO?AlzfM8vtXN=kuW0SULOh&l^ey*DSE=wcL!4LfS%ps!dE{GglS1= z9wdte`w{_8(f7xjJTpxiolI2(Y3d1xbl2~deISDzU`46F0Hf-6m1hF!ci+*4H`!Vh z7su)1lJ@1h_3U03AaTA&FdZ_8v>B9lR5im;=F^(Zr_u8Ys8FU?T3$Ws3ZIO;agScC z=D!S{%3YEG;H}?;;8M_M&ifa)+@tcAM5~Da45)x9QpQFpK-Q`D-lbil=JF zif*4){DGca_rQJ6gL8tHmIt#3r2Pr8Q(GY*({!sr4C0wC5YcL!?QFuE5LLGbidq3T zIJwr9L?Jz=%!>_)sa+Hko}leB3nA!XjJo*la+`oOi7 zRtVCXDMR7lVc3j(!b1dOt0}ZEC3Gb{$Nz76@>cHV&waeP?RNYTAEh5JwBfjqTKinp zd#Vg~y67*$v7FduCm~G6wVMr$HR&p{guYg#yjyPH@%dJa>H(1Kf%+!PzH%xTeBTbP z$lf7BAKgv{T=Mr4Ge0I7^uW#3;cN*0)+r-JRX>6Zo)3CEj03jej<+^aQwo)nTc@~F zH)CslyB*4ZN8Qf>{iQy68n4rYd{SK}f{0lk)g7(cyZ}f@-4E>hn(q)$-wpgjYQe_g zioTO2#Hf=-=>XqJgk;!Opf!hhkk-j@}E&G#fNqGD8mVLFZx<`YWXc~~3n!DX_dsfwMNN&M=mQS6G zN%&bstwy5k2V!Pe(~t)jzp0z1tAr$Jt(anZ4g%eXT-k`u6&B@72F^zyd8s%52BBpoxxIBHZ$VMuBH+!Dub7o)#x$7UMZ@v6c(`X?nyxH$NTyE zSw;fU^U~b|60^;faY;dkGiL8O4|?Ug-E40cj*%)0FU_m`W*b=JMI{Tdn12oAB!Akc z`nCd0G7AZd#796?_3I36z;?Y4^eKV`r1>3NqBrq@e5G;#fB%h{!Lc2i6r|9@f<6y` z5l@yHV`w?hZ|1F3mNv!WqH#s^|Nq_{52DQGlHT!fxx8HGJD*Yv6ScR$nSzYFX~ibg0_zQ#*cUKeoWM744Nff`^WeEs`gAMJf}hx zgN(mNUw61~x7xr_SikGj_j8PA@Eg}%E$2^I=uWR~(Y6@_v(xwSSmDYgN@_<({q=9G z(a0rCP6J}sKn6eOz4Z7k5LO+Jvb5~&SDThvgc-;EI4VLBE;&(bW9}pv?4*|w^IV$k za$QDU`bAU%I1`=)V9tm>k^nECGD`>cE^o$5s2DL?#}rw?Mw3+>kxgjY*<=LE^y zAGqMh`R`GkqLH1VQ>*x~;Hne`;c9k#CV-696kYM_<+2jj^6?y6)&gR5K_U!w65u2D zVRN%60IS=hr+LqzQ}p$2$~J?U^SYtQmX2Sf2$Qtbx7bGr{?T^c-|-z-OLc6|a%KzI z%j_bhZGpfz!v>qjhFF|L5i~@G&$cr%o%Py=+d9AxPx1Z&jqy8-4(E_oO{8hzOU1Yv zge^!?ZuRqKy#B&`h2v@<$T=oA*zAr;14xmV<2rzZ$1{$*{%+SQw{pAJEG4g3gFA$> z&`jC)-DNdZXmgd25t6P-f$* z9l_SH6B0#wPE^17_}yUH1MY4O%5IAaQQeTAcZNavkYS{#b~ogO*gUf{8~8e@q;hKZ zQb^MbBIS+)z3~GCZ|jVA;sGMfRRDIz>$T~m`cMdvKS1rC$pdEsyEa?ttGF5#qsw?` z02j6!hOZS)GRlX`zVC0lMj*mVGdH^N_5ac&GhL(KM>fB-ywAGgX&pQQ*HraDsH@oN z7~TxGX87oYs2}Y9HDJRXeTsXTGk*qO&gh>nhOSzFJJ>nGof?WttKPJ+BljC&c$@q4 zD`=#KL1i1RF^dJ6|GR&C~-|!br`ufN>(@de7U`eU8)}3HbdB! zA|jdzI6`H6y9nPkJc0T=fzDFI^8xwBh4!c>d08%3WLUo9`cz<7*eM8Lr(b|m_(TGzEJ^73`V%N0?I)b^m8TWcvsS7QW(-pvNvsQ~5$DOV!UZji&tF?@G z_nMYPKikn9Goe-a{3A)Tz;@pWHf!9(-%fKw2kIoeg9ni(RWpY=?_u5TLLkj z8bDTjWrT+(U*e!ZYUt@a&V~CCm*xAo2{%9Sl65$?H=NAMelVYVDA|ZYtc{31%(T>a z?CVXI%AgypWg!C3VA3=FIVGq%54^}C0(YM91Zg(ZTBkj0C)Lrjzubv0HAV|fu;CP0~_NIJWEM$~wcf0U^=z;S+AdPyorI01r3aT5- z`B%jARM*4z2o1!R=Z4f{i`Z81Zmjv-;GmpNROej_2fl4}qG4bz$zS$4knp|HF2C@8 z{Eo_f9q}P2FY5tQ#RPz_%T4`7xV!fLb1VYqw%Yah#JGf{O8Q#|)gj(0OP%~12A_!r z%Rvy4NlE*$i<~o}2LX*>8H{Q+wSlDQbKS1-ZyE?sus zALw~)D&PXC!(O<#G0icnRnzJYx-iVGJED9g$Btg$Q@llQ&fg2YwE%i`}a znfs*o(09vqO`6F~!u-&KWh0B9o5S|@HLEXW9tcUVSUXPoMUa8->R%-J;)R*K3KxWd zP!wzlney+tl?*wFVwXvmd!j(7MGIJ~nX#zm+6M3+&2if@F2beJ7QOG`2~s{voXZ7KQ>IAtPYu&vk56K#Be?tgoUw1)X z-Wdy&zMbohw;vpX|)0n7$2*scjhFuOq# zFhR5&>)8oUL%F5cO46pMR~PIAN%q8dt(3J`NdaLCj#GEUg)keewh6>ea1bYGh!h#l zOV*8z_8J!4rRey%DXFEj1Y0DfL$Ty}lKxD1Jy_Tw>|Q6A~4%Se}q+1JpidP)I;A?19B= zAyPw*aDeN@gA?4lFqiVqL{9s(F7gHnq7sKPGAVSp*R_{&OmYDwseLblb09fa`tt&? z-qat7i0NeXUDfP^tPwh(goEaqkr)W5f3>%!re}|Sui?dv@hZ@VAF^iHNNo5!5!Tb` zrNr;+zW0+tIah8rN~}4(J(DLs<1RRg;ieuX@KVxX@6gEBfX?E{Y0CkSDYL@55P6>m z9=MuCLH7v{cGNk#-5_xqD>L`x^v~?KH``q%nA54kz-1Y(elySOK8em2f7DfOrVL*f zRwRub(PK6g{!#Ko*ATG7HYQU3CF2VPT53##z5wc+uuYPWOhX29dM&+77w!qi&;=RV zRJ(knmh$o)PY_B7BNX2M`Vk$WO?pN*eC-tdgO8Jg*L1KYE5@#aL-5;0%peAUA?zvn zl>VxB>k&fA^c5^~8*YDF@p@9eBKm~1&dFpf_?HDqWoB6XfVi%kSNL{Sprenr*>O?& zuKAk#YzzIxF)~c058eyfe`>qnE%;=4PGe_#8%0dON>Am38aXIaGfW?$jWGOm zJBknKc|2|olPUPeF?DMS;samR#J@V`i5*W~jgn=@Xd+)&2}&H*V=oaikdt!cjV{c2 z4)1&h8CP`RIsPO^+^|?2N+F|8T6cD?w?b5n@v?s_k1lKj6?X@mPz_@buisz8Nma{D zQ3gQB8B2YM;vtdUeT~om`beDHmCeopLAF=9=8grtRr@PYyk%m)zS%MT4itktdzY5W z3A5wgdXY`>wwsL3`Dg>m&!dX2XRf2#rw0qX`mE<*xP1B%M{(isCEq3~lDrLCTm&H& z>kVNnw95Ith{rd%>PV{4Yq-G~BzV@#i%S3Ad23=B3pha}!Ou^ycmCFZUzoG8k8#0j z)EtRmiA>52c519gmk!B2Lx$mrzP$ED^7np1!TI^qi0uEo?R@Fkx;V}%<4Auw1PBpL z9e_X&SY`L;X3eP2&w8DJ1Hi0eG2D>Wfsw^;9Ql+4@Uk`jN%v^GQOg8MUl*ou>E}>h zMl|U{-dXaJRy04tza-pjsn+nk7@Cu{Atw;j)K<9RA4ms-iW_ua=R}V5F+l(SA9!C* z<#RGFlx)GftckLa*YD@pu{a8zaExox$1vT}^JArZ3D5R!t;NP(*u4@$0c!yQ^V{^j za2LMm{9&22wKZqC3_t4f93Qe|7tl;TC)vuh9B%|59KEiXlBBe2doThc_~8A_KaeO@ zPs_nBoLvyKHV*|Su|FAEb#Qf^(jX?7$fnebn&aIsCB2WuXN254dbT1vVlLU4F51g` z8uXJTY;RR2^m9X@x4Ry+p9NybjzdycmheO4ggC6m`zv4a6B4FPH$vYZ!T4Tz3GiLu zPaUr{lmC6bk`+DnF}+Wr1Rl({x2#*dL<}k?`FAOn{8qsJ_!wm`s7^ZCLy4=#)CYS^ zxYZXzzuASD0T3pGYsaJYo@axE0<$ExPoG`{3MX-+z{2bF(p7)SmTWMVO~n@BCi8<2 zk0EV_w*c}(BJ}!~PUmB|PJ^T>(WiXsTm_1sw22weO@TPf!(a#;iEVr+CAe%JmiT|-TpD&&Sr{DU0wc}S_t8%Ueu){=ED%>UFn6?@ho3ICKr z<~>~uSdY0PKtFr2Uu8H(*)2lAh*3Db5F!GtLuIc(+Lt_btKN5LaK6839$A(wzs_#m z&tWy`<;i_pfWdGjZd|S``eXR{z>8xUl0hkb7TLRVJZLk!z3-P?HAA)6BDZsFBAjDH zKVU|Z>UuPzcmU44-TOsdor{xjx1Qk{Y7=A5v3WD=-}~8YdNBrvd%px+j$D{*2(SY- z({NWmtV80ByPNModEjG3g*B$RI|;Rh9Vja!qSkcxMQICH*G%v6_bEgRg*es;!5jXL znYor}c(3|_yxD$U*Ur6qmxhpK8R5FOTPFR!bKxZf!9v?$9kX2T&<#sj)(8Da4Gi8D z38VaQ>Y~AFUbjc;c0XI_##wntcw0wioPJ`mh&NDfw}($V)QLxjzuuE)v(%Y&nND?{ zNRF^eZo0c)xM?Hg`U;E!~cfAqdkb)qO8h;u|!Z;nLrfqQ$Ye>7EpFFsu-lP{0qv#`3o_%4c>=)VGCOCKO zh0DWm3j?7htDt(Eliog%QOz}CKHY4#+|_=9je+;0FcPzb-s`h*AP=;an~=AvNq}|0 zKqH8^Yig&74FET3(^^>4jNhInJXY^Sh&)STn$L1H=fBV_`@-Yo&QOLZGl%&IcGrJ3 zKAz2E-JP#{z6?|iK-yLG%~T}5LHsyz9WHi`u z+t@}n<|&tG6^?wLiEj&rg5?z;t1wwM$RQ2tNNA+efyCj^ekf#wGQEg9lnM>dRDgN$ zK+9tRXPIBogw#^#_J8{P8h4t!!60Z0b|bXc(^`H@yXIH&4!M8(+iNHdchRgIAx|Dr z7353y6VxB`C7P=@56RN>Iyo2YMy6>Q2|opSbuG=f(4eyhn<1=<8A(Xifd{v{a2d9+cyrDq6cZ`|1I zxNgr~J?~VL(4bjg>xZb#nF?Q7@P~AvF;i7ML`@P9xk~ZSyRKFve$$}PO9|K7?jKxP zuEL&x$O`JL3gL_pZez4w&|;2-epZ=yBBT)iy0(I!t3P9|Sn2X1JM+(otWMh!$9oy_ zCOjWW4Ga@rI`yOvxxPRA~Bv0n#%x!KYraOH2C1_Qe~;j>waJ4 z{&ZFcXO`|7n#CVpYDo0lZMiDBixmf1USMOT<)wI^dy);1bO9_itW?Jwtq@K~pe=_mM zc0y9bMt_4F;8Lc2`Y`)mMAl&4=p^f1!E#kH zGO0Pk9@AhnKp)d$djAw%LKAz<=#2hOiwtK&*m`cZtf*x0?haLPv5Opv?MARzkvW~0 zSwCEav*QU!TyL(gl{gqV^WOKJ648tJm!=Vdc$t(mf zwybT=-kGKqz4C9`35u+n%-B625I*TLXJzVy)Y#rR?zubOp&wL;mieSINq5pmHaz(! z=IkGzx(s$tS-;+zSykn8l~-c>Zm3tAu@?#9voH2eE$rshwM_2)+Tuf%+verL$M4nU zQt+kEV5^(E_<6qn#ue)muXX)PJ!yMlxFBVuqQDuyG#|5tbXiYt8FK58RsSaIcKIZm&p&yqocXANd%AQ`}{ju(>c#8 zw+opnP_(7m8%KF5uA2T99{1Dy>xwERvmPdX0uFTUTgJ+aI!6)3ZLt~}z68XMJ>n^t z-8kiRWJ#-#d0&zn?>0zW&R-1=bu& z<5s_P*Gjn><#IN|a}Qd-tSy?qIdh0=T=rhz5tW#OdP=nEa=;S5{O}O512a2n+`+AW z>a)N18A&I%ilz)=ZNqil5LcR-oE_PIbbRtuY5p2lYF1;7dJOM|NWQeWjC~j6E};s+ za@A1wC6+@Sdd@QkBV!!r;L5lPGOkP%sEFtE1-E_B;*b>*iO3WddN?3eY)Ycx)>GQ9 z6KAuTWBEOhR|BBF@EVITY|^FZ^I22AFi~Zk8jP%ZkZjRj1#hf6gh{1} z#QWE|4*Esc&8IEQr#Mz#%Uq-{%jD{ST{Qx;mGC69?81Ea8f)O>JiL2SXY=ZJ5%cO! zaa-{W46L_~XXfYvPdpndhG{+L7ju+;ybQ@Xs7p|#4M;EL!ppfT4|xm|o|!A0V+}XB z!8@N%!}}wXL`9gsE+$Bv{FrUJL?mx}`_MJ{ulp_gHcxe!Aiwad`psNnpw z-#M)%`LR6DI_2CNz3Nibfg{6=fPKOKCzczy6(8{_>Ug2Z@3aJ#nK zS{KU)T!!%3$$-o0zGfi(+kIo9jb+~%!m{ew<9a^7 zb^zoe$63B28agLL2?K{TCXP#$J_*zn4w{AfImIg-VtW4;vlYjBxM11GLxivPz}0|F z=x#!>RFu2Y@sTM|-+H3~Hna(8UrtT zt2}P`yNbf+Zwt5?Vw4B_xgt9vfqqWQYEeH92l^ruy$LpCcb%FDUVawI(z%p0W-FSK zy=y^ch@vedkW`X&;JSJyGvUql9RwY|2t8@)?f%}s_Ep4+O&Ux=4YTwweup}`nEh8H zI@ljo%-T1MuAu`syzabs)wg!KDm#Q`cFd_g`KZjxbpqA7uOU<8=8%zxO+s?Q4qSnR$Kp@WqrjhS@$JWfiLy>wb1d zU&F^tT=FI-LzOh|+2s59iV9W`6 zUOd(dcrBMTP_04pGW9j=uY;b0@TWW73hm2jkTskc>p7uTSqoNX??92UT&OMtd-T8t zYaKy4c|6jAm&c28a2e%rIf2(<30Fy%M$zSC;T}mwGiKKAFE{J@)die+;!J|_cmr1g z@jy2DHHW8>{fwGu$;NVwc#9>RRksXS*6<{>C}7!q!jnlR1=NA$FL0{_KjRsA%N7Kr zM}g%N#-?zQ#XUKMAp`fu@6}2~8Jtq)v;xCy05uqGjQhwfXo$)jdCh$++3x)}d|QBq zk{&!)Q_jAAl$a+a<*c|e#ZSbe|NlSgahGNKaZNXgK|^_X)Hsl|h!;)W%9`C@RuV$Z zlJ=~qJ8ceR$crhopdzBSGK9X3wTBzx)82G&jhY@1?qGYf_>l@FEy>}&^XY6ka=cr9 z+Ng|cNWOWSgnP`gm|r~Fy~W$d(ipt;2ddO*U#_|)Jw4~s50Lu#&EkbH$7#d7Z%b4Veau7Xq19j4c(S*5diEw5d1NUjY& zh!#Qb_Yp4LbgYaH_il3AJkv@$ZB0rxI@Q^W$9NQ^NU>DN+VPBQNjmwyX_jjv<0z zae%fznfq3UYV7(jS&L9w&IY59y@=>o_8NkvNgA8<+)P-XD}O-QOTh**_JTDR&*(xg zYtqRa`U!Jn%yj2|&k=RNC-E1z$OI(=I6q{4TwDap*O{)FcDy_a^3*5Bm=~RnlBy5W z^ZnV^ss;_jgG+dIG@kU_$+5~{MSsnrimvZFs0-G~e|90V-ME8lGGMYt-_Kj7G+jZ{ z{&G;`_`H+)G$5KV4wM>J0H$qYeQQsd1Cg+@#CRqA%`wKkIPx?9$}ou7^X6o+pMCu3cn_WO^M85J}RFFxE+ zLqb_#bDNemJ|~3vX{yBDrgV~P`-7=Y0-+yJuKXt=Qi3DhjTo)9egs_cl(o0J|G0{b z&T)@B&qh*kr+yZ3KAwlbT8$Yg6k%c3+41I+ALEeh`Dat!oCW5dl8u%7_&dXqSUIk6 zp50SrS1rE0w{m{)M_DoTz%JcF6Q0o|yh-JrX4w#9By-y-fJ0-$Mx4XtZNK~m%|=r|50*TNpKUOv5!xA5Tpz^|3!gNlD_Vl z608&7o7D6wnBB41%xxJUDXa#ll5BCAe-E25UcjQ!%LfRx{cuWrY*FAp+QKvTTH3A50$I71E~zR{oTv8; z^Ui!HPP&s`%8_P*|1jqM|L@GFEv8gAm;m| zol^sn-4LAT-Lt*biz@G3w!CAlEo;Kp0vbf+p`K7%`KAj_r#kLE)EBQI) z@w@)~>HMx9!C9}*k&TAe-UQm}c&3G&_)Yk=IKH0-f~9+nycU(%NNGl=>Mg7f6!+=G z8_zH{*w9~Y51y{Jr?EX0F@PZIvrDKqtQocK8YM^S9I-UOb`S2g{|QtsYgM+nbxHzu zCdvWzMws7rs#Nm1AA=1;7qgG_WOTf-w*&HRY8LH@g3-k1T?AkIZtL=5lvvyXDwiab#i2ZjhL4 z!-$@I;C(RY?CAO=G-wZr?n%1pK_>a5dolqZEZr59UUoTRJ~A7~^yqe9d;7YFWNbE? zc|xJ?UPo^ez9%0*c;n6-sY_Ns%h!W(`8pE9CMvG1vokKd;QRQ>(rYv>$V%(4B9f}Hk@xz!wB{klcOGVgYCe7 zoBN&>JUCz1w)$k1=TA+a(B^#)U9BO#_MA+S`GBua;sDmHKi_&+eww?o(`&@ph{wnb zQ(|i-ZFwi$4Xsgek?(qBhw_XoRKBl(_X zHx{?+dHx=Y+W_&z@Lq&*4xcW!y;rAitOHj7X?KwV7~{=LZ@<@BagN1ZZtr%E#(nut z!)saten_FzgG1fd@QJ3{bKb<~>zf)^G|#z}K7V%}rXTquc?KcEop<`+2>duCqJTf= zHDI>$WfeZ5>LwR0Ym&Xj(U`~XvGE!ebAR#g{uK$H?|144k4;o7T;h8Og-Ok30w1|* zI{$nhLky1hwRY*|qj*pzwDeB8AkT>i8;3`JRoTDAd%hbs7;RkOP;C6APGuSYj$s;f zd@oJE(OdoJaJeD*wT|Gc&M-lWLrF8O?S!Z|Q^e^Ia_NiSN*R)KJR1n9}$d7k<8 zG3y+^1d-=w$Jtwt@5l9-(6(y4T|;V;8hWbdWC8$c5Lo`Ss$S5$eSDw3Z>)a_&1*H3 zt^50AC=x{SB@fxd`=T1rT3h%V;82;tOkXG2*oJ!fo{(}rn@Awhw#tV8>OZ2uD%M8e9gmVNiVn$!id|bT6bT?9B5JB6q zubw}6m!R5lQUtszVCt#HLI5{G9|&hYdnYL?dki2&<)$jHq<6Lpsz* z@el}{lTi~5Ptb;el0-H>n+XC+1_4Jo`3UdY^bTZ6C-+!ZyANRjy% z6Q8DAb3j)ULTvjx=zRz!Ni#S*{qL=^Dk-dyY}wZXVPJcc9msjGKo%&t!bNQL!8$5nxyV$nlferJ($isbomXb zc*uClW*9zEvPF3w@Iwy! ze0yIG=>Pv~h)Dx@n{+qt_GXwkfSAdSRB>1 z_f6*VW2>&f>;EmmXSg#K{vsdX))0&<(=YP@8HK#R259_6*vr-t*t7Pk#lx2~*`*SW z2r_Nn7nmtxHXqLp4z6RFq&ug>6hkq0PQTir5bDbDu+PPS6J>0+MNNX^H-J0tk2rtv z%%@RZF-2ET*wYY#R=u?K9_$n|VKH(3n(a1xl;b-y4k|1)bWzxTKx>DoVT*_QTOT^A z@}~)-5O(V@-Mrj{IGe`z)@h(3J?E&rvadl1z~ejOJl$2+xnik(>?M#yXQwkjhXPxC zH5#r1%tJSr6gOcxVFm|-rkQD|r2zCMK2@Ih+tgdKge7)CoVx?mcH2Afr4)M>@OHvI zCyAKR|1qi_6n01LsyL?;tP?-(4#+>dkVhqowbSK7Jg4-@uFoTF@E44$Oi+-Yi}#iR zZ8?REsSu*Yt?q+A*fqg@?!80rJZvuYgKUe1{ptD=1p(sOTc~CI;D>A$R zv!&HF$59u52XNcGUu0WI76m45aXwSFtaJD`v<0TJntz=3p8+ThdK=bN|I@(Ow$p32=@b%_nP@yyCOV%bL<^x< zH-y2v6Y28qtrq$gtc$<-9tyO|M}{pOUC*I}B*b|C)MXhVV>ToGx@;^*yE>J;J@SM{ zn{0lDXfXy&?bXhA=-nUk9)>Y16jUr9lgT}D?*(Z*Jhjzy(Ht%&12>Ph%Nb}rgA-~D z*3_iaRr-99c83ipECbrYSbO$^fMy!mQ@N;)7}ODiTs!=@=U1*G{B|@N2s+^z&xC74|M$aDIlRS;@Hs zh4PP?MryewFA#SmjQW&VK5-V88LgxN^xR?*&{ew7LR5#-9nVF#11W z_8$IQDt1&3ebqP%-nn=2aRet=EaTU!0aMK8oKf8axyJJT(_>GYB&86!B`IF zF9ap&TYjJICuWJ!AZyEZ#A}iz22EUsyF$*5`_9OV-C^s$o9Th=DUTt`cFri~(f6qh zkB-vs&gF&Yzw39Ud$XmF`=!9Q=_FJRzLQ-8vi#bjjZf5(+lCm@QE}9n`kT+7>o-KX zBmR`-;25+NbD5&=cUMSDt%HaKg^`o0ybzsVceGVu*OCZUi;5`uBDl8KpR4d?wN}EgyX+{DwWM?i zt$$RubX>?QkbSl!?{YS@PL`cCG)?mp-h}9<(Kl}>udsS{*5u{ z%FqmV%|3|JU4Y75&3h2Ybm@Nb3=Wh(DA3vucJKyNqO}SlEAL_KEv%^KYYm$J6QXN( zaH&56jZTpR)i`JHx{HMUu5Wd}RB%b>52<`$8GCLH`#vkcOPqdduwk3z=Bi$yfA&BS zk55^r;`&J#SP@RLcX2mqhpl-1(lEY0sKQ#mu>k!!zM(AsI$1i_`Ea4AB2Gf(7V=-? zA)n!v-=M49UwB&R>}?abB%&*~uix;gP|}kvWEXiXMtptKaW)gX4WZyoppVw5RpA{s zm66}Rg&>>cbehrXz*u$g!%-J=)WT(XP~T9Z*|+hURL1-vnGb;i?saRZz%YZeYGra^ z@81TTkjKj~(*hJTH8^7Osq9auXr?<%qhkS6gvS9d(28h=&rNFa(CqHdH~-0nuY(iw4v$1HHR;!<1c zu-#ZJhXfz!tbMa9YZmnQyVz#+5}rtBKABAs29N@Nuc$YBg z#qkiUd2Si9HCpMJ+Mfd@K7RGHgZNVT=D%`U_VN?>FX>x|A&VRuj!}!nGk-D-J$o3& zCUh?W(_HE-;y20aqpB46~n<=4p;9^Z3{R6`2 zao>MpBxqx4t141Abnv(J5XB5^|!yw{Q4?&+dlnq=`s?M zof;5ri;S0=r%6fY$(4{VjwvLmeu}#W|e=HR8Z`9a!Jxtpxyd z_Gs4NZ`~_dBvVcqLtw+reC2uhiQ!?sJyl(T&XbBJN^AMgI}%T)P~x=lH~4QkgWP>o zt1jT~hSh!X{lGx3%Vm7pzPEnr9LUUA_iGZwr$WV&mV`}?)pR5mlEHZN4?6s=BwkrxbT#NGOC z!wUVZ@>%yC0G|2G*H?dEcf8RTKb=n%cufC(u6NW!+rw+A)?xiEq_-n&vKM*dyaoo? z%`2lrS^--Mfpr)eEp;p(={#kx0p&+4_p+}gU^vehXZfe;O5fMI8;6#*ISU&KAI+w$jaA82u_)SKX7l_?1TAAEFx&#rgAJ6KT~V6^<&L<`{x#f<_lsZ z^(=gw`UPGNx-E-g-jsiQDrZHLqmlw2Z>oF<#8Vj0TIqS^Enn>8=sDL_3ni;|(Mm*2 zuz+Z{#UquX6$84!9F#{ktYB6=F+Kz7_1^wc%{&4!X4jt>_NZvI6zolPjuSLp#{6YD zY?=K-Wx!xUen*;#CrN`Y)oCQ|TIyX?xLca{>3IrJ1WOn-JodEqz&T&BknESx;GRiI z1+GMC#ArWa0P(r=e|4Tx--xh+3V%2-=bkcdx1vOJb11C`D$UBX4PG*Q30%25-q4tf zX`kzzimt01Qa$?rfAgLo38)(+PtUZOs2A-V zmI%kdb(F_gqH)V5nm+*^h0g1+*NpcF-HY@)27Wgaw-h@Sx;lQp@=l>DMaj}bD;bw9 zugI?FB1Nf0gp5ZgNlK-gy62r+4r)e6osj+vDVzuN!4_=xEqf|m+6TxK5phDCg!~(0 zfa<9;-sNNLPTJiB`*>5uNMwi>eGw2K%Exz#xtvBwM8;jK`dm>M+xroEckb}m zfzk}m6t>S6z-qvRY@K$n#CSwMgM1=B^S17)vFm61-s%!&CRy1?L1?7shA}`*eNU zk`WmgPYlw`c&=8_iu(w=#QIRJ|s z-Oe>$nM5zfC^@?A0^P}(N11c^M)6;eb5UQbA3I99vYtED_lJQ34S{`QRA1%TE2bp} zDlpD$U;ow_p`Or~?w|z&#oas)@jVD^K=$Ek_9mm+hGW zS0YUb&hJ#&!6FVr&F@t%BcG-O^FH4C7Gd#JB`6qxNi7aQ9n_FM9WT-?;8AQ_8KWJl z&y`+aq@hTqo~7}Y_BfiY*ns5I6&MD4r#(SfwKWB8Ag;&VjQK1Q%aA5qX%(DZB9AD? zw+ep8ndX7(!0(2@nuA;JNbZE#R_Aqxp_9>(t=-+pXACT~=Vl?E6Vek=1(Wdd{zZTO z#a0948t(`*k4{n0RYKVz`cynUIz+;qDy%dl9k7@-GJ|=gX^`!{*=3xtVPaBBkRvxrwMP4^7!NcH_1a~Ej@a6pW9{vVU3K@A}kr9pUQju!{`BV_yJIL(t? z$}oK-2~xIV;~)mhFEu9Vo`Ffp(D+m_<6f52<8H9YKmlitVgl-+N8b~68AtW41@SUE zI#(KSl+=fX^>zU^5vK6AUv4F3!yQ+FB2Qr1$tW=m{CavFd}Q7|;C4!C?>(Qgg+CSm z;T)-JWVe#ctN1Q2f_VKnKlYmw|QJ;8O4 zm?SQoZeY^lgIK=GOZc{UK`ym$mc^X0iV3IjEc@f4M&jTHXPbih*Tt&2e+TX0Ak77f z5>e70Xs!bqG)5PGWP{*ZfJx%#v+i9wgU~) z{p)~z#A+g8_jk|c)VR`4ENvvhimV>OvaSkJi7vn7JvL&7I$f30SJQaw>Eu%6lex_N-q5m<#lith4>@- zmc%ne+5Bgua<=+Jbpn(B{rF%I=El;Gyx$pbCmGyW8{+~~f$Rpvo@;F!a-AdOV`#Ge z`E^Xj-zlMc!br3kpHl=3^v%J&1mB&&?-Fb->rfP-e@|B!-?UpU#b^559p@`q*k6=8%m?a*bA3%APKVHT zGj?_I^h%W>enM2GzaX172jiv3GS9PfaZ**&e;C&s4!NY?eS~agAodKpX{^kBOz|l} zcyCwZHZY-?cHl9fyztln+MAI-ro!slSXlml+oyd3KiUsuZ7$yL;gsBqZ%47eoolte^8 zVP5{HLs<`~$9S}rL6w-1>&R=wI-ArV?0M%=mCD;)BdZ?P%{P*myzvCtv~2y-Z)gse zN+(Bq>{#T2MGK4U6|bNr8qaolXs`w5*l53jpC%JjxFn8}Q`tn`~u z8Ha*jvDR@^7UzZ3+5^(tCiS}ML(OVm!j#wZ7Ms(@^xI?l@U_#@9+2x|5 z_}8LeD_v6U9Jim#HNOli35f7r(i7# zs~@}mWMaB=mI)bnm1cwT;I+e{P2K*Ii2@BzE_h4>R3>!QnT`I~!1qc}uvSQ@iHu@? zcbEfDijS-0a?xG?b~$uY(m+{`t;hP6m`Kp!H3t;=3IaKOEa`!jSw8#5Uc!mpRLQT| zcPEvLruZ)cS}JmP?-J$NxFCrax{ZI>sqxl6Fxlak>BjRP?+d9Izq}bi10{A+kiRN0 z*yvOhF38{e((KA(Qvs+W=z7bC1_W53zxR)ZvoUMhpHE?$#_-P^&MU?rOVj8?tt-LT z>yQTaf}~~_++d+tL;=6ulJWKr7O4cw0EolZ2yM9fdhBt#EU<>h>vSMd?w)p+8&191 z$$?$iZB-u)Zq5Kme=m{v!KYX1M8`i(*ANF%@XPD2fF9dz^v*cBcS>b}Y$5LYG~GPs zK{~t?LR%uqZ(+HFtb{fu6@}$z$a(k78wp zkN%~yT4)Kb}5?%aXna8H} zHy6~!);T!^EDC$_2d-FU$UX?I=1Xw^XBu^A(ezBTjrBVEzN`MVq*6v?$<= zIv_rzuIQdbSlhE1W%D$Wg>g9A>>J}D>En8u(@fhAXwqrVe!g1oSg;U?dVKJ{<$c8- z1L`~U~8PvPMP?ejtX{#3g_J)os)dV1bO$8Z-jW6 z(NRcnYhkWsr3wX&mRQsP%f9d-E;aHdzam8^7c0Zi>{!#}5M{p%uo>!O-g}zDR9D!! z>>`FX+?=IVAtA&Vyaf{jTa7%b`ZyxED>|Ih#X)BpcFRI}%| zY~9XJ?|7B2N94mDW&G(DA20g*s(%h=*hIkoc>n8fevS(spC12&(&hI*WC41aV$6fT z{=6?|066eB-WTuqKL7new*L7g|Gs#AJsu)_ssH<;|N6hbJ>!4>-}siKYW@3`{=ULL zzNbU|_s`zfqhc^)v`Fiym-w?;TNq&dQuPC#R^?0drJCP6vtF3=y2jz*Jl!i;3-}vI zOOQE-naB?=h>f;zi8I7CRO)AiMk&n_pFeI`KaiVKwv{e%J9BfgE#=uWu|>9rydl1K zt|3GrRl1rvB6wM!aT&g|CBBFBtTcTuBEvH1NG>R=_{4r~>K*?qHXQymB&Nq{%7;=m zi*hC=6R((JaS8M_3j1*q={sZRj{RmY2%sy6m$vaSiBZt0N#vG<^CAQnJYX}cU_luq z9Ya5op}4riXmMxkP1si?1NDsIT(bqpR+Jt4D=6*P3XbFED0{F8M)yT=1r8s{_K72B z^BE0VnQ`##b^X(jxXbYN9yf*7dVRoVO3KBH86U5hQs9B8^}h$=pAW)6KeK;42lM}Y zX8(M0lx_EFN=msC{tIu*PigjJ_OafhdBs4}V~=BZ21QNGziNMSynAx6QE%zh4 zr7V{jPHS=T0pN-!kQmBnE zk{GG63J9kTg_Fa3BgS90ui4A-@pL4UIih9!ZEQ^S)RtV@$Lx{p7@sdZ46++_BzxHy z)&zJW&P!*uEH}dwNYRAwQG~FgP^!@WEWB?YA;!*;AN`V+=y3b64R{9M>%OTA>Ewit zd6s5qiW~)e*~`Y66;{iw5O`V~Ng$V@3{%}}sTq3$a+s&^H80!;O3aK+KB2-k^wZve z{!aarq*w66A2#ys>$beCpT`NIVFOb_NA)EiiralWyS$Tc`SU(v(EL ze74T2V{mGo@cv6=Pz&l_hRnKW?`c?^0UEvv9yhrRUJF)L?Q3)|!pTH+dV^ah9Y0!& znudR!QojA>0J|aUEw-3bFu87?EE*=-EC;ySa{R8WA1vdktlohE-pnOG`(T7dJ$D}d zq6quv_D+|bI#|E>Bo7tS&H5@{1sGjU?N;e>zWX58#bto-EcYzF6Y=UEBlw<{a5;W5 z{X1XbV{Du2{0-oAeZzVKT6@nlj3lDwU~f6qXKdblsV({tVs$U>8%WNj^W2Yd8iWpB z8GKB~?NQ9G89{Ejqm?r)vI_)wFSt4op!AyFy1zhY2WJ9iSGKi5V#$$(*0`{xfHOpB zF-&e`eulTt>}q5%AgH6Bwjq4ORT4C75^xYaANwmV^7G4G2h4llSRoC&+R9cQK?vag z9#|@8h&9@QH)>4)O{s91q*OzWHA2HGVCN8Z33-2^suI$IKG3LHi}Ip+?PpX%O(WFg zI5;J&``g~$tOu`Bdf#=oCl7M=OSr7f!TTg^4*zLQKS{8!9P5Fadu5jOMxR}vmbT)8 z`0cj=;YXx$Cy~8Oi}sW$Y(|Rkxh)srN?S+A%a06g&`K^qPjIA?fD+PYpJQ^HdNt8J z3TrG5BPO(0`0<|m0PD0Hl!nOd=1?maqfXAZrh&kR~;J-l%hbXjqo8kvm9D4 zc}E}Mp+EPQ3kXm=9n12pGCfA$Ycb@#Ydin|U(zaJykAiSJgan{_n$1{k9HC$9H6b?d$qskIwBvj>}R?Y5@3W1I}G6ZGtCCl zL^hyQOltYt9b7ENsAG<#8$xF<#M^jvUy)_m2NtNOqsA{?JbF&x!y$i|6laOhK9E+j zcW%`ED^tf|eSEGZWnQ%QJ}=r9OpyURHioE)W2f#%?<2mRa`lAGXHS5XuCHGU3cTOm zXrAwf5|Q-r%Z%e^i&R%760DFF*s&5}Y^)I31$~QZL1w6J6!(VPYcXCZ)GiZ++wO4)2 z${jg!HX^`e-=4N4=xG#c^r;bS;kq(Hz3*=36=3=kjPO2WtnUqO+@o>)MXO&-t68H1 zX}#yZT`Iv?C?Wfe6ZvM@XczE|kO;|cxt8jOQ16HthfgN;=2|(o@teZ(_@O=Wl`ztA z2V4mkp;ub~{yz|3-diq?s|Hujf70@pPnwxhgwJA(-RCrc@p-r#^4d|5Z1kPb>b~{8 zBH+poe(h8HykJyuo7^)9WZ3J-oJ4ZDlz9I1>(Y6$P7zeoD0BCxaCO-}LI z5CT>13w$_hoB`X7X)X;4{j@I%uI z-!)_tj{Z#ZNcpHIZRfW3?sy>HaFdR)!Q|u34e|%rq)4J;9AelzKAm_2`&^-i#PSJk z2n1?lJ8+@g(aT<%W2~WHQKRDNQum{xphw#a_Wk>GXe1J!Zv-Q@?ki}aJb;o78+=k_ z!o8b%SQ)*6r<>#^)yp+P#KIfuEL5A3kY~%fUsy|T-oodzoikl*aOq;5qnXIgO6-q! zf_%VmZhB?C8QRZa%=rtixhr~gKb|l6Aqe+_&k#YbRw5fdBKb&x*h$=koHDjPLF*B* zFzKw3pLqNyN}i@QaA!_Ezuq>OD?hT1XM=jaFWS=G(!%s({t!(cf4(8*0Ke35GZs3l zW92TV82STR1;`X|nSsK?2vvJ3NVoGP2k zUTLrX1bzQD%M#l=e~CDg+Yp}1Fy{VB0VCrqlCKnlat<8+;S`U1I3&H9uQGYWK1qmv z0{eTOE@ZV={EY2k8uB`%rZwx$FG{6E^mz3tog;&gNSGr%@ErGDF07f&_V<0T4#`D} zddPYK0c8O~&gHZ{;Mpk-we>uEXJmdiFa&q}J_d0b_qIILGI z0esm9I%Yr~P8+0a|F~1d%{Bl4lymn{Ebf&V;0(j;FqemO@{E!FMt519Su0xG$I}*@ zHL%y}J-T-ft6f4y%F86D^qYSF%0rrCF0r54h^QHHYDuCZJ`WdKinfr`93shvj#j+? ziyf}Hw>eJustM$BEJR@j{a4t1GaIQ8r|*rr0*!O*Z!*PKq!TkA20k5VKO!L%!n@%} z&eQc^sHva($3yo3EW7d(IdR)7$Br`BKxR7Wd;D-Mi?pF?g)FyMrza#2$YGj!{udPW zO8!m)y&(_k6S2X1{15@1C5^4*DGNsxBGGnlnn}Z1xkpGv?QFA_Rh@#x0Wd{)EKRv3 z4%cmeOr$^ByHjP>iv&2_%ZFH<9noe`lKOULRgG|E{lUt?$iq8uj}C;>#w_`X8Y*> z|AWwASZBo&sNNXXwua=k%t3(rGqE#kIul8&g16G{1-Dv-JYXmn%&sFuwx^dOzuv2f zGG4~Lmi*itj<|B>5{vJC44w5)?S6;Tqb`uhB8(vN4fsUcTJ~=brK-k7d~GxA|CIL9 z%D-4xa?4c?Cd>SEpVS?yunto!)SQZiC_VMjETW8f{d)FyVbo%$D_z4*f|cR;nxy>(Y@<+7w3lBM9# zQ)~O;Q6OF|AKXZOuJy|A&S5vLb=Ea20k5b*BK&+VpSRBCS(R%P(-9hb{mADYCpYfs z?R0;hlP`rcE8PPlGz@=RUkR4HgHv%x${OqV{j?G2Z8n)$KG_pQ4(m5D1k$>UiM3qL z>oX1iGIEITo_i!JV1TDwfcQF$Z?ZZeS+|~EqvMxzRjR*t?IMY+R{QzU=wMR-zz*rLI?^QX}x?&P}18e}Dt6|v!xdmH-_Njl0qWNoZS_}tp`<(BuL zs_FD>BeTSc-=wL*l<`YHPjIyGq`u*-0M4U#Ur!z-5Q$^z@O~Pb_R!7Gkv?HZGPff) zRqNgv3R7gVh59V}@m&5wvg8l&9{eGVX(j!Ih2!H6)x5WDHnE6B(w`3FJ>~d*WcbbN zvWEASnhhpA!w~IpH@>c$^U8!Cat`F#pDIFF$TC*m-s($Bv*)&vwGAqwKT&!M_A5Zc zvXc+1u!ksBczuLfB)oK6W0jI#H+iqwb&ge`7KQV#JY%&WSW6z9eyO|{+Z>Bg*NlNq zzYRs{20PJoUkDuAsT$tB+|AnIc$sC+u3Wm9Pa$zFtG%7LDhrk(7Qc-Ls1c!9=k{76nD)n)2jNWMG=FBp zln`9PW*4`S?wG`dy4eO$L4DJ()Lub?$%2G@SW;ZZ&4WKS)0(}Dt?reBUub3ObBfFk z3gOYO_tH&uEVVl%fw+gAnm6d_wRZhQA}^pd@V159hk5hasd zZqIPMMyGwQ(->x8@kR^@263lFZ1yn`MF|1M5)N%{H@V;LTwD5kjy_9dJ@%swp%+nc zs{_1a#TN$Rx|xVrWB0s&L$iGj?-CYvPp&F>l82jo|xY^6|D52Bl{mt8x-a z=?tTts+FY)^HVE3Z1y4llG=;8{3Pcw=yTjkCDhv3dw}t80 z2~?oMYGUGu=@$hqx^t3UYo@T1_&sqY=+#*FI(m0E-tkNIT+jZGHvIZ!igAa6iJROxlX8`BwD0QnH^G1O(>Dw zPK&!k4wf-zu@;!a1K`2R0Xz=B+mY!ih~am%rk2&fa^aw}&{l-9E}p0l-1o7h$ZqKu zSLe2&hforMmN`VAv-6qR6B}@DMBaf4ZV2c4Ox)K}81?1z)9wA$5#g}vJc#VjZVv3J zX^qpqhNfAOh|N1QV{Y%*WeYX;y+5t5a?a23{!8WhyL%n&<{d+&6dl3pp_>b3YqlZ! zhDG_(w7tOzR)R>4H7^Q7 z{?pJ$a(#7urd5b@VG%Lw+23ddKval55X_@DfIY7F4nF~4k|bhI-T=|>PoDW;H2Re; z)A@_I?%sH?F;vxuYp{Khc?#PSJQk`bmuqp!HaEls38(2E$Dus}38j!&hs_vSJok== zaaav#)(5P+Py|fX5Pae4fO&B)msfa$gG84&R}DAip?k=EAU=ms+h7?(2)}g3||G1mN$Nw35Wb z0->19AU=W!V^JJWe zvyG535~E$~xHY*`DNAz?xl(-L?rdE>FWwDd9~tV*0xONE4y4EQSW{=&n}GeMO6_Zv z7xxn3>nvMY>1Pj}Rlfk+IlzDIS-1JDou}y#KuIqp$Yxo-*_Z^81mpV@=fh!O_zU640>tpsYMRIl<^SXSe9DL%&jF^xL^0~Fe!W6T;uBanPfQ<HLEQyAcmDDipQb7*qxBK_Fj)-Y^q^`x1Ey zjS%mN%<^)A;)RqwfpNg@fuG%%0@hZ@h}>Kz+dnWln@&&pFb2+^_Nxpj?!s+`-9|fG zEB)3?lS4={TOgC8bbqyQfp0U^#!Wdp4`au@h?EUP?mmK zM0XPzHC`g+PS4SAcloro_LZ>_Y;l9MaQ+Bi{`qxJ6*&D)k0IV<@b80i)mq1`>%q5p z8xa-tcIG^YZLt57E9o@EoCruZ?{|WrUalnjQLlf2PWvKSC;r|wJUJtY=8?2l47QWS zxNj0-cz30xk;XU202kxn=ll)z!^`7Ve|e$*i#@TEqvU3|lTPf9X3qUy&F4KHI_LRa zA4oabJ~Antfs}`$bD5;w;lN(Ej~?F)*1fFPM`yFxf}NvU>TMpJtUQ7F#&2GM(IZ7+ zk8GLY<4W9(O_MB}C+=1lF~Zp%{9OFHCNJ0@W)@~_e}R^Pq~tgDM71E-F5$lrNo$90 zLyA=QtL2P}Dtj@PS6^guMclvVZffs(`skECZ`t}5r0C6c$NTh_i9MtJ_Ud zc6#^LqMDd#9WI8evA#2AS-U^~)pCPKA+iXE)Ng%36-coqe1a6NPB9LUjOYjE*+b`( zsQ!(kqXP+ti#H>v^AR$jE%)YQxbne8feX`YWIXF7`~kx14O9KAjs5(s5f7}Keso1FN0nO%@@y)WIhGANZbbzL5qkhp5i(O~tkRz(v1q=i^`ys{rCxna8i!`a0%umG3NGp7% z%5qp@M@*x{7m6vaIDuX9{T8`@hpstA`FJC*WPq3@h?p|BpqpRuOs>4E^wNX&f?(|sjU2plbVy26Ll5xc=$BL-d4{P<$7WxdW*r}r|{P7^%4*DK2%GJ{5?`M4(g zhqedBWqDv@SNi(D&?80|S+e`wM-l}l#M5`-X+zT31r!lbtdAVQvl}9=|1D_yji_4v&56=lb z2c)AhkdmI%!aNO6nw`v_XK@&g0Bw9Gq1|gsslVIq-1JRLH?5B|#j~tmAg}raPxE_p zDz^SC)8sIpr^?ltnHuh6>}~hszRwYH=04*gSbL91N!N%;gnsBnr|M*o@v;&h9&U83 zqhBRQl?sWzf?EfMdil1Ze3 z_bdHWK3p7`&bRiUpfc#F^q%>P!>%cK5FndP8ejq%#~?S}kvG~x=7B<3%A{A4O%2rcS3%iah`5@_dtjueQFB<~D#BVRyOExm_@xZkHoU`%UeTb-0l z)&~MDx8b5nu!%F`)lvvl;#EU)GP-+<-n~Paot_+vIodl_caeZj0{KYxvGF;^cTVWxF3sfFft|%?#U=4 zhZ+)}Cm6-7+aS6&8o&280wmJ6pO`ze$9?%0e*8Olx_IfV9$9MUJwU`8?=Ve zeVzdeWmk-Lh%Ybx8{ktPA!suus)$tgs3%;~D%ZIoS>KTIMCx`r-v<*n-E)tU_J)~? zO3Xjx)y>7pu53aI7ml=?BM`#$lUKg8g86ja|V(A_h})eAxo~lV$j4v`w#J@O*-uJC!^UF^+Y1ro4imycjVIF9|LP>` zit!qBUms?axbAEEE24~VQtNnqzn8mz@0UlZp4>XTLi*z?Q_1p{V=NL3HP4zG3*Qeu5_cH)#Qpf{-_o(l z##n^my;PL%H5Iid(Y!@6AUqX5$O`Xz2I{V9uO&L~c!YQ@>r{o}&f|-)*qk|`Yr5Jm8X)7j7qOqL&A$%wN=Do1w?Q_=zfY->Y>}H_4e#Zp z`uriT6>Zg{D=hk$W(GF2A5}2S^O;k~^5G$yB)b4GeS<)bF7k;U5kNwr=TK+ee5t`k zVy5$(BZ}!I17HiBG3I$e>VUSl2JfhzhC!RG4JakioweY;3w`5-IUN`0Z<4H~g}uQw z>Xoef7ga-*ZAJoyMYv-87I6zVDsIXsF@71{*N-n9s7gw%dIBT2WOBRLALEia ze9Ytsk9+Xg9#6#>&p@XyS4Kh-^@pR5vC4MrwqI>=c)YXqX)g3sHNs2&e12Xx-p|Tu zJUAx%UGFjGY4wY)r#F-mbCT@uG<5%hZuIm0`Sj`TI^_hp)<5<@px-Do(rW$PN2zGs zLLD@LSers+Si|rKK4=6JC|x^@1Q$FIwcJe^a9`at{&3-+bfll%Q>NehFBP5Y;Hf@v zJOP$Uv3?wI!W~hl6O?%Lg(KKjOA|hmv7Rk$4l(m}+ts#NcYGol4fw-4l2=FWE zzBVFj`#jv;&!OB--2i+aP(3&k!M939{e=(Bl$}{hb8$;F)iQ>{xL{Lkcwv_Grw_6v zX))gqZEBxG^%fApCm^JU&W^y$xluZvWX(7Vs*SLsQx$$1B?EVPg9qF0B2F_ zr^6E&5x>dxA0C5+hFTb2;zw|oza8yH=-(Y@9Aa`%1ZXod0nWgj zN+jqz{ZF#4mp0BXGIrUwR%poSS-i~wVmFUNFi3KD`#WZKh}+4Y=<&=S0@0+s+G1{+ zV!I|j4;0m??CRYC55v`;@?un;=E zp98sa+GMYwKCvzvo=e@@n&am3dtP?x>A=2^V zT0M8x$9z;$Q?1C38y>9L7Z~DUrLt@{e31YP;{gp=UdoQr*EoHhFKt z+Xd7G@mUY2YKL?l9AbwvtePdutQS-2rZOCCds} zAa7OKNmkIer$XFBf&0&{mHv&BM`;QS`(JPQb2-%$< zmA|#GVhw!7#jw{(&o9=5Yj_Oip}g1SiXb<1Z)?pU8cS?HZ@~1IbNkU5ag6Nk;oX#M zM2yd=co{cuHha6c5e@+Q*8^m6Cilh+?-N|BD-K5E8cyh0b`4f*;H#Tmh|Zt`Sy9Rb^{OA-A3$=r0#Y%Au&}X)d)y{ zxyPq9!O$Kw?geLtjO8|J8add%q0Dv%XPB9^hTW)CYmR7G4`s-h7J~iYpP*$zY}k6k<(EhXs`k6Gp$!h2ZnA5eFIcxr^C%W z1ybIZH~NvPb!fCfa~fs;NeJk{HYq77`HumE4cgp~zEz7ut22My_j);7U+m$#BawhK zaoYt&qpi;sdz4;E>-hIEy1+mOB)pXJr&rQ?4B9%sMCD&*$^u^o>5@Cc|9Nn7AYLY| zceqksxMjJePzpps?i4)8ncrHEJbC+wdO&>?x`*cHsyggH0^aXa#?@@QI|_BPoDA~? zb8)%KPK_KgJiVG(#H6{d_utHmFhDLPf@116hY4wUmG4+Z%tzV{?*r29B{xbSBYpxs|zdShqFEO<~e#3x!JK4PKULobHOS+=<@dPut47Z zCaz`tw=-)Qru%&xigM7N^>lXI^eaUvoaYNLm?|V($MXRU261uhyu`bI{%vorxih%L zn+wc+XT>0$pd8I<^n?g_&s1tY-PNXgnNE<3S$7!=+ep8)kMC;c(o#xhrKgG zZ;1K0v)H>I_Fsz2zEq1zWJGpiW#uTyiW1uR4+NBEH)}SAQPPTE+TD)^z4h&h+!oSW zRl5&->Gzf7?0Llb5SWM*S4EO0#NAJCyNsZ){S#F}DsCu%XHcL4ERUG0+y^_G!z?Ji zqp^dI{`%k`@-fDii<5G=zn<4!Cv&TL7kHP1O0?==YEHyRAea5ABwu)jkPK5E3oMf{ z2zz$-=3mhYfXQP=u@8p}ISisF^Pwlh{0*_Y4LfS>31eDceN!AiN2pH-B5uX&cg zv;>+lPXKEd%_o8)98|2M4fu?C&{@>NgiUWw)Dr<)o$EamKxXMV>*E=lc8 zL<5b?;c0Nh@^M0s@AFH^FZO$!0`^_H{rUWT?w*)Y0J1_$^tki5*?t|hkB!|fgg52t zwua!f{!v~XO@_9FzkS)|nmzMk`QCn;6VP|*y1MXz8@HYUE97auK4+!w+@D0tFfCw+ z=Y`-P$EH7-&pn8sQz)_yyJm3kGZ@4mqH_2^x^Pb}?)(XSn?E9k-bGZ2ez`3iqSFnD zOII~5@6ZWXfND|e=&IVeqng$u@IFh=+9rhHt;%-L_3#DnB@%1Z9Gq*up2 z{N&rh3(vU++(CiI@&Tj&;O}1504FN=dUxQ=OZXmH84Qxs_&kr(0`WGBaBDFU;ljwy z`>|F=0w-N|49oiW{Ed>`q`4gLuuDbMsmVqK3@H75XF#*Rb3u>yLoo2^mltsaVzi+8 zo*pl0>#+p67Ri%f%KX0afkC2&gjC~{mIiv6ry%8xh?HRe1*8bJz<}C{bAfQ>-wy%r zvUtJz$o34?)@ty%>j&^f@R!`t;GQ`uqj)Z3=a14nPG`hz-zD4+{#h8PwS&&C=#nPL zz55>Vf(>BDA&g<#%Ade^Ag73)E!eApi&9+4nIcA zTm0`Z!7I7Ep2Ms3-{Zx@3+yt1A^xZ zMxTM|ksd9Tn6>bOfpYAXohv}h>y{p7xa=u-%h-Gi5^IrZYm6V$3w_Y=oci>bm9yzE z3CC$wu?LcE&jnV$k|BLFc18?;iob$jV7f9a3h8@Fj%9Y0=yb6El@zo6pbkmFZ1@7BKDhf(;ff7a7|`7odoam~BY zN;=3&I(8wu{Bqi&UN(bEF$w}z?2gn4{aXy>rWWixqTjR+48A|*nbKn9x6D*udf(lE z4o1KLt%XH-IGI?mI>6swku@es^8TBym2-LdRL_^t%A5K3w*gkSH0;HEkZu0C{p?=9 z26l=(W3V|*h#LhkQs2a)5Ms<&agUM!;gK*ct#`^jIu`3u8;g7h} zQ~xr$`3$Sf=)~#x7N$da|JiFGabd*n44VTysu5N`cdPDGZ!e5>8SAFR42+|~fU^Zc znagEHrfgY*-*EAOP`aAYf3x={JFlZ%mR@EVZ~-<725i7XH5yo)Srk zq&Qpz`ei&%C9Kg&m6YX6xb}-xL;mh_oeF zEuyq7WnGRz3_)!12~2Sf1EOt^C5vZxV+*33v+vg*;jt^}eX;T(f|gr)?K6m-Ums%E zrKxbi02oUQ%CTI%Iowc^U5^;F***FO4KC;AQi{W2lRQ?>*J?um%_IhMD7lopJhF5| zBCtf732d=l0N02Y@IUNF?Hf#}-ScNTI#xPj{r@+1bloGC?S3TWap!#2KcS-X1^6b! zcxqNWwW-Bb%dW9pz9aB2)Eg3BNd&ium?~l6zGX~<23t|kWAAGX{>)C$$S}|1b}fsQ z;-b2a?w*JE85uZSiM;n+8Yhy5nd%Oj~Y&>bc7$d*6>Zc`? zV3&6ef}%l@R(g^)^M{$A1bfkStJk4X5WQ7c>s0*_xgn>e0y6Vw71jg-a^Q9`&B2Yi z)jJB{p|^d?iE0>LJyOG}BwmI^jJG7PN^8?4!fv%eH(8bk83oKJ;R~&8?6U7BE}M_; zN%u5HmMdC$e(5V4f)vb-od6m)8s1cA5{d;#`UQ^ed_Tst^mA}jL){7 z*HMFMe`+=SgCpPdhk&33T*IrpewpT7J|(Vjhx?k(<{AICi-LLaA@D-gtMc4;Ee>|~ z3enrO@}e?5CRLrYJ?Pc!@q-G>e*|5F*GJQX{U;NJ$E2@2)J%t-UZ{(N>Ok;!DfkX9 zbNL#15jv!p-_}>Ec*@c>A+gI#)Uno(;qqg>D&`#_m;O598T2mByxA^O7|-6dDR#vE zu9shFb)|A(d^Nd ziYq|mFjKSAC=>v;c*tGpt&)!*nkhE>Fh1kezS$%BW$|Rp^y#kEc6a77k=DM0^>6Ds zwgeMYO(O3)SMT45XJ<$PqKdHUmm%ZQ8aQLrhq?*+U{qV=aH-q&$9HGt7V_cyL>7nptTDDu9}cZPq>nK>XvydWl%m5Qw|;oQsgEvg%8I53v@5O%tTy-rO({*Do64X@ti za`PEV&()wai8=Q@zbC;sS#>WX8J{z7n~f9%KJ4*b-wdqF(#smHqRQNX^N!e|badEf zK*nLEeF^eBv|6}Yb0(@rp>wW>PDsw!2C0DZo`iuzqp<1<6jW4@ZU8PT$chqS=T@kP z=d*aNhVvsjIRe%jS>qAPMP9qi=ENh@4*mcr>XRhyZvM}lj}jkxf@p}XArQYv4uWwP3E%ybbB?)%rnv|+yfI>A6Y z{`BVpVE~_tAq1Dh*MkC(N9Ep`@cyQNu8<8^icWclvmtTeBC*^BA(NL(GNB}Jm*v9S zP4}d>Fu1?Jf!d2nhH`iMix*Iz%ApLVb~2DQYoA)m>UMh$JmvOKzY`Jh1tn0BkmnH* za_gF@1tH>Z_gd2_vl;@_)WcMg2J~@)|1oem_XwHWRh-Bi+q1>vA|WtPKHDS0e15o? zIU5YB3z1Ztm)dm)X$=;ESTBE|Ni0kcjGT8ja2Db1;p9@EGz{|XHubNtq=LVd&S(mF z-};)jqBaUVM3ZIuo=Iho(p#js>etpqb^V%R+}~T2cDo}AVzCnJ zeWMQbVepQ|&Of4Le|g5zBHPb+5w0a&ul5dDDVnvwzs(uiebK_e`y*zG9^CcUS67yX zr^re7R1Mqot9I8hr&~w9x;#J1++g_W;DCOAsZ`d$WXI=FvE)X(V8r^3ENe*Ipy{&c9*10%z2)vJ8z0Tv9j%K9oy{_fT3j(iRFKpnweI6 zObwWwV?;b&;42j~mN##~UA(}gCVP3OJ>>nX({?$xe4@9by4EHqY~L5SDJSpex6bjh zNe9?9Z*tflLg;o6P??dp7dG=|5&&e=PjpwFpZUleRZ;3P$59ATuWyb4w@6IakIXjS zAS4X2NcUNwpztTvl5F8a*1KG0gkoWd>k2r;nw#hiM_vyd;T1(eod*8%$^mhMVQj{Y zfPm=tPChRpxQz^ErW$Hb%H{J(2bzF4=kXaao?}QW*9D3w@Ji?s;`)77xbpRYI05l< z=-v05E^J_<{*JEnXMr{`hu!P(iCS+M&O?P&nFw^)4cx{FI2$qr)ChF?wqV8)wi`PVcX^VfTmyU%UFSWf7 zrY|2SELS!hreHL7HUg1h?iS;X$#2JMi4cG$^QqCFTcLcQreJ3D>n3J)l=wNnh8^bw z$dqxLa#w?%eoyLc+3&((=QA#m#o6idI2TPOn$R!LGE&i$A^@T#aw zA4oVty2fUh%}$AC#mz%HpXx)cSkLBm3_E(o1_sN;L3B=^(7Q`d1Corj2|##z*v3LL z1~&&4Jy7-IN&EEVKf-JazfE)?#Z1FF z4+)WUcVME2ypOW1rLQTSBWv2E@L&HS+b@7FRVD0Ji z9h9JZQUzFqGwkMSAhx&|t`ww%J{(jcgatEcyGlD5N;% z4lUd?HWUisgp27)=(ygDw_O(?KhBa!vcu+f0>Wz!gml{}UhFUG1J30W|FLYBJ?CmV z^00gKRd}j>+tRh0A)DR1HK zu9`pNBiZaXu)?R*`MsZ=$@lUI@&^_rJMVk!3dN}oz56IB@%k8!%|}MCC7d(9?on*^Ra+UM9Dqz!ylJq+Sfx?Zl3~t}O&@3vw*U(BhHf3+2vMLxKxC}oRYlMbt$e1DK=-3$=8O0>w1RqWCdCC-1le1R z={~vPRq-}B$v0wpFV*!?+X>E^)5$<004jmebj&Rk7<$?ns}1bcn3UL4kT^jwR!yIf z^=_z)xT$5@qXX|2WIg7EpN{C|l{Z-5g$bcq7{~DeQP5Z7a3M-s(dLTmxIQ$1GB}IO zm6NR0#xbxD^}>1v2uSwtuj14mtmplqU7HydoUqwB z=&gqyN(LdvZ5~(m{g3(o{X4Ax|IOdN{^sBQdtCi_`B!g&zx%)c>woia|K{?){vZGG zmm9U+Z|`aP%Z5(qU+5@4{Ib7qw!iG~D1tiVF4_=jG(`X5QAZh=fUjHjALFRMZR!7M zeJIv6%i3-kYEH&-tj*#c{zthvoheuMVhI5Oo%SZw&f*2niFkpc;tCggLcni`VbgLc zQ(l$w(0{NBJ`eBzzV3VB@+-jeKX3mt*Z6K^guma9ivTa0f9Cc7qNl4e46Ne&(*5^} zcNSl&BHZFoUyN(#`P+T{=l#cT_fJ3XQ>nsjzOTfu|Gs|lBu)6<3cvUH{Q39pKmOkR z0`i?7@Bgt8!i+$)_v7aG?Z38@8TyQO`O!)sdVB#FipgFwPGLpu>U+(P2ft6mTQof! z-*8hXf42AcVO%(LE?}?F*h;R5zQ5tuorG<4zwbZgxElJyUwz(RwRZq?QvKV0`_cG( zSYv;j^e5hG`FKb?;1>Iezt=x6*#H03?}4WQE(on9Y&>yq7No%#>|z#=yI0*GRs2z8L!ESL;E%g&z35eHQ-E^COwO%};J=?O+t{9;f4_bEum6ibw&D94u*SZ90RQ7VGxHDIEAk@zq{TwwL_!qR zLdzx5Sd$rc+k|5#7X{H~;mY8v>h<+vA8|+-AiU*g2Q+UUo1xbLwPmr|P5p5%#a`JEwb`s1*&Lx&E8DTMr=e33IEmK{cr#C-=f$4U;fYk<`*VDkee;D`(=|v)GzdwNPmfw z9r;VdprSO{!Q(w){_M5??6q-@{@H6|MEL)!*UnUY_iv-(Zyl#7a<(e`-fLsN!`deQ zqq_u)i=9l7{f_28dv}L()co6P+a4Tf0~uY3{(G-&5{5(HSx>6fGI>iv_R^PxJ{JGt z9vdUfUwUlyXV3j(Gyl+IFRFMsYq<@(*~?q_hrKpby}r%c{1TA1Mgn@ps&<`;8xD+T zC$w1gY-fhn*qJz$-^W#(kHigc*SW1(e8l~DO0^q~$D?OE$J=wZ#G`mt{QZINgMa+f zzAwNB@$T7f0fQ00ANccacvRM~9ek5#28KgEV$awj7hla;_>I@Id*-?3`_Okoemob6 zC?EgrMLh0&H-HzlMyzw|#}{3GY|{4|?cBoCQ0K)jK55>eOPn`q(m$Sca z(&f96cB$g$mmBrFp?F5Jzdz--pCCGDhDP+!PCqvY4Z(^V4X^mN+PA^Pjm~1LzgyI@ zcFwcE{@Baq+q&3HJ`?>PANgve@X9;+y%fl5+6E|7g%b#IllSKNym3$+`>A__+(Dmq z+TFJMM=|q}?({Gq9!l%(ldvz{i$v9CtMaLp_MYwK93r-*E{=u+1)pR@WeDH9iK|-_e{-%f$;Ii z<>_s_&K0_`akt4Ws0w|)hxk=P}@6K#4{Q0-$xAPFDHOD?3+j`E9!+aImp`fP? zrS&91RH&-qZ$yQrxM*0A$IQLjRcZK=);#2Y;aiiCX0uq5J%iNY!=_R3jnqS3_C0SQ!KAp} zaPH>0=i2*n@#Xf>_NbQVQE1Ar%h?J$_z~Sd%9}Bu8mNzZf3HDw@>Pk<(XJWHml@Mc zzGAnK$WQv+3im=VO3xT-$Q?@`ks#QLI`&^V!R>h-k$re?Z&acWx2eDRBgIqn`BWE7 z{GrL4*xdt%9X^K=P_jEC{ z`7gff|G)jui@(9YKQDi_z@IJfXAAt<0)Mu^zd{TA-T(gi&%SHu|Lec}1!>jY9aq0l zC_4LvrU~Mg1F^&1_4d)ufKuDwDJe5 z%6(i*_lh>A|I*ICeOva|-}VOKHN*5k-QeXP z93A+4&H0s(_LH&oqmh3c9)Dn<{iAygneFeJ>n{%tpB@0xCCv$c#bNlD0~;?0)W_wV z{LXlDxnCRUcc9nLJ*k=4aew#;I*c>L1{+oX<$&gJ5P-V|2e_L470m{a;{%maj`jUm z70@^_!ZSZM_>a)AzZ@+;p>9yR|8@@GZ2Y$IA4zc<6z%|RI_hYA4_p{I0RV^A`@ZFi zt1ExsnSa00aBzCTA9mUw4n}RnITd3A(L_HEj_>b+K260JnQ=)OJs@~r3f+Rg_}49x zejv{N_*RE)AHVk;XXz)X?st0KUmaZE*7y~8$64QBSmC#fxcU2O_dQhtmO!EF) z{QY;&1eKG%klwBNwDN8w4;yP$zs`fH%7Jdb)pavRLSgKR%Q0M22B{@CVLy7$&7NG9 z{5zjs&!*yJ^*O@-c}I@t9qa6f>h8RT)MdW9qsx1zi<)ShnY_b0uN%d1GLKX5Hhpd)`kHGf(!` z862OhcJe8pjw`xK?uupI$QN@x@c#4R_PMq`dq@*qxH-AgG3@)c*O(>iY0GQPP+g7H z9kiXP5Y{{9>yx;DFUk8BfwtDPy!(2-$%`4@cAynb{8PHW-aF!SUfx@P!kEWq-4!d= zc%2#=Vq@tP9Ct9DZQY}zv8Pql9JY+Ib@uiPysSs7>tWx=3qj_DlE^e;bngbLqxO_X ze)CML;sKAlS$_4bTlVWV3=ZnCq@UpLU8clIDhSu_H+~PU!M=J+rd1qZXA7Hi#k`dB zU26TNE(Dc+O1*g}SvxMDwQHYPUmC-czGv@Ln;)M0*sH_O$xs67z0OZ(s=lwf<=!id z!K~W*jv3bXeq{&mAv_5Jr)r^ZYS$RBdw5Sw@@xIBQS_i37Gk++D_~@68J<yVx1L=&pGU zF(^Lj@|l5*i&gh)S{}-&9q5RLCA!3-A?MMa0+`st-eXSFO1pCk$uALYy6>&KUV191Y_kb3y+x~{xQOP{WELRJUM$~}XWj_J9Kqjf>A zjaetG8?4=?y18!L(=*xZ1oNDTu|Vq79Ccu?0`^C4)`!;@OB zS4P?5lhRXe+C3EUhFV(l97oz~B=Td}Y%74U?<`o2k8yUhiF~xCkr(&74$&)I^i@Lt zpt$9buJaHmgN<_7!+Y9*?)VtI#X|^`z*SR@1|^I$w)341w~y1smjLeB()EsRp6 zzj;&jys0bNsf{jw8?`GPxNB-V^OdtyThpfzmO3hNb2eLx)%s)bgflJ896+=pLV$43 z;Qs*~v{KzoS%EWkbeNP?piAAE+w3u`Dg?fkENw{k*f6U8`hdozXo7sMQ`CGsW=+$M z&uU0-4|wc(7kZv57c|7eyS!9^cc{#%nEft)9ddU91R*~d-YO%kD|x)mtNgNA$>)49 zt|^1MJUia5*#51-*0T1W@QKOjW;9^lkwlFq+wPm)$+jQ44uyVQg6;lsd^@*ngF-m2 zkl;+auaN1o7Ge)#$c?&)enQSluM-Cc<$Cnax#pM45QyZn6Ev1gQPkHLviW(?M{Nu& zkfWgTiG$JGq<0m760)vX)BzJ+k+AIZT;H{5qS}5GXDT1vvjl9-P^N6~P?zH&EIP)g z(8X%Kv7^-YjZvAWG774xLWy-c#g@^Hce2Rrbho44uRCcFv7)Nfa?Q`56RL&J?qVhT z7&uAbB$6PgNj4&ER*WQ*Y(iJdzA$^bG(>aUY z`DqQP@<{4cLumnc(9=>Kgo)$K4Pmqn6C?BUx^pXHQ_s$UL#ud@tKPPX%~1zi0m`sfr@M9rB+pFtyKxwMSo;y5 zRuH!Ot!nGdPUiInT(u2%A&NqPCjWJ|(|^$YJ*JZR^R|e08tq$2pMl_$-l;HmM0q z+AtzjYFOpO1!%6s-Fv^bVV1%#M>4S2+Cu7w2oX|YiG!!c)&#QGZ0tudq>*sCt(kMcK zU)xFPEfv0U(q)0}8FkOi#`(BMmD3{blTztG2plM>^Vfv{zWn;5${&^C^G#SK+Zmp; z)~+nsnA)5NW33yb;Sb$a_v>&=+@^W#V+m>0)o$7$;YxTs^1VhS+tVnUd*`;9R_T!MoswEtu;= zgab$+b?EJSl$61lt>VX*K_2w{y)iRyr^zP*)h=%pjvH<=7kT)RpC7)4H>8cz@F`iW zkk~!9%^SX!56WUG+rG#T+p4mxQ8YZR%Udl3#<(l?%L^nnvemeq{ABWwxWo=mG-V4v z90~q)CzslbE3$P^*t3e+XX-C!03**HN;t$-5`uTrzxq}mJ{h}J%Y%x#uu}+K`M$KI z4?sRsAY;C19A`qfY*0{h{Q!le>Vv=;hyH0K& zj6)I0NJW1fDeXG!im2fyCe#T!@hmWdLPb#gr?OqWo8LW8VFXEAw+ZqgyRtSUkX z%!klpoi%P2p*&10)ILo&O()LD=|#F$@;T0(64uUe^ZV%5L>3Fcu%WZ*dVYOtWud2s z53h2jx;&)fnctu=_-33&%rEED=i;1g>)^|#GDQ-(MM)%6wpaBH6T8>|Q-^KmhXkXG z5so2~*JT?4fl=#NZh${7G#|dtKDnq z_a-cwjbuOj_-@g%Dxn*qb8K49&P$bxxVbK{_IP6`UXKHOQTAs#U#rA%K6t$13E-4m z$?+4%^%^yur~u{A0A!<&u)G!G_uD zn3qi63JAQ5%-o2pBE4-m?4G9Ju@m71&kUkZWjCdoaR}@zjW|y6YjbF~AC_J%6DU_G zp)(Q+LKeE)Bv{K}(W)Fx#)4g+oYf^vd$bp4+17V|e;4Vt#HbzmKrvj4(pZ5NKBzWz zAN>2w#Y2J<-?HKLeVD)n?w%+~s2Wt!6GjZR){=i^S1yQvKd!LiV@ zDGGckX0<40FO4&GfvdGON}6v$XsUw9F$@a#i9S1+eDo;G06z9>rNAjsQur$L~KZbO^=k^Ta zdYhc;jH?Q559UxLFy;P5 z+>wKFsh3r__)HjgoBf@Jzm$|8Okx<9$mU+nz!elvfWvC`0w=&;Ct}8G4db%eqKu(W zrI!ZeQ;eXJwcq!ZyAN|oM!7HCey{j% zX9Kn!(KQ?}uG)HgUTbk0Et#}kA@)?8Yq8k#@L2JKs)ns{q=YEKMgi*!Lqr))#`AiR zYRWY(@K9HH+S(AdhHrqP3RTP5%evUF{I+p%M52F0#0du^Vo~4l6Q1Ev0q75>mnZ=8 zP_I_=im|;RiFx6`pblDh+X|i2nSa!em+GGV%d4?-F|lUY?oS^&brpSz&PSO!kzTtJ z7nr85#a=F@=eai#bYBg_N*S?YHkxoNJmgl)jwpqX%#`5P&%`*nOoU;wz8~JS*F^3y%4erfc8ar@HzV5*-nI}hz07ug(bPm`J4xDXr^qO5 z>=6k}^gH=wFN8S}xY{>d{2-AlgjjAdQCMW3$=RGBgvL08;x9X9H)$Bzp> z$JgGxk=Fu6&_KG_btpo!{3W zl^pf+<@Rab7houwy)&)!_94}a5I47LPz-`(`NZ|{fW?k-Yvsbb^~rG~)-vrb{N=C$ z{^$ma<~iwi@#&nAt*8bgT*)vm-E2yNg%-6jp8_jb$9;StUWe*)fE(P@n-M4I`+HDo zhlyP=Vao)|BDGs$-lY?U!?AA3a}mCD!gHw4bD@Odm69~KQefH|P0zH1t9rC^cg_ef z`z{IiO{0FYc`)E5d$@C<>A452#kZJEM~rC&7sR++U()w@o;p=H{Zf0oxJT-hU+@OI4d#PU^ETB{bu*9A{k zZPb>N+_d`9b`~cSN2|*LqzN{_CcXWISh2A76Q`=y5~XC>#|KJ%Ief1CO82&)vPT>m208h_4qzue0uJ*7)o5d zd~AzUtMcgjJI~&Ct zuek!K=zO??H&IyRbRR?3k&@`Z^;~WnV^Khp*#w(A5yR@lI^7T>WO61)LShxS%zA_D zKngE>1`bfioMZB6^< zP~!4Tjtr07xdVmLpUvJ*Le|gXu2l8ot*OdtXJJyX4K~MxlDJ&#yG(n&kwkE5QeSZp z+xq9};IEeD+dso=>fX!s<_-i}&jHG-DP?sfcCKa9!HC0lYr`D6h7h6I^n-Mg4~R}r zY8u|pE2%ox;7mNhU^OSV%^&pA(sXmBx3^1GU@ay+d6LRvWANy;ax%DC-Ef}=Q=Ow} z%T(LX*}F*Rrzn0xK~B2Nr+H)8_wJbN zs8L(Nqj>J2vX(b$!)6Co_|`BQDmb4>|J^m72TXGQVugMTCyiZ-`OWNZuJ2J% z#?4o!OJYi@blKa)&%xTy>IbvCpc|d;-3kZ;Y<34Yj5oY~S-8=ePWFQu{OLsly4bb! zu9YNNr73xm6RMZ9o1bm?#T(D$e&roF_4ShCFrmK_d+KLA&C1)s0S$vY+yNV?HJn|U zyR|-Xzl;Q@5+l<&FIbCTMIX4)ut0~ASr$9@H^r;WFezaneA{>6>hQEWvTPb3qzT~H zs(_;cSD%SW66Wf>Y{Y9s@)iu(&-zZCM<9QQG~Vt~CK(qU#;xskCROw0oQ}ZF02y-g zsUtx?mdd9)kIp6=bMZ^!sL7TW#+-p8=@~fnF$zT9RH`bM40RG$#nh*yEv6Hzgahkz z_wrp);9ic(<7pteGMk84yk2{RmtO6yo_YCer|X>8&x~jWU^9ht$8`6LtY6afyqxVb zzwyg1DD!&+yxod*%rL0UlEL0?_of|Sv8)>+vSAu_Oj88 zXTNJ&+5uY#hYaXG=hqe%O+a3I%kn&95lsNy%DbDslMw?6%ww=B7GE1)9q0kdBjwl8 z>v|$T)hgPP5zvJojX$lxy_Dze;vaRDH0I>FgAHj!ugj1LCU-1Rh@Q1=wKx4}XS+(| zqvSK-KYXi4^Gxz4U#1O!vrG&;Ub)!^6vnK_UmB zV<~p`Qq@A5+1^pl3>z)=Th?~RP)G)TPD!xaGLFF zTnKv~)(_?3;XD!DP_~nzt{+}ED$lVq{W-dY-P4Ov7vs<)(dE4mUrEC?x-M~BO~3Q{ zqnTF5=7BX#8CJ0G#QOh#h=aY;rO`b&-2mC0;VBJ@`ScZM&$HxugSO?9`)AOk~D z^uT{A@4KLKoHPTgmSv@qs6iWlBkz3VMqF#+FgK`FE?@2V8YBNAB)z)gKh7JWDwXWz zk8{=C0s|u0z5c|8PxmO1vtT;J7PT|TcZrdIXjN(y?_qI~$m^5zS+M2-e}moSgnl#%jrPxu$bo{* zY`o-(veRi)_eo<_o2#!qJi{{esBOSeiJi0cggPX1Ei^iBWL@#0sZ-HskVxF~spN^%%~Ucj-m+B_T^1D2tvS1NyU7t(MN^XihWAY(cft&~CG%`7a)+}e|fwXLO*rpf1P z`-Hb}qaRxsIb!(`3M!SLP?j5LsT)pgN1oSHn5#6QphUMpIIB<@|Ll zZ}WKEd(CV8!X$6&BT29g3l%f>_t7AaPb`+S6Ub{lC?mKEuv&Xv|z%+IuB?NJ-e1^4RTB5pE=B00lD=l=Es1|iBD%o7pX z6lmex4lxT#qK|*uqU`ytel!LF2AqTn#x59b40V)dL0x=6cqYr47>C5%CfX@}F2U_w_vdbV=U;_O6I##ge2PtBZ;tzK~uZNoOH{%9ix7 zVwI@$=x(4;n)D775ZQ^Z>?^JoT__uRLdZ*xY_7gCJo(Kf4pK+I?dj*W15bmk z5FT}`dR`hBH$9Hm+NoBm5VU0c_afBSNOOI7~8BAY;{9{fn{}*hpLrfRGPqvp3HB2 zEb=s=9%lcJT-U{&VeuL2(b;k>wDk)s5E4oAoprw)S&IZkk3fr$w+bZNa$hS7-)wu{ zJ}(d6bg)>1Iby=EuEUT-{)eB5Vc*ruv@GL;==-EgAfZ_RK6wP<*VZ|@kys*?*Mi%~ z*IsbqU10kslYQq!z7y6qlWooOWgS&7vG&%HH0;C_7I0f%dlTCl3>a9hH3<5jFKNit z_fstdh3dp($$z@)6NC@z+(F>cMt+3=&$5V1=*H!#OxD4r{LW63*SrVytUeswiKwgz z=2Q!;!hy4uTqbOqZiM2}^_h(2vBldIiD9GJx-VEwR)%n^9yew%wWpZY8<0B}Y8+#v zM7^fJlvX@5Ir1PwtZh~5q{gfE+}d}DIPWpjrS`4EdZt_#I+p*EQN_R{Cry;Cs9}2V`o7Ti%G8=Ln`{ zzhT$Mg^r3@2Av|?Oew$La+_qlRB;ExujnkPeR*D1_W50&Qk9Jp5{tyf)LuSOYZSI? zdvS`v+~@KO!g1+fKpDefP~AmIvRa*o_9K{aH=ofns`{|Gn%BaNQL8)L0P3o)(PLeE zVU7`fn_$)&-Ni(G3SH?E-2F^#(ZMO`8x7L)6mP>lAsFx$q;r#%i-f8s#t@R#+nYZW z?^mbrD7dY3p_X;k_q*t3H(wND0T|q&|M{5bWT?`$x zj98WRNxQcYSUrE2u7g$dcSgN^r*O|lY|b0I^`+jAXzOr>xO0qGMC=Y-BF!gBP4os- zi1ziQD#4#d!5`U?b>m2U;%HvcQ72&p|1Rm87d5@oS*Ot{Btkj(hKee-Ut zCJD?gr`3nodM!nHJb4cN4?Cn0v7p#DJ%IN*jx?}JuRaYeK@qpI%ksP62!FwkGOpY` zIq#%a5&M&&B4_#uMvUMQj9{&JpvG?^3R}v7s5qUJle-1X9`0vXDt$()0T!Co%pBLl zTi$l0Ao*dmdBS|S6TD)N!f9Dg`-(&UdW=W%@MLce;YCn9-i?-KRuASpMq)`&AicWc zg^;Muxxc>&2uoeR)H~JPYpGsA3~~gg=jv#tt|M868D$n7ag9=EWWuJOf!*8Y{Ikn+ zpdP)Z4qb@g4sd-3<<%QqyBOu(rjMhO{FoM3Di0>;5d%~;0~w~2Q)@%Bm#NHqa`rRJ z+iM|R9J4Bp$XVypsn>ynPnO;4voMcwT3+qmH%Eae3B&74I3|N9A%{-@uEyQmTTVoh z6;tq|&SWweSqR2I?6u1BGQiN2yv~zbw7tpt5qs@o##fr$a-E#9w@IIj>QvB6ir~mq z!lFIfDbV_T2s792$328QfEHGV1G>5Sx(GmytRFh5`fs^-ok;2q1JMFnk0`Hfz4XNH z?7q-PbWa`O7RNr=(FTZlOQMceCP6$16aFG-wB7N+mYs4So+pF3ohF{%k9P+yzCE!^ zwa3wbQ|?M;&&OTVrqnoJZ+k3%?VG-*p#x}lnDF6LBMYj?qT5bB2E+coo-}Z@#_<-t z=1L5W7h_N#h+}q{5iH|p86kkUQvJIQlofL2pX&MUC!kQH>DXl#>pD5iD`5GluczZ!Ymx$0bw)`NI)nz~Qf!O}OYA|vHPMNk-rLihUe z>M4duXGqS6Sch}bmN~XN_!)!5ny#_5dLb0}AT|MKBKK<&F%^MZc1Ia^gnV8+Z~PQi z%Y45MeAwBb@^Bv;a8S(rQs;-TC2NW9!5W)qx|D7^t;)Z4L^YEW8*9DP{W&0)O zUiQm0fdlxN3i33GtNF0^_NPFPn!IfsJnt(`kzTCLkahVMBxPxontYO0(Z#3nbshNbgLpyp0ed$tnXld#*Nc)T$V$V5k zeIRrwrhQ~Mq59Tzo~e5*UmZM8Rr7Z%YH)bvX^K$)uuT$2z8Ag9_O-_*rW z)CA54UK=|1da1}yeft+Nu*=8s_Dvj}`NI!QO|M^Vm%C(5?q2L~niE-~SAJCpJ^y(bRV_rrLz z_k@q!eHqO|H(Gg`+Q4iKqVCo)Mfv0Y0d5iW$1)Ttl1qpZNa>f$hY~h*YdkZEV?d zog972y0z!w<(KnGVA>?@&Lc!v%>K=;9|(`Rh1|zkqb!)n@9W)jOAecD6%TnFb^(h% zWd87$uzq`pRp`zhf~~%SGOlL|^69lqh-zR2qwgshz^ZTxBo5I?kz#t+d9%xI3n?>z zds(4ePCTh!iKk?)T=S5D8A`FoN!cQk8lCcUKHlX$N(~=o*;khAkcikFqszWV3}E#j zPn(K<@y_`QQ#s_hBbVMt@YY|y%dw}r)IcP*216GZxyH1@3Xvh%yyt!jYao-v1_TiOy7X03BD@&6VZF-5&5*p z<^B#&^wLvHFWJoQyDClmF*35ua5j`E1>j{n+t=npXGR@a2sKb2c$5g$64+9t$dT-Q z0@smtAg&v}wVSv6c7I>~pZ4CS=T)^$(|fz~&fh_#j(X5aDN;t(miaJXmlTyS7;L~` zzDg$&IpCTwen|)lKl9>$DU`%&8{aAe+qV`h73st}G zN>ie(P57Sq%Q&Pqu^$w``gTz^W8?H*5sF=|6(q7gCe995DcNUN{i8-{H?p39jeWmq z-^6N%P#Ztug6V~ha`Ok!DZNRf-oJ@c0D(?bt?vGMicNX~(knGh4Rh0LJ$uhbNLc(t z;2GF%25}xBQa+J{ z=79mFQRn-;85QX7-_jsD{z$3e8*_IxwW|$6;?LpUna!ZH++M%Q*!<47=&-Ep>4eZw zuxa=9Wbm}6sYdRP8`X8i``n9+DLN1fd0IKp9cl&AN89s6ZnWW<@v@Q0?^)tBHC>z=AIhSbYzK+U5`@UIRDVIN7$T5AHgj2&=?lvdAx zO~@-J)l4k%LObsAyC%ZF!aHRiD~XTG_6N?ecwk#a^E8b2lQttld4k z=y6cwoxvN+utJ+E!xZxtcW_t@sBdti%bzm6OI$bLSb*ezY{J(5yx8w0dY<;jeg`we zJ1xiOmt>~7yaxp$U%No@&6%m6R!+U7gB8C6pJX|WsM0;;bOxI%1r#-2+d%E#Kt&}W zlJwP<@1Md5RTKOBY0Q(ZpyUMDIbllGEo`dpMf1()_nckJ@0OHe34^sgZ{>&d0bFH( z=HvRZ8$&Jc^@zr{=ud4h?=dOq(UKB#UBs!JtC-z^YfPJ48?x;a@KB#-JADSO0y8LIArwYKODv>9v`Q#z&^aGjQy@@hfLlqU z=D2rBQ(U8^aAjomZl01Mo1Wu-1{C?(QB&yu*e7*Qe?iZB&eMuyhq8TNBjyvqYx!J` za^YkAe`(wDDc^_7a)hewCSJQv`d*jI5C`7x*O;xu3$(19jl#SY#Kr`QlN~Wy^z4`` zU)M+D5#G@i13_L6c)@mAx=gzcAgwCHJ46{`2q^kViiJeNSO=K)`@Y(>49SQWB6`x( z_|{o>{HT7v(RU3_s+$@QNS9B}CDQuD&0mRO`E{k~8$c*7eqQyd;EsGF~4o%Iw zoGuHOncip|*efw`12OKlP$Ln|`RVcRpft+`4_Kx+E>D*2*u(<-s)S*%7rZPH%bwyC z0dW20#t^8J0j!nC$N6wOI`*MDD~_edAdb*uKC-^boMppEyhW&WgW=G?nbS-k9rkQO zIpaJhYoG3L9^v1$8sTwV!gnkaB1joeG&H_X@swRcYUq?4en|*UO#YS(e*J3wYF~CN z`)UD7E5@*yDrtQjldkGv-6A|k;5v#&Qa!fc@Io&uW?$anFgLRk7JPe_y5~Km^X@aD zG3>CqJiP{hG>AKb0f#bMO3{Lj3M~d8p_`~lR{vI{}W-s*Jz%7PbG3Zo!J5ks4*aaDkCKtcqKdKr) zJ6$M0ad2vZ3A5cA4?Md+vf>XkLMCLzMH-k9$JbO*&J?(~{hELPKZq-#u*6Znv3ZKmTG+^HOKTNvP+L)O@!uNSdJwbw;`QZq6+w z*Oo&|>hy{mLKJ0bHby5>pF#L$WbtZaFQDuEd4+gOw6z?^IKtL0J5gpD5h9a=1mAhS zd)#H)BJSuBrm@FrDXv5;ER_4oY;qk!U8&xu!5|mh|3|iq2~QSMbULy1a#~pDqPgJ( zy0|&=*wF5^gTh)9{0ig6a^QSIhuyJnZ$CzBZ_ziU$E*jai6JWSn0N!}dUTUg>L3ES z7QU`YZIN}3rsxQW`V>cp>X|sUD~m)gg^(Qf+y~~PfWHJ~{C>F0o{MF&nlPNKWrV}iffCMe6M zUBK7%^PDS1R{RLIP2mOWTcD!OCZt@=Lf5x7pcQHAqm-Kl{yf2H7y2M)x50}!^q(}u zR36Bur8X6x>5m|LzU-DZJe6Rk(_Yd-SWLtx_J$>} zg3qhYb1&`Q$#Z^5!M!&Y6!dU>$JzWH6d2wl2uVXWBnUm&UiW-H^g7S@3*N`lm|b&2 z=kiYKWb#zmTOEkogp{A(tBIkGe1ZqP*OAJ93xhLSneqhZRD3(@_Gus=u{&K+A1Z*L z=0|ZbkIiu$9)%8J&>nyz&bNQ{1YFDp-Sm7hS4a3`v^_sj&^E{U0jy@7b4vB5Hev&f*rJFIOY%a}@P#7KNOXvGCD@2waHMsPq$;oHwRT1n(5~2I?41^&)h@)i27$S zQ{&^hdBI$lBadOL$?@A~o3tk|scvabjV@LnFk^D1zEP(lGmjW`*Ma6-pYi?>?y9%hhWfN!%gb}cNw@18@uNd>OtKd3^RcPBs zT3TdAGsUHH$fHsfXYJN;&ySJ(h~!(ugA9x5t4DSHoZa8Ud!bXd9`dqjwq7x?CW2Z*K}Be`C`icoHd@>tG-)nMCeVK!-06JOFa=kZdiu z>?MfcD98Q@v3Rbs;hA%H3f$LKC6Cn=ui+H7JC}1uflvdrJ32Ee0vtc0wN&Q*MP%dd z^*V1ow~jlhv5$D>Htl|U#*Du5;mj0V!Z!^(W?j9bi)AsgJcTu@z2Jqip0#WT=XHvz zJRzjd5lUVgi6^q%iY~!L!=SQZ-k$aEP%7MV_SPi{7x@0$+wktMCH>aqISRqidB1d> zT(@FnX>Q`xpUxNHOMhoPOO+a$VnmW3>jTz(v;*dTrk!+31zVy(wD^6?mZ%V3Q1gjs zSq1T4i>s~OxpHg?oxp6nsjOjtHV!1rldoO(>>o>ay6i(vRTEIflXuAEgptN(waAA_ zYsLmsvCnI!q(h|LUuT_;eUi{ecL^xJek)fbBtuZ4Dv$t04#e>A(IL(nMpTD~?rxzf zNxpw0X??O=A(qSMHbBxwx$$@9C-162&LPHyakMtMW3>PVuVJtW&sW0)=$VU&G!~-v zICTtJ4(eEkH9xJs;UX>M^yVzz7f$f{a4%_<+^rWrs1-!k+t=4#?FT1M1QtMnsjjjn zg=1gqQNDUA(>6gzVcv?wm7iW7MvcTvyR1-04fbsl2)Dy!dkkCn25Dv!PHcDIZ)Y#+ zuOCHG4au3{GE%&;dH_pcXm={cc!!dWFfC=92 z$>NN(v|&$4SsW{kS=!<~5gAz~*d}rPvYrOP;L3e4X0I4-bMbpha`f}-J-1$!qpDeJ zv0q-qjY@}u%alcST+7qmZu}W|;{co#g;gO1Z-oW^PPmS9C>FVa?U)JDf%hn{OL=6Y zY98gbYQykt&=qjxCwgdb$^mbX$xoYf;)kOJmV^ddEH?9JdSVFpZLrik(fwpZP7Mir zuDadfn^V#*wZ@qmJ{Wi3gSR)!rv65=+4<(kNifoM>cV)40eI>Gi6?dC2ED_m8&6Ee zYAyf?GNy$bLq@lp3(5 zXYI@mpQyEACJSqvEw7|;Hiiic)@*oh({gjLJuCfL`W))TTk57^FyBpdd$J50#nx8S zzQLcT#g70tLtf|7>C-Bf8^gqfV|6(kFXfKWe6}`8T>{0BwwAm)v@f zB%Aq1@{tk`8d>$^C?BOgHhRG zad!{d%$7|*ybwdmoILMd93cM{DqQM=`k627E7=fX#O$A%fm9A{-R}pYiq*(7%4I)h zhfY3E=PMkF`knE;b1B0EO5JAi)xiBzj9#X?#C<04*1~}(R*2)G*Dl@@b@ zOT4s=hY_JwwHPaD(SH-AVd6C3)Gh9;=LV?2&l!R_z5F!Z#zL%tx*2A$oheUSZ`<4T zn&xmJ!yVilr>Rr-Gyzz3c(e7m96`bMEt5=Al`@eK&_(V$q#x-g;x1M~CjwJF4afuu z49?j|b;mErh=;~2;(|1?bI={Rl0R^i@qHO#4Pgh6Hz*smrXPz%Fl0QhX&^O2+-R(l z#L0tlXVaN~s+7&HHSaJQqf~blOI5MC+Iu`Wm@r(f#>p!$TR+{e_3py2u1LM3JLEC% z{xKfd+8iWbfFKjPnZx77m%IN|+D|V@a0TlOsUHMH!h~u>n7qqp59twA5 z-_c%pB8=n?wJ1K_;k*IlvU_H#zJElsJG3cxUp45M=73N4V4GuYk4%$>g-0cz}qWcfNnk%Y&?qGW^Znaj*4dAK)Nu>k(nv zS$SQ#vuZJEdeqg0(zv+*#Xg}f?URJB0d`tg zd5a@TNtG|RU2@!dx4q)6UWXGgfzPkV+f)9?hNj<8QM9Pwu%C75wEB8smFJw*nnn%ymOcv^?g^t|P%^v2oZyA`=RqV%~3 zPi<^w{Ct|IyYIP04p-_Te)kRc`2+|my(h=Hr z#JvP^mk6{m4#7+~pSsHi*3bav9W zCZc5=;QEO7MSE}T!ArENy;G3zlXrz?$M|S4rM%&JHuga&!u$XQ7kTW|nZM)w|A*7b zT6oO*h&@tEnD?9EHO-%PqZ}L{khA`7F!_X>K5$LqSr?K82Bf-N3Nz@TP8o|HY|A^L zwm9e}-BP_|?lGMm?W(yyW2Ifc_u16!5x2F%6nQG_pJ2Wtz=ZJ8Z-nkD0?cloQvJBk zdsqmM!qaTV5A{x_TYaE+?Eu5ecBbHNB=6x=KZDq)0&zDAZR*Uq&za}L+h;DxtfK|` z^PYjiMgMGS^Bv&6If%t!%{N0tu-0nqyGQ0e(Rgykm#0N>xa;EW?!GWDTmXUX=S{>z ze>4yreT9sd^e#&3zN~2qL7E`-5sJo*YIQqWdX?wn*B6tM)`jr(E{B7pojAg|W#0>% zSm}nE${6hhJ)xh(t=TB+!1v_x9rn*2T+RzyJdAN42Q$|pp)5NeFSK5QlxtiIFso1d z5&cF&G}7G;`5TJ35l~9zVd27Lg$WRritOT!-JXjMXyyARId5c0V61l~lltXx86X(E zdn(zv1bdIAfHgT{Up}q_w$d!t#ua@@Wn-^1>FLpsDnoIt5rP0Io}tVe#<$0q-}f~< zEyb$k$d_PHn$@&IAxNYP1>~B9nSZOsvvSpMRobG2wf7Th(oJN;*2ily1iRQ*-lt9I*DIqucpCRV!gHY520UD4kqtzAA7MKt_p$%J zdf6}cd&#;XO^mxHc!!%Mf&#oDZlPMMkMIIU@1}3<`T<$Umyz?E41x23(EvlqJUFZJ z2iU<9P~CV14%dJWn0yqZ!CLM`u-(njUA*@oJ5vrNrW#L6WU{qMfE67LIRq;bB4oP3 z^nR}*Z~)1S9g=$MIb?b?MIKP6h#0rMYxAsiw--~A&$GN&tAjV?XYSrlUvDnzqK-2; zeC2GP2$M{WZg*x27#U(NKh)CFLYK)vf%kpthDEut%Ii5p1=$YWT*8;7@Eo`fsBKwz zPE({7dJOD6>qsZanF@>XwtGB}qKu)fn$`dW0dx%zF#A>gxq;LkqjcVO@(*sy7g>pB zj#?ZMrB$c^esi(pC$yy!C8G8KW0@3K%EN$^a6XAvEGy*ys~}CU271qQ84K;pBJtpTGEl?q$&!KkpHz01pQ6#jO1s5iC7IP)bTKeY z8uMrP6;+b*kk{!DUuJ_KtalKx$uxP2;luSVys*%5aKacXV>K>6CFJA86o$K5m;*c` zuW5?uPJ7l(ZEoMZk0wvg?rh(6?BR+8RJy;p=2uzQBXdOCm5|mJ8InDA+zu%YIE#2v zRLS1lG9OQqQx{>0=5+Ltp(Yp?+pYMG8ZI!1&PU@=X7uX6A(k8TC+9ah2=}{7^(Fd4 z5y02Wk<{+7wCv~Sqq@+h3bT^8y#!qz(W0#-!0{9zcLY7Qv3c4y8aa+=TUZ&iETW%f z>Du;ZU9hj>Kzl3puUtgA7^T_ABl03X%JOxJ7q9%VRP=^h`MQA-m(7Cvti$*uj+U?8 z9z)Q3XAqGo#}9|w1D~W{;0@YkEX>0cksj7>2`N=XQsM2|b{}ayh$?NAgH(=>Fxdax zs5W;B&E(b|@zwKpUooMsA%{%bV?}4CNDrvi^xK8naJIy3A*W`!um9Y*DXSKmTYJpw zS$>g}OzCU3&X}j3>hYPz;Ik9tm*+MsyU?oQ<7ggE;cL?}<#g=kJNGhv+Rp$Tofiq` zd}zw`rE%DzYTR>-_LIfzX>_X(IOwXWSvmr9bd?}|>MlBV8pYqrLZ3GFcaN6@F3PnW zHeB==5s=i78}ps0cmkzm@Ahg86JWTcr}d5b@ z+s$L&o-U7P`*rLIl`eOmg~mbe!3j^d?wCCj(HKO;+-0e`=_SO-8X0qAAX?qgJF4LX zJT(%riIDYsAKxh+`@9wq^pguUVxO>AIq|2v;Md>JD>Ozb$InSoG#grpSK$b>Bs$By zi_W)O`+7np_Tb15q3JalI>X}zOL4UC&nR^Bd+L9uXL?pDM3_*GcPV^_caICeg%d z6Uo@OfkOc+?!F$Kiggml_SE)qFA0_t91hNl78VDO2e@f-q3FD7Lj1CfFr`{?H*JnE z6H?}M+fANu;CIp%8(%Ad&i*J%C(RIxy+)fCWOOH0u!EoN70+FRU$GCLK%6U%&FgY^ zdFbq(r{Y$>Ko*ToC;Mf7a0<*n$r8Bkz2NT6@G={t96up~qkQ;;7fg%Ztl1IgQ({Qg zX~%o%>hrtev{6$`k)U!wblD_+cL%iR(y@^|!x1LQLyw(NG_~$7FvLi~;>rPWAkCNi zx@TPKu6*8>vVjR`I=-5tqANV1C~b}od~4!xtC9I+X2&D_*&>yTWVV7f@_y?J5Frve zjzefdcpjY^oH_aX$YTb5<0y?!<4BqC3 zEYyO=2GE8Z;p&tapw0G1^k3&)kpaQZC@f;V<9j;{+B}t4tB;iLMEU$S>wjc}+SyA@ zl81gSQkjG79FB-v(1r54gR4lj)0`tiLXdG3y$)_dLtEWWm(~Jb&+UVozAw{T z;*Lp{?#<|^r^P)vlJ~brwEZ)nQLo4LZYv`PLz!S=cH7}AYH-Z4cPsEMN3*Hw)9gB~>e4$?g?T{V+v#5H?^|AI z2;-PsolF|z>#lCv<8aw|;^U%yU^;YTlkdDD`<{j1rw$>wi!1a1?_n)GtAX}oM%D5= z*AS15B^P(-q|~DMVM!ts%NEo?&@Rr)>@N4a`#Z1^xy_%`<$`tr4gk2HB5YR3khz4; zOszHluI_eIG&kjTF`gBI96pV;>Z}r)QdrsRxv2}7(lIUa4mCDMLY>LG=ms*ysP3Rw zmK$D=9^$`SUbGpZCKQBw0U3##`UmcaY`&kk?;l>I`@;@I0A+Mx_NtBC1;IWc@2e=F zt;0heMLhQW3xZpC&%*aKRzb&|-=T~zL(Eb8C&<$Q3SEAG;*tE?*T?1L6Lt+vcL2H{;2!`|Ni>t*9!bvfnO`|Ph5fj@_+poe+1v{ zzxwyWZ}fvE5;~)QW0C{-Zc&{6cHs8$Z`6Z%FcHns2kIB!jsL|+2eIoHBmMtxM*2U_ zcRT;k(*AKqI(TY7e7EHC!!ox4Tl+I3{dxl54Zt181(3obzW^`_Jd#e`luunKdVXbyey`5}XjZr_C4UeB2%yUgWPoyf}+rPW){a z171a#8qPmk^H|u(jBru*{)8D1uB)`Y%;vguMeeNt$P{@()Qq|lR#_(@LPp#E4q?NO zIN1UnfcQ}>|D=1uq5tC!e@O^IM<4me$q9v(Xx@Vp0>((S-?u%c6dPfX8}#eEOF2D& zrY@JS5wq_{J)s5pQ{1Kq(Ux9@f%uv<*SeJ&cAG`GJuglP1NRisCIBLF75fj!h84Ow zKw60e#)H;eB1jBFnSZ4y@g2(qX$-X@@e|ViLp?`UDX7m(rNcep_a*@*{OR{kjg)5b zxOn-iYvgNLt83wtk?ua&Y0=~mTuf?v9ti+=T#AY^hm^oV;z6C_gZV2T0 zaxSxdQM-NG!zq{IJcFd$nIMx*qYS}#L@FzmqSpr((y5aU0UduYX8r0j3n`0}QPa2h=_q;*-=P?nHBL>hlgiV|y)A_LgXYMK02 zLr`yV=^q&s#REG>^*ceVxymeXa1mV*t6%f>`&&Yo(FRsq7Bgb<}gN`+P(r;9=3YXB9(puB4WIR6Quo;V)9It zAE#&&(=~Ho+>K)G7}q(Cifyk~!mxG3@c*Pt!#=vl(C_-KYWVfK9Owur`|&{6NR`|T zK14G}I!spHADM45#wM(v)Pen8gWZCl&OsM*PVmv97vqc3VQhC%u1peEhwq(`zSQt{ zKix;q$Q>+RiP7jJgKUcHj`or9*LI@pN8EAxiY3Qsh^gSO+5Gt+^JN;mLE7wzlfR!q z6{{XQ-9o$<$&^3yg_JzGfvQQhfwWtvKu-MbyiYeRogpfYjFtDbi8TG(g`48GB-%p) zU>+I)+h`t7_W~ssWcP!?(rN!l(=f!P7%%+!hyEmvm#FS{@48bzO~6*z+-~{-zUV1l zWenyxn=r0>d%d;jrxhg=c2S00i+JS;B&A+IqxON-#SK*NQafS7nz);bkUt1eP4gV=U2p1rVBrHUA9esB;x&jS1)L0 z)bAz&jO?x-lQZI3#ZPlPdQ`BnZ_%Z;`XX2_yfs8TAx5-vM*yPu;D9=#(H}DV>U8<2 z_RncpxSWWWs^Zj&VczLt1pl`mWH8Cgj~5oE_n%y4IN^o;X9EBMKSZ~~2m21yk%_iG zSZmAqA$FoI{4yJNG2S&4`v24(^*9!bvfnO`|YXyF-z^@hf|GWbK@;~}d z{`ki~{Kvoj)nEP9-yh#oe@PJk>YxAd5C7?JfBUch=l|n>_#gk~zy5cB|F_A%WVpZh kXMg;|fBxJ5`M>;kfBPT)&ENd@|I`2e-~6}#;7_ps7eBfnUjP6A literal 0 HcmV?d00001 diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..7beab41 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,15 @@ +services: + cici-website: + build: . + container_name: cici-website + restart: unless-stopped + ports: + - "8001:8001" + environment: + HOST: 0.0.0.0 + PORT: 8001 + volumes: + - cici_data:/app/data + +volumes: + cici_data: diff --git a/index.html b/index.html new file mode 100644 index 0000000..88b6cbd --- /dev/null +++ b/index.html @@ -0,0 +1,162 @@ + + + + + + Cici 的个人网站 + + + +
+ + C + Cici 的个人网站 + + +
+ +
+
+
+
+

About Me

+
+
+ C +
+
+

你好,我是 CICI

+

+ 我是一名小学生女孩,喜欢画画、看书、拍照、记录生活。我的风格是甜甜的、 + 酷酷的,心里装着亮晶晶的快乐。 +

+
+
+
+
+ + + + +
+ + + +
+
+

Diary

+

日记本

+
+ + + +
+
+
+ + + + + + 相册大图 + + +
+ Cici 的个人网站 + 欢迎来到我的小世界 +
+ + + + diff --git a/script.js b/script.js new file mode 100644 index 0000000..a818541 --- /dev/null +++ b/script.js @@ -0,0 +1,538 @@ +const state = { + authenticated: false, + folders: [], + photos: [], + selectedFolderId: 1, +}; + +const pages = document.querySelectorAll("[data-page]"); +const routeLinks = document.querySelectorAll("[data-route]"); +const loginOpenButton = document.querySelector("#loginOpenButton"); +const logoutButton = document.querySelector("#logoutButton"); +const loginDialog = document.querySelector("#loginDialog"); +const loginForm = document.querySelector("#loginForm"); +const loginCancelButton = document.querySelector("#loginCancelButton"); +const passwordInput = document.querySelector("#passwordInput"); +const loginMessage = document.querySelector("#loginMessage"); +const ownerPanels = document.querySelectorAll(".owner-panel"); + +const profileForm = document.querySelector("#profileForm"); +const nameInput = document.querySelector("#nameInput"); +const bioInput = document.querySelector("#bioInput"); +const avatarInput = document.querySelector("#avatarInput"); +const profileName = document.querySelector("#profileName"); +const profileBio = document.querySelector("#profileBio"); +const avatarPreview = document.querySelector("#avatarPreview"); + +const folderForm = document.querySelector("#folderForm"); +const folderNameInput = document.querySelector("#folderNameInput"); +const folderTabs = document.querySelector("#folderTabs"); +const uploadFolderSelect = document.querySelector("#uploadFolderSelect"); + +const galleryForm = document.querySelector("#galleryForm"); +const galleryInput = document.querySelector("#galleryInput"); +const galleryGrid = document.querySelector("#galleryGrid"); +const homeGalleryGrid = document.querySelector("#homeGalleryGrid"); +const galleryStatus = document.querySelector("#galleryStatus"); +const imageDialog = document.querySelector("#imageDialog"); +const imagePreview = document.querySelector("#imagePreview"); +const imageCloseButton = document.querySelector("#imageCloseButton"); + +const diaryForm = document.querySelector("#diaryForm"); +const titleInput = document.querySelector("#diaryTitle"); +const textInput = document.querySelector("#diaryText"); +const diaryImageInput = document.querySelector("#diaryImageInput"); +const diaryList = document.querySelector("#diaryList"); + +async function api(path, options = {}) { + const response = await fetch(path, { + headers: { + "Content-Type": "application/json", + ...(options.headers || {}), + }, + credentials: "same-origin", + ...options, + }); + + const data = await response.json().catch(() => ({})); + if (!response.ok) { + throw new Error(data.error || "请求失败"); + } + return data; +} + +function showPage(route) { + const nextRoute = route || "home"; + pages.forEach((page) => { + page.classList.toggle("active", page.dataset.page === nextRoute); + }); + routeLinks.forEach((link) => { + link.classList.toggle("active", link.dataset.route === nextRoute); + }); +} + +function syncRoute() { + const route = (location.hash || "#home").replace("#", ""); + showPage(["home", "gallery", "diary"].includes(route) ? route : "home"); +} + +function updateAuthUi() { + ownerPanels.forEach((panel) => panel.classList.toggle("hidden", !state.authenticated)); + loginOpenButton.classList.toggle("hidden", state.authenticated); + logoutButton.classList.toggle("hidden", !state.authenticated); + + document.querySelectorAll(".delete-button").forEach((button) => { + button.classList.toggle("hidden", !state.authenticated); + }); +} + +function dataUrlBytes(dataUrl) { + const base64 = dataUrl.split(",")[1] || ""; + return Math.ceil((base64.length * 3) / 4); +} + +function drawImageToDataUrl(image, maxSize, quality) { + const scale = Math.min(1, maxSize / Math.max(image.width, image.height)); + const canvas = document.createElement("canvas"); + canvas.width = Math.max(1, Math.round(image.width * scale)); + canvas.height = Math.max(1, Math.round(image.height * scale)); + + const context = canvas.getContext("2d"); + context.fillStyle = "#fff8fc"; + context.fillRect(0, 0, canvas.width, canvas.height); + context.drawImage(image, 0, 0, canvas.width, canvas.height); + + return canvas.toDataURL("image/jpeg", quality); +} + +function readImage(file, options = {}) { + const maxSize = options.maxSize || 900; + const quality = options.quality || 0.78; + const maxBytes = options.maxBytes || 120000; + + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onload = () => { + const image = new Image(); + image.onload = () => { + const sizes = [maxSize, 640, 520, 420, 320, 240, 180].filter((size) => size <= maxSize); + const qualities = [quality, 0.62, 0.5, 0.42, 0.34, 0.28]; + let bestImage = drawImageToDataUrl(image, sizes[0], qualities[0]); + + for (const size of sizes) { + for (const nextQuality of qualities) { + bestImage = drawImageToDataUrl(image, size, nextQuality); + if (dataUrlBytes(bestImage) <= maxBytes) { + resolve(bestImage); + return; + } + } + } + + resolve(bestImage); + }; + image.onerror = () => reject(new Error("图片读取失败")); + image.src = reader.result; + }; + reader.onerror = () => reject(reader.error); + reader.readAsDataURL(file); + }); +} + +async function loadSession() { + const data = await api("/api/session"); + state.authenticated = data.authenticated; + updateAuthUi(); +} + +async function loadProfile() { + const profile = await api("/api/profile"); + const name = profile.name || "CICI"; + + profileName.textContent = `你好,我是 ${name}`; + profileBio.textContent = profile.bio || ""; + nameInput.value = name; + bioInput.value = profile.bio || ""; + + if (profile.avatar) { + avatarPreview.innerHTML = ""; + const image = document.createElement("img"); + image.src = profile.avatar; + image.alt = `${name} 的头像`; + avatarPreview.append(image); + } else { + avatarPreview.innerHTML = "C"; + } +} + +function openImagePreview(src, alt = "相册大图") { + imagePreview.src = src; + imagePreview.alt = alt; + imageDialog.showModal(); +} + +function createPhotoCard(photo) { + const figure = document.createElement("figure"); + figure.className = "photo-card uploaded-photo"; + + const previewButton = document.createElement("button"); + previewButton.className = "photo-preview-button"; + previewButton.type = "button"; + previewButton.setAttribute("aria-label", "查看大图"); + + const image = document.createElement("img"); + image.src = photo.src; + image.alt = photo.name || "CICI 的照片"; + + previewButton.append(image); + previewButton.addEventListener("click", () => openImagePreview(photo.src, photo.name || "相册大图")); + + const deleteButton = document.createElement("button"); + deleteButton.className = "delete-button"; + deleteButton.type = "button"; + deleteButton.textContent = "删除"; + deleteButton.addEventListener("click", async () => { + await api(`/api/photos/${photo.id}`, { method: "DELETE" }); + await loadGallery(); + updateAuthUi(); + }); + + figure.append(previewButton, deleteButton); + return figure; +} + +function renderSampleGallery(target) { + target.innerHTML = ` +
我的酷酷自拍
+
甜酷手账
+
闪亮表演视频
+ `; +} + +function renderEmptyFolder(target) { + target.innerHTML = ""; + const empty = document.createElement("div"); + empty.className = "empty-gallery"; + empty.textContent = "这个文件夹还没有照片。"; + target.append(empty); +} + +function renderPhotoGrid(target, photos, options = {}) { + target.innerHTML = ""; + const visiblePhotos = typeof options.limit === "number" ? photos.slice(0, options.limit) : photos; + + if (visiblePhotos.length === 0) { + if (options.showSamples) { + renderSampleGallery(target); + } else { + renderEmptyFolder(target); + } + return; + } + + visiblePhotos.forEach((photo) => { + target.append(createPhotoCard(photo)); + }); +} + +function renderFolders() { + folderTabs.innerHTML = ""; + uploadFolderSelect.innerHTML = ""; + + state.folders.forEach((folder) => { + const tab = document.createElement("button"); + tab.className = "folder-tab"; + tab.type = "button"; + tab.classList.toggle("active", folder.id === state.selectedFolderId); + tab.textContent = `${folder.name} (${folder.photo_count})`; + tab.addEventListener("click", () => { + state.selectedFolderId = folder.id; + renderFolders(); + renderSelectedFolderPhotos(); + }); + + if (state.authenticated && folder.id !== 1) { + const renameButton = document.createElement("span"); + renameButton.className = "folder-action"; + renameButton.textContent = "重命名"; + renameButton.addEventListener("click", async (event) => { + event.stopPropagation(); + const nextName = window.prompt("请输入新的文件夹名称", folder.name); + if (!nextName || nextName.trim() === folder.name) { + return; + } + await api(`/api/folders/${folder.id}`, { + method: "PUT", + body: JSON.stringify({ name: nextName.trim() }), + }); + await loadGallery(); + }); + + const deleteButton = document.createElement("span"); + deleteButton.className = "folder-action folder-delete"; + deleteButton.textContent = "删除"; + deleteButton.addEventListener("click", async (event) => { + event.stopPropagation(); + await api(`/api/folders/${folder.id}`, { method: "DELETE" }); + state.selectedFolderId = 1; + await loadGallery(); + }); + tab.append(renameButton); + tab.append(deleteButton); + } + + folderTabs.append(tab); + + const option = document.createElement("option"); + option.value = folder.id; + option.textContent = folder.name; + option.selected = folder.id === state.selectedFolderId; + uploadFolderSelect.append(option); + }); +} + +function renderSelectedFolderPhotos() { + const photos = state.photos.filter((photo) => photo.folder_id === state.selectedFolderId); + renderPhotoGrid(galleryGrid, photos); + updateAuthUi(); +} + +async function loadGallery() { + const [foldersData, photosData] = await Promise.all([api("/api/folders"), api("/api/photos")]); + state.folders = foldersData.folders; + state.photos = photosData.photos; + + if (!state.folders.some((folder) => folder.id === state.selectedFolderId)) { + state.selectedFolderId = state.folders[0]?.id || 1; + } + + renderFolders(); + renderSelectedFolderPhotos(); + renderPhotoGrid(homeGalleryGrid, state.photos, { limit: 3, showSamples: true }); + updateAuthUi(); +} + +async function loadDiary() { + const data = await api("/api/diary"); + diaryList.innerHTML = ""; + + if (data.entries.length === 0) { + const empty = document.createElement("div"); + empty.className = "empty-diary"; + empty.textContent = "还没有日记。"; + diaryList.append(empty); + return; + } + + data.entries.forEach((entry) => { + const item = document.createElement("article"); + item.className = "diary-entry"; + + const time = document.createElement("time"); + time.textContent = entry.created_at; + + const title = document.createElement("h3"); + title.textContent = entry.title; + + const text = document.createElement("p"); + text.textContent = entry.text; + + item.append(time, title); + + if (entry.image) { + const imageButton = document.createElement("button"); + imageButton.className = "diary-image-button"; + imageButton.type = "button"; + imageButton.setAttribute("aria-label", "查看日记图片"); + + const image = document.createElement("img"); + image.src = entry.image; + image.alt = entry.title || "日记图片"; + imageButton.append(image); + imageButton.addEventListener("click", () => openImagePreview(entry.image, entry.title || "日记图片")); + item.append(imageButton); + } + + if (entry.text) { + item.append(text); + } + + const deleteButton = document.createElement("button"); + deleteButton.className = "delete-button"; + deleteButton.type = "button"; + deleteButton.textContent = "删除"; + deleteButton.addEventListener("click", async () => { + await api(`/api/diary/${entry.id}`, { method: "DELETE" }); + await loadDiary(); + updateAuthUi(); + }); + + item.append(deleteButton); + diaryList.append(item); + }); + + updateAuthUi(); +} + +profileForm.addEventListener("submit", async (event) => { + event.preventDefault(); + + let avatar = null; + if (avatarInput.files[0]) { + avatar = await readImage(avatarInput.files[0], { + maxSize: 360, + quality: 0.72, + maxBytes: 80000, + }); + } + + await api("/api/profile", { + method: "PUT", + body: JSON.stringify({ + name: nameInput.value.trim() || "CICI", + bio: bioInput.value.trim(), + avatar, + }), + }); + + avatarInput.value = ""; + await loadProfile(); +}); + +folderForm.addEventListener("submit", async (event) => { + event.preventDefault(); + + const name = folderNameInput.value.trim(); + if (!name) { + folderNameInput.focus(); + return; + } + + const folder = await api("/api/folders", { + method: "POST", + body: JSON.stringify({ name }), + }); + state.selectedFolderId = folder.id; + folderForm.reset(); + await loadGallery(); +}); + +galleryForm.addEventListener("submit", async (event) => { + event.preventDefault(); + + const files = Array.from(galleryInput.files).slice(0, 12); + if (files.length === 0) { + galleryInput.focus(); + return; + } + + galleryStatus.textContent = "正在自动缩小照片,请稍等一下..."; + const photos = await Promise.all( + files.map(async (file) => ({ + name: file.name.replace(/\.[^.]+$/, ""), + src: await readImage(file, { + maxSize: 520, + quality: 0.68, + maxBytes: 90000, + }), + })), + ); + + const folderId = Number(uploadFolderSelect.value) || state.selectedFolderId || 1; + await api("/api/photos", { + method: "POST", + body: JSON.stringify({ folder_id: folderId, photos }), + }); + + state.selectedFolderId = folderId; + galleryInput.value = ""; + galleryStatus.textContent = `已上传 ${photos.length} 张照片。`; + await loadGallery(); +}); + +diaryForm.addEventListener("submit", async (event) => { + event.preventDefault(); + + const text = textInput.value.trim(); + let image = ""; + + if (diaryImageInput.files[0]) { + image = await readImage(diaryImageInput.files[0], { + maxSize: 620, + quality: 0.72, + maxBytes: 120000, + }); + } + + if (!text && !image) { + textInput.focus(); + return; + } + + await api("/api/diary", { + method: "POST", + body: JSON.stringify({ + title: titleInput.value.trim() || "今天的小日记", + text, + image, + }), + }); + + diaryForm.reset(); + await loadDiary(); +}); + +loginOpenButton.addEventListener("click", () => { + loginMessage.textContent = ""; + passwordInput.value = ""; + loginDialog.showModal(); + passwordInput.focus(); +}); + +loginCancelButton.addEventListener("click", () => { + loginDialog.close(); +}); + +loginForm.addEventListener("submit", async (event) => { + event.preventDefault(); + + try { + await api("/api/login", { + method: "POST", + body: JSON.stringify({ password: passwordInput.value }), + }); + loginDialog.close(); + await loadSession(); + await Promise.all([loadProfile(), loadGallery(), loadDiary()]); + } catch (error) { + loginMessage.textContent = error.message; + } +}); + +logoutButton.addEventListener("click", async () => { + await api("/api/logout", { method: "POST", body: "{}" }); + await loadSession(); + await loadGallery(); +}); + +imageCloseButton.addEventListener("click", () => { + imageDialog.close(); +}); + +imageDialog.addEventListener("click", (event) => { + if (event.target === imageDialog) { + imageDialog.close(); + } +}); + +window.addEventListener("hashchange", syncRoute); + +async function start() { + syncRoute(); + await loadSession(); + await Promise.all([loadProfile(), loadGallery(), loadDiary()]); +} + +start().catch((error) => { + console.error(error); +}); diff --git a/server.err b/server.err new file mode 100644 index 0000000..e69de29 diff --git a/server.log b/server.log new file mode 100644 index 0000000..e69de29 diff --git a/server.out b/server.out new file mode 100644 index 0000000..e69de29 diff --git a/styles.css b/styles.css new file mode 100644 index 0000000..e5ef5aa --- /dev/null +++ b/styles.css @@ -0,0 +1,1127 @@ +:root { + --ink: #20172b; + --paper: #fff8fc; + --pink: #ff6fb1; + --hot-pink: #ff2f87; + --purple: #8b5cf6; + --lilac: #eadcff; + --mint: #84f0de; + --butter: #fff09a; + --sky: #b9e9ff; + --peach: #ffc7a8; + --shadow: 7px 7px 0 var(--ink); +} + +* { + box-sizing: border-box; +} + +html { + scroll-behavior: smooth; +} + +body { + margin: 0; + color: var(--ink); + font-family: "Trebuchet MS", "Microsoft YaHei", sans-serif; + background: + radial-gradient(circle at 18px 18px, rgba(255, 111, 177, 0.28) 2px, transparent 3px), + radial-gradient(circle at 44px 44px, rgba(132, 240, 222, 0.3) 2px, transparent 3px), + linear-gradient(135deg, #fff8fc 0%, #fff8fc 52%, #f0e5ff 52%, #fff3c9 100%); + background-size: 52px 52px, 52px 52px, auto; +} + +a { + color: inherit; + text-decoration: none; +} + +.topbar { + position: sticky; + top: 0; + z-index: 10; + display: flex; + align-items: center; + justify-content: space-between; + gap: 18px; + padding: 14px clamp(16px, 4vw, 56px); + border-bottom: 4px solid var(--ink); + background: rgba(255, 248, 252, 0.94); + backdrop-filter: blur(12px); +} + +.brand, +.nav, +.hero-actions { + display: flex; + align-items: center; + gap: 12px; +} + +.brand { + font-weight: 900; +} + +.brand-mark { + display: grid; + width: 38px; + height: 38px; + place-items: center; + border: 3px solid var(--ink); + border-radius: 50%; + background: var(--pink); + box-shadow: 4px 4px 0 var(--ink); + color: white; +} + +.nav { + flex-wrap: wrap; + justify-content: flex-end; + font-size: 15px; + font-weight: 800; +} + +.nav a { + border-bottom: 3px solid transparent; +} + +.nav a:hover { + border-color: var(--hot-pink); +} + +.hero { + display: block; + min-height: auto; + padding: clamp(28px, 5vw, 72px); +} + +.hero-art { + position: relative; + min-height: 420px; + border: 5px solid var(--ink); + border-radius: 8px; + overflow: hidden; + background: + radial-gradient(circle at 22% 22%, var(--butter) 0 34px, transparent 35px), + radial-gradient(circle at 74% 32%, var(--mint) 0 18px, transparent 19px), + radial-gradient(circle at 82% 76%, var(--pink) 0 28px, transparent 29px), + linear-gradient(145deg, #c6f4ff 0%, #f7dcff 54%, #ffd4ea 100%); + box-shadow: var(--shadow); +} + +.moon { + position: absolute; + right: 34px; + top: 28px; + width: 84px; + height: 84px; + border: 4px solid var(--ink); + border-radius: 50%; + background: var(--butter); + box-shadow: 5px 5px 0 var(--ink); +} + +.moon::after { + position: absolute; + right: -2px; + top: -4px; + width: 70px; + height: 80px; + border-radius: 50%; + background: #f7dcff; + content: ""; +} + +.star { + position: absolute; + width: 20px; + height: 20px; + background: var(--hot-pink); + clip-path: polygon(50% 0, 62% 34%, 98% 35%, 69% 56%, 79% 92%, 50% 70%, 21% 92%, 31% 56%, 2% 35%, 38% 34%); +} + +.star-one { + left: 48px; + top: 56px; +} + +.star-two { + right: 126px; + bottom: 118px; + background: var(--purple); +} + +.star-three { + left: 88px; + bottom: 78px; + background: var(--mint); +} + +.comic-girl { + position: absolute; + left: 50%; + bottom: 32px; + width: 236px; + height: 322px; + transform: translateX(-50%); +} + +.hood, +.face, +.shirt, +.collar, +.pop, +.profile-card, +.edit-card, +.upload-card, +.photo-card, +.video-box, +.diary-form, +.diary-entry { + border: 4px solid var(--ink); +} + +.hood { + position: absolute; + left: 24px; + top: 22px; + width: 188px; + height: 180px; + border-radius: 50% 50% 38% 38%; + background: #2c1c3c; + box-shadow: inset 0 -18px 0 var(--purple); +} + +.ear { + position: absolute; + top: -35px; + width: 58px; + height: 94px; + border: 4px solid var(--ink); + background: #2c1c3c; +} + +.ear.left { + left: 12px; + border-radius: 90% 16% 70% 20%; + transform: rotate(-18deg); +} + +.ear.right { + right: 12px; + border-radius: 16% 90% 20% 70%; + transform: rotate(18deg); +} + +.ear::after { + position: absolute; + inset: 18px 13px 12px; + border-radius: inherit; + background: var(--pink); + content: ""; +} + +.skull { + position: absolute; + left: 50%; + top: 24px; + display: grid; + width: 46px; + height: 40px; + place-items: center; + border: 4px solid var(--ink); + border-radius: 50% 50% 42% 42%; + background: white; + font-size: 20px; + font-weight: 900; + transform: translateX(-50%); +} + +.face { + position: absolute; + left: 47px; + top: 76px; + width: 142px; + height: 126px; + border-radius: 46% 46% 42% 42%; + background: #ffd7c4; +} + +.eye { + position: absolute; + top: 52px; + width: 16px; + height: 24px; + border-radius: 50%; + background: var(--ink); +} + +.eye.left { + left: 36px; +} + +.eye.right { + right: 36px; +} + +.cheek { + position: absolute; + top: 80px; + width: 18px; + height: 8px; + border-radius: 999px; + background: var(--pink); +} + +.cheek.left { + left: 22px; +} + +.cheek.right { + right: 22px; +} + +.smile { + position: absolute; + left: 55px; + bottom: 28px; + width: 32px; + height: 16px; + border-bottom: 4px solid var(--ink); + border-radius: 0 0 40px 40px; +} + +.collar { + position: absolute; + left: 70px; + bottom: 94px; + z-index: 2; + width: 96px; + height: 32px; + border-radius: 999px; + background: var(--pink); +} + +.shirt { + position: absolute; + left: 44px; + bottom: 0; + width: 148px; + height: 126px; + border-radius: 34px 34px 10px 10px; + background: + linear-gradient(90deg, transparent 0 43%, var(--mint) 43% 57%, transparent 57%), + var(--purple); +} + +.pop { + position: absolute; + z-index: 2; + padding: 10px 16px; + border-radius: 999px; + background: white; + color: var(--ink); + font-weight: 900; + box-shadow: 5px 5px 0 var(--ink); +} + +.pop-one { + left: 24px; + top: 28px; + background: var(--mint); +} + +.pop-two { + right: 24px; + bottom: 34px; + background: var(--pink); + color: white; +} + +.hero-copy { + max-width: 620px; +} + +.eyebrow { + margin: 0 0 10px; + color: var(--hot-pink); + font-size: 14px; + font-weight: 900; + letter-spacing: 0; + text-transform: uppercase; +} + +h1, +h2, +h3, +p, +figure { + margin-top: 0; +} + +h1 { + margin-bottom: 18px; + font-size: clamp(42px, 8vw, 88px); + line-height: 0.98; +} + +h2 { + margin-bottom: 0; + font-size: clamp(30px, 5vw, 52px); +} + +h3 { + margin-bottom: 10px; + font-size: 24px; +} + +p { + font-size: 18px; + line-height: 1.7; +} + +.button, +.delete-button { + display: inline-flex; + min-height: 46px; + align-items: center; + justify-content: center; + padding: 11px 18px; + border: 4px solid var(--ink); + border-radius: 8px; + box-shadow: 5px 5px 0 var(--ink); + font: inherit; + font-weight: 900; + cursor: pointer; + transition: transform 160ms ease, box-shadow 160ms ease; +} + +.button:hover, +.delete-button:hover, +.play-button:hover { + transform: translate(3px, 3px); + box-shadow: 2px 2px 0 var(--ink); +} + +.primary { + background: var(--pink); + color: white; +} + +.secondary { + background: white; +} + +.delete-button { + min-height: 36px; + padding: 6px 12px; + background: var(--butter); + font-size: 14px; +} + +.band { + padding: clamp(44px, 7vw, 86px) clamp(16px, 5vw, 72px); + border-top: 5px solid var(--ink); +} + +.section-title, +.about-layout, +.info-grid, +.upload-card, +.gallery-grid, +.video-box, +.diary-layout { + max-width: 1040px; + margin-right: auto; + margin-left: auto; +} + +.section-title { + margin-bottom: 28px; +} + +.about-band { + background: + linear-gradient(90deg, rgba(255, 240, 154, 0.7) 0 20%, transparent 20% 100%) 0 0 / 38px 38px, + #fff8fc; +} + +.about-layout, +.diary-layout { + display: grid; + grid-template-columns: minmax(260px, 0.95fr) minmax(280px, 1.05fr); + gap: 26px; +} + +.profile-card, +.edit-card, +.upload-card, +.photo-card, +.diary-form, +.diary-entry { + border-radius: 8px; + background: white; + box-shadow: var(--shadow); +} + +.profile-card { + display: grid; + grid-template-columns: 150px 1fr; + gap: 22px; + align-items: center; + padding: 22px; +} + +.avatar-preview { + display: grid; + width: 150px; + height: 150px; + place-items: center; + overflow: hidden; + border: 4px solid var(--ink); + border-radius: 50%; + background: + radial-gradient(circle at 50% 44%, #ffd7c4 0 36%, transparent 37%), + linear-gradient(145deg, #2c1c3c 0 52%, var(--pink) 52% 100%); + box-shadow: 5px 5px 0 var(--ink); + color: white; + font-size: 54px; + font-weight: 900; +} + +.avatar-preview img { + width: 100%; + height: 100%; + object-fit: cover; +} + +.edit-card, +.diary-form { + padding: 20px; +} + +.info-grid { + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); + gap: 16px; + margin-top: 26px; +} + +.info-grid div { + min-height: 116px; + padding: 18px; + border: 4px solid var(--ink); + border-radius: 8px; + background: var(--lilac); + box-shadow: 5px 5px 0 var(--ink); +} + +.info-grid div:nth-child(2) { + background: #ffd1e8; +} + +.info-grid div:nth-child(3) { + background: #d9f9ff; +} + +.info-grid div:nth-child(4) { + background: var(--mint); +} + +.info-grid span, +label { + display: block; + margin-bottom: 8px; + font-size: 14px; + font-weight: 900; +} + +.info-grid strong { + font-size: 20px; + line-height: 1.35; +} + +input, +select, +textarea { + width: 100%; + margin-bottom: 16px; + padding: 12px; + border: 3px solid var(--ink); + border-radius: 6px; + color: var(--ink); + font: inherit; + background: #fffafd; +} + +input[type="file"] { + padding: 10px; + background: white; +} + +textarea { + min-height: 126px; + resize: vertical; +} + +.file-picker { + margin-bottom: 16px; +} + +.gallery-band { + background: + radial-gradient(circle at 12% 20%, rgba(132, 240, 222, 0.55) 0 58px, transparent 59px), + radial-gradient(circle at 88% 16%, rgba(255, 111, 177, 0.38) 0 64px, transparent 65px), + #f9f1ff; + color: var(--ink); +} + +.upload-card { + display: flex; + flex-wrap: wrap; + align-items: flex-end; + gap: 14px; + margin-bottom: 24px; + padding: 18px; +} + +.upload-card .file-picker { + flex: 1; + margin-bottom: 0; +} + +.upload-card input { + margin-bottom: 0; +} + +.folder-form { + display: flex; + align-items: flex-end; + gap: 14px; +} + +.folder-form label { + flex: 1; +} + +.folder-tabs { + display: flex; + max-width: 1040px; + margin: 0 auto 22px; + gap: 12px; + overflow-x: auto; + padding: 4px 4px 10px; +} + +.folder-tab { + display: inline-flex; + min-height: 42px; + flex: 0 0 auto; + align-items: center; + gap: 10px; + padding: 8px 14px; + border: 4px solid var(--ink); + border-radius: 8px; + background: white; + box-shadow: 4px 4px 0 var(--ink); + color: var(--ink); + font: inherit; + font-weight: 900; + cursor: pointer; +} + +.folder-tab.active { + background: var(--mint); +} + +.folder-action { + padding: 3px 7px; + border: 2px solid var(--ink); + border-radius: 999px; + background: var(--butter); + font-size: 12px; +} + +.folder-delete { + background: #ffd1e8; +} + +.upload-status { + width: 100%; + margin: 0; + color: #6a5176; + font-size: 14px; + font-weight: 900; +} + +.gallery-grid { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 20px; + margin-bottom: 22px; +} + +.photo-card { + position: relative; + min-height: 250px; + margin: 0; + padding: 14px; +} + +.uploaded-photo { + min-height: auto; +} + +.photo-illustration, +.uploaded-photo img { + width: 100%; + height: 170px; + border: 4px solid var(--ink); + border-radius: 6px; + object-fit: cover; + overflow: hidden; +} + +.photo-preview-button { + display: block; + width: 100%; + padding: 0; + border: 0; + background: transparent; + cursor: zoom-in; +} + +.night { + background: + radial-gradient(circle at 26% 28%, var(--butter) 0 26px, transparent 27px), + radial-gradient(circle at 72% 36%, var(--pink) 0 11px, transparent 12px), + linear-gradient(145deg, #b9e9ff, #eadcff); +} + +.doodle { + background: + radial-gradient(circle at 24% 34%, var(--mint) 0 12px, transparent 13px), + radial-gradient(circle at 72% 25%, white 0 10px, transparent 11px), + radial-gradient(circle at 62% 72%, var(--purple) 0 15px, transparent 16px), + #ffabd0; +} + +.stage { + background: + linear-gradient(90deg, transparent 0 34%, rgba(32, 23, 43, 0.18) 34% 36%, transparent 36% 64%, rgba(32, 23, 43, 0.18) 64% 66%, transparent 66%), + linear-gradient(#d9f9ff 0 55%, #ff8ec2 55% 100%); +} + +.photo-card figcaption { + padding-top: 13px; + font-size: 18px; + font-weight: 900; +} + +.uploaded-photo .delete-button { + margin-top: 10px; +} + +.image-dialog { + width: min(94vw, 980px); + max-height: 92vh; + padding: 18px; + border: 4px solid var(--ink); + border-radius: 8px; + background: #fff8fc; + box-shadow: var(--shadow); +} + +.image-dialog::backdrop { + background: rgba(32, 23, 43, 0.55); +} + +.image-dialog img { + display: block; + max-width: 100%; + max-height: 78vh; + margin: 0 auto; + border: 4px solid var(--ink); + border-radius: 8px; + object-fit: contain; +} + +.dialog-close { + display: grid; + width: 40px; + height: 40px; + margin: 0 0 12px auto; + place-items: center; + border: 3px solid var(--ink); + border-radius: 50%; + background: var(--pink); + box-shadow: 3px 3px 0 var(--ink); + color: white; + font-size: 24px; + font-weight: 900; + line-height: 1; + cursor: pointer; +} + +.video-box { + display: flex; + align-items: center; + gap: 18px; + padding: 20px; + border-radius: 8px; + background: var(--mint); + box-shadow: var(--shadow); +} + +.play-button { + display: grid; + width: 74px; + height: 74px; + flex: 0 0 auto; + place-items: center; + border: 4px solid var(--ink); + border-radius: 50%; + background: white; + box-shadow: 5px 5px 0 var(--ink); + color: var(--ink); + font-size: 28px; + cursor: pointer; +} + +.diary-band { + background: + linear-gradient(135deg, rgba(255, 111, 177, 0.18) 25%, transparent 25%) 0 0 / 28px 28px, + #fff8fc; +} + +.diary-list { + display: grid; + gap: 14px; + align-content: start; +} + +.diary-entry { + padding: 20px; + box-shadow: 5px 5px 0 var(--ink); +} + +.diary-entry time { + display: block; + margin-bottom: 8px; + color: #695474; + font-size: 13px; + font-weight: 900; +} + +.diary-entry .delete-button { + margin-top: 4px; +} + +.diary-image-button { + display: block; + width: 100%; + margin: 10px 0 14px; + padding: 0; + border: 0; + background: transparent; + cursor: zoom-in; +} + +.diary-image-button img { + display: block; + width: 100%; + max-height: 360px; + border: 4px solid var(--ink); + border-radius: 8px; + object-fit: cover; +} + +.empty-diary { + padding: 22px; + border: 4px dashed var(--ink); + border-radius: 8px; + background: rgba(255, 255, 255, 0.78); + font-weight: 900; +} + +.empty-gallery { + grid-column: 1 / -1; + padding: 26px; + border: 4px dashed var(--ink); + border-radius: 8px; + background: rgba(255, 255, 255, 0.78); + box-shadow: 5px 5px 0 var(--ink); + font-weight: 900; +} + +.footer { + display: flex; + justify-content: space-between; + gap: 16px; + padding: 22px clamp(16px, 5vw, 72px); + border-top: 5px solid var(--ink); + background: var(--ink); + color: white; + font-weight: 800; +} + +@media (max-width: 920px) { + .info-grid { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } +} + +@media (max-width: 820px) { + .topbar, + .footer { + align-items: flex-start; + flex-direction: column; + } + + .hero, + .about-layout, + .diary-layout, + .gallery-grid { + grid-template-columns: 1fr; + } + + .hero { + min-height: auto; + } + + .hero-art { + min-height: 360px; + order: -1; + } + + .profile-card { + grid-template-columns: 1fr; + } + + .upload-card { + align-items: stretch; + flex-direction: column; + } + + .folder-form { + align-items: stretch; + flex-direction: column; + } +} + +@media (max-width: 520px) { + .hero-actions, + .video-box { + align-items: stretch; + flex-direction: column; + } + + .button, + .delete-button { + width: 100%; + } + + .info-grid { + grid-template-columns: 1fr; + } + + h1 { + font-size: 42px; + } +} + +.page { + display: none; +} + +.page.active { + display: block; +} + +.hidden { + display: none !important; +} + +.nav a.active { + border-color: var(--hot-pink); +} + +.text-button { + display: inline-flex; + min-height: 34px; + align-items: center; + justify-content: center; + padding: 5px 12px; + border: 3px solid var(--ink); + border-radius: 8px; + background: white; + box-shadow: 3px 3px 0 var(--ink); + color: var(--ink); + font: inherit; + font-weight: 900; + cursor: pointer; +} + +.profile-main { + display: grid; + grid-template-columns: 150px 1fr; + gap: 22px; + align-items: center; +} + +.hero .profile-card { + display: block; + max-width: 1040px; + margin: 0 auto; + padding: 28px; +} + +.hero .profile-card h1 { + font-size: clamp(36px, 6vw, 68px); +} + +.owner-panel { + max-width: 1040px; + margin: 0 auto 28px; + padding: 20px; + border: 4px solid var(--ink); + border-radius: 8px; + background: white; + box-shadow: var(--shadow); +} + +.owner-panel.compact, +.section-title.compact { + margin-bottom: 14px; +} + +.login-dialog { + width: min(92vw, 420px); + border: 4px solid var(--ink); + border-radius: 8px; + background: #fff8fc; + box-shadow: var(--shadow); + color: var(--ink); +} + +.login-dialog::backdrop { + background: rgba(32, 23, 43, 0.45); +} + +.login-dialog form { + display: grid; + gap: 10px; +} + +.dialog-actions { + display: flex; + justify-content: flex-end; + gap: 12px; +} + +.form-message, +.upload-status { + min-height: 20px; + margin: 0; + color: #6a5176; + font-size: 14px; + font-weight: 900; +} + +.home-gallery { + max-width: 1040px; + margin: 0 auto; + padding: 0 clamp(16px, 5vw, 72px) clamp(44px, 7vw, 72px); +} + +.home-gallery-header { + display: flex; + align-items: flex-end; + justify-content: space-between; + gap: 16px; + margin-bottom: 20px; +} + +.home-gallery-header h2 { + margin-bottom: 0; +} + +.home-gallery-grid { + margin-bottom: 0; +} + +@media (max-width: 820px) { + .profile-main { + grid-template-columns: 1fr; + } +} + +@media (max-width: 920px) { + .gallery-grid { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } +} + +@media (max-width: 640px) { + .topbar { + position: static; + } + + .brand { + width: 100%; + } + + .nav { + width: 100%; + justify-content: flex-start; + } + + .hero { + padding: 22px 16px; + } + + .home-gallery { + padding: 0 16px 42px; + } + + .home-gallery-header { + align-items: stretch; + flex-direction: column; + } + + .home-gallery-header .button { + width: 100%; + } + + .gallery-grid { + grid-template-columns: 1fr; + gap: 16px; + } + + .photo-card { + padding: 12px; + } + + .photo-illustration, + .uploaded-photo img { + height: 220px; + } + + .image-dialog { + width: 94vw; + padding: 12px; + } + + .image-dialog img { + max-height: 72vh; + } + + .dialog-actions { + flex-direction: column; + } + + .folder-tabs { + margin-right: 16px; + margin-left: 16px; + } +}