From 6c336118100015db2f63a1a4cddca4d8db13cd1a Mon Sep 17 00:00:00 2001 From: gpBlockchain <744158715@qq.com> Date: Tue, 15 Apr 2025 09:46:15 +0800 Subject: [PATCH 1/3] update ipc test --- framework/rpc.py | 7 +- framework/test_node.py | 2 +- source/contract/ipc_test/ipc_test | Bin 0 -> 121080 bytes source/contract/ipc_test/ipc_test_with_exec | Bin 0 -> 18608 bytes source/contract/ipc_test/ipc_test_with_spawn | Bin 0 -> 21160 bytes test_cases/ipc_call/test_ipc_call.py | 287 +++++++++++++++++++ 6 files changed, 294 insertions(+), 2 deletions(-) create mode 100755 source/contract/ipc_test/ipc_test create mode 100755 source/contract/ipc_test/ipc_test_with_exec create mode 100755 source/contract/ipc_test/ipc_test_with_spawn create mode 100644 test_cases/ipc_call/test_ipc_call.py diff --git a/framework/rpc.py b/framework/rpc.py index de2c90e1..ff59f6bb 100644 --- a/framework/rpc.py +++ b/framework/rpc.py @@ -50,6 +50,9 @@ def local_node_info(self): def ping_peers(self): return self.call("ping_peers", []) + def ipc_call(self, ipc_script_locator, ipc_req, ipc_env=None): + return self.call("ipc_call", [ipc_script_locator, ipc_req, ipc_env]) + def remove_node(self, peer_id): return self.call("remove_node", [peer_id]) @@ -97,7 +100,9 @@ def get_fee_rate_statics(self, target=None): return self.call("get_fee_rate_statics", [target]) def generate_epochs(self, epoch): - return self.call("generate_epochs", [epoch]) + response = self.call("generate_epochs", [epoch]) + time.sleep(3) + return response def generate_block(self): return self.call("generate_block", []) diff --git a/framework/test_node.py b/framework/test_node.py index c1f3f088..2e5b32b7 100644 --- a/framework/test_node.py +++ b/framework/test_node.py @@ -320,7 +320,7 @@ def prepare( root_path=get_project_root(), spec_path=self.ckb_config_path.ckb_spec_path, ), - self.ckb_dir, + "{dir}/dev.toml".format(dir=self.ckb_dir), ) shutil.copy( diff --git a/source/contract/ipc_test/ipc_test b/source/contract/ipc_test/ipc_test new file mode 100755 index 0000000000000000000000000000000000000000..d6a5a039788ed7fdf5ee263078c3c571f693943c GIT binary patch literal 121080 zcmeFa2|U!@`!_x)DPm?A%h-lg$i5RLOCej34sZ`+ola=XpKn_2QcA{W;5Zmd`oobIx_0lVoYToSTaa z!*<-55e&q!E+LpH`oN$K;i3Pg7y}G1_|K1-11JVF1I7@Krf_J;58~euAs9C0L%hLH zp>RJP>Jbgcszjc!DF%!1kgu8GkBzhCWK)g#NIY!%$8eCWM_Q5RM?P}H5wd9&!eTn) zQ3=uXR`szcP`H2B@nA6FQ2us5V(076F|0sYHf8%_G$6ky^?xt@`d`L3_;1RU@o)NP z=l2sT=lESD|F>HHH5&C7{@?t?^S?@G`(K35;CTKCrjh`$9W?L=_~%4egzEy_!w zd=N@aKOo`vqR$Ob-Wa7CD0M`s3rcsR{{M>Vp#E=sN7CV)_N!fYP0y*ELFoWWCsBG4 zrOG@=_&AgoL3u@#cR{JTE0fA#ss~2W!>P2u&|sRnnm?HlNLOc21B00?MyxuM;jbP{ zqflei{262xm8lj?SJey9)Td}^`T3DGbu~0J1JwOP{8Sl{OqME>MN!pM(@@hu!qL_J zA_D@b3@Qcs5zPo@Q5k9sCI;ini_}jP+RsA6*=+DTm&M+wk1G%(Q7^j8lJ_G6GiTlc3k zs7S*FtxlaxA%_FXRHxD+!>CZ>XSWIrMsGGEww4*cfC$pC}iQ%>9kVAA04*LDEcemI>;GC^Ac(lCHu$Z^KQ0vHtkukk?j z7fPimD*b3u%y2S;>f=uiC;JDpVilF3_&EF5Dp1@|{c_@G0WJe@q_vV*bQ0W2lUPAi z61%8K6fz6SFXVy*Kmg$6;Qttm7)pPwHz)84GU!oMh9iT%j_S{1s?(^9C_0lyWku5& zA?ktQI`FW;^k)Qzvs8n_{ne2Hh67dgr-y~nY4B?aavDv8D~d^th@{f|sfaYF5P*;r z{bIo&MFPzUc3`jwjSQoa$Rr>Qcn>UTVDtd=2$~NX>Tf%s(02>lp`RBR_V>^LIzIc8 z;kVh>iOP%&Wf>Vo(xMsUa786w5_sjwG?K3+gW*exB8Ns!GerFpMFPe|8jTu?v|bG6 z!d#?8!qJS_0cy<76rk+1he(z~fEhiKMzLm5!|af(+rl}qr?V_+^vJ*&~x7R)TCFwH^F2+9CW3nJ|H!lr&`yKzPG@$2jV zA59~FGaZBaX|#ctVUe1nqO$3L7ai)?*p4k9o1Q`CG!OA}j%9+Elg@CZvFq599$-NQ zX$FHP5J!a{{_JmkL#Y8Qk`gI8h)N?dK_x@Y%9lZ=1yaGRltO~%#3Xh*Vy91H1P2DO ze1DGqp>#3}3K>oZQ(Ka+hNhObj;@}*fg#z?pF$0=2K`Z3cqo-cbqkGfrbbv$q1i3? z?EretfKYn06UaMYVd0$rB&suziRunbso{r^M^_pvIP?c+8AJAG!JJuS0Q4ACI#d8F zsGuh%hg#ENjx9Mt+2zKjdT9B9PMk#teJLEoAp~to7GPjNTLAn3{mm|E(8L@9;0K`d zjr3=+TRTXq9*>lq;GdIcF9-c-Z>J2|J^7zKvdjJJXZEk@pOaAeIp?`fvoILw-Q>g< z{07%V@js`6L07{tn1;WQgAbMCcj3Fy@cwifivg;QsSXB2A25=!kohReu)BH8urQKu zc{D;%K#Aaw6W0XTeAEv_IL9?L^m~&toCfe~3H~^7HGn~XoVY5$pmBy1R{EbZ~xHb5*BeQ~*Q7Fz(F9w<)G)&vl$rNXJasi$z5|Hu&)d)Lv zl%I+6Iw;TXui5=_Fa>;p27}RrLH1+*xfPSF!~I=A1vx=e5hj=mpfdbxzDUu*V7$>H zQA4R=APMkE47<~)98i8C_ZN}D`TbY?AjxU6lfx*8BIN;nYeDX>;@~V&Bs2zXJs1pF zPlX-$42B)MT-j^0>~d%KE9^cS`qqRT`z>dW)9mq;lV{`X@KBq895h#k9GkM^`@1N6 z+-1wdPKW(IvD*#XA6qW=b2dK*5fif$?f=Bl@oXVVwNRRmK3|6NwkUN)sXt1?QOb_* z@1iAW`o~e~j6-U?8>Pc2Vn*ye6xClH{dfdr*dUI` zV~dvO9?-B9!0*3lBJ%ssYW7DF$9k5A1R@W6J?k!z1^N!;#2)|*YAgHaAuZEZ;h&}d zyVCim^YQ=p`2XE<{wx1~_582O&U9y)4rIv-b&Bf<7LaBLvd|Xpy0zkZj-+hzhMFs{)J!oITn8KOGf+tW$$& zn|e5z1?`z2p9arSIUGRRkRyT#mZ#YQ4VPz z>kt;x3Rq|k`)h1)D5$-FX#de%1wzXJ!C+Da=NT>FNmNc6D(40;p@-)3oOl6>bLI=$ zR)Fe*v%Nw7q4^o&hL<8#!4#n$2sO`Z9A&QAfJFPLw&O z!9FnTTDdvKWSejA>KEpwSv4`zCkPgfLp^Q1#FZA?AKCHV8&0X#tufAeNok&C)-#Ec%cifs`8 z+;-}zm2JX3k6S}H>-}El!)HU5Ti?=lc~{CCZ|zl7eR^TqNo!_9agkF&GlgI&Vd%CK`YXvI&}Z7oLXdV62{+Y+iqq}TTDwv{Xl zFO8JGXSdds^fixzfgR&(&dVEqG`khw4FxYul-NncHQZOa)NXfRx6yJ| z#aw&Jf!^|lOf!3v`e$vmYSH!rhC8!@zg5_mnLqooL8`}oTi(OSl7pfSHRr8`Gi_}h za3X^5+D>e65Z!|-YnD9Y;5qfE1enDKQlVbpQG>&!D;p31AjT(9F^#Q3giP}Xsi$j@69r+clu>tf@o&}*xk z_(d^J^&iwOXG`ih86K||U?5$CqZ?2vLDSbkb`+BLrxoAZ_C6yDDS`Ex>R@( zr78S_t6+z&$z=0A zrDTJi2M1Rx>lEGUZ0K06yUZ#E_g&EAnxg94H(ur*9~fUt=j+6HROUnpsV_V3(JXN+ z_|ia+$I>E^8}CZQ);KgsjFx5Et`cfL+rZk70X=N8s3EQc6WTvYd5Lm9oDI-gt5kZ&=anwdL`43Kla=*S0n(mTE751+X``V&vC}>ud}fDqJ?r;*f40fe{gJfqC#M6MZlzAX zCl_u~tFYe$-VQ}0clk@c-1#19QMw;}uaDE`Kdf6o{`9>`Z8Ou09Fws0l5WE`a+_C< zin-A(vVhL%FAo~NlQ&^n;?le|{f=VN_ViU#{T^carex#`{L)B6KF*^pex(C%^p9xG z^uJfqXX%t=5N3YK!KZiHp7Z$XJU zt>GkM8B1~Nz8K)K>jXtlK(G7DrI!@*9P^IIN^zbNid5>rm?nWL zagIukNnCSTc93eqpYyftfqa0#-BV|pGu#7mHu&^Tt=k$fR&`;p%dalLVBfko`QJYW zY_yo!mr$z`_|RtFiR@40z|GR{)|`si75G-6?1PM8bD(fEpZkLhuAuh3+bVo-b%W*_ zP3YgIh6GtzO#1DYEe=}q=+gJ}z(+wRZ7SmeugwWQVP8?vea^}BK0M$<2$6Usxx$Y-JGrI23&6k z*4Yjp-gs@kY>0-N;-}rw&LI~CQUqFcR56vLSNg&Jrbg8!mpQjePL*d zK=yU-YVXkd^#*%ubGL`y8oOosTBkl#|J>KydE67B^OyxjZgN^-Zyn4U%Z~hOUm{esv{A^x4>xv&^^QXMcjkJ75x#qXG>uv5Z z_)qB!*8bi1-)vY>&hnqC(>f{ef@OS#ne@zo5XpbSvFqVMo5;Yh?flfk z$&pw2qU|T|RY!ifEz&c=^Cq%w(zY_uj1-l%q-eE_vrCk^eZyd1;O3|cdO9bx$!mJoUS(3y)9q0+wa-@)dFYlYArHxAz>^x0-C`e#Mi%e)-l#sa+Pe>un9bpX3i2Uhl&j zxBqUsLj31V;>*p-JmSB(+zZ*vmm6=OeEnAWoE!1=pP1*|=8naG{g4|_;i#UlIG=bm zWV?UD922=J-ss&4wpmJE4S9DHs=n+ooRH#4ER4it829QY^6bDITlp+3vB%TY#^G2= zVke_T>ZMD2Vs6fiUPM`M8>Fn*aH`R-`=c9FxWJSPS(}Gw4$8CFY1zTy9dRQP<|_J}y^hN1-xrDm zxU1+oB76OG7!8M{_P5RVf3x98g|^Ay8L_x3l41ZN7G@N%65ux{4sGwqO@l*fjL@1e zr+*ALs{h3iKctp7T|E2%SDq#wA%Lq)gG1_m(Dwyrx?h1j5YD*|8HqYS7A-P>!RCHa zMC%O%{12She-P$>caXp7OY1l7>E{M^kUFRU;HYQ@ivVj0eskib0EhOrro)A&!4Cuf z&|V6s|4M*E`+}VK8Gu9IX`J|DfJ5zr6Mq13Xm5@a{|4~si;@j>1Djz3)1mIA=`>Wi+KyC{MS2J5n zA4dmwT_0yhTWc3ogO$uA1#3g9(-_Y9ssRR#XPkHgz@T(EaY&DOI{e^o@FIXii;$f0 z%mdkl#zjti0l=YgkrRInu<87N1Ne0EaQ`MAMSw$dVnF`rNPGAE$w?57uXqtB^7G$w z1>Oxi%`-#$zaRb3YUhXD^>B8Od}vHusfxMO+a5h)xjAj44Gr^%ia8C70 zd{Bj_-~HVbd!keB}6+gPb;jWY2_SNgkvXAVka~EEA zD6#77ddG#wIubfZTRzI@I8v|rG#+-kAl!8PhH0I6?%_9kY#+WAY!ov7sJHj7aPl17 z^-Aa1lglK09WQ^bk`3fzac4eNy%xCQ^x?_1Yb2bClyvD;3OXAP)V-ZtX(jSRVlelk zhji}#q@c~zHbbnBQdPC|_3yU%T4hHb&HF5Is@B8%r0y=03QyVE=+`$y6#ZT#EL>Zj z?`CcLefy?;*tz?H8ao=xKMo7VeLY*clek2z)+ny{qURchn(B@;3qq6SceMuM?Gwkd zGq;%SuMB_0<)c=X64tf}+P3%62jQIYi-^VJ?yI&^X z^(=vfb(^Jg@I}tE`x^xAYwj9%CR&Dm9w0J%%XCc2K3Pl%5%#-%b?#A=cJ|J9@?Mw! z80+W0^*qlL@>{i!jytheMu`KKhwATH*ck{bH>L4<#0&kHeGnPs>; zxC51n8>J3d&EOfK_!mg>KM}v|98%TCyH7Vq`ZYncgs`GXX!FRM5Swj`UQ#(u|6)Xp z?UQpB%a2K>g>hL*`S@SE)kdi2ndxfHb9wJRQHj@gLM)#f=;=q#3Z6VJhQGEho-3M49b zeSc7I)*q?6xpg`Ou#x1SM9`=&BBQnlxT&OEZ6SjAVo;g=PP&h}nDE(Sq_ zj}>cV)KngvkK|8CGWT`1@Z4f0zIxu%`Y(?(_S};=su#aFOn5=-7$a+Qb@r(o!4G4L z2(ssvspTA;rOZ$~%>SwW;xqAYdoPzd7+$!xQKrp{H@{c-^B0ZT5_M|}+ck#2wJAK5 z{pz!3mPk;ab?nv!>RqW(627lq%*2vb(dy?oUFo~GR)mhS*b6lzdRAScykL^hR9$gYkSpAudx$YmD$gO z4!@7Lc6pOb&r>{2RCw6ye9ry05!Q9@l_-)IAvH?c+&6ZyAM@DpskOY-FIFX z!D^LDy?(_V)PBd192-4eXX-g5>f*#rij5%mtBy4W-6443H#+XylU);38t)m!BDi@< zw;r~6v1A)*)db<@=Vuo2VuG?I#3@s|vfCE=+fTMM;%%COzfkTT=f}}jJ33Sg$t*S= zyy@7HXgMMf1?Az&|>g%*jO@yDAy}t6f?#NMkt-$`X0Sz)Q3u>De z-E)>(uroYS#i>X<#d>G>X2wzCxn~Qg!>rT7`yw-lLTQm-vecLG^>0d-6A%yzdU^OLX;0?DG6-D)A_7`OM)Y6%pGvE6PvY!o0xh&%B?tXC8LNv!#}{hXU{R zD?F-Rk<%){d$M_7+iRx|*|X2CA7C62F<3ZfrRCt0SP7NHV2QeoSdWgQxRRGXN;%6l zgmUyEh;hOf$~H)yt}P82>F8Lykf45a=exZx75!Fi&Z+EP`3@@5|_xNfh z^VQo#rf`R&qpG^v7-4Fnv02Z}r^;51Z5ufiGkWPVF1vD~b#kdxoz%OtYvlbYQXN|; zW?I@+Tw=pMgqoT&;N?s$$gcC?s_=OAEceDD{6QW=AF&yq?^e_u949`+OQ#m9+ExUw zWn3zdx@~1{CRX@zOWS4_@zIGMQNCHh1^8Pt%P$GJY#me&`5@52x+y&~M1GPH)qXik z{#y8Q<@;hYF4{LK-o#I}*#~Y7xiD9_Xe=RywRlyNLSn~yyidH09eHw0sd4V?vznFT z%aZ)X=WJ-olY7`+baSD?ZJp*6;pn?DF89t~38V{znafq`%Z^2;J}b>@mh}kVa?j3v zOuYWnrG!<_+LGc%ikB{__$JIhsNOiBc6sXhxk9ap*e|ke3L{0NE1Cg%-$d&s>bFb8 zNP7{9%?r=1{a()16dEbw+Z(_B_-yAL;*A#rONPC%dy4XIR++t(`NYawx~^ZH_~KR6 zjD_5r`@EE&X=TWci1fc*v@iW`(b=lOD#fCtI&4Q*7nyFu8&(dygAy(SH>YxAU zPPbCYlH8m&CgDTds*S6nBkTsNn;tV_lyC#?uiFML53H|psmMv&8YxKpB)1%$>_ChO;4xnafDMm8*QGa>yhE&!Vlz z7bc3j*}GpFmYU3X;}XJe&D`)p@&?`H;8z>dkDDdi_v(KY=Bb3;V!i>dvA2#Xh32Vx{7)`BTZWA{CbPeyVZDtF_iHmr6 z5768-#7^wLUsm8GocsK~aZ|#4;(T#Usl(gf$e8w(X&6sRTb+$v^D^zo1#!%(jaM5r zS3bB|e>`QMbEEK`>VtR8UgMl*9~QgckbXq=P_EPxZn-C{S?9V;jrKcBIL@_c;;JTm zndvJL_`TOmq-+k~>;k3dU-eJNIgO|4V%why9NA{3k?nC#`RoqEAqnA?b4Y^RTbH~T z8~kcUz9J%I%$K~Rz=YagzxrDNaSygvWiE#DwSiVDkexf0n@xN(@6evtV-GUV9*i(0 zcP=4ZkaB!cn|IWBEalT4B4G-Mr~w$_I=WI?+coen~6%I>vrB~JpFQ|yM)E#37UOnf2!0`qt7X`V^{FJ$e&-j<=s8e+V3}l z9{PsfOO8!@LmOU-S00-sxJf6jZ|~>>>`J1xw0xc+e`v1Ssvc$YPCkN{Sk2M;M;8xg zc5ZOJ_u>Jz3cpF{vAkMDS8kzeAGh;{SJI&ZA`Y2rY&%7tOW!-P_pR8LgGWnC)*n0` zlX$X})FUr^bmq~Lbv~^L3-fDA_Ui4Iak)=Q$w+#VFI(}&p0GVpJi09TE^k15tnIv8 z9nV<1g+K6f_09=b&8ZAIxNw)t8rd~%7{?M11%b;$HL@{Sf&{^G@8b<3(&3XIznmI- zj1`Gqw_c>cTeWw&9}e5G4o^dZIwBK35!lh)D;R|ZqfIgL%&oUaa%r1 z;{+ICH2=TzUE6jAF5kRbrb*9`Bofy4xirbDv%8 z{t-OO>9ZgG?VU|Amg@0}`A#z4N7klXk>`JKYu%N`jd(Nh-t#Mink9{e4rELjwF(9a zhbhIH#;N#<@9x~aEwxubRzWULyTR@Ba^W6fK|Seq@iTVjN<}d_22ZP>9@=KpCA{TC z$dQ1BNo#!N$i*qgnq*6^44r?Qu0^n`wyQ3y|kg@`6S)j1CfUz(U_jya#Nge^>3~Om|>(TVdxnCDccm}tLv=rG0KlI+; zbZAUnBz{vl){YD3COtD2@!CC^4zbSJacrF-N1`ojII+?*{&xMLWIb z*aD#s!kO&}r)J6ct?Rm?Ebp{*p*g*RqR1<5pOLgD!~O|Xw(#R-N0NcC&D>^1md#B% zb;lc_YVE5six17-^tpJQN1Bj4^K;!E@m*(Tg?{ZHtkip4J-SWzxUieMK=;VfL~Di7 zTKQD@1X;_9Hrvlrl!vc#cMb#%Xh_`O9AolzD%E_DY4P5fv`~aqyd(csbK$)YIXoYP z>}0V{+~?;XT0u^dIz4kB>3EZbkZ%3i*R6KVqF(pkO?@a4d7RtoBPYafg0JeFr|p@7 zz1HuzCun6k+3~b8Z~CHj#K7~WBDE#*_NHF0A?q&65uEcd&+-QB`R`a;TpVod$F6#h zY1q^$hPOKU;Fe94fMn+-Oi`%S@+YC2o`yWyc93v_a>w=(?@a402VM?6D|5h|H0p_K zn8SC(e9GXJ`r%WOpVS7v8e!IJGw`UTu?m zEWdOr>5TjXFR70%yy?p}#MMxzrnU_nsS+JEH_+$e^1E?XOZ&;j_Y3fY2Sz?{1?d@i zq`lpCh`=wMDe-w>!TGh{yMr&X9C5~CZEOSgvzJfTrbZMUCs%zG*W0&6Q$_2un%=cnm-{_Ng@?(}DZpLJYUP@zP3;I#v$pz8JX`z9-S2Dsz^M0BUn1osfF({R{qSIg4q1| z#X{;DXHSAxTTkVzIqdRn8Dc}}WJXlgN)5ODC z$8Dp$2~G0i=BG`B{S)0`*KspbZhs*77r&(A#3xTH1TWJsSe%W!U(lLVR(J1YZhjZxeZazcu%ZqyGLFQGThVIh|3ptjM{yOjX3c;bLxS_T?&kd4Iv`U|_e$ zbt%=Eo@Y&^RWchN)X3T$=N40#5$|&+!HxbWA z;+=K&`%PYajriHa$KEz=J!2EDvg>|`;0p{V%7O9;g zp(D;_UA7X*a#uRy_i^`_&r>oFN-`1A-k=pXkq~6BCk3X_TAJ8%cO7$gHk#U8x^;e~ z(y9T8Tl{5*qaSMXX|~qWH+7yD37P#)=2nza(N@6+S6YwfVY{AGP!77AVXVc@O-Uzi zB1*iR_ok+c>rN5gch5;pL&EVIsf=y5cf;)>UsW#5{)X*w%{yFE`I30zLb$a+g0kd5 zw0Zgs_t)z``fZ(Ml7E4)X-s#(7HNy<4z>WG>tvKSw)CX|vsvmo)!9gh!-ofk>pzFf++U;jkY zVEc+s>Q7z8ig%~!tQ=cC`$|RV^(@hH=%|oCI<|TN8-rA(|LCBt!9O@t**`GgX9lzd z`3JWSI_l-8OHPBfOnSeeKqf;!98hfile|E|^-unRqU#_1Lkh2d z^baY%ivEZUQGk{D$-|1U&=NK3V1?K}_=go^CD~8GZZxDI`_n(FDEs3%qA>f@KcYDM zqkNMQ1zNVbABKb|(n4F)u*=JZ6>5L@Kd%ET*0Srvw4V!Buw~arh6bW&%l3aP9#ObO z{U<+s@)}mWMg12wIw1 zio6V6n!db(6?!564X0NqU9Rzk6?>ujs4d!aTJ>cNtl$gk&y+R8GYY)M6{2V? z{9OHu+nO@#hBb)7v3T3}>USDAueg&$Sn*hvD*a){s6umX>9d^r*4EvAh+?x;-ljL_FJ4bQ;EgCa<6@Pl1Lf6} zSv3S$(OI;enb_0z!o*r0QFxXN;LEXFP4PXlW3Ne6F7xKyuv;Hdj3#LLif{k4qB!wp9IPNslr?sE z^0irkejyZAl*TUPpNH4S4BEV@hZUwphVPWOStK8Q)*A~ePD`BeUBtU+c=H@}M1dOH zYjCDsH&o@05u!*fB3*yb(0o&L@@zz*TB7%y0G~+k&hC|nVzq4c$gK1VvUg~X6s%w^ z%ow&lELO`}ae5xCXf2)-`ZQ6ZOK+ z>|q6LF&?vo=SmajSLgY`irCU-)`E+SmaxtiN+Sx{+n?O8X|P+>$Ac(li$yyve`!=) z`rHCh(3ajZ!hiQh+Cu)f@vx#cK5RIf>ofJko%x8uwrEDh#|_LYVawD}#qCGs`kF`b zdow2bVFhm7?Oo|6+b>DK9WRCzxkVGkUp0SL>6;&qD0EBS^~RbKjZfrnT>>k1wuH(~pBi5ai&aG6}f!HV9J1>bW@PLkx7iy{i&xRh_&{Lh1qwm+GG6~77d z#xU80>pSi^AqwEcGX+;;-h0Gfbw(7yu?Oph+k(Oiss@r^g>VtukqUuS+q$PcU9e)f zgpl~V{`>T?#`l@9f;d)Krk{MPDcbn;Agm}Zvb)ds+u6%IGY_tV6~-kdWyZcz)z;H& z5yf#?pVI{wrp5(sIv@(N6rKpmXqrAdnjtoRW9lz91{B(o6exD$ss4jXh?s-?OYWn`xOju!E>YBjY zraWWegZ_x(I_|^0zRC0aV8I(vU>6-UKahAt@b2+UTUe1@GIGm22c4nJ)E?sd?45U3y>f#U z-bEA&$VWbYGktX+6jppEe!-X=Z7&=cdU+jIfXC`A%i1ybM$g-)ELag3Rr|gvBC0s=K3nx*c**lCFV?^c^x~B(zcvZ1Y*XJG0V~qW*s8Ce z>L2X$#vlsy!m{5zri$13L|z?+73;Oa&EYEHqeupU7YuF~{*k_*d6h##6@y1== z+VW}#K1w1A_hS6+x>t{lEg$kj6z`=2-Q>>A@ydGSjVR#bxhj+b<}!zDM(bcjd{Hj3 z>MJb{<@-*JzzX?NzS%9&J-Eyg2ShO+H+J#{!Lv;@(;rdL7ma?d`{cvQv9NJ|SW#bc zPC1uS^t}r=5)g%b+#Q11h|Bdiy55N5KEbpAuc6GMrdB_I75F9jiuu>>4U%njL=^e4 zHk-3YubP$dQW1rI!oEcxwIYO9SzW#hEA|u3Jln4l4O}TNYTO3mXOq*UFydGk3*ZlSd5%j`a85-f_$| z;;k@jC?L~_y|=b-%cBKM#9%=9`@@td^Y>eZbNXS!0db=(^IYD=gK1n1!5D`%AG~KsOzLp0M+^+`RPTsm zl_n|I9_zz~2BKH0=Mp6D^k}xE!v+UZUvd>I)vv0`mOOwB4{*9QjNOYh#tv`EfDI5t zQ~YugZQ{>5R=$A^5u~>5lgK$<$#AN`!v+bs&ojEUh#o?L?ucOmL7R8?6<_rSrmBd6 zf@C+(mFU8WR4Ze|PyyF*XVi9>5vA_fZt!6@Q-3uAlD=T)%b0a1ljams)!+jh)uhGcW1zY@pHqlK?5=Sm3*@mX7@fOV%UJyDq1wP1~Zw4 zMGYL5WPH9Hk!*5U1Tl1wuve~D%kFNz_m}}2JjjOc)p)jApj)nC7Hs$+Joj3>2wiBk za_wx`07BgHL&0Mk;lXM})DWUIimO4eStMeQI&2UjyzwDd9Dd5Z%W7AR#lGwu-*of!47eF_aL_Y@E+8{&MqOB4RKhHn@0b?sHF-6f$BsAsv}s)3ENm z=ZAR2fCAt8sweJd*(uehH(^5xv5iFqkI$@)I`gJ7+jJZF3|W5r6uFhkN_ zE_b8%ff|9FMTmh$v69Y!&a9XB7>J<;VUEr+dG5w1sX~as265xnAlG8=;8UB8VZ#k< z*>K&l*)=?}6-}@Khsga3Cc(Dk#)AAr#E^r>HfSro&nQL)G3dbZ_|%0r?Y9U_~KoID(?w(t|Ev5h)ka}!MNIPPtCg?*bqc`EtR-Zu6U}a>X)mx=z!(c+S1*pNhuYrti)D%h};iWrpO zxaHrNNZ;5bn1mRXh^8E)Y*naHYTcg>8<4nl!}M_4r%tK%D3jg z1}Vh1y~8K*tI9er1i*$V*ab3SYu)Fsy1x!FP!Xx3^66F5O4HMaVM7&S_R^cnRH&Pn z&WOPZHX=vQDSAn;<3J{CxFTY&ePaP3JC)L-1{<(Q$eTun?~OP#v9}gBWRWFUS#QMD zZ+u=P0vogl6ZbwTyBeb?+UNlrwul!ex85J#b;@%wV&Ec6$(@(#w%QRAWVZ5W--iuw2=cF{wmzeV zXMeDS4RMH%hOWdMTgp3jW+iNpgT4KBNOb4D6=x5vg$;8=F1;%Ein}h+XNMT*Na%&X zja4CPoERR14Rx^QwgJ1(lEynj5rZ8Om#(D5KE(^Tj9akbj)Zc%>~onBB~fL>fJZj& z)dQOm{Z2a~V#p&b(VZbZeADqo_iWgpM_g9?twQLRLlPc{VULXP5I+APaaPsY6R?4g zaL2Lsc-t3zg{1|sp^sSh&bfsLB=~u9xM71I>DYvfYdpiR$a`MEhClfB!Z#;pRQT3T zJ%$Z{#O7L1pU-UndL#)k1d`6MnL6gbv7pfbF$lsdOJCVJ9>{(1r6Oz?B+BYlyYQWh zr(6m#5Rz)NpKvjG@#4*g1F)eGZheXIu`G|h)WQ1NfItmXQDRfm!=WL})a%$_(+$Qg zlEZ7KdPjHqF4cOstf6JTAFe`g>00ImgL_K?oxWL|s3o}1xTov*hBsA^tKUG>Q%UlS zU$Gp+sTX(DH}~cHjxj9d!t7&$f!=NpVpv{E4h94h?oS zNGtSM(wDA*{iZG#;4`Ivef2^h9eY)9RxMamMdkhD z`7BU*apF*ULhY3kcLf;qo){SbLn6qb=Te?R`A(E3qSOL?o{ZAZD83uz52Jh*$}>=Y zFG{0OJOJhIqI3;Pm!QuPVSYW=abPhbr=KxGKkK7BI31ZpW-!RHesp>$6*{rl7m8y| z08*b&9wFzC@(7BY%O6N(kbL2%VCUm6{BzoGa>fUp76XpC{1IaZ8Xwzkl+!{$X*qkzycjR8b%IBy}@VgvLB*HJhH$EzEt+f zq(}fZ2i`~M+*cMUoJ<1;rTjftCBP z&hp^o!THm0<#6JPK}dOl<9lGo`5g2&Bzgd_>s8Z;)C2Dc+d=O$s&&frJ3=50(A+zXV z!TzXG3`kEg7%A6a@Eda4;1Ajy;>01j(M=}s>t}hg%Qbu%@?QQ;^7}2T;Q%jxjx;(_K2&^ycNAHt!w`D^Fx z7tHbjgAJ9X2>pV)EEQ6)67UN-&Ug#}HeI@w0EhatU*nf^2G=nd8G)0lsA1vY*!)m% z-HFmK@lw$6oax;MIJEi4i9ZFH+;4EOdH0L|E`ULspq%k^18g4nV}QeDgBjpJ`!H}d z1qmG0L}$d3nBb&;Ds)yqbddydcs0oks`+KmX_+7taG^;1gxV$Kri&jc7fu{9yN7Ua zjygCLJCFvQO$&vOLE~eeZ^{{t7ld0lO?(gzy|*A5M(i}tzW{8ya1aiK<4kAZH~t}f zI{&W$4$X1FP!~XAf>XXpVc=c@k{=iZq3l70sHsPSPmBY;Fc_;aq}-sgha6}6tpJ;@ z+>}8uXtS2n{|bOlSMM4Chx&zI+hrt;90ks6hiFi5~6PZ^v+4T>nzKuPJ>^fW~(0vxLMf3)0abeaz<2s#9VNe%!V%^ylI zh=G(JJjeh!pnO5?pA%OEm;DFa#&Aym&wzhuO@i&%^KdpT^hD<4w&YmQMZtGh{7uCV z&oRJvAG_jV{zpI3=7prY3%a-sxHl-zyB6W|P<#%`Z$T-^2YKGk_${Q{4Lx4i_^wdZM_d)U28OVHy6Ce5wZVn=W?BzKf5-aE@ z(R%zh?rVah;!NKHq@x9%aNUr)ED~B`gv7#pjYdig{c6B;gO4#F0ywuAI#ZY&Y6M1gmJf0!EjnhyXZ#|e ze+_?~2N{1j<81~w^exGWKmU#Y@4vxcq4IIY(~sh0aL*kymT$DL1P8v*f$BnV;sD?!yrfdfV&IO z0z{%6W;BF&uV+~j&3x@77g1#3K zDZ!F+i1>K59h0aq$Zc>6SmIG%*QyHPLP*AYoMkR-lDBub%8lClPDFlQeO?42> z54*mSK=nZH39TBbC*GR>j>e$zWc?<-UBAKq+jRf#@G1YIoD0zMx_uTYw^#oqjX#IP zlZ#T$`1bw==k)jgHUI5jEQgI~et!KPqf)4$EHZq$54$=4IIbO>{;p05j`aZ@2pMVD zmlBXSOAdY2YypMl@0>U^FNJWZltsW_1NdtJb5s&|U^He}tLt2Uon>ZqH2*E;9~1?%1SGz~6Fw9uiKoxhK@I z^ARoL)PkyjTa^lW1nD&o%!~zHru?rmU7N**#;6|^FS>rIf13RCJ?+!op{G7yoM-;% zC;wEW0ii4{3b-BybS7XX9T=-lVUPpq&@}qj>Y=DXyI7YTD_>}xOnw^wf&iaR{<$dLWl1#Qxkr3;?R)bi2#&dZ zYj3^SWO(`0?+;<#;pxT8<0qr1K7W4-^8#%l%Z9eOUB->~!o2Z#Qf{Se%T|@~cQBv2 z*Hu%|Yt@70*nLT#sy&B z{q7m>SiEt{$#D^w*LVAFrc)2Omv@!u)~{ z*PrkB+A}gV!Gig7$y3LURMynYnT&_|Oq=-7nLd7-=1-= z?Y69R`(0}$^I-l`qEfg*^jH^bvJmET&h?!;aH;EX&g3DO&r4us-19m5_2^^;%-<_G zlCvY+;{1)tYM2ip2wnL)%(ta$@*>Qi(bS~6&ab*NHhBZ)E0Wf?-0E4nM`WrQ=6M${ zQoe!p0!O?&g!u>CnZbJ$6pmR>J%xF}+nCgkHJc{91K?M2^KDEe4?G%S zFln>%zQ!0X-5>+6c4IK739}m4-_5^jfZqBL?)7Hpe`1U?ZDgE>;!kYzx9UUdlrjgT136KXjzo3B2# z1LFeod!-}H#-zP(e8hOc{OW$m!z#gc+vjpoVE)b4a3W=pt8*b&D9qbL5AEG^Fs#Ik z3;J5XVA4Yps@KQN{^-RO5A)ID&ti*vU8_=~J}l(t+jAUvM3Q`T1FfPju=EO2@e>VBYJ%?t_fI zw?2z%dcIWuRJ}g$$b&#dzQ(66dM`Ou;so1^QAFf4+`#*ngh6-VZO^*ZvDs_ z(cK%kAHuwmhHU=RnxdWp?x!%n>-0-6=lhS3oZ;?;d1H&RLyzMNzPE6{gL$mQp)y9?vbeP?Es`^N6kuNUSp|=2uiTYV9u=6+nX*`` zUKp5tl}88Wmz~Qh+$W~}u#?9a=8sCgtls`aV*e1irWlkSP%#1D;k&^ITioX~gyjrW|m>2L7L-^35KQm7n$m0u2;nEco^g=B^t zXL?UTdeetTCt!ch_AlX|q2W2>eU9RQVCH~73iulUYXw-aiCDCe3u9^~gh}4D8-sZ< zIumny?_$pI+F-sqUAgH2e7bTA{SE#S;Lx0$GyWlf+f0Kuqxk>WZhvTjfVur*8 z2QyDF&-Z8j8VLC1%S6J-{TeO|T-Y8Q9vVAsIMd&UV+I9-i=g3qoqr7)gN9T1H9aI8 ze2X-E*Xtj%hp9rtAzx^qe^pa6qk~nF=>NstyN5+tZI9#oz0QRJ28WAyYhZ*FmC*5C zc1GeI71PYr(#i&3hVqh^6idq*7+x*{UK)|q>{MTu}k!0pZ8*z>Wy1+Phsd2PF0ZNWXb^XD5qir&r08)Oi9@8V* z!{5lCrGS+9%ey|yC!=6JfPXJwwAMHWHa;Tpsqn4B_`dJ)8B=uhm55OC$@E0NfA7XFi8IN`R zcZ&>pL|yCe>O#-frG8g>iWs-)ahFn$v`S$HAO3unzum962}W`$`K+lRp975pwf*{O z2j1pCAVGE?q!s-6T>To-UVN?w|ILMexa|oq{r}|zZs+$O|L>pfs6pa+(^3{JwPURz zG<9ufJr;t&#NMHNBb4KuD*0V_k|!s|Z|ryo0B1|(ACZ?&+rij;7JmF0s-X&nkAFOT zs60nwApEWCVt-xX@^+>&++^-c@ko@%A^d)v{21uEGlBR|RG#tJz<&vW zgoEFo*b%>|>xrkhTzsSMkK#=IRdT>%$ zTm&a_7sG{$W%v*l@vJtbevHx%JmzuUr)xQmNe5sYo}w6vr8$*~R;x9%mJ6VRSUnX& zcjF8pp;QH8mM@8(sS;bR`0@yDqz+0gF8N6dKqHP6m} zd@`)2TTb4Zx7fg-kZ%144;?L7CnQgPB-Q@Z-hDlLsnptl(1_uqMpx|k=3C8(b?Yls z+WQ|&o4fY)kVVfN_~qAGbDCP)9-Fp#OZ z%isR|gj*HaBRb~6zx{ma*Ea7F)@X`}?Pnf2dVKQ3Qy!Z>tuxr{y2zDNfIDj{G@& z#;diC^4ZZsfR+z5jOMk&2eJ{4{STx*rW>!(T7{nD)sF>EP-z`4R&8%)+=LNKkXp-+ zQfV`WN2=~;dd;AMhXgveq@@Qq4zGS#49rTN0 z_KEB$Rfq+fMDbO1)|og>>CYMFV5&DC#Huq2^4R%YAfr*~U$>3ZEPKGwqFt(99A;e^ zsteUUu8DNyWQ=2^#Ne>3DfjTa1{r{Xf}9as84%xYQM z8Itty7{{Rpc#56Q^&CoP1Px?Ubu+Y%og;e(4rDbdI*4~{c7DT#FoDdA>@&QMrGjC*z36+wjm!XMP(VDDzz(K|P;b*aXb=02`Wk(myFuS%+BEOIv?9N- zG~w|l@(b4W`Y|YY;=|Wlbys;z57tZdLDM&CbX zLh{pDYXG?C!;g*}Klw#%9lB-i_hWmXoodfozh&#OlV1de^dEh{FyZkhpPKzls=aXi z4yfWi_V3!d#=sC^LaN=7_5R2IJaGDK<8MwWe|z~q4|tD$@!j|1-}vOjk&|CcnEc4& zGiN`Ow`T3`z55OvJaY7GNO;7PPqkdR+2(kD$xr_dx@X~{UcH}L_3F-ly!O$@;SqiA zv5uSk2)6%MU#s$defo#S-Az*9kC++1fjAOg{0VbGvKs8c5fXi$P>8`#nWDpY-92M*+ zU^9y&1Hy7QaQAWdgQ<1bIQ|*EOy@Y$BSX(Q{vGi9Tg(Ve##5n=57dr-aoX5j|*1$;sR;@-_fAIgif5d35jarZmngdGwJ*QB${mTrw4Xk@A@R%aX^?cTv+&&AI72 z&!;?osWxinsfLo7M)b?fM(VX$@N+pTGzbDz8vdik2PA~)DLa@kO;fCi>eKVdfYBNa z)t#j@Fy(RsmV6G}H-J2SXtFvlA(b7FAnjQsnGfTtpp!(1Z6@Z^P zK%heDaG1FP8)&O36{Ds5Q1?S!9n|ax)T0!w(y8ZAv?f3`f$jXiBA~=l~4`gO*CCqp9T#OKT{e`5u%2(yA~;TFq-|D&d~NYyv!UR6mW5HbNsQ zW+VWiA~RY|({C_TAf>_#8TyC?QJ+R3rjW835kHqkETuKlQ)uw-AbTXuQN?tRZh=&+ zIx--hNr1M|^u5$Wpn00sLA&mw%s`cN74TQ*?9QuNl#bfl6hDk0JSsFsT|T!bTjlkSOm2W__35x z+mDxfil>=)P&iV7La3?XAPP`f$pZt>IanKJ1wY*tKo8|O{Egy+5qL60{f&JT|D;zu z9RZ6chUL_1TGfZ$z@QQA5H%GzIePz{kOa;cOX>WpDQ1FGj$$mVF2ha3DV6#1i8 zPDRv96xCBl%Vjt(unUrC{x}-v!En6##0lkhv=f8$Nf}fwov4#hF#KWo_Y}b8So{v~ z1puG(7xfDOo(Av-;1eYVSvt};LeabMFB9Nz!Y9C|jK}=*nAcfF1|t-of`8Zk3l83K zc;O_R!GceqW9&)?x1~F{q3-}k_M>-b%SeEK4RCoqa0mDk06z|JoVN!awvKJ-3q>yh zeA*WXT_W%)5BuBV;x_O~djdsIFkZxa?`W!&Ii}Qb8IWrY54Y*gua`a+_}-XxtLE9;7z*@ z%^-MFI@&shrviLAz?1F*&jR>nfRDZld^^DR0Nh64i@VZ44Dcp^I-$AfI302ldaIa;~2v> z=m5MKfR{jMyQwLib-Yncj0)qv3%Iiog-(Ip;<2Pj?TTBh!D9&Hegn8S;m5udzu}kIH!fE(`s$73T&f$#C_=Pw2a)+f#_IpAWRBHQBsqE1<^ z3aImfnv(b1K*qc3^AzCi1U$tj-E~Z3Ia&etLDP&vui(M z*)IY76@Z7rcmVjW|7OQncB2|-LN4!4J_OsD1>my)uJ}dUUCdYZ6AJ+MgKiXpX%US6 z_HkMO@H7M1H-^)ePKJnOc^BZ}u-$Ki?;!tee&BO}&-e@YC4g_d3mof52f6e!09WJj z1@!-$U1FImP{$Kap$cLToyHCx8#aIsfnee-@U=kmFXs&`!#cos_k;lUe<8zRsPjs1 zr~~zZM<*GujI{t?0Pt&s=I#Cul7?28sA}(0zc0YGQ52eThc+6aP7=UJM^or20=IOH zIr;(4bAa=L32a=!xtpEf@vs4K8~aiy+Ar^2=ADlL?_w;4K7cxRYWEKS&%BrN&kL3g zZeO;?R)D|p7w}#Xf9(7V_yYhx{1@=201gL!?#llafH(dH{7r!K{U|i@F75jm;C%qT zoWR$0oVRel{{Zl1e*td=_;G+=x=a0DIv6kgDfIgt;6^BW0N~HXflnrVdRsh>Wv~HG z#eh5e4-9tzyd2=z_V3h(Zh-FvIL5sbyc*!|1H8vw;57h$7vOjEnfNe3DZuaK-!M-j zz}*1H=OgdL-vaP811a>+yYROGeBdAoZM;i;2j(Ats}FA*yKaDA1-NVjNu9^G5qMSu zTz}u4#{d=y7EdKPDmQ>m~RE^4uWsX0qXcs$$7q=9n^NSOgl`f-KM5RQ)h?khBvIm$+HTJG zC8{zz6FHCYh+|zU#DFF@w6FlvmcH&hLL);Cf5Y(NmEaxYMDa?vfvcg#obn(8H-#0m z%MpBnp33=t2#=p)7&|aFABeW6U${`=%4unJUAYnr`fV)^GD!Rl*RtkdacQkO0!BJB zEXK5BeAsxI`%xabvQ;-+EiJ*~jc`V+-;PArcD=mul9sxs>=?&bO>y)PoC zHN$P-TH02ve>KdMa12Jm4wPOY%O<_e6WQJ-vc35>_?_}>zif^n(e|jzJ1Qh0@=&a_ zslv>yvxpNp6f2QYW?YjY7{Z$8539%%Vk(MYRCa6``k!dK=5nH)vd-PtiRzcp_Q->Y z_A%~6dxl_2*e^>o$XzAG*Aly^`K7B})bzko2Lkqv4px@wXs_eG^qb6uXtjE2w0-7{ zM0sSJ5;W+yeWZ`QPmn&geSffuW3ERHQ4i|*%lSt{$iT0_7T1B{It zJBRzjIl4?6EBSqvWA)f$JposIl4EJpv^miQzw!B17%8j%x%Y)pFk%c`9z}Fx{IRQUj2hEW z58?!PMZfGpZNGc6DB(t=>-3+@&9JgU)6fsWhkI`GZP=?(A^fG#bmtK8HEOW&D>H(+ zKVQk6MNaV75|1rBv{_u&Op7fuSbw=o;%>N_o3V{wZ>G;xxTNM*{9H0l{CS^N{A~tZ zHm)nKSicYGg*N+YXWSIqW~eLGn1>p%Y{2$NL4G`_8p+hsA- z^R$bf!UHwK8T!19Q+$)J*DxWj#_x%$kB+JUTO2x_rUZF5ZpIf8YrmD>GO&2I#& z-BY}o?#cwuok54k<;lJqe1>VybebD4{?UzLQ#NjJLW;@2?!qNGS@7)?Ey52eQ{yEX z={<@sR(!j+4|%TnJMrbhyUO!h#DXRM z%ai&g*oMJge>*}mBh+YkF*6SIsM`KY3-0a{Q|S991+=#w5YxUGY!bDz5=7;@oO&FeG)G=q2i>rHdof+ zZIwS48{ZT&a||5J{OQfX{jK5)UO4o?SxY723mvXG_Ci7IS=F6Rr{3i_b(3i%i~8xK zvz1wROKEyyy2dK5_VziS?y23`5GEXRW4wN-RDu{%o~Mj!qcN56s?bFHh0^|lrzT#R z#ZeJ%cW#GS998%B3=%%6FsQ;%_a<@WS$(Cdo>;Xi1{u_PzE_jzVk5-DmZ0~GWouUr zgYs%zUd)D7EXlBMa{&w<6CAXVsnMF{*&?7B*0nTKJCgOu^-UX9Hw; za?Y|3%6vooe7l{|`uW;^GjK?6(wDGH_9C;1=rExS=E@LvKXto= zXh*43zu3C0d>Ox@ey&FGQ=hKvD3Pq8jVyyD@~t_0tzDvOtcl1o$S;wlp|{ZdNet;H zc@^MT(Y2o(WgYotIv9vKos|+TwlR$J1Bs%>?MST5c?mI};&H^tV?=CuoR;8-LIg7H zNvFkeKDI}W?-%Aqj~o*7`Bqco$hU`9%icWb52y>?otHm(vBw{Xz_+~{@kd)5M2S-r z{2V0?^A#gGo=(AI8_!Mpba{4qX$IZ>d6(MF>1 zbe!Y$&Ay^THv@@(m)l-Fuj|;XE+S*o#km=A^FGA!n&TOQzByhZ<&nZMC1#N9iabwr z)lb>&+G+S5NetGE&&RYyRv4aRXnBqczpAwQp{=CV;!7)*@J-Q;A)jtNxnYSTU3}qd z`pxJ2k2mM!$YbB2g7FNIq_|u~ajc`+m-_Y13}IFHs@Go)*VpOJl`f{22{2EMvJR;| z$HisAXp~!Od=j^`V@z$#@kr50Cc)f)~RXFXS8p_p__$5d=25`nBG;V4u_&szM2*{oJOaGFAuo*Qz~)uX<5IN zfT<9iZw31SrN19h^qbf&UH5b>-Q%=#?;WI*z?Wd@;McUwARTp_QM!A?7wii`10edL5(`M&`;yp4`@uI_n~$gy@A3hPF#m6^!@_N+@Q!Tmv8Vw zyF%RG-qHgSI_SZIy%1VV+NiW|tkS-r%CkjzHV<3EUyi;ITbF$9Wb0Q~&oq74_|v8H z4fVAbYZkV~t!C${Q{K}wVPsR*@*+c!kv2KJl%XILnMSUr%vob7L+*_> z*P%b#iXpmmWpR3!y7783UK2U(AJrw}Z!TxqhupZL$%f!+&J{dG<$^OY3-hT7mD~VI z%$A}nbupBr6W8hnI{(F?N@*FzoZt|r@u9$*m8uxZm3^g6eEE#JQaXV`j*Bl2r)Z=RSrG*WL3Z28X z$d%mE=Gkn{j-$*{_E>SQH`$sR)~V8Y>A}Xtf{pn-uJ&mn^O}1r?lIhRxCe_SbK^=uABjt`W`4??lM8wP zZ7~mMsU-)dO7XSlr6C2RCfYnFyVQ;$b3cg$+B;XDml6xYFSXOIDLy0Jo%;DXb8`K( zZ+s#;kFk-*#l^#e&0q;|eiFfI<+}Jy8E6OEnRU#9+iK1`fy6};Pc(L1f=ENokf2YZ z<(|d3A}4VK?&83rK^L43YvH0TIn|S@om;=cy0UyF|8o6&>w@wH{PX8m1%kKZpata; zX_>9SIaEvixEq(9SIUg}xTW@exCFS8m>>_A6)D~(W<42wmg~tyF21=}&%m@F6Ppo>r88ji2@&xah!bP$godr3bx z)ZRU1NW<{j(KQ`?vyJNNDQts0SrIW5tiH>-M_FCGgNCThfoZz=SPA?1^Qp3zzm*}H zd}(S!{OW=fW`vd!&(#GD&l-~F$umoJ7V)*yNGpBikNQFwfkNvAv3C{k#QJ`94`gki z&aXvUsZgwyWP6S+YVRH6HnWt4M0*kRg9m2!JOnv0$k~;-A%53+(E7x%&!Ok&XgL#j zTFwL>zm=a`3Q?k1y`Apwl@dj2Iz6}|+Ma1Q?b(4$yY{0nHzf?dm9vu)O*$>)180Ku zET*?PAOiq+{Q2bpQc2qwILuYcB~NXjFRf3GgnZ3v@Gy2b?6(B+RneCqKcQCZ z4g3-$S+TXZwL$*r?_ejisGrV6r1rnXBacQVP@E-`vUVU-${FzB2n~xUhjn89ia|Lk!acL81Ls;VgPm@7o zqyurzYk=qK2#7*^hCvh>$k{aZo*cKt(>S88nd`|l2YVXE+E)zo)Q*^57zCN-vLT$O zW<>f(x+jWg$%8$FsLH(+6o=dqJza+-d&2f3K*tJ$BL_p zpx&;j+@xD2%W%oMN4dgz`BSsR`2yptDxk}Y=1EXnj>u7pSxTZr8Lx4g>En0lV{S$W z2^87s)FQoO>7>J0(plN1*~K;3wj3+KwgS!e^eA--EiJS&0!R6Rrr%hkuU`C1D&u7- zQq#Dge)ai+*#*x1S;$$XLC%k`h0O*FbMDPU87G;&8cJ#3k)Qnbw1b#|lYhMFzVklD!53v^!V>Jtir{n5!Y< z(Ky(XPs&ACz#NSrsEFY8JeZypBSvnPHSM zPw<6RUBi9l%LuquNF>bM+pS$f3+0z^$|D^l zI)G9=*w1tc?0=Cy;W2EBe#>z8m69T>7oo+k`Z(?fS9(u`d!ag@7~%()RJLJ}-gc{R z){XBVOE4c#WJwtB*H#DZ?35+ZaG|)BlE>eg#ZwH~&228or<%|~y;#V{Deal$xq*A! zFO@MS@*tKeW1>bd^lTo0ExM}QPeq^DL5=`EmeANW_I5c?xhzKjXT)-FN#JFH+9ITX z8QV;l+uys@I$t;Lhj#hhYj8bZIQJdyU7wbN_|f093Fa<6E6*>s1y1N$tapvoSKvJZ zPf@=0Mc2SPK|GS6^7X8`>IwzhWVhh)tOCyROzF6STiW=lnk`kLO>~60pOWPjLje~} zSp_x|6;~@IN&B!gFdk6jOULbMmW%`RsUIKDCcf_POe3v?7If(KQ$srTx-qy=a1}KV z@KGN@^cIirsWSP%z$1=r`hh7Cij!py_m==nllD7QEw49AjnO9f9xQpSXKt=azc z_2IsewI+`d%geIXx^dsgTBEor?OHq4=T2HfGdpN4*ZVay9JCgacAaQV&x-+7G(_^e zFQV$IxM3~@Enn`}T#XO7FMy{6d3J)hR zda(FvisK{CgEyJ|{taSgw~UkPhj?$EOxtw)7dvT7%)^|O zXv;C0lyDO{>qY4+MTf>wvkJlc&kqztUm22w2so$4&5Lgm9bBkbTojslj=n+vnRz+$ z!WQ-M(p*gjWIZ~bHh?jxch6X8pPU+Z17qC<~WVeUyfT@=$4XTje09OG#>aV%}~@bzy-cd)KwwH9^lGd zsicgbNGy{W7>F)r6R6N1k1xeuA~+%L!qm&Lze!0`FU?HKd|8_w*U;W>DOM6dyJ`g+ z;b_A+%!MPi1l*1iV`=)F`C=v)F1}SX8qd%;t6&O5M ztXkyGh0b4pQui!rWgU#x(OE=pqb53MW)dm4N0K%FhkpI2V6XQaRRY}M@=a#5=fa1V zcmCEMJKDa4$Q?0zbP$6}U@vHpb11Z8bcT^C6kE63n5qI4UG$X{>yOvVOE-v3S%7I9 zVEW)qq}J3cbD2AsNuo4TQive-**?TMoHEW#iaxjLxFT;bUYRNK!sr%r_~Ez4chIJt zx9iqBRL%BQbc-tenv#2)ud?~IMRaRe4Oz31W20QtC!$BKv!v{0E?$3cTB=xgx(DXZ z470_VxWahm*!oIIqFragsDl|j&xWC5lJ7fczIUI|3HyA^xCq!m zvhbDJJQMboHGJ&r@f)4iaLBdsXd5~gWJ13MZKJ*nGEoPE##)c0i8s>>5pd>~8O{e6 z(3aM+P#5f-nvYZ&EA4xYyE6>X8gsUn4%wO( zma=|U5u>ysW1>lOP`6E8qKlUXm5#9*xb+Y%g}~ZP_S%a~Y(^h7^{#=$DVFtkWcf#x z^j-U?s{ZU`+RUW(S=0NCf7Ub}jZP0aAqEEc{pVTEddTjNKrCMEeBV9!yqpmre(B#h zBM@zmYZ4>!Us+UhPb(Q2WoykbRYrd=8rb?ab9Nr+e=q1Cc9%g{UnXS~m^oprxUeV| zYZCXt)FSX5a$78OFb+Pyhdtp;h&z1YRlC$I$f?I|bqvKlQTH*%5_=YfV+gFmWmxqP z?3bj{you1uE2T1yo8q zI#9DryG4!D0tR^S!vT<$E>dIc*diBKEoY@A7IQRUD|rQcL3&egrBG(X=XVBYxHzzR zu8IzPlgQx&IT$O8s7a(%2X%2-{oR^L{RQ7E+nWq_*tZ24uol|o^SvOosM&HkM=smY zJy>`9_jS@|Z(LTk57)x;;+*+DO;Lki&QoCFRWe1Fg!hDY8zDx78O_(HYC{HW!q>wL z4LLN~T57g1LPnqUf-j)zErV)(AE)pvNc=c*TF1dIZHUI?+y|N*fwpBHMW)QN0J|4$ z%fMw3fTKdDjH77w@@qqTamLQDPe}8+4F%Xx8?e3_tngFbwgC8*fiK}go zhs8q915x$Uc&#ONf9Eic0^sb`DaA&^aLg~SF&iKGRLo}kig}v8RFa&bxV0Yh6?3x| zHGYvJ*X8SWLX;Fra$CmQj8al6{iD6K`uv3oQX1oFFSVWXk<_0tX5!uI+Fv4dqgRfZL`$xrJy4i`m7jopXwAe9t9-e& zHOoEuqd+I71UVNVV>!lm#d0i*%gRU+RRNIg@0?rFTqZIKvz2^+ETiq=jHJ^1Z>t=s zIvcYe=d6<1_6Ykpfvgg|M z)_;37BQKG{xd!d|9c#>8vFaXa$C`9k zENN0ZmT*_Bn2GIJO9Z^m^fYH)-~WjBlnxYhs=T~NwyvqD@doQxeJdRhH zjd--V55Ow3A#32R6(-sH>5o^Ku)gfIomQe?d6dV*aaRABuysF~R)sT1Wc>H@`;?mS z{S`Q>#?kc{s}hgy$FX&80L0evh<1G6k*c?EJ5^-p=*wbEeyWa;+4gS*(NNXbxmU-e zrJEA$lxe7d{n{{{;@1SDAKM+ocnc`*TrOTS%Pq3uotwagsj#PBTc(B`QL0J}lwf}f z_R0M9d)=z9b;6D$GnDG*9GY=2Gm5&`IVvL-BAi&~=!_W11IIwNu`j$Ry07zr3==bk zGC9X&M8j@o|4fHnD65((6;(YgNL4Aq?oZ?q$Vt=9_V?gy%kHYVLP^#0!ul$_8_USM zvDoh@yRpPS8~i#p(nPyu-IU!}*~3&LEO|-G?gKbJOvdq{+{T(emH1Fsb>1ob)`zj4 z>*KV3*#}mCYNv3pk161wdYkr3HDle~$E3w&B>-RFXPf4rdiHXNdez(1U#dx5m>b}a z3#+T;sBjBkyS1vLZ?Wr$Z>iHoRdg(`(~@#~0A$WdZ}<1)@BVORCr{?M+|`pgx?}(C zQw5ZF_20hU+;+wP(qld@#vUzO%7VPqDQv;jjtH2OAU1rcxJI5oejpmJ+eDrn-zd+k z75I0r+JCZpF7LcR%I)u9imvRs3jArvvBT}2UGzFl@h(iw@+FlVB}Bm~3eV-SLV+f} z$dn*Z3+-#tm3-Sfgo*@xAdjanU0icpZ>uQoHAaME-4KWo-nz z8g|pM>@nXf&u|k<465n|Ck_Iux^2b&9KMHnpj1~C3Z(&6p-|cbf6q{8+0T-?=r||f zd>WCmxw7**!HaPbJ~1~5 zpE5P(v&%sG0PV+EF5Y_$+NU3a?;BNPT^pYzwY^u0-LmdiWI#{hQ|)CPT5T^RwCz_3 z?YdS>n^3k@cBpa1qevsHCN+d+Qp4NQUc<7hBki&rf?4)E!7OX;q@VXX;?`vm+`3;0 zZe1tbYNa=&4~fQ%@7=Py>tls?4aDwdr{7fU&ITusu;obm6nuaEy~^_r0_T1p&knzx z?or@xEAa0WxPmXeufWR``ezilf-mh-;M)}V*9zQ^zf*yiDD)M$(XBlHj{^U@Qva0l z{FVa$QhDC0z)vdAZz}LF$g@Mim)=(3n-%TE zn4exC7|s%Ur1jgbb}Exw?Cd@G;MfqpHoB(M z>W<9+9{&vKc!PLkZijz$S8AhE$5Ig@=Cy5Orekc#&YZX!;up#uiK~^r@tjTmR7+D< zOGDvQ?2sHXc8$;a&)+3COs<^@yvt6!pOu?7*vstaDUs2z&i%Z9{Zb+c5Wh^pW4`9) z{@%FN@;Q9se}^dX$lp0QeRN#8CE+fdDg{<-J&a+D<@9F+N7&j<$M&M;f+Xl_sfvsw zNr)2qgU8Ph)U{)U=py!(sSu4LKo(Plmw?cCie#Cfd*2 z$@dz;&q?ONg`wRC4dG#^GJUT$%KG0qq5u39CuC{oWceGuRR`-~A+BK{+F4u7Ay}iw z{J68BSYGqhJr;i{Pl#`%Ti-?TO>tNIsg+Y#OX_VgAU!_U7FQEri^l`_rTn-Ct>meV zsDoeC=fmzK5%;xUB4O&CC2~JU zB*Hg!;%eg?h(z`ZPg9`axe9XB5;^Q&cp577AeDfnvj5_j$~)!GQW?ei#Tt;R;|-v% z8qU;yS2MeH&egQ0d5sG%d9sR6$)~3p#qQjLxr^5=GkpLz$MUi$@wM{dR8qkLm*x~* zj3a~mBO6=+)wC;cm&%|s()+^UUc|<5wQDtRGicpRfA_j3E=gQgJ{0faGAH27kZ%W5 zdB!tg{Sl5|*M#?e2bGJO!Z0yn4D9-f9G|qVX=|yAfBKpM=W3ok8(LYP7PVncW_H1I zxi&605a(07i;-;iTsS>b&>;5Vx_?;?H4$%F2RD7n<7H0xhAJP9HZ-|Za55m|O1v0& zdLZ7tz~!-Wc{MMFT^VRjFNd2x<#B%4a2b}M5+km}iO%x4y+w?dLm~WbH}DAJhXaq7 z%KLTYVN{9tT!|F}PRIJ`5FS%hqTx!c%%iZpFQF9(?RMdNxT-33$#$R`zz+ectIDIh zQia-~SE5C9I=VAeki7d9qf9lk+}M#SKy+2~2@gvpXuHBu?oUH5W~d&uxI%sWEsFFtxaUl^V16o7HmizyOxglcJ0Lia}HQg zk_u*&d^kO@dVC0+9v~JJ;t}D%4V)j~#DH43t#wKz_Nt`~S6YKb%|2?F8-FvfaE>e_ zhnDpnzOL!S7dIl_Y%u4vAm_s>#Eti*lwbSJ?ONU)2QxfZxWTb;pTcx9-L#|Q6a#$n2JdFe_%xz#ELQS?N(o# zV%!%C49(DHeixSq=l5{#YnMt4sp9e789$yo3a?(2JEeNrXFuG28_PPcd>%jl{L6{2 zl)gf*I{!TO8Gf2u1z#YJV}WMxDs737zOO&y=K`<*w@1Obl9DM^XYO_>u4Y? zs_U+tR}WC0Ba~;Y@*J)_Yn10O43V|& z`C=?{cHN8ZvR40yBZs(bbxJXhqn%jDwvcEiGrL%xMYtPdtfe-H6Do0>!1N)d!)^}h zP`a&G6hEYfKqOjTMX7ky+Zt8TULJEzDgSbO1b8abe;P4yTy|)c_h7E{k&uqRcBC0 zy{3+W2xEsk(yLW==`E)-DsoehU6&H}nfM6H?#zp5Mi8e=f6yQ_wHanMGx*uS3EkxL z{&L)7yA*iBlXX%GkeA?%*xG2Ac}Xt0=Hd2p`S?^ml@ujJx|1QQSuMpE zp>xspLrR=sJK*m*7jJKK?LC5?4y)u(S<(whPiFtEy(j&BBm6=7;7H>j>v}iQgO~28 z9R`uoVXcEZ=xp1~_I~6TLL(auyVZ~AW~Y9<-jSm3nqS{zJ5Y4~NlMF_gbt;qtE9BK zxueZ}+Coah8anov*i1^N|K5=s(?m*R>N|4V_PbL0M@QU;ej}w^W5-h8ul~4pLyGf# zp3Yis$jzq2tJCN=7rNkH+lUA_haM53h8u%6Gt3JNyh=~}HJ3Ke$Qj@JxWs0)_=;Ya z@9o89B`Pyg^|xKUPc`emC0JHr;K7H7A4VC%HpHPaH*-Wnn&SrENSm_Y)|dJ)>lG#) zz&oU3=pJ5TzdfAQB3_w>&;Q+7nv3w37mz0Mh+mo_p%CgDX|eYn;KEtA!5%%{#caRv z0`EfLuoT2zmRk*S#hGiQDAA>VX471+^LbBII07%yHstsy}WYM?`;)<#D+N z2{ic9Ee%54)H597CYA>c=D@BeXz=o9wE67e@qz#1SO;h@6Ydtq*Cu9>d{ng;^H*+J z%HF%WF*;Wbk?)EM7Yj3C_(oWnY(r|a!p$6&5cMy(M+mx;pzH(m9%MH`cir}?Id*1s zVxFT#d=YC8`cjd^z=I??Imn4;+{;C@`SFb%Bq_pg$}r+N!}3X2IV=syx#Z4$2yg*O zGWNhb4J08scN>CxHmKs(JsUilw+h4dorb<7I;-2O_~#w%D+b*Xbvnc=w0?n$Kh>#s zE8&(pzMn1DwD6VFu8iM$7~dK9!8vr8DK8n|Of``ak+%Y<`e% z$B8tjzjfDKj)`n=cL?&UkyZ2|`?(5(L~gdrCq~$Q2zDuwAaf^UR+lNa(g9PbIArIn zqS{NtU3P<)75|5$;~O<_cc}zceK61Pbv-4(5miM9FnW4v@fgQuB$ZVVDA&WqEn%V+ z%0@n~BEAuJjBeHDx@)?W)P?thEYlK3*@yc#=kCHUv?JVo9;7Cb{Zo!II zZz=j;k5?`2?`hhZwPDG+^tjdMIPs-3^cxEdYKZk=)We$`)bMr!o0&TbqaH@)!d$)i zbk2D0m>ioG9g%wiZU)P?;@B+PN{4=Mcuhk+XpGx{N1}dv5XY}NxvmMXHncdqPik$V z?a^}~j){b`bVK7Pyqj)H@F2l`C^hU@Rke7M)seZT=&S)&tgc&gjr7h*Ohuk++)`Xt z;N{7UT*dCgqL;D>7iN8>o(l)jOSDnojmL(WCyc;lD?=bM>v>S$T$b?tz=DsxJK_9VY!_&k4f) z6A1ld+H)LkEXzHF-=rYx+UDr$)okxz$pYbRJ0#I-wEK@c-`@Vy1`%^h+y=i;ROgCTkqvv=?STf0LI zu(x)|k(`V3?(1!ZNLAK&%|t3@(7A0u&ji0#c>8TMtXUTqRy9b@;6mL!B^5;5cGqfY zhJQSL>4&GkA9jnj(Yl3$d&a_vFO%U07&)V2)WF+wZb=U;crC$8QYxv+vLkrFU+WmXo1Lwk1f=lSJ$i6U;3&svnlgxX6xj0Q?JIgX4aTkiaid|ln!EVyxy}F9ZJhMxrQe^gcVU%Xf5IJ zERFZ4dQ^eGzPLDfnP-`H#l^YF^E~tVgZ;{xc?+?@>VEXqetMwTh$*6z_@-rCYy4Fb zRZG!0s&-{_#$r4Z=17}htw8I$las}^@p6`>R?ej~1Dul%LDoWEJJdZB*Te~NS2Jth zRmZn_YSik1dcx6ipI>t|lkmIbR!z_7axR;4N7T!DUf{{b`E`=>G+B$G)Rlc?UOc>o zV7T<5QvT@^{+I^m>V{{%pA`?cScy)!=j53})`>AO&}*KNr;UR+RhiGP609;i_AZc} zlkut_i&k#S;`|!UuHknHL^s6N!b$!*9Ql^bfe2T|t$9Fm%#)QNz_V=MjwfT`oeznr zrKueD6D0c>=C7X&c|^%OByT5V5_=ykm?s^}og?!_*eXy{;0c`LGmY#^#Z;JvvWTk? zgEh3`-?B%!;Rk<|ry?mC-(8mLxi8OcX60ItF{~ln>A9GHtmM7=<37KS`9I7JHr*v- zXTvhruyV#u{%&Oboc<4UgTMS0C(F%tPL3PQ5e|K64ICGGPBhfB?fP}tJMUu_q;B%A zdk(yhtSQ?M=Y%LL%*yhU;g}2B(*!=}V9wY%*vYRlVJ=DpqYc z5{6tYO)A&vWvCB7eN81V!FjeL_>L@Of;OW$X*;ugy$-kf^OMG3==5{@4yDreIrB1C za)mCgsZIQ?tb4RQw&)Db#mIJK{33QkbOW3)g$QMafiAw1KpVppZ7c_EO!sS}NY;kL#x{vJ;LQwa z@man%+qGf&5zCQ?wJ|^QWvb96fi_yp)X@vfTmkwC&*4NL|E$z*Kr=ui0icoD(sxQ9 zS`N^5&vuWf63cu^kG;}|@Q&t4$L$olOK=;H- zP8>=t{G?-vKZ~%}Xo4^`#{D1S`V8aU3Uu5V>>hRNk;NcrQcYa!!&y83HOjv$x+PRgHDT@4%OL%4jp zT)rkkrt^%dB@)xW%H-JPat|qgOx4mG({EvN(&h3ar2KJJQxvA(#N~rT%)(Y zUnJIgk**G4@{HkqmCU-fdjEL#NNRhSH!G#!IkBM(q7-;5-r6#>E*0NeHD{Gs@ZOPs z#JGzb4P-pao>%4;yGY5z6n5HIGRe7~mpYYgllO_H_&NWzr?zdni>HR!0rqnSD4tq= zYL097)X4S!&Qn`F9sFm9H5u#_{qJ{i{?b#sx3zPsDa9HMP02gXjT5)jBegxQ)`ZTX zkP7@Q5LV;(6V_Fz1R_wyF9(x1-n91xp7)vR8R2;5gu8E$i!2e8GsvsBgSzMRsi8LA z1$|xUIrg$CA%^Mb*Q4MR0^}~`8Opt-ef@stJlL=bIS(ddS8vaAlRQ}OYH_@r2P6F( zC<)vIm__7>sXDzkL;xK!U)9(b7?(ajCDt5b&5 z?!3CU$Kk27xfAP*#t1q=v#qXPAtQ;z|itHJBt5pm?!^)96UsW0+?>iGet5NoP zou8@g2EOsNso|B&z3|@EBeXb`gZm}m5!j7xL%0_WI&X;KP#{<2#_u};Ex`Lu;%dMm zj98l%)1&U4Sp{l`T3H>xST5PE;sP&CG*Pxrj!v^%#21Ip^wIFJ6WBHI9}L^8iN?eQ;0rLowsdNOP2&a7})+ zJ>46-^8Cy7_R748@GhYJLD`FrEXaOg&iv9>>6c;`nbRi*xN?7Q`|fo!V;@_|*v77! zZO(px!g(a~nUmwAj(?XWW_>|bPWw-QD;s9ZYgW$8ud|qQ-hds6p_C!3rETyb@x?t4 z;(SkKc7eRd0ju$dRiVDDuWwdn&mUWvcf=y*egQLOlzVEn==_2jvi4+tW!{9bzW?mM znpYvNV-rdF%53xUw17(0{ZyZgJ#sc?iNU;HRI7%I*Y^!&4#PVivs-2Q5-X{IL%0tC zhrEEXiP^s5FRrKWV}vL=@*p>v-ClBw4Is!X<@Lt+U^}F59q@UYd#Yr{;3vUP-+eAB)&bAreNV18O zS&A8Vw5@l(EA&}pc=0MDtQ`!yL`~Ev{D0I#1@B^Ho?Z)|EiKHqYexM7dy(o@GsKJa z$Z&QqS}{X&^kAj|-XOUo{QXU$L&KVRknH#Uw3Fvy{|UHFK8r|B*t(sv!W(>c$rgFs zw{ibX2Hu1#&fpNk)x)Z_@w#F4CM3=qJ*dBMV>;OT^{=ujvy&+?0N$8$B@5ni1(`sh z9u;jDL*9%PsW)l-<^?!|LEgUGT8_l5J<$?dnY|gEyXxIHCqJXMcSUS|;b-FVe8w!z zqZnAHVm@MZ8L@nolsp68PBbg~ydqb1wJ&r5oZek9wnX42!FyKpl?C&th~}HHHuGAd zto5)O#`4=9qhiv}xdQSb<2L_Zzr3?S-j$S?4|i8yY?t?PsTf+&N2Cfm%X=N<)$HlP zfxN3x3YIr3(k(uhr4i>(yr)uvcB^3}EI||mnh+l?@3ZMJBk9P~tnyxFe&SeoFO00s z>L=l(AR2r@Oj*VpO0ASYhTH&nPi#ITb_Y59G%V#xt7FFER?o)o29fLAcKbrJ+RXeb zw3p6hXs&GDQyPv zW5!{41rGaKkHIRyf%^^(CH~55R$Bj<96#~G449K-jGDnRhAQS>tf$yp)=~2osaY1U z==~98cASFgR`(~hgnqbI^sQQsEeb!Q!tY_i&pT;2UYW=otK&#rE*96Fnhkf%NY56N zx>6K*c8@2q9yf`!N}2|lYDSSdTJ(8)h)-3AZ?#s!PN#VJ2)vJ1T-F@U9K8ZLh%0S- zb9|Aiwy@HDeA~^Qxh=oC!qxQfH}+*a959O1hGL%nD7Rj{FI=nLl3nh`&t_*ma(-Ie z<~)?s#+-b+jXAont(2*(e+*uSKSyPL_9#_32W}>vJlp2{^k|#&o^)W_KyGLExS)mC{#MCLU-RoU_q&^|&H*5lgF%ADIE85hS!xOi9>_`Yf- z9NyLfhZmaJ&K%4+Ty%!6}q ztt_!yW(~|7UV^W~fac?lk3poHl_QXPD>O#aQhTB4=Vl`?_()Atd?oN(`|LA-W%u*> z{{9f>?C08huf6tKYp=Z)XSz>ab)}BLn~Vt(y+zLWp5lR&q~gKDH!KtjY;024z~;Wd z1z`Rti{Cyv*gg)t2dHc|!RGf7c<#-2ztry&C6HlTetw=1$ zGJBT3giao;%TGV$BnazxHensu1w`2Q-itJcdjnK|L3Zzd zp$)wFOAE6{*T~uT{tf+DBL3nB3yH@d-R^xEY3koWKQ39{dk+V85+w~KxdxBl&wvF1 ztiwe!FA`%?K{s+Xv@I2#X>m&ib2a1DS>X`K`am1|2K*u0^#H z>==pDlUdnS;MLcfVBEQ;fwGfjx2~{zVPtz@WPAUDH2Yv=+&3kA_!+umOFT_Akn=al zc?@!1hH<}x27=Bb8Ag4q7{!8|H<%nJ|cOI{o zx#_%AA|3n#)JyjAxHtm%2m*CUA?QWJ>=G<9qT#l z^RUY@J*lue^IKs5d|}RB8g@!d-OIdLmc7LKExz!n9$#tDc=A3q2l~_OgBjBALzs_b z+9D**f3u%UEND$q`eOtA0p1fXo44K?4N@k>&5VDmcz%oGb=`0D+tj9h-&FGh-!~|h zTY6C}H-*9J9pF#Z9bgTkdH#NZ9gy*Dh&6N;e!Yeb&m`J^va-bIs3(7~vIlU{DTE6m z8QcQiT=~#5O{L!UTpRGsnIYB$Nu8(nLT3>#v?0Jti$}b{G!<8=@cyR4`^%lRUf{ca zaZDjtgK_q_9*ks}u1aQgdo^QwK+sg+8u&-T@Eecxvybk9M5ze;7Qvh@%huspYx-)o z2QkF+R>iv>ZCX-J2|nv&HK3yz2>LD1pVSeG5w(7Bsqy1N#ZTj6rH3i1_Qf~)iH3ev zQ>dZE&<78iY{?EU55VEe8h1{e3x;<;=3fHyDXk={ifZM9kC79`=>@a7i04T{`+ zCeT;LyJFsIWc+x)+8fd1P%4C0vepOB6RQI*l|(a$cR`!I1nu2QnD-vgbJ_e6 zO_Pp;URoW8E0?Buk9MVHjtU}n%Tj_{YV z)-tmncqjxO1Swp~CZ!ar;qf~)dVPk6SFNS~k)R>=eBr0@%^Gc08R3D0csZ}7E%Y>g z;TZ2}DT^XDg32l>E!lLMGzL8jkse@nVLuQ(0%HNpKi#uZp8+%P+a`^2?M_YbMZ3aM zNBF=VpU&9AZZ}{`iut$OrSOkZA(n%3nn_y?{*qT>tT{9auwuXp#t>&H+ z@LT(MA#VbBGQJw3`Itw0%I#kyBKw~EfV%6D=JQAt83`0ax9^-ds5#0mXpy+NF{&KW z^M<-UQhp}~Zn)+un1Ymh4rP?SbHsMQ7`mym1-iDDx^WVf zWo_w73g`ZW(gE`aNs5Ivp&@;(u@1OfQCl}ZPg)-+k=8e4u!IgPezrHZ1nyjvllrxz zeMUG!GZi1@pzq{#a{j3{@UzbKJ%dkP2`|3__~A&I6YwvueL#4qJv&$9au*Eb#PkS8B1j;lrt;|n}A<#LCdWDpQ=U)Wrm-Hr>sbLUKe6S zEhuP$vocJ15x>;|91x|TWdot5(ifJ^?ElnusFC?U{h#6(u1R>xOX`7V9MG#oS~Rm{ zuprZKgs+|xz$PTJn$0FD;Qx>0``NDiuF^)P1%*u*T?UaSG@zH$CzNmOUD1wb9Yrh8 zbl2!op2|O8wMWIP3qXqkk<{^pzXrqaTgpsa{2?TmlX(*o$AKKf!oQjtkO0z=r{)Ao zShvfr*9&&dEqTx74s6jNPx{-4sq~zvYwllXsG>0W}Vr&eG;XgpXje?eS-KlA}z=~_jlrDcD1Ip z_p5n=foH|UG*)=-D7#w6qcPk)8r-<~o}eXTI9@MuR^n+$$7%Yl1N$~ud(8yZBhpfT zyK$+vT{JaBX;Q&M56GB;+~(B4jV#>MqK#0_*t;5d*kG18ek6H?Rz74%iGE|-bj$WbZC-& zV~M-nSkll=JOjT0_iM_$L%of~-gbD6+F>kqw{MgBr%h3Cq3JE}iC8Hx|4lP$PJdG^ zTYG6X(%DgP&!0_k4RlA!xAiskd)V#vV}Uq-v4yh1i@>`Py#B#(7mzbKZAIb!hg`(6 z&xnp83BIM1{Vt?~P9ABD%npFW$8JRX!SZJZTC}_;H}rimz79<_h|O-qv0e_gap8I@SfFl&Z`xRyyhlz zFkkD0I7d=zoQK=Vu09ga$cD*Ocgyo@V#`8igl36cl{o=?wKwR3^Tz`JF{41eGx=BU z%ndUdEck+@U%3~7=U{8vY93^p#9gd7;ZziJAHEl&r1a8)kDl#pZGtGS&Px!9hG}OR z?x^X-Oz2lt+W;18Qd%g5&;k&)cHpz#w>^u!X0hl!gdZ`#BXZ^>nac=odaWAOW}k=h zhA%z*PPPwMZi4+NNvC3+A(^4p{tXGBCwvcdINskuYWs*l3N~~%cOh;(&I`J$$p&76 z9%&1=fE^^9=54z|aBuC~ZD}57Hsi_OWj^VLs0C|-*d|7cWXr9N*wszi9;mkAtFKl| z4PVKi1E_I&_+4ybB8*Cx2&2-mJIis$QJ$HQ>3Soaj9B)Y(Cvt=Iwtk zDehOvOn`Q@ke^or?Hp~#uT1EvtV@k`tlR*&QQg26<_JdzB2VH`w$P4SYgr*3s6Fi5 zpj?@+yW!zs53d#CO&S4qUE%mobGHKj+z;T*8Q(efa*qAfDb{Rfd**s-x3ML5{M$Zu zU7lpbhrW9`~##yi%^)oDoBXFwhc+_hI5(6JIv z5b#*PZRtbLDAQcJhs-ya@!TUyuLUsUPCdJIrMNv@)6?eJ-bYhn!yOK7&Uhwu+FzBv zzxZxSg(M~#G(AB%sMA!H3)xqD3-LfZUfYPqNLtMp{&Dm05+x;$wh|7lh;RK9jh43N zj>~I0@3^@&ceI2fL(p1R4vZM15T5kkpY(6gv#~2Z)vTr@=h$DzC8PgkI$A(6U7tCU3MjjVQd$)hl1aF1|y|KlR}CfWu6 z@N#!bZTww5R!i~!+Qz|tI=7d@9XpcguH**v59W|J1^eQAN5Vb@|9*GxPQkO{dnOt# zPY>n<&Uw#hZjs@W6#R00kHqXf6Z>;%qY@xxM+(k@lujS&iwxB%cy4@9qGcxnPwHb5 zpl<6sAEjUnY5pEhg6H-B5)6iz_fzofcwJ({yJH~bA6rPiF5sEnor34YbBWHC&_e6; z>r=25zAU}TmvL5duMVfZF>{&)9)gVTMxFRDadKT^Q(C=cp8iZC_UJA zl2XLRGsq$aNoM>Uyg1}yP>Ds%+7bLl1c8`B>pD$(JK*f>Z$4>vva{t5kyA||33C>_ zY7;B8-slbdp@w+2#-&_>hnuGOK@;F5-bR}nc#jwqvkE_M>-DYVcZrLMc4!tu{Fw#% zvCU0irLpvblZea`ftCDEYHva~-3BcTLR0gCV03Vn~39)%6Cn*;M5o}8Y9w58y9is48f3MMk zW*59ON?EJ(Y9@$42`#yD7J=#*$O+($5K@+}-D}vb@+K8WySOGJLp&?)Kr%p80zElD zF{R?SYgm=PYVf$dQJox?dYY56g-~{VwV?Du;p8A?z$dbwgMMjy5~LWaRsOx7idCD{ z@BZp{1^u?(t$w>H#`?YL_a^nbUj5#vet)ihZ&2$8+FP%F-zrz`(X3inMb#dpZXvDP zaK4=IJb9*H&ReKWM%0_M7S}^<)kVKsuh3Swt0&cxw%2JJ)(dLMcWFs$2mSV~q2Fnj zXie*{fttS8XpW_w=2#e+Gi%iTU!{3cPufb9llCILMuvT{c4BXZKfXg6_yEuYr?xeZ=$s;za>i>E`zjjM)YnLDO`pgH&@1uY z|BhB{PH5TB*AsqK101QkkB*30N5J0!o2RiDkWsrHqSC^PYl+x?SpNxDH43*Yo!svt zzrZ8IrBSI5RngxK7amIOss1*d@0mJa!^EVR`mXvWeP@0DBv+)LK$G@bSZbT%w-2PN zGow-uDwa-49k*g{(h#U)`EiHZr{zq1>KPZYgi^|J3T%S{<-GqMpq6tt&gv?qv}XD) zP|ErPeI;IrVy+PD6|h~o&fXfPdN?+B&^PGeaI+w};QimM5zR5=4SX}Tf^oNWw(~zR z=eX2BDTosPbZj`a|H&|As_Rh@4*aa* zUqV^S&-2&J-6rMc&zr}$4!kt@{NyuJ{8LXJxpn;di7Sm4Th3`Az7$yTr^Y&PQN14C z*4XNKT%rwCR)mvU2Bd=iMbXnn*{dYZa_sz!iy`y%uLxj}I@uS=gN1ld>c6KnD;N{Z zpO|{3aB@0Wp$9LXeoK1zgl||V^<)rr;h}?^MREyT2s6W14s#CN_t99GmDqC>C%pfT zffxG3f?fYg$o!(bgj)k#GkkQu{NKl@zWMw|W3GVJ(DkA`QYztAZu7RzK76ODUJ0Im zcIM<+RkMO;x4fCUuwo(qR?D16;VerES)tt>u8b+bNRkV{t{Reklf?k!jLy8Gac0R4&$XbY>r7ep-h_wS4a zteoX&4*qYjP;LgFU8tft(n&DRgaHR&N5QX|fCJt9Akew@Rt-U&_;j3u*({qs2RPb$IrJ-972liZbi624YSHvq>=OX260 z5%BS!_N26jQl#m3@QAXJ(5j6qBV~o+Jx>20|5Q>~LcuohNCF-z$lCG#9i1LXGL&10 zd%I@fPhJgtOra|7`hPSN_D7f0%;b zjA9|G{H{Zj=H*@8@N30|17{DleA`$Bnrs35-oy0?@qMpgYgFpMvk+5DZ?T002TMUI z#M3^=ao}qorX6986f6-xReDnj4(0kzoeg|wD1OrtG_?^=4DJh#Jts|7UuV@dLA;i} zF@;4+AGGz1A7nQ8qQC`(Mx2$bs|!dk1cIQH+jLZKI~I@FX>Rfxm6&~Il2fgCa- zOpt;?V_I;Kg=5cBtZ=)Bupw+{Fy+(hPBJNeczM>~!o7o0WHnhA=PdBMufpW|#(FTO zFwDhGDuP!Xz{%4cdRQNP0KRepK9b+jn3yo&wePM*Q+<=0r=Bi?H>%V=5*<#ed^P*q z?3gRD7e{2T$bL2J+pL&#v8P8gC-{0=3Yz;%Jd!NN548w;-6#mWdi8@S>kvx}ya+%P zUbMlQWLfSXTG?oYnPUt02j`7&>NCN&j)Ey@KfFT#3o0TD&=lW3&c&nv#3|iVZF{Fk zw&sGbUV*v)&anU;gC*3WX_l^wLAtbEi-&Jy^Y;RA1VKSJ!S zfyQAu10l9nlyPKqG{oMDjww{|Au50i879CCEtHBP7}2^RL>nyKjt}-YCJMh)s+H>K zTsKUWSH+?A7U2Hrj@daJJjM2N66|b7LIZS@scdGrsCc&^1wP z@Ex#^fLlP(fkaLQo*v%uYRO0p1=`cy-$C7_#C5ClrqmI&1mpj$5O{H2F{;{TuuZ0+4Bq%ojrmeiX-*DoX&XH|pTS8eXf z=hS?3=?)Z4p=9=lRZ6Cz{~LpEvB z3+I+)YIaI!#JhOLfhjSC1+y^EO_3M0!Yvj*Me~)!01jtXvu)E$ELC}2juhN+j z%V|3AZI>560B_z`KbmO~tKWl{)!Y=(y)e2L=LrHGUem0{@T}2~;rt%KnCbD?$)}$y zobCv#G=4Y=BD9ZU7WK>2Rup1g5Gy;tN})OKDg5HQ(~ZO8n5KI}ZV{?71#X8ZzSUhP z(eIAcTGE7P;Vp>cZZy4F4qA+apo^MCPY-u33O^Zi!GS|&!dM;;x85iLeN9>H_79~DD}CCMR3JH;WC zT<;JKuAy*W!H7Ia$#e4V_LTHb!WY-xFAjb`+A}jN8n0Z*c{q^C@y=d&X54U*FGgZ| z1tX@XGoJJs2EWVSRXUU0_j``)orst7cb8_YoYB`8-n?=KY@tTX^LLARZUirc7S-Hb zTP0TXjrPpQiWa`O-tpYZ0hRXZTqGPxK--*lu;5u+} za97*inc71oP0|{l=qzQrVGW6;`pb?mY#l8ahizw??hd*2QYY5b9ftR>iZtX_ZQkqN zSHC|hr~Ku1&|Rw%Dk`9P{z97P2kl4(N2OPDo?7pp6uJx#{WiT%%bGsyYR6`${;>Qn zt0SpU{bN}JvWb6ZfVXt-{2gCPbmp9QF1)RKT%p1XXkF7p+LrkP{PqD}Z9kQ!p{?ro z8|6@2$g{phG%2)x-J3MejcM6B)$5=8nE))NZ2?&PAKeKSDKh|zYc75#j#1}fgF5bw z)fU=Q)O^~L^bqaIwTXUn57Y0cGBy8&K+jTDpl3_foqG0X1$stVw60~8I*L;I?Nw)> zPFC|L(EN<0YQFjnx&|^coJF0*j1u+xkpL{-^#NF<^>>2BJvji2`B_?58buU(RM|8aKIIS!Hga zGcfbXG{+jPLZpt)e;@sJ72sE@w6u)rp#YTb6#*!%EA9lPG%)~W)D*S-WZJWJVxVW+ z=s%0m9aE?o4e=nzsWsCQo%670Fb@Sk8A$4Z3w!kCxu!YQ?e_RWMl&V|UQlr1j76+i z7)_#!hzl0>fGFK<9_dRncDTcr{XKlfN$ny-Q_@@<`cTs6_T0A)^9Vmqsh2PfSlslCpCBPd2@b;%{=n-0iP-uXt z!98)>`GSm)Oyh?;A<}OZf?wOg5`S14vp&4ZxA^L!G|^xInitQ+G*3B=d&Fzh^)S(O zi-wo_ENDhZs?1BNLr{nwxQis*=G3xgW^?LxVX_^wiDYJp* zbmIBLfi_Vr&G9p|j$Z>dKq{RxKXB(e-K^%>KFw&bB1=07^Iu5G4c$sY z9M2&*>sjVTCG#j=^mtFOv>B`!Q%Lv1Y->;Zm>|$hAg%b;`@y2={b-Fr3* z#B$dV&w>hc{s8#%Gm~>aQ`@wrsx`d?FM3n}%PT&*s(bB>dps~Ak3T-T*h;tt5@V`6 z^eyO{eV(f=X5n>!9UVdaJ`cc7d5o?dfprk4Y~iCll^L2DAFZ9)y&qpBg|e&sypv$z z1Uu+ou!H`o>>wxXASZLDdzTG!*tz8HMa8qD6q}@DGPg{{rVJg;voz2=@6oP2mr9$Z z1a*H5p=IIzN!dT>e*A8*N^LFF6LFp;DuCS?r)X)@-Lz%XfB<$!A)3R5(;Nxnye?Ds zSw=g}vz(=Qmj0dXHFlqu43#tRo}%TveFNouKhYN4chMa8J#c5Bwr;yl@DacHz6yc$ zJ~|ScIx_2E_4~f?O#IRjR@Oo3YpvS8+4!w%TKznbSctz!Uf$Q*0XMs(t?Qe4!xAyA z1}ua8$dlHJJ|Su3CilG*Ml;Wzj`V^yo#VbIIY6fef%-+I(oy|sX>UJTIzy%K z-g{$Cb6`^q6doiS_Bw6Bf0(x5zh?*vv;c;>%IumV)&4pH+EOCZZ-Y0+_?8#xGo~G+ z<=jKm`KTR|Vf7E0*_QTzkJ~+DzRYR0!@VH)X7!!1vN1d>{1on4p^XJQgGVbTW<2oL zu)kL|Z}p9U_~#GwrKefO&zxmQGqE9`k(Ik($ms{p4Z9e3g|=jA8}iDqIrtSX3***e zpF4P1#se2Qewgn;KSTV1@Uf09;F*u(3Sj@5&gcP-5MR&p6JL2`&f_mUIkW2YR?s~s z(B72u%oR*++e4f6r$f%ou;ykDT(D<>{$j|L(Cgv11WwDqU9wWLZb3+f#D(~}^sjW} zQl!eSR?=^-ull`N%@3h781-{t24fsUGBeK)nYk!^m@mjXm-QQQ*J z=yVOq2+iQQA-?zvdgv?EHvs10@i|Yv@K>0JZOt{l(J&86Kg#&fP0#~dle47MaF~lw zmo1003BTS~nG020w`8cR_++vF0f?2OhaU8Qm=g<6=fJ1(=-$A$Qv+{R zLalu>L8mbDV>VjniRYzXcKZI6|5Z8#geY+J~$MG?_D zlBdio&kg1*U~jMNLR1~FwWhwPM>t{%2kgNUwA$FBNVo;kn5zd#pyLD$lj7;fRcwG4 z>ECwwVqB*1QANgKpxKH84cEv*#WK8cW|#kH!t-oUwTZ6H0sYmVdO@Hbl?wkv^Q^#> z-Cxx_D__pL6wNb*FZcgV^Sr|w@GvbL@oMA*uqaVHO$%jlNOmTmFmL$GUR(nBwI;kB z@oTMej(?_ujw176UZv=umEX3N0nar7KU~vKKi6#E1)R|09(wW?#%A?QpRd8$^I^53 zEjucOh65UT)o3*BBwYb#$a+ikWY92vsPK{VP5U9T$GKg+J)sB60o{@kYjGcs2I`(& zYTq{)+3OR~i84_;KWUGyQR`j$?9#rC5*N)ky*0nhI1KC=)Yl~y8T`z~`N?l=c!Pbj zadz^H8(z%pq?VQzm3q}Plcy4oSISuG7E=teUJ0`V;wRaj?T$e}<5-|@h8kqB=k6kUIsiegK^xAWzMeUWYIir5uIm`QMJTddjfAlgCHUVaC zF@B>(ow<1b@D#FUoVsS{QQV6g8CbRKBVDT&HQ5+-Kg^vm?mgK5V_-~+LF2Ryk;Y z(Uw`Yv}XKq0_|`W+NfmUTVn(DoL_d;Gyj({st3?2fKh?;0PFzqBSVtTpi7 zP_xehkXvD2Wy6caX-nv?@-***H@KU$LTelvdIsNIrH-Kb8+8OK7T89C-^js%RcqZd zyb}*x3C5_0VK>72vCdh$A24AtyY@2`pT1JYq^`a%4)^4u0%J=1v};UgL{Ez`3T9s! z6|@H{(DO6l*dVm1U(Xc$8j*PxE3%p_HS8Ros-8wJSTnWOgD$KqWJ|zOHc&3@<3Ks{ zI$93;P*(VU=GZ5KWI>l!3VHP%u|*Zmn2RH>#Dd%#W~uUl%&XE!--nGe2U^Kn9C(Y5 z2wk*QCeIT6gQAVY;u*Op938lL1n#%1t{12^qE?u8Q|!+Euo89lU#79{=IquSPLq|y zRsDPG@ohiYvlveE{BEuN`5bLYiZN<6%6qcr$jhsn&p(pxo{4TUU4WX}g{T@5Pp7_MNfJS~}|_$CgtM$#=LbqBb9u^w!*-5x70? zb}yvNgtW5rUPu{v)L+P`z=CGggY4u6`a*US|Ph1 zia#k>!L~1M5cp?^WAx{g`QiL)r2xHNo@rTcq3hziG4vpK3}Uo?@SS(&_jTN!co(Of zH(J=QT2b}wYzWXZiOliyjG=R zX%aazf$LK+%zXYKILXK@@?=bXIsK5g*32aG;kU4E(W5+i;~+M z2M-PdI* zz&ZjvFaoTpS}n0Hf&1<^yTfX0BpfRB6@H)-R^Ly?4}nA74jd}H4DOmsdNOwJ(bmRT z{?KP3yjm`baTHqMUfriyMhvTRaD_e33zC+Rz{4a>wfzN~IW6!jfE~a=sMrCadb_P2 z?NPqk+%ZrhF=eOZAIMid4{bQ}nR@5*)$hh!IKmN|S5;VO84>7z2-qhT2A!D#BLv@) z%FLmsxk~wpzXQ)LWks&kEC!nx{BjjL7-n;_x@Ks<@k8)fr_94p=J)eJUv6@5QL7n{ zWDP`DFR9yz2*@V0LcyjI2Fb z#<5#~4(@p@3dV(IYAFa<8cHtI-3vSLwHlNd5}O`SZJDT*fC|vyC!^>~Iu) zM%I#b?U~9=0^XFaxPb35L7arZw=ERjFCOOL^)c8o&|UJclNRCuGBB%_%t()NpT1Mb zZU(;s@Ky^>8IQCV;ZqGPKFERH1Fh-$xT_B6E0j^dJ<%)5E^DXXrswImIp7CiRymZD z^B|p+&v(B_yr&BMB}8d{#+A-`N;&sTwcPC6%lR&Kjh;j!O85h=`#9RhaP;6%AW~;z;twz^d1J7POPm0xNd$R9^TXc zIiB0z{onCidX&y+AnF7+g?>jh|0g_0mtyh=Jd>qu-7wuXYDXoWSr1rVAHed4PTJVe zNgD~4OBIARrp5r4k5I6@%ez|LYyWpFcPFX%5%3!^Ud4|e0L#gW^U}2LSdNxK{qJ(O2}_I)>n^oCoOyyYj6M-Hy9adpqkX<*W&6xv{sGbA3*D3gBRro$UL*N)i?r z5NGLkR**Q5x@mgGcZ-x4CY0aknl14A3wwe@Zw{2K`?|`J#C6eq^fey;$GsrMci#)- zB&KxQ_fi*rO}RDoI(_w4Q@E{YD`*3RB8~x{>!(BX%TuR<^$|0HLRYts^V+xfK$`7~ z5m^C<9PJ_}k#GKB=?J-FQ>X=c@%>8jvKW6Eq^GB2wH{8#he3Owly<#ByhC@dVSb6w zISI~O+E0{siUapg({!D6zTG6AGVwuAVk`sAQd-KG+Z_tqoGFej9nh#dX!{9$W*(kS zI7H=SM-WAvoGzvTWXRD~ z{lN1f@g{iS;-Paic2$jITTv`%xX2uL8=ps-gzt*iXhv(1eUw9)UBFspl<05x+~hFu zIF=+z+re+WGgLSd#H8)bPMup>Qiu0y!|5!i{YqvT&IYBHc{&c}`cxH8ft3MIAM6F32o&my3^G8P8aS(QEub5zVRA|fvu3DhXYOrPRdm- z;Rw7xxx*RjJ~Z`o%(*G_j8&+z@BTlfKCh(Cub9uj(K3t1`w4=zq^oDSK}TmUrQcrF zCfv6)K!r?UDiyk@@J*?Kba(IW=}{Jf8x^V@o7qZRv;IbK0`~uP^1qPpZzs3`oT8bW zjOM&9UE=RC!&P=WX1IRpjv3vl0V+-60{hx5-pM1k+?XCj!HpXQ$L6(Bk>AoUqd1}yvsRT!Tif%E7+i#2m z4bDi=ii};2A_*)Ucg8sEJ#=SnAv=?3`V~s}HEAK^9Sq)6y4rv^>`EKnW-=F~oj^2+ z+x3o-%FGyt(9-_zsC?*qN&Rl7-?rI`+(UVY6qW0}D?m-%yTP*&uHnPy3fCe~&%^T3 zba)Y63oq2J@$yr(n&m%7=-P^oElFtRCM29T9S%R=uX3vcq!b5j$*czsLkfL?_$k?1 z7JkyRpf8DrJ)o>nE?8T1?UsTpJ) zGoEA5krbJC{{&v^iOsvRFQN>8q*gHwu-ssT?7L7*v&pNUDL*+Kd4imvb=tz~U+@IO zFJF~Dwoo$$q(?;(YTY8h`=j+1N-=z4ru`mnwfUvHg!JPYV#N^RH;#-4uY$yntsZ=? z{&82s?sSv8F>f@5()(lA&6ZD%zQvuOV{tt}$0h~7ACI;u@1N-U1pKs}C|735bOLTb z6(NBN@}ixCmT8XMIvviEh%$q zJ!ViO`tB{+vqsJ1ZwZ{x5{x4?%@+@@Q`VcPa+i*Y3U8mqmfjF>b12pD}! zg*38j*V**o<9>DxA5*B$l*0`OzgebTZ^6GgwKV=EvtN?{5@uXIw57BUtwKw`$-Lth z>@Q_bP;X7V_BZalCf@OzqJ;;W;K05jy7z64^_HeH-ka-FXq(Tr&i#zBsCC0hEqgq` zM%xm)!=^yR8PF$Q1-6^c|7Y0D+<%5`s{)(zjns#HdjXCi_rmm1EVx5rqX= z9EnPBuwVv6KnJU6jJ2j?|J>Z-{dYAJDRTD|tr^@dcQQDrZT=^o%>`Xfdu$YGofqfA3gnmKez0FqhK-fn{gya>EILJ z2%gUZ7*6h)lp7{O4>*&D&;{W8K2+#KzG(-s@f7$g>fX!H6Rk{uBZzALvo~F+AMk{Q z#*y2v7{}IMfpxkrbJ|vVyXlJ4jCNed+TaL)?WTQ{_6EGrh`@GjUx@8WmPjok$4& zx`&a0x0b;ddu&8$jL_pEc&)KA(0i*U!OxRPY zUH9%Td^p~9XpJ%F5oV+98F+m>hbajnwQeu%8%#>SzaQGZYLC<2(2UjI6uI~$jGbEh zSjSaS8cV#?DZD58uwoTyp{aMsO;VneYx?Cq=wExaXDV>ylwyAbGjxsAom5M5wiYXK zk(4~&2Q3oGeYO_rUxS{n!Yae;bggo~%A85uWMdp?m%!ufqO`XS#1i?>->6BG=^Q_K zjm&Y=#kikIpE;I*wP0N(oNL$Yqa9>)S0`0dSXJ7$*-oHJRlK!MW7rAtRl5(mHiv4;nqNVtKWH{!HNVc z7h((sTHZ=M2W^DkL6hEh^>5%9gI{Ryk`ld?5>D_f;)Jt-3?Z|t$@R?kTfRtiq= zQ$%um)3ScHTiMQM)(~zDF8KBg0oB-3aQMcw1GxXSzGgp1K{m&RX3d`ku-_6 z1WG7t7gb8yI9A(zZl?NB-zo=KZZhD*5wKxIA+~zif|*mCfp+VPr>ru5JcwZ|0d94J z8V`D~6icH}E3KQCd@I>^Xqj(n1JsoET6YR+DkpmP_jV|Bt7C0pOyLf|+aP!ewT#8{ zz2U=m7jcvq*gFj@@ckUhNd;3PBu6d@ep*w(8IZ84;}moe&#&K9+d;k?kQWuwo)UoGhWTeW%998CXh&;ya!gZj@Mt2bOkkR3_{TQAR6e$5@rdH2)TY;u zjI$pDUbier0}|LYe*6==g>(aYqJ;QeA%88(UrG7PF(id!;jg8&gOsaHPfJ^!m!2kr z&zw)eH)~i)B6!j1&nJlBK>_fFL<`TN#q%(KOYfF zzeUc=W-cfGf{@lOxq+T--ym{Z%&>R0wP~S`u9i&Si{PV0euiU(G#x9$X)5HkcFZd& zoa~WynxXtw<{(bpj+v~wvVV7~>rk&9K&fCiG5V-n!xL54#G3sN5*F9t$w5cAa1i?+P)(sT@ zae^V{N1^@)fv=25AaCa(iK!gJMI|L0OO;01iYU+F33{Ip`;h%@` zZINL*|7E;Hj|g5jX{w`Sg9+|f9T&DaxzuI5!L7$A$00b?uOG<6*u+%j2|y*9E>+xB z#Eab5W}pL5Hla+0acwQ@=`Bv~o9wCeqa7v0Ta>7~Xnu5Q7&kBCQbhK5a0+h3Pj5z2 z$PJf}Xh4f1NlMeC&F$ccodudxHWXqHXx*Z86b+qlXL{3buL7sEqi^VLDM%CV01jvw zywQpKplM-sp8@+R4Fs4z@Mv4mmI-z%ylw*DM>WonJz+f1L7-aM*H+P1dR2#))&Uh9 zyXj*bq9+hU3?UHg{69bt@^PQg-JBkzAup`eVKV-%l`%hH969J1Ne|eJ`G(r#9EV^H z!A`e(N!L*0*wRLl4w_bqU-!|H+UDC!qWj?NzW{AE!`-k_(lrQ9^b4SY`(UbM9J_r3 zZngl|Xj1Co z6<@Dq?3PC%UO?l<>4O&&>hFQo75Mt5gtD@-YVXSAyOTX}*U&>t$xCgIZkhSnrOVZI z#d9ub;q^IK)&tDE)*X|-CdrX3gWq=dKRnyZkpPjuA6n;0yo$urSJ1LO%eh67%lUa7 zSfif--22w(iB$yv-6q`OMx!c)T7nr(f4^{(nK)Hab6{llkx=5&4?wSmz{z&eEa*~> zjVmuJe`v2`e8_lD&35EgaL%Ls+I+B>to5bH*01s0by{4kXQdP}#{yv2-u#fH@bR*@ zwWE5ir=|f3SHsbR>pXEasG&IY^DvI=h#MU^S3BJ}GW-MKg^4Itf;roS+YHRmN;xh9 zwS_mmzV0T03{t_KNkjgBr{Q6loW2TV^@j*#roF}E!^eBJH=t@2vSr;No4pQZO(OgB zFo6s9X|h&<%e~gK-Kp%=_t$x0<4rZ?B!OqC!F z4`5~&;d#d`LSziU<1>5sCKOTr;GU52Ymzy$%w2kKa?N0`YT*F_nPE-$>?EQ83R zo35V)y66VFh}(|*h0;WUPXUVfZW;H#Q^V<7P+K=zh?BPT!jEkZ!6;Zus8I}@7g{%* zz4IffP-V+v zLL1c-zh##OavrUzSd1Uv%mann0CZ~uPTRth5eBHF?I`S}51@@hxC!2!N`$sUq=b>d zoB_0Q|3t+}V%`=Mn(V0oPlxn`ff(f9l*}{uzX7YG3-H3DGSK!L5dY4A+6<8Xt6L8* zvn6052Bk@kvqX!belNHIGo=4ARa~!_0S_DoA{49b0upaj#E*QqN z95!3&@$=LOmZM6N_p2H@Z5^u^?!tVUTXE1bEGZl6!>IPMuNVf zIsQ{L$9kq!&B-`SbG&D0j^*b-ow|cG$9;q5xNm{}Mx(a(70vViO7r}!@IFk(D5eS2Bo9-3}ibbETnZngZv+tYoY!Og5Pznm|CtFBK0 z+v|;E!$uoN=8QJREgx+h7Cpu|cK9gc$fQxmxF<##hh>g3j-8hX`H7GZ5u(>88pnPV zZ_};GY%0<5RfPrCCZ5xeC|owHsW-15SJpJ^YH*W(bI9n$2}Snf5+j!eYXs?9$L`W6 zcFSo7@cb*MnUud4<*%gtVA$q&6OWbxQG~P{x6T zEH0=9*=a8LftAxNDArkP=-nHlo?N84b4zMDhFL8cLekk=+T&V|%sUGONSCwco$Ucuc2NKO;RiaT+5WI5%KKBRX1Dg)P4J@JT z-Xn_Cvdr8mwH&5c5%rEx)saXbl{)4SCUBiJ>Z{?-n_W3!ii4!+h1fTqwu{7 zM_TumapaRXhFXN4^%uU)#V=NA1^qIXXn*Yq{#)*e#A~Ch<6Ph7M!SCOgMa%g3-ta5 zUc|jP_gIc4nDc1gN19VwlxsLvA{=!h5qyb0Xczfw>~f&-E9DQRj_>yXHuapp0vdyHe%Wm@hR{%t*d1REP+<`EV=|d!VRc%7-No! zDIoZaf8k!nI=wb$q6{O2^Y)iL`P%WNNp3}25U*}0U0=(GwDD?B?3YXX=H{sqN zzbYHxyyUgNsB)7YG;}v`Q!tYb?ZYYd=Et*x^&So-$@~|vV;qMQ%1AFe%cTFvTf@th zH*4YDG2BTjd~u|jOTb18yZ(RLMNC6EVkNW%gm z#{tiHNH+A)2><5B%g!De8UE)c;_r(Y=HY1-VqS3)o|DQXIXbr}^=?caJz&_2aj%dIsn!!;~;h= zO394B(vrW&q^Q4w_MGTie+gK^)}`en+aDt9=D1*t+f;8Cwao+z37m4T`g$3q92S7T z8#*4eW78s*!uxIDEP<2t;t+mhaWY685pBm}3UJf==p}el{sk5yi6lYz>t+^W?QDMI@Ttg?4cUP#j2-MQmyAVvJc6IY9VEba^3aa%+ff1@22X)^#14zGVK znMyMCxPxOxRZ>nF*79`i&78*+8K<5|5+LK$LfKx)%QbWZ_(^@~T9`Qm(LkP45D2B;qNhKvWP@HUA8 zpaQ87B#Ljq-^q*BAX9+s1yE^^E3*brX_Z-{95=ahhFMFfMcyUKtVP1Cb>JmDNI2TV zg}sv{+!n0BL^wIl()334&C~)&ZMutr_;GK0lgJvI_Ijj4z#Dq<>QHI2SlcOY!P+*I z%!}}o8G50H%BZmO2qabc#mTop@_JtaNqjBHsM}HBJJh(?3FXj?|m!nwht1 zZUPM4W20oLw`TG`jOa7)M`)roeAN4q+sLNCy(K# zDwGbVKD6|D^PWz6V#=HZe`oH5&o`JZ(ncZL!9pOd;uN7@EO=InmP4~K#k z?<~f+@(sd$j{)v`3~=A0f%_f}-1jKpzDEJ~JrcO@k-&W?0{5K=+;;+S-wD8d#{)ky zHrGaamU=WDE54CkOF1Gh$e;n8u&;y0c5F>9CovxLxD4R^Ldls7@Bc{(=TD(I{=Wgg zsN`fkKy$pQG{^h5KplwUr_^z$(;W8;3cpC(8%p#1kI_7wmJn*7DFynQn)pAp( zk~WpPK57@2XKLswXKqo)^BqYGjMCSvj^|sF3KG#UvR1Yxnrix{d)cT)+LL!;7xX@# zS|4+?ODMC@`atas^|oNr6$=deJt#U)Pg%1 zenH#t?hUk2r=vOG2Ucm_*5j8> zoNqkS;y-)xr8d+De3@x<88J%=tl%3WBcZT#7MA!K;AQ`pmKpfP%`-<7B&Fi)!Osgv zj%e_`e3k~-O1Xh&iT`zv?n86V>TTs^oX1&%K=-O4{vkb}q1(N(qI?DKaW+7z)R}q` zQkSTy-p>fz2%mhMQ$_PC2YE~i%U1}F&OWzzk)yK zGIl$~d#fR)$Y*f3{{2<_kBY}-xS2GLY`#KDc!XN;Gv$FixRqY+e;nx0&0SI&)Zgut zrPlF@WrGpid^nPMh=1{u2clyLM_V;poU!F#!^GiNYM=3d$8q4Q?!CTh+P9x#D$nO@{>FZdSytPe@T>Hg!h0? zUQTzyi_FVYopP`NiAP5>o=}mIi!XNcPn!TVJM_N(5L+0emdp5^YB<@O6sqj8-(AiU^A_&b=+(*{wl=Fyow5~tMj>ea%vh{UkUqioDiQk z4$lO<(%Htzsqv`LrNmCraiMtLRhD>xhuSYFwHI7PwcrOH>JO4rvr%*g{?m&cVyl=my~$xF(j0>zw)McI1Lc#Q zO}`Cn6RQU@$6OUlLEoFiO#t8h^Gy9lFFlbj=B;BrZ^kX64+8aly~e+u4> ze9btQ+7n<-;vAPM%HZ#>(;?QP`PrtMKeuyvSWPd$?I< z;(H%-jweCO`CpC;t@q+{9a=J8Sc}WX4>^Wt|D0%xD`)&w&>2TCc(n%AEW>9)0ULfW zi+Q0*;5VNA#^T{VW5HhJGCl(s&e__?_X#Jy-oP4%@o1; zH>SL~_03)jFT6Nq&el1-=AK<-0GkFV%jjE-eXlYnKU2@i36rG*>N%NFNzWYjgg}aU zvk@#ufM35VgGCTmq}FgVD$W4sn!!|J%4;xp1Dk| zx0L3Y0}a-EJk8evbGbu<6%i;-$KT(RShJQ4NmNjl_0-wB0E& z!cm~n#4oYdXUtSCotRw;1+>+1)XhhRIvH6$s$qXE zA6K5U+{4zwKGid0fD7=*%}6e|+#z1?!+4H2g5DfBdx$f?`sic?kligHtyDzL;_4n)~*3tj-Tc zO*c;6B>Q1`RpJDQ_@UDc!Z-bF=JWl7b+duCGPu>k6k7Wiar1=3Pr(TykW-^p8i$+x zV1ovy$>BtDf)IO`U|lHmuSqP2I3mHi7nIspEett9p#C7?@ayCRISMC;R_7v8Ic{>I z!9~L1a)_AnQ3r!N>i;3)PxQlr8K($|fv%$fZP|A@P2cm^Ys4 zZLIJ^Jo5BC&JaKQIjNIeyL8W+_e2UObmQf3IZfN&NDZM7PMLmNCT&~X_N2JD416vB z*7I9w%<;(@k8UUX{}uNw;89d}-)ClaW;ZvIFu5UMp=(h1N(w9lL2Eb2Za{>pHBoG( zgdr#>2uJ`g(IlJMWCID{un7p*6$pmd@+wOb#iD>DT&z^l1f|siO9F_{5R=V?B>Vl& z%r3d8y}aN1d~cp7yR&D`{rt~4|NH;Ff)2A79E|7JaBj|EwjFire@~>ftvqeTU3EJr zo|(vYMS*^4n&7`<(&Mx{=IkbS$rcns7$1 zH_KCY|H^&(JmXofzl7+%I=8-!Gqu4#XAa(M7h$hS9frZe_uvYPxbzOJWf6Oi~NMe+Ag+mI8O-0*UgWrx%pB~ds7O^ z)6DuyrE2f$yR>)dcn8gMwcNpn)ptVaCI9YMQ^_MgwEO3s%`!+GBInLsZI-+W>&`VK zNzZR0N>m&$&rN1!qX??^6;^8F7?WYOS$&_m38yvRN1IcdKlW*=)d>x|0csEQvOW>o zw1`AGOr<{t!&6mg_B4~DmSjGvu5ll0w??#XE4;^PjMH-l-_JZ@R=}xHShTy$WN0)yrWqq*{kgq2A}$*5jAc+B z6oH;I#>ECo+^A&>i=@?GKwm1%6?&y`9nCZ3yUiz|(Hi##tB!!LZ#DSfLCIr`((A@w ziL_3}x^DOD^l3TZmrbSgEZ_D(;xIoCK>k*H$6xF6!*-UR2Y`4c8hzNP@WTS|dk51? zXM7KIdbPcrl{M({+7x{Dkt=jT)|_JIIB)4~(IfH>va6ToU95>(5q$V!V9wWP zX7DD#m;c%Zdxout(p)z3MQ38K{G<3|5K0>+ZW6uouC) zt8mb3EwY+5A7xo_$lZpS0lyzJ1RIdp397xoOBA-SlI^tb>RPL?WuZ0&)OG+6W`u4% za&&<@_pX? zXVyNo{)vsWO+XbO3)=kXZFAq&OPBatZ&6#1rgLj?($>`;VJ@{^RxhHxPp6ZOavj0CeoouLb6{Od)BPo}uGqio zTJv-a{>43eOZUWwX{W_hnle3QrbD*>~$X zODGux9rN6_sKt?14l-5S1YKKB@z`_H##f=!9#n>Rt*L4)vsJ5aBl!d64j{kD{%Vq2 z-U$6eU3*Tkn|GO+%cA8La&4_g$A1gYA{MbFnv~BCp5L&-`rNMPgy$O;S)bbVl<@TV z7pG)y&zz3atiP_kZXpLrH3v`0@O(>#)^Jr0hOUbuIP0hectSy?%$C5f9`3d6OW75@ z{pSsqdE)OQv~+A$LDU;^-#mH!Z-O(8B+_Q(8F<_!{PdP@bm_K+shrqqB|-miCz=`9 znp1CILBYXvU%;;D?M&AmM|pu18O)Ab)BC<{`7e6kmdmN~SM{Gi`j|a`>Dm?i^c~^1 zwE~`S7wiLt-3%L!o!nN=Cdc_{`Qx(sLq3XLy66k}@nh-4oNg2$LMf1>dzc|?DgqN+)u zg@<(;KZLg`F;>oG0gO+GCQ>xM2QT0vT|$T`fCnj;n?=4_Eor=SemksZ?tU0&&XEq> zf*qnAk&F3#9YYT*h~^1=(4*FCmHr&UmNZ~}3+%sRoT?!#(xNmfA9^nbC6Zfz3`n$qD~Jtdf$BnRzQ*YN;L=nXS~egLY0~HXlk` zHOOVsk4X}v^_=(^)j-!>2V6iWLihGAe{_5EcYuxSlMdmt36OFfyrt{tKfQNxmmKkO zF}gPC;S)N%r?yJ1&`!9%A^D`g^x5P;y8J!A&jIc2rgQcQEdz(SAwniDVxlf%<=#aqLYd+m8>MeqnT45`q zVM1#lxtj&a-7HA%WHx)o`xkLPqAa`!1bPGR3ya~B( z6>=R{Mf;gQi55fjB*A+PIk9HfXv6c40BA*@+Lqz6UhT zZ&&NbU60bOvjP;sf@@1>t=O|-z;o9Y&RVo*(SWDEc_9*~U8H4pMUZ8BMSw!lW=Z%} zAG>RgQcN~BkY_#O{FU3sfw!Sie6iYl^22xv#ZaI-1rEWHjxeiHcccS0XRu|^;gr`= zd`ZQL+mFG1jYXuLf!upRgxep)D13{rh%d|*9noZX2zbMsJGg>9r*q8U@8{s(bkGS~ zVlLHh!u`F*w{b~Mu{4;E$bS;^*umB0GPa6bU;bR$p7W4YEHeZ7hn%75n~!H(xXN5$ z?r0wvkTi596Ynyl$^KM|T_QDPCCcl3(k*sIbXtg7@(^PkgP#%+oxtalyBXE-kr`75Bbl zvLmrz+?sc*ZSyUh*cnBtf+LBf3nfbMTkNc@O3PHT`w%!Vth9W;F55yQjhTcQ%o#hE zClK*=eJADM%EEr9XH!jg!q(8VZI>NoQ)i27q2Cbv2}{dgzRt`DP1}5RbXoZtRpP9k zfaVe9@*Fu~s||i-RUQm$yDWN2M`)`a|d{X%9#zmzTIg~redb`CuM_paR>KKAm60(b7(Bw5!L_0=&hF^r`(%mI#({$+d_ zZo^I0M5!GDJ0Rt6L&zXkgPeVTpkD50Jg4MB+b3$<5n6JNd>-W%f64nJ5n31SS|}{~ zUN5uy_u{NT$9TQPmRQJWqonv4Z~3^(6tq66Yc{y2{AMDBP2hT3k#!lhrizWs><{{v z`t&+uF_z8baK5w~*B)S?35@O`k_J2VkTQ<`k?=`{Sh4_jJEBKb1eCv$rqgECW1lEOcLNAmbc+9QA)m`b!*e z@R3ZmW%yBW$p(l95`Ho_s7%R=B86)+W8J{8-p?I+RLVah*z$D5^SQoTX>ARcE`ncp zNe>R~RC4YECGR$J9G~OK^{SJ3QqEBwXV(*Hsz5f^PjHDV5%pY81{5BWy5kv>{awNd zfMtE-4Qbj@!dRs^LYOko)_C76yObM565s*q-IKa>br&psSKS4O^oU-b{J~uywL4iG z;Eb{I$?k%EW+~~k?%kSHd-i>=yG8*^4alg5dCTR8WX~06XK03D+1AA;F^@mUq0Yno zRZ@uLa~A; z)D?v87ixG2r-q+Lz|(V{FLQ@3P0D;6yI$T(q~KDfr;N6SUtXP;~Wj{?nP&i0;FjvzS6E*wif)yHSElzoPNn_?f$B zO#IuQLkEU(wZSB;T8b^@x!O_07z{k%4$3)1H1SmxI_NPj%HS2utynXGyza8?E5OZ( zI6&X-6l}k6fJaGm6n1mAC7px(uhVmBYxlc|(^f!mn=*m^jQqIJMfK95p>w-flS16o z`bubS+gmKg@|_j)BnD2pEJJzj5c>X^$qq_S=9DNCZUIkz zW2aFEZX$d)fD_pXZ14u%t$th&XLRlj&YIh~yPCI*YyfWrK1C#FDa%{mOh2-0FKVkKdmWyRQ8%Qan<4!>$Q#MNHpa38 zpT;QcFcJR)@gGTd8X0Dc-q+@^IJQyh3RG2SMV#CICL^5_Zg(R#wG?Ium7bdx#(~3x zao&(DyFxeb6#2%VOE1MU_sLUW_ZHQv$??v{*?>(ymd~G~X;an&s95togQ_3Pr|Ur9 z4=snaMqA)^%X*NrJlt-xOl|)uKeG^=iZ;&jd7I60q>Zy)XtP!4{csC#KRw#{LZ!={JyrH);&Xt8&k@p zfzt*#4@;d^#>BtKEOK&KVRdxVc9GKUpsm0?L@eK!nnE#z7)}+;D*%1b%H1sk4+u$G zM73*LN673}X$a^P3pfe4q%*eoscj=<&~;w6IP&93bB)Mg^4yi0;+L{^I_L5%4x7YPe7$!|iM`X+g3ZEArE!N8w)slrRXl4vnMmfi z$P)ujJbpz!>0kCb|w|EdFD39YI#klG|Yn+Sj4L&&`gYBOOv)Eo-~&NQcS^eU+}NHeYmA z1HO{aKR4z1?a#9>P+xX7@J%Tc=XR7kXW=eP`|{ied+anWQ)trcqM(NLEAy8RS)P-} zsM1-)&Ze_7Lf0*MONmi{9L~BBzHll?FK;;leTQtr?9=A}%ueJXd(pT2 zLv-q)L-YojNbTMP*uBB$2$h?1Ccboku}S|0tJrdgc8i+iy~L2_w!6v3d6Np=`f5hB zwD>X$VGEvD!zeXgNJUZ#O&RHgsXxSf+TZDv)>Pxx+N0XF_7AGF)@GRV0tru-_i zxK<`5r*TW?-)`M7MdV1hIH2){GQb?}_!a1h&cgeZAW)>iqywCd0b)pF``a`4nIm0F zE;ygTQc5#WxrR-e#9VUm*^#D ztEkwandz&EFy++}POm5OOwa6V9fQiHrVAXcZ>!`MwgQ4;Cj!bQzVY%`MeRk|4d4`= zzu=QPk3f$WZQ2DQ!Twv;c?K1CpL2P>J>os?q7<{#bTo8Ni7gAXZ=Q*hlwb4GoWZ)8 zDm5)N9}V`uE0Tz`?K55x8r!5#Vua~sikEat4l9@DQtU*pcvX6tlg>Bjwv{RNE{3K^ z7gyr@s&CRG(uM{>`ui|mvEPPysL=(+;(7SmwcV}*VT!jaT>8h~S?Q}`9Hq>q)}t(1 zrWCpLYgVz3hi+;Oyme|bfboA*I1}feHMBnB@^Hj&9PW~5M!Fm`b@fI=DYL^+!64e! zxqr&-xrx_~vMZ2Yp4;NKzhRcn)(%7~X7Se(K|65~pc7WFA`GH<93?g$@fu6{PE|T1 zBse{Bb=}|uFa|bli<@sHi6w`fHmr~GhQ3od8cTRRtZ?J1x^G&*QoXcw^<<*nN46MR z!^IK~thL%EFk$aVw zK{P$Ah3D0V8_p`k4EY!yxWEfhb_tzIO$_0MM9f5Gx1TP^g0*JLhv7wh!fQ&!fYA3~ zk>zfApA=MHU1a0Y7ZODSpk zsZ>KPv0$%bPr)ch{73t9nHj)d2UQsut2{%RzknIHX3rX_VZO-?eSPWM43p&9H{KNb zJZRMOGJF>dqY}8Y-!So#jvom5cG8(Ol9bMruYtBR54$SsDMZZ@5XrLve9PH|o>wco z<&ezOuGBN~@IM&G&xVERB;I)Ublx~7NWecdfbb8$cA!urj6-%4V^|Q0-kEKIR1G~E zUS{Geq1o*YNl(hQxP=Nb$}Tk*>r8SwBfa1pcB+{AW_U=GSzp=JDXrhdigGk@TQV4> z5>iFk>$_a&7Ctd&z|Q(mRklThE&XbSl#M#%b%MQoKl7}Mm*}pFJ01p zr_}0<(Z+R3jlAkftLT&>E3|ek(G0bmQQ#X3?E+F37n+0?@;GhTj+Uq0lfUo-COLbW zJcYM1WlXXxxN~BX677<0x!x@_;8aA*7TVSY+VTs|2ql^JBP!{Ar_|+)=+pAKQmti- z$!$rY904NcwfGjU(^_^5)o7VXRs_uKl)Y$K@&KIj={TfyAvgoR4;6MFl?E_Y#%PTj1H-$q*))JHV6JI`q$AKeb^ReNxy3 zSLh9j(~A=afL6yXDuy?<{rF8f>9=FcOhOl-k#ohBLa200O|+uFo!pZrwZul5VB1Wi z*eVy|>S+@~(u zJ2iFdf=?LNNnefTf4FS6+J~DnG^hr1fxGN`ZQ!)%J(JPEH}%Qn@dGr~ zZErNMKew^o&0i&(*BQr@GI8~xmxo*(Hu2q9)Sc^EgHKCxzn<$nT ztLlZt>nW}aOc+vnNSmQeiTBV@gYK64zCH-=DIN?xGfe|bg@0Z?gjT$f7SPI|6B6y< zH$caQN-_gA%M7hqtqt0UT5UY;3)&iL^XqDAwUwTrwLwa)>bX&_3@A61E54KJlC?qu zOqKf1UCLN%0vl`JyUZ9^J%1GI zn^H{AN9G$TqLPK>h}NTDOV3uaTt0Rjdf@p`?;BZWld&_wOG5M-L{!_^EL$FQd4$T& zJ^r3&eQi66nlClv*ixl#E;r025 zUl&P7y(U~ z#lJz(FtkrENEu&nK7O%Cw&{rr1Z~#+IUJbIwirNyJwS9%W}MhN~{#zl+tv19(uzo z^EPag{>~Fb>vIU4ttOT@=n16%Dfnl2bAl&SKf~kHcMW%GoNL|@z_K)GtS;Bq)-|C- zy@4!m*7zZW+^#`Qe7RKyOsc2lN)sFlz-$lSMEQlf8`tKOlNt0~jU+4sTo z3(A>8MZ>Tmz027yRn>P=Zff;iz_+UEgUJ>KWg z@O#9Zk*_JjusNP5>Y69Us42IMD&CSB1G!(sOwYFsO@oEH+YearzG-42ecup0^0jxZ zo@eSB#g+9wW<(Wklr8p#Y>z-w_->@^qA9`>PgvcxiK(>Ag0&-G+idlu*IldP|KS_G zt%~pRZISt(xF=MQPY+B|ebJ9-zOQlCw^?MAV{mOe5x@f-oH~IB!h`ru@qau0-_Z$bPi4_WsE@=I(Gy$cZ$&PS@sJ2yp+fs&40jA=~Q&k-7)Ao z>0M;A>Iu~u1z)Pu7<{C2NATyJ#*lqDT|d#sTX*0|dZJjT@E1BwpjH)u@~r_oPUtY{ zcZ64TEBsq}>T7}K7-`)-J-}U_t208jy@Q{`oL@R+#r75KbLSTh2TwJLNsWob=vloL!r4BO~%Rd?X5Z zn^ru)Bt$bq4vVmP;X|Yswy;W*7rfarg1(_QVjgJx7h?5ym85_NUE}MDQuH;x_v#>f zEQ&gOkKHqOOE+{v;)BS0&J@Nt>|GM+8j+7%Jfvs7rYzdNh<&PO*5pqhgJZ!bQ|Apa z+|}D69)3TwZl3*FqLy0yab^ll*YXYU#0 znET)liQ7%Yd}x=v0xzoul!0Hw6GdWl0&Dk2nRB&kzoAEG@I4bemy2)U8JPfAPzsVPQ_ z!YV^kQKH@U40c&?GJ3Q@NX_%e;oZ!yV)DH96M0hef?(Po>f?2T-ksabb--d?{5#Kv z9+u(%lX|!*m!*(!;BI?}Y1=Ys%7QzSP-kVx{BgMbdCc%%zV-~W_rkd^0m3M=I@z5VBt5<-S>R?^P{oH zv^6gMW3TmZ@~`I~dav@qMlC1*rkYc|Ife!3ncY2UXZLIQEB`{eS<;Nf5J*!gW+w^st3w!fj3HnPUfeBzVrH|v<4lMyn9;w zw934f^wZm#sSpbObE)+}iH9iqg)YEK)AVLe>Y&qMTwG zJmtFfi#7smqf^^E2S4dws{Y?7HTUEGrT91hbz9^_|5EY)Mk!ZK|5BEJqm=o>UZv=H z!KcIb!oQl0vmXT3J^`NJE!@V1(8ep+a3boN$$m^D_A@Fky7#tzzaP*v6G;#>QS!5s zfhqfTTi{XFzLFR9USDMPj_|r}SwGp%99LGhz>1)<8=Nn$7CV9%Omd4^I#8a{1$$24$%@ChUCio(N?+tv{n8^9?mMM0vq=sMZ82sOwi}R&|HW#IChpSHw|L(Z11ZGqIFaNmI zo5HoK@3`V|mS8s3nLfB&o8kKMp0uoG-ydtFI@aA+sYYkt(S8_eNbA$ve|POYH^;kk z12jeZ)bSsWINjBI#92@F9WlSHXLK$}8*%lPp0v61dN`t4hH?2yss(2sbRP5(x5w51 zdmCVXRr=1$D#92+`es+~NUOBEdVnId0{h%}12`JhbRoM)JveHL;YgRlUg(0EIpN$3 z7{>y!NLVH>7`(1BS>en=RYMEEWt}&Cl*2S3ogJMG85MVz&~8>@1@5>4-xHkjc`S3t zrnFvs*`2$B4M;-`prg-mlTX#V!x63SAy}ry>zOOYc z)d%uZEx5jQ?eO%xGo)$vgw~4jNZ?Hbw2X(`)Eo+=Mx{lhQ;Ttb8THhYo({ato;ElJ z__7}M-}F?&QhYl(T)c70mf}hx71dBqT1Fl5bk}qa zcO`&(T+^xK$3jDreuBPcrK>SPit`SVu*sGVPei9u7~rX+r95!i7EB{4Iq)B?vn@F0 z+Y=+6u4I*(Cg0v-`6T9gbg^B!@CfQyIyyUf(6-E&*rVu`KJPBck;=OHM^x(IkH41| zv=Eu~#H4ob%@JD$-n=&fscKzcbzH5|&Yk$50Dm40EcKvj-ML6hwG5%7wE9zrEey=Y zA*=LMo$#LEGK+01iJRl0k!>L5d3#hozcK3~k@b-8ezU6EozFuHLr7AV=lhhF)qvGs zlh+SPvmekY&O3?toy;k%`M&iMm28OJGWWWElSF;ExTB9UpB5V5a+BAQHrei}|Ezm# zS-Cyzd{~+E*aM_SUY}-s>qGjM_gwj`+bur|nte6&zCmdrVuCS?${HZg{if!oEG5u; zNDR#2Ul}M5CMnsJ4{pKJ4Fi-WjKuJOS^3WHlh(1somUM!g@bfa%=7wotXt6C6}#W= zx#a1#ZgLw^%}P_gkG6;rnHL_G9)BQIjKPSWwR7UCd|#+^mvGQ5zJy;wo-b~m+gZ)H zA9;d&RjB0Ie8xYyyVGLchq{Hwq%E6k%JYm_Re&VV)r;M3L!FsIid$$U(nF1`xJl-!Vk076(ZfST zgekF&#Tm+ex^9SPxZbnmbhqeTO_+utjBZd(VzDs`9wY?M)gD;jYXZ;!yFEf7M%o65 z0fz`&B5$u)I?w|!$qnWJ#u+GOsixk1j~9w{@#Ir{TGUTj{p10;Vja(ZT1b81i*-E_ zQ>gaBend>!&_7~|x0*PzuNPK2X-#|kMNGL~*f(Md^&@s}gDJX#h~UhnMk}e%{z&%v z+KZwKGdG-y4l4p5;NDZwd!0Q}zd*lxpNP_50;!pg@HY3#ddhix`BW@#l`fuU7q62p zTx7p2a-1-EONlfM+{;wyQFtdVW2}>0c&;ubqYF)mF5DCSXQy{7#+#hGQTEJ7M6s0< z=NttWM)`FLM=hnqM^iXcHS{o`m*HLwzPVk@QuM>J+)dStbd}z_aaq!3FAMz;;Z|b0 z_yyU+x-ZUyHuy!>RCSTPbyIuMVJEy%$nggi;q1%O7nQowGK^5sMxivb_((ccOpZZieeo?X;3`#A0ht$6VA9(Skwon1o z&`(+Yn5w-h(WfzOVVgG{7WdTJR3p zW9W*>iE&pnuzYgZI_fDgC(d0J!(}T&*TG{Hbgf!gJI}_t6Hl{UIp7$|E!V}^7~-y| zXO+4X`1YAY3a_Qcne1-XEgUl|c^7{<*)Hm_XHr{r@nv$38*?n;40tG3%4k)0N6(&7 z@>+i>XFmju)(n*X!mO5itQ9=OzA!I6-pIOJ(#fgVuL|wLyDpO#8o3!q)gAb@%fDMn zs&t;H%Fe#<4L)V3=lJP1*}CmDcP)5#_GHc!Q->SY&Dtr(Y8JiGSb00Zk?hV+oL<`@BRb@}7P#fB3Ui0_7q`Izs>%1#{aFQ`hVbS z(`NN=koL9t=C|wE75TeApL==6Z2O&c)r-e>olMJ(T=nNSN8dZ-%K5}wi0P-F|AsaF z-1z5+qx;_}6v!j1#kYT+UOFj|Z@fwS`>^GX->y5{a)-}%@R=sNk@#M&+4)i-N3#0; z`FzqF?#i=azkY0s>*w!GB_BNgi;rK~5y$q+cJpVToj|+UA3GoTaORYdK)*hyy?Wqe zcf()*I==FB&ewzQeVlgUx9ixzcmn-;_g4AJgYVqRKRYP#()H#|&QovQ_t$&k!&iRh z|0X1E<&D4HnQ^n>A9)D0ckk+b%Z@zuV({Pnf754Kr_Y-H@a$J=X9|C5%$nLi-9Mkd zBw1%CKKEhLy@CF{sx8Q%N2*#U-`MgD7j*8^n#iZFkMxz__ECuM%74j?PkQnz+M)vE z__O~{DV$m}b1We(KF8y$EfUkeUp{~O{R@{omA-uPu>0?yI&AEn31btW$+$e@*%i{T zmFdf$UHHtBVPg~S9Gfs^*d6KV^Cpdv=BJGvHg3$g@uSB~8a-zGNRng)@GM{WthACa zcjFQ6|CX;z9KUef(y_l=JZ|Zj-=)zfi9S6)FKw*)HBbAJw6ACJMM%Q(XXdA^NFxd9 zPyTMf^0dY2BwJ=nGOMTY=HSgJHNrL(zJ+pXm`VwSN8&61Ev10kcc^NCx@&4H- zpIxzhMcTX`=>G3N(fvaI2l}g6&uBYny?-Ok*xI-5{`)G(U*5kP$=PjM!L!@6avQ_{ zd3n)aUhrpIaX>4-;*VMaLMr#EAka=AaS$G84w#6me`QTtjt^C~2wDN7*SD-lQUmnaYH7(HoqyBU0(ORuw|Ni!?j{K}&`M|jrC{KpSOg`ofd literal 0 HcmV?d00001 diff --git a/source/contract/ipc_test/ipc_test_with_exec b/source/contract/ipc_test/ipc_test_with_exec new file mode 100755 index 0000000000000000000000000000000000000000..c0c7bea57630eda22d7135deda10d65ac66bd626 GIT binary patch literal 18608 zcmch93s_TEw(velPDl_G4G3D>38q+N6a#_qu2kGuBS=Kvx)GvEK+ z|9oFK+3UU6UTf{gIpGE4;uHx*A@P!+9}sS7A0aS(ABP8Qt z1aIKEF%98gN^VHJD+n2n#e5@|Kq&BOg9%2wqX5#zR5W}u&sYd zCiuT(5Pjl3UP9pOW(pPx`hM;$&cuBG?j=PiANOym;J2~-3k8697kh6iDq;(Z&3U=% z^lUb(SS`Xues!UF?YiQ0b(YDT&1NR5MY!l!@xCsCaL!u}@`~oIEy>GgbJu2@bLT}e zroy#(^9tFu=Az=l&GU*1nR({iOmXOKzsXKUUvo01tuBSoqff3%v(?#yIf518n*@a1X#V@F`>q zO3a09kvb=@kX7ffaNDdd$~Q5rx;Rg5&NUaCP1)uxtU4Kwd=egb;6kWRO5#e#x9+yn z190q@vGz{}HVn@(7lGWhxjAfZF*G4bh&(^sfNLzD9MF&41MUxS5L38$9DFap#^b|q z%r{og)qBum_;~c!03HROY}S;eF2at=DJd#eXRvC%d)SFldUeKTNGPC!dPtLgV&CIy ztp3jdHlE*b8c!XEej&ie8+R?han9WxmnFHTQYadxjBIvI1`OwhHGI~qA64g$BmW7I zgZq8AoY0X3;+-GK=l>ja5rlo@D8bG-?W(+oUv>g~-Z=ET0UiYKyT^HC znE#z_jE(C(Ab-4Zef^$#hoh2@B^*V=`ps<78k}q6#LpWb566SxAyUxB>F;lVZoGW{ z?LF*#OOX4&I*(?VieM(fHCCKPQMeKm!?m9O3-ucAcwQI_-+m9c72vp^BN@oor{Utn zJC`q9Km?aZ&^MDbhyRY%hl@7$^H_M^J>dHRj>rFh)qlBpxoe8o6|$zxB2yL=oKc=! z=S%#^Pc~o&?jO#BvG8z!Y2jlmEX>2cerG=6!#>BCxUOn95cq;5a^EA+F(#Nh&BdG5 zd8KS&R(9S-!iJulK!W>g^u{n3Gy139}E>@d!^0Qey?-MHv+2WGITsBi}%2l)2>*|f`*j#n- zI#yi*%hAH@&6pLIsH`bRooUWg=jIjP?S-tIVm@aM`wNqmi;9m*h}K3&MMp>LqGO_CqxI2o(ecpFjVsx=Oy)I4{uSx{RF$uBS*r?d(SY2#PY;3GPHZC?kHbJk|N9m*WI(>{jRErbYaoV`3xac@tTufYSoIWltEe0&-TnE%e*=E>SKwZj)O(Yw$=l5Z7pjeM_-p+x~#}Nqexsg0EU_lvGAxZY*Nicpfd_D#IEV!d_ z@Yw)vxetFO;4cCGQNnK+Enf|=x8TzQ`27UG^hvDWA>Az#Y``?1!Y3EbChkYm1vDK% zgY|)(>alWgUqZlbX>-WlZoIz41O7?C<2}Q8_+JA4alkhceER6VVE=6b{6~PlLGVi# zi+yp@d*q|~QwwyJb72nxchI9v9iii?u&mR7vqd75PGo7vlZE?q1L*z$bo|^i&iKI4 zqh`RXiJZH}caDHxOz?N~3Cmv$_*US5W*j`WGaK+zVNvig!Pio0Bc0hJukyhi!gBTi z-3g#eCUi?j`wrue0sd>iFSrN(3&7(=247Q?C*H;11^DS0Pkid3Mk&DZ1EmPXM8Te! z$hVBe#{k|2cs0S_;U^eU^o)Q%M&$3Jp1HH1)ruPBUSBfEU8)`V|otY z{{VQr?;9`X7X$tT;L`~{f0SGKam@z&Ex(=Pu~ac2MfSU_rcErd?(;biG91q#>Ha5rzDJzR|8Kr;P(SQQy7c!>dr2p z`5FTEUOqko_)CDt{uplzJ_URW;HTaL-wF7S?;}3|4)e|f{=IwfYXQG*{%{}f7(+Gi zECu{~fFDmk7Kv$!f#%44XfU0`I0sQFHSq08oDC5EOBx;*wWr4jbqCFfn-Ux=?t7y8vu`}2^ zGz8xcM0C-{h`w#@Zz&@C8$AleoPe4DtW#a2P!KtuX;}N#8dYGK(z>Pc)1RZH}z z9BH&ib9#F)90#pMA5N_StDN?Z!;$5UoSr)&z?s>b3*=ohJ7?WUy_(jpw;i=bIvO3p zMr=>mTStMP=sh{b->qBW@Qtut;A)^aT(P9TNvPb1E^xE#=LNd-hi7sJ^CiWtnaSpZ zW}|7Fh3J<)OHG#Fn0a+pd#WeG#<`;%hiw&E51y)A&z-Bt;Q4uuI2%Ey>q=V4!PN}8_Ay-MWZ)l3E%kArQcMT1^taJxtMt4T^f$zJ* zQDDFElUYT(%u}B(&ulF=fn>@^d}COg%(k-RyX7gdpAj~h*&0nFX5TYt zreG!NvqsC1RA)mv+6m{dG~#45`>GCX8j9 z*xqIl`<2?4*0rp2#f?>0SGT{nNK(*g-tkeN?q?K007b75(+i+*6I) zBFb0WR&g!%W%di){`47bTLVLVPRX|RITc4ytMe+<^TPY6Knt4ie(<#m!VAFdZN=LvFu zA~nDi$VQe&bIn|$UBFFDnyjxlS{~tvY!AK&`5~tZwsSFvGDerzsQFBMF{(g5F!RS* z-KpQD-CTBUg?H8EZ~9yNI=ZfR{^Q0jlk^0KqF-S$&Zk8_d8#6fH&|1brE+b*gUp3W}z64=kq` z^ZK9Z==Dju<;$tE#UNu{6WVEvuycNNS=&wbpmWC@#QgWGOH4*x({Clr6go{;_gv^i z+NJz0V%p3&PD$6QzSaFL9>z8y)md?S zh_NcBtLOk3gC;Cya!Quy{Ip34Iu!>w=b3I{6!j$+pjM?R+4K>3r>{ zx>;|Bx-zpunZ0{y7tJAtIWdvRjEU08E0JzRJ*8W*f^w~BrkGdc)AwXr&&ZLh<;;`J z%kmj}()VVBcmmt^W!P~(KA>2xWn4Cy~3wBF4%IJ52EUjvRNxY{KG-+m$|{T6A5y+-7O)sD#VqzZD@2tBz; z+U)Yib~3wqPc&X7u&|#-+<*$-Dd~R;MRrB>VW^XKKO3$fdQUzk(8Uv3h92hE=j8kH^GRF%Hv#`kQ8U*lYIaW_PqTN0s5yNu;Wf?{dhu7% zb_*Ujc}c*>5qx@!fEU{8uLZo|#q=+P_M@UL?gOGN^px>zsY?`XsePF6a%!Rr{aI+o ziL&U|L|I1v@no@aqAbr(2(Nn)k!84`;-JQEj->_o<3fMVF?l5vfzgRI{3z2KszlE# z35K04SS0k$8%)}@e`4|*WrQYdu4rZ5ZqZ7wWIQXmc+pBrkRU&rXlCO@%^oVYKz?)P zwOQWO%NP1T?`!G0)cMVg)~g-u5e{i0C*fzUOk-%-Q@S9-Y-Upv;wCVT2_bU2ExT#Z z8tb5>^OX|jB|4BY>gt~hb+OHAUFmZZoHlyE#r>CovDF3c+7y^^S++H(ZTp!))q?J! z)q9xy%%4Mvvs*H$Ottr zmWpUkyUI+6l?vk#M8+)?R)~^5Nk4`<<(xho`6;xDn$Dr2D;7%$b7O$Cl#`VwjMZ6R6?k~XIk+6M%DObs7*T)dM$DI?Xz!0S}e z#{VEVqv4zoleM=9SJ+h|)X$J()yS6t>{|Sx%x)N)vWgQ9%&*iVJ7-M9O1AgaFo;c))4cO z^5MgkDw}eMTfq3gB9qRyN%8tUOBf+f6ds{V{2WR~h?ALQo4-Qos-5jasoeEpO2a%% zd2kdZ<41=xS*6V z5Njh+J+q~H*`O28yVX{=9H};zAYHI0+|}zv4CfQ5>-8F(B|%7I=|KBVZ4H`Mt73x? zrq@?XQ{*u31O1AYCujeIne>)M7gR^-f>>&G6~mMS1+ampz}5hESI5hz8Y^Y#wEt+$ zhMBlO^}|tK8}2HtM>o&wO6m=G-Z#nG_BVE~*vV{NqGEO{<)MwExzitVL62PC*w9KA zuNoq&tzgZF^&RN5v#y>FgK8t#j#|*P4@KL_8e=3Q7$15n^V|}D-b0zOp|Z@;dOX3z z$`Sg4%L+b&{s0;D7N0>?kU>>cM|w(TeWu*px;c5v!7Y;KS~nzTAIz5IgpI`gSrSd$ zIVZhKh^CVlNOT(A1m`|GfBQ#be}v-sKfjS zCd^-qZp&GMp=AWaDL|)?XD8hRXS_sk#tFmn4vqFpy09{Ee@W=v3X#t6CXrC*OE7g4 zowP-e?s*@_BeUggL}=Jx(i4l&Gj^)b&J8p%xh)c>4^a1Z%R)++=X+&}0@$(08J{M( z^KAD}V+}8>?@f8oi@N2_NVnXJT+6%BAHBnMW)iW0o75!K3XiZx^U4K}W)eHRw9saR z_8X+_`ITU2ozPw-;Dt64_*rQUSr5ra)@JJ8B^2yocbWE@o!vdsNYC3|ouUOXrjHcP zjXl!G+fQBDw@vqDhi^cuV_`tYQ9F~-E7=-+)PA(QnRD9ZGRE61+26XW!!KixcWZE9 zYjZid_Nz{CrmHi#5?H0qu&bem64MZ6z~HKPXjn`gH~L1@^0G83m^>Jmtw!zjTiF z^VH|di#sye;Sr&QGpqCh;xSHa=aV))Ks=+47CjhY3pbf=hG%YFq4g-;;p>>eI?2o6 z4ej$W;0PJewJ)L)v1nR2F+CFk{c< zUEaWq$_~HQs@m}MfOMJ;_r(4~0lES_4}u?-W8li&%%cHQG1&X`?3Qjed<*HW+Hu#KX5oWn`s8 zvpwL&eqyO%!^r8AMG;xetZ$Y_IN+2gFbFYQs$~a^%Y;RdDwTLr@8u!&Q6XD!544;C=mU8$UkL2co2QNo8 zFi6Ce6p!FMzfpQQV`Y12Ep03_RXH{vmVN~TE=c8hbD80m!>3=783lcFA_DJri zpwIF;S@T%}YQPq&o6Uhpxuv3Qw+?wBat4Fp1rrs`&IRZoiEH;?AcAfwjWF)FH1RS# z>VrTj#28N_=l+6YK^V!@5jo!Q5jn;${+S%8^A|_tq$iC;06rVFC=NR+*$Bshb5hv3 zlr2!nITV=Dyk{UNN$wr6HaVz$=a};{iGo$d!n&?WM&;}bx@?#2Jjwi*OhG(fwVE^1 zsj~!McpQ|ssiABEWJ~;>TYUet!+G)tY>BuZGMN0m5I_A^h*4N&-qyq)f?RkPPHWB$ zM>sw^#ZgYY#(rFbbJp%XhwrL#_H%qLqLOzBxu<@bN?kT``rSVI6d#2=V25)kIZ`w_ zn9>%B^_Y^veP;H(fzr50hcM0;&U1M81~GwPk0@K-@W90;q=}IAPrIqQ$RZU>`)Pb3 zOS`+J@I*rKI(%0ydb{?4i!>GFRb6yriitc$l~HPbS)>u^H51cxDZ$uD zgw`t=MLW!isYTA$;rrx8qSf?HCM!%zEOpWg22#Z*4L>=*NAu1;bm!BCH1G*fkY@?a zSjJb!NBd@(2Zc1+U>{2hG?Sih>!r{D^YKj}nAxy{%l#rAAIg zcMamoD4bP6?G^LKcot_Ejxore7|0*FZ9wzr>03C5aNY@hog&HtIM5w~oRnc2F(Z5V zOmagk(P0pOyhI@*oqR?f>jw(HCPS|C{xkTGJ!wFbrSEbQTY)vvLBUfZ9HF%PR8-0= zZrdw#>LM>hnG{wXluB--pf`P_8r1!_Xp_*s#`i_&1C|06;{<5$@yEUFfnN4GY1@yQ zN00RYXCL&qXV&oZ2g@A)%S5yHgp${+yoRx2u2~`?wl5pA^Ts=FQVlGMfRexh@L#_s z{)_&AoIrC3t1$8NlJ*Ojo7$m9f&a9}2EpTjZw&JF#KZ6EjiQ9Wk`Ryp)bZ{8fjJ@O z8N38&YuiCWmmuNvphhMed|h^IlnjGVlPn56GB8RQH+bi0z>Etc%a1fv5OFLlT|ou* zn+LC1CWCF?gT3E_{okufx+j6n-z(2?MkcUH*oo8~nq5o0>TLj7T}opm1K#cW-A&Ne zg*{5fA*=Yp9ycc~`vLSo9K9i&DX?#1tNe|N8i-`>bu9ToL9+W|#m34a z;Ox=FAM2^etK6__?H;TX#t+8u(bHXEZP%UJjTZ#%-Mn@h&l_$(tev+AqF9(q&SNWh zi{il|h*@HR@gTNn^6*LpDEdG3MrXxe$J-u9z3R`#PccE`}3+-=p&19U*eI@}xS85?D7vJF+FV|`Vpm}-uiLNBZG zWA~jaGfJCn5SySM#+7-nlnSd=m^cB7M-`wGN`YTC#7wtSswyMmIZsh3(`x-pbV@}g zmKBJzLkk`U&x6l;w^gsamNdb+eS5#tW|Ox4#<%O`2I&b0#rXNkaJ{ykz-KkLhNjSy z%T&rBbij9t?*W;#*%wV7=}FUez9&)MUFlM=AIp_gKX~($Z_@NrvbO2I{dm4$)*V8R z!TO2+UQ{c=bKn$Z#J&-KfCph!ihVNe6m6VbOBox}eKR|XQ#RLcmT&1;pR%ETgFJf? zR1a}qa{lUt_Rl>l`r(OJS4L;njrCV^+btpQIT9WE?a@2lbz3uyQdNH-I_^6eF)}~o z^gSX;+wbgNfDWC4U7>_2JRvJHGLw9fPW}{i$u2F2vzkYI`c(^q5hp)U)wcJ{VB~&3 z(`(lp4GUJPDyM;jPbHZD+IQ4bex`jl=QcF%SjBxVM4M$nBe$B1+;44~fVflEN8vfu z*8S9hiUT*SMovnnxGF1?n6zfa-`s4ibv`YTm8^yta)tepeOWoF^6H>Q*gLte?ayA# zS5dNeOEK4*_*~vKvb6`JLE?Wt`kV;cHDb6A+QTiAs@%xH1Hty8; zHAz;(iP~uChDlM^W^H%bDw8Eh1u&y&Wke;=jZ%- z2AWpe!Ido*XC5^VD+_vfn`z#JtldW({imb;S)aS6W7_;Ii zFEd7tdYgi*LdYyMtAF$pe~Ti}6k>K==|J#ag~R)&q(6n^=DbS<~ zHf4jeJP_@y+#2lSY7Fn$9z4rboR(Y5WvJ~7pFwAD?n_*q%1L9!L*tKkv*7=-7`csH9*;I%!$4AoU36f>pB_Yb@Hdvc?P|G+hlSB;X)hU;bM2v4N zHNt@-W^!!{#KJSwxE2iW#{;pYxxy;3T%0cs+Z#Fj#?BqH#br`?EFpN7#4`ZQH9zvR z7MU?u;8}}bEy0?FpRM>c9*cKT_nEE4{T#{@wMW>UJ|*b#t1kPS2F7!7imv>kLG^ST zVtl0mN2^tvHX_Q%RGvjv8qT`w=zga=2+{J$sC^8#8;oe5$E({yjt?HEDe6@&C_q(1OI$B`QJl{ZdR5UoNmZkeoYHo{MzWUmKj=I;86frVdzjy}?vswN5UVChd-{a$ja9NENTVsDBaWOutvG zOy-BkDMfxNrw)}ZY`eU=UsWpowQkY{^u2v=hAO3Z=)rB%td&_SU(}WMP>)xu;N0{< z>;Coo%D&p^>h7jgXMw`H&-(03`*U?0d#MvuN2^q4Fc-jHbZzXR;3QIVxTfuuj@wno zDP!3u@csbAyR%;2?>sXVJfR0qG!Kd^e=5b<{o$k+>B#?dHcj;VJ$=OB>V6OHbU3SH zku`QA3Y|zS5cOZ48d>e_ag|J^LbvHkr^1^EE{>L-dO5O6lqjClG;+cG2)pr0Zrqa^ zh>(7AI-vgfST66sz;$xTST6dWr$QsT(o@HBh5ZX$XyI5c}5ME!yLlS?(99aO8;H0EE2Txr#O}^cWR{vMzp4%9I5yg zMRbL8g%PT3K0FZ!cqI4??7$|Txy}60BXP>La^`xy@9Y$2lY635-V0}kdv5EiVV5q| zpnBwOpx~XY(*sUP`#{Z9I7f2LddiWddQo1$Wj*jx^FpW8AV1#GO~3k5&!h;4E|!(d zEpz#}rSs)K8l1s$={cvX{EF21MKE>B>g>Jpg3DGcq5m^wYEO;zbTCTV?Xq7**0Vn7 zbxSoWt+pyEgg4-B$T*4Fe_hzlJ6Sfahn`{%)^hDN)8tA7KtYAHIy?Sg0E zA7U)s_U)esUED8`s&o^qwc)8IydQ<1c5-r#Zo7VFxVDY5etnA!TmRa2ozF$I?@VL4 z#&R5NZo7G9(4}ZGV4Ga>Uc|slVyeBI^muSUz-}LBxle#j-zR~nl6>~kjJ8mpw%jiV zRXv*!)u9C2rk&AOYb?#6x9#TLT1U^0ZQqKvjD|8jaD4Iq`7)FUzeIxf9q|RPbn};i z#V=LE6+nKmV&EIFG7|3M?^uK;vW&TghL|^9%^v@!SG`(0@0|tc{bwKhWcTYKk}+h% z&4CLh+vJTO|MnM~RKJ_Y)+LmEQnmEMCCL+XGr#ziL^n_K{>7VryfE1D*T2Rzf4S|O z2cCHLr4PEp|IbU3r&ikITiiJ@AL15(-hGJs_UG?BL>EodU;VCYZ`J2VQvdpR*rd`w z3wQV>O6l#d<4cAW-{Xs@?}<&v3Qn(j-uLgqwJ0rRQQD$sR_?yIME<8v%Yw1+xlhda zwpBms;4X z(bN|x_TyvWa_(GkW(oW@qI<~k>?R{ajkRk?fG;-ZZeR-&)r%J|P)Ef_Mn%TKZ*Sq3 z{fruZ*I9)BFGo~ld{m@X9nP{D30fx86s3k=XvNIcCd}2w%tlG@mNhCg7cr%XdKA9O z0_eh0eT+FeKWa@*biQ_t34deow=MABHTYWwxiREc1UG~t3-dBf#U>QVu3M8;Xv$$x zWHGy`7)26jk#Nf>DngO`A0{t{|DOtxyz)r+Jz}9bqXhr^fyknD@GHtaasn6sj^&4!*?E4EO#Htu z;{Ssg{=YAR08x)95C5JP>xV+jU*i9N5&tjDI|5w1jn)4XK#bV=5Xx0$i|DC>JLXI-wlNhi(0E zF~NVBNAwA0iip6AX7CpB`u;OuHDSJg_YxyigxmKR@3+zX3weN03auai6LR+wUoPXz z&3yR~U!LU45BYKzUv~0kDqk)tFqt<$QEGi6H>0q$z_iF}&R=3FDX|o+z1t$8Uxc!j z@BhW-g05W{uTcVx3!3%nVi5Y_eF_ttr7e;)+YK+?Pefk8^k>!BEEW_qgD@cSvtHua7b2 z<(W;Y>}BSX(mZQwYH7iyVq;OvtZY?bfy!8*%GMVbXRDy0rDjgrXgwhSjfKx>IM)C0 z81QibONWoKq{LiowSbcBJaev9RctI+YgU;HOezcRL6s06K+0XJV$0ff)@)TS_}*+v zRq^1V_6UA_XD;EKyBy?~%w1brSOh(qXDOH)#~6#(7S1g;ueFp|i?*DIp;z#~82EXyS9{=9HRDTjqd|3Yj^YxTH7@$Hqa|a8Ta;s7p-rZr}}5 zLW#%iXm}*Run)$9EA9gyOU?s88#D$zhU4)&>|eoSITq_07zt);48AiK7aOzB>^1#ir?vaZJ0p=gA?<0Us9s~Y4 zz@qL0pEd^k?*PN8bhLawz|`<5Hg7Do6q`#_`Gv)1RlXUDEh-pDj9FzZgxIrKEikB` zF{?6g&!^*#2QIjzq<^)fHm3Zs+7$+D7@lt_0l8}n^34TSEMhY+504XkjkXt~e|#S} z9&;e3c*_|0n*bY&55qCvXgyu`p~vvC=&t}g9zJ&sLQ{*vE|!9J67zD#uu2USl+widDuE zRV*ZPa8YT>tXcQAKOXdjjbX>*0FNF6{tJMQ<*z3J{@_2eyU17!rmy)Y=BwtY;%BQi zVr%cU_h+EzpZbS$38y7y!>k|jQxQ=zhMr&Z?Ie9wSZY-j=8{PQTXnBpRrm4BPJquH zgMJUdBLIGHKM!~FztfD-aa|4a$LiN3_tiTTm0T?0C>qjlF_)~tV{MH1c?smzEGY%BPwVwNid<`X@7e>Rk-v@37 zIBw_g2;}n9P;%m&%Ox%#f~$+yH-l8~(SwsU_U~x@h4+CU1UT;Z|5d*g6c((pu7gFT zsl=EIiDrZc*98;*agz+#f!l@Se>6M>U>f+q@~#m3cw#!?!@kCsu%7y=jIh|B5dff5Q4`(z*n9nr`QOqEzU-6@l~+;#U>>X6FQ85?iZNaRtG&LLZRVIr`RZwWX*9*D%R&J~u9ZxI}`s>%QpBoSMfdzQ^ zh38?Ie^hv%a90=kc|O74Bj`&?bGSXny-XlCbOO;A#rt3cUp{OcEJb-+#^ihK{(L3t zEO_CM*Y)?Z+IYT)?$t;5xLw0N%|mbSe8PHTRz@NCdef3pD;Md;JUnW)sB$>yh>gS` z&o`0Rr-CaL?uCBl!Dx0Ufe7%?^&(?|h1r06*{VuaJn~4?BM=nKI#_VtwSiHnRJZ}D zDg}WLZD=a_eT1-I+rsO^`v!dN=Ib~o;cG|`siM*RZ;X=n;VAym@&rSK_VHqo3NK{g z;*SjkFqfNgMaUONGYQ>ui%B^xiuT9WuwTW7tHc6YTP0`Lv)Fj3yCM0ST6BBibNr}mcDT(uR z8eP0DL8sLv>U6p!U9v7kH!n$(6rYrkq)kdp(j_G&B`2jM%}drK$0sKwYm*a`b;(J| z$;m0n^HMY^@hJ%@+LXi;T}o0)a!N|dym?^aJWxLmM9%}Zc>p3i-4d&@7*Yhc*Hw*N z-rzi9KI`CspTqyRnx@OUpWR$G4#_!Pi55q$Q@wqXBl2K+mKzeey&7Yl81)78=u?ePGe z6DH(oP=X#!<}e*cg=L)q+^^yh$|kZjW68p8x(0MDKzF}3LD!?#0k0x*?&;szJbp33 z-_<58e=*=c2mYtVz+*e}03Vuw(4Pq2LuCy&rdnDPgd2qAR0G{{pvxe1OGo++4xJ|h2>wsr+(vZwC`zQwJb^~2D&}oQl54Ci(Y!V#U z&OZRHDf#~6@pHhh1H1}oN5|-F0QK|u<3c;08m$YrgXqKUo-KhGN`dhW{sVbM|D@Sm zyR(7k3+MiYvD}iq6!_X#T%hF}{n!*{v^*_)y%^!R0Jp{5o0lWwB{MZ|F zY+*V5KsVzNvOgZ}AB>*{3r-c_v*8}McSM+QaXKIH**}2)CEz`PZzOHHXFNRz_?Z7d z2)Y}~zboHi{RaX6(;vY90q{@#0RD5pum1sjKj3XYfS(2jhP8k%BlhhcIS#OW^8tVD zK6n-2e+l@EH0XQ2Pshr$HlW#-e*Zr30Nw_8tZ%G7ItBRW06*zIct7Bae?UGyEG+{3 zAMeAj0{r-lAs^h;hbrJn1H1|FW9i2tF^vgmR{Q`BrW5IBBg#+*cVF7FBi*tOX?#v5 z?$nEAMt7N%D!-~MlZxb5BO!0CMUMuNvi>+=YF=K4nr+nsfgN}!FqvE*$w!b#^vjga~1P6E~E>qbD^cMxc^ z=`Q`-2{ghIJ%U#4;w7w`Hv;-@1%cMA8!4A@&e|v)m~m@nZ=?av3Z;g~;5J#Os7ur# z*T-I?O$TJ%hiA)Tpm)j*)WY(G)ML13Vq{7w3Uy0RXt|!W$P+ZfJoD=VvJRluC`QuG z3KW~&bZ98^Y;*8CIk8{U%mLY-fl8p6#A1md*E7rqWa1;``nxrST>rLcne~`8-nh-i z>KRe9bf2CHX_maGXC7>p?9(4=1gN4}22i?LHr-IKXTp6@TjZI7@0C7OqmTPK_S;D4 zQzae9;e6mUXX8>?5iq&w*F_pdoeKAg|Iao0C{MXQ%u_#tr+y9LiGG^!)N?$9>J3FRXsu)iP@=#@kQy=J6V+n-i$bauyf#Gs~Yk&u&=baZRejY!U3 zvoW@t*2ng3>v&Zb*Wcuq$!3Svg<@Mh>tr%AUi?$=c-gvqwC5-f>CuLNG&vL4Bxj_O z8#}>u(9aO>U&mE6u}SPn9^U@omW|Tx88>EL%k0YPNOBx=#JQSWk$P+o`_(bvCwkLl zAwKO2mm=12f#rL?lTbxpxxmhJzR%P7r_5jv7m2KGrVPtriynH9=(jJU!lc(`bj|F@ z^v60_UxMqXqcV5;>8kbY`N|xQAEMz)o9$-E2jzNMhdSjUD!NgfC_!{1GeIuGy2NQc z^gItE6KWB3CfmRgZ>YYp^hh`^Rv+wd%g!(zHi;}W=%2~@`u=v}>5a~g!~U85u@1;A zbOid{Y2~B{au@K84%YJ$UB@xi8d|a3i)4eBT{|!b4{|iF8l*409Mns;ooe zZ^)LK+N?&9OzDYlPNip<+sx!1r3>whbx17s1R62>oM)u=WZfr0+MTj;`Wouc|9@-cQYnQd?-FBhA&33;GXg|(pzMZ5LSBDzI z&2be8Yzv#}B)L$%EIll#@>oTzKdys|J89tI?Q9~V^a&Lt&ON*0H%jl!_?(X{q~b1?k6)_X(EN%U>QR8W^{I`f{ zw>-gEQlDTd#wi$T+|M(+R=ZX?!Wz}D&!g1G=TTdy7$prZCP*%FJLDA8k@z!a!~Ruj zO(NC)qu_p=+p<_8v!Rprc@p&53H@^A(-BDNn1)t$xaB*LQhr0c^%wD;t>KsDUpts! z6SQTvRvWPcX-i*Ai=ve)bjZ8&3}QN7oXxC1IY<5aKGZ%nxPRu5rtGeeQV3D7n`&VlcT&jxlzjZ`UY3;o!)3~-iDN|N$6OO{Tz*6 z-0rRWG)8UfLH1@5b*x5wmPXo1tpM>MFa0t~bud>06SYBL&xWfKCNJ^F-k>Vb{4%9& z1$&l*J$vYhRVMd}B-B!4_tD5*R))M6FFwXp13bIh814`5s5aU<>Fu`5PxpE+MpE9^ z<&^iLlzQtkx+z9>m7T%oq*I5y%bO|Sn_6YUy+f>-?$SmyfIao-YGr$9$Teo|c1e!e zOK(q8YhFR3(u}gUGU-}%;wwl!|2$G_J`<@EuZYwsZ=$P3nbsz&V#`%a=K7}fiVdC5 z8lG!-PP(--e->ngEbve2Z9b3d$v8?|IAeoSvO{#|sSHcJ=gu^v8q1=2WFxbDV0Q7TjMj6gB9D%O{9bHl0Yd{gkig)!|vg$riflY%$40*-sFh zZvnyi76FbXIL{KEZ!M9dT0rXbIzmft7?$JDBsgCz-;!if*Q=U3$gCAO+0@1J_rl6S zAA3X8|0;^>j_t!xH(ehSBjfYrBRrj$$U7s3AXqS3AO}2AIlb&7HskGy3Ah@U8klIS!R(Si+)j%75$g7Wa&kMEdP&qJHv@A zG+D_)j@_c8dAOW!kCG`Ye*A6q9zG}(S3rI z^?L*>eIJZvrCBUkX^Y_H->D<NE{wfoYIFRrz9b#}zM z#Hp-^o3%{(sPf0P5oxoS&CQ4%$GFB#meTEc%>#CwixNL97ctM%;gnw6@NAUV+@jK! zJv+|rpznCu|4w5Z_2IiWhv!_DY>jB&es(~)pl5J(HB)5zQDvTe9;_28UwKg6?1FqL zN5PlzU1h+2QXU2;52v7F9Pa)1hL4ZllY)>w3yVg+vzT1+T#h6al+)<3rLdS!O7 zQT_T!q(0t+;O_WxO08K=9SU#v@95pSTpOW>oTsB=JF>c%aXK;IAAZtrQLyq7^@;j1 z)GakrF(_E3k=5N89E7!DDRXUuynIm>do?@L)MQdvI=2{}X?RBZZ080;UPE38UTxxD zr2{@bTCS10d4R8f#p4I+xZXF5-SjC5$u4P}PFRI22rhcuc|ImRw+I*QB~onNe7%>i zf5+GVLO5x;5L2Gd31%qHX+dUo55f5UKzMwAbkjwAp7VS+eWUZ*;jV^`_x)M@%lcMy zue!1NT25DP$9lgwl@>AM6%WO_?DJU4t++MFJTHIfXqD0-A7mFWA^RobhaF5hsqY)9CCt{PA&gBv zQ~a=tjD_{)5c|V&*e4)~_PN&-+UVD!v}RqDQo=&44NLXU5+_Lp+<4xtwfm$M3o6nOa@LFr^Wp=5S+pTc~+==L@HsswCNT$Vkm;GjMwvhN9dP<1K4I*WcHcHl*Qs z-zaH6*wnLPC$n{llG!7dMm3G(&VJAfE%F9*QB`KVYKW_~gEhm}ccPEZd3!t4l$*eI z)QYCOE7(rf7{eoi38E)4&n^k!JY>>ENlYX4_#=sx!}J?3%eWEr2N*%GawDh)Mo7I9Yu!OCxq^ zm$xA8@&NKK??G<`hVsm3!~*lBX5KbGzee+Y#Cw$Yk?%vk{#v9DXDDAGse9^4U0=l4 zU*hq6{nTrGJ9tm(KN?<}seU(aW3_p=aj(VQ(<_eizZTHSS`lM>Pv+j#EBwU+*03XF-VYrA_)imF|ThoJ}EhTqv0Bywn&aSVjWDs56QAu z^3lt-lej?TG1=xojOotu*?#(TjMYs`B=J7j_vTK{+1nPL8~!B|(jbX*B(O^wAIqNo zoMv-V$5DSme+-&EnLmU4iq^+;%rL)W&dJ?Y7SlERn&w7gH<6^j6H}zgV~TttHx09@ zzh0rqo_&LsYW#Bo6h5ht#yMVTtTfVeC5+$bD>ASn*dKEJv7*I!OV>SRYU(=Lam=4Y zv~ly9M}albhR_aKSMaqQ^S06%W$%>9ZUlFS_J#K=X$b|V8yw}Svfyl%4)!+`Nv)kG z^H7hNKj!V;NIVu0>P4h(K1V#`e^&5dtRu!~ydGoPxuB+(f*&|NT>H?i26l!yBbPOVgD*nC z7oxJmWf_}fH$uC^`zCX~AT2$$YnG?#a#dhCAVII`R3|;cSr!PJ6jiGUlQ{6Ks6pybSt=$9^|B2@3IxkLgA$8&zkj2RdsUYdLTk7Z+ zPOs1eu}*TEzAn}|Zgcxt%|1jIL;ChBzFUVD5SdT+Wc7lzyLw84u@)I()hqaf;Pv@*__5>h#O;jSLcS z%l|lx%WjefSbbGTl!w-r>nl6b^)qYKnrN!(u5(8rM&tqF$?U(A(uM>~tTT>1#_K~z z$(qj=S_ih+efkp+DYulgX z`55D9q=CaY7Wkgb9F|jGJS?aFH~&nIn-2Wfu$=7l;Rwj;UUtJKJL;-3$GQ%k7sJk_ ze1THRqVSxS>N^qX(!d>ivy0kyo_Sv)l9`n{Sl2a6sQjG~mz|QGrHJ)&fJ;{z9)kvdk=Kjpgeq8Ta8 zbg)_hqqL_-tb_!11n%XFUh_O~k)|R7%8NcsF`lES(TgoF2s8q{dfZF>A&cfTDr=fW zr5HPb&;~>!Xoom4wZM4ru9O4}R)}bNRLkVJtPV zO1gUhXGZ?43Ucqz_}PO;7>+R*KZ!7Yq>el4`Dbq7F@(n*-`0tOEPw;uaTt>lOe2iQ zbZ#VZYdZQYmIV^|5$Wbe;BqpIbFSN4HO*_6< z&p+M^oPE&Z-kI$Cyj31^$YrA0$I3a)@+%lCoIQA$*zLd{g`LU`$9kO0&v9sS|? zlP%LY2~gK`fP`*d!kGcJL^5zha(sl0Q;!QWaL+(5Vcfvoy#X^W^eorYkU@mLuysdl zbY4Gv#TEv(eGB$}3-*7jEbW;9Hh(KW&%$%XW+_>dv({N2esx{~vbyE^Dh9mU{k!X+ zts8rk^h4lB0PO=9$P!@s>A2tAwB$R`199}yEh0%@jI9dMFKQ%pa{-n-otNypSh=aH z1UP%uDaU&&3#&HlUR#ZILjOS@&Og%))^^{mou15V@8Ps_PZk3>CW%E5#r#|nj;-J< zN&$-?W{CyS`Pibcp_K|y^nrG6eF2*K-{IrM@1L^K*?+hX!QS+xKJYnEo#})A!+PKz z#vC_iL4Jbq2e9vfjvqDVV9-54^wqBiIG)GA8dw?igT6bUkFyB4Zk-hLeO9_r8kljp zq5u893*8^zXuWo+>x+&ye{TQ!zJhKfKjxwyFJGK29UM3?uJ<3x+Hs;|2a+c#6bB>? z9_2oXXy(474)J`Nf)lBf<9#wS=Owm#5PO$cLNCKDnY9FFonEHLLY;49x-22yN=v$y zHBoQrnSVr3%r48ga)Xz?2y-+(v#Xc0()N9S8CdR729+Y?0j>1qH2R$p6czPBKry9t zKv^jpWJ=#dk2K=DL;AQndve8~gz=vJG4(~Q``pdJJG;E+9-_XetBZyeKy&>J_nGd& z!1I6G)w9zTNSCGuwQqi}|CrOBD7ndun z1t)5VUet3{VzzfK5G!vQko+Isq%`W-_M@)Y9gJL|;H;pd^;#;W|1H4^{lnObXf8v!X*P8?SU9;r>70Z_bxrIl)^$bPvYl$$j%RXFZLDhr ztCmGmv_h@XQ=`vQab6c@-^jBtk4Oy(ckPzA=g@YMK(l*eRVjJffZqcVJQ{n%;<2if zB9U5i=2nP7Eje=w))Vk#4Y!xe9FRqh_kI5!tW8AlOnIXC_i`jYDW}|Y&)_b4XSvc9 zfuhF2nUC13Xck?TxE`k$i<8EoDev2p9N*)ZwCi>ZRu^omWgehIE7xH!iqASId$VJ( zG8^lwInC6v)I@q&O|W_2`EtFu#R0Pg=!aauOfRFNJu)N9Lvfx3=(sZAmkcsfos_ah zk2ucLlwpb|*hm{HO;}bqp06}#xLgSRbaPwn$}8#P+}pSJyB!X3`+q6AUuYDcbWu#O zLV{ON_LKPZ^w!`+I;>nNk3feM6BUOf;uZx88*WMScCIDyf!*0+upi46)lR>DT9H2W zw4{Biq93o|n02q9M_@<8-IsVocvU)49=mVYAK*dQCt{yWIZeZRDwKY#(TT^Ua8mGo z*M*Lc{VV$68FY8fjofSNy9zpNlmF;SbtP?2*zu;%ZqkdD{o&|@A`CH-VB}W3F3LLS z?pc6dISuDDBBuDHq+HKTP#~@Jaq5y&Tmh%2KMv|wE{sI1^khx@-m?R72ZN0-UU4-p zSgEX<0unwHVg4)MP>%;2_g$aU*tBC6`!S#YRm+>$)ok2Bd-FKNp0>|t5wrCmb*S>t zHM^b_(*|!)G>^{b?BQoc&$Z=cML1 zM@mnd5PxOncCVu6$5EG&k4{Kp1r5Cl$)zr$jM{|Aj4W(B%E)m;dOsT8h64kuj>CiSGq?+$p z`yU9Bq7#xZgrnoAi`h|!>@9Lplj9h>tv1#XuDG_UYjuZB7H*tu@qXEf;0+>I;D6HpXL7#QIg2XSN1b!a(0HW`O}OBY zH@Yjr(ax%^kzTeg?T?P>=a|YfQhS92wSN*c;J$ft0`p}g#dHNx?urHI^4so;htPTW zPDJ0FxKP1tJ0}r4gAlVoiuMI`9%WhY1Z5B!zwFZz8c2Vmau>ZRW9a@P-@% zKO3ML+Yd$$W;q#$9L2egx!$}Wfw$ja6coM5jRHBsR$dr$6fob{i0lw&l!0F8-F`fc zN&i&x=Ghg_^2|e?SjgAH3LQl^vCG)@uWI^(OJy4m=Hoq+aE^m_xozt+HXPmnd)*3n zYo@LR-o}`UScUu2RD_=z*&k*_;-5g2NhU#*x!x1Ej1w(mFY!?}r_tWBgIdO7nIvM^ zfL6YAIARn!YM28@Oqiz?V&N%jObdo)k8o^hfv_(lt8}49ZL%iEG>k7yb+xz>wr{I* z>!!lqy}Dm5ftC7v$t_sr!^+Wddw6$<95CulQ*FtWH=B!HEY`Q!f(htNTMv zi+u~kVJ`Xgk@IuUd77J_X}#+%IQxGve2Pb_J9W=#fiSZjbvCj1ExM8OT6-(Wk+#Wr zg^lMbn5)0%R=nJ5+xJVn;^lT)u-}1Mn_ubD7x7GV|CO$A7L@jreaZ20k8ArG{%2%qPF5 z03`1j}~crBdJ4n?afFk zwN@*YiqrQb)c7tlLGZ)oiV+O++q~0bZb%h!uHFn`;}$lUuh>?K;Js| z<|qv}2d8hFVz0_wxl3EtOZ~J~3D0z<+YheaSN_>fZ%+@Ugf;hc`#$^A&mSz%Zn{aG ztT|SrJd3#iw#&Pzmx8AxqN8=~`#W#foS^jOAHcg!F!J3E(th{ZN#Kbj@I=c1AKf;} z;O=>M!Y(@QH}2-~!M~?pPxJQt5$$xjYjw!38;_#K6AJ|WmnX&5270}vlc=a|+OkRT zmXw#J#iw70s}Up$XUI)#WHa8)n@gdG$2>)b2<#`Po7q95x!8Y!3rR+E)&C1z9yFTE z_b+gz-5Jdl_!qeR-;>oOlFN*7mE{YSQpw;e`YDZWXBn*w>KzO#KQf_pfDKA@Qs?no zi0$1i1JHlsizgrt%d~7y8gsc`#I2>J<|0Y6S`KAb-R)+oiJ9Eb^>bO%k3C_5^hR0pG%3acp zZ0-Zkw=8sv)1)Uld*}nt_fCj)X?14NoN{lFPyDd-`!si?RD9m;t@u*x{v?t*ZFk@N z^4DI6RYd>BFsZlBekKy7@9{djko{Z`I%2CuWwrJNlMsGlueS9fud|JVs%>Y{#>n=z zxwn-;n>c&hZ#8r)C(+_Xd)V9q&X$E*X{$)T%`Hundf_hOMMFgT3tJ+~YV3vxgmyFqy1-UPy1a_98J9m4mw(oN1H;toTsSUPikj7kMMjQ6KG8zwSkc z0G8@(5Bzx`zOl&}(iYOltXhiBvb*8^oOdynZvX1f177y$NLjWSb{+7>1-!e7-^5_0 zEZu(f>`-nSVg3463AX;l?b@J=Xy4hU3bpM7*xY{o%K@*fH4WS3mEJ@Qyuhm5%Zg7# zhKBA5a#sX}YLogz5LKd&o}bnp71Unv>436#Gom`>VB3_lNwsQQ3+QdXey`TMX5X&_ zTSh{eUN~C)|9++Yn*Zf7JdMB?{IrU@(h4bZ6H0zbnnr4fhYtO|lm{c*sB3VLdD+|I z4|#Ic0ngkw7NEDEe&mBaM<$C#kquSvTrfJqHvQ?hKijPQ-CT41yz&ofmcF|rW1M!z zC%+JB=c?bnc>S#l1D${UYhuf%+rD_<(Wjq(rzhr@&x;;k=}c+$8%=HgV<;>8P8@hNffamn!eDflNJMg{-pP=f!LD?TnIK2D>GF`IMdX&93+UIo9b zPMo8eH%F5=3#G$vD^RhegegPRe7Kc_(#2&-iI#+-_%-lm zc(_oE*8d|wjO4G(Ck?M$LO5)sDzM)(zGngk%M|p>`1~Myg0PIXca%8pH|Qhzh5RD$ zBh}p&rxCG3-!KF?`ys^cx&;2TyP$*?g9JP9Z;HY8qETc+|8KZ(6hhz=!1%Y*LfZux QE}!SyzhWd1?nm?gU#!{>umAu6 literal 0 HcmV?d00001 diff --git a/test_cases/ipc_call/test_ipc_call.py b/test_cases/ipc_call/test_ipc_call.py new file mode 100644 index 00000000..e871403e --- /dev/null +++ b/test_cases/ipc_call/test_ipc_call.py @@ -0,0 +1,287 @@ +import json +import time + +from framework.basic import CkbTest +from framework.util import get_project_root + + +class TestIpcCall(CkbTest): + + @classmethod + def setup_class(cls): + """ + 1. start node in issue/node1 + 2. miner 400 block + Returns: + + """ + + # 1. start node in issue/node1 + node1 = cls.CkbNode.init_dev_by_port( + cls.CkbNodeConfigPath.CURRENT_TEST, "ipc_call/node1", 8114, 8927 + ) + cls.node = node1 + node1.prepare(other_ckb_config={"ckb_rpc_modules": [ + "Net", + "Pool", + "Miner", + "Chain", + "Stats", + "Subscription", + "Experiment", + "Debug", + "IntegrationTest", + "IPC" + ]}) + node1.start() + + # 2. miner 400 block + # cls.Miner.make_tip_height_number(cls.node, 400) + cls.node.getClient().generate_epochs("0x2") + time.sleep(3) + cls.ipc_test_contract_tx_hash = cls.Contract.deploy_ckb_contract( + cls.Config.ACCOUNT_PRIVATE_1, + f"{get_project_root()}/source/contract/ipc_test/ipc_test" + ) + cls.Miner.miner_until_tx_committed(cls.node, cls.ipc_test_contract_tx_hash) + + cls.ipc_test_with_exec_contract_tx_hash = cls.Contract.deploy_ckb_contract( + cls.Config.ACCOUNT_PRIVATE_1, + f"{get_project_root()}/source/contract/ipc_test/ipc_test_with_exec" + ) + cls.Miner.miner_until_tx_committed(cls.node, cls.ipc_test_with_exec_contract_tx_hash) + + cls.ipc_test_with_spawn_contract_tx_hash = cls.Contract.deploy_ckb_contract( + cls.Config.ACCOUNT_PRIVATE_1, + f"{get_project_root()}/source/contract/ipc_test/ipc_test_with_spawn" + ) + cls.Miner.miner_until_tx_committed(cls.node, cls.ipc_test_with_spawn_contract_tx_hash) + + @classmethod + def teardown_class(cls): + print("\nTeardown TestClass1") + cls.node.stop() + cls.node.clean() + + def test_call_math_add(self): + # deploy math contract + ipc_script_locator = { + 'out_point': { + "index": "0x0", + "tx_hash": self.ipc_test_contract_tx_hash + } + } + ipc_req = { + 'version': '0x0', + 'method_id': '0x0', + 'payload_format': 'json', + 'payload': { + 'MathAdd': {'a': 2, 'b': 1}, + }, + } + ipc_ret = self.node.getClient().ipc_call(ipc_script_locator, ipc_req) + print(f'main: call result json={ipc_ret}') + assert ipc_ret['payload']['MathAdd'] == 3 + + def test_math_add_with_exec(self): + account = self.Ckb_cli.util_key_info_by_private_key(self.Config.ACCOUNT_PRIVATE_1) + father_tx_hash = self.Ckb_cli.wallet_transfer_by_private_key( + self.Config.ACCOUNT_PRIVATE_1, + account["address"]["testnet"], + 100000, + self.node.getClient().url + ) + self.Miner.miner_until_tx_committed(self.node, father_tx_hash) + + tx = self.Tx.build_send_transfer_self_tx_with_input( + [father_tx_hash], + ["0x0"], + self.Config.ACCOUNT_PRIVATE_1, + output_count=15, + fee=15000, + api_url=self.node.getClient().url, + dep_cells=[ + {"tx_hash": self.ipc_test_contract_tx_hash, "index_hex": hex(0)}, + ], + ) + result = self.node.getClient().test_tx_pool_accept(tx, "passthrough") + print("result:", result) + # + ipc_script_locator = { + 'out_point': { + "index": "0x0", + "tx_hash": self.ipc_test_with_exec_contract_tx_hash + }, + } + ipc_req = { + 'version': '0x0', + 'method_id': '0x0', + 'payload_format': 'json', + 'payload': { + 'MathAdd': {'a': 2, 'b': 1}, + }, + } + ipc_env = { + 'tx': tx, + 'script_group_type': 'lock', + 'script_hash': account["lock_hash"] + } + ipc_call_result = self.node.getClient().ipc_call(ipc_script_locator, ipc_req, ipc_env) + print("ipc_call_result:", ipc_call_result) + assert ipc_call_result['payload']['MathAdd'] == 3 + + def test_math_add_with_spawn(self): + account = self.Ckb_cli.util_key_info_by_private_key(self.Config.ACCOUNT_PRIVATE_1) + father_tx_hash = self.Ckb_cli.wallet_transfer_by_private_key( + self.Config.ACCOUNT_PRIVATE_1, + account["address"]["testnet"], + 100000, + self.node.getClient().url + ) + self.Miner.miner_until_tx_committed(self.node, father_tx_hash) + + tx = self.Tx.build_send_transfer_self_tx_with_input( + [father_tx_hash], + ["0x0"], + self.Config.ACCOUNT_PRIVATE_1, + output_count=15, + fee=15000, + api_url=self.node.getClient().url, + dep_cells=[ + {"tx_hash": self.ipc_test_with_spawn_contract_tx_hash, "index_hex": hex(0)}, + ], + ) + result = self.node.getClient().test_tx_pool_accept(tx, "passthrough") + print("result:", result) + # + ipc_script_locator = { + 'out_point': { + "index": "0x0", + "tx_hash": self.ipc_test_contract_tx_hash + }, + } + ipc_req = { + 'version': '0x0', + 'method_id': '0x0', + 'payload_format': 'json', + 'payload': { + 'Spawn': {'s': 'Hello'}, + }, + } + ipc_env = { + 'tx': tx, + 'script_group_type': 'lock', + 'script_hash': account["lock_hash"] + } + ipc_call_result = self.node.getClient().ipc_call(ipc_script_locator, ipc_req, ipc_env) + print("ipc_call_result:", ipc_call_result) + assert ipc_call_result['payload']['Spawn'] == 'Hello' + + def test_math_add_with_hex(self): + ipc_script_locator = { + 'out_point': { + "index": "0x0", + "tx_hash": self.ipc_test_contract_tx_hash + }, + } + ipc_req = { + 'version': '0x0', + 'method_id': '0x0', + 'payload_format': 'hex', + 'payload': '0x' + bytearray(json.dumps({ + 'MathAdd': {'a': 2, 'b': 1}, + }).encode()).hex(), + } + ipc_ret = self.node.getClient().ipc_call(ipc_script_locator, ipc_req) + print(f'main: call result data={ipc_ret}') + assert json.loads(bytearray.fromhex(ipc_ret['payload'][2:]).decode())['MathAdd'] == 3 + + def test_math_add_with_type_id_args(self): + tx = self.node.getClient().get_transaction(self.ipc_test_contract_tx_hash) + ipc_script_locator = { + 'type_id_args': tx["transaction"]["outputs"][0]["type"]["args"], + } + ipc_req = { + 'version': '0x0', + 'method_id': '0x0', + 'payload_format': 'json', + 'payload': { + 'MathAdd': {'a': 2, 'b': 1}, + }, + } + ipc_ret = self.node.getClient().ipc_call(ipc_script_locator, ipc_req) + print(f'main: call result json={ipc_ret}') + assert ipc_ret['payload']['MathAdd'] == 3 + + def test_test_call_syscall_load_script(self): + tx = self.node.getClient().get_transaction(self.ipc_test_contract_tx_hash) + ipc_script_locator = { + 'type_id_args': tx["transaction"]["outputs"][0]["type"]["args"], + } + + ipc_script_locator = { + 'out_point': { + "index": "0x0", + "tx_hash": self.ipc_test_contract_tx_hash + } + } + ipc_req = { + 'version': '0x0', + 'method_id': '0x0', + 'payload_format': 'json', + 'payload': { + 'SyscallLoadScript': {}, + }, + } + ipc_ret = self.node.getClient().ipc_call(ipc_script_locator, ipc_req) + + # https://explorer.nervos.org/address/ckb1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqp29j5z9tay5gqgqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqj34x52 + assert bytearray(ipc_ret['payload'][ + 'SyscallLoadScript']).hex() == "35000000100000003000000031000000b95123c71a870e3f0f74a7ee1dab8268dbfbc1407b46733ebd1b41f854b4324a0100000000" + + def test_test_call_syscall_load_script_with_env(self): + account = self.Ckb_cli.util_key_info_by_private_key(self.Config.ACCOUNT_PRIVATE_1) + father_tx_hash = self.Ckb_cli.wallet_transfer_by_private_key( + self.Config.ACCOUNT_PRIVATE_1, + account["address"]["testnet"], + 100000, + self.node.getClient().url + ) + self.Miner.miner_until_tx_committed(self.node, father_tx_hash) + + tx = self.Tx.build_send_transfer_self_tx_with_input( + [father_tx_hash], + ["0x0"], + self.Config.ACCOUNT_PRIVATE_1, + output_count=15, + fee=15000, + api_url=self.node.getClient().url, + dep_cells=[ + {"tx_hash": self.ipc_test_with_spawn_contract_tx_hash, "index_hex": hex(0)}, + ], + ) + result = self.node.getClient().test_tx_pool_accept(tx, "passthrough") + print("result:", result) + # + ipc_script_locator = { + 'out_point': { + "index": "0x0", + "tx_hash": self.ipc_test_contract_tx_hash + }, + } + ipc_req = { + 'version': '0x0', + 'method_id': '0x0', + 'payload_format': 'json', + 'payload': { + 'SyscallLoadScript': {}, + }, + } + ipc_env = { + 'tx': tx, + 'script_group_type': 'lock', + 'script_hash': account["lock_hash"] + } + ipc_call_result = self.node.getClient().ipc_call(ipc_script_locator, ipc_req, ipc_env) + assert f"490000001000000030000000310000009bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce80114000000{account['lock_arg'][2:]}" == bytearray( + ipc_call_result['payload']['SyscallLoadScript']).hex() From 7889ee7b2b9d00d554f9ac0bfc404062fe16944a Mon Sep 17 00:00:00 2001 From: gpBlockchain <744158715@qq.com> Date: Tue, 15 Apr 2025 09:49:47 +0800 Subject: [PATCH 2/3] format ipc test --- test_cases/ipc_call/test_ipc_call.py | 243 +++++++++++++++------------ 1 file changed, 133 insertions(+), 110 deletions(-) diff --git a/test_cases/ipc_call/test_ipc_call.py b/test_cases/ipc_call/test_ipc_call.py index e871403e..14bcba1f 100644 --- a/test_cases/ipc_call/test_ipc_call.py +++ b/test_cases/ipc_call/test_ipc_call.py @@ -11,7 +11,7 @@ class TestIpcCall(CkbTest): def setup_class(cls): """ 1. start node in issue/node1 - 2. miner 400 block + 2. generate 2 epoch Returns: """ @@ -21,18 +21,22 @@ def setup_class(cls): cls.CkbNodeConfigPath.CURRENT_TEST, "ipc_call/node1", 8114, 8927 ) cls.node = node1 - node1.prepare(other_ckb_config={"ckb_rpc_modules": [ - "Net", - "Pool", - "Miner", - "Chain", - "Stats", - "Subscription", - "Experiment", - "Debug", - "IntegrationTest", - "IPC" - ]}) + node1.prepare( + other_ckb_config={ + "ckb_rpc_modules": [ + "Net", + "Pool", + "Miner", + "Chain", + "Stats", + "Subscription", + "Experiment", + "Debug", + "IntegrationTest", + "IPC", + ] + } + ) node1.start() # 2. miner 400 block @@ -41,21 +45,25 @@ def setup_class(cls): time.sleep(3) cls.ipc_test_contract_tx_hash = cls.Contract.deploy_ckb_contract( cls.Config.ACCOUNT_PRIVATE_1, - f"{get_project_root()}/source/contract/ipc_test/ipc_test" + f"{get_project_root()}/source/contract/ipc_test/ipc_test", ) cls.Miner.miner_until_tx_committed(cls.node, cls.ipc_test_contract_tx_hash) cls.ipc_test_with_exec_contract_tx_hash = cls.Contract.deploy_ckb_contract( cls.Config.ACCOUNT_PRIVATE_1, - f"{get_project_root()}/source/contract/ipc_test/ipc_test_with_exec" + f"{get_project_root()}/source/contract/ipc_test/ipc_test_with_exec", + ) + cls.Miner.miner_until_tx_committed( + cls.node, cls.ipc_test_with_exec_contract_tx_hash ) - cls.Miner.miner_until_tx_committed(cls.node, cls.ipc_test_with_exec_contract_tx_hash) cls.ipc_test_with_spawn_contract_tx_hash = cls.Contract.deploy_ckb_contract( cls.Config.ACCOUNT_PRIVATE_1, - f"{get_project_root()}/source/contract/ipc_test/ipc_test_with_spawn" + f"{get_project_root()}/source/contract/ipc_test/ipc_test_with_spawn", + ) + cls.Miner.miner_until_tx_committed( + cls.node, cls.ipc_test_with_spawn_contract_tx_hash ) - cls.Miner.miner_until_tx_committed(cls.node, cls.ipc_test_with_spawn_contract_tx_hash) @classmethod def teardown_class(cls): @@ -66,30 +74,29 @@ def teardown_class(cls): def test_call_math_add(self): # deploy math contract ipc_script_locator = { - 'out_point': { - "index": "0x0", - "tx_hash": self.ipc_test_contract_tx_hash - } + "out_point": {"index": "0x0", "tx_hash": self.ipc_test_contract_tx_hash} } ipc_req = { - 'version': '0x0', - 'method_id': '0x0', - 'payload_format': 'json', - 'payload': { - 'MathAdd': {'a': 2, 'b': 1}, + "version": "0x0", + "method_id": "0x0", + "payload_format": "json", + "payload": { + "MathAdd": {"a": 2, "b": 1}, }, } ipc_ret = self.node.getClient().ipc_call(ipc_script_locator, ipc_req) - print(f'main: call result json={ipc_ret}') - assert ipc_ret['payload']['MathAdd'] == 3 + print(f"main: call result json={ipc_ret}") + assert ipc_ret["payload"]["MathAdd"] == 3 def test_math_add_with_exec(self): - account = self.Ckb_cli.util_key_info_by_private_key(self.Config.ACCOUNT_PRIVATE_1) + account = self.Ckb_cli.util_key_info_by_private_key( + self.Config.ACCOUNT_PRIVATE_1 + ) father_tx_hash = self.Ckb_cli.wallet_transfer_by_private_key( self.Config.ACCOUNT_PRIVATE_1, account["address"]["testnet"], 100000, - self.node.getClient().url + self.node.getClient().url, ) self.Miner.miner_until_tx_committed(self.node, father_tx_hash) @@ -108,35 +115,39 @@ def test_math_add_with_exec(self): print("result:", result) # ipc_script_locator = { - 'out_point': { + "out_point": { "index": "0x0", - "tx_hash": self.ipc_test_with_exec_contract_tx_hash + "tx_hash": self.ipc_test_with_exec_contract_tx_hash, }, } ipc_req = { - 'version': '0x0', - 'method_id': '0x0', - 'payload_format': 'json', - 'payload': { - 'MathAdd': {'a': 2, 'b': 1}, + "version": "0x0", + "method_id": "0x0", + "payload_format": "json", + "payload": { + "MathAdd": {"a": 2, "b": 1}, }, } ipc_env = { - 'tx': tx, - 'script_group_type': 'lock', - 'script_hash': account["lock_hash"] + "tx": tx, + "script_group_type": "lock", + "script_hash": account["lock_hash"], } - ipc_call_result = self.node.getClient().ipc_call(ipc_script_locator, ipc_req, ipc_env) + ipc_call_result = self.node.getClient().ipc_call( + ipc_script_locator, ipc_req, ipc_env + ) print("ipc_call_result:", ipc_call_result) - assert ipc_call_result['payload']['MathAdd'] == 3 + assert ipc_call_result["payload"]["MathAdd"] == 3 def test_math_add_with_spawn(self): - account = self.Ckb_cli.util_key_info_by_private_key(self.Config.ACCOUNT_PRIVATE_1) + account = self.Ckb_cli.util_key_info_by_private_key( + self.Config.ACCOUNT_PRIVATE_1 + ) father_tx_hash = self.Ckb_cli.wallet_transfer_by_private_key( self.Config.ACCOUNT_PRIVATE_1, account["address"]["testnet"], 100000, - self.node.getClient().url + self.node.getClient().url, ) self.Miner.miner_until_tx_committed(self.node, father_tx_hash) @@ -148,104 +159,112 @@ def test_math_add_with_spawn(self): fee=15000, api_url=self.node.getClient().url, dep_cells=[ - {"tx_hash": self.ipc_test_with_spawn_contract_tx_hash, "index_hex": hex(0)}, + { + "tx_hash": self.ipc_test_with_spawn_contract_tx_hash, + "index_hex": hex(0), + }, ], ) result = self.node.getClient().test_tx_pool_accept(tx, "passthrough") print("result:", result) # ipc_script_locator = { - 'out_point': { - "index": "0x0", - "tx_hash": self.ipc_test_contract_tx_hash - }, + "out_point": {"index": "0x0", "tx_hash": self.ipc_test_contract_tx_hash}, } ipc_req = { - 'version': '0x0', - 'method_id': '0x0', - 'payload_format': 'json', - 'payload': { - 'Spawn': {'s': 'Hello'}, + "version": "0x0", + "method_id": "0x0", + "payload_format": "json", + "payload": { + "Spawn": {"s": "Hello"}, }, } ipc_env = { - 'tx': tx, - 'script_group_type': 'lock', - 'script_hash': account["lock_hash"] + "tx": tx, + "script_group_type": "lock", + "script_hash": account["lock_hash"], } - ipc_call_result = self.node.getClient().ipc_call(ipc_script_locator, ipc_req, ipc_env) + ipc_call_result = self.node.getClient().ipc_call( + ipc_script_locator, ipc_req, ipc_env + ) print("ipc_call_result:", ipc_call_result) - assert ipc_call_result['payload']['Spawn'] == 'Hello' + assert ipc_call_result["payload"]["Spawn"] == "Hello" def test_math_add_with_hex(self): ipc_script_locator = { - 'out_point': { - "index": "0x0", - "tx_hash": self.ipc_test_contract_tx_hash - }, + "out_point": {"index": "0x0", "tx_hash": self.ipc_test_contract_tx_hash}, } ipc_req = { - 'version': '0x0', - 'method_id': '0x0', - 'payload_format': 'hex', - 'payload': '0x' + bytearray(json.dumps({ - 'MathAdd': {'a': 2, 'b': 1}, - }).encode()).hex(), + "version": "0x0", + "method_id": "0x0", + "payload_format": "hex", + "payload": "0x" + + bytearray( + json.dumps( + { + "MathAdd": {"a": 2, "b": 1}, + } + ).encode() + ).hex(), } ipc_ret = self.node.getClient().ipc_call(ipc_script_locator, ipc_req) - print(f'main: call result data={ipc_ret}') - assert json.loads(bytearray.fromhex(ipc_ret['payload'][2:]).decode())['MathAdd'] == 3 + print(f"main: call result data={ipc_ret}") + assert ( + json.loads(bytearray.fromhex(ipc_ret["payload"][2:]).decode())["MathAdd"] + == 3 + ) def test_math_add_with_type_id_args(self): tx = self.node.getClient().get_transaction(self.ipc_test_contract_tx_hash) ipc_script_locator = { - 'type_id_args': tx["transaction"]["outputs"][0]["type"]["args"], + "type_id_args": tx["transaction"]["outputs"][0]["type"]["args"], } ipc_req = { - 'version': '0x0', - 'method_id': '0x0', - 'payload_format': 'json', - 'payload': { - 'MathAdd': {'a': 2, 'b': 1}, + "version": "0x0", + "method_id": "0x0", + "payload_format": "json", + "payload": { + "MathAdd": {"a": 2, "b": 1}, }, } ipc_ret = self.node.getClient().ipc_call(ipc_script_locator, ipc_req) - print(f'main: call result json={ipc_ret}') - assert ipc_ret['payload']['MathAdd'] == 3 + print(f"main: call result json={ipc_ret}") + assert ipc_ret["payload"]["MathAdd"] == 3 def test_test_call_syscall_load_script(self): tx = self.node.getClient().get_transaction(self.ipc_test_contract_tx_hash) ipc_script_locator = { - 'type_id_args': tx["transaction"]["outputs"][0]["type"]["args"], + "type_id_args": tx["transaction"]["outputs"][0]["type"]["args"], } ipc_script_locator = { - 'out_point': { - "index": "0x0", - "tx_hash": self.ipc_test_contract_tx_hash - } + "out_point": {"index": "0x0", "tx_hash": self.ipc_test_contract_tx_hash} } ipc_req = { - 'version': '0x0', - 'method_id': '0x0', - 'payload_format': 'json', - 'payload': { - 'SyscallLoadScript': {}, + "version": "0x0", + "method_id": "0x0", + "payload_format": "json", + "payload": { + "SyscallLoadScript": {}, }, } ipc_ret = self.node.getClient().ipc_call(ipc_script_locator, ipc_req) # https://explorer.nervos.org/address/ckb1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqp29j5z9tay5gqgqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqj34x52 - assert bytearray(ipc_ret['payload'][ - 'SyscallLoadScript']).hex() == "35000000100000003000000031000000b95123c71a870e3f0f74a7ee1dab8268dbfbc1407b46733ebd1b41f854b4324a0100000000" + assert ( + bytearray(ipc_ret["payload"]["SyscallLoadScript"]).hex() + == "35000000100000003000000031000000b95123c71a870e3f0f74a7ee1dab8268dbfbc1407b46733ebd1b41f854b4324a0100000000" + ) def test_test_call_syscall_load_script_with_env(self): - account = self.Ckb_cli.util_key_info_by_private_key(self.Config.ACCOUNT_PRIVATE_1) + account = self.Ckb_cli.util_key_info_by_private_key( + self.Config.ACCOUNT_PRIVATE_1 + ) father_tx_hash = self.Ckb_cli.wallet_transfer_by_private_key( self.Config.ACCOUNT_PRIVATE_1, account["address"]["testnet"], 100000, - self.node.getClient().url + self.node.getClient().url, ) self.Miner.miner_until_tx_committed(self.node, father_tx_hash) @@ -257,31 +276,35 @@ def test_test_call_syscall_load_script_with_env(self): fee=15000, api_url=self.node.getClient().url, dep_cells=[ - {"tx_hash": self.ipc_test_with_spawn_contract_tx_hash, "index_hex": hex(0)}, + { + "tx_hash": self.ipc_test_with_spawn_contract_tx_hash, + "index_hex": hex(0), + }, ], ) result = self.node.getClient().test_tx_pool_accept(tx, "passthrough") print("result:", result) # ipc_script_locator = { - 'out_point': { - "index": "0x0", - "tx_hash": self.ipc_test_contract_tx_hash - }, + "out_point": {"index": "0x0", "tx_hash": self.ipc_test_contract_tx_hash}, } ipc_req = { - 'version': '0x0', - 'method_id': '0x0', - 'payload_format': 'json', - 'payload': { - 'SyscallLoadScript': {}, + "version": "0x0", + "method_id": "0x0", + "payload_format": "json", + "payload": { + "SyscallLoadScript": {}, }, } ipc_env = { - 'tx': tx, - 'script_group_type': 'lock', - 'script_hash': account["lock_hash"] + "tx": tx, + "script_group_type": "lock", + "script_hash": account["lock_hash"], } - ipc_call_result = self.node.getClient().ipc_call(ipc_script_locator, ipc_req, ipc_env) - assert f"490000001000000030000000310000009bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce80114000000{account['lock_arg'][2:]}" == bytearray( - ipc_call_result['payload']['SyscallLoadScript']).hex() + ipc_call_result = self.node.getClient().ipc_call( + ipc_script_locator, ipc_req, ipc_env + ) + assert ( + f"490000001000000030000000310000009bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce80114000000{account['lock_arg'][2:]}" + == bytearray(ipc_call_result["payload"]["SyscallLoadScript"]).hex() + ) From 5c90258925915f337c7aaf77f05da2ff50f63002 Mon Sep 17 00:00:00 2001 From: gpBlockchain <744158715@qq.com> Date: Fri, 18 Apr 2025 17:58:38 +0800 Subject: [PATCH 3/3] update ipc test --- framework/helper/ckb_cli.py | 22 + framework/test_node.py | 11 +- source/contract/ipc_test/ipc_test | Bin 121080 -> 183048 bytes source/contract/ipc_test/ipc_test.rs | 263 +++++ .../contract/ipc_test/ipc_test_with_exec.rs | 10 + .../contract/ipc_test/ipc_test_with_spawn.rs | 15 + test_cases/ipc_call/test_ipc_call.py | 896 ++++++++++++++++++ .../ipc_call/test_ipc_call_without_indexer.py | 88 ++ 8 files changed, 1304 insertions(+), 1 deletion(-) create mode 100644 source/contract/ipc_test/ipc_test.rs create mode 100644 source/contract/ipc_test/ipc_test_with_exec.rs create mode 100644 source/contract/ipc_test/ipc_test_with_spawn.rs create mode 100644 test_cases/ipc_call/test_ipc_call_without_indexer.py diff --git a/framework/helper/ckb_cli.py b/framework/helper/ckb_cli.py index bf5661ad..0f6da3bb 100644 --- a/framework/helper/ckb_cli.py +++ b/framework/helper/ckb_cli.py @@ -306,6 +306,28 @@ def util_key_info_by_private_key(account_private): return json.loads(run_command(cmd)) +def molecule_encode(json_map, type): + """ + cat demo.json + {"args": "0x8883a512ee2383c01574a328f60eeccbb4d78240", "code_hash": "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8", "hash_type": "type"} + ckb-cli molecule encode --type Script --json-path demo.json --local-only + 0x490000001000000030000000310000009bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce801140000008883a512ee2383c01574a328f60eeccbb4d78240 + + Args: + json_map: + type: + + Returns: + + """ + json_map = json.dumps(json_map) + with open("/tmp/tmp.json", "w") as f: + f.write(json_map) + cmd = f"{cli_path} molecule encode --type {type} --json-path /tmp/tmp.json --local-only" + ret = run_command(cmd) + return ret.replace("\n", "").replace(" ", "") + + def tx_init(tx_file, api_url="http://127.0.0.1:8114"): """ ./ckb-cli tx init --tx-file tx.txt diff --git a/framework/test_node.py b/framework/test_node.py index 2e5b32b7..52781f89 100644 --- a/framework/test_node.py +++ b/framework/test_node.py @@ -18,7 +18,7 @@ class CkbNodeConfigPath(Enum): "source/template/ckb/v120/ckb.toml.j2", "source/template/ckb/v120/ckb-miner.toml.j2", "source/template/ckb/v120/specs/dev.toml", - "download/0.120.0", + "download/0.202.0", ) TESTNET = ( "source/template/ckb/v120/ckb.toml.j2", @@ -262,6 +262,15 @@ def start(self): # //todo replace by rpc time.sleep(3) + def start_without_indexer(self): + self.ckb_pid = run_command( + "cd {ckb_dir} && ./ckb run --skip-spec-check > node.log 2>&1 &".format( + ckb_dir=self.ckb_dir + ) + ) + # //todo replace by rpc + time.sleep(3) + def startWithRichIndexer(self): """ support richIndexer diff --git a/source/contract/ipc_test/ipc_test b/source/contract/ipc_test/ipc_test index d6a5a039788ed7fdf5ee263078c3c571f693943c..9d7d861c9f17b8c59c6d96d42ce0700a2f7f56c1 100755 GIT binary patch delta 102786 zcmce94Ompw*8e_d<_t3k3Jwh7R|6xYn1p=!nGMPrmCVeWcJr1E4ntxps9;*z0mng6 zG4zOJWsN9ARHh+nmWd^%-s+k+t-MyFh?#v^S53?Ezt-7%m|+~Q-S>T;|9KwVXaDwE zYp=cb+TZ((SGEN$Ti2$2CXF~l#U{1<--i4D zoIHtil=1HWQnCB~OM05GL`W0U^x%1Ffi>U#xp3r7=y%*CUC9UXCmm%t^(F%D^Gk1H z@#!plyf^iT`k!clPO|Vj7Mg$N2El?aX5o`8e4Ekb zu=q+AKmBj2z|e~{eDx9yJ746K{7J=S3bbpYKaU z7YlpeM&q7vvmaj9SE2-yf2A26=}O~Czti{x7S3hqJ@qs_fralf`qW5@uVQq&B4|9< z6KCl=3>5!}#Scpi_?3lU`o%qXcZPowLj~+&b!%nu-mw&amBnYUcm)eHS$L9#R~VhN zg8`)sILgAe`%r;u6Aibs_%0T{%EAv=c!Y&KqrX|WmC{S(!0j}H1xYmgfyGa-a45q) z>7H;r!!w6azS5!plMwu`BS!20N-!ba|BOQD{~iVQ{|__tSfG0*wZK*uPG#W|7ACRq z01Hn-sICi z1;DZG_XvPvcN^-(`x8&b(U4&DCbZ$-f`0uKTu#s?@|HwpS};MYv`-~Z2%&b%Q9weHVCIqn@BTQ>Xv_*O zch!~hokQhkb?@-oLggvJPw`_q%O`@@B_HfeWi4W|P)<1f`QzDuq3sTKma98icnHpS z8sGghE#;mMDfn!Ks18D?;E5q4V$5MQIYvn&B#MRE#(DNRMfTY?d3Wd|a_3O(;N0}o zhjX$Evl(tLV)49`WChO~m`>9R=PF?li_6B)ZbNe!5j7H2r7eGE(X83VB8EeDg>&;} zKa$6UinDF`IS^kSCQk`XNTj*TS*s4p6}Hh+^9u8`2MkP1N*tJa`@Fff+h^uYOPo6oIE@ih+Cwa# zFCaw3A0G=~AUq3k`5{e~Jq{Rwn?)eot^*KZ23-YG(SEO`i;Bg*Kd#E!=mJ_;fYCBMm6fu zX@6NbPnBcub}YZ>Dlw9%NN2cRPIDxc66P@KOHTf=o;UP{7C)6zfb!J)+FKbwx=Sn zx!`m1wzeMSN?Xh4-)MUsI}DeIg&+CW$Zg_BXL!bg~ys z^uEsU5}fwFKI?sb!AtwD7oF`ze{L(7sx#Q;Tm6836ME7j#L}XZ4G?yRKYx6eoDp%0 zMA&fapSlw`!~k54fF%aNw*xjj0Nwyt=Ky#eU`Yg~0R9=*(1aWCJsk-8C*at3`pfwo zuv$Na1}TfDq1uz?{PaDDUt`%7aHWX zrQ|_hsifr5U|N3uOeJoco=ry?7&eM*QlW8Ve$nil?70j7g7HEH^#_fQeD1o1x;oBZ@R>jB;raHt^Psb#ozDWL=TP2l(D5iQdDzjkLFo_MvJ0|p zd4)>H^Dymi+ENvTmDseI`L;(Nwl65O&qncb-^gAPc3bV0M+CaIw*HL0-)*0TkkVBu zFONEspw@bL(UXK@%t zlqcCQeF%%|So(r)l%MSfk&!ID6HC9_kN#j3hxKnh2`w7N7v@JiVYEORf zN;y(IS}Jb)1LMKc$LmnO;upXb+ZOT9$=ZkNI0$)e7%qXef193c2=$jh$fr!k2$a!D z$%?umuq$dPt_YDRCCz7aXU1)K#$e{8hoY$}RyM!LXW`>4e3+$|vG`gRZeZanEZoIH zkGww_O5|pQGnfMNS@>2IRrnd^;k#IPh=s>k_!*tnzgfCZftCDku)xg(_@{f~U71tXPJSDJehLbaY{5gi3lPLWRg&Ov4Ad0J$ z%ZUxUW6$cO^}}d7E{*VciN!tht-RUuvuEbz7~$U{`%okKjHTlS13v!rRt1HFI5wJj z=5gBLG#~meA-7KgtIfMzzGXnRl*H0<8804;M8ms3{tMtS0r1}d$N8l{J%KidD=dGU z2i!-_DB{Vu6C@-AVCVuk?w`}UJLY*0r1xV#}ze`FSTX70}`;7{WJa?a8%eI|0m$R1K@aY6G)-!fT!F*4~-Bl zGUA2=$P{o~yZUE50&raG`s0%U50vo?z;XKGPd^>-Xlw_?BN`?SG^ph(X-3(&68_RB z%kQM=x{{_$&>5bGm4Cr8sQwd;?616UyXUjYxK z5Fb!Z!`VR-6QtpDsEr;0UVN}wV4nW?zz%RT;Am5S`Ygb(tp>t<=o@xUyPcDAljnK1 zKj%?(Jf^``rF3O}_@jUu;E(v>3jjhB_~Y1j2ck#s3CD``XQ&4V?ck5U1Q6QZA72Yl zpp2gfJdm7M0ayB5C;-~L%^95V9*2Nm$yNY_8Dk3=1_paLZ#Hg^&&#tZwks}dUys=O zF<*Z?PR@8VTADXKFSpP*!kCf_Bsb7t1I9Y?=M@3N!vJN3#GO}TZg$>Gd(Kd!BF~=l z@Vuf~#^HD17XHwov$7XFtc)^!`x&$68R2Z8O`Z{i;A4TmKp8zG@5{-Nzqj=dKT<@C zHC>?x3t%h1`?*mXE}UH zGOFT_W5zK7@JWgtAI0uwKq_v61)ymJERf8jfCrMf7jUezW#2>Z2haE)Xh>MtmxUj& z^ffsQ_=ts>EIiA?i;VCDi#M_OITr3`_;wcW$>Mb^z7pf|tk52}rT;`#*~-Fhj3V2J z`)~H_+1WQ8yKbwEtYRsQ&wBAV9?FlLmCUVN- z&zC>jZp_a$-eycp${U-gi?RRqF^1CG6eKmF+r=)Z*O#1`S1w%wkW*L~TOw3K;(4R#}{(m&Poj#MlwzgM_Gm_>5e*|W3! zsc^}JW34}a7vOOL@V^1hjC^=@E=o<#SAu8r6O;XgtZXBO7kE4tDTnCoig5YY{HZti z-daeeI>~bj#$z7u7R28m{6(Phv3HyBSG?Ta=aeQ_EP*&YGn9V`nF}F$s6W2E4VRD3 z88LEJd2@O zV#z1LghakJ?;hD0td{>iZ$JnF>8b2E_R72h{>i2CjKUacBy8x1#NYhs>^95Cg_Ue!ONMSx>Q ze^E|~y}J6-xxtSE@gqJsfLyl(34H=2oB}+(101WsKjYItKd1v7+oM1I7eJ2%lG<#= z3gu6D53JP#l?d@bB|n{iKz5#F%@L?VtR~sJZ!-PO3vjC3EZvPArPY8gI z2K>$r@cw={=1;}|1Dei11H^G%9|(^RfSZ||fc6hSKd&d)A7?-Q89)LtcYp_S#zLSE zq$uKn6fFQ83k*}3#bE~3XXz?=UQv_g{mL~a=WrECP5ao|g1bi&uV^~p+nyHH4jih0pQ8dhAp+Em- z;76bI!{r|zo5Oc|TAsFGgw*Y6S`r&8$$KCX2O@v`1Hf^@=#PKd0sU_s;Adf?juvEc z@~SIX-EfJWWc+;8_|Rl`L6F>nIb>AMtq{{;*~Gs5M9*z7(2f40}#lG|sGw#H?EKYb|RShN1PxdZ&Q_VVTYWkdMEFUa-FMs)WV z@db#WC6oEG5jSX>0=;J-jnV-Rq|wX{@D{+w2PgsF5zX@A^4_u``~{c%Ygsx5$;(Gz zFn9TQ4BlOy&R^Lm{|Z6hYB_mDI&ZC(XRJuqJyQ*ZfTxchq8Dq6-oN~ zm2K!ta@UIVt}aFft2E`=@lwN-ibQVOxjHKD7KY<=4MhjSaqZ!ci!c|$Zowa)*M`gI zS0^TyzD%>h=>|Suu|sc|TPn{LzZzcqvYfTXGV(LV2CH)AX<>1+2R`O-DppIQL|0Ga zkh$`Jn4@drWBtWg8JWizK-OJO9?EO|tCH%pCULU2}vy{)^xp;~@N=-z-IG{A%A zz-I#d;d{eY`SJDXeAqVm4G6|;lh3c8E{92xqh{sj(DSFG+bE}}{&~<7k?g`kJ6xzV z7Umn_wtilY-8gNb@p1dyd`QDb`$oguXP2v@V}FBp3Mum!sFe5;(!k=a}C+~crm%Q}_wdyJ5Jw~_; zGs~57_QoDT=vGtLaPsvRda3>j;Vm!rQjLf3P6$7P@ZlHZRL{$ty!6EZsx_4$>BSgf zISkKMIb&0gPOv;8J;B@GU564PWn-N>csRu028y>i`O6m!@^F_{b>B0bJlZu-m0QEf zPeAzWR!)B1HBj^TPLBMcl6PTc|%I|=U>A=RiD>>7)WYvb+--f4V?BfXXM z;SlQ$vHKuBD(FFoO?-!wRn;-NCGdV3Qbx+Ns(T3C_Hras9#9>n+Yk6~hz-S9&>4tL z-pk1=s-uI{(8|`q`z!F?2i{+W_rJqCE}{-Jaq_qDo&)cOeVp8B(}197;C<`6P|!^= zK~3;}1>PUo6sP$P-mkqUuh|r@=?1>!Iv~HZDR!U{N}dVPXAgpFK(0{XNm*FoWvVr5 zSx~AStuq~IKHx|!S|<`+co`ti15$uqIkIyxCpT@5lHHrsy6uqS{?OxUpFr#k#L#kJ z*Uf6pMFo))HYaHMz>eMYf5=ldC+hwRuTwteNDerGQGm$0kL4Yk6_IW^Z0EwVh0q-)_+@f$ELE00vuJsXpf%XC*BLP`Xb+pQJ zHbsq7nq5!mkzN1d$VWg$CU-XaHYT*|a7Z72k|Rejoi}$5^C7_W2O<5BlhhNQg!d6& zDDVBAhxeyo)?o!2uzrCL8-8;@-iGvdAYCgzwE0%WCKmu%^A$(xRiQv3W|i zyp*6b!|Sp$==>h?LO^oP(&i8qycS~jLF`vv{;1lZ+YZshZ#Z%WtQDpE1Y$o!YywD* z(p-dC?6-14U2jb{=!>U(Cy%d-*JQ%$XWz?@*Tn|Sgx8}#V%v_^t%Uave&on5MbN7d z%eeqHL=_doegH`3Pf$!~a8OJu_*gdy?Q#VY7F^_%&K45dbyAq#ErgI&{~>)aq;LKY z>3@av-GS4`D;2u{2#y3MP|}})^t1mVeHWx(gY>~za_KXOMZo2x`Jg%!r-JjTPo=n! zKI1>6cY~>X6Qoykz&{w$lP-6dKAZd%2=MFh?>Z2$0Mcjv!jYc?q#FTy2GU1df!0e~ zz=ScLK7jAhDf z*YuP&)UyjzA*Anuo)ewVx8os3z$O5}47l>OOaAGV9=bw^{Q)t95_<+>7a-Oh^OoJO zXoKEHaVlQ^@s(aWH@tUM^W>aDs}6(i3SyMAFT@T)tgjsYT2CEBK7hz7Xn3!5*A+lC zJ;+137GixN_JJa07sQT0>@dcHPC{(HmY1bhd+BiPVTBuLiu|BH5S!SE>M;i1pMsR5 z3eQZ4-4;SqD&YOEA)cJJLo5qoR-_C23}U4ayA5mrhDnmQz7nCk2H+|H`zp#9VPd$3 zu}8@TuXPIAO32s6=D*8}U#kg%>vLZhTVIzGx7-;7?fvUwV|Tf5i+yz3_3L`UX{&N0 zX8s^bi3>SZ7?wJ7Wubzva$#Dril#MZ(6r{eylF5d8ebpK1%4qw_0IksRT%Ewze9fT z^_|fdP>15z5=ys}_9bsP(@U$|3i6qJ+t%cXqxMjt&R?hkO${_IT%mE}jwlfo6b`ZU zZ7luYEWVZTUuN;w<*i$v4uYQ|P^Hy8BU`qW)511wlTU2BS5lNAEBuuqJ58xClTgu= z^fEbJFtV_^kY5;+y|}nhOgvMi@H8#^X=h(jTUr%{%9G`>_6L3+X-6(ol8*eelWNiY zIn|i8HaiRt?h4ux`#SbAMZTQWEk_`5{k_Y_U*y- zOIohje~+4k#zLw?G!!%p;07u6=(Y{1D-lhplXy-%Z56<1X<~wVq>~CG zHWU`@^wv9B)$qyoE?hKqf_r@OI-r$F7iY5g zB>BM|PDv5!y3;35MX2jhsu|@GvYE`W56vk(Q|*qwmUU(P#fcXte^KvD%19Q-WI-HquQ?HRE;`fi`q=aJF6z3>P_P$Rbv^6 ztyBm}BT+Rj=N*l~yr4GiDkHWzjUkRS9Z9TIi2?zS{#{>msY{J$Ypn@JlVvfJHKop~ z(+d}`vDAXbV23BODsN`Qf_XIvmBdu+B%me_ic7qHNd!?c`>k0Wmo>1iL2v>=rH8~2qtuyQcLY)HM7i&qqx&nkdwVbO(w;b< z+^pCAbF=oBpMCT0@PA*w{s`Gr$c>It-c*J1l{b6G+SbwNsG$s=6BUPTQOsc;%E^Ow zi`4C17yQlS>LIV&ZR(=*y0>XYqely*-%gCMWF~ z(hGVXc}a7otiAAC6_(r)H@r0q-(-ho5IAT;w8b6;!| zEEAolS<5!Qs2U#3*>@rmTS{BIdjn#XdllV;)^KVN<8xV+vgXot1r2g)W;;J}RyAP{ zMyPH<%__t`Dy69F1NZm3@p1yfVK(E3=6Mb;Ga)y^s-%5)EkcUBkhg{N~w zXuLz_Xs*RxiNBb2Vf=R!<$Lx`r1o$fk?Z!!ccE2n#gr6;&JtZH3p~o0ih}q+I%L|DY!9CCx?huD16=`TV{{rJcy>|ifF zSM{CD#Y?87lDka9SC2If-Z<8jx^3*1{OcS_>rP$RF`5x$=YLwo=FD}ud; z&^S8bC$B2j)2IqnSFa9L}cDxyP8^uIG#DRAP9tOC z58kOtD@leym21%z{hn`38mk(P@eq!RnULv7T}f729m7J%`h8QKi!0aWtUp{aos}@| zOXf;VtrQXapesS!R~*552CZDP7xRGf8z+pi6-t|-T*g%0%KG)ropO&0{cRCXfWBel zO~W%%Oi9^krc^G~l*Ajk1UX*Z_YBEY=H32B^&VjF~d;%F9#?T0-i z<@noU!Vd^Si{X_&@{JdgZEG7rW(6!K1seOjfh z(8)pdjFTfS^#AY`S?dCKz?tG&$dD;rg3W}N?fv1yEC5C9iXfS>8knt;2P#$bz zP)W$F@C2qNL%|lwj?@yM0ovh8Mi#xmjR9Uu-_Fp_ShO0`@Qs$|w9i(T4-xf2oCV9| zEztoxW^3&ST~qRN+7s1b22Y9OogSsEx5*!U6fGs0)3gS?hJ?ZTLTSY0EVySFWS#k( z_Iz~+q`_VYv)A}GZdYGbI+v*z!on2qNh+Rkq6}0VSv5f!-|klp<3>RdMp74VveBNz zI!D!XbuhJT^Y_@BNVI0%>l2oP%0_E8SSw#^s3IuFT!5B9=Qd`8{ZbrhTnadBGI|M? z-!ym|_}D&+Dd}U2)*uUxru$Eywb<*=OVvMwE4sW~>vcNuq_5Li zpN~{1YEM_6jjSF2y{xSW;KT_l7e$tdwwy*#&3tQ{1&?AMsaJ<5V-cJBs>HRNLtMhC zESoupWjhxu33r!|)ST8#T6J%^L;M61_CvxMPBr=>S1o*8{;pKyFYV zRZ##0sDZ8z(4~_0{PzK#33v|h7v9JZPVKRb`!HH2TEd#|af4afmFlKe8TmiAiUejI zyb%PnH%t3c-P9_m!2irD64qw{X`96s5lr&KD(2emgD}Z>`wY9ve2KO2xUEicB5aZDgR#q&sQ1ietzLzCG?7{$?^U6Zpad^K?m0Dtw zg{?s**ai^9`tvmH*aKj6RH;H9qNtAOrfz_LqAJZF-{Q7B483|=^Udq z478;7qHvS0ehJpp1c9;$pJ@#lmhGW5)g44r3sm40$qo_bR%yXRu-Fzi^C5X**|vxs zpsLFlW=~uvYnpfyISvYie1lX~XcMP>WE?A;@wg*Z3MMP3FSF8e7<(?u@s`jjtURYm z4<=KbrS>YbGNpNlX6|}Il^RT7H0={IU26r`>_hpByK5DG%ognsat^aCgYs`nrkSS= zgVHOOwSI&$LL?ACncY#8nVMH&hRnx1Yn?Rnrb#q&_dG{>Nt|jB7ffy$ z6r2Mzx6|~-RIOpG$K;7nHMgn;mE20xB2y);0qR<*54VwJFbkObLI(XPkuzCq7~;vG zH_PBr5R?Fd5||PLwT62cjkPDGvF2ej)@EZR(Hxr6RH4AN?x&Ja=1b=ru>=+Wz#}k(EPN{-f*9%2%m~ZjM07PQ0=k+$Bt#o> z?sSoDElm8vD)cB3%eo5jATOl-{ zFmq>B+H%-Eti{!lvgzr58_hRmt!eObqS{@iv>Mf0u<58&k}Cv_saG0YGwgO#Tl%UP z$F()P7kyNeATtu|tD|EW)lnOK!U?^%qNOqG=bVW-U5jL4U6ul_8YF0)XU`utloI6(q!Pv@*UDR{PYVFU7AlNxN1M#}1tuR}iw$3Sv1+ zjHf~V8)mT<$L6sbXhIfMS|{x1);5!u?}~I`U-$A|N^citj=izB>qNU9OO>)ZZS4Xw zX)9Q&O6^3@8C!IX;NX&Pe+T{5&`#vJW0|BM9b(jH`|CAfw=Q2`!$W~eHNV{6kk-gI zuFjgC;uKWFoSV&hgPW`CgfQS}z=iBD2Qx9{hwVL@UrOiACVl^swGdBnZ z)u9skQtK_%m5u|E1edAtk2R=U`Bu0u2K?N%WSzJg8swHGvXG>)U9MDvHLrupsl8Y}*bnaLp8#JmzYZ^)os^-P|APKcQ%SXOoF=VWXUFQIeRTd5DX4qZ1srVRd zS2vT>XP$GyamQ~(oId2zb$zQ^6=FDDX)3NEg6p};2vS|CVk+rFTCZyj(<(PX?~j9R z?DtCBf-#_B$%+iFyk$n^RBTtsA6p5ocm#f)8#a@cf+JwFVm0IVL>JUT8mIbn6KpVP zU#sGeP^-#Tgms38wZ&LvB6)i0xvn25ociYDv}6W09nx=91BIKmfBx539$Rl)B|-o%|s7RJ>tDRD)P(_?i!Udel^qL~*GaDQOj?L0w@^(G+LsR-Iq5Ob4?hr5iV&`ypq1PUoU=y=mP2HcY}{ zoWNOOQ>ZddgzhjuaA*>A_OAgZ6-Rn|_};2D1fXNZPGncc zim-hvQ$icfFE{C!KzFoPUJM&C+$a1;jAFwk7%zmo^%80~IfU2MDSAE>0t0F&=wkadWTdpd65M052)kr54n>9Mr`znugXKtp56(^5(afi<$(r6EXjE?r zjb?eBp!DtQc>SjaZr|ePjvGirts%zoz6N#`4MeYo&MRmszkb7k$bG91RI1*W=wM=k zL1>fer(~0G3I?QY$s5G8^KC!Xs)q@JwzQ~0*uj@TpD3srG&{@<&UHK;j6gu!V3Z=X z^7hrV_uH0SE=F1+UCBS+nekBY;cA;$;vi++QAL)V( zePXFpS?KVpU)g#chnY<!!T5&E;lTWsC}{gxY=1QOg@MYqLOxdqG zwd9!!(9ucjXY3_;LAD^Ar+FvWbXnPcCU9wd+u(HGV{DtMaju`S+uIrr{Ph|sNpn8e zHg5;75#ZvDN?+94CB4!ivN;-z={VE~qA;$XD|8%`_1ESl1{IjaidoiUu6ZA zJaeA?V}op=jnm_2-mI+6X3uzGJlR%OZDZ~YWd+F_4&qQ0S{`b#NwrM!1kEO{ndmhW zf=m#?`p+1I^EIe%Wf8hsNUNhv;TGGIwFOkHRfB6lm;WD#nw7m@tirZzh$v z;`bD2vrc0ZZaRsRoJFag@|geOVYYFN58hB77-~&ME*aJ|THEFA&>O5y7A*T*&mG%N z-uzxZmP6!LA;bi;0{PNKmFyI>I784`7S^$eH>*_7tZ4^Gs3lU%arN<+-^z{5UVUS| z>&CVGOMN=B@www_PQNZwg@VgZZ!4D1symxtu9vq)uhBp@`;sv`oWg`!ggSZMcK*^D zxm42yX?90^Qz4hCfyzT~f@Y|w2lU~R1r}h+=wH0oQ+mfMhcq@_%ENhl)GLt*pLlr$F+%ZHo_F-&#R zn;OMu>zCL?+Zosi3`>giOtiRi+@gT?n}uE-TM0{P&++*O)Ti&LbEMI!sN#5qwd0Wk zsg*{oxF7YN2|=4A#jV_md#x5sgLivZ0o%(2X!|2NwnFm&j}_dncx-3WG!DPPbHF9z zaUV(PW6TeQx9Te|-c@h6^=Ra!wg&Q8t(j%jUc+_@hMa@eftv?SxOqU5ycRm5Q4Ljd zT5F0RX4vv7L5YbzwjpmFU8`2w2J9X1m?z8+RZwM8a>wPf$9l>~UT7;{P-D^!<%5=S z6j%0&ADN$PqgBHc&3)%N!2&gJM1`%hLZ;`tZ~5AbNamRcJ^ZZ~GCqpP^&ciWt8w>3 zVRYwV{R4VIut4b*%r$)_(0%o@m$Ud0h1(Z<>4+WZF5I&m za*$AOg|Nw{WO3og7rlhV(~vNKqZhGeBl3?;sGNt>Xl0ylcm-!*kIxu_>tFMI2zB|FSD5iHDC{3_4CSdgG7*v6zw*_-X#y+vB`;m^JxG`Tix;tu zS7crF5*^y&}YK_Z{!XiU{uKT^}g|uA=6{v_K!!Yri_s31AOD=km;ZM z#_tT7-nuQ^OFshmcl#E?bq5yW&9*!wIH(^E26DgnreH}}LTzCk7VAXpmM^@bj6*^6 zj##JC(5S_RV2c;FMYd(<9uzYD>aK9OtVHFw)3GNUxPxwP6@9vlkF%7&+HNaX!t)4a z@2lwJWqhQi>Ihz~D1I1^9bmf14i-E;`j+#{_@mgg6e{CGuhmiBnj_2jftHx|qT3`p z|AD6>l*j#mB3acKL60mXujmRM4aJs?r(h5J!*#i~RhphV>`}+?_L8%+V4(+8?vFmM zR?bBSktiMIXm)T9e;5%4;MCJc=-rh`BvPyD1M}Rt?l9xpt24%?Rpjz;w*6U zmX4j9RGFOR^UQG3)_pU-E;s(y^@pj_q6#k(dCt{f(>~d@SQ7z<(aAJj61kGPJK%Ib zJQLQp7MhjYY9b|>+U_!(;8ZD^TK}~!*CR6S53fk;J1Fw|!(M^nHIJ2CZ+}zQ?sQ41 z=E_~@1++5E8OJ58XLTd*f3y@@zU6$VrKO;jr8IRoC>iXl!R#%)8_zD|A#24oU0sgb zUu%rQxq=|Vosw(R{OjkLQ0`cL<>g1Wi8fm!i4zw^ZWL|b)R#O4AZQ4_644OqrPk7$TU-pERmmalpZoBPHH==MH%f5E8fLy9ZjX6MgpZwKC~T9Xn-~`%fpIe2 ze}rX1BasE1`D1uQgWEB`Pd25VfZO&b;QFV5n1=5rroksjC>%*2=1r;fylF6m!%x7W z?FqFhHCPQ3J9UD6QKV^jy;@(X;qmmqlvJW<-s zAXBG$4Y0$(aj;eoCt|>^H4Rqc!A`i&wL2J6LQKPhg8>Z&Ng<}e^&$F73tR|<_oRd_ z`pEfr0p8iv_i$%Z_u$TYy!zFtzO(KwTjvlW8>A-*tK)qcaM6f$6eYUMPw;?0?`rdT|}hwAb> z!XHSF@TDX;!(XoBZJ*%LTJew>^!%RI*)FFzzLZvoIVWLBbSsD(BxFU4x>_MK7L=_O%4=3D z#vkS_FD>pIYJ9N0G{bIlbmChMbeg7IoKOtk>~e}znc>~zxYm3!!77Nc7sg*a>Q4Bs z)(L6U2d)QF)z=S-wQy>fjIOI(`XgJPQVqo;doCs69A5h}OB!$)x-MCPyK|C~>#%PleuSivkTepKMnTf3T|KldG(}^tKYikC{rT#m zEkBH$|HjW-F4x+({5oy^8-FCWO#S+_J@MPAKgR!i;x7ryN7@s9)5FO|!u8WF^93r2hcvRLD3l2n7;cn~$UIiL zmZemSb1A!)rKGq<3qDQs#1D|c7vLqC$Dvi!vKdlSXSigPxmvXGjeqEa!ZRJ>BXGQR zKU`264F_}K7L!AM_0w2Mm0ps$sdy)B6n+Yu0&uSl?zAbRzlC1qbWQm@6XrtCYW@h{ z>K$aQ&m6bIwEbHzVy*(@$enI4VqAyFUblDtPbyc!%<}2w-bt-nl5w(`zrxGbv<5~0 z<0~)XT8+q$*Ou`xNm0i5;tE9afAZB4@_e{vt{e5km(=#OvkO|A=67>w(MEJ zSyzH8M;>mG1WP@e`I=Y6I}zObrB@7D4(c7b4g;%4uzMLIFT&vLL7J8-$R)hM{7sz+ zF2Z6}z}ALYndi;HYOsX}UE!KS=Bdqa2PjRS+Ji*Gt?-SReWl)Xl2tq(ug)W*@`aKM zS*;uE%ko~ukHLVD(UEyK(z#!#FI&db55ioA4V&pLV^u2NGLCh&-7;>*iL5;vrn!m_ zHN`{$BEi*FE4yZ_z*Zx|a9@9_K<~LKD7od(SiLjvx<0L$$j*h=Qv{cJR(Vw`&UeH- zI^Q|5V*GO6*)K~k%%F6_A9Iy2y4D}j&ofAIN`FzigybaYqKe4a6BQ@+(sg$E-yz>E3sz2>9ZSho8 zU>WbNfa0=xyjW_nH@3^r#WLL3T<441U!-{Ji>KP*ts5Bq3;SH{=${8%0?k{Wx3^1Z zeU>pim(fm;eLc%yeN8*OwTjU{<7_9#zK+qa+t?0oUCZbzg*vI7MlxfNW7=o1nlY?F z2W1XhT3-fTDy#sM8DTQ@n&x3JaZ^0Tcnv>Gi~b%iIB-A#pKVc!njszv@+%;C2hKT| zPP1XHqOcZU*)vwyf8f!M9L_nC)*!kY6>3lQb=KmGd&YLe+dP8u9(eSQEZ#XF3;aK@ zw>B%8P;b4rL!Y*rQ5>a8>yS!NGNn|L+EYnB4XI|BSJ>G0WIj~l5HHoh4yjtxy;K<; zQaMv4FWHa|$>Nf|RCjbp)qJ~`>h2Dy>;t@1VwPU&!2CjgFWDSu?YNYNWpukw8NA;c zm@mVJA9O7}!x?`(Cmq(&whNnk({=P=Tt~Z<8vyfQ9erv^ymt*PvDN77xQGrHZM|>_ z4Xa(H4-~rymct&W{0I8_9#}TP@|kv}p&n0e`f!5_SJ1eUzQaPZvd+YHG_;qIGPaot z?9iLedSyFxifsBJaML0GhEx;e5l#-`1m$!55V5CYN3bfP$dm-@$=4i$m5q4a7-osdFdH~iqlJ$exkfF>A|)Rg;7b@L!Up!_tFPFsF1t)xlT?j=K%MC{gGY(Q;|)Zp=cz)P4Z= zN%$}W{dmDTg?_1%Ax676>8=F2Lj#ma0{f5e;uN(qv~NWfk7>vXWbATJxurm3+_Q z$7$U9BaMrnu=H5pU0#?t8U9=CVr?&an-mG4E0NE49r%U%*lU^l8``CqlL~e zEE#{VL>Y*P+NZH7W)~iyqMSiglrvPZ0~=DvWiBg5?AO-H>4+lwjVRW`C1d@m;OpWv zKQeNVgD!#z%gg{*;xgL?DA-`(MCw?@&6oyTu8NzP4+vs8OL4!4<(D<$(0&%UlIx7J zapV#5US5<^So>dKqgKUm2@*z4rwOeK^_mO34?`|4No0-Sz`Ju^e3U)vJ%W7q(D1!K zXxMT;4IL9${4N@*Cb5j~*K4dka^AB>y$8R8`v@_OqlBh=X}C#b3QhB4c!;Juex>1i z8I10)aFO3f@TkAB^emb#Mo#jvgY5x|3dv(FiBg++RDY##O(tAJ@t6mcb4+GRDgB?U zX)bJUCC7a%vtcx}DdQo~-QHe#)kG>kE)Dj~+LVn=Q}Ra3$yU^EJHgJgs5dhA0_pdepNte6L!Yt<8?QjDzlhIVri##;|Es5R*&K z!kXlmF(Ny$Q(O5>W2y=UauEg;U~^LercxTJ%9S)|tl&mpP|V?=p=~*2p~q@$84GWJ zL7JBGuk;H&Y=)u+X1b7@1d{$IlS6qgv1&4$>Z7Ts&}JM!4ootUFx#N?&4m$O!7gr_fi12_^HrC@4LVXoA}1<;Qz`k=5|tG))aFaA2#Hs>siw{U0A zRvQcV(h8d6e>X^Y2`{A-uI*(Q#A8=`F`)`3zNN{FKFSa`qC)X2IWrXx^)hACv(#>xL3KXm24`z zL`-GJ$e^?ElL?aMa+iG;+vBwcnsx1f(|Di)QI*4pqa*W6-{4nA%_F)7l03Sv;M#Jy(O#TaRS^^3-+DAzn!x?@Fy<~YAm`S>F8 zg}31DSVJkQffm^J$kjo=uR;UU(x(JH#z(W#t30J&44E#zL^e5EiOJDSR$I^mTISWd zBVBWy%4NouMF+l$sT&CqNO(;1)j)O$w`ET4m-OB!ls^b-{46iR_aAuU_ADQ*e4Jva zRE?$=AFmo3mL4OUiob>}@s~)lv!A6Ur};!m+$5ul-LJiBNI?qnKKR;8ib@wv zX*N^=g`=_Akdpoi-=KMgPx)mm*Dz=&-=N;fr=-2a*RM@!+)PGPru>r0?OxZg<19&E z*O2}e{BFZre0^m~V+~2KOkCHHwgc{&$x>t-S-2)8X9tm|w5l)*M`~QxSoh>JDb8p4 zhP1VOVr4_8wY*Jug`}jtLg3S-#)aG+-;8&jfSr;Owt->1ocLYJf!(CRvYAX;m2mEk z(+e1o%+-(8s^z?<-vIc4X|WPN#x^JTM?a3!t$?()QI16xh0 z4{)ZWGB_bUM9vpv71kF9FFc=@HKTq;@S|s+=m)=K!g>n6s#uwA=@%>gfUJpA1v^8u zTM7LY6W1Out_=(6=E03`xBKOobCb^`EOAO%+YTj{ZCSD`x8EVhn;H(z7&WTh8iJO9 zCF+m0_=8MJf7bL|#=iRHNAWCCncOvvr!@BO@v6&5jH>vx$r^}c^`S}ghM4+e0|cg{;_UYqxOv@72E(-rlZ3^5j#_;FyT z`#8^UzMak+Iiq?8{_$lO+CChkRJH+atUV=&-EqsXQD2_KD^K>)t{r4>VyMBotSWe zzg9;QF2YIYmA>$uvofe1KWmMH!aXpj^kQ4rF9^njbHPrKT_4vL;BVvHs8aKMk4mjydU*X+YWk3>6g{W(8WsrWH=smG{l$S| z{S~EngOu_KbL-F5g@Im;@ZX>a;-mE!s9NF|9?|X9G9Q#fzKsjos{GX0F?sN}y@HN| z=oOYv8y@`jMb1>A>Ut5F2-35((;Hb)_Y2y}uvMySFzy_a}D;>cg2{Sd8gd>$2%pM z#OQ^%gE*Oi9hoCC{@#-rUCelx776yYlvZi1VDVZOf11T>SbPp*1ev2+Lk2=OZpP#Ves=kB_#aN zNW1ooAZnYuKQ*NiSCi-uS6cf@gdQdulVZiZ-;+h{etjfK(7He0Yf4g+eF4Q5Z}N)O ziCTAivARRctnBt%*YM_$GglQ!KkWqt+#zQ^ZYMF=DN#+WFTjo_;XaI2G{xUeYA-gN z^xC)53cp8XRI2V2Z^sj3_=5A=NPD%N&()p_ITPl-x)TrDKi?V17UpMA>1bvPQ`lxY z_mh-g-a>PPLIz+sC4;87RFg``!mFytjl|S-Gs&=Pn-1+Y8P)LHl7WO5uW2WoFyU>o zQF%|LxE?}UkPUg7IQa1*J^tDY=yP?aDNIdH1>T{-4H9@&_Y{M}Pj&w=nzS|V9rbd2{w=cYk;|dZBmN0k7 zciMCN_F@bhq1ial(&VK1*z6x^5~_ zN0cvtFVv`I=uT4(G#VT1JB-_WKJ3Ad9-^=x)>sV5ZC_4ta6YgPW_BA%qO+gtWl@)D zlNt@UvRLk{t~5#TF%=#(>9bM^eBGTVMxzSBD;k6qpa|TKs!)1Q$I-RFM=Q!WbYX%{ zAKb*lJrKCK2dkG5dzXH9SJvr^t_Aou^ey3S^V!H#tIxK5Tjo({8%bEHhY!|Om=%80 zg=)x|sU$^c%&^U@)Sx1Q4pV32$Hhvw?RxwNk0MXQ39YiRe$lxv}Hl%mC4Q@@M!GB*DSi(BN{#|yq z{+1Xhe-J}W-|~d`HD&`QS28b-!;GAbzL}f*AofjzF9s_Iz$$m*N;jbtey!^O_?+W107i^Px3; z%Ovz1;)A~T4MpueedXHDc^WVL@M6_iH5VzZc11U1D@IRt-}SObcb$oD>GChsHqptd6vZH)8vFx5XOdhC&K-}>3~A%!DjeX|?&0YzKG ze6wpg%+PkUjzbh}zQtF9>7Z=>_ubLOO0|9EGd(O&kYKs?-!BcMssFqo^^bZdT$DOf zvNKAVlePYv?n}E)%1>RqhspdqaAn*KK8|)M;LMHTe3Z=P=LfI23m0#l~W#p8r+73V4 zL7LS%i>+s~2B$mlE6aQ$EQ{dh5aHY%2cR0=RiLw}oe~dZ|BtnA4{WN)9=`V`bDO3u z4Wut9U}#N+3YAg|BI*Wg3KXco+U|nN1}-V`P(TSTD0@@d+miAov{At|6jDo71WLg- zK?w*eh%Dgx+(23u5w*A!L3w;<9=AyWcYoja{r+h)uXE0vIdkUB+?jK_uxb~5dLEi` zf&xyMp;?`wTaX%1TzSzvwF?Y+8Va8^iLwV`CQbv8t)gAya zvOj?K9!B4&D7>`b zGePsF!n?tZ{H_Gfxo&NO4vtQ3IpP^k13sjsV5N|AqI?8@7)3qb7OFmdts1*dC$b!T z{t&#hx53lQy&{}*M@dP04Jb;|Ms<0rvG7PatppXJSX# z1`%NNsL@KUi`sVBG647Eg3dMCMhtxEXM$Qd2+I0n#KsyyTKO4A^E<0ZQ%=C4>PC=+ ze(ZCq+Gqcg8|RvTM|fCORg4vJ@^R38M$vp?OL<>-GDxM`IZ2fU?$>YGgh#K?0rIb; z3INry^oqyMk5?J$&xynG?-l1Xs;1cfbWiEcL(a6|$DD1y+L8N3asy5pbHlz{(kwLgVqu z5!C^(g701@gc547+@E7h?sUS(2)*ZDJGlYd%~HY+gC;*lBO$Tdq9obvxEP;H1TyoAM;{*hjPFwm zZnL~O2#yWGLPgrN2$Wvf4f2|yu!ZcbNetB5bt!Dafp^gw^VKPKO+jZ(sLQ4+aMncL zi+G<978LD1HA7esCgk<6spy)$l>Igdr)AK^-o84ZkBEoquFc+))KRVdZg6kt6>$1&OQ1>tK99$ZCx&wXg3D3(#DRhY%Qaz#;3`h|7XoKw${x7vt(BKN3pwUQn01 z7jPTkJR!zrK;8~5hKR`15iHP6`Ps+t29qy_}(0MeG``Rb{nFfWemjPqAleMc6Vov>=F zOl!hw8p)Bpb56wFhea5(oR%+A%lqSD4?fo3{WZVQ{Rde0Ga|a5bW`_-{$}@`M5WFq z-6y|;vq<+TIe-3*?vqmU{0`j@MRcE*&%3GnPpjR-y>kw`srz%)a(c>Qh3?ZaS@;{> z&tTo}^uK6zVi}U1+%?QaW_A)8=laCK^>o$j1TCA=ZgmpQS^f~VI$I(q;d4!4tCQ69 zK1^!%jI=uU)Dx?dPDX6u&1AhM|O@pbYnreixf#L&DSrQd&c_x76sn(nyh_pU+ z9js5CbhGtIptX!+)+gb#Wk0b#W!3zo2p@ux?2zLt)KT-3aK@AYYb0szw1v%-TUwtK zUO|NQNpgH6BjGtS;DJX6^OIDv509*5xt*Awc%GsFqH^H;!7*2CNjq70<=~~m7ml{V z;Z~KLe)NO-n165eQ@wA zA{7R*8KIgl3Lfjhao4?kZOL1whSn1`y&9|O#||t3B~6zz?)zbOT!K$f;FHR^u&ri# zvFjlW0rY171`c5C`@o)D4W|mQR_sUl=K2q&PASnDfWgG%uq}rbQ;7S1isJ)EZ3(;? zgpYLal(9cJsyRp(a`RsD7RisNn613Qrk{FxUjBl*1>(Yypfv|u8=BS5m_EUssfSOX za7&2}i@Y+rRGzi_j!U37ZT^lti%`ZkPUMG(>QKuX?oAexW4I z4i2hQ!0!p&(tu_7LM^OWA4p4)K@)|z91$LP&X<3Vm-3?oV^kt1ar?V`UoR~|UBbms zIyy>AO8NbU&JFmJvHQ|RcyQVp=YHmAjdbmpPBYxhy%=SLlv~Ti=bZT$CxvSC#waU1 zyvpS+rnod!=*=vk4bMBhQF-q{+ha%H4`-KgV&gJCoy2g?e9x4c#tyvcmBUa$RL32H> z!fNz@kKbvZ6TA1cEq`j=RB`&L1^AQRjqR-aRZWb=$a@YRd64<-?d5xqF1)@&OdxkY zCb!2y`v2bXlacrOZdASABV8kQ{L-?B4L>MU8CJ?`VcpvXn}_xt|NI+uujLA<8Q$?5 zT->LTJN|BP;i+B7QqIM0eRzj1Wm-8hEOV{Kz9&h6&oRlE2BuF>> zwtkCu`{|uww{IZ3eWJyzTBdL5QZT#2ZlBaJNAC7X4pMjfWR^M)tLiqW!!tt$-C_8R z-97~vx!b1z)!jbTVTW&}ZUdJi)vfpAu(~yGp<^GcA-cgm=;r}N)0Y^q4nPNBTL@~i zqXq~nH)??3R;=`x7D(L`i$ur4RTt9V)Pe?p!)YQ1!E*QeKPSl(Kn3;)Z2nj}ppC^U zPGc$BKtDDI=HQb|sJ<0TslR(>d5>=kTXVe|_DUaW^|WsFUuj+Rq+&&RYF(~dgDdf5 zTI*2jP%nO%Odgxi1FVnJ`@aYZr;6)S4~vF!Fow{Bw|oAB?#D0npq8QU!@jx^1c0*d&+2acN&&R<-t|;HY)5r&e43-!|TI`_4PO@utfA3Bu$^ zb^d(h#(T^`w(+Kdx9_HncmK_BBo(pop3}bZCM}#Fk`{9N&O5#T3vjYE%wDZ-ya@w2 zr8DG}svB>T7Yt!J#i8yxoLx}iJjk}&6v<$fm)wchcQG4(G3BFw2Db9tJKG+VNrx>H zZ#x00IwWuHVkVBPr}`y^6o-w~-vgRUF)Nt6ZKBlbxo2W?}v zH6g}!d&E8om&+o0qa)aMOZokqEM?pPp&5*aom~Ta4ZC8 zvt%HARgv17i>2Bc@00Q2EUBU_xzRedS2E2>xDlM8inPTSHe`O=I#$YVw2tkIBjH(Q zBKa29vDq0}iJMN;H5q%QfR4Q-=YM1D@zBd~I8VmjnResYJI6#vF4a{LOZ6PAEd9@h z$G#g{>X=S**+N`;Y$Kp zsBa5sah=CbhQ}QV;c-X8P2)~r*q@CYcmKH#tF(`txmp)Qj5}#${&VCIct@$@&Q<)E zaVM><^CHHb!h1Rr9yhvumA;D}<&#P+b0RDGM~27UdM6!sF2Q~H(hzw{r9Nz>A5^V$ z93GJjrB}d1$u1lb!S(h#07D5@dg3M#tn?VMXZj9slJce=*63okWAO5VJ#9Kz>4{CS zXlC+7wI573DsNqHvPwZ;iU%lkEB4;_#b8yN9A}`)fGg`2=p& z$9m|%IAYPek=4_KwE`>EJCipLJw%%|J+Bsk0WpI&-_P>x5&7Q7F}SYQrae9CF=yPU zrQ6VUBK#%1IeQPyw|5HXTkN=1KkG|@0tM{$Bjkj~ctTdKm5FS-$u)4D>wCacu3py8 z-p=qH0``)eo>LW5I7TNK6lB#fX*!4IR{U7|UERM9h6=Bb|F!t%iT|GT5hC32=T=mlhaBKYih^y18xjl$){ zSNJiDFD-_Ptcx!!KDSstBU}(#g>#FWg)>4k?#Ce1naeyC4MAJuyd`X+1W$*$AZ@tc z&O<~-@Ry53DGohZGfUI73=VffQD~xDS;nXDcnvgSEVo2oqMo5_E4E*p;j)I}o6aRU zHdv)keE3nRAUAc}U=8(Xx|EESA_`3F1$SAh+m|+6O>$(O%vgT7{DjN*p3e%dWn(v6Lx!f)RNMIm^l9fEmrRIA zy1B%b2t*_y5arW$X|Ye9rK0D&QWsPLsUTL3wvkc_`s0=sh_iGqyNQB1-mga(L1#dq zK?ygP*y0I-uQKe&C3QxRx5IxC;M>C8vn<6jBm+Y}E*sf75fC*OHBxYa40AgorydYR zBg4%lK^>Ivi1pDN(Z&)5B{8TQZIfsYL-Qgs1V^!uudz$(e6mfY&$LQ1qT(=p-klmV zpBUAm%5?x?HntV3@Cp~8+7E-`L~euphH^e!=+?! zEmcwi8mrdzO3-rHmdnU0XI{3xmEizZ(PC2BSt<2IqX{WwFih`bR)rGK+huu#Qx}>5 z!D)x&@)fotCTZq8q42`?V(h(bKoM7n$tkkl?~gFwZb8lhud(alH3jDhx_aw zL;7q$J8+*H&O@`-Xh5~kE-mqm22{iZ^)8ZbL&L(YOe+CZ652Y@(eQ1Oqv3mKb>{s0 zaP?NB;3wn-YCF?H;IJi3VsL||NG2?PO;gk>vEd|~0beQF34PTP(?}7HMSeS!4;7#AGs{sGP>Yd2C7!S=b z0$s+&_Z*P*f#LpeJqZ_jqFOTYFrt~QgLguIc<2uV#!<<#JRx;Q1H$csPzSox1$l9I zGJ$)U=RSWISwFA?(;rY<1*gNT=&yDL>>tyY1YI&(PtXDTGS66dK#%Ow3g5kIGiM2C zhrVHC{xeviDsUkLM)~>TZ{OQNl(7cgo@A#}*n5AkJzJJ$J`rAQV6B08so}N8;)M4# zpoPTu=1X1Ca|0ZquCJE&?n1p&c%NLob<5?j&JQkTLb#qF>V&%2*q7+(y>I^}kbq?L zV$#B$^GFL~UioFx0>~pR^kLGt?&h{FZMY`$Sz=m5swSZtQZ))?65wR?{I?VSq@cBB zeTF86!3W_ZIIz1rT66e(23?9c)R(m5$P9Rn3`cjgib_|wr3G#YL(ALH3XP0cFac$e zW<*XH2d7ZjLT%1Sn+C{Xm>xC$W2;~U4?C_g1^6DESFfp_}2n2UUcBr!iDMe z^q2YaQ1%P8O`w~1lz6n1wP^Wtvus_?5`j-4n>25^xUC+f)F`U|Tn5~J7~+K!!io<2tX&yI>yMC2VEew^V5M+PV;i6wa{Ldh;H+BU zEzCR(E|Py_VD`Hhfl8ns17bgIReP}aC2zF#h20HTaho5%qivMEn;8=B_j7kM_-C3} zo8uq8q>?c1J$W}{;|GITvHgS2D$7o7W_@Ye1D+@RSe0;v+jcR4@Gy%0Lf^!BujCe6d`t>7u#zbTfTQY za`ET(5YJTsBnOEOWwB8>9 z*$MiFmlL63Th~1e&jw(<8=5%%P#CP~RXl+}*MEg4(AEkK} zbOIA*J)kj{CT4ygE)RY{di^c*I;Kf`a3<+>eA8CiYx}GBTURrC!q?ElYJP|2w`?|B zb6LK5b067?Si)Z4&)S()^1YI6?bR4Yu&T04|U5yUrKTK#S!cy^YJ2u_XYPL6zAXL~yf zIWg>mH(*lF81XSGYNFW+C!oprQze!g=if7{w$+}rg5bI!17VSKnj@e0S9< zE!o~hsrYHP6c+=Jfy=LdPabyzII_2KZaTDU`~1?w@U$D(N6IPe)t8p}Yw6`FmB81} zr|UKgxEngbI7>owr3?dXgS-r6WZpTk`)LTc~@+S>k)UUEKmimcLU zdwx88^q~CU9!cNP!0s+JaMx^;roKP5=k#9|OkDW(!fwz0GIQdrw`X;G;^LzF;X|QY zTgA9!{kzJgP;AVFo4I6Jb7&VH@{_Qo&u$6{GCC7+BWpe|E-K>_?8gyqT@hL>D>D=i zroYm62-S!5sQIS)A9tv~tiArh@C~jW-cW2@5W|6|{s#toLx`nh#rhF6Uz(--;5f^6 zsiq}Y8>s*(KT`p+1Zf&|r)lpgR^G9wq>(p6rCp)D5txu^GU`)gzErq9#gvXt4KcuB+w4_c;lujpOT3KM&AIKps zwP23Wap&IZcy%SKV%gk;`I%Mj=n7uCv{T@oy!l4%G4)2SmfXlapoj?k}3ozM*T>)?(|UwA$5A!F+;=}fMs;18ng zVhT|&=C$}<%CPD9UJB@t{^Tm`G*|4do4VNh>S4gqhtXxP;xi`?Q@Nqt-8^ zJ1aTh%y-Y*T>0tR;~eN4A}^-HP8$hB6QjmJ^O88pBwW+mTCNNtA!u^p4V0z{JYv&W zFf_8P+l8GDM8nmadwDolhDTyGV1DRJ=15n3!hd?ZR{WpdtSyXqv*v`iVt|^y70Vqe z*{V}83G~rgA$}`1mT>*cMu>++t^m2?x^nL5Xn3>c7mTs}MR%-4>@(&)FOFjuj%V12 zsx@)zOA;opDqdS=g%FPUTJU#BAB*kbGRuv2t)>yJqmR{q0OMZ#Sj{|CnyG+erYa7X z72tTN1ij_&jbPVvN*um}BrU%`3e&9F8^?i*G%aOWItM{GfnDkMWb&bz%PzX$wc4i3 zlmImZc{;xV-l}cmlsw#CMHyP4T*7Mxe+i*w%Ez1@W`4c`k3+?J}HibtjZ7o1SiDhn&dD+!Ok)fm14 zP4FG;%3#OJ3Cr1H#Rd0zY7dM3{gsPgP( z@~m$XZVb4y%2uez2Nm_}J9Shb%#T~VpH;f?3Erm4VQeT$I}pANC@x_(?jNA z$_?|-zgBA_L7urLaY=`eg3HcePn1;(=mbJQFtP0JXo!3q&7lut_D(^Q>w;ID zhq0ItndCO(m`*M(e7|Yf!rF!Sj+2b?!C;_cHhJ0O6LuHClObqEa%?sXx@h+RGG=e9 zV@ArnlTIiZl?5wdfVwwyQ zT2Af`ukM8xGF>@nt0m{OPjCD~KKE(98@%P=qn0qu)7@TE0nQ(lc$6S6SZVi&Y%-QzcN?Jy2aw$M)42eFz1BD4WSATxY5*9 z?T+D%m2#zEJf6(&DO>khGS~P@a<8(zQE=xmnKOdtm>gsmTxt}<0F7d}QFoq8*RAF@ zM#H1>=uf#pE#NT+wPA-jjzChf9j@Z!+VdCzc{#at;4sI>=j47SM3?5EA|ZNZ4yuHR zf4Tg~(mhiz%XizC=U0~vN1!_)LTyEfkoa^YT=~_UKPIBpJ12@QVkC2KS zKMg=elz3$r+K?}m)afV@2pj~}31ij_3M>~>QPa{Kv`Od%af_kX>xUq%E(bxdY0~qd z(-sU`03FxJ?LDs%64&P^3|$4(MN(J;&9DI=RQ~lK+L{`Pj#iy;?=HjH!~s@B}~NJ zXzo)88kjp2{Pvbqlc`vx9HxPiEqHzM&Y_c$d{dO?4O>vV0AJlNfUTISU@d(#F!4U$ zMT|3K?L^IqV4n{2q&#K1ZZfRys0E@}-dpV^LDr9RC@SR)Y|4nS5*$m`a&VCwsr%gJ ziJbOKl>!^Etz-jcIcl&G<>8X1?i6)XvFZT7GKAWoU1w`lZs%jqNbzde%Ww#Y@OM$% z1+3fClr80NtE#Cxj%|_h`0`y5nlv>Q^dydY0T{M|({R|wcGEsSH=>HOYwY8bcW2KP zuclqjXe&5h`2F~Ai(8UmP8-EKG4_=1v`$B#!CAb5!v&|hQuikPsTpN&!9x2M_yC@Y z@58O_gM|{##V+HJ3LLnLB{r7tet6j%E=@51OpA?rwMwwoedd?jdd(p#-5Vd2lpbCo zQc!`PdgY%`jkQL1?_bkpKLL8LaH%)A@}XKSxFgNJ*q(VM>k=J4%oD9Meqv!!%*9GrkwW4-2-CQA-B(HM6++HC@(~hM-Q@*FYcRI4zU~ zTKH7+g8T5VU1iFhmWGM}VA3YLv17E2tFcaSSL8QmRW>LCmA6^`gPRu26)&W#2AK$h(?V;R|A~!(gWx3qci-}Inj%y8 zA=opU6(oW0ES^g{lL0P_Sc9)%O(B(SOQH`zNNuaSG+92*P)^x~O|6}Zpk3nJitlT` zt!p`WvheEo%f)RI&rkY(%C{vgGfw_+Wy|u+WxZ3_m)Ebs(SxSz9?>3MugP1jc@jS4 z6N$I|7#B#t`!y~bZjQgk{a`Dcx@Bso>1P)dENob)fA;Lmf>{l-^iP~#)DMs)E11cO zF~`1%xW3cujDy?T%LS=z?*OB+oG;tCod3;dYEvrb<7aBp3N%mArtgqn5<t5kM0-09XmjEe4eK8OUquM%~TUDgOk*@FU{a=ZhUMWu^fD|+-0??**AXoR^ z{$GLEE3*iUQj`^jfx<9;-D~=77&3dkH?8t+)}y<_K+ZR`6LNWP_umG>U_4p*M*^b? z{V@y!q9>@s^Yh-6n_$T7MP~am!fBNQ86gA1Kvsu=wCzo}3CN8wW>rolFqWXHVHkWE z#=rL(R2cGa3W~k*aRQ_iJst*f-rL@r^Lt}eAioLY$;ugwBQwGRG;g~@hz`i}R6AMi6d?FP{`a8}!MON$_M3F@vA8qAC&G&+J%+45;5 zr5v1oWBmk_4#$)>GD@9e#dbnXhFcM8T89ZWw-f5bzOEsH>W-2yp{p`fLW3!cP#Lon z?sch@+IsyKrT%@9ggReuC-nYELb=glLcQXx2=%UtBvhVl;6@TkxgEAJrCYnJl-lAW zSn5PNmC#@^BeWo0J2Wah*4!pc7+h=7i}vgSl$Yt!1mf5M_X~SKX1b>@d0lvtseQlf zYjBOfaxmC%E~L?FvkOA5XmAa4L)4BUY!6uH!8x!KuUp=`lSz*GX?ju$s~pKU<-mm> zo^+0FK z=LWX-$3)u}M6w-65+j7lQ9H0JbvET%qf|;w5p0(#&>WTR;1MBW%7xkP$1bWc+jYjS zt#`s#$HdEb8k687ad`j-cD#2R844Ke`v}_j9fcIDjAwd(UPbHIg-2UjiXK`@3NZ2#c|p?=5ca5w!6+wsXl1i~^jr5#~BMW~ES z*Je}kqFdX)5QGS&h<4hi4&r5SJ{c)qCTD}I7^LfHbHh1_)7rKbNNaJRH-DijV{&_F z7%F6i?LyXx3E7w%ge>l$3oh#Yh4dWA@^-fmN9+@72whZN~XvfZHXve_n5IKZXn5g!yn3XMqkd$;( z5uoGQ7>>n@hiPhN)kGM>!_6noG@R=i1d-~KJxWT@!#Ix3#HVHO&1j&Wgd%}G1Q|v& zKpjTgPc)~cKZxY*q#N-&uy1$P4LMk(_G8YZh<-T1Ydu}%46QS68a2W`u9);A9u2q^ z_e`lO_iU;zHH^LA4N(@|_?F_5_XKH$IKVA4BwMW*Njm5yP>rPD-bwxPzOGk^+X_zf zBbt_q{Z;Y|58l|4d&HdQXm4o%zxfd@%f-HG%Q+UXe>)jBQQC8MT~6lkC-D;Cvx=4~IPDcO13tfAX>%mN9BQ$df-iy*NQ^;7{L8Oul{rU}uLROSl_i7^m= zU~1fE%|4k}IEGeB1ekKvO$9S&%&o!L3K*ED#HpoksKl(gKLScAN>ZU13K*2|yr&YB z4;NWr0>+_~is{=5A~YEoN49LZ^;@8VZoMZ0H1mxCCYWIkksH+n3-{AzA;QUno`n0S zN4lzTB8T+k9(DaQ7>3=tpWJ-}42Qa7Fk5@5U>8Znt87yf&vkX^8e zZ0`HPt&H{Hj1R0yCPSOD3pO+ybgga(EsuVZ=E`t4WaG91SQ2`bj&c?B8-;i9?r6um zcy%W?h!=!cc0X9h9ZXcRviq-`a)=PdvgqG+cIibs-w%I3C*P6$&+z6Rd+?WbtjL0Q z!VR+4@DMq>Kxbsl(648=zVU;!b`%dr=NPC=X1|5QMyUU8NK+GfPnL`1TK=a)`|KI zK=?ssQoT&or|)aJ3f3}H%llGvJ^zu)SZ-x@L9Htrg3UC5QZ~h>_a6<{0Pcg(>njy} zgTOUv`Dk)7qIdX;U6}X~LQ@G}WqeKBU<1?hX2#n7MHpM|Xv2)H=Hu|40m4|@lt{)p zli-T#PhrNI;9hyDW+d?SlU7MP0r=`1rSdg+7IV?mt#=A^1tuYkzjyYO1r^h!1YFUd zk}=cX&R&yP;ebApxoUZ0$^vmJwr@fyn@4Xe0H<>i%U0-lG&+*WPEBSNHau#Zzko#x z#BJENf{;#6z6o_$u4KaSmi;QjElViF1N&f_{LTm$yIrH>#!%)RUp32$pK@JIXy=&!(*d?(t(vN4pA)F$U2cV-gebo{-4D*)C)}91xmV78L?Tucoy;iNuqTu-@K=o$4s>}t3iWhcmezvE8NAslv9^za zSg!RsNRv6_U7l4%a-LO2zrH(^IPhn%e-IZk+OJ9p_hb6|sZISK;fjWZYE!O?Oh3-B z0F5c#MP=F@+drz<74Dzy2e`c29PS@?9P<(G&eHC2=)UlvdGBW3lhxfWQ6=6tN&l8Q zPS)8&)mGBGQ0MAjsTBKlDtW>8;evAs83fWZt~VZp5I133#>}CNJeYF$oJ`;JB%5+E za0st%Vh!FqDFJf(cAFBgl@L&Y3FtWGymy9$24v=+a5eXva9?fva9{D1i~pJto1_wJ z+7arErm7PTBxW!nRyRS)n7K$MlPwg3#*(QWnY9ZPnaL=tQMDuExadS8h!sBlGBxFQ)hk4;|BIDiz9VKGTp|mjDZOJ!?wM^J6r3<{bx(uop1lXcgna;fg zlX?=Qi1M<{&vF5glTg9t-4td~VGn%kx<3gpWa`A5`|Y6x)-kxCPd)y7ilH#Y^5#B! za851D;bM4m^m)M{CHUaiM>V8g@cqw7?tQ!{>X)U}pqK779$#L3W zBNrD*iJk=eT261fNz$$O+@xg+m2^1oPfsQ}fyqT12@z4Kr%b3IJ>j?rB1&#SL`ftO zmYNPkltmW<5uNnKwzb5GF##XBH_cGcBXDsv53@*a7qhaM=h1qQpvPY#=&F1D<3DZQ>iSUdJoaxhcp7q%L@J&2>2|XN1rm3t0 z&#J&GkP9Sq3$uVws|;7E4MtIF?fF;h;8-mWjm)mc|CN!G+5Z6hzoE8YUS?GUr)tpS zj06krjA?FzEA7g7wa&$QDUN@bOGW#6kI-v?SV)ohNmQhKO$D+;1Qu0&YT3l-5Bi z5#FC^j(Ol7Z*)flYtf?}5KL)DfZ^*2eEqH9%W$xm-HzZqL(pIG_UVXVJu2>i;L#2U zv;+a%61rsv?rewu9fO}qxd<1?sFOU?+3}cph8+S}eZ8b;vS%T}=l>!*uK>zIop$t0 z@4pP5CBMc&{PIsTt0*YN4C*!Suma!oi1<2NwiS$zFifQvQ2$86ZR4m29wvsV6eDZ9 z!Mqjq-G5`=-lo#d1sTGgN`s0#(4!-A|JOGl_n^L!$h{*wAdk~_!Sb)uC)^r&OR|dG z@(+qUkaWCWMUIj>BIi!rfc&p0BNBOVXe9E-K89|`=wl(k;tl2jRTS_hj55@FgpFDJ z>+PuRojRhn9lil|4N8kdZMioRb+(^qN{|-7EJvPQ5!61NikdsXSRO^i1?+b^#`_1? zOVN6~ucb2b=C*>t-g++9uA7{7Df2=>6>P;S8=e~m?pf0BdkwCuy$kM29)&I0XnuAu zeoH@mj?#U{7miozIazHq^p%6I#4TYU2VFhtGG>;JTpe*N0ltd1Cp*X&?myA!FQ$~b z8KooRMuim))HzM-_#R^sViGYNB?3;!iPq9OcKH!n$!o-wsykMCkybKKpml7Wah(m3 zbt+Kb_TBrQirX+vckZD-MunsK;YhaOg-e=x!dX-zL;Frj8d7i2E90)0iRT1V5W zoJNY*KOilMv4DZ4LqJ5=2nNHcPw<~xX$$j6+9G&eijBKZDvy1D&nu1K53YOL8d}$$ zPwPSeH9Ul3OQG4D?4Zscis2Ov$@Dz}uVBb8G#nl%kze)^@cbYOjwQ(gV%hiltMCFS z_;NWdRYq?EFa+QP7yD%$9@)b5VS}qph5vgM6BU3-iFURBBmTnxD^fD%@Ynbq(|hR z3zZEU2=Q8!sS@vfKg+e~P=O4OsXqBPHNBOOc`HQ_ywZSsyoKdAsrj~FGs|ZOWp!Wh zx|$!n4Ee2hy}|0gpyt~yVK}$F$MXNG<_9n0`agb=tibrg24k06U~9t#Z=7Te-c|F1 z|IUOlzrK&=ql0R`?I&FSlk*K=1Eah`*W4ZIueNt#Clw)zp~`l>(47hGF);IF13etz zE)iQk1;L>JjB+P*ugWOPYg=5Bh*AoHQxBbNaAA2Ubd|oQB8uCt{u=i-ysH5+#zUXu zPh}F4W(Q}tw*ifCr2*_qlvfNje*6`82G;*v=j)8^{*#$-hz4J+f-B!70*Q`42SG#0 zm~%l2u!xo9KC714zJXQ%bP-cU)eF=T|5vn48*9_@i~?@E7`!iW*<1446p?j)xXAW7 zE?UG&TITtzY$~F_(`2`mehS{qQIS1HiG;45!x-Jj z{tU9B0+|(`Xo#3Zp)&OG232U*BP;map$iQ>TmmtJ_+pU?NvcF2u})m4BkSBn(`b5_ zG|O@DNs$^|{yI}#)@h_nCV=sas8F})s*|iRcbYmR!B3UWy_kO`7)f< zk}9U(!!b$wmujh|qrGPWRYX5ReFGbeY(E??bkfrm{H6t5Sq|ESzzmL|+Qh!BeE}!= zw$beixa`DMx%d9;Q8%sNonE~`q0FKy_>t?|$3xT;s*X)Dvyc2~8{^RUb`HItStWIg z{szwmIK~UI^0DpZ??QP>bn~_X8CSTAt=Q&5rifAXnDEF2-?F|#0VIxL+8ecuf|r$a zUcBjOq@})5s<8QYP9`nfsO8Vm)|0H<{5qTW)wI6(HArJe4nbxNm|tZT+^j+aOS2Ws zyqTp}v+{bDUd7U{u=Glnu4CyHEbU|I`Y$Y9&C-ildacYdo?{tqmVTC{*Rb?LmR`-$3s`y;OaGar;jTO( z;2D-)!P4_-+V>tyJ6O5=KFgTLGSmuBv-G>H{3(`xho$GT^xG^who#@5X^YzaO_o;M z?_z1zUN-M!87hD#mY&T3?qKOBS-O#>pP*^qR+gT{(r>WzOqSll(lc24b(Wq^(%{JH zHJ0%>tMDpIPh;r@mM%%QV;M0opy}Xbmi{wK+gSP;mi`k<&u8gLEbUhXuH z+9docf;o*E<9T1;9mZAU+u(d0=!@Ngb>IM&?k}&V&@$WXaGCc>w|Ff(ks!9*chcG` z9}Wpg$~MG3`dW1lx_OwNu{P}t-jU%zPq0g)_4~W8U7Jp8*q*#qjo=;b^6O9BMq$_+ z^=r9efD!{xCMn>HpFlC)R&C%Dqeva+l%~G?a{kWw*xEkb&lAL5@!Jgc?bT9qfQxN` ztFcs#^rH;4ah_(LziSj}ZR+7X6TYyUOn`_zDUjfwIs~775Oe*(st$P}oTo{T7zxYe z|1=W0`pA(eiVlxN@TZ88u%$+DyIaSR@F#@JxCGBu4R1{y2&3%Zc>%{(g$G^`E^>pF zGRpt8$Drla*psoI2O#kv8SG%9OAR6Amquu{TU=CDa?imUH&Pu?@9`dRzxlAz9y*E+ zOE*uwmN&DAmb@nu@jX31Y2kV?*p8sDdwXIL{}4@BGdxoeKS;*bl~_Hlb3P6UPlG2! zvyj)J7jlQX*?3iSZL=zWK0Th{Z1Lp;Oh-ldkxbQU_U?L%)sW% zpdL=@@nAc1$9cDuFVi_$5L3%Db&5S-niYU&%$OeKcOJ(S_)&pi&o)P(ch0#siXeXk zMlj}RoRy|8j;IYbG%w*YFC`-!M-=%puV9lHCS=#lAVf`V7FrD{OCajefHNq6z&Sk& zvgN$$St#;%k*$E(64RSA4?m$yVS#EblXm$(+tmNO9}^)1gVIIyTkqr>wTJ#UxE1j>;Dfjg3cc|m5hWiD;0d`(;Wr}whDabVO{7;f-I+DbNm zhMT3eHw!+&5PrfCmJpc`eOCrzokURjH_*l{$8g*66<;uvrWv%Y{RrdS6e>?GztV2m zHEww5#K?X@3I)1JyH3XNYj`Z|;IW>k&7Aodj9U!+9Y1EEy$Nonpq1majwO$#(Ful% zw1H?6M+dTS^Zq)D+}_HN|8m(%ogzCI4DFoOoB|U=5!&z=fj|U8w7z;T zOgLK8_Irl)Rf@%*$gsY~(h00wO&cjr^LrF0^1D&1Kw)vCXqnYd%K{&%^w>tm+6~jC zXFO*Od{I1^I;epmi1rkA=AVut){uXM=cCTNy%$Mv!*VL%P3oHmI24m?|C3>bN@Pkt;@icp7UC!;zrZS_J z%X#IL$@2_UuAH{e^JW6Ss23i5(L5X8Y!Z@#y(y!VS(FEs1D@hU{!dX;p-uVisk`1y z+}2@yzJS&yK1F{7TEZUBRAwDo=`b z2D*6!6Yry)R(erL7UQm+CjLRbD`{>2HC2zeK%NxLjZcOgO>W?qU0u@nD4q(BX|KnW z&i9HZ#MvRD5EcUOx1O=-ur9UY1Q+FbE}b7mt6Sdk98TxI!yR*1lvI2CxAW;Vv2Ts% z?Crdrc3E8JDK^s*V3W(^H1iMA$!tALQ8@Q7u|LAnewq%b>D~0PlXW30f1jlnu=IN@ z{b!bbm$m685nj< zV&6=`*c(o=noj1T$oh9ya|a`!k*0$?S=vWi2IM-mY49v9@@=O@z9u)aXcz(C(z2F4 z6pZN&+Rv6hc|ZV+6)n@ws|2uZwN*vPYFZzoHLZ`UHG?4xQ-+ndi2}8}PJ#L+(yG2G zYE{cgiXLsFHN6d#Q_6>|WgSb`GtM=9%gFJ5O-owpXoAYdbNTJ}NQ+??Da+$7XEt&UTEFlts^>`{*$FQmgme?)57 z&mXKd!itez>Vvm`L1CjaKwjae7X8e}f#=gBV~u4M7emXUCK@lnlie2~rky^MlXC|8 zIrq*CuJOqeoN@oP>p3yQdC8*bGN!~RCgtUb9}4UKn86!sMsOaOh3>M`ul1}+C{e`F zQt{D2HC;Gkr;B&zRD7gKEgr}>u6W!szs4w@(17X^LgV*7$|o7Mt(wq`y^jtl7j=!= zJdOLPRw!N5Se~z`ThsW@4Mf$9=_a%+c~|a28+I{C%VNcZ;*+9Z{>pjKM5|z5=rdiztWw zs(l!9rgT*fdRUWD-8eqL8IJ>h45)YriqSPz)B#)ZBjSP8jT3Mg@CVAIbs8=Ikn*4u zqwAKc2prt-om5(Qwaa6*sTGillf{RP6+c}cB8s|Qz(RKgu&_eZ<%lPQxHa#TM+4wv z!tyoJ)qOhtA){y#LQi~nX7d&XYP?Z_w%{vPWiE!3g91X_>US!lbvYIL0E#rHE|Y&K zwP+GAC87Q=?dGj`2#m>kA!pEj2!82q%=?$=ov0Tr)&GJ4h(dkWMd`VFt3s`xU84hl z(&zx7N$LQ2>!n$V{Ynd!2LoPr#ii@UntZNjjiCgIAtV+wR_xQPJ28;ISfhy54~LE& zEBIb?V=+8;tl%9jh+%mi@R47WBf?$ajGCO{6P&wP6hhTvfjdbQb{zvglpp(eaYEzH z8t8lDz7wVjaY+0L7)kJDJ?F!W$?x#_Dz_FVB@TCc^dL^3fjALqQeLzqwxEoVUNogD zdhY$I(3}?56?-D>ihUgG3dD(8zYazsCpU>V!mIYs$-2CE7S~$7Z-5@&R{Ee)I7AT$ zd)>l`kB5{AFca+XB>rw;hyn~2?U=y}PKdBgtBmHhyK?gPnNpLIxX{%7NvT?ZH)2!L z5G5X_o?TeJDkrekB%*gJ->?`R*W-=3iJaW{?~UBx6~^2oZU~HfqgVnx9)iaXe#Nb6 zytajd_s1(ASQ(mp;+F?j)~%FkI&rVp^Lf(JP7vlKT3FmAC$|X3JICq+&_k5XmhA5b z9S05y$3G^d*S*j+Ra5suS_Qg2G;D7yg>nWcm7n zQ$@V?1q+Zh2PFs&P?K zPNIX$aWq&$I&@SWbF9&ZM8UAYJN)HtI^rz?d@fxh$rpuMV5wAaY~Ej#?Ji&?4BlyA zX%y5xjcb!ZJPl~w{~RcUW?a0Iv+sH@ioUc@suIuTWUjVGv!D60SlMzdedY0Mjdhi#GL~no z3|!y1qU~DxisRSbRze~7FK+0Hbit0?i7}c3tCf;<6+4GFD#wLDsav#&jTOhit;Uy@ zeMx)Pcs#J0R!);ozh9$*+Zg}zHFwm%uBXR;cI|=6tflKv47WL7`tEqzy2Mn@Q$wuF z(9Y_zeTiII0C5|kUV8klYm&vEX5Qo$ez~4&m9EtiE;RyoFvE?a;SL2!PXyAU?QR{K zI|%bhtaiB9h{7P?l$;txSw$v>lo1$}1DpCG;@>R!NkiArev8Kjdd{cvDKga&wrm>q|HVT&f{6#b znUz@JLLvL-pEtVgF`A878vY0d9rTs$2ag?n0rxoF3Bg4nx8TK%@JpJNIm(DKIq5m; zT~rgI+o&S+U(Qkp%yagZ$?qYn^kPG-(eZ0M>=ZS|Vuh2X&Y~@+!pvg_GDb93+(`cS z;To!?ah6_571^68Ax+oZN>{EB4m_xhY)c3el7lAj2sOP%QHAHre;0!~Vfzho&>V;j z%R${6H_O2yZ;oyP7-*<{ERB^ZoMa2=VMb`^j4*bpb_hN3d|1~BrUSUMVe3P~uG26b zDlf)QEO#e?&A4-)#`xt4n8fn4f;973W}|q_@(#9a%a3WQSLIYp6;}T>wI+$ntSQT< z-csl!-G42oZj-4jkLJ0>{ns~k@?1;rwEx<`%225Cm(KMn*D!Ait4kZ+uE1(hnrDYQ zEHT(M3z;I=wgT5IqD2<*5~a?OWKbr?sDHhDFL-HTXjh)TW~@AYJ$>cAYj0O%E=>hp z0<&fcENktv=Jfgj?e4@jLcR2rb=UfMjaZK0*THH{0NifD{({UH@*jrVShGH!z%{}peFJEfgC(x-|QInH#!qm>rmJTiqg|f_xh~SI_ZK>0JSc|wjZs|F*li1cU&8t zZvx{|}dwDJW_d;iALudwp{tp2N> zBP714S8V_pSY=oOtileK-pkUBEd3!%Z)fQbXj=I@O?z2= z0ArQ3v@mBY=v8Jn+5EJs@+z&032rDfLT zlss-LOCMwDH=xt7Z$j1$wAWVf>q=4DPSdKsmnc~C%PQsmW?G`WOo0S<&@}SWnrLGL z0jFr0^{=$dx*=Q!?mdaj$jW+JsJt95bbdomI0JuSNM2#-g)Ci18wXyZX=g1O$S!cnt|0}EdC?3OnDpEmEpXohGj5Lpue`TVK5!0B`q&fF!uFoiSy$QAGkJ> zk6zDq$ZI5d?-(ZQrWi`LRN%*j$s|wnHeKv1-iKW5jFNt-3?0MB+@jfUCSQMO?#8J! zw`h02h};LIWHYYYV(Ar;8=8z=(P_X?VG8RF*fp38Q-liaXAB-vbKr2OIoXFl*eJ6a z&S1!JZsdFCfR`e1{B3al{bYpPV%tae=f|<%*8Oq$J!(e`&D=`>G+_YNk0=0Wzk8%N z*^0?&i|?F&wVrk3!@>E7>UH+aX42+3ZWH)HZDZf{7R6~7?H}gmf9q|pNIoaoZ&xd} z?1Z~YgfD@2r-y41a4qN5TFUlJ2n?LrTF+%(z#pC9lhY;PN`Do;YdL-}g$0T3Bwz@;b1nWS6H-4(|$+F$9D->aT-+Md=cKbz%S8?y=5Put9s+1QOp zm<+D(;1dE%4`2Vpc4cwp+__>~+WCy{3%)IE8SmNrCqBj#?8A38;tnC7zej$W!d(77 z=!wnbQ$|#LUf4{eL!a^H_zSLr;!BI0^-CvSQAT|e><`!7h<4s`{~@?n8B4ot{~le7D}_qwwm8g z^IMj?B31BMDj9AxItFjO$K!j;#!tPAkH5tE5p%6fC{!}}rvez@w@w&rPSTjWrO z8Iw+jS#8C6AZCM==Xs*t-KZ#T6Ye*Ym<-Pscfz;Xt(ZV=ou_|a{!W=p@=%Y|3Iv-0 z1$%A2YM6}o=8Xf7aG$Th9#sdh@h_v^3&o=6qa)^LdN)G6nCOX%$o(*d=C)Kv=1R#l zw`r}K3oA8zL{FmGiaRj^#Kr`g>sS+s?m;8X&0Vd6zz{;6X)an7nOkO{xyM&T=BCHf zT;FoQCbvuXhjBE!dRb&;31X6BC176~nX8G>oVIFolil-0zVxhdz9>YWP5wJkjT@6c zBwZRw|A!tL+IirT?Uk9qEGo33y|PNVo8zqmD)ED2Equ9{N3Iai@bsp;++SVk-aXO6 z?h3SVaEBxJcjT_XD*TDo-y7c*$nebR$3G;GB{OFnxfDQtJI7M7%q$nq;W$V_&@FI6 z(j{bHr#tS9P0=fSerY~GymUA};%ScKx*hRTr+^I=t z&Vx7EDMzQnKF=U6%#AKQB^{1VQQ#_Rp+YYXI^*!I-b@!^vw^ZXIMTg1y48rH4M}Ge z`?@6<3nn2t53tB#G_i_-jHJPw*H8{8xrU=tqw}OwYrw6S){uEx(&r-KEFBK}Vgk&Ob$2%)ll_=Y<5LLvG>FVr7BeA1Jh~IsLC^(BwKjk1K zOY`YXj9?N(Ip|z%1rLT?VX&aN5d1QZhdY_Laxi*A{Zo#kj?4>Ltpglu98Z-TEr9^y zX9hG63_`5UyBpw)P~;TwbO)Y(13oVLkOCn$KnV4o(RYCoCz9{{Nm?2WR~8Cz*gKMA zJD=#~^MJCv$Xu>9L%{)l)9-oZ@*q=Orz;IK6nr&KXHFyMnlWV4rL~bl$qV zw4fM6BXh@=imd8yZ@2IwH=t79QUMd{7!EH+CzTQTg@#r<>eZ#o40^={quxH^vDG3O z3eji1zeRKyMZW+&nNla}Qt-(71(jo#UxpO{ziw;NGPYmBaKVXVv>$c}c(QY+9^2DU zUL})ejPG|GY^}R+@X|5^sCB|z=TCfnDa>4jOu_X2TCQP^e%{%s1=GhsPfP6k?3pcD zCo}97_9^o}nBQ<^%cboXcDBaBjWLz!+Kx=`)C31EQc@FF=NM{T{q30DkDPXZ)C#T^ z`>uTsVBDvx39rwbk z299zx@oU8jGDx6%_t_7H#TX7gh#320bozsE3<6_9m}#mCOYwM+;_)EG8H~}E<3pJg zdwSl*KXexzqW9sN8<9%5jzDsP@1h8)RCAs0c-G$qH+86}{R>&4fc*BJer)c5$}JTQ zi-qQ1U=m=dN?aUk=*>kx7$H@9J4gl&gX^=#wFr)0`5;r1>x9fR1I|gtfRJWS-%$&p zDbu&sa@c_>6^Qh$+c}(%bA(nr{bjd^62SYW&S0P+rA&XhS=ViMWi8EQgXU(s4iB2C zEQ6@Jz+$ZGu+V=|Q5e=ix@sMesAGlU#y3>i*)>797psDq{#sLKSEaZH+TO>sv5Tb!lbvAT;jC<$2mhtu+8*b?8iTt zO0Za-zj?BFk9i)>;z!ZhVLlfL-~Wf3XGit=@a!;E+-i1M{?OB9ri%+LFfV>4Bp+A4;U38IB+%MeC zZNLi^0b!b*eIT>EtG9GyFBrJA_Jzu{!}Dl={*K>)@EgUJBVf^JVM2RxcWj4ywQGFa z3t>;M|EINYk8i5T9=~&wo3w>OF{EjEroVLH5BQ!ZY!;zI+`1KI*|ocfqKIA#zUM)z0=@+ZnB zq}lz7VxE%b)^c8<*4ptbEMF0hf}qs9pS(lLNK-}A$7}}Ou!#Nr@XzgL+*?RGxg|d; zjij0g#}cCRNLb!_4SzNWH8D$Zz3|6_(ZlS)mgGydpa#VDW5M#(F4~r6oRp46vZX4n z>02L@*Yhc>w)Ie+uVccm$kXZ)Y%2D-rCZrc7W$mkg-$`8!0Lii6}+pA4%df0o0}M{ zxg|o!_#pk<3MNKAMJ7E1w!aNCdOBwg?T2ZPo*2@c@tY|Vh~*LjwfDp@#@uLy(Hcf8 z*i(AtxQ3O5%2=6OQ3`gdP^IjL;eLnDct*gM&44{S7_hCQ@>~@b#=IvijD5hJgps$0 zg|QBk97B+Te~~dWe_tyyPW}g2jSL&uXbx%Bu>!%xSo_rqz^*WBxhBjyV7?RU(9SSx z_aKHV<|%5Z*fXpe(RR1-O8sj346nFvDFCd%=~oa$#gJU9g0LshC_@@> zm4~GsLdT_%%kV?P(IB=LO?X%l@;GB6uT-9ov1efwV=AwKd`!){o0DU8B4%~s`eTYM zg14CJW-Fs&JHa5$16ym#{{G;J#qkVoz2V=pCuED&okmC`w}nD?iJg-5aD=2}{g*S&exPrXTqhneAbb{eNXu!s84{wgFScdfahVCk|$HqSQuk=S2CUJhzBV zq-+`n7r39n1#DqB=MGlmd79OD=DI9`Qz36W45_tRTKYD}fb2>yG%C8;pJ%!mD{;*z z^nhZxd5n@guU2VEqq3JUG+Qx^@&Q)p3FUbuBOhvI&&~pc-A&~=U#VA~-3q+@F~-S0 zo4IWbjhnUj`3KN^CW~ht3#P#r`3nYt_++6kp#>fH_i=JUjFM({XY>P4F=$Tt`Y153 zAFLYm`+;P>aDg*yyeAYweHew%+$4z z06hy8zg~b}v7+zqr$bDBl6{Eie}MrBHsx87N1o28`ya*YvrwovMG~hlAg8hkJP>|< z3cofQi8|t8G(rt5Un;HPcCreBtr2o*g^dPX$aC5-cWyKWe25C97{3Y%#S%f2`WaauivmWx@6Or#c zXqfOXz{AHt;x&*C+o|j;mxXjv+UMVVFQWbrQsLY^qlKFmEYIFk0_rb5rDkgD(SQj9KyhKB zqWHz<+K7rV10sswk6T6b0FxvA20yHnt#Nn0J%OsQ3O3X!Dx_Z;Hg*_ML1{bZ zDM=90!mZbIby!4+?k3}Xs0%DLk;6YmAkzpqIA-8$ylKcP{_Se=DqVF17Ql}<%$(|I zI@d>-T6#$HwDzkq%Q?6rC3y&-N|oC+deLNji`(vI7R(6|=ED@`{!b;XkQ!zVqO~!1 z>rBRua83=dq^$2ljP-r0f4SAc0oOW^3msBKsb#yOWz#<>8^wUOkKihKW7vfCjl@tU7P&?1b(+Js(^hP*==bF1!B^8D^XVei1n=QGCNS34ZD$wsu}ioHUiGn(;OnF3 zTSEO(OaoyfVPQA!_~p%4OU7<(S*~C>mzxi=PF8=inhUGoUWM0BKz$sqaYfVXPVGN= z;Do6U2y%BTXG;BnGu?BBGxhtJGu`(dXG(jEldGjatm8}KTm!0tX`ppTb=+*M;z((R=*}k>S0GWyS=GyxUux+W;^RHn?k6zpM8ZL`W|l@ z_#Qvkk$WUJb#c++wv%Xv0MmhIxXpIBO5jYHkV2Z2dOh3rue^c?@0{qcu$?9<=``Ze zG~)D})Gfu)PuDb>Bg%8<|2*m|-WfT;F_MfKWef-3%xxR?fx{!)I&HAgWE>0Ko_tq2 z1jY-jeOxvTxm&d?YP6VPqg!~eoE7RzCzsxPEKzW&MNV2iL}1;cVmIM7QsKsJ1dpLt z#((Jjk!_uq3r4w&+_wnM`$~@wRzzGz;GGCc@N42SQXTIr=5Zgqqw0SOdkeiMYeH6( z=C(2k2?@|uY06>VozYrtN0Eg!9aeFzId$D?J3 zv}e_U)s}M*IUGvpP$Gv6k%KUhD;7`AR&xJ)Aaa2IVNJ??tQm6WM2i=k3~#?kf;LB++h3Ep8xWvi#DH9K8#^`5xyJXnG z#VKof#1D~2UgPc{ZoN4P1oT>T@XR7&_ zGrjd5XWAJKEU_I(V5yiC|3B>m%ZVZyTI3oI1fqe(Hft`tRm(-ox8FbsQSQWY-T-git(^ttY(TObrhUPxc@( zEU4_(r}4t^sQdkFEZt8f2#=*CDPAy!B^O3VByc~0_m4;BE_4jYqXsEs!2LbGJRTWX zu`nWBZ2S%`Ah{?oDn`p@og|4Aj|1!lS_NX!$J*II*EnV3RnrVr6%WgzQQj-nK0 zYEDnw&}n2N?RX0bkdYmVp$Qmc#S(>B@IFi!6bUKtIWvXwv!gaNq23uJ7oug(X^f@W z7%#%PK9r>u?#?5k*^Tfqb(sEKS|s+4Fbz(Lj-4coMP`cI$xM;+wX5+yGMCfAC3z(xyt{_<#7IZNT{(-2LYu!$y*csvl%{D{W?Y)}-E0<` zRz^ZoeN)z068ys>%lJ!o>6P!Q|Q<}XyV6a1He-AqSF6iug zSMs@SiHZt8F%I=`+}a+a_}m}c)Ayf-B!CP-N?*Pfq3`ZN=tqWN{Y4^IRyb;%RHj-K zPxvK*XG}J^VF>O8X{b~%1a}#TSp8KyZJp*^d~xEEnk8{dFD{t)Yz>Ydj|MBg;jAK< zGAx~cg@f(xhG9t=h!<(zLlw6rnB0?)X)pO?Jgjzqh*c~3iVqYe|4v0!#%l106i3G@ zrQ``kMD=$dfyDv#qtXIFu%YmQ?yI}GWy$elr58$goeYD6Aj;;mS<2w>Zvd;i8P))| zq%Gk~8zXR@e}>_#n85)P+D84+=kK$qb!EM-hy<;zBxpJA5Vic<56yw71+E|*wQO%f z)KXl5ZY8*aAHKc}uAnVyaZYdrOvBU5xv&Vv)&C}HMFlO##;B+THmLd)qSp5iwZ4I< z^;d{m??Tkt!R1yj%aKZ}I$k@lgWoQuo;2&7XKxadnG`?p_1)9m~q>7@L&gFaMCw0 z#(L%_X;?|1IKEK$;%!5vTGWd`g;Q>8pxx_3N2%a@cF< zgEvSEhkJWqYFoJHj+)%yPpDrBtK8nN=+{wk$Fd7a;N7+$^b4yQ@JGb89dZ!Ia%aDi z9Pul}?l8}tn$4~PwLSE2{0fB&><_~QCo{O@D8Euivti~}(pGMD{A)HGBq@f?7UfrH z3HM0YuZYN1(v_QX;rI`qhCK^|7!*!2JbRXNVIkb&fATC2mJk1To+YmaJWFv^qO@9_ z*ydXrJW100{Yh=Ug^J>Qnhtq=RRZ{y!tF_IzU2ZyKhL1O!Va$5(dLevClq(o5qwKA zK~a3m_ki-${%$ncCMazf!FLsJ6bFlbD<~82MzOr~BVf$A6NWKJF}hW0q%z8ZcYyoi z!F_d;p4s2+6wBx-6D4oELJ{t&QcHhK@1875CEL4!EKB(wrvW-3cUy~=d3i{d_`ecp)lN`FkBbKaErna z@W5A7Joi#oCRQYi8x&e_EDN186;(JGG22#!VH7dr8+UfrutdR}buC$W;BsSoWLBP?LNpE$#Mye8=m3_o^?^gPZLRqoBq$aA0?kNToG)da?zVf>Ogb9 z91@s9uZYA)Q)Qjc{D<6+DVa`1ReUtp8x|GFJdIKkmqtVlN_WovPD1Y2HFkou_-+-= z=?J16SS%_&I(Q}Qqx&OR)p%zI*Yv)my<4SZfD}6PLKvF+i9yFIo_ZyBy|!Hj=wK;e z`wWn|I`mslZM+`#)Uf8=J_BU#flLOO#hzWxg+&N9{(tk+%iQ3ni>f+a`8di;capx_ z*Xa()*&pV@5R(#W)!?c5s4TD%vcMnqb)w!)u5mEGOXcVKD_)dm?rq<!sS>4zH zs~hh|t!_YIeFu`#y^x&l`i4uXj&g#um)NqEoG)KE73~B4w@cm?#DIts=!9&5A%`CJ z?U_ZLARX5Jp~QqbO=uQ%g0#$;X_!IEQXf-Z1J7YF=2(%7IlIYj~l}9 zw$5UB+*1t3^Jp8M$_X!;izcD8iCZK?0omy##j?L+5~6l|QIP^O+BSSK^67+}OC!!4 zz`mN02>zG=zBLJ@_arES`El88pu<9c`zi5F@RcMKxG&&`{s$Q>6eP4L-7U~nel@(3 zQNwkS1X0LIhLa>=Go`Zj&q_Uy;8*_#iCV%|4o$(0|ATt>XQS?Cn6gfUH_DU&cV;BK z7bH8z$zJU~%6;j^6g+S;%A(jB@j3kG$!HkEu0J1*ZT(!Y?7vKfJ(Xc>TOvL)8BW{r z6Agk3Y6^vt_)D<49myifW~bEo=Sx;WZ5jfvE8r+h^$$#F@nQVP6f{}O5TC|xO+ka$ z>4mm`;*Y1Ip1rBY;&8Uk75spq1(avlw`+V585lY=)~E+j!MzM4O~LRgj0Uo2=U-qW z1Tm4uoQ*F&hz775ZD4(~msuzg!EaMh{1ZFQk^Uyc#K5V{irIFs^E5XvOu}FPA z+@b*V#YD;?C?^QTp?l#HP+q6G!eQFKtT)>5C|szI0(Vb)IDa#an}WKtmNAaFQ_FC_ zlO7ac8LoZH$amwhQ{j{@Y7XlVTsalp&srw9E2?Dz9hls9WzqHI4(lVx( z@TiATvV#H{m;7rZcz$7tfOQFz#N5oDgDE`pN*3d@W!THX#JAm^QYdxLQI(L*`&8IeV{1X}N=`Z^ zz+KqnJXqzd@5iIXus()I+_tT{GeAJ4)X9Gv1Sf z9x%}dKWs#e95L@gN4w2GSm6U)15N~VA* zQWaBJ%i1dzydWh-tK|TasI%hSK87I#?bYVoj)7vw1wKl#es>;11^4{xs1bHB5#?$o zBKdAz>Fonau(d6FVo}k#&B4^xi7j~RBdD*Awue50#yDz6cW)eg1a&u3(f#iV$4o;Y zAsq?{>4=R=j1#w+2JXO@#v(&MevVFvjwJ4Vk|<~*C@aHZaSML@QPjIH9sCW625M0A zTBRKf%JUZXY}4V*kD_9c0*PCwDn+8lB_#0dg{5^gLlCwx1a}AaELX8-tCpuR%%ur! z!q3k_ll4^1bc2qa^2-$E@Mp77x}%<~4-0=G6kHnNwaC7?U>u_=zQ(9J6}KJ;KVMf4 zQ{{+h-TfG}{WVPFF0#J{6D4YNZXoe6eS%yJ%W96i1|NFEcix+A{G2TGv|$X*K7JPl z>iAUou^79M&8iL5V$xOilyVZefO!rK1?Wmcy!nzO>3VP*t|*&Xnz&^{V1s` z#ei>Qpuxfy-S+g|^*DMIjidIkeRXdr&y6O?Vv4xI4c8m+%m>w8q+fVY80*QN-wvvl zxNu$5g-D(A1m5!mnmo)#9Gia$`SyJC1!n>V(-#Cn-z00t3HtN}*JZR))Amy*jeEwe}2!YH9g1Cet=m5bb$V(###$WKR*=X_u ztZRQkGNiDpalVH_wbglJVFEIA-3`--svGdtS1bKmU9dkzNPsV9F`UCAo<#loQrYZ_ zFyT@ZdY=5%72E$rw(aXQR~18AJK?e?(a2#o(h-6cs^Nt#k~$8SWYjkbhN-W^;#{Is zpiYtk>K=+;|1jDC+TO-$8%ohS=@7kw@3TSHMQL#>vD1e7vIpaGywe5;by6^Aqwi}Q zsz>a}{}HZx8ck&n)(>$f3C<9uskbHx7fR@D2eXp>IWi$+q_0kt&)P=M**u4zFTlnr zW(3dUv275+E4n5%pYs)~kss^QR%5*kHEQv5Ruh`lv#rMcBh`_Oarrg_uElg*jT;roVjq4E48D)J6;D5W7tEIPB?s6 zr}4*vzosQ_19X)kRiB#ft~xA@jpd<>cwiv|G=j`wC-mpPgrD4RSI&cMm)7`q;9m34 zOzlG2pfCGgo`+nBUC-u!8dB`9fXv_8_NlHc7*hBtkow9c6asTDj=3B7PI$z+v!oo7 z6UJ~kgH)eu59tIA*Zl}I&%w((3K^6O($zmg9RABR*)(GBX6c-Wd}Z^|uRN2<*x$G2 z_vk&u`-kEw&!ac`I*FwIig-AqCIOC@sp6y#9pHSct{m(TR?RA6#_+pv*FV5kQtID4 z&(bEbQp9A%=PihoIg>~q&}lqJ=aSO{j0Dd56Lm?N&^!W{4e_6p2K5YEo*Th-Q+EYB zw(O(~k{JqV)e%Ss?2MNppxj-IsOM=?1}`fqs5^m`iZH5`-a|z&o@eEOC)=01Lkj%t z_T|QNv|JEpW2(0J_;(IvDG=UhPzURIoK<;deW%n||ITWJ$5@T7x4Xd#~%4+O0 z!!_L3v_>P&_>BN(s2zp$DopHI6!18%gatUos?1wim1kR1SO7WzVK!RLYUJ%<9QPLt z2R;?N)OneD6LA8r~07MaOpE7Mc z6J20z)&Tw%rjLCBDGN7?t(lRQw?m(x4Q0K?a6{P>Fp?SkiL&}Gn z2B!F)`y=XulIh@f!+B$e|E72hTH>6Dt6u;w{SfKewje(F0BvwBfi1vYJp=Ruf949hcEdGo+IR zDZ$){ReDUc=h8|etX7e_oSm5bg^qhkVdm`5N&?#=LI-nL?~u2Wve7cjL7dZBso4`< zYJ8ZL2FM{x4t|CL?4QcW+BZkYIv-+X<~Ji{)(5FZ8hh7S?>J~y(C=2b!0Vx5>^u^ z4%gV?e212y2az^|qa@%FTp{{OI|OW6s4l>VW#rXn!b9=A3%*y1 z&`87#>^Y@Gk1Tw=7@P{Vul%2uFfnEj0$ucU1AlbC3^{h8SEL9i@GUC?X_ zEx>21gi=xHLpXDfSFj#ub>{b2od@b*f=Th*vuK?rAp~xK>O_l!kK>ce(Q|r2OB)De z$b01BMam|nm+_1el*97B;CFaW3HqIq42JO467)cSisbP|Be|cWY_x%PrPkl$*(>0a zY3P4&1nB#?Y6a@c9y0dh6D#2RX+lac*Tvix#CsY{UA5{V-*?F#4$^FZ;zVX{WELme z=%kFY3>`5It-1j@GnrZqRk!Li>RYCPhg$)n6~fK0is@6r(^$paH}ESfVUJ&W@^`CV zT)uGKb3_7{tUrXeu0-aZW9YPYP#9-T?(#)Fo>xE);0r4um#56_@8hIZutrTEn)c&| zR-yj!GpKN$n_w|m&0M|;cJvYAg8U9XwF;$}r+^|iOhfkGV9Er>5Cu#lsDiBqN(%C! z9;N7>j{fBMZ%GN9)wLTxREoOtegmFc3iGZ6GUv4&!3RpwNcLbng!wY`aBpfMy9Mmg z>Jrq~O#}Ddidf6z#{Z~6DY&8xb))@XBfn0&a*X^IK2X-y(yzf?dQ=koMvxXZGOm(< z$kpAKz@%59q(y0n{!mJy`p=+)QWm-gShoP{Uw}2}S#^U^3Tyzp)_8G3HG38+3FV#& zq{nGmN8!H9|hdlM#<;ZR@*{eUrmBmd5= zMicrnV%>;A01*rl?nZFgDp?F*7GFyY(+mG`4O}u&OWLlfFaF0GxV$G9vZY${THo)> zkqVJ2mnOFpUJTdAq<~w3mihfM_s$Zy)Uit(KX|3mn@EkE^DItu!4)FR)jow^cEPO~ zv?lO$Y<7O7*-cCjOF>WL8W-B6ByeN#ly#{1cd1ab0`{t93zMXdar}U4Gznf!CRJT# zo+sxn&<9S20d0N;t**dVahoy0DXL7s2^A=%C*|4{PrypVCU-Ql5Ra!+pjo`_60WI0 zBW81>-=?B~(tHU_$kfeX&Fe6dc5f}3R?K$1I6qJ&s#_YY$6HH4jJ=o1vN01yf1B`t z#{SvVm2`w5zob-`i?y|^w*Dp_TZ#Jd{zkm865ZdKiWO+acbl!#>3acatJfoH~8uGuyM-vp(?$wxgcHLqDm}m(P;~> zl#hdp$}f|FXH7JXnBHs}IOjS@(PA397y5f4+?30rq5I&E3#Yue^Tkd}ew;sL!OjJp zp1t@|7g+G&yrcsD|9*$n#rZEUV0D_^8@mTV&0-gmA+I5Wd;Y8E6`EVsH5(5 zUpU);8y`yn<$MC_)zn*E8xlFfxMa2N4LGGTWbqG;-Tg)?iE)-wvJPcQ*m2jD{h%$^|!a=pXN;Y=eb)hRY1i#3XbTwTd%8* z_5$!u+?E2UEZD|vDFi}=n0w`QmDmZ6;p@fS+Mqg`3^1|W78zhV+{AC3A;O`334Nu@jd!^c;TY)C8kI{6C-T13oJ5`vuDy4h^h;w8o%Z_e{f-K9 z?(V@FrvKa)VjkU>TM=n*{U!kCGtYM)qtj+y;0+dEBQLsKe?EWPXMj`5i*atg!Rx!m zyH1|w-*+81(02Eo=fwiT&Z2GRH@tSFE8LEu$}IkVs!rQHl{a|n8u^N~ne$fj-L?3T zrP$HPBWU+#{&&TVR*eC{S?arfSO4$K>ffiD!3IB%gDJ(bK147xkFg$;ZJ42)Hx z0Sv6=wv?W{Wh(6o2Hr*uyg@r!e&vmV?A}n@ncLzdnCH2TGsaWvG@NVv5!7?=nV^eK zi*uQ5x-U=hvGa6V?IMfz0-s!}GYF~)E_vR@V&6C-rfa4afqrVDALf%cElSokpLe{1 ziEssDwZO{2W$UxbUx^&BuJnm5c_2XEHg2@+N{nf16i37S=Eh@dg?ZhzzH!jm_&~m; z_!zp{>RP?0R9fJPiNe=rjv?)6l~=bf;iOyny4-k7$yruHVl&uTJskW%A zS}fY*oJ+fqFJCQWPl1UQ?2qQ|BO%F_!mdEnENPsdyjjATH8PwNdP&IBR^@eoO zCFgGI5`GCo+g93wDNs|YZ^Ra4Mp}W85{}_#s?c8E`A1(b57O}|0Hf0i-;rC^Mi(g) zvVRB@4*KY6JlaqQPum9Hm{4SK8$P@Z4d#PmeJ$Hi7O%~Lrnd;Yv9$&jcC&XOSrWvu zNZLq<3mz}Yj#7E&$9OAbN!{!n{tet;6u2V_oN#A2^G*fMk1x9+>pHgsnY0E_Zh7DB zxYJvxTsxCQxNR$aTi-$^75mEGeaQFOU(iP00gAxHYUWnBxs3#4<5QTH1ZIRwI2$W5 zx4{HwlTSx=8hK`#9EO6=e;D5MaEbGA24&8PKv^GSWueKl2qw(RdcmSez5+M}R`A$F zt%#KflW~j}4eO!-ZZSpa<>L+TKNmlDifyQd44SPY=wEH>6#V!;l)@?l z8diCv1FI}D_}1-1Q;~KtjESP`0RCY=dUKGGj7RrZCSe1&MHq%6htQ`G|4D?<*vD)q zZ?$Qs;6A|z-bG8a6fO899`zpDLOYH|wvaU?SRSTu&V7owgGnhYC9p2_4l4}|T$V%1 zS*gE{mJ0G45KY_fWu^A}NNK7Z!+>pj@H6j2e`gv^^sRj#J%Jqb z$+^Wea6*TPa{I#u$hV@5qbDIsno5Ow=V+d`3I-{3qL7#A0C|s<1v*B`g8NyS+<{Td zAb{?2MpBH6CTU$0c6ZyA&*z;zHY?M9yy64&jw4(Tw_|A+b3M;);RH?=uUC_U8g$yv zcuCU;e|Pbcp%IQ9+``pz$J_<94$9UyYGgsDHS#XiwcFC%Mh(hFW9}Ug*+JTc)r(+E3f0yUT!9QjVRSh4lo@!*u!X)QCZ&bmDN2WLX} z;<}qIt^cOfa(?ih!ks1kN(4B&p+S-F`n}m5}$Na>+wP4(5KT@lX#zLcj-b;?QkT_1_{ecRS$uH|B!`u!szRVD} zsWiE?p?h5GqG|#|^7s91F!_c&mnE}_b8IN>St@mk(~u%5wG6*gbj z72_M;A(-=O*I2(=-SFel8}YtnqV$J~IC7+EK$Mo&#t|`zfQoRx|47p&+)GD)j0gww z9R6lkBAhNq%a5uc%=cGZaX?F&hHi&Fk^7)kj&Y5)>^WQKXy%_?GJ5IerTj~0pEbh> zijrR;18rLmZ3|>VK&Ji-Vd^3l0r7S7w7g3T;%hKi((`UX9rG=a`&GYWvDDpP%>q%u_R~psLU@}=jZ8kDgOKEhIex2v1F+j9nZo!7{1!&^lg%hSS+%X-Z>#Om z)m-1-R?E@VZqsk8J<-)xV^lQ>5Q4ai@>ce<_P|94QQt0k!<9u-!x!{~%D3@>gGd}i z6w(CF$YM!0yc?lWB{;Um7B^=C@&2T?$PVx8Ik-cW7=yDCv}8Q_5W3GnaqacdxXzL7 zafK5RT=&r2MVe5bZ@JjCa+*VlUjd4hSs)fPA#lRd~t8VUxY3pe0AGZ@| z$ZrHX7A4UA|4|^-|02-C|02=95eW9cM6B!V{~Lk)Q39pnnnTDQOARaRFL7h*A(TGh zdk>ttP1-3`8%>Gp)t-{PCql`X%-T-e9VrVMaOH<+eg{T^B?geFSpYq$nURi{R`^b0HxXy9I?i(BL1 zI-@@aI=M9Xz+u!=n*o`(_lOstJ&am;+cg{vphG=Ayek~z^Tv0FEJY@p$@CWa&>elVS7m!U5sY>#Sv_^O(u2fox?=8~6J597Vj!ai;+K^o6AShVuX3FpOMeULuNsjOH6L)Sb{%fM?K<5R5{7x)rd8hN z7r7Fr_v(w>fpr9BEA}>PVI^rM|E&u$5_QgT*GwQg=YJvl-%%}`$veJXBVFp+K~gn# z^kz0fdgPjJ;JouNTv^)p-%I`9kq4n&UlyxUZn#dvC6DKt?qmta={8gR*F?b*g<5q( zbJr%9_OeQ9!u+vMEnnC3Q>$TVfJ5VT$3X?HHEY@Gn`Oym7AQ+Dt0;YLD?kg<6@!qU zNW#a#k8aM;ed*Bf-bX5VOYwR>`E@=~cUs^dE%VN(N3Rec`jGJw$=4f^KI!cul7!F=Js89vkG#(@!qC- zJ{{O|8gITK%Y}J>)h*Yy>U0JNCrydry)&D+ayP6CU=43s(9GqnwOmLDmyXx1i zq>t;)K(f%GW2uo8}f%DEPLb27}uPZp00XiX`hrAbWaMDlH@3Nd(%D=l}y4BTu zL#rzVEBqC#Ajb2S?ya1+;~8F>8P9vQKk(imXZWqyb+QNNJ^3Q?;+YN*JC%wc-K9SyjM4JJvUF%|b@2U;lu#2QqeX^Q#(*XRA zqrb)UR|_;UmUB;B7vShzR58*m5+(;KC}_rAn%!2iN}# zS)f`7RM&V7pg{Al+^qGZUiD_);6|;NZgoWsi#A-8mTM9$r|TVj%4X@44jS*wVpLl# zp~e_84BxM|d?_GiWSCAs%UZt1a6xUh$~$D7%FB;a9a!u2{Y*4io~_#OlO)XGyqPn& zWVhF+M;p$g@fOVttG7;%lB?19;g!p})xly}J(p2Q$|@`MWnNjIwWQj6(oqRVo=RY_ z(ht3-Z}5ZY5c;Y?h;wCj18K>CN-paO!>6>``_5_JTX>#7vd+8wG%pE&Ik=Lr+@nWQ z5zn8%u6*c+;)KZrSwY(@~lfqpnQ7 zyuN@to@**CGW_qICc4I$UFnsZcxEh1hM)VqOtQvkYTbmcT^$GmJytwH6LeSBJlS4dRVR9Iw#3JCD&?mN}U+0v{S&XVB<(fn4D z%dTv1HeB@n!Hom2Q0#ntI4JBN3obLY-J*jMn2j~paV7b9%_r#I32-gyw`-H#E)A#F!HvGI zip3~X>zp0`#xnhqQm-DCWKYSw>lEA_gauWW>#MR&<+^d#ZeK5zOG;ngSbq%-t{AY% zViyn|e**Q?XN6lgQ^PrzWh^T7X`Bwc^aSeRyZl#F!P8FALuv!dITo!fs91_^pP{7= zOJW^d3|+^~NYu@|rg9yxagubp~PX)QqW?A_w`pKnXdxzP( z;9^u6E^EAebXsCsrAw3W&WXgGmD0jfyzW#zD$~18rSq9uF2N^oR%zjBUKVz5%7QBu zFFU3sO0U#8xH@5bd8Wqi_`LLO_wG%St5GAY*u80AweFOta%qC&e6X8Jx^P4dsmajt zQn-6jC0(uK^2GG&n=^LjTmDqf?T0I{mnB*%k3dK9bKZJTs4^XHc+M&F!PN&%dD7J* zoGc7-OT@_6^e|}yRRpGrIt%4HeXBl2eN_CG6|`6IQxD<;$C1+tjRhy->N23QDsyRL z>EBqExTMUYujO1h&{#8|vEWq)X{?^*x}#0Emy`-6C9ijf#@YjogDr}^hrOP9_=|0@3!rRJF}O#ujZ0tcUn&aP9|F!G&944Zvf zPQ#JFt=*-T^j&SWOBQLa_PNX@Wfbp$xg&hCB&csHAIN`I&^f*ECd}_{l9w9fbq1b$ z0#-Lo+g+chz1ZE^+<~M2U>-{Tso5XS39l3_U!Y~i7m_nBT)Dcw;>50r-;6SMUi^jf zm*Xy!s7*&#_?%y$Bo(jPi(fs3((YPciztQlwT#f%yYSbf{LE=qeEU*3wloknRL zo;e3=>G1EF!#sZYG)lkA7-9v+08cB%^Y~Q&?DEWc1@I^<=UrJbN%+cXloS`K!MZQe n$k=BT5G#Nf@WL;VF}7MM8b`5qe~Eg>{-hMmAVpfri{t(enWw>3 delta 44261 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 diff --git a/source/contract/ipc_test/ipc_test.rs b/source/contract/ipc_test/ipc_test.rs new file mode 100644 index 00000000..540e9a37 --- /dev/null +++ b/source/contract/ipc_test/ipc_test.rs @@ -0,0 +1,263 @@ +#![no_main] +#![no_std] + +use ckb_std::ckb_constants::Source; +use alloc::string::{String, ToString}; +use alloc::vec; +use alloc::vec::Vec; +use ckb_std::ckb_types::prelude::Entity; +use ckb_std::high_level::{load_cell, load_cell_capacity, load_cell_data, load_input, load_script, load_script_hash, load_transaction, load_tx_hash}; +use ckb_std::syscalls::{current_cycles, exec, load_block_extension, vm_version}; +use serde::{Deserialize, Serialize}; + +ckb_std::entry!(main); +ckb_std::default_alloc!(); + +#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)] +pub struct BoundaryStruct { + pub usize_data: usize, + pub u128_data: u128, + pub u64_data: u64, + pub u32_data: u32, + pub u16_data: u16, + pub u8_data: u8, + pub isize_data: isize, + pub i128_data: i128, + pub i64_data: i64, + pub i32_data: i32, + pub i16_data: i16, + pub i8_data: i8, + pub bool_data: bool, + pub char_data: char, + pub f32_data: f32, + pub f64_data: f64, + pub str_data: String, +} + +#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)] +pub struct CkbOpcode { + pub vm_version: u64, + load_tx_hash: [u8; 32], + load_script_hash: [u8; 32], + load_cell: Vec, + load_input: Vec, + load_transaction: Vec, + load_cell_capacity: u64, + load_script: Vec, + load_cell_data: Vec, + load_block_extension: Vec, +} + +impl CkbOpcode { + fn new() -> Self { + CkbOpcode { + vm_version: 0, + load_tx_hash: [0; 32], + load_script_hash: [0; 32], + load_cell: vec![], + load_input: vec![], + load_transaction: vec![], + load_cell_capacity: 0, + load_script: vec![], + load_cell_data: vec![], + load_block_extension: vec![], + } + } +} + +impl BoundaryStruct { + fn new() -> Self { + BoundaryStruct { + usize_data: 0, + u128_data: 0, + u64_data: 0, + u32_data: 0, + u16_data: 0, + u8_data: 0, + isize_data: 0, + i128_data: 0, + i64_data: 0, + i32_data: 0, + i16_data: 0, + i8_data: 0, + bool_data: false, + char_data: 'a', + f32_data: 0.0, + f64_data: 0.0, + str_data: "".to_string(), + } + } + + pub fn min_value() -> Self { + BoundaryStruct { + usize_data: usize::MIN, + u128_data: u128::MIN, + u64_data: u64::MIN, + u32_data: u32::MIN, + u16_data: u16::MIN, + u8_data: u8::MIN, + isize_data: isize::MIN, + i128_data: i128::MIN, + i64_data: i64::MIN, + i32_data: i32::MIN, + i16_data: i16::MIN, + i8_data: i8::MIN, + bool_data: false, + char_data: ' ', + f32_data: f32::MIN, + f64_data: f64::MIN, + str_data: "".to_string(), + } + } + + pub fn max_value() -> Self { + BoundaryStruct { + usize_data: usize::MAX, + u128_data: u128::MAX, + u64_data: u64::MAX, + u32_data: u32::MAX, + u16_data: u16::MAX, + u8_data: u8::MAX, + isize_data: 0, + i128_data: i128::MAX, + i64_data: i64::MAX, + i32_data: i32::MAX, + i16_data: i16::MAX, + i8_data: i8::MAX, + bool_data: true, + char_data: '0', + f32_data: f32::MAX, + f64_data: f64::MAX, + str_data: "max".to_string(), + } + } +} + + +#[ckb_script_ipc::service] +pub trait IpcTest { + fn math_add(a: u64, b: u64) -> u64; + fn spawn(s: String) -> String; + fn syscall_load_script() -> Vec; + fn test_boundary_struct(vec: Vec) -> Vec; + fn test_vec(vec: Vec) -> Vec; + fn test_input_vec(vec: Vec) -> usize; + fn test_mem(byte_data: usize, kb_data: usize, mb_data: usize) -> Vec; + fn test_cycle(cycle_limit: u64) -> usize; + fn test_input_payload(s: String) -> usize; + fn test_ckb_call() -> CkbOpcode; + fn test_empty(); + fn test_current_cycle()->u64; +} + +struct IpcTestServer {} + +impl IpcTest for IpcTestServer { + fn math_add(&mut self, a: u64, b: u64) -> u64 { + a.checked_add(b).unwrap() + } + + fn spawn(&mut self, s: String) -> String { + let argc: u64 = 0; + let argv = []; + let mut std_fds: [u64; 2] = [0, 0]; + let mut son_fds: [u64; 3] = [0, 0, 0]; + let (r, w) = ckb_std::syscalls::pipe().unwrap(); + std_fds[0] = r; + son_fds[1] = w; + let (r, w) = ckb_std::syscalls::pipe().unwrap(); + std_fds[1] = w; + son_fds[0] = r; + let mut pid: u64 = 0; + let mut spgs = ckb_std::syscalls::SpawnArgs { + argc, + argv: argv.as_ptr() as *const *const i8, + process_id: &mut pid as *mut u64, + inherited_fds: son_fds.as_ptr(), + }; + ckb_std::syscalls::spawn(0, ckb_std::ckb_constants::Source::CellDep, 0, 0, &mut spgs) + .unwrap(); + ckb_std::syscalls::write(std_fds[1], s.as_bytes()).unwrap(); + ckb_std::syscalls::close(std_fds[1]).unwrap(); + let mut buf = [0; 256]; + let buf_len = ckb_std::syscalls::read(std_fds[0], &mut buf).unwrap(); + String::from_utf8_lossy(&buf[..buf_len]).to_string() + } + + fn syscall_load_script(&mut self) -> Vec { + ckb_std::high_level::load_script() + .unwrap() + .as_bytes() + .into() + } + + fn test_boundary_struct(&mut self, vec: Vec) -> Vec { + if vec.len() == 0 { + return vec![BoundaryStruct::max_value(), BoundaryStruct::min_value()]; + } + return vec; + } + fn test_vec(&mut self, vec: Vec) -> Vec { + return vec; + } + + fn test_input_vec(&mut self, vec: Vec) -> usize { + return vec.len(); + } + + fn test_cycle(&mut self, cycle_limit: u64) -> usize { + let mut sum = 0; + while current_cycles() < cycle_limit { + sum += 1; + } + return current_cycles() as usize; + } + + fn test_mem(&mut self, byte_data: usize, kb_data: usize, mb_data: usize) -> Vec { + let total_bytes = byte_data + (kb_data * 1024) + (mb_data * 1024 * 1024); + vec![0; total_bytes] + } + + fn test_input_payload(&mut self, s: String) -> usize { + return s.len(); + } + + fn test_ckb_call(&mut self) -> CkbOpcode { + return get_block_opcode(); + } + + fn test_empty(&mut self) -> () { + // Do nothing + } + + fn test_current_cycle(&mut self) -> u64 { + current_cycles() + } + +} + +fn get_block_opcode() -> CkbOpcode { + let mut ckbOpcode = CkbOpcode::new(); + ckbOpcode.vm_version = vm_version().unwrap(); + ckbOpcode.load_tx_hash = load_tx_hash().unwrap(); + ckbOpcode.load_script_hash = load_script_hash().unwrap(); + ckbOpcode.load_cell = load_cell(0, Source::Output).unwrap().as_slice().to_vec(); + ckbOpcode.load_input = load_input(0, Source::Input).unwrap().as_slice().to_vec(); + ckbOpcode.load_transaction = load_transaction().unwrap().as_slice().to_vec(); + ckbOpcode.load_cell_capacity = load_cell_capacity(0, Source::Input).unwrap(); + ckbOpcode.load_script = load_script().unwrap().as_slice().to_vec(); + ckbOpcode.load_cell_data = load_cell_data(0, Source::Input).unwrap(); + let mut data = [0u8; 100]; + let result = load_block_extension(&mut data, 0, 0, Source::CellDep).unwrap(); + ckbOpcode.load_block_extension = data.to_vec(); + + return ckbOpcode; +} + + +fn main() -> i8 { + ckb_script_ipc_common::spawn::run_server(IpcTestServer {}.server()).unwrap(); + return 0; +} + + diff --git a/source/contract/ipc_test/ipc_test_with_exec.rs b/source/contract/ipc_test/ipc_test_with_exec.rs new file mode 100644 index 00000000..0a9af2be --- /dev/null +++ b/source/contract/ipc_test/ipc_test_with_exec.rs @@ -0,0 +1,10 @@ +#![no_main] +#![no_std] + +ckb_std::entry!(main); +ckb_std::default_alloc!(); + +fn main() -> i8 { + ckb_std::syscalls::exec(0, ckb_std::ckb_constants::Source::CellDep, 0, 0, &[]); + return 0; +} diff --git a/source/contract/ipc_test/ipc_test_with_spawn.rs b/source/contract/ipc_test/ipc_test_with_spawn.rs new file mode 100644 index 00000000..ce5bfea5 --- /dev/null +++ b/source/contract/ipc_test/ipc_test_with_spawn.rs @@ -0,0 +1,15 @@ +#![no_main] +#![no_std] + +ckb_std::entry!(main); +ckb_std::default_alloc!(); + +fn main() -> i8 { + let mut std_fds: [u64; 2] = [0; 2]; + ckb_std::syscalls::inherited_fds(&mut std_fds); + let mut buf = [0; 256]; + let buf_len = ckb_std::syscalls::read(std_fds[0], &mut buf).unwrap(); + ckb_std::syscalls::write(std_fds[1], &buf[..buf_len]).unwrap(); + ckb_std::syscalls::close(std_fds[1]).unwrap(); + return 0; +} diff --git a/test_cases/ipc_call/test_ipc_call.py b/test_cases/ipc_call/test_ipc_call.py index 14bcba1f..1894bd4f 100644 --- a/test_cases/ipc_call/test_ipc_call.py +++ b/test_cases/ipc_call/test_ipc_call.py @@ -1,7 +1,13 @@ +import hashlib import json +import random +import string import time +import pytest + from framework.basic import CkbTest +from framework.helper.udt_contract import UdtContract from framework.util import get_project_root @@ -71,7 +77,167 @@ def teardown_class(cls): cls.node.stop() cls.node.clean() + def test_not_spawn_serve(self): + """ + 存在的out_point,但不是spawn serve 合约,预期: 执行失败 + 不存在的out_point,预期:失败 + Returns: + """ + + block = self.node.getClient().get_block_by_number("0x0") + ipc_script_locator = { + "out_point": {"index": "0x0", "tx_hash": block["transactions"][0]["hash"]} + } + ipc_req = { + "version": "0x0", + "method_id": "0x0", + "payload_format": "json", + "payload": { + "MathAdd": {"a": 2, "b": 1}, + }, + } + + with pytest.raises(Exception) as exc_info: + ipc_ret = self.node.getClient().ipc_call(ipc_script_locator, ipc_req) + expected_error_message = "sending on a closed channel" + assert ( + expected_error_message in exc_info.value.args[0] + ), f"Expected substring '{expected_error_message}' not found in actual string '{exc_info.value.args[0]}'" + + # 不存在的out_point + ipc_script_locator = { + "out_point": { + "index": "0x0", + "tx_hash": "0x000867a5e09eebdedecaa0437455e54d99f9c6752adad1fd299bd6ede303f461", + } + } + with pytest.raises(Exception) as exc_info: + ipc_ret = self.node.getClient().ipc_call(ipc_script_locator, ipc_req) + expected_error_message = "Get out point failed: OutPoint" + assert ( + expected_error_message in exc_info.value.args[0] + ), f"Expected substring '{expected_error_message}' not found in actual string '{exc_info.value.args[0]}'" + + def test_type_script_args_not_spawn_contract(self): + """ + 存在的 type script args,但不是spawn serve 合约,预期: 执行失败 + + Returns: + """ + udtContract = UdtContract() + udtContract.deploy(self.Config.ACCOUNT_PRIVATE_1, self.node) + deploy_hash, deploy_index = udtContract.get_deploy_hash_and_index() + ipc_script_locator = { + "out_point": {"index": hex(deploy_index), "tx_hash": deploy_hash} + } + ipc_req = { + "version": "0x0", + "method_id": "0x0", + "payload_format": "json", + "payload": { + "MathAdd": {"a": 2, "b": 1}, + }, + } + + with pytest.raises(Exception) as exc_info: + ipc_ret = self.node.getClient().ipc_call(ipc_script_locator, ipc_req) + expected_error_message = "sending on a closed channel" + assert ( + expected_error_message in exc_info.value.args[0] + ), f"Expected substring '{expected_error_message}' not found in actual string '{exc_info.value.args[0]}'" + + def test_death_cell(self): + """ + 已经被消费的out_point,但是spawn serve 合约,调用serve方法,预期: 成功 + Returns: + """ + rand_account_private = ( + "0x000c06bfd800d27397002dca6fb0993d5ba6399b4238b2f29ee9deb97593d2bc" + ) + rand_account = self.Ckb_cli.util_key_info_by_private_key(rand_account_private) + ipc_test_data_contract_tx_hash = self.Contract.deploy_ckb_contract( + self.Config.ACCOUNT_PRIVATE_1, + f"{get_project_root()}/source/contract/ipc_test/ipc_test", + 2000, + False, + self.node.getClient().url, + rand_account["address"]["testnet"], + ) + self.Miner.miner_until_tx_committed(self.node, ipc_test_data_contract_tx_hash) + # deploy math contract + ipc_script_locator = { + "out_point": {"index": "0x0", "tx_hash": ipc_test_data_contract_tx_hash} + } + + ipc_req = { + "version": "0x0", + "method_id": "0x0", + "payload_format": "json", + "payload": { + "MathAdd": {"a": 2, "b": 1}, + }, + } + print("first ipc") + live_cell = self.node.getClient().get_live_cell( + "0x0", ipc_test_data_contract_tx_hash + ) + print("live_cell:", live_cell) + ipc_ret = self.node.getClient().ipc_call(ipc_script_locator, ipc_req) + print(f"main1: call result json={ipc_ret}") + assert ipc_ret["payload"]["MathAdd"] == 3 + + # cost ipc_test_data_contract_tx_hash + tx_hash = self.Tx.send_transfer_self_tx_with_input( + [ipc_test_data_contract_tx_hash], + ["0x0"], + rand_account_private, + output_count=1, + fee=1090, + api_url=self.node.getClient().url, + ) + self.Miner.miner_until_tx_committed(self.node, tx_hash) + live_cell = self.node.getClient().get_live_cell( + "0x0", ipc_test_data_contract_tx_hash + ) + print("live_cell:", live_cell) + ipc_ret = self.node.getClient().ipc_call(ipc_script_locator, ipc_req) + print(f"main: call result json={ipc_ret}") + + def test_call_payload_empty(self): + """ + 测试空 payload,预期:失败,IPC: EOF while parsing a value at line 1 column 0 + + Returns: + + """ + # deploy math contract + ipc_script_locator = { + "out_point": {"index": "0x0", "tx_hash": self.ipc_test_contract_tx_hash} + } + ipc_req = { + "version": "0x0", + "method_id": "0x0", + "payload_format": "json", + "payload": { + # "MathAdd": {"a": 2, "b": 1}, + }, + } + + with pytest.raises(Exception) as exc_info: + ipc_ret = self.node.getClient().ipc_call(ipc_script_locator, ipc_req) + expected_error_message = "IPC: EOF while parsing a value at line 1 column 0" + assert ( + expected_error_message in exc_info.value.args[0] + ), f"Expected substring '{expected_error_message}' not found in actual string '{exc_info.value.args[0]}'" + def test_call_math_add(self): + """ + 存在的out_point,并且是spawn serve 合约,调用serve方法,预期: 执行成功 + 测试默认值(0),预期: 执行成功 + "json" 模式下传递 JSON 对象 + Returns: + + """ # deploy math contract ipc_script_locator = { "out_point": {"index": "0x0", "tx_hash": self.ipc_test_contract_tx_hash} @@ -88,7 +254,39 @@ def test_call_math_add(self): print(f"main: call result json={ipc_ret}") assert ipc_ret["payload"]["MathAdd"] == 3 + def test_IpcRequest_version_and_method_id_not_eq_0x(self): + """ + version 测试不存在的版本号(如 999),预期报错或 fallback + method_id 填写任意值都可以,预期:成功 + Returns: + + """ + # deploy math contract + ipc_script_locator = { + "out_point": {"index": "0x0", "tx_hash": self.ipc_test_contract_tx_hash} + } + ipc_req = { + "version": "0xff", + "method_id": "0x1213", + "payload_format": "json", + "payload": { + "MathAdd": {"a": 2, "b": 1}, + }, + } + ipc_ret = self.node.getClient().ipc_call(ipc_script_locator, ipc_req) + print(f"main: call result json={ipc_ret}") + assert ipc_ret["payload"]["MathAdd"] == 3 + def test_math_add_with_exec(self): + """ + exec 调用spawn server + lock 合约,预期:成功 + 存在匹配的script_hash,预期:成功 + 通过校验的tx,预期:成功 + 调用合约执行exec opcode,预期:成功 + Returns: + + """ account = self.Ckb_cli.util_key_info_by_private_key( self.Config.ACCOUNT_PRIVATE_1 ) @@ -140,6 +338,11 @@ def test_math_add_with_exec(self): assert ipc_call_result["payload"]["MathAdd"] == 3 def test_math_add_with_spawn(self): + """ + 调用合约执行 spawn opcode + Returns: + + """ account = self.Ckb_cli.util_key_info_by_private_key( self.Config.ACCOUNT_PRIVATE_1 ) @@ -191,6 +394,11 @@ def test_math_add_with_spawn(self): assert ipc_call_result["payload"]["Spawn"] == "Hello" def test_math_add_with_hex(self): + """ + "hex" 模式下传递有效 hex 字符串 + Returns: + + """ ipc_script_locator = { "out_point": {"index": "0x0", "tx_hash": self.ipc_test_contract_tx_hash}, } @@ -214,7 +422,42 @@ def test_math_add_with_hex(self): == 3 ) + def test_math_add_with_xml(self): + """ + 错误的 payload_format(如 "xml")应返回错误:unknown variant `xml` + Returns: + + """ + ipc_script_locator = { + "out_point": {"index": "0x0", "tx_hash": self.ipc_test_contract_tx_hash}, + } + ipc_req = { + "version": "0x0", + "method_id": "0x0", + "payload_format": "xml", + "payload": "0x" + + bytearray( + json.dumps( + { + "MathAdd": {"a": 2, "b": 1}, + } + ).encode() + ).hex(), + } + + with pytest.raises(Exception) as exc_info: + ipc_ret = self.node.getClient().ipc_call(ipc_script_locator, ipc_req) + expected_error_message = "unknown variant `xml`" + assert ( + expected_error_message in exc_info.value.args[0] + ), f"Expected substring '{expected_error_message}' not found in actual string '{exc_info.value.args[0]}'" + def test_math_add_with_type_id_args(self): + """ + 存在的type script args,并且是spawn serve 合约,预期:执行成功 + Returns: + + """ tx = self.node.getClient().get_transaction(self.ipc_test_contract_tx_hash) ipc_script_locator = { "type_id_args": tx["transaction"]["outputs"][0]["type"]["args"], @@ -232,6 +475,11 @@ def test_math_add_with_type_id_args(self): assert ipc_ret["payload"]["MathAdd"] == 3 def test_test_call_syscall_load_script(self): + """ + syscall_load_script + Returns: + + """ tx = self.node.getClient().get_transaction(self.ipc_test_contract_tx_hash) ipc_script_locator = { "type_id_args": tx["transaction"]["outputs"][0]["type"]["args"], @@ -257,6 +505,11 @@ def test_test_call_syscall_load_script(self): ) def test_test_call_syscall_load_script_with_env(self): + """ + syscall_load_script + Returns: + + """ account = self.Ckb_cli.util_key_info_by_private_key( self.Config.ACCOUNT_PRIVATE_1 ) @@ -308,3 +561,646 @@ def test_test_call_syscall_load_script_with_env(self): f"490000001000000030000000310000009bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce80114000000{account['lock_arg'][2:]}" == bytearray(ipc_call_result["payload"]["SyscallLoadScript"]).hex() ) + + def test_type_id_args_not_exist(self): + """ + 不存在的type script args,预期:执行失败 + Returns: + """ + ipc_script_locator = { + "type_id_args": "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8", + } + ipc_req = { + "version": "0x0", + "method_id": "0x0", + "payload_format": "json", + "payload": { + "MathAdd": {"a": 2, "b": 1}, + }, + } + + with pytest.raises(Exception) as exc_info: + ipc_ret = self.node.getClient().ipc_call(ipc_script_locator, ipc_req) + # todo add expected_error_message + expected_error_message = "Get type id args failed" + assert ( + expected_error_message in exc_info.value.args[0] + ), f"Expected substring '{expected_error_message}' not found in actual string '{exc_info.value.args[0]}'" + + def test_mix_payload(self): + """ + 复杂 payload,含多层嵌套的结构或大数据,预期:成功 + Returns: + + """ + # deploy math contract + test_vec = [ + { + "bool_data": True, + "char_data": "0", + "f32_data": 3.4028235, + "f64_data": 1.7976931348623157, + "i128_data": 17014118346046923, + "i16_data": 32767, + "i32_data": 2147483647, + "i64_data": 9223372036854775807, + "i8_data": 127, + "isize_data": 0, + "str_data": "max", + "u128_data": 3402823669209385, + "u16_data": 65535, + "u32_data": 4294967295, + "u64_data": 18446744073709551615, + "u8_data": 255, + "usize_data": 18446744073709551615, + }, + { + "bool_data": False, + "char_data": " ", + "f32_data": -3.4028235, + "f64_data": -1.7976931348623157, + "i128_data": -17014118346046923, + "i16_data": -32768, + "i32_data": -2147483648, + "i64_data": -9223372036854775808, + "i8_data": -128, + "isize_data": -9223372036854775808, + "str_data": "", + "u128_data": 0, + "u16_data": 0, + "u32_data": 0, + "u64_data": 0, + "u8_data": 0, + "usize_data": 0, + }, + ] + ipc_script_locator = { + "out_point": {"index": "0x0", "tx_hash": self.ipc_test_contract_tx_hash} + } + ipc_req = { + "version": "0x0", + "method_id": "0x0", + "payload_format": "json", + "payload": { + "TestBoundaryStruct": {"vec": test_vec}, + }, + } + ipc_ret = self.node.getClient().ipc_call(ipc_script_locator, ipc_req) + print(f"main: call result json={ipc_ret}") + assert ( + json.dumps(ipc_ret["payload"]) + == '{"TestBoundaryStruct": [{"bool_data": true, "char_data": "0", "f32_data": 3.4028234, "f64_data": 1.7976931348623155, "i128_data": 17014118346046923, "i16_data": 32767, "i32_data": 2147483647, "i64_data": 9223372036854775807, "i8_data": 127, "isize_data": 0, "str_data": "max", "u128_data": 3402823669209385, "u16_data": 65535, "u32_data": 4294967295, "u64_data": 18446744073709551615, "u8_data": 255, "usize_data": 18446744073709551615}, {"bool_data": false, "char_data": " ", "f32_data": -3.4028234, "f64_data": -1.7976931348623155, "i128_data": -17014118346046923, "i16_data": -32768, "i32_data": -2147483648, "i64_data": -9223372036854775808, "i8_data": -128, "isize_data": -9223372036854775808, "str_data": "", "u128_data": 0, "u16_data": 0, "u32_data": 0, "u64_data": 0, "u8_data": 0, "usize_data": 0}]}' + ) + + def test_script_group_type_type(self): + """ + type合约 ,预期:成功 + 不存在匹配的script_hash,预期:报错 IPC: ScriptNotFound + 已经上过链的tx,预期:报错:TransactionFailedToResolve + Returns: + + """ + account = self.Ckb_cli.util_key_info_by_private_key( + self.Config.ACCOUNT_PRIVATE_1 + ) + account1 = self.Ckb_cli.util_key_info_by_private_key( + self.Config.ACCOUNT_PRIVATE_2 + ) + account2 = self.Ckb_cli.util_key_info_by_private_key( + self.Config.MINER_PRIVATE_1 + ) + + # deploy + udtContract = UdtContract() + udtContract.deploy(self.Config.ACCOUNT_PRIVATE_1, self.node) + deploy_hash, deploy_index = udtContract.get_deploy_hash_and_index() + # issue + invoke_arg, invoke_data = udtContract.issue(account1["lock_arg"], 100000) + tx_hash = self.Contract.invoke_ckb_contract( + account_private=self.Config.ACCOUNT_PRIVATE_2, + contract_out_point_tx_hash=deploy_hash, + contract_out_point_tx_index=deploy_index, + type_script_arg=invoke_arg, + hash_type="type", + data=invoke_data, + fee=1000, + api_url=self.node.getClient().url, + cell_deps=[], + input_cells=[], + output_lock_arg=account2["lock_arg"], + ) + tx = self.node.getClient().get_transaction(tx_hash) + + print("tx:", tx) + molecule_hex = self.Ckb_cli.molecule_encode( + tx["transaction"]["outputs"][0]["type"], "Script" + ) + data = bytes.fromhex(molecule_hex.replace("0x", "")) + personalization = "ckb-default-hash".encode("utf-8") + # cal blake 2b hash + hash_object = hashlib.blake2b(digest_size=32, person=personalization) + hash_object.update(data) + script_hash = "0x" + hash_object.hexdigest() + print("hex:", script_hash) + tx = tx["transaction"] + del tx["hash"] + ipc_script_locator = { + "out_point": {"index": "0x0", "tx_hash": self.ipc_test_contract_tx_hash}, + } + ipc_req = { + "version": "0x0", + "method_id": "0x0", + "payload_format": "json", + "payload": { + "SyscallLoadScript": {}, + }, + } + ipc_env = { + "tx": tx, + "script_group_type": "type", + "script_hash": script_hash, + } + ipc_call_result = self.node.getClient().ipc_call( + ipc_script_locator, ipc_req, ipc_env + ) + print("ipc_call_result:", ipc_call_result) + + # 不匹配hash + ipc_env["script_hash"] = ( + "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8" + ) + + # ScriptNotFound + with pytest.raises(Exception) as exc_info: + ipc_call_result = self.node.getClient().ipc_call( + ipc_script_locator, ipc_req, ipc_env + ) + expected_error_message = "ScriptNotFound" + assert ( + expected_error_message in exc_info.value.args[0] + ), f"Expected substring '{expected_error_message}' not found in actual string '{exc_info.value.args[0]}'" + + self.Miner.miner_until_tx_committed(self.node, tx_hash) + + with pytest.raises(Exception) as exc_info: + self.node.getClient().ipc_call(ipc_script_locator, ipc_req, ipc_env) + expected_error_message = "TransactionFailedToResolve: Unknown(OutPoint" + assert ( + expected_error_message in exc_info.value.args[0] + ), f"Expected substring '{expected_error_message}' not found in actual string '{exc_info.value.args[0]}'" + + def test_script_is_data_data1_data2(self): + """ + tx的script 是data + tx的script 是data1 + tx的script 是data2 + Returns: + + """ + + account1 = self.Ckb_cli.util_key_info_by_private_key( + self.Config.MINER_PRIVATE_1 + ) + + # deploy + udtContract = UdtContract() + udtContract.deploy(self.Config.ACCOUNT_PRIVATE_1, self.node) + deploy_hash, deploy_index = udtContract.get_deploy_hash_and_index() + # data + invoke_arg, invoke_data = udtContract.issue(account1["lock_arg"], 100000) + tx = self.Contract.build_invoke_ckb_contract( + account_private=self.Config.MINER_PRIVATE_1, + contract_out_point_tx_hash=deploy_hash, + contract_out_point_tx_index=deploy_index, + type_script_arg=invoke_arg, + hash_type="data", + data=invoke_data, + fee=1000, + api_url=self.node.getClient().url, + ) + + print("tx:", tx) + molecule_hex = self.Ckb_cli.molecule_encode(tx["outputs"][0]["type"], "Script") + data = bytes.fromhex(molecule_hex.replace("0x", "")) + personalization = "ckb-default-hash".encode("utf-8") + # cal blake 2b hash + hash_object = hashlib.blake2b(digest_size=32, person=personalization) + hash_object.update(data) + script_hash = "0x" + hash_object.hexdigest() + print("hex:", script_hash) + # tx = tx["transaction"] + # del tx["hash"] + ipc_script_locator = { + "out_point": {"index": "0x0", "tx_hash": self.ipc_test_contract_tx_hash}, + } + ipc_req = { + "version": "0x0", + "method_id": "0x0", + "payload_format": "json", + "payload": { + "SyscallLoadScript": {}, + }, + } + ipc_env = { + "tx": tx, + "script_group_type": "type", + "script_hash": script_hash, + } + + with pytest.raises(Exception) as exc_info: + ipc_call_result = self.node.getClient().ipc_call( + ipc_script_locator, ipc_req, ipc_env + ) + expected_error_message = "IPC: sending on a closed channel" + assert ( + expected_error_message in exc_info.value.args[0] + ), f"Expected substring '{expected_error_message}' not found in actual string '{exc_info.value.args[0]}'" + + # data1 + invoke_arg, invoke_data = udtContract.issue(account1["lock_arg"], 100000) + tx = self.Contract.build_invoke_ckb_contract( + account_private=self.Config.MINER_PRIVATE_1, + contract_out_point_tx_hash=deploy_hash, + contract_out_point_tx_index=deploy_index, + type_script_arg=invoke_arg, + hash_type="data1", + data=invoke_data, + fee=1000, + api_url=self.node.getClient().url, + ) + + molecule_hex = self.Ckb_cli.molecule_encode(tx["outputs"][0]["type"], "Script") + data = bytes.fromhex(molecule_hex.replace("0x", "")) + personalization = "ckb-default-hash".encode("utf-8") + # cal blake 2b hash + hash_object = hashlib.blake2b(digest_size=32, person=personalization) + hash_object.update(data) + script_hash = "0x" + hash_object.hexdigest() + print("hex:", script_hash) + # tx = tx["transaction"] + # del tx["hash"] + ipc_script_locator = { + "out_point": {"index": "0x0", "tx_hash": self.ipc_test_contract_tx_hash}, + } + ipc_req = { + "version": "0x0", + "method_id": "0x0", + "payload_format": "json", + "payload": { + "SyscallLoadScript": {}, + }, + } + ipc_env = { + "tx": tx, + "script_group_type": "type", + "script_hash": script_hash, + } + ipc_call_result = self.node.getClient().ipc_call( + ipc_script_locator, ipc_req, ipc_env + ) + + # data2 + invoke_arg, invoke_data = udtContract.issue(account1["lock_arg"], 100000) + tx = self.Contract.build_invoke_ckb_contract( + account_private=self.Config.MINER_PRIVATE_1, + contract_out_point_tx_hash=deploy_hash, + contract_out_point_tx_index=deploy_index, + type_script_arg=invoke_arg, + hash_type="data2", + data=invoke_data, + fee=1000, + api_url=self.node.getClient().url, + ) + + print("tx:", tx) + molecule_hex = self.Ckb_cli.molecule_encode(tx["outputs"][0]["type"], "Script") + data = bytes.fromhex(molecule_hex.replace("0x", "")) + personalization = "ckb-default-hash".encode("utf-8") + # cal blake 2b hash + hash_object = hashlib.blake2b(digest_size=32, person=personalization) + hash_object.update(data) + script_hash = "0x" + hash_object.hexdigest() + print("hex:", script_hash) + # tx = tx["transaction"] + # del tx["hash"] + ipc_script_locator = { + "out_point": {"index": "0x0", "tx_hash": self.ipc_test_contract_tx_hash}, + } + ipc_req = { + "version": "0x0", + "method_id": "0x0", + "payload_format": "json", + "payload": { + "SyscallLoadScript": {}, + }, + } + ipc_env = { + "tx": tx, + "script_group_type": "type", + "script_hash": script_hash, + } + ipc_call_result = self.node.getClient().ipc_call( + ipc_script_locator, ipc_req, ipc_env + ) + + def test_cycle_limit(self): + """ + cycle执行特别大,测试cycle 请求最大值100亿,超过100亿,报错:IPC: ReadVlqError + Returns: + """ + # deploy math contract + ipc_script_locator = { + "out_point": {"index": "0x0", "tx_hash": self.ipc_test_contract_tx_hash} + } + ipc_req = { + "version": "0x0", + "method_id": "0x0", + "payload_format": "json", + "payload": { + "TestCycle": {"cycle_limit": 9999994700}, + }, + } + ipc_ret = self.node.getClient().ipc_call(ipc_script_locator, ipc_req) + print(f"main: call result json={ipc_ret}") + assert ipc_ret["payload"]["TestCycle"] > 9999994700 + ipc_req = { + "version": "0x0", + "method_id": "0x0", + "payload_format": "json", + "payload": { + "TestCycle": {"cycle_limit": 10000000000}, + }, + } + + with pytest.raises(Exception) as exc_info: + ipc_ret = self.node.getClient().ipc_call(ipc_script_locator, ipc_req) + expected_error_message = "IPC: ReadVlqError" + assert ( + expected_error_message in exc_info.value.args[0] + ), f"Expected substring '{expected_error_message}' not found in actual string '{exc_info.value.args[0]}'" + + def test_payload_limit(self): + """ + 测试返回payload 最大值,请求小于64k,成功,超过64k ,报错::IPC: ReadVlqError + Returns: + + """ + # deploy math contract + ipc_script_locator = { + "out_point": {"index": "0x0", "tx_hash": self.ipc_test_contract_tx_hash} + } + ipc_req = { + "version": "0x0", + "method_id": "0x0", + "payload_format": "json", + "payload": { + "TestMem": {"byte_data": 1000, "kb_data": 63, "mb_data": 0}, + }, + } + ipc_ret = self.node.getClient().ipc_call(ipc_script_locator, ipc_req) + print(f"main: call result json={ipc_ret}") + assert len(ipc_ret["payload"]["TestMem"]) == 1000 + 63 * 1024 + + ipc_req = { + "version": "0x0", + "method_id": "0x0", + "payload_format": "json", + "payload": { + "TestMem": {"byte_data": 0, "kb_data": 64, "mb_data": 0}, + }, + } + + with pytest.raises(Exception) as exc_info: + ipc_ret = self.node.getClient().ipc_call(ipc_script_locator, ipc_req) + expected_error_message = "IPC: ReadVlqError" + assert ( + expected_error_message in exc_info.value.args[0] + ), f"Expected substring '{expected_error_message}' not found in actual string '{exc_info.value.args[0]}'" + + def test_input_payload(self): + """ + payload 请求特别大,测试payload 请求最大值,如果是str 128*1024 ,vec 1024 * 64 就会报错:IPC: ReadVlqError~~ + + Returns: + + """ + ipc_script_locator = { + "out_point": {"index": "0x0", "tx_hash": self.ipc_test_contract_tx_hash} + } + ipc_req = { + "version": "0x0", + "method_id": "0x0", + "payload_format": "json", + "payload": { + "TestInputPayload": {"s": rand_str(1024 * 128)}, + }, + } + ipc_ret = self.node.getClient().ipc_call(ipc_script_locator, ipc_req) + print(f"main: call result json={ipc_ret}") + + ipc_req = { + "version": "0x0", + "method_id": "0x0", + "payload_format": "json", + "payload": { + "TestInputPayload": {"s": rand_str(1024 * 129)}, + }, + } + with pytest.raises(Exception) as exc_info: + ipc_ret = self.node.getClient().ipc_call(ipc_script_locator, ipc_req) + expected_error_message = "IPC: ReadVlqError" + assert ( + expected_error_message in exc_info.value.args[0] + ), f"Expected substring '{expected_error_message}' not found in actual string '{exc_info.value.args[0]}'" + + ipc_req = { + "version": "0x0", + "method_id": "0x0", + "payload_format": "json", + "payload": { + "TestInputVec": {"vec": [1] * 1024 * 64}, + }, + } + ipc_ret = self.node.getClient().ipc_call(ipc_script_locator, ipc_req) + assert ipc_ret["payload"]["TestInputVec"] == 1024 * 64 + + ipc_req = { + "version": "0x0", + "method_id": "0x0", + "payload_format": "json", + "payload": { + "TestInputVec": {"vec": [1] * 1024 * 65}, + }, + } + with pytest.raises(Exception) as exc_info: + ipc_ret = self.node.getClient().ipc_call(ipc_script_locator, ipc_req) + expected_error_message = "IPC: ReadVlqError" + assert ( + expected_error_message in exc_info.value.args[0] + ), f"Expected substring '{expected_error_message}' not found in actual string '{exc_info.value.args[0]}'" + + def test_ckb_opcode(self): + """ + 有IpcEnv 测试所有的block 操作是否能正常使用 + 调用查询 opcode + + 没有IpcEnv 测试所有的block 操作是否能正常使用 + 调用查询opcode, current_cycle,load 一些查询会失败,报错:返回 + Returns: + + """ + account1 = self.Ckb_cli.util_key_info_by_private_key( + self.Config.MINER_PRIVATE_1 + ) + # deploy + udtContract = UdtContract() + udtContract.deploy(self.Config.ACCOUNT_PRIVATE_1, self.node) + deploy_hash, deploy_index = udtContract.get_deploy_hash_and_index() + # data + invoke_arg, invoke_data = udtContract.issue(account1["lock_arg"], 100000) + tx = self.Contract.build_invoke_ckb_contract( + account_private=self.Config.MINER_PRIVATE_1, + contract_out_point_tx_hash=deploy_hash, + contract_out_point_tx_index=deploy_index, + type_script_arg=invoke_arg, + hash_type="type", + data=invoke_data, + fee=1000, + api_url=self.node.getClient().url, + ) + + print("tx:", tx) + molecule_hex = self.Ckb_cli.molecule_encode(tx["outputs"][0]["type"], "Script") + data = bytes.fromhex(molecule_hex.replace("0x", "")) + personalization = "ckb-default-hash".encode("utf-8") + # cal blake 2b hash + hash_object = hashlib.blake2b(digest_size=32, person=personalization) + hash_object.update(data) + script_hash = "0x" + hash_object.hexdigest() + print("hex:", script_hash) + # tx = tx["transaction"] + # del tx["hash"] + ipc_script_locator = { + "out_point": {"index": "0x0", "tx_hash": self.ipc_test_contract_tx_hash}, + } + ipc_req = { + "version": "0x0", + "method_id": "0x0", + "payload_format": "json", + "payload": { + "TestCkbCall": {}, + }, + } + ipc_env = { + "tx": tx, + "script_group_type": "type", + "script_hash": script_hash, + } + + ipc_call_result = self.node.getClient().ipc_call( + ipc_script_locator, ipc_req, ipc_env + ) + + with pytest.raises(Exception) as exc_info: + ipc_call_result = self.node.getClient().ipc_call( + ipc_script_locator, ipc_req, None + ) + expected_error_message = "IPC: ReadVlqError" + assert ( + expected_error_message in exc_info.value.args[0] + ), f"Expected substring '{expected_error_message}' not found in actual string '{exc_info.value.args[0]}'" + + def test_empty(self): + """ + + Returns: + + """ + tx = self.node.getClient().get_transaction(self.ipc_test_contract_tx_hash) + ipc_script_locator = { + "type_id_args": tx["transaction"]["outputs"][0]["type"]["args"], + } + ipc_req = { + "version": "0x0", + "method_id": "0x0", + "payload_format": "json", + "payload": { + "TestEmpty": {}, + }, + } + ipc_ret = self.node.getClient().ipc_call(ipc_script_locator, ipc_req) + print(f"main: call result json={ipc_ret}") + assert ipc_ret["payload"]["TestEmpty"] == None + + def test_ipc_time_with_exec(self): + """ + 死循环,执行时间超过8s,预期:rpc返回sending on a closed channel,vm 继续执行 + Returns: + + """ + account = self.Ckb_cli.util_key_info_by_private_key( + self.Config.ACCOUNT_PRIVATE_1 + ) + father_tx_hash = self.Ckb_cli.wallet_transfer_by_private_key( + self.Config.ACCOUNT_PRIVATE_1, + account["address"]["testnet"], + 100000, + self.node.getClient().url, + ) + self.Miner.miner_until_tx_committed(self.node, father_tx_hash) + + tx = self.Tx.build_send_transfer_self_tx_with_input( + [father_tx_hash], + ["0x0"], + self.Config.ACCOUNT_PRIVATE_1, + output_count=15, + fee=15000, + api_url=self.node.getClient().url, + dep_cells=[ + { + "tx_hash": self.ipc_test_with_exec_contract_tx_hash, + "index_hex": hex(0), + }, + ], + ) + result = self.node.getClient().test_tx_pool_accept(tx, "passthrough") + print("result:", result) + # + ipc_script_locator = { + "out_point": { + "index": "0x0", + "tx_hash": self.ipc_test_with_exec_contract_tx_hash, + }, + } + ipc_req = { + "version": "0x0", + "method_id": "0x0", + "payload_format": "json", + "payload": { + "TestCurrentCycle": {}, + }, + } + ipc_env = { + "tx": tx, + "script_group_type": "lock", + "script_hash": account["lock_hash"], + } + + # IPC: sending on a closed channel + with pytest.raises(Exception) as exc_info: + ipc_call_result = self.node.getClient().ipc_call( + ipc_script_locator, ipc_req, ipc_env + ) + expected_error_message = "sending on a closed channel" + assert ( + expected_error_message in exc_info.value.args[0] + ), f"Expected substring '{expected_error_message}' not found in actual string '{exc_info.value.args[0]}'" + + +def rand_str(size): + """ + 生成随机字符串 + :param size: 字符串长度 + :return: 随机字符串 + """ + return "".join(random.choice(string.ascii_letters) for _ in range(size)) diff --git a/test_cases/ipc_call/test_ipc_call_without_indexer.py b/test_cases/ipc_call/test_ipc_call_without_indexer.py new file mode 100644 index 00000000..9b4a444d --- /dev/null +++ b/test_cases/ipc_call/test_ipc_call_without_indexer.py @@ -0,0 +1,88 @@ +import time + +import pytest + +from framework.basic import CkbTest +from framework.util import get_project_root + + +class TestIpcWithOutIndexer(CkbTest): + + @classmethod + def setup_class(cls): + """ + 1. start node in issue/node1 + 2. generate 2 epoch + Returns: + + """ + + # 1. start node in issue/node1 + node1 = cls.CkbNode.init_dev_by_port( + cls.CkbNodeConfigPath.CURRENT_TEST, "ipc_call/node1", 8114, 8927 + ) + cls.node = node1 + node1.prepare( + other_ckb_config={ + "ckb_rpc_modules": [ + "Net", + "Pool", + "Miner", + "Chain", + "Stats", + "Subscription", + "Experiment", + "Debug", + "IntegrationTest", + "IPC", + ] + } + ) + node1.start() + + # 2. miner 400 block + # cls.Miner.make_tip_height_number(cls.node, 400) + cls.node.getClient().generate_epochs("0x2") + time.sleep(3) + cls.ipc_test_contract_tx_hash = cls.Contract.deploy_ckb_contract( + cls.Config.ACCOUNT_PRIVATE_1, + f"{get_project_root()}/source/contract/ipc_test/ipc_test", + ) + cls.Miner.miner_until_tx_committed(cls.node, cls.ipc_test_contract_tx_hash) + + @classmethod + def teardown_class(cls): + print("\nTeardown TestClass1") + cls.node.stop() + cls.node.clean() + + def test_type_id_args_without_indexer(self): + """ + 没开启index模块,IpcScriptLocator 使用type_id_args 模式,报错:Query by type id requires enabling Indexer + Returns: + + """ + tx = self.node.getClient().get_transaction(self.ipc_test_contract_tx_hash) + ipc_script_locator = { + "type_id_args": tx["transaction"]["outputs"][0]["type"]["args"], + } + ipc_req = { + "version": "0x0", + "method_id": "0x0", + "payload_format": "json", + "payload": { + "MathAdd": {"a": 2, "b": 1}, + }, + } + ipc_ret = self.node.getClient().ipc_call(ipc_script_locator, ipc_req) + print(f"main: call result json={ipc_ret}") + assert ipc_ret["payload"]["MathAdd"] == 3 + self.node.stop() + self.node.start_without_indexer() + + with pytest.raises(Exception) as exc_info: + ipc_ret = self.node.getClient().ipc_call(ipc_script_locator, ipc_req) + expected_error_message = "Query by type id requires enabling Indexer" + assert ( + expected_error_message in exc_info.value.args[0] + ), f"Expected substring '{expected_error_message}' not found in actual string '{exc_info.value.args[0]}'"