From 15937a6b4654a331ce5fd5b1052baad82f9319fd Mon Sep 17 00:00:00 2001 From: Teknium <127238744+teknium1@users.noreply.github.com> Date: Sun, 26 Apr 2026 08:24:26 -0700 Subject: [PATCH] feat(kanban): durable multi-profile collaboration board (#16081) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New `hermes kanban` CLI subcommand + `/kanban` slash command + skills for worker and orchestrator profiles. SQLite-backed task board (~/.hermes/kanban.db) shared across all profiles on the host. Zero changes to run_agent.py, no new core tools, no tool-schema bloat. Motivation: delegate_task is a function call — sync fork/join, anonymous subagent, no resumability, no human-in-the-loop. Kanban is the durable shape needed for research triage, scheduled ops, digital twins, engineering pipelines, and fleet work. They coexist (workers may call delegate_task internally). What this adds - hermes_cli/kanban_db.py — schema, CAS claim, dependency resolution, dispatcher, workspace resolution, worker-context builder. - hermes_cli/kanban.py — 15-verb CLI surface and shared run_slash() entry point used by both CLI and gateway. - skills/devops/kanban-worker — how a profile should work a claimed task. - skills/devops/kanban-orchestrator — "you are a dispatcher, not a worker" template with anti-temptation rules. - /kanban slash command wired into cli.py and gateway/run.py. Bypasses the running-agent guard (board writes don't touch agent state), so /kanban unblock can free a stuck worker mid-conversation. - Design spec at docs/hermes-kanban-v1-spec.pdf — comparative analysis vs Cline Kanban, Paperclip, NanoClaw, Gemini Enterprise; 8 patterns; 4 user stories; implementation plan; concurrency correctness. - Docs: website/docs/user-guide/features/kanban.md, CLI reference updated, sidebar entry added. Architecture highlights - Three planes: control (user + gateway), state (board + dispatcher), execution (pool of profile processes). - Every worker is a full OS process, spawned as `hermes -p `. No in-process subagent swarms — solves NanoClaw's SDK-lifecycle failure class. - Atomic claim via SQLite CAS in a BEGIN IMMEDIATE transaction; stale claims reclaimed 15 min after their TTL expires. - Tenant namespacing via one nullable column — one specialist fleet can serve many businesses with data isolation by workspace path. Tests: 60 targeted tests (schema, CAS atomicity, dependency resolution, dispatcher, workspace kinds, tenancy, CLI + slash surface). All pass hermetic via scripts/run_tests.sh. --- cli.py | 25 +- docs/hermes-kanban-v1-spec.pdf | Bin 0 -> 213669 bytes gateway/run.py | 42 + hermes_cli/commands.py | 5 + hermes_cli/kanban.py | 662 ++++++++++++ hermes_cli/kanban_db.py | 1067 ++++++++++++++++++++ hermes_cli/main.py | 14 + skills/devops/kanban-orchestrator/SKILL.md | 140 +++ skills/devops/kanban-worker/SKILL.md | 120 +++ tests/hermes_cli/test_kanban_cli.py | 210 ++++ tests/hermes_cli/test_kanban_db.py | 438 ++++++++ website/docs/reference/cli-commands.md | 33 + website/docs/user-guide/features/kanban.md | 167 +++ website/sidebars.ts | 1 + 14 files changed, 2923 insertions(+), 1 deletion(-) create mode 100644 docs/hermes-kanban-v1-spec.pdf create mode 100644 hermes_cli/kanban.py create mode 100644 hermes_cli/kanban_db.py create mode 100644 skills/devops/kanban-orchestrator/SKILL.md create mode 100644 skills/devops/kanban-worker/SKILL.md create mode 100644 tests/hermes_cli/test_kanban_cli.py create mode 100644 tests/hermes_cli/test_kanban_db.py create mode 100644 website/docs/user-guide/features/kanban.md diff --git a/cli.py b/cli.py index da401e5c18..f876a93398 100644 --- a/cli.py +++ b/cli.py @@ -5818,7 +5818,28 @@ class HermesCLI: print(f"(._.) Unknown cron command: {subcommand}") print(" Available: list, add, edit, pause, resume, run, remove") - + + def _handle_kanban_command(self, cmd: str): + """Handle the /kanban command — delegate to the shared kanban CLI. + + The string form passed here is the user's full ``/kanban ...`` + including the leading slash; we strip it and hand the remainder + to ``kanban.run_slash`` which returns a single formatted string. + """ + from hermes_cli.kanban import run_slash + + rest = cmd.strip() + if rest.startswith("/"): + rest = rest.lstrip("/") + if rest.startswith("kanban"): + rest = rest[len("kanban"):].lstrip() + try: + output = run_slash(rest) + except Exception as exc: # pragma: no cover - defensive + output = f"(._.) kanban error: {exc}" + if output: + print(output) + def _handle_skills_command(self, cmd: str): """Handle /skills slash command — delegates to hermes_cli.skills_hub.""" from hermes_cli.skills_hub import handle_skills_slash @@ -6055,6 +6076,8 @@ class HermesCLI: self.save_conversation() elif canonical == "cron": self._handle_cron_command(cmd_original) + elif canonical == "kanban": + self._handle_kanban_command(cmd_original) elif canonical == "skills": with self._busy_command(self._slow_command_status(cmd_original)): self._handle_skills_command(cmd_original) diff --git a/docs/hermes-kanban-v1-spec.pdf b/docs/hermes-kanban-v1-spec.pdf new file mode 100644 index 0000000000000000000000000000000000000000..c7899cd12a92e3f14e8c44e7c36f96f174982c41 GIT binary patch literal 213669 zcmd43W00)fvhUlrJ=?Zz+qP}nwmI9jG26Cg+qP}@dEb4{J$tQKYwvaUiu*>K5A{UV zsCp_g$G`G7GRMd$5_w@!8U|VxD3XJl%NHmXe0qF4LrW-bZaQTTdlNc!IYUbmBWF4# z7enViUyIr~+Wg1m&v)?|=mZ7r+_mWcxQT)OKOQ=CG6v3$7VcUMe~kSx^5<2DPSM24 z&c)Hl#0iS^j{!wGQ44El6Gu8xYXfH!VG|=eV-q@Q6I(N9b9_b?US23CXGaqQ8z}cR zC3<;#HF|mRFhe)c&mEYMJs1F1Fi=7$6Iw01ZrM8;6*l^=syMu!=C~8|Nk%Uf9^lqU*f;~-}qkxC-zVL|7%F`KllG%5#`_0 zU;J0hzr-&Bt2uVKain3YWb3MnlAo^tyK-Pf`_SgSZ4w_x>Qp#;I*YoFR{FHeuUG_ld}%pC_a# zByTlC$xdqA_FbdjL66=SJg?nWHI((29#!r)n<|~(>*3yRk8jZkUJo_jXB9fIRk#30 zhc^eBO~0iwNF#T&rjIx&-`4k&^0@DWpD0Cba$rn%=JEho+IFClq~F2xr-{m!jrIHI zGo7FA*MrDtsSCAWt98<%Slr!jcn#hTb9EZ`Z103=GXooCTMvId9cIb|_Zya|#^dRq zd`e%Fdje=G=n4`W)X}%ocf3(HktlQfKIAKVH2;MruD@|+OmBUU9GP5+mZT= z;9GV#R2aBgVyAgUU1|!7fK_yrbF~)hC+_bui}8-JCIhH8)m^Qn>>Q{u@t$S}4_h`X z6mW-4e}g4u&z`WHBCw2%3rLAuUpo}o9@2Vedz1N<0i{`(Oq?~V+$5b5#%@l!OztZ$ zLMV9#Nx3Jc&x3oKzl&Z zXvM#?6Bswvy@d9Oqqtvnd6tT5a3SC%P30xr@y0Ezo4#n(RKZ<>f0RdTGt`{gFeT1v zE+^P8cde^oIM{i|;zp;}6A@)gmSLrixK}@rR=`FzJa+h5!C$uC04Oj5+XEi? zhu_ncGUy=iai+4gZg8b!l%R#lU>zHua3=i35@j{z0r5{0-|K;$i{zL`4lFsUSkK2T zaPuH^sz6B=d5?U4S&wuhzTrXCFqSkDUDMf@F6v0+Wm<5OfCWVO2iqFJOK<~!J<@{mEv!eXyv2JrfH&9`Yt!;P)1^Y z^I_6LNEt}-J`)6exqh5NQ~qB@zp&ioLPF2xY&DJaeW>W^O!cXzp?^6d~yp%cK5rHq%hauAGZ6-&gRY}X#_ZFfjZz6$}4xk6& zrC2#oM$@$U{l#yb`{s5xhh4L3bk{CwmCVcC9u%>>J0n40gyETnUpERnwF)2BIp!N4 zfHK(Jv1nlomoRRxkM@#u^P1z9(2L$ZMx?wGfzM2=Gnv5@lj;Ga2BSm})|jej*0A-1 zcAWnLAZ9(iCTSxPzv$KOqJG!;jar-?XWLkrmD5aNrBy6nu^5JuS7Q{5mxf&*0{lio zgbS)4_f}j&VWT4tYDTElr1g&b?!`b55%ap0c4|09H~9OP$c0)y&k);VN{tJIfTm7E)W7r`XWB`_$8<&ImLRC~J)kH;E{ivV!A0wR-tj z7KsZz8pct!-R_B@awxh$->FRyMsO*XlFQY6IoIzDrL3bsz{VTWmvT>7h+sX~DV$1T)2W|1jO=I#_PK@~I`-{#hOg>bZ zz+y?{NE87(CAz#0_*5t!X{bg~FpNfL+_uKPh{dC7)oZz`RJLYH;DO5|w+>~~j;(4y z1%92(c0_(W@&&-k7y^bJJLwRaya^mwiYsY7`{=oXL~OQ3PK9nwja%g(vUVgXf#-=? znq02hka|E76_z|LqEI0yX)#W;!4^H~2Kxs7EHqY9_?+Vy>=M0Qu{nxbeTlRuxqG;! z@nGNB6a?$FMI68a$w4u`);eOt_h=yVsoa)QdpnathK6RShcOTCX;Wn(Wm*!Sxo^LK$}F(cDj-s*51EDgT-YTVgL>Vq&t z%#9K=text6Kp&GUlI~@r##I&5rSRl4(xVI=R~XA_^j-0&>M)&=tYNwIo3erm4{3{Y z8%2hJ9V2wT?H5M;+z#gU%jYF&za4Znv^5og;5a&_h&;fb*yQ@$%WnD<)@zD9(tg=O z23Og8a7DUWcSmdO(^Dp#kA!WOM=EU@qpTonUOu5CjXcvX<4mDt#siN5X;`hT4QxDeu6-Af(>-cW@aQWN{ zbiknqzH*NCkP9n*vO*EYTVwPb5gnsNvOKvq{ze2QhGwGAVO1drzMFF&<*HrKJ*2%> z#4E*p5v(@He*GE4B~I=W4sAP~GM9#6r_X35=Us<>R!R2KFE7!uhZeU-`Gor;OH4mEIO-I(EswM1={F2* zye1Gz*Dv7HyehnCa{DuGbbp7?ly`0bG$EL>}DSFe@u!w z{-zTDZ<1mTHm1KVgfFvyCvLRD`d@oMb@h@Hzv!_nhAES1rL2>77dx7-=5!guXG-bv z?eKwAjGQ@4a6MIM+sL()P$0cQ1mXk8^~g9Py@<)ek(v!$_}H7iy-@i+L3jI7*6Nk? zc>nzRU@I@72ZvUb!_&Pnx@m-y3_Tqv_2Yrg=iP@6t`mglO3vNAE6N(FT!SFs+v~{< z22kiw@@rj7qr0 zl4_sULBmQz{V!kD+u*a2>Cm^njovcf{vxge2 z@XpImbLYP}hYLnrCip?heN1)BhETtThVn7jk(q?A6Z6b)cL$PU^vd8ixGGcLz(AzW zE)s$}azQ7@8GMI4)r9w0iX#|#;t|f2C>4?S+9nRQj)14NmLv0yQC>FyJ z`!y1J%L|fj9V;|5u?kiT22z_wMuA^mL#4ob8&DcDuhfO%M{?R#eD>?bt|Md7Zz(IE z$jW)v%|szKcR(zdpKLI-*}ln+^}u^*HKM`!-L<6^;&g5;(O|nC!9kj5Qdd8!Fu0pc z`Z_2!M)|cc584#$GTL;8;1HGb#d|>A>O9}@C~LFWw@BHXxZn$u>sCwyx<`+975Uwg zSByz*oSy6ACuNH`l|zG*Odkzpx8*u1DzchnZeH>%?gT$;rT5r%p{CHG(B(4;RqsNo z`uaqxC7Bj4g*skokamNj%z5MWvj^zMdg>#+_^0T+r;xAa^qeJy)qHF83u_>|?1s`| zeOK}pctM4b!t!1T%k6mCN_C3oL#O~I8&|n9p7u5a%C8W8vdjsdXOpQE5?UJRj%4M! zKk^0ZjXPz7;WznFGx)aG=x2i(+T&(Q_L*Xli3UdHkSaTHi@O#g?{VUN`RjUwh=# zz8LL|;qD`_ur{S~ft@2|-KoV`>8>n9)VE@aEpb|HKGsXGr}Il~CbjiYfasRTGhJgt zFSf@M*(fz)kBca=V36VdS%plcc12MF=x!J)G5H-u7!K{$u8p-ttKM#Fgda6;_k}iy z02{gE{(6=BnAQpAahTY#t_yPoFhUMyOV!D;N!Dqk;2c<&${1db6?bl&t1m%>^1SND zL6Ll(L%Y$c5CKfn+=fr^q+z=4xV5}_?U)xE*HqkA3YgE)LbbB;+rT-qSk}M6m}e;t z;GDbyhm(X(C;d-;b!^dD>}O0 zg+ar!Idx__d=yL=Ik%NLj^e4oQKY%T>EC};V`=J4!QFZEW_KHI#W}flfB%@kTg99K zuO(xrFuio%mVfU%h{#(r0b%j2ae5e2;;5pT$IhTS;!VnOJ1Tn2X5{29Gy0LzDgesN z#$LG0Qn;L;@Gcmg&p)G`Q98hyQ>!tyBtjvA<-De#JYK!%X!H9b$`sLcX%3tx_5|dU z2Ema47n(ry`v-Wckoc4@Q7~mRf~c5iv*ox)9lrnKGSuV)jm(mdK-{dWg-YCY^t|oG zE9CmV!T}*Kng}dYO@^)$$|t5skAb#tji-%P5(%?JykPs02DVHbXjMJUqFpx5c*hHj z`62n~2YXi1bgfZB)V(^|t@)&36Q0>@#^ahbL=*=YCVZ!w4JH=Rh_JcB48E6m`4(I# z<{^S9Oed*L{0TTHPu3%>nZIy;14C{vFRmf&o)N*YG5`P|@SrDb{T4m_YQ3|gT_=hN z6c48TFNp$$idBIRP_xZ!s1(@agZp#!gFWt45tyC91(fQSy_%({jD^G{#(J2Aj9nfn_M%-wk3Fi0g5g#N)%_5oo0hDO!sdPf>4 zf-0RZjr~P-0inIS%~G@ypIoanHx`M5H}hrMDI6Hvx_puObgfr59_4ZlL}$DsOOd*Q zb>efB43yR@&m3Sqj*R)=$0B5JOY0$*$&u{<3h>-~ihhR)mkut%WF1Z9YXaKa<-@IZ zws1kZNiRDjLR87D>SGbcBTFofEP_7^jzrUdA6~Z3Mnhzx+CoVzkiwM{%Imv7o5D(U zW-RzkxnL8`c=8h_xQyaG2|?1P)eF zJI*3(M5U*f&*18j4waKE!K~h2yBVt{UV>hqaeVvsc#PwLVyCNz!Fw#JYX&gAg+v>^7U&wG)}D`BJ(euw z@mLnKuOlCJU>&F2B(8U(^TsFb)E34^-OEG4E>%J3HjB@T?mj+tKH0viN|kCdvZQwV zh}pyI?>B_L!hoXK)^#nzU6oFGyOU+w;X5Mi)e8q^&$1P;Cs5$*pb{=OGxLB-cySJC z!#jJapcv994;Z?@44;WF!>fmOd3?A3!>j1%4$vG&Z9_~0+1fGYd+dA$s3Gc>3u4!}ROL3ywKI3AL^yx*%d0%VBmBkHWk_jn{gXD%VU8a;=X#!ftnXCHs~_HD9M< z&f3(6kF2i+FgfZ|p1+#D@j(>czdJSWYc5LlR|SN@{*4?n)p5w+S2a9o3v|_~%0}PP z^7VS-ok0$DPr#%=_(&o}p-w&xS<!^;!Fz%&vPDD{E?_;>eCzbg5nJrOmv;haRDILWY@+uYR#+R(f-4|4e)wnD z2=MYGTO2yU(rZ!bm)}6y<%8iSsAwZ=?vJfw&U#9)%F|qwiaO2L$8N_550WI>=G$)N ziM)j`bvvU_P)obD;N|`aEeZk##M89NoiAP+^b$YLaz|@A=E>9#r3GTi)M#_6f2Vg`8C*%GNBwfqT$II~N^W)=G6&QI&n!lS zbMTp|wpD!0$}U~*BKW?%oPXApcSTimfvH=0iKg|gE3E3_sB;S(ZTF%NcZaFE@k80c zPekck$FHaZy7jy-pT%#dE7n7%1%tEnMCZvd)`03@!7PvYZETM=Qo_!-yU}~gB4I>B ze0&39>*=_&$GGP?q_#9Q?f1r~5YSffk10L_!=I;I|GU58zs~U)7?}P($JdaFBVs}5 zx~KX8H@u)+H<2pDj@Ku#g>EB&J54vHyD(_Gc`m;b^JC8@NVn1FpDiQ9ack)~d+kzd zF6<_+g!$GG$s;GmF(RzZ;d5Fi;CL3kmLk~kj0tWfKliOW-T9>ppzTk ziGZgk#W32CpEl?biu7LeFuGv!>&5_HnR@QQ^*zY>>@<=V&D?plDS49KC``-gd;mFK zVteidhifbKRMG5O_aZ{<+tTtd9KC-1%IhYFr5J`dgO}*FxHIm0tIBG@90liM`6}^M z#S;UGZf3pnyNOPRV<^kztz!PtttT{zktI#XAR)tI27}3Sox3m^m}D^Jbu4n|ks_{7 zJhVFwloQWF-BS{w8lTmS7r6Ddb4MK1sx-z^>@uX}wZR_d8vc?QE;DSzIOp{Rx(v6w zLcYO{mnzS>#o(LL<>~;mJce;1d4VnizRyzJ9?I^No=E#K)G#|WS7r$RO0!{&RWu;vjTU5r}x^-0C z9=Z_Nn?*OrCb6^dhwf@7OoVJ$MPCS;jPHv5FbHsC<(^lhvDd2PdCDv`1lXP zTf-eeKzNR9qxx;_lTg!{-`1tBP`?uowU{nk)qELKIt)5rBPBNO?9{E+LA19U~?{TMZt1Pdc-*w zI{hhG2Y>WsMSU4c*tlS$rv{+`ldLZ)hrJA}2)X7QqPE&G$seq$2v8zoaXV*`&!H8$ zrNP`D?l{}~+q98YB!-vzE@uC&6b&MMtod>LP}^6<{FkdIwcOMb*Oj=>k4)n$S*7&<+tgbT?8kb_75UFgx1n9uq?C-$M0nK^us!`{|4~vY|%2HHd1a zzXEanzmJp9=wNP zY%1xz_;nd<{tVT^5BLvUB$jOQnFub2;CMzF@MCmO*PGtQ_T4@-$X}h1V18{eH{*1S zn^Yu?t8$FBy}+GD;)8t0WjKJh6f!3d(|#XEax^Gjxc`J%|It$MFPX*6%)s%t`x0H+ z5^+W?h~39(C-6=EK7g1$5b+qJzsEKLu|*3{wG)GU#k7OZ4wLnhMP+%Lvi zl9g zuri5G(HmM54Y4MAmDU@8yxh0&&bhDW4Bw#1XeD?>H9xjKdVIYc-c1~ySyBw?d~LEK z)Nq($(S5fEo7d8g7$5HP(fM_KOrrR+fU3_fW`KOVZ0Ua8%^&U7=2}E3cdghz60By# zSJ5r$7&()~Z4OM0oPBpB*tBVC?Y1sK_N)CI1UjWeV$N(i(7g>m(eUDnt)vN#Fto8~ z6xA=XqJ%_m;{AAJqOmxA(llx+hbegRjOj&x z5v^IzwA)DWPZB~z0u3U*4|)#J?sm|ts5WySVygzdA&WT#yMD4eMnchZ$T8o|#1Yi* z*%fruoG!km*Q;t%RgxjVEEy&t;YLzVQ$)wyF!Wmg8cx;5m9o$ZOBXvQb**-RY2{fq zu4hW=J7T1tfd}`H?%|az#Cw{A^O|cV*oC?B_Hp{v6nS)7105E0DsRfVC`pb+Jq%NO1tnto;7q}Dxnp@;WG8a#V*r;FG02e|f@ZXk3NyWzSkd$#0}b<>E` ztnEDe${#im01tNhz-OCy^7$bTLz}D_sa(wckn}{(c7Md5NmaL=`^D|ZCES>kU8PCf za7h>Ez=>5f3RYj+*)kdX1VtlQ%;OTYy2g5D*>`!Y!8-XR`e1AjQ>@IzuSq~ES0BgzX?<~_ok2bq+QL%hj z5Ga@!+KRxOnU{vZomgqXyot79astX<~vH7A`&? z+F*gQ0_3dymYpuxD)cwA<$l$+$ znxOICwQaCR3ScfekA78sm-rAY5vbbh@F%R^3PvTxI2n~7ND%@)e&2{RE~8nmF4V-_sq@~b7Xga#Q9a0 za+5|Rx{GSbvnCegMkvP?l1gbn)=x7Rri>Z;nh-Gjw6RBfB2gyl?=SE3MGJ_otHXmj z6=R&{ZbKw8*V}>@f8hdCS*$*ZlP<0r*s3i9cDNz?adGq0Ub?y%3(&uFbO`>CQ(Fmo z3_<_9W(PEV3km!~I)mXFJl!8SqLyjGlPpzexZpFpb;pxl^aluoM_yAeW8E8_kOj;= zo_lw7v#=1IXOuA}MMHvlt_UBbG-__Lve@xkCiXU_Bs*nhJOnHGbtyzbPQ5U{UJe(t!h%{cNZw50s>RBdty~> zZrYR!OsO&$1+{eo{k1jEli6aH5$^E- zM{rG!V*>u{N(i?X)?pR*4lg|S9Ff)P^$}ba%qJ!~%xxq(Y(mFz59EiEYUpwB>Zo{j z2e`>?P?e_^!lQR~*o`GvA@r@^rfT*#)N9C!7PXlD`Wl^5OuO5|>(&aWD5c1Wx?&U` z?1KH|BUgJ6Fe*C;uA6{UqNctQ_3G$nr6!rK-a5lzvL2W@*D{RB`I(=rcQfwCsk$qJUD> zV1G$PuYH7QwMcc0Byow#dq9dANuUO5ZQ7QB3An(kvcOP0qQfZ`MAXFLM7;fx;>1Ok znNmuH@xpLlBI0%(-*C1H0p*Yi0-^j6?!^%3mDbw_gY$84f|R1(zI-xiel#ng%>7m{ zIHuio-$v2lZHL|L3 zB{)Zhyij?icus(z0}UvOY-|qVj(|5#vZi$(B3#L$4mFAnhZ7o;Vn(YETA0rZ9H%~e zb#!YSwcvR|&zX+P=(M*4w2L8;#Aqm_Obb~VEI)41h|WFY0kJLFih;WDP`lNIC~ z(~%-J&2?a>Ip73PxqHoV3i7`d+(!<_bHd&`KZ^yRhjgfr8X(fMoX5qM3Sbsuk!Nzt zs{g=`qhkV42lngafI5e{r5G+h&A^8~VxzLIk$(~^EyQy;vEJ5(|7ao}6^Yojx};#! z`O&%sNEI0Tan)Q+jkRAjE}tWN+ERfoA;;2;jg=`tWoOwVQi^nP0uv_FsXL58eMd9DjtE>6`vY?0OH1@*5c9Put9tgGLn+?5~|o+H2>m*r3=KF6z2|vxE^{I zG)HJHAYi7cWmakK>>iMSU8%u_0V$xARY`br8hnlR3lmE1_mr6pOkgRX^ozipP zBn)aj8l_!KB>&`>LQoM=cR+FHy@l+p)J6?2Oa!fLFgDFQ^)m-POLZ?q+F`q@KPYVz zhbE;DLWFl`4UoX`^+q5L?lMaRj3R243k~WD@aQG>*!WBdHpv52#7MIAH_*$RAtu}nT!X-$}u@Bt*Z{A#vax{u|G!s`I@~|`A>2pNS=B5*B zF`-9I=H^E?%2I|i2slHo25zVXg_7`@PTrN+P5OD3$N8zi;Ec8PrZ}8vHaV_IV2CZ& ziaU^^y8{)kt8=Atxg2c*o9VhB^2|0;D2l{5lvQITi^JK*SfDu?$=#hQogc{ zgX%_#4ASW=KY-fj)j_)M=xmb?$ozb>Vl;WuprK%$mr#7)~pmD>Z9m6FADLN;n8! z@SQ>mHG6atsf%rl%ZIWu6>ZVJ**v55OPx365wo49$0JS4fOCQ{k}uWpZO?G7_oqX8 zk+-)E%=5)Gh!(+EE9 z_ki{7CaYL7^f1j|PxkhiE9k%apxy?|XPmR7t~ zw-I=BIKp|fND4-2Jr>+~b3s;>LdC_FP`~Mor`9x1JlZtb%G_x{Bf2YgLQ#aNs{;=M zpM6$YjFeLHhH{SNDQjzBl2^O*5j4)HJO)-CWp;o#)GTr?eQIvck90H5RBc7&Pcx#( zwrK_ zE2Z0)zpJ^(&X&1ja+O{{iEk<#hvl@eJD~t=b#gkPgi8Azkc%Vh%!@?|{JL5Dv1n!G z())YF(odiJ6%!Ci7??u)k_eyWZI+|tg*cuQJ7eSQBm9#*!d{wiHq!|5w>EFkD`Ja~ zeqV)E0w?f}?E+axd8_NgDd(*YwHP?Ag#-drM@mxlS1vt$&2D^{mh?K2h}Kwb$a3by0E zan1C*6EL$k=|qCQm@^PCUm76nb0t!L!FGS7iCH8k3PXAqWoD&EhFNQ3-5kJg`vjh# z=Xm(@_un5$7@jt(20(hbn)n-nuFYQZ=Rh4&m2_{4MOz~;?G)d0rQ{B>mqHT&Vd{{w zMbX5b3$HMz)Gdr70GH%m&O9X}ETu@=;qxI^Kk>Hna7iQtJ3(i&LU0TDLVPc)3z6Pb z%dnnPF(eoDA;^AtaCJm3Ylz89Tf*6nZ);)@2zJ4KAOVZzaQ$3EZz^j_Qf`_#!rg8x zT2l0Aj(?_p=xgCIba&3@ej6Z}p`Tq^c`gdCS2gMLX|{sA82~n93DfGcb;T4RC5t5> ze%U~EWEVqE{;Z;glj=zVp7|5=F`LzDMY2+{~u0Zcd@LjwlBhjhmPIn0SS00YS$F-mMJZlHln0q_m#^wXW^ z;iG|?YMdGBPWmg_d0Z~`=jmEy63X1GoO~-dN8>4>$C@#aMe~4*>X`($*vd?{oQ7$H*3q>t>uag4%{M~#4#6>F$mK+HZw2<5f_=n(3kK`k8}T}E z^BK6XogKJiJ8MtJSKSW?zzcB}-??V%lZ7E&9PZh^jMCq9t^|Flcrxx z3^}i$5%s-cCDL{xs^!;1JCTWo3a=%WVt701#~UmIa#R8583YkIySYl(ANSW^z+?_+ z9sgt}=5IUx|LfgjCJy?)Yq;;y8nY!HLF{^`dIN9IdIv)Aq1T7Lk$KvH!7B+XqFoZ` zetG^QLrnOQuCi#26i5ssu6l@h9#u@+qjNFT`~8%-NmAOLqUhB5@q(K33H0r|=hvhC zb$5Ap+@s-FuJz|eOv|4eF=!Pnk9U`kdUV4tY%l-MM$GZ{=H;1FKnnq;kzen$no(BT zw%zyFlbbrnS%?oyrUarZQ>SAnDp3uJ1IaV3)d1AZ^!B>s2U_m1eH577f$i*GwAcD^ z?e-t0u&PN>T;1_?@~=2fvg-PF1)H;_88z(h`q6%OesC+{>s75*l$W3o_Mv{qiirC! z+oC%;7tJ)s-7t5-?Hw3jcoFUepXi>*5W#5E^oA>2h!UCTfs2_qIkiothwtmHrg zWSVd=I`4`TJ?hRk-9?^=w#H1bh_x`b09y8)@=C&uQ4lyqiQw-bsW(gTPWwo;hRo(7 z_hWcPPh{&+-RP zzSxj!>qCmr;(${NBzSlcd!F(n66tZBE-9y1Z85G>!ip#v^y~8C*~4J&-qeYp|4B+3p_d`az_;Et0E zAXY_GkrTSUnX?bm`zxg+&aJ zAp1{_;jYB1Z)h@mkA7TroV(`ce-2$r^2*bQfz4t6h-;QfsvJv>_hL`dW&C~8$aL4k zN1?aSDl%-jg8dQJJ7nAJ-;xA8VkX?QL~{s&;lQ@t^~DR`L~6^T)&zNu*3IoC42?$m zV(%-2xlkO+Q@~hE3|`D`yyltjV<)T_=?DeLr~l;ZxIC2_#64& z)=-r*Wd)T5cor6m$W{{}UIeN1)L8i_Gokg2s}7;T?+QOQAc^#~2(;{?AhGDgp|nV1 zbiwyMeAF7o^}M-M|J7TQf~(X7`#=av(nx2t?!O4>4x`1&R*zo!#m{Xm7uIn?CII+WQoF^*#Ek zo8>8%9eOBf}-9ynUI@-mGGW(ozSqis|OIcC2(L{vQHNQU@9GmfoDGZOeq z>sHD+j-Dw71W!3T&jb0eLc}juigJ$v;k3gF94qiDn;*qS4b;7Jd%DI(-vv6qJIj$0 zm0E~+wF^+>`p~(Ew}luG)gie<>IkDXc2uE(f6dKda-ztX#^Bf||G0hOzd*8#517*$ z+q?Q9QA2a5A|DcqAEpErmursiFNPi(jEgKixcd6lh3gJC1@Rs+3F&GC{D9@7hzTQYyT@iJAc=A+HNeH&N zj!j)Ac%(`=;_svEX{78TH_SFt17eeT;Z+Le7>xeaZN%YXe+Qt!ZMDq(RGCS~rW+X1 z@pyyE;pI)|W!W>&FTp54EWZ}V_*`l@t~w38$TEFa!bn9v7`e56gSD51)U&Fg1IcVz zxC>di0-dxAQS!|C-uHZJO8O@7fc&Uilb-;fGH@zn9kBcl;x+{KeIMjxsK|*!v<)cVBH5x4qGTIRQ zS})8mXxIzPI3xXmxH9qnOp1g@D@@X$|DTE$o?2BXOvMJ5YL3^+GU|<`t_8B*?MWITc-ieoZl)+3r!DESy8SI1`4)67)72A=bF+1wz_ba z+(g*RQESWt8iw1EUY47vw1%lSdvaNJDI@?#!v`-}!$`(;U%-TNJh5D!-Ms!$eha`U z-pBkfrt%)`6K!y=y*D3MDWcFLyh4f|Bk&l6C@2ho^Pp$CgG_Cjy<{HFVeXSdomka{Py1!U zql6MTq1$-Flba{bibhozsp{#&!MufP8W3~WMmpj8I!tkiTmnGT^{ivU5?X-^+Sy$* zSU-|qcz57ng1LR9xz=`mbeUjw%^EweKXgLJ=RwUgG4Hvjd}URzqN(1hau|!U2(!TH zIDd)7OTd|o(~TnUj*OmUg@?PVF}@q}^Q(K)xh!3+Et24lBF-H;<)cv@CSxmWlp&{6 zb1GitYbu3^=@4pyJxdU?&>nysQ2tg~!^QDx|ei#?1%n(wK+BAIJx!l9VhLG^1q z84t&1 zP2&CrpT~)L@nF215q{|uQS!+`(jtSTw$V64Q-pn_7-(2Ka5kRrJe51f{ z1rYgmCeIjPcOk)-cFrzmUU%rV!jmsl5%kl&l%;=y=YGk$F-y8aA=YY;q!qlkelr9k zT}3Cp*b5$zzVkOYGn9x39OoG{m^uJMU?x%6?aTgf^EnvxKqrzhrM}JirlEpr9xz`U z4~UajULSnmko*PNJFvOSnI)zqM?-Z(35L3}-GeaynEAL;Iuz%Kfw07C(3~c@bN0_8 zX9ee$SeMu6XT+~!UfhvG;ObJ2x%6VDjKnVN7Wr3DgDFi8bMs+={rt5?A}gN_5#HEjH25R(rTYP9zTyEFhk2%wBmD?WQcV2d{$Zw|v= z@Kj5)abrK;~;L zvnDF#ca(Gt#f_39FGD?(9UxcWdL!bzs^r*LPLe$qti{9|)z6laB^GfpxXdW)4XE%I zc>&E?w(lzZ45?=6=mdHP{)BoaTa4d`_t-3uv;MxuHn2m#!3)NPYEs)d@C|-OH`EwO zRYz6@QEw_teHLAv5cr`<<)mg~zi2{)d~u9^RZ12ccP*8~QD|PX0G$5RaTGeU*+@h6 z`t%R#Zq}0}yMh*E@V8J22ul6=djcKeK^R!raCIS)-$*&>6rkkJH3VYkfuiV_2QX|b z*SFW33QWkxE;CC7QYBB%V>ju+p@p4`hR)r&xe}JcYtWhvTP4v-2Jx%MVbIU%6o{GY zq;a*Nkp6dDUlhPuP9JCUM;B5zgFeI^PELOtUK)XYr6JpqFYm*I^J5(Bs3zy z8ZtPR=rA{3zS3twdtXIbgG^3!pj$r+l-I&tpi24o_j#-D$+xt)3f!kRtC43oBKIs* zXBJz10&V4N$tQ)L(;QjNXLVfOfajR!zG?j^24>1AVP}X;D1N*&iICqG6)x4IHpYdD z`?HsUb@+;-O1AIm9_iaR)lRJEJd+2izPwJpw*h|1ZWNk&s!W@cOZ%Y~^KImr$lW9T zyue8yz}a@}qmon#wA?QMw#r-TZmPI4(HW}6xe-QdA?|kBS8tvETxn|BrlEm02q&?z zza$DQEX+EFUY69RhlK+Hlg}|1$}Ktr>t=1Dt#&6e@wann?70sL#+kr8&B@?xrxKzg zYw_IRC!LquAKWTEx|^^DJ!&zj7ZVPjuNm3_6UIYF0FX^mF%SYfz1S+kk$rAiY|}Xc z9)QhmS1%1&8$!MNhCsfza5*~W`@|CotGxMVrTE|c6V-oRiZinQT~CBhJcI23J&ee6 zP9S=nq+)?MU_cmvO@OUH7pe~SvPK4hQZ3$iYG#R$jkkJ9S?M<MVx>KOR6Qho+^u$!kb9JuGbzBUju)WbRLvqc>j@g)o}jcIxJZ@ zVs7ylk3`+i&x`l?7j|NJidXRaP5#yGnK>~)``zPUdyAB-9S#*GyUWT@i4!3*X5J`Egh^|n14 z)E|p3O{M4DtfvHERJ^u}zPDAE9OgOmJC0zrS;}IDXn0euZ}5*fkOT^my%}h? zNzmurUfOeJTa1t7w58Ixrj~vw>m_BOE-Wf9@2sKmooWG!fC*o`uK?kxW^c-Wi--*a z^sQWoKYW^YW^k|8qN$k{76DpnMaqWEuZF_%2UVg4l1;(#QP9-0o{209F@Y}r!)Y=BKqeZXNli5_eISkh+O};?+tZk~ZQHhO z+qP}q@5FsMapS)cf5d*+4;333xmK>q%F41V>GW!%&1YfI?$)2_Lw?uImv`P;U{CM% z@X!^Ixq~j)DeuG_s^5-xY7a`c)tkWu_g#AIHl1_2Jf-1p?8Ot!!DwoCUn{Q%wwzyS zeX>bwaM%t`oF;O+l7hdW({NI;a`G}9rPR^%IjODu4RP@Ds z6J0u$TcIPtF}$)W@kA54RmI(#^<2{UK5YC;ik4~)d@8rSim7|XawaVwoM@3WgOFx>vy>Tqh!d=)jq$B#USQZ{ix;t|wOOzz)d3hT2)5WY@wq7s({ncLwVaTKwgB_PHJOCVrBf zjQDI+)~j-{Tdx?iU68Z1eus^`s(rBZglb&X!CosxB4v5w1YhJYG1i!C8NDb?1R}#F zMUQ_P#X9Sjr73eykS>SAbGku;KU^{?(>+jBrDWc>zRy#}j|o|DZIuHuPK@HLxN$Js zfx0GWk8hd!_e(q%8Z?*zK|7_A4mCW>pY>}6Fi02o9Vo-@@niU2{&_)dFOCOZN@XWDc@NPco#fA$=Jyf8Bp@s|#PEwUhF$`_ zkXHQt-!1#fua8dZZ_%T#EL?w2-gEi^NnVGDSa;U=lIl2%XRT#)}Py zJ(!d{p(xJX2)&SLKDz_BnU_NEKZt~~yC@u!O-O9w{D8oeM;#&-d zbvlp-MMyr@XCztK5|l)+dq>f_F2p_Gvx-MKop$n_ScHxw!+M(6YG-ALQNZ8A~o)n0t$g5I3izWgzAmFabR! zyJ=1(Vk2~kT%VI;u(9Dm67p$q(JLBC9Nvi`;k)<;AIZfTST`IU!dUcj9m4nuc6k^Z zr>yXGb&1Q z7GS8t)^9BPIlf&~bZA~ucXp@I@`PX-_X4rxlAtz|*ei3A9w6X$!nZu`1pZ5#jrX1l zQr;Rjvj1*uf32OE25(Yv?-6DT;g^@K2V(LX3_|a19CpEwTD%u@>I$v+6siCh9P|eF zS7d>u2WF6}x44g<6Va^IXbsN{A6HIQfg4HM{QGcPIF0ui0hKy#=ZzD5YWQrem|d4O zeAM$iOTNQ%y^%Se0Gwb)4C-|<4<05%^~QVs$J>a4@vR`N??P^$d>|F7)yQMWy;?SI zg|%p3Y1eL52hFjAm_a3a;MFY$d2v+Ept7>`<_Of&BNw9cMkquW_B}C~5Gsh;D_VR` z--UEd!V&HV1g{Ra=E3E_SwrSf6FQh))#Np*dbNDVL7QsQp1~j0>+$XaowS2-g2AQm zk%%0S-Mi9k>Vgf{bPP}HyH6bxNU#Wr0lP2n8Q~Bu8?GvsCoVoEkUgMWZ?M6Loq!EN z@s5f<`jf3IzKZ>ZMGz~RD-Po{=q zTyjBeKZn#vy_Dr!&X0f$VEg6;k+eNNvDPm~r*D2N~avA-WC-uM?SpKYnYO*{IoAJ4}pU z`<8>XKRGRU-dLIP@MfQb!GWg$ZLt1cg|9vwn-CQycE-S|;ynLa*~tSN7v^X8xGN0>R*|p62L?tCn95^yLiAdL{Vl z;Q*K6IT#ivJx#23e{Fwk!x{lQ^z!*-q*`_KdLKJ&J^@}^mK zZ)-0{nbK8_Kq%&oMeu27D=U-2d^uORorXkdb6QC~&Y+UT-&zAdX@M%CT0f1LUc{LG zJjVtRYe#g852wLBf}|Qu3IUqroo#@{SF{^3jb{LREkWEUgk3%(h_y+2%w@=B zUsL%TU=Xl({8t%41C&lD&~j))NMHYxQy{S-xMc(U3v=khqo_R|^k@~Ec1ODE0>_~0 zPCdyk5j9EGVLYXEKV$Y}i(AC3w~-4O{7p^M&z64|2@}^JD(ONA^_{YHoZBsBgLDen zYCpcpsTzLl7$~+#?#DW!?~VSLPZ;nRk`ef~sAsUU#1~^$7U;MXu|X^cofX^-0i3I0SWx#rU6-IQW!9BD#;p5mxfxPA`!(rygjLA{}dJmcrJ4&EwqoracIZu-titd zBD-;~ut9ilER^m-M4J0PMZA4rpDbeuZi#V!cM~)(b5qUVDEexh&RASfa^>c6<;XR# zyk9+@mLNBfQU;)*n412TVq-8iF3_4p&O6>YvyL8Ku;n72FN`tyo3|4Jw~wUW&yvTB zRGI-M!jYs9;5@2WQ0hq0-xTn%Q22j)v3Xc8l66p8kA`rpsvIiR z%WDQk{E9DBs$QP6&-0aDLd};+mwsAkZZsJ~+gZqR^&I|dX*r&p|McnrA&I zsPOL+5tkDPRuWST)kI~qs1iyQES0})|D1Z9DsADY40v4-DG}ApK!8(#hU1<3`0k)G zn|jLwC}5&+KS)08#f^A7tEqhSA>m+92S89k*(?*nXuy{5OmwNW$g} z&0SuQ_gbU#^`aUqf+VwSybMc=9><-x2^TDxd0UbisJ3?l@fJEr zn}UkYZyj7@HX^qv_vLzQzJx#W(<8Xm1odszrbahfrg5el=xaXZobfst3~V)c-f16! z=qG+(8?xxvM=FIL782RRNtPb3Mn4%0g6cXwN)iq$;rZ@O%P+bD zGMUfM%T&PQ2-xg%blIBzZ7NE1`=tcJ)w|yo765@B&x|GV!d;dOFKb+qV(wk zMFyUYKk4@qe_E~>A*Oe~Me=p}dbr9)tX`r;0FDWDf*gpf8oPSm^?;%VvyBsOHl9DE z#&xNk7|K6XghOr>G9TVE-BD_+i{9YHeaGEpQfWfYoOv5aY>#BYpeA*%x z;!D`9+F1guyHd++@>&Mlyf%!+ihXXimn$xis3qCDPPdSZnRShbRjJ zX-mTGBx#0A@1WW|cw;eLH{SjcaC>Vc0w@Avj__`@g^Bg&Ap>Ufb9VL6=lstC5U;@b;gKY4{TEin0?`agV9 z8B@v)_m*ome^g5qAo##AW>6bz9FZ$3Ei|73G)~;|iI`1gVmUk#*a#&qS;5Rdw9L9* z#xSbxRFc4cnqRDk{7k87h zS6e~e+T%)tbS}cf=G_>{qE%pYeU2we9KP%fjAIQF1$u(4t;!%U4g6TxLW{gH)l84= zT~g#)6DPX)JSyyh8!V>mv0y>paZ(&j0l4&$^SC>MQlHl&9P+o@7oIn==vbYFhl*Qh z5)9l%lGfJp6Ve|GF#!8a5z}+|+YBqQC8kp0zDbx0T^0xeT-X3QoxsO+Z_u3%3GNmL zL7p9H)~ZQw_)gz?lGObRlchcO{Es?MiJ@Ut@n&;izIK?#V1!o=xpN~}6OKPLxi?v# z`l%%Rq{;`aK<{m?czW==kmkHaqKKj;oh~0$ER`?3yx1nrfj^}~{kaM)L{;iF)k~Ez zZDWfaDeRx8Os$V-tR{5_m$NU$CXQk>i@H~u2?=#QyGWLGxKq?2PjQZ=8J|9}L=P!Z z1XAmA>YrNPkZ@+J)I=-M>=lb2ezsTNlngw2f#hi@u;sMHou)~&-DdQJaH=Yus+=zv zt=M=9M8tGd`mf^`H3K`RU#zU5cKC>c&s>e=GkycY`7yoWf5K65kc3%JbFmo75YgA- zLoV=;FS##X^DjR*Z)=egiwKwR1PS1QyMIASp2A^{x8I<&d;d%Js&AFpQ2pk()5Q<3 z6T3>Q5aF@TyMicd*Flf_GXjNuEXij1(PLW0A3a1#&gAR%h6^cjchH0D%$+MsNiZks zzbPz09}xr@L41I^BR-f+Okzr56(M|q0@WmN;HhNMSb}4|-d#Uy`~Wbd4b zKd&H{Kupy)x8(Bmh@xtb0BkKJz4?!(sKhW|>YqY*YZDh#wEO-9uO0ceC)UP%yK{_n zrwa4TAF0>yM|t`cxatGc^&&RXa_d&uL+D$NDXRPQ^zG}+jdT@@>tPo<4)u8yETMFxJE&b*x`tH5eOU$@X%(6_%V2-g zuO0=o?3GF*j7)a&5`Fu7H;*$komdH|Bgo~8^fhNHuTAM7(4_V)4AxTwVzy>SK#>tX zO?R1VrbIy3#Y4qoPYKu{m#wo+57IVng<9!^5T$y7fhbQZNb^nVVs zJnLCRXN}h->qY;TW#gbJxRnmEdOjXrK_xmKLM5sqUm7}Ei^&tY&^@!?FCY{h zQ682k+CVMwaOOZvVGrF-GO<^(;DnXGNFjXNpXoBaAn6J>xv^iOQ1ZP^{B*7^))MHv z3(1uY?a+0hd*1qpb~>YbL{1C4z!U0rDq~{V4phG4+%Q(h+oC$`py^8JtD~l>a=v9M z4*Ij@`~g(eNIjy^Lzm2;?G9Dy082KHoVJEmd&&q{9gT2 z^F{FnL<%E!YO!@)Zzi$*jT0?G5pzq^920fG>NJ*;Vzbw;h&|ajmX5GL{q^Tb_D;NX z^>)Ctz_VSEdWST6#B!8U7{YN3V7$kvg?L9#d&lUIvlPh7h#_{T^msh$qRv&)U^Bin>Ue=^ac9%{J4f`T2UM+8I(%$BUq~IpR{QaLLR#4x zCyv}<4Qv5$i9T3Z_1$H*Tz~a#w5lYE<0|3}M_{#|RI*0T#hi3jFOh|FLzAoQC8IUn z{WZP7CgV@XahA;`jm{AUeh*MG$~&gQl8KHHd&FJj&31$HcH^s&xSnzi92gcA=vK8> zBQPvEJkx_7q#aQt(JKFqU-QOdk$lcTH+q|w^ zD)HkY>v!dj6kt~?H!{s*e}u)wl6sVU*8GQbw~|;naE(pm%CJxQy~jtAd3AjpZbU|v z$05%f)b9o#M^=O?N2(hgsStPWyB+Y8h!|!(aNd%a~60!XIA_ZHER5)FEe$A3FD2;wSNlEV70HnA6>l`N3`^ zBH&Vw<>!^)v?!8)X?|1qOP9D#*IN(|b0rgdu3X_!jaFhn=DLCbH9he-H5YJEfv?AP z+~nVd2Nie=nI%1{#Rj{?rwo_uO@WtW4?w@c3}{fE-f4OS^CVu>s0SnwNHv^b1RvPF zDf}H(2e&z5SA!HAj(ZA6Yw@WWoxLa_5=Tk;LdGoJ6HDsUh|Ka>C*Yu&WotT!NFLz^ zi{*aqb47c7lvCe%M=qoLjCvXRmuzNR~z zlVymwSgh!O^MllQd@tP5&MjNpUHgv`glca7>$X)yl11FP{f>!TM#SyV7Z=3Y|=CJ0FW< z+E*-hr(*QiW45th7&8D7f8u=#N!k{_|f$qkflrzjJ@@0<3hn~2RG+h+}h4m)m} z)4!!8z1&R?1-=j~5Vpeqhm0%xf1P9S|1YKBU}9zZ@BR`;y3#TDJb$)N)H4Nk!?zK4 z`y+tHfYxLk-Gne&wyxJqFq}BvKJrvVlL#8Mb&Hnc;;>g+DwRc*5Pb^C!aY9^`Uv5^ zX9(4JEAKL#w$DdedPLTCc4zdX1$@0eCvIYVzd3#p`aFnXJ-vRxhX-vWrfdrM_r6BLec3Y$NSBp0!V6TR}=dB zQcZCfHtm`3{qTN2+^sBv5G83kcjFZD0m{(ZGOWyI&cM6{4V_}SOYpiME6yy|a*jbw`~n&NDj zP{I6ui{nuA?DnW?a}e*4=&{7YqG*DJI^7?YxN-^sb?$5&UJZ`h>jl#iS@Z4q$Ikl4Q>*3*UB|2iP%IIFxh%oH~Fpvc`|-AGhQ4%sWm zQxTPpOIki?N?CggLbx(13;~o%eL$*eqWwwOKBG!=(W8wOveDtT6s%W)K+&2?<2xMh z;XVhobBDhI*SAC(2B~PM{4VzE;4u8@)(LQe*qH;PElx z424&i7~aeE^9I^t5c@N!jU3cpPj*T?PZ>Jz>_Z{WL&Q%pqI&){Ut*YeN;B&^t64;V zx4kee@csGi{!utQ@u8RopPfkMbx)VInzEMr%fu3W*UHx?bs%JF0^#f(_}m5#$ivSW z)K#vI(Wtk@ke|5y_22@tU{|OIA2FT~@e`bYq`KpwWP&{gMXD^y3%98$k;V~?Dge$g zyx{j*K_NOtJy1nXL#>(eGSx=??dbl7&@34S1ud{Nrj~e4vI|17W)qWrzfH8IWv9$w zqf9hL*dJpp%qQ5?!>WpHzyzc;v`a zaNVdr^`3P3ju-6oRTf9e?-!UwF~f?icI7;+>KTT&H^KStd>bmOMA?ak??tanM(6$g z1J_?hDU!(|V6{4c_Ql%LuFjmitnfUV5)~X{27&CtQVzQ8@d>cTAbvIYiGNrrL19sr zN1Nps0=PU761Y-T;Hnm|*2qvZ3=-qdR_dyN4$PhUrIzf&ucdFtCSMMO_5vDDTe@;7 zUu0&9w!lA&Iw_$Utjc>- zM(5u-K|hQ55d#M9jVCBnOHj508u_|#`bx-0|(*cDUhO_gTnOKTdJqQs=Daf{3?u6kBY3rC0V3(ueB(k)1nW!8H`^! zApW(MwsR`mI_3mSY*@*Cb5?FynZ6cvRY!Cies7F#9M;VhgQG%fysNK<%BIwGKS-|J z{IZ_#>9cyd)rnTk=m;%HfzzfFyUf1T?C5>SklL1T3*uURD%<}l%jR6fSmlCaaK^3K zX?)%p9!|so+J{?O1x;2Ezy3+w7yY*^Pc;R=EjHjK3?4ND!QHCY+E} zQAJH(sxONZqeR*<}$*)uue!+XRxml_{^yM%#u)9J&1(fk2SsG`JEtt0T0d_ z*LkHXBxdyi`|Et~ZcbxVgdkT1^-T|!kzWqGS@n35Y@(KrjIj94{A#C)|>F_<5XYh=eGy=;|xzCGmO(* zPi!#ICGzRcgmL`?RGr^0GX!TcQXgIG!`m@?S6so{DjPT_JcOO&1`P3|hFt9hB4m9a zS@}eCmRFe9+ngUvWeYDyZLs73c1W%RE(w!B$G*L@3F!H|IGg;pP@Vd{iWaS( z1)77~TdC9*tFq5P7+BzKl0bEogG-%h^H#Xfh?jf%6;Rxmu;qz2`ApmkERs^#6RNa~ zwCOo&sJ+?Em#FqpeTS&nTbOLc<+Q{e))l7lAYz>~WFJMsi0Uscd$UC23ln?Sg)3O+q`(v4;6Ogh9%%AJ_hzB{htGjsOQsMki@o2pxv$%y z#?kT4i~WTf$X*2IAFFL4=~Y4ep^(`p;*Sof#xSbD#hha1MrYLGuzoLjjUn&oWTNe~ zM3&15VBOQ;^E$~GA7Z-}m?1d>R79$SitszqIVA7)0z^ipb%geRC|^G*W3CGZ4p0%Y ztknmBt+3gdeEWJs>Vq(%yr_aclLiP9qwjoOqU=*sOE@|b`!rJR#d0wmAODe~GcR*) zvxj(88AF)D5SRo60oBIIeRQA8F>kUDD~f*h_anKclfU>OGpD-ZiASaR3un^bBqDr>hdw&xY1)+0E3=>;y zw=`2VK&!JU9m_Z9z!{=;`dO<4rP*ge&*xuycV3hDg4d$%p(F9!$byWX2)h!?L^O~x zcEpGhS`6??^xw_%#uf-3qx!5Z2;tIfhvNzI9E(Ik9obWyI8dA*%x)9D-YLVblbQ8d z>}P8(*?WVSiGHed4py?Fnfa?xKm)VAC|1OLqpwOOs{2)Sicqs=L}&-Gf-Oe^Rm&0F z5Mj0`;v1lh!Ve;tTo;eHfX9R&@mBM_8teAem^B_;~8m0Y^(N$P6!A_nJ zXGEL%2PKh=HY(+6;t-;AORa`j_bMaW(+;3-x2#6g0u&k9i71V!u&(WAg!!4 zSrBo!7@vV2I?@vC=8kXc^QZ<~c_(cgMfS0T3DEiAVzz(#jj9j^G}2lN)8{SJgM7aY zoQ2Ez4X{vPRzS{g0yHI&^9@riG_e&&1dC$pSj-^YrofL`lk5V(8;L(SH=e$`nscEo zG!~u>=i1M%PHbuZ5gH_7{;tAUR}I&kFHCu7fgI`5MIP;h7YUs|>_awL!&V+QON3^d zzC}rB5xrCPCixL~1e0mu zWQvR!Z|Q^Ij_`|?-!8w?eIi1$$ph9Bio+#vW@D^i;^e4yg$UjL!zQQ2n`?LX z+ws-|`~!Sn0B&=!JZb}ua!}+i>RFg+-HBxU?oZbh(MUGmiQ7sK1WC@( zG6HB!eci`6ki5Sg8{w;SA0i;^%^*6h@`vC!H=|0liH|ly>Om2tdiA99zFy%j*>#Y` zYn7fB9q0)QF)+ou8l_)}{Fpx>Epjs&)!U(dyvt@d5n_m3fWBt?27$DRqOj;P1*2Ky z4bC7jOVp(ci4F;>w11Cf51SWPBuWaua=hpk@xQC<6ak1@o%%*$JRtpo27MlBdkRXu zEM=qtg&JyAJ)nv{xuzT|dE*8xrA99Y-i4Uh|2Y~-d;Q^7ko+07#M3H9oBobADm3ji zNmAHv+WYgoz!$s+xp|Ya!P^JNe8J}F5T43HYN0rt_ zEWnPSh0VH+?-xhpwp5TvsC`G<37CA_U?N)em3^SS;eI40s-+ApmNba)VEo?3G){G` zG2}8^fbT2U?^dR)2|}X1cj+s}g~xt{)s^ezLT6UXmg3FAx;J%|>T*f`^tFS>2sD_I zrHr!z(|DxlC2zti00j`zE9&)$Pw*rU7|ko* zDAY7@IcAsy8z-Bs^PP4sPO7Y=rKd>>mo9iuT^9I?vH(1TmE}f3%J9U>j2J#ohLp7- zVZjjG7riLD|wSRoiWeQC^CVwcax z+Inbz^q*1dmqgyi_efj;uikF8y;cq5wcY_v@7==e0T9jQ)2gnEbRCKGKjFZ(03^Rq-DfB8qWZAfxR(G`VT;L17$_0WlyW%9s};M*~xizejnFViml&DYkMi z8@!Uz?aaT3MO1tOAvK|=(Pb58nPwBW5g%`_aHKjyyw}4JBkLD7V z)R{3zgPgl-t?hZbB(^e0(!st}Kq$V!fRi488>&ZCddbpafG3N6k3lJRNHJv)QcsXF zp;Obyz{a;ACjp)h#GQYJcIazVA zMe~0)+WtJF{B-;i1X;tqHX7LUO&q*4y@19+189Fy<7!RBpJd;8Z@K506 zC@o*rITlY#s~=V}$cq;rKGjPuWNKU@yFODRyUt&IRFkU}&vBsA0<7ZK5t9V4ih(J> zDr(30QbMOXm2`!~yS89zuJ^B&N+$}W=oC<~P1E+UC)d%cu{H<-WXS_-@Y7E);Y&Cz z$&#F)z!pc^z$>dOQR*3%nDJ6<^zII0G==YO>k3(p>uq*zebN`M?Pr`(!O9%co@GVj z@tMpV@>(k|AJNSWmxA+^X|6;7liqx|<^oK^6H8TN0C|s4G&!KdqaYz7_yWZdoh&yV2~gkk2BYC!(I$tV>5mdn@|{`fan#bzhz z*FR?Xt}wwgY2n-r+uX}SUtlWvaabVJxjZx;@mTl`E%Ye*w->~FRZc~gAWPsfs>58^GNV9l4-9k*<_aqN5K~kyVsYT zV-+1B4+rTd`W9dj!5C^-WW+}oyLh7Z)U_&V$nf#=HrR?K8hF`uFP*TZCH)D!%-tbr zXasAP2WFloX=H)8E<2WQLpc(9)Uu2=B~%;U&*^Z*#pzJ`U3I;Wd%ua2by|Rj;K*PjOEtLx62qTMGs8Yt%AvYrZhNviwd}t!Eu&x^xn;j>ToG6g^ zeRcu0-gW53Hx%A>>a7>gtfY2VKQks#CIcr}OU_(e$Bv2(fDdO!Oe6q4M8*L4FazKN ze5_*vfKRUt7_;mBX?RKy&<1=wKJ)k6T|Ioo(!QxRa7sjqt=6qir;Y6Wk922cy~D=> zT1!w)I@*P}Ufzf_EZ zs?ln*Elg2wZ&fE6rWzNR01~HvvMuA7ZwN}+AZbO6SU9qi9%sXn*r+t+~2>g|@ zxc*C&`gc;{pz4DC3Mqetr<%6mz=SM~E^8k$g}og2G;*wp?FPhw2NPMU-3;Cin}OaT zFls{0;^hYuqKpO5& zH&p_NmkG~MlgGokiro^ziKO*hYZ;&tbu=fd)9=HIFRI^KjGDp@tP+N)lK_`l>p0yN z4NGAAc|=x@Q*K>gtffyli(1y;H=u+Fp8p>>6Rd*lfHOs@Sv-=2JE02TeZWfqDXK8V zli0uBma8QpvbzhVaCJC`PKua<3Dhk`@0*47rgeB^bchRVK0K;CnGz8Pxj{G(EQKa_ z;7I`kNIuMZ5C;7x`LG9g5ZW|PBFIS_m5zi6&}3pa{@htIYt4V4PK$g~wyE*~4=uiQ)Q~&orw{^FO0E zS1SKAniep+0YD~bf2z#@!g-ugxPjXv624{yXMKk;ZyBbhW+;3C=^ud`T+NS9qJ)l2 zb3I4rHq-$W0Wp*w9%}Wg!O|U)n;Y0Q&|Vjt7qkz0f<_5Sn(tEgU!NdEL;2Bt(_}B` z`M7*!kxvZ*I;NVF2@#4g`zs_kg)+sALoO5NFy zu||T2()e&B4~P6Z9nNf2GaTkh)lDq$xDfkUZ>#wd`(x8ZYoPd2sHuXc#n6*v#Fxw7 zr~ru<4h@L3jQ;?UGufdU8UW17Whm6uG2>cj*4ViyuWC$|e@Pm~vP7B8NMMMaO2p}c z!4!u27tQ{J>?-zjkZRv1(q+7n zC$lD;tg1u)wwufkZ=z*qaNBQ=tR%%bfPI@X`Yc(H2bT83g> zsXL!}sJKcV?Ha}bSU^h>>g;BwN**#;PcnVYw4^u{Tmd_no7PXAT4kSW8lQPOSvfkvGqeh`s@m>|72 z;-lkl3vDh6CRJxS^BZq~AllhehYCD3mV~y7xFBUsTwRTt=ZKREXY)>bwJgw~!{p6P zgY*^QnSY>4u*9^#{=MQkY8Ih3`3OHj;4Rv-#HNqX*Mr1KO$246VtEFALTqB3H(+=7 z;1mp$knt}!Oi5#pLJKQQ`_JG2A&eBEqB2XTmp@vYH-&}Fxx}Ci1$GD9Bjw`0z zxOW&u^q;y8Ps3XXmksgr@8Cuua^*oXBIugKz=>uTjZDKcESXoI6p7IX&5m4Drm!=) zvU0{t*MW3WPAmxt9u&XwnQlQ2D5!6+!;tEb$`?!75yPxpe51vc8LN(-x)!U~ln?j~ z7hi$K2Hx*0AD#`qM%hx`%A$>*z)&{wf|XCl=V+@R!0kO zsRe0+8c}0)q6$75rZp2ZU z@ftpO>SzoP@%hZBm{7RX!j@%1Y1Z-FkQ`^mQPpBCL39w{5wx~4)GnV?M7xkxYHJW` z_e&(qr4MRWr}xy~{Q0!~_3`}k9E$~`{$QS&zmkAWitUDb*1}@Mn`*ogMz7uwo;{)`z?ZY|mQ?e+;8^>PfgL-U6g zS`5U3a;AKK{au1j|{*Qnm-Qnvc+G zihfPO%hvFIoapHh0Q!D0k361vd3t!b-}*Qr{FyhCw7x&Qy8lKt2(OS8D>?ca2*E9y zr2H!ZI54{2?TKS6TPC#CI!o!DU$H;CTS-#!+KKg1>Ok!H!Be;OMo>0e8%Mf>$lD!_{ z?#a=}(Uz0N^C2ZH8)ntYVdisP>_Z`XwK1i6zZePoV%$$Xcr62JC*p=n=P+dw=$_rr zZ1j|>BXixG;6)rZ1--!7U`fZP^FVFA^anwuh2S<;rKX%(O*DucCfwUcJmJ&~h*v`X zKp*3)?sv*f%{Wdb#51(xVHS=ph#h{92#nMNk_~n2!HALyyRWFDOvFlBU_TCsvJ&d* zKoL;3rkvNQdGIhBM86}xXMQ7u-PnEHZ#%)iz#tIY8eN+VAfD&DGc4{hv&mdxE;z!V zt_-mPlDvq+gmg}RNHeV>-wj~TeLPZ^)WK^$X>L?hpIf_u%7#VnNoglrst`PQg~^1; zhyr^Tzz5wUC!vP&(Bo77oMuhoRAygm9!*dhnTyK=|7Z;8M&B_`RFg1&m3MY_`1Rfe zZ!ZZX(b@gxW=)i?S6mIfgXL-(JPY zS!T=}Hq`4G4=YOm_KyT#0fM}u{@!LnB301Ik31cOX5_?lkcNi_V-G3gFKRvVR(ial zX3-K(O1B`p3KN5kmIkZ;&+_kpP&K?t*aQoU8+A;!hSo#g8#P?jS%1pTp@2EqA{xQ? z8*b-#L}&ukMpLj5w?MOrxw;%#$h4$UYH9_r>!tJ=VJt-8gyn(&$_J)gI2qL98UI}X zNvnW6N7`LPnm#|$?UT5@Qw#>>>v`Y4v*}dto2p{xagdSjC#z9E-#FH61JZq%@?R%a zbc;QA8YsWBs#bvHkFEWJ)YyTY;&KF$&$miznG6u>{A9z}Ato!>%(NMo4JpKCk;tX+ z**9tsvai%3VYQbqP;#T^O}d96_-A(8RqNzRMv-ORFe;6oAm~yd{3*pNgtiZ1f1_{_ z;%S8i3QLY>a&j4e*>;<8#1iZzRt^`67-%G8;D27MwK*kdU#a8zyCi(E?2ejL!X$hJ zoOFp9{|5VqhD8F!Uu%d8A(5VlkTsbD76W}w)9>oyOmV?spHrE$WavUnW=UHmcC8?$ zj87C>$rxq;8f9qvhv_NWU$pb^csp>21sH=tD?zVs|LlWARBtOek`nB^jx$`y8+;Fi z*GCTx&M(`4FT_!}SCA-{X?lfoijV)Y^+TAvT-Lm#t2 z?4qg)_FnBTjS&`C9_*C0(0IE~mp9IfFEEEe2(Jz$jqHP3^sY&DH8zdho3L|t{KF$%^PB_~3yk?6%)>Tz<>1$Yzl0$mw^Pa+YT*5k6!|8Fnr@)r&x{xFw`1)I8sb6}d4pH@JjS=zLPx8rDc zn>Tn#rzw6}cwB{|fdtZiqa*AMmBFGq%WwM)=PUCdFe{h)-E_shW3o31K?HDGmi z&)J~K<+du-`-8_qU3!@nrmbd+eOWVF|N4>hZfvDHrf8xhIkau_Z!vNi!@<_J<+dP$ z%#QzK6lsQ})NlUlYHZ^#x*aJSL)bmUx)Uphaw7KY+Oi-pLwO+&fhbOnm)dTT$kJkP zq>Z}qQwPDu<&@hA;ysl|wnB%^F(ue>StT3e9<5KbEqiq1N_$)YKNGgW*BPt|A(=2Y|b=nwsvgWoY=OliEZ1w z!-+9*a>ur9XM%}s+cqZ2o9El!RZrEs|3H7}s_X3PzSdetplJGmW5CDzuFfHtj=n&( zXmgUVne=QL#OXOYjswpfAh-2H+=VGU_cSLn35nWO9tZ-T-wgLR4GVJkUnE)_to68E zxbA8K0yg!{s%7E@$&_GP=6wy)Xcg;o?O#`XEukR*(651mO?bAUfb{BiqMQWTyvzB% zJdM)qQ+VXg`haQ-a0_gwX;_G>W^?Olz72`GC;?QQLsv5R{>m%x`K)Ob&uRTY$mwM? zzz1^;50|r!pjI17-)c7oZ4al#$<)PCYlF37 z?av$k2ngw6kW@mPoR3Y2HrJ>lmbxEyR>x}#_G}+5-a%4Cm?twxbG|kTSPR(8v7qPgo4?q@sdzB!!TF@d@ToKy*g=m9UhYztU4c*ce7o1bu|w*txlijdGrQa zWF>4lt}UTcoB5oy3n^sEu$BCXo8;Ajng!l75|4UY4yHDmT$a{-`~v-8)BHXcLUL;s z)u#9q>upOb-iJz=LB4{cwY23-##gT8a$Ant&DW~1S5*`A4~{;E`LT|iqc;^r&28x>BI8*j=9}mdjSZ&ey526Y;3Jghad!p{pNK1o$6r)ZX9&B-fbb z(vt+279^do-33g>pD#sZ3tz(zuTZx+ILykm2eTdl7i?qPUFI-%+4g08KZ+>HTxyc_ zza!bXs2I;ycHMzMzSM`0wcy6eX^mF`lda?~+`&C1iewPT(lja_#9hFhyfjI)?cjnG=u~|D{3h8OVLVD-G0zsLVt42NnBy+$S_Jrz#HNqn-tXOEe*J-n5I*c&9&Evj?P$Sh^{ecVm4Qr`>xaj*So z*Qc7H){&k>!a-B>6dA7bV*N^GTXl1t@ehirtF$A^y-B@snvKU0Xg#DfEJagDq@gwuhY&;ck^=&_{xWh7R;Lk9g8<>s%n*{>PXKvPdUW8 zpOws*vfbt@(A~4x`T`Q_3)okySsrX`DaYni!A%5$jb5LTC{ zT8lpM)GOoOHLa8h=+hZy9$G+1qP3jJ`Gdn=vRPx>;`9TS;gh8Pg`_ULcC)&fWQ%^* z5{WKH5I7ZGW?g^Y1=w5ES^l@>_Wu-s#m33a`ahT3A>B>~`gYXG56t}uq=oTka1;!j zI&7zwr%428o5^g2u72Lz>&~blvfp-3R!wxmoK2o@A`Q}5)8(3m{@o|PgTBt?*i&)t zQdD9;@1Ec{-f=(us{(`!|C8`Nu-(*s!0;VAaJY`>klEC3=icMn`FXBQ^G^5~ts+8m z`1H2k#lM=iQ+_Xd%JuSGkzD`p{cwBx6G^~lwSLk@wST~>;)x(%Doy}!F}l&_cmn!) zVc=b%cw6JiWRNd@G-PX6pX&Vic6oPh&c;)0#`rY=+s5!#_Hmf{``(*v7JAe1^Z0Ih zT+tppg+XTAgXlehD%goZ&o)GxM2J!eDuD?yD!qeXVJ# zPX8X{2s1@~fQ<5Opqd2>3u76HcqevmGTwSXM)DY+r=)4_#($u>FsYK>M5cYdb5F91MsxFPDedy0594oOq(c!vQ%oIJW9 zY+U|WdoK@Br!P!VKP_zGC2kQIr~G2vJ;T1u*rV*V<(@39fl4CcBOSt z&6t1Vx$Y!q@FSMNAV z!L4xZ>5n(G#rV)Pkyq=Ka5L61TbxH#7U&f&xwGZW`4;0Hb7nWyruQH?9%(w$(bRI{eo3`Mc)!6lbKw_yM0f|*+Vm6VC((-qJPnG&Bp1Ag;2R}*)>gwa zFY~uYpcdC0&!d1KR6vk^+y;UKTI&S`862QX14pWSp4~qimTH&F_sGKmG7g9H0TZn# zEWZVS76O?{YF)igi;6oOPjZ#W#zZA9Tg8 z)W(4OEKzsTW_nC#UC;`p&KrVow1Yk7uVO4Zot!a!Vp)Y7iqr42C|Sih5-+Iktq$na z2&Y8qME0I5s7)5I+iTAe1<_{9)z~IEpUdBA>QqkARdWsnOLYO9%~Ry0tzjP{)n41E z_zAUSkNIf(ZAV!B=%=Q@X;-ACvZw0xbE#+*;Ns{(!kxxcw)4#XOw_Y=URh;t- zSvxHhaOR~Z?#(cnR2rnA*5w)7IS6n+Y+2fTlnQ+U1R~a5*xPy5HE_D3!xpXd5J36T zoJxss$R1e=P8k#2#(yvg2D15wgN#~g`^Z>`xIYLg()T=xARFO5lAHYvNu3Pbqb;R_ zvB5dsFqQNGUvn8ESq&nra4DffsVJ?ZzsYwL35s@uK~2qIVB>p+kdc*t zmUZ-u7HbW~hM>SyqRie8iyu;OX$XHl1QxkCfh`Ka#$;7nEf&9!QF9=Pve5p9Q4F11 zo(`J>6oD1jN>L+nxu{0`u~2Lj=MxRy)YP%kP`;a4S7q9x0e<35g+kxrh%Z@TQ2i20 zV;wcvz%D#rP0D9vX1gIW<@)Peh=);utDExC9+X+i&@J2|+ooEdf1{dM%`qVQF^ zyOFLhtcclvnK6b%S7r4CD!KF|bv3`x@EA$o$22q<5Sjey^lKewjwY`Yhnk*Jq1E1j zLq#bUnf@`vb%AF!xbPl?bznm9*Th!%F_LqB#ug*4u@-i=^xw_u?rIMXLd~S>pY$^Y zA|sza-U*KLJ?2D6tv7T--|zTsL~t}|z^_qS_bi`zSl|$p_+Pzs!NY6T^#_?g6Nli1wz^Ga0PeTd^ z@Z(S!@MXE@p0%G2vY>Hvw)k=;J3ASGJi6fIU+Qa+}nVyl>*HR;1X?vVff;SBH>3G;UNpc9A#HG)Ai&HIuE|3BHPO zvVC<{vRq3&Yd2!utdPQV@i?&vfpBs?lP+6$o^$Zr{z!(E?}$gG(l+k)4sOzR8nB}# zLNFAU`%d!2^kM#|7qo*Tat*Z9-B$ z-H}@Y=#?OZwzb2w-yoXV=+F}t46}ao=)$ zhC8-xpD5?U1`Ln*&yEUIUxvGV3J^@(SseEcx%a%~qymvq`@U1kSbyAkN%|Yv*g1aQ|DPAdJsnsExWyQ zK2ohgRDuF15T&hFox1D1A_B2#VBQ6zZjM!v{PqJA>V2?`JlhfsM-B!&NP^QP=1OSm z_#lU$cadGVVKFpqjMuEsOk`pAXg)AlE2OeigkpFGI6I-Bpc!0s<*`5zPxmM%wl(H^ zLmCQP^g}PrDv-x3EnQ}p*=YBOs z&AIYoq5^8+0=iQ;PXI;7Lyz}NzQM6gyVk%il;79KJv|lvYgUa3xT0hO^6W9XX66JD zQWA40Z~DnNVoQ?WCz;r=SO>LbEz&6S*J{`Vze?nexABOY-i;~r4uWo3EXqc)C5(>p zzm-VOo%Oa@#Oeuh!hK;?!)v}l8gff7bk1CG4QiG6)`o%PVQ{-+;TX4QT^uF%Qf;Oz z3)O%0S8-rHcJ4~Q)dA$qWcnEH9DG9Qn-3{aLUPB42v|wVn<2ZatZy--_&8KA<^SMp z%#=$sQ5_lb>VA)=NIo_D04CGy6p3)`^b(C zH9I%#{-lwqb_Y3b2MEWtXw-u3Q2VEDqJ1;nn}0N3a|OX;peq3#Ya##u2S(UP z`srYP8(CaZJ@DpzE-5`lzD>5q&4xwLq-B~N-Cc7_@#=#54zg@ok3T+bX&-?JTv_pL z35Vz|^R#cSu7(7X@!+VCUrS$+xEsYTXQgX?bom3JmA zrwE1?b4UjzZ9uY``moro^x^FeW2HgGN&r?qadnPkj47V1mHbaz%e-nB?s|%%ab8~) zOFb<`yVCDTqNGK^%KAV`=cj;L{p_cG{9Pzh}a81qd`J|wA*=6y9 ztAzJEXCdZ1yKjTu>wv4(c2w0S+?8_HmT8&5I7&Y@fV96)bf8q$|4DSi(uee3dI;Y6 zH*aE-i?h!r!TF_9gJyKl9Ki%i?|)MdE{HMFK@l9>#0P> zxEc8vH@8@X4CCX(XD23rOcgdhz}QeWnLzw;iv=h!XA&F9VX!dIiUuhm6z_m>EA^mV z(Cyf=z@;IHN<3yTLF${#9YAJMz%wW=E_<|wtcRyFv1leggCI{)Fe?;~XByIcfK&xB zavE+fQHyG%`^H3^bcpqJBEy95@_}XjFRNtv;IYL!SLK;vTq($q@0j3)*5Zxp9$ zL$9`u)swY9nQpo#QwY^U2+=*#p!LF*$MuoE+^IgyR>eY;IKNrM+Sf~!0i~8d{So$u z3CaNHSjL%amm7P*jv_mBYSQ$`x)QG||M*ivryfa@Llr7*$P1AGi@rUZWSjf}pDY*+ zouhgV5>UKCDR369@gBIWo;R51q}+XrTQw9V^8>_~H|xQd9+qc!G~t?6={>kAm(?94 zrg4)YbFZE_c77$@DjG#yP0@mJFwCW&^Vt&~x#9fNg#?RG9&c$WUQ}8p>=>f9D}CeW zX56hXU;6?a1EqlGxZKa10Lwb%^8d1^a^I>c1;j&Pb?py{KL~qxI7tY>UQlmAX{nM3mxce458g>|` zcX8W^hbQXaQX$I|@T(gS{AYmSr{8N5#Xj{4MPtUVuFUepNQwe!(F6!C;3V41ehYnh z4^a65o4o*4Z)Pm&JD~Y}{LWsRbO^`zl@#g)7*Ee=h#ltv`N!yeCt!Sg{CE|-Nvn}E zNj`cAk_s?f#(1+1DV^MAU}i}CYDue8z%>2yB7#*$a!}K1^-pC_wcu})-(AMKKT)PP zoA3TQr0ivQg%O7P@FI z#N$NvBVHNX>WC6e)wI-@yo;{nudK4MzWsJ@VK0WsJ*9(K&WH<>u(;B_LBOpmc$%J0 z3Dik>C{JSg;$Ui6G;`i@kx(t*nP`2!xiP=>u&|S;!Y2*Reu|v+)DY}O#otq?Eanb!B)H$SX1fldv@Y+{yeC* z2PRGx5#=Tj;ZM$gQW4qKOk-**EPd{P>hBN`qogS0|0=Hv_%M>j7$x2g#dkNb$A#7D z7f+Q)7sSImPVFN4{DTN4)?F~i*Pk#2imxVn<*IF3rY0)K%DUUna&$7gnHnaj=?tn4 zlDl7ZnmmW%`x{h9EOl4Im^LTqhpDBbP~+<=M0+$#@|DH}sj&Y=%eD+^gUP)u8Z18Gh$u{#4R@=R~i^BE#X208BMUo5eX&_)jf*L8s=kW3bM+ z-z@c)XZ%(ufWAXE0%;iHn5Sv}sL%y>%WAJCMj0Yrh-Z`TohoiTNkr{>MAtdQ%w@ON z*IxGf8~RjNcDAa=>JLY~Ou$DDjRu|8SO6-e8M_3y*Aj~zApH@kaRZgPAw^Xq4l8|c z65VaO4tmR&>8>Va!8rHN!>;y_c6=PsJy_wDAoUlK_$b~4(3)Q%a9f9`f1v){%r`{D z0=Yqqw$6=Jh@f+3xQ+62K6oH>=RofDmGy^Fz6;e>00*VY2Du46h^%q)rEqcu2Wqe_ z0O=mIhV7cRvS+oP0`Q9}kz_sjBMNiR+pQVB2>6^+*F#fO=#QT!r;uHtrJ$8gbE+!& zHzX(xw9L0OM?>OEgU6VfOp;}G1!g@SUZ;({(r-~)vrWviu-ZFqe2}9&Z?8%8fVKs> zyn)U*Xlv!3(Rk5RT@m1bXKz20H^g74h2e`=Fz1zni%c)G)tI9L=e$V*eaHJl-ls6R zrc-9CPq^rvpJL9>tP0Yco!G2|juwQDU)VAt5KVA7dVFCo1(BX~y~A0yldVL(jHCjF z&!qf8!=&7eY=O1mpd zMdflwc&|x+?_o-u_SY{*4mA~>dpsJeO>7^^?GYoGz0+1cXZ-rP^^lTbt1(ma&lu*^ zIG=5hlZ^#Gpx~_E z$;>GQ`6@M$NmP#Q{Kx`IyV=0jM&P#Ib4`7K5yX(C)3y63N|*G4x7HI_W{hw0EOg zXI!=AnnH~ASEs9nYkhHagmJ2A>B~z9nF32vnStstmV6Y~ggJX`8 zS8K(*=GGd=c_;YAA8nhji#F3uN4N@^KOaewezkUTx(B2?XJ-yMh#+0Eha1hg*>yxs zP+#X623@_Kw%zUiDra+iZ(FSQN3=4zcDK0CcQGy2o1ZMWo6NUP*f*shyN>I)N*GXF zaaT3^cFY(rvyDi z+S-_z2*QYKIi77RQvAGnEWTEE5mLTVf5mw@h{H(ltkzHsy?bK+&JB1aCJGc^{cnSl z^Zzn9**RJN*Wg^#mvPi<|Brm>fp`Y~8Pe(ng#?$RRmK{n4 zs@p+kGYa~tX+eQ!)d$X#Iebc)e#Xr`)Q;d^XgW5_!!Rp}BGeXSsA3efO2cm@hMqA zRcE*u?-gHvA<0V7v}8-&x;CfWPsO={W14X?Zwy{;;+ZU*>SyR%f^O%ZM*4E+tV0!1 zo%z; z4F5xk8@CluU3X8jjF7fS26IUE#0b&UjU-AxBdPdJZO`<5Sd{$HPwn#OQ1~hhGEQL^ zzkpZ$D++L2eAH5lL&qX-K)YB(A8(>%TVmvJq$Sp~LXLRnYuYg&O5pvDj2KT$ZIn}U>kIUJt!;3+@)KSK(OTU%u zj=(HajLSeG*#D{6AMI!WD+>aig&I&1NR67#zLpV-NK+Ruq>0KH=0K>Z2A#-Rt+HR1 z%q^lKuI+Ue`sNNaR2a4|wmhR#h{H^`)xRHPK{_6C1HpFG%U3R`X%R8FnvVZb`CDFV zym)u2IiY7}21W{&Nv5*V`UFR>9Cc=G9?sjLOL~FCvr(>qZc|Mtc0ZV*dV^i@BTWm- zW_`@_iQ$xQN%}G&QEM~Dy2~JSjTfv(<`DhlLii}SL6@Di54zsE*pI-=1`dfDd-}1I zBFh$>sDP!WfQj6fhx3KnVA#qQ{IxrFpH&b0FN;DTU!oFS^4pzWH+Ge}b?ihy#N;1~ z%L3;_i;~2UpuS4zLMKEl2Rf#yXmA6Rn3qWT(VdTE$5ALM%9m1pv{K^-d6!B_WMF)i zYo=_HPbAk!{~Wp#>wR&O=|IR7PXGu!Ub369j&akRyMA{ANrcr0Idlw>=8qN`evnRm zf3lpTTr@@9>I*SUq)16RmtW_G1Ph}|02)811;&|yjyTZCTlGDD(fS5B7@=S za2ioMh+U1hBPE7lEstWb1PTGzKZZcW{&Ya+ zXu}|IVe26=4~rtW#4Z&ni95`$6-iNyIQKC-1=_{9ppoJn>&s8rz`*P`c}_7&!ok-Z z)>-c8EX7kS+n_g8zM$JM_}^8C|CC66(abCMDlfK^c+6+k?U=OWb$I zcYe(C&=O!|+6+@$^S0pvJ=@$oLD!d_QGmUKb*^haw z8_~4=9AHyYPDufz$C5bt5Aoh%_j>`#FLK-QeXewv-Y&}_HZB{~ia3Ix!Fgs#X0{&e zcW@X7T86Eu>5>sMz(YVgb_456yq@&K$)zkckENAR;{-B?^e}JMS;h0r% z7&o)`Ts3jOS$}jWoa|U?+i)6Zkc~nAp&)c=djO%anNUICN#`Ew&`NY}e2^>WM7S^5 zMRII{N3MsWoAw1^&pD;aYGC0Xl6kDq-Aq`N6l;81;a6ad8dg^rkqIjO%ioe=tMpE4d7g&-5M+tGOfME!b6i<_TY03h2!MGa;T)lYk!smz z0gqWSHTdWBkT<03Dp7B-;fU|~kkk&=6u287gnfW-Hq!Jc4FWg}YEL6oPSdGzEe zU$K|-V*x42l(Q!#?+@MwPBk=^#6lwQKE9ViZt+Bt{9@23TgPxIx;{YH>^@qypyN>O zsc~V!j8H;j5D4ojo)x{0oMWs@a|j=%eoiCRid~94g5gtooQI~%3<-Mi+$_7%YDn+d zP|_x>5Q+VORN`?@NtI9gMviV2{OnMx_^?j&(aKge$4L>E8fQ1pUC+;qWoc+Bl_w^v zeq+ym1Z2IiNjqHZvLBw1c9(S1zYR9^4xJF-o+rx|Y*RV%d%u`d5maC&`6+ZNhi!1x zCse;7vj_FoKwv7nykU!Zk0rQxPro~VAZ+iEBq8d23g@?loW@+S7{(O9vihTcF~iq+ zEyadoEyBi;T*c~Y{g{W>Vpr>~+g_l@;n3pm8cZW3;<4BW@w;Ructm+aelN}X2LoJX za}=1ByD(^Uf-mVaYQSk-de4Ofm1D-+PxCWh?qr-s%(_R&w3NA|`H2B9-~EaQGeNip zIJ%VQC!`PtYaRHawQNz^up!u5B1{Ega3nPR^gZaWf_y+oK_b!|P#B9mE~ zm75!l->FBtJF^E!U-`p$6X_eV=AiWP90ZH%lAb_`cwVkgsEx;R6TMsW_MK#}R)i0t zcD-GS$cOx}E-gRWh*m@#7(d#5&CqhO?LCKjQvh8gTIYwOk2Ih25m^tf|k?o2g>V{XL=`)uX~ zkap$t^vr@33Wz!odm*R=LgyqJ@yk;%>baRzYdN^nozcSAFSj261xm%r!W_Fzx%8jA zx6-vsYMTiqCRko}3bI48IcrgX~__Qbnquyxf`A?wG*|0V=X=>h zC^6hbXk+6#X?%j1W=hmuuHzj7#F=3@1>Q0yxBTeVO4lG$%dIkYsN3p%EZDGRWQ+sp&ojYqmLiNxgx6NYmKw0NUEYoaI*`4P@lg6WjR6-!FpLxoa=?G zHYn6|J^9k@-kuBeSOd)_-6jYQS36(|Aa{f~{|H2_q<^n2VB-j^m{eL?4L0|LUPAp! zBaf-W+2P?CF?VDlcEvsvTeEj*dAG6e3?CIvd=}E?sAO^$V zI*zWQl^9(gl#P{5)ON2qzOc1akHIHY3= z%c<M{j>HxrUVTYPFN_Si5=k&pBnB2J7U#m%qs%bHrYBj z3YK*F_-rrv8dnUCny;!WGl8SI17RKU1&5JsV~%Q}Q@_jYIJ2qAA{+b{N2}ZU&m1Tb zo^a_m=B^dAAVYOCm?cO5Ty<@R5T1YGp=!ys>V8f~d|{O15E6Rh0CU5TfdpUav55wcO92n! z!-qxmU6sB{AOMQ~08C%xz`nk&&;r!(IxrOaFLy}jjDgI`{R=Za0rZO!JpoiF71kVR zcF%_%U-o%+M-K<}9{@_5Kf1S4m5qm-l36l+{KaLSSJjuTaQ%0igcIQ1LV>N2L$Mi< zvE9(rLA7e%H1TRI4x#M{WzucD&jF_FA%>8kNBFh6Y)1(-kaU7Ze|)*mjft828#A2DwkV&*y^;m}XdB$_U9K*sJ(9m4QRZFMpaJlt$- zZRWPy`+Q5Y&SziK(|3mt>UEEiADV)KHDk=0)-L!r?Jxp{xxWS-e;Uj9tyJrCWNpVA z+dnfg9C{9(rMbnhu>44kyTIh1GETQVi5=aN2Y*=@eNstHh zbZsWt(uzNxdS}!>e8$%AO>CnTqj`66ez}cGw9NS*YvX&{54>;-EK_;-3xt&;H{Khr ziDdlURvzV`im5kgOOxM|2QB}*e0YNDI6&lE^t&@FNNsF8bhZ0#+z>s=OX*HmHUI5^ zRG?m>cTDtoy2gFl8TN@c5{C$Nn!N6K6g485__(^vpWoxOapB zcPycD?p)xMizCeuR@WMCN;zB2Aa~69aW?7-sy*s+gS=SzmW)I#k0J@;(MF zqNQjr>DA8U4oi0I6Xnx#E4>vQ)Uvzw1sl!8!gcZ}mrF6kFhDX%nPY1`C2<;Ptlu?o zt!_LCqgV0r6-;^SgT&mcbrt53OCr}GyQ+s9%R{;ttf1G)!wm@xR?+_|P{d%)CebygT6u8G z>=y!%5H1y}9aQ&*g71Yd1d``_!o{7Hc;DKQ7+}dif$m@N!sxikHWKv2AzV9Mgf5A` z8L8UkxhEHK7)R8xLQD{qqcu>!2{XcwP+7w+%L+EOxH^*S`h&$W9A_Kj@Vi?M_i_Fe z+4gqp#2^%))0QqNrXVh$GLR`8EUW|f=Z2$1l{ttK-vac7%6tR0`!tzsx-Gk9YS5-( zDQ3{kf{SUDX|0n9L-7?MB8-zCQ9->DjJKu)&aZy|%i0v6=X6?rU?I^4i?)wXba5{* zjMJu*VOYfOgFW}i69e*V%AS403=s*Q4AM)r0U-FIHufQl%gR^}m68wq#XENGiq>xE zkiJl_Fls){$a5>5cBY9BO%AF%4S~+`E(7chhg=Fb@_s<9TZI+Y5H@o$9-U&(X5nH* zUbpdZF~!V6W_Q@wp;kL|VXNt~{K7KNKP$xSp2gA_++G{+VQckAoR-^3T+)iw zhNd#YI z$@P5b1z?kv-((u1kOA?$p7+fxy@CZNPpb7jZ zb>~PxXY1|LqNfy31Ji$bAGq27Z>MJt=KuLXOzMp%nsUW%PHUcg$Ej?`!ALMt7ObOo z-^*W8S}4l`z1a*_GCx0{go7Xe0N_}7qn(tx3woDymB2hGNHq&mpPsOTac)`df7^8`;Ar^)TJgtJ*|W?|Gy#f!}>Dv=Jtzo zSAl1hGZJiR^YWZmWiQmhkriFs)opbN%>dw~+;z9dq0Z&_yFqX&>dYT_vz@e1M^0+O zb+ml{T66h=d+4XW@w^eNLu~y^=fptdOfG}WC1c&nRt{K6$0>X&JiQ!yaf1v?wfM9p zaO++`v8tnG1bDi4U$HJC%?B;nCsi zXaX723OqQ;>@0ugip7WBTszIR!x4=mGkZ-7FSYHDQ&pF6$+C&4Fll`@D+-DqOrO-v z+7^e{<@GBqsX^L>9l#TvsD+36-&iMXt>(0s?RRa>uBqLa!qz*_bHl$EH!u66$c{#= z;6nrzWsOC0c=$^B6qVOXeox>YvDA`c5!xW0hfZ3^(FP%BKI|>lR8==i6Q1HT-$r8O zSIXt$%FRO85ZNx%S6V2tE<34%$K%ID$l?E6GA}a3Lp5`K!B+`f@Ja!qR+=y4FB!ph z*aSl{l+9movKnY_B{HCs>TUN9G8Hkrn0)dVxmw}0{#Ip#gKd*3sEBt4bD=llf%WyqkPZ$>i^|yRb&5juA;ds4yPjUULORBPqc1VFwP8_(=^=R1fm)ZbLgR`Ti|lXIH_JY%W;thuv6X|CR6k#|QOE^=8tu zETeKOy`Vlk59A2meZGdYM!KaHqHVpm@2nd^4w4tU&mX?$ zT;h0mqN@g8l&$h((TTaI_=B|%4Y^ocgU+r=qu>+5uzmE5+!n0CaJtQkM6k6ibo6teiO$DBX@fSn+n7%0 z$I21kMAA-t1#v`Y6TWDP5=iWMTdLGcjMj+M;Xdeq{w5TVvGy_8q0kvtBi7t7tRqhg z`Btpy5&ScmhQzEhOJ2MN1S+UEyT;a;ks#}mz>_Pl=^a-H;qcg2*e#*Yj{L)&oaM4f!tz#KiL)5=Bd7q+Kp;tJ@GhVkVF}Z+w^t2M&(Q ztI%+G;TH4`zm4y&#AM%jz2wv-L+qA$wl-`5iW>B_lAhF^>Jgr_xyURZpEzs*`RNNu zdei3F@4QK_w9^C=7N ziyNedH`sm2gA^@b)AdzM%=iS`uG`=yT_U=bh#E@5_lcF(oTp3zlD^Np#Q_>oEAJy&P#_>=AI5z^ z3oITRiOayVUS{KVbvSOYm*T1nXhuXoI@aWXW;?Q?w;P)<#WKi|%oGGA82nKW&TLik zL>DMhXu3Ntgal7?`XP{)_w=s$3qn7hF6*ZGm+(x(%}y>TG!foz&Z%@}Ls|-`J^-fH ztFeXP>IGwpNx*?8^!~yJli0*bxZG`1@J4ZI!kv0ev~@W?enqlSQK(-@yzX2%PB(%! zw6+O7J9_i%vn|~#@BUc}_UftDh%yA{d3fKpI^>6WYlF~$G(T&fDJL07Wg?p#y0R)` z6cg0~M)5wC8xe&pNdzW^EHic_>loyTZuk1HmLNf+IAJeXTp-yb5DcNCoRD3ps?X>A-A_e{B1vv!ZY+ zId;f&H_pEFDa<|id#2Sl+=7&Aqch9K_g+v=TKh|1 zV_oIg8nP%ClD?5UJnQq|K3C9G#mRWSq{K^fi}8`(6q7?)e+^$t+N*hr(x`W`4(X;V zmh5<7vP)PHha(nR6CW3;W69iqAeJ+B77^0-%V7m!oBEG0>-)FHQ|;5p*>wFQV$Ah> z^&_G=lVO>m1YTqf$lWB9Dlz>T=R4cwWzD^+Op4hr+D*~4*h&$I(&B_ZH+w5H2d|x$ zT9wtaU2y$SK_mxr zq}VbHZa-j23Hdb!T@h#-me}D%3Z&q)xR14DSC}ei=jxnSWj5FmB&+)}EUE(Cdj{FK zi`Qd_`n^dOX_5Y^0L5j*S_f^u*fXT>HZ6bS3Z=hCfIC%9ZfJ9IfO$U$YO1ux>P(*= zd=Znfk|nRYrZToPv^0U(!jS){$+LAo(S2`JLB~eI4O9N(&?DGLk`8MkLe8RZl}-F% z2PXsj!1XLrB}=MamEUb4e?!|!wZa;kVpiVFK0>+q&I`m&0;&gKUzO-GVLn90HH7W= z7siVy?E0LlIV8@;+5ap(k1x{IQ8Junu^k+fip2;9j_BPbd+$$)W zupIusk>-modP^6z{($u4vD1{SAA=lWMIL;|C{Jh>J{$t-D~+U;9&P+pIKeDyXR z6g&t!3IF7#!-R;Rhe^-JIrZU@B`7Wd9D!UyM+I$1=A##H=NIN4>A@{mK^3XHXeIG$ zskUSBhL&91#?#(ZPFZ4Z$W~$HXT$WT%XkGO^hDCGOW7%=yaI-MG_0YLj<>$BU%ZF+ z%PQ*Iv)m);war%<018t4;(!Ny+v&n#5L;?tG~YgwRrePKNnJX1zrnBYYbYamu%vN%j}YLC#pR6sEkQLlKZFG&Je|G4_u^l6AovDBPa5jcMDq zZBE<9v~AnAZQI7QZQC|(yE9xxjMhj4{sw77 zhB~y6A)XW?=0MpF{R~;fxudnU{OJF?5acbZw?S?1Bxn zyz6Q%-Ckfrw>jzfE%6A>lQZ0_8?QV8b>~H;-sIfCZok-f_M(%adRym3Y3zK?hWnsc zx|qOjm#ATTF}bVb8Pi*@)|9;)gV{(@&JMHNu?wMp;eb%HgIzvMKD};laGkwvOQY+x zJ-lFox5DpRFHHY@nB9Dy#HVok8q`hL@HZHWy^Vl>n6wzOd0@em#TE1R-%BZd-Mfr^ zCAr_+*_haMS$TxVf}u`iLcit>Z|Zgd*G0i$x+O!_z@PUIU*%(Y`25KRy0LnHZfwU; zy1#b_L(V7n=?i<0kQK!EN8iWp1yicHAhXfWDysr|F_bB1{bD;LE6dtFp1*u>;0TTl z$Sfa$brX|Ho4lh;1u^Klu4k{A`Hf0M@kL2IGC6fT0S9CNW6908G+2DOcJOkoAU>p3 z-7}mBr|`6Op#0X1sO;NY6?l5*O@eieo0HY{q8e)l`@EUWWedUyv_7Th|FXo+iYC(# z;bte|R3P*Z z`~JsDpJ0?GoPGV!(~e1jC{U)#O}rAD?aOYSa3I!D5k`LbclQO6Ycbf@l@7moaL~uJ zWhu7g#81v=fP0`92(MDwr6(y%tM8cMXjVw;W<+qNvEh4)tC#bsx+>D|2$+d5@%N_9 z(8eodVR&+qQDG^Z)0&0vz4e#J;-6#l;YN`y2RdD&^4_skS<3i;o9Y{=9(7x0b=$W% zjkV&bN62u4dl+1`w=W~{S}m=Hgq>J~nlx`@i5tPgu{@&(3Tx(C8}6<)GV3O02j;$# zWDGksFmg6Z!N1c!6Tql{Ut7UO+e`!U0X1u|+2Wdm3hV;nXQN|``av?0TlGmIyzW#N z%kS~<9kb9c=~s4R%JN23PV36>TG?$;WNWSa%YG*yb`F;}TK!#(0a$p`J>4}UuxMM_ zC8-F3zx^cx^QS^dYD90sv9RRfUSgH5^OP|R*y%Z!f4?osWvSeDmJ9|Ctk395e5ggw z%`z7v=-iOG4iSMU7Jnm7FLu5dvEGCh8PpapI2Hz7QV>XqCw6ozcwUhg3hCu=#gZ+I zc7EAi-F;l2y`_t@bNqGKYaMK*)r0y4{kiVybYUc(B8{LD^$X~=({)~#ZB>`uDC}T6~*T;j|lO>@*>!q4bB)_xRC~CcIZhYk%%+ z^M6EK|F?h>`~M~2#K_9P`u`0$HLH)uY_cJCpHM%7PQ?vV(FqhH03(C8bEa#>1+reH zOMBVTy?v>~(M1 zjp}9THH-s;&>_fo!H(-c)6pZW@J}zl&wTnd_iIL4d4~QQA06tHSnd%2_H0J)>e2i5 zdQGNWkXbde`b%(ZigPrEDoGKq5I|l$h5CADmA~j>l6)(qN)iCW*$&{S{QNX}7@(ZR zVE_0FfHEZJ=I%`d9UzFn+0lPAef0QTVE)n|VVKFbtd*$9+9&KJEuzLMV%gLjU9q0X ziluITvw2mBk*F@TRqh)OnDWt|2YYcEG@W<|xlBY8R5D;iO*!1#{T6X5?5ds0 zh$bvP&djc%i-)2#I^Q-}J}Ob@SMZLR&Y_llYUdHn=ee<2TFeF&C2V=Juee{-V-<_o zEJX}7$D)&LLVHgW(c-guAUx@Wur(X=lXh>9dj%ZcQLUfVX68;<0b5n7os; znWvXjwtO+*N;6XFbae6IAk{Zx9Cc=pBDc=~PU6IR9d|B)BBN|u5?d0wDFHQ$1{r(_ zcG~)?FDPmXcgYfha*-;tqzzj+vE;UanC%ZjwAx+jN`iGPUSIPDRxZdqU!%uAw+`|~ z<|Hq#)G>!+Pf?dma)R}!Y{&fj#Z6~C*3nR<=w+RA-PZf@Gt9@PqJqm2d7X$B;U+j} z{2=W8*^ZhJ?Cjtb5!WR|ynez*;uZlY)>p4bt*_o!U9$5iM9T$n$1cT+*(Iv86+1O_O-YM}9`R~8#lynTto&|Og;{`hK;>evBK!V8982OZ&Xv~Si%+V0bw!0G&MU9Fi4pPb!{urcFPvgo z&FDz8nHx9VDG~Z{`_|HUw}oUlDRuk-bWZhYvu?`Ie&e3Z@P1*XDaK7g2Pk>1+a=BWfdA6ZwM&L}xUF z0fr6kaZ0kRDcl~Na%}Yvf2$gz{AJV*Wk)ga&A6>Ig1hh5q81vsVWGbo<`5^>Gqgh7 zd8#=3Dt%zGHzItJ`<)ePc)oa?s!=dEZY$xCtk;Q49egXn7h5g8MT@b>+Rv|KA2LYF zMYYvFZK7(h^e*~$SCA~s85Gh}_u)Cfna@YdC+dDIjU#Zr##(VwB~zhmRQ=YLxRAE` zzS#OlW{j?{F;gNU>@z-B@YX2{tFbFPG}S(!PbW+%tc7mT<-o0{gSEs~Z)WLWZ~~!v z_PC~)S3qata*wgV&%IUs@m!v{$_XZ=Tz2CXTTXD{0(f0GHjB43g>YqYvUW>mkl#IoQztGsc7r$bZhzX;$G3tao+_cZ#cQaB7#qHHb=fW3Quojoq`zetP)3D1EVk2Iw(z+KyoC?vn2qE#o7W z8q8MGfsWOEgU)sjg9FA(EbU}xA@$XFqIfP!cPCq1{n^-CZ&*40d!~+A&qLYf%(`C+ z7mrZ5igA{rUhSY~5+}jV(uep7Dc`NsF5*UyYMi!J^o?%b7o2A zwnSxyD%;iPC)>4-htc+l3{oUBl|PUBfhbwHec++YF%e?hFE*6O<2Y*f7kez_U-mb> zORtK%l5l~b(3IJ2-5mC={qp}*!(3U3iyQ3-0$znmgJ>Pd`jM8~M&B_0+9%9{^3xyP zM^6}gxvQy}2X~i;#aZ3F$LEciS!yne)tpe{-M&q|F3ZawkOawtJTF&s2FXos9 zg|c`@_O`X6Ss(cK2Qm%^=8tc;*d4TVZ+4^gjZ+Pc5uaNaWNVV`i+lvJtGoiX2x~g! zz$8i!a8i=TnM-y`(4xx_8F$2e65=d0!dENNp-P<4GjwcymTbelrY~?eKB3*;OGq5t ze-BGdeo}m;$i*ZWqo!}mCQTCRM1hVR%i!Tt@19|@L8h0L$A%$6r8CTzd-Tq048kL; z3_~r|5GcU7r_a;B%4#xys?8?Tnwnz#RfY+dI&`=;8*X`nyJXMKK|}vA`KD{peE;gg zc@5GVoqL#^r;q>Bj{NI!{f6!m!o%n+ilXGSEAwr|3j()4WQ+$G&hLAPTANURYRmFv#Tzjf?eog;VJwu++6vKoMae+iUBv zV1Slb4UWMfzwLQV7pMme5#Lz5K?21cwtK4(RcJxaGf;_Q0^7>K_x9d0JuF?oAK-5n zrD=Q>YoxAD=xveJECh%nY)}|badDu(MMxot46)!$?>ae&e#Nf9C&oa(e-*}$ymKF; zX~P6U&lT~#CwP}@j$YXcNZi`xt%M_#m$)*pjmrBumy* z#gWSRWkbok4bB3~#M4Xg7~TxX#!|z8E;=l;g(hgz8`J8xt**41ROhx3uaEC$+0zHDxl3257kSHAe94GeNWKmIbKBq&AvR-F!hSkp1X|5>lE7Yj{VnQmJ#xETxo>*Ip|l~HUA zlWTR!t`^YI#@PvWSsI&phIKrA>niOp&n>4`%%x?N{Rou()RZUf?3gZspRInL@oYp6 z1Q#jCEM#;UoKgL_)!j=SsUzunLX`b@Ls0*qy{FOP5brO3Vz$GaS^~CNxTB)*dP8Ag zxWO~eFgWhfJhpyWgTDR>D(Z%N4&F+ZjEv#~$Vs5Q5Up&9G~HKmFM-Ga)?xXCZpbn+ z(0!#_t~Qstu~1p;L9z^E^xtS&M5Ha@Z6$kKe_>Lkm5cP*6fF|Vnq*ZvUimcP50hSV zrS|_Z6}E%-#?sDJ)Eu}16@{q|bs<}w*gCaA9vN9EI%FGfcM1+Ic5f zK#{F3#W~jZk3n6nC#j6T{qlYXw z7sa1m>Bq(700*U|B2<=y1M~=ZL&jvWhAH}+rf)3XVZiy0jBP8hQQVN94Y@viC1T>8 zY5euDg5O1^@HKC9kTm&1Rq4OCfV$xE(yJrHh((j2Mj(1gel1Pi^S==_iUP#j_`XNQ^yc zVP=HN5S%6IdQli@gL6cGGC{em(AFwk18dnoO_b1Jc8|gI>hcF_Qq!{s$P^7{f^bt| zk}BUIE+5qN3a_v>Tv+b-I{5KiiVQxVyiS9?4$Emmu0+pUh0eqT-Z@oB(niN47Hnl< zy-#aOV$F#LUuBX}Ql(Y0Y#hSOF`U~RVI?9@ILJkePOmM}DUz$WQb|j%Wb~ikp|7Uy z1hvD1PlqKunD9hix^jk$*869s^}#H)DpMQk(SZqQvZxuH1960bvq5YKU$7H#70yIV~6G{#_V*^9Y^oRLoP;$qQ+PGi;7@ zv}0#MUDVm_SfoU@p5o7Y^b!6^TVSQ?Yh-Z@P0t)_+bciJ#@sJn;0?0uNrlHo<1WB(!WN!!SJ_5h0_p_1o=npOTOsOv zzs4#YVU;>E>i;dtB=t00L}-#2k{|Bt8UAsRkM8G(8l`n22$I5|C;}!iMAO=D4wvGi zR(_u@Whg-Xr^35yMkJO-2zF;(6h;OWZYBTV3OSMFrE~n6B|`cjT#|WbL()xr48M&| zghiPqOIOh@p82YH-!iF_c!S4UcCsP+M8ISn#ubEfxBBB=f}KdJEDP>E-( zh0dX#W@G#%@j#Kl%;JgJ{&@F==yse@6R_>b$6byUy#c|7Aok3AnPwC-O3AkMl%AZZ ziy5K;feM5lWwZj^P+#@>4LVJfJxRE&KJAadAb~K#c!14tA*9HV7 z@vM+dJLr93A3LrI3Fjbzfm6iMrFejqE{p+K>AV<#m2OI^KbHW8D-?WG5O;~GzmUUj zK*6>ue(T~svkY<*RNRFAOY++!V20o$$=Vb3ZJ@s;-yzhrek6hQVv#>DL*i#ipQF}| zHK7<IKwGrFb67fO#<8({FybZd{o_0UK0)I*(f#<<9o}<%(WtE@{AjE z!USM7=e@EfZZ3YXsB%4fK$1&wCXjyWReJnF2q$^VKBpP^itg?FtM^rfXebr9H)!`E z>hw}wpt{t>)91v-8O=6ouv?>aB@&8RY0E+w@$s-No-iuJ9QNMg-}@luZsKem`L0R- zI#g(6ap7r7D1paF$C;!DJ{zwNf&Kmq{b@oEg)1T<9F{-t?Qawsz*3-(mEeGH2xmBL z;Nni5?nvfJoX!k@wzARmho0|TgX#7YY6dfa$j$uzmjz>v>9Zcld4pRRNgXU|LU0Z) z*e~JHAd*ZK?QAvsRVbPC*n;IWqnkmYZp;d0x@fzVTxl5;II+Z7M{pJLM`;Yb>hwCb zsRSz{iIyaEZz0#EszCuV{&DlzM%-zrvs`E?f~|G^8aBqcX6aHT;Sf4lPSIAFJi%hV zNF(EtzdG@|j8Cd?7{7b7Ai}z7&0xM|JHD9oj@Dn2bU&(0H)v*@H&(a- zp^D{WW=X!Hi8=U)e1(KsT=hsn8WDV>8f1R?)6kOHP;48dX_1-rSaKzUhCY?8}0LlZfypdCb^m%Metb9|D14F z_5UG1JQ7&22R$^XZgu37WNC(mnB9gFVIWy8n4Q6$_Qq%+*Km9y@jompKa5S^hdqo% zMGh&)JC5c4@D1Rv;nnlwN5`3{pUVHN4+=4`z_hU3j8tr{w1M&*d*3UV1tf7EH)EZ6lXs9vs-eO+6&5z z;APgzb69p{v0f#MfHD;|CDAKL?`A9jVk!CSd`bTSRMkxIDK zrhTP8y;q3yK5Y(&>cc&U0i*El+Um328BMP_^D^Q>ozt3M@47tyiKL~=o|WcZe^EP##?sfPC<>EF6_-K+JjoM&D$#$$ z2{j%-oKOYXlTheJq>un;cW^@}dWmb4>hddj@TN}}Jl}*~V+XPYaw7RLKTKX30ee$x zsC0P3+Ulseo{sqL10^hKpux94S%l1XLxM<{z<^@Vo~W_*$1F?+0Ba&4HWcEXBgp9> z*dcU}1WeqctK!B4;VQRr=*gr^HRIS<8C7%t{}<|JO5`aENv7$kw?|`WI_iMIz6Xz9 zcC7KZ*0vd05+ps!I1?mmxTpqurDNRlqWYK|S8)4@4c-KfYCi_BBM$5Jr7z|pN@p+d z2@$r$LNy~O6z~v2Qr^?~9>V8%QaG!M(!NAe9W0=*iNET^qE0c%HvF`h(JyHP+o}F& z?wsNUU(n)_m811O@;5UC-sdmS67ntygy2T@IRo*UA_TM!1YNf}d@a455lN1pX4L%qmjoS& zRtTP!gH7OQxUh7t$H9idDgPkM*5PP&seTEEN)xi~t~{;PJrq?nMLx1^J~>pRa#oUP zoH;dy^C=}bq9IIdyF3E;@Qw#nvGxt{UbTl2dUTE&oKv!3UDFk$12G=4Uv2R$-LF5G@FZlM!mPOPz>-0WTYw8 za`KzsL}XY%I3oiK_V~?-htfUlidIKNy@uWK@fw&4s-rX8BzlR>TfRs?l$v8Uc1)`Z zA80cErN^*|2*iMlwOIxfrG%j^`b?R%@I4&>g5S~s5L_DPUnjIVrprR0>lLn%d{BlW`a?6!8ov;nxIP32Gp4~5lWO1- zR6k@I_hgv_LS;XZ6)np5zm9ns4V>Y*23V3Bchor+l;d<~(z(e|JCZq)IEJKaj=4<$ zLl6WNe927^Jed{_s4`&+vlt^>d;acR!QWYMz#D1@1s5?= z452V%J69SW>#h`Smf8_HEW*6!K9`d}HHso|w#4AjBU4EY3%>BMWBDMJ(UQyg zAgXNP8HaDly#!xfD9XF#39|0+(g=p)`^eKw$pRYm68hGWR4^Q*R8wK!S^%?cw$^wIR!M}M-0e5wWH5FP`(7ZwYy&zc+VJizo%Dlc- zb`x0&(LjzNyt$o<{^e{j&aYAbY1~_iF29}L``*$NHhS+z`=HiCpRE%)$=W#oMd{(t zUKa8`jH?oQmEO16CY){wl#z8UkUL@lvY7k;d5jSA6?Mo0zzSa66PEu_Z{a`GvjCtT ztT|070QJ&@5#$;jqo%VU9HHe0zOS<&v`M_UaZl|K%q-bLo;%Sk}g1WS*m3D@#PrW8+$Vls<%7@&#~q z5W9EzYvGL&DfGm#YuL;FL1=5n9K6hbHh#RKN%tnp1x@D-4%(XyP5+wy&eeamn!(V2 z9u9F}>QgY)6B@idfuHob!Sqh=9bw)1GI;JHJP>6nOPr`KT~+hH6 zsV90Hd~fUHZnXW?--2h`gkXYX`V7gQ!g|1wM8WM~D1ItXL|lig8xQ8ll6NN-4o&g5)Tb)!cB1)m_7c@AO!lZJgwux5BV^CIexlh&UD)Ul!&E|(OD2%O^G25N z_wyjrko%_)QSFQxgOt!)1qpO)Z5Y?Zy$H->)-H|ZiQo>ul)pE>k-?a_XLY1i^Wwon zu8nI$Di%c{$!}R9C&UQzhJ|J2ZR2eS z_?(PvXtdLIk)^_!g6>32G-moSM9VAxNMKXW13XR6PXKfQIFrabAod{Q(UG53#IIUJ zpJz~X`Xk6i4Ny{jI&BXce?^BRK z3#)<2@5-eg)}J+D0WcY3A{JMO&(hh-T#~}K%W86G`t$rONj2F`VLghb0L$fVHVbj+ze~q~^T!tQc;I;(EtTz4CcuLi-{q0C9YbJD{2Z2#%tK!;G53e|9EgT0ObM zFJw;0ql|@n^t5VT-(7I*;egIfTG9V_{U21j^%$oP62mb(gAquN2hkcinfRwkY6k9( zxRood;(k6IOP$ZR3%D!mWAVb(-v^tyZjIkc&)r$<48zYtYD(;qw277W}{3 zlG2h5@WM5~kRkA5jFti8@2>(ZB15DNMW~$-W95JD)92oNc_fe7| zO#5E}F{L1oa%pt++n7_kO}QLG*VywaNp5sL4h=mKU45!RIBf$+ z9~ATT37yNrf3xP4l8X&jj!~qqL1^r9w2$l)j?$+RI$!Y=$f+&Hx0>x659z*QR2H`W zfEt_gre&Q>c?Lxgl4Z`=u{vi5c8bvbP@*HHd{l%3x_wM zgXx5nSKCLIyLIH@`(3^63jbDyXleuN=R;<8}ZEMWuj*B3!!R zB*-~>`PL5Dwby_e8u<@=HLJVg@4j{O>Zi=jL682V3oZOA=b5JtEts;Gi(L6$)oBCM zs9|gz;bhZb#|m6fd*~r3n~6?`GX70$a(C&<{@VTou{sEGRIS8^hlP7*Mg<2z{)aGx zTcVJI!CS-YE^HCvminjFoA=u)uYR;+`*)~m6%CfcecVx;2-j>ofuRoCWlC+&Fofx!tJ6-w$7 zO3u5m#4HH=TUM(e3YiJlqYB0yxfa+v9Eu#xBV5@J4INtD5o;TVHeGd0i@ z?QJUxP?*OlhONf}CKDT`3+}Ll&sHzzX%y;^I|Jl8%t6=0f z)ZP(4rkNZOUsY!neUg#SX)|_V!id8e%U9Di&}YF+Ory%8-sI4(Kc3MNs@T1VaGw)> z3n^q+kdK+?uaU45?+_Wi$c5w&gVL`Z8Iz|-V%wp_;S$|14S57&tJ4yG@guk%Zxya; zB|79NT(Y^~a)t@6J^*So>}~$EZL8rH+6n-==1>N@RE#whYI`aijz{V$nxE3zBz|Sb zIOU-Ukzaw$#gcTGCChsk2^N+{{e4i}-)Sl5u4_j0#2e6p$?ul1omaUz*A209UBard z*`CCjArQVFlKxexHs*{cE?9tCO7gr7Lu1bBE;s9MkI-lxVFfW%){DoGS%4plel~IF zQ?sG7c3o~e23HZTpe?tPj%)Vrr=93YitNPGN7k9&0UdzRG>4OB_vS(RGQy3YchZ+1 zvOdzvnUz84ml&ZvM_zep>?6!&P(a=mlMuAg$04_6l2o3ab02i3SKpG_!ikcuOU0{o zzB#8-R-)={U*t*RENQ$??M3vkBJH<4Q@w4#%7iFJ37hNmMCVyFOvWvf3ccw7Y0XCY zwmZYQC>DdE>OYj1DT)ij?J2!@?}4Ekv(4oZy8V)!Vj_^bGDW&1?7J>z_~b)fj;-f( z#aMEFX(E-sT@vHti)_G1M?$lcDMIeyU==%RQIdQgsWoK{=9UMF8l!ChA-m^`~U5z5*w6n=6z z-~YH7;&#ll`~`8H?OLuF5&WP4+^N)zG&m(+4UOCO%xHqmEY7?lcMP802DfIp+sC0E z=qE|I4UJNRh3SVu!SROaaWbP+7TNn-yu?@(AuarbF~h=i=WMM1D9c4*PJ#g&USrq^ z6zJvmAN?@ZXTkW;H%wX|+d+e%1A)bV3w%zI&oZo_8O1%NQ>nDDvKMHNvq;0*`%s0cidae;S&UT(?I$UDGtetQp@hYaCS*L81C!lBS= zq34I&5wkvrYytMFWK#xU*(_x3T56sbqSY5eStN*NO1l)GyZ?-fyu_k^glWkT;39Qfn;QM-|=jNm5=LZeBccXZLBJ^`z{ zMb|5K`6f|jN~k<|&l0U{W!Bo@cGFMNHEAF>c)I8!u7Ra!F3Z8;6o)jDGzGJfEwFM} zX}ADgZZL09pW&*fH;{~KnUI>*;>gFIt!;dtT#7UMlm6Q4np}v7NVIKTa?UQB;fl2e zoI$b6MYe~LU1xLcdh&HkXO9fi5hdbWF41A7fq?iaDq?}Ig(2rk^TY=(Lwa0J%^~#V zqgu1{A@%R3G~!7Hqz)Dif;gaH6b4WNf0X&sk|Vm)&b;mFeHv6z=BZ(@feUd`T+`nZK0R==$E-u1t5A7pN@P(FNofoZagT-# z!b=49gDsZ&Uhh|8r~7E2u>AXp_ac^|=eff6Me8?#uR&JGQ~9=Cr_1ku%pr}n!UztD)h4=!vq!8mIwMHxlAm;F({9-T*McCuFhA9CiVp)+olT*ZL_=J4dC(~)|^7#NE zIP5`#-2aXyhW{Rtgq78-62=N0%^oha@+?mVy*RDWd>h{-Jt~j8qtY)(q%(Qud8s8Z zxcz+0t3(-I-BXcX8qsZ#STTzTJfY2~pN*elPO2OEnF)HxFygoW4Mf>0CX|I} zNVu#7hbV=f4<}F-7ukXgaoT#*>Kd9~IN^(J_4QciJhThLp23+$Y&xf@>4R_rJ5#p% z!3{zF!s~VqxvU83-A4hWdNe>8E4UD<)g$K19xkNP>a*WReoPM8&W#3>#6nEC{ZCqP z<^qY{B(GJ^v27}mF?261+G_Kas7=EHZ&fSb)J8Il`A$ouA2a-uKFVp#R1uZd+Q|lS zPMZ|96`!!cHh?k{EqSLD!b&)pTly4rcPmdh)OV;wfox|+vT;W9D@_1+LQC}UT12;cf!(;SDTzkUEWy{ zMKffHa$C}8&k9h=K97R>7!-9!OGqFG&X86HIK>VM;z{-f>F+le@kGre5W_UNE_}(z zaS!ow2fZT1HA}4Kijl5hsG4PzpEF;9PyRw=LRK~qrYZ`BF0RM#JkG`CtC%me!VFc) z3cL;543mh&vA1l%N_6S7p%+>$qhy{v23y#X*|h&XC@tBk@=D|JW*AJ;O=4-nbW7PI zGQ~8Q9rZZ3!J(MjbyRASjpL~cE~9zTgmq(7p0rrV_~_mz!|FktcAl%{QQ=Y7ukAx= zr}GL!O*7omundzjX7-K^J%bdeC}`~!(NKb)>|16pTSoLKE2(t-B)-O;O;^BB*q?)q zipHRxp=9LW_lhEGr{!unTIp}8G6Oe6O>XJ#P7qo7%>fz!WHi+DKtu{j@6IsM#4h({ zehF|TouHVM$eN|q=obrRZoaIer9y*hta_rUV0y8)?q(BLvP`VqY1@z&OL#GZCEUhEmbs_RZ%iQFYdkTjA$zVJK@%2T zUhZ1u=3OQCnzcx}vcr591x|V+r|Zgfk6v?`J?;$;FWUYuQ|3gTbn0;>nQxD4AQWtb z?{M!4_fJg%@jr+XF$m6^^m0#@eS4*0=Ag1SuNbPkD9=gsj>>f?zc;Og@V=^kP%Bf69=%40+_<%EPxXmc}Ql8g{d@ zqS0&~RE3H#fpVrn|5ouWEn6lun%$gR>1q@`Fbd@VF`NrZ?3l#*Ak;+dHWf`J5~ttD zuW&H?6Yflam)%p<+_I$BG~f5HZm)xzjH=6+u&O3cb2QVSIO6@%p<1)$m-lxYdj2LC z3Qddp{<&gbH2OcR6FONG2&t@u#(TTYeU^%Avq*nVcjHL5Wk&6iw*mqt%ercgQ)p|5 ziW=*AjV7oFpH0$eejDV=xx8wQRo&36{db`bp5)uu8WDNR_q*?AIy_|s@|txGyc(^J z{4OpY*0f47bADDo8_ZTeXh%&y6=3^2aeIcf4s7QD#xD^H8bQ<18I1;=Z#S6xB&h`O zU)sPPWIWpvMvjEoFrto*pp(A5{0SxGd?4PjMd+L*fOLgA&V(&cyOY%hL=@=3Ar8^C~B zca9Ahbn84$Y(igWkXGU2{xx}WAYHmE?LrdhxI?T#1r?;Hi(~oaJ2+L3og!M6-_3bn zt*5tM7>?X0I1bKKwBF22*FuSmBQyIa)t(x@A#)J5A<3JCR|J=0)ZqS?Mhu~+uZMJ= zwkc`9nBUL39Os=U;o(+RuUiGQD=hv)h48G#QZ)8_fEez(h6jQO`R z)9UI0h}~aV_A=k-(`h7n{>&+$5sKsOS@jJN`R?L&BZ7GNLy+goxFjzFn74o;{5LWY zyOXLBW|)H(An)o{qNzJoIn*Jh5=&dztK8G-V$!h4tLJ6GH=Hh3=^npURnQ2|I~CjN zYC+sfAX~g8#&#Ew4JZFdg7m3u~88t6@MEUTdGAWb8hx6KaH+>P$!mN5|eU+-Zwd?UR17Ae- zUC9xLqPRdxIeD2uFj5E%9DTulC-#zpkdLc{^&R;c`n%hJ)l>-v93vsQDU3=yVGFGa zab6Z(R;<)jBf2EtecV-5(B|F2*1SZv{#xocxQbUQK`h+aIM=6A{3ugd;;f%-9IdEx z%(WbdH(? z13R-ep?=XcJF9MSA}70caXBl!W-%ityPBoYF5Ea6T1u23uTvJzhfl>5D*>bNlwC8s zh4pYR%ROm?Z5JtR zDkdivN6aRKGkS|;fgx1=&Y8!!a_tdd`SNdjmuaPgJ?pmb)k6s1*Nic4+UU z!^K4ACRY6QIV~ceMy!3XZtk1egfV(bZQRhZQEuAM(qsm3v6`MVw3G$B%TR0^Nr1^O z$|baUG|_e_=ZAFMPLMu8IXta?yQN?i1SwlmX7K3oxNzxBV@fT*Zy!u#llB*}ko={6 zs5rm;bhwk)^6>~ygi@HW_(+$3EaRi59#Gft1!fCS#*kEiGVTGi0jakgwHBa^CgOHo zf_O$)xIAnF1K!1tFG&L$z1*|Q$?1z$%-&sfVD^(=e0*fSk+A@=y}fe~U|h+)H~?5n zt>1eGfm|WToNf?Zj1hD4$>YspdZfu#mt35wR!zLz=~k1R%$ZgyyxiGVzxJ^!m5_hK zMNdj9Zv$sjw9%!v-iYZiy(U4w=E|Jz8GWGG2p-?sY4I{8{wC$M&iu)F^6CpCKyukY zk(~-d9+5E?DJF%CUYiPoII`6j(YOc4RAkM=RLqzNv$R4)b_62EUSdpof&`gK4=v?x z+)-R6F58hVtBiJSUom}mGl1Gp`|$PxJU_mCLhbGWK>2F;S4OF=5L0ru=f$ioCKU_e~pJuik(!pv(fVr>Teta?t(|8b-yks$lS z^~q^MChF?$Sgtmz%B8Ooc0zliTS_?bJuWKrbi-rJ8xrHY=uvMbY5J;s9*)eLP3o== zs!6Q;@P%2iq7KYI<%@!q%oj$AbX-lK9I%A98IelKtdMoM{z`x)RDjmKEW#>6$b~M} zEUXPsiq;_~&xvj^16(-C=~|mBK2eG_{&L2;4H*W$(6!<PqZ4X6_K!yO~(_z5FdjQ|q`2V^+pAn@83`K|@yK`DLK+A+bwPb>C31z{k z9=22TLOsj$Wl~*RJpgR>tKLoKJ4HQzZr z-(z$XJhrWIs!#IJ46JV$>A19R{!hTFA%7^6}%Xu+Ixt;V)8bymj zy65d51LlBkggHv|9npt5oN1QC?K-UwQPw2BN=D6vl6CyGwpE_>9$!=gNn3^_4)>Vt zu9Qkvaf0_RJ(W+-cIDSRu5JzOu&a4{Va-R_Z>Gd|t!(cYbBMu@3PgFw`q?!qLYsUu zA6JLRXMy>ce~HaN&ah5a5;i5pO~nZ%syLFv%t~lTYYF0>guCJ7T+^dE9%RBKNybC) z0$3%b>X;Kr&{7B{P5C9U6MKV603t*n3DBQS3pz;vnz~IPkyt26$%D;Q_PZVo@O1C#+U69SFc3b4|p0jAb)0gk`? zj>}?@W|P3Y^rT&|&0V0U!KPH#@L^dtj&lKpY8CPz8P#h?H7|_<4|ioeKvSv$P#KPm zr-tHsCzkT`EKKT+yA$i4f~D)4`~SjMD0&zR(b<(L3|+lSA`wV<)^)Ddjpc9L z9N;o2VW+^R29Uwdo&%55K56sPN%VkO{s9lyInkM`E)#ILf|R6);tlz~-gZMy{_)rt(GyWLYY2(df<+lB_|1zL6K=5cz%i8<9ncTOwB zI<5pd4bV>&HZ7R+|6%N#f)}J?F^uYo~Jv@ z-{UXOz7v~#Z#z3O9_6zoaUIpm<{V*+0W4?bFU#lc-JI>nMaX6817jOXAzQ%FE6+ss^yd7tIyYYbOEH^6Gx~19Lq5kY$RuC{~ z>Brb=Q}CW{2CMa->pr0D@%-A(j1A0mAyjh8)*eYJaP~#s3k}tlo_9x|+9rwgd`)57 zAD)DgS|qZQtA#3nj#L(}X+p9GmQ>c6)$N*sz3JN3bs&W5AMG2zuxryw^Z=<*gQFDM zJGET(BFIMR#BFeS1578llGQYOc$tJ}v2gV-o<^Fk`N=wD)Zox! zQ2rXPDH|nMX5Hnq>OAN4OZt3!9SCIkN8!Wo;PadkJ%Y}3;3&`=PK8b;ut@T8;WNL3 z7c{y)akE$0IIDt#%Bqhjq3J$sUvd!&Qc{3X1+ZQ@j*}FxT$7v>v_9RUS_41=Ta}Bq z9)W|_Jq}wLwNdeFI9=bltyoRWX*j*h0Bq6>kuWHo zmo#6?JtXy!j^~UDkJ#O9->3YZd7SFa8zqNv{r07|j1S5K7h$4}%q@P8f z4SvlW>lW(Opz1La33@)sB5M5dom|bBdC;7~v3+Gr%+X8|qix9wsVy^EQXW(owhcn$ z(;05BgUPc@P~`inDs9GIl{&*V#);{neQVLMoDTzc{#P`VSi@R?!C{8yJs$KBDJ8BW z9-v?`l<1;8C|524riqyjzM7PuDN^OOgc(b>RUfNmCA|ZH*)YXA6Ad@jX^)T~|8y9y z7U9w!&-!X6E@hLwB#T`suNN^}zIVhw{HO8v%?>yn*-VSQis7pCsrejuceE1Z<)Gv~C#_qFIebdv+Pq$@YYtQQwA8C2KNjI(u4x%Gv z7mMwRUFkDJ67v+Y*Vig1;}k6Ri|H7L{$L<~0$O?3*ICBMZA4eJI3{GAE3@;FmOA8B zMCAIi$$G&zElc$+Afhf_Ju=ldO&5$Qn&mg#Zmu}TOi->(2Ot0Ld(tn5_rH$T_Zw~i zrv2`Fx1MxNYAXcho**pn7Z?MkfZbFSobXv%prr*)g;fD&zf6nsdKAe{wE&Yci!(#V zqRXX#CnL63GL2!x4}%6C0Ml#Hv~}sjib7lWXf5iEZ2K-Z)C*b3wHA`;y`|YD-t`@1 z*PIpHih>XB;=x==0g6x${3Nsnc#h4~q_?kiLMHkJDPfz%`3f$4TJWL*3v`jHv#V44 ztZOQ|DVoOl_pscGdmTWihyBl7M<}bv2sPD&pM})(Ng29bel`IZ^(hq5EMI!E+SdWN zY}4;*za`_ z;f(46vqpO3yP#Gr_4#0e=*GcCWQSrCJj7Vk*!BGI%zVG$f8%#Cvkv{IgQEY6(VCfs zf&G6Hh-_o^z%SOH2HQa7DVu`jMuS@Mgv8O#qZ zR2Ae@-(skE=HZk+Ob-q^Ig1(RTL}AB3Tixba26c@3W!pe8|%mC^<#hZ<@RbnCngiz zDitX(roH~b9QKcyX{nfNXf$@>u-_&~8-1#w^rc6^uv~w;HFpQf`4~{Qz{tSETR8dZ z2O+VJi8UV(S7bQ&1vB5Gx}RmTQ)(QcOW? zDc*BEJ1n0ok18DtP9q?1#1I#q*lDD2jd|41OaLr!HJc|IDaS|lRlfEot>*4R{E2L8 zPMlau8ahuSg}tc*rPxOs3DUj(&v!@nYNVIFtp@VL^K90HqrP=E{p~SB1vuyLk~Hn% z0a`k8im<{`LNZdcsM8WDnZktr_3X6HYkhHZZNJd>t`pa6`ss&tQf}p5qi`v4%xlH$ znVtd(`@hOxFy|~V5-Fn4GH^#S*=#Mqt+QqX!*;wD3C5cCjIT$Xcq&Ft`+qGN_-BWS zGuIOnQlE7dN)lQma-?*gYpwbZ?~G5>PcAEvEgs*_a1~%}&thkJN;2rVox$h^*8nj& zD`f~S@v*v$Oae1I5CL1-|HPV{+XN`8su~$fLy())Vr!i_UnBA0kzpZ38 z16HZJlX%)xSTDE9Rj>AXWkQxHCK2rtIb(tBp+6=_Vghod(Bof1Ofxg49)sz;Z##p2ZHIRG`7t8Z!?Mw4~K# zo8kMsXwWwhL!bs`mhmiURY54)JFAa=XS){yBQ2vbHyZ&BQDqbg&AO^LM2XgY&FWTM z4DnO?r{LBD^wJBPP}S_yc<(e~odM;Zpt=)D+sWT`tZ1RLOOj3%8!J?1j6gyj&1x#I z$U)v{k#?-u1{wI6Z9G-DGEbHr*6!#eY63Yu7Q~BLMxCc=_;ryRGdT&n%k(3*LppE= zEy&yh)uIYcI{~xg@KW%sf>a77sZ&bOl3sFJ2SE=sHk!xCl!Xw4=N!TD*kj=?$pG0pNj_rD{WIi(&ymOYv{S!rw;A| ze_1xWIyNgzhq5K;n`-gK8QpM;E?qBMwKDpn784vNJ1h1o=3?SHvA(*DzyTKwB>`Tp z?>mtulT-B>*U$%iHySTjGC-9HfMXw-oD87UleR+uZr2UsfUE=n_szU2!fvG13tUjZ ztc})NC>Rx6XkCzpFM@7xeARNkuj2*oqCh+QVRHW9FsG4s0Aul3%mL^w0aC`)3T{2N zlKtSYu#=WW#LJV^s1;5v5N3sOLbBp?lQXi_U2hwGsn|u-t-~~z|G*=FLzIQZ`+E5U z`)dI#X1+><1GhDh*pZLrmjt$KNr76C>BumpB|$OMO+0R7Sb%ES6bGALs`utKv3wkd zB^}78i?@qT^o%fW>#SEVZ5%{0sRO@Il$zFMD7zIF=Y#AskM)q%2?@4G$rhwH1@Y#U zWT{Hjp5r0<114OGk6TFtHN;R~a`7tg?<&{UMgdDX!H4aQjp(dAd-Z|P+UOmkwho*C zVs?etK`7o+S#Udbnscd;k>I73U`JhJvzeiCnoA3YF~LIL;XjEPzbcON9dq^V?nnM`6C5vJ&@o#r=uUL=XQWd`u z;s7y$eG-Q6e_{{>Zevhd6g#hKUI%;o-#II^%R}IFGn*H8ABVqfTNqQ|0L*9regH+t z4#Pm*t{UvIFYrP8bC*v2bP7OyTZEEDOoK2hC&7L&2*5oN^7?1$t4dM`d}Af&?JvR? zf?&w_s~GfBP+BInux4UYnx|AkKF<%cZXu zbEgF`^y=!4Pfn}s`e*6n)Fe57*}3zk-BFHm0Q81 zT_9(|3w*KPWkv#$Ti7%gFilsL+s27coIi-p>Ajv^b0PM2TXniaLp^3L>~p<*J()&` zwD~PV?y@L~H98cy11np4a1rf7R=R1px`LGVs-2C%U>8-8iottE znGi{)#SgXaUyM|hL2h|kceMvlg(CadD>2o_?za%zmdOraZJK?lfUmk-Lhdz@IV{T* zvFIM4`XYlW72$KWZ$&^0XB!Ly(?7FgKyry^i$9qdg%!cr*FYZ3N24G`cI6!Mf=-Yy z6rwhBVlUD|`RH(TNYt4=G8Nhh=w5bQ4dh4#?UQLw2U9E!S2~FFkPxEpL2fvW8HJ!D z?+tv`els_><6ZpIayk)w&3g@G0NjCnOc-$6a>gZOgKaKTam3K%T%aO%+ZxvHAq`q* ziAlCJO-pI^({1;rf4waKGTXmp{?UIbk8*-`?SHaq05!03TexJJjB;EtK--^N)MXjk zZa)@Kq_x#} zvg_siepy9p(9Jrkk2m;bXLgR)rPs?7kRI6h13>hMMz*Ax}o8`y;lK7;Td51!Q84*SDh&|*TLp}1?1;^n9tu%(d9 z&Ya=4B((82vfpc4P=Y3rJsU2p3*^iqQ5<;t$B%<*nZ>1oqs7d-hUVh+VJmBv$G<`_P9|p!yBwbNqkrd8nZ+G z1!u}o_jG53hhak$W{PJt=2J@(7v+p0U)-Nct*?D z?o{zRDisp3L{oF^$}j)K%X%^{o|SJ$ZaDGiD6aB)lyw6P!7jA?SS_?{Wj0H0Py@Uy zZp!GkHryJZX&x8+xH{tvMJMlf>CAcZ%agJHy#<_sD4gH?)Jrkj zb#&@Eqf(c@XY^i(C|vRkgs<~Qb3X8d7ho#sAI9S1-;V{*6i`cf`?fIZY!AjHy>Xq? z4kfBi_6!7jRssEiRkGU7i7w*eYOqqxqNjH$kg4iBXCN~{CM;A=@r6vE8&1`CQt0x(3O};{1-S!%HpuF6QM|u^~*LU_;eMncX zLys6|01@JGp}&ZrYYR(Rd_yGrx4|5~@7#Vs2Lp6w|NpFviGk_Aq3dF0|6fU2in2`H z5(7;41NA*P77lkTvc(cG5`lvjBl}RXk|}*>81LOn{bEr%B}}-g!lieY8Q-RZ9UaFU zJBI*y`D<2GU1!(DR%7g}4NoV$*~_;Qftt5OS^>A73sz%Xh@ivi(82!Mmd z4~HCyh8i(&aFnkaK+!j!AD^FsaSvz-5FQdWHjA->FdGRQNtdg&$ee(bh-D?)q=P9# zoc)PD`QM3$yQ`h7(L^WFmqnm(U3H*NHFQpQ6j=l5p0?V57HWI4kPd*}0YIE~iqfV| z{}i>0kiW0h3FOj^cyj(Sm@UzVt#{RWmf)?I;HdhXLW)@bk_7Z5T3#u!wj668XQs<- z_Ctjdb7J#{HL1X1FRNFpT2S|9vxA-d9YcU4jC3c&D`%;iQU0Q&O|uf>Fh^-dTiTdC zeD|k(i)S2PbKk~cC2G>77UCr)tt@z&Euztce*fmH+>4R6Flz9tNaTe`@PXrmL6Ft) zuu5)P0bwt8TXnmZ;jK=Fv?9WCi`(g_7Q@N3tG*;7dJKe2T*3E<1?Bd`@n{i^s`a-`+#^bDbAA^-R& zB~vI;sl04mA26_YFH`ZpzP=_bS@+s{D&6Mp6s#MLc}a4@B;Zw`-u?EXsGeEaXZ6-O7( z+WmaryQQs9M%bu!LgA?@*_=QyzcVG#GpB=3!!q~9b?-}GZ{9C;ve!<;PGznh$6(hy ztkQ4RZrVCZj$8jwgWG#ODtuh0PJ47`o&}wR{j7hte=U&$csbS;>Qn;!u&dhrygJ<7 z_V$_>r(Be5+v?15D%a~at#`9iwk&#aC`>sA+GYOA7yhyEQ4d~zFpWA3j^q!hp#%)c z%vj(T9^4wgUN=VX+z?lwTiz8>Fqw(Z1nOOxeXWXy{)%6?Iw)Dr`IWOtF`?_62D^GP z9L#ZHa1NALMJxfF=uMMfy3t{lRDx~%q`UmPtI(b9ZeqlmpVf1AE%$6@QbZGV%B~@jivNCo&dvF?I`3Kst4?rpaMnYhQn(IMx7O^<(KYWv;k3>`YN%m-|Ms>|O%z z;IEWzvYa2)5pwE%KoTdqKq9QWvx<#|5(P3kA4ET2B%FTI%>vQ7K0V-OWRixF#qsu=WS5(@r!r+6b>?A*we%0e{oj|IB z69zrM2@0=5MAPS#k6W1%x!(p}n8z66b&4&6h#1e=9V;N8@GI0FeD5r>_dqQ#|3)s5 zjI%`8A`q?J1$;XQWAHs{%{f}Qyr0ny>g`8VA*W^M8VjQm4nZ%M00IDbKm7i(kz_dG zhc`u$z2};PGl9s8od_+ij!0P8fU_YGzG(^-1PLeI4?c=fSQo;Gy8_>Qx9*7K_ zf(b<5BlVGGieYD;7V|WC>Z+K|3=xQrs7Fkv4Ie!?S#i+9izi{^*FPx6Di<0iZ>Ukpjc z_gV~Rvg6qAMSUYzp31}%-1;88SxOp0)y_e+fpX)&<#w{ia;Sk{c68w@Th~vm3;*Dz zanS1OO;lkDgUM4fD{KRVn$#aH=Iby9yHLojf_rZnq2I z+Lo8W2jS_gkuYeTH+|NrYCe-B-}d^_b~oRjJLaxEdz(o0+3I!~VMbvYwmeEA3^tL@ zf91adNDh*<-X5<`~sZ$)x?>37iH&sm@-YN>Y zM#-Sg#}Y{l{DT}htG>!dJ35}8)8Q@dG^PfuqYnPGKFb+U#3A+>&UwfMm!$w$@L~db zB$OYepW?~UZG|tBqZntw*a|#^IYa5GvRAier$O>ZPpEE_uq4QLuWePrSTxd79oIQ8 z;Or>zQNqB7X|})zq5X=DS(#dRIPa=RY(!U|Xif(4!fIwH$ZV~)Q0z8(2ImbDOF^L5 z-Ng0?%>-toWnCxZI>uRogF}omz}d^8;vDF2zaxV|db$HNNm9-0LRu6HX zmBx~${>r|(vHd2kVVKO7Hid9w}2mmB5Y(v}fN<@{IF;q^MJZMC$xj0yM#VaTxy4{3hV z)?4)??}|d6JC?D=WDW%|3}QE{L>PkJ5YJlv+$eTllPU;_LgOaa&e*1f6b8hGwH~+< z8d78F!@R%*zep%{ADJv$l!?&M+s^qDIVv7BT$f9QSQx4(Z7@QL`!Pfqj#&fn9)E$? zbWUK3)sdi4i+_{BIG2tip@$hX2e`6K?~GwLzuNJPPSLc{j#1q1l>?`)z`x(}k#-(z9Sn5N3&6mr&aFq;sx z-c?}EK~xbq%?13BuZfP;Elf+#Ges?QVB;5|dZsNOm9bR$E-HK>Uj!NMIOB*h9VT`s zQC(Uq_T`ZgAfiK8aCg4KH~W)xWK7(bcTnr;8Qx_8)MG7yB9W0xg*{4|f!gDR=37t}o=^_C1$v>KeKzc?)u>HH+?&JH|5f8W zziqQ55-!VVFkFS|u!hXzKU%b5+H;5I{FRoei-v3%r+>T%#8h=1oH)G|AdbWzzRYiq zaIZ*Ga_GURyC95>9au&8r%b?gU)vkGBt)LYs9lHeH!&f}2xg1i= zIt45dw5GVOpb5g|R6g7^=h9R=_hqjW=i){ag&V@!cut{Kgc#S;}PIasbf;XFVO@HuqU`JGD`S+-58<2+GP-miLJg2}v#)Re- zO{Dh*^N5woK*9z1uF{SjKwu@Zm%>uHV7WC`6QXrzFNS5;*08G1$1yC`yeo7Y;fJ`z zo*Q_5vu?<}iA?7a$QD^$)XUGxDyok~_eJ$R^QwcL>eZ!}y106wc4zianQza*HriC< z*ch7Qfnh62%QKYFzxT#VXeSm^GW7GH`Ax0M6bJTEUO2-%=B7&(cdAj5xPRg|@Yd5PZJ`8p|%5>3qqF6n-RP?E=ls7E-fXT7Dj`!Br*<)>@ z^@G%Kdx@uh-oTPAeh{Vgg{*(R>uxYopuA&L>w<$OtuB@O2yxx;x_Ntc0TC|hJi!EB ze$>)AJ8nicxVRjfFJc?{aH@7j(}>S3c@wq{CSuiUE^I6j)?Ql9GxY=Wo(x8JRv;{y z{J~`G)Vkqwdym5H@pYT2hbQ(C3JHg66mV@2rRr(f2{>Ot3s*MsB59b2RIV%;(O5Td5xBa-V}8n`Y`1E2qh!CQ z-Es+WmQ3N+WTdYdJ;c4O;?9Dyj2FMe2$xNLiLiu$qNXQp8 z<`CPSHFX9J>+}hpcSPH>%Z7+9af0rxk^Azncg*yc2Gzs`F{W&J!Bhy3ei+xXO~de~ z4U}YMmT8PLliE#7nnrD(x5X?P)rJiLW>=r(QH&lOap<9|^ok zM)P@mE4zlVT;ZST`CX|t?K}R@-_TtCqBi^MZcO{jbkk`N-&h_pW3#2!{=jJoiGuKx zQFTn;RNtCgd*+7yB2sPZgwywZ@CUHr^%&qkrEVPmP3p$P!ov7JQ@3Kx@z~$gt^0%e z0Gx_OfjfRI2yhmlCuW;{Ff5kpRGTO4Zn&3^gj7j@{mtu77~|g2$CuvjcW81D*;S;53`|?5MKZD?j4&kvsXK&C zkw1PbW3g+hYEUn@5Kcd@x~I{h&-c5{n~z5RQI^3QKIGmiN+Rr}T@<`)2ucBN)Q`q@ z{pSL!Kaag#rm8xNsBq!wU;pR1n z0aX5C8SQ+=U7mPONc{x&$&{e@mrjN!7Ns}`*7d@^51Fe_qTx05)NAjeWnl`>F-yJv zkMUI%v_@r9MHIO8g9A3K(I$E+KbyiaC zI{Qp}0_{=4f7k#apmy`7E7kqz@$yL z)K5TmVl1VB^JE}^nhh>D`U#G%tzdXc<&9raP?_ua1nUEvO77&rBKX=Iw+2>y#)kyP zgmV5OHFKXkUd7e<&?~gz3Kq+)0M{C!)NRyyd$da}+cDPV4%@ z>p0~t;r?L?*ZIo4$TGfxoN}&27+U-uBc?A!Oz1{9u7sfWVMEe0!rQ!suhqk=wHDh9 z!IP}TTk-JlYW%79?4}M}qMlHE!lo>-eEUc9akJfTgFO=$ssdE!aN6O9;3G;=v zoL|D=3Q7EdwM^;k&EV2SjVb5c1`duj!=*}0xR_|8(`D8M8>W=8hS~2T)7D}aS3-*g zsAjAgHKme*-t;J@SHXonF!*8UI8$%oJZs7R7YD57GndcvJc6s1!$ z+M+&H@CB)Zt$pJk-Xvmv{eh3-TiT_q?sP?6r5cQDuAH!EgSH@hpJ&!YF>xbtzf)oQ zcF*&;U=J57@?;pGFyMw-nJI^D?$YbSb3T+l8Bou2)`M@VQaON;?ag5W%@)6=P0 zpftxKM5p2RqF&14aJA@YspIjps7eN>ks3fo9#}b~8S<+mS{=2K7J7)*QU^+$Hazl8 zbRs^3Qq1L;XOz%11pFI@w;svB168FVJl? z3*^GyTQsX#YpcX9 z_F&uy_T|XbwO)fcVBWdNF-tB^S93AZQ|=~9tDO}|^>AunnU$@GEM?-FPM9Ut>#bsQ%TeT}n1w zy@f=HbLsEX`OoaA%F`DJA||C78PX2ewI2hXtSNjwTmP3mu{)_$d6_6_M_sd3SGjd( z=Td2Tv`iCYJmx~dx)v-lg$k$aqCbM2_-FowQOL67wnJ?>NLWPY)5QEr(60l(hFZ~2 zs#WOYC9u@#vbJE~L+`#gL8B8}#VTWj+XQ34CreE6@+u=9yH>~o9_WSL>m%c)pDnYM zy3R`_^YAiVI$aWDZq6p>)7nqO%(S2T(v4Q?C5Z<%ut8~?v6FKtQjXmKIbKso-X#+C z$95??1^|W2JF$OQUcjdq$B`|Ew;$t0BJZ?5%`Q58A_Q{8GqtG2uqGEir~DFp9y{A` znh|Za&0TKx%uBfR>qA{O)pO0!P9oBi>0@vaH~sP~Lr$-mFs**I{386(UqndKBzlVy z^d&>)`m)U?R0dVZhJO(#DjmFn20VcDR=EPS?Uhk5k54}Jg>-DCilH?OM-_#jJZ-jB zA#O!~WV?(DIXRCHKFE?lrd1$@mpK**uwU6pW_6K{|GIFy-lQEb=S)^@Zj$JaZW%3) z%!z#iPEX{__Q!s{3txp?IcCRqrxB%`G96`MmDJI`3e_5%%-AKjnGWA0+oFs}=uC0N z+E}L%Qz7@zH+4W#e(RCL`1iu|l)>wSL>%k}wdzm{!i)4n-;7k^nl387ZTj3}ot)tcBaHdxWQ-5@D>~m1GtTQcg#L&* zJ;C7V0$<6VezN7to`I#t#|9y(tg+*Jt@coGth}wot;Z7E@kaB3K!XWNSYTO+vHF!)WCV}dePQu^Tf~n}l~MW+@f;)Le-qEKFf;tG zQv9;cq$5o$?Di@33HZ|fhXQM{NClFb$?4HQMGf03^(z3uLP!_jK( z)WsSi&IsBSG+pJ3MA2$kOLQx2&H;HpQZ_5+7?!insuGA?tV>ooNPc}jZSKDe78pVZ z;C@E|GeouOZVbi+)jKNeaIHiAIK7_kuTK2x$^(c*p}>7tHt~EOrb_JNr*@^cd&Zm2 zkBpx&Y2_AaR;l!-&THXV;r829Q@8f9Q>tZ`txio%_3-f0k*%B$Ng8(aL9!N)7-NM? z({X$g3?qr45E3BDMa4pq{FCS;l`IVhLodTW6S`zt##W}}Q!HLi*g1K+YlnP`SeTWg z!pY2140=p->#E=`Bsr~-H??v1Wdh5^O22HbshVooZVfCZh_B2jky5~r-<<;1=g0c@c4fyTD%uoMRBJu-b>*ldavZK_ zFG_B10jY=`j6jlpMR>SPW+REU#N4Y?qDVwSn41REtSe=uT?INU6;K?0=eN7Q4s$bA6iC1WyiCD##ORYMcO_$!1( zpEoWS76sX0ej$|Y$`a3J9zqhi2&trUU)9Rq6i@OS%|<_}-!c;wj>YYc$iE5>s?`iZ z$z7?UdgwSQA&)0v_k6Rh&DoxuL+swpda{y6_LYXVnkr&Down)KQ)|7PxfF_Q1Pm)e zqg2K?N?*-m7(|H?Gs=W<$TWcCBf~;Y6xhcS{ndMBfC5=L4H1%@sH5$yt4Cgt*`;KU z@b4l8i{rDGZ|Ig>o`0IhPP{s7B2Z|iZV=m8d_0`|ucAVn2-cJ>K=ti@p8ZLeMesc; z9qeruc-VxkgKK_l-0M0MQJ;M1ymsu|g8z9{Fj=~LJ5K&68A*hnsAcY|7J_N2@9_eQ z3sHb9lgoJ4maru-SoYsvo=(+aIn7Loi6J8;-7HiWOB^}v7m+pKX6DRJ5Qv$ZItj@* z>wQ%=C*t14kzH<(bh-+7YE7zrEAim~;bNuhm}Vh`QNbFq<3y({J>x(U2!!Q151<m!jhg;F>rh5LLW|xx8;$Y|KtMBG& zKFeBu?$M4GAojQ_c%bBFG2>*q-UBge^#LN)RchVU%DCXbRXNfW508fAycoynAsA#MW`vzEu5Ju|c z>(slBR$YYk~+rr1Buu%&Ds5&dab7{gx*rae}4t% znFTswm*daRMiG;4w1cFy7x_|{1?}CH}bTjh6Tp>b&c_!T)$d09*Y1a zV&oS-c`^+xDX!~0gJk$rTYy29`=aa@#Qf3f&5M1shg&Wj??CQE(dwysXVyv8c2Gl! z>On5g-cMhUk|)9Dvx_4LgJJkHyIVp6-z|BSZV3f&!+1|@E+w0};T%}y&pH<7-wV3V zSD$0jqb%q5A{oZK!eVJ#5$u^MOfp6DJA>}3P#T1_E@MK=<8`&tC&0qYXO5RS8kD&z zFC~D}DD;OXd@}BK#HUTS#D`yVa_5NzF+vR`c;Kw<60F zDyh6K>Jgcxj1K+F#kPKUtTT{$0fHtrd%Rb?1UL?A)ep*hujFvhPScu*B|Vv)jhUAZ z6T#wx5`kA@YpSE^hGWiKeG%FK)-67 zEXyr`rl`$rx83Mwo;|U;Nj=NLWEKp;=M*_3<|}2!Y_LLpt=tN?bQ({H+GXlMx{Fc( z;NtItqZ8pvU9N!+e%@i5da!HHP}4;az*IZa2wD`WMDf;sntBuMfSlz+&UI$=y~I`n zgjtNv5w_8!1iG}71> zUb{urbam?0DX~-fsD#Ey(HCqB@qe4L-5GfsbqPp_1Ok^Un4cDiK>=N(PEPNe)Q)He z(Y{qHFf-MS9onsvWI8~BAQfj_*Dc$uUua6PhzX7tT1fOIvigoQAe)N&*=7{Ag3h%! zGNsUYMZy8wXO#mwaT}5Vo+5_^*L1X1C$+Fq6h;wJiSOSfa9v zG17sg_e?}JoMS*3ZEC*HB#KNzSgYYYED(m}Y^ARZSKk^os8_FFPWE2D%X$yM-pJA} zbeu?FlA(<~yOT7s*d47pRJ+MX9aqvS_2N!|@Hho+Dz&;UCQ&iI@v;!;MF!AK1eQWxCKjC4cP{^(6*9x6z8aPL8Z# zP|jK)#8*HysXr0Ex4`SB#&*b;r`Orp3_+HtBP$UzC>74#1{Tg{VwmV<_bY3iL@~6; zIE9<2f7S}2#P#rhs6)(se+UE}0_OYjU;xedpddVjRU-mp1Ar+5!G-&)?FTMLqQ{8| zKfA74s%x8Mf$4z?UQ(%HOdxsWJs~IwZ+M5#F(VkD*D~7P2B8Q37=vC>noPKNbCL19 z5|YG1ZmHkov#WBfWOfC1)wxH54VrGUmeRv|Z`DAHMFj%GcVe5VZN)t*#_AGb)s3PC z$`t?-M);HG?43mhVI-nQRB5VP&&`4b$e+JmMI&G2zpWQNa z838IKtU_l69YLvrrW3IP+|r38>`F!wA~kh^xnMJN?sEcOs4ADxA+v&sfOs56_8F(} zDt0RaQ9aQH^15gjo-B`n1ApMawf`&F_b*6iao<^M5D&zBhkj;b4OkO3K@141&^S=A z6?miPxfZZ#<6aGbSjW1JTt7Dm2A)}DVgbVUW7`un+a&hoJo z5R4Fq0VMg9Z59LAfbt)!^EnL~^$0}X)M_t5xm8KL7*arM9t%&3@}viG3X5Rrr5{(4 z_2o}ienD72P#l9KPNCG%0SI!_g4Y-R1RtF(P+^js_RztaHEJAIl^)#^@zW=5M(zc4 z^k;t147NR@N{Ofnec1sRp)>_4B)aT!5Zz~@bd%6+o<3gIwY{NAu#z1f45**ACKr-u z7pA2K;4KZe)<={(caE!fX?22Ej)xL6O2%g4n7GIDo=1r__Eg!)x-irSFq)wdf|({; z{%ri%CwuXQz}`6n-tsx({GR#xk<-ltU%AUw0N&;gRR5gmBam*$WDhm- zgRFRg%X?G6XU5#&3(C#3y)r1|}IUR~{%m3)57C#rma+!+iF9yByAE3!%tINjBiQK|?4dD*^v zUTorrZU9g942k$3iI*}ePTOiW;{00FQnLQSW!*~9e@|M=8@XfpHqrbY24A&A8L_+||1pc>)uKl_e=+Tn5bxbK& z5vXF}{Ap*aK6#u9HEe{Dud`tANiAK{@OUm7woix0UN zoe0^o1Go5p=Pt4Oox9{McxLXSo?%;oSzyJh@9}qTn8h??LI9rMuk?rdX(v^p_{isI zgg7^n>ANSbZX{qz=!;YaADVr6VUEI(ogIlp#=Sop%=o7CRhjpvJFZ7_3j?Di+K9m= zn0%-B9~0ciDboG7uHD;z?Q`4kYoFW1U;BvSN2UJSC%h9}_up0FLGk?>0}eO;hv?s# zkpaucvpbxWp{A(0N=*V|Q!OYkAi(+-pXX3Ka5fP;+#Qd59c8dx;kPX92z zfEs7oU;bHVx|cu>y)1oDEQb{OqmyyV50xbrk+g33XWtAFJPj7oBTx@Hbz!{C5Nf@k zAXkR&WcG3W3%8hIA-#_M{r*h}Uq2w!XOTk;sWNKVf-*8*N}2Mv+I3MEI9a18!kHlK z^8INtB%n_$%$zXvdOl>qv1e|odH+ULbvu)W!h9>W6HQmzYApcIF#jczmw=5tsh*BrX=Ez;qXD>(=z#>=#q0qV)|G zi49B zAVCRa#dom7SlV)66Jo{Wrv6~Yn4mj+lAJtkG$AqDM#XWSby1%Q zWY6+Haux725;{enC_Fwm%g)WbdYk!3gNXsjZUmP_C@e2MJs6T1iAeIbc^5# zHY8c4w4377ly;_m_{1g~MlK$*dx;t(bzNSGKlv~}3#G1@ie|9sqME8nbSiS5?6ae3 z|H5`kJ=TAIJ~3v|xr=-+>4j%#S~fy24q=sYEIzH(r} z3HbdWqx+kJv!Woou5dR!XhzohW#CucQ1XKdsvzI12eX8z5`McUN;wU^pY(-AhMMqJ zx26kBc4Y#^>A!ag9J5xoo&0X593^m|!IbZ;IhZn;B~211hBhNMF?kL=^|9QjsmhV7 zP#wsX?W)3fT6u8@?8iBoyVL+F(=Z^f2q8h)6u5%yZXqU*eX&hTv#bz@wu&TQRiDpx*U3_esnB38r7P#gEfCpvS4E@X?L#60s|Usj@ktI| z3T8HV=3~#$<&8H)Q9SyCx)(j~$^Chs&-l7Zt}QbQ?)wLpj|X=5hvW%iL_dXfa1k~v z1z%>42}W*pcSi7x?^Z!joiI54wY4Lw>EU(RAK@N!SB)@vrkB2#?<+bvpR6hfBLs9y zhQTBZC4d4@L9taDn{uzPR6L@0fg%kW;y_%7e<70c-^1bJtqF$8?M~&s9a3L3TvqV@ zgFb)kL_o^JUhZJ+;Ha0gtGnsK3BfT2K+%&#HaX?3UG6d@$pLeZ4@wTG`zD!YtRhF@ ziWlXE7+K@I5{wJ+17PK{ZjwW@6tgmm<9@UbX|KZa4rQr~@{`2+yp+|o;Oc|9qU#ao z(hPu+{R|xWwb~smSd2K4h#{6)}nZKU{ z$Kw#XAzkA153U<7C!)p70L%~(>_9~BCpP5?O8d4lSG1CZ;MV_#v2$t?EJ(X`xw>rI zwr$&Xmu=g&ZQHidW!tuS>bpA=F&Fa>GInI_e6iNE#K-jf7g6TT6tQ}|GpcJJyJ!0q zh~|Yl|18<9|{MKg8ryiM}F8AAl|S(6fL}8^~lx>MG!kj7(wM3XY&``UDM+0 z&3=xwJ7%PU5}I(TTDO5Uy$;kJWRHr+y-98_JSQ=_%VegFqy8HZp5D~-%%NY@sPhm4 z)0ZXSNKi1tU%^lCdt7QB-#`ZmsbJ}kJ{qWUs?Kl`M2JQ;Xi-|f3Bv2c+G~*(dk2r^ zpT`JE@{qtEt3l@RE9z}Q2WGLzXZTERTMJ}5jZbU1i7;gpfS{I1I-LDYZXcP~sy9;s z_3ukBtZHm%ok1U|{tFSCzt|SMYVA}*Fn-Gst^Vwk#R$#=CT?qT^s#2A5GE#ipB7>( z;b@~f7_a4w<5DQaC`;(1KzqIy$Lp!V5IK}sc<~mnG7?Z;AvGlXy*L++6gxM(2&!GY*ACrCwTFeUb|$OXc3z3S&PCoxI=8L#T%SU$9ri;L7Qn z{g|uDluAKXB!UfHQ)7REmUflrUBp4*+TRe}JVZx4;)a7%jevgxUyuYcTYOHJ8)}|# z$6GMkc$cPjSEgz2b!ZF4<9<=#-GytxL9uBPl0)!ry3D8^r6pnYzS*C6u)h-d@Jz?s z``gXs`vUQrOtqJPXwRos*r4wUy1<4g9onsgONqS8XTkdC1 zCBRxsqnZ@}NoEPkiT*)l)1c9HT{08HKqF1EW*p_}h|+?$gHukEr2#ylIB0`H_0)us zu;HHePVb3sam@J?^_x`{t#Zo)P6YY%bnU_VQfDbro~7(G4#IO_?8rsu{^ySV|gS_kn)|MG~yJNJR~lHXTC~E2(Y(Z z;}W%rUTd+a$UmS0R^7B8o({$#dIKh=!9FD|hivNU)Sdvg^aV4&eBWqb-GJVXPS85E zKWh1%mS0Y!qiIm6&#+z$=Es9`&DWoJmzq4R8(YUcnp;1YY|)ulMeiO&C{kSL6CchG zBMI^CQ{sX>EoL)@A75AH0bchL+mA9tl9yRulIGZrNA8~L{%a#=oYg%*(3rKV(IOU+ zA5HFQw%Wg|AGTSU;y(kUP|}5?eoL%`Tz(kUkn-HqdR_Z%nGfj0nmD!ZRr#u~pf}fs zfG3SJXPvzA$PZPfHp>&-4Qe)dxNdyb57FycuNpU0oRSaj-rleobnH@bN5%DFNl$vk zlyFD*V|o{V4Br|mE$~@w>|dhtk#!fbux3Ndju2{1BN@hi^kp6nTz>$zrxC>e%X7o{ zKLy+~GBGm!|CPWr=41?3`&~}$DV}^NHL9K;eJH>Ez0Sg<^!6}E(CO9V8CA4*{y(~-2jlnAhsPIRbEaVq zPCIs<-Z}apjKVp4kDkw)s-!n*JoyQV;@f8K!G-Zxe%m?9V!pYZNJag_x3iyrKcr(V z;8q10$&EoWC}TPJnjwEN5W66(0{HPBGVqgIxh?L-DNFw3R2`$#Lj2>)E!`=_F#H2p z!j}e^)%~4L^tiOQqVJ5^DB@eZCLA$junAyYxiCb6|V~UkBYysl&(kU#2CDg#BAM;dHYzaqfS#_0PZ$|k28Nj{Y zkQ#w46Wyv{D%33A4Bvr8T`p;fL1q~SRWQF&kL0sV16cET6pz<5&i zc%q}4qww=tEuj*;^s`Totz-AL+rcZAqfZ+4GLZv6|K!z?QGBM7fnI@86@rHN3qVnI z;^tHxYv|*&4dvbbyb?pD&1_$qHlD&tt!pD#q^M$v5O8lqdKflBDO8~>pB^T z<*Th6St!TwF?i_&up*>`iyLTi8da4#F*N!YBwFb-2z|aCg)bzeo+$hw0rRD6JU?{f zd>yJE{YgFd>U*B2M*sEA52D%tXHA=m_MLYZ-hpH^bIk|}mHn_UTMhi)8BQ?Y?*g&i zn>XKzwzEx-X*UiML6a1pT7A`tRIUP0Mnjd7b8x39y6F07x7FGj@IoEbiOPFzlJUz6 z9;w*ExLd>MUWoLMw~Za6qLN^O8fH7ST72=Q^qsdG^TfXy!kXZA;|^Dp+Whx_fe-e< zSWDdu3gRw+s$sm>?!L|MUAa78T9dbfONTnALe{1@vv`inql+BN2oeY(oTbNc;L991 zI2Y%KgU&Mqr)-NHDA#iGCyyDMWj?r?C(un*mWf=89HaEu<&Map1B#-v)B{OQqVvfXMhEjt6!WXT#qW3N3j?3g)}axR(ScXh5_M{x-pe|dkd zp1;EKsoKn|lz|D4tr^ds&E7ya`_+g!CeQc`kQ0@FVCJ;C1aF%eTxy6i{xY348Sx0= zylvzY4?9BudtzD*bhvS%H*ccv5=*RWn%9>`AUKcyD5I>zO$K$-D?GkDEh{q?FnBCG z2>@GKZ9>g0W*O#FD9o6hb=^|59@2(As+u^u3fq!%lTqw8q&u^Ah{jorELtn3sTB~+ zQxrivlm{gvs9_2hfd)Pp_$*xH@-U_ShC$MHn+5yX0SPJ0~^$%_>S;#0UZh%H#<%U*qTut*wfrX69TY&vg| z^1-g1jO(+V6?qA1xQpV= zx^xv)oddUn=s$3Jm=xki>ke6Du!FFMxe0y~hhVqk z55|YI#-|tyk`#@(M-Ujwe9y`_v_d&~=2^0apz*xu9c#7OgZUa<`(#AStG9L=mSd!B zR(No5YK?^4rtB5V>G=8IiB#2T`sp;fvP)ezMlZ1HPW7HgLAbY8*EM_(#9p)jpreaC zu1-5a%AT0-*)(-^QAz$VSISCVS%SIf?`w6}^oi&yGll?PlG@8&3GX%ULit zZ~~6()Bw~L2o8*jTEN+h;s;N&JIw+{oXRXLRAJ{HLsn8J4z7RQCIOedY0r^U63-U> zr!3N%kRt&D-h%{*)KIbv9&&O7#dy6c(9y-wo|T*s1Iqq=v1V$+w&=Vad3 z(9PlO#LWU6P{Eu1ibLrp{_!E(Hl+kWa{D)ix)Eq0nf|9fe^S?VJ6-Vv@`o4h4cplF^>cztOCshwOD1#4(G@;jzi;r0vmGBPa%6ROwb383X0iWi-BJ0pzp zLggqXB+L0}BcrT#yLJw`wh^sWZutqa{6ri?;NA)prs6sJNuuUW%a)$ zLb0*`hw`LaV>||%4Z8b;>Kwd-P=RaqRLF0L-$vpX^>8=CI| zl%R$cBReJa<3_D`itN)*QJ2EF^&Yx45&~gIvoy(P_}Bf}H}-H9o0@BHx?*dUpqcFI zmO;q{zBxB18{-n7^E`rcYt+)Evz+AVG7xD$Q)S?GqN0sofDmkxJxEpTl`-kXN;xeOvw z)lyMnSR7GXH4$LXg~3N=T?hq#pVpHD37TMJ2Va{@dh2aXG+m(QIh=Sey&r98sWoUY zs)_vKGMQyOZ2Te1xcd}Z5yvonKhh8uO|ud&sHj?+d_&}$T}PN=cS_LK0eQLvr}0dY zt0e^TrrnjYTq`A1F6crUhhD@?3B+Wp>a-+73(qOAn=L}^UZ%(aONs(eO!0y9)9y7w zs97UhM*dU7C>xf34NoFUEGJ=3Ae)=9Y>@TpGObiyA%U%j&6`m^X%@g1POCnb0X#8? zD_8#NAJY(`Gw<}c>S~7C8Auu9thjD!&R81fVVa}cK~L?dyx@KWU_gC(8!heuIvg{w zW3xg@4Yp5tscLHp{HFs1;Aj)u0KJKDxIc#EK1V>~5T|<5LO}KAmEO)-R#$glO+i2% z;)Xq{#Urbz>+;&^8vR_AfH|L{2i6rdl1YdJ>|B-;VEr}>(=VDme1)5ubdpuvyX!zw z%M?aFwOs>3Wdt`tLn^P#OcWv;(oARFgh~U+yh}+ytaqQtLP5qiE>=e#7495MS<8GQ zWhM{=MWQ4Q%fDSfcw2q45P6Vv4H2xT$8_m}P5&oVGp{NR`(cV1CC*ta-8}f`ffolj zegf@6E!RnMOxZ(b=4^JY+|WZ+oqHC|J+x6!_3jD%V{BW{q%$o~Ajf4OA*j%|)~6rk zRy3xMsgaUq3by0#5T}Z&a?hn4mOV7E;PiH}H zT|C7GiWcKwY;|Iy-9HKOS`E7x3HTtARs;K|R^8ikRfz5N<(pwbqC&aBFURuYCQsX9 zY|dqO)iL^}s%^F~#DOoQpSruvZ0+RR0ZGF7#7CG(o;gm}pCf`dn-5)=90~cm#U#S{ zv?5RNDYuk&?0S<66VqA;M~Vo!w|VlOG;*bL zLI%6dJi-ErTJW&t8qJF1B0izTPsFQ+MH?v>jGvvW^7qz$Ie3<*MI|~=$bBD7 zecZCVu&CGQHB!(oJ%*tYiesac_3|`a)fs z;LL01^RtPLdRe~LeW5_f3*35`y^{Xa@E~`87V(*w>yZ=WZcXQ{}+E_8iGgY#2&P(J*b!Bzg{W6lz)5#Sj>$JDO z(rB5I=@%yJayE0}==q4`THsQhm=~vN`I=UV-zbU9mjMDMCtLMzf^V5!<{K7g1hub8bJ= z;80f)m`Q8>CedHVsj)RBu;}8tub0Xe{rY;Eb8qORFo;A8bg578xc;%x{mRxhRZTj-1=;z`3CrvXuy}zdb`khUr?3e?Kx?Lpe_-I6_0ChQ6=zQ+n-yD@v0v?Xz ziwR1E{sgE__WERLe_q9tH7cVS2eHbEqz-#1;#URlPF~YoG2FuH7Q)Kz(iO8tq9-St z!1#nx>#Gt%swJ}POj#7#B6g{W+-}2Xa`vuKq^w@SjL}I(kQYMdTd8m%Bm*A{R+cDw zdxPhydh_`&*rv0&j#sAftC{~AS@-929&}h?_7i#lIY97s?s4{ErwJ5BP#}$ghv_5D z^8vH*yY8MhU^dkaC>!^167z~5oBxa)%4teB@}Eh3EW7tRcY`)OGpRqgC9=lL!5QE)5eW5e7e%eb*BMn+ZeV#DDcyOOkU$ww|2Y{h)Ga6VDMCTf}&%=nwb_<>-< z%&_rUQc(^{ZCM3D%Y@T(tJuz9*j$OT&|}K^r%qx02$|-bhO#Ulw4IfIW=}bVp?U9|4+Gav+DgnlC%TY^+X7910a$c$-b&D9KR_oK?#fF zC^RK@p6&VdO(qCA2Ic`MY_ZJ!VY2#8(j z;wRjzo{bl}LnL!!)X2W(cb!9JF)-ddrw9~Y<0*mjlk|zvs)FFNt}s~rsVWT2gRnA+ z=o+L+3U>%eETiOXAG?bwLx8nPuz|`Jmr`Lyk~l_;JtevMHe_ukde5Ta`b|->l4W}3 z`6WC&_^0+3#vhWDTNu5dU(18>V8&IY*om7mD2`;Iq*!`dAJiBxK8uQU$a#CT*uQAG z^h|3<7UM3vW%Fj|=Gvtt_K;0}6?YOrrL|Ev8E_gT21lGn?qknO4AS8mwaXOf{>BdhJf2jYic!p%WEZ5jb}L!sb; zXRhGO5u2tw;MILM7+6Oy&>dMcwy?DU)`1iHz!XE-En-CRu9d4l@y^yL4UU<*1c!c@ zUD$l3gc{r!an1SDkR$|;E5XS&u37Aj`3 z$DU&&)$(I2tC_tM0iG*0gaz@a-ewTCvi8s}6jJeH`p&T=tO;Myvl3=+U8$l)Wm+al z$h{`}&Y4?HfGCb~$NUTrS}JU+2aorzYxO!(C-Wp?TH|Y>B<~PK|6DC=T^)Ha1o8yy z>0kTA?Kw{$Jc4I0uCzgwCoJiG_CVls7p!|=X{^JrauldI`t4N*ES9&iRpXQ<<|4cK zcbgvf-ya%wgIGh{jWMdg zlBHoPo-Ed%7^1<=S}IkvDN`PVLyV05C6W4*!JbX71JGt+FD_%=VV9T?A8inNh%@XQ z!^h3Ur2ISkeWZ2w2jxr!(_lq~mIyJcc3MDsl$6}HaRl1#^Mk#LH6_GxU=mP@aafS~ zQ)xdp{Tg*DuxsW2`Vk}}qMWip@Q7Dp>_j^+s7iQF^po!cvCieH&P4RJ%Fkq@enuc= z{ar;jjUd!0Z?)bVUH8L`V%Ir;NE`hiPzv1I0P0bMt-MZ2^we!Eg%|!1*Wsy-z5Ajm zqB*zwmv^ezUdBBv$I*8phh=qH1_6iSHVb3rYEiIx?h+ZSdXKp)YoM|LIbzSloQc3& z0-A+wCO^Sb9fAT#i~sJ=JbsVhx;FdjMbHD9yr1baZvC9eb;)m}WX+p@b*j^=6!;3b zgk{BGKmvDLb-n`fZMNk2xOv05#ReysbXen)@?Asng=1NNr`4fkPHWYEw1WI3f6nM+ z0&+qocM!n>2p4su)m0wgT8)ui07Z2?4=E6%vZ-c%S3$lR`;eHg;R#T?8Bwb*eQ(P0 za3ZCue$a?l5kr(Sset|yRzQu*)hGYJJfe<-{*hi7dg;uxB`{_G&yu^>7qlSybS@e}!>Eftov0ewtCGuV7Rz08G$OZ*VKrRA?1sO|D8CdmQ`GngV+7c)> zXwF-F=5<$gd59rxfj%-~F zWFepprZRVV_w`!{Ww0F>OH4n;DQR@`7i2ku^zSP@{L0M?-=dkmq|n{=m_7pl7cH_T z6Ui=8Ja-gUCuVu$+~IjKFdeB{LfrOg;nYQDcUWVz4l>68YGPHZ?{V*LZraBq7oP0K zDug)pPlhP;Tt;bSJB$A|-Y-ee+MIZ-UEp9`KXbV1+RnhNM8?o=J7HM`kn&|mR6a7f4sBZX1qwht1T5h42$>)-BlxZ5UHX zRuih>TU9gCO2r%WS3K>!sVz^{muYh!v$g!alSU)Q+q<@m-r9n5=L+TcFCUxfe_|Ih zv9bKeyl_}cDwenvrsqWM5$`l&8&3as6C3WonRQ7sW?<>Lk@~8ycmEqtMK z)2n^ZI+6948J9}e>f1$O+&dVnKuKP_8Pl8jQW*`A^MA}Zu%GQD#uOjlpOe(yfeBq& ztHyQZ+q%qwWTL9mNy(n7zt>HyRRDZ0wN!fx4lA9mwU8pmTNn4kx-V}Jsgrc6(}zh3 z?Vp|4eb#egS9E-OSu2_0yk6q)iCG;%s1B;J2S6WEc2-x9$ zmhdxbZ!J`o<&*)HOSV@mD`@veM_7||hb`6`WoBTfP}z+SIv2{YM*?cCae`boUJom3 z+r%@cG@i9Wf;}5u?z>LtudqKQ72erDy~b#j0-|&22PWX(c<2N&47yG04HJ|IclqLc z?bKl}=DLMGnWMJNTMY{mcqxB6#wSIHY1AS+I5R6{Se(fdpoHB}xVOO5vApUdJzu*Z zzPc+Uw7PUMTMG?$HDJkB#sg1o^R^DDu`AM~3{h5Upx#)MztW^XxLX#muK$4i;G$Hj=uk%FCGq|poYBQ|Jj|Dnf)o#ge42ub>V2)Q<^UpL^Xn5|> z=O4Y0;vhGIo9;K+gEPo=Xgsa2%iWfo<~c4|ZrHRvpOsmm>g=G%eHX(W!^ab?wb11^`;){wbP8 ze_qi!Gk~Gl1mYw_5<)R{^eajz(i=KG=AGOa-j+O8-jY^ZcG219b&iL(Xi`bhAr5*t z@1x}7*wvO<8tbS;SzFgJYcdBjtl&W5h@U}asvvc?oba^}c`o6xY*1 z8U)i#r?68EUVe5i^-!LtaFt8-(or)oJ69S!VytQQ;rzvQIm^w`tFm9Gx+zlCOzt$|sdLSTIW`g7 zt?MWWMXT0hzsvo=Zp|vrNL5Wu$aY}nHj_st=+ykF#kHh&tJr%aP26&UtxNI+ zTZnRuGLZLk;w0-bIx2Hhce;Vz1N20X>A5oYP3TG0Jn%M&?1@)3Tgu(vdKKWOzAYk* znWK+=%`rT!4~QJ%eu}pkH(Z=Tn}Sny)?)QYPs_oYOq;sClT!MtJ zg-i~g@4%Y0C3bYGgA#q2D)UbIB7P;3i0ulQpl^o#Ia_-LYKf*Zd21<2SyQQUd{Q$F zXE8iGMfpB-HDTkif1m^IA^4wp`Ctx%^Cb3F>dH=z@|tI>#mZ;wu%5LJ4+po|zj$m{ zQBrt^xkV;m4JyS4RVHNdK3B;65Ctwaw|mVkw9SF6-KgkH#h8~wA=-Oitq!JniA64^tnoURcs93nfdCjlP5pl7LY(3i zoWrh=UZOuiqkG(E*=d?T)dEaGY%?BX!|hB)5HcF8(=KlQQ2Wj(DA4?+d7N2wIfqex zVQj-gJ0?#zGun{KN~fmHRIllRJlT;s&Fbj6B2!cGi&52Bb593 zlr?OxzzJPIh}jx$i@54tyn~6>0t$#^p`&)b392R4NeTjnAbzUrsDw3(x`ZR^1Qpfi z1%QJ$cXz_GIY3h7JeosSJ7NmASSG4%4D*tCeaJFDp;y$|tSF6IO^pNJovn={)4Vq5 zJ*(RRIRNklG)wY3`<4_VpWUs{orneWW}%~pog}ysmU)nIZ$l`dR*sBK&*aGfxL_#N zyupr|s+;|Mq>8GLS;vk<7LXAYWUGYMM=+Z1`ec!ZI>!kWMTHPbhbgy6xH@KYwu}sP zV&~ocn~*FkUc=Fna9l~y$+GgZX&=eykYSmpIc5Xo)QeMhj3L;M!f*~4&k1zOVr|!}p&xWh z(DbAL_YmX0%W0)I?FpiX5IVLi-2sDOu?a+_FyrY<TqDfkowHTS$Ud?C=~CvM;%#@d(_k6_RApPV41D=*5ucdHzCseXQGYh= z&-pdlp-7Yy6}_rH^NO$@ovc5L?*Hx7PRd`3wX^Smc!gr}IsgS?ZtxaMIIp|%h!z7z zYG?@sp+?5!6lzn1>tF$M3N=|uHEr;BW8U6=XYtUGuC!N5v83&9*wgh|tj}ulzIdnb zg!D-I#`X!2P36D3;{~k`t`&m8aG!c(#*du4eZkLpjuwfE*oypy3TGwAmiMy!DXne7 z{IY{6l}i#b(k_L2Oc|cY)|S%gCW{X_HxqeR7n z@4jh)_qcP#m{FUN{JWwX3a%5$wAMx;((}DBJgmclA>NlaJ1Rw&+|At!(xj^fU~4IL@19N_*;}2);I<3F%1#F%i$L< z(dY%vdL(8giNE(}cBuj8FXC{<^F{$w$6?05-HEJ2Ojt<4VNezYdxuj0vNTW>H=bc8 zni5d|s^z!NchdGQ4p2yM8jME3w{#2obg9;cy5&{I^V6OLj{PPW2@-5oL!)jkXDrEs z@>ps!<^%jefbhyXZV7*UF3Ckt1z1zJ6CbsIsAVISmVeS)y#P0pAHLzW8m6R94uzwx zw??y4>N(RTHpnAql6mYc%jKT8Nq42ocxt>3Ak!mPP5BvoGB?V^Zh{5mTSuCFNfw@q zk06a2TE2w?;=MQVn=`sQYFvx$DfvOLme5(}d>u}(IJm7YnN=sz=!0&YS&?PzSw zkjqS4%@JTC1e2OHm42=Q<8Y@yRL?`wtG6R(0ju>Ca|ug$>`w%xOwR`Td}a<>a}lui zFc$4jFJmdQsrUw5>G)my2HT8Q#5PwFTe?d!OGHY?%k2Tj6bUHO`S0P$dUa>U>e@8~ z)dO!bdm|wThud1<)>MoB@;LFs4f$#@;Fx8~RkDTnaWetOG3wfKe1KZTWp7a9n{2c& zSSZQ21YzKh;%y@neT)3j=6G&e8Q^nn{pzz@RpcT_W+uuzzt``ikXG40p)M<6bo&jU ze&O-(qt112JGT!}b7tH?NsS_m4dEuuDYDXfFR2)tb{Whi$(NFU2R&mG~l`{vrW?1HVn? zBh6U;)>3oo*5IYF9v>lzWRlg&B5}Hav+Fpb$lVLk(a}Z$TJp~YNgtw@rjc|%O>XZ| zz25yv>HC}U+vLanNw0Zh5sUk+i@WckL0F}XXz9_{cdZP?Lo#1plA7dN_cu%{8gQdP8E6jAG?I?M(^gQ5*$l(P11ScbZE{9G?l97$% zM?mI6n_=lMYp=&kOI4gfRQ^z4l|bc9JhOHxq0q?qtZ^-C}N((Q8~C=zHF#Z z5z&R%?b06&WX4)^|0=ddJx@VNH{Xi%;&^1&d%~+;g;A^f=Er4jV7FtPC+=VK$k9=6 zb~NkE)v;C8IhAp}SjnAU?3gAm`YX5wSDrqhzyUtf$3l&wY{_Sj!gl#J)8^4s7u%$_{lN?ux&KM}r4S{8~}~ zDowYsjXajxG;ffF%u<1R>DIDnE=_7>x3tRKg)@m_&OAhRoopV=~EJQNIo z-}OdVf?gv&8P1^x(-Q0G%&nmsFrJFe^9^D)kJlvT0F^vK`m z2aHF71<5u=6bz1t;ArQOod&*#SAD?03BmcE-X#%k|jvMb^O58|;TgojPgt&_X*65!5~8S^PO z2(WymRav4+j515ped^l52pRiT6iv{>H}Jv#%&}EKO;F=`Isb_Q85F2DF1DXp(qkwI z-A-GKM_w;o_8yyQjSm-GW$DZ6^pBzt$q`9HiWUU+z6gazxJn`(2;D6hTA|=pxV( z2(b^^AM)_cA8DqLE7FwdhUpwL{Bq)0Go;_6i=#Kq>@R%S3P9N2HK12+@Dp~5<@$ap zqhmuA&WS}LxmutmOj;jHP1uvI{w3h+j%Sgfl<=ZjNy7zekdLWrdj#0TQ3E^agCcBU zp_lU@<=!nfVNe}qbsy_MmN#VSj!@$*MfH0ILD329B17wvcR<{l&!UFL)}`8zQy%+g zl?%xH%hJr{wiV3)fK*jjT}hl%n)Nk$|LVC8Ooi3Pa7uMpsg>2&_$7%I{Sq0T(LGVs zQ@`b#*%20QwcCuk`+XU*(%K$IM5P=~ZsXktdOx`1N!Q~Bu2t0S3+hf`HoR}D$RuGo zKDF3z^J9nPL)eFc^<}f8_lL)wd4NT~SkP;G+#?tcfBmL8!f^wY5jB&nl^Ains43b} zRw}hKS)1St=gXX+&-V`;y1ldH$uT~X4SC)J%!vquMLP*+#yD?YYYzjNj79-l`P@_p z2c9)uy<;`hxVvMdZ8IRi3_SZN7Go`tRk6E!>l2vxWb-BJ_T->IFstrJ8>6Y+8}U}| zN#fq@rW6~UlSoWy*;0GeSBzk>K*OSuORG(mai~u1ztgr57SNK^H_(#szoF=1v4mc0 zAHaQi5(10GNpe%^+Lc7P&zzzh-*!DMq>nxPceKt}{MwC+TrWIsD4hr&PLM+noZfj@t9jtXf})w3@Lj z)km;4r}>7hvxU3pS=P{dky{gT3#^Y67+$VUJncy>@>p97ZO!^awyU!{J(CC>`-$$8 ze#{^hD6*ZfX><%<5my5-4SS-J3|o)wJI^$(U%*pxEs54EE0RdD7TfzZbw9W)y|>vo z#-7F>83|84C~>Sqsp=)FL2MzuICre*l!a92f!Ri(SBHHNiRK(_z`sBPg>tqQ&P-y> zh;|z!t}pEJE9OW%!UTR~j#CJiJ6@X*;x)f}@|72>AT~Skaq(e1N)izldfxO#Js4ZY z(CGJ#N@OXBKqx9_7)ufvZD-xmE3jAROlZ3NjA#vR82{xbFdVP9T`1_3Y``f=I31;b zV2sDAE}=SGUQt*$oZTK#Y(4Qe8XBFnA(8 z%EjPFl{zwyx^7YGi#$d?6Qh18smDuufnnfxn#^3{jBSqsbCAjH_k4U+9KclSQPlAH z(ZqE_`8hx4^D>ruSv9Y6o3b$UYtmnFbl#>MNpfQuW!2lq^rXW|Xsp#vIsp@!nnkaj ze5mdMLb(9*uyuJ-x%Q}gvT+`tZ{uP0ngf;ilFSSAm^5p$v7Yv@zMDgcX2xt_&xkhL zS%URk%l0>tz#IO})m*8trk*5MZ~7Xw+`#M|>}FyG&T9CQmxs|x6V)}TzT1~+xt)hX|9DIbSappcfmTAN>Bx! z)IVNmd@-gRK4Eh%ij52Djzy#CQnMy_tg*d>x0|&Kb9~-=$aZCoTA`v8XcFYh*+gXE zg+@ao^k9M13sl$#^DA<-RpU`s)%0V@ly5Lq11q|F-WOt$6~E^cj%NE5vI`Mf4{#IL ziW4>%5NSeaJ(t5CRV|rTTiCNaOJ3N+dqhnR=lJno8oV$!Z0pKf zUO80jM3kouRuRh-)EzTgsf=?Oog4Hwh;<`NF5so77C4I&kkayg^%=@1~Vfn!2-%aiDj16eTf|W*2Yi%IiM% z$}DVjDdy$NFyh|L`}6(CBpFkvuQz3(IJ6Wc4wi&2p-3!oUD2Qb)bm*^nNaG)7UIZU z6wf6l#YF3zjhCCkm%5ak)u{Dd0uzKnxZ38WE7(*Sm}b@cHhO1YKZr&52T7Id49dVvKT3%BT^@BT7RI=%~xc z)4Eke4yFJh2}%MjRf@~X;}gZmn+*$c9D=C(_dJi({JR@#na_M#HC1|bPuyQ26?t4M zE{?g*Hjl0l6YZZVsHNzxhV?ds4DWlATGqe0^xR*VLiUUjh4GiWW3@|@HBuG1_V7iH zE=|rrd8L&>8^HrN6s$57ud0?zd&GoSRTN|)vtEq?V>Yd-6X)6jMcMF`fB{Oz<2*}s z!P#OSoQ#J1Y9xPFbkc(Y3{%*frPY~Jcx{ccZ$h2K^3)JQBTV)Y4vEZ!}tWc-8_BO8Ycmh#a?{~1So*5>3!B@c0?w~ z9nP}gh&|Gw3JW4#8m%&%e(C*MNAT?qMdxYfCuqwmBvDjOc@@y- z43JQ``Hzd#yn8mO7TstS#-c_d7xyeiw3>B^6a9r3BA>N;vfQzENCYg7;yvCb) z0H!y>r?}^ooZUHej5D^;abU_m9J1q+r*p5@d;twC_A>g>IQ5^O>?x)kbB(|pDe+#F zY}p>Inc=vinN;c+Ztf4l}XrBaV= z0Qek+=Dmu~zs68Q+dN14B6Rd-kqr20Q?O%+T#1GwQ|BkwBgXR*G=sV7=r?DEQz)TZ2|7peqDoHg<0IPOV=60PVz^stKS)y{i` zP&=l*0rjS{uwoPi4#K1MZ?|^N6KW-hOvaM@av&_K?6OBxrY`>rkSygU55l~lWp_H5 zgPlF*c!AEwC0?^|nj`kcLL^bLh$)n8@W4iYNgQfe9b8o67bWCC1^w1YN*t6(*F*p< zGNIPKP&(mN>uFsItC-tW23pdHs$;1Ns5eGQ-I6UC!C>1EQ8C=-nQy(gVQs!58;L(e zlmT1PF6+09EJ5BFzE1TQogIJexb2TKS=T>JbMA}P&yr-(NQ6az#tk>Nu~kSzfR%n{ zEauC-3DHdX4e-B_>Cvr+Yj!<2ALe>|)po~;O)5+uTeGMsu>@#JycW~>XdxA(yfK>^ zvWq%z{wo}F`TKn0zHLCF=n>EWEEx2wLdjncMmVKHY0W^dv;0Yy-VzW)?2iY2P%*#& z_Y3taWCzwK+BC}ESh@EYO+;g!`DEt!s2DrsX0^zMJX%j4DrcJW<{cy6gP5cVkNSZ; zZC;LlTT%=y2e9Mt`9LQ-XN8lwfocUk^(eBaUHb00vDbSH>8mdb;>7kdtU}Ecv44ZP zp=`Af_Wp1N5FTUB7zy#2=HC3pwEIFC-43~aZumzGsf!-FZ|6$rBYQ8K(Zn8VVw36YU*i$_86 z5M27+8+zde14N`NvL8$aZktUzSDr1lwOxLW8-W`$AJ~2BggRR?3$K)NmWA_1CWHy9 zq0twPQBeZYVZ)^4lWYhLMOx9(i^pc+(b>}hU(KiT#@;pqcrar0tp-Yyrj&)X#zS9y zoG}eA$9g&42BAn7H(edzxF{q(RC~y-W2Hef328}F83(Nu+hww0s;V7j?klw1;$psZ zWo1eh@!15RyDb{j{h^sGWI*1RBM=Nb_t{DxZTvD>)!Envqa$pu4lNq%?$sZQKrD~% zLzl`34*hQN1ITJFlvvPb7t({FA=|rs!oK1vHjO>g}=%h_-&792% zSy&nWAw_Yiqhp7|k>azXrx1G^Bt=TchYwA~b*;(jQRIaRnL0whxJp%s15^dGhl- zyDY25`XA0Iya0Xk<@Il$TO)?xOUH1ub#z=GmslE|0lMYno+p{gll6FKtLi~xFb zRf%1>G;u0A*S{M5V?;dRIxx*0fQJRNf@V<+3ga8U-{9bwFUq&; zu6|KU*ySNUa@zZ|g(}|np`wpU8TzRlg1_U8lbJtijFVv+3L%23T^ugr{leZ+R3+js z7|u6A3Q?^jDhah4D+_&uuS6)Hv>R&>dJBCGCKRBu)*1nmRN$jZs{uA01$||9=8E`> z`G*iXD=6-O6 zYC21}tvC=mkH${N%^wAF-iunA#82bV$X{dHONdL670LkJC9}&KEw74Fh7;sV89^@~ zhol+SE2B!UVu_k!s&Er7k*>h*Cx{l1NjHg8RafWEXgGLnhd9AxMU4zk(8s$e*gTeRyvavStF!JK~ z5c;XIB-t0$B{KA|)d8=MXI`{D-QA<7W0!jVLvx$wxY(pIStofa)4+!*Mx{&Ox||vC z_v)-B`SUoF!drHJ$%xO658M0G_3`r67u*3eto?Km)BYvyePb<0b>-X*mQ}gwYsdF~ z>O!u^8l%F^&Nstv^;h{js(kO4YfHCp*J^kA$K}ye0|7>lwOI}Cv>o~mOHa3rZC^^06A9J13Tx*sr$NouP-6LBB!%=w?5DRIeX~ z%}}!o8;dI3UYXk1*Zwn3@LuWH{{2k#ui84>)Mnkz*s^87R@Q{x zzp-R#udJT1;R@3%sttHV-r;{e*sbbG{NAM&5*53!W5hA8y!^$g?)~xMne0ISx(tL= zp*V$Vs8Z~)e=Kr8c&d6IOrN6~r~B0k=<=@9Fm76Y1xfSc--9=d0QS6%2HQ~Qnv_CXtoqKu33~WF z_%{Wy4P*C-T@LNI)q+EU5wG9)5-HH)VUHO4lDn(|cCw4^#(zKt_k%s;D(@eGg{3n*y zWYgX;0ylG;N?wdXAVYt$WHV8q)|Af#=XElf`9RV4_mUJ%5XyGTCGm!vP*_rOM^^iZ zwc+Bj%UX(9>tH+E7xgM(k8zL~QZlVIg~=>UN&{kNSloLFvw5?KFM+tqU74;KST%{A z8K|`T2yW|cd6DhZ&}5nq#L8%8ts)!11?K?E-E_cOYj#3TV_)E#K#LB$NpEMXO(Iq* zo5o@k)!w|Gy_WY}Eri@^If3Ucgc0N80a06mN$PW^0M^a9mIVvM%Asz^S=^7-3L8s& zv-BJ>jhFsge@{#&3&d$pUU(q(coQK!7zLx%F?qW3a8{*0pklfVBkeaw;t9Yal7TUa zbJ*8!>K(*bW^wYicNg6D;d>^$1rwZOFMCeIG<$hSvtoW7N~|$l7yWTaasvRVyYy4C zbU+6tOI&53NW}~@loAuJc4dRoF0Cj$>A~SxfWC@Zx-TeVOmG_$j@t!R3kXczTA~C1 z8+;O;T;Azd6%L1Gli4(eFyNl;2l_PC_guBMw3>UoafPZz$YX!$e~})bmBOA6zeBb< zI?6XY;?C}(0HwBf_0TqHVK_%noGb~RWwhtjKzW)|6 zgp01`WECnfN+1JKUe5S7A_Roolr*dH?h;3shEb(7Blw^GUShQiaa|=`=D1AQ(k3N+ zS|Pz)QA|L93708W5Re<=MZ`M?mMGU#-K!eB>h;o2oaUZ*SitgEn3{iUoB zhgp5>mTxwT1Pe^iu@D^+q~sF=a+B2Gg)>gm1FmUr0b&yt6p1BsJ^?78&WcK43nL)0 z{MhMvzsb<<)3Mx!wCzz2P1y02;<7Li&K>RZM#qX~XJ{^bpAqBpkQ_mHMB#)r>q3+6 zr(E6Gz2+z(3oH|Qk(WgNv<w$e|ZhLzoZ7DG3iei+`wBs&&ed^IZ&R+f*M4rP>GcG#-m) zl1ZDtmk*v%LLRXxZxCB>v75>gih(OJqDB&kCqKl@VMfK=dYTLiF9rY|ZXE)5tV~?y zcYoGu)6n_>YO0SbAgei&MRCJR=z4$74CuR{x{rf==VLf-cc$$y+z9s{fjJOT^{;=6 zk<>2l1;9zOg^1yR7y@*sBfMGks%rQq`E+R6GT(;CLi>4ssP}|+j_=}Q%|tIwVG#w8 z#P&GivopSJWDa651Z57599eoqT!p2mZODwE?SjUUoODf4^JFasQ0+1kdiE`-dX|`v zf@ybaS*Ng73~d48{3R4O7Xpw&AqgpR5A=Hd{90NyCtFf8HxMT-0T6vqB-|)v=NHIu z7~AaL115XM9XxP>Oh9z@p1}Dnf1~?5VdQU-Bt6S1*0qkpX+E)^{xSy^4>=lArOeQL zj+?A0LFYTI33#A64GP`7AIDfG>L|TUGR4>=z{~w?*I|NF8O_T(S;O?IB_svCeLtpU z5O>GFx1QK*80{jdt(G5=IZSs-1?+b0v7dHuq#PBT(RSE|8ZL2+)Yg4d)Szb0z-~L- z=<6ajFhmD)dqTB3QPE))JLk=qjEFh?dF8oo^L}O62N2wsTHw1%cu~Qu;LNat;m_{I zl$@k)wqAMz>-j8q&PkA8gW9oMn&~-5GHpXY3iG8#@O`oG7`QFQbRQmG2bTjTK(kLR zjC8)@Kz(clbM%z(khu|&bN1pY=uG>17*@D>13%xq+IBvnI37?WuF*mLzV?26^|<$J zZQFi2v36+K?(FC-t(?a;;Qq~m4+40EF&!}>j@{!5PQFpLl9x2g#n9uCQY^^p!h&VT4@5Yi|!8vTs*}ko@!&WZ)SzJ(l#Q%Nx=y)~l>VBymb!I)k!%8`f>e%QwGL1iuJNGl?REv_!#BybSmtI>FLffl{r{+It2o%3~X~oSD^AB)? zfWF%v`Z66wJFdM$=PuQ`WhKUEW!Nk-A{@-loR;lnS8DI>@a3MH-w?@REI$M&Xs1UY&)nl}>5-^k3dy|%5E_vjW$)xDHkZvOFE z|K7T3yWQ#D*4^#hmAzv_r`x$s%gcBG1}ShtfYIgF3Kp&0s6s1^YHb|_W3okc?{jS7 zU+!V$8or4?clFz$c_AkEg3~0b{yGV7e2);nXCN`uoxA(I9+fuw`VLj$>MoJi9rg&A zo69vCZq^@XXK$EavU}inK$3SD&cJJ)62ud4j6UAaUnHN`Cf(Cy8_L~AbYG7)Yb8R9 zQXAm}NQj4dBp~9vX+Fq-i1l=WfIj?wBwEo&+qY4|ui1F8K?2S||Gz@VB^wAOME)g2 zoi+q78zg^m*IIF|u6dE%4{;VM9T5kc9C$WAFGsg&hoEttY|)E~_$#E?r|Jlf#+vO79AZ&opM}0fG8CgInEoSy8KV=; z6$lOJ0m&Sgn=pRqW29mTuW^39j+z8CS4^S>PzsrM(N{PO-$%akNS4+#;1DTY@u-uY z3KgAT%(!3?9(?AIzXYWYTrIX+X(zf%s5)VWwdlV*EUt7Q<56LL-$7&Lr47W5#Am(~ z14F2Wb}2P4;X&C~i6=!rDO{q&+y*Rh1|)IytrU{N{vMKsj0Ndm1SaNh11$^GaS*&7 zz_S5bZ^W}*$<^CO(qd=`9eOJLvkxh|R0-`tWaO~hA(D`jfeayBwh&Cn*-(mJm_o#l zRF>S6Z~6*bvVq}#e8akPDun-~edE}Top%Y-F6QZh6`|u2XT51^=zy8?aUYmpbST{_ zQiUYn|5qh`fY8HobZ?#)HN{yyXgfjzcxIgucHnCj-Cp6(Bz+VYMRlQ!e&7uL1e|y@ zN=K5wK!J8-jy}RI35Fqjk?t02Ol34SVzO2sHK>TQg8hCdO!D1*sH}$tl5Ygre1J6%8;^eRwtSQiV>9jHx32V18MTzkfXXHl^*C8nNnb0hqI)x>1>@eCqFVXKvWp) zcL_3I9hK}u(00$jNp1r*wC772rRVjkjmp$UpE$C zH%vW}=$iQYUUM5H*?T*>YRl1T*!?GXf8p=eBNjMREKx-o<`8@3LgoRMNI+zPQb8bI z+MS)y+ZT!=fQyz&HnYBq)j&UBmMUqkyT z4kgV8_{&h?j;_FU5X@En0+b{5e27LGPce zE;xsJ*lO%3o~wtiBYf=HtS)&-=ue}H;^ARZm835|wXTHL1}t(0B!c8x7rDzKh_M_K z4wcYA!YCM4TLxAj#{Pg=V0mV3-J_9m+=DXzZaX2Hv+FZk$Z$|8bXuK6Ta326h5|SB z<2-7!+2s?BhmnvHmk{dJwaA&FsP_L|ulTMOcU(J zl?t;+Y3o+@YLnps=G&B3gU~XTx~rWv*NfdaVORD8n@IvPmq{saage)r)Ck;MFRNlI zj=IR7dQdNM9oO6-){C8HvqY|{O~}pP*@Md+L(3gS%~|h65W9KnkXZKoJIS1ZxeJz0 zpc(aT_LsswEB;Eagn;Zv8QlH4=V}t@R^pQOgd2=%_&c^E`#oi`0Q1@3p%0lYTtpH0 z`!X1^F3-R(?E?tfkqda>`(7neM9lRKY<#_e7_x4y$oXgXpvNv@SU1&N!%)jE+-00S z3q4jTf-g0)M>|t!JYPd)iJ)dZROjns2CM0c2Z31%VW)k?XP?D8-DtUt3k<&Ilg`Wt zB8~U^A5XT-%iC>B`CiEVp!L&UE5j>Xsfw+v&D(8E{Y?%JvPQPd#oKMrxn7ZNgK#0u zP7BilzALiQTw+_B zNtvkF)*|*EWMr+D<5J_ak^;&Gw2lc{n)OU;RvMC4aH2Yq zxt4e^=c-^SgISz##c&_FQ!BUuu{Ps3^$BP=Gi_L&pnsH(s-sSmt+~D8!7vz&2J7 zQ;w$+8m|i)){`9$ETA&%g>9xnaSWJP-J4`JHtN&P#m33JwVsC7UXHXj98I(K`H|WC36&(Yh!Ed|u-T3TN(B}@jyjq#$nUS}UPa4T-hzF;q9 zD}a6+*#`1M;6Y;0 zhhg3at9rOYs^vAV6h-X1WUW#(^*8~^%JyfAib)P|^{v`#na03>M4^+&G%UxhMT!?s zEA}-Y!iiO~^u|x-z}uK9>lG)&LnD+RK#E#@Z$_@#P!bsXAT<-Vy>oHbN)bP2*EA-Q zyWbU&%=4SMqf`WPpCtlsaw_U2xJq2z=O7I(e$rRpXsQjnT(K{Nq2#Js;wk^&PmNbO z7cYs_(S0bTtG|VHsDJiA)fBV4+?~&bQvo=%O@*ISP=f?__;8K_gZ+ zkgH27*HXd6j643x%u?=LwS-QPXk6a&6E5j^QJE+`E0p|A@i!2CQq3!21}5cMUB0CE z7Y6RogNasiBm?kzd!YMll{>teeo*#(p$J!2d%80}8R zCYG^`sO&&jc|;RDRcyJB%8%+82hpK2oua6H4M=>l6|7SC(Z{*vE=|p(w_DAqNR@Hz zD0}t`8cU;>xdaQE+{R`2Y_q|)r=6acjS)RQ-y z9hBw~l3ZXJu__gVAKngyNa zQL@H zzqaN+VN7ShzWM`nk%P@#2;zBEjaD*;4mx(Yv`#derBiosPMfR(4 zdvNWNbIUwCA(F^E_mzn}y$`3#J@+yE0q`x+4+rbH19s;?$6ol}_ZA?l@r{C6uX?}h zV7=l#;Oe#mL}lDxnVWgc5Q1Oe)eZGK?0SPM?%>5IFh#pS&t)rLWUZx%e3U3zcD$gt z7U0Dz&=tFY#h~S=2|U`@(5rFslA!UeC{aJTPtmLcpHMnwZ&C)}s?q-l^LQ@EkARsG zXaRPG#jR2mtb*TZO&)EJbcmA7Mq}_sf0HLoXbW2IoqCriE#MnVbO2k_2fe{lN&y^F zUwK2auIP6BwPAxEaN@Kkct$IxSxX3bW?ERpw$TcOOs_7v{Wlo|yO}~zd6UeDSA9q9 z17o>l2Oqr$EKoXbXKg3kYhbE&{5yeyJs};34!C=w`4%QrDP6~2*cCe=>`*&rV@jZ7 z`j#kKk7Vw&cgI-AoC1_;0k(CUF(GX`0m-=HmyS8AV}GqO#d~_aHZB@?+KcQ2__^(5 z>wUm^{UMv$L)2|u&wF1^acub;uuhpm=6T$=fm<*y%IpEpM9E!;!h6)HV-9L)mK@2o z5t={!JWy7--7itRajlYzaN^9$X0O;i+Mzr){i|$AY^@Nlm+L|v;ab+o^`)3*&GdU9 z@2ywNsBNvTuy9fBSK+cS9mO+*sQ6CG5h8f|ri8L?OX@Fgh6kh27vO#|**Bk*m^N#) zQ=`@B%Q|eh+rp0JFs<}mx-Hl(eMPlB$>g-2OX>Dars}A+s@?o7siEGbPIE$Nld*5# zVQj;4fQCQ%xez1uHd)NRVU$@^`n{8xfl&ZBr2Lhn02pqWQYD#DF)u8euH#QDex4v{ zwp#!;KFQl4AwL#PXxukZbMQuhl~bF~j-K?f|NeA!Q@lFgz@N-=en2>6Uj^HK!K{p+ z_Uf==bIih@<=(R121S_U4z^q3%(=qkzG5wzS6wf>JREbnN3q}3xC-i$O}iZ{cEn%D ziwR^<%H&!pcDzbod1XEeeR1n;cEnF>qd1nRnDAq2PG%ygCPlw9LA-H)DczvH3%SVZ z&(_tQZ~nnP@woNiIb#hojpekq*+sY8+2y6T+uZS-*gYMmqZzzvW~ds|5ZR>c^yqaqE^B0Ci)F z8kA?`xabUsob$-hjYxufku0aPq_nUIT6Sr@Tk&}8VB~Wx_-n;ZZ^U~!=&CQNS>?b! znF_5#mt0o#?viAe>!@tnb{eOWJJ0t7=0;HH3>Hk5HQKkK@)zXUm zP1$gohMT|FAPxcx8ucqdC{Vv{O$cQGQcg}zU*7-{pG*AHryE70tQ4KY(g;!4Lby)- zVJT7MA%QV5BkL(qBC*AQm?!>DX+MnFVoL6yuxogyRWzh$!ML$+rMWou}K_#!c zA;5vRC9GnJQwN5@;mM_kkVCQMCf5kT;ciB!!@=uCFUEm+HSg#y$tA!BG! zD@?Bs=Y76A5ZHx)98ESG5!wXI8DHeT%2|&F4Tf4s|I5pe3I&Rs-&83p+VI0)s34aR z5#cw88~!^cye~Ilm;}FA@1{BbNnhTa{+>TiQB>fbmiXv2oTq+o2Ytf1L) zjWiUSsYVj|!=r-=;Zh71?DfIvjnJ)U-A^Zg4G(xoVnuicn-CTv9**dXMM34_A zMQ7t+$!$P%8*4>SZ&pE&PvIBV@bZJ!Xu|o)1Gh5L^qt{yOec*0NC!omFvYs3+rY{S z4Kuu2Hw{kSI@?>M5pFwOfElazA;sv6(}K_hN_c_;sn_TVIYiCjoJQ)417t$^Cz$e$ zvE-)~fE^gQ2XTQ=0=)v!w*&YRAcqHKvC|0D$wiK_D#5@9p(~VPh(J6* zm=$Q`cG>8uHc8ph;Bb^nP7N@?G~<1K?`BF^;n!bidmj`JS{kRy=p(baQwaVB>)o?Y z8$uRIKccOhVDJma*A&T>3dbNE(iPC^i7+hh@rbOR_Ln@`kKK{AguQ}ZC0KwAOrb}~ z)ZKOK{&0jC5oqrbH1=utsc8GGyG~5Z11?vemSE&&iWubZ+F!2wT)Gj!4}d&VOdhSD zBKSx8g4_hWzmY>H>G~bf0w8MVQF4j@O5s|02P#-Xj8h=shvPx14l1)-JGjsO`tc5C z*MMse0+h6gGJy#XFwh`A_Ggbb*M*1pZsLYxC7n`;TAg>^#{!NK>m&vrja3infJ!D- z|CXlCN_}F_AhHc$YAU3UiOo=nEcEA+<&fsUM5vT6MyL%tqXDfd&cXlujP;WZSV+$i zI6YX=^YwVjY?++k#59dbPB8^i9kF5Jkk25}GMhc)XazPoFzcy;>w2WxkzKY8#aVJ7 zxXP%!fYYizs0D!*hiTYY&F`QT>TxktH0ZjxGF;$#xpN&8L&=GAN#tcO3~PvK|Ea@ZQkxVH+ie%@`7I zcP31+=bNBiyC0U>pY+YjOz^7%kMf>hm+XC`f_&`;bexEakgOyP4nYnZiv-_)&*ZZ6 zw-lK%9!<=wF=WJ;y)J>UD|h_di7T#$PZezU+tps!`9vxP`v}VZcITcLpWpM{#6!o) z`F(@pDHfG=7@BJmj1;w}B8*5xK5R92$_?(!EUe-xInDJPODxTG7GGg{^#Gb6FEe__s662gNcW`qk)px2EfDhcBjYl?Z?Ua z2;Bs2j>zZvLyumHZEu}+-e?hc&5VgopW2a`PbwICv3@)&_heD@*)NJ8>wD%rO2%d! z1nF1eqE3Vdu{kwg8kz)x`cA)UVNLQ*@{=aW!z&`a*3lX%Q$~UX)#Q~8xJ~?@+kEtb z>rH+$n*FE+8UUirMJG`=NALBZ1=WP7Ucd@4e9JY5j=c2WXRXjehs$(fP0_EYB{9{` zNe3tbf|rU6bzWJ3{seYz67YHZzSL**>TUN_&hvgFXEpjeua-JAGScb;%;M91V)ffh zBClnIxi`+oq_1k$-Ew$t6D^I?G*#v^@oLT}+L$EKIE-5@zi^OCRv>4POs{Qsb?Xe6 z!*{pSinZpx;)~I7O#@tEp`qoI+%|nDQAv6g_Tscu6YTRx{ z1GbQ{(e8D7j~=Rr9H#f|WS{o4Y=#?>o zIz`_Ly#%|EL$o|o<~3$*@~70iU%_8JFYCiKzY2UMvDjU33bt__O?)+yhD<=}Zp|Be zTlSt5MMHa!uYKk%#Lgc_Ej7|~LoJf*w(l&1x|IoQqiNh{PE;U%)ZAjDO~@W!Wb~=7 z(fDKfd=OY6TU?6yGpS?_8HyX+C^Tq2Bd~Fq9upx}n>B@ip@#`Z_iPgl!m+thS{bzU z*t(Ckw-vWXTYED>rOkSi4>YDg#4nYH1F`eWpob{iLJAFRdLy?<`OGd1azT71vi7?Kb6fY@XQ z?>!^i8oU1Xby_S=eV93K)59jC>l(~{JC_FRGU@$1&DHpD?ZVIEz$w1O-mSOg^U zRsE9XdFb!;dc*rL*;idCyMG^&dg1znTGvc~a_-YWIt z7sl}rMowZM73+>Q*h45zS*1gl%^Vc#tSc3J&+sKfRp;0p@LXdu-4;?g?Wq>EI@{;x z$?MT6A~o!-z8sAyQ6it2X&HmvXY(oRUfDHA&NN*jZ7xP!sYaU-%@D(!v`;R7TZ!t^CFI`V?c!Z9=x# zrz7wLtc6ljsb(g)_htZSZBqk5l+u~r=7SwG9jLjwgZ5%hqJeAO`i|$aH7OQiy+5nT?b-Zd~Lx)?F^#pB8VI zDLa=Y_Q|aBz5EqARnVb$JLml?FH`e{t}Ilz|3r+e$8EB>z5NcDR?y=h(kNJ-B1$m- z(jG#%k}!_+k+PUYknEr&Ifu)+8XSVseuOt{5xFsavvn;icb3JJeNfAJ1uV6(xamnrA)hGfvRo!47UO+Q8g!RV&k`PLt|4q>Tu z#RtoFS5WUq8hi~qr<7y|JO42I6jvf^F2~p?hP*zOMLC!u7~yI56ifUUd+v$nbyRJ|A(EXyV zU4~ovkoFPP)$Td;f@vMCottv|@chvkqRjy;) zI;@H}bjGG6R!*%C<~J0oqM>XcNE)#wp(zj;YaqFv`G4AEUK=QHWTSv#`3~rl=w#c- zXg3i_*U*|Hp#Rz*!~9`>qm#7mT)!&JGl))OU6!N9Uhfn0t`Xg0x^#YHeT@%&aE)%7 zER3DXO$FuKl$=&JC{5;PHq|q(N1HA=uB=#`z?l4Qgz{d?qlfX(DI%%al^#g`4Lx}**qw@)62V-dUAOpr3Fxb-{PPjBlPJC1Iy-IeR-DS}{VUy++s zurp=>z4UG&LnXBA9!7V!hR*YH&WlvJ5j5`XqTL=5AT2O^PiBudMPjiu?zU%Jmf}bY zlS@_fKbCBl#zYHw{3TRb!Xz*O<1@C!cbU7^z0Ritc_pibkI@(2>}N}1PWnAWm(vN; zSORgZCEm@*ZHGB`MpasaQrJAZ!&hy2MlcH5#c|yNW@N~JtkWSU-nQ>-Tf8sW9W<`s zLT=zelHMyxe4=1e>I;m|0{`dEDT~xzD3`_(jhF2wwQ)(?2` zi;cXPCI9b~{)%vCXj~Idf%=h`ccSSC;G8mjJ9Pe3Ly9k7V7R|_sE-ua>2?ALQx(i8 z%|B>B4&zK4Um?PNidZv*{?Cu(Pmy(pmb^C6xP9j%pr^0=_k;!;{lByv{4ZSvOpO1^ z>8X>X6IDQu7JB{hqb9EPi7!r7GWaoTbnd6=@S>$FF2>TN#Yho<|T z3m_}YxTzv?+%-}C!&S(MK9Sv}+2xo~TgPZ{E{h9CxX!%8l=$VVxMoDZ$*XK6$Hi{2 z{1u?)_vQU|d&l{=>Gyug<;@yzS5I<0N)?B}>4pt6F}d2%o@=_a-r52oYbJmA(s}2d zi6h%>T+6^5H?2*Nww1Qo%>JH_+YL?FIlFJh_Nqj%K+4MzaVv|E6|K=0rrJgWH0$2G ziJ{W89y;d6=St0TnkzR8L6cUf*oKEYCb`0~#fe0~KBfjNI zY+*S?kpAtHs^@quq{<)A%g}cTy_)f-WA1-RiE=Cv1Dk~Zq5&kJ151eel=iKa4xIqI z(90QM=a^n{26#*$+(yE3d+Clc?v^NwY5BTnlg!YjRDVSJq!V|E9e%>lqL@{j2I5h* z7P4!FBrcPtNmN5Kjh&Xxp#8{?latA3*|*S4G>2!Bu|i=A&$4j0Jd|#Lh}X$((7gUp z5mkdez3SKW92x%3^Lt?Qn)W9dl#dC>&-dh$EnV8LJL4_A%Huzq@4?S*Q+%=$T=N=E z-_N;$w&}|bACM=_<$v-l_Wwpxnwg&MAD)#sWfjDaG<5y>!^@hgFLr4QEif((EV!8F z<&=o6AW=EI!g`YE%g1FWP6#|ChwJ|M1@q&V-f{6&$d}EAqgWUFN^!lj)paweL%x(v zCq0Ua&ZG2|2CK-)%Uba%Z&YY-5Bo7+=E25@=>}^Ebir5(?UR)OMc4%2}r?NR$&eWa|yorG!d3-R3G|q8cs^X#o zagIpRX=3?(akE?wWm2e&$Ox5I$B^;W_-Ofbe`cur!^QYRrsYLK)pX8CP-*o*^?STR zepn>tADx328E@_&sM;0D1*BkA0%?Ttih49=nU{hdJROXiCh1BuE zf#+c9@C3&{(|0xN$+fMFi#_m_nO{k>EIxTd3PV-)vN2OlHy=;xQ{Ak>mYjNmwf;DK zSqjbc6kB!FO>FtGHZL>&C*%HCRKP4u?Ef%sl8)5|JsSVc2ld}o2FZ7_vH&FU15CJc z){M~0rMl$F+0|hO{JU$jb8Ss?!hizmGkgg)w>p~od>hfGXCCLJ?caYE8y|M7w`@wY zINO~TAQUS96k~_H+qqD^>DT#Cz2zJYm5JQ4?Ywh%f8E}#>x{F)5Jc5^+m(+DXyIe2 zbf6~gTy-hc*~edAugvL0J}#Cm{gk)7<-GL43+wP)UEG@U$sF;8Z^FrVti(sy=ptC# zdHvkd(dH_rSFibSMRrwD>#)*OwWZu>fK}c5t5KoC>$4nSbx!AiQ-9%J{+T?$&Ep9u z4l}^6;<4euqKt_ck{6UV7y1>jIs{cGRUg18w~$+ccdkfjhLcKAd0&?LhpyDFseli^#*xVb7K2 z!LYVjP~Ga!kiJdGVbPe`jkLQ33BZ`%-LiaS*CK>oij;uOybMX`hq-H=p(q5k>0;Cm zCZaZht4YJ+Hm0cbAN`YxMCc8{nJqYFTd}WAYbW8AJ3cYbmJ#_LBka*1k(6@WB7=8m z@aubVK(=#O)KJ&R&T%@e#_1vdJeRJ>-A+CVJ>1oGebi=_@c!DDYkA7=@#C>Z#ZmbjT?mVv7AtdaS@YAb{_M1hv1wG7 z&Nt@_UP`t4Lf)z>f1L8eS@C^HzCJ%j+v=)*GBEKwZ+G*1oMMTjm@skI3GA$|dM~1u z+`*U{lS99~(GZQgywQ;LR{Ch+%S3&2{q=?Z@$7y_&y7FgQ4iOMV4TNnLKnjLDBQq* z44ff^V=kf%5#JX%8dsGolWV{*OX9%MNQN+u@(35qNG+(r8srE?lTJ1*7{iW?&)5Zy zn0_}F6m%#+nmtaDEsuW?e$l2pLsW*I$612HQC>A#E9T zbT1Y@u7w=KNHw4^9)X1m9~EG4EW$p1iV;*mM2HlV1tmtM!pJW9?O$>EL-q(%w(v30 zjJu-|i&FD}mO_4-%3R3h@G-y2v&FZBcq^{<3TeujUWX)EUMg*YJ`5Eug-fTCfS1x6 zbJu5GQk?9Gr~4>_aO1be;>BZT&kn^4opP6DPYCnuB7Q zLugPQO0&$V(nbqSbve+-pnf>zrnYnw3|nEo8Q8}%HQT^zga9{W@P!z_%ikWUjJwM2O})AvGt`@E|q! zK})MU^=XR`w(>BeM`w3gWS;Qsu;i;88}?*lsB$ES`@NUbwb;}7?(2f|TVp9vojQqE zY-qV1TgmIG2s2s2|A@7?Y^w3rV>5fOSHB(@|6Fz<_}tGF7@9Lg#!uZ^6)fjhBIEzYgw9Q0{Jh(1kNJDChA~2cz zi#!Y$WyVaLJA^TOb40m+>_>3ZkABVqTC8Q&@1+so4x_MT4XU6+EsRjs8W(h2h3SZi z0U96lgE%bd$+q;tod^kwgNSi{aVRdH96$v5J1Xxk!x|n7D}rBCR{T{&yO#BD`p`PG zfz9Zs;bm~4P`Fv0tVav_c@jdMp$vCaQ=ZVTWm%|mWn%s8NZ932-iA&{NRB#k0IHRC zmO8A2OIgXlq=H;ndO>QIGvjq1P0wkgo z|K!ZmN$Rs*=SLHH@*eu7q=MW$!jvcu6~QmBkkR~ete9&AzqCkS3j+P+tv{>cS0vbc z9gpt`FJRlbO~a=B(YUy0xO;mzaji**Y1qgQ|J;0gzx$Hh!yu!XH)7t-r!;iT`9&L^ zuUv?EVQ8V{D5s=mCnx8vdZuAx$HC9HW_V*I)#XYC)s6f8jzL%{oUP(=MPi|ypFj=SuHYx(kzzI!Ia#Ayu+$wSa`7&R{uA~PZQY&NtKvp}jh~msFq6x!5XTB(5 z+AE$hJV{_FSwQ$iiZO}wju=H_5*KTnMHqsPILIUgH`{G8ibMe^zBHFEMmXeWTwZQF ziI9M1n2S8P43yHz&97&*@6T-Bt3x6$$CQ1a;>m+s+_`C(_KqYpYpBcwxd8&fB`Q4a z=V{`xE=UHK?q+cm4}shc(06EMInMOEXQ%qTOySJn8k&gfperH{I`%nlRlKnWCR>Fx zY3OS%CyhGq+DSru+HytLe04@_Qvb=t{wv{9CT9A7K)nP#s~~!`p`8yjk4?-WK9!9C zsH$b6%8gQ+9i=YLykVq=ydB>R)Yn@7e!7$G!^3SW3XhB^SL4UnKNEqXsxA47%zqPq zMr@T@gdBNRT29QxeWv22rex!`z3<~Oyk+R}O_#LH9F$$Rinrowo4MqhwmUVoXECuE z|5zGj=Obm9u?L{X8WhrExXk2_8cqTh)(w;qAL}b#ak^-|cFKvDB15~h69li(5|iBi zh(}M>?W+@<^c$|JF^lUa?B^3vJ0AaNpv+XWjxYT@14wi%9nq;twRYqT;ElK$$wU+* z9aah8n}>}y6*s|t(;*VWqu4)OUbn&uv0~em-anOEx<9ug!SL5gTmVl)t&; zPE2Q2j@I*s-x&S!!Q0fCRITEfU-)}9)pW?|gx*k-e`i;&wevL}GD(|KO*3>+)ZXl@Qbl+O1C8 z1)%4WF_T}JfbQ$2#hJB(+vElqgH?g$F%1PflO?2;50g-Z4nhwdoq|p0;h&(#6#rO-Gd+O{K-RUb^lD@k4nArv zLQOz*p$e^4v9hkCbAGNJNsVNaHw;}3@ZH8VM&LC{b$7pavyJbhrY_(m)wM~4^Ehc# zfG@c{BNdG3VhgmF*L<@MSAp-3C#?zkLZBgNEpdu-h?!l1d6}T<#1;oxGEh+zec~9r*c|*sO3JE5l*jY>fy+}{V9nbWl zV%SmxE`*{4e6)fki7UhAv)Gam8PR(Z2yPAVa@pq*A&6A;-E5WxB6MCN=HT(3;5UtS zU;SOx0mmY6VxgqkqAsvQM#M&dhE=>h&FC$_NASA=*21JuoZbdFsr_K@J$ zz|gCDd-$x0o19KU0y#b;PT-&yPFZpFp-VP9D4xc*s{vL<5K0_BzaP{ua9yIqN;Qct zQSxZoHG4XI*W5F9gU5ZFE`=E$!N^hQ%(|haXAd-t)fCN?ch`c=-0 z7ll21>o%+LfyQZk?MuXlZJI+#(3cu+T0L#cR=+4)W@IgL&-hfFxR*Dp(;JS;tvfcC zn&JZ-zky=3PX1-d4?EL;$&vjN<|fGeha(HV{tD+UPTWy*X$c}EP4}B=EFwR!a*Br@ zqpsjQ*j9VSb12QdxtQp@->u9!(y&Pvc-d~Qg2o_?H6B=VP$Ny zb*AB-mUA_J*4Pq%(MYz99$AjjQAp>5J>qw2)0N`pzi7!rX3g5|^mQU7KH{Ol|NPmq zk*QUu?IHMLs6LPIL}XIY&O1Bq^ki&VAJrDRN<_CIVSn9DvpEV&d=o!77F1eoVR_b3 zPpp*=<36tEh5T2|DYq9__PuHtRXgAIMt6CDUoG}bs2&(run_k{go*M;)ecqwVo55q zm;&@#uOskUKMHC{t%N)%4vM7(VnwIFI#{D#k}F~bBh?Ic;cnO;Q6^JE!9|OGaX}?( zffF5Y!mzJc9b%zCFJ#BK)HLBNWPp-C$z&kx-|tdQ0FhAT&r&4=6GOwP1gLLu0~2Uo zv)Cgq`Poc_`-M`?0t>iF4m->KcSgF2#*=B@nyaN~%VV1WtrPQSY@unG`KC?O!!3R; z(uMwi%QycOJqGya?k1hNZHvD(6Znm14si-z!AprMH)7r*w9UDy$vaRPe%9ZF?J?Vu za|F|ss<&&}jS@3im%uYA!p;0%`BtABw^&t*3inwkX~1rwso#eGw|UJn*JC_VWK2Op z-{U4WF~v7^J+yp&T()DdQsrBkcBNfalQIFPF2Y)$5<+@}b!>i%DSGCh@Jt&{JABbr zi6{D~SK+<5ePZnXR7I^=Wwvsbj`}9SB;j5XJvfR>6aDBypHA~04n8KOsLf&|GW8ct z{5hg&7FYgW>H;!uY5zF12X0LBNZ9$b*$I+ZWIpy+9Tu zZ=1ih=tFbN8hwF(I?vfj4)N?|E zPTz#FZ{N1tn?{SacQXoUr%6@lDm zkk*8l3aLrue`FPEE8i$Wa$0B3I~RI^I22X#26~{Eca)lzWtJ_ZTP2thMj)THwN{0A zbSnbwUg3AgS1s8=Xc_n6d3izU8s8FS&chiMD2p{GTPHl>Hd-JVSa;%zaVly(bIVSL z;f2_*lll67L3Hx|Tg3h=k_EsF_(#nm1-0!I9?=Q*}drmv9FbS8@Iqd|v_DX~svu0Nwj|*fX zpgZe`5;(-oPSE++U(rVQ={;wpova=)8#_AuFbKXs`PH+Fl`Q6l{}I~h-M!3!kRf+9vdY=TCSJT zS!1!RLfD(0DPgtj4 zKlwE6SzInyJp*m9PT^gnZfu9nnoK#|BOp`c4F6jo{wwAI!1}*n;bwRMBVy3Cceu8T zMmYat2@G+grhxi-Q8R*`vr`bZ&_YD_r-kgv5IAc0MA}4}(FBJS^OnrSN1Tw#%wT%- za{RD`STNKJ8mMu7XFu37S{8ChcSKZ`aQ?ZA-D;*=5`hB|fjeWsO)CNSk zvoN^{=6rEH(*bSP1(xu7VvW1x$Qe!5!G0%=IDyVD3|H+!-t@DU#EOk*j5gy}m&W+N zu9k#y3Wx#Gp_izav?9?k^=NJQqyCEXP<36zY9rl0`A#6$0_3N82^oM-&(e`+B;p_# zY@mN*=qiXmE! zIRsu*FPl}@t=oUd=3xqDmGbsAi>M3vw;26b(486Z&%+|mYdOdWyZK4O@{5X$AgCY! z3YYH({?*&=#>{M8(!zh5G{GP5!`*g55Ks>f*@Y#)Zvidjg11PS$e8+!st}o*$f$xb z1$Bkx0yt>T)TXQwa?mbuU(^(Vdw;me`Epi8ya;q{bhPjU_U%laD#S{k({qNn#4=m) zaOEX|!fUK|a0j465?pxs$S!!zV27jaTAAXI>fF8~P}U&H%+q_0N6laD;diwf$Mn(sZ_ptWx@Cz%e@)3O!vbK@$@^vul7s|)o0J}cWv&CpCt%S1i^!{|kd7AIn$JZ|>nfXNWwxz4!rRohAV+y$no8zlmJRgWpgg3m#v!j>E{g;ey zcCERK>aEqTanrHqZBF}Vk>|rJ5PJ&2n2>D9uKCH^tm8A+uWPG2ub~LvH3t3nDvm6j z=m_`pGhh5E2_9`;o{jgmC&z2u-T{!o&TWElAfT@MpqGC;0smuO487KiUa5e?KkAzFYDfN7UzZ_JMLJry<56%3 z_hdYfdyEa?TM{^m5^MQvNakV=aZncLProD>3NsIgVH5@4eqIXx=UF@u8bo2JFa@cy z25tfIAFb#i-f}=O3UWEX-W{rWz`Mmd67R$?+knl)oIw^3!qjs^%IyPF(>x>SnV`Zb zd+Fc8@IUbP|2YhQy(|B5YbOfW?)~So_<$zp&{X+}yRIxKj;aY|ep-#*{>;K;RTwV} z4FB;C_m%CjB2MTXJ#xS0#=O61(q(=Yf%Sd1?tsB?B+srwFn!s?Q1BW$(vBqqP+B|` zN&FgDnvEK+u%7KgD={0sem^|BoPH))w_b0Qi|N_Febab|xqe?RV^`s+b@e^Z9~;bg zymILtoG<2VG~pw_0^s+b-52$w{cVo;4B9?7<#?mLw{xb4JTKB$T~zBlW69OErH+}^ ziI2!2sWq$cxQbx??T!r3dNK3B0DSSXhbY+=eXj>1Yh#37TTZUmOQr{&#z=GMk*kp1 zXSo!P@|J~n$rRXjH<9ZHjpegPs|e*b0I0dFjienxGkYRtb$uU#TOF@BoPZHL@+|Q^Q$LBAl?LNf^UaF z!pBWQc(W04gM84CpO%}8on>i@$#_rvz>Ys`x(>-p5;eyTc^*??zqMR*v38A-?C~`P z7yj4!{=dW5|4XKjAZMG&_?IE|f+qOe9?|=th*K4Z0!1s!P$g@77*1cMQ(Pis@LaLg zy}>y|B#rfn-ke6vS7y=H8SMz_cPL_A^E2_Ui0oj*y?4%c^rQTk|iYI{_T(AFclGk|7~})O=-=5;RrCFKf^u z6)65)S;ipM8rD&w&o$F>xn093kNGLF(WR#IF|Tv{8ZdQ$5l3c>HGfDsB?F>!w54$J z85Xb8%vZF+dagu%5W-+zRC{UX^!-*#H(lZEo}AXXA&yQ6H5X?E<{?@Mv=~P^f<35Q zDEOO2T!h*pR%F7DqXf)8IYgW~;Kviy)GMT5))|x$q9?e3Kpyj>A12DVy{wxW10e^q zG(#!22X<2_c%mU03N?-0Z)_WD@O~&sj=54L2U%tEyb=O|o7`8YSqKp4aZu+dKFm@r z@=PgzT5wLfc7vU+9on1fSrQQ5anNh*FWQO%!{o;qrg59y>HeG`ewat%2#h$}4HvQ& zi8owQS2+Ey75k07QL7fuhX>BMdluV{y?25K=HrEb%Q^oQ250_XIVV=Y@-Jx`bp49v zxKTuV=3@DmHLYk8@37WzW#}3*Y6O-MjD-01mPzDwBJ{UqzGiY4P(3O_MgMJEpdN&d zP1M#W5EV?cumUZS&uiCrA^By(yGS}ZrR+P0Pc-VgwG}foF!Gx3L0w?ys))xxcL}<_ zSuKJJGGcfFUJFblcbf0V4!trVr{ zx>C@H7|-(PGFwligbN{qg-xwRD#4)!Ey1KFDSzjC9TQP*v%wPve`p^Q5H&oJ@jCO7v*{tY$E#M=sPuXdvGC~b|1a+n@IO%3|5q6a zNeGMD+Bp4(MrHiJ(Wq=3fPY|sEKLY))a9idG#3aYwE>P$ZmtIPy5F-Ho);@{;a&9N z*R`kuf96)ZXvMF^Q3O=$de@Li(^FSilb<88l_mgTbh9T|od=)Y9Wd8q4DQ$Ockju~ z6B}*MnT~R=-_tr!#^w?dr13uEYL)O%4hY#VPcQC7{@KM+5rchuh(-euJY>+w3ae61 zwTKYvd#`NhDb}L$)!zLl3P^wR>2wc;#Q*aP7IQQ z8VcT2$%^vZN`!eH=xOIzd%I18^E4d&48%v5P*YP0$032kf$y&`qLkY%F4-(o51#1` zTcC%E&v?K@vu8m3MV_@K4yT}p;ZT2)h-MGUbLN;x)lYX1&+$*HU~g5cZ`X1ol|6$h zlK6Is;_}XBQ4%e^J{SI+#NGgrz2aP*NY9#)E;LzmqySSIlnB!lswquZl&nBgnv_V>6s{@LreImxw7_Kn z(iFBPZC#?A$bBf_uJ|jF{ZQ&v;Y%3^O&m;tNSP8%G)M_a85K=vNby$rcVI$i;)j(0 zTS%uiCB{6PhGIu4J2Jsoz^|(=zO%=OA(jYjsj{M!L%dVXQ(z5S4Q{%UXRRWQ&lOM4 z>(DK_rLM|=%8oadCwIMpwS{Nr({<_`N`{p06wl+s}dKxhIUH zUZ56W(^X?DF3%yG*i8tK5%|iwYvZ2DuY+9UfNn)lN_)H{{c%Viz0Y^09zCT`&22L{T_pIdVB zB+GUv=9XY2c&9<(f`J!53YU+a{IYnJ$LaM z{i!3LL|h|;XIf$V4d&(-$Vrc1tzVI#z|+G6leA1t80*7w&EsM>uym@lkzt6Pj$MJE zR-`(NehU`Nr97l#{g_UEk$b!DHs@ls3#&T2{PpCsUdQ{Rp%16b=V0A<@wHU6_dJiC z+ecEmmmFartOum&`_$&wFM-CdUZ5sXs7ODb8#LJFlgL1{3k0Q_-EJ@*SlboX@4~&= z#11#+ZC0Jf^7F6&$qm8)^JjcM^c&@u-#RCp1kXpeW~D)7^%#o{Y|!sFye@6qPSW>o zoL)c~VZ~^vYviN1>*nCI<(u0;mh0BK-GRil`iXlOxhDFfFSfUc*=@(|#-@HDKqY28 z>>}m))5k<|dFLZ+?fK>TMq_ zvfM$kYFYX14o3E#jgYQuXRd_!5=O2;HTvl}C}gpvf(t3X zY4=0o`d)h*u52I54dg`>uO16iD7v;EIHx+wq}H6~pg&#wfF4Lh@0#EPnWsXffJBE= z`=FDLsl|x_1w1z)rt60`I&7f7`*Gu`c*){f;KW2=t6k8$|H|9h02#%#A(tzii$-V_ zV-&>q4rqbio=@$c{X?BE$lw3~YzmLxE_$s}qk-1vv!}-!gohjEj~HC03)@5ckVAs% zIEdQ~N_A78nbjYP=PMBcrps0ckIxTf&z!638p#O*=Yn%3vRYBWo1H1QD$4pP~? zKwu2txL89JgRa3KB=BsnQwlH1L6kgy=X=z;Ej42Xq!aqE?MS~48Fuu3(RDAhDt43SkvfI0*4iEX}C$ch|%zn zgyT#id+d=rqpHIxQtP0|=w2dE;w#6LkCCC)sHwh(0Mti4pIjl*NFW%Jovj+1;TS0zrDb1*9lhYCKs$>q|(~$I+-G-2*MR z{mpNUbaun&zfwne)SO{@>=kC;*4E7kmfaA{&q4Q%+(4K~uI_*PxVLS{7cQGSzP1(~ ztWXX`AEkD&(ixAq8PrVgR2_=xFDdvA#1P_HxM5ktEI>g5dk(9ToaxiR+?DC>6LGVZ zfR?&p$^ep;|M-I|4>O@FZ;F*ZhS&C-J=|&z*(hg@7Dy*1P61N5U92|??e|q}>C0D$ zPm}cFm_ zbMd?+F291*m&7d>B~g3z)p*m!^g;201YH8}p=SLht~M-2<}zqNr}xj~`b2N@_ug)! zzf-xxTqg9D^dd1GHsxi@$VRG{i-7Eo}pC>MWLADUw+D%{IN1D`U>SsPf zkud8$yJq_0Rh>g5G?XDgvvO95X&*TJz2%k;ruxb35yjwD+OV66qmKg zpheJm(NHaJG5^cW6MF^rK*VeNz{`;2m z%RaiWAVEWSoxdhK)Bs)pi2#yHyW{oNT)73lXOw;mampA^f}D)#vTWwhE= z`U-;c^A70s`-vZL&Ci^kFMD9hP?q@KxDh;Kx0wsb^V9^C)ccM%>JVg*oP&o|dT;iQfPI+dUb$%V zC|6}q?gwvgrnp80fW?pw&FBNC=mEb&x^m3k(U+IFz>W z5%eGs5UG3u)rx=B%r0Q7zT}*1hAdVz1&tH`LW6A~69>}jGCIp!ooW@tl>!j#y2{jN z1Jr`fO*E?Wz-_igl+g7q*u(i7s(jwNcz%5F^1_4S+gP*V5{cMhZ5bdkq?&3&EL{(T z<}svY$TvozDVcSyu;`1x%_T#zVo?%F&K`=}N_n{+P6gt6Gxu)1LM~=gGJ00l{;Y0GAYUs8;ZHLab(q2ubKW0tZpe zvLx_H!8bbrk>!Qc_$O$t_Hpd(*!}?iruVOh2-{v5cB#iS&QmPtNpjS&1cAwIB$l;@ zE_cTpYNH3UkS|en18C1As5B;#Jvc=(SCInRD8!tsxGJh40O1V2m2W&cItH3HNxb<$ zejGc-QSbwjaO+4we^FR}RkHXC1kTDr+(hLUo zI>7NxQG8gLF}=|2x6dTPf({#Rt~rCq8k<1%$D$K@mg-UcMSOb%(DqPfJjXO)0c-;G zUX*c6 zppTO>bGRhBoyD?1CN+MdDn-IK=Y?2uCvn8WX+N`@wR9tWa0KCD)l)PTG9SAou0V)| zLbE31)U5F$x@{s!LB_ot7ms`*QlS8<}^jV+b&7xXr#Pp3xu^_Q)= z&6lkN*{vC#dJa=BzowPk50Gv~AV4ppE#ySo^e+MV->&*T53oF-Ffqq|GV2h=Ijr}6 z4}yUyhQ~j1KJF;HnOfT0|LR9HaS)FPI=pw&;21`QQM&zz@e$nq(8Ic9?uB0QdPjDH zj}5IYrsHPU(ZbHv+^CICQ{Z1+Y#SUQOZD~TH=uVL_F>#JB8M2VYB-`k_3`Bn!Xrv{ zCl*G(-K^v#Ixk3Xp7g&5)hJBvCDU(z$EDQ1n!G);qve?Jn|1xs<##Fg!gakyS!@>F zohjc#D?oMV$3X=TgJMJvfGfK|?Ei8604q1B^tZBgaoZ`lWkf3W`h>M|w^ACF6$!+y zU4a+4eg{2JZMqS&j8?;Li_sJmq7LNcGy60F6M!{nz9j~Ry(MfyEReXuBi<^&X`=Mg zWy8=ywCPY%A>&?&({fNgDeoig*3bGy9YgW1<$}r84$Pm)V%{w)ZQzgnOqMrZPC#PlPfZI6*Ndn2v65P1bO`4q`m8$=3 zV=^k|7RtE{Hw(=DGS6~<&_a~)Emor;B(_8V^BovKRMX=Z7f8Iei*(OUt5jwo3w}p# z!LhTD7kx*vQRG;?l3n?MIwIN?MvjwtC^1{~%l1z9Q z5z$cZfI1XL$*U2O-|xnQJ0B4Wpi|vBT)rX3l#De!_{B?o;DS-Gw>?$mZUp@NbGqLF zLp?AASy>0ASVThGgIIFn=UO@D5BS<5B!*rXRJVQd5BTOmMLs5ll5u%b^ny(=59O{D zJNw)kqWDNdkzwYBr`R0`M%2fv$8@Egjz21-psMHh{KKe(~C9`kwq2f5))xH)IKn{As zLT0`HBJ7%qF-ESzOzdI_4qHgWa6cQQr2Mlb@xGAlkwX;0d5YD4z2=5%>4cc?v3OY~ zsrlW;;+G)fR&CEtp4-a3Ywwqx=hu4)6y8Uc?M|CrTGr`R`pz_+=QXY!<6RBK^d={t zcLgDThFK_cKM_b{Y8inLHUJ)Or&rne>k&ySE7DG{|mTv4%$yX^u~=>{DGk-d8Mv}ntYZ(~0dN75&7io#t6+9>3@w|+yY-Ycw% zs|~3XTxbGopHe4cq@I>Q^6S0W&)cV5|$M5Rvp`l;%^MA*`c~n#pY|9Zc zU3$GP(ip^unS;x-^u-oS$;1z+=`X9m*t0-hlrai9kzL#OGPqjjE!O8hhs#pY^9nEO z#dR=hPg58jqFm{tKhrccnrkNFj+h!*D9!__{s?tCdbbktfa`bU&G0+;w#RPiiI49_ zlM}$Xs&$@6=Cjc<_#*dTOUxS&JwZyk!jy|0dcJh2C~of)vuRg4agq0;lBQvcODIe@87N=GT|5%4=vs5cm)&m*S| zH(pUZl)9GNgE}7q<_}YgUCxQ|Nfw?L$fxL8g=aMG;8!0i@Zlm=`%)z(sy(v`a{nn9Z~w10S$_TYgvQl)1Vi zr;gJzkqUzu2KifqB2rTkQnZ7SvbN34-HiICq6S{r+s5}XV~X*2bFsw5EMiJlpHs_ zPDRNfAdDNKApsfORgN1MC#mL#a)cwiow`SM{CmSyhNiY@Z@^-H5bFU5dOtJ9YT;Wk z9@gOC#d0y+k9+mtn68MQK5qzWl|a5_21<_k)i$zyfnio0($62F#9S_|dDNZr*-m?t zdAge}ss9|}6Q|_nMphM$VI5%;#G1m$Yu-OX1r-p0B zd+Rmm(NeB&7n;G@JnW<`a9;KGUCB-_$J?wmPJe%8&iK{_M=+LdQgXrs^rC^Q$MT5) z`46WllvUeHsFqPR$m51&8IiU;#{C|`P+KRU>D7G2Y95(m8Xv9#3@={UmhsJ^tK+2( zEw8fnJ^}fy3|Dqun9s#5FcMi z#(Jc1gB{y50hifdv0&#g|1+&RDwbkOZlokEN%B~9; zVVQqf?~r&XrRl3Vx5@Jq<+E&$Oe6Wb-EgstMUsobwE~5MpvaC0roByOlBjT%qHx6U znO+x{l3bz(@TU>jFb)G_$E?_7dv4}Mioo1Sz`r_^hCz4{?1yqVzm$}NBeX5ju3C~< zm|-OHZ9PZ--!2lmyPYo)9BO+WIWHQKH5ZXjmpzfmuHOS}8n*!v^x9tO$et3J(sb$w}3ms*H_lS?*IovVWIn?R4>;%v)nvB&6)4*kiJXoMmyn_#sB&G?3 z{+Xy=bc@5J{Olur1toUh!Msm}aH1)`iKU0`i0#-;=;$jL8wQO8oIm;nALv#V*0rsc zv1-e>{Bo}bx)*j$-9Dt>H11Y!;x3_<^TWKQFgMQTdj_VkJzHvOsMA{B0cFk-`<*sE z4|ZJunr|Z-&xo3$hYc^qPfSy;6V^Ns#yK^+O4Whl5MNb4550IA9yz#L_@yLojE`0q z8VS7;`5^EE3v$0>D}MOk5D_Und^X!_7tK6m$HCl40BP)wb+s)?xE$$5R5LCm>zT=v zysglb63KQA3uDd=y|fn^TtX@w`mTpidnpW4Cg_1kc)0wpOEc)MdC*t^US3V(WsW68 z6)VC^B)Dm3I?%Pk+{@s?LRn_`mn?&|mC%~^0jQbj!WB>8gZpd0BVk@JXBoHufU}x7 zmCYF=9FqX{oLQ?;;zDYzbd1=G@y9&L3{_(8=!EpVF*2&3>pt*|kqgu#F|ux7wMj~= z_&|6y(rMUj-)UGtvj|u#?Ey2gLbd3ODJvR*D(1qXfd3g~58cQHf7|zNm7%BG4a#Ow zQ5)wg2B&+zfR{-uE{PuX)*yxCF8Dj90QS-jX`s?bqzDHROYYe3R?|Q^)CP4F3+c8-|4hCjskB2Z zHx74c=%paB2u*n>6oS;mTzDnM&n}z=2)Cnhecj7lz&ank1a|rUhu!wKNKBBEclDH7 zZ;S7?(Fqc$7aURWjBj|HDf+-dp8Q$-vZ;|>TA_I?DWlq*&}Uq5rk)-I!^XQ@>gDpd z8@+i43e9M?x6(7#^usi7o)iWq0&-MZTBm3N5A6*Q(Ht2-wUZeTfIoxKlPGc!MX>Cd9njS+A-=|g;f$lJ3G*a~9p_tU) z5OhqHoSv2b51oXoS8_3AmSNr<(*@lZ8d5aBOc~yD?B6HTlzsSWvJQLttus^{!o$eZ zrV1r}J%9qFEk94|9OlIk-Xbz5#qVB$Es9SYK;fFhhVm_et+tiaY4@w>mIGHFMA^I} zmk3YiQ?rt?vWlkvOw+Vm8_p*?=DW3Y6EbM&#v0D6eHi^T#e3)Pm3~nFw^rDHrK$R- zUxuZgUMyoR!`Fw;dQa5#SGS~LFX#_g4u4RfJtHWxfBTbvQ6l}f{WcaBz(4&()!nsG zme;Z|F67ON(?vh>oh#I;-hX(Av{Dn-2Z<2*lOoE;1+tDw5RQ^-K@yJb z{HUj*MxSlZYtqzGs90LEtVq_h?BWdwdEd1CZGCzD>-zKfJ^q9IRc30!efqxp`ku$s zEj0pWc>i|8+v^k6KJTt@_4oA0`rM(N3srec#cPvD->_sblXKBLi<%r zTj%XK7sL?s4~F;+dhl(12zLzow%=8?tz(a9wX65C`(F7uhcpZ1zP?Z$(u&yyT_wgl zx7?_sH|uN&QaIykIAoeOUV-fG)6HFaw>VNxeq>m_-X6277?!l^}2FgFfKR&K1+fYEGTU7Vsw;eu|nKzeCBmC77t5i!#*)>)x5 z0=$BF3)DZ>idR}x5lKPiMo4qQ?t#)&Dq`b><3E;OrBbL5EXw4hTcxYxB}$~@BvqKx zSTw7mbM{ZmWFzn7DGPW=+L)-PS5g9$v!~9BX>}Ube8Z>1MWj?~wD$63Ri#MKB+Ub* z@vu=U?p`p=eEI7%^CDrQhFUSgqIPTDA#g%u`pFHI7!f9LGQuYN`FfA^VQPa`6sy!o8ck`_Uce+lcohGyM_(-vvNE1G_ymW4Ps5? z;kL7SqP9<%*T^Oh{d>tL1}JuX`=3LPLYom>2)v9(+lgd^e6Xl--V!X=Yr_U?T8j`; zVC4vWj0gLXn%RT9;tsF;zjmMK^z?fK!M)+F zvcx~~%fcy`gwJHl{?kFe^M<{|kR8#F3GiriTGYq2%ZKpkm5Z@nt+``iF9UCK(*OAQWv(Q;(9 zL*C1n6^(a{u)r{Ob#jfR08RW{txhnU>lAuL8|j)#S_%s5*kCSm)~q8mTB8M~#!9Dl zxYkS4Ih=BWw5jh|cOMj&bR$)$yO4j@F`QEyv#37fMFHGHC>ST>l#7`95Cg(vG|nbB;-n(Rksw zu}KL6mc;u3N%{(whQ^$$>(=`_rIRx%%EvEPW6lzBNZ}?mzmRWSRn) z6B^JErj`$zRuN{4H>P4>ptU;r(%kIpMy-EWhd);SW}>@_#-F*I2chE?X0i0IGZ2@4 z1-|_ZNX%nG{lKM2N2)>_y_JJu208s2S#;Yc6EK?8Ull>#lk?0=&9+5mSPm-BFIAUu zyAWk2Z13yN+A;=lM?=O8Mv zHb&|IrMV2gu8;F^A7?q;b1#}ue!>EnNr^2YYzYtM>O@v|(hv=xkATjk;lS&x)JFYbjgnTd&r z@v}PH5xE=Uc*Bx+*2%(D7%mGPs$Usx-O{qMXyTA;o=gFp_3I(PR6IezQQ`?asJ_uA1p`XhzNj*;({`NN%ue;TvS31pw{@wgYahbzu9yq%L12+`K(g_9z z+rO*#(KlOA1!f#viA+6GDxD&=aL8?8F+Ofd)k5m|@mc*oQv*G>yu6{da?f%lcgerz z+bt8xGxpXyX~6LiKw-&E>&BSR}OG}8yq~4aHu=XX4#O?q=H}&}` z>8|Il9@$*4xP#HR|KM`MQ@|S>1*`m>MOrQGEL;<_(hNu{4~y6$At|BPWt*-cs;A5% z$G4n!DIO&uwZusTTU|KP$tYNoO6I!@7}%Ymps2Z?PggfG+C^D`x(YF<(?V(t$NHQgd= zdI)%!($AGAH_2?=5-H*m{}R@u+@^k6z|tErj>KO#rGQ%tY=cjsLEmhG15S7SkrA+? zqhhY|#&$$)vTH%$R9OV^S+eMWHe>=v9G9)5XF7r*V~@D*6U0fb8=*Flq9ib zo-eiN)o8AHyucjGv)Yg0nC>uxo}1UtQ`h8A{j?>&kJQu6m%u3aL=7`1-0K)=Vnsc5 zlWy&=hKEf3b_r!7e~s{=Emu@hizpg+2|63-bTuW@XdFxtAx-tRV3zKY+kLlXoESfD zbnP1oRQwi2Zsltbk6qtXk^iZ~={jfx2*cdSl>o9g>JLu2Q`V=I*e04KEdqkJHzL(b zu-m)mS8ThC0bWda%*^HH5YSBmUpwvD#gOxjp%l=Vv#~BGC1d3taX;5|8iomuwTbl#X{ zpoHLXHS0*Pl*D~jil3WQ?LEjbb0snb25q?Oo_)Y~z0bXRC7Tu;iE9>|#rD*vvmtgz zLVPf*R`%D0@1cb=0lsK+%P693A1Ea}JsTd9o{`XC;-Myrp~0R(AmMM~kfuPSkh}4} zzxsbpQzsiWE?)8L{yyX#3{{hjV5b|U5R=mxZli^Dnq2&tpmX|O`c4cAYOSwl-Ae+& z2@0mq;A2qj9x2aTVCAmBl|42FBcF0bB3VD@u9P`=bo@0MJej*x)@O z9cPoBv`gF$qf07pYB^73UpS)ey+W}^xB@ZUZcq50sH$I> zy|e8Y2PZ0j^>pu4pkjs+x~-R4AC9u_P@%ZrLtX?qz-Ay0Nakp?HFA9WF!@i)V5+0# zH=P0L2aZ(e`92;I;2?WUBN6E?2sD7Srs9mh9Wrxt0WvI!p=waMv*mCd2h2ooqJY`K z#b`+CfOYMzyqwqNkM$2zp^`Os9n+n10Q>aKs`3d5UyV%+|4)%-2n;dQJb~z0oF~wn zR?0Sy_IL73m8idygi4uklT^eJ{zdV@eIRVgIUp{^idt$g^j4Y*^+CcPoLl>BDps7R zvh2bvg}%vivG&wWEK*L=T?~3zMt!>I)6h?Je7NFOmlJI!JcP{XCmaoVV5?Lt&_@%Z zE(+aa+VvS+cCv_DD|q*;P&zjJ_;z(7LlQF`$jK^q@QnkBE_`0_Q1;79pQk~}3*9dt zXk_`VA3;UOr0-T@1V4Xui&dumVY~!yV+iXoFJm7`0 zh54<2ZNOkz5+?aU27J=P`YC?T1+a|ocuoc#x+k{z0jnZ=V2Bc3E1EJn22$zg#teV1 z77bc(6sNmQrL7_D#h`rNirmeF8t>?Xfg$wP!D5diaUf+;vdD&|Uld`Oa|rZ=JV7CS z!#s{%fnZcC*z5pa_K=Q4H@WdQTVe2nw#k?|L%7v4DHm*~ZH^gmo^rtvHJA zg!ojno(W0(KpP)u^ELv|SnPHw<9zw8(2lQc3J9T#8R|A|Gkb~N?142j#AFrjsP%l! zgFI}pqzAtLE`6&~7PPip6Ehm}>BTKfOTQy0Obd79E9D4#G;m9*OrJJExaftuQ%01U zVsm6S1E}vc#yioDhl_R&z+v46=wm0^!vXptYVyz~dlba)+@9&&B46?>F-9Y9xsh_}QT zHx-$KCdgvwCrxl+u+o;EwC&D6Bkkdwbq~(Nsmbu=AW75xYlnDb$!U$7c#(iBW22=3 z&j)iz>sXN3Ob#PN7YtA7Xu-_rT zu0LB(*3(8kC7Z90^}_&o__ks8CrVW6tR7GqDK;!ve@?eKmzL88rjlIHnPJmkZ$Gr8 zCbD-vXp5ZVpkOOu%%~gRHHj_ zo@M=u>NxLjvM=3Gjf8*Mug4DfujX5r|1n1VA5sX3Nh!0@ObTp2fd-Bqh(ZeN@ZZRw z{~=`m|0}-cU;_NZ6r{-m!c9qSsVcCwKam3}8rh41bJE3eLT2>ZT&cphsQRQ?O>Nc)B;+(gDmjOWH2T{wzvW~(s z3JBiE;>O(2oeX<94izxlgOnW!?eoqnwPdNghG4j5juTgx_caG5Ml zr`Hv|cTj<;vT&L>xc|xZiXV=G29pW{RpsC`*?7!-8vp6Vz-4Az3pi5pf&XP;=D_3RqT-+=Cm^HbU?%@(rD!(1 zN{!EVOH5h}S{)S=B`XmDlgUCwPDaJSK~BrfZL}YaevV$hn5bxAGQ781G$n@aCbtQ_ z>$SMER>xzsxv4Z6xM~BIlS3;78zC+O6%i>58zU>0`7`nN`~LepULL*&M*S_c*B)&g zZO}F7narHb9L=1~9Po@`iDJoOiDSuYiEjyiLA|nBHC#npRa|vcrN6>iga|tJEI|@2pE!p;5CChWB~?|L(Rj>M!mJ6a z!i_u=a&=%9+_!v^acb!26msM+;J_W0tsw5)2~Dz2h*}#{_R7=}qFTDHDW(^&5?m3_ zkUkM<-4tCHu6Dtn7Oyv51`h@!q_i;H!85?71*g)zCUED7J8oS7tE}7=b-vj8-2@$> z3hv?k(HTOpjQf!hs>_D0=^4+fwzIS)fm6AQJA00-NpiCn2;{s0vbAGP_rVqG1|WU9 zqp{I64V&+G6Z4f9zs9C3Z0%3$D5BWSgr#&^YtqOPtx8jhu(BpFJeBf@qWnj9Bh3JF zXMdp14h;K|D(esD?zETb-~KP=FgHxJaK+Xnlbk);YpsDWU^m$IURQ$|76$N~!xqq} zSu+~8C!`lN3!**!YyR=mcN0(KEevuL+jxlJZYUX!J-4Sm=j{#V&L%u|?szQ7sy<>K z3kEi{nJUIHM!Iatf5K6)FzGV5czFOBmx0_EGbSA%>C0TOEI~v#=?S*>9UL}P=zz)| zk$zA=rz@Iyrf1Yx}bc!uBf-BBj(c8`ZTO8|3JdZ{BH=u_Kuki ztM}3Wi09HLsf_J{hBR@3!`NSe-b1n86~ckVTIoR+QUsrOk{^-z@9v1ee~SR?mg_K{ zfwCkp!OHyk6!!T$^JBStqilcuY306UZXf>>PVIO83F5`)s> z;8(oARcnWq726pmbnnRhu=gb6M7Be-ENNn(nWSlXV|jJ?c4^G2uZlxZ&+^9RqBMJF zGn~+~ED^#;JV8lWL+ixSi|)D~^BMcFpuzm`n5oJaOt1YZjqv;TPro;8VlOTj*qBVn zwVx;5GvEwSh4|@>?SWY7D9Hnr3ChWcY!b$CcZ<_Zt~ejWXlLd!I?AfzJGD0`EZFZG zMq648K>H)?e?7$-GeJkFzbFs?I-i^Kxu!z0_EFK{n9e_Jx??2Fhqfj3pK4DIqRJoS z^q~Od=oSpyF0;z(I`Z})Md%iO`2eCro*EwXPK^>uB14b3)p8MSv*c+HW+f_M{5q9& zGA5+r>-3(fDlDs(NzxW!6Nn_lEuAfE5Z|{PCUaf(+=e`CUp?-&u!@geNk2s;M&!y3z0);#d3w2G&@3*+0mnx%*j~-lITwsMjuI{Inx%5 zDF+-2=#2_1g9n6T6ef%n zeHyl{F_KcOOeW=+9=Ssks+`P)Us--0_qi>$9eaAmCH(-BAbJME^Z5Lqkr z`!6s;Qn`N-Ca4fQsU)P?>HZ$OfAz}fOYA{)i!`Cls5iA;9g3OxzMT#2zj6t?h?dYN zKbt7DS6ws3&BK)WXdW1r?S`D)IdXG#19aDhPli)eoR7GJj0*>atMpF8>kp$WoOMWj zg-WhY5GH2?JUnjSG$c!#QztIMoDNnxE~cEomy|*t3U)EVd2c}&Y1X7OAvk1d9qLOu zP)wKZ9kUL033#YKl@S7%2Mpji#Y5jvmdhUW_>%xCur_uM??VNom z*QdB!-Hkiz#!ARR2J+n396V<}$4F#ggoTk$R#Im5-nP_P-(_zR>l>% ziE%_GTM#YT%rCY7Nw7R`Tlh*(cVP@o)@VVk8Zd7OY!Z{(ysDUeY_B1ZFk&LQ2=QVw z9hPsnn(A9!;4BJYP?|A$Njd2Vx!6j<`jF~U-3g=PM^v<@y!q1!#fsd?g@{w%goScv zZQ+0;9=3WnC>W)e%#9*C8%}6)fRc3X1nd+vT8fZhk&Q5pXON!%Se8QEtSMqzJI z?0+A__qWo{ZQ!jP%VxHwfotTcf>1&*qJN**?rDRGv0(uh`W#mw{1w4{2n6mjmAu$%v-T18rc2GVJsP5YH@%}hs#1GtR z5Lf>*1#eOLYIqU{!q#+1=T-12@52zIKd~Ufv|-%>sT`b5=0pJn!NDnrh>WHeRhZn?V|@24CXuIkqgMV6&GMD_k{uOq zbHUu=;$*o=MvlVUu;M_I(vKLNJtsFMHa>$#Bl>~pJp-j)NwPg^)G7l`CGnIxrD zQd3sHDQ{3&I2q$Q*k3xnfnTdlad3!$*e6>5Nd^Isx%J{dZ|0;BlDy$CK>;C=B{~n3 znx>Ts*+4P3TfvgV`oWy)qSY>f#Smm#yAc^0NpQC9CZ$W-);@#XLisrADPPn38dAG#LLVC&g?(Ge^rt}HISJ5zr4^9-;_#wdXo=EQ5msND?-A-XoO@z#{QF;mv`po4$f*_ z(Ki>wuVatL6lGJ~B$5`(8s{+qBQvwK(x67eoNFcEpMoD;sYoq?U}7>o zCu2GE`74L0^3b4(mky%L>V;8$rDbl$QEJzvO3bOIsA^n1nQUtHpFxgO_BUHxRj5+Fru5P)1*i{cZeV9RjXk1Z*k0M)b(IEXIre$VH*&DeJb9Mgrx*q0vs!7spbkB7GY*Y-Hf6}clIdHsGbo$n*_9!gfTIqD$x7+}0Y_jA17NCT@LZ%hi7Lv_A(W6JiFhS`D@8Umk%5on^Pb>`xMkW1V$23i&y-?o)u zl8ABgqesr!3sf$ZF%|!N2j=J+QZ)p?vY*0lp>~a+KTv#oUUbUp6nUm&vynv-S>tqL zAbqD~{whVc-KAOEHTj-rJ&XNbE#AM~jQ~q9@sYTEq^*#Q6FoFTRAJ}yds)nb%7V#N zFP}4zJ%7iVnsW7zp^FyA&6z9fRIw40zHXQDaORTWK78~LI81w5;~g`fO-wOCJ!Vn# zxJ|0pz%ZX)NSgiT`#;=2=f<4QEU4}Scd&vx_WuqtuuYyxUVK$TcG&oS+eqHCqA~Bj zEm^a_OUOQP$F%M?#)F>7ykkTQ?U5sl$-#O)Rp7B<-ultg0aEmD1$M91k=t!Z`LqAa zWYU(J+IGN%y&(_gTg~VFUcTS)dGh;s`T!B)O(guH^8I0s83owx;<4%GJhkiL`5Els zykj35gqa|M+n$A(M4#FHBaq+{bW>1ZxV`FOiC=OL*VTzXYA+TUre<8gGwp&joEm16+O7L$R1*1x2_NAQ0*&t?ZmKM3w z(1ZnIuBMCFpE_w|qu^lk!atC9R%>gxl8-x`FIv32lH0P}2iace3#Ta|mLs~mjr2vk zcvoV6{u9{93GxJ--9LlkIuIt@(!_Cy9z311XUC8&$g9s{ow(hIX1`|rq~8{1 z-kROx{9vkrK*_J3#&ZO=W^YLYs)`RBqbCgkvhJbzuSP4lXwE&99|RgGB*e1^;R>Wk zF*1}|*ywCuTeJ#MUL3w-p|{nUOkHEAr6RsDT{@L)?^%~_jA^kc$&K_*P?hc-pXIta zU9oaSGE_m!AN9ykkWv~m3JLZDJJ#plK7RWojL@&_tCkq= zUf9fs%G~&0*1Giie>sDDp&)MDST%r{Zbt$l(C~rQ{M|GAOPOLN+qCfILT(!Mm`L#B zcI#nJX+J%Q|$|l8H70PCOb{{iGXp}tFXD=EUH0`m~CD8W3@0MvBiv|rUfA20< z3F%Pf;p|Y~9D6FD>s;vF>mKnq-MoL8Et6PNRJA6%PoN&v_s|$f_FVXuj7U{A*qGxGQ zN|kx#SX$9CGBuf_zS)aX`geBp+39x~a~NpSKiIXdF~Oav17G%Y4<+WC z+{j3+eS#YDN*WqUF?pC$#Amj#`ck*mFrDs$ZsDrD zWy^)jW>kXwH^m*a9RX8H$Z2fpXu8*>{5%8Bt-C!R<%kiVSMDdBD3Op}Nk+<2O;o<7 zMfd$!he9w;|J!Uk#XTDfxIU!;knFDW-PilXXH_XlFzZXX67mH|E-$mLqE|(;G&d}I zmj`mAxY>i*MvS)VdfX#;T-{Wid-zNKq7Z=$|0E{W7wr9BWjjNlBE^sJxJx%nS5F|> z6_j`_8xmm5cN}B?4eo^A+2~i2g_bGH?RBCMliW({3CJ8DdR4=)2CcxG*RwL3ERWcw zTcE>66CwF}RDmn4AYXrn^UOWQ*0|n!k-3_Mf@7zNrrdnhN$Lc(?3$j>p%?XHJ>Dvv za*Arpj!Ce1tMrZ1x}dcJ{o!BR&Q%)??WpbRMh~H;k5#ET-`W9J*hV;5=FDg7t6_W} zMm1t_O>E_PJKR-uqDZ}7Azwo0BO&p95RB;`Bl(6)mL;7A%+m~mDNMZpLNeiF{oyq3 zwA?sD+AOpui(I}97sZ~eGm~ie$~G_&rDlJe7HdSIwfSmU)Ut2}>EdgyQ zFc+wtGh-@RsA^Sv1`UB`f3U>F0`}E_(Vps8;y`e$LtY% zow@6V);-{MYhW6HO{A)8p=qc%oHT6$HIkFu#s;_@*n7dcmg~IY1%k~I z@cXU?QrZfanh*bBL#jT0DfNyEfAJcs7q9tlymXwy=yQF0AUY#gOX6G=xKkA&A8xJA zJYDQ;-A(_5fzsXLHo)LPiy7x{3YtI$m3b0@0M(~?faC`-r?8v*y|1TP7M=L`)Z&o` z2ZGX()`YN0TL*zS?s711#)q`C%lAz7!gb{K*(J_pnxjpkV&U+}znkYvMNn_1@bOX2 z9WrG=-3U0FhnoVYhNNC!K^i;^&_kUsO_gWn2x)S;ssOl?*b?3L8!s6 z7gaf88w_GjieSJD7|37avi#mpA96v77h`dv!e|jJm>EK%zNTVBa`5nI+(imX`5XYMMWZC>qeY<` z2GwOvRFm?F8h!u$A!$$<1xD(| zrcdW!mk%-QRfOgM*FPZ_{itY?fj*^R&dT7XKhe8-$8^iM9MHwsA})Pv9m)Ob7yDW@ z6K$o6Ha&*K8GQ%>V-Jjr;X6Li=(&5es#y$*a9Ex~RdGz7B_X_JSac1M%q&;6wAk~; zcj=t=IdB2z>xcU&&VD?DWLG!=C4X)iKvMm+D!^V?!(2zAR-yQD*{cghji^)`EFFo_ zq)W)Orqc<*CipiyMDer`%<)8O2V6jLU~#bZ6L=<(1{W{aJK!(nkWAeF-oCdQ-K%ruLVbLcMnx8-o=vMzy6?b(D76+kFZNGMSYBBjtq8MSbF z0!j*%g!rad;1QNN%i^Qq6Vj@Z4mCBt>vLOw;b7kQNY*rNQ}t6cN4M1j16^AC~RGZ~^UI1okTjb06mBoUz-%?o#NRKK(IploOPauLQXG zX0`b4Ao^?MHZGZVo|ytsESyr73}}22HE}NvA!^2)K$6-h<*7eZ;eQg87#p!Tyw8P1 z-qPOJ&HF%uT>Z>I+lNxH+$@RY@;#hlzJP55r?~G@fm)AC z&Hi$iqx~8x)@`RR+?3eQ+7);`cOcF^ZIj}X+k8!p18xEA04sRpC_I&)D}6ryyKu3rrPAREb32|IddaVaCGa?YLVa3sI4^E(wc&OlYb1^ zr8v7_7WewQ{=e(L2wR3Xw#lY_N%@Pc>(CIl7t+&ic=jD^p8(mN+sH(jjaYn)SLNus zk$GYI&gf8G|9WgNsXh}Pbs>&{H1n@tQy6LW|PlsA#K3Aqu->4mcWvcy1l$S?V|v;Usf{Jqr+pE-YqQcxV*;1v*Uw9X13j(wXv$%YzS18KfvvNjPtv0)HHO z{vTxEdzfcY5tP{)P%1GCj-;55sP&6r#d8xnmnnrFw1Ns=Qh#*+WrKoF@5;kk;?TVI zE=m;TQ;zX*rUYG@>|e*z#L{iY?LV&t-G?7LB%Da-I5hglHF@r!hJyUB8Q*haH)q+_ zAuD46tJ-tZX10!oluCG(8eTtDn4-=4E}HM-=I-zH?9z9~Vd0|4`b@+cNA}n~&?gXnHySa#+7&=2o}2-KJSBUf!n~@cu(K9c*8fN}hr{RCh%3UNc$hwseBjil zgAyTy#AzA)!cfAMBu^8ORVLnSW%KbR)SKz1aYYR;e^Tm%5iMsaSWHV<)-_j|Snz3~ zTR}_El`bKHkqh_buq2CL#K6W4>!eXaNyWm{7 znLTgqqaJ4VGy7V801d%zqmU=O3*b5vH#BvI5D8sa=o<%9ACc-KexM-E0JALbM$^HpR?a%&crRzSW%bw77*|`_tY?Q5Mvo4)xTnnS*JaLT_1DA2EBwXnpZv0^C=;F!fbi4*+Dq)_A`i_ zL#MbeDhhXH2{hh@GK;oJ9U`SWPtcs1E-d=clZWpuoq>j2soqCB#?N>|nWP7>78s zRq{B{UfXra$(uN^_&e}D-Ycqo|JBiVDuvpNAJ~`QdGsBuv~ziWcLVMXh5ojNeSGm+ zd}fDXG9dWLCclK{;?3gn%^G`8xS%DH8#tE3A*^DszV; z2muToygT5$O?4}BD?;075<~o^Ycd70u|68I>*XW}E)5ZEKc00(c&rOpV#!4Jb}d8?ltM16C|US1|AeVkk3YD zAKV`WtOaEdu8wXQA^M8i_S$-_8U6}KxRgueNG}ksxI21>>gp5X(-U_17xUHdX1^4& z(IW=0iW(e#F7iwO3Lg|9HrywSsBp)JXMBdbf7rV{v%|N{#q4-FJdspJ2MHbx{rdV0 z*^hkK=q{Fb_`Xao=0&wtN*>-dO&rb`@jm}ID zZtEZ1mdve|jS0c+06}Z+06=4ZJOh#qn}))u^*n^xWYd_PALX~-lu87Q!q?0?W>u=L|i zFNJa9g%eV0wN8`8VC6{^uX@u%P(%SjK`So6K&$O-!R&4?0n(r0rW)ERFz^@07vg&u z2`GY4gu$@6Av8lOx>z(BDLhhy#4xfUB|}WQY`4@ju_;1R1jn$~@Yk@nA%KAxH8Cne zR0Lc&$*`g!Mnj;wL^Yu*l2v%iFsC6;L%_PYHQ{x{%&@8&Eh#!d?=qk4>Nr z>;lrc&yVM;(=FOwols>W?-kzP?6q4Zs5Oo`gZ)=O(zGIJ#z&6M$;3g6|d`PPD*K~M_= z0{T8{P(78l@qfc@c=76}Da*LWu@&(|U~+S{Ijd$xxXeL<)f!xamX6W23Xo5QUUR%+ zBB-TSeXnNKtcumU&^-DE#<`;$~^w059rG5Qidh62FvtR5NO_ zqfRma>K<>un!<#%$Zj%9DdskttX*K_rj@@~*(~hZt1e zJXj33HpP$WtC@KA91mre>xt57mV{p6uXb99UCME(=*JU*or-l zh!(GHUVC&Ks_di-+SY*w&a-)&$7;hj?ecaB98}4?8sr5-T!L}#((Jf7tgm#zf#YJ@ zCp(u1*WOD`u4SiiC~Aw{S8_;??+=9JhlXW^*rui**eu($PaBVv7rVPEOW1t_3cuDQ zKUyVp`BP*E6HQrD)q0SOz^#gROO$I6lo1S!_|~VlcNO@nHOi26aY}2f5AUx673Q}X z^vk9tT{kC89dDdKkPhAtgKssJiOq97Ml=$1A(LE4Kab%NFgn!?h=zk>zPP-Dxq9M_ zHL>AZevQ|GgFB$@h8IF4Cs|R#iFY+9In;(>e$BoCpbB8)aYY3_Z^V|V7^{ah4{NN5 z)dDm#3U%I;fX~6Oun81C2_;sLZn- z!rg#vZY$obKU1GIUxt&$$;NmWIf}1?w7iA8jf=-bZro{Gcig9}An;|-Cl4-64Zaeb z*O{Zb#yvDBH`0z5X=oO(m4%LYN}r#2c%Pq&xQ>pB3Qm}<#_vhygfP@#{tpv^b}f>S zSj)4dcvh8~vA(>#guar3fvGKSSq4`9s6$zbV1Z%@;{-+p#z&i-5M-DEC_TCeD8lhA zjt}5bZg`BAei^bYKXrECX&=WuHL*SI@xFO`EZz!U1ktLe?HS+@TQ%N9>~$=i0iFr$ z09m5cnsHRz)7RR`boy92k&G?7k$;&(HHP<=P5sX#r@31}WnaK2KE)L|-M8ezNL>iV zV@c+BPUVfpveP*_vBKXRfj z+HOYm5vm{`$_rS`KFD@?vdSJPBraWHnM6_&2APE9QJA+(K*V*MTCYqYk3OROqKJSO z#2i#*?pD9xPr@pRp$D#~Ep>5$s~~ypQMxdo5^@2+F=OA7y(!)qk!mbhnUd<&_g39y z-|9njWn3hvu6=Ebr0;w$E;I#%oUX=|%cRpHGS2icr8!w#mN8qy;?V*hvNW_k?CQ8i z%{xA$BXiSnx+&kFV>mazGt?oyVytb~>X$?LJg(zfo(eCi^eDBhy1n*B69lydl9WxF zbw;nzLMgYo6}=D4tiu}*W1C@vK9==C6MKEC>~%^`qilTE&LOhJM{xKlmml(on12Tc zCi&rLy=llP0gkvft;1Ff+G}r#>9;L{y6*~#=9*2cumicA*8XAkG1$u&n;uTqEf z7p4bp24TzAw?cj_ZNaKmSat!Ztv3MjtPi0($UO$!muc`eFpE2Q7r!@y2`tagF*}p2SvcNQ4xV}W8qDNbcrg5P&c->td;9=z*y=@CJ zlLD}*2cbYDnvE~?@~w}d^pmtSbrE5C0ucZ&{;JDuVzJosr~$`>w7e{gwCNBuuyqww zly!&GyMd^DFgiL5C9LU-9X z0faIz+3P-*(XJtWYR9d6*M*K+V;%slgt9r>;N$Xjt_NYr=ENSJ z13@TjR8z)Slh3Ov3!l4;dJ^3poJagI)*yJ=Cq_pK`o zlIw#g!7>&iB$ZS|&^o&%^we2*j)}Qwr_~B=xBxacUX%DYUMJ1>V&30dUFH6=QGp_+5M?RZ@DsNVL~6vq)4A^@o7UqzjA_Ezl= z-oTXR%N=j=CcS&&ekvBIHG_6VloFU6Lzfnq+Yd%_E}y(SGz6-waI=6Kqukr$EhXmK zEftYElm}tXU{z7o1m!XGEP%>#|pxl((*`1gZ+1Ro$N{a+A1iDl1ugyf~fOV93GdEJ-Crn;PtY# zQdK4jM#AGkE4>W^JKl@u|Ealhx+`iF)zU3KJ)?N|x|-NfeZiokObSKS>MDMXY>h^1 zJANM*_{@McZ+lGem_wM}@4(+A0^HuzCXm&Cq?z%(S60viD^_mmR zA7VQ9iSEH)I>2opLcf-~wwd5{zL;g}1;Pu4nOX`x)RfMFH z>UT)P!amxgyj;C7snMQo*zL<-TfN1v-s5U}$tHtIjnu=|rsN8hTrqHetVMxxmMcNu zy|4i*IHk~07teIfsAMhYMXk7HS*iAAcGmb5^eXbEK`~yqVqL8|ZdGI5{*?|MZNZAn zS@-_>$b!{`{j+N2W+@6m8%Fj)-N;mK&n)WSQFxQ&hN9V6PcPk^S^{E);FGcvtorGG z7)MdZXg0I+sKEuZ%asPpFX3rUz6hod`tK7_8-m8KSIiD+JEpa?I+0T1%!2=F_KQ`4 zFMyq{*NTkAVrz5;n@70;Is57O;(+Y&O_>cO8SMVqFvG2yNDip$%8JXcSx{+8gkUO5;hxk)@6xG@jgzZ$kXsg_DcA*77+;NW6oSeJYx;_lx+l=3L@=w0f4 zM`Zz1($nD)CSP0pZRQ~6OjCF(fxR7xKZ7LERM^kj_?VKH_<*Ea?!p5_#S)2$ zWyXs&x?@wPw751a%4Jn`>pyn*e$U#~a-)WIlS*w5Y$RMPJ47$=M$!=ZNLz0w?x^PZ zLlthmlGOb%9c96u0@A`QjE0 z(gV22-dEF&5%#&w@trqflZMnD*}!YdYC_ zO-MR#Zz&%s8nr)JrWIdYDKg@f7ysFE(q8rnvJ3ah+AR9?9PnN{oF!CnHoe-ZQTR=QC zZ=u{ngRg#lDVni@iBPo3S?oGyscC7u8ZD2gdmxfHcv%X*!W7SgM-K=*Kr|ys^Do9h zj4C3`8MOh``W@^so%ci0Bo!zyxt$i-hrOYo40y3W7Iy6R>qp4Pf~$@_4H`XYH=Wjk zaowa0`V{8owaV|*i3eH4Kd;!=fqGw_QC|o!SdicX1eWTD*-d* zZBH&O`omsICg*}Kk-X7HaVFm>vg0cL`ybKVShbt(+2CfotqM(pVU3X+;JHz1f1vp3 zT2Pc1_rv_5!JIBI^TSEq+h#^Q;D&q+9Y<KlpJ2oCeyj-;7~b-{4VomE32hH|~PC z%AWyc*Cm5y9=^26)d?DLyWpj3&uEBCIN>%E(_mi{=m}oI}o( zI+0(%xOvU%E42PBYU53}IJ?x{MIARN6xEsShmX8<>%KMLad;gau?Qb#gceRPm@^s_ ziJOZ!P$So<1j#H%lqMCx!fVHs)!!fVu_y4xdOd-B3=o|%F0n*`P)a5A#A!p(7$$m< zHr2)TykaKgczzA>qH^4rcD7ly!WuH~cH&x=w3|54%EFH@n`mLGC9RKKRt`ZdP7!(J zi{XvxKz9S3dFwxKg=;)GJQT=GR46VpJ>C5SUp(tLnkU4I>@%FkmShWXe60J1fZba$ zs4qfs4UPhCTtV*JyuCnP83L6cAcukjLwK(PUFIL@l_dC1BSsZYP77)jgk|mbyc`ME z3}xl(DYaYBS%h%$%wm$OuiFnGTj12BW&0%7r=^t3EteeBPVV`yB{^aTqx($~T+R)? z{%oSofR8=)L+X~j-@zSL!@zucy5eXQ4Mp}dwq!5uFHr3A=o_9paV|B)Mrs|oTy+`+}7*b zg?saJ3;s~i4o-!fu|IWiRLm2^_5`i=Qbb0iF5ceHv+URN%)3JG{sx`F{e2J)9Pi>r zwukzI^;Z)NT+i(y61YL;eZh0~l?*c|LRDJr{<#2DHze{sFTPIHF7|S zE%yzv9vTh?#srNXaaMDvL;q1VVc);wWXBlfW)J6{hRh-)wB=+q<`$;$)~b7%U$_ze z^?!1g`w_R?pmJXtOD3cJb|o43a7bYh6O^_MgH(*^JGsu^UFy8Ivd1YmFjiQXZi4(CH_jybP>DK|1}GU*4M8Sd^GHyQDTky`<7M16Be@3cm$|JGRDVtH>j zTs0fQdQ=`wXyS|qnJ*IKIn0^EhUxVbAs$^cWs|hPCO5w38Bt>TS+SoRTX?VBUE^9& zzzgb{ciUzy3eFhI)L}K#F)98^ML*SC4GBf!e7AQ$JW@f+nX?s9aPfwLm50wIUp`(+ zNn^?G;Gpe$4+;ThD^PMe9uH93FC*2(L#&GBQvEoZvW0%2k1q+^l+M!QVURtn0mjLX4rrg6bE*|b$eeVs#yR=YS}Uk)L6$7!tsWcM^JVPV zCp@rf-CY~&$8z%WL0I9))+{E22~1dF#PX*S=82xE*FnA{eWF7)ncsVt|UtRRXJ*ASV?+^e1eO1usc953{F0K2$R_+V}yWbV$-U zG9+aMu5E|o^b!4s3WWCcY2C6pYj|>eBBko6yWRE?jSoTrINDp)=uOK>pliCn@>hTx z^LKvyznsxV)n(g>WPT7L(mbtq5N1^r*e}1Baq2A9+^^cv)%N$bP>QH_la?F@9>%Gc z;TqCsU<6O*Eg#&teJ~^a{;Mn4FDozM>Te~Nv#r^yO_p~}*$W{A!Sg`hrZBNx;p@=z z2CrtdFTvHna!taf%N)Zvz-g#oJ*Q&{C|q9-1||vX{WBuSKm=3t$5=)#Jv+7Jc>j3{ zF$R5Q?r)z4DqGB?Z{NVTTpYTVO|Q9Q8#gDjP7zHP7a@<}XSAkbFRCvGh&7U`640d8 zOMpBsfR=T$gXc^43hd4_CCxh`)kXAEN}$| z=gY9<&xW@XEam&Pq3?9vmgfrucYc=Ms~v7Of!t?27K~n1e0;(`T4<7JCMUs;;fN;7 zV~}q=iDMii-X)>Lh6}WrIQrdsIc`~3%$%?2s758nl4pc>oyU|_R@d8Rb6dKCy&3G9 z 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 literal 0 HcmV?d00001 diff --git a/gateway/run.py b/gateway/run.py index 9926920b81..c85210515f 100644 --- a/gateway/run.py +++ b/gateway/run.py @@ -3503,6 +3503,14 @@ class GatewayRunner: if _cmd_def_inner and _cmd_def_inner.name == "background": return await self._handle_background_command(event) + # /kanban must bypass the guard. It writes to a profile-agnostic + # DB (kanban.db), not to the running agent's state. In fact + # /kanban unblock is often the only way to free a worker that + # has blocked waiting for a peer — letting that be dispatched + # mid-run is the whole point of the board. + if _cmd_def_inner and _cmd_def_inner.name == "kanban": + return await self._handle_kanban_command(event) + # Session-level toggles that are safe to run mid-agent — # /yolo can unblock a pending approval prompt, /verbose cycles # the tool-progress display mode for the ongoing stream. @@ -3727,6 +3735,9 @@ class GatewayRunner: if canonical == "personality": return await self._handle_personality_command(event) + if canonical == "kanban": + return await self._handle_kanban_command(event) + if canonical == "retry": return await self._handle_retry_command(event) @@ -5154,6 +5165,37 @@ class GatewayRunner: return "\n".join(lines) + + async def _handle_kanban_command(self, event: MessageEvent) -> str: + """Handle /kanban — delegate to the shared kanban CLI. + + Run the potentially-blocking DB work in a thread pool so the + gateway event loop stays responsive. Read operations (list, + show, context, tail) are permitted while an agent is running; + mutations are allowed too because the board is profile-agnostic + and does not touch the running agent's state. + """ + import asyncio + from hermes_cli.kanban import run_slash + + text = (event.text or "").strip() + # Strip the leading "/kanban" (with or without slash), leaving args. + if text.startswith("/"): + text = text.lstrip("/") + if text.startswith("kanban"): + text = text[len("kanban"):].lstrip() + + try: + output = await asyncio.to_thread(run_slash, text) + except Exception as exc: # pragma: no cover - defensive + return f"⚠ kanban error: {exc}" + + # Gateway messages have practical length caps; truncate long + # listings to keep the UX reasonable. + if len(output) > 3800: + output = output[:3800] + "\n… (truncated; use `hermes kanban …` in your terminal for full output)" + return output or "(no output)" + async def _handle_status_command(self, event: MessageEvent) -> str: """Handle /status command.""" source = event.source diff --git a/hermes_cli/commands.py b/hermes_cli/commands.py index 614d783d95..2d748d525d 100644 --- a/hermes_cli/commands.py +++ b/hermes_cli/commands.py @@ -140,6 +140,11 @@ COMMAND_REGISTRY: list[CommandDef] = [ CommandDef("cron", "Manage scheduled tasks", "Tools & Skills", cli_only=True, args_hint="[subcommand]", subcommands=("list", "add", "create", "edit", "pause", "resume", "run", "remove")), + CommandDef("kanban", "Multi-profile collaboration board (tasks, links, comments)", + "Tools & Skills", args_hint="[subcommand]", + subcommands=("list", "ls", "show", "create", "assign", "link", "unlink", + "claim", "comment", "complete", "block", "unblock", "archive", + "tail", "dispatch", "context", "init", "gc")), CommandDef("reload", "Reload .env variables into the running session", "Tools & Skills", cli_only=True), CommandDef("reload-mcp", "Reload MCP servers from config", "Tools & Skills", diff --git a/hermes_cli/kanban.py b/hermes_cli/kanban.py new file mode 100644 index 0000000000..0744a78753 --- /dev/null +++ b/hermes_cli/kanban.py @@ -0,0 +1,662 @@ +"""CLI for the Hermes Kanban board — ``hermes kanban …`` subcommand. + +Exposes the full 15-verb surface documented in the design spec +(``docs/hermes-kanban-v1-spec.pdf``). All DB work is delegated to +``kanban_db``. This module adds: + + * Argparse subcommand construction (``build_parser``). + * Argument dispatch (``kanban_command``). + * Output formatting (plain text + ``--json``). + * A short shared helper that parses a single slash-style string + (used by ``/kanban …`` in CLI and gateway) and forwards it to the + argparse surface. +""" + +from __future__ import annotations + +import argparse +import json +import os +import shlex +import sys +import time +from pathlib import Path +from typing import Any, Optional + +from hermes_cli import kanban_db as kb + + +# --------------------------------------------------------------------------- +# Small formatting helpers +# --------------------------------------------------------------------------- + +_STATUS_ICONS = { + "todo": "◻", + "ready": "▶", + "running": "●", + "blocked": "⊘", + "done": "✓", + "archived": "—", +} + + +def _fmt_ts(ts: Optional[int]) -> str: + if not ts: + return "" + return time.strftime("%Y-%m-%d %H:%M", time.localtime(ts)) + + +def _fmt_task_line(t: kb.Task) -> str: + icon = _STATUS_ICONS.get(t.status, "?") + assignee = t.assignee or "(unassigned)" + tenant = f" [{t.tenant}]" if t.tenant else "" + return f"{icon} {t.id} {t.status:8s} {assignee:20s}{tenant} {t.title}" + + +def _task_to_dict(t: kb.Task) -> dict[str, Any]: + return { + "id": t.id, + "title": t.title, + "body": t.body, + "assignee": t.assignee, + "status": t.status, + "priority": t.priority, + "tenant": t.tenant, + "workspace_kind": t.workspace_kind, + "workspace_path": t.workspace_path, + "created_by": t.created_by, + "created_at": t.created_at, + "started_at": t.started_at, + "completed_at": t.completed_at, + "result": t.result, + } + + +def _parse_workspace_flag(value: str) -> tuple[str, Optional[str]]: + """Parse ``--workspace`` into ``(kind, path|None)``. + + Accepts: ``scratch``, ``worktree``, ``dir:``. + """ + if not value: + return ("scratch", None) + v = value.strip() + if v in ("scratch", "worktree"): + return (v, None) + if v.startswith("dir:"): + path = v[len("dir:"):].strip() + if not path: + raise argparse.ArgumentTypeError( + "--workspace dir: requires a path after the colon" + ) + return ("dir", os.path.expanduser(path)) + raise argparse.ArgumentTypeError( + f"unknown --workspace value {value!r}: use scratch, worktree, or dir:" + ) + + +# --------------------------------------------------------------------------- +# Argparse builder +# --------------------------------------------------------------------------- + +def build_parser(parent_subparsers: argparse._SubParsersAction) -> argparse.ArgumentParser: + """Attach the ``kanban`` subcommand tree under an existing subparsers. + + Returns the top-level ``kanban`` parser so caller can ``set_defaults``. + """ + kanban_parser = parent_subparsers.add_parser( + "kanban", + help="Multi-profile collaboration board (tasks, links, comments)", + description=( + "Durable SQLite-backed task board shared across Hermes profiles. " + "Tasks are claimed atomically, can depend on other tasks, and " + "are executed by a named profile in an isolated workspace. " + "See https://hermes-agent.nousresearch.com/docs/user-guide/features/kanban " + "or docs/hermes-kanban-v1-spec.pdf for the full design." + ), + ) + sub = kanban_parser.add_subparsers(dest="kanban_action") + + # --- init --- + sub.add_parser("init", help="Create kanban.db if missing (idempotent)") + + # --- create --- + p_create = sub.add_parser("create", help="Create a new task") + p_create.add_argument("title", help="Task title") + p_create.add_argument("--body", default=None, help="Optional opening post") + p_create.add_argument("--assignee", default=None, help="Profile name to assign") + p_create.add_argument("--parent", action="append", default=[], + help="Parent task id (repeatable)") + p_create.add_argument("--workspace", default="scratch", + help="scratch | worktree | dir: (default: scratch)") + p_create.add_argument("--tenant", default=None, help="Tenant namespace") + p_create.add_argument("--priority", type=int, default=0, help="Priority tiebreaker") + p_create.add_argument("--created-by", default="user", + help="Author name recorded on the task (default: user)") + p_create.add_argument("--json", action="store_true", help="Emit JSON output") + + # --- list --- + p_list = sub.add_parser("list", aliases=["ls"], help="List tasks") + p_list.add_argument("--mine", action="store_true", + help="Filter by $HERMES_PROFILE as assignee") + p_list.add_argument("--assignee", default=None) + p_list.add_argument("--status", default=None, + choices=sorted(kb.VALID_STATUSES)) + p_list.add_argument("--tenant", default=None) + p_list.add_argument("--archived", action="store_true", + help="Include archived tasks") + p_list.add_argument("--json", action="store_true") + + # --- show --- + p_show = sub.add_parser("show", help="Show a task with comments + events") + p_show.add_argument("task_id") + p_show.add_argument("--json", action="store_true") + + # --- assign --- + p_assign = sub.add_parser("assign", help="Assign or reassign a task") + p_assign.add_argument("task_id") + p_assign.add_argument("profile", help="Profile name (or 'none' to unassign)") + + # --- link / unlink --- + p_link = sub.add_parser("link", help="Add a parent->child dependency") + p_link.add_argument("parent_id") + p_link.add_argument("child_id") + p_unlink = sub.add_parser("unlink", help="Remove a parent->child dependency") + p_unlink.add_argument("parent_id") + p_unlink.add_argument("child_id") + + # --- claim --- + p_claim = sub.add_parser( + "claim", + help="Atomically claim a ready task (prints resolved workspace path)", + ) + p_claim.add_argument("task_id") + p_claim.add_argument("--ttl", type=int, default=kb.DEFAULT_CLAIM_TTL_SECONDS, + help="Claim TTL in seconds (default: 900)") + + # --- comment / complete / block / unblock / archive --- + p_comment = sub.add_parser("comment", help="Append a comment") + p_comment.add_argument("task_id") + p_comment.add_argument("text", nargs="+", help="Comment body") + p_comment.add_argument("--author", default=None, + help="Author name (default: $HERMES_PROFILE or 'user')") + + p_complete = sub.add_parser("complete", help="Mark a task done") + p_complete.add_argument("task_id") + p_complete.add_argument("--result", default=None, help="Result summary") + + p_block = sub.add_parser("block", help="Mark a task blocked (needs input)") + p_block.add_argument("task_id") + p_block.add_argument("reason", nargs="*", help="Reason (also appended as a comment)") + + p_unblock = sub.add_parser("unblock", help="Return a blocked task to ready") + p_unblock.add_argument("task_id") + + p_archive = sub.add_parser("archive", help="Archive a task (hide from default list)") + p_archive.add_argument("task_id") + + # --- tail --- + p_tail = sub.add_parser("tail", help="Follow a task's event stream") + p_tail.add_argument("task_id") + p_tail.add_argument("--interval", type=float, default=1.0) + + # --- dispatch --- + p_disp = sub.add_parser( + "dispatch", + help="One dispatcher pass: reclaim stale, promote ready, spawn workers", + ) + p_disp.add_argument("--dry-run", action="store_true", + help="Don't actually spawn processes; just print what would happen") + p_disp.add_argument("--max", type=int, default=None, + help="Cap number of spawns this pass") + p_disp.add_argument("--json", action="store_true") + + # --- context --- (for spawned workers) + p_ctx = sub.add_parser( + "context", + help="Print the full context a worker sees for a task " + "(title + body + parent results + comments).", + ) + p_ctx.add_argument("task_id") + + # --- gc --- + sub.add_parser( + "gc", help="Garbage-collect workspaces of archived tasks" + ) + + kanban_parser.set_defaults(_kanban_parser=kanban_parser) + return kanban_parser + + +# --------------------------------------------------------------------------- +# Command dispatch +# --------------------------------------------------------------------------- + +def kanban_command(args: argparse.Namespace) -> int: + """Entry point from ``hermes kanban …`` argparse dispatch. + + Returns a shell-style exit code (0 on success, non-zero on error). + """ + action = getattr(args, "kanban_action", None) + if not action: + # No subaction given: print help via the stored parser reference. + parser = getattr(args, "_kanban_parser", None) + if parser is not None: + parser.print_help() + else: + print( + "usage: hermes kanban [options]\n" + "Run 'hermes kanban --help' for the full list of actions.", + file=sys.stderr, + ) + return 0 + + handlers = { + "init": _cmd_init, + "create": _cmd_create, + "list": _cmd_list, + "ls": _cmd_list, + "show": _cmd_show, + "assign": _cmd_assign, + "link": _cmd_link, + "unlink": _cmd_unlink, + "claim": _cmd_claim, + "comment": _cmd_comment, + "complete": _cmd_complete, + "block": _cmd_block, + "unblock": _cmd_unblock, + "archive": _cmd_archive, + "tail": _cmd_tail, + "dispatch": _cmd_dispatch, + "context": _cmd_context, + "gc": _cmd_gc, + } + handler = handlers.get(action) + if not handler: + print(f"kanban: unknown action {action!r}", file=sys.stderr) + return 2 + try: + return int(handler(args) or 0) + except (ValueError, RuntimeError) as exc: + print(f"kanban: {exc}", file=sys.stderr) + return 1 + + +# --------------------------------------------------------------------------- +# Handlers +# --------------------------------------------------------------------------- + +def _profile_author() -> str: + """Best-effort author name for an interactive CLI call.""" + for env in ("HERMES_PROFILE_NAME", "HERMES_PROFILE"): + v = os.environ.get(env) + if v: + return v + try: + from hermes_cli.profiles import get_active_profile_name + return get_active_profile_name() or "user" + except Exception: + return "user" + + +def _cmd_init(args: argparse.Namespace) -> int: + path = kb.init_db() + print(f"Kanban DB initialized at {path}") + return 0 + + +def _cmd_create(args: argparse.Namespace) -> int: + ws_kind, ws_path = _parse_workspace_flag(args.workspace) + with kb.connect() as conn: + task_id = kb.create_task( + conn, + title=args.title, + body=args.body, + assignee=args.assignee, + created_by=args.created_by or _profile_author(), + workspace_kind=ws_kind, + workspace_path=ws_path, + tenant=args.tenant, + priority=args.priority, + parents=tuple(args.parent or ()), + ) + task = kb.get_task(conn, task_id) + if getattr(args, "json", False): + print(json.dumps(_task_to_dict(task), indent=2, ensure_ascii=False)) + else: + print(f"Created {task_id} ({task.status}, assignee={task.assignee or '-'})") + return 0 + + +def _cmd_list(args: argparse.Namespace) -> int: + assignee = args.assignee + if args.mine and not assignee: + assignee = _profile_author() + with kb.connect() as conn: + # Cheap "mini-dispatch": recompute ready so list output reflects + # dependencies that may have cleared since the last dispatcher tick. + kb.recompute_ready(conn) + tasks = kb.list_tasks( + conn, + assignee=assignee, + status=args.status, + tenant=args.tenant, + include_archived=args.archived, + ) + if getattr(args, "json", False): + print(json.dumps([_task_to_dict(t) for t in tasks], indent=2, ensure_ascii=False)) + return 0 + if not tasks: + print("(no matching tasks)") + return 0 + for t in tasks: + print(_fmt_task_line(t)) + return 0 + + +def _cmd_show(args: argparse.Namespace) -> int: + with kb.connect() as conn: + task = kb.get_task(conn, args.task_id) + if not task: + print(f"no such task: {args.task_id}", file=sys.stderr) + return 1 + comments = kb.list_comments(conn, args.task_id) + events = kb.list_events(conn, args.task_id) + parents = kb.parent_ids(conn, args.task_id) + children = kb.child_ids(conn, args.task_id) + + if getattr(args, "json", False): + payload = { + "task": _task_to_dict(task), + "parents": parents, + "children": children, + "comments": [ + {"author": c.author, "body": c.body, "created_at": c.created_at} + for c in comments + ], + "events": [ + {"kind": e.kind, "payload": e.payload, "created_at": e.created_at} + for e in events + ], + } + print(json.dumps(payload, indent=2, ensure_ascii=False)) + return 0 + + print(f"Task {task.id}: {task.title}") + print(f" status: {task.status}") + print(f" assignee: {task.assignee or '-'}") + if task.tenant: + print(f" tenant: {task.tenant}") + print(f" workspace: {task.workspace_kind}" + + (f" @ {task.workspace_path}" if task.workspace_path else "")) + print(f" created: {_fmt_ts(task.created_at)} by {task.created_by or '-'}") + if task.started_at: + print(f" started: {_fmt_ts(task.started_at)}") + if task.completed_at: + print(f" completed: {_fmt_ts(task.completed_at)}") + if parents: + print(f" parents: {', '.join(parents)}") + if children: + print(f" children: {', '.join(children)}") + if task.body: + print() + print("Body:") + print(task.body) + if task.result: + print() + print("Result:") + print(task.result) + if comments: + print() + print(f"Comments ({len(comments)}):") + for c in comments: + print(f" [{_fmt_ts(c.created_at)}] {c.author}: {c.body}") + if events: + print() + print(f"Events ({len(events)}):") + for e in events[-20:]: + pl = f" {e.payload}" if e.payload else "" + print(f" [{_fmt_ts(e.created_at)}] {e.kind}{pl}") + return 0 + + +def _cmd_assign(args: argparse.Namespace) -> int: + profile = None if args.profile.lower() in ("none", "-", "null") else args.profile + with kb.connect() as conn: + ok = kb.assign_task(conn, args.task_id, profile) + if not ok: + print(f"no such task: {args.task_id}", file=sys.stderr) + return 1 + print(f"Assigned {args.task_id} to {profile or '(unassigned)'}") + return 0 + + +def _cmd_link(args: argparse.Namespace) -> int: + with kb.connect() as conn: + kb.link_tasks(conn, args.parent_id, args.child_id) + print(f"Linked {args.parent_id} -> {args.child_id}") + return 0 + + +def _cmd_unlink(args: argparse.Namespace) -> int: + with kb.connect() as conn: + ok = kb.unlink_tasks(conn, args.parent_id, args.child_id) + if not ok: + print(f"No such link: {args.parent_id} -> {args.child_id}", file=sys.stderr) + return 1 + print(f"Unlinked {args.parent_id} -> {args.child_id}") + return 0 + + +def _cmd_claim(args: argparse.Namespace) -> int: + with kb.connect() as conn: + task = kb.claim_task(conn, args.task_id, ttl_seconds=args.ttl) + if task is None: + # Report why + existing = kb.get_task(conn, args.task_id) + if existing is None: + print(f"no such task: {args.task_id}", file=sys.stderr) + return 1 + print( + f"cannot claim {args.task_id}: status={existing.status} " + f"lock={existing.claim_lock or '(none)'}", + file=sys.stderr, + ) + return 1 + workspace = kb.resolve_workspace(task) + kb.set_workspace_path(conn, task.id, str(workspace)) + print(f"Claimed {task.id}") + print(f"Workspace: {workspace}") + return 0 + + +def _cmd_comment(args: argparse.Namespace) -> int: + body = " ".join(args.text).strip() + author = args.author or _profile_author() + with kb.connect() as conn: + kb.add_comment(conn, args.task_id, author, body) + print(f"Comment added to {args.task_id}") + return 0 + + +def _cmd_complete(args: argparse.Namespace) -> int: + with kb.connect() as conn: + ok = kb.complete_task(conn, args.task_id, result=args.result) + if not ok: + print(f"cannot complete {args.task_id} (unknown id or terminal state)", file=sys.stderr) + return 1 + print(f"Completed {args.task_id}") + return 0 + + +def _cmd_block(args: argparse.Namespace) -> int: + reason = " ".join(args.reason).strip() if args.reason else None + author = _profile_author() + with kb.connect() as conn: + if reason: + kb.add_comment(conn, args.task_id, author, f"BLOCKED: {reason}") + ok = kb.block_task(conn, args.task_id, reason=reason) + if not ok: + print(f"cannot block {args.task_id}", file=sys.stderr) + return 1 + print(f"Blocked {args.task_id}" + (f": {reason}" if reason else "")) + return 0 + + +def _cmd_unblock(args: argparse.Namespace) -> int: + with kb.connect() as conn: + ok = kb.unblock_task(conn, args.task_id) + if not ok: + print(f"cannot unblock {args.task_id} (not blocked?)", file=sys.stderr) + return 1 + print(f"Unblocked {args.task_id}") + return 0 + + +def _cmd_archive(args: argparse.Namespace) -> int: + with kb.connect() as conn: + ok = kb.archive_task(conn, args.task_id) + if not ok: + print(f"cannot archive {args.task_id}", file=sys.stderr) + return 1 + print(f"Archived {args.task_id}") + return 0 + + +def _cmd_tail(args: argparse.Namespace) -> int: + last_id = 0 + print(f"Tailing events for {args.task_id}. Ctrl-C to stop.") + try: + while True: + with kb.connect() as conn: + events = kb.list_events(conn, args.task_id) + for e in events: + if e.id > last_id: + pl = f" {e.payload}" if e.payload else "" + print(f"[{_fmt_ts(e.created_at)}] {e.kind}{pl}", flush=True) + last_id = e.id + time.sleep(max(0.1, args.interval)) + except KeyboardInterrupt: + print("\n(stopped)") + return 0 + + +def _cmd_dispatch(args: argparse.Namespace) -> int: + with kb.connect() as conn: + res = kb.dispatch_once( + conn, + dry_run=args.dry_run, + max_spawn=args.max, + ) + if getattr(args, "json", False): + print(json.dumps({ + "reclaimed": res.reclaimed, + "promoted": res.promoted, + "spawned": [ + {"task_id": tid, "assignee": who, "workspace": ws} + for (tid, who, ws) in res.spawned + ], + "skipped_unassigned": res.skipped_unassigned, + }, indent=2)) + return 0 + print(f"Reclaimed: {res.reclaimed}") + print(f"Promoted: {res.promoted}") + print(f"Spawned: {len(res.spawned)}") + for tid, who, ws in res.spawned: + tag = " (dry)" if args.dry_run else "" + print(f" - {tid} -> {who} @ {ws or '-'}{tag}") + if res.skipped_unassigned: + print(f"Skipped (unassigned): {', '.join(res.skipped_unassigned)}") + return 0 + + +def _cmd_context(args: argparse.Namespace) -> int: + with kb.connect() as conn: + text = kb.build_worker_context(conn, args.task_id) + print(text) + return 0 + + +def _cmd_gc(args: argparse.Namespace) -> int: + """Remove scratch workspaces of archived tasks. + + Only touches directories under the default scratch root; leaves user + ``dir:`` workspaces and ``worktree`` dirs alone (user owns those). + """ + import shutil + scratch_root = kb.workspaces_root() + removed = 0 + with kb.connect() as conn: + rows = conn.execute( + "SELECT id, workspace_kind, workspace_path FROM tasks WHERE status = 'archived'" + ).fetchall() + for row in rows: + if row["workspace_kind"] != "scratch": + continue + path = Path(row["workspace_path"] or (scratch_root / row["id"])) + try: + path = path.resolve() + except OSError: + continue + try: + scratch_root.resolve().relative_to(scratch_root.resolve()) + path.relative_to(scratch_root.resolve()) + except ValueError: + # Safety: never delete outside the scratch root. + continue + if path.exists() and path.is_dir(): + shutil.rmtree(path, ignore_errors=True) + removed += 1 + print(f"GC complete: removed {removed} scratch workspace(s)") + return 0 + + +# --------------------------------------------------------------------------- +# Slash-command entry point (used by /kanban from CLI and gateway) +# --------------------------------------------------------------------------- + +def run_slash(rest: str) -> str: + """Execute a ``/kanban …`` string and return captured stdout/stderr. + + ``rest`` is everything after ``/kanban`` (may be empty). Used from + both the interactive CLI (``self._handle_kanban_command``) and the + gateway (``_handle_kanban_command``) so formatting is identical. + """ + import io + import contextlib + + tokens = shlex.split(rest) if rest and rest.strip() else [] + + parser = argparse.ArgumentParser(prog="/kanban", add_help=False) + parser.exit_on_error = False # type: ignore[attr-defined] + sub = parser.add_subparsers(dest="kanban_action") + # Reuse the argparse builder -- call it with a throwaway parent + # subparsers via a wrapping top-level parser. + wrap = argparse.ArgumentParser(prog="/", add_help=False) + wrap.exit_on_error = False # type: ignore[attr-defined] + wrap_sub = wrap.add_subparsers(dest="_top") + build_parser(wrap_sub) + + buf_out = io.StringIO() + buf_err = io.StringIO() + try: + # Prepend the "kanban" token so our top-level subparser routes here. + argv = ["kanban", *tokens] if tokens else ["kanban"] + args = wrap.parse_args(argv) + except SystemExit as exc: + return f"(usage error: {exc})" + except argparse.ArgumentError as exc: + return f"(usage error: {exc})" + + with contextlib.redirect_stdout(buf_out), contextlib.redirect_stderr(buf_err): + try: + kanban_command(args) + except SystemExit: + pass + except Exception as exc: + print(f"error: {exc}", file=sys.stderr) + + out = buf_out.getvalue().rstrip() + err = buf_err.getvalue().rstrip() + if err and out: + return f"{out}\n{err}" + return err if err else (out or "(no output)") diff --git a/hermes_cli/kanban_db.py b/hermes_cli/kanban_db.py new file mode 100644 index 0000000000..862f9f3c1d --- /dev/null +++ b/hermes_cli/kanban_db.py @@ -0,0 +1,1067 @@ +"""SQLite-backed Kanban board for multi-profile collaboration. + +The board lives at ``$HERMES_HOME/kanban.db`` (profile-agnostic on purpose: +multiple profiles on the same machine all see the same board, which IS the +coordination primitive). + +Schema is intentionally small: tasks, task_links, task_comments, +task_events. The ``workspace_kind`` field decouples coordination from git +worktrees so that research / ops / digital-twin workloads work alongside +coding workloads. See ``docs/hermes-kanban-v1-spec.pdf`` for the full +design specification. + +Concurrency strategy: WAL mode + ``BEGIN IMMEDIATE`` for write +transactions + compare-and-swap (CAS) updates on ``tasks.status`` and +``tasks.claim_lock``. SQLite serializes writers via its WAL lock, so at +most one claimer can win any given task. Losers observe zero affected +rows and move on -- no retry loops, no distributed-lock machinery. +""" + +from __future__ import annotations + +import contextlib +import json +import os +import secrets +import sqlite3 +import time +from dataclasses import dataclass, field +from pathlib import Path +from typing import Any, Iterable, Optional + + +# --------------------------------------------------------------------------- +# Constants +# --------------------------------------------------------------------------- + +VALID_STATUSES = {"todo", "ready", "running", "blocked", "done", "archived"} +VALID_WORKSPACE_KINDS = {"scratch", "worktree", "dir"} + +# A running task's claim is valid for 15 minutes; after that the next +# dispatcher tick reclaims it. Workers that outlive this window should call +# ``heartbeat_claim(task_id)`` periodically. In practice most kanban +# workloads either finish within 15m or set a longer claim explicitly. +DEFAULT_CLAIM_TTL_SECONDS = 15 * 60 + + +# --------------------------------------------------------------------------- +# Paths +# --------------------------------------------------------------------------- + +def kanban_db_path() -> Path: + """Return the path to ``kanban.db`` inside the active HERMES_HOME.""" + from hermes_constants import get_hermes_home + return get_hermes_home() / "kanban.db" + + +def workspaces_root() -> Path: + """Return the directory under which ``scratch`` workspaces are created.""" + from hermes_constants import get_hermes_home + return get_hermes_home() / "kanban" / "workspaces" + + +# --------------------------------------------------------------------------- +# Data classes +# --------------------------------------------------------------------------- + +@dataclass +class Task: + """In-memory view of a row from the ``tasks`` table.""" + + id: str + title: str + body: Optional[str] + assignee: Optional[str] + status: str + priority: int + created_by: Optional[str] + created_at: int + started_at: Optional[int] + completed_at: Optional[int] + workspace_kind: str + workspace_path: Optional[str] + claim_lock: Optional[str] + claim_expires: Optional[int] + tenant: Optional[str] + result: Optional[str] = None + + @classmethod + def from_row(cls, row: sqlite3.Row) -> "Task": + return cls( + id=row["id"], + title=row["title"], + body=row["body"], + assignee=row["assignee"], + status=row["status"], + priority=row["priority"], + created_by=row["created_by"], + created_at=row["created_at"], + started_at=row["started_at"], + completed_at=row["completed_at"], + workspace_kind=row["workspace_kind"], + workspace_path=row["workspace_path"], + claim_lock=row["claim_lock"], + claim_expires=row["claim_expires"], + tenant=row["tenant"] if "tenant" in row.keys() else None, + result=row["result"] if "result" in row.keys() else None, + ) + + +@dataclass +class Comment: + id: int + task_id: str + author: str + body: str + created_at: int + + +@dataclass +class Event: + id: int + task_id: str + kind: str + payload: Optional[dict] + created_at: int + + +# --------------------------------------------------------------------------- +# Schema +# --------------------------------------------------------------------------- + +SCHEMA_SQL = """ +CREATE TABLE IF NOT EXISTS tasks ( + id TEXT PRIMARY KEY, + title TEXT NOT NULL, + body TEXT, + assignee TEXT, + status TEXT NOT NULL, + priority INTEGER DEFAULT 0, + created_by TEXT, + created_at INTEGER NOT NULL, + started_at INTEGER, + completed_at INTEGER, + workspace_kind TEXT NOT NULL DEFAULT 'scratch', + workspace_path TEXT, + claim_lock TEXT, + claim_expires INTEGER, + tenant TEXT, + result TEXT +); + +CREATE TABLE IF NOT EXISTS task_links ( + parent_id TEXT NOT NULL, + child_id TEXT NOT NULL, + PRIMARY KEY (parent_id, child_id) +); + +CREATE TABLE IF NOT EXISTS task_comments ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + task_id TEXT NOT NULL, + author TEXT NOT NULL, + body TEXT NOT NULL, + created_at INTEGER NOT NULL +); + +CREATE TABLE IF NOT EXISTS task_events ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + task_id TEXT NOT NULL, + kind TEXT NOT NULL, + payload TEXT, + created_at INTEGER NOT NULL +); + +CREATE INDEX IF NOT EXISTS idx_tasks_assignee_status ON tasks(assignee, status); +CREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status); +CREATE INDEX IF NOT EXISTS idx_tasks_tenant ON tasks(tenant); +CREATE INDEX IF NOT EXISTS idx_links_child ON task_links(child_id); +CREATE INDEX IF NOT EXISTS idx_links_parent ON task_links(parent_id); +CREATE INDEX IF NOT EXISTS idx_comments_task ON task_comments(task_id, created_at); +CREATE INDEX IF NOT EXISTS idx_events_task ON task_events(task_id, created_at); +""" + + +# --------------------------------------------------------------------------- +# Connection helpers +# --------------------------------------------------------------------------- + +def connect(db_path: Optional[Path] = None) -> sqlite3.Connection: + """Open (and initialize if needed) the kanban DB. + + WAL mode is enabled on every connection; it's a no-op after the first + time but keeps the code robust if the DB file is ever re-created. + """ + path = db_path or kanban_db_path() + path.parent.mkdir(parents=True, exist_ok=True) + conn = sqlite3.connect(str(path), isolation_level=None, timeout=30) + conn.row_factory = sqlite3.Row + conn.execute("PRAGMA journal_mode=WAL") + conn.execute("PRAGMA synchronous=NORMAL") + conn.execute("PRAGMA foreign_keys=ON") + return conn + + +def init_db(db_path: Optional[Path] = None) -> Path: + """Create the schema if it doesn't exist; return the path used.""" + path = db_path or kanban_db_path() + with contextlib.closing(connect(path)) as conn: + conn.executescript(SCHEMA_SQL) + _migrate_add_optional_columns(conn) + return path + + +def _migrate_add_optional_columns(conn: sqlite3.Connection) -> None: + """Add columns that were introduced after v1 release to legacy DBs. + + Called by ``init_db`` so opening an old DB is always safe. + """ + cols = {row["name"] for row in conn.execute("PRAGMA table_info(tasks)")} + if "tenant" not in cols: + conn.execute("ALTER TABLE tasks ADD COLUMN tenant TEXT") + if "result" not in cols: + conn.execute("ALTER TABLE tasks ADD COLUMN result TEXT") + + +@contextlib.contextmanager +def write_txn(conn: sqlite3.Connection): + """Context manager for an IMMEDIATE write transaction. + + Use for any multi-statement write (creating a task + link, claiming a + task + recording an event, etc.). A claim CAS inside this context is + atomic -- at most one concurrent writer can succeed. + """ + conn.execute("BEGIN IMMEDIATE") + try: + yield conn + except Exception: + conn.execute("ROLLBACK") + raise + else: + conn.execute("COMMIT") + + +# --------------------------------------------------------------------------- +# ID generation +# --------------------------------------------------------------------------- + +def _new_task_id() -> str: + """Generate a short, URL-safe, human-readable task id. + + Format: ``t_<4 hex chars>``. Space is 65k values; collisions are + rare but handled by a one-shot retry in ``create_task``. + """ + return "t_" + secrets.token_hex(2) + + +def _claimer_id() -> str: + """Return a ``host:pid`` string that identifies this claimer.""" + import socket + try: + host = socket.gethostname() or "unknown" + except Exception: + host = "unknown" + return f"{host}:{os.getpid()}" + + +# --------------------------------------------------------------------------- +# Task creation / mutation +# --------------------------------------------------------------------------- + +def create_task( + conn: sqlite3.Connection, + *, + title: str, + body: Optional[str] = None, + assignee: Optional[str] = None, + created_by: Optional[str] = None, + workspace_kind: str = "scratch", + workspace_path: Optional[str] = None, + tenant: Optional[str] = None, + priority: int = 0, + parents: Iterable[str] = (), +) -> str: + """Create a new task and optionally link it under parent tasks. + + Returns the new task id. Status is ``ready`` when there are no + parents (or all parents already ``done``), otherwise ``todo``. + """ + if not title or not title.strip(): + raise ValueError("title is required") + if workspace_kind not in VALID_WORKSPACE_KINDS: + raise ValueError( + f"workspace_kind must be one of {sorted(VALID_WORKSPACE_KINDS)}, " + f"got {workspace_kind!r}" + ) + parents = tuple(p for p in parents if p) + + now = int(time.time()) + + # Retry once on the extremely unlikely id collision. + for attempt in range(2): + task_id = _new_task_id() + try: + with write_txn(conn): + # Determine initial status from parent status. + initial_status = "ready" + if parents: + missing = _find_missing_parents(conn, parents) + if missing: + raise ValueError(f"unknown parent task(s): {', '.join(missing)}") + # If any parent is not yet done, we're todo. + rows = conn.execute( + "SELECT status FROM tasks WHERE id IN " + "(" + ",".join("?" * len(parents)) + ")", + parents, + ).fetchall() + if any(r["status"] != "done" for r in rows): + initial_status = "todo" + + conn.execute( + """ + INSERT INTO tasks ( + id, title, body, assignee, status, priority, + created_by, created_at, workspace_kind, workspace_path, + tenant + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + """, + ( + task_id, + title.strip(), + body, + assignee, + initial_status, + priority, + created_by, + now, + workspace_kind, + workspace_path, + tenant, + ), + ) + for pid in parents: + conn.execute( + "INSERT OR IGNORE INTO task_links (parent_id, child_id) VALUES (?, ?)", + (pid, task_id), + ) + _append_event( + conn, + task_id, + "created", + { + "assignee": assignee, + "status": initial_status, + "parents": list(parents), + "tenant": tenant, + }, + ) + return task_id + except sqlite3.IntegrityError: + if attempt == 1: + raise + # Retry with a fresh id. + continue + raise RuntimeError("unreachable") + + +def _find_missing_parents(conn: sqlite3.Connection, parents: Iterable[str]) -> list[str]: + parents = list(parents) + if not parents: + return [] + placeholders = ",".join("?" * len(parents)) + rows = conn.execute( + f"SELECT id FROM tasks WHERE id IN ({placeholders})", + parents, + ).fetchall() + present = {r["id"] for r in rows} + return [p for p in parents if p not in present] + + +def get_task(conn: sqlite3.Connection, task_id: str) -> Optional[Task]: + row = conn.execute("SELECT * FROM tasks WHERE id = ?", (task_id,)).fetchone() + return Task.from_row(row) if row else None + + +def list_tasks( + conn: sqlite3.Connection, + *, + assignee: Optional[str] = None, + status: Optional[str] = None, + tenant: Optional[str] = None, + include_archived: bool = False, + limit: Optional[int] = None, +) -> list[Task]: + query = "SELECT * FROM tasks WHERE 1=1" + params: list[Any] = [] + if assignee is not None: + query += " AND assignee = ?" + params.append(assignee) + if status is not None: + if status not in VALID_STATUSES: + raise ValueError(f"status must be one of {sorted(VALID_STATUSES)}") + query += " AND status = ?" + params.append(status) + if tenant is not None: + query += " AND tenant = ?" + params.append(tenant) + if not include_archived and status != "archived": + query += " AND status != 'archived'" + query += " ORDER BY priority DESC, created_at ASC" + if limit: + query += f" LIMIT {int(limit)}" + rows = conn.execute(query, params).fetchall() + return [Task.from_row(r) for r in rows] + + +def assign_task(conn: sqlite3.Connection, task_id: str, profile: Optional[str]) -> bool: + """Assign or reassign a task. Returns True on success. + + Refuses to reassign a task that's currently running (claim_lock set). + Reassign after the current run completes if needed. + """ + with write_txn(conn): + row = conn.execute( + "SELECT status, claim_lock FROM tasks WHERE id = ?", (task_id,) + ).fetchone() + if not row: + return False + if row["claim_lock"] is not None and row["status"] == "running": + raise RuntimeError( + f"cannot reassign {task_id}: currently running (claimed). " + "Wait for completion or reclaim the stale lock first." + ) + conn.execute("UPDATE tasks SET assignee = ? WHERE id = ?", (profile, task_id)) + _append_event(conn, task_id, "assigned", {"assignee": profile}) + return True + + +# --------------------------------------------------------------------------- +# Links +# --------------------------------------------------------------------------- + +def link_tasks(conn: sqlite3.Connection, parent_id: str, child_id: str) -> None: + if parent_id == child_id: + raise ValueError("a task cannot depend on itself") + with write_txn(conn): + missing = _find_missing_parents(conn, [parent_id, child_id]) + if missing: + raise ValueError(f"unknown task(s): {', '.join(missing)}") + if _would_cycle(conn, parent_id, child_id): + raise ValueError( + f"linking {parent_id} -> {child_id} would create a cycle" + ) + conn.execute( + "INSERT OR IGNORE INTO task_links (parent_id, child_id) VALUES (?, ?)", + (parent_id, child_id), + ) + # If child was ready but parent is not yet done, demote child to todo. + parent_status = conn.execute( + "SELECT status FROM tasks WHERE id = ?", (parent_id,) + ).fetchone()["status"] + if parent_status != "done": + conn.execute( + "UPDATE tasks SET status = 'todo' WHERE id = ? AND status = 'ready'", + (child_id,), + ) + _append_event( + conn, child_id, "linked", + {"parent": parent_id, "child": child_id}, + ) + + +def _would_cycle(conn: sqlite3.Connection, parent_id: str, child_id: str) -> bool: + """Return True if adding parent->child creates a cycle. + + A cycle exists iff ``parent_id`` is already a descendant of + ``child_id`` via existing parent->child links. We walk downward + from ``child_id`` and check whether we reach ``parent_id``. + """ + seen = set() + stack = [child_id] + while stack: + node = stack.pop() + if node == parent_id: + return True + if node in seen: + continue + seen.add(node) + rows = conn.execute( + "SELECT child_id FROM task_links WHERE parent_id = ?", (node,) + ).fetchall() + stack.extend(r["child_id"] for r in rows) + return False + + +def unlink_tasks(conn: sqlite3.Connection, parent_id: str, child_id: str) -> bool: + with write_txn(conn): + cur = conn.execute( + "DELETE FROM task_links WHERE parent_id = ? AND child_id = ?", + (parent_id, child_id), + ) + if cur.rowcount: + _append_event( + conn, child_id, "unlinked", + {"parent": parent_id, "child": child_id}, + ) + return cur.rowcount > 0 + + +def parent_ids(conn: sqlite3.Connection, task_id: str) -> list[str]: + rows = conn.execute( + "SELECT parent_id FROM task_links WHERE child_id = ? ORDER BY parent_id", + (task_id,), + ).fetchall() + return [r["parent_id"] for r in rows] + + +def child_ids(conn: sqlite3.Connection, task_id: str) -> list[str]: + rows = conn.execute( + "SELECT child_id FROM task_links WHERE parent_id = ? ORDER BY child_id", + (task_id,), + ).fetchall() + return [r["child_id"] for r in rows] + + +def parent_results(conn: sqlite3.Connection, task_id: str) -> list[tuple[str, Optional[str]]]: + """Return ``(parent_id, result)`` for every done parent of ``task_id``.""" + rows = conn.execute( + """ + SELECT t.id AS id, t.result AS result + FROM tasks t + JOIN task_links l ON l.parent_id = t.id + WHERE l.child_id = ? AND t.status = 'done' + ORDER BY t.completed_at ASC + """, + (task_id,), + ).fetchall() + return [(r["id"], r["result"]) for r in rows] + + +# --------------------------------------------------------------------------- +# Comments & events +# --------------------------------------------------------------------------- + +def add_comment( + conn: sqlite3.Connection, task_id: str, author: str, body: str +) -> int: + if not body or not body.strip(): + raise ValueError("comment body is required") + if not author or not author.strip(): + raise ValueError("comment author is required") + now = int(time.time()) + with write_txn(conn): + if not conn.execute( + "SELECT 1 FROM tasks WHERE id = ?", (task_id,) + ).fetchone(): + raise ValueError(f"unknown task {task_id}") + cur = conn.execute( + "INSERT INTO task_comments (task_id, author, body, created_at) " + "VALUES (?, ?, ?, ?)", + (task_id, author.strip(), body.strip(), now), + ) + _append_event(conn, task_id, "commented", {"author": author, "len": len(body)}) + return int(cur.lastrowid or 0) + + +def list_comments(conn: sqlite3.Connection, task_id: str) -> list[Comment]: + rows = conn.execute( + "SELECT * FROM task_comments WHERE task_id = ? ORDER BY created_at ASC", + (task_id,), + ).fetchall() + return [ + Comment( + id=r["id"], + task_id=r["task_id"], + author=r["author"], + body=r["body"], + created_at=r["created_at"], + ) + for r in rows + ] + + +def list_events(conn: sqlite3.Connection, task_id: str) -> list[Event]: + rows = conn.execute( + "SELECT * FROM task_events WHERE task_id = ? ORDER BY created_at ASC, id ASC", + (task_id,), + ).fetchall() + out = [] + for r in rows: + try: + payload = json.loads(r["payload"]) if r["payload"] else None + except Exception: + payload = None + out.append( + Event( + id=r["id"], + task_id=r["task_id"], + kind=r["kind"], + payload=payload, + created_at=r["created_at"], + ) + ) + return out + + +def _append_event( + conn: sqlite3.Connection, + task_id: str, + kind: str, + payload: Optional[dict] = None, +) -> None: + """Record an event row. Called from within an already-open txn.""" + now = int(time.time()) + pl = json.dumps(payload, ensure_ascii=False) if payload else None + conn.execute( + "INSERT INTO task_events (task_id, kind, payload, created_at) " + "VALUES (?, ?, ?, ?)", + (task_id, kind, pl, now), + ) + + +# --------------------------------------------------------------------------- +# Dependency resolution (todo -> ready) +# --------------------------------------------------------------------------- + +def recompute_ready(conn: sqlite3.Connection) -> int: + """Promote ``todo`` tasks to ``ready`` when all parents are ``done``. + + Returns the number of tasks promoted. Safe to call inside or outside + an existing transaction; it opens its own IMMEDIATE txn. + """ + promoted = 0 + with write_txn(conn): + todo_rows = conn.execute( + "SELECT id FROM tasks WHERE status = 'todo'" + ).fetchall() + for row in todo_rows: + task_id = row["id"] + parents = conn.execute( + "SELECT t.status FROM tasks t " + "JOIN task_links l ON l.parent_id = t.id " + "WHERE l.child_id = ?", + (task_id,), + ).fetchall() + if all(p["status"] == "done" for p in parents): + conn.execute( + "UPDATE tasks SET status = 'ready' WHERE id = ? AND status = 'todo'", + (task_id,), + ) + _append_event(conn, task_id, "ready", None) + promoted += 1 + return promoted + + +# --------------------------------------------------------------------------- +# Claim / complete / block +# --------------------------------------------------------------------------- + +def claim_task( + conn: sqlite3.Connection, + task_id: str, + *, + ttl_seconds: int = DEFAULT_CLAIM_TTL_SECONDS, + claimer: Optional[str] = None, +) -> Optional[Task]: + """Atomically transition ``ready -> running``. + + Returns the claimed ``Task`` on success, ``None`` if the task was + already claimed (or is not in ``ready`` status). + """ + now = int(time.time()) + lock = claimer or _claimer_id() + expires = now + int(ttl_seconds) + with write_txn(conn): + cur = conn.execute( + """ + UPDATE tasks + SET status = 'running', + claim_lock = ?, + claim_expires = ?, + started_at = COALESCE(started_at, ?) + WHERE id = ? + AND status = 'ready' + AND claim_lock IS NULL + """, + (lock, expires, now, task_id), + ) + if cur.rowcount != 1: + return None + _append_event(conn, task_id, "claimed", {"lock": lock, "expires": expires}) + return get_task(conn, task_id) + + +def heartbeat_claim( + conn: sqlite3.Connection, + task_id: str, + *, + ttl_seconds: int = DEFAULT_CLAIM_TTL_SECONDS, + claimer: Optional[str] = None, +) -> bool: + """Extend a running claim. Returns True if we still own it. + + Workers that know they'll exceed 15 minutes should call this every + few minutes to keep ownership. + """ + expires = int(time.time()) + int(ttl_seconds) + lock = claimer or _claimer_id() + with write_txn(conn): + cur = conn.execute( + "UPDATE tasks SET claim_expires = ? " + "WHERE id = ? AND status = 'running' AND claim_lock = ?", + (expires, task_id, lock), + ) + return cur.rowcount == 1 + + +def release_stale_claims(conn: sqlite3.Connection) -> int: + """Reset any ``running`` task whose claim has expired. + + Returns the number of stale claims reclaimed. Safe to call often. + """ + now = int(time.time()) + reclaimed = 0 + with write_txn(conn): + stale = conn.execute( + "SELECT id, claim_lock FROM tasks " + "WHERE status = 'running' AND claim_expires IS NOT NULL AND claim_expires < ?", + (now,), + ).fetchall() + for row in stale: + conn.execute( + "UPDATE tasks SET status = 'ready', claim_lock = NULL, " + "claim_expires = NULL " + "WHERE id = ? AND status = 'running'", + (row["id"],), + ) + _append_event( + conn, row["id"], "reclaimed", + {"stale_lock": row["claim_lock"]}, + ) + reclaimed += 1 + return reclaimed + + +def complete_task( + conn: sqlite3.Connection, + task_id: str, + *, + result: Optional[str] = None, +) -> bool: + """Transition ``running|ready -> done`` and record ``result``. + + Accepts a task that's merely ``ready`` too, so a manual CLI + completion (``hermes kanban complete ``) works without requiring + a claim/start/complete sequence. + """ + now = int(time.time()) + with write_txn(conn): + cur = conn.execute( + """ + UPDATE tasks + SET status = 'done', + result = ?, + completed_at = ?, + claim_lock = NULL, + claim_expires= NULL + WHERE id = ? + AND status IN ('running', 'ready', 'blocked') + """, + (result, now, task_id), + ) + if cur.rowcount != 1: + return False + _append_event( + conn, task_id, "completed", + {"result_len": len(result) if result else 0}, + ) + # Recompute ready status for dependents (separate txn so children see done). + recompute_ready(conn) + return True + + +def block_task( + conn: sqlite3.Connection, + task_id: str, + *, + reason: Optional[str] = None, +) -> bool: + """Transition ``running -> blocked``.""" + with write_txn(conn): + cur = conn.execute( + """ + UPDATE tasks + SET status = 'blocked', + claim_lock = NULL, + claim_expires= NULL + WHERE id = ? + AND status IN ('running', 'ready') + """, + (task_id,), + ) + if cur.rowcount != 1: + return False + _append_event(conn, task_id, "blocked", {"reason": reason}) + return True + + +def unblock_task(conn: sqlite3.Connection, task_id: str) -> bool: + """Transition ``blocked -> ready``.""" + with write_txn(conn): + cur = conn.execute( + "UPDATE tasks SET status = 'ready' WHERE id = ? AND status = 'blocked'", + (task_id,), + ) + if cur.rowcount != 1: + return False + _append_event(conn, task_id, "unblocked", None) + return True + + +def archive_task(conn: sqlite3.Connection, task_id: str) -> bool: + with write_txn(conn): + cur = conn.execute( + "UPDATE tasks SET status = 'archived' WHERE id = ? AND status != 'archived'", + (task_id,), + ) + if cur.rowcount != 1: + return False + _append_event(conn, task_id, "archived", None) + return True + + +# --------------------------------------------------------------------------- +# Workspace resolution +# --------------------------------------------------------------------------- + +def resolve_workspace(task: Task) -> Path: + """Resolve (and create if needed) the workspace for a task. + + - ``scratch``: a fresh dir under ``$HERMES_HOME/kanban/workspaces//``. + - ``dir:``: the path stored in ``workspace_path``. Created if missing. + - ``worktree``: a git worktree at ``workspace_path``. Not created + automatically in v1 -- the kanban-worker skill documents + ``git worktree add`` as a worker-side step. Returns the intended path. + + Persist the resolved path back to the task row via ``set_workspace_path`` + so subsequent runs reuse the same directory. + """ + kind = task.workspace_kind or "scratch" + if kind == "scratch": + if task.workspace_path: + p = Path(task.workspace_path).expanduser() + else: + p = workspaces_root() / task.id + p.mkdir(parents=True, exist_ok=True) + return p + if kind == "dir": + if not task.workspace_path: + raise ValueError( + f"task {task.id} has workspace_kind=dir but no workspace_path" + ) + p = Path(task.workspace_path).expanduser() + p.mkdir(parents=True, exist_ok=True) + return p + if kind == "worktree": + if not task.workspace_path: + # Default: .worktrees// under CWD. Worker skill creates it. + return Path.cwd() / ".worktrees" / task.id + return Path(task.workspace_path).expanduser() + raise ValueError(f"unknown workspace_kind: {kind}") + + +def set_workspace_path( + conn: sqlite3.Connection, task_id: str, path: Path | str +) -> None: + with write_txn(conn): + conn.execute( + "UPDATE tasks SET workspace_path = ? WHERE id = ?", + (str(path), task_id), + ) + + +# --------------------------------------------------------------------------- +# Dispatcher (one-shot pass) +# --------------------------------------------------------------------------- + +@dataclass +class DispatchResult: + """Outcome of a single ``dispatch`` pass.""" + + reclaimed: int = 0 + promoted: int = 0 + spawned: list[tuple[str, str, str]] = field(default_factory=list) + """List of ``(task_id, assignee, workspace_path)`` triples.""" + skipped_unassigned: list[str] = field(default_factory=list) + + +def dispatch_once( + conn: sqlite3.Connection, + *, + spawn_fn=None, + ttl_seconds: int = DEFAULT_CLAIM_TTL_SECONDS, + dry_run: bool = False, + max_spawn: Optional[int] = None, +) -> DispatchResult: + """Run one dispatcher tick. + + Steps: + 1. Reclaim stale running tasks. + 2. Promote todo -> ready where all parents are done. + 3. For each ready task with an assignee, atomically claim and call + ``spawn_fn(task, workspace_path)``. + + ``spawn_fn`` defaults to ``_default_spawn`` which invokes + ``hermes -p chat -q "..."`` in the background. Tests pass + a stub. + """ + result = DispatchResult() + result.reclaimed = release_stale_claims(conn) + result.promoted = recompute_ready(conn) + + ready_rows = conn.execute( + "SELECT id, assignee FROM tasks " + "WHERE status = 'ready' AND claim_lock IS NULL " + "ORDER BY priority DESC, created_at ASC" + ).fetchall() + spawned = 0 + for row in ready_rows: + if max_spawn is not None and spawned >= max_spawn: + break + if not row["assignee"]: + result.skipped_unassigned.append(row["id"]) + continue + if dry_run: + result.spawned.append((row["id"], row["assignee"], "")) + continue + claimed = claim_task(conn, row["id"], ttl_seconds=ttl_seconds) + if claimed is None: + continue + workspace = resolve_workspace(claimed) + # Persist the resolved workspace path so the worker can cd there. + set_workspace_path(conn, claimed.id, str(workspace)) + if spawn_fn is None: + spawn_fn = _default_spawn + try: + spawn_fn(claimed, str(workspace)) + result.spawned.append((claimed.id, claimed.assignee or "", str(workspace))) + spawned += 1 + except Exception as exc: + # Spawn failed: release the claim so the next tick can retry. + with write_txn(conn): + conn.execute( + "UPDATE tasks SET status = 'ready', claim_lock = NULL, " + "claim_expires = NULL WHERE id = ? AND status = 'running'", + (claimed.id,), + ) + _append_event( + conn, claimed.id, "spawn_failed", + {"error": str(exc)[:500]}, + ) + return result + + +def _default_spawn(task: Task, workspace: str) -> None: + """Fire-and-forget ``hermes -p chat -q ...`` subprocess. + + We don't wait for the child; its completion is observed by polling + the board ``complete``/``block`` transitions that the worker writes. + """ + import subprocess + if not task.assignee: + raise ValueError(f"task {task.id} has no assignee") + + prompt = f"work kanban task {task.id}" + env = dict(os.environ) + if task.tenant: + env["HERMES_TENANT"] = task.tenant + env["HERMES_KANBAN_TASK"] = task.id + env["HERMES_KANBAN_WORKSPACE"] = workspace + + cmd = [ + "hermes", + "-p", task.assignee, + "chat", + "-q", prompt, + ] + # Use Popen with DEVNULL stdin so the child doesn't inherit our tty. + # Redirect output to a per-task log under HERMES_HOME/kanban/logs/. + from hermes_constants import get_hermes_home + log_dir = get_hermes_home() / "kanban" / "logs" + log_dir.mkdir(parents=True, exist_ok=True) + log_path = log_dir / f"{task.id}.log" + + # Use 'a' so a re-run on unblock appends rather than overwrites. + log_f = open(log_path, "ab") + try: + subprocess.Popen( # noqa: S603 -- argv is a fixed list built above + cmd, + cwd=workspace if os.path.isdir(workspace) else None, + stdin=subprocess.DEVNULL, + stdout=log_f, + stderr=subprocess.STDOUT, + env=env, + start_new_session=True, + ) + except FileNotFoundError: + log_f.close() + raise RuntimeError( + "`hermes` executable not found on PATH. " + "Install Hermes Agent or activate its venv before running the kanban dispatcher." + ) + # NOTE: we intentionally do NOT close log_f here — we want Popen's + # child process to keep writing after this function returns. The + # handle is kept alive by the child's inheritance. The parent's + # reference goes out of scope and is GC'd, but the OS-level FD stays + # open in the child until the child exits. + + +# --------------------------------------------------------------------------- +# Worker context builder (what a spawned worker sees) +# --------------------------------------------------------------------------- + +def build_worker_context(conn: sqlite3.Connection, task_id: str) -> str: + """Return the full text a worker should read to understand its task. + + Order (per design spec §8): + 1. Task title (mandatory). + 2. Task body (optional opening post). + 3. Every comment on the task, chronologically, with authors. + 4. Completion results of every done parent task. + """ + task = get_task(conn, task_id) + if not task: + raise ValueError(f"unknown task {task_id}") + + lines: list[str] = [] + lines.append(f"# Kanban task {task.id}: {task.title}") + lines.append("") + lines.append(f"Assignee: {task.assignee or '(unassigned)'}") + lines.append(f"Status: {task.status}") + if task.tenant: + lines.append(f"Tenant: {task.tenant}") + lines.append(f"Workspace: {task.workspace_kind} @ {task.workspace_path or '(unresolved)'}") + lines.append("") + + if task.body and task.body.strip(): + lines.append("## Body") + lines.append(task.body.strip()) + lines.append("") + + parents = parent_results(conn, task_id) + if parents: + lines.append("## Parent task results") + for pid, result in parents: + lines.append(f"### {pid}") + lines.append((result or "(no result recorded)").strip()) + lines.append("") + + comments = list_comments(conn, task_id) + if comments: + lines.append("## Comment thread") + for c in comments: + ts = time.strftime("%Y-%m-%d %H:%M", time.localtime(c.created_at)) + lines.append(f"**{c.author}** ({ts}):") + lines.append(c.body.strip()) + lines.append("") + + return "\n".join(lines).rstrip() + "\n" diff --git a/hermes_cli/main.py b/hermes_cli/main.py index a53b8d2c5e..19623434d9 100644 --- a/hermes_cli/main.py +++ b/hermes_cli/main.py @@ -4780,6 +4780,13 @@ def cmd_webhook(args): webhook_command(args) +def cmd_kanban(args): + """Multi-profile collaboration board.""" + from hermes_cli.kanban import kanban_command + + return kanban_command(args) + + def cmd_hooks(args): """Shell-hook inspection and management.""" from hermes_cli.hooks import hooks_command @@ -8116,6 +8123,13 @@ For more help on a command: webhook_parser.set_defaults(func=cmd_webhook) + # ========================================================================= + # kanban command — multi-profile collaboration board + # ========================================================================= + from hermes_cli.kanban import build_parser as _build_kanban_parser + kanban_parser = _build_kanban_parser(subparsers) + kanban_parser.set_defaults(func=cmd_kanban) + # ========================================================================= # hooks command — shell-hook inspection and management # ========================================================================= diff --git a/skills/devops/kanban-orchestrator/SKILL.md b/skills/devops/kanban-orchestrator/SKILL.md new file mode 100644 index 0000000000..1b706b9fca --- /dev/null +++ b/skills/devops/kanban-orchestrator/SKILL.md @@ -0,0 +1,140 @@ +--- +name: kanban-orchestrator +description: Decompose user goals into Kanban tasks and delegate them to specialist profiles. Load this skill in an orchestrator profile whose job is routing, NOT execution. Triggers when the user's goal spans multiple profiles, needs parallel work, or should be durable/auditable. +version: 1.0.0 +metadata: + hermes: + tags: [kanban, multi-agent, orchestration, routing] + related_skills: [kanban-worker] +--- + +# Kanban Orchestrator + +**You are a dispatcher, not a worker.** + +Load this skill in an orchestrator profile. An orchestrator's job is to route: read the user's goal, decompose it into well-scoped tasks, assign each to the right specialist profile, link dependencies, and step back. It does NOT do research, writing, coding, or any implementation work itself. + +## When to use the board (vs. just doing the work) + +Create Kanban tasks when any of these are true: + +1. **Multiple specialists are needed.** Research + analysis + writing is three profiles. +2. **The work should survive a crash or restart.** Long-running, recurring, or important. +3. **The user might want to interject.** Human-in-the-loop at any step. +4. **Multiple subtasks can run in parallel.** Fan-out for speed. +5. **Review / iteration is expected.** A reviewer profile loops on drafter output. +6. **The audit trail matters.** Board rows persist in SQLite forever. + +If *none* of those apply — it's a small one-shot reasoning task — use `delegate_task` instead or answer directly. + +## The anti-temptation rules + +These are the rules you MUST NOT break: + +- **Do not execute the work yourself.** Your tools literally don't include terminal/file/code/web for implementation. If you find yourself "just fixing this quickly" — stop. +- **For any concrete task, create a Kanban task and assign it to a specialist.** Every single time. +- **If no specialist fits, ask the user which profile to create.** Do not default to doing it yourself under "close enough." +- **Your job is to decompose, route, and summarize — nothing else.** + +## The standard specialist roster (convention) + +Unless the user's setup has customized profiles, assume these exist. Adjust to whatever profiles the user actually has — ask if unsure. + +| Profile | Does | +|---|---| +| `researcher` | Reads sources, gathers facts, writes findings. Scratch workspace. | +| `analyst` | Synthesizes, ranks, de-dupes. Consumes multiple `researcher` outputs. | +| `writer` | Drafts prose in the user's voice. | +| `reviewer` | Reads output, leaves line-comments, gates approval. | +| `backend-eng` | Writes server-side code. Worktree workspace. | +| `frontend-eng` | Writes client-side code. Worktree workspace. | +| `ops` | Runs scripts, manages services, handles deployments. | + +## Decomposition playbook + +### Step 1 — Understand the goal + +Ask clarifying questions if the goal is ambiguous. Cheap to ask; expensive to spawn the wrong fleet. + +### Step 2 — Sketch the task graph + +Before creating anything, draft the graph out loud (in your response): + +``` +T1 [planner] — meta; this is me + ├── T2 [researcher] — angle A + ├── T3 [researcher] — angle B + ├── T4 [researcher] — angle C + └── T5 [analyst] — synthesize T2,T3,T4 + └── T6 [writer] — brief the user +``` + +### Step 3 — Create tasks, link dependencies + +For each leaf-level task: +```bash +hermes kanban create "angle: cost analysis" \ + --assignee researcher \ + --tenant $HERMES_TENANT +``` + +Repeat per task. Then link them: +```bash +hermes kanban link +``` + +**Do not assign something to yourself.** If the orchestrator shows up as an assignee anywhere, you've made a mistake. + +### Step 4 — Complete your own orchestration task with a summary + +If you were spawned as a task yourself (e.g. `planner` profile was assigned `T1: "investigate foo"`), mark it done with a summary of what you created: + +```bash +hermes kanban complete $HERMES_KANBAN_TASK \ + --result "decomposed into T2-T6: 3 research angles, 1 synthesis, 1 brief" +``` + +### Step 5 — Tell the user what you did + +Reply to the user with: +- The task IDs you created. +- What each is doing. +- Who will work on them. +- Roughly when to expect results (or "I'll message when the last one's done" if the gateway is wired up). + +## Tenant propagation + +If `$HERMES_TENANT` is set, **every task you create must carry the same `--tenant `.** This is how one specialist fleet serves multiple businesses — the tenant flows down the graph, not across. + +## Pattern reference + +The eight collaboration patterns you can instantiate (load the design spec if unsure): + +- **P1 Fan-out** — N siblings, same role, no links between them. +- **P2 Pipeline** — role-specialized chain with linear deps. +- **P3 Voting/quorum** — N siblings + 1 aggregator linked from all N. +- **P4 Journal** — same profile + `--workspace dir:` + recurring cron. +- **P5 Human-in-the-loop** — any worker blocks; user/peer unblocks. +- **P6 @mention** — the user or an agent can write `@profile-name` inline to address a profile; the gateway parses and routes. (UX, not a new primitive.) +- **P7 Thread-scoped workspace** — `/kanban here` pins workspace to current thread dir. +- **P8 Fleet farming** — one profile, N tasks, one workspace per subject (e.g. 50 social accounts). + +## Example run + +User says: *"Analyze whether we should migrate to Postgres. Include a cost analysis and a performance angle."* + +Your decomposition: +1. `hermes kanban create "research: Postgres cost vs current" --assignee researcher` +2. `hermes kanban create "research: Postgres performance vs current" --assignee researcher` +3. `hermes kanban create "synthesize migration recommendation" --assignee analyst` +4. `hermes kanban link ` ; `hermes kanban link ` +5. `hermes kanban create "draft decision memo" --assignee writer --parent ` +6. Report task IDs and expected flow to the user. + +## Pitfalls + +**The "just a quick check" trap.** When the user asks a small question you could probably answer yourself, the temptation is to skip the board. If the question is genuinely one-shot, answer directly. If it's the opening of a workflow ("first, check X; then Y; then Z"), it's board work even if step 1 looks small. + +**Reassignment vs. new task.** If a reviewer blocks with "needs changes," create a NEW task linked from the reviewer's task — don't re-run the same task with a stern look. The new task is assigned to the original implementer profile. + +**Link order matters.** `hermes kanban link ` — parent first. Mixing them up demotes the wrong task to `todo`. diff --git a/skills/devops/kanban-worker/SKILL.md b/skills/devops/kanban-worker/SKILL.md new file mode 100644 index 0000000000..a6e6d54432 --- /dev/null +++ b/skills/devops/kanban-worker/SKILL.md @@ -0,0 +1,120 @@ +--- +name: kanban-worker +description: How a Hermes profile should work a task from the shared Kanban board. Load this skill in any profile that participates in the board (researcher, backend-eng, reviewer, etc.). Triggers on HERMES_KANBAN_TASK env var or a "work kanban task " prompt. +version: 1.0.0 +metadata: + hermes: + tags: [kanban, multi-agent, collaboration, workflow] + related_skills: [kanban-orchestrator] +--- + +# Kanban Worker + +Use this skill when you were spawned to work a task from the shared Hermes Kanban board. Symptoms: + +- Your initial prompt says "work kanban task " — e.g. `work kanban task t_9f2a`. +- Env vars set: `HERMES_KANBAN_TASK`, `HERMES_KANBAN_WORKSPACE`, optionally `HERMES_TENANT`. +- You were started by `hermes kanban dispatch` (cron) or a human ran `hermes -p chat -q "work kanban task "`. + +## Your job + +You are **one run of one specialist profile working one task.** Read the task, do the work inside the workspace, record a result, and exit. Everything else is somebody else's job. + +## Step 1 — Read the full context + +```bash +hermes kanban context $HERMES_KANBAN_TASK +``` + +That command prints: +1. Task title + body. +2. Every comment on the task, in order, with author names. +3. Completion results of every `done` parent task (upstream context). + +**Read all of it.** The comment thread is the inter-agent protocol — past peers, human clarifications, and blocker resolutions all live there. If a reviewer left feedback or the user answered a blocker, it's in the comments. + +## Step 2 — Work inside the workspace + +`cd $HERMES_KANBAN_WORKSPACE` and do the work there. The workspace kind determines what that means: + +| `workspace_kind` | What it is | Your behavior | +|---|---|---| +| `scratch` | Fresh temp dir, yours alone | Read/write freely; it gets GC'd when the task is archived. | +| `dir:` | Shared persistent directory | Treat as a long-lived workspace; other runs will read what you write. | +| `worktree` | Git worktree at the resolved path | You may need to `git worktree add ` if it doesn't exist yet. Commit work here. | + +For `worktree` mode: check if `.git` exists in the workspace path. If not, run: +```bash +git worktree add $HERMES_KANBAN_WORKSPACE +``` +from the main repo's root. Then cd and work normally. + +## Step 3 — If tenancy matters, respect it + +If `$HERMES_TENANT` is set, the task belongs to that tenant namespace. When reading or writing persistent memory, prefix memory entries with the tenant name so context doesn't leak across tenants: + +> Good: memory entry `business-a: Acme is our biggest customer` +> Bad: unprefixed `Acme is our biggest customer` (leaks across tenants) + +## Step 4 — If you hit an ambiguity you can't resolve, BLOCK. Don't guess. + +Any of these should trigger a block: +- User-specific decision you can't infer (IP vs. user-id keys; which tone to use). +- Missing credential or access. +- Source that needs human input (paywalled article, 2FA-gated login). +- Peer profile needs to deliver something first and you can't reach around that. + +```bash +hermes kanban block $HERMES_KANBAN_TASK "need decision: IP vs user_id for rate limit key?" +``` + +`block` also appends your reason as a visible comment. When the user or a peer unblocks and the dispatcher re-spawns you, you'll see the full comment thread including their answer in step 1's context read. + +## Step 5 — Complete with a crisp, machine-readable result + +```bash +hermes kanban complete $HERMES_KANBAN_TASK --result "rate_limiter.py implemented; keys on user_id with IP fallback; tests passing" +``` + +Rules for the `--result` string: +- One to three sentences. It's not a report, it's a handoff note. +- Name concrete artifacts you produced (file paths, URLs, commit SHAs). +- State any caveats a downstream profile needs to know. +- **Do not** include secrets, tokens, or raw PII — results are durable in the board DB forever. + +Downstream tasks (children linked from this task) will see your `--result` verbatim as part of their parent-result context. + +## Step 6 — If follow-up work is obvious, create it. Don't do it. + +You are one task. If you notice something else needs doing, create a linked child task for the right profile instead of scope-creeping: + +```bash +hermes kanban create "add concurrent-request test" \ + --assignee backend-eng \ + --parent $HERMES_KANBAN_TASK +``` + +## Leave comments to talk to peers + +If you want to flag something for a reviewer, a future run, or the user — append a comment: + +```bash +hermes kanban comment $HERMES_KANBAN_TASK "note: skipped the sqlite driver path; needs separate task" +``` + +Comments are the inter-agent protocol. Direct IPC does not exist; the board is the only channel. + +## Do NOT + +- Do not call `delegate_task` as a substitute for creating kanban tasks — `delegate_task` is for short synchronous reasoning subtasks inside your own run, not for cross-agent handoffs. +- Do not modify files outside `$HERMES_KANBAN_WORKSPACE` unless the task body explicitly asks for it. +- Do not assign tasks to yourself during your run (you're already running one; create new tasks for follow-ups only). +- Do not complete a task you didn't actually finish. Block it instead. + +## Pitfalls + +**The task might already be blocked or reassigned when you start.** Between when the dispatcher claimed and when you actually booted up, circumstances can change. Always read the current state at step 1. If `hermes kanban show` reports the task is blocked or reassigned, stop — don't keep running. + +**The workspace may already have artifacts from a previous run.** Especially for `dir:` and `worktree` workspaces, a previous worker may have written files that are incomplete or stale. Read the comment thread — it usually explains why you're running again. + +**Your memory persists but the task result does not carry over automatically.** If you learn something that matters for future runs of this profile in other tasks, write it to your profile memory via the normal mechanism. Comments on the task are for humans and peers; memory is for your future self. diff --git a/tests/hermes_cli/test_kanban_cli.py b/tests/hermes_cli/test_kanban_cli.py new file mode 100644 index 0000000000..f7c84d5df8 --- /dev/null +++ b/tests/hermes_cli/test_kanban_cli.py @@ -0,0 +1,210 @@ +"""Tests for the kanban CLI surface (hermes_cli.kanban).""" + +from __future__ import annotations + +import argparse +import json +import os +from pathlib import Path + +import pytest + +from hermes_cli import kanban as kc +from hermes_cli import kanban_db as kb + + +@pytest.fixture +def kanban_home(tmp_path, monkeypatch): + home = tmp_path / ".hermes" + home.mkdir() + monkeypatch.setenv("HERMES_HOME", str(home)) + monkeypatch.setattr(Path, "home", lambda: tmp_path) + kb.init_db() + return home + + +# --------------------------------------------------------------------------- +# Workspace flag parsing +# --------------------------------------------------------------------------- + +@pytest.mark.parametrize( + "value,expected", + [ + ("scratch", ("scratch", None)), + ("worktree", ("worktree", None)), + ("dir:/tmp/work", ("dir", "/tmp/work")), + ], +) +def test_parse_workspace_flag_valid(value, expected): + assert kc._parse_workspace_flag(value) == expected + + +def test_parse_workspace_flag_expands_user(): + kind, path = kc._parse_workspace_flag("dir:~/vault") + assert kind == "dir" + assert path.endswith("/vault") + assert not path.startswith("~") + + +@pytest.mark.parametrize("bad", ["cloud", "dir:", "", "worktree:/x"]) +def test_parse_workspace_flag_rejects(bad): + if not bad: + # Empty -> defaults; not an error. + assert kc._parse_workspace_flag(bad) == ("scratch", None) + return + with pytest.raises(argparse.ArgumentTypeError): + kc._parse_workspace_flag(bad) + + +# --------------------------------------------------------------------------- +# run_slash smoke tests (end-to-end via the same entry both CLI and gateway use) +# --------------------------------------------------------------------------- + +def test_run_slash_no_args_shows_usage(kanban_home): + out = kc.run_slash("") + assert "kanban" in out.lower() + assert "create" in out.lower() or "subcommand" in out.lower() or "action" in out.lower() + + +def test_run_slash_create_and_list(kanban_home): + out = kc.run_slash("create 'ship feature' --assignee alice") + assert "Created" in out + out = kc.run_slash("list") + assert "ship feature" in out + assert "alice" in out + + +def test_run_slash_create_with_parent_and_cascade(kanban_home): + # Parent then child via --parent + out1 = kc.run_slash("create 'parent' --assignee alice") + # Extract the "t_xxxx" id from "Created t_xxxx (ready, ...)" + import re + m = re.search(r"(t_[a-f0-9]+)", out1) + assert m + p = m.group(1) + out2 = kc.run_slash(f"create 'child' --assignee bob --parent {p}") + assert "todo" in out2 # child starts as todo + + # Complete parent; list should promote child to ready + kc.run_slash(f"complete {p}") + # Explicit filter: child should now be ready (was todo before complete). + ready_list = kc.run_slash("list --status ready") + assert "child" in ready_list + + +def test_run_slash_show_includes_comments(kanban_home): + out = kc.run_slash("create 'x'") + import re + tid = re.search(r"(t_[a-f0-9]+)", out).group(1) + kc.run_slash(f"comment {tid} 'source is paywalled'") + show = kc.run_slash(f"show {tid}") + assert "source is paywalled" in show + + +def test_run_slash_block_unblock_cycle(kanban_home): + out = kc.run_slash("create 'x' --assignee alice") + import re + tid = re.search(r"(t_[a-f0-9]+)", out).group(1) + # Claim first so block() finds it running + kc.run_slash(f"claim {tid}") + assert "Blocked" in kc.run_slash(f"block {tid} 'need decision'") + assert "Unblocked" in kc.run_slash(f"unblock {tid}") + + +def test_run_slash_json_output(kanban_home): + out = kc.run_slash("create 'jsontask' --assignee alice --json") + payload = json.loads(out) + assert payload["title"] == "jsontask" + assert payload["assignee"] == "alice" + assert payload["status"] == "ready" + + +def test_run_slash_dispatch_dry_run_counts(kanban_home): + kc.run_slash("create 'a' --assignee alice") + kc.run_slash("create 'b' --assignee bob") + out = kc.run_slash("dispatch --dry-run") + assert "Spawned:" in out + + +def test_run_slash_context_output_format(kanban_home): + out = kc.run_slash("create 'tech spec' --assignee alice --body 'write an RFC'") + import re + tid = re.search(r"(t_[a-f0-9]+)", out).group(1) + kc.run_slash(f"comment {tid} 'remember to include performance section'") + ctx = kc.run_slash(f"context {tid}") + assert "tech spec" in ctx + assert "write an RFC" in ctx + assert "performance section" in ctx + + +def test_run_slash_tenant_filter(kanban_home): + kc.run_slash("create 'biz-a task' --tenant biz-a --assignee alice") + kc.run_slash("create 'biz-b task' --tenant biz-b --assignee alice") + a = kc.run_slash("list --tenant biz-a") + b = kc.run_slash("list --tenant biz-b") + assert "biz-a task" in a and "biz-b task" not in a + assert "biz-b task" in b and "biz-a task" not in b + + +def test_run_slash_usage_error_returns_message(kanban_home): + # Missing required argument for create + out = kc.run_slash("create") + assert "usage" in out.lower() or "error" in out.lower() + + +def test_run_slash_assign_reassigns(kanban_home): + out = kc.run_slash("create 'x' --assignee alice") + import re + tid = re.search(r"(t_[a-f0-9]+)", out).group(1) + assert "Assigned" in kc.run_slash(f"assign {tid} bob") + show = kc.run_slash(f"show {tid}") + assert "bob" in show + + +def test_run_slash_link_unlink(kanban_home): + a = kc.run_slash("create 'a'") + b = kc.run_slash("create 'b'") + import re + ta = re.search(r"(t_[a-f0-9]+)", a).group(1) + tb = re.search(r"(t_[a-f0-9]+)", b).group(1) + assert "Linked" in kc.run_slash(f"link {ta} {tb}") + # After link, b is todo + show = kc.run_slash(f"show {tb}") + assert "todo" in show + assert "Unlinked" in kc.run_slash(f"unlink {ta} {tb}") + + +# --------------------------------------------------------------------------- +# Integration with the COMMAND_REGISTRY +# --------------------------------------------------------------------------- + +def test_kanban_is_resolvable(): + from hermes_cli.commands import resolve_command + + cmd = resolve_command("kanban") + assert cmd is not None + assert cmd.name == "kanban" + + +def test_kanban_bypasses_active_session_guard(): + from hermes_cli.commands import should_bypass_active_session + + assert should_bypass_active_session("kanban") + + +def test_kanban_in_autocomplete_table(): + from hermes_cli.commands import COMMANDS, SUBCOMMANDS + + assert "/kanban" in COMMANDS + subs = SUBCOMMANDS.get("/kanban") or [] + assert "create" in subs + assert "dispatch" in subs + + +def test_kanban_not_gateway_only(): + # kanban is available in BOTH CLI and gateway surfaces. + from hermes_cli.commands import COMMAND_REGISTRY + + cmd = next(c for c in COMMAND_REGISTRY if c.name == "kanban") + assert not cmd.cli_only + assert not cmd.gateway_only diff --git a/tests/hermes_cli/test_kanban_db.py b/tests/hermes_cli/test_kanban_db.py new file mode 100644 index 0000000000..fcc6396be4 --- /dev/null +++ b/tests/hermes_cli/test_kanban_db.py @@ -0,0 +1,438 @@ +"""Tests for the Kanban DB layer (hermes_cli.kanban_db).""" + +from __future__ import annotations + +import concurrent.futures +import os +import time +from pathlib import Path + +import pytest + +from hermes_cli import kanban_db as kb + + +@pytest.fixture +def kanban_home(tmp_path, monkeypatch): + """Isolated HERMES_HOME with an empty kanban DB.""" + home = tmp_path / ".hermes" + home.mkdir() + monkeypatch.setenv("HERMES_HOME", str(home)) + monkeypatch.setattr(Path, "home", lambda: tmp_path) + kb.init_db() + return home + + +# --------------------------------------------------------------------------- +# Schema / init +# --------------------------------------------------------------------------- + +def test_init_db_is_idempotent(kanban_home): + # Second call should not error or drop data. + with kb.connect() as conn: + kb.create_task(conn, title="persisted") + kb.init_db() + with kb.connect() as conn: + tasks = kb.list_tasks(conn) + assert len(tasks) == 1 + assert tasks[0].title == "persisted" + + +def test_init_creates_expected_tables(kanban_home): + with kb.connect() as conn: + rows = conn.execute( + "SELECT name FROM sqlite_master WHERE type='table' ORDER BY name" + ).fetchall() + names = {r["name"] for r in rows} + assert {"tasks", "task_links", "task_comments", "task_events"} <= names + + +# --------------------------------------------------------------------------- +# Task creation + status inference +# --------------------------------------------------------------------------- + +def test_create_task_no_parents_is_ready(kanban_home): + with kb.connect() as conn: + tid = kb.create_task(conn, title="ship it", assignee="alice") + t = kb.get_task(conn, tid) + assert t is not None + assert t.status == "ready" + assert t.assignee == "alice" + assert t.workspace_kind == "scratch" + + +def test_create_task_with_parent_is_todo_until_parent_done(kanban_home): + with kb.connect() as conn: + p = kb.create_task(conn, title="parent") + c = kb.create_task(conn, title="child", parents=[p]) + assert kb.get_task(conn, c).status == "todo" + kb.complete_task(conn, p, result="ok") + assert kb.get_task(conn, c).status == "ready" + + +def test_create_task_unknown_parent_errors(kanban_home): + with kb.connect() as conn, pytest.raises(ValueError, match="unknown parent"): + kb.create_task(conn, title="orphan", parents=["t_ghost"]) + + +def test_workspace_kind_validation(kanban_home): + with kb.connect() as conn, pytest.raises(ValueError, match="workspace_kind"): + kb.create_task(conn, title="bad ws", workspace_kind="cloud") + + +# --------------------------------------------------------------------------- +# Links + dependency resolution +# --------------------------------------------------------------------------- + +def test_link_demotes_ready_child_to_todo_when_parent_not_done(kanban_home): + with kb.connect() as conn: + a = kb.create_task(conn, title="a") + b = kb.create_task(conn, title="b") + assert kb.get_task(conn, b).status == "ready" + kb.link_tasks(conn, a, b) + assert kb.get_task(conn, b).status == "todo" + + +def test_link_keeps_ready_child_when_parent_already_done(kanban_home): + with kb.connect() as conn: + a = kb.create_task(conn, title="a") + kb.complete_task(conn, a) + b = kb.create_task(conn, title="b") + assert kb.get_task(conn, b).status == "ready" + kb.link_tasks(conn, a, b) + assert kb.get_task(conn, b).status == "ready" + + +def test_link_rejects_self_loop(kanban_home): + with kb.connect() as conn: + a = kb.create_task(conn, title="a") + with pytest.raises(ValueError, match="itself"): + kb.link_tasks(conn, a, a) + + +def test_link_detects_cycle(kanban_home): + with kb.connect() as conn: + a = kb.create_task(conn, title="a") + b = kb.create_task(conn, title="b", parents=[a]) + c = kb.create_task(conn, title="c", parents=[b]) + with pytest.raises(ValueError, match="cycle"): + kb.link_tasks(conn, c, a) + with pytest.raises(ValueError, match="cycle"): + kb.link_tasks(conn, b, a) + + +def test_recompute_ready_cascades_through_chain(kanban_home): + with kb.connect() as conn: + a = kb.create_task(conn, title="a") + b = kb.create_task(conn, title="b", parents=[a]) + c = kb.create_task(conn, title="c", parents=[b]) + assert [kb.get_task(conn, x).status for x in (a, b, c)] == \ + ["ready", "todo", "todo"] + kb.complete_task(conn, a) + assert kb.get_task(conn, b).status == "ready" + kb.complete_task(conn, b) + assert kb.get_task(conn, c).status == "ready" + + +def test_recompute_ready_fan_in_waits_for_all_parents(kanban_home): + with kb.connect() as conn: + a = kb.create_task(conn, title="a") + b = kb.create_task(conn, title="b") + c = kb.create_task(conn, title="c", parents=[a, b]) + kb.complete_task(conn, a) + assert kb.get_task(conn, c).status == "todo" + kb.complete_task(conn, b) + assert kb.get_task(conn, c).status == "ready" + + +# --------------------------------------------------------------------------- +# Atomic claim (CAS) +# --------------------------------------------------------------------------- + +def test_claim_once_wins_second_loses(kanban_home): + with kb.connect() as conn: + t = kb.create_task(conn, title="x", assignee="a") + first = kb.claim_task(conn, t, claimer="host:1") + assert first is not None and first.status == "running" + second = kb.claim_task(conn, t, claimer="host:2") + assert second is None + + +def test_claim_fails_on_non_ready(kanban_home): + with kb.connect() as conn: + t = kb.create_task(conn, title="x") + # Move to todo by introducing an unsatisfied parent. + p = kb.create_task(conn, title="p") + kb.link_tasks(conn, p, t) + assert kb.get_task(conn, t).status == "todo" + assert kb.claim_task(conn, t) is None + + +def test_stale_claim_reclaimed(kanban_home): + with kb.connect() as conn: + t = kb.create_task(conn, title="x", assignee="a") + kb.claim_task(conn, t) + # Rewind claim_expires so it looks stale. + conn.execute( + "UPDATE tasks SET claim_expires = ? WHERE id = ?", + (int(time.time()) - 3600, t), + ) + reclaimed = kb.release_stale_claims(conn) + assert reclaimed == 1 + assert kb.get_task(conn, t).status == "ready" + + +def test_heartbeat_extends_claim(kanban_home): + with kb.connect() as conn: + t = kb.create_task(conn, title="x", assignee="a") + claimer = "host:hb" + kb.claim_task(conn, t, claimer=claimer, ttl_seconds=60) + original = kb.get_task(conn, t).claim_expires + # Rewind then heartbeat. + conn.execute("UPDATE tasks SET claim_expires = ? WHERE id = ?", (0, t)) + ok = kb.heartbeat_claim(conn, t, claimer=claimer, ttl_seconds=3600) + assert ok + new = kb.get_task(conn, t).claim_expires + assert new > int(time.time()) + 3000 + + +def test_concurrent_claims_only_one_wins(kanban_home): + """Fire N threads claiming the same task; exactly one must win.""" + with kb.connect() as conn: + t = kb.create_task(conn, title="race", assignee="a") + + def attempt(i): + with kb.connect() as c: + return kb.claim_task(c, t, claimer=f"host:{i}") + + n_workers = 8 + with concurrent.futures.ThreadPoolExecutor(max_workers=n_workers) as ex: + results = list(ex.map(attempt, range(n_workers))) + winners = [r for r in results if r is not None] + assert len(winners) == 1 + assert winners[0].status == "running" + + +# --------------------------------------------------------------------------- +# Complete / block / unblock / archive / assign +# --------------------------------------------------------------------------- + +def test_complete_records_result(kanban_home): + with kb.connect() as conn: + t = kb.create_task(conn, title="x") + assert kb.complete_task(conn, t, result="done and dusted") + task = kb.get_task(conn, t) + assert task.status == "done" + assert task.result == "done and dusted" + assert task.completed_at is not None + + +def test_block_then_unblock(kanban_home): + with kb.connect() as conn: + t = kb.create_task(conn, title="x", assignee="a") + kb.claim_task(conn, t) + assert kb.block_task(conn, t, reason="need input") + assert kb.get_task(conn, t).status == "blocked" + assert kb.unblock_task(conn, t) + assert kb.get_task(conn, t).status == "ready" + + +def test_assign_refuses_while_running(kanban_home): + with kb.connect() as conn: + t = kb.create_task(conn, title="x", assignee="a") + kb.claim_task(conn, t) + with pytest.raises(RuntimeError, match="currently running"): + kb.assign_task(conn, t, "b") + + +def test_assign_reassigns_when_not_running(kanban_home): + with kb.connect() as conn: + t = kb.create_task(conn, title="x", assignee="a") + assert kb.assign_task(conn, t, "b") + assert kb.get_task(conn, t).assignee == "b" + + +def test_archive_hides_from_default_list(kanban_home): + with kb.connect() as conn: + t = kb.create_task(conn, title="x") + kb.complete_task(conn, t) + assert kb.archive_task(conn, t) + assert len(kb.list_tasks(conn)) == 0 + assert len(kb.list_tasks(conn, include_archived=True)) == 1 + + +# --------------------------------------------------------------------------- +# Comments / events / worker context +# --------------------------------------------------------------------------- + +def test_comments_recorded_in_order(kanban_home): + with kb.connect() as conn: + t = kb.create_task(conn, title="x") + kb.add_comment(conn, t, "user", "first") + kb.add_comment(conn, t, "researcher", "second") + comments = kb.list_comments(conn, t) + assert [c.body for c in comments] == ["first", "second"] + assert [c.author for c in comments] == ["user", "researcher"] + + +def test_empty_comment_rejected(kanban_home): + with kb.connect() as conn: + t = kb.create_task(conn, title="x") + with pytest.raises(ValueError, match="body is required"): + kb.add_comment(conn, t, "user", "") + + +def test_events_capture_lifecycle(kanban_home): + with kb.connect() as conn: + t = kb.create_task(conn, title="x", assignee="a") + kb.claim_task(conn, t) + kb.complete_task(conn, t, result="ok") + events = kb.list_events(conn, t) + kinds = [e.kind for e in events] + assert "created" in kinds + assert "claimed" in kinds + assert "completed" in kinds + + +def test_worker_context_includes_parent_results_and_comments(kanban_home): + with kb.connect() as conn: + p = kb.create_task(conn, title="p") + kb.complete_task(conn, p, result="PARENT_RESULT_MARKER") + c = kb.create_task(conn, title="child", parents=[p]) + kb.add_comment(conn, c, "user", "CLARIFICATION_MARKER") + ctx = kb.build_worker_context(conn, c) + assert "PARENT_RESULT_MARKER" in ctx + assert "CLARIFICATION_MARKER" in ctx + assert c in ctx + assert "child" in ctx + + +# --------------------------------------------------------------------------- +# Dispatcher +# --------------------------------------------------------------------------- + +def test_dispatch_dry_run_does_not_claim(kanban_home): + with kb.connect() as conn: + t1 = kb.create_task(conn, title="a", assignee="alice") + t2 = kb.create_task(conn, title="b", assignee="bob") + res = kb.dispatch_once(conn, dry_run=True) + assert {s[0] for s in res.spawned} == {t1, t2} + with kb.connect() as conn: + # Dry run must NOT mutate status. + assert kb.get_task(conn, t1).status == "ready" + assert kb.get_task(conn, t2).status == "ready" + + +def test_dispatch_skips_unassigned(kanban_home): + with kb.connect() as conn: + t = kb.create_task(conn, title="floater") + res = kb.dispatch_once(conn, dry_run=True) + assert t in res.skipped_unassigned + assert not res.spawned + + +def test_dispatch_promotes_ready_and_spawns(kanban_home): + spawns = [] + + def fake_spawn(task, workspace): + spawns.append((task.id, task.assignee, workspace)) + + with kb.connect() as conn: + p = kb.create_task(conn, title="p", assignee="alice") + c = kb.create_task(conn, title="c", assignee="bob", parents=[p]) + # Finish parent outside dispatch; promotion happens inside. + kb.complete_task(conn, p) + res = kb.dispatch_once(conn, spawn_fn=fake_spawn) + # Spawned c (a was already done when dispatch was called). + assert len(spawns) == 1 + assert spawns[0][0] == c + assert spawns[0][1] == "bob" + # c is now running + with kb.connect() as conn: + assert kb.get_task(conn, c).status == "running" + + +def test_dispatch_spawn_failure_releases_claim(kanban_home): + def boom(task, workspace): + raise RuntimeError("spawn failed") + + with kb.connect() as conn: + t = kb.create_task(conn, title="boom", assignee="alice") + kb.dispatch_once(conn, spawn_fn=boom) + # Must return to ready so the next tick can retry. + assert kb.get_task(conn, t).status == "ready" + assert kb.get_task(conn, t).claim_lock is None + + +def test_dispatch_reclaims_stale_before_spawning(kanban_home): + with kb.connect() as conn: + t = kb.create_task(conn, title="x", assignee="alice") + kb.claim_task(conn, t) + conn.execute( + "UPDATE tasks SET claim_expires = ? WHERE id = ?", + (int(time.time()) - 1, t), + ) + res = kb.dispatch_once(conn, dry_run=True) + assert res.reclaimed == 1 + + +# --------------------------------------------------------------------------- +# Workspace resolution +# --------------------------------------------------------------------------- + +def test_scratch_workspace_created_under_hermes_home(kanban_home): + with kb.connect() as conn: + t = kb.create_task(conn, title="x") + task = kb.get_task(conn, t) + ws = kb.resolve_workspace(task) + assert ws.exists() + assert ws.is_dir() + assert "kanban" in str(ws) + + +def test_dir_workspace_honors_given_path(kanban_home, tmp_path): + target = tmp_path / "my-vault" + with kb.connect() as conn: + t = kb.create_task( + conn, title="biz", workspace_kind="dir", workspace_path=str(target) + ) + task = kb.get_task(conn, t) + ws = kb.resolve_workspace(task) + assert ws == target + assert ws.exists() + + +def test_worktree_workspace_returns_intended_path(kanban_home, tmp_path): + target = str(tmp_path / ".worktrees" / "my-task") + with kb.connect() as conn: + t = kb.create_task( + conn, title="ship", workspace_kind="worktree", workspace_path=target + ) + task = kb.get_task(conn, t) + ws = kb.resolve_workspace(task) + # We do NOT auto-create worktrees; the worker's skill handles that. + assert str(ws) == target + + +# --------------------------------------------------------------------------- +# Tenancy +# --------------------------------------------------------------------------- + +def test_tenant_column_filters_listings(kanban_home): + with kb.connect() as conn: + kb.create_task(conn, title="a1", tenant="biz-a") + kb.create_task(conn, title="b1", tenant="biz-b") + kb.create_task(conn, title="shared") # no tenant + biz_a = kb.list_tasks(conn, tenant="biz-a") + biz_b = kb.list_tasks(conn, tenant="biz-b") + assert [t.title for t in biz_a] == ["a1"] + assert [t.title for t in biz_b] == ["b1"] + + +def test_tenant_propagates_to_events(kanban_home): + with kb.connect() as conn: + t = kb.create_task(conn, title="tenant-task", tenant="biz-a") + events = kb.list_events(conn, t) + # The "created" event should have tenant in its payload. + created = [e for e in events if e.kind == "created"] + assert created and created[0].payload.get("tenant") == "biz-a" diff --git a/website/docs/reference/cli-commands.md b/website/docs/reference/cli-commands.md index 947994844b..f0d28d958e 100644 --- a/website/docs/reference/cli-commands.md +++ b/website/docs/reference/cli-commands.md @@ -45,6 +45,7 @@ hermes [global-options] [subcommand/options] | `hermes login` / `logout` | **Deprecated** — use `hermes auth` instead. | | `hermes status` | Show agent, auth, and platform status. | | `hermes cron` | Inspect and tick the cron scheduler. | +| `hermes kanban` | Multi-profile collaboration board (tasks, links, dispatcher). | | `hermes webhook` | Manage dynamic webhook subscriptions for event-driven activation. | | `hermes doctor` | Diagnose config and dependency issues. | | `hermes dump` | Copy-pasteable setup summary for support/debugging. | @@ -272,6 +273,38 @@ hermes cron | `status` | Check whether the cron scheduler is running. | | `tick` | Run due jobs once and exit. | +## `hermes kanban` + +```bash +hermes kanban [options] +``` + +Multi-profile collaboration board. Tasks live in `~/.hermes/kanban.db` (WAL-mode SQLite); every profile reads and writes the same board. A `cron`-driven dispatcher (`hermes kanban dispatch`) atomically claims ready tasks and spawns the assigned profile as its own process with an isolated workspace. + +| Action | Purpose | +|--------|---------| +| `init` | Create `kanban.db` if missing. Idempotent. | +| `create ""` | Create a new task. Flags: `--body`, `--assignee`, `--parent` (repeatable), `--workspace scratch\|worktree\|dir:<path>`, `--tenant`, `--priority`. | +| `list` / `ls` | List tasks. Filter with `--mine`, `--assignee`, `--status`, `--tenant`, `--archived`, `--json`. | +| `show <id>` | Show a task with comments and events. `--json` for machine output. | +| `assign <id> <profile>` | Assign or reassign. Use `none` to unassign. Refused while task is running. | +| `link <parent> <child>` | Add a dependency. Cycle-detected. | +| `unlink <parent> <child>` | Remove a dependency. | +| `claim <id>` | Atomically claim a ready task. Prints resolved workspace path. | +| `comment <id> "<text>"` | Append a comment. Visible to the next worker that runs the task. | +| `complete <id>` | Mark task done. Flag: `--result "<summary>"` (goes into children's parent-result context). | +| `block <id> "<reason>"` | Mark task blocked. Also appends the reason as a comment. | +| `unblock <id>` | Return a blocked task to ready. | +| `archive <id>` | Hide from default list. `gc` will remove scratch workspaces. | +| `tail <id>` | Follow a task's event stream. | +| `dispatch` | One dispatcher pass. Flags: `--dry-run`, `--max N`, `--json`. | +| `context <id>` | Print the full context a worker would see (title + body + parent results + comments). | +| `gc` | Remove scratch workspaces for archived tasks. | + +All actions are also available as a slash command in the gateway (`/kanban …`), with the same argument surface. + +For the full design — comparison with Cline Kanban / Paperclip / NanoClaw / Gemini Enterprise, eight collaboration patterns, four user stories, concurrency correctness proof — see `docs/hermes-kanban-v1-spec.pdf` in the repository or the [Kanban user guide](/docs/user-guide/features/kanban). + ## `hermes webhook` ```bash diff --git a/website/docs/user-guide/features/kanban.md b/website/docs/user-guide/features/kanban.md new file mode 100644 index 0000000000..068c37275b --- /dev/null +++ b/website/docs/user-guide/features/kanban.md @@ -0,0 +1,167 @@ +--- +sidebar_position: 12 +title: "Kanban (Multi-Agent Board)" +description: "Durable SQLite-backed task board for coordinating multiple Hermes profiles" +--- + +# Kanban — Multi-Agent Profile Collaboration + +Hermes Kanban is a durable task board, shared across all your Hermes profiles, that lets multiple named agents collaborate on work without fragile in-process subagent swarms. Every task is a row in `~/.hermes/kanban.db`; every handoff is a row anyone can read and write; every worker is a full OS process with its own identity. + +This is the shape that covers the workloads `delegate_task` can't: + +- **Research triage** — parallel researchers + analyst + writer, human-in-the-loop. +- **Scheduled ops** — recurring daily briefs that build a journal over weeks. +- **Digital twins** — persistent named assistants (`inbox-triage`, `ops-review`) that accumulate memory over time. +- **Engineering pipelines** — decompose → implement in parallel worktrees → review → iterate → PR. +- **Fleet work** — one specialist managing N subjects (50 social accounts, 12 monitored services). + +For the full design rationale, comparative analysis against Cline Kanban / Paperclip / NanoClaw / Google Gemini Enterprise, and the eight canonical collaboration patterns, see `docs/hermes-kanban-v1-spec.pdf` in the repository. + +## Kanban vs. `delegate_task` + +They look similar; they are not the same primitive. + +| | `delegate_task` | Kanban | +|---|---|---| +| Shape | RPC call (fork → join) | Durable message queue + state machine | +| Parent | Blocks until child returns | Fire-and-forget after `create` | +| Child identity | Anonymous subagent | Named profile with persistent memory | +| Resumability | None — failed = failed | Block → unblock → re-run; crash → reclaim | +| Human in the loop | Not supported | Comment / unblock at any point | +| Agents per task | One call = one subagent | N agents over task's life (retry, review, follow-up) | +| Audit trail | Lost on context compression | Durable rows in SQLite forever | +| Coordination | Hierarchical (caller → callee) | Peer — any profile reads/writes any task | + +**One-sentence distinction:** `delegate_task` is a function call; Kanban is a work queue where every handoff is a row any profile (or human) can see and edit. + +**Use `delegate_task` when** the parent agent needs a short reasoning answer before continuing, no humans involved, result goes back into the parent's context. + +**Use Kanban when** work crosses agent boundaries, needs to survive restarts, might need human input, might be picked up by a different role, or needs to be discoverable after the fact. + +They coexist: a kanban worker may call `delegate_task` internally during its run. + +## Core concepts + +- **Task** — a row with title, optional body, one assignee (a profile name), status (`todo | ready | running | blocked | done | archived`), optional tenant namespace. +- **Link** — `task_links` row recording a parent → child dependency. The dispatcher promotes `todo → ready` when all parents are `done`. +- **Comment** — the inter-agent protocol. Agents and humans append comments; when a worker is (re-)spawned it reads the full comment thread as part of its context. +- **Workspace** — the directory a worker operates in. Three kinds: + - `scratch` (default) — fresh tmp dir under `~/.hermes/kanban/workspaces/<id>/`. + - `dir:<path>` — an existing shared directory (Obsidian vault, mail ops dir, per-account folder). + - `worktree` — a git worktree under `.worktrees/<id>/` for coding tasks. +- **Dispatcher** — `hermes kanban dispatch` runs a one-shot pass: reclaim stale claims, promote ready tasks, atomically claim, spawn assigned profiles. Runs via cron every 60 seconds. +- **Tenant** — optional string namespace. One specialist fleet can serve multiple businesses (`--tenant business-a`) with data isolation by workspace path and memory key prefix. + +## Quick start + +```bash +# 1. Create the board +hermes kanban init + +# 2. Create a task +hermes kanban create "research AI funding landscape" --assignee researcher + +# 3. List what's on the board +hermes kanban list + +# 4. Run a dispatcher pass (dry-run to preview, real to spawn workers) +hermes kanban dispatch --dry-run +hermes kanban dispatch +``` + +To have the board run continuously, schedule the dispatcher: + +```bash +hermes cron add --schedule "*/1 * * * *" \ + --name kanban-dispatch \ + hermes kanban dispatch +``` + +## The worker skill + +Any profile that should be able to work kanban tasks must load the `kanban-worker` skill. It teaches the worker the full lifecycle: + +1. On spawn, read `$HERMES_KANBAN_TASK` env var. +2. Run `hermes kanban context $HERMES_KANBAN_TASK` to read title + body + parent results + full comment thread. +3. `cd $HERMES_KANBAN_WORKSPACE` and do the work there. +4. Complete with `hermes kanban complete <id> --result "<summary>"`, or block with `hermes kanban block <id> "<reason>"` if stuck. + +Load it with: + +```bash +hermes skills install devops/kanban-worker +``` + +## The orchestrator skill + +A **well-behaved orchestrator does not do the work itself.** It decomposes the user's goal into tasks, links them, assigns each to a specialist, and steps back. The `kanban-orchestrator` skill encodes this: anti-temptation rules, a standard specialist roster (`researcher`, `writer`, `analyst`, `backend-eng`, `reviewer`, `ops`), and a decomposition playbook. + +Load it into your orchestrator profile: + +```bash +hermes skills install devops/kanban-orchestrator +``` + +For best results, pair it with a profile whose toolsets are restricted to board operations (`kanban`, `gateway`, `memory`) so the orchestrator literally cannot execute implementation tasks even if it tries. + +## CLI command reference + +``` +hermes kanban init # create kanban.db +hermes kanban create "<title>" [--body ...] [--assignee <profile>] + [--parent <id>]... [--tenant <name>] + [--workspace scratch|worktree|dir:<path>] + [--priority N] [--json] +hermes kanban list [--mine] [--assignee P] [--status S] [--tenant T] [--archived] [--json] +hermes kanban show <id> [--json] +hermes kanban assign <id> <profile> # or 'none' to unassign +hermes kanban link <parent_id> <child_id> +hermes kanban unlink <parent_id> <child_id> +hermes kanban claim <id> [--ttl SECONDS] +hermes kanban comment <id> "<text>" [--author NAME] +hermes kanban complete <id> [--result "..."] +hermes kanban block <id> "<reason>" +hermes kanban unblock <id> +hermes kanban archive <id> +hermes kanban tail <id> # follow event stream +hermes kanban dispatch [--dry-run] [--max N] [--json] +hermes kanban context <id> # what a worker sees +hermes kanban gc # remove scratch dirs of archived tasks +``` + +All commands are also available as a slash command in the gateway (`/kanban list`, `/kanban comment t_abc "need docs"`, etc.). The slash command bypasses the running-agent guard, so you can `/kanban unblock` a stuck worker while the main agent is still chatting. + +## Collaboration patterns + +The board supports these eight patterns without any new primitives: + +| Pattern | Shape | Example | +|---|---|---| +| **P1 Fan-out** | N siblings, same role | "research 5 angles in parallel" | +| **P2 Pipeline** | role chain: scout → editor → writer | daily brief assembly | +| **P3 Voting / quorum** | N siblings + 1 aggregator | 3 researchers → 1 reviewer picks | +| **P4 Long-running journal** | same profile + shared dir + cron | Obsidian vault | +| **P5 Human-in-the-loop** | worker blocks → user comments → unblock | ambiguous decisions | +| **P6 `@mention`** | inline routing from prose | `@reviewer look at this` | +| **P7 Thread-scoped workspace** | `/kanban here` in a thread | per-project gateway threads | +| **P8 Fleet farming** | one profile, N subjects | 50 social accounts | + +For worked examples of each, see `docs/hermes-kanban-v1-spec.pdf`. + +## Multi-tenant usage + +When one specialist fleet serves multiple businesses, tag each task with a tenant: + +```bash +hermes kanban create "monthly report" \ + --assignee researcher \ + --tenant business-a \ + --workspace dir:~/tenants/business-a/data/ +``` + +Workers receive `$HERMES_TENANT` and namespace their memory writes by prefix. The board, the dispatcher, and the profile definitions are all shared; only the data is scoped. + +## Design spec + +The complete design — architecture, concurrency correctness, comparison with other systems, implementation plan, risks, open questions — lives in `docs/hermes-kanban-v1-spec.pdf`. Read that before filing any behavior-change PR. diff --git a/website/sidebars.ts b/website/sidebars.ts index b654291810..0b201baaf2 100644 --- a/website/sidebars.ts +++ b/website/sidebars.ts @@ -60,6 +60,7 @@ const sidebars: SidebarsConfig = { items: [ 'user-guide/features/cron', 'user-guide/features/delegation', + 'user-guide/features/kanban', 'user-guide/features/code-execution', 'user-guide/features/hooks', 'user-guide/features/batch-processing',