From c2a23466cac3c148ecb8a4a30616bcfaf4c39b28 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Thu, 27 Aug 2026 10:39:38 +0200 Subject: [PATCH 01/55] feat(services): add Executor one-click deployment template (#11530) --- public/svgs/executor.png | Bin 0 -> 176782 bytes templates/compose/executor.yaml | 35 +++++++++++++++ templates/service-templates-latest.json | 18 ++++++++ templates/service-templates.json | 18 ++++++++ tests/Unit/ExecutorServiceTemplateTest.php | 49 +++++++++++++++++++++ 5 files changed, 120 insertions(+) create mode 100644 public/svgs/executor.png create mode 100644 templates/compose/executor.yaml create mode 100644 tests/Unit/ExecutorServiceTemplateTest.php diff --git a/public/svgs/executor.png b/public/svgs/executor.png new file mode 100644 index 0000000000000000000000000000000000000000..a7cc57de9f1992625720221a1004d4d023fcc5b4 GIT binary patch literal 176782 zcmeFaXIPWj_C5>*f=F>9qaam5u>&eikfNd}D4^1m7DWY-DpI6putX71Q9+TS!T<@9 zAVUiRQ7JZxVklA)0YyRyEp(Fq4mCi+c|W`#e_v*D=DMC|uf5j2?sc!V_rtkuY^W!= zQfws$2Z!L%Bf2L!I97n4D>zm_!M|Q7S1W>laeAE8JHU}%A<@CXv7Y0o?tT*=&aNiD z|B~$YCv@hNemN^(x1yQ{vgMPL=(~MLnLXiF;(x>5LjOL|uR`+Cd#e%&@J( zc$WOQuMm}DbVhr3{FDFXZi#1jK7um_zMA%pZ=kQ%&umqyl=-ASb%OjWlQ=#`rl&TW z2BeJXQuD}Z*pNZZb%-tm+>BD<|{Bk&z6qWprTG9ejm zE!znlgd!8VAB|SUj2pB#`y`C0WOB4SJ$YC5$g;-i*_mH1Y-NpgOBs~Ltpi3(CK{Wq! zM8nC0@y06aif~@7=MjAlcid6<_KTZsCr(k5Gb5paXNOjV-ZJ-&S6H2U+_U`ns6vy- zrsY%%yn`qGOp~wHs81!C*S@Tq{$oOoHf(DDq;dEUXM}CtJ*d3(MmHB~N4*`CmOl2r zzEv?0Hx@T~lq=aJ2NiBRMjy!KST=-0XGqcHwNXz<^yg$%`$!tyE_-0)edfoKOf-MH z-jfDIAx@*JAm=l^IlNlgt6W;Oca$7ts*oCIqKUXZHg?!6CnXl2VaK)eB zg!=|#^t}o(%K!nd&)4Xn^^u-Hwnv+rP~s^q(v>38dPv)^Z3*%AFA*Ioifehh;wFPy z-;noYmhrvG^R4MR0f|U2eW~5E&sO(8k0e?|$GPPMq|<9W6-7z!F`qP{w$u+45tYZs z6-@0O5anqdhAmI=!_62yNR+(L$YJWo(T|+1yEa6m8NPBk>D}`12>K+prp*3`~n^E zf+9oo*EXWdNM3~UTD8Kl@X>*sGLPIKSCtO>WAY%GOK-@s4gUNV^l>ht?+C&J9q~m< zx|fJbHd*ydK|swtjBZP=hAqQ{b&80WsK|EVNp0iFiivd%b}#4$geT>$Mfp4!hI@sM zXBmo!3R>Y5N$&}t(ebHL#!acXikp+R^&&FMfZc5qcec4IrqER-k3Lv0M6WfAPbs|g zf~Z?`J5bO8UL<%|kFN_=xZ6^ow}QM1MK^9jK0wkIR$q(LHtk{a|*`h z^L+PiBK7wT_A!=|bBnCsNMB{HkkV`!@KQ`evpf7k0;iyZ4urP>pI$EuDKsv4K2}1u zAt=iYwWB_>r(7o_UJW%GNKh~dvW`97ty1rr5du{L?@Bub8ArLANuzA6H2=j}dv@KN zNNo>gZ`^5RHO1E-q+XfhU z4mg(GnHcTd&7Om9?R0xYt{?=Z*;of;%yd#no>Up`ZIBIue*A3cXqPl)4*Z##`{dZ`r=`+@ONvwTD-I>KDxm6Uap z!%>>k&~84qujBo@PDNX4^m(T2gZR^vcAhT3)aZmbjy-QXCJDg2Ub-q4J!VC<&*X8{ zwrog_a?S?I+XMu_#W~XvL~U^%p09vxIQS* zZyj6QA`H`{%rtX+Z9NfuLBauYV~iL&ko1)mr4R!pWXwhW-+}4sN$NGjYuUdeY;~>| zHKCrn!~;dQj&*%U*FWB`Ce(2M&y?fc5}>931ZSd(o@wrG|448~$BI*V-(U{1(`#vk zc(tb^S_D^fx<$bI>qUG)8h*+QtKbL4L?Z;$3VaDpXYocAG~a%5P{Yra>|Bn>`dd_Q z6)|tDq~4aEJ?5BIt6O>V*r0@ieM*q)FqVO?OAMc%r#>LxLPgf}i*v+>va6mJfe1;0 zx0z9jjdkpaFj?gB-BUyc%-Z1v5vh>+JkU(8&n)Zrw^f#^ZVh4gn&@c!akO*_En%#^ z-i01|e8h4lXkr#*=#Xjq7bD8LWiMdv6_)w7#v6HY9m2B>cu0WUSB4T3& zroyHJLDz%Wdl2HyB4Xo*JlZxEcDmnZ6E`>yPrA0BVQ<72UYa(=A}CaH#|R@&5)dDO z4490yEyx@zCl3*Z)=V^)ZDLd95RYKF7d?sO98}QLRf7$Lyr=o<1(;@Y2BnCpJ%bLJ z*_&cgrA{^ZTqqR3vVol`w|NXxq)r$3d%dA_c#Rr)*|+~Z#x+_X2b+pJ=^eQ#^Au;G zUpBIrM#zd9@sm}EW#i!;Vfe3vt(muJwyCs2b&Ocq*wZ&>r}F~Tu`^0o`@)po3j|q| z`@4H=)fhaCI~>(xU4R|a&1$$_#ItG&$KWkaIuN`2KUGmVru0jNEBd09$7rR=8`!XT zBy2<*6_2957`tOlle?w@e_+4UD{M@{OZqZ!jzu?A{)wjVpO*xRxp%6U;ctySBKmAn zLg)b8z;l4y-mW)p3x8LeSTx17z{UKH_-68#`e6l38m*FC%G(zZVax6%W`-nn!mw#& zEal&ZEPTj>*VXi)a6<}a*c?>&V5m?sqAw*FV;-bw`FC$F8M=MgI)71 zf=@)CD$V_ljWsl-PE`@$;ycQ2XQ@V+m&d4NDFR_=K=Xb)ySEr@Rg{|yO7JzM{&MVk zpz+MwD^Nju3OT@@$4LkS)GG5zRL^P2{D;KyYhPJ|NAWbsg)AU)CM(Gjk+ik@ECzuh zV8E|RCm(I}#gN-4&@;!e{d|$-)t{_ifvw`wKv7VEE-DF=HROGfG&$d6gHvw+>EL!l zuq#$usN+BKcgKbULCNhUtWyEMk=x~jrn6UKcLSPVpx^fAdiraLQ(d0wCoQM^tAyHXEI5~~0Q~aOvz#@ zcXhbFBfeNQ>)^+Q2y22KnwVyoo-JSEon!+h>a4aU@c>@|uzhL3{zG`HUH2QiS$Y9_ z00Z>Eu!&J@0L6Q<{zb4mIg$;@SX@EusvDOiP)y@fN_S;IN7u~)E& zx9q1l7x=TZ;@C-&9HG*bf+}^#E_fQ$G>p18ZAFToxrW@R_3KbMmX3I^;%=*T&>LSn zWiQ`#ZT9nfP{I~LOJ61!V&ZI@vVUZ6BvO2zuyVs+7MDPWf6E+`Qg|{f)_PpLjp|`F zQ-&CXGE|FK+eto1P%u?Z&rToou9OdF$=UpJie3(}`!uqtPY9dQnsSpneW%LMbP`*H zKufotbbTeIsUb;nBs}IB*Q)!>l5z3+EAGCn?KFwN&@ylif>58~9LSf-`gJKYYyfgu z(eRPFpO*~&^F@BHp5HLe?e5w?S>})h2k6_z&FKYWC|O!}S7z_Q=^SR105?eMf2k2B z^i*8xDbBSdp|=LC+6;IHw~MlN3%xabMD;__TR^t~Kd5sgxdzB9Sa0d5ESI4Lj)E2zSLwLiVmoJo1AM=@Xv7M&Oka1;c=8{?iMaYGmK=+Jx6%pSV+`up z3t5_AzrvsO^fldFg9BbjM+QFvk6_Whm0f=IW#;BoWblmwO7A;XlwzTW5Jqn{rKHR6 zT4cyaanWS1XO;yoa0be2abv7J5sd$|@~-5GRZmyl2_(1#g-jS|eQ+&HmW-b=0C?2u z1SB85%2eC7sVbFYyI)W%D;tg(f)ZFj-b&y_?Gp7p1W5{v3!ANipz5HMd#U6~dm_Jf zBJNXL57bJLRqk%zfX&3!`sdJVyM}W9ynQ#9`bvs@&><6Pbex%W8L+{O!|PuS8d%hMtV5_F?8zBmtp(8E#HZCvQew zHnCjWpNIoxNXQ|@pOE)O`Lv6QhLewY_>AeWSijKGKhbY?^(~!jyp)y{VYPmfe2cY>rUNHNR}LM z{TgyZdTt*&5Ca0fgkXujWu}KKVntr?r(6wa4bz~Lv6t_8r$VopUub{YiRC{v=ZiFJ zh#xvAHO{Qb;c1Rq`coDg801d3nLI-ECe-abU-bwvpB$hpp%Izrc2lB_b8Pd@i0v#2 z0`>=&C91RB8xm%{-_HBqej6y0^$e|AfoV3@OjLKta=m6Hxiq&B1QF5v02gD;{IQc+ zmBmFj<|H$ttVLUa3?DX&NDar7a-C&4INos^pH2Qw&LZ$YeKxD&FK;F~QrZS+zCp8b zRQnFPNK$2G&!xbZxQ`DS8+=$*CAsa`OkX$ZFrn_3M+zh)P+DU)F{Wk{UJzR}&BL?P z@tMSLRy`Vm2bLR1eMpXHfN`h)ED)zLnSLJ9ZXRUQl=`D^{jjPHl!X^Q^4+yoSH%S8 zsAr0mUHg$#!h~kc_R*RL2=Q|cLLIUojlv*ng&K*v&aoI8@N3fhAE)q+D$R29gT%pAi-|iE@J6hX*!Uqu@qg}Bfg9K5;t1DK_A0J*K$B%C|-GNB{0D7@WS%Au;f$Uc#Y?0^*)A+4|ru0Y6! z=|!`HGoopkeTOr-Q$?VF9=Tx9VZc}k1v zf~a=$_8mVth!=Zy_h)rqnVN0Q*nvN%q9}EC=stP##n5LFv2C$&EEHSxGklJDkX5XG z3$aIjffwLBKnp01pQqXp?nmagdaxK#Zdbs*!X2b06K-r*!`t)Loa@2&7y8&T?L#FK zk?|L458)L0GG@X$o`0!!wz!7qCTt~KK0eV?liSDqZwB5 ztX>k%w1@a4VLApQ|Mbs#-~=V$gsTgj&;lmRT+d7=9X*x#InBsYbxRu)vy<>+6GX2e zyJHi!AQVCh3;du18Fwai)l2?#HQD^CE%rH!vSs0j*wq&lPd*Nc=g5!-!xb&v`2IK_ zBW73RBNWUlQ(W3~gOdt3549{o6%Y}xaDG%(g1j(Yjy6kAGgKjQ5@NRjPcc)C-npU< zx7s^Y{+~H0%>IC1;w}xR`U8W*3ZeE!U3El3BG!XP=*KNG#SP8cZ-K`74RZ9~X!rP&8tir&0Bh z@Rk26mFakBo}((e5xXytB_RI% z+Iah%ntn=6zm)GProhzT5CsHY`(&<(6g|j}53$)%OGHE+9O3?*ew#osv5#4#$^ciu zJH+cw73BNsWCes!b_MKRqAwB0SLfpu6H1?w7BTds4}J86z#c~o{kuasi~eyPB>1` z|K->ta^0pkMbrmNk}`4)7_PVUQ3;!t)@?A+{H)YlLhc}BZT73}dbi|ZgY}BxSN6FN zwI&hNTE13DEw-G|5f7Qhr^gvvd-C;o7w9f_JwB1U6c%1|CZK7t@?p?|+a~ck%K)se zZkESM@2~QY7pEgOm`l%8+a}h16R-DB&cOT1df37miLZO^o*SYO zsC{q|v5MvTLt6W;RAO9=onyNsbNM&VCh#oJr$ypL-SYbUH0|4FnS*GkzY+2VG5GgvlzDmtjwMBhQi?tT{qTA!iUy z%YknFEATn9)Ic0}fqR2_id{!(YX^%HP%Az}#>*Bz(1O|}-)K^q9i`9Z4*Y~zuG

$376?V0`?08GMQL3hP_9ZU_dVD0C`C0g|-K5AwGBbYMQhN!df*3p|;|QUs zjL4S$kZrUlw-@dK95bAQw0_4KnXSTvM|W8lERDezo^Vv0Nk9oJ2x1c%0J4ca8CKoB z)B|#xu$g1DdimR{%`C7ck0 zvSyipYn(`z!I50JO^1fRh~A<)aLf$e=_FDth}KRk%=;%qgEv#Q7?TxpWUl*}f-;`0 zs%V%$euNr8P~)lOU0f64n?O~)wb|5Ot%q146}mvBF%Xmns81YCNy~m!Y+V>S3*6bN zBDYmBe7wkyTH#13hWd22rvV`TFQ;Z2#$oQW&8SjK7Jb;B;L3;T5?0+D@ol&F)%Aa zXc9o5Xx=)wZ;9MS+*mCNSxdAo$p2yAPi&i?v(6|J2U4)0l`&{0Ov0)MmtsK0nsmJ$ zULtLtFVG|5=2m7HM<9M|)f|#yZpf#OiPa8Kl2Nj%lR`xPC0^X_HrSOyk54PS*g`C3 zVFFgH&T|pDu+PBLL^Uyk87vBjSXpnwbV8oT1EKqMC zRp11B>ON+UXGl7UI9pDwLQ=ARneAnh=1J2ijz*Uj%eTn)0 zMYk7|IiurxkE)Cw$?4s{WL>N=Xjg13V=bJYw58lw(r2VU#H;ntAA>y6g!-&?3@($8 zDQ~#&KCWOv8eoxv&nz{ctCRJc`o<3}QURb8hQA7YHHNz#Burm~Ur>mX9N_!bk~9fT zXvs*i61R-SPY3d3n-8aHsabL;LWS14n}^i41uW)sFe`J1h?pgpOY>tri@fQ94;J|V zkWt?=e2iI;2_qHXE$o~bp2VL7s*oB~ICkH$T|dGhck#Uwk|lSk4n72JB;I(M{8lpG zHr;2KUtDFucJLHB@$+W^m5LS!k(_Gc0SJc_DOh@K^S6NFJ7f<0+nqzV)7oLm=;`~_u=Q?RQDNXiCuWGoc!hFs`_ zw3|~kT^i-y>S}y_!7ym*CGazV3?|Qc4mt{W=B`|*XB0IN?u~R$w7q%z6P74a>;Q5| zI<3dFJGxo%_Tq8UX9oOFQJWnbNe%UH=Ycz~N50|@5iSvK6YBPn7VAI@I0O9glHJ}J zw}bel7j2mFiaH~RT_)Zht*0&sN9g&yQCeVp^nc)N20_?7>|y5`b<0|6LCB_cffeJJ zhaZJD^wlj{G?PT|tgbuLbaklpm)B$i;cVZ6Hh0Pv(qCdDR$v~23vNY4~Ij?p@8p=J9*_T7PX{7i zhgTCMWf44U9PYkfd~zPS7F;8_u${k2f$(+Z0{XZ>?8~*IdyVmqouS(th zV%+U0m#@?=Qh;FNq}L4QGmo_j(_6FTm_leh_CjDyi_~w9 zQ6GaeG?qGB%;Evm5F=$G>CV$C8MtWhdrTkh2P)<%gDdReo{h+O@^cMA5cMijjNrbA zaY?(m$|`6yRTTemT0{Np!8w!r@TyyQ7m=?;^Cx$tt>BH%iqq4ij(toc?rp zcpoeCYoPLRVLf-th3u+B78P7GWb32dgi|zi8%Mu-9>Y6fi?9cD!irdusy>B0(7ZgbVq8*nZcBhJ8 zqBD-ZTa;}}{L=k`jT9y! z_JD(ihNyE7%R(2-@em&wY2uC6vI?_r+}WAoZ<8}@$bw*~PNbIltsIpprE)75$xQfj z?rf7Xb8Yj0_pI6sM&X>B??1;(l8V<5oo23SL%2L`Qu(BBk5q47 zx8YKj++hnLrUhOaQY(46S^FLLg1B+3n39m>4TO3Y)0(L`A`ZI1olrieo`mC)9epJW zx_$TquGSB9VU)-hvlQEw-?V$KJ>8!y3a!^Q@1Z3|r(YVO<389v7jc zxH!P@xV!G7iOfm~R5=Uhz;4jf`^YtYH*3zfq2w*L9@NU1ulPK|OSJ4}&E3Bi&N1QT zpi~i01=O&MA~<@hvo82oJ@p6fqO6t{Y(cXF`t@yu0aR#Hqw7fdI`M`@Th2whY9;JPr69x=}O4E1O+BRM1U7X#*OK_p!wwSZ~U*XTRJeN-DX9*J{?~xNoH2fANfKi7!1%P;Dz@uB2d}c+ZxQBh5!~(p?=Z*2 zb$$R6du`C%y7NB34hs4g;*7Eak`8071Qx_j!gy-hsTn?DJ2tg_?kiMcjgB8^30ygr#QY zk6+NBO|HEnm&y>e=Xmcf0WaJ`e8kF=SZ`4kzFlH#zXCIf=)kw~WS2)w1SQMTk55=m zuwYR9d9hpvl?PODDL(AO)@wEkn)RXWie}fe6UH9IjDKuwY&e^dr?F#XV6kRE9C8FO z`b6F~F1fcqk~#a3U`x1km3QdZp-3GVU=H<&w<$hD&A|0u=*ZTgMhcYfREfhkE} z+Ma>>jU5GYEfAxA@tdrZd>r!|_}43%*=zr&Ue;D*Iyt-Bg($pLhcB#e<)Arw;o5E! zYIsBk`d2dpNO3PBW7~KR%KDa%o&Al;-x%z$l+P+w+9eUHb*ky*53RiWDk8_2$`BZ} zi=wfvTKVh7^BvPFY!YL1F(u+?%!Te?p^bIkb|6w0dC0@SR6MeIT4pW()Svx{K9z=aT8EviQ&ruphAn^|Mp zQ7-W@m?a>d>a}TN;1b74&o*e-?a|%Ld1SE{v1>G_fy~dQS79`JZQxo?vgu|MOEZ^^ z6+Fy0FX56rrHvv$}1uqK+B|M*@FP8K1o!YctMm=q@C@(yuys_p)Biiu0HySePB zgUToolYAij>zS{?Fp+7npuhXjhfm|C4dxe3DsC|M`EW_@bn}7&F?8yyMCL1WOw|ON zB6v4)d%SU2zL5}?EX4wfgU|( z0|e1m!d}n>!Dy zG@OW!d=j>krhYWjdqBY; z>x=0|W+E{YIj@;+)-mk@&L#M!2&9f~@T*91zN^gV>fpPkT?C3*>k1|G$N77k^N<1I zKgN*Z4d#|+zJry_H-^F0eRn&LbJWL<@$8dMt`0v+h^SEca94Qu0?@!O@ff1CcE63m zrKZ8XW4$gfB)(}nL~O6cZzAkLw?6httYkhXfWHR!oX5@V!Jbj9_pAc}ACEMXso?V; z4aYysCuN{zi3Q)x4m8%~azq1vz~SqD;rSe>cnD|N>WhsWNmV45h&DY$(md$@E7kxP5r%x;bs zc&%mWa)Kj#pW(m_0s*x%QrelDsoqXqEGx_z!+i{jTsjb)cAZ)p7^u0T(=)fq1{5-% z_D3=}{+uU5JpVl|BlAp9mRYBtc0oLgvM1pJp`cwz8-tHV6ySX3cObsa&5CM^a#yPV z*<3X;DZq3h%}f%#uLPf+XhQ!eeEu@9koiN&NMW@?-wVp&8$IkwnUZ6{&(3N*I5K&^ zlPkJ$1kFExy9~Qws!gV-^tt|={y1!@?^F`OHUDH2J(mwF5)=;1msoI}KHG$76Ywdl z>1JcyY2_j<^zXbYj1Q%lxRvn}z7BLMnrN|zUkkbE{c6$5b@|>@ zxDMoV4gNGC77gerZvj17U1EF^fi^d9%{%wmtF@KtTe;Y4)A9TF8|bnQqWeUR7PO}$ z-dw6F%@_K?=zPgJ+Kdk#zd(edHk;{9mGv0a*jKxg3SR}XuVqOV&&uKv>}+ol~&Nl&22sG zavrLBnc<~H z9!?PVarJ!97w(NaKc8ulYeXaIMz7>mMqT^Zq1`MU5m6z+c~@A6nbxuIxXMg|jJw_K za;~U)p$mPRsP)fTipg|;h`mX&S%bMxT6NMqL4tWe2Dk>(w@*>kV9D|IjN#ZHg8o@J z?_Yo+R`KW0F$BU?xbCEN@|Zy+Xs0b$^->_^6jPz{X;P-$R$2RvYUjV(gQLI&y=IUf zCxN>um?3h&+}A`4@P-Jv1mD5sbI!Bag!hQG>RdmHF#StZ&o9;_0MD+CViZywIJl)N zkGp^0Cg6{Q&inh6aGhDx^Rc_)`A3O$l3(=QifSqrl;GKP1v~G06=x~AC+qFW+WAY> z@OmB>>wvGzEbTzrEqM13hXOj?#`*Nneq#(1*iigkDLv)^le>xEE%OR~Y|kkuYPMZ) zOgIY|#_nyYIRs_%0PJ__e9$Z|0{Kf%A&bk=Uy*B;65I6iLRI*f_RX9-2BK4#{=x-( z6HjRy-N+#(u) zU-O~g1OwSpi5_}7k;O6VsU;gw`vNVrXeyTp-n34V>C;*>eehi_j~u<}yX5cVO>fh= zhdaBaSaJ-y349)X>SA)Zi*@Q(6A>opB6z@U=?htvZ5SR778Egs9lV&Tn+t`X!3#Dj@zJ z@Of3bWx>Z{4D0#9RAqyRpb> zPh9mZ{uY77am;59XraAmwrF3__MvfX1VIAgxC2PqksILNoTvhosej(_3SUERtIy1) zT@x-$&2jYeG z;{hHg25mh*#1W%*r)&P+-;NvLu1*75L7t>aHFL)FpqweMhRs-33KCpgG?c^Ur1gcZ zhiwXu%!fdH2etrr*)x0D^*1@diB1QrmMHRZAkeoFVZht z>P~E3kIOdAAf*R*)5*B(HTmZbm82ix+n6|P6Fn#pdFjxst^>;jMkB> zE*x(5w!vI`zTsHmum^Ftc~ASbp1rH@=}2$77fQziO&7!JJUh#s5h72YN*q ze;ujzCgQh6fF<7%9j?{)g1I-Y=j2n;u&P*z0M?>Mg$KNWYP4 zax(p1DS=1lpFfgtl24$3UQQ=&rFD`ovRXYDAtw4^JLj?6NIf&he{0_|t^QpL@fOzC zkIa1u4H=8O%02Gt`EU=O10tZf=pV+KkeoW91n|i@*NoxdEsu_pg2$sK=>;uC=`Krm z&9EgU717A;me$R&Z4aeehq2+Q)pd3Xe<-1w>lRxpOMdUHNw>+#_8>poy=YO!|Lnpb zKEm9O?X)8^xe z3~%4fT&;7d9UtH}7i{AgZm3@IX;?;i0?idlHSIR@vQqD3Y5Si-;I-aPq}mIW%rYU9 zx%H1EnDDh-pxY*lV0tm5AuP-WJ|Ft1l7sCYo=h%<-E50cB7I7;_!Idx<6<5 zNZ3ymavF+rUR;m3X+(O6{9`gj#b zzds;?m#Y3^7$bYe<%%7P_oTc)bi?{C9OroS)W}w`9F8=C)1({b2q+Z z|CkBC!1D&A56EZ$z7duI13?_jM`#}^wv;*N@V;DPTxZU0I$TKxq(8`L2V){7WNe$) zb`3e}5ti8Lif2F{hZH@DTX#`-a!u9GU(H5Ur82?p z{bo0~?i;dfR!n*;sXtuT7O6FAj?l zARB0=)bbQitgBu>Si|BiI*$aqkjTr*oJwu}Z&q!Z3;mc9!fHZ$myG(FWnBMB^uuuu z+X&>rv8y-hRp&#$+98_zN*_HDX>r!r_R0Q$M8!VpvnMqpM=W$D>J&4-X(5>+ z7{AHQN_U6xGNiNZGARz}W27t4o%!So!ABpF+-*{hnY|r5SQTL$GljOd%BcMmf!v zDe>1Zz@Mw%XWJU`dlid?K`N!hBAj7;ZAek8`=c(mHq3e6F&2-2^+^v0G+l<<<|7K^ z?PGgbl7`|v!L)qW8+FN-xl%k|;olm}=p$nU_szq_<1#H$B|#-YtQUtT)IiO2i~H6@ z4|}bcvpeB2Ut0_P5UfumWbDi;vZqgHFB@$o52==Ifn`10H6=M5!%+VFE?W6ytnV;VXzDb1&F$J0kwzhNsDFU zvAQO_CakXqsg|%dvt8)q98WylfsmCwcfF-3+=h*-gAoBrZr-|9qOgMoD$+fz`m;I~ zp})Boi_BG#>2E%s@9j25>}SU^qCSccZ{6b1o`%(M<0Sj9lF#PyWXn-5USf`Jb+W7s zrG5||qDD8=VhtDIf4|+>tuj){d;dsf?%wc4+&-E9-N*gJ{u|ZITdaep zxMnJRq2Ny=xj&E#{!}9@5j|^zU>s04Md~uN7bBQa1nVjx3QrIb_!5e=6Z3azEQ_40 z5|0elQ%VN^LDtpqLvR5d6NC0wSFl45K@}@26Sxkx3f-87gFKjfhamXdvak%ZK3hEn z77RC~vUC*08B`U9JSgT9-l)g4{*m=Xqx3qYMcrqJdTc&{(&!l;YsWg0b>@%;*_IHP zJABi{8p-Rk+h6Ta#T|YJnYt|g#_I6#GA%7g(QgR@zqB6DJ-fw|>snqC<&dsT;3eC9 zrOCagSrw_NfPkhzL#AaN?7n$2)nE>PM-rk|fB3v3Kt`tjwZXWC@c{8-INK29Lu(Ef zr^0sSM*YqY5TBzv<4y)+#7r?p`6{;PfxzLXb)Q*uKJn#Mm`fnv4Tv{s-wb41ydjDS zoh~9N+8B>$HU^}mGuj#lg)e^NYv;3figa3K&qXeqL!2rg_~~~*?mx?5CY@V+&;Ekt z2=)dW=D2v~d&XL}KW4o;?lOY`eivdOeroh??fGhzrBC_^+hw{ed_vacju%GN+DOBA zzdP16zn#zF$zvoEa^#|J+pmYXhJcRB&v#ib4-x<)=oE@@4Fo0Ijrv| z^26sXR4PaLaMUh#7{=4YEJR>sdc_GpzK}HLWl~ibcmI{6BD%UZT9<-&t!NtcY#}rl zh4>eU9o64&Cr`{rKZfyq&UV`6K(_p|o;|KsfVJ4lH1Ir*z^vZH420yGvqo=fDcBcwWHbUM(QQEZ)<2<^Fz z%sE_q@5~pn#*w*AV57K&ZX?BI&gmWH^;CBi&mX86bq{1Mm=lTwCbr5{5V)~Xj={v) zB5`$g4mPiu|9`!q4&ZXSvQVV7XLz+Mi%U5tmV%TkM{8HXt7R zgl`%y5b!>&D`A}XB#?LG91Q?)=uWJcxzcWDE12SMThC4}2`JrR$ew*`xaLAD7P^gT%fUSu@eVI7+mZ(;d*vaHvRRF< z6Ts+Aq{EQiP*3O(Tf!FT+Kt^HV+hpgjr4hS3cC3Zv7wkyq_%ifw^)_(r`4ylZvCoY zZF(>Qq3U*7SE8vmb8^0|&oWx?y+doKOwV!y2~jva0_vq(On|u`=|-=d8=)mU7xozp zaHT7#CN#7L8=80Hy$R~P6`ZV@1K`Dv;`gNI4k(>fnKZ3A<&$+BUKcRFb`pqewsQf{ z9tP~bm-9_iPguvfbDNOWH0@Sl`2@m{^g9gqjVq;GekgP*{$S1?)&?jlVxcvMicg7o z4H0=~g+qcDAdA~JQZVoB%gJ5EDrX4bs<<^qL2xds{#+#pIhntj z_{C4Tj2+OdB1VcGk%Opk-@h#W! z(|u+(x-A6qaE9K&C<9C{6~d5>w^PJTpzJ|An2y*A>%-nmT{*IT)^Zbdgq`e*gMGFG z5H?W)@-*NaTu;|uOGYT|YS!Dgv*Th#5~G)E75p=HUMKlrwztOlUt5h>TfQX|0fs<; zoZq&fIp|-OYH`bO8shgAC>O zLGsoG(Z5IURtU4(fzBF%9k-G1q5mBq&CO8~uJApB!7P_8D2i1SXrVBS*F3$S6g*2# zqW8GN!;!zBS3%mM57?vZs?M^jXM>IS0$86b%pD(W!Z(pLYq*IVqVdFt_%cl-2sHFN zL)S{noO8Rd?JptS*_I;k_M%jtkm0%{D2;D1M-4W7`)81qEv6>|pdX{D&nKAqypb?Z>^mSyX%z{5}Yc-a$+)zu!6)>WOm|FB-4ednJ77ZW+mvpe^8pL`Hg*kBv*u;_JIQ zLgY{}WtjmJcyh}tKnAqtn#E(`q8*GTA$s5lXHOXvb?Sj}!4^j6ebg;`)Z zM&r-I+?N}w0rx*r>@7o%l!?`7NW7lLMZyqYn-Jbeuh=UDr!PRhN>m9Pe&x|7!CGqT z1c?Hv9+4ifMwerHyNIWo++1`g_Ad{sPwPa5Vb|8c=faz^pG!}-SRaD>1o-Qv$9LlM zgX|dF!5?ysN?ZkYD_A$T+ilPASma3RG9yIBZdH2ok!qNCRH0jP(}FG~fQwfb1XsqJ z)=~A4O=V`Flb})s1hXlV!Emn1+enQy%L!mbV{yneQ_>rC?3^eu*@8GIdk(>A?F_w& z^FlXebxx=ku`Ur<474AGzvfALqtEpGdIUtaMSpp&a=f%2BlOIiZ)moAMm*T8xKYMt z9c)6P4n{J8_RQrhJ2?G-_HTQ8Eo*+WTim&f?jWhl90`GL;rkDKIC8{FS74`m z`Fp*YbO+c6BvT)pUIS5=%qR5Jc?QPXvR?O3I3i!Rg~~`jg79qmZ8^&|`g0Niib_D! zwUP16{&Q^ECIJUkIaK^{Q<~q%hZ!vXkOPOeMiEHuZOiq1Kt}M2ii*H)eb2trf}iOY zHW`pckQTJyTX`}{k~KaU>}gVq{|3$x&wKtQ zZ9ZL+z&WJUI#|pay6084t%)KYuO$jPBw{%7c~)wo+DwbBb9A-ZJ{gz#TetEI!JZwL z-?Lzw=?z;LEX3gCs=i$_PJ0Aq`Qx|&+Gd&T%N$i-KeFp9f$2?3jMEIXzj6uZ%#1<* z0e(QH#k@rAF)?4Izl zR^tp0w)Uw0QBuE~x;X~hJ;T_?%=kD2OvSXp;TxahCao7U zY`vOsa#UnGQCq&8vjgBHZ&=?y`X(k4Gt)e<>o@W;JslyuIG1uqfNxC2cJ}xd+!2a= zuW!7k4>l9%Btz0JSjK74OKxWO6bRm6214ObF=tXbYNU52BcX(?y@XU+@6 z)EMo^<3Qi&&hKd#lm8tczhUd`t_TECw|Kvx)xo~6Ga4dEf4#z__VGSj)#bJ<5R7=U z27g)K^mO0Z8D9xL)v+0)%fd43IHdlJSM&TS`l`7Mw5bAV5lB5Hhn*#5Gn3zka){)^ z#nONOkCf&RAGx3_aq{WP&{f-}tD6IsTPO@!51CM`O*&m5f4u$s-V5yDStktv4Av_f-l_E+l#bF0rP_8avA)E_~wMWa44~y}Sk!k^yU#sYcXZXH|acy8gwqSuJ{qZ(8~967 zZ^yK|>pZyh4iz6L0d4NA~E`cWSeJ z0pt?gLs!BYvpVAC%$1c1XRgYu!6KK6)m|P#ZR@`gyKjlIfk?tG!HH5cjv&hw{Tfq& zHjd}Md8pW_#8!}l?TP}5#+(dP)*dbkp4N{K`I(ec&O98IPspF{D#`rzP}C+q8$0x%&%MUBTQ; zIcOv%;lzJamtaz^BPaos{0`M3nklaDW@q&W*!$|}ud>yNw_Cq`|0rBNm>T)*?xo1; zFY8WyOIvrUy6Z{d`RSd4nS8XehhyKq*u4Szeg5T@^%HMmcVF@s)A;>ZY3woVQgQkF zQ2Tz@pz)YNv@K0$ayVJb^mgCPQ3%h*86&r(B9vk7y0I&D!cC|ANq&OwfMuj6uDUF| z`HttbJ9QK7W8Dv*fJdvHbvp6g^{KYTPRnl(&6E@j(Plf2qs^6*D~29_&+|QWhWPcV z%GGpz@tW+UuulJv)4Ya=6a7$GJz-T|Sv&Epys|;rIVWkT=2xm`$+z#X{ZI5Av-z&1 zS{}3KrGw}PL9Um2VaJFQrM1;h?Bkx?6j*m|pWU&~vw3tC-%F}6EA6Dbt%Os<;`hTuUa<|h<%FDD*ObT_~xsoQ?z4OqnbDwV#E;anFxY}Oh z+2P$#Gd>&7NjNFJp*Be)JMFlos%K)kxS2?0TcgB1@%}TGkN^Fh#Q*Id%l5y^IaC~7ZC%$ z-!OVMs*0jRRf5u$;^QR`-hYl#TI0IzcaG42<=wpApz(jhUyJ~S?A-*8A~^q<(oF~& zKwEwu-+Jwk9OsT5aUU&J(vQZ}WQkOEcuH;$y%@YEXQ!dT+6p3J#l0NL-d;T9RA8xi zJHhW+`-H~Kg|WdrL=9&j09W*XqZjoisMbwi1WWLTN{xQ7 zt0riV*qo_T+WhKF-i}}I5ULY?X4g*?KaghRHC|`khjPDbzvA9((`lAkuT4xgjEgSp z|D|w=qw2_9?H+uEAQFq#=mcy#7(RWAZ(A(hKt_h*VaKrnGL3rui=_Xm4UbnR8|pi6 zj}j@NzbWd~S+jGZVCBW>NP^wDv@`@L2Q#4B@K`~AkNvTu*9?N6AG{@oe&m#PF}=iU zW{{S&TTvBEfpB7Nq-o{4mQO+qRu0{eBz8Tzch}GN4Coq*s&%Gi-bq3X1ipY@9sY(`mvexiZZ(5MYkD}2{V*?j7QXklsNH_M{j&s|;40AeibLyf zSjgoQl2`6cQ_4r~{)1hu^F1Jdzjx6Uy9%m4!e-y86UL<&@nKiRior|q|g>J656e*Lq?(ic-FV{m$!O&=f{Kr#u& zqQ9XYeLe~9=yhim9la%S1u1hwhG&+nt5l&bw~-;+Y&TsAp59d+clcd!q^(Dlm)c9O zVB9}4wtlM}ZW zjTCkKc^RS7K~#;L-x^f~T=N5WAx01B&rUg#j=+!TPMGUDnU8FB{aKdh(ZlEpe8qFy z9)wo6+!*-wLwS4kV?p$(=FJw*56w)DO&WAuMm|^4059B;3&sRZUcMttl{ZwIHWmOs zz#i_Y+a|Jga#k+NAgX20g}yscz^_+PG{Bg+KWxB@6Mc?mOwey;IbZ55RTksOHq9r! zOlY6J?{jtCmTZVcgIOB4qWinLtKU!PJsF|o-wvw(G=0VlY#ccU*4Q??hSF6o-owRi zhvKh@{6DI`Gpebr>pBp`tAbtx=>meHs5I#ykb4nP5J8k)rAQ}K0jbez0i-CsBVB2N z^ct1kdxs!Z2)#oBdG|@c=ljO+r-O6O-fOQl=Uj8`c*V(*bm9r+Nd1_YNZtn^TV&|{ z^_ATBhpOh&Mp^{F|`9?9dGv_gfK;50D4;rk}n zea{}+7^_6YcpmqPu2b-j4?k!~+czT`!UD6?t-fZfgGng1UG9Y$oq*{gh-J7J93xn3 zo3Hx?-!q0zC_h4V>~3U^4T)W3mY~vT9G)y?DUo_Js5i>MuGom{XZ+fDR5w1dbi!1F zOQfpmu(yeAwZ%5{Mcw{%=v2y|nN2@6)sXsFMY?Y{cX~={Lu59KL@_PyL8RV?HKoKg7bX+@{2k8i*aXAyfS(CbOgQ*E-Js zKPaB6sHT^E*2R;mT-;;C%I=()qX#NXZvF{hZkUn}@w0k6(f!I7Eq@Ld zC-c}(zl&w|#v4EU5l3-!K*9#mQ8*29@yttEvNB<$+HY0y^mxQFt~Lt zxv`dbhG6h23t(z1{TgwB`y|PxL>-MbqsgygV0Y%e@ZdTLT?wEm`O1GM3)?o=_Ey?F zUC^uI9CN`*BE7B1NgO{Z9eU2UXAhMbs%J&&E#SBB3hg9!k{*Icqb^jaeM+r;V*L{- zWoke@5*BL7>(ajkzMH&+yy2OjP)~opNn7#S8L2ZRG)G*S58}1H;AN$=In=}Q$-5)= z2Wg9J^aeDtse~tIf6e#hc^BnBrEYjL>(z=Qy=W(rQih#I&Pv_P@hdU2bgB{qVQXTg zl&5KH=2UA874w3tLx1`^y}O+erqL#Wq^;F_C=t zpyEMTpB3A}xz$#_azA+#5}6+$H*P4)m-EvUpfRkz82) zO}#7QnLImkuOG{6I5)EQ%oioiG+10FGkSA&#-Jw~VAw@@1CJv)2%mmdj- z3^NY0(L~<4<4x0Zr1BzaE(`2d*UZq;%|m}@~8?s!;HV5r2N~NFn)H+W1Jc4$b7Np5F^+QeU;47|8}b_QA#M@x%)n~po}2@ zQv(v@BBQ)+H=#fyct>54#4|bvz|cn?*~GBF>=R|vYsDn({p(5itCQy*uHXlJlxgdO z?{Cbu-n(I^8z-7=s|10xvQvm(8Rf6p=laVa_PJooA+~Qj*8Ax84ufc$^3_Dog8Xi_ zdc|2qx=*C!Wt0?24dvaz0eNlyrt8kNDFQ^B7S5}rrl6|?7=e!PiRnHvM-%kY zj@ZfR$?wb5K4;) zE0~2rIY%I?!(-ce$yr1z>WEV!;EaQGG#S0$gl95|GEx#ht++I&9n$w?{C!G!5mE|Z z?nPhFtd#YdZ{|-Q{Y${Qz8AvB5A6Bq3WfQv7oV}vExSEa?^|h$2EZbq>OUtZgdJ65 z7RB`BzlY5p)GO7JzUt(3P0dd(Z)oo<7GYz?N46?)HJC&K?~e2wA4A#Z8o0CE0|KDfj9~P{@oLf0Oggwi!+14$*6ZdT}L${rUit_><=oMw9im z)Wns_V-jD;OzGAJJPRD3viZFZDXI94a~&#Nc5DfE$8K>3vWrP7M+?g+CyJJ7@o*qn zzFK@AHRky>%JJ1|rl2r=shC9i%AC%iq;pt9&it)$R<&~>@MXkGmym)~z$Vroo1f)= zHE;1z_G*6FH;aWPUEk@KPY;^|W$Fe15o!R>bPB+@FgCTOX&;Br~JmG zu-#&&0gF_WwZOn1^062SW#lth^%%!OQVobaRVmDQIC-g3<=oRy4u1<$qP+bdD)L}T zHr?811MA$g%Hp5y3&rygNKEN_-~5;0>;7apyh@Kfuq`cIdk6s z;VmO0BdY1UaeBfXCkVO!`tYF{PT*aZ^=v(k|q~S6F#N592kvTrY7QF0E-w`Zr8dsu=-2T9o41ZaQHW_ z$%*QllzZbOj2#TgkXO7`lWu7n6&wMs7#4B->d&5;$Qr3C!oi9X;c$ih9%gS_-EwrW z%hJ){iqS%fE+F>F_}|x1`ApKF z43b(d-Q3KO=9Qje>bTe8IV;r7WPV#n8mDcZO2Bszt`*ZX;;2HStQb_6qhy`!3RBKTG9{CaSLw9ez?e&6QYddmzu4LP_>N93-;D@(& zOLbL|L{W~O0Uh4)sVqaglb|#b^Wn@&nYgTZf1$9`eps@D`NH%m`KJPgS?(jj`6hQS zc)XsoMcfUlEGvybR?pW9&AFWW8Y88gshzK*>E8w z$`bGlX?U;l>N(|~$eV`=l?RQDG-7GGcgOW?gEc28oe;lcXc ze96FJxyAY4R%fGRY#kjIoyZLXKL`q*ktG&0qXKonsjcwU^|HM<00+Z@VExH6!%ECUgrV%N_<}-3Ru1WI? z?u;>EgGyv|dml#uukjFbvR6{_u;ohd}0p8vyM2O%C6Xe z=VeBkHe6qgEg!A6zV4`0aN~PPf8zu|!|UtyWk!*hklcT}>IHiOm@6Bh^5tqL~eOP%yfe(c2bRK?^q5Hy$kKqdfZaj8qpQeVmU}^J^Z;jE@7pUvskC%N! zwBMME(7YNgXzLgwWc{M+T8QTT#z4Bd(^vF&;%S=lJqb^nY{K$d)CxqpMV<Sp?Qkle=&E>Zva2 zNN|WzXo;Y!=Dz3dpmtp=fEeLSuls5`T(Ej=E3Zs}QSMLs0&Z^fFObrM9m7+I_Bzz~ zJ>Wu*8j7Vgt&Y5VOpYyt;lW;uCOzl8R}VIO5)B?NswV_6m0gQuAzQDWb65Api!LMR zbnx;1K4T&wnC3Ph!-e@6e3aoIODw5}q~`s$JfCRq&7WC4)qV%Od{5;^_MxBr4t0A&y_;Jt|9S((l;9Kw*WS4obrd)TxSU1`-Q zR(b8T$ zB2wTdZ}=*1R&C`V?++NdF10@c_`qMfV}qr9k9Pqt>SFGp)I}G9X>Y6R*ZXT8YaFnW z2irx!%XqHvGhnvTee5(WEywrLeGJ+-#R{fN+BRb6+?jAYAzC!vSWz4|0~lMGlOQH8Cz z?|utk%iK&tUk<#_O!{xz#uFq~0pK*mLLns=6%0gD*dpc{1YS9!kz%9@sO; z-MEX_zM7clxgs$W_PG0VhRi1mszzm2Agl9j>m&jildpc?Zo9E=fZBS*pO@X{aWYMk z>}i6&kAfx~9aB8g9jD#X?ON>>j(gy@EEMRrvJu@XO(HFwCXnvqpFsB?zJ!Ev4k+H- zsSRfb}6-V?U0* zGZpz*U9~+rau|cugd+?-aO&chU90u?upRh!do)K_>>3Is#Wne%kKa(@Ut-&C5JQo0 zo~Gu;cX-=nxjO&rtxWfbx=`46^jZUZB45??BuIYMX`t zU{>D@WVG;knCx%mdFNYaeboC;e^6LVgkL{Iqxj~1_tziW`))kXRV#2%?qW3x_dTef zuW%acpXpcz+z822+_ZPNQ;lVNlH#GtRBt7dlE_1>$W}HJF~Gj+b4Kn^iuhrfc90^u z$}G#FtQS>E(uN>YG}QfYp7gt#TB(oT8X$-UGI=S*NSG+H)9Cik^~ z4p;tL-hZr2l;h|znzhA+h&!gO8C+x*-wjn*Mu655! z4{hj{maRr$Cfe&t^jh2GX_3EPoN-lAK0PF_*(Dp>lyxr~s}&6tmYdsyhrjwTDl6_C zGr3K6dZ8`{(X&E{dx_3%!9G#x4-!J`;>B(NT>WSPEV#zU!NTe>>HA!WU>36HNLXY2 z-C*WupurU_t1PRK@)J-jO&FutXilymQH?%ViD;-#i9?poE(d!jda8f(`?19Ll!M_P z8Bn59L4S-Wyj(dmm(d@QCNJnp?2bjWvoRQMKS6AJ%-G%pcSbC7G8}9q43`Cq8d$ zej-d^v(TB8%9Etqk)}@#%hF68U5(I8a2vz&U9T(ZV(DbkD|BVx!Gun$TztxAsf4-qs3VzX>()~DLeR{I35o-5ApnizrtAldM zY2MSg8Q#SeY*|ZPAur27YF}1NPr(&s%lg75D5Ircm7c#ppP3Tm$h$qEv-wRq_0?I) z%u;sg{jP=!y7wL=2v=JOSXvr{t)E{mTQkMlDZ_9J{fSwJRhGy(H-JcAD?0_eDH*6* zc3DDQU}dGT z0hMKgBSlxx4;p=@g$!vi_Z|S9Aty5%d3BU9V6c_R@|b|jsH#|TcbD~9eZA1jrcfU+5I zfqPx?O8vPiDesVs+ec=fq_>p0nHr~Bx=6C6E9B`hod5N+_8g9z=hzU0Iw`o?LBKC; z))?;UL8`cwe!i2EFTOvAv-gnUQ*(^I-C?6L2UbeA$A7l2Ze*}*l@LwXbAAB;>b&HO z5Nu<|%_^Z&k`SExqFHrIe>digzd9NBd-lh|JiG?td8M)!+F;fr-H`UW#N+tABzqvX zV+^-5I9l7=2MZ}Fi@xok_u?nkaAkaEoTPSuuojMhGHT{BeE{B_lz1MJXDHOJJV@Va zH;rMPX*>#j52279hnm?2*$2uS<_z-1m7B$rPgWQ*n5BC_pNbBtGv_rp*BX-m(IBk_ z!o;g{qEGv^XrC2{vn#N8B}kLdnae(S=y}Gna3X1PF<-5WptGC$@Q#0 ztcZLr0-Nqrir|Y$gii7JDkU|{!($ugHTCaN`e#JIH5Kl7ll2~aFA_#l=BsTlIgPLCnINO{B-YBj`si`oi#XnX3AZgO&r;|JPU9~KW%fd!h1!;aThVn$!~ z?2J8;?Q(D$(9!s;aR@X1Nu2u~=%4I|tD8d|o|0`bf<+eOzxAq;Eyz`SnFo_K3} zKjds^AXM!-HGa+&JtpA@%;pI_Ta&&AXk1Eu)=Eklp}v zS>k-w9`%v04>pmooX~z0e}PtzT#zhd#;*Xm!IH*LQTe|M;NryKS+>4UJ4uKg?Y*iy z9J9Nx`PjQcbfqLdpmzLAj>bPr?K#-);x?(sgAOILIdyi3C25QoB?^Ao66()yVAIW} zwBJw`OP_yyH4Wq?HK6o|Y4Q&hde4b+?~R-3`dW?EuzfjY1bU~&U?@w!7IdU)z1pGz zkFqYKg&w>OxZTIE2r57mwn=QKSea;+xM#nJ2+ny*CX(JQtOHG}BE=iXB6Xct-_yDo z$1|5!v|+GzPQz_&rTLL*%bWvfW!8<)yGJkbgkDW$sM*CkH}hPLWwajk6P%mKJ7smR}{p2uC%|1;u)hA}e=Td1zx z-37?8XFGrHzwcPW?^GaeTN{D1mBTNpye|47>X*#mg63(S2wCa?ha1 zClTY{)^a#E>0`hqowq39H9VcH^#Y)!<-RSOdq=`d+QM1Ql69l9_7f1gNvG$5>&z zmn>}7y$gssAp`>Xp-%&4nPyp+<|JNhe@l!{AmHcHfY9aBJt$ZLwdU#C_}$fEH)6t8 zWct-7d@_AzpB0TRekgglyX=~)2-0k-wS{cnr}FnMtQihR6dZ0hagJtf*T1ilHHe7C z?$iP`bBC=EewZX8Xl(r7Q3xN_qaisBWF3*2gF>gSn>F_jRZlPys`LG=_bO++@|}J; zjmI&~yPM1IAltv?m*%_mQR}&m70GWXjWcr~U*+36nRj>gYVCX(cYAI#R+>IIY1;H- z&k|}0ny_s!?ns%i9Hnt+z(bFPMoztj)Wnp8I*UKEWQL}9A7mbJWrQ~M?E_1d8{56@ z9@mjWrQEh7-Ji*lOmUWTV#cm~e$rA0_>2L!jheNqH4jv`yCh!p-7x%6A9zvU=1eE( ztaj1$xES_OsRlmt&54!te^XT1*Yx`lmk4aLtLRC;U|@&sZBlAM{A31Ki6m&o7esOq z`(!BK+U94gq{dB%>{#4&Rvbv^7a_+C zMiURq@E`+2a$VDzdbl$nYnAmt_RZ5RW4z6~8wa`% zDx9$8h3-EWlK(CS6##-lp3K4)A=qqGo{%iV7NO(yisxKSICbyZW9g752TK#36b*f=qXlO znl@>-zoROJ-TyesH$zbkGTZrcxBpwyr~bCT8{adLvg)PvUl=@Uu-`04|v1e~BYqyNk~I;+|l}GWIz~pw=K@Tggvt zCwKETVD^}e#iQH0P>xJsKmp0?I^U83jgqKhDAq>^?C;-s3hluDM~YO*;Wbs;VwT&j zpP{Bq7$#^b;78!fkjLxd(bTTt0%73w#4RM`RVxE6F}oQO8d z=2$dF{?6M|xv2Pwk2UyXbSp*4SFspq38k{3kLiVGQ_R$`5#|bxVoNWNeB+c4%AdbgU75l1FhttJU21DvRzPWXU1MRz458De30!M%zZKSaKJo9P!q z7WG8f*OYj@SW+wH-Jnt)UYnT5bU*37yfDaIXrU4VmP*KhmXUZ!XCh-FLs@P)(fe3M zIkE<)58?jLW_!uTQq+MefnFWh^2Aw6Um%`zf4QL4GwsI=YrZ|ZIusa9T8PXd)CkvP z>WhdDqJa|S$h}(nZgBFKKK5phVoKloo1Qb|g8&m-Zhe_eHro5F;>AhLbgNdYTk9i= zjj?pITd6y;#@Q@Cx!$&g;esx?7Il)t3JPE|;P}e`z+{j->Ew3crx&hNS5(~pyh}~M zJM;dm|7I;9a2qCsn&O;1$L2id-5LE=$nuy#gRPY4aDN^n>Hcqi&ANVxm>pRrR=HF1 z&}k_qysmntY}Ms(Z%*t#mMNbpLII2T`a7=fVDH^m!sh*(#!9}Gb$2hW@SBOxj>1A> zdmZ5jZ-a|Ic$2Y{fyWjAU(`A?xR~ecHFJs945)#t8ceaS#w&XrR~y`cT>p4f?G|h% zhB~}8V#K{|^4YiJbqB5}!vY5=@&V@tk1B)!`0!;-_p4=b6_nDhnuH0Q<#3oEG5m8) z%!VtUx-{?nxJ6fwU1tJv@33xcfKwV7x-_SKO0#v_6KK8; zo4I*V>##ueUC0nM z=Js=oyR2EZX@*twx5RCz$=Rn#NV>+y4;)!8#Va=N%CXOHkO}{|4zCb{wML0bfGt_e zO{1)e*mfEH)xnfP3K3Ng_|Bc$mM?~Po&JNuwK)=f1}e0@MLw#rZh~t^3L{vyh6dRf zofw7-9yc-7z}bUNMYYoy*~azzlu|P|HXvAUPX;%EQ=uI)y}yQK{V3+JSW>) zI#?Qo@)oe)pU=n$;Co@~FgDXCw!VE$KPzR?J8&O!;F`B+1#6r$?tlLoRIOi<0(RDm z4zU|kc%nrD^qi__92{I)EP|jbW)OSlcQf8KDiucg9=oiG0|4y%6EztpO4@n0tJ{&< z*KM{8pIRfek>g*>#n}TG+La*t!CC1|)d8IoxgxT1;dADVPVEvIfJY9WH|p8n4%3_+ z91+3p;FhbSojUeh0S6uu5`mQlht0`M>PcvlF!t?K)N2|C(>+B~8R*Un)WQ{e)jO>l z6E7N1MxN54Ej&Wvs?2c0A(H(bWZZ$=?7+ItV=scHhwUv90L2fO$u-<-)(orvm`IC{ zQ@sMub8kCg+4}oK-GKwBZOMPdWA4^qp9jJYhE~6Nz!BpKzg7;H-FEJn-28(RnW5Q| zku1%-PIrhg15(_(Qen<@Y;IUV7ManOe=^O_(=gDzEUyu#PaxH#cNceR+;noRVp1UJ zs+vr}x3gVC=0|qw=p~+Xpuy}#HN-L?t(~XFJ(tXAf(5qzoC?U1_Xz9!NDchJlUm@< zaceulK&K3Izv2t@OiL`V(w{;it;01yR81O@mh`Q>WN@8D*1XalWbGqC-j!yaEK1QQG9QTs*+|jZN{Eg+D%=FH7-^+p+4!F0t za#Jz(WXL~%9sdVaeYm?1R!^%7*6AvrojZ9bcOX=wUI{=k#-w&3i01ent)xV%X?2(k z6R^A+exM~b=e!jsc*hTSLRK=~R{F8hN|25*RR{`SyjLk9q~?KjyaC(%`LW-_n!MDc zWf%hL#(rxUo!Q|7Bj4qd^@ryUHZTAa#{!2_vPFLru4j(hxAHuCJlD3ShR{X^I%q(^ zAWE+GSk|^j%V!d(k8_1SoP~4pKkqLdd)CAyf##_5>nS?rRA5c_?jHZIXK*fs(XiR} zgoI%YD;Q(uzxv)D;xz{~)!#(gqD7>o7aj%Q%2yxrFfF`a3+Em)9a-sM@C#!0z+~0E2$V|z zR0G7cE_~U}Q|${KU0)}#3>00+5_kZdXBVAXyK*c14PCwaztnfc%*8o9goc|6O}p@u z%;V*se|i-%l&B5$!M+yf3_4!Q)0!IoTwgSGTQc})Grlsw3A)(kxK|Kg>3j<*M1-Js zmDB$0xn_SXVoyfVt1QTS-<~~C&S8d8+MM_gKWlGr=mTWe0JFMa86CK9qCEbl20fgZ zackF1Am1dU{tg#7wE2!Hz36_|`;K612P^e@tk9+RA@(K+t{+jUlO`Vv^mb%2%;`u+ z#_O4p(w*D6=dgy=(D)K+nA`qk2?4kG%dFss>G3>-a2#qBCg4<0M-8jm?YDA0V+j&R zI%vqLZFHZg8>wZ6y>C#y7SV#X=C2eW>TotOq5ZkqKv;-e&H(Ubnlhj(<*w+cP;Ze= zu65s@V>JmsUwe(>?=6;`BTmzAK7wZMzKtL9*U5F(z9m0@bf`D|QNZ+LXAVaM@WRS< zOILDa6EXHn7S=rD9MxviZTI26Yo&fo>rCQvaX$B;_97U$phM+sNR4sl;qmaq?{drW>YiG$bHypSfn3V zZwZK?lHHEXzirfD4Ztvm1~m+>k==rOlV{KuN6#A-n_ICw3=Kq-@mYK8??-3H$%a;K z{}@OGDV2U;qu#}qr{?>(Zs5Nzco}&(I-r zw4{556=@tKiQ)XNvl#LRH@EVGBa{V$UlFtaxiydm!~kp9?_aTBqfv#-I#f#8$#6%fcaMc^tGa?lH;Q72;BG zN5Blgp>yyN&Pj(V)s1ytQkEq{5(cKeTl!9uMjpW26QN@~-gm$y;^ZX3ra|dn#e2j5 zrDmsfszvY#AehRjPBg0-fBf3>TvG0&1xvS@&a?8fQe@;$=Otek+oU1RH_m#MnCKdq zwS2r{jky9^KmyLEuecKkPM0nPEZr+e^@vDJysBa|zpxOugNt8@Tk*npw8N<^V2qzV zP<-Hvmo5AbJXj{T@;sK{^$LPz<#nbehOPNEzf#!!a&$%e+2#drbzZny|9140(Hm-w z9Z?u7%Tho#nNiOhmo?zo>0_Ojd~>WZXTCwzJZJE29^gHJptxg1&pFXU=o7ar7r)hh zbYfRwaPTKgJ966ndDRKEmeSikcnhDUvR@w0m);FjZHt^^WS5^Xrbh+p7Bws-99phcy!}&ANcKqq(kL%+74M&IXukI?E(fWXZt>C z_uYHOGa$hCA$Z~x=v=$RLDG#rw6($vgOG)vOb8?W+{f)9&_gvBD)(Wr=u>OM`Ybk|c zy)|S;HmN1s^ZgfHZT$u+_n8}X{es1?xeJ%Y_{*k0?q>Mx+bj;3<@8T%R8_#JDrnKd zF|cK8nD{XJMccQ=BN57AV9}?Q)iUVMMF?L^I4aJdAGd!xoKcVmJCRgC<7T5cpLyqr z%lSw3!&*mh2YoJkITIL7N!*&lA7&6pREAFmK^xFzLvBr)z91kCwD#Ly*Q`+Mfo$TpTrWzHAq2_Ws;m zq^9+v-5{IKfo5XFYM#LlOcaaLQ7AW3c@FBst{V=}!N3Oa+?i0h>^3X&ovYrs^{6@K zE(V=8Y8clm{Vq>?L!05Re7W5)jfgGMzvYokl$6^Xy@dUt9-}o zaBuM}OgrTcQd4(vsEF%u8+rJpP-fk`$_S^|bIg?EsachI%z}%y6`+{AGeJcoE}Pb? zJJ&RvtZ)41LbXN|Sb#15>Od-I`5u&XzQfPq(uFUY5`2#KdRjN`+qH+Iz^ufV!Ab}H zrCjz`UKjld=R8jOe$as<3|)1XmQQ7A=DgFaYQ8O@DN~hKcKml8Z6*@Jx^e9w$D7go zO-7UHNkN|)HXfnY%&pWUF97XC9SHaX7TBAUl2b-g3By-kiNLf{v@*gm=ox13{5x=dFpD&b*otS9du&0j&9}bsZ%J)IaW$S-yj#sg$`!e^M>-GEU$v1 ze;X1+w2NqCZ)lFvoZMas0ud1fa>~`KZ^o!6s9fQV#-Y-;E(K_A|Mfa6ue#aAzwB6= zg6;`fe3e7M3cK(do`;THv%_ z15>6Q|3Dn@!?X?-n?2riF0TJ=F?W$Wq zQ`RUk$a;fP;w!r>bC}PP{MkVz=ai9Wp$Z($1hP;A%rsE#?b+qPHkN?~kpT;sfXWk- z1cCN?(v?`K9_Gen^3{=@ERVe`Vo8x9M?T~kTS|2p4z2gPZ@)&vezf43A3>N&SipWC zjDO3i8GzZRVb!Q5A;+#RW<6q3 zhxbpW89#S#MR^q+l48e5hq7EvkwK$+@+u6J63!4cosVi(&gY~1@841TNA37hY(*pj zx;N39!kU6|!F)pB2j5VX{9IE($+V-q!+%WvMrTLEb`X_w-LKjDVG~+|jTp_y!_md4 zY>Xh!wlQhX5SOS-UCG>Hn-igLe1}lvSK{#+Xv+HgDt{AI9rw`}Mu~xZxL|10l3-f} zMW;a#X9U0NNtiXgb;K7YH>~cV0_$Ln)LqI7V^G`UVp#hrR+AdY-k*K0pxc6i0^Kc# z($~G>Zsu^lg-^WC5q=FrMTB+B`};uOs5vO?1r~E|IiPyEIEoQWl&&UG`lkGp?s~p!v^bhCVz4tj(Au)sJi(eSWLF#ua4>f=!1CIYv2Xgf|tmZv`OXZn@U)S|m!5dDfib2$0wGP+AmLQf%s>J zWiwo!V{8mY8M=KxW89#x%ULmYu!_j2fQ^p8>^pl7$eZtv`B+>E zDla39{@N*jDBv$}hIs80RyrKI3o|ve{^V{&kh`I?McE`uxo$R5jvZ$Mzp)e~cXFqG z@LnDz^c)B9oC=*O^x@cAy;$}4qWevG%B}bJVnW})T_gUTYrZHS6&~rD)30T5*C0%& za-ZiSKf2cDm));p2MJYg7b(7}&cC3V?m)XBYeXSn`suJ;Tu_ECgBvTW>9v6?naXP* zfYj1Sf09K6CT_6dTFFdna->f4QF%(Fg?S0|vqRPBnhS-UeRosceT9Egf=*C3_#QX= z-V&3ud=ZpwopLnubZA;44d?f}wg7pleR<-H@zk55uD)?KfFsw|tYlA5j8poi*GsQ) zyTSw%qPYHG?YGS0(Q3_X0ZYM9OoWM&2P^XgD!R#f{?L72`|hareIc%&?-zFXHpZPJ zm=eIp*y`=@VG~#Z_oua#gK%#;bnPHw)1?He%xmdl?i2{Nwqb53o}*JTjYbFZq@761 z!4CP5o6%0{<*R20w=x2j>I!vp+r+RJ) z`)!vca;I`fdL_uLC1PelZ-Eh5#ZC3zA6-ThE@Us9wz=D^`4_}rlEP@TV$>F#jk8Am zl-K11NmH_9l+R2_(QwlGB;~s01cT2SgUQ&idRHk@bMtvoz2DlWW>K4|Dw-ds~WG^Ab&RKjP>=Vw%bfv4s%OI62_)UH@F)pIjzaX$Mn=@^UQG4 zojq*4Z?_w+Q^VS6+i8zB1dWcSHVtm@_Okrq{rnDu&khNbgm9j;m06xgPjxSo%swET zP@W)rgO0vn%!*0xE@NWii-pJ5u4KQLZ?mSzNf&YZ-eSP1lpu>JeaE-OM@Jd0HS(NK z`U+jGya2ELLqPA%BNQ$DzI-Ca;wADSUS-jHXYZf=qg_!wXdoW2p0&xMSq92k47xi_ zY09t$pEjI<`KI!nonH?lW{1s1z+@M*fB%>P$;sSoX(kV=!3D=++fr@T6kvpjuigr6fz_;rnyy zUrtTz=6}aA!}{}dFGlJ=pO-V99yZ#}rLI-Gc|<9aD8Og79y)(G<5R2;ZJGD2H0J^e z+JY06cNmWAmOuw7{|1GOnj|q&dhfXUTm@|05J!iv?K%{f5Y&t2_61xqs8F=-&6c$= ztaYR4r9?8L(|-=P9+HCNb}gFWvEtB4ivt>HG5@_gVZy!r_Q9h6$@AoY!iNsvI8d~B zpYnc3I8cpxkK`0dy`ehie7Bz>WbBktu3bf9#!eeE?9INEbuePE^eMm=JaL$d19cL) zf#LZiXNoz+USVLL$&d*%3Eoh`d2?I#-*lrH_eJj zvK@tv(J*P%622xFC23Jc+|)jwSh_aV1w@o3KG@Z(%@~-yvFEkBCo57wl?L4cI%b%^ zSwE{u5FWOxAjM_6~gq)JTBLxB;4t1phfio=ljAo~Zi*eGGP zdXq1dP&@8>$%@nYmiHW}h)isz9`OC=z15$>81X7IS|dh$hj zP$Nw#5)#$++n>3~8*5Oy$b%QGHlwr(Z#@(-6d@uo zQ`}I`5c9~&@cCfx&6JGL)h(S9#}iT@qvi0V$-mB~9JYW;)*YjN6z5yc-`Z1YWaKhA zehNg30WTa69G2O*2G0;%Ep3n{mV8i`#YKl1v_Ifu8?dq&ZFQmmICX-!kP?PnGrDH< zM{4g8TU`q47P|3RzAyzW*z5OblgElzul(~ck%ET7;fM{9QKl2=XMmaZnjOGhT2)r^ zHx0eh?zC^xN*HrL3m3MZPm8Rd4aBB^_`XY74kU=AO=_6em@Tw*mA^H;(>|Ik?>}1@ z5Hr4_adbHCL3cGyty#thODz7=eB?vZo7FuJ^yq6o8XO;B7`#Um`bOWP*R_oBI^nN2 zL*2XIWO1Q`CFbVNE``0z7wMlFBCUm?-c?D=m-7FBbu6XLwM(c%yy`3hIJ?-P!DhWJg9qmIih$45_w@8^*_^CbviI!c#(0{s33TC_j)P zit}=v)4JM0h5%bs6Q#BvWcncgqhNiD+fiXeBoLWFhtMOO>tXpip>GhB4Fx zo@PUyDFS0%3SQ(piQ8U$FJ(6Xn;485&cF0<@;Hh!1UmsM4XZevL=EJCOjAe!seT^g zXT^Q-q4!;L*5jIiMzoReE#rA(Dmn~05#L1culJ%B1RR)F0XNladN5Z!RCxvz$zP1J z!|ZYg@kITjbmRGe;Qs_(Q1+}QWYrY;vrW^w9+EywHd<{zz4pNxtx$a@SB`QK=N9ehaZNrg{MMc++ZsSRNU6w^L3}O(~EI%RlkmI!!>fXI4;$(AfE~Fby z=}1IXKHo~JEsH8{2;3T>M^iGkA2?Xyq2TOVSi83NeO(0hp1QWtNE76gi#IgKEvsy+ z{&$bQJs;)6^sof2GQ|`qNj0idM5KpNUY2T)Tl|}agz2DdhICZ0rVZ__K^GlpODdV% zdRQ=wkgV4ac>dD5`360H%R3K}C0*tQ*BZLf7V6<^rl`;Q&2o1C^NY#3Qw_>sLbe7+Dg~ zGkR$u9YrKdv%N*4JO5FT$xm@+g`+(jR2j8%YfXy&(8m}H&Lxs^1M$X9v8(Q>~3Ot z3|}T#L9wqqSkik!Zu=jkhjOkOswom2&eBH7=O-WUBWS%a9r58yPwNq7RN1-}k`SM_ zNfiqUJ{OTpGtoPJ&(^U1jYrB%=OLs@-zMyJ$WE07&O1hnCe$BalsemqE)MJd(X7t4 z1lTu1pDRRJ(lFttUz@SE;Qw+`DJfluUG8DL7KySkz|@pndQmZKl^8{sUEA+)nk%Q) zhND3U>O7XSb~3RU{VFQ6irT4o^Lba~eOZ>CQ{>jnw926DNt-T#5iC`_%w8H`^7o=ql^5YM7;Q_RQAb$73oW(|H9iVe)bX#g^eqz9kVge zZTbHbr6-)QRde_ZzzyyE+c)9{aJ2YuYdC9afZ4jnhv`O&ZQh?V^rELb?eT*~&a4u2BPF&$!Jb-R1x#ie-VXX*Jld4ojR+;h`IqGyCk`Az^mi*5Jyo>a zdc~bMv|zk0BT2eUjF|nGg@`57QMY7rn%D{V0P(oV^B^>v+>aqaD|e9ljlvf0|GWtO^YV2mDQdL?ja zlnBh(l`TkLs-!NEoe+f$JFS-ymDnsL%cN^Uyb&}+4xXW=s1hCeB~c8>KtNZA5}>2_ znzokiaR&>uZ$TFi0vB&Q7wU!S*qu|V4T11%dkc)qR%lZ%T;uvY2k5NrM9U20g+ z*g9K9egEM9(e>ToRR8b)$4ClEWkg6Jl2t}B-<1Z5P%1OBHyPQdjjXb=8zN+8uT$AG zdyh!U-rMoJUx#z(bA5mRbbYSR+jU;ganHy7xbNqti%=3JnM`yEQbvK@gAKHO2%Hei zZ8Nt~Yv;Om@B8#G$IbY+zh*PobctAA0^`e_hZeUe7T(9)&Gfi%93ZA*QYdU>iZdd} z8MJ0GeeV0*w?kpNWE|v-DPZzNVobDnTI6{t0(06h(~n!&5D)cgX&<%^(7~1S<WkPi->Jj zFp1#l_M2X09_Zc$qwco-kY>MBD_9#kFxPVZ2a`Ji+_$~gUnlkn<)i|FEO+VX>fA=3 zT+AB7TeAZx11oXPUVp|+yQZE};s-`0dZif>v~gEIq6(@1wC6U+R?iLS3{HR* zw<{Q+O$qgWlCr3Jg%G_YnD=kQ21ebel#7i77Z^HEuJKBlF*wOlC;hxc3E{QwP<5QC zqpXgqjqIs&nopojb6E~LpwMz%=&<`BOjco8Z7(l_zKD863dRLdP|e=k2ac-mFgQb` z?lf&${E-M_*Vqm5f6CI9Xxt$Yt#hLN!34md>S-L>KX_lc<8@^c=fkrDcx3CN2_oSh zpYBedo81f1?Nn=a5l5CquMz+>5SIb?&G+CSW=h6z+?T8)l1d15sOdv)Ne({lf^rv> zaPCx^Y;G`<{FEHGIX~t}+?DYrE_?(nQ@NP}Gap+9KSg!w?iVhLqQ8lminV_G?8_mL zI4?>B=$5Q)Q&IaDYt4e0Hn&>4tCh(B01ZX?y-b$EpofP9QAVFdPKfc1NZ|ko|ITfdqLG(vZy2RVulovk*YQ#h12!J}v!6`8XjBQKL zkgMH3e2DpX(}?ow@_v&MMo6BMey+~;m!R(Ql4_AIk0|EzkW6>xO%e~iY{v3rYmqG? zM01ObqTFAvJDu}+nN5=A$D7$1^<>@v+WL%gl*_E+`f%|Zv+odobxN7_Wr+oAKa3SFG*H0r!vmcQFT~3I%|5A; ziAxYO4xpp21D^gw?%{!xWsSG-8)?AB%0y1!eSyeZK_$wY`aKu+5A^Bmf6tq5<}@(>a_fy$p|q8iry3*q*j)Y z5RR)4-VFOVp&++fOpJ%_1q2+(u$FRvxr07wbl!kdwDrOa1S(HHrvHWIz51OH=m|vQ zz7(ox=@zo=gI;0GS?KKZ{v0lPvFqn!L8(r9um=N3>hblj1QPxu4&)hg7a&%euhfbD z+nQ(!!N_h#$3?N5r0YnSr+;i}2JqCe{jcL02)Q_AGvqe_#}!EsW5O!({L#xoR$ZU9 z{Qw9)#`A%Gnh&M-y|AIT^-w;5`f7zH4}0pOXT=QMLd5VqK8E;wG(?lHs#FD#SOoL( zxWD9?lJhqyw~|5->k*vEL5&_5Jx!LN-wy)<<;DQ|`%V&x6d@q@EPo({)}CxLph6*4 zqlstmaD&E$mU+gi?mM4zn;e-e;R>K;R1~hf(sEdhbRDWWG91UI&Tz+CirrJiKDqby z2c-VQ`?ICG7Jypu@@^<0xGWdqG3+v^m=KOf+$UbRErz6K}(+t~uk%D^5 zy2QxRr`Bn`0w2*$j{}bY1qC+3TNr}lACNsAo02-=DHqMo&UMInYhOo2H|>r{n#jEv zC$fpoJZ>nbnEDYx-9t4=9QAVU60S1!nFy1nUZ~ebpdO5v=p2iEQ2H|Ak=qrp1amaE zgOyE0uD02|s#EwDNwRP2_hWi-zaO9dUvZyA1!j$@{mVVgah19Ek9({kYI_SM;CwpB z%bHpA`uCw`Ez74*{@${`O7}<>p`fp|a`Gb*O@-bd)dJ8XiuN5jFB#rMqe!+6D$_Ib zFiFdqRD<~{BXJi2aBv8cqC|xneDB)O)N$7og|I$G+*s_^R411Nf0sqz6df(c)E=aK zSLppn3@aFCE_2d!!^bYYm2VqQ?5^DNlx0h4DuOn%2*o5thWIEPMaMeTS`n%avJ0Lo zmMke78fRO~bFztIAa~8VL?V-%%w5CL5-$HTR}eQ32ROx0gj#=KoEU0<4H#ONXdEBN z{WaQk;v$9e(|vf=JQ@dw)m;2XxV=kjm3?&NCXep&3=cDpnB=XbL3YvV`~A!H8_P!R zI80mjLHr5C7<@#G!JlyxACgrEsGw_@*9jSJ*%r{mnrt+ap(@+l1uzD&J{Zfmz;weW zHH-IuEqdY`;~)y(Dp0!Wx|YezQ%b=23?JU`*2}YBT{Fv35fKc&DzE3GspD+uJ)mfm zDNcXiK>%h5OXmOP(ZiR}!~}kXDBsoSl>5jGWT4Pn2x=}etfPC*e4x!<%$TsEP4?F= zeg{OmPlt{l?sI<&(yAeNYWnsRlYj8tmx#O8@lEBWLl`YRXa`aJL~25 zRQ6%_BKQ;mC3akTeyB3hT)6nOfHN|6{c;(A@9z-T`fjDrfhe@fd}(w!%uIdN+4mv@ z3`j92V0<@y#_;)5r38LQ=qt1ecWm7CM7cku$c1@h9&*PX=d9&c2&0=gw;LbYq8~!= zeRMa#gv>aY21f)aezoy%&eF%g=awDG9inwBTfLWl3$zJDI)I1W-8b$R#4`bKe%*s! z0*pPP-(N4MR{I5!jV3P)Ka{WEk9h7{<o84pGz*=7|Q>(R(*jo&@!&TRUfW z+t>=hwWI~~o|VEDf+S|4bainMN!oj~=koOEwfD=P`zG}cOc zNSpy?{&9^Q4+Qh;&r$^dKm#W3!EJU&>Jk$gkQPa==2Ev zP}HhHmcA5xXM^hA)@(G%E?Jfe#p|ju#~z`i5K{Y@&# zbWTtallgRPsx`1tGEV*eYS^#s=Qm^uA%sC#fWracGG5)9zjk-Ihjt+w7-~RB@`UmO zq*4Nl4giZG*7$c*#^`V6|bEqOK{<4co)f~!tL))OfZ#<=Em(GBZ`ven|gr6qec?*RV0Azrh z4SWxRBFRW1>Xzpu*K(d8F_Q|UQNhY9!S}D`zUC-v+X~z+p(d=zlyG> z7bbdXz*kwDeM#9*g#zoJIj&i3;X~%Jw~KdXKEyoRZ8Q6bQ6($V2ut|LjNFtmDfSz? zR>D;cA@NzZaYEmfq8Y{E!r}w~CxI`?;COKLS!^ zc;*XILdWqX4Z(*9oVe+FJ$+-=owA^R7k_+@+y*ep7!Hq}yhtL`8vg_EVG;A&^z@n! zZWJCYaw~qfO=&Sle3@JR)J+9(pxFq-l1oU(&M{YdFDq)jAlMlci3+&=qtaBUIL^xh z*?nt$9KH#WXHR3x+Fx=d3e1x3eZ&rl; zZhO*hrJFTx(Jd+oN1Osc1b-g48a#5HeKu-;D*yGDc>4(G14y7E@K6~%{4_R*+E(^r zph`1IhMiNysv$HUGUqOe2EgsRnUGxm;h>WP%BrAdb$TEyC!(#StR)9$*MZBi5w7f{ z{F5i#9^nBd(c}okHoN)0e!AfI;K*h>9w5^KN1g9j$uMbeUzUJ`zI;rLLWo}TrQ+qAc7N*>6@{< zm75d{MB@Dsj?_#G>PK_Ce@MyGasP{YF}h?(_*|%I9w6zNG-yy z8o&u!+pz3WuCBq(s4Xd*FpPOS)q=Y#t5)*0!S#KPR}XsMz&mOWbT=cim1AnRn$v^* zWuWHk!~j-6A8{*Sl)C9QGCn?eeegSiQ7q&<%FnWBMD;UPKg45~3>Dt!Nf3yMq?XO? zn33{b<)&)UOPg?zJFpGuU2B85)&&Y)(FKtc3{HiEut2~8y~Hj3e6ubDxPFr|C9W8a zL;(xIGl?iB<@jdN?OWfDFTFix{tkrXI!1IG@HgK0lx8pbmk^8^j>}u!{rg&kZU-LAmJGS3|G6IlrDCjPr`4|`+nd$W>99#=j#uPFH{<~dpcgG`SHQo?WEt{eo`<$`5T4lX? zvNn)E!b?5cB3K@{cB4Htvm5X~hwhpgY%^esAuy>^{WOA$JuhBVw|C`Gd)m>qgwwl z_XAf}VUZbKo{xO6ynMIbgH&;Q@R$PXgOjc`9C($%BpqJLKXZ%5^#TOF{xnOI78}y0 z2S0p>`?j4OQ9~5>D~0H&b5>@Fw;lZd5QG7IzM56r0DPG7rg_j?n@*H~vh&5SkUzF( z+J=jxYQATFb5WmLt#RM_l#&%mA$RO$+Vm>p_i%OBnb5Smq666(c_Ro0%cr*4hi{t_JcD+%{Kghh%KE=^%i$KW1cp9LV#F`_=&)-B#`dqFtEg2PMawSr8U zP+MGpp9v8nx4~|Fp~-125wkoPSE5pRP|=s8e5-wC7H9LBP?yNg4HnGS+4hX)g%FYb zuEo5Q^&aS%#8$WG>Y0AY7A^(Bw1B8V!M6l3AOsZbT`Ci;QGclsUDG%3dD~lf%QPP9 z#$1v6JJWRQpz95|M=4LCTey%)gE9?}!^Hr}gPx)O&6q(lA zJ9-==Av0Hy(|2Jwi|A~r*ye~&tKR4(IeEf=*B{+TK%w&J4L@WEJi70=h#d|Au4 z8W86J;XYanarFre_gT^2Kj+%*1VBO)(a1zmYn_dWPTqx#hg>Ne%+ewZKC6ra!Ri)K zZA&=@pZbKo+r9D7{h=C6T43YBy*J0dq=Al8zrbkj3V(3Qm&1QMVKzbZAUh|Bw&xO= z_~4`2dWV8@TJT&(FJ-|nFu@A*9ZK4-SXy{*bgVh*y2Q7}Px++uowiI1SiSLJhweT@ zj|rkI-DHFtqya77dk`HL7l?Ib++FbW)8@!^T%-fz-ockSkjUKnl{Yb7{F;fsRq~Z4 zWndph8(XS<@q3-Qph(0dnFknUBz3z#EXY?q*~q}8w{?14@#qx#kDbOBK-XCIql>xz ze9%KDO%b};1eACpkXjg00Qgk7M*n@*iDx9YJ9$i`4Tfc<4Yo|fV@b2R{SRS!D1rxF zdhTT7y4zzcqNO?Kghl>5)9eBITvl0xH@aDzLLX*08>PJBxm%TX9gNA*MI19s@-a#8 zfGP|w!~fk;da`b!7zPFEjhUzJHBaeHS@-ahCEU}g{x}cSqkvHeSEomQd@TeS$qr-H zRN3|&zgiH#ZfdJN{sp~xMYi48V#Z49t9*ksThXDuFmwknfQ5ZKdICoM6>tifh1_Q% z;W(3OF+PF>7EoicHnBOI?SlfY^nh=d+6W%Jb|y)6@7<@IXs2Rj`m)Stln(id+X%QADocuiVLF95DIe>9n8} z!L)QhM8kC*q<}pi`*_l47X{rfv9x<#?7a-gd{8JJq${>jQ$HwMYQT2)67@rt1SR*~ zwj2V(PUB;3rUS>fe(F#sa(LRsDS3bR;qY>OF%)okKMp37qDcvp68)9oV=$A!o@ZiM za#3t7te8PZ=Q@?k;AnOUaQKj#3*b(<<|rfJN!{udi%au23t8Rac6X8R*l13Fv4$@! z%J#cvSYgyZ$aQYzBXC8{EnpUO!TmcBF^o*UU|kMiO-^JoW!nSgS#uo0O=zr}4&rL0 zz#PXpE2fqOoHl?EL#Z|8cSu4HvKjfwM1d7=2nP9%L%%{J%N{?Q6B2lo8c?>A4B$J4Y39`*E2Qp8H}|~(v4cXh%`GLvn>lsq zeyw=c;gl;$haSr9cnGZ`69@4zD{WFYvDmqdYu%g{+gJGx2?L|SZ8fb!B{I$>ah%$< zUo!1}rS4Pyr+{LH+L0jdvf!Ao4|EhM=e}HCSPC%nt?F{`U`Dlm))XFH)tA9rvi zJW%$l5%YQR=HYc&(4-I=N59H5A+O_Pi=m9SB^m+>NQiUuM;Ia;{?1KI+Vm9ke81en zCO!`*4Ktk02N!)bKNGvj*fYOddv&&h9qDufdXxD+q1^-kgYwW<43J@FG;T?n2f}II z^;b6WKXukQUB;yZpENLVJwx0FG+0^uG=n@bYGbzEN7kE;maXF+6UPt(kV403j%W9- z%p;x)$T%fXfbMo(kq+kvvp#km#P*a<;?XP(R=UBJA7>Ar*gU-7B_8D{uG8K!zQ?CN zfE#(U_WS-!hEBH5Rw4*Ku>%npDDv(~jq?5NSk@H%yZz0uUU}G$u+%X!t!b~2a)f^d zutYYvfGqRQ96sy}|Hii?M*9e`00Y+}bhwSi#usCRB(rv}gMN8I@faQ$XNX6_fKr$g z7>3$6)^#{UYvs7qE}ow^pF9aMKlP#s-g%5oySE-@WGd$0MdkrfYMOr2isNGbhN#*u z>mkOBb8Vr7PB^Q(B<0F-eu)o)TI#%It{+cr`C!+1wfY~v58{Z2z_f>APZXA3MXBu6?aVu^_U(?anQs+smLKb#UJ!Jz0;be!kE-8?!#-J zr|C~m<7H9l1|o}UKhA{^cU5}6U3$H-Tz5PDewtq1yYer>iR^#P7?-BzS%IOGuZ!g7 zUK<@69WA{F9L#$TO*;2E*FO9$u|u607_M^jRv9xl8+gia98Wb7p>OP!*WGp@I1Dxr z9$esgfjIRx?1Z}Bw5|ebUaDx#&DN!X%4G_wCpdR(WhupkwA`&~st>Hg2#g!A3bR!1 z5kPXC{)xaw3Z6UqnN7$1zmrR_#XflV$J?Qcp9tdVEk(0(M-CD~O<^La#FWUp&zGiI z{XAdEQONIPKZlWl zs7B}W6|BW9?Iz2=3Hywk6xrvr^2ruGJ~>p?pb zj%}otU+Mbn13$%oWf5T_>%}Wqc`-4!d(*;e*ibI8Jli zcKRyzO_AYN3mY7jbP!fTP-#XRM&%^w+N@pLg`co-9_)W%vz zu{St^7^BMlT|DS=nSD5h8Up=6-w*I4LlVh6%)$|HN4t3Fw_}}c)OY!P1vzz2{dU2Q zFLrNTVniwCXJ8}sP!fxY?Zp^nnx)~4BQbQLbfI{+jUsu91R^jz3^=ia$J>gf>$J0y zQg3~(1fF`lAG*sjKl9f8$q}PZfPH+-9*y>nu4Y6bW!_qI$7aJv1-Dh=*x{w? za(@Bx>ohTxJ$jkucBt}5h*7-ayZ^dN38Z^m`8uHi}FalS+O%6DCM``jcT(?9>ohI`rBcoc%k$uAu*B`9dQv@+%?}6 zLRI8+8Po;|p78^Knn2A?+H;hre|_#uG!3}D2R%tB2mz^0`(MfPc~XtGT~q-aYizXQ zCJ^H-oz3$Rz=Ypz+MCs0J7Q6Dbw?;sgUJSqU42!u*#IfVS!v1rRjT78p}4zeYtB8a z4t)obj2I^fD-X)7{v?@JQCzRQV|%}r-Lp*QA(e*9bSVN4r&-q5RaoRk*Rnla<~O}! zB$dODbd|#}2>BZ0WIy~aiO9T+`pttrj;wouW5YQ+uUV3=&Fo8^h0el|8vDi$D zC`_E~Ej%wvj=Vd@dD$%E0}IKl(b0VM3d{9Y%S(_0Ku8uGKHx552#71vPlh!AB^Dp#(zrSK;hN?}o zJ0{I6k?#Q80cmMKI?Cm>R}xRvJbvn=nX*)v9JGZP#FUUtT;*PO+Bfn}p*Z2GDz&212<3bHvx2qB zY3bSD0L>tjRq<>~pOC__*tj11hs>or*x1AjOXoRGrr0Z!+U!U70dq-Hl+IswM`Cps z@rEiDRbJEcE0z!~xveXt_(8N3)S8zWnaN8sY|w9sU1`cx?23+HNbb^@?-#QH{2w@j z@9qs}IWAXg8DMP+2{j7=B~_AjXj&4B_vs|1;c_Ll2sm;!`X z;BLj1*t;PGb=2ZD`Qn&8GT)No_nhgHEVti)X7885A6=0mr3E7jvblGI6>r;nQYE#p zHh?4N&$##KZ&Pj}z9KkOM`R_^Q4#u`d`(Htc#d-S+YjH4oS-e~+2fDT=R&37%R;E` z;^~n^z^imN%ui0S?0nJeW(F|Pc}m7EU+19D%SPQe;@!D z8M^)7ZEr8mwL;>+9UB7dDUo}%RZsMZ3~2E6ILcq`II71YL~2;KKbU04IsK4QXfQjH zFD7OGS?#mha2KXr+WrDk!vYBT z|K=l(4x4=XrSHVU9d45vw=0PpqNA&eWp+FR>D7Ee5-06vDwYlx-w~c_@N;7aPBsg; zC#0Ylb|iT<5`_>vp*MzcaokI-U|=XCuXz6KiPgyDT?Bkfj%mrkk0><%TZ#i6+FM!f zxk7qS)O`*r_Np!85OW$=T|TP`Ua>v@Z=&`~iaP1y)8&tZV}y^A7>Zi0LlhM$o>eBJ z==_p(yuMTuRd&hgeM&y>K9LFEE{pX`r_{4*B8C_V-TFE)6=c}kZ*D=2*5cTdJe20u zm!e&N@=Fa6b{qH|cd&85S1t+`CMsC$ac8Lx=Hs=QDan$@3JQ3WK?y>2wZ!$7qcjxJ z7sZju9f`v1Ld@+49lG7Z$vo~HF>QM|lv8)cw`_AbKUnhH!lJQ?lP8IfO&M~Qd{cOF z;2hmD-V9(U!M?@2lOR1zmfzomp%8z?T0Bdw3jn5X+F=&G){xc^{nM!sX~WwKNJqH_ z!03JprC`jz2#tHwI`k$JVI+n$2w~cx9wdo*9%uqrY9LL_RQ2U-HvcOH{1;IqhKLEr zmM+3mVE289?x4qSR=e}k@!nOPy9o0nDDU?lp)$K&%!zavfdPQ9IB6C7w=UBFFkA-w zq1(9w`>0UEXNwH;wWcK7UgLilQ^1gOB6cplgWuKZGEKZaDW3v2v#4inH9P0D?!9f{ z#Xt-qA%voAD|})9Q5@C1I**OYT3Q~KJVAHrc7IOoS8LN+liIudBnVFq7}wyuUJRCx z0J{vrAEa6a^dD%nJx}7XTq)*-*FLVt=;B2CPp!S)n6b zia2JOv-cYH;>N_nh3Q`>q^}*=KCR#FKYcjyu%^%$ff>_1GGa5stj9HOT-9DG~>jHT5YL# zW05J#(u;?$xZqFap)P*53b^=g0CoVda)2Jq(u?~Ly2O4c#(Mf5f37+jQQ@ItbN)z@A6 zSCiVQubwCSXw(mYqi+vYm+7uWz4xwmmMEkH7ffR2vnTVTtq^t%oXx8XD;_X-gB@L%vo@NqydvnBv;@R=+{9Mk#4vwNQ4+X=CG8iBiF+UoVY(2p@Nn z>!`HnS+b9o{g>V6yxMbJ5g55e>Y?^zE|)0^8Os1=qpi|mdBp1-+eNUuh7R7x$c_z2 zMeeLAx=-^P=n}lpp)TCDp5g7+kIr-bKB~nGan~vNN2P98=uS@wkh#ry@oY7fGC(=h zu9yS^jipd#d4W((jR*72ZmiAv{QUm%?P!*+cJ^WE!Oe_TMjt_xoy>)+GZ*fX8t@bQ zUFD7xvc6?75V+reKLIu^!c8Uccmp$kq(#p))7HDzxqE?675i9|NU4g!(1vKUFtw(5 zLem?-h&SNTjj;gs4owsk{PX}?WJI0RQJT0ufwzk%@Aq%iXdP}A_mmMnKD834+^TT= z9@`EYP7uT?G9(xnPIq6rtEu6L^y-=VmjGj^jQ^AjY!&tk?WwBad>h z(OMJkApTdaUZI0?*Q(w%ybB~EV`<%z zqnyZz;i4J-Xz#Iu-&)mLLns5=Fs9nGVF;lLnXA)oHMuxRtkjn~2Vg4X(m;J2Wf{g# z$Iyu}Bb$hbRE~F`L66Ax-}UsI;pBYzIc;lbI1yPLQs;K{z7@ywj(*v+<1?mjJ;a?6 z@oVahrPwR%rvci7B2!$Mg7&JM5ZJ$t&x{>A@2}S;v^Y_ zM!XiD9@yX6Me=SoZkL4*sY@>iqY&Zwc_bLBvH$+x!nLXFwFP%?B<$nG{p7S-0g&jr^d+&f0cH^-X<0sgGb3v-O3C zMwl<6DG+aSee7kHYpHR4y|IMO!U$`?^{Xkk}duAjv@W2=isM z&mocN=;@HQ<=KkARGTr-yz|PI-_vO~P5gDzZF=ac zUX9IJYw+_0?F+T75u*&Oz{t{T;+i8Se1jR7M?S$s)dhw}kzLtNq%xi_E8DoI2$1vQ z;iX%0e+?5=@-pL&SxwNi>l5c%5(m6YQ`&AWFv2;=zlY`wXFBt@5~PFY|6-ocCoO&fzc>GGrz!d_fk#oeGPu z(mfCFiDgfeXIr>>I^_|OTr)UK-@kBmyX>c< za}F0#hWZ@q{$7Z5%q;!b-FpyG1Jl!GZdZkF)nOtXy6K=W_6|a22(emXiTX>Hl&-y` zx`>b#pnV8pfLpoNp><+?rkckIu<=vjA3@4azj8w^!BzvMi8plK@r+$G{BH-@ss@>0 z14Z>@M``sw2pt*R*XpESlzP*PyBYpn%KVu5@pBv+8JZ42d>PV;4>O$tTp8W7etUl^ zQoOasdiakQ^bx@5fW1)Qr5mQld%&0^vLf&q|1HaBFDQ}L@e)%g%bCw>Z~<3NcsuZU zC;&DMOL0qu*DPq-uEX}5w(EQ%q7yu(%CPmbx5_Y2>9rUp-TRz%>yw!`nSoJ@oE~XE zdlCL2GR`j2eaZLs7o!{c1JTb-$-DaR2IE7oP&JZCiR{MsXgc)F<^E3)ScixHw$n`~ z4c>o{Dp?iOsb7mmdS%D?5Gg(e^WO@~S2Q+?k#S%!j%#CO$lcRW zYW7Xg3x~rgvSY7J31og9IkHROLu@RDZbFC zVCb|_CfS7`i3MUGf7!mwbXacdMc#$g+pOTH;2Q4xua&Qxxvhh!A;uoTgWlA;Jj*T7 z*s&*j1V=3V&^@H?e1iClA3`3Ky82?~1l!9rL4x|S^x~{i#vT9g3Fpt+wwLeM(>Nqa zt)-p3q#I~RlHKj1azFd0rK#9{FiW;DUa?0XnUiNfj8?bE?KpC*13zX84w06`U2JwH zKKc;a=5oIwSiq2LH#tdGjgz+hSKXGipc^+_op;~Jj`q4NF+gJ|WHN3rUWIhPz?Acm zH2-!y7r?i8HNV&s!7u_^KLWMN%QFovW=x87rNU@1WV{fPcEBTT0l%r+w&v6#*6XHV z>f3G(jm?dVvs2GRO9)&l!?%ktgtBhAn*ZGMCLI9dms)6`E`uQy39nMqqF=p^6+$|| z`HI%~wY{E2cD(}{926w;X1}UxNlW~=lRv+KP~r2kwV8$^9kjRy|DH2)OMYB(2T#U` z(IMjmT?O)WZ9ic^N=7`aO_+RixmljXI;nTGw zw*Ch`sE)SuNqvR?$}g=V!%0^1x)9oH*uJq(!gOmreONnq3Z_e*_Dq}Ha?!2R+srx} zgMN}TJOL}*G+dUXSQWXy`C{TqymvY9)O3V$zuAQ$A=sg<@;PzPijROTg*-sINK_e3xt#l(Tsacb?g>wxrXFR%%hn0AOjl!;lwIR{58 zqU7EU3#lCOsF^_46r0oKMe+v0RT#_S<=W{KZLD(A-G`UQ53T`li*!0<4!A*e@FMs%BIuvBi^YoOO8HBmSNTRlPR_HFSm8iHp=VpBS?L7H39u$2 z8K*x*A3)n&($SCHcgb6I&yj7>(trd9()He58%^ujarL%xju4HAYQ3^BPp&fqjghQ(_= zuIt&@oqpEUKf4Fl^sCvk*|YJ66z^Y_(CA2L4<9-;+{r@|szr*usO)HP^`7-XQT#E* z6l{S-(~|t!;y|tKbsO(O5R?Ow(pTnQJiWaw2gv_w5wU_<8_j=%t`^=UtvZapd7y1b zL4#>W=DyWT^^kiZ+E^S!ZeS!a`Q>b#xZgWJ_= zL|-`ttna0MX_$z^W3Aa+l9?u)g?H+h8e9jPf867;J{=8F|K)3isv|+il#0l^xve!PN;0Q~i}1gOUsU$7jqm35oj0>fOX;N(s;;uE z@>LSv;n}y-p(Iyot!^O!=+7%jB1l+Pp*#45h*GII@#v(L*L+Hu$f!^ z(Nzo3`QRnJ(d1D2io-iG;!oP-fk^x&a6c)NNo96Q`%W8+C#Lz>)V|98Hyn>k6}s`F ziJsZ?@h5jJN)-JrS<+eiZCM~l$KOh-lgziFVZJp_62H2LGK{0#-+@m-@`ZAwRkY}E zMO&FaFB0r82TqG(@!!QP;;zEKd;qJOZG1oVjN3d1zZZo1XFt}C;{Ryt7jK?H8ql5& zogD3CqH$az*9cS|X+g#C5a2MV)HH1_F`;y!peQ*7#$^m}EBXQh?G|r?o;wGDE4_6* z*twt8v07}zLtdC!Wx2lKF-g~SHH{MdXe|aETxL)}w-A@1`F!7)7d!-7&R)d6H7T0_ zP9zxU$mYuBFI*yJfpLxj&B4ut=mfgTH+z0VufLV7Pw7D_oevshZ_3ZLYgZDOz&MS9 zp4(?Cav@SKmCZaCV! z-MqTcuITwc2bV{7t`5I8sZ$Nkzb~e=zo5cv6h>y#>lV<@8s@pazo0ptWVmhy-LF>; zB;{Qd(6b!dj_#nLZ7&&CGIs9COrYbqCwYVzaTiA>N9K;dIGc~tD1*B?{NL)C#kv_3 zS3kwwV(ZXjP{##wayZvVjnT4BZ%6ewH%I<-&9+J9TjLi)cW4MA{7UvD(Oj23+q7O_-W;ETK}J0XIuHDFmp!<<99Guguc~)j z|Hxks4<7EpxHv8>EA621AUC;_13EL_quol7m`$B|E3e{p3Qxn)W174U9T^$ zsIaem7&|?QxTzXxu`u_fE)KPSw|VCb;#l;CxMn*kXwE`;O88z)=M%R7IRD%BqMNmw zVddNWjrCDrg&c|o^KezT&n32D8Xg*Wn}IWvfDcGQ6)3XEY$WlR(i(19L(03|*%yN^ z(h)8d^9AP$ls>>aZ5E@y+GWkVShAu_jDIC~OLu_sf=yl0*K$5e9Os9z zRgvrC!~DnflU-~_^zVSPyb-213XP=QVS0z#(9`0iJ(xB1#bveL^TeAIT(>NTK?g?k zy7syGn>1W*q`gAbyS+bnlx#P~%WQU_DSaWvnweQTtiD~!jb8uT$kNtY@`}J4#%)@L zgK91=u#U&=QyUBLX^&6sd3~4Tgm9(!)5Ca2uS2$#!#{GO>3hH2Kan#qQ>_Qe@Z0xr z4RdQxYtIg?29E9or3;iKUOo@L?kY>_#ft9XjObQ4d%)y?3I6Y7uH&q(Qpv!&nfWZd z|2WVPqG{k(^>^*QxuyB`ks!|WS{KIhP;s*<^~HWPO^#6PgYNqRV^~4XQ*)-=d>165RvC;$R zA!LENm-`brzf@f}I$-A|fd54d<)-L0zgsu6Tm)29V?IHx47l4h9A`r1lS)6A{;MDw z3>6cB*aF=UXY)exwWGw+uarjwa)0UC1PHtqAgJA5U7Xr=@O_|PUMF+%E17l2=BDX< zCAPi&-){jilo$#x4>)hp&qmgZeLVB2*i$C$_*6Hr=fo;lZT#gmu4-(bW5nhdP+7kA z`qC^1W@E1t(#uyNi@`TJ}QkeF+^NulxsJ_5Jg5}2t5@3PW$ES+pUT7V-+(;m+ zfO(w6nfRDLr7O9e*c9yO@F0w?6Hq&=z4M1a01wq76pi|m7L{$m-Wcj*snE<-x5XgD zt?eVw>7l%qdoqT8-4!udanjb0IZ>WP?>JV>_%n7c%)du)J%Ke)Xo8hgMegyd z!Y26zuaF&~6%raM&7EJ@u-HJzY|-v(zPIxpc#?*ZGXA?snE=W)V?p_%th=Oc`_aR( zFv1bdi{75Rgu%?=1VtcZ*WBp>L{JK*=Tkfp-XwQ}o;nBTzhbiCSGelYns{<{cY!7U zp0~128S)3q0_YALNO;spO5sIv^45bFS9D7Q8XBw*QFxv8-8Fht*H9_2_yrZwe;3d1 zK|lEw{KeVQ=FH$(@{SEVrOQ_2?AkrUW969!J`~GEtC5Qms}cEqiw^Z6*=WlR{g)%f zpJc>%rd)h_6-?(6LY%h6<`5YviWHR~@WFCH@Dyv2I7{k=TUthj3JLEdS=j94+V%hi zur_xnPwip5#y{NN7IzCReXGBav7NDf$C;bu5fPz?JPfGo6KAmUbi6NCC0tY58yao| z8~D|K68twp{$<*~$o6Dl&j|KCaqMSIOITre@7T>V!UQd0*pJ$eim&o0qAi~u)m}d~ zk-BcrXtXTyBf@zY-|U1FiYi?lSMr}98n3&#PL1)TDv;mH{hj$6&ssu6EZjl{C4-8g zeLQ<|{pF-4)+c8uSUoWI=b)|0bpp(Z+sHDbqv3+e{aswUO6>T$TsU+Ks3xd~pdksw>Sc62k??{O3+e|NcYJv8wz!R(J|NFe=F$G@IlMCvWFS{(WHLIvtqZKX?`j2rYy`l*- z)S>vAHs%5C**ovEvo59NeIle=7@2!GDexj$wm;HT?{0Im+oH={xOv7bUTm_CFkBmP zgda@$dm9zpUHiv)ru-P&7~6ITdGn?$F@K*)z}8H<%r>6YuL@KRmy!y3#{Q4d@Q+6K zJ>Sm~y?*fyk=#u*tI@Adp9rl1@HJsZobJsC6ls==q?vF5vN=n;y83;Lbp&Cpi+mqy^xT<|cLbRcVKSj-cn#vi=5k&pX=CW3f z7Dbk4-*0%7(`AugR#$hut^Ha`+6vtY-HvM#@b^G(P_jwH3LVs86&l^E5sZ1%P|~oY zbC4?&r_1*HDr}cJii>^@Tf=ZVzInTEz3Sip6)Ubx^zQTIm-QuY+E2xP!kniMSJpNY z!cfZN_lYLOY0fW!CzgwXT6RN2)+5cIk{|BTn4P1Uqrv|bqG?A}NK&|JN!xeVW)XKi zg`>Y|6cfMm=2FWQ9UfKbIc|d*WK-i(b(PZrOX$Vo6ASb6c?K=kwT-)f?A}gJ5bZHJ zZKY}a5hG=kMeF#cRI_QI)u_>kQ14}M4Bb2~>N4Av<%5aO2L8rHGCDgsv1IKVw;Z?p z$H5Vig_-Htk>5MoRhdr0FS|>s^_OhS;rD{uBJKYa_iGVkQ`|>Jy?#0m2ws-vvA4H3 zu=YuFXe;?QBYh<>^?d)g-q=v$RsW7#{deiT+4<-gZ;>6x-#7H~A(rcdz@hr_GcQl6 zAKEbJi=!Y4TwD3X|CawBDdRX}bw2C0{_ZH3U0GCYNvAp=dJ*ETR3<@U&pc&D+rZ_>}yaXp0DafbG+$dgp5rl+3-KL`>k z`vO0daM~@luUF;VZ}}pZwEZ5VP8U)}S2)5t@P~kiL@E)9!_)mAIi&Y25M?A`!bLn< zpWSJ~zlM(JtAfx`XkGMg6p$#dKMhuAWBwh5uDf>hXd9FODEjvF^du`z z+}OEO(16<0RwlTGJ-}Th4a(nYTU>Qw1aYTt!<-Z6*j@d6()W4Ixw9Z)B8d%yuEI3` ztP5R0RUrNMYASVz{;qxGY~3jxU7-dk=MuIWC>TthO_kBUtZ#_?2gE_m)z6-*mhNNeH zi}1t=F4)KaGb5CG>Pf0yW0MXmU;f?#g^XrtcRFr|RTS3alV>?wxz&`{{%_&Z`@HIUVL&WxE_5WJc73U?>vy*Fw$bzZ+ znEl)qZXhwP3SY{{h}m(Me`4G-lp2vefgMCA)X@ip;)UaP$ca%B*entQw#POMw`~^9 zr;Qa|<;MQ}F}gHc?rd`Me>^P1ZMyUAd>x*t)WJ7*^}g%qYBxx6N;pASIrv1eXT{Iv z>QwIaxAtkUMo&E{ry%;(1XT#TMt}aSKq7a>V}&eY?WUO4n4R~R2KPr9 z{FI_fzdueI`(L-y=;yEo)Jznk_rG_?g1ft@v5W1ys}qQ`O&3J6IufHswuADcD5d0| zDfbFzZ!#>c8Ey!J^Z;(q^ob4soxlhn3u(PwX(C>u4P+Q+fdLZZ7ENuDa$w=4S8zSyPMvoK)}6 zl&^)hY77j_cMmN-T+vEPOq91x?yMCXZd=|FD0`qUG2W&>-_DU}47Zm|9Nqdqhc%7d zUcjzBRhBwG%|**4?cMJlXZo*KUhiK}D?SUodV%~oyC}^9Iz0h1A6DpNxsdQFY+LBa zQGxDDrXG_==%C?iA?&Pqrw~=1iRhmQ?O{TN068W`gFy%j_kQ#|0t(dvls3wy(p;R|W3e?6c^`uca$%-EsV0BHUdcN8L+&6H_F51x0F zvAt{ik0D^%kE(Ds(x7~K;uclu(07M&XF9A1c15lDg_`EWhifzR(oFRm80SGT!)RJ< zrxEVy_F)!gzjHHFOA&fe%-S;p^ioUp(hC99WtOh%uN>DirQN175fK0jbz}eA!jE3I zRtw#tCB3~-mxP}b`2Fuz6-Y!mglQJ;!MRs5!nx1=bM8n2-6@`AKA&1Z^w@tC&jnyu z=yMzOfsrSxs)*1o_seX&`2M@ZP(rUSr<5*J`dm>)#u=%hN=2`Fx7L8^p}1lpoTfx? z{7N`mFvs`S!?Tr%NjrD!Ys@7zwGd8C;qV7_iL=`jHE=dQ0;wmT{0L}i?)b{7g0>Zo z6OP*<$40(HL>{fwhU$`Y{Lj8h=l^~_tvOsY|CMOnSKN$M{MO=BQdjhk9H{h~#PanL;%AUB_ zrI487k06ttZ-dWv$6X9FoK3=E6igT4!j6PUdu}WxJCwLCcI4}mY?Pla7#Hc1Sh6E7 zZKF68okD)%%enmlP4zrQtv@XnT=UlBiz#<_bHpt=vLjjNb3-Bi_Y@ z%XvAqB7X9mqyu*~yE5ChDt>UMs&KaVH9DJ*iowvh@gnGz=# zjd<<8fEv%MTgsiV-g>nRK$=fZFB`G~8%072Bac=^J@u!S!QX@1!CjM&MW2WG)E` zan{dFQ#{L$tS7ZMHK};IHbH#J67AmTIjyc;%+AMJ)TKr$#6@Y<5v%R>Nt*T@W!tsr zhQfa`?~?}o>GwZ=le!{8%T?s?ZVBrtCzO8V`Rq3C>K_JjG((2+nsnf2i7qas3s;+& zo`{T$wD#+Xrt4c&94^hDEa0HK_xzUhowst*De-*|H>MWa``QfMKbIp5-jR|_0ZYf= zjGcW9+@I_x;VZ5z3eMYyc@hqjOBYR^jbFA+-aKgU_0ML8t9MZ+ZGPNT~PT2t%~R9C7Wt z>2eZk{EB4sAZ-ZbL0PSS7A<@4DOM`rN-wqX;kHZMdPxGCB56Dur4s2C zU+D?4wETQ=`3n;CA6OCKlAZks8LY@_L0^7Cn^L3^ZrG<-+mp=kr?M zzWg<&B1WBq=TWk$_v4rybgEqmo#r^NUD1V6Pmh-4k*Pj8CCc`sFXZ#|uUWaL+xZ2I z1V+iM5P3*0wrd_YIL;(kSSV>-H+E+lC<`x4%b!Wo=p6rs+L(^49th-CVd%P|r=M4} zn&ig1GrL9m2u%eAE4U+@5D`gO*m&_a@3pO z>Fd>L-(8}6h$JqN6JnXKXrfk=)Q^U5-~MBaX$7oQ7F3LP8Qt0Cn*vaSOoPn!0{*L?Zj2FsP>qMa{e$E>BM8n_%p>&`bG>m0ZNPB;d~D3I;QIp4?eq zGRS_4HxV;@0F^TRc6vLLRx(D8iws5AZFAui_EAq%ytPlvKuTA%!#C?`fanepx66?0 zEKl`J$B-=gfwdURUEID?#3C#+a236ByGC`up&Pt%g|o?fv~Uk5B+JJ5G7-Iggq+?DwF4sy=7uou-rd z);XOV?^jnw^PVTaz;`UD@P(0q$lEu@g}3>)KBVLgiZVxxD%Hu0iz}b3QCN%2jh_VF zqfg13naQy?gYTp~LW%Y{ns-}2A3tpN?(5y;HmyOae`;q6LROdLVJlZ!Y1>acnTl4p zm=y3fVEeob6XeisT|A&!Olok@Qw5Sj&MA=HEO|;n=MfNp&mN98VsPHO#$x@cF zWGl>+t&J($*w>JC$TrNF`R-?AX8OMK|DX4q_jC?s?&o^0^>_WQ>qZI_vP8CUc%S9% zl|n9=bb@&A?JmnK*#gZ% zjFPISmsdfXRov2^r9I4N=a&0%3Navlug>`Jnt9FqY~1l!E`!FCjm$(O5Uma(%ULOC zin_48HEx|r(j8yl{-;{P{M$Qk2c@%Jd|cD~jToi{ZrKwL9mvO_NR(NE8uP3p#tEUjkr*B#zs_vF&|UNu+W)3Ltu_ovIH8y-qL zl~~=5F83rEM$I5!j8=~?pAJH4@czEqy`lV;qUE#V_y)rhf#n1XVmXx}AL#5iA>}&J z>e6x|&^};xxumP8qs61^#$;aIo2P=TwyYt<9shIoK(6Q$$2IdC#VOW8y7uNaiOibO z(i#|Y0)+cjWi!hM*&g+Vl|NL+=Y+6f(f%=BoEO%^7S_xB4`!oRUze*Thz_#^3G{m& zKe>*PcL?V@YpfpdQq7;Xl%G|w;Fe?hMv+D!|C4Niu55w%;|Q+~M*?YpwotC5toG~{ zZ?e+l0+!g7hs6*NVGi9=PFG78;b0ALa=bY#>)xHDiie?uQ_7%=+p<^PXUIP(s#NyN==>P$ygH99Ze5l9#zO57J|7&Hfcd* z`Tb!fIbIr-2NMRWD9Z);!2WeyA0~?I$H&K;rle4ncxCsEEJ^ui0&W>J`ZC*>wblrl zp)(c!6DiMotv1S-N|pPupMK`B{9pbj$0sMl;f&TB|Eb4nJ3DEPM;$eFj!U>iomJ&P zr(Ypg?VgK4*jGZ`-JjoOT5 z$ARbuIy#k0v%7TF&c#Kp-nX$+2{g>~bP%Lp`_u%}FTS|)-u|V>k9d#doKcoML1Tow zEbnI}l9u;a6FhYe*?mMtKRJB*v5%jolTg#)K{ zLcGn)l$xZzORwplCRMxmb)7mk6gy`q0V?d6gaA9B&2Oqa8U$@81urA#SR#?w0R%z* z4ry%pn)xLFvD{B=I!VYq)X9jsk`Az?-x&WzvWfSqZ)-6=O)#D|pe#@Zjt|5(YZ~5z z^undX!9?Fr0Ki3#gv7Rd`1yh9g3Objaq{ob&(uhfaw!Wvy;qiBP)(2-BVMh@=A%*Z z+Odg=;C+cM4rL389R*x$Fy@~${n-CLw56PCOwKkY+hw<~yv@UM0FA5oi7+R|c&+Ky zeYGYzI6Igbok8{v8_m3Vw&N)ekTHSTh#k`e?9yp|@xV33oxDkZe(j5<8rdei^GwJn zzQby6iU`_HfX)$J3saok*T}p}?kGxDuw*(XG&e~5_iTfn3xv%KEv^qVnZMVV?z~gB z{MQE8+kUVAoCrixW@**gMePl$5|zFeWyacEM{hB8{n}@`^+KWC?Z?$C1cu%^Z-&+t9K(ja>o1p&Vlhqg zO76VfaA0&6O z?@x4}!fZF?UAsg!_3c8jerzE69gj+FlhGQ%>u4(Pr}cH|^NLAL$mP}FL6^bNo*(j# zlsMb2{Uj|uslL9xWWmh0CN76&n5qfc>ustgBrT4Dy0$Uu*n8BV2kmx60=$KO6(5ha z>V15M2UQ-iUPS@qTm1Ho{F$5=9)z75`*Pm46-6UsJCur4J7i-;W}+0JUkqZ zV>RDomaj-tjRJt)D+(X z+X|)%ytaW=UVID$w{4J1!gEDOBT7}Rx-cP}M_-XcF5lsD{1IP0=|sOL{T@H9^I1Kk zxtJTG$F6CLK+e$E40(&qtVvybYSr+?$JOlbg93^YJ@NXUG`tR)zb8JwFjq||8|8Ba zCGyt?5P!F)Tc=~Osg$qdph4wxR_x-uL$AcjsfVJx#chlP)-zQmsv!{4uwx4>xG?hB zEN40_8$e(5J`2E2z?oeDLx(cKZ(> zjOJ#$7#>j-fpiHF{!Q%3u;&-uwD3}7l;sN`gtpuinfK&$^8_HCc&a+!lXN!%YjU!1cYpj-XYL1OIm8B$b8pM1A3JueAI9P^W&OtB{CZu{ z`X*!aB=4u(P|ZP^jj@Ukwye5Qjeb}ccO+j5kEj8Ou4CPv3aj>V=YtOhz;xB=vfrN~ zt{vvcb)VijeLyGR3P=Xt@n@}Ju~>jw_;Z?FBTf;E=KSs&R{>!bWv>Rx4syeFI?(=a@6QdoZQQuA29Qz@x`Jlq*ZWX_XWga&t2oEB zk&F>0>IKBX{jL^gJ-U;6r+oc3wm|Y#+gBuEL6+|=rAO1x)pxE(xFv(NPwLiAdo>{> zsWZL5>CIIIa(m04J5l;T-2SqRP$IY_x?= z@u15h&(>pS7zJt*=%auX)+|df>}5qoH@K`iUZhrECi5CyrTr!{@s9wgk~6JfGLTKQ z%W@w6>BFoKZGzC3SHxRe#FjIJ9%8Z;H0D>lQ~XTYQ7h+$?%eqrJslk#zqXNddi1%* zm8_IFoZw;tD}!2R@v8f$`zdsbz;nRQsOVgrXWEBauQh@NAII7xGQy$`hP z3`o|3hAav%PXH=?j4kj>@K4eM0#A{aM}sNu6_Jwih%$=cC^%5;{tgmaO9rQ)k#KI&I|{rrHT*Z%2kZyQMJY z`kUF6MyduZqANDSa9BW}TT)060?`sm{+IdmLj{4a|0{k;?ToTm-TLAg1~~f~(6Hcy zWruay#er8oVWAH8#`mBQ3?ic;5^4$Osr7M=6$-^1b5TDx5YVrp#DHsoqF<}Wy_wq> zSgzKyew_cL!SE~H($KpSk82ofi*?yo;*XhU`-SYdEm?7gCy^gMfMs{J>PK^g4NYEP z5CX_j>BQ+jjW=B#ZmH~3D^UA~RkO#bcVaOdv(u-XPifD+DfM6k;o^^b%(^b)HGqrW zu|u*x(;K8lz6Z#LrRhx*{>UmV`p|hPU#8gWEnR*XgEwBBgAryp&)^mM$Lq*80$X*@}(H=XKZ({0P~u zJ^u5aIkZue4@tuw>Rzmg5n4ikbfRLwUdzlGMv7XFvZdBx>(m*l2_Yi>ia!sp`k<{= z&Yoz1x|->|1$RJJr4%?C1D9_+uEPnQj{#S&<%t55f&zO)`5Ii^+(tAk{%vf~hRdu( zFPoqh!Qj;weOgWkwVVj|ZJ3;#H1Hd&f=z1i*b0gO+AReSvc&%t%OTGHejTsy`~}oK zS2*rqxZ!W+NT}GFl{c!whVytCO}O8G4m!*ig`D*IT6;&(FLCJnH#`bBFqMJ9 z^y@=oPzW!MOdTl$tqj5+qxZ#>!S4T+tnB5^0@Mm+{B&VTPBFW)%jS%#(;9B4QyBEI z{V#z~+}WYXttr!wDmN8|pDzjjT9H06HWntUzMKk&pz|v0l9j@bAjxkHRQi&~hiirj zvMd!*AX-t7*0^J7 z-wPi9PHpdE1$Cc{aGRNu{D}O`)rf~yggwkY2tbE|)^+hWwBPw?|Ef@*0LVMdWzu+{ zJ+JS)-%h$C{-8ebCNCwWvOT|O^{-cAi1v|OGf1q5EudVB+R-T_9gc*UuwSz2U&*MD z#OfYt+n>qM-#U8z9yFA6q!`F%472PSujX&B7i*qsx*(%YAhPU`;(qrX_i}FI-EuYj zdg;8g#zkipROD5dUoK*`qB$RrfMR`9W2@-K*@fCoWi-|3b!;Y{BQgE&Y#T*9mn{zR z*w+Wmz_#<(#x)u^6BGW5JeuFLVS{l{)sxktMgZJHO-~OGk@I+V2nY*5CaMuT|0=pQ zbz-Zli#bj;`_sZZ9>aOO=`iy=0vT<%(6OByzWxDxt%vT(+5T)U`z{!yg-n?FzqAvG$+F(-8&QP|c_rdNh7Y-)ff|Fd|NuiraB*tT?n@JCWpTQv> z?e<3qdA$FQl#4D`A6BRj*0y-p2EV>fR zi)#%@osQa`D17|*aRstsPFwn=Q5Gko(akB7;UzFWw|L#$imR_ePf>=FH5+@bKG==1 zE#Mt~rF=oi>-}-c+T%+N#UMznT51O1(}Am@cN{=f@TH~0KhJ;RbfG@8#R!(tfQBcf z23$MVP0#8MzJ7Rc4-Xd)OW^x&1=|rV5bZEPG^S~XBFjiUlAGB}$o0nk73A@*eESKo zz!7V$%90S^G;VU{yjeMTG8dFZjqv#lfpqTNsT0?9xWOG4510gF4Mm`rKy7N}V-%}# zplQ{guI_PT?@0(-I?`U!tY>WHR^AgeGv4E2$|!fiYXl&6$zJSq;cnn+*rC|5*n>>D zJIafJFH3%t@}}SoXHn%;_o! zaZtfUr@Rt)7YzGp2zSQ#AFm!sf1l4mv)Q%g#9D(5jz$~i)8dMb%2IDvNQwtysN~^+ zUR+?I^#l{MfK{DFz}W*Gt- z;T)tfg_`t}Oi1=na-Rdhf&bFJN36oI8IHm7c)7h6d3=n zkxp$#&~}_`RmA|mo?Xn2xs(^&cf>Z3`GCJx;zl3_a+x?VP-tD;0Zph0=3ZQ;X6< z{uu$-O_#C!r>6@ps&_Kbpc+zI$T|YYnkx^X5Z(HRYNQG!CAlYV1^7IBPbSI(t^gW; zY(>~u$i`PP^HQ6gX4=SD&;d-d1u)ak9)w(yYeH(y@8#wO!2kv!q#yh)RJp4jP1q*> zz^i=5F|W8deampQYEj{W!JHlw&H}g9JZ}tqkz4#ZgMC4dqvA}U#OejmAWk2EZDkuI z5O!qa7ARLM>rzmbw;y#_&HwTn1azAB2FQg-ueQg7cX_n8;Fwy%g<(ei0ge`?=yK{z zf&Ihw!1dC_C5m@kZRG_d8N%k4?}Ur2K-CwjhDUfVCRKQp4Qchr`g57P+gw%||Ir3; z+JZhppH)kbuW=8n3I2c(`{d0f#t$BTgPZ03m6~codt{Bw?UiREGrmWimIqg{a zIQja}8Ac5F^*4+C9<&BB@qOzv;j`53TMc?)QED7h^l2f`{VY`=3u8EsGGZ@;@DcL1 zM+|-H-W9q2JGVIHl3RLg-Ok}=9|pelbw#s{4%QkSB>Rkxj)olBcuXwEEWmk0bA@C8 zI5s(Kv0jL#MK3C|oVtB@>g7eC9|dfD``IC^tnb#!VS+TXY}jAG5Qbbj=Ut1stQ&eD zxj7(vCm`NH;o1@}E=G+uQUaQrhvHxK9qu9edtx!n_|kNvcZTQr2H((&k^noH%tXY6 z6@@XDoC1sWfE7>*k{b{M?ZGO$qp3?vcLt7kE2;yuCh8bRuBU_2>Xgx>rbqX~tVKJF z4=Yzu@a+~cnq7D=u9EG?eqLEt|fc3;}8d{Y&Fdq(&TqL-CR{D zjTsma20HFDb-cmHInk?7JH6;?`X$gB`%Q-3wV>&iP3jIsynz8hiL9GFt}D9uO91U| z3xvb@oS@u@ym|bFVMY@88RQD!KaZrI_d0{|#P?$|Fry5Tp|-hM+d84k5W2LFUwU@s7W1`m@PJO%fk zglg3mek)bnHUx?Xwlbgg>l{e?kX|^Q*mCJxK#@I@X{m9aN7@l*(rRpZ1$;o<%`nCQ z0;nB;GXz6)EQtJpYVTH{ABj}kfT7-KKAX+)21~OgS-`S2wS9RA2&Jk^gmx^b8jsChyUVY@78YVCPZX#YuWuxIOo zg{ulmO_7Ey_!pISGWS@uKS^cJxW!X~r-e&h8H!#=KW}b;9a7zn(Av(2Ql=Hy2N(eJ z0No>cSEK(6=VSSnN32w82;q20Zu80Kv0o_dH(CtQl?NM&q_6OBePp7KXqp0?Aeker zkpDeHn|gL1kf|7JX?O_1$UpvgpOQGV&_OHjNqblC$4~HQ1XwUGAqO&n5A~(FG1gbm z1B#ntv?Ifguy_=n6~q;pHXRuYmWNwcMeh#1Aj&Rac1K^uvgPBXF;9ha>QM8rD-XlR z2z=TBuNa@b3dbmL;7LPL zhk;6Sa!ShX5#JMboPHt%a5(`ZGCw;!)x!>XT&g~DXR*h)?A$@KIwqAPM-8KT%TqVeZJ3Tn&0ISEzShb+Lfh4G@nQ~Ri!Yc66CjDQ1wNJ_d5Dab zDnJD{if*t#Zh($P&uG8Nqpm2(fq6LZx$FAZc5zHq5>fm3Ya{Kl{bdOBif#3O-rEoh z>!2oOKK$=N+MoST972Rzo32~4QY(32EaU(rCkST&j^%u)I_*VC1G)?M zL#HDWMc1xfo6z$xzK5qPj^c(bW`;JoCsAm1F33{;BW6Zd{l>IJp|^s#y!fiH=$$#( z=WK>PyYRGcS6`|q0aBg(fbVu4{M-*@4TDh&6~m@^q&tY=<)8Qu|57T>?I=M)$@Oo% z&&Xn1`?c++?KEr@8LGSk_Q(gIUeLFBH2)~VG8uGS69d}c3vC- z<{50>5v6_-QM2gg#^^bG{o7pR22n-U7sDg?{FsMb+2nS8{aqZn4qp;n@v5FMyGuyL zY@zi}k41v!Fk@f1dGaoLqIYRGWhs2_Ye;gjAt9OZ$pZVcS0Z8}l&ox-MET7*-|iMs z0=#lG7n=z@LifS3_~68HP_tI?TUN4wt~k))xw@)?J9Eu^cbzM9Mi@A^obLI*`W<`a z)?r;rH3bIZ0B!vGE)JJ&^|G$35QVDywMX=;d)Jg<7o&Uz3=<$|g-;lwIm+o{b9t}B z7KQbzY651K;KErKGQTNbuR=SHoI5Fn#O7 zREEuARy6S3bmL;o9*%f ziDCIxtW2;txMd0uU~vEtOiASQbuKgm7VLD_aDosJrlJ7*a|4BUA8Fa%94JYeS3_{^ z44xIi1mn3tszXn`&1B1VFPynQ5L3ZaE1P0)X7>jufVlnChe{;gkz;jhlGK0nh+-+# zc!?vQF$%hHgY#11&tW&)lgw~OA6YPSqr^tc=Nwk#_p{=Ud z4leiP@5=%SvYe3bd{C?r$kkzfu0rOw=@J@`>fYWq{ILcF98v6_SM~}#Vc8H#L3E=3 zjPrbX66fE$2I;>Pw*pKB?t>g+kz=OiB6i83lB}S5U?k_R0+ju*_wPfC#K)}9t+9)7 zM&GS$_HGByF?OxXJpooqPfF@uOYZm$pt%jsA4=be2f{NL8#i)W`s%!WcDlB|oyl?0 zJp^pfr*7I_tv!`5$T`T#1xAimyt3{w@H5aIwyKN2d`xrRBi886j#jUv@(V%`+~5N1 z0%QqnSRED@j?=JX9PVXPEQeY|4YTv5;Y1HRw~r9LGf@e$73<-m#a0u-1Pp$=YCpTE z5{qXQ9I#@7Fm@%P|LvBc$LX1&fE+>5T(9`uSkX6`<1vbm%YcV^ z-K3eNYHE36JS(+L>>lGtt{+`KviSbwa`0q;a4CG)KJ8Dygac;Isb34iNm_r9|BQY*kzrWo*X0;y$VOB2zY0#m*hMX_H(Z?6tGk9HO`pE;HrM4b)-939f-0Y!nojjv7v&VGsDy z&B}PIquJIS@{W>@Ss?oe7>yK_nwUZX%w6SEq=uwplR}NlD(nJ|2-Cw>+{x2t?8Td# zpD^P|#$zB3P;a|g;om+!NLJO(_7w2$-om0L{nZw};b`}`rfI2NH zsJB15z53hmjaBR*ALzLl^dnq6JL!P%4{ih)--3zV(sNTNFsWwkC2IFz4RJ(}$>Iat z4e%11RJP#9?pN|7E4L?|LBCwXc*Qu06bos|a;F$pLg$(R8E$?kYE^#SySxo?)OnNNivN5F z9(cbRww87j|7b3qg(1h?bZa$sm{`4RF8m?Ssld7F20*BXTON8)Z;3_H)dl53d_Mkb z9qj4P(|*(XF|^Qq0>3;bg)w7H9|V|)hgPlF)b4VO)n)sW0x}E_#s}&S_yhOK20Sg) z`&np3>xf?_f>{=LZq0ZUOObs*t47im=H`rOE&q=oXYz`zA)fQm`?srGwE-Aavr_L* z#p+`ZH-}Z=Q`beuqXBV*G&xfr2Eba7)R*~m3q@uUYr3^4z5&Awv4O;L1H(i6n(*eA zh}qnz+#cr zH}7Se__|reRV{wgsvU@_uQ>f7{PE*+JXn1Cf#`ea)wBeBVE;4?cG!^_Z+h7Nkayyg zz3Q1SL=hf#T8YZ_+8VcxWPM?67Hox413)9&I;`#DL^RA!Yw5*ll#PBR>fIz^L3&DE z>WTI0Vl{DYhW&KN-+0@6&s8l!XZ4`Te&C0|>6ZCaK!Iat7jt%Jt60PIqJuN|@D-VE z0}a!m$A{&Y{Lb+F)7k|yiuU2inV;PaUnS5HxVHbf_l3r|nf@|{?f_zo+^R?F)8?5ilff|@hu+)dzZ0=3;?dJ3K<)LK{Qd;ueCgT~YRq9b-`+Z{A z7ES7ZYmiH8kVW^N;iaxK7MQ{#S`Z!Z$-l-k4xlO5pF6P!mZwlKw}O%~T>J6kiG^hB z`?aZd_~F~8OiGSPN0q;9sXn+ua zBNp038oU$S{9xPaCu`JzAA$zkxAAXR4#Ngpa@*1sm|EopVhEUMZCzFvAlsiG`)ci) zz|`K1Mw}?n-g&gQ6UOgCLaW1T$Jb0hB#_Za2NL~XoY9r!48i_~1U!sXQECLngdd)H z0%}#O`nKNpnxvxtM#8yOmlBBn&eORMdeR|)ogeVm9tu6ZTVpp%IG^}?Q2G2Ta&nIC z??`mCtB>{pytrun_lEs%$}hk2v}0J9+z&3`K-r-%mtU$T5sJ+khbXA_ zt4UiP#&lm_>Z9E?c6xMtGS{Ck&M*Aj49n0tSe*$^6n$*3`DhkxyvEAOE(nLkykXTp zcytsFJt;#WL+AN9J-a+&yg_PyUY&w`PYU?f0dW(R-8-L;P=+f&T!>Oz5-eRIFe_4P*C4pT!AOTir6ugP%3@{LphRPnkMI?TgDPSpc1@2PIL-oyBrsE3{fKnNTpy zs*K&Sc(B92Yk2O%eum;{Y~`lBns?3BAJRkbf~Foyh`rlfyqW1q%+3FHx1Y;G<`Yi8 z{_9a3hJcJ}&sTkB;XbC`F4;!6Gxn-oImia)9`8`716fx#g zR49rS8WtO}d{3{=iu?E?9}#;i*?XL}vBP;g7-`c4uXUl@&9~DYuX@wkI-UHmhk<&+ z0Ib+iL`?IF)Im2XpeO50&_Z(+6GJiY&HJm}SDmyuYK{A9+Ga4pE6i=?ZIc;Ujicg9Mhuhk$2Vu@X$ix< zB=YR(zupu%dpGhXSb0Fc9!J#A;b|^WREnr)EaCwOA2D-9%gr&opNuw?M{O`2&>UcR zzl=w8KLxj`&Ik$oCPs*2dno`Sy)p{n0D=xS5L6tTpPw%ozWytbU^CW@pJQ$t5!;Gz z{tgz~d)s4hO}w8*FY-UILR+!$U7rDYg9LGfjsIxSDR~aeL6%x4>{O-g^=c# zxT|dH<)#W*0FLbOnJBvSwfs`N`Y@B-nQX~vc7?3eD&>}iJNqTDgJj>yNEo=UeGPmYRe6QBxGjA1_)xo) zOT_)zM;p#Xel$m~BJSqNd;gw(J7g2=Oa4(q)P$LlaO*xi+rS7Yqbw@Gqw@xN!oXdW z1>6VWifYrF+phJ|?1jY|ew#A+is@Hrc1*-47hXXF#Ny2!Sok5&{%9eJ2rv87T#%6l zDF?jP1a7#1sYjbx+j$n>0_+qeFL%6FyvQP_oSl%`@@~pUzH?QR*f?*)xT^uwD~x1& z(zulQDG#vNYRcz3cgvXiX|1X_@dYaLWBM1yRkn0JQvpqFjfsLOY2;$1q`Zo7kT}ar zG^8goQO!B{gc=Vo26Y1zBAFY)m6r_jNRo)6hTOq_nWuYhfF+YBAhB-Oq6o?9w ze5+1Wqli-kbm{zg6UU@vT|R!Ezk9p}#8d|1i*|MdswbAkK?I`L?9Q@tq0&biu^i*?-Td_L1#(w+H{f#9*_Aqnx40wG3n6)|D z;x00gIi4A7YYqkm1IBlYW>rn0ntwm@h7k)eh;Lu#&-6raisSl_PVN|6SjUIUDf8D=7*4$K`4oZcSrdP^k@<{<$}uQIS1yFaR)kvd^bj9d=J z0@fqEhK^Nvb{6XQ_VRv0OxWBcy|7h?j^8xAs?Gv75i2PlM%5m}?I8;K6SO~gVh%Vq z3rA2QO@fJb!vfEp=5)&N=LUI*9^CC0{rZD6wL_trY1VH6`VTUcker=YmkDG2c{G^g zXuw@h(0*NbNpWrlp5Or+RQBE6Y-64hAY_-ZdYcH0BU|3;{c7^CHT=UoEEJmS%g>`H zU-soszmY7wBK24EZNM7Zz;~Q+GxgJa(EP)R9ws?cfV%w#8Xo?N2V+`|nDlYLQF7~L znHG`z;etSBtsKAC`6L(Z)*(f|Lv{`V{EPs`?GQzm3mK3!9}2<=_6+`oF;MV10#)f! zQpMaE(@mmAYiV8YSuhtMaS{2c?!QNO;5+#|H_+r1O9sv&Y}xAf+bd}(rG@P19aPz} ziJ=m5W1=7^ggBsk{Y*K6e}RpyWkvIcKqg{>{<%#^R4r0MfSEpQ1V#u-;_owjkaE_C zZ4r4G%+ZQT1+nf|JBRXbs~|bpPSnsd^Ho0H1_&c($HDhj+fd@PXWOxI;TRJ=pc;Qk>gE}z zAI#pKy}kNpz{)eq&}%^@o7hM2m>MqCxJG4v$(F*#KvnmERu?!qu<=%*!kehhuCC=? zy4wIaOemI$1!S#=4u=_~h1gR>g>07z>yiML2n&=M?y@T&@JrR0Trr^vF$Gn5Rpz%V z((?`Aobaf|GYLn1_xolT@oYmaqQKI{obML2(7!bj@tp-&be9{@NoM{n_!qin2Ppy4 zXgNZ8zmZy6s3=o*sgbcM9{hNT?z9aw=dxcOZpMHN8!Xk?I`H*rb@bvlTD4b~;6j(R zGfzd00;%cBK^9vu@5OVr+~f7c*smY2ZqqaOd?6^IX0KLvXt=%fZ(@QLrhoRY-p)f0 z3@C%N4VMDUQmKEiT!)1Lw3f%Es8l=o&t^;*oqqg)cPT%?{P@&+Nx38Ua=TwSkX|)G zPk%52oA*Unr@{Cl9vIF1gRmYUuyUeyYdFdYd^ida?YwKg>4aA29cuJGV)r(UHPG;$ zG%z4=w1yVsz_XmV`&IYvF;Xu;5QI@xKoBgtk=A=jlV^5zR)y3`g9mkhn8BzhJoG~D z1@xe!MyMWLHwBg~UrY#r{eI`}MDN&JcxVJ)y(=#Cv}T-Prwc<%n!thuP}>Q>Mm z!QLc+6;QRcfcr0bgpvgMYV?`3UR+>#YA!d!J;1*DhY6zRtv&mAwV}Q_miH6!ic>7f zq1o{f%Zj#NVBIlnI%PhI&=Yd3L(??yO^wvay?N(Ri&!wHLf;t%COWS~VoJ5u=B^`I z@(+Ri+z_WnvS(veN`E{UyKOQ$dW`V__C-qVIUlM*@X2NidUnkvtF%r44tkO(&Nx zIcI%mPU*G!p=UEgWryGx1Utq-P{n}Ei6_RFM}3w8$^bPbiYT%)>k1IcO;TbBEdc)* zK*uPjlZ!OLXRLaH)0p8AHY3auLJKfB9g+5TQ$3lDfwyH67^^+S;Q2Jr8nOG6W06>!HVht($pKC^IIL(WMr}P9f68K%~A}6ktueA z{$Cxt7Tu^U9>wMjn#=)xp8`{R-=y3BlQH6nYI&W~WSH>x6k1Dp6q(DV53pfaR|__rKTK0$1iVxk@m2U zr82lmKYVLww41D=l9E8rVtDbj+a#EQCUCUFp&-p<##=VsYq-vb1xZgH>UC3?9M~183vwd-DIN@jhX%xuWZc_b1A)sF{m6gtb~c}-wqZ(+HOjE3fH-% zeKdH{47|1&UUHg(DGyU)X%oYlWyw#H(V9_s1dS9_bJa&sr#{+^(el3rdb{AiLX*To zN=dDDM9<<-YP2v_7QP(7<5yoEm$ICpNF?iD0E+T09={J@B_@Hsfwiaf?6vt_FVVXX zFmeevi~$FwCcW%$aA;c(*rPNMt?!q48#M>NIe1<9-^pi@g^*K3zMQQi$bIpbVA^b6(j>N9&oF5kUx^qb_CBV2j8rc5J?qP=%7hWo{9szKhW3TLb+K zV#&Dx{r3JHui5|X^agNhS&?NLOr3+LHzV$Z^&inrVkJKVfe-Qsw>;{@Ea;-0-y2+` z-h7#70Wq?uJ)o^imv*_o0lc#TUK0dpiBiWYSZcc{Ow5-7)p&{Q9#5o;_E}RdrR zT}NHApGYm7XRRfG^PnkAtz`>5^SGj1>oQv3$bj}CSNYn)q8~srRR9Y&i>j^X`0z=oAClfq+ezulO11$eDrxI1q-fM_7@7D z7u_RQ)1J5VCVEEf$l;wj@T*;2#{r91|}mUjFO2XL%^^E`zl*DeP;(`mpqi zb%IIF5bO$86g_zySkILWP}#ZNdzR0f)vW*7+iM>0+w#J7?vJk&_-yJDZFP@`(3RqR zq?>;L_UJz+U&rm&-AZ5hu~U;Pa<2x)_USpz@Y6?c{QV9RZMk1fQsRP& zYw}*{zAHjyzFOmzS0t01{3y^M%O=yYQ1A7t!Xl4bTenr0H@|NV+3;B;pXmE(Pvk|3 z@6TR*kv=DJB(mDcsf;#!F|7I?PI{qUb+}s;A8Gx`a;V#_XNFus_9v3N-RwRFat8V- zKz>u;swcY}oe3_Vrl*69D|WW+8z^A+QJ@)?I-C&p>dc$}IscQX-QZsuuG|#=Hz8ON zEslJy*_M;}wf5I8G9AL_P;dj%qGW{~lrdR) zf%>eE09%ht4;;9X_4@OpdcsdF(Va;Yl6rLoIuZWx1&=Cwq+57DiqEKifc)GdpM_Ni z6HfwOTsda^#fanl4)hpL!?TSIoA;(vnS5VWG<3T{G8?#^XBt^Ct!~@!n$(p}yYxND z%}ZEdG&8uL)(sebMc-sY0eI6IVFxh<3jZs_y4M=q1NL7&X)Nzl@5D2m!3%1^*{#e{ zM%YdRp;0dgbraV^4+Rg7(sUA4l+CCQt+niD(qi{hXqLqKK8c4y>K+~!;}owy!+4)l z8~(1$5~x8d4yOYy7t+n=M_)P9+k9GkQpxFy`>F{9qIa#_MEb~SCgA%KtM898sq-NM zo#iQ3Av8k-PQPNd^s|%KlZBZ9QW=s7*}_JkC7*jF)!qF-C|2YGNB)KLDmFiMy8bx# z`ZtRN!T1DxL-siKd@=1U1`}}=ED!%)K`x3d{e{va;i;Cz%FmVEtj-PZQ@mh(Rl0hW zhC{c|Gd9VWOM&EfqGMi11*n}2+_K>rEAsnzHgTQL;%g?Rny`Tyz^=HAe< zNIkhur{iybjr?9a5FZg%-SGId>ozUMW3zGA-0H2rvK^(G$W=jGh<=5bIZc7OOn96U9)k73BdZe=5)||)LTr$XdYtKO7wc6 z60?e%QkJJ_~V4-ij*}vtC-7wlh5;%8G(a;-Hi5q z>yA4cayEqN?S9q6R?6puxkDr0wyvU%AB{9>OQ-56^^r)O)@pn~AH14O`qb^+Th&{I zh`vOm6xCPf2$Gp`03YMA!&@%Z-BTI3nX4R5Pt2F<|6MC8%z@_7G&?dqbU`+}VzMZf(nR}cEZpfq-qe36 z!sl_RinUv*t4hAB^re251QoYiQ0d8)J60>F&-cA>R^kyejfN0g&HoBts~goqAk^A| zn?j10r+OaB`lE7r%|eke(q*!jj!mC(o8kCgS2MUf;==T1Q5Kc_dNUbZYbUUB{`?CU zEEk?XxyFlN{S62DSNLLf6IH<)w=FSde`!6HP1AH6*_D&P0wS?PbC;Fe-Cn;4P@5?xG3nOA%t(#j{O zklxUo1D2)oymWNxw$r@a9YVLO(6TZzGY5{WRnxlJivN6o^%dg;xczkA02SgxU%hgk zTpM_0*U4Rsxg?MeT?YQ<35GKewK%$che&GQ72?hUon>r)1X4shY|O4=D#`y3%3NPR zer8m^=GT|VwyfN`E5-}nTRyRdE0;%T)PDVG!T|g%Ihwe0@@M6lsw$_;3EuRdW+>P1 zi(mb>UccAmZx#`%5*2_8T~oo9w1f|#X)bq7hpT@una19g(6S@o&vi20E|Aqa?y_?) z=+_7j?$wZVl{m*pGXV`P1sE{=3?I9WKlk5OFxV<}DNa$L-giQI8rQ;^wA4e!TJ+;| zk$#jE8gFB|wnaX>#J9dqi}PHp9uy2M0Be}79R%UaVKZr13);UZwzyhq!y!2swg!EK z#{8SH#!JVeiCY!}-ud71)FJO%ZrM8UA2FaYor=0n!gE`psLMSSn)CSrSkYn=O}v`c=GDXBHo-goZLh#;{G%sR=-5M3Ne5D`qYFSFJKd|Y^?cpM{m;(d zy5t~up=On)t?~@cAnc*fGUWkFBk6|wVr&ys;Gvmru(ge%>{UzsXjVN5nW;o+S!g3K&RHfGlH> zNp8f6r+jZGg3lN4`!2J9`n0aLRy(OeW{G@k8+FqGiuL5Nj@bS-{F1+Z^8SH%`-?G7 z7eiAGSVX6L1;H~YO#yG{^RB7>s0KWD=d+C_Uo_9L+~!>gzb9*ihTdcUK`H9*+?iVu z@6i`ECIzDaUK7KH_CDFjIs@Y^}gp8h&& z{(@83!P31f*L2ItU4d1)1IjJGg`Ag)!O{iDPfT9}gk5CPvY3-+O zn(W>jQ!(=DxxDQb=fW4i-MSOJSbT^8srELAdlg)kn_Fej9^UL1E>J&-YQ6=0Yfd zP=aF;mY*5O)4Ka~3a#^IhM!uv;1kqCQX9b zoA25+6)q{H@=WrXBvTVh!FA}pPdB{wIUt4_ut$1I1@8VX+U7q-`#oq~JO05rwA}a3 zwq>nWQm)nDD^m8p#P|=&=R`DiF{xy*9G|-&)`AQ!_EA4(m=~=t)Voy;w-*)u@xBGIJQg5Q$Mr%XGIRsj@k{0KyFjyp5T{Mr~9^Y5>Yr4su7$KGe4RAO*vwSQx7ivyRwzU(Sx$jY0h)M&8`3#}to(x%u>| zZ2_tefhsEPO`Sz5$Yty?bJt_WlWX6BCHKoimen20LFKMB1xbdH#fayJEY6tR{&_#o zhFUH&r~dU7%4#1uQsH9RB!zIwbB@E;@!UmLg$Gdwxr21K;T_jSOAgN$eis?LHNoRX z;lWqjRDgsX*u5w0>)*VP2uw-SiTKuY$I!u`z@db#-~3Pq;b&Xd(H~oh*gxe@O;3D` zH>yy+?oiEWrNX)VdYfKZ36RK_o-+4mTN`W{qBF&Oj%_vIOMdcQp1I~;v6v>*UosG$ z{gqro09gWYd9rb!JyV^3Vw3zCPjZk-b%jmsvudJ+=%Ncqb+YB$B25BcGv{7mBv$SQ zXZ`hO{OI7vxMH5kbwZt6PON9P)pUiK|6{KX|Pu(q9 zZZW>8@BHBvO+a=IWfSx%B4En-Y1he*)OPAWeirOl;6-519w>L%6^c!~z>%ZE@$%kj z9*NW)Q&xZq!!O;M$8RyQmjYU-J2r0$iWSj#9nn;bEr;QJjbj`py| zULZx4$LQ{;hC^EoDRU;fTs*}y?EZgE@b>$%=gd;>cGSPX3U+_D$~FAT{O_d zS%}O$_ik&G4c>(M{kCKw$2i5_x8NH&rtd0sleIm*zTSJ}g4wpV3BK|4y^<_;3u~#! zN1Xn?_kcZcsy8aCVNy%uzzgvkt4d4wc^VENJGK0x9jWAUAnHkz=&G@Ke#Q5!Lo-uuT%HV~a!BobKplH#=uwt-)XzCUjxfr4@=p^uY{kOIS zby}Oy02~?%Gx;~soaTdPU@!99jYJEci%tlV!g%XkOgL8EeFXtq6-(xYJIh^`wxt@0 zKfvB2aA8*?@oXTA_DuZ-G325HTJMBO*|%F__Pr%TZ?b*Im7%qi$efFIPu0awLu%U50fL71~8+h|LK|F}h6 zp>m@Apu#VfSscKJd&qh0>iJs9)1exBcTGKuYLInP+P_DCk3JKdT<;9(jl1s3>l;Me z`b`QQx&*KbA9Q3XCYE^F9sj&b?u#YpHPQPicP_zs((9-Ol)&s(wcmT6Y?EL8IJ6+J zCiDLFg(3YnP3;iJecSsD@qTA6#>#*3Geyi4mOU!_XD3}$D^430+ZQhPXn}XX9{pnd z>4E#4(CLvY+f!A$tDd)m*@Aj?Vkf9dj>Pz=Gla47%>tol^-N2U4}{|Uc%b*OtLK4J zlyabATd!ta-?n}DieM}3;+MX8RRKat&9mO=<6DB5uZjMzO=(eP*&GMiqaWka_xN5& z8t1!uh&kX6s(Lxouby1; z?7dgs>t1WWiwaeLM1fSeIWobCno}cVW95U^I9f902@qBe<(Pbt`MhtlmVKk8j=RhC zad1VE)8F_T3jUUQ=@6P;?Zz)TQxwQ6xI7A+W-)JH{{Bz?sbB%V%;Q|q+0jwG%WyrR ztPqfw2!eSb%}CZn_yqO1&fgnNxk>0Php&rw`63eFAb+eM!W0&6Eu5?f+7A%0Q!{Gh zA0(BxuegA4EDh88gA7wi88u%iT_xM`H`O7Y-@yz89FZY_Co}oCJAaNdmtOjet=~lT z0pGAfZcAQMTSSI%T`#H^&G9ws?CD7$YLa01CfXo+vM$K12&qL3w{`GVE+BKdzNbX? zhWDNT39%PIFh%xJ@y@#qstLzWAo11T?`|>%{RE`f7k(LT^9nT zCGJS&+e%_2dV$zyD$sb4KTi6R^{AvIvqQi0p4WMdgE6Q-;2Y%-}k}F$GAqhw~D{8oTpeA*s_9Qh2{myAImhc;ya-t z`&(npNK)R@-}oB%{(E#ZTj3oAXU17^tE1IuGC%*rG0i-E0yC%zL8q5dua~*8gA)7% z0$VUVlQb33w{6CTs&pUym+kez63*~Vak{;vyII)m^HR}*h%Z*_9FZkF2 z1g?YJf&6Q&Qzio8w)jGk$HPP^NurNV=$oigsI>8acS;qF^x;I2MkUHJst~*1R+#<= z?x6wK!Ij57nWH@N0@798utJOZO$8J4VQH0$otzLRC zzoJZPJaSs0mFZ>inZ!i38DSiy20TU_6eE_B+363=<=Gw+PW_$N9VMj`<-@@sfr_)X zHp-5!e_8*R)$vCrQf)~O1y+Yb<%G=EMp*c}@OLLV#!&%&3B@^n`9;u}1!1PPnBnrU z*R5Z}H^$9b^8SihI1-UPT*5)p^vp}Lk@COTNaYCwt{$5<#x&@-^uvlA=BMiI-+y$x zCo%sqErHTmjOYI;d^AmiU4icd`k?AidA$8hh10Lc!^Tfu3PC@i{SM>ZH_m=kLKRvk zZRn<#xIAZm)5mA;Ntm0L<^SXpDenn^)m2utqCiUA95LfWoxZIqDEW_k6lW+_Ramb9 zx4!HtP-`tEex0Y>tGK>&szPD8T4pt-!oT9b!p3_UPP?ML<)Xy&Qg&n<_)hBYsWjh7 z#z~Zp6#)h(vIdTQ>ueb?y~1j6ug$fZ3H!<`@0H?Ka!uOld+7i3+#vu%n-Nv-JFnn+ zgi340o%VkcjQ1A+eH#Lx{Utkai;`)}qaj!Ibv-%Q^2ht`nhN7;Zp;5n79$w%K$oxR z@4DD9@eb64HwE0druYU67;wabi!|Yx0T(%Vi_m*QF*yk2%l*6Bx!eEGvZXgjyLzoV zN5{%Cwh?b>lM{-_Gs-g_-=;q@5SX=>IZPYKH{KW9Zk_w-yU;LYyPsHYGT9tQ4g$GW zl2<3^aqwT&WtD&8Jh=D8goxc!8^4)i-2sSXw}9yoar#w6B0E2)wjAwl(56FwnsD}R z4QHB!{IX%>$ymOF%aBG9nigwG{SyGZ0v(bP6dbsJiSIwjp$fco9D%70K-!eHB;Nh# z&;CDP+adRcd~*u2IFnYQ*yVhDd{B`RNrrE+gCq|1fw8=@3?swXLoC9H5@6A}H_&J` zHN1^wI@LiT7Q(-Ryfx#OyJwm1C;FY23I$;PMM7u8s4F>&~ zUhbUPEiiSlWzTr+H-%+7QdNVS-M%ceNc+1BraFS~2l$d>t=DkY7Ec~q>3@U2@kVJ^ zz4Zbo!)+ITCV-KrJz3l$tup4oa#*Epfqp@dX}fR#&$g+l-HQOtx4ypJ9(&zZHz`6Q zRJP-Pj?G9#VH&T?jF{tJyjEq-J+&`oMWo$-k68_d68BxQm*lHKKHLkt%S5BUQ^Q_q zM{1j-d_i3Q(;imSrRB$zUA@p>vixjz?1!-LWxGGkA ziS#GDHMhKV>O<@=vipu6_fatmgCvai8?BwXUEqJ-mL0E zQ%1d#O}RzvZp0)Mk#ytB3Amo33)MU2aC9zJmrT9!XnN-UMV?*LI-+4V0@hN9G?y5| z)IPN@VWi-WrOmi|CFB{Q^|PS;EFzoG?D>JWX&Hil$_9+J+BSOoeq7((ob&3dE-V%z z6o#9Iz?x#X0~z*~c9#G2RC60RFO-)0wse)zFPCK&9)BA$pJuCoiQMmE#u@M7C#v1} zpWkccV;?m7-~=I5dhXoOgN){-q?2{684_?v$dQh75t1a zK<+kX2)^lU?_Fj4*m-%>sFK^*;YgtpNQ}%HPj*HkpMbT@$8_h8xNA|prqR&Jd z<>5q8o%q8KXQAWK@#dDzYcdJm`?)yygLH9swHN@!3?BkFkxUaB+!afNknmpUV_(;c zr+t2Iqc3eoQ83v|3(=5$CfDr8vtI*eL8MwNR$up*t#2o^QB$TszLgzm29AZ?vS3Er z#qC6f#~Xnb?fEl*Z8GmMWGnp@T06YPg@R~F{cVGg}eoV zk#i>TrCPsTZkT5-rB&qOu2}W4IhWoBumi{4CXqmP*&mC~rIX4NpmpVMy5XjRcQy}A>zwP7Jjmazy~9G3XM#vooDD` z)cW@wXk~{ZrT>aNN5Zk|-AQr=g+zVNMp~1Ock;4|D>}nONQEGE7Z1sY}L3gN*n3qk*QFlx+DK{a(rwBVN_&_Rsxz-}XwZ z6gy~M=^@M9j7A{8H!hTzZW$Dp8vzJ?HRPlX#dCYcRpsX;` zJ>WRvBdbC81RCtR>@qnhDNG|D5r`zn;?tbOp}?oWRPWVVx11RhPX@4j-E>+q1*nyj zQm1Z|Mg$dF7;RL#)jxB|F!mbg?k!JCdrJr__bjR}dLNQ!HPKP>XGSHSHuKkCGHX1- z6BQ<#Lc_GQSXjcj5zqSg{0neRhWQZ+{>8Nboo5habVbp^1R!>JkGQUa$@fK~Q zVm2FPf^h)<@%B<+Kw33aaP;`U^tMf)!L$fKRi=$(yM4``+-N9&GiRaF&oyqZE8~@{ zm$f>m_T_lP(KoVT4k28ySmu^+tX}gSB2QuzNUImRs52iHWc>erF$4wRY@<0@ zlT({BF9reMs$|AK=fy|$v|Fa+%;6Ifn%f>_3;ouq_rK2kp0)|tfBiboFE{6{7OWxu zLVU46O`us2v$b;WdCqw;8HrkKI?WM;jP6q1TBng=3_@o{bzCQv)nPkJ`}49&E|qZI z5fQZzq)XB+WO;(j!SfRIAlOv#o@0O#-wlZk34-w&G@-Ef<#?fChVmUT;}6y1`Hs4c zqITwPUIK!4FU%Av>HxOysO&Ua(_iS?ligbBd^j@#{er+-cUl`Sof8+dDH9WV)83`M zdwjJ1$ooJm>+XtVoAP~gj+sm}ldWag8yPmPyCWAz)bgBQya9bXdHdl(tT&AT#Xmq2 zu&mqFo@xaw6i8#P=m< z;86rBlYOIjRj2!M#cNE;K8Uh8l#~Ip^|kJaBubJM9xdpwI%OBwZJS_Xv>DnfuDXrz zAG&DU-kZw}#eyn+e}1%3cdH$*2Ih_kFa3z>&{3#kQoT)F^7Ce8KCR0#<;l=3Z6HIz z)h{!t3@fPY`aTIIIdsV10o}`+H6de>`k9>YDL~(dm9kg1v9}HUyuSdDRlQ{{*xJLw zy1Jd7x{A`xuFlfjB(84H)@`S%BV8D|geU`e^j-Dk9&2Lc)cYvkjSJ&K<`JwX-$fwt z2qY!7Tn5&Fr!G1$lrP%qzQNyeE{vC_S6z|*?l-ix;c7f&W*!y^%eii2^aWrKi)tX( z;#085XCEtkqIZEtBlHu-#2<>zG%IngYg(nwc(DHU+H~LpNG$^!1D9(9hXLzrc|}S> zob7hJ#*=p;CQ#(<3 zmUKBTBF7mdug%C}M%LEsIs|w1Axh-2v&BG-G90A8s+qV&&mQL`=e*fpD4A0kdbgGH zA^SywI=tY4q|id?PHS(jou+BbAZAzvGX-izsjS^uI>c^+9;d}c3r$*t^97T!5eNV# zK`Fc`ItUmZ=9ex-y-@*w8&+lrjh{PZR=YJ?V}~)a*Y~LPGM?$=oP0{$d~T!D>1;GF zuXT4Obc+H)nL)25=a;LK_aSR=-wbj5Cjof9>dp0_nC7=ZTRL}h+u zU3~m~Syb-i3d!gCllNgqTmWIP1rb>r!qX<=T2Sdf!4RWBC+Oo@Tc6;Q?jr`56LOd@ z?5SBn1-h`@&|9o{DCmglEFLuh3^;$rj(&dmwA_!mQAV5?0XmzEiq_+eL#M zR^;4!etSJ!xXYMX=;RYlg9zb+x8ujCr>>_bmg$a34ZPuVkIYnm^NEL^WN&0{#Q_KeBu3V@^ zu~qU&PJx4L1B`>5$R(o-mU?9s3Hi(SmYNC zH&7%`34)u^AdD8@<=mOix}8^$CJ92G$@e%$z+VF8e1m|^3NB)~_tHazYY^vvI7nJh zZbXL@l{{b(W|MmLFY;YyHc)$jQ0ut2eKnZ}j|@Y^#?G#;2}#khEtU(^ThYj{-5*l5 z@tRF_M3# z=f#te1W;Z8&XGQF110th)C`v?7u~%;sgSizp1PjRvH^Vw0TP3-x<7?n&v`J_AUUO@ z`gR8{ZLNMqmsbUjzBJV=W^Foq#gT;lXxUh4ID;A!1yc6~`ZcM@2b&>VyyL_fa0e_8 zFd#MZVXi$9ozF{?33gEUNa1v)zgmHyJ0F>mvoB*);b*%BsL&7}xL+^c_}8OS8d&CP z#mVSj522-|sE)ou)!lU(*^zI$LlR!|5r3&3GgN7WOQX(hqCEE@QXil5WU~ajDP6*o zOK>?}hdq~`npbs%c^T$jAlDAh;DUWBv)#b^PT?2r=!S*+;n$f4Lsb+d( zOA{EVzAe!rpEV!^Ifr)G(wV8;4r}T*dr9oD(s#7c&ty~XGN~r3>6(2{*gCl~Dv|sH zkzCQRpq&{v=i!C+GO6L*N9tuhN7xZIJl%h3iYt{wgHO?v-X!3dVnGTp@Q)x2@RfeN2 zf)+fsw_i)zE`QV7y#o{>j^UetRIkc_O3c8)h}P#)C6H&J78j$Z;@)3mm}}C6qv0(f zj*F6RmN4En_neb+1s!5)3g#T=f~2p?j)VZCy~>*NxWiFY_{3sDyaXUQ250}IiiQFl zaQRgecL<=gYdqZTweGj(=e-X9k){&#^xWi4ldomJ2iqx5KU)!IHz$PImyH`chphkg zaFYR{&27$>Ocby!mvL2YbDF*8@wgZj+Ej}DBB~D`An1`xDC9k$%}SL+JhR<58OAdj zwSHdry!PJGx^I>bkwZY4?QPoB>KuNpIe1janRaaf3%%<2@X$8wF^;|O?L&i zkP6wtR+OI9dpVxhJm|Q9z)^N^h36?s1DDnzx+ZwpEfkP{iiy5U)Jl_6m8^yin1Cz_ zjJG3$m%EJ@;fzEC@r-7jtswVlncSKeKMq{ZAcpP))f(pL;8i_*f^&cM!O8eH-h&bh z05|^qg&E;%eeEMh=QYPCC}lVA$hx0ii>}=KNuEH{EemWukpHQCoD|^b^u3p9Tg1DA zPcFbi01C($I8K2}x;c_>)ko!ZF+$?x-%$Ym1#J|SUIgIcR0${f1-mm3M%VV)dMo|5}#d-1G;a+^jQBf}F z-r%6WqlV`PI?cHF6f?J_TVxlkuIv%9?A5SU*jCuaQ-+j1H(3kBto=t9%?`rTxexaJ z)AoMJ@3-e#q$W?O&PWNG5?N|(JS$P$tFpsn;=TbFPpq@k(F%kxhzdU!QzZiUsH?Fy zj!F^!1i|g-(^6ZX0hW3nvQ4iC=Syv1BD|mYi){KYP*wsHEZWUT|DzvE&7vwsZgx6> zh>{X%A1hNQ8F0%gnD66f`s2Z`FU=2KSt$-cEx|XuH1Vr+`IkCksstdw7LrQ<@`evCFzmn<(c{#vHFj39(fnpm40O9-PMB3pHr9EbSU^gv^zsfJZi)@UQ%ynraCy%=3e#z93Hi5$guV)WJ+=bU zI0wkr()YJoteBzlRKcX3pZsqjq)iQ7T4OL^;PnoXkMQr?9Fp|5+*=5JrBA+3)QapQ z$N%HzdQ(Mf)*_@ zrKq^PU09vN3>wok12H649ts~sUtRNPrh!2zW(aMMEGVkl(ZceZFy@43f$hd8gmphD z%w=1n5j`x1rKlo?GPbyInU?&Bw~FvHRY_x?D8`X+*C8E`saa6u4uaK2poBk5F*UUV*xl&*X)gN_p@GvaRxeDt88+F(;m3no%xx70<0 z?KS#Pf;4;=m9*!FQt=}NJ9Q>iuVrV$e@%1iH8gADi~86*V$Fl<;rd6g}^v|^GR0Z zs0hm{RV*VM%@1N_Lziw7NBjw6F zB=n^`AlxmC$T{-@{fl@jUOw*uyDY6Mt?RK;1F9*6XDZ3$VZKjUXcsdj?T)Jl*Waj1 ztxT`9x=I!6vpATCa=h`-?Ng1BpBr}$jJI?6;^6D6d0Cbw2Y}{|E+7jU{je4|eH1K7 z;}Gmhpw@!FDkfJk<1#ti!9nE8#LApZia|d)@H8XeN4-li)u}FuiLU)0AwtNdx_J!C zGF3wia(i{MrYI}nt(%hr&8Il$^amm6{R7$gwq4)_a0 z4G=hp7)3#ID1#S7WWjvftOK2AD-i;YbR_Ns8ff(CY)?O^AnNK`T(9Z}8YaJ4!qE#C z+lTtepgO3q-$FsA2Kt*!_EU+N!sF+xKx(R@uAm}SF+MF0);`VbV5czs`4NEy?QPoI zC!d!OF{E%tjKZt*4GVCGK_`O+M5eY0ou3C}JdS5bqP@Y>2f*XvZ1emCrl8cpVKdai zx{qYGCp);!XM@c-#^pp*r0EF+(xPV0Q;7KhO%;*At$z=CG%k=a|1%;Xs)9AZP!$W9 zr|d77&-In7^-?dW`5%m5(ix>C(n!6MP_Yydtqe@vYm2qM}Oj*|S{;yF#P&`7BvL+ekha%~y zL}oJ!jE8>iJd@HfoY{Wg85Sc5vl%GkyvuD!l3cZn@O2tV>zri>GrxVjgH!xV44kMR zL_97>n-md8tu;L&bVyK6IC=388FAR9+WE9#Zn>;TxPG-&tl-_<`9YT7R2)S}(2=&C zXWG7N0nkRLW^t5vv!o7O`bV91)x$eKmp;z6n05d4T4%ISE*nb2&Em}uOpyN>I(lRr zC(0N9i81?yzeg5QB_CK_1s#DVdTSsX?zIfn5>QQe8ZTff=A8+n9D=)Y?RK7V-{@}} z`&J*gG$<$amZ2`ax?*sl$I$JfoT!uOpm3E-@>T%Dp$mB`=rH)pOnI0XoUR()0$(4w zYkmPvF%Fgs0tPlgToARx&~S09pa}w1>df)$()QB#tOTh`W?RLL=V!?CQpb?H!mu@$ zn^0BdlaYbG*Sz2)|LT#i0s<+`3T~6XdgRtq<>ABIT+Dgj@~MYOv4yk zBT)7;&LBkw%Dx$<#x>50&3rG_;m%Xdp@1X+r~!o+2w{3cwl7YtPSptZ=(lJn-wttY z8Jo(AJTfvM{Vk;A2`=DRI=bH&8^<5T_2%`bs0Vu1Xo z*W%!$kTW)TJiIYJzy4HmvAyyGKUo6Ymr<5YS*0>Q+lgs=exM3Q5`?geS$a_G+8&@i zXPEvAF0Fy@r8C@Z*hS7}u;YT{y)3>GFFCN57z>bxRoa|=bSkw3w*Bya4$jbuX zXI3!JDP4W!@NSYIhi`N4$&o9c75XUj@z|(ABV-PwG7m^4U`-aZ?mh;cWgV$v1;Y_9 zOj3#nn-loOAwbH_P!4jEKoeXO9s#0N?LD_4JKus=Cyf3N?~plR@4io)%RrYVeNVv> zWh!IK&YXBcJF)^*abVC)EMZi=UF7y>{h~+8fv6ORD zwI4qeLn^RJN#xYf!cPe}bnRe-AZ8NC+RuT$Sx*$eXw%zsGHR5Xj{+P(B)`sA7oTPb zLS*+_cvXg9{^8`jgMRm9bulFFNad_R=Owtk(?L678!qdCvdd2*mGgV@dhYupiD^ZC zJs}-k74{Q?@IKd5;c^M)D=UlQ7_(>ms+KkTDbCo1`W-bxBak z4|rWF6TBh2{L8bZWF1OL zJCuQd==7-->^Dek$w8FUsN!(WzoOqse^T;Dvj9Qq9^mKJYcH-@gTR6)0R52@g-Kt* zzmcz;A9`$3j7EeHeEgCHxDc_T+SO#Y_oLONW5Sc?z0C1@!l|~tN_p!*i3ZS!z#dqx zO&$Wan&g3^1X`dFAKM=E{f+v%LN31OzL715w{`-W%@PXnmi&TT7q3Z15c20nN zB%9{t>0chKKdCr!kzNZ`{7}^gMBmVk0N4g-BAqZ*Bd@M}6vq6bVw8vfI2vrpIgH zAgpS^rbfx$(Pyg~hAx`bVixbeF+xrx38^t^KPQ`UK&uu(=;=AoL3Cf_?8J0W_s9Fd%!f68mIaENJRc;oQ43 zt(Z)I2Tx|C1CVzj&eqCb7CA~2A&<@LdIT=u7_HU`I*yJpFaSyd>Fe<&ZxU+)jX0#9 z-`ZoynL%ZAkb2UK^^ET=f((hzZ-|Z%rum@5({XNAHjh;NP~h2`rS%l1wNXbK106d! zk$q2YKZuYJ>O9_^^r-`H?T~w+7<3&&jA)uLa=NgMHydxdOh;P9ed&MU#Ep_=lBBlb~iW-4JEz#Q`8Hlpqk4FXZ@w}TxI#i$3pMQqnT{wif@rvfI&Z#%}1*jkGx z48UJcL2rDv_ICg_gA#!rTsm4jYh5s<$DZLZVv}AV`018=YdYi13uzA~UM|$9mhqVK zMwN($No=1CM;?fH3I|{ZO#kIVp87jK(rC3<>9sZ@HX;h`MskMtvY`s{+NKLdIu2t3 zV}VS5XhHb9WW1{3 ztLNAsSd_=Rrs@fAbFafd6^Od-tAu>HUUK)rl8Ttci@&L_PflJXTu!quwP{|=(vKdB zjtxBiJ&jT%At#D@g44}Y18Dg3n??^5EVZIlID`rUPaU6xbO^LjFGAQ=J>j~=>w9j& zdo&C?8)YOPCax{*=~Yoem55iiA$+~V_c9?g`UiVnjDbThGcv0 zeHXxtBQjLRuzLmZwLJh_85#=Lbyp}%cI-2=pDae~P2RViq?$Wwj`<*Z(8HTsF`*m= zR$cmjW>*vRo@Q(QTmax=Ki~r!XO)U$gzbDuQ~rqG zv*EDe0KKP?9<68sF|N7_pn5XJ32>7tjZ!KgE|eb}4cK@k`~504KwVU1M!z`Udda8y6|uja zTulR@2uXdJ;ere<5FL^OC+KHBwG@3$C{vHzzH06Em7ZL)*|wEzsah@XLo>5gh@87T zo+I%|WEumKlWz=2qWBlSlEi(x{kvFDPxGKmFAVbrV*x?|N%ywtKP!xo@4=+_=fu*Qnw0{#OruzFV zwamybrlsJh4wcoCJXa->V;UpyXJb%*aTzV_6?Z&onAcDI2%!m;{ug;v{4dpZ2i&U2 z2a4=yxcALtFl~V|D2`T@8WYo&vk-cknkCwusY_w+`Gd9fqvLV%PQa^b2bc0K`SNZN zgq})Dcnb{n#$Ahwt=PPXU>usoF-n$pQx7(fZ)q#B-IxaPO-o5B=nd6^aS+c4f38$6 zLeQmYEoN>7BWnd~2z4`8@%jV+FmT~x5sKWC@z%#T=8tru-D(QpboQix)HMiQzZ#qA zq7-=MM07;M)A6wy#SX2XEQlz^-aJuu|zamBEVqpZk&rz;H;)B^*I<*W1-cENyX zR$EJHXnMY|>ZECvBMrIDi7GqUq_hxBkCibn#^0ee5zFH{;JJRtM)*TCvO&M~Rw!~4 zjU=PjBLTWk0;{|X{0K3skTYI4H+b=IGf+{f3SY`wsC zLh)L`wIuZa>DUA*8k-QV;WdvC&y{?gS7g{M&I!zzl3o{p%`wb{RPUgp`CQURt1A;K zY2l>SBWpiY!l32_LfX4>Acv=;y4;`#i$N-_M+zLKCm`DH!dY$fLY>Zf5g}R%rtfC+*rH&VehNaE~K?`VBCt$ zPOC7674$tu31$jjfkQpWQ;Ci@Ar@Ucjc`r&P$(!3I&Z1m)#mw@41yF0HtFpsxkS;N zOln`T^aVdG)um;tNARRkMfCza<@F!4vK(U$CO3_xt+_Ku%adp@t9a{iHeXaL4X(B2y;mIdYU zSmDj85>>eWCYd$XHGoIh_8mu?5|g0#?-uda-H*bJ^eUrIv3W;I1Z1GAag4^EX)c%4 zzrFy1zX<*b#nu;KUL4>yfU=6cl{O`W$V0vl693{_h->FowbueQbG}}c6Pb$EFL$@I zHb2rPjuK?@`=}(xcmKXy1Rht(8;@I=Q&M{=pcc`Mz*bO=MtY#7%K_QUMG>@+><#6# zrBwz(K)S{k^xIRbqsYm+-_uqhfU*W;3?gnrd^;(>b*@QG>yuZykxtaT5o+nlTO?`b zWCsWsXsVe{uX)h#tT1|VxKUrB!xe&=$`(O`rU2BSRvJM znLc{Z>U0*Ghf~N25$+84zQx>JD{ES=n&ZpbJkAA>>B0_!;eju!c!0+(J>%UruD2eU z6H>);%mqHEPu4;;FWR@gL}6fD)SkysiC5AIYA$I7Gn(N87KL z@XW9&rg}}*Iirvfo6$>)5`g(*4{uH=Bqr$`Tw_UtEo>$3;Y$K11MCMuiMVPr!vCQ8 zNz6q-G=i93Jp$UC*$9{6z8a{j@b6Az4h(;kZ+@}6vvqgL_wIaF2(&fa9i5URhtGz! z=ScmPncpP*^e&3+;z!u@4hVdsgV4*IC?w76SQ~%VN7#ig1DGSlT{ayRG+6_1hTz)E zv_TuOBq_3jOY1opMVp~d*CD*k)jHxWIQ?R72$?>>Z85toliJQey^byk?9=;=)5Ptz zDb<;VCn>wMSg8Lv0RdPKMpXw;6`+D^?HcK zP{##8uB!zD68Yjquc~OBZJ>ea#?zXB8+Kf6NxrClh5pa}%wo6R@wzbhbE+*5h3Q>6 zF6lpR!2Exc9ci(H8;xE!9eqXj^2(6~Mg9u_GTxO@uhO%c%vWETC8zs<2~!juafJnY zr0_1wk(L+(8eoKIxf6-zhKT#j*5t&}qOFxL&W=4GgaHp22+@DdrMx0byUR`z|CCNd zzq$f=_{{PLKTsA4UA+7O7=gTzhB@w64;OmC zx8g&C$aQx*xr+7f6+@B%AVNGC!{1P}cu>O9sbI7#o8~tOmA{&Gsp78ngJX|pq=Bf~ zwWyWDKrv(AnNC#Hf>2(Fm2rW`D~%JI4E5#n(ZGs|Z9+k*j^>6a-HnZ>8&3C~~?X86Pl?~^<`E&Vt)TUYjTWe|d0>kn4Ck{=)a)go-)pNJ# z({vvQVs4TEn3{Jx#%X0!TjD5hla>Wr<+uq)gR!3g4C}PI|6}%Ur};=bp~M8IN+@80 z$U?M6P#Em9RS5Ll#$-}ovW7tjIb?nz9IvIc+wA0WQ3AP=sE0pq1%~NjsPTAj<+F1)hMzZBm)u4*_}qr zV=X2iQ;;VBgyU$I>)qG4@9q3Gt5^eyn6!%C&-Te0X%IWm!U9N73g0Q;fz>-06m{z& zn3wug=q|D*&^<1O8uZF<{`4`2=y;H=0~pO0VHm_+1JpUbsVcASIGEHBE!nZgr#vGt zjluYJeMk@U)du@|OYE)%DpoY{?`$5~J~}>eB&40t0IbFB*=m8wberZrDTRmNK^+fg zbGg-5&wel11OSte4p8a}OP}VdO}o`>kCT>PFtw{6H2-|G5d0AdgfkcrtDI?JjR{ur zL+%%^97bcR3DAa$!DO#B3>as5*{tKUiM%l%G<_E;I6_enpwj^8Anh^@jE1(m7EqHk z^Qm<7x+eR-dAJQ7eJZHb8d7Oav=f1K#+h*4=&rrAC1ce%z8^ql1pN%szO=Ba6;vB} zUASa89wofcY~;^uc914l%uVwndM3g%0|2+`U;7*EY|+lP9m?` zdJ3#UkoWEZ{!9+okXw7<*^3(gJ(8?%(Ves6&F{GwpkJ((E^dL8r=M~%Y&cGV|u9{9dFFd%)bB*P=q(C zt#pmuOU_pxv?@aB+E3pdTh|=^vYe=MAqRzS)m}s5lguDcPo?I;!4E<_#hW%nwXo z;%ktSX$h9hcQeHKwP3sJz+=6FE;s=hfZ-@?pi2bH9j|uevU<0~fAeQA-%jV2` z3e~Q}*m)?(M^wG9)Z(LpF28>a;72NTyrfvQ8J>nGCd^zo$5#m6dbI|=0t_DH?W|@7 zb3}Z7Lg)BdiotLi9t6}>kmvCEr^U|_ZqOK=@qSCn`;`BnIMmn#n6Kd#7;HL)y5_JK zdpXos9#4i*i+IbxKxjPlhSSL$b)$EX?C0PZweNcUeS<2#E1Y@8+Y#<5rF_8oX=sAl zh4^C^>$?E!d7vQn;AR>9s&n_kp^?&f4W77-YHiRY|M3|TOHN$MG!UUiWS7bJ*R@R^ zH%_O68Ywh=aJN=`*r022E^aQ4iX$62U|(&!rM?33p#dJE2`(zf9D?&_KC1AY*4x3} zJ3(*{`hAqzUTk{E(RSSR6+X%_rIrK`OtqFCJ2_ndJ2Lta!c@FR8^>-7Z22@^24*k_ z3D`Xsp+X&?_fX9(W`jE0epRb>p_66eA2I+fl+drl&mVWwrPLsQfc8; z8I0n;y+Z3+|2qU^5Jw6%st;0w8D3_bsbB*TF{#5PHX~ZG z1kdB87*U5U;_vI$_2UzO2*e;-#byDPZh8k8TDc9&Z6A20Cg5}n3WEQs4Q4LKG%d6D zaP%A^jnZ!jG95w3N0;5j;4{JExM8bhu;u?Zm88gvP4!4Te@y)i>)~Xx1mqh-LqYT zfncjN2;D+Lv3*?s2tWtC9(VYQSdKmZm}bF2rqsnvO6=F65Yk z3~GR_*MLq(L0D8{*m{qBc6H4SiNnMHpbN)@>tNSYwK%N5Gr=u2)q(49!7npdjqB=Pm??}p@pXw+*nm&ZI zg2oL<5yJY|Rfl&cg+l}zM>bhL0CQo3Fj$G8te12fCMFUPzT1Vu6d?R<7B0>$hPG}@ zYJYM_Lcqp8*o=LM?};=>*gG1w_7y>|#JOj-kp2qVXo@NE*1N`5TKbcallX9p(ylu5 zt8G#$zy4VUp4!PQrK;-s(8{YOUk*HH~FImQ%J^;UG;Yf$dBw-a848H=t zG$yK|<2MfE;V6+@Hw)fu6p-+qL|)Or)i5#;!a&P}@pgVK4U8qeF2Z6({AW~`^u~3- zNer~`FBxtv+!RXO#k4m+Ldn;n>C{Lp*h za`eHCjuUUqM|Jo{TJ^DO(mFSCAM3mk9WcxqRe*e(>?-HAy2P$>4-CfsOdo-)ppF$c zcLmfHs{J(#=@keRVqE&F8+NS=YU+V$z-GPIL&`rZ63}Te{eBMW0s!k~>ZeiuO^1n_nmY zAvg(%oIrnv^aS8Osw53n`xYW#&NAFnXLkDfhuRFCTe?7X`5TzIK;M_8kk9ohcr#+h zV`mSL2;YKUG8*CRpyKL1r?Kz)So^~Zh#M`Os5sUfUQcP@&VSw<3E)Is$B*n+jupYQ zN*$@qI5ZOL8)X4l)e6R|GVYP&U{g4~>gGFTxjg8%<7(6Q=@RHT%E(^w%O!pThzTG) zpa5L-x`AQ9qj%3~Szf3RUpy3(;3hO-X_lH8FIX;Lc7&F#)$w*>>inmb)w0#&eIoAw zKHba5fUQPB2utO)_A~RVMb`jQW}>rkhlqg0_VKAztDUm)9Fr}I(*Px^9}s|P z-|&#arZP9pNBqE(?EHQVCZ0^1k%KXiLldRI@#X~+lNR2t;vH$} z@bBVkR~Z9`GOE4S0h%6d0LS^)^IDw2HOa`x=}7+h=H|F~&P$#-XCl_kCGR_sur)@h zZ(QGr?6EemLn`yyv5&qqio>`e3?HN-BwNEx{ z*eV)>DtM26=1duqi8yY$?<}i*Fy1XjJN!8=rj6aO6rxAFyHscx;^^<_1;9##F#QaN ztY}yl!M4$F7@Bf7QsLb^(&=R&Z;_(fD`Ql^b z*k9pa8Z6PI+^%Dh#!XTgk)x-58S6dumICbNXeBf?(D`lIERHakk%Y0t7yo*KX0LtG zLe}L0J=(%*@rVvWm}EPJt*&9J8S7KA&2;CXBEQOvVWPAc2vQ9z3H%%cA5>KRM>Pu#CFv zwx6CR=z_1^%Vd>3d7`ByvZAAKwkK1HSoisElf!?Ad`(5v`Lq~YF( zW=FzUeH*8|fTQn$AxJDh8IcB7qWnwj6r766cI45y)}FUtB#PJkDqan4c5D{P(Ft^C zIZLe;XYaC2G2%;{rk)R#;y-^Mx@K@NBm8jtfCkZ|9OV^+yg%M(61s~izt0>_MOmf4 zWqkBU{zx+6!#hglZ3lN0EVQ&JwVjvE$>ZvV@%pIBkh4i*Yv1v#|0Tub)bHrwcQ{6$ zPVG1M9*YwUQDmKRPsTOC%PgFd5r<^S8<*iiI3dBSfs0o-x!<`v;_UR+AKsGt4r{y2uYM(-l20fr+9MlMrvkcLlJeNb3o12;ty z;ZJyGUCD^W4)<|pBMnx}=XwthFl^49;S$3Nejt*+ZMWjpD>5rR=f@kah11rL2ay)A z-xhi~ns1z1zA5!^ai`%hatv*YQUeh@{N&ho$QC9it$!~ER-D0q>7PTg)y{G{dimkS zWzmOe$D#xNR;l4&F$bS7HIxWmBLoGv{>ZB@pq1jsn|? zkr99Vi#Ph*dfl+sAU#4r5YX_sDqUga!NI1`znE64>Bw;1REb)lw8P zMwaF3r7jtRCqSdz@J)G*ysXfZOv#V1s~`n|)7lME6z4LMWxlWFoj*EoiZYQwJ4m0| zG2{tyoLXd|q)+!{a%%XiI%#r@t#{}rf#2~f#y&HR_0)c%plXd>t~VT6EHh3rtjXf> z6_P^55nbZEsV8$5jK44qr?IzX#JGU40JL5IS(5A~-U~KxIR>9kRlJL$T6kea!j`HF zy9}1CR@QdkS2~z{Mg!_ceVfe;&uvuIZJ6(v9BQYxeTuxyhP*awI3*KMt$Vl(#Npfs zuVJDMrSqy$pN~EXy@_2%5n5*|$tyIQyP*r{?1oG6^sW069M#1_U6wlXZ?13jGFM5x zFW@=tW%yvHVDCsM9EF!mhBcWFx1%!RMo{O-5M1h>#&K*NLG)>SXpOjkmEplZ3%$&< zLUrHOwDPh}J-^|CmyMGG%(r6TxwUq={V$?lm0PK)xE@K~&E4zUKTzHa4sZ+?({r|p zh=y~(yl!zL`~U z4Pc*1UnB2VrR_itxoYhW3qsXuZ^3oc2DOJ;t&;w?_N0F0&RyTIN1Tr~LQ;tp9C+&-V0 zN{iyjb}8xp?C(bS(`~p?S4|@&t7YA88pB9|u~j-ReAn97plE-Y$j@kZf{y4!bd9dS zs}Y;r>9bEp|y4up|hPX6m-Lsp|Qb4B&>>7bRNSS~~jE z6+()HA!|g_i|~JD)zZ}1ahhTGvvy?VF0Cx=(BT5%1+t2{5I*K}FJQbS5{A#hisY9a zPgc5B;r8z%Fsu>#IW@z;6wzD2EbKc}%|7Y{?mRljZREt+8>wjHSLF9EL8f+!& zAJkArMRZHQ@!!qTpn=6^j`m-G2k;sx4hd)Fv?sMvT%1`X zaD__`inV;x7tA(!z*Iz-^O@?%%$|A>hJqb&0f0x6Ffl54;qCP=xzzPIyj%WwH(8f1 zA|AF8{MKJnzjCa|jH*D9mjDJ`RyYwKm#4-9ih9!9V`49683|a1&=ph3KY*>6w>ei{ zjuAfp@KhO2${V5aI>Re$LrigzqQ?e`UidpZ)ANw@iDfwu2a?39;xbT%-wz{ts3fCC zaJ&`_&I#fR|8Zg1Ll*&S%@6+;T>D`OyY<;8cvgZRD;TN&qwKw-n(UT0(9i`zL_~@R7!d?SniT0OCcOvKLl_LNBjY7iX4I&DcNC)O0CKNgj{+^0;@|l z3YD^&8n>FV9kNHAqMIz6z>#f>6B_Q|rtQMId;BkZPApk-x^GI5{F~9_g*0#(cP?#k z9=u)(ZG>nXv0^Lxk+LWW{3=`p4&R523HFZner4`8heDy1ci=}Ofz>EOR`Zh*+#6cTi%fqe7tiR=4I3Bi;tL~)IoYn&ZO>nriX_hIRFEp5k6Gx zU6h}UkA1RFfSt8nsypz+Y`?$;DtHme+J5TdtxrlwQY3=a8s>WP9~UK(aT)f?xxmvs zX_upm^-hDatPIWCA8Cr=4bq*vD$_PRHKlhNZ}F^5y%*snp?B)XQh==}7^##0j8=cK!sdj{|(Fgf1b&3y`r;qPZOpP=$>0vI!XD?H}oD)ajt0&YTNrw-j{)0 zmX%Rl`dgb4!luIaA&l-~^Pm3)GzNk1=isby8n46nK$v0k6*wWLAV>OCjHafonV1>B zpbQEx_csy9c_xFOY`XSsb>%G`fz>@74<#8-?k|&B+!(tLJhpDa^uPe_3(*}Wn7{i< zag9y!P54Fq!pA0sF+*`12Vf8aS{s#tX)o@4Ief`pAHlGon9gLE2it|7_|;#CJowe2 zGwl!x9iRFRL(9=dyJ@VtRiuX1);E?(BUL~9gZb(pM{`pY458d{;<}ciG=>cwM&>VK5 zxvf2+i!x!#%HIv z2c@+B&0W6n?Scz>k_k&>FMs@ zf1c_w!3Zn(o=`QUnMzVJdv@NrA09KyA_P$RlUi@SlY^B@ETr2KPP6gq`lWURQ`bWO zMmrc$g8cX&#d~Y}@5*qKP&7D@>N2w(;1~}Li7j{EXwm+I&eqv^9U#T1+<2%7a-6_v zS<0`iXz!i+YRim54UijJwA?V@s&Jq1q+D@&{762?z-#l7y;S!@ap&~L$cy+j4ovmE zP2-9avvBdCfX<6Dx33PogSGx@=uuq?^1~m75w$`K{1~P^q&6GlIUX6(=k4(cXV+5qH9dw3 z+_2VoUtRAFas{^_`)UFgP{J~wLx9$l&$z(TaV|{qX+cZ@{o%?HW6(qLCTn8T2oI*c z*A(|1lN)#9Q{`9~jGg&=zOW#{LU)tAHTn7a4->4r=dtT=i^^A|FphzzQorlg!rIql z#zKW07vK5ar^{4xZ&nbj6XB~)r^AU-IawMa5>C5=q!_nJIhAI09UnW>9~+S)aH{3W zjr0IcDYFsinzB0t6P=3U6o{96AYr$J&(CBtncfhfiKt+nXZkxdrlQ|sx8BFt9c#NH zNy^WEp2*zX+-;1i$8zzH2bHL1(F#rkfz>sB3i_Owe{}%dRkB3^lGv&De_UB)=#d8- zJSMoHN^`}Qa8*M3HDt=^uh5(DrBg&JrKG>ORKmjr81ZX1dwy2nCjpqlal9V})*ToF+(tz^?6|pkCvXo2_M4CH za_`hOkq^ZP93jFAEKD2js$YNosDH3OV|Rci8prBD;$u@H2y{I~x?CfH=Z=}pyk8{! zyV*TxBH9eh;ztNH9FHQ#CIy|sDSyh(>D9y=^hV1*O!+nM=vNNnrhb9P$2rt|m9iuW zVl>FQ4Ve<@JA_^Hc67R$ixlblEo+O?os?!o^t$f~8=ju&26+{LP38c3cEHe^2}7+z zF4eKM`)>McGdetw`Banz%MeI$fcFSTbIOeilP&IYnr=s**g@4y(xMglpv(MYFQ%G02U2k zZKZ&HboTnv_T|c9L>;@l@G3A(<&A0m2VisIvdSl7Ip9a@uBfTFJoTAxx_bQYVqw5a zG}^)#29G---imbR{Adn+eHo^wzt3vIn3`@$m{*QjT=zA33>^!6qOO6;G)JoX!%Kump@uD0MO;Yboh!oA9p>(yLtS7q_F+ z#b;k2GY3YJLl>L*^317Vr`<3EV_Hkgg{uo+WE#EddqWO!;Zw6W+H$7K?@a4sfM4`{V}&9o2UFkVU6Fi`z7siF zI@8hEl5}|W$|;YxceBulYgsz(TV-^Cd%MSG3-kjLy%?$?XJKdH_m?cn6J5FIH9OL;{47o}=OvAC+_!5S5tQ z>!Pi%pSkBYBh4_7XHn20q7G8HubheSpxuLj4+(K$&s4s#Se5pge8$^=ZyK-xw#`~W zp58uv)Ea|Na3P!t#&9%J@RVK7?`q2yAZ$|w*uFD9Q`m-UyQb<`G?tZRC|0@yW)x=7 z_)Slq2sUUWm5uJ0!G(^|Ku*D;j@1K%5Z?ke-mjX3+Ty%RtnyxIXKK;19gtI~5Wz7-XO?`^DUqyz;G!X+24GP9i?>XSm6B};=G z>XEjJjZx|sKPk)Aznd8meFJbgL z0-37YpzGAuAbk&yUY?QBA5w5jNxJBO%QMXY?#mq=!_ipP8|{*>4Sop2KKVf$v~5`& z2s=MM&VMjb@IQFJw$m;eavcvfQpPZQ4*w?<^;8|y7I&`tDe6*O$1j6RKjd~n-%t=T zgI7^sBlg2o3XV<{GjjjAB@HEe9UADa=IV&uVk$ zEIQEjiP#rPB2!=b&g?dfuq%b#|{Q8)jsj zAf?IoUkRg6z7eE8AkHma{5=k)8>}HLRLw#}08!E$>X;;Kd1`9?WT3!tH6pX*O;>&W z@M%qwAf%|k4eENEP$VcpCw>N;$J`=CYFNll+%h}<3HZa+NwHjT`r4dZ^`d)VPwc$i z%fMb(UD|QRy?5WY5#?U=JNY~dfMVYhusQp^|M>Gf%KnYgY+q-)g7(p62dBJBP_(%p zU|Gq=q@bkq!w|O>V-w`2n>naS7Wb|9bB~Qwoi3424)O$W)TeDLygt{rvc->^nO?+0 zN|0f62Q|#uXSOX`10D`4c{O{W+#5;xFKPdq@B2)eP4Ffy18^%0gF51`uO;MsHey}# z_yd@m0n5BfjtZ4Bk>P#-K}8onSGYp?@;TlYxm*qL&(Z~v3&pykpnxcE=}-wB7SW%e zG-K?KtEWVs#T>vZ{&a|a)c=|3;9cUN6O#7ul{T9`KNcw3Iy>(Q7Q7J1^16G6|TNz-3{Mu`mjyk^H|yW_E%`W z+|MLj_s);5_8AtE&!x;M1--(s=hL6wWozeE&)u)nuG7YUF@LxlDXIK;6nRF=;)%UP zpojPv4bAEAVrt;Nhrf$oN(J~1?IvIdWrI@g$)CMFf>oj#g@MZnzU#fYoZ^Vvm64pY z{w7S&Bge3i;+y(XT>XdEr5?3MaW^mtj$^X)#!r|*eSk4!yBzcBieA>ldwI7rR4`^k zF>aKIhwF%br0JK!wC1q4u%rAQmJehVo#~d`+0NtE_@}e6)d#_rdd_ z%64KS1WdHk{}aEAR`tsJqPzCjz^M2+gQn_Am~lAKeN{=K!;83G`s|8t%89erz%6zplE57;w^B z(_Pc0ObZ9Cf8w|3`P{l*)Xe6*$X%#5Z#c~puACM-SKn4l>a$AK1##*<245&(&FAhY z;Q0tPKgyl!a?%MtZupf^8Fr*`J?BSi$x*8Q`03G@M1=zewZaTd(F7`6nRF>T+FunX z)~yf()YNjtLMNQV2!LC6-=;QZ!k8429+MhBo`f5fEctv>>2A{ftMQ}Wqw%a(#eRV4 z=DnYk*Q4hkynL)#;?OPnb_%FnfD6&ye?3;a7r6<@dkZ%XWTejR#PPm2nqV-x$h1Y>eJ5CI@CyYF0G4w5 zHz6F^#JQh4PFr`?l{?)BA+JYIg$Op~RU^J`>|Rv4cVyZ8s4C9GV>sU&t5@0!pz0?! z3Ilh9{K)J%ng}Iz{4H;*9h~g~A-kXU_2xFt>D?MR?X5_DL<&d##^nf77|*fpuI#Rv z?0arYjhyzEn#=e}J*-cjca{|hh=k#SJY4s#7`%c4>xppmC3xW_5>m@cpUaN?#d7wS z?WU3t7FP|BJeO`_5-!M|FNFyYa`=o;-O;-6=^hNb%Sm0J`qe&Vm?>DX&4o$q*Bhc$ zKi4*MK$j(S_hit$<-&5BO}w6KHAT!684v#~yA1pKLux3&o(_LJi5UUcE6VW(TX(QL zw55u2R%qj=;s07rs=I90qmL+`2(xA!2em5TR{H^&{tUB5E~+sNIKthXsWt`&_a}30 z#nhw~mPSLK>rPEr-Nm6~8JXUmnnIi+vqR4B9Ds3_pAtfWg4d z1-dJL=@)+Q)~#b`^yC{Z>aNunAFD6mTCLx;hTHK~OG_Sr1MdJFc)zh!c0v6dmikX= z^h}Bb6S?JTIRz-#e9y{#N5IxMb*@5s>MI@zeMO^r$um&BT#w=!RH*E4m zkS!`o`#}Z7iXWFG8Un4<#g8Tc)l{5^dT~wT#QcqcI|9v2LjGG4#nqhe0L0mGh3 zf1hdUaboHNG#M#S?hjem+)nS-)Urr>Uo)_4t0Hw-?|jKfw$O=gz#LujSba2Lmg3nP z?`ZLd|yUJap92LgZ;d z4XUvhmxfGeFrn5!*s+fk;gmmdyYuGPts8i8wr#2D{NuBq6NL#@z=09hc&ihawNjL_ zOG$eVo09SHbo#JJ#b|KTYPI*GApj~v1Dm$BrnTcX;DlU8{XBfNAylq4= z_bf;(U{qL4>)`CT)IogJNL(hf?H*rs;uU%jAoiLDA+mEE^s#s?j1gLhlx3%8xBo=$ z52$okarRqeCyOUB`d3}3Z`HAq&{8Rs+u}Pdr?r{B*HntTzrd?y!NagUY)cdt*zk$C3**8FVWtHQ!s-Wb z|3a(^Kr$)(HWYQw zs`_LfxUF8b=X7p$>%eMt)!X~2vnn=v1J10I^NnXLb2e}QZCQHp@N#vUrMSj>^2@K) zShv}4NK74Ag|95bMphv6)JF?uTmL-|6pN047X}d-upM(zHsE*lJ=igHDW%7ZF}T1c z#qC;Z#DYXE&W43x_!%9{irgNR&>Ii4$l?(OWioqf+gy^;Q)t;8N{`=4X4BRs1DU}8 z%@uHK?v%W~r@bUoR*Nl&=gkJ->LW-^p|Ax=ICkR;Q!0msimoP2rUwx;yLeF@ilDKx?JcyX_y(7Onw6+rgRhI~45 zlyG-Bh1K-)w`y8VD~S|alu)bK^%!3LY`RCaz+11&=|0X}vJ-kO{HS-MuTwh}kWyRY zQDH^YTOO<{m`(cm7)#Ovqiv?#(U*I7t3xGc}P7N zo)%l}yz2z`)wLVCt|G+&A@?wrg!$ejlT^ASZ`k;Bt3B&ytJWHvD0;ZOgcjPvyfjoL z7m4)&8sNc}T<$9K>=(pXh9v9Jlaam2L=*9!DTES_^1UKnbZNv0`9T=6lbG=C9Zp>6V^a#6{$5 z8!$p7qxvqW3zbcNtY`6jwcBR4%{t|`c!iH$>&ZR`lEUb6T@Ksga8GRTI7HE~bNSNB zk2|GMjq8Ov2)sP>7o$eQMJb!15DLQ19YJJmIg-HKUpj$$gY%8gHoC3eizI8W#b$W) zWCR$+`_Z&vGP$5w>FkGF>%LJk4ra!Zg{d#rh*?mW3wl8Vngk8AT7* zzz0WZ@?_mRGBdQ|B9KaO(#D>J|4!xP+YpM@nv1KubKh+sBNxY5X;gBd^y~y4SSGtgYK{XQ%qI44-aK4lg3hw)YI~%jtKy z8#3L}->PfZUt)tMB>;_w$*B@agG5&#b{60^jc{Xn!m(4CRtV%isclt{PJll_a`MbbNH%qcwX5Eo#6?D;z z^pz>Tmhnu1tZ7FYUp~GDK~?IWR<3qB0Cn@HaDbbupKM;A$0Yebb%zr4&VgCx^&3<(0^D_?(MeP>l@tuucNKF-n=8DvV=o*SwjOB1&3wczp`u)a^nji6$g ziNW^r_1(7O#G8-YI4@0EcN86dtuFX3Ym@jqt3t1}u_a-w#5#98>@gv@&YVgT+iN^mwlLitjk;+;X&YEBfvxXv+YrUQ zNJu>myY~7~IVdcwy|AA$KcUU@lgNwGi& zf>shS{5moOM)^{E4DW7b8Dg(NZf0UMU`wJbL6{^OH-tQHjwnG2iF45n^)(#Qc(h?ip9s`< zAfY0Fh~hf}-zI{{lRpe+ll-J(<(C`T31ad``c)UKX>}_ZN!6(ZtcMGq-#o+vGkR$FT zBRXcDSN9{3{C%w=O;FF)jozNO{;-kqwB-)yOfXKB!kVhM7F^P)2(*t_=Kj}5TZJzX zP{(Xx%hZH0=!nP*Ilc-_ILd}iKyU9(m>MVqPw?#eZ*_WBP=)qkjcz& z>Lt9Sh3z$EB4VyAJ}GW47Y7$Ceff=G1LSxyorrbgG|0GZJ}#dRq5lJ} zv1*lzS?4V8y&=$hW8NFLz4|u5D=p;IrSGF%n{zL5po9VHsb!`Y+?j)CIWNn-_qzT{ z7^YnmV7(1$|4CBrBHP-OYXutOhNEU9I|o|a;VY16T2x9`f9ypBbWrMPOO@rU*d|6} z{^nz{!Hluep5=p{JxS%xDj)lwEI8jRr9<7I__~w4CC`Vc)BO4AHR}xH6bR%k%?dqV zj!9`CFxH}LnTGoiR1%9i~O^>JA}~+eY*>IZ_#nGzA+WXLHEk6qgOsU0-%6S^+njv|m4V<+&oCt*TprCr7>~FvCRo8W97@%}L9kd{ zVhY*={al+2D^;$GPhn3?)#wA&nZ z{pzEL5(NNnH;J9;A}o%Da@iZLtbRR1DiFATl4HvWbk}fO(|J(cdd{^6)FS7~>Ls{C z7rbk@U+T~Teb>DlSql{yQ2+mG^IE$*;MAjkB_@pqtwp-lXT}POte#Gwqr&DR?pyE) z>ulW*pzMLDujXBE%jB$K8bTr@Pn!cdqjhH&N!cwTbZ48WnAy2QamT0$dJbFtW%-`) zAR825H`slrLC_#_PCV9I6)(q5w6>2<7Es_ZWsJLS>7&v$a=t(CGvM*C%DeEnnk-Mu zROx~4gHKthI)H{Ky$7GU@|#+E!^gm7gd`EwPCRT*v^`&4ZD3bJ;`aMIJ*uE}Zlh$e zl>)aG81mRX%6&YDvE;QX!`M^Nx);SQz!-a75HkfSOP?I7Q$iN7S5ok_xDf^EXLwK}^=mA%Z$gU~%hq3a~+qf5zg7yjZHMUjPpd9RzZeRIf}YF-B`zd@DjC((7>q>Hvv zxndUb9e_IMzeO`y7yPk$b2V?}IqhvD@7qh*=HkBIsPr)DC3+wteIoDe{;F0XH7dud z;8AnxaLdM;0THO(VY((Y11>Z)b*p;*VW<o-mZ!8_(Xbw2_}}eyySXjo+@Pz5*#;z;^4NY#@(?T zsLbcXccM4y9!#w4$U>w18xHlp)|qMO57q0@^wk^km9yQt5S440#XXRO13*N)!uJub zgcr8BzJ97idFacf!AXvt(rdQAx?l2UK+AsH z^Y$!`->NJ)FH#2O+Sh{&XTUHofg6)L7*RD?!p5EJux0U~3+$K&KcTbE@p7 zvYs7QYvud(W9`qVrL_UA-17=kUwZ7;%-7%8?fLnOeX(ocmgisKUL9f3hSH>@g+lFu zNRUhOzM4}ob781OtR!k;jJqMhKkYTnGgd zwBEqJ6Cp8{Do6DRiB0*zalE!3{gQGAqht14MRXto;?~o^tq}Fu;Q~+0vUx{r5Vh%U zGyy4mSQRQ=mZRTiC3R?hq|Br`IxFrMHFC*Vki*p0GaC*Oasd3MyD<2*i}TqxdCd;&iH z9yo!YAbBefCitP`y4w>!Hj2lzP1cUr(GB{a)|j1ndM77Le;bEMzY93ymXWtEkn4Fu z)YT2QUY*w_vmWaHN$y_8XF3yW5?WN#kcTy6&xIAC+bULx{W=DwSy`!l!m-)641xM& z%8$7S4?GuM5}>wm*M>COTvGR7%rbG+1-PvsO>}7xe<6n@9`7{!@CJEqjHGlzQU|CQ zZdsT48c6)N=Zf;J6`fH$(WqTxUFLqB#X#JAd&CWxd*^eyj{871dj@0qEd;2aZsue- zgC0!@l&MRK=h_4H7Ktbe@}W~?%ywv$aUXQqm43m)INiY^P5y$(2td9A?YmvuBhkB% z*r{GMKTiNz`^85X)|+_(bQib{RU$Y&yoZ^?93=72$e*uIbe5*CWoq^Ep!8ml;UEAU zN%*r4XX;zZ48$&iQM*rf3HPG<=p&=KpJiJOhS-_pVgpU}3?LiRD|lDLI}?3rZvN#3 zKfz$*#S1TAth?W*^%;0;UHb{NIP`=*Y=L#hJ`6j;U$nO4>@J74#ZC3NfinQE0$!qP zO(JrflSItjbK70*`Tavx>Nf=z2qSbUu&eiShi&D1f%vcAWionw==ek~?m=Dg;>)X1 zyA`0w45;Tp_cr}dMFOU%QK#0r^$E8F0_Zp`(b|PSwp-~Ib*Ilm)xndB!-SdyfsI!~ z8%a3m@!JUWGt;@1nklYZ9}!1!$mVJ(B9v(VpSj>9tD0wdsTt7)SfXU+e zeVse+0FwqKR-U7a^^TxyIymBmCXTPplVWk7x#J0Lt`_DI8sMF;23Rnj2odA`NuF$5 zq70RC&AWp#R>o3VX9%j}=2X|;N3vq}tLEy>vSooYaq!j4UX*)*Q-u&D#+t!r)M6de zV26Zz2jxsPE?_m*_+@)vQCJr%cH!zCTeU@>(~79=CLhXr-iol&OL}bs>R63W790c*& z60`=D9*_{bHSvm0fAQXVW@?tx0l>TX6NDAeuAq3@gVWD7J+Ni|^~BFx*T$2ZM5iix z=Y+MZt~6cLCaH2=_C#Gl$fa_%6xT^} zQLh%j)ajQFKhjz$sXOnUecjp#jIivkK&c1OZQkwTkmO)x&t7A zX6LM+A`wcdd+z1?hF9Y99LR~6CGTBX|IBw{lLJBB?&p~@XR

t6`Z5TCF(3W06@49{C;zW6VU#pFpY_{KiKbyjt?D7ty6$Y-FOuFJ= zI$Xz%ve`zH4d!t&dsj5oEHN;a+!i-~*)+49B6A%G;vi{S*S+67Kfkee`#dm?d1P=$ zGyCl~^`3kUt)gz;1RG2P^7VkcHKrB$)>>(9Zm7Vuj@WkGm}f?NOdr6&`SK`I*d*ct z8eek-`~4d(=%7IrECWF|z`maK{S9Aw7)gD^H?j1b!|ksJXQWZsuJy{)FMY(o$Mpe3 znDqM0k6f6!p8`+h>(?jCQ4g}N(TS_GS(5jZ5ncz4(x|4sIWgu+VkB=^Yaw><0_mMs z%XQ8SeVoXh!P)2#L>P7Nai^w63^yaP!UIT1g~@xDQP$o?uP45*DISK&X>R&{JpPbO|Gjxrudo}JH_sdfnNNu8#x$OG z?hWWWMk`i1yNxtH3gEL_q%89%S!yR=-l7t4&@3r3e0WHn~z^xYk00Vce0?m^FE zV?-+Gi!7^y=|1?9JZp_uzwevJtue>sn0@69Ah9rEAUhpMn(JmT%5v^qo}mXFuxsm3 z!FhSA`qvt6I@RMrJj3Q<*(_oT|Y<9l{~CQMOE|8)a4F7o{pwd+!EL84%Ii-HDO&vTtYsS2ma5J zWozwBiTe{)vns#MQ~1bD_|S*|feX9iyWcm%rbyn)4GSX~hkZ5iQ4PNAGM={I>BjMJ z_(zKLJynU>A6r1}c|%oZx5%xIF~y;+)BqGbP`bUr&-^yaK)=IqbTx7`PHMV8IM~^& zdf>`qB}2@>t|ouc!!+J8TLj(x_My4x;%gJp5~jQQ7v6raU0aSMuq3q0BBYcX@G@Yg9kNtko8Bk1%9#!7_~?u!!X9;$ZWV; z8bt8svKtxu3ggD7Oh3M$a^|e`G%?FjckjHZXl|yhkxJ`ImYCMuoO`M&kvWfz=D!Sv2@Cdan5a;#C0mmaZ(qqCsbONZ z%4W(!+s0{+J)bbXqGJ%9G$HnQtlR%rMnTBUNS8+G`SZ@k1!wYdHfz_mCFV+BSbF7d z;_)V0_6g-qUSMxa`hlBYP$LWoZm0`V{6w-Zx%wMT`Ica;vce{E%*v2^~ zd*G}k$z`5oowMJ0hj6z?nuGm-dAip*nT7DY(s|oXu`M|z?(D}9eBUJQ2$3@AE-7$4f371~BHY2Es7nTYgeN>TF>O?5sRL~ zwfKjwUj5tY@wEk=UZNF;Wq2*J7Yzw)Ir3uySDqXX#as;!Iufk69}j(#81mn5w{3l< zUrFRknvL#7!o5MLMimW3FRd=p7888!g$&AKiH=eZv#G zRyEaNS-p*_OhHKBsQbWc+!<{jT)@3rAxK*5oN&MBMG|dq>Sdd<3DeeM=O?+fiPR3# z_}Klm27Mi{AT5RT^Lrez0{TR$j+{vS2n;PRMn8i8vzhN`BI=*>b2BB6cB~l1~x1MOa(P+?`1wpgz@nqQCA z{xS?Q&C)LpRFmQtT=3!1$2a!$FIpN@*{i+YTUkPu+eXwh=3{IO%g@-Nj-RYNI8hh| zaFtGa)x78Y4=wtNcZ^w@<*1#U1>2?#$X}a1uq}4<2F)|A?k46|DC2J6oZc6dU5|#p zjtSAI5cPm^%D_qj2`t8fv74PC^PNSICGSPGX7Zchienf z!j}r}6raZeE)uG?j}WiXMTk?NFB9Mw>^L>i&~B?IkZXS%$m!|+`DSfq5a=Z4rL)|d z&g>4{BB)~}VL;Mi_Qh={tkIg-0)JUuss6ou?iQlQ+l)QCvR(5G2rP)XT}wr8 zZ#vcsrwZ^U(kQ@RxC5%t0idFBS?FAnBJQi|R@9Za0}1L=%VAJ=)0FFw)EgVkfrxw< zxfQ2xk^J}zZF<;-*U8rhrdA_pH&-?Va-v5}nHPV6+BV{Y3`x}ZN#%y5pL=0|jgAs1 zCl~xPEIB^i^Rx0h+sgOM$*XbA)cxS6A}!u1%gu18d+qeOk<4~a`c zB0=XDNE!h3d^UhN8$z6!YJNzO9;mf1{o06ciZ3D4!790uTCKhT^;?8N0Z1j2-TrWK z*$;l*Il9b;KcE|EpMlG6FR7>XD<0vodLlR6d%5OnK!_*Bql3SrW-49upN6#fpc*zH zS1FYj^Hgz(g2P00ZSOC_DM)8L9)iYTDfNsB$KqsNwowxUD{{i!qE)m%;(`> zn1{t0@dT|=1?gJ9C7HskFe1^U{=7qelzcrAbty+be7%6sou8S=o)*PV2zGogPl%{gW; z{q6WEiVL0L_!A@y&X`}4p@!c#(8uGgV#t+p$&_D_-m&W|)O{fQt-~_{Kv<rJ~#9XA43G?zS>Ys(C>LvS=b36u2EI{PHuWNV7AqHkEZ}nU-~C=Zx8@b zL^JtKt$OW)<*QeLyUQ}t5f1?1v3hR}7sm%vQJ&X>qlXb70rMZ-)0XeCI?TC3--3t%6`#o5Fy_z*9MXgN z4d^sV?Q?I1PeM+cM@avJNBQY*FhP%9ij(=X-=NQCnjjwhm_CdP1<}qOEv@`CeDW#83hij zdMRM+aHl?HGGck*%^puAn|V6lff%(6 zO_RuB=>%hJKzB#wbgQkyl=nl9ZLZ94A$&ywcQQh$J{Mj7ER7NWfcrB$(!}bqbJDfWxpgzJC~C@8wo8SXf~NwFYV_CCm52@U?|Tyza*nm&b@P1h`r4LQ=*<76IXzWBTyF( z5TdoOaX_O~K%;3%XCCjSB?4#7^sXW5k35T)bSMNSjwBOERAKDBOoF_5HmKJS<@bEu z-tmGC^$nX5Zy;&}Lc~-z^iAn&XP;jC>unUWea+-eCV#!7_TG;*Yy?WfmuUJbQo$bI z^u_P79?`O)$JL@DO`uIz2GSn$wD(t05()Z3K2q~N6oi`0Z^TYkj2_1%T0ugyTQbv(rf-$J3%MH*Y)UQ@c50b}&Lx^>4ra5`$PAAs#&%dnDU9knt%iw@OQw8s3 z{G`JIjr$7d^HGBayPagcApJK=jx*#Zh*xvMf7EerE!gh+XLciUJ$AV5tkqHq?t|W0vLCd)lXhYSVs1M$8MtB4DH#BK#siO<(lmN_bmw6TC;3w;EbZ{-oOxWc%5INbK#LHcQ{LdBb36h?AarS@o;*A zP3KgKx2B=TgXF56j*#-<*D;PGS$V(S`5gswCA6FxA8u=BD8(#XB|Wgld^PlJlTZZa~mo0q97ftsI`bG_CQgPxl&>;PpLJUPm-&N*&rgMhFU^aI)$a}~*Qc$E zbM$do(e5qd0USBpxr4G^C=Efko+#Cn6LC;m@4PxNtshV!BW{eh;eY&!MImTZPM;3w-iG?mAhNvR1juB% zJ7A#1gZF@kZt36GLZKWQ94AhrcseWNOZ7em4M)425W6ckIQ%Ag<(c?EQ!Z+mq{>uNki0qxR z)q%_c6Bg7%djScU^^NoSsKCxAvZ}ubl5RI{INgfm?ZelF|I>`nK<(Pw5;p{d>ZukY zJNsA!^u|V_UExclDzLxV^FMqR+9KcQ4B9;KqKE1eBMJBw6d|91!$ZX0aE|-@uWO($ zS5>N#<6pf`^n*zdU=^CJ(#U-{{tm19=O;L>Mbri`POPTuhAG~PRY3h{oDBZ3E%9v@ zxU}w{KZyUovNKdGK@E2>osTzo_ACI*WH|3DC7<>ZObliFzdqayHDs-a1P;7v;B7p*Z(xC{-Xe1pXEz=?tC((r z*H{13!S)h_CUQiFUZc)a+@o(~2{9aY>47^*9I$xU|FH)E2ag9f*kDc>ZAct!Ap1FA zM);B#*^1(s@BiZhc+*DoHC|X)h{qdIC9(7+_?`d76^@DI>&SU=z<-oz`HT$h12qLU zMyQ2U7tG*e?yUDz`=BJarXP90X8nJ>&@d;_w7f~4$w_CIJ^dGy>go{A(?--nvjOq; z`cLZznTWH+Fcr-eZ?jr@YzlrG;?M!|LfY2&3|3tI=fz&}VV%?Za1zriLy6W4z^Kl_B8RuIo){KG@|vN3A&!rfn%41be&{GY?aN4Z>gvw2cNtD<3{xM zqfKcxk163)KmGhVwI3N>xO|o5$5sAsQ(_w?wb0%gQaXQe@aTRpGC9$EPcE8l$LDsy zSofKi<5yY!i#IranaDPr0dN08)xo>7og$w(3%4Y)Q~Qt= zm3#ZYe%cNS0YhNqaKVM#1*wBCKsS+twqJt}_k7I>HE=C%QSczAAh)g z8EsityyD)GIhJ2}hG}U$7}oRe?|kS+d>9!{MTFI5W_(`XXOY+lWY|HSB^&&F>;Luh z4ZvW_99clFM;drvLM_ zgH~PaC3t;^Li`Yg;K6SL-His}c8J0U>SKQ#9Z6BCQHRrj|H=Hpyjd{Wk6O;e?H$F1 zievaE5FnV2-2Q`UYjScpg{*#Q(7Z zih^nv;qGbo3H(zI!*v8`-Cqg})JB{+6OB*8|8e;MZ4ala;D9?s-eDUN#$%p)w7sfw zOwge2eX%3n?l*9KDEh}L^X2*LLwyb@l;nyE3T(&UeN4PgOrrjF@y5O9@947Ktdh!hH1vU93f(uze7NBQcc!ZhfeInRuR|E&4E`FJ1RQ; z97yuROKlD=`oiDCg8oFwoKscCl&d!LcJHBm2r=5j%bB{A1hI36_p1EokNa8+^6PDR z4~cknk7)6{*?-?4!Y?^6um7jL>)>iC>)H^CNU@BF2qHSZRuG~{k!l%rW@u89&=W;P zsZk6FNQunAC<-%!g^r3+5&}V_ms~}_f}r9Rqy`H}sEPrkN2RmkO8|N=JjA6k-Ay3S> zh0Ar~#(g5bXl&0bR{c0st+91_VLXONCN1^q2!3s9Tibs1uE)`M&M$lNd@^|keP+0j z415EZb+A^>t&ApBqYlaZKSwrIICqFJ_0_O*&;)3gePn7eg#2@a96zyi?Ea=j22op4 zg16pT4=KT#YLm1vXZc{v_al#qsikLWisJ4?a~%@Lg%T|suJ9`>3R9BGS|09VJ^kb! zVxHvr1B7w$sT9vwXAC!Q_gK};`Po*k$K`Q2JMpQTx`l7TmzJl_=s0&PwPfs@Ys{?XXyNG8dOwnt9{<>(_o7L2-7x1zptz4M-##kD^TX0cT()f?ZE-34AoBfWkRub*g2c z1tD#{P<pat%ipNkF&`Kn6k}HHV-5@$kYeAG%X$syt0r!W>sdR zCNhxOU$Q6J?OevJz{3y$s-P`Y#r+ThV$R^8y%OJ3jUhZ-VQO9|U* z6dkWHPpCYsL!A(hM4402a)TN&>bBEtDJ=HJg5Cim`&_EcL#aaFcn0=?1q1p?A6&Z z=^MUYXulBuhuGp$y+UljbY1?CyTr?CMnY!WkR~hxw=XnjpWf>ysyz+rlY^?RA_c&a znjoG_k~ktJJ7{Ao%h zf41dlP)ZW&i}T5S0-Q?E4*dBq4_M}?5)6ekPM)!$%T(xh=5aVNOh{Vz2f)CyIa23g zop$LgjCBqW9pT)~EJga-Uh3>DK&ohihUq7lvva>3wct3oVR1uigF#t0R(a;k88)cl zZ;oaEn0u(p#Ft>AVjZS}yZ$n29(*%Pw!6fp%$PxXK2kZ(F86$fqx15K9z39){WBN1 zWDsJXp?J;0);!i@+;G8T7|S^@GE+Zc$0h z2W8}-l~fIg2~e z-!WJPR@%%&U8}s@WKy1ty8uRtxl8PjEHgUX*Yx#w8umMH1F$7*L7J>|LbV=~fR+g) zPw*a4jlm19G;@_1@3@CZQA0`#pLZraj%szuI>e6j+m|&C zjLcvx1mU}~(Q49~(DGw>=Rb$8z+LTmIs>z@*B)ZuHoOy4T#wM4Z{>2^Cx1oWSWg}Q zz2|Bn9WIV6j$ZM_$FpG{t$mgvBoiFy_ZYfAmUyG3NX5!?z%?8CS+ph3Kpd>DHh33) z?$eupw%YTJ)!n4_V;TZj4QVfuoxQ|!1VL-hp0R7mOf{s5a*zw5=Euj@@}M^{F2NC> zr?O_BG$BLf45POh&0ozDFE+h3d(Ft6{RKT9sMj<>+u=~swNu*%1J=&j2nErFVO9J; z%N_&H{f=w3UBuvA;3sKP0(GGqnsb_8M7Cz8{cb>eGWVn3bLjle2{<3|NOQGumK!{E zO1(G0aCU9FwU`eYYpb;L$Am&q9Ias7w%T4kUOa1;NHU^?l!mG9ZKMQL*IM`Wrn=@e zB+c5>3=_@#dBTIfA1(ta23pzeoYTzOI#$F$SX}|c2D6;UgH7-!bV{bhA@FUiTx%e9 z#(l}g5QqWRUOCRbO-d!U=GXj#qMt8(a2j+_FFPMfX)@>$3#^;db3z6n6jr*S=a20w z`2_tOlVx48k}w;1?jioU1(=q8YVq^P)-=Fp>4~ksP==fM+ZLoRf6jx@zc2G^z&~>= z`kPpo@v1=I{|{sS!30|Lo0pTb9#_^T9WhQ`^)@5dS%5i7Bavr-O?YQ#pygbzwMWbZ z*}`Jzl{z&4ipRdaogMcqokE|*bABe68=JX1@P+=CdEW3?5p5=T3_(cQ((gT~eZB}} zQ-l1YMxbH&SmJw_mOiZZflc3D&tP2vk&6q5CNO?&Kfz%+|XBeb~bI~ls$jdfM2xJ z7|dZjee#hNuJXZuCZY;K7~9hm7$ed`@*&*tok#sPmLdh1C}s!iRZwlmm07P$LX42w za_;E)Z1Stte&QD2+{qu2_!~rLcmz|i@-zoi7P9hcerFF5Le~qeDChqeun*&-xWdUk zDUwKvP4~#AImU~Yl-@5Cl@(^ZzEyK|H!Dx@zO6;PGW&gA=@uHzDK}*s$Qy4l(m@0% zIQf%ur)QH@4&^-@cs}=_n{1T$QZWi z{+^k$)0ok(h>EixKEg6#LMEdEbH17)Vn=>H&040Qh~vp+LF{xn_;K4=Uj*tPQu>9(50-^2#`1p(7ed^sDDP=C{*aN7cOyFxHR}@&)7_1+H} z)+BJ-ns{ddA@6;S@tdH1oYiy1`kf{tf0%jNyVDOduKClUOs_ck{$bEU+EU4S$wbCfYo&}AeOD8%MYcsNoEZ>=)@OVht~bI97$_z z0o4;H<`dKY#@JrXx6k;;hU_1(|I9$a4_0S-2mH=~$28kv9a~TQaAk4n2@679^qWME z`#g*b6AK&P5g0%?CZgw)>R+t~yEQit^Ec(e8}MB?a&^|}09Ve^D6z2hA_r z$^WQ+f|nF2Kw+&YnK@Oxv*jX?LwKWc@`%xBtKP;$*QWXgQv`nvgJP2x0LUHJkpzlc zz;4dA)3)MijMg6#R{|2B>3=Y9WS85s^6y1*HWMJjL5!mvXhsN44A2|lFJcJ#BqOan zWt81y6yEdJY0mZEgmk4G90O}=CqMc2I~IFLX&N1%*Ltce=&IgGTHF|uu%d(C z;?k-#qEVJwmQTXR;(N**;*NQbC?Rjg9Fi86M+j2&!6S47_@j5JXW!j9hbZZO8)Ohg z@D9C^l*S_Mva*T#=KLHF&d+soB4qqFkp|3C5?U)KwKsXrBTLr!5k=rSRJF_xR=)lU zsy07AI&hEWU5*?0IJdgJ1qgdSh6!CiQ$1x}UtaF{QvyGqK|C#AnBjk4gH>>JYwN&V zqAQmM{Rz97jwlE`@%1Vw5pF=2ta8a{Qke@(WgAI|F7r)$S+8p+U-h=c)7Msu7WBF6 z@xy86aop%2tC^f=pBK_Q!Z8n3C*nAI0QrO5#l{9yt_LW?+uMH1!_1a&K&}6pn2+@c zxy`F9=!kEBL)b03bU{K0GN}6osLB+1iY|0n+ z`9^w~2nU}ORbuSLD4wrp|#X%jrS>&`Dzh3v$`ma?#hyT@5{w3_U=BL}R{ ztZ;Yz&k<67gmMSPa|Z}hUsTNlHgg_qw!jts1YuAGO-0E)iQ{>jf&!oaPlvD5dygE9 zW0dyUtQ*#w4LF6xu4hC2j2`m-A64MIkJIbO0qX7d?)%=E4Gy+Y6UD+*gwMMX(h|pu znu@d^7(_1iY<}x=f+tgD|7r6KVx_B*ecZd=QQPM-iY?Rx;BCz*)0qLsBDg=*yoLfu z<7!=&_kHJa5(QDQ4APJmt~pyBMEMPi)ex@b=X#)X(&umb-_&5G<*D}j&AMsgM>T5j zm*Jq>x+fkstmF3_`~O3tM3l3#zIL$As6PzwofSBAUusRd(_y6oZzDJ{z^dha?7Mu5 zhZ~>ph6sy$rmyX^Rjiad( z7IYl*r~N|B<=!;^R}Jl^!Td}MiCim^Oe#MoCj}+VR)|6W?z~tnIcU1zX4S^mE|AoZ z;+`36-`B7{Z!Zm~o;$CqR13vFZ+*!2_9E>{gQTsV%}x1yRqR2}XQ%{@8a=z~RX3;N z%LUV9GAfu%K>6hjgGKU*^nLPHZyxg!h~DJ(0&iM(;y4^#KIJ(U&rew3ZjO$%L3xu# zj~JFy5dhuYjj%G1u_!l|I09#N0v<=sj9(}!cpep{(2#fAQ%iQ~C#|L+5oCNGxfRdj<9gIcfvZ4I+9wvvjx8PF|Bk65FvZfanE>p>;etSE@!Elg7Y<4U4grsdpH{gg{BT4p&O_Hh0nER}rmTKh$W|{tMhh?|{|~XFh8678hb>&`sBSasAwcK8Ue+cf ztXUY)txjs3X?AlhKSOfXMkah?ZGg+`Gvmju&z3Sk04L>$D^!A-5AEvE8xCDF&`vbu zL(-7E3|mJu4c03E?adJ!d$2h~RN9;+I;gc@NR3&=pRh1OL?NvQKM+U_kO}q=!08YAVQ^cINtZd^i z!~l#JaLP~l+P<*3+zSZ*mKAKddnkBC#G|Qozl4MBZyL2)nZjp~x|?Xzqdf_R2uyW>h& zWfiWg?QB7}Ctr|Nx#4t%Sf33iu;m9_2Y#Ky7_LVu!M?0m*K-+k2mAmOhp#xFYGR4; zq-wNYLC~q!UNcQ>_Vc*iQV#fczk|j`mEHl53;a(Tqb*WkjkW4?sy%Ky@cZ1dpwbR1 zIR3Z5I}Qhvau*Ny>3#a@ulfgP(Ya6cI|eft5#(!q_CGP>Ii@UY(~qd=6AGH99|7&l znio(tN!|A?>!Z`<;eHOfQmyFFvFfojlCwt31MLF_iCbM03H&?^*u1uNa#sbbTU9(j zZcbUm)3S|NgF3cB?_bAPWF{{m0vuYMBiiH039z>yTM^@+-W{G+7;5BIU*#0F_#9td zr8?6^;LwC`My&^Mb+aQHAT7#bhaezIMt=0*@5qTBy9WCiY&U;x|=L4RUZQ zBPfA`>v;5P#$FI~a1fm*TPVfU-8IXeXC3U$AwHS${09eD0R3Sj%f2$Vy)Ria16R{3 zgC^t}En0K^QJO6k&tBgb=ZjAyQob;6?7C~+gqoNCaSoS&v<6Kq!DNGcNa*1*3BG)= z*>Hjt4)^EDtq3%oFRD%&w++b zt^^<7Oj$9OGKUTzEY;tLMh(jbSB`n~N-4OqI8Db?8^jK8Lts88sziQ1Rw8J=%2?m53ynj^oa1DKX zm2gtuF+DzADd6Tk2rSpar)lByx4va?HOK$SvloFcm!7GKZ6F+&_$$hOi69wnXX0ig|>$%1A1H< z!;cs~i_SF%g}7V_(zW`^kIjcp(xXTbTGXJf>1*x# z;@(OoZ$@*{Ebz%}8{UkW$@oiPhc2@jgesbb6Go@*zEtM2F*QJ~Np`LMLSC(l&ZTzL zc`7)mmn~QyXA5R->L-R6hTb{%x(;v)9klrz1CKM83!KHUsRy+&Uy?Cd$t^SI8y7Kd zL28SkNp)FmokCvEMM{syT8<&vrS<7Z1o2BeoRi1OrfiQ1SOmnuXOg*%LLn=fya`h{eVb^sdb_ht*(Gl6DG^Fh|`9x1l1~o873C-aEJ5 zc}GzFhe*pPr`qkVERIpO7z%9Z285&=GR&aW(9~$g>zN}U|Nzq zrX}x4?7)38CiQ?B^{;$)eORQLgw3c`Y-J>Ab1JxOgn;+cIV|yrxjYpiW&qg_h!!S$ z=kv)psprK#vxCxgUEsJIoY98q)2FE6_cH%=jfwF=X7clZP^seRIcB44A$*tH3EhN9 zU?O9H685Cq&j=bCbKkH4COGi^q&AB{be=OjcAaNk$pmYhIkS*qB}m{PZR=oMqhTCD zdL51aIyZayomX{CiAT>iZ=u#A7Lk~rYyzpl)w#7sk;z4?1%JK#eu_z-P!#+kaF%i?^5moFYhwk%ICPFKi6^BCzC>H)E^ z#XWV|ZJ-l)XMqm|xP`P7<+Bcci-vdG-_QTpzybR7C(u>90Kz#W(L>US@7XErIeDP< zZ40!nwW<*_nae-}PF%NuO#w;egAxPtNjSO!-oi}|!eXh`xELtt>#=3Hn8$65tzI;9 zD?Z0|0LL~hzf+9=-OWDf;54ty{Rf94D#0$OU~4693EVQiau)%Vm}IGBlQ;ZfUJr5_ z>l$0|1q>`YTpJ(a5*O@HKapS1x3EC7S#k8mhY$ZA0w>tSdxFk8P!i)JjLZrAvNyq~ zhYy=0sZ9`G^NF_gNL+N@cJ6Ep)ErPC{@PFS1xYa9$sW+k^hE>KrYU&t;8i)YS}ZKI z0Gkz=_->sS^HBj!Pl}IEkPj!Cqgf|+3Q>I{8}dtcaRotph$yio)^(Ylpia}2yntQh z<$){umlbT$>IEzO%WJTzzY<%c1Bwi8`_n=vUMhdki*R1!a=LLr;|BC>BCXXk)Cf;l zVz%(m&iPK6T@oy$jy-pc`RdfO?nT4dBMXmky&ifV9lam8wcxnC4GRpHitr^T*|(nJ z@7Iu$A_FADYFn06{-v&u^NJV1Y8G zz4>cGk_R>$x3ZUSxAu)0)|TKC|Ec~#^u;VqM_)e{__UeZt;;q(L{w}SUW*ERymxBf znh(j{(n9UN*B40d*(qG%2bKyc0Hc?W_jsJmOV|&AchAmIv*trx{abOTh+HghoDq{m>=6BnmR_FTlvhhwVZ#kk{n5Z)2lrD}uCtnoh?OE4n% zw}%!$zy={wadF8&Ru*V*t>+BT&PW4ELIjWwp$8lgF7QU0VCeRRC;&I=o7Zpjh-G>{2QFobWA$P8}S8OfSo4P}RU z^cs*gtB~8zXaeNOi}J6=!+V!EzRuM%nRScI56n2m)U?(P7D>9^waBs zdQNZRBLJLE56hQ4j;UBIHE%d?MtjsJh>E++DR0d+XYE^FEcCXiN9bXUc=BYtL&IPl zFNLsUyfXMbiME4pW|039!Xq9UlL9jB;s-Ij*k?OSJyHZ|75Y&A=RLs+F3Zm?aUt^> z5HeUiEO#mytqB+$jNrrmZ`{zZ?6+?gd(Mxq-jZ-R;y zn6puU8cebz2KVk4svYIjduBcnbCGN;ykq>EYZE>=b0u(|At3(*Ho$rb3#oohsN7e# ztM=#5YiiNlSJl8ZNB31cXztsEFZHjxm^`T+9G8LA5DezwYVBpOS?yxI__)QaU52hmn(0W=qZ|L&|+Gb7zNlQsDVy;5h zWq7jhyz%BdM2pq(W)kPDm>Z+>!00xS51K{61(&6XYX)iMx+ij6tRoC+q1bi}yt`s^ z*!<1p*MlJ%E3$|&HLHUsfCP2{DS-Rz?N)(&?*@UnI^-ye!8mhc92ATnaTSc&GPSvf zP=VVsoX|@7jk#AN44VDKFShqdZ{(6DE=cA)b*$KR;9tt|b9%gPWeXl$qy?I8a|Vu` z8;BqtmGYp!_;8tp&0q&{tI_+<+w-WCxKSP7_8};wj^bI+nEOJY4A}SSTVZFCqj7mq z2TwG|mV&O7bcE>Aj5ZsY5y_UUKNr(5_FRVmWRYJ5hY;q?ywFR=H>ek-abSL#9Om~GGQhXAogliXV6pk;sTUB)eUqQ?&W=%bHQ>Wz^i0W{7W*PKb~ z6oE@m_ZTkZ`0c~)&yLoWCI!AD?AEw6-vs0v4MBKllwE$aiSUJ3Xv7;AfL$~@;_epv zpHY6u>dXhD1JW0G$l3iVBm?`R78Q)++6H)?8`z8)28RWMP~)v~I4gj{+i%NrPu_>Q zlCe%0!WXetfqW`#ZvbazeGW&sPO<*t?NA*`dv{O8x&^k71}-%Av-;qM!WLFd!>&>x zUJ$XbbFixrn3C<#sa5`+%$gP1&ulHYQ~?bujwVN|d@?90rYeXtcoQL4jl3mvLq0caL!>`vucsUV)GH%#M*@eCY9 zRz+goeUe!ZBL${E$66RH%91N*bE-G)Dq#H-r{Kob9UlVM*9eoxwoC<(z2!Q$v`KLW zZ|BhX#sW+{e`0Kh@xv9R+iT7l@V;6ELa#3LJA*34ruSoHLO(BLS1__8r;|PQV1>(G zclhC@cISU0xe$fJt(9Jr5mewG^K4T6V_cXvXC`y@ETGF^;b>tHyi*z@a!5Rmb?~+S)gR3hs+|>;v3x+s~|V zEqs^AQ^#eyYvdTnJG|1{&@wKj3D5UMB*PIrr;r1$k_gHeOK_FPkIad0p2q|?BE-PO zuIY(j9v_7>laaQ^In$o;WQR-t{_>XZbv$b2Pc3 zEZ5&b)8R=icW>(Zc0fo&1$B;;Q4sjyg|;kyT7w%6yQbv}s(??!YrE^672eqnmz{$b8RMi-m(vs7hZcm@0PLWC?8O{q^uaqqg~Zo$=|x!l z4HECh492W7>9&FE7es<=_i-Eg23u_!@hr_(=zo7MHP`Swb_17@;J(SU*p}V)-=o=L z$sc1x$u;RyzcG(2D1H-PD(E@z$ED?YY+1) zqW%HysRn0{CAtKZg-P|QsY7TZVY+>+%SK1$k2HUusqu-ye zMO3VVHjr6PAkXD3=i6)%QO-{Ces|rgb`;x1r1CaV*am#P42PT&X?y=#lpK|OvYZgc85}e zKW}4V+IHj(wplirx!m`~v&jL(ExKc+>xPCPrL1 zwYafMl~QSF{A@UPl4B)WuD~N7hxe0}oQ>8or}!CIei}5zSPX<9tkc8g0P-uL!3Qj3 zQe6f*zl&Py#mAL`)V*G6jm~Me5I4u=ID5HCE&uC(2X{$p%rh~$dI+DvY9~#3=JnJs zrA=@RV9lP1*r$$k2s=}#35}ozGyyK4)wucL0sf76n8p;=!ts45tIy~!rZk87IG=h{ z@D|Mb3{w4-jgL3&K?cUh9;b?OI1Ck3*i*MS!G@c_KSw`0*`(mn9#{#Qvx1Xq${o<8) zYCbUDtuD;-Kh0dHJmEF5r=B)%K6MVFF&@MrGigNW^L60uAEEOnHZQ+`p2OLwrOXE` z_oZeACH%noW@V#&Ac2_%|Fc|eZ1;Y*&$Tb^J$L75h4`F(scA10ay{O&gfg*-4|NNR zb*6#7*A7^boFXoqAUtpX;9m9#`U<$tdR0x`kr>Qvb}%s;*UWx`hUFRqk1nG#;aeN+ z2b*hb_f1i9YdFA^x6ubtca*h}V{7$lR&xNdyMRyNEm`9QUSPAI)DF5=67*j6d9aeV zStnAlh@}kbzK%|PG41=+vw5?wX}uD=SIUbEXJt)U5rz=kM|bN1Vbt;nLjepgk;kfG zVz-i(AAe!Ufg*8LjmV~vXA|ETRzM(=mGiCD`xvOMyxej#f@`u=Fmx-+7|$)#m}t`R}PCUXcfWC1*@rd7`d=-AfIAf>8}(!|WB~ z5NQMyd_}p+cHmWhg_JQ0xNU`R-pMDIV1umjHfXJwXS7)=#lE}Uez11g7cXw|dZ$pB zGj@&P3NZTeWdfFaaAHQ?&{i;IyB1ZJub@_W>IjM}>H)7l>&SOjPIP$3N@LgD;KvKf z<})$e@1XFcPI7W;J-Q59$2GR%4na993KYl78T6}>$Mvu9m8m3{;y_B^k2AfzHRv7ditjPpb@fGMdRl37>;6rEJG?&l}C~0PY~T!g;o>V5|$qVk%b)On5c^eqBBC(Ziw4Y32M3FmclA>2lOxVt^)Ov&qOxXlWj5w+0dRpL?We^S=hX-YSe7Qg-S~2Wth{Tgy+iBbgt_fSXGIlevy) zgED^%;q|(Zz4K?_zy-(W(Z&-rlD`81Zx;1isVZL@k!@rbae@y|IuRb<9(biXrW@h4 zyY5{srwa>i0e3K*8ZbuojwqP|;UVrYeF_sWBD|s7vF-GP8&#?Kst{5Ba>lL2`&Nib zz>Affg)tlxBTe&++dv@*j zW4$c-BwE}0t+b#(Z)kP*S>F=9T#e*!eKjQmLlenH!U$1`W$X6feiN&*4v9x+Q_S)V zLJkT&U$=9e$lO20pGBN&Sf}A=G8yx}u4hVNA>ybX4U_Y!%NG4W8P!PHjAA67Sm2{?l4#zdwo_gHWAVjB=9zw z0@o;5=diEhoG|BqDBOYwwlOFj+e1jr5K8@dMkh0xL2FR`bb|~}+kIsD!a?Y9>{aXm zha3F%lDLs-PiO_Vm!5K5uDh>so$#7Jc(O z{V0s;{G1BJa;v;)^Xt|mleuroY>-Yc@cM^vm>J+k80;GdNME4lJvfS}8phzhe=t+Z zO4#JUe6ZP2r7y!%o6+i7p1U+3L~g(5z&4fzUqO9=c>l|%Jn{ze3ewQ3-bVxA*PAKLt7xtMl`-0*eacS)@Oh63C;_LRRVik=`EW1_MRF^MI@W@C1H3%t=UPJi4syBn&L1~Lv6j4sP6 zHq8s);P;&Zcu&<>3>m_XBn*0UtRznC=80t-*fv(K2Jfo1W_@Uz_0wvf|b;?BkSkSTo)&utiOzNL)sto%7&& zvbuHGDe)K5>u1ja7>fFIwfu%DbIO#5Zl`{FQ-Df!n&AO{Un7hlufyjsPQXUb?L{xc zw&<1}^A+9rQaS-O=|VV1*hrqlbo|w7%1_UGaEnBTN&Qx3ZcWk5udbO*O)po_vZ~Ey z31N@;_01yjq-<0jIScD}eo^EBM*#}*xd1i(jB95shJ#J)#V(^9%;*|i``IayV*525 zCX<>?Dp{?*4^L;r|8F7i*z!Ti%G--N_!gISS!1(m>!ok5-ZyVQS|TZ*f~)j*Fd)}D zlz#tNE54{(M-4+bU+sBLzJYG1Xz6{U-QUbAaG30BM~BXkH}uX0XYz+`zP|~fTT_4P zD}}Ei?7_*1R{hl=LTWI#7n``FKz@)g;WE#WL_~wzyYI=gtSrkbPY$aI*b5!-?jp=U zh8Z}_@_ibA&B7lF1HT^3aH~JbN+I=NoDo;0_%eco>Mh6<{s>-5sT?~JuDKd_8ZB)1 zvb*T&ckmG_Ye0qM;*geku;rEC%mr*>4_zCPvKq%?3^Lxsv1o*6UEI55OnIjbR;beYlO~v1Z5EF8(rd2P1@JkxGs{1J#Wal*Jcv@oqFU1~t4Pp9r-f4m)v_ztJck-HG3udKj=GEp;n^~>Fb+=~h zLDgLR;7e8-9ME~{5a!;i;6;%Vg6KxhjQ%g&m)0j7nXpOp{B7L|v~b+|U4P6*Wx6%M zuJk}hZV?9KP?)lF>0kU&D3N&&Du>s@@nq%3ZF_`ID#?Xp4mu{SEKhQ)%LBgYEqoe| zu{)c5N+o5I@)i4WgOT`4|9yP0SsbdS+M!m=HfO_KEGms9Nt z=n+~mn2HoRz|u5)I@BkCy)wjreGpOu&na7!oiIFQWY(tg2FckNTD)o-D;blV5Sf}} z)tcYrmJyYye~!QVTt|%*9ZvVORk8@IIV*H!S=`f$lNm-*eD$5^{ zAea>vRkLcn%{WQ5USv&{bRIBwTO;Bil(^Mm(IU!X`i9)AlUR`4}95##7Z zDD_N3t3=x?s0(QSoipMgUb#jbB1e-8Ol5+?Q4Q!p?28obr4a&vmxXE{^BR;|B22-b`AIloxId2B3+FP9_v29o{lw+rF8!?c-jj(r2jTRfu@-*;Rf&Ybht7tuR zUHH<;64GCt<4=>ommPczZ5a*D^EYL_$QTU%=xWk(dOhDDfi1;M6{0c9IryCmN;#%L zy78FF{jI{^Gd$xs;a?C50LS<>e#kkgt2w-;No{2(a>o{EY2H zn8oq?uJ}t zt+niyKb~YJu=9cG04C>K5HriK`1$tKhpZ&>*Q8G;_!9wJAyONW3WzKRB^{5IgPDv# z__utS7t*)ZPXpCwuQOUEI^{IJM5+KuttZTO_41c=&5m@KI*%Dcu?kFdc+J z^QdzD~`T2>8u#zi>k})cXYJM zVeKo`8?zL+LFj^ngL~3X$T-9jij#HVnKnbZ{+|zI9Ods{2zZ}GA8zsMSKA_@;ygjK zD9iKzosfO%4l8fv_^J;|Zz}{rP*kG#f57=GT90HWIhOgxDIn1?NvJD7zZP4WcK&h% zo1rqz#H-NT)6B)D-jgtsklCJ-o=lZ1!f}XQVUM8;CvbOP1luty88V=lG;Xa;Q7clz=Cp1V zcy3^bdh4ilrA>s(1%_wW`c6JzJn}mVHIDcjP?`u>ePuvltF96)J{c8^*%HnZY8*b% zya+>#5nnpa^Pun~8^%ccoqD0yL25FWIu+Xx3#Ee;+2@@5^HfSp{9P z{UbT!2j&lSrzCZ`6O;jcNlOwG5NpA-##m!X8mbH%JJM$uuuUlPHhoxbS)h{2Y8%>W zdGcuWuD><9PEWE>Wj813vpE}ecdre4axyf(8 z?6p4r3#%Kx2&Vy?wD;35DrV`YvX<17rpVg{)dy9w!w>!l@~b4=iz=a*pYe6zwfIAw zWtB$QK-$b?qB;EfeYqw@(OeX2Hod@|A7ZI*B<3 z5B3g84y2(DVZ2C&`d3b~+?g;V0FENpcOATtOZM*akgAfsU=i}>Fm+N!OvS0f^X|#u zT7Ao4+5TX=M2A4PIPuSwuDiTT)BHV{6Wv4Mn58X8Yo?xh7g;_w!fhMIK4(lwjqHC% z7LfnV?3ZeSC_y#EVj`ldh*D#@mVc~GE(sve82{A25i=)Em5)^y{XKb|Q8pCw&4Rx6 zxp*}On^kU@?ZE2SkDOWrM|E!c!(xr{3Yn_(v6p`%r!L?A)~Ik~;#;L$aMkP3?JU}t zfos`H4T=rQ1q8_(LrV5myplUZr9Q@qMcIq7V~GX`P|* zs2jFL%Y#?^h*f|5r9XtSAi(_?5C1*&pM3rUC<$-F13mw*@F?fdBn=!0eZ-eYgw%2X$4`O#lD@ literal 0 HcmV?d00001 diff --git a/templates/compose/executor.yaml b/templates/compose/executor.yaml new file mode 100644 index 000000000..e6913ae5d --- /dev/null +++ b/templates/compose/executor.yaml @@ -0,0 +1,35 @@ +# documentation: https://executor.sh/docs/hosted/docker +# slogan: Self-hosted AI agent integrations and code execution server. +# category: development +# tags: executor,ai,agents,mcp,automation,development +# logo: svgs/executor.png +# port: 4788 + +services: + executor: + image: 'ghcr.io/rhyssullivan/executor-selfhost:${EXECUTOR_VERSION:-latest}' + environment: + - SERVICE_URL_EXECUTOR_4788 + - EXECUTOR_WEB_BASE_URL=${SERVICE_URL_EXECUTOR_4788} + - EXECUTOR_HOST=${EXECUTOR_HOST:-0.0.0.0} + - PORT=${PORT:-4788} + - EXECUTOR_DATA_DIR=/data + - EXECUTOR_DB_PATH=${EXECUTOR_DB_PATH:-/data/data.db} + - EXECUTOR_ORG_NAME=${EXECUTOR_ORG_NAME:-Default} + - EXECUTOR_ORG_SLUG=${EXECUTOR_ORG_SLUG:-default} + - EXECUTOR_ALLOW_LOCAL_NETWORK=${EXECUTOR_ALLOW_LOCAL_NETWORK:-false} + volumes: + - executor-data:/data + healthcheck: + test: + - CMD + - bun + - -e + - "fetch(`http://127.0.0.1:${process.env.PORT||4788}/api/health`).then(r=>process.exit(r.ok?0:1),()=>process.exit(1))" + interval: 30s + timeout: 5s + retries: 5 + start_period: 20s + +volumes: + executor-data: diff --git a/templates/service-templates-latest.json b/templates/service-templates-latest.json index 00243fff0..b6a452e75 100644 --- a/templates/service-templates-latest.json +++ b/templates/service-templates-latest.json @@ -1400,6 +1400,24 @@ "template_last_updated_at": "2025-08-17T18:23:57+02:00", "port": "80" }, + "executor": { + "documentation": "https://executor.sh/docs/hosted/docker?utm_source=coolify.io", + "slogan": "Self-hosted AI agent integrations and code execution server.", + "compose": "c2VydmljZXM6CiAgZXhlY3V0b3I6CiAgICBpbWFnZTogJ2doY3IuaW8vcmh5c3N1bGxpdmFuL2V4ZWN1dG9yLXNlbGZob3N0OiR7RVhFQ1VUT1JfVkVSU0lPTjotbGF0ZXN0fScKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfVVJMX0VYRUNVVE9SXzQ3ODgKICAgICAgLSAnRVhFQ1VUT1JfV0VCX0JBU0VfVVJMPSR7U0VSVklDRV9VUkxfRVhFQ1VUT1JfNDc4OH0nCiAgICAgIC0gJ0VYRUNVVE9SX0hPU1Q9JHtFWEVDVVRPUl9IT1NUOi0wLjAuMC4wfScKICAgICAgLSAnUE9SVD0ke1BPUlQ6LTQ3ODh9JwogICAgICAtIEVYRUNVVE9SX0RBVEFfRElSPS9kYXRhCiAgICAgIC0gJ0VYRUNVVE9SX0RCX1BBVEg9JHtFWEVDVVRPUl9EQl9QQVRIOi0vZGF0YS9kYXRhLmRifScKICAgICAgLSAnRVhFQ1VUT1JfT1JHX05BTUU9JHtFWEVDVVRPUl9PUkdfTkFNRTotRGVmYXVsdH0nCiAgICAgIC0gJ0VYRUNVVE9SX09SR19TTFVHPSR7RVhFQ1VUT1JfT1JHX1NMVUc6LWRlZmF1bHR9JwogICAgICAtICdFWEVDVVRPUl9BTExPV19MT0NBTF9ORVRXT1JLPSR7RVhFQ1VUT1JfQUxMT1dfTE9DQUxfTkVUV09SSzotZmFsc2V9JwogICAgdm9sdW1lczoKICAgICAgLSAnZXhlY3V0b3ItZGF0YTovZGF0YScKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ECiAgICAgICAgLSBidW4KICAgICAgICAtICctZScKICAgICAgICAtICdmZXRjaChgaHR0cDovLzEyNy4wLjAuMToke3Byb2Nlc3MuZW52LlBPUlR8fDQ3ODh9L2FwaS9oZWFsdGhgKS50aGVuKHI9PnByb2Nlc3MuZXhpdChyLm9rPzA6MSksKCk9PnByb2Nlc3MuZXhpdCgxKSknCiAgICAgIGludGVydmFsOiAzMHMKICAgICAgdGltZW91dDogNXMKICAgICAgcmV0cmllczogNQogICAgICBzdGFydF9wZXJpb2Q6IDIwcwp2b2x1bWVzOgogIGV4ZWN1dG9yLWRhdGE6IG51bGwK", + "tags": [ + "executor", + "ai", + "agents", + "mcp", + "automation", + "development" + ], + "category": "development", + "logo": "svgs/executor.png", + "minversion": "0.0.0", + "template_last_updated_at": null, + "port": "4788" + }, "faraday": { "documentation": "https://faradaysec.com/?utm_source=coolify.io", "slogan": "Faraday is a powerful, open-source, web-based vulnerability management tool.", diff --git a/templates/service-templates.json b/templates/service-templates.json index c193f0934..d279a6a33 100644 --- a/templates/service-templates.json +++ b/templates/service-templates.json @@ -1400,6 +1400,24 @@ "template_last_updated_at": "2025-08-17T18:23:57+02:00", "port": "80" }, + "executor": { + "documentation": "https://executor.sh/docs/hosted/docker?utm_source=coolify.io", + "slogan": "Self-hosted AI agent integrations and code execution server.", + "compose": "c2VydmljZXM6CiAgZXhlY3V0b3I6CiAgICBpbWFnZTogJ2doY3IuaW8vcmh5c3N1bGxpdmFuL2V4ZWN1dG9yLXNlbGZob3N0OiR7RVhFQ1VUT1JfVkVSU0lPTjotbGF0ZXN0fScKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfRlFETl9FWEVDVVRPUl80Nzg4CiAgICAgIC0gJ0VYRUNVVE9SX1dFQl9CQVNFX1VSTD0ke1NFUlZJQ0VfRlFETl9FWEVDVVRPUl80Nzg4fScKICAgICAgLSAnRVhFQ1VUT1JfSE9TVD0ke0VYRUNVVE9SX0hPU1Q6LTAuMC4wLjB9JwogICAgICAtICdQT1JUPSR7UE9SVDotNDc4OH0nCiAgICAgIC0gRVhFQ1VUT1JfREFUQV9ESVI9L2RhdGEKICAgICAgLSAnRVhFQ1VUT1JfREJfUEFUSD0ke0VYRUNVVE9SX0RCX1BBVEg6LS9kYXRhL2RhdGEuZGJ9JwogICAgICAtICdFWEVDVVRPUl9PUkdfTkFNRT0ke0VYRUNVVE9SX09SR19OQU1FOi1EZWZhdWx0fScKICAgICAgLSAnRVhFQ1VUT1JfT1JHX1NMVUc9JHtFWEVDVVRPUl9PUkdfU0xVRzotZGVmYXVsdH0nCiAgICAgIC0gJ0VYRUNVVE9SX0FMTE9XX0xPQ0FMX05FVFdPUks9JHtFWEVDVVRPUl9BTExPV19MT0NBTF9ORVRXT1JLOi1mYWxzZX0nCiAgICB2b2x1bWVzOgogICAgICAtICdleGVjdXRvci1kYXRhOi9kYXRhJwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQKICAgICAgICAtIGJ1bgogICAgICAgIC0gJy1lJwogICAgICAgIC0gJ2ZldGNoKGBodHRwOi8vMTI3LjAuMC4xOiR7cHJvY2Vzcy5lbnYuUE9SVHx8NDc4OH0vYXBpL2hlYWx0aGApLnRoZW4ocj0+cHJvY2Vzcy5leGl0KHIub2s/MDoxKSwoKT0+cHJvY2Vzcy5leGl0KDEpKScKICAgICAgaW50ZXJ2YWw6IDMwcwogICAgICB0aW1lb3V0OiA1cwogICAgICByZXRyaWVzOiA1CiAgICAgIHN0YXJ0X3BlcmlvZDogMjBzCnZvbHVtZXM6CiAgZXhlY3V0b3ItZGF0YTogbnVsbAo=", + "tags": [ + "executor", + "ai", + "agents", + "mcp", + "automation", + "development" + ], + "category": "development", + "logo": "svgs/executor.png", + "minversion": "0.0.0", + "template_last_updated_at": null, + "port": "4788" + }, "faraday": { "documentation": "https://faradaysec.com/?utm_source=coolify.io", "slogan": "Faraday is a powerful, open-source, web-based vulnerability management tool.", diff --git a/tests/Unit/ExecutorServiceTemplateTest.php b/tests/Unit/ExecutorServiceTemplateTest.php new file mode 100644 index 000000000..7e3d0ce50 --- /dev/null +++ b/tests/Unit/ExecutorServiceTemplateTest.php @@ -0,0 +1,49 @@ +toBeFile(); + + $compose = file_get_contents($templatePath); + + expect($compose) + ->toContain('ghcr.io/rhyssullivan/executor-selfhost:${EXECUTOR_VERSION:-latest}') + ->toContain('SERVICE_URL_EXECUTOR_4788') + ->toContain('EXECUTOR_WEB_BASE_URL=${SERVICE_URL_EXECUTOR_4788}') + ->toContain('executor-data:/data') + ->toContain('http://127.0.0.1:${process.env.PORT||4788}/api/health'); + + foreach (['service-templates.json', 'service-templates-latest.json'] as $templateFile) { + $templateCatalogPath = __DIR__."/../../templates/{$templateFile}"; + $templateCatalog = file_get_contents($templateCatalogPath); + + if ($templateCatalog === false) { + throw new RuntimeException("Unable to read service template catalog at {$templateCatalogPath}."); + } + + $templates = json_decode( + $templateCatalog, + associative: true, + flags: JSON_THROW_ON_ERROR, + ); + + expect($templates)->toHaveKey('executor'); + expect($templates['executor']['port'] ?? null)->toBe('4788'); + expect($templates['executor']['logo'] ?? null)->toBe('svgs/executor.png'); + expect($templates['executor']['category'] ?? null)->toBe('development'); + + $generatedCompose = base64_decode($templates['executor']['compose'], strict: true); + + expect($generatedCompose) + ->toContain('ghcr.io/rhyssullivan/executor-selfhost:${EXECUTOR_VERSION:-latest}') + ->toContain('http://127.0.0.1:${process.env.PORT||4788}/api/health') + ->toContain($templateFile === 'service-templates.json' + ? 'EXECUTOR_WEB_BASE_URL=${SERVICE_FQDN_EXECUTOR_4788}' + : 'EXECUTOR_WEB_BASE_URL=${SERVICE_URL_EXECUTOR_4788}'); + } +}); + +it('ships the Executor service icon from the public path used by the service picker', function () { + expect(__DIR__.'/../../public/svgs/executor.png')->toBeFile(); +}); From 7b7d5a0aad5feb37dfee42fc6575d9f1b141b17b Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Thu, 27 Aug 2026 13:45:26 +0200 Subject: [PATCH 02/55] fix(services): add CDN and default logo fallbacks --- app/Livewire/GlobalSearch.php | 3 +-- app/Livewire/Project/New/Select.php | 26 +------------------ bootstrap/helpers/services.php | 25 ++++++++++++++++++ .../views/livewire/global-search.blade.php | 4 ++- .../livewire/project/new/select.blade.php | 11 ++------ .../ServiceTemplatesLastUpdatedHintTest.php | 23 ++++++++++++++-- 6 files changed, 53 insertions(+), 39 deletions(-) diff --git a/app/Livewire/GlobalSearch.php b/app/Livewire/GlobalSearch.php index bf64ee8e9..c6ed818e9 100644 --- a/app/Livewire/GlobalSearch.php +++ b/app/Livewire/GlobalSearch.php @@ -1507,8 +1507,7 @@ public function getServicesProperty() 'type' => 'one-click-service-'.$serviceKey, 'category' => 'Services', 'resourceType' => 'service', - 'logo' => data_get($service, 'logo'), - ] + array_filter([ + ] + service_logo_urls(data_get($service, 'logo')) + array_filter([ 'amd_only' => data_get($service, 'amd_only') ? true : null, 'arm_only' => data_get($service, 'arm_only') ? true : null, ])); diff --git a/app/Livewire/Project/New/Select.php b/app/Livewire/Project/New/Select.php index 4cffff800..ba03041e2 100644 --- a/app/Livewire/Project/New/Select.php +++ b/app/Livewire/Project/New/Select.php @@ -111,38 +111,14 @@ public function loadServices() $templateLastUpdatedMap = $this->serviceTemplateLastUpdatedMap($services); $services = collect($services)->map(function ($service, $key) use ($templateLastUpdatedMap) { - $default_logo = 'svgs/default.webp'; - $logo = data_get($service, 'logo'); - - if (is_string($logo) && str_starts_with($logo, 'svg/')) { - $normalizedLogo = 'svgs/'.str($logo)->after('svg/'); - if (file_exists(public_path($normalizedLogo))) { - $logo = $normalizedLogo; - } - } - - $hasLogo = is_string($logo) - && basename($logo) !== basename($default_logo) - && file_exists(public_path($logo)); - - if (! $hasLogo) { - $logo = $default_logo; - } - - $local_logo_path = public_path($logo); $serviceKey = (string) $key; return [ 'id' => $serviceKey, 'name' => str($serviceKey)->headline(), 'docsSlug' => str($serviceKey)->lower()->value(), - 'has_logo' => $hasLogo, - 'logo' => asset($logo), - 'logo_github_url' => file_exists($local_logo_path) - ? 'https://raw.githubusercontent.com/coollabsio/coolify/refs/heads/main/public/'.$logo - : asset($default_logo), 'templateLastUpdated' => $templateLastUpdatedMap[$serviceKey] ?? null, - ] + (array) $service; + ] + service_logo_urls(data_get($service, 'logo')) + (array) $service; })->all(); // Extract unique categories from services diff --git a/bootstrap/helpers/services.php b/bootstrap/helpers/services.php index 07fdeb086..96257a632 100644 --- a/bootstrap/helpers/services.php +++ b/bootstrap/helpers/services.php @@ -1,5 +1,30 @@ asset($defaultLogo), + 'logo_cdn_url' => asset($defaultLogo), + 'logo_default_url' => asset($defaultLogo), + ]; + } + + if (str_starts_with($logo, 'svg/')) { + $logo = 'svgs/'.str($logo)->after('svg/'); + } + + $logo = ltrim($logo, '/'); + + return [ + 'logo' => asset($logo), + 'logo_cdn_url' => 'https://raw.githubusercontent.com/coollabsio/coolify/refs/heads/main/public/'.$logo, + 'logo_default_url' => asset($defaultLogo), + ]; +} + use App\Models\Application; use App\Models\Service; use App\Models\ServiceApplication; diff --git a/resources/views/livewire/global-search.blade.php b/resources/views/livewire/global-search.blade.php index 43d6e6b55..9e714b59f 100644 --- a/resources/views/livewire/global-search.blade.php +++ b/resources/views/livewire/global-search.blade.php @@ -655,7 +655,9 @@ class="absolute inset-0 z-10 hidden items-center justify-center bg-white/40 back class="search-result-item command-palette-item"> - - diff --git a/tests/Feature/ResourceIndexDescriptionSubtitleTest.php b/tests/Feature/ResourceIndexDescriptionSubtitleTest.php index ab570b7f3..eec80be0a 100644 --- a/tests/Feature/ResourceIndexDescriptionSubtitleTest.php +++ b/tests/Feature/ResourceIndexDescriptionSubtitleTest.php @@ -9,3 +9,12 @@ ->not->toContain('item.description || item.fqdn || item.uuid') ->not->toContain('item.fqdn || item.uuid'); }); + +test('resource grid does not show a placeholder when a domain is missing', function () { + $view = file_get_contents(resource_path('views/livewire/project/resource/index.blade.php')); + $gridView = explode('x-show="viewMode === \'grid\'"', $view, 2)[1]; + + expect($gridView) + ->not->toContain('x-show="!item.fqdn"') + ->not->toContain('>-'); +}); From c97649bda2d52e4079ae13a9d03229c700448777 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Mon, 31 Aug 2026 17:57:29 +0200 Subject: [PATCH 21/55] docs(security): require scoped authorization checks and regression tests --- AGENTS.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index 34b43e087..f9f8ca563 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -148,6 +148,11 @@ ### Authorization - Custom gates: `createAnyResource`, `canAccessTerminal` - Role hierarchy: `Role::MEMBER` (1) < `Role::ADMIN` (2) < `Role::OWNER` (3) with `lt()`/`gt()` comparison methods - Multi-tenancy via Teams — team auto-initializes notification settings on creation +- Authorize every server-side read and mutation where access can vary by user, role, team, or resource. Use policies, gates, or `$this->authorize(...)`; never rely on hidden Blade/Livewire controls such as `@can` for security. +- Scope queries to the current team before returning records. Treat route and model identifiers as untrusted, and prevent users from reading or changing resources owned by another team. +- Apply authorization consistently across Livewire actions, API and web controllers, actions, downloads, exports, search, event listeners, and any other path that exposes or changes protected data. +- Default to denying access when a policy or ownership relationship is missing or ambiguous. Members must not gain access to administrative, credential, security, billing, or instance-wide data merely because they belong to the team. +- Add authorization regression tests for protected changes. Cover permitted access, member restrictions where applicable, and cross-team access; verify unauthorized reads and writes return `403` or otherwise reveal no protected data. ### Event Broadcasting - Soketi WebSocket server for real-time updates (ports 6001-6002 in dev) From ff8b019296025bdf0e8a08c1989b270193edddc4 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Mon, 31 Aug 2026 21:12:28 +0200 Subject: [PATCH 22/55] fix(application): defer Docker Compose loading and preserve domains Load the compose file only after the user confirms its location, initialize the default compose path when switching build packs, and retain existing application domains. --- app/Livewire/Project/Application/General.php | 22 ++---------- .../project/application/general.blade.php | 3 +- ...pplicationGeneralBuildpackSelectorTest.php | 35 +++++++++++++++++++ .../Feature/ApplicationGeneralLayoutTest.php | 8 +++++ 4 files changed, 47 insertions(+), 21 deletions(-) diff --git a/app/Livewire/Project/Application/General.php b/app/Livewire/Project/Application/General.php index c5015dccc..0c424631f 100644 --- a/app/Livewire/Project/Application/General.php +++ b/app/Livewire/Project/Application/General.php @@ -321,17 +321,6 @@ public function mount() } } $this->initialDockerComposeLocation = $this->application->docker_compose_location; - if ($this->application->build_pack === 'dockercompose' && ! $this->application->docker_compose_raw) { - // Only load compose file if user has update permission - try { - $this->authorize('update', $this->application); - $this->initLoadingCompose = true; - $this->dispatch('info', 'Loading docker compose file.'); - } catch (AuthorizationException $e) { - // User doesn't have update permission, skip loading compose file - } - } - if (str($this->application->status)->startsWith('running') && is_null($this->application->config_hash)) { $this->dispatch('configurationChanged'); } @@ -608,14 +597,9 @@ public function updatedBuildPack() $this->resetDefaultLabels(false); } if ($this->buildPack === 'dockercompose') { - // Only update if user has permission - try { - $this->authorize('update', $this->application); - $this->fqdn = null; - $this->application->fqdn = null; - $this->application->settings->save(); - } catch (AuthorizationException $e) { - // User doesn't have update permission, just continue without saving + if (blank($this->dockerComposeLocation)) { + $this->dockerComposeLocation = '/docker-compose.yaml'; + $this->application->docker_compose_location = $this->dockerComposeLocation; } } if ($this->buildPack === 'static') { diff --git a/resources/views/livewire/project/application/general.blade.php b/resources/views/livewire/project/application/general.blade.php index 7384067f9..d301b55b5 100644 --- a/resources/views/livewire/project/application/general.blade.php +++ b/resources/views/livewire/project/application/general.blade.php @@ -119,8 +119,7 @@ @else

@if ($buildPack === 'dockercompose') -
+
not->toContain('x-init="$wire.dispatch(\'loadCompose\', true)"'); +}); + test('docker compose heading separates its title and action', function () { $view = file_get_contents(resource_path('views/livewire/project/application/general.blade.php')); From e4146a631409c18083718a13022ca093751dc0ee Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Mon, 31 Aug 2026 22:51:30 +0200 Subject: [PATCH 23/55] feat(backups): unify service backup management (#11574) --- app/Jobs/DatabaseBackupJob.php | 11 +- .../Project/Database/BackupExecutions.php | 7 +- .../Project/Service/BackupExecutions.php | 124 +++++++ .../Project/Service/DatabaseBackups.php | 23 +- app/Livewire/Project/Service/ImportBackup.php | 80 +++++ app/Livewire/Project/Service/Index.php | 6 - .../Project/Service/VolumeBackup/Index.php | 85 ++++- .../Project/Service/VolumeBackup/Show.php | 6 +- resources/css/app.css | 21 +- .../views/components/backup-sidebar.blade.php | 10 +- .../views/components/backup-tabs.blade.php | 62 ++++ .../service-database/sidebar.blade.php | 18 - .../service/configuration-sidebar.blade.php | 7 +- .../service/backup-executions.blade.php | 64 ++++ .../project/service/configuration.blade.php | 3 +- .../service/database-backups.blade.php | 47 ++- .../project/service/import-backup.blade.php | 39 +++ .../livewire/project/service/index.blade.php | 2 +- .../service/volume-backup/index.blade.php | 81 ++++- .../service/volume-backup/show.blade.php | 24 +- routes/web.php | 5 +- tests/Feature/ImportBackupUploadIconTest.php | 6 +- ...bleLivewireComponentsAuthorizationTest.php | 14 + .../ServiceDatabaseVerticalNavigationTest.php | 144 +++++++- tests/Feature/ServiceResourceRoutingTest.php | 307 +++++++++++++++--- tests/Feature/VolumeBackupTest.php | 10 + 26 files changed, 1066 insertions(+), 140 deletions(-) create mode 100644 app/Livewire/Project/Service/BackupExecutions.php create mode 100644 app/Livewire/Project/Service/ImportBackup.php create mode 100644 resources/views/components/backup-tabs.blade.php create mode 100644 resources/views/livewire/project/service/backup-executions.blade.php create mode 100644 resources/views/livewire/project/service/import-backup.blade.php diff --git a/app/Jobs/DatabaseBackupJob.php b/app/Jobs/DatabaseBackupJob.php index 0b73ed0cf..b1f2c38b9 100644 --- a/app/Jobs/DatabaseBackupJob.php +++ b/app/Jobs/DatabaseBackupJob.php @@ -322,6 +322,7 @@ public function handle(): void 'scheduled_database_backup_id' => $this->backup->id, 'local_storage_deleted' => false, ]); + BackupCreated::dispatch($this->team->id); $this->backup_standalone_postgresql($database); } elseif (str($databaseType)->contains('mongo')) { if ($database === '*') { @@ -343,6 +344,7 @@ public function handle(): void 'scheduled_database_backup_id' => $this->backup->id, 'local_storage_deleted' => false, ]); + BackupCreated::dispatch($this->team->id); $this->backup_standalone_mongodb($database); } elseif (str($databaseType)->contains('mysql')) { $this->backup_file = "/mysql-dump-$database-".Carbon::now()->timestamp.'.dmp'; @@ -357,6 +359,7 @@ public function handle(): void 'scheduled_database_backup_id' => $this->backup->id, 'local_storage_deleted' => false, ]); + BackupCreated::dispatch($this->team->id); $this->backup_standalone_mysql($database); } elseif (str($databaseType)->contains('mariadb')) { $this->backup_file = "/mariadb-dump-$database-".Carbon::now()->timestamp.'.dmp'; @@ -371,6 +374,7 @@ public function handle(): void 'scheduled_database_backup_id' => $this->backup->id, 'local_storage_deleted' => false, ]); + BackupCreated::dispatch($this->team->id); $this->backup_standalone_mariadb($database); } elseif ($this->database instanceof StandaloneClickhouse) { $this->backup_file = '/clickhouse-backup-'.Carbon::now()->timestamp."-{$this->backup_log_uuid}.zip"; @@ -382,6 +386,7 @@ public function handle(): void 'scheduled_database_backup_id' => $this->backup->id, 'local_storage_deleted' => false, ]); + BackupCreated::dispatch($this->team->id); $this->backup_standalone_clickhouse($database); } else { throw new \Exception('Unsupported database type'); @@ -480,14 +485,14 @@ public function handle(): void } catch (Throwable $e) { throw $e; } finally { - if ($this->team) { - BackupCreated::dispatch($this->team->id); - } if ($this->backup_log) { $this->backup_log->update([ 'finished_at' => Carbon::now()->toImmutable(), ]); } + if ($this->team) { + BackupCreated::dispatch($this->team->id); + } } } diff --git a/app/Livewire/Project/Database/BackupExecutions.php b/app/Livewire/Project/Database/BackupExecutions.php index 73877a945..2786a45c3 100644 --- a/app/Livewire/Project/Database/BackupExecutions.php +++ b/app/Livewire/Project/Database/BackupExecutions.php @@ -6,7 +6,6 @@ use App\Models\ServiceDatabase; use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Illuminate\Support\Collection; -use Illuminate\Support\Facades\Auth; use Livewire\Component; class BackupExecutions extends Component @@ -37,12 +36,12 @@ class BackupExecutions extends Component public $delete_backup_sftp = false; - public function getListeners() + public function getListeners(): array { - $userId = Auth::id(); + $teamId = currentTeam()->id; return [ - "echo-private:team.{$userId},BackupCreated" => 'refreshBackupExecutions', + "echo-private:team.{$teamId},BackupCreated" => 'refreshBackupExecutions', ]; } diff --git a/app/Livewire/Project/Service/BackupExecutions.php b/app/Livewire/Project/Service/BackupExecutions.php new file mode 100644 index 000000000..87f24fb1d --- /dev/null +++ b/app/Livewire/Project/Service/BackupExecutions.php @@ -0,0 +1,124 @@ +id; + + return [ + 'modalClosed' => 'closeExecutionModal', + "echo-private:team.{$teamId},BackupCreated" => '$refresh', + ]; + } + + public function mount(Service $service): void + { + abort_unless($service->environment?->project?->team_id === currentTeam()->id, 404); + $this->service = $service; + $this->authorize('view', $this->service); + } + + public function openExecution(string $executionUuid): void + { + $this->selectedExecution = $this->executions()->firstWhere('uuid', $executionUuid); + abort_unless($this->selectedExecution, 404); + $this->executionModalOpen = true; + } + + public function closeExecutionModal(): void + { + $this->executionModalOpen = false; + $this->selectedExecution = null; + } + + public function render(): View + { + return view('livewire.project.service.backup-executions', [ + 'executions' => $this->executions(), + ]); + } + + private function executions(): Collection + { + $databaseScheduleIds = ScheduledDatabaseBackup::query() + ->where('database_type', (new ServiceDatabase)->getMorphClass()) + ->whereHasMorph('database', [ServiceDatabase::class], fn ($query) => $query->where('service_id', $this->service->id)) + ->pluck('id'); + + $databaseExecutions = ScheduledDatabaseBackupExecution::query() + ->with('scheduledDatabaseBackup.database') + ->whereIn('scheduled_database_backup_id', $databaseScheduleIds) + ->latest() + ->limit(100) + ->get() + ->map(fn (ScheduledDatabaseBackupExecution $execution): array => [ + 'id' => 'database:'.$execution->id, + 'uuid' => $execution->uuid, + 'target' => $execution->scheduledDatabaseBackup->database->human_name ?: $execution->scheduledDatabaseBackup->database->name, + 'type' => 'Database', + 'schedule' => $execution->scheduledDatabaseBackup->frequency, + 'status' => $execution->status, + 'started_at' => $execution->created_at, + 'size' => $execution->size, + 'message' => $execution->message, + 'filename' => $execution->filename, + 'download_url' => $execution->status === 'success' && ! $execution->local_storage_deleted + ? route('download.backup', $execution->id) + : null, + ]); + + $volumeSchedules = ScheduledVolumeBackup::query() + ->with('backupable.resource') + ->forService($this->service) + ->get() + ->keyBy('id'); + $volumeExecutions = ScheduledVolumeBackupExecution::query() + ->whereIn('scheduled_volume_backup_id', $volumeSchedules->keys()) + ->latest() + ->limit(100) + ->get() + ->map(function (ScheduledVolumeBackupExecution $execution) use ($volumeSchedules): array { + $schedule = $volumeSchedules->get($execution->scheduled_volume_backup_id); + + return [ + 'id' => 'storage:'.$execution->id, + 'uuid' => $execution->uuid, + 'target' => $schedule->targetName(), + 'type' => $schedule->targetType(), + 'schedule' => $schedule->frequency, + 'status' => $execution->status, + 'started_at' => $execution->created_at, + 'size' => $execution->size, + 'message' => $execution->message, + 'filename' => $execution->filename, + 'download_url' => $execution->status === 'success' && ! $execution->local_storage_deleted + ? route('download.volume-backup', $execution->id) + : null, + ]; + }); + + return $databaseExecutions->concat($volumeExecutions)->sortByDesc('started_at')->values(); + } +} diff --git a/app/Livewire/Project/Service/DatabaseBackups.php b/app/Livewire/Project/Service/DatabaseBackups.php index 90907abc6..8535584dd 100644 --- a/app/Livewire/Project/Service/DatabaseBackups.php +++ b/app/Livewire/Project/Service/DatabaseBackups.php @@ -22,8 +22,6 @@ class DatabaseBackups extends Component public array $query; - public bool $isImportSupported = false; - public ?ScheduledDatabaseBackup $backup = null; public string $section = 'index'; @@ -32,7 +30,7 @@ class DatabaseBackups extends Component protected $listeners = ['refreshScheduledBackups' => '$refresh']; - public function mount() + public function mount(): mixed { try { $this->parameters = array_filter( @@ -67,10 +65,13 @@ public function mount() return redirect()->route('project.service.index', $this->parameters); } - // Check if import is supported for this database type - $dbType = $this->serviceDatabase->databaseType(); - $supportedTypes = ['mysql', 'mariadb', 'postgres', 'mongo']; - $this->isImportSupported = collect($supportedTypes)->contains(fn ($type) => str_contains($dbType, $type)); + if (! request()->route('backup_uuid')) { + return redirect()->route('project.service.volume-backups.index', [ + 'project_uuid' => $this->parameters['project_uuid'], + 'environment_uuid' => $this->parameters['environment_uuid'], + 'service_uuid' => $this->parameters['service_uuid'], + ]); + } if (request()->route('backup_uuid')) { $this->backup = $this->serviceDatabase->scheduledBackups() @@ -85,6 +86,14 @@ public function mount() 'project.service.database.backup.danger' => 'danger', default => 'general', }; + + $routeParameters = [ + 'project_uuid' => $this->parameters['project_uuid'], + 'environment_uuid' => $this->parameters['environment_uuid'], + 'service_uuid' => $this->parameters['service_uuid'], + ]; + + return redirect()->route('project.service.volume-backups.index', $routeParameters); } } catch (\Throwable $e) { return handleError($e, $this); diff --git a/app/Livewire/Project/Service/ImportBackup.php b/app/Livewire/Project/Service/ImportBackup.php new file mode 100644 index 000000000..29e8d9f35 --- /dev/null +++ b/app/Livewire/Project/Service/ImportBackup.php @@ -0,0 +1,80 @@ +parameters = get_route_parameters(); + $project = currentTeam()->projects()->whereUuid($this->parameters['project_uuid'])->firstOrFail(); + $environment = $project->environments()->whereUuid($this->parameters['environment_uuid'])->firstOrFail(); + $this->service = $environment->services()->whereUuid($this->parameters['service_uuid'])->firstOrFail(); + $this->authorize('update', $this->service); + + $this->databases = $this->service->databases + ->filter(fn (ServiceDatabase $database): bool => $this->supportsImport($database)) + ->values(); + + $databaseUuid = request()->route('stack_service_uuid'); + if ($databaseUuid) { + $selectedDatabase = $this->databases->firstWhere('uuid', $databaseUuid); + abort_unless($selectedDatabase instanceof ServiceDatabase, 404); + $this->authorize('update', $selectedDatabase); + $this->selectedDatabase = $selectedDatabase; + $this->selectedDatabaseUuid = $selectedDatabase->uuid; + + if (request()->routeIs('project.service.database.import')) { + return redirect()->route('project.service.import-backup.database', $this->parameters); + } + } elseif ($this->databases->count() === 1) { + return redirect()->route('project.service.import-backup.database', [ + ...$this->parameters, + 'stack_service_uuid' => $this->databases->first()->uuid, + ]); + } + + return null; + } + + public function updatedSelectedDatabaseUuid(): mixed + { + $database = $this->databases->firstWhere('uuid', $this->selectedDatabaseUuid); + abort_unless($database instanceof ServiceDatabase, 404); + $this->authorize('update', $database); + + return redirect()->route('project.service.import-backup.database', [ + ...$this->parameters, + 'stack_service_uuid' => $database->uuid, + ]); + } + + public function render(): View + { + return view('livewire.project.service.import-backup'); + } + + private function supportsImport(ServiceDatabase $database): bool + { + return str($database->databaseType())->contains(['mysql', 'mariadb', 'postgres', 'mongo']); + } +} diff --git a/app/Livewire/Project/Service/Index.php b/app/Livewire/Project/Service/Index.php index 6193f14b5..23ee6a096 100644 --- a/app/Livewire/Project/Service/Index.php +++ b/app/Livewire/Project/Service/Index.php @@ -59,8 +59,6 @@ class Index extends Component public bool $isLogDrainEnabled = false; - public bool $isImportSupported = false; - // Application-specific properties public $docker_cleanup = true; @@ -153,10 +151,6 @@ private function initializeDatabaseProperties(): void $this->refreshFileStorages(); $this->syncDatabaseData(false); - // Check if import is supported for this database type - $dbType = $this->serviceDatabase->databaseType(); - $supportedTypes = ['mysql', 'mariadb', 'postgres', 'mongo']; - $this->isImportSupported = collect($supportedTypes)->contains(fn ($type) => str_contains($dbType, $type)); } private function syncDatabaseData(bool $toModel = false): void diff --git a/app/Livewire/Project/Service/VolumeBackup/Index.php b/app/Livewire/Project/Service/VolumeBackup/Index.php index 49da9e21f..e856d1373 100644 --- a/app/Livewire/Project/Service/VolumeBackup/Index.php +++ b/app/Livewire/Project/Service/VolumeBackup/Index.php @@ -2,11 +2,14 @@ namespace App\Livewire\Project\Service\VolumeBackup; +use App\Jobs\DatabaseBackupJob; +use App\Jobs\VolumeBackupJob; use App\Models\ScheduledDatabaseBackup; use App\Models\ScheduledVolumeBackup; use App\Models\Service; use App\Models\ServiceDatabase; use Illuminate\Contracts\View\View; +use Illuminate\Database\Eloquent\Collection; use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Livewire\Component; @@ -20,14 +23,70 @@ class Index extends Component public string $search = ''; - protected $listeners = ['refreshVolumeBackups' => '$refresh']; + public bool $scheduleModalOpen = false; - public function mount(): void + public ?ScheduledDatabaseBackup $selectedDatabaseBackup = null; + + public ?ScheduledVolumeBackup $selectedVolumeBackup = null; + + public ?Collection $s3s = null; + + public function getListeners(): array { - $this->service = $this->findService(); + $teamId = currentTeam()->id; + + return [ + 'refreshVolumeBackups' => '$refresh', + 'modalClosed' => 'closeScheduleModal', + "echo-private:team.{$teamId},BackupCreated" => '$refresh', + ]; + } + + public function mount(?Service $service = null): void + { + $this->service = $service ?? $this->findService(); $this->authorize('view', $this->service); $this->parameters = get_route_parameters(); $this->search = request()->string('search')->toString(); + + } + + public function openSchedule(string $backupUuid): void + { + $this->loadSelectedSchedule($backupUuid); + $this->s3s = currentTeam()->s3s; + $this->scheduleModalOpen = true; + } + + public function closeScheduleModal(): void + { + $this->scheduleModalOpen = false; + $this->selectedDatabaseBackup = null; + $this->selectedVolumeBackup = null; + } + + public function backupNow(string $type, string $backupUuid): void + { + try { + if ($type === 'database') { + $this->loadSelectedSchedule($backupUuid); + abort_unless($this->selectedDatabaseBackup, 404); + $this->authorize('manageBackups', $this->selectedDatabaseBackup->database); + DatabaseBackupJob::dispatch($this->selectedDatabaseBackup); + } else { + abort_unless($type === 'storage', 404); + $this->loadSelectedSchedule($backupUuid); + abort_unless($this->selectedVolumeBackup, 404); + $this->authorize('update', $this->selectedVolumeBackup->targetResource()); + VolumeBackupJob::dispatch($this->selectedVolumeBackup); + } + + $this->selectedDatabaseBackup = null; + $this->selectedVolumeBackup = null; + $this->dispatch('success', 'Backup queued.'); + } catch (\Throwable $e) { + handleError($e, $this); + } } public function render(): View @@ -68,4 +127,24 @@ private function findService(): Service ->where('uuid', request()->route('service_uuid')) ->firstOrFail(); } + + private function loadSelectedSchedule(string $backupUuid): void + { + $this->selectedDatabaseBackup = ScheduledDatabaseBackup::query() + ->with('database') + ->whereUuid($backupUuid) + ->where('database_type', (new ServiceDatabase)->getMorphClass()) + ->whereHasMorph('database', [ServiceDatabase::class], fn ($query) => $query->where('service_id', $this->service->id)) + ->first(); + + if ($this->selectedDatabaseBackup) { + return; + } + + $this->selectedVolumeBackup = ScheduledVolumeBackup::query() + ->with('backupable.resource') + ->whereUuid($backupUuid) + ->forService($this->service) + ->firstOrFail(); + } } diff --git a/app/Livewire/Project/Service/VolumeBackup/Show.php b/app/Livewire/Project/Service/VolumeBackup/Show.php index eec60497f..10abeb3bf 100644 --- a/app/Livewire/Project/Service/VolumeBackup/Show.php +++ b/app/Livewire/Project/Service/VolumeBackup/Show.php @@ -20,7 +20,7 @@ class Show extends Component public string $section = 'general'; - public function mount(): void + public function mount(): mixed { $project = currentTeam()->projects()->where('uuid', request()->route('project_uuid'))->firstOrFail(); $environment = $project->environments()->where('uuid', request()->route('environment_uuid'))->firstOrFail(); @@ -43,6 +43,10 @@ public function mount(): void 'project.service.volume-backups.danger' => 'danger', default => 'general', }; + + $routeParameters = collect($this->parameters)->except('backup_uuid')->all(); + + return redirect()->route('project.service.volume-backups.index', $routeParameters); } public function render(): View diff --git a/resources/css/app.css b/resources/css/app.css index b1ae74c09..40af521c6 100644 --- a/resources/css/app.css +++ b/resources/css/app.css @@ -2521,8 +2521,25 @@ .backup-table-grid { } .service-backup-table-grid { - grid-template-columns: minmax(10rem, 1.7fr) 6rem minmax(7rem, 0.8fr) 7.5rem 6.5rem minmax(8rem, 1fr); - min-width: 45rem; + grid-template-columns: minmax(10rem, 1.7fr) 6rem minmax(7rem, 0.8fr) 7.5rem 6.5rem minmax(8rem, 1fr) 7.5rem; + width: 100%; +} + +.data-table-row.service-backup-table-grid { + background: var(--coollabs-base); + border-bottom: 1px solid var(--coollabs-fill); +} + +.data-table-row.service-backup-table-grid:last-child { + border-bottom: 0; +} + +.data-table-row.service-backup-table-grid:hover { + background: color-mix(in srgb, var(--coollabs-base) 98%, black); +} + +.dark .data-table-row.service-backup-table-grid:hover { + background: color-mix(in srgb, var(--coollabs-base) 98%, white); } /* Persistent storage volumes: Name | Source | Destination | [PR suffix] | Backup | [Actions] */ diff --git a/resources/views/components/backup-sidebar.blade.php b/resources/views/components/backup-sidebar.blade.php index 90c86ddb5..a2177b690 100644 --- a/resources/views/components/backup-sidebar.blade.php +++ b/resources/views/components/backup-sidebar.blade.php @@ -15,7 +15,7 @@ 'danger' => 'project.application.backup.danger', ], 'service' => [ - 'back' => 'project.service.database.backups', + 'back' => 'project.service.volume-backups.index', 'general' => 'project.service.database.backup.show', 's3' => 'project.service.database.backup.s3', 'retention' => 'project.service.database.backup.retention', @@ -48,9 +48,11 @@ ['key' => 'danger', 'label' => 'Danger Zone', 'icon' => 'shield-alert'], ]; $backLabel = $context === 'database' ? 'Back to database' : 'Back to backups'; - $backParameters = $context === 'database' - ? collect($parameters)->except('backup_uuid')->all() - : $parameters; + $backParameters = match ($context) { + 'database' => collect($parameters)->except('backup_uuid')->all(), + 'service' => collect($parameters)->except(['stack_service_uuid', 'backup_uuid'])->all(), + default => $parameters, + }; @endphp
diff --git a/tests/Feature/AllResourceRestartLimitsTest.php b/tests/Feature/AllResourceRestartLimitsTest.php index 8418b552c..7da82f7d6 100644 --- a/tests/Feature/AllResourceRestartLimitsTest.php +++ b/tests/Feature/AllResourceRestartLimitsTest.php @@ -1,5 +1,8 @@ toContain(HasRestartLimit::class); $resource = new $modelClass; @@ -34,17 +38,8 @@ 'last_restart_at' => 'datetime', ]); })->with([ - ApplicationPreview::class, - ServiceApplication::class, - ServiceDatabase::class, - StandaloneClickhouse::class, - StandaloneDragonfly::class, - StandaloneKeydb::class, - StandaloneMariadb::class, - StandaloneMongodb::class, - StandaloneMysql::class, - StandalonePostgresql::class, - StandaloneRedis::class, + [ApplicationPreview::class], + [ServiceApplication::class], ]); it('collects restart counts for preview and service containers from both status sources', function () { @@ -157,7 +152,7 @@ ->toContain('Application::query()'); }); -it('adds restart limit columns to previews services and standalone databases', function () { +it('limits restarts only for applications', function () { $migrations = collect(glob(database_path('migrations/*.php'))) ->map(fn (string $path): string => file_get_contents($path)) ->implode("\n"); @@ -165,19 +160,62 @@ expect($migrations) ->toContain("'application_previews'") ->toContain("'service_applications'") - ->toContain("'service_databases'") ->toContain("'max_restart_count'") - ->toContain("'restart_limit_reached'"); + ->toContain("'restart_limit_reached'") + ->toContain("dropColumn(['max_restart_count', 'restart_limit_reached'])"); - $restartLimitMigrations = collect(glob(database_path('migrations/*_add_restart_limit_to_*.php'))); + $databaseModels = [ + ServiceDatabase::class, + StandalonePostgresql::class, + StandaloneRedis::class, + StandaloneMongodb::class, + StandaloneMysql::class, + StandaloneMariadb::class, + StandaloneKeydb::class, + StandaloneDragonfly::class, + StandaloneClickhouse::class, + ]; - expect($restartLimitMigrations)->toHaveCount(11); - expect($restartLimitMigrations->map( - fn (string $path): string => substr(basename($path), 0, 17) - )->unique())->toHaveCount(11); - $restartLimitMigrations->each(function (string $path): void { - expect(file_get_contents($path))->not->toContain('foreach ('); - }); + foreach ($databaseModels as $databaseModel) { + expect(class_uses_recursive($databaseModel))->not->toContain(HasRestartLimit::class); + } + + foreach ([ + 'service_databases', + 'standalone_postgresqls', + 'standalone_redis', + 'standalone_mongodbs', + 'standalone_mysqls', + 'standalone_mariadbs', + 'standalone_keydbs', + 'standalone_dragonflies', + 'standalone_clickhouses', + ] as $databaseTable) { + expect(Schema::hasColumn($databaseTable, 'max_restart_count'))->toBeFalse() + ->and(Schema::hasColumn($databaseTable, 'restart_limit_reached'))->toBeFalse(); + } + + foreach ([GetContainersStatus::class, PushServerUpdateJob::class] as $statusUpdater) { + $source = file_get_contents((new ReflectionClass($statusUpdater))->getFileName()); + + expect($source) + ->not->toContain('$database->trackRestartCount') + ->not->toContain('$database->stoppedAfterRestartLimit()'); + } + + $stopServiceResource = file_get_contents((new ReflectionClass(StopServiceApplication::class))->getFileName()); + + expect($stopServiceResource) + ->toContain('$resetRestartCount && $serviceApplication instanceof ServiceApplication'); +}); + +it('does not render restart limit warnings for service databases', function () { + $html = Blade::render( + '', + ['database' => new ServiceDatabase], + ); + + expect(trim($html))->toBeEmpty(); }); it('atomically claims a resource restart limit once and can reset it', function () { diff --git a/tests/Feature/ResourceHeadingUnifiedNavbarTest.php b/tests/Feature/ResourceHeadingUnifiedNavbarTest.php index ce69f26ef..f7951e93a 100644 --- a/tests/Feature/ResourceHeadingUnifiedNavbarTest.php +++ b/tests/Feature/ResourceHeadingUnifiedNavbarTest.php @@ -82,21 +82,31 @@ } }); -it('links the service header missing variables warning to environment variables', function () { +it('shows disabled deploy actions when service variables are missing', function () { $heading = file_get_contents(resource_path('views/livewire/project/service/heading.blade.php')); $mobileActions = str($heading) ->after('
') ->before("@teleport('#resource-action-hud-slot')") ->toString(); + $desktopActions = str($heading) + ->after("@teleport('#resource-action-hud-slot')") + ->before('@endteleport') + ->toString(); - expect($heading) - ->toContain("route('project.service.environment-variables'") - ->toContain('Required variables missing') + expect($mobileActions) + ->toContain('id="service-mobile-actions"') + ->toContain('aria-disabled="true"') + ->toContain('Deploy') + ->toContain('missing required env vars') ->toContain('href="{{ $environmentVariablesUrl }}"') - ->and($mobileActions) - ->toContain('Fill required variables first') - ->toContain('disabled') - ->toContain('Deploy'); + ->toContain('underline') + ->and($desktopActions) + ->toContain('id="service-desktop-actions"') + ->toContain('aria-disabled="true"') + ->toContain('Deploy') + ->toContain('missing required env vars') + ->toContain('href="{{ $environmentVariablesUrl }}"') + ->toContain('underline'); }); it('places the account menu beside the desktop sidebar toggle while retaining it on mobile', function () { diff --git a/tests/Feature/TraefikVersionStateTest.php b/tests/Feature/TraefikVersionStateTest.php index 3dad5423e..de3cf8e17 100644 --- a/tests/Feature/TraefikVersionStateTest.php +++ b/tests/Feature/TraefikVersionStateTest.php @@ -1,12 +1,16 @@ hasCurrentTraefikOutdatedInfo())->toBeTrue(); }); -it('clears stale outdated information before detecting the current version', function () { +it('clears stale Traefik version state before detecting the current version', function () { $team = Team::factory()->create(); $server = Server::factory()->create([ 'team_id' => $team->id, @@ -204,6 +208,80 @@ $server->refresh(); - expect($server->detected_traefik_version)->toBe('3.6.23') + expect($server->detected_traefik_version)->toBeNull() ->and($server->traefik_outdated_info)->toBeNull(); }); + +it('clears Traefik version state when the proxy changes', function () { + $team = Team::factory()->create(); + $server = Server::factory()->create([ + 'team_id' => $team->id, + 'proxy' => [ + 'type' => ProxyTypes::TRAEFIK->value, + 'status' => 'running', + ], + 'detected_traefik_version' => '3.6.23', + 'traefik_outdated_info' => [ + 'current' => '3.6.23', + 'latest' => '3.7.8', + 'type' => 'minor_upgrade', + ], + ]); + + $server->changeProxy(ProxyTypes::NONE->value); + + expect($server->refresh()->detected_traefik_version)->toBeNull() + ->and($server->traefik_outdated_info)->toBeNull(); +}); + +it('cleans stale Traefik version state while selecting servers to check', function () { + Bus::fake(); + Cache::put('coolify:versions:all', [ + 'traefik' => ['v3.7' => '3.7.8'], + ]); + + $team = Team::factory()->create(); + $server = Server::factory()->create([ + 'team_id' => $team->id, + 'proxy' => [ + 'type' => ProxyTypes::NONE->value, + 'status' => 'exited', + ], + 'detected_traefik_version' => '3.6.23', + 'traefik_outdated_info' => [ + 'current' => '3.6.23', + 'latest' => '3.7.8', + 'type' => 'minor_upgrade', + ], + ]); + + (new CheckTraefikVersionJob)->handle(); + + expect($server->refresh()->detected_traefik_version)->toBeNull() + ->and($server->traefik_outdated_info)->toBeNull(); +}); + +it('does not inspect a server after its Traefik proxy has been disabled', function () { + $team = Team::factory()->create(); + $server = Server::factory()->create([ + 'team_id' => $team->id, + 'proxy' => [ + 'type' => ProxyTypes::NONE->value, + 'status' => 'exited', + ], + 'detected_traefik_version' => '3.6.23', + 'traefik_outdated_info' => [ + 'current' => '3.6.23', + 'latest' => '3.7.8', + 'type' => 'minor_upgrade', + ], + ]); + Event::fake(); + + (new CheckTraefikVersionForServerJob($server, ['v3.7' => '3.7.8']))->handle(); + + expect($server->refresh()->detected_traefik_version)->toBeNull() + ->and($server->traefik_outdated_info)->toBeNull(); + + Event::assertNotDispatched(ProxyStatusChangedUI::class); +}); diff --git a/tests/Unit/StopActionsPersistStatusTest.php b/tests/Unit/StopActionsPersistStatusTest.php index 35b6052dd..67a7a8c6f 100644 --- a/tests/Unit/StopActionsPersistStatusTest.php +++ b/tests/Unit/StopActionsPersistStatusTest.php @@ -21,7 +21,7 @@ ->toContain("\$application->update(['status' => 'exited']);") ->toContain('$application->resetRestartLimit();') ->toContain("\$database->update(['status' => 'exited']);") - ->toContain('$database->resetRestartLimit();'); + ->not->toContain('$database->resetRestartLimit();'); }); it('persists exited status when stopping an individual service resource', function () { From 2ebbc5113ec8ab4e329e3c14daf9cacc3b0d5155 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Fri, 4 Sep 2026 15:44:18 +0200 Subject: [PATCH 48/55] fix: return null for invalid repository URLs --- app/Models/Application.php | 6 +++++- tests/Unit/ApplicationGitCommitLinkTest.php | 11 +++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/app/Models/Application.php b/app/Models/Application.php index 6bfbb6de7..7f7ce5ea1 100644 --- a/app/Models/Application.php +++ b/app/Models/Application.php @@ -714,7 +714,7 @@ public function gitCommits(): Attribute ); } - public function gitCommitLink($link): string + public function gitCommitLink($link): ?string { if (! is_null(data_get($this, 'source.html_url')) && ! is_null(data_get($this, 'git_repository')) && ! is_null(data_get($this, 'git_branch'))) { if (str($this->source->html_url)->contains('bitbucket')) { @@ -731,6 +731,10 @@ public function gitCommitLink($link): string $git_repository = 'https://'.parse_url($git_repository, PHP_URL_HOST).parse_url($git_repository, PHP_URL_PATH); } + if (! filter_var($git_repository, FILTER_VALIDATE_URL)) { + return null; + } + $url = Url::fromString(Str::replaceEnd('.git', '', $git_repository)); $url = $url->withUserInfo(''); $commitPath = str($git_repository)->contains('bitbucket') ? 'commits' : 'commit'; diff --git a/tests/Unit/ApplicationGitCommitLinkTest.php b/tests/Unit/ApplicationGitCommitLinkTest.php index e1a15e714..378384fe8 100644 --- a/tests/Unit/ApplicationGitCommitLinkTest.php +++ b/tests/Unit/ApplicationGitCommitLinkTest.php @@ -26,3 +26,14 @@ 'https://bitbucket.org/coollabsio/coolify/commits/1234567890abcdef', ], ]); + +it('does not generate commit links from incomplete repository URLs', function (string $repository) { + $application = new Application; + $application->setRelation('source', null); + $application->git_repository = $repository; + + expect($application->gitCommitLink('1234567890abcdef'))->toBeNull(); +})->with([ + 'missing host' => 'https://', + 'missing scheme' => 'github.com/coollabsio/coolify', +]); From 89814743c8233fa856d58fcb72a2f04ecc9e600c Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Fri, 4 Sep 2026 15:45:55 +0200 Subject: [PATCH 49/55] fix(applications): TypeError when stopping an application --- app/Actions/Application/StopApplication.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/Actions/Application/StopApplication.php b/app/Actions/Application/StopApplication.php index 3feb5117d..fcf1e1d0f 100644 --- a/app/Actions/Application/StopApplication.php +++ b/app/Actions/Application/StopApplication.php @@ -78,5 +78,7 @@ public function handle(Application $application, bool $previewDeployments = fals $application->update($status); ServiceStatusChanged::dispatch($application->environment->project->team->id); + + return null; } } From aafef73aa651366d4ec14f8fa2a1d426817eb105 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Fri, 4 Sep 2026 15:53:49 +0200 Subject: [PATCH 50/55] fix(docker): match helper containers at any registry depth --- app/Jobs/CleanupHelperContainersJob.php | 2 +- tests/Unit/CleanupHelperContainersJobTest.php | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/app/Jobs/CleanupHelperContainersJob.php b/app/Jobs/CleanupHelperContainersJob.php index 425dd2591..52b4064fe 100644 --- a/app/Jobs/CleanupHelperContainersJob.php +++ b/app/Jobs/CleanupHelperContainersJob.php @@ -21,7 +21,7 @@ public function __construct(public Server $server) {} private static function helperContainersCommand(): string { - return 'docker container ps --format \'{{json .}}\' | jq -s \'map(select(.Image|test("^([^/]+/)?coollabsio/coolify-helper(:|@)")))\''; + return 'docker container ps --format \'{{json .}}\' | jq -s \'map(select(.Image|test("(^|/)coollabsio/coolify-helper(:|@)")))\''; } public function handle(): void diff --git a/tests/Unit/CleanupHelperContainersJobTest.php b/tests/Unit/CleanupHelperContainersJobTest.php index a649985d2..bd3e2e175 100644 --- a/tests/Unit/CleanupHelperContainersJobTest.php +++ b/tests/Unit/CleanupHelperContainersJobTest.php @@ -13,6 +13,11 @@ 'docker.io/coollabsio/coolify-helper:1.0.16', 'ghcr.io/coollabsio/coolify-helper@sha256:abc', 'registry.example/team/coollabsio/coolify-helper:latest', + 'coollabsio/coolify:latest', + 'coollabsio/coolify:4.3.12', + 'coollabsio/coolify-realtime:1.0.10', + 'coolify-helper:latest', + 'someone/coolify-helper:1.0.16', 'evil/coollabsio/coolify-helper-copy:latest', 'coollabsio/not-coolify-helper:latest', ]; @@ -31,7 +36,7 @@ $process->mustRun(); expect(array_column(json_decode($process->getOutput(), true, flags: JSON_THROW_ON_ERROR), 'Image')) - ->toBe(array_slice($images, 0, 3)); + ->toBe(array_slice($images, 0, 4)); } finally { unlink($docker); rmdir($directory); From 92c0035002d977cea4925984999e1895766910fd Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Fri, 4 Sep 2026 16:34:40 +0200 Subject: [PATCH 51/55] ci: sync main to next once a day instead of on every push merging main into next after every commit clutters the next branch with too many merge commits. --- .github/workflows/sync-main-to-next.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/sync-main-to-next.yml b/.github/workflows/sync-main-to-next.yml index 595a21e79..b9b8b361f 100644 --- a/.github/workflows/sync-main-to-next.yml +++ b/.github/workflows/sync-main-to-next.yml @@ -1,8 +1,8 @@ name: Sync main to next on: - push: - branches: [main] + schedule: + - cron: '0 3 * * *' workflow_dispatch: permissions: From a04c2ecb442c3ed8a4eac60a6bb9e3413111d13c Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Fri, 4 Sep 2026 16:38:24 +0200 Subject: [PATCH 52/55] fix(docker): preserve restart policies when stopping containers --- app/Actions/Application/StopApplication.php | 2 -- app/Actions/Application/StopApplicationPreview.php | 2 -- app/Actions/Database/StopDatabase.php | 2 -- app/Actions/Service/StopServiceApplication.php | 5 +---- .../ApplicationStoppedAfterRestartLimitTest.php | 2 +- tests/Unit/StopActionsPersistStatusTest.php | 11 +++++++++++ 6 files changed, 13 insertions(+), 11 deletions(-) diff --git a/app/Actions/Application/StopApplication.php b/app/Actions/Application/StopApplication.php index fcf1e1d0f..12ac56900 100644 --- a/app/Actions/Application/StopApplication.php +++ b/app/Actions/Application/StopApplication.php @@ -44,8 +44,6 @@ public function handle(Application $application, bool $previewDeployments = fals $commands = [dockerStopCommand($timeout, $containerName, $server)]; if ($removeContainers) { $commands[] = "docker rm -f $containerName"; - } else { - array_unshift($commands, "docker update --restart=no $containerName"); } instant_remote_process(command: $commands, server: $server, throwError: false); diff --git a/app/Actions/Application/StopApplicationPreview.php b/app/Actions/Application/StopApplicationPreview.php index af5f3fc0f..8bb3a3dc0 100644 --- a/app/Actions/Application/StopApplicationPreview.php +++ b/app/Actions/Application/StopApplicationPreview.php @@ -20,8 +20,6 @@ public function handle(ApplicationPreview $preview, bool $resetRestartCount = tr $commands = [dockerStopCommand($application->settings->stopGracePeriodSeconds(), $containerName, $server)]; if ($removeContainer) { $commands[] = "docker rm -f $containerName"; - } else { - array_unshift($commands, "docker update --restart=no $containerName"); } instant_remote_process($commands, $server, false); } diff --git a/app/Actions/Database/StopDatabase.php b/app/Actions/Database/StopDatabase.php index 8005311b5..d3c6fafc4 100644 --- a/app/Actions/Database/StopDatabase.php +++ b/app/Actions/Database/StopDatabase.php @@ -62,8 +62,6 @@ private function stopContainer(BaseModel $database, string $containerName, int $ $commands = [dockerStopCommand($timeout, $containerName, $server)]; if ($removeContainer) { $commands[] = "docker rm -f $containerName"; - } else { - array_unshift($commands, "docker update --restart=no $containerName"); } instant_remote_process(command: $commands, server: $server, throwError: false); } diff --git a/app/Actions/Service/StopServiceApplication.php b/app/Actions/Service/StopServiceApplication.php index 11ad337ed..1b5347265 100644 --- a/app/Actions/Service/StopServiceApplication.php +++ b/app/Actions/Service/StopServiceApplication.php @@ -22,10 +22,7 @@ public function handle(ServiceApplication|ServiceDatabase $serviceApplication, b if ($removeContainer) { $commands = ["docker rm -f {$containerName}"]; } else { - $commands = [ - "docker update --restart=no {$containerName}", - "docker stop {$containerName}", - ]; + $commands = ["docker stop {$containerName}"]; } instant_remote_process($commands, $server, throwError: ! $removeContainer); diff --git a/tests/Feature/ApplicationStoppedAfterRestartLimitTest.php b/tests/Feature/ApplicationStoppedAfterRestartLimitTest.php index 58ebb8c70..f5875adb2 100644 --- a/tests/Feature/ApplicationStoppedAfterRestartLimitTest.php +++ b/tests/Feature/ApplicationStoppedAfterRestartLimitTest.php @@ -126,7 +126,7 @@ function applicationWithRestartState(array $attributes = []): Application expect($removeContainers)->not->toBeNull() ->and($removeContainers->getDefaultValue())->toBeTrue() - ->and($action)->toContain('docker update --restart=no') + ->and($action)->not->toContain('docker update --restart=no') ->and($action)->toContain('if ($removeContainers)'); }); diff --git a/tests/Unit/StopActionsPersistStatusTest.php b/tests/Unit/StopActionsPersistStatusTest.php index 67a7a8c6f..a6d8d2fc1 100644 --- a/tests/Unit/StopActionsPersistStatusTest.php +++ b/tests/Unit/StopActionsPersistStatusTest.php @@ -6,6 +6,17 @@ expect($action)->toContain("'status' => 'exited'"); }); +it('does not change Docker restart policies when retaining stopped containers', function (string $actionPath) { + $action = file_get_contents(__DIR__.'/../../'.$actionPath); + + expect($action)->not->toContain('docker update --restart=no'); +})->with([ + 'applications' => 'app/Actions/Application/StopApplication.php', + 'application previews' => 'app/Actions/Application/StopApplicationPreview.php', + 'service applications' => 'app/Actions/Service/StopServiceApplication.php', + 'standalone databases' => 'app/Actions/Database/StopDatabase.php', +]); + it('persists exited status for every full application stop path', function () { $action = file_get_contents(__DIR__.'/../../app/Actions/Application/StopApplication.php'); From 851a902346aa1f1b847ce9dd4fa79d2a2513f941 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Fri, 4 Sep 2026 16:47:12 +0200 Subject: [PATCH 53/55] fix(domains): preserve removed compose service domains --- bootstrap/helpers/domains.php | 20 ++++++++++++++++++ bootstrap/helpers/parsers.php | 7 ++---- tests/Feature/ApplicationDomainsTest.php | 27 ++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 5 deletions(-) diff --git a/bootstrap/helpers/domains.php b/bootstrap/helpers/domains.php index 4e4ad73e6..28ff41b3d 100644 --- a/bootstrap/helpers/domains.php +++ b/bootstrap/helpers/domains.php @@ -443,6 +443,26 @@ function getComposeServiceDomainString(array|Collection $domains, string $servic return $matches[0]['domain']; } +/** + * Determine whether a compose service already has a domain-map entry, including + * an explicitly empty entry left when a user removes its generated domain. + * + * @param array|Collection $domains + */ +function hasComposeServiceDomainEntry(array|Collection $domains, string $serviceName): bool +{ + $normalized = normalizeComposeServiceName($serviceName); + + foreach (collect($domains)->keys() as $key) { + $key = (string) $key; + if ($key === $serviceName || normalizeComposeServiceName($key) === $normalized) { + return true; + } + } + + return false; +} + function composeDomainEntryString(mixed $entry): ?string { if (is_object($entry)) { diff --git a/bootstrap/helpers/parsers.php b/bootstrap/helpers/parsers.php index 590b68d16..03ebf5af7 100644 --- a/bootstrap/helpers/parsers.php +++ b/bootstrap/helpers/parsers.php @@ -525,8 +525,7 @@ function applicationParser(Application $resource, int $pull_request_id = 0, ?int $originalServiceName = findComposeServiceName($normalizedServiceName, array_keys($services)); if ($originalServiceName !== null) { $domains = json_decode(data_get($resource, 'docker_compose_domains') ?: '[]', true) ?: []; - $domainExists = getComposeServiceDomainString($domains, $originalServiceName); - if (is_null($domainExists)) { + if (! hasComposeServiceDomainEntry($domains, $originalServiceName)) { $serviceNameForDomain = str($parsed['service_name'])->replace('_', '-')->value(); $domainValue = generateUrl(server: $server, random: "$serviceNameForDomain-$uuid"); if ($value && get_class($value) === Stringable::class && $value->startsWith('/')) { @@ -648,12 +647,10 @@ function applicationParser(Application $resource, int $pull_request_id = 0, ?int // Only add domain if the service exists if ($composeServiceName !== null) { $domains = json_decode(data_get($resource, 'docker_compose_domains') ?: '[]', true) ?: []; - $domainExists = getComposeServiceDomainString($domains, $composeServiceName); - // Update domain using URL with port if applicable $domainValue = $port ? $urlWithPort : $url; - if (is_null($domainExists)) { + if (! hasComposeServiceDomainEntry($domains, $composeServiceName)) { $resource->docker_compose_domains = json_encode(putComposeServiceDomain( $domains, $composeServiceName, diff --git a/tests/Feature/ApplicationDomainsTest.php b/tests/Feature/ApplicationDomainsTest.php index a13b5fdbf..f2beb22f1 100644 --- a/tests/Feature/ApplicationDomainsTest.php +++ b/tests/Feature/ApplicationDomainsTest.php @@ -111,6 +111,33 @@ expect($this->application->fresh()->fqdn)->toBeNull(); }); +it('keeps a compose domain removed when the service declares a magic URL variable', function () { + $this->application->update([ + 'build_pack' => 'dockercompose', + 'docker_compose_raw' => <<<'YAML' +services: + web: + image: nginx:alpine + environment: + SERVICE_URL_WEB: /api +YAML, + 'docker_compose_domains' => json_encode([ + 'web' => ['domain' => 'https://web.example.com/api'], + ]), + ]); + + $component = Livewire::test(Domains::class, ['application' => $this->application->fresh()]); + $domainKey = hash('sha256', 'https://web.example.com/api|web'); + + $component + ->call('removeDomainByKey', $domainKey) + ->assertDispatched('success') + ->assertSet('domainRows', []); + + expect(json_decode($this->application->fresh()->docker_compose_domains, true)) + ->toMatchArray(['web' => ['domain' => null]]); +}); + it('generates a preview domain when the application has no domain', function () { $preview = ApplicationPreview::create([ 'application_id' => $this->application->id, From 5ff21103974a30e107ce046190fb478658a214e7 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Fri, 4 Sep 2026 17:01:42 +0200 Subject: [PATCH 54/55] fix(environment-variables): preserve generated Compose variables Exclude protected Compose variables from bulk deletion and developer views, and propagate deletion failures correctly. --- .../Shared/EnvironmentVariable/All.php | 42 +++++++----- .../EnvironmentVariableAsyncLoadTest.php | 66 +++++++++++++++++++ 2 files changed, 90 insertions(+), 18 deletions(-) diff --git a/app/Livewire/Project/Shared/EnvironmentVariable/All.php b/app/Livewire/Project/Shared/EnvironmentVariable/All.php index ea8394c1b..47080cd86 100644 --- a/app/Livewire/Project/Shared/EnvironmentVariable/All.php +++ b/app/Livewire/Project/Shared/EnvironmentVariable/All.php @@ -818,19 +818,21 @@ private function formatEnvironmentVariables($variables) { $isMember = auth()->user()?->isMember(); - return $variables->map(function ($item) use ($isMember) { - if ($isMember) { - return "$item->key=(Hidden, only admins can view)"; - } - if ($item->is_shown_once) { - return "$item->key=(Locked Secret, delete and add again to change)"; - } - if ($item->is_multiline) { - return "$item->key=(Multiline environment variable, edit in normal view)"; - } + return $variables + ->reject(fn ($item): bool => $this->isProtectedEnvironmentVariable($item->key)) + ->map(function ($item) use ($isMember) { + if ($isMember) { + return "$item->key=(Hidden, only admins can view)"; + } + if ($item->is_shown_once) { + return "$item->key=(Locked Secret, delete and add again to change)"; + } + if ($item->is_multiline) { + return "$item->key=(Multiline environment variable, edit in normal view)"; + } - return "$item->key=$item->value"; - })->join("\n"); + return "$item->key=$item->value"; + })->join("\n"); } public function switch() @@ -908,8 +910,7 @@ private function handleBulkSubmit() $deletedCount = $this->deleteRemovedVariables(false, $variables); if ($deletedCount > 0) { $changesMade = true; - } elseif ($deletedCount === 0 && $this->resource->environment_variables()->whereNotIn('key', array_keys($variables))->exists()) { - // If we tried to delete but couldn't (due to Docker Compose), mark as error + } elseif ($deletedCount < 0) { $errorOccurred = true; } @@ -926,8 +927,7 @@ private function handleBulkSubmit() $deletedPreviewCount = $this->deleteRemovedVariables(true, $previewVariables); if ($deletedPreviewCount > 0) { $changesMade = true; - } elseif ($deletedPreviewCount === 0 && $this->resource->environment_variables_preview()->whereNotIn('key', array_keys($previewVariables))->exists()) { - // If we tried to delete but couldn't (due to Docker Compose), mark as error + } elseif ($deletedPreviewCount < 0) { $errorOccurred = true; } @@ -988,6 +988,12 @@ private function deleteRemovedVariables($isPreview, $variables) // Get all environment variables that will be deleted $variablesToDelete = $this->resource->$method()->whereNotIn('key', array_keys($variables))->get(); + // Generated Compose variables are managed by Coolify and must survive a bulk + // replacement even when they are omitted from the pasted environment file. + $variablesToDelete = $variablesToDelete->reject( + fn (EnvironmentVariable $environmentVariable): bool => $this->isProtectedEnvironmentVariable($environmentVariable->key) + ); + // If there are no variables to delete, return 0 if ($variablesToDelete->isEmpty()) { return 0; @@ -1001,13 +1007,13 @@ private function deleteRemovedVariables($isPreview, $variables) if ($isUsed) { $this->dispatch('error', "Cannot delete environment variable '{$envVar->key}'

Please remove it from the Docker Compose file first."); - return 0; + return -1; } } } // If we get here, no variables are used in Docker Compose, so we can delete them - $this->resource->$method()->whereNotIn('key', array_keys($variables))->delete(); + $this->resource->$method()->whereKey($variablesToDelete->modelKeys())->delete(); return $variablesToDelete->count(); } diff --git a/tests/Feature/EnvironmentVariableAsyncLoadTest.php b/tests/Feature/EnvironmentVariableAsyncLoadTest.php index 2cbc5537a..4d83862b6 100644 --- a/tests/Feature/EnvironmentVariableAsyncLoadTest.php +++ b/tests/Feature/EnvironmentVariableAsyncLoadTest.php @@ -121,3 +121,69 @@ expect($component->instance()->environmentVariables->pluck('key')->all()) ->toContain('API_KEY'); }); + +it('preserves generated compose variables during bulk replacement', function () { + $application = Application::factory()->create([ + 'environment_id' => $this->environment->id, + 'build_pack' => 'dockercompose', + 'docker_compose' => <<<'YAML' +services: + api: + image: nginx:alpine + environment: + SERVICE_URL_API: /api +YAML, + ]); + + foreach ([ + 'SERVICE_URL_API' => 'https://api.example.com/api', + 'SERVICE_FQDN_API' => 'api.example.com/api', + 'OLD_VARIABLE' => 'remove-me', + ] as $key => $value) { + EnvironmentVariable::create([ + 'key' => $key, + 'value' => $value, + 'resourceable_type' => Application::class, + 'resourceable_id' => $application->id, + ]); + } + + Livewire::test(All::class, ['resource' => $application]) + ->set('variables', 'NEW_VARIABLE=keep-me') + ->call('submit') + ->assertDispatched('success') + ->assertNotDispatched('error'); + + expect($application->environment_variables()->pluck('value', 'key')->all()) + ->toBe([ + 'SERVICE_URL_API' => 'https://api.example.com/api', + 'SERVICE_FQDN_API' => 'api.example.com/api', + 'NEW_VARIABLE' => 'keep-me', + ]); +}); + +it('hides generated compose variables from developer view', function () { + $application = Application::factory()->create([ + 'environment_id' => $this->environment->id, + 'build_pack' => 'dockercompose', + ]); + + foreach ([ + 'SERVICE_URL_API' => 'https://api.example.com', + 'SERVICE_FQDN_API' => 'api.example.com', + 'API_URL' => '$SERVICE_URL_API', + ] as $key => $value) { + EnvironmentVariable::create([ + 'key' => $key, + 'value' => $value, + 'resourceable_type' => Application::class, + 'resourceable_id' => $application->id, + ]); + } + + $component = Livewire::test(All::class, ['resource' => $application]) + ->call('switch'); + + expect($component->get('variables')) + ->toBe('API_URL=$SERVICE_URL_API'); +}); From dba3d114e5ed2be9a466c030c8cbc2ec58b498d9 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Fri, 4 Sep 2026 18:09:53 +0200 Subject: [PATCH 55/55] chore(release): bump Coolify version to 4.3.18 --- config/constants.php | 2 +- other/nightly/versions.json | 2 +- tests/Unit/ProductionImageWorkflowTest.php | 4 ++-- versions.json | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/config/constants.php b/config/constants.php index 7ad0c4594..22d5e1011 100644 --- a/config/constants.php +++ b/config/constants.php @@ -2,7 +2,7 @@ return [ 'coolify' => [ - 'version' => env('COOLIFY_VERSION') ?: '4.3.17', + 'version' => env('COOLIFY_VERSION') ?: '4.3.18', 'helper_version' => '1.0.16', 'realtime_version' => '1.0.18', 'railpack_version' => '0.23.0', diff --git a/other/nightly/versions.json b/other/nightly/versions.json index 0e83c0cf7..97ab3b3a6 100644 --- a/other/nightly/versions.json +++ b/other/nightly/versions.json @@ -1,7 +1,7 @@ { "coolify": { "v4": { - "version": "4.3.17" + "version": "4.3.18" }, "nightly": { "version": "4.4-rc.1" diff --git a/tests/Unit/ProductionImageWorkflowTest.php b/tests/Unit/ProductionImageWorkflowTest.php index 140a6276f..206cf5f34 100644 --- a/tests/Unit/ProductionImageWorkflowTest.php +++ b/tests/Unit/ProductionImageWorkflowTest.php @@ -23,8 +23,8 @@ ->toContain('ARG COOLIFY_VERSION') ->toContain('ENV COOLIFY_VERSION=${COOLIFY_VERSION}') ->and($constants) - ->toContain("'version' => env('COOLIFY_VERSION') ?: '4.3.17'") - ->and($versions['coolify']['v4']['version'])->toBe('4.3.17') + ->toContain("'version' => env('COOLIFY_VERSION') ?: '4.3.18'") + ->and($versions['coolify']['v4']['version'])->toBe('4.3.18') ->and($versions['coolify']['nightly']['version'])->toBe('4.4-rc.1') ->and($nightlyVersions)->toBe($versions); }); diff --git a/versions.json b/versions.json index 0e83c0cf7..97ab3b3a6 100644 --- a/versions.json +++ b/versions.json @@ -1,7 +1,7 @@ { "coolify": { "v4": { - "version": "4.3.17" + "version": "4.3.18" }, "nightly": { "version": "4.4-rc.1"