From 7a1c78c5de023548360c4adfcda7958305774310 Mon Sep 17 00:00:00 2001 From: MeowOS Date: Mon, 31 Aug 2026 03:54:38 +0800 Subject: [PATCH] =?UTF-8?q?feat(nyai):=20=E6=9B=B4=E6=96=B0=E8=A7=84?= =?UTF-8?q?=E8=8C=83+=E5=AF=BC=E5=87=BA=E8=BF=87=E6=BB=A4=20=E2=80=94=20?= =?UTF-8?q?=E9=98=B2=E9=99=8D=E7=BA=A7=E5=AE=89=E8=A3=85(version=E7=82=B9?= =?UTF-8?q?=E5=88=86=E6=AF=94=E8=BE=83,=E6=96=B0=E7=89=88<=E5=B7=B2?= =?UTF-8?q?=E8=A3=85=E6=8B=92=E8=A3=85/=E7=BC=BA=E5=A4=B1=E6=8B=92?= =?UTF-8?q?=E8=A3=85,=E5=85=88=E8=A7=A3=20staging=20=E5=86=8D=E6=9B=BF?= =?UTF-8?q?=E6=8D=A2)=20+=20=E5=AF=BC=E5=87=BA=E4=B8=A4=E5=B1=82=E6=A8=A1?= =?UTF-8?q?=E5=BC=8F(=E9=BB=91=E5=90=8D=E5=8D=95=20find+tar=20-T=20?= =?UTF-8?q?=E6=8E=92=E9=99=A4=20*.pre=5F*/.bak=5F*/logs//*.log/.DS=5FStore?= =?UTF-8?q?=20=E4=B8=94=E5=8E=BB=20./=20=E5=89=8D=E7=BC=80=20/=20=E7=99=BD?= =?UTF-8?q?=E5=90=8D=E5=8D=95=20export=5Ffiles=20=E9=80=90=E9=A1=B9?= =?UTF-8?q?=E5=AE=89=E5=85=A8=E6=A0=A1=E9=AA=8C)=20+=20=E5=AF=BC=E5=87=BA?= =?UTF-8?q?=E4=BD=93=E6=A3=80(app.json=E5=90=88=E6=B3=95+exec=E5=AD=98?= =?UTF-8?q?=E5=9C=A8=E5=8F=AF=E6=89=A7=E8=A1=8C)=20+=20install/upgrade=20?= =?UTF-8?q?=E6=88=90=E5=8A=9F=E5=90=8E=E8=87=AA=E6=B8=85=20.bak=5F=20?= =?UTF-8?q?+=20os.meow.*=20=E7=AD=BE=E5=90=8D=E6=8F=90=E7=A4=BA=E4=B8=8E?= =?UTF-8?q?=202A=20=E9=AA=8C=E7=AD=BE=E6=8C=82=E7=82=B9=E6=B3=A8=E9=87=8A?= =?UTF-8?q?=20(agent-180)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit nyai e5514929→新值见 fw_content.conf; 宿主 17/17 场景全过(首装/升/同版/降级拒/无版本拒/黑白名单/体检/round-trip); cmd_upgrade 同步加防降级门禁(堵绕过) 出入: 版本严格解析(1.2.3-beta 判不可比拒装, 与定案一致); busybox tar --exclude 未真机验证→用 find|tar -T 兜底 --- patch_v2/meowpkg/build_nyai.sh | 28 ++++ patch_v2/meowpkg/nyai | Bin 105516 -> 109596 bytes patch_v2/meowpkg/nyai.c | 248 ++++++++++++++++++++++++++++++--- patch_v2/meowpkg/nyai_host | Bin 0 -> 73848 bytes 4 files changed, 253 insertions(+), 23 deletions(-) create mode 100755 patch_v2/meowpkg/build_nyai.sh create mode 100755 patch_v2/meowpkg/nyai_host diff --git a/patch_v2/meowpkg/build_nyai.sh b/patch_v2/meowpkg/build_nyai.sh new file mode 100755 index 0000000..21b69ee --- /dev/null +++ b/patch_v2/meowpkg/build_nyai.sh @@ -0,0 +1,28 @@ +#!/bin/bash +# build_nyai.sh — nyai 包管理器交叉编译(mipsel 静态)+ 宿主编译可选。 +# +# 目标:R3 Pro II / MeowOS(mipsel-linux-muslsf,静态)。单文件、无外部依赖(POSIX + Linux)。 +# +# 用法: +# ./build_nyai.sh # 交叉编译 → patch_v2/meowpkg/nyai(mipsel 静态) +# ./build_nyai.sh host # 宿主编译 → patch_v2/meowpkg/nyai_host +set -e +cd "$(dirname "$0")" +ROOT="$HOME/Project/R3ProII" +CC="$ROOT/.tools/zig-mipsel-cc" + +if [ "$1" = "host" ]; then + HOST_CC="${CC_HOST:-cc}" + "$HOST_CC" -Os -Wall -Wextra nyai.c -o nyai_host + echo "== host build ==" + ls -la nyai_host + md5sum nyai_host + file nyai_host + exit 0 +fi + +"$CC" -Os -Wall -Wextra -static nyai.c -o nyai +echo "== nyai (mipsel static) ==" +ls -la nyai +md5sum nyai +file nyai diff --git a/patch_v2/meowpkg/nyai b/patch_v2/meowpkg/nyai index fb4e9ea1aa4177d537894d5f0ac9793aa56517a9..f234b6cfe3eba1090ba72c240a96324f85ad7cc5 100755 GIT binary patch delta 33716 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 delta 29976 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 diff --git a/patch_v2/meowpkg/nyai.c b/patch_v2/meowpkg/nyai.c index 517be95..277dfaf 100644 --- a/patch_v2/meowpkg/nyai.c +++ b/patch_v2/meowpkg/nyai.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -36,11 +37,8 @@ static const char *meow_root(void) const char *r = getenv("MEOWROOT"); return (r && *r) ? r : "/usr/data/mnt/sd_0"; } -static void path_apps(char *out, int n, const char *pkg) -{ snprintf(out, n, "%s/MeowAPPs/%s", meow_root(), pkg ? pkg : ""); } static void path_data(char *out, int n, const char *pkg, const char *sub) { snprintf(out, n, "%s/MeowData/%s/%s", meow_root(), pkg ? pkg : "", sub ? sub : ""); } -static void path_apps_root(char *out, int n){ snprintf(out,n,"%s/MeowAPPs", meow_root()); } static void path_sources(char *out, int n) { snprintf(out,n,"%s/MeowOS/opt/nyai/sources.list", meow_root()); } static void path_cache(char *out, int n) @@ -177,6 +175,45 @@ static int version_cmp(const char *a, const char *b) return *x ? 1 : -1; } +/* 点分数字版本:APPS.md 附录 §3「更新规范」升级门禁专用(install_mpk_file)。 + * 规则:以 '.' 或 '-' 分段,每段必须为纯数字;空串/含非数字段 = 不可解析(返回负数)。 + * 段数不齐时短者补 0(如 1.2 == 1.2.0)。 */ +#define MAXVSEG 16 +static int version_parse(const char *v, unsigned long *segs, int max) +{ + if (!v || !*v) return -1; + int n = 0; + const char *p = v; + while (*p) { + while (*p=='.'||*p=='-') p++; + if (!*p) break; + const char *start = p; + while (*p && isdigit((unsigned char)*p)) p++; + if (p == start) return -1; /* 空段或非数字段 */ + unsigned long x = 0; + for (const char *q=start; q 0x7fffffffUL) return -1; } + if (n < max) segs[n++] = x; + } + return n ? n : -1; +} +static int version_ok(const char *v) +{ unsigned long s[MAXVSEG]; return version_parse(v, s, MAXVSEG) >= 0; } +/* 返回:a>b=1, a==b=0, a cb ? ca : cb; + for (int i = 0; i < n; i++) { + unsigned long xa = i < ca ? na[i] : 0UL; /* 段数不齐,短者补 0 */ + unsigned long xb = i < cb ? nb[i] : 0UL; + if (xa != xb) return xa < xb ? -1 : 1; + } + return 0; +} + /* ---------------- JSON 读取 ---------------- */ static int json_str(const char *j, const char *key, char *out, int n) { @@ -250,7 +287,8 @@ typedef struct { char services[512]; char depends[256]; char description[256]; - int has_routes, has_services; + char export_files[1024]; /* raw JSON 数组(导出白名单;无则黑名单模式) */ + int has_routes, has_services, has_export_files; } appmeta; static int load_app_meta(const char *path, appmeta *m) @@ -273,6 +311,7 @@ static int load_app_meta(const char *path, appmeta *m) if (json_str(j,"description",m->description,sizeof m->description)!=0) m->description[0]=0; m->has_routes = json_raw(j,"routes",m->routes,sizeof m->routes)==0; m->has_services = json_raw(j,"services",m->services,sizeof m->services)==0; + m->has_export_files = json_raw(j,"export_files",m->export_files,sizeof m->export_files)==0; return 0; } @@ -724,34 +763,68 @@ static int install_mpk_file(const char *mpk_path) if (!valid_pkg(pkg)) { fprintf(stderr,"nyai: install: 包名含非法字符: %s\n", pkg); return 1; } printf("Reading package lists... Done\n"); - char dst[BUF], bak[BUF]; + char dst[BUF], bak[BUF], stg[BUF]; snprintf(dst,sizeof dst,"%s/MeowAPPs/%s", meow_root(), pkg); snprintf(bak,sizeof bak,"%s.bak_%d", dst, (int)getpid()); + snprintf(stg,sizeof stg,"%s/MeowAPPs/.stg_%d_%s", meow_root(), (int)getpid(), pkg); int replacing = (access(dst,F_OK)==0); - if (replacing) { - rm_rf(bak); - if (rename(dst,bak)!=0) { fprintf(stderr,"nyai: install: 备份 %s 失败: %s\n", dst, strerror(errno)); return 1; } - printf("Backing up existing %s -> %s\n", pkg, bak); - } - printf("Preparing to unpack %s ...\n", pkg); - if (mkdir_p(dst)!=0) { if (replacing) rename(bak,dst); return 1; } + + /* 签名分级预留(未实现验签):os.meow.* 系统包二期须有有效签名,无签名/验签失败一律拒装 */ + if (!strncmp(pkg,"os.meow.", 8)) printf("nyai: 系统包 %s 需签名(二期)\n", pkg); + + /* ① 先解到临时目录读元数据,再决定替换(防降级 + 校验 app.json) */ + rm_rf(stg); + if (mkdir_p(stg)!=0) { fprintf(stderr,"nyai: install: 无法建临时目录 %s\n", stg); return 1; } char cmd[1024]; - snprintf(cmd,sizeof cmd,"gzip -dc '%s' | tar -x -C '%s' 2>/dev/null && [ -f '%s/app.json' ]", mpk_path, dst, dst); - printf("Unpacking %s ...\n", pkg); + snprintf(cmd,sizeof cmd,"gzip -dc '%s' | tar -x -C '%s' 2>/dev/null && [ -f '%s/app.json' ]", mpk_path, stg, stg); + printf("Preparing to unpack %s ...\n", pkg); if (system(cmd)!=0) { fprintf(stderr,"nyai: install: 解压/校验 app.json 失败(%s 可能损坏或非 .mpk)\n", mpk_path); - rm_rf(dst); if (replacing) rename(bak,dst); return 1; + rm_rf(stg); return 1; } - char appj[BUF]; snprintf(appj,sizeof appj,"%s/app.json", dst); + char stgj[BUF]; snprintf(stgj,sizeof stgj,"%s/app.json", stg); appmeta m; - if (load_app_meta(appj,&m)!=0) { + if (load_app_meta(stgj,&m)!=0) { fprintf(stderr,"nyai: install: app.json 不合法(缺 name 或 exec)\n"); - rm_rf(dst); if (replacing) rename(bak,dst); return 1; + rm_rf(stg); return 1; } + /* TODO(2A): meow_verify 验签挂点,见 MPK_SIGNATURE_DESIGN.md */ + + /* ② 同包名替换前的防降级门禁:新版必须 >= 已装(相等=重装,允许;<即降级拒装) */ + if (replacing) { + char instj[BUF]; snprintf(instj,sizeof instj,"%s/app.json", dst); + appmeta im; + if (load_app_meta(instj,&im)!=0 || !version_ok(im.version) || !version_ok(m.version)) { + fprintf(stderr,"nyai: install: 版本无法判定(新=「%s」 已装=「%s」),拒绝安装\n", + m.version[0]?m.version:"(缺失)", im.version[0]?im.version:"(缺失)"); + rm_rf(stg); return 1; + } + if (version_num_cmp(m.version, im.version) < 0) { + fprintf(stderr,"nyai: install: 不允许降级: 新版本 %s < 已装 %s\n", m.version, im.version); + rm_rf(stg); return 1; + } + rm_rf(bak); + if (rename(dst,bak)!=0) { fprintf(stderr,"nyai: install: 备份 %s 失败: %s\n", dst, strerror(errno)); rm_rf(stg); return 1; } + printf("Backing up existing %s -> %s\n", pkg, bak); + } else { + rm_rf(dst); /* 防御:全新安装前清残留 */ + } + + /* ③ 部署临时目录 -> 正式目录 */ + if (rename(stg,dst)!=0) { + fprintf(stderr,"nyai: install: 部署 %s 失败: %s\n", dst, strerror(errno)); + rm_rf(stg); if (replacing) rename(bak,dst); /* 回滚到旧版 */ + return 1; + } + + /* ④ 数据 init(MeowData 数据保留,仅保证目录存在) */ char d1[BUF],d2[BUF]; path_data(d1,sizeof d1,pkg,"data"); path_data(d2,sizeof d2,pkg,"cache"); mkdir_p(d1); mkdir_p(d2); printf("Setting up %s (%s) ...\n", pkg, m.version[0]?m.version:"?"); + + /* ⑤ 安装成功后清理本次创建的 .bak_(失败回滚路径不动) */ + if (replacing && bak[0]) { rm_rf(bak); printf("Removed backup %s\n", bak); } printf("OK\n"); return 0; } @@ -869,25 +942,138 @@ static int cmd_remove(const char *pkg, int purge) return 0; } +/* ---- 导出过滤助手(APPS.md 附录 §3「导出过滤」) ---- */ +/* 判断 p 是否含独立 '..' 路径组件 */ +static int has_dotdot_comp(const char *p) +{ + const char *s = p; + while (*s) { + if (s[0]=='.' && s[1]=='.' && + (s==p || s[-1]=='/') && (s[2]==0 || s[2]=='/')) + return 1; + s++; + } + return 0; +} +/* 校验并相对化导出成员:去前导 '/' 与重复 './',禁绝对路径、禁 '..' 组件、禁 shell 危险字符 */ +static int sanitize_member(const char *in, char *out, int n) +{ + if (!in || !*in) return -1; + const char *p = in; + while (*p=='/' || (p[0]=='.'&&p[1]=='/')) p++; + if (*p=='/' || !*p) return -1; /* 去完仍是绝对/空 */ + if (has_dotdot_comp(p)) return -1; + if (unsafe_path(p)) return -1; + if ((int)strlen(p)+1 > n) return -1; + snprintf(out,n,"%s", p); + return 0; +} +/* 从 JSON 数组串(含 '[' ']')提取字符串成员;返回项数,负=格式错 */ +static int json_array_strings(const char *arr, char items[][256], int max) +{ + int n = 0; + const char *p = arr; + while (*p && *p!='[') p++; + if (*p!='[') return -1; + p++; + while (*p && n '%s'", src, listf); + int rc = system(cmd); + if (rc!=0) { rm_rf(listf); return -1; } + snprintf(cmd,sizeof cmd,"tar -c -C '%s' -T '%s' 2>/dev/null | gzip -c > '%s' 2>/dev/null", src, listf, outtmp); + rc = system(cmd); + rm_rf(listf); + return rc==0 ? 0 : -1; +} +/* 白名单:只打 app.json + exec + export_files 声明的项(逐项安全校验) */ +static int export_whitelist(const char *src, const char *exec_rel, const char *export_json, const char *outtmp) +{ + char items[16][256]; + int nit = json_array_strings(export_json, items, 16); + if (nit < 0) { fprintf(stderr,"nyai: export: export_files 格式非法(须为字符串数组)\n"); return -1; } + char listf[BUF]; snprintf(listf,sizeof listf,"%s.wl", outtmp); + FILE *lf = fopen(listf,"w"); + if (!lf) return -1; + fprintf(lf,"app.json\n%s\n", exec_rel); + for (int i=0;i/dev/null | gzip -c > '%s' 2>/dev/null", src, listf, outtmp); + int rc = system(cmd); + rm_rf(listf); + return rc==0 ? 0 : -1; +} + static int cmd_export(const char *pkg, const char *out) { if (!pkg || !valid_pkg(pkg)) { fprintf(stderr,"nyai: export: 包名无效\n"); return 2; } char src[BUF],dst[BUF]; snprintf(src,sizeof src,"%s/MeowAPPs/%s", meow_root(), pkg); if (access(src,R_OK)!=0) { fprintf(stderr,"nyai: export: 未安装 %s\n", pkg); return 1; } + /* 导出前体检:app.json 存在且合法(有 name+exec) */ + char appj[BUF]; snprintf(appj,sizeof appj,"%s/app.json", src); + appmeta m; + if (load_app_meta(appj,&m)!=0) { fprintf(stderr,"nyai: export: %s/app.json 不合法(缺 name 或 exec)\n", pkg); return 1; } + /* 导出前体检:exec 文件存在且可执行 */ + char exec_rel[BUF]; + if (sanitize_member(m.exec, exec_rel, sizeof exec_rel)!=0) { + fprintf(stderr,"nyai: export: exec 字段非法: %s\n", m.exec); return 1; + } + char exepath[BUF]; snprintf(exepath,sizeof exepath,"%s/%s", src, exec_rel); + if (access(exepath, X_OK)!=0) { + fprintf(stderr,"nyai: export: exec 文件 %s 不存在或不可执行,拒绝导出\n", exepath); return 1; + } char outbuf[BUF]; if (out && *out && unsafe_path(out)) { fprintf(stderr,"nyai: export: 输出路径含非法字符\n"); return 1; } snprintf(outbuf,sizeof outbuf,"%s", out && *out ? out : pkg); if (!strstr(outbuf,".mpk")) strncat(outbuf,".mpk", sizeof outbuf-strlen(outbuf)-1); snprintf(dst,sizeof dst,"%s", outbuf); printf("Exporting %s -> %s ...\n", pkg, dst); - char cmd[1024]; - snprintf(cmd,sizeof cmd,"tar -c -C '%s' . 2>/dev/null | gzip -c > '%s.tmp' 2>/dev/null", src, dst); - system(cmd); char tmpp[BUF]; snprintf(tmpp,sizeof tmpp,"%s.tmp", dst); - if (access(tmpp,F_OK)!=0 || rename(tmpp,dst)!=0) { - fprintf(stderr,"nyai: export: tar/gzip 失败\n"); rm_rf(tmpp); return 1; + int rc; + if (m.has_export_files && m.export_files[0]) { + rc = export_whitelist(src, exec_rel, m.export_files, tmpp); + } else { + rc = export_blacklist(src, tmpp); } + if (rc!=0 || access(tmpp,F_OK)!=0) { fprintf(stderr,"nyai: export: 打包失败\n"); rm_rf(tmpp); return 1; } + if (rename(tmpp,dst)!=0) { fprintf(stderr,"nyai: export: 写 %s 失败\n", dst); rm_rf(tmpp); return 1; } printf("OK\n"); return 0; } @@ -929,6 +1115,21 @@ static int cmd_upgrade(const char *pkg, const char *file) if (access(mpk,R_OK)!=0) { fprintf(stderr,"nyai: upgrade: 找不到包文件 %s\n", mpk); return 1; } char dst[BUF]; snprintf(dst,sizeof dst,"%s/MeowAPPs/%s", meow_root(), pkg); if (access(dst,F_OK)!=0) { fprintf(stderr,"nyai: upgrade: %s 未安装(如需全新安装请用 install)\n", pkg); return 1; } + /* 防降级门禁(与 install 同规范):新版必须 >= 已装(相等=重装允许) */ + { + char aj[BUF]; snprintf(aj,sizeof aj,"%s/app.json", dst); + appmeta im, nm; + if (load_app_meta(aj,&im)!=0 || mpk_appinfo(mpk,&nm)!=0 || + !version_ok(im.version) || !version_ok(nm.version)) { + fprintf(stderr,"nyai: upgrade: 版本无法判定(新=「%s」 已装=「%s」),拒绝\n", + nm.version[0]?nm.version:"(缺失)", im.version[0]?im.version:"(缺失)"); + return 1; + } + if (version_num_cmp(nm.version, im.version) < 0) { + fprintf(stderr,"nyai: upgrade: 不允许降级: 新版本 %s < 已装 %s\n", nm.version, im.version); + return 1; + } + } char bak[BUF]; snprintf(bak,sizeof bak,"%s.bak_%d", dst,(int)getpid()); rm_rf(bak); if (rename(dst,bak)!=0) { fprintf(stderr,"nyai: upgrade: 备份失败: %s\n", strerror(errno)); return 1; } @@ -943,6 +1144,7 @@ static int cmd_upgrade(const char *pkg, const char *file) char d1[BUF],d2[BUF]; path_data(d1,sizeof d1,pkg,"data"); path_data(d2,sizeof d2,pkg,"cache"); mkdir_p(d1); mkdir_p(d2); + if (bak[0]) { rm_rf(bak); } /* 升级成功后清理本次 .bak_ */ printf("OK (%s) — data preserved\n", m.version[0]?m.version:"?"); return 0; } diff --git a/patch_v2/meowpkg/nyai_host b/patch_v2/meowpkg/nyai_host new file mode 100755 index 0000000000000000000000000000000000000000..e65753997ec761ee2a587e62ec3abffc48be865f GIT binary patch literal 73848 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%0A11|3m9hi&~F`lFw-Pk0pF%6uuZY4aq4G44-m| zul5P5X)EBwzw+Aor$%IWlmE4j^$lAD0{@Tus> zlBc4R9Tgux;o~N=XgJa9OD|t={I5dM@$nqsjP;J!17Ke!#IGYEB}u|#OxRWL{NWPd zLkhhs1X!zYu&)53PHnl1ypFZs_WxVd*+w#J~pA_kq( z81UK{@VjHcAC3WkHU_*o2K+C8_a(Qs82A@sz=y#e`jXqY81R`f;8y{j+=pGQj)Cur z0k4Sxzbgj(p&0O^G2rh4t|_B2l;dOIe*}16a_%I!xwn7rhl7#68zRH^+eQjsbrn2K)uU`&y?fxIBCE{Cqjzmt)|+Dd8%9Np$w- z7~{5Zcu#y!%o07?W8injfG6P~sV{wv1)TI7%};g={P}=uifKbx7z4jL27G%A_=5yD z_uh9r5(EFa7;v`Q>G4g^tzr{u*@O~ix6{di&#{gHTn@0)QBh&P#pPIUFLe{l4VZhA zqdeEiDqU5#*gaKMKIW|PRM;IG9px2{;tCh@dCDtUjoa%eb=j*OzA|>Rx5{nz`aG

8dPtd2*{A9$)UXTxXTr>#O!uRfC4N%rRruY

Wg)0KidGI)Hi3H|O zXBAbB65;|heGazKPGfno7H~5?o2ls`ad_rqY24g0TqdG; zd#h?ZPM5vhUE->>S5!g5ea(Y+E^+uA5hTkoQPK!Wj!#iYfJMVuAA=aAlw0ogI3O%B zchKX^xV#Z#t+RVQPOrcb#HrZWnpJx** z^*AbB_L7>)%1!8Es9_T2z6eyi{i;<3*DkRyxo)xD&g_eSa$Ui-%NL>7((7)tFIgsA zmn~k!>`PZ%Z!1_~zy7MLRxc^E7Z%u7EV0AFE1lJwtV>rcw=J^I$eliiAeB`cT}BY> zy29l)LQ1P^d|o5K;j5~sFaqrMit=J7mIUnAUg;?B={_@`*_RhyYwwX^;kAoMf`xo( z+3m$%uk2@M9#=FocDu9IK{CUVxix~#s%n=T%gM+E@#!=Iygm#Yfns-&2{Ny{+EecK zl^T(`W*|#q2&75Cc7x?t-R7Qz_rVDL4e9?L;C6ODulEJ~;l-Y&X1f$_2g+i+fDs#hW7%329`3sF4nQjQ_VQE%;7C#xh0$2 zpdd;FY2G5ETSUc8mgB!ZS1tZa?iy`X+->B#%A|uXD?wjXW4WBI z0^9N&$~1U?;kQM9^^9R0mE}(GfE*)NP=u-(qEuxif&t4dSaof#!-ssMxW$TYy8l$&o{VBRJ-ve`Jl?N5?PJQ zFDnfMtazp?P}Tpqd{AXI@^Jc4K|5*HKZAhy&@mywReyC)qe?m#Gk&7^r{g=iD^+Of zK1Y@6_($=t@KpIT^ryR5Raf^usw|R&6aR#x_?KXQ{!6q~e|0~kN_8Ks##jB-{5PU6 zwb>-WB5~jpzE4v3(S$>H*wOv{fRRkFz2F~p-=s>VKiSO3QqNRw#-Fjjx|dR=HS+ia z`;o}cFQWRZ`zuwZE{(*uMpoJGsQ&7nOO;Aas+*Fds{c~TZ^-9XrWl^wO9FWFzXzkDAf znJzH!IYW(xkK$XE?PxRh?^%hWqZ&t%Q2kW>OFR%PJicT&nNx*-@<%cdE&s33moTQ` z&-hXOFEax1tf;B-Tfi`Obrc$|wFJh5sD|kA2}{|&5w%G6Pm}_nI8cH=HGj3P=sa1? j-Ppg3E`;!TlZ?~wQG6>9olW)C|MCohnH1F_s>=Q^q>j^i literal 0 HcmV?d00001