From 7da249cca1891fc46eff7660f46218de37bc0aea Mon Sep 17 00:00:00 2001 From: Redo Date: Sun, 5 Oct 2025 20:42:40 -0500 Subject: [PATCH 1/3] replace compile.bat with instructions in readme, remove third-party lualibs, add string type, fix luacall args --- BlockLua.dll | Bin 374823 -> 374823 bytes compile.bat | 16 -- lualib/https.dll | Bin 341033 -> 0 bytes lualib/ltn12.lua | 292 ---------------------------------- lualib/mime.lua | 87 ---------- lualib/mime/core.dll | Bin 24576 -> 0 bytes lualib/socket.lua | 133 ---------------- lualib/socket/core.dll | Bin 32768 -> 0 bytes lualib/socket/ftp.lua | 281 --------------------------------- lualib/socket/http.lua | 350 ----------------------------------------- lualib/socket/smtp.lua | 251 ----------------------------- lualib/socket/tp.lua | 123 --------------- lualib/socket/url.lua | 297 ---------------------------------- readme.md | 16 +- src/util/libbl.lua | 20 +-- 15 files changed, 20 insertions(+), 1846 deletions(-) delete mode 100644 compile.bat delete mode 100644 lualib/https.dll delete mode 100644 lualib/ltn12.lua delete mode 100644 lualib/mime.lua delete mode 100644 lualib/mime/core.dll delete mode 100644 lualib/socket.lua delete mode 100644 lualib/socket/core.dll delete mode 100644 lualib/socket/ftp.lua delete mode 100644 lualib/socket/http.lua delete mode 100644 lualib/socket/smtp.lua delete mode 100644 lualib/socket/tp.lua delete mode 100644 lualib/socket/url.lua diff --git a/BlockLua.dll b/BlockLua.dll index 962b4c36051ea8f2f51ad4d30783660b1c4d17f6..57a349acfbba67d687287175e87d983812396b16 100644 GIT binary patch delta 6854 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 JYjjB9e*kI*19boZ diff --git a/compile.bat b/compile.bat deleted file mode 100644 index d812f9a..0000000 --- a/compile.bat +++ /dev/null @@ -1,16 +0,0 @@ -@echo off -cd /d %~dp0 - -set buildargs=-Wall -Werror -m32 -shared -Isrc -Iinc/tsfuncs -Iinc/lua -lpsapi -L. -llua5.1 -static-libgcc -static-libstdc++ - -echo on - -g++ src/bllua4.cpp %buildargs% -o BlockLua.dll -@rem g++ -DBLLUA_UNSAFE src/bllua4.cpp %buildargs% -o BlockLua-Unsafe.dll - -@echo off - -rem objdump -d BlockLua.dll > BlockLua.dll.dump.txt -rem objdump -d BlockLua-Unsafe.dll > BlockLua-Unsafe.dll.dump.txt - -pause diff --git a/lualib/https.dll b/lualib/https.dll deleted file mode 100644 index af815bbfc5a3f6e41749b3cd26bfe5a432e8e9cb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 341033 zcmeFa4|rTvwf{ZSCXkkt2@oJkg#f9vwm`vxEu|8;94%bptxBXS<&XTomjbs;1eE^4 zNu=X28nM-?ppC8GUai`Dtx%y#QfgBKH9+(RX*FWh6DC)qL|U|(-{-sbK4&I>iuk_o z^SsaVK5vzrbM{_)?X}llYwfky{xc2lYfVf{Bobx(H$0q3Y~!ha_4fDG|EwbW@Dm<6 zJh64s4^P~dyyS-`UV7tAx7Xgb?A9BWUA?sSnyYWQ<<@lV2d=AK)^tnlO}Eru_%H9S zU3%-a*PS+H%H%qadQp%_T#~FxEWYW<8xmnM@yVkSiQdE^CmxoZFe_1(OeA*kUu7ck z`Xeb&#ecPYC+e2k`vga~P>Fu~x5XvCq3RIYRS$5jE2jb~&p&(gCKDIyV=$R$JwY!A z`Byt3G3U^O2aU)!*s}hN;PP_K% z^woTBRZ=Z5!dbzya^DNax?|W&Bx0zKD3!Sh&+Z zaQp3ot3QlCT_f|Au79gk?{%(T<0U*b`o1s{z8*BE-Q?hm*YG@13xf6Iz@=}tdMn6I zRMA+qw|xv8?Y-{iTdzsDzNrOB1$K;qyWsRQT!ZHd-)xWX2jjq_ zyY;u#!}W~=H_y@cA!V)iaK9M~XUO=|nEiETpr*5|uB>a?((vP(6Nx7tx3tBX<&}x1 zliCubx3sTF*-Iu&ZcsvDve}9LZV&^POtqZJTW2sJw4FhpG$I%DU7Jf}gWeqfuP@66 zVP`O;{K84OU|@a_HccWylojSve~1-o+x^nCrNdpBfwG*S_sn^I+R|*$(;0NDT&|%f z7j)+u_Y9`~YjQRi$Sfa7G;M903s7c%vgvS;NRh*f{tJ|+Sb9r))A601r37uJ>a zHB4Iy;2s{~Tma+Z$1AtT<#sFg_2jy;aFJFHC7O=u47x;9XYdqBiCp7TxuEObsNh0v*BuCXFpU8hD>Iu^D&7WRM2uvR8gEm__=gF*f#3P+4#MQ5V`VgQdG<|4X?6?1Qco@EAgCVg$)hr zwQl%-G6NOaT}qizlCq%;f?8fqAEAtD6)CIRwum}@%1e87-O}(fsLfwD^!_WZT=IDS zA$8!k`Wxz&es4B^3hnvy8@-ga8K(C1qzFS-n@E7hN~Co7=m#8KPdwggwrwuWULEwM z9t!$a2m5&J1FG%XAsHXz3=OW!2ceU9i9PZzOkonck2vOo-)Dot*4A8O2&#O;@3WWG zRiO1{xyB*1J=+nsFR*?RU`KeuZfthp*zDu(vr3=Y9^w1`J0*1$xg`gpdaG4aN4WZ} zRP?xee?ae-Q-RT80{ma!07Xfu3ne&r9ii?7>+R%b+LOtk(kFb3g#J~qFCXlN*%g12 z6kwR3Sn!j@=Ac(Oyp`q*0*RpI8+W^Ay@KJR^Rqhur)2i&@SEpaioQF-ukxYJH2jX1 z)2W(T$;^|f1{GWJ?AH^CmiE-z_U86f%hl98s_aYT7wW_|A#b33VS>Jd?L5955ARt7 zUe7>@>TD#xi{5t%67}3SU0q+GuC&BH*I4bEbO?xOQol@kKG@^UcdoHA;?4lZf(+_> zv+CUC-cQ#%v?%>J-XXnm5Sh)U>8Q&cUmyQtBJqew5g5!BMkKVJl<@K2`@DHwsWl?% z^u{8q*1@KHD>B4ZX`jwQGJiz{^9{`X(8MC19p?-|&L zHO#l1>$q$lWQhb+sEsXq=(qe@fw;QPtG2p!1^cX5Z8&qidNovK_Lm#wspfOY0VtVo zk-}z!zSh=!ORFKX1lR0)X&W^ErdvoWJZwie;rocP+MXj{0#H)Tm%irY39N{r$@Xta zLT0`wnQ5jdZCXsO5ExWZs^?$}U7IrPv-4{O<(hQ>SC1Zd1)*q&?|hKMRT15{0he#g z`Mzp(M4u56?N}rjhieF31{b}$-a&pQLT)e}p}vK@BYfRX8tV80_znktqXSpFOO)o% zU$u5ubdF`oC&f_Y_lMcwZ3%@ttvPn&$ACwbp%&!%bBkjA4 zaoa)U8#lU!R3ifFzhEPUenp{NOOHwv4a>*=Gb)s6uPI6Y?4O5+S1sR%EAbs9N1Wqf ze9+TN*tEDXHa-^&QpuNgp;;|yDskT*vhUmYE?kzkbbwC%7C^xO&TUDJr%)p)Bgr_D zL@^4bi^Mu%m8u3XeGN%L5Ph3`1=#6B@e!NboAPQx`p`!;Z!eTTDt$q&JQJTaM8?66 z@J!>iDRf6Tg_%aSr~jX@16T~FsvTjbgVOzSm6Yg(_Jy+}Q!Bx}N+4!=qi)+le*ZJn zoB4AxeQ5Ua{%`ZHk>r=mdhqn~!SmT*594DH<`{`8a#g%#JBFWO;Apv%cI6wMXUHsb z{n_26{;W`;j_{>+D)T+@?0<+4f+yn^kzefM$H=p$#{j27RJa%d`hTwy*k<9|Abf?C z8s`y}3vM=Wu1TJ6pWhTEc;3AnCwTt-P;IkOJ9RO_;zu0Kp2nA>y(Y} zIE>S_shKl+vOBU}$@XMdNAJY^)I;XI6tU;zIk0CiyI&G{%|c|zyO8GmRfJE#Zd^h6 zg7Oz?BTxAv9OGPBOATJB)BIR=u>r%+Fh-w@`YW+g0$q`7sFV=r8V0kK_PZ!l%xpZ{#x1QnQ~6&xK5l9f;4?ch@bIMW|Uo&eXc_E`jdS+e*C+ zswJO&`=~*k>b_G2vEg6P1@F;Ue5YC|-$9BZAD;@pa{|1aJcQLLt9w%Ke|u?oIDGPq zL}EiPQqvk04u60kiZ#wpo}O(OQd4XS3;*x^r4iiv#E!CrAP~H5=bl8%4uP~8JG1$| zy~uHk{sKMi%d*V+=&YYj`?0T;`9(GPmN`@snfJMHCiRddWd@V-11kQRW!lYOeX?J6FnvbE*bmc??BlyyennkL82ipj*$tt9gHZA?mKjDDnuP5Gqp>Y_ z*iMvgc7)gbH@L7;R@z+oyL{=lMAem9b$s3E`Y}xx9i$)si-vn#9btuBxvJcesfY77 zLR;$LCnP@ky!esnm|7Gf&xzk5<@uJ-aq}%yY7AVMZ&@h&X0%;IDpiw#j|27RLyCFS ztApQqxQ=j^OEfQY+N$NhW$bw5!;oGme`J+0qloW0=mnoI3b$PSm~ctpd~(IYX0@B| zH>-7Pjr<*RqaHoR1AWv39nQDhehUOa;zw}Avn{h|0)ZjE&#~|6d>3xWTRMql|9 zJwdlD)CeLTI^7X*zsLU#zH^P;nH@C|1#3LSS`Tp_-!bOXu_5^uRp&5^5Vhs8P%@Qj zxr@$F8`n{IM7?kGST~Q(I92F97p6uuRE?scf^TDeAmrZ~jidiGNpReaAA@HQg(%nZ z=47iZYR-3o6%u`qpl~A@R>yH3(P-9v7yzV^7U$QRSeXp{FQi$Yo5**BSK~oI%S4Ua za~(K6vJWWcK31B~UVWx*nv;Fb=J#>dm#r3)sg7`+eRvuEH~Y9s9PbFPcf?3ZJHr3n zB-P05D9atGrX^}2G;gJ1%Zfum>@VM<;*v)u6{W2h1|0@5vwTk?J)!WGR>*Ov@As%H zb4SWX#}-MU$9zkbBj%M;;}2t+(TG%>Pr3-&X}mUIQm_1t*`LXe%0l(m;ea`;`9-rG zeNH*kMp9Y0`XP9QNfA;Zn@lMO@jgd1z4%vS!!oMte}rt8Vyxf`Q*(~W;4ixZ1V!UA zSCBN5?}g}7Pks@jdUF(wfIq@(y?la|tjs+qgPac@$TjxBLi5)_jQ|%xhoFLJ8bD44 ztG1hfXwu)Tl&8Z-W;u}oq9gn^AIiaRt{$}K`E?d*evam&wD#Vr*|T5BC<4gGIidudEdf($jSvqe*@ z;u~TC1Ad$hx|r@YY}M<9byYco&#e_K-;%G&oFUJxtyCHfN94jscL{y9>u}uqeB)Nf z;IGW|JlRUi+V~LSj__nUzx7dMttf2Gg8WOeX@aJkMtDcKh%|z9vDD7_y8pJpvLn3j zK_ufZV9D-U^<9l~iFB3N#_*Yto3Q##JYVYHXb?(xyG!_#67YSc^iVTN)hLGI#*mJ1 zKVUAw>u9GEu9EkxzI`srw*GxG`ikWB5hWZUU^R8_x8-UZcCS{SiwpQ>-V`Tz?Yv~O z7~>oH9}hTU9CN{V2(5N5w_;#k$(%E{qe8Ji;u>pcp&PpAP@Fe9$gf0T21``v$4D4B z-zM%8j$~@WWUVpGK0Tu&*EqoRK=vYz<5jv|4Ivm^04=^peyzcnm_0nhb+;?l5q^{J zTo7j3C*pZiajvmX@`CDODW$sKGfdR0VD@m+6kteQPbx`xSu=ya><%TOmBqr(I-;|V zjLiOFA1&LAM2)D$8;HeGErXzB%w=I zBo(OZvy0|vcn$^&i+Ror2F<<oDw)ozX@*s49pOFG zRZX94Iuq=m2h%l^7#S93lWYGTF;77_WA+Ceej|TszHyUFodXgLT$JeuPv;{av{SW@ z0}YM9P+NjwZoaYIVff=I9z#1A{+AD{VJ;sPz~e}n&vdLyr7M5pdgEKJ7|FX5$-*?r zzZ$ifWQjlNeEsaRk?i&omun@_=4+8}y)fH=dn3RHq1>cV^3ZA@eR+5z)5)wE27dT? zCq zdv)-86C@wF{;g}A9g9<_Ce_CrEKF6R+6XFr9G|#zSOQFL=0X6zGI8b z&Uxwueg3yTV`McEvKq1uGqmF?=?ZzNPj0uwFJ6M~o z=tnkxE!H&GqQBtDe}+iz_O}wabtw!b%IU1PKv?Rb@;;_m=F+Fn&bQpCLUb+CGy%t< zZM(0dqVPH-C&Kwoa5}@cfk2&$^cUx3t~T_$O0%>2GR#8yaQ7;4nTsKl_IHGnLE~x9 z4EWg`$=?D%I$D9K2#_)h>->a~32{2xuo02CJ{zo;I@L;`faZaQbqV?wj4tc5O39(N zL6={m?F@P}()sn#)WePI^TAeioeC{zS9y(&8>Z1ZuO^@2J>U2gK$ZE%E*??zyzME^ znJUGfbHP(GMk_P{ueT|)Di>L*5cF+59=uYfW@C0ynSoYiJM4+LZOpx^%q$m$Q2(}_ zQ32C)zYyg531)7j8c|)qBQXq9sb5P)4q~!aTvIJtPZMd>zuTiLD*~||v(byeqav4J zov3w8SaGtt*hTNflw0guRc;~DW#U+2v+T^kTvHznDKvpLR|=V&6v?S?O;^M%zgl|N zq2374!BRvgJ+B2*_iMrw#ReRgzE8xNihN_EctTmW;Xp1p04Gag3eM=QUQY`YT43m_ zN@{R$7I_nv1BK%|wp%wjhi>e`OwT7xx}}(`*Ezhi4}y1*!>h&H^tphde#S&}#GyBN zR2??p{K=Dn?JP=UcqumLJ1~B^B}y(*d%3HzxEyH9l0RyNYiim%X@SsKBW8P8X<8A(>m!;+ zG;IwS0E?Mk`>^#xp?XBw$u1S*+*syW@4`gT{*n7Jg%8LSdgFxCL~@4(!I2IVT=FvQ z=w&z?Z1ypgkCXY3GN@!n_)ZXc`$v#0VkEIvsv1!Nus=Dn1kDicc3i=4qYn}BJx2s@ zLr!jr_SDt+d2baNCWS&>bLI(=RlH}QndCg1QDVWl>%Waf$h;!(xj?OWg5gaAQ3=?) z99VWS+A5Hb%cmU)a=HhpkpmOspEnA>MzEVa{t~bwOYjTiG>^XoD>zT8(CY&TCO8*Ix3qOJ=c-C58R zM>O`52!6{paWfliE*#z&FqEqj<_LNWxyPU$a+Fz1To++`i##TJZ0JXpm&f}y9T;41 zO;>J5nB&70TuVWXC*BMHsC~*50aZ??V`OJpHI20xfa#j#U0PR{YaHZJOXgH%$`QS^ zPT~J*ee$f*Q!C4iX3jnjNztW|vg>5CJZMlLK5`p~9Mm!R7qCRS@MeQL+Ck-7R2fDk_3&CjryhO=s+lKvi+Aom?V_phL$r;# z{RPAuL=!;di0c2OL(cd)mj=*nUIDhKlRlLrDcGVUc6+U2I@1~S&Yn;&xLOj?hE4S8 zR6c9;$0mR4N~==B?AciH2HwtRuXD1o*oP zmD&}&1k^@o$2zR$QLWNZOIAq?ay>JyAz zOqD%MuG}CQe$FzIZ{c9&hXio%-U&xDBU9Z5T>INV5OO4q$Z*a9;$lFWHZw zQ|Ya7<_S^eP_lom%j}LbKho;kxGyP>Y<2LmYADBSFd@&UE&oPJ>)qgG4t8Qs6x`XihPsvrwUrMBn)g9sEROe)MRG=%J zb~2E^4Tg)b_lhu2ug`?R>RDi^HEw@Pr7YDRS;6v$$kHs%*YqvY*}-;fzumF$wt zo1j^3=dgsQcuULOvJ-3VZ?Gx}2R*iLQ_d;-TjCa+^>Is+RZszE6}lXmMY^waP!NdB zX?f=S7(v>>Dx$E;mA*eNz0kG#2$xVKsf)$BW59B2jAezZppc3?G1c-dTwQ>&G0-H3 zXVvnT6X{d(!FpJ6Hj3L<@6yiw+e6$1p4uOK)S{b(N1(k(2tXlr3 zMEY2l^*e-%Qf+q+X=@rxN>(2)TKBJVVU1%TM_YHaIdS0%s94hYF9UbF)O*%IaEUe)Q*~ zzGIArQBQ}*IyM5e4k&Pc(1C!pKZG%{!?vuX&c#uke%om@(+R&iG`7yBF?DWmDb)F> zt8*Dc8XPRJbrb*7VoRk%$EW`2#MBy76vWL82b7W=`NmuvBlgqto@#;+FogB8EuDd)4SWzZ+=lz3kHWj;qWe|v z3Hkc{$uJXM*hvn6V{_^cnzPX5C}_jXVd4ijbp{)S1eXp15SuOdVA%Iuy~29&m?jWy z#PM_b|2o@>E+8zWN9@1c3fTgwWzwOEq} zI|H0WB3fc-uJM6+Y;x29l|0KNv@B`?I9v;s#UN!4aq~YZ8eVZRX$od#^w1^1(VvyC%NDkx#R09n&80Z4TBU@iQ>1tK0y1JRon6 zIdisy+GgGVU+Vsd%tcoFI+l-uHF4s6ODwj~Vy7}sD`_E!uZt1qSI0fS#&zq5T~$DN zb)M`%a*e_-brum$o&B8R97X`tIU8u3%JLZZC-04ME9{NkJ0Zrs+O_^Phg;!d^QB}` z!Uw-k`y{h*FB<*67hhT>cDE|;X)RO$)u(s~-8MCf!wbvHzq6)(DJJKSANAzq8dQ2l zN4B9i-nHA}2!a01jZnDnMDW_bWMTp2U# zO2-KeW}6(d9(3&nD(#rHz1cHsQ_QTpVwe>UW_JmUU!ZA>VLYC635<`aoe{&_=kTmA zfvNHKFNX1WW|hGB*>S&X1vLB4+wWjH17`8!+mIfG^Trtt7v&NQB!cPV$IYzD1!h^+ z#iQb*)bc>gzh7jGIpUv89KyC>G%YtfTI_7n3G|bB8ta_-7<6sC{YA5sg$l1{t+M0k z!z4I#T_?JS^!T-t*e63HRIfZ}HqKr6l|Z`?c~ zKHdaL9>yeg$>YP*Ru8c;taW%=vwyDg&pZ7yZBO*u#iwD^6EG?~`EF^99oR|RnW`5^ zRh1C+FXUnNqXnaI-(+Ar!praRo~B!6iQ3E&4F%l!uU!rH$1~g-4I9sHV{{7hbfz|* zZT(+b)1trN+q?o6+Q+DkXQ9?!yyx=RFR_=1%7jWq)XVyyGT$NqdQ7z5@VG6EPP(T7 zaaxrqoG7RlM?*F46jZ9^mI|s|Qkidgx7_$(yH@tK43l4L3DgOHeotx0`}LP4MHLQ! zs+ecK!x_@7-`}8;;>%(9S`K4J_&gKbR+$ynCV|ej^g?Ui{@Pe#MMe0_j_|s?OCkCy zW7n=QRoS0K0We=Mn5L=Ym4AmTKYB)bs4=2G5neFKI_*C&e7Fjk4O);h|@1t!a@})UXEiOoAc^|c; zREzcyF3h*=R#)0&^lbHiZHX{l4}?6xqOSkQ+k|^c68tDs-WlP-rFtvseD;JI&5fLXh;Q-~=8XcEH$6C>gSehp$9vltuXbRfa zn=6^w{~_Bilm7d>(3$F-;r11qad{nen{n|Z_7ge(M`?NO+^B?xxY;YHib-xiOtG%k z1|K&W4Tsap+MQXxJCVLE7wn$N95vXxhl}Y)%t!+)vH^M`>tcd(5VlAuHb>Sk8$6X+ z{!}8(W($F!&ez1iPBTC}MyIw!#eH8io$89?$+d{Cct5G>qV@bYjRh6`i)d3T(YX9t zYk=iF>e%Ca42ITx<9at1eF2sXMj zdy@%4$Sqp(%@1qfXxbdDZM&uIY6N+%4pdY^2GzJ=#ko=H%h(>afbqFdK)>ZP`#8#U z<{c)}Cd&%d1F&&7$1Z+8MG90rITU_c!;~-mpOh}{lc;g?|27@0w$N{MoFlWmg1w(U zR|lIdH`;Ph12$<;n~rIhmYc2;+GuEvb`E))&T9*(!s;EKHtS{Q^H2BBI{&Qo&#C@d z>OV{#oIlW&Sz%Cx>^yKSTfQ^Uq%Y+~c1;{@LxHUHAq zwsGZ#n>G$}Wrv@_m-#J)j5D0e5(uRVl3kYWQGr39iU=R6Ou`CCms_FC+d_aKiWLEe*i zLH+}{uHlt8V{4bh;NdlZGZQE|C;n|9!W#a-SDl@!kGks0+?2AX>1{1Rbo5TpnY;R}o83?xtkwBfo+^NkLl$*kRk zQW|Zc9oy87VMdj4s?1k&FmE7xLDe{U$=#hWg2p`|yzChq$StnSoi&!c!F=`WvWqIm zML~1r!Au2@+smj(LR+slvRdOg^I+xh%X06sg?7!jXh@G5a<&@6^ml)Ks`&?CwfC}A zGiR9ezF-y4RP&Z7ry|w7F?ye%>vaZkRPYsesaN{gE;5#MWiKc@Sl*uO1r_7uvHn6V znptR9_7cuXa01eAoL7VQ_y$+e;A6cf?z^XQF0Hx>kIVWKz22aH)xn4Os)EuZndYjD zTfOPkb>nB%jGw%)V%+{@2`O*;dMa%Os#D3OZGg5?`AglmRCc3;UenR4MEZ?hFkfJG zU|bEIaT9%!j7;8Q49QFl$)U`%p%R7pl3wk9tx|Lu{GnT*O6aqTPYJ0cqbQ`|n`u=h7{I)7HB;rX@Ae-F zC5E|z1-3K`Y)}y?*&Oxa=Q!F=Du-dQ#wtXyfegR0hO=tEew#KDv8yA?$AGW%=O z@8{1QS7r8Bqz}#PuS%a%xD?vt%MtLivwzc8K_vF`a?Sxx;d(kEYu$x^5zxbl)WZ=_ z0w{paF(9A>bgCLnh24d^==P|nW-p01strG78;kD7(K$ogC+rAjt>gz;c*SK?-B2#J z@f79LG+nV{6}>0iu{77vYbN&*5)-K}?|8QN<&N4ki^XTOb5oW@X?l5i1j_MppM60% zi3fDg3-;U%r+N0Qn6A2+UsDecdNt%hX0NAnjp#hh_AZvN?jo`7%9wS>7v4=lb*s#I zzOg$B+gy&S6^I&Jp2mQZyn5wvRIo%G;&OH5A@_sOGl)E-K2nP%DhluPwo24itF_JG zv=8aB62t9^Rv;~MJ37C=W`i|a=W&8f{Z|zm#6GYW!?99{nOna&$EbHhk z+aSB!SuWcEte+OT6VmbmFpqP1gxZP`K7kw>Wqv8clE0AgA~ug~Xij1J@aS z+Aa%>x~6c6q?Xkr$midKTa0XBW{qLmTuJ0d0$bY`xO^>C+=R z{IY(=kuVagA3fWIO+HN^DN8W$=?W|8o8qL-YAdKOa#p+1V5WLXDED$%e@YdEHH4x<9o@0foZQa73JJ8lhU2~=~T8Os=fTr(8 z*kcxz$dEjnRP&?o#oq4yj(eMsYF;0`-TP(tmPpSAhHK{5@*Oc&SEU&{w?yQ1maFg8 z%Y|FRYI@c{wL##@xK(n^jKV=)Xk7RKyd1|sV|j09xq1T}T$Ltt_U3C^6V+5WJbaOG zaiJpox>F42dindMu-W7IigL9|{mq3ShmHOy578d@z&JAPp5;~Na>-m;0rQHPq5}yI zF$1)B$~?sWwhy?pQmMX=w213ISUIj#&!*B+slJ47F~Ui;zNp23;w~E@)i(P)NA|Ts z_7$NUGMV(sV;aPf03Eb-?41Z<224|bP}2KtBb(nfe)HcpPV@i$YGmMMJoHhb=|paU zxTV33c1RM!Wq^<3%=K2>Me%L4@A3UwG1^$1WrdwadA81wo;hQ|Q^rC(py7j#iPD6s zQ9R=wylciK*)wUq`FSRe&tBzQCsLr_6fmYQM$#2YBF$8h(wDu2b* z%)4g2Pl}_?1zV!Omp?I7`c;|mdBz;ij~`w6YD|cl{I3)k%MfdUbp8fM1_VeJtT9FX zy*MsdV%#LnG6_c%DY@`fDRDRJ8QY_CeFy^P?*PYMa8j;c(C|K{Z6cv?p`C;|S9_rk z$fMYwbl*=Lc>FdBHHc=SE{FVK(vPOvJ7sVr#1An4vALV zL#NPL$-MJa>I5aU4vAJK`@s;j3WK9{a3rlYoxuTJ6HMF8#*d%~pQmCb8P)}IvpiHA zP=55T9$EgR5#<>|VBg4|^n?_P54q}1o_>Wq6&Z3Pjqt_kBZkzt^9EyvurI`S9@7dc ztD6QtYVmSYGQi@)fkJI&X$5?U`b~wSetWXC-$u3NJtK&j2&O2qII_*BjewhX5S}ds zs%TvyGEs0ILEXMCE|t8gC$;uKBwNMI~-H@n@EdGt5%T_c{E<0 z{#};VI?WIbfGCOsc!+<=HKJU$wdO!(`GGjFf*%YkHI-t{#G7_hyg~e2IYr-63#u+u zIldmKF8sLF^U>ld&;P1b`yvJ`#x*=G^v^#3?6v1R7cJ1zMxI&mvZL?m*L!AC;#55? z*WEv4O1;Ec?b3I5WK2#3s;-D_yy_<Nmik$Fn~pIoY*~ z_Z|x`J6{-WucX1#1WBufDz~W45^Lw}SOGs=cCAgInB!G4rW6xwok?koVHLw>fexwa ztam53Et4yUFEcQxXBdR~g$0%KZHHpwPlrp`LM zlY<)Q!(XGwP@P{ioNZJ*<|kv2K5h`AuLSAJpT(g{0&)t~bp{o)@WsR&Yx3#tt%Q3Q zFQPYSpL)-3D^bruLKhVjPWB%S?;RiLYXC)joy);0;fNdpw}~&TekVoIk^g6ze)CAC zFB!w14JiD0Ona}`|aD8jSuwCalbJkXFhu#n}Xa_ z_a(`K4c3?$>4_yXg`{nQz;4y(*rryC9PZV~v`z3N*B=`R9hNhd^P=Gk0Mg^tP`j^Gssj&!8{c zxTk-+L8wsON-?Mgce?*SEOCe{!qZHM4Wnnw*?dNfc@qP~Orj;+0oSqrgpTm| z6FD^7#Rlmnn2ewyhC{m&vs}&SkKIheQ!^(y)(Vq^N7I-2g|p)V*&oQniPnRaD7;6K zs0KK=Y{#UhQ!N*nIf7ga%Zf8axJDGwsFS=lhgfl(X7Mp$)QPTOiU!e!-;$wQ(J{jg zM|u<}so1yF#~<=MvniWlr-aQtA_$i9=|;ZFrnTdR%WbevtRlJ_!$Rj>TnS=u33ebY zNK8m1nob@~qOh7RtT6+-@|OxIxkAn|PnR;dcK>8+haIfD?AT*E->>s`;j__D<>yUuuq#%FcCz14ttH{Fk{ z&JX&UxYJ-Ng0-q|pAb#8=`RUdW>WlQ#Vp`v27NR9=Nl|+W!*KnD}lh%bqKu7|8EN? z8aHvrg>jmG!h!Csj0X^dw@T3o)iE}gRFN}1Oy!5_o}i-+0x>bazWa^X*(6Z{c)`q&#W0#7XRRnIT2 ze17>LV~0gB6dfV7(YRlhrSX84yaKif*z|Luk6YrHsLG;*w0bPN8}eg({|sQYET;{4uH7;^cv%$>%vh?8&B(aLz9b9YVvT7~Do42FRY~mEh*bOO*QSIiMTy(Az-qGO$ z-vPG~;t0QUg1-uY?a8ihP$?NboZV_3u&+X#puFcC~O%QM&%z@7bF9_(GOT-*I2EO7j zZew`?yxi;r#dPUFb`jzo-zLTEJ{%kc|%uPZR`#cz>hNGJ1*?Y2jW>ZuH)heIA4*wJ+L!g0iZgm5nk@t8$ z?anWpQ1q;K<3!Hbk-tFEjKWdQsZgac^=79{nC@gV#o2lEQG z4#r85I>oCTJxWnF>Yp5FCTUk2?tJT_;XPOvcs`HDc@|U*R zWLbL3qEz@0ToU@!C$2>SWi6uSTWg-?t+jfHk;5pv4w z2y7X!Wylruoxdua{tvKXVN6KGRtfs|;t^WIuG*A=T@dhDoWN{jU%~B?f;%@{fBp3~ zOJqVc!6u3`2rpKNlBVaah10nyOu;YoYPv=#mngr9I1L<_Zf0MyM|^dH_owtZ)A>{5 z=q1dyp+|(#R>_sOgWt0a0&q)8>llSHPLYCm!vQ47v2C@P-GNJ^xVmfsdzdYgfodr8 zVp3=2RJs0IOiX74+>$v+{F1r6@5=BMdOHrC7!J*IT%#)yYS(Cnc#ZVc&KZyitkeLG z?{X1S17pL$g2bxf;U?Tu)_HWLi)fLZlt3JhKok~g*ABT2)og$97dOTbj|rkg)@rFb zylxaSvchD~@C>T@nu zqo)3lgH~gylH4<-iJ`hAihhL6UbZToFevSyZ2oV&)KWqfHyX?4hv|&|6F|q@3U?@V z-*okpe@ZiNYKx)gF?F&R40w*YwOv zopeOhRrZ?zcS{q4by7>69LK3!uWI;-jbIz@+V!2m3lre%Iu6$>gwZq!Z)d%{9h}8r zeI}f!D*$a?PT!_hf8SWmq`5M)|M1i&TpU7$Q=7YzPrpb_*~SNQP3v;YsZ3z}G$dO) zcH}FyY@e{%vU%box5^|3kNC4MYoxS1b0;2^@Fv@jU?M84h2xE)_A*D2uXJL^ixW#r z<{D~p7gav03G$35^OZU|kr+L#H5!Xe#uF2zimUt%X!k|)Rx*sbj5`?vtj+C7MlS{? zTU&4sh>uvgvgA${cwaE)XT6PL@(QR4Y!wWSKkGw<~d)JSCrw^PsmV zJX4uj-j!%N(qoH@-+3D8lRgM#UHL^m2BV35SGJ>oWn{%@wj4fR!)lT|pUOI3EOUIy zEZxJ%w1=VaJcdFlV3yc)Mns34suIFA6)%!o@{WTH7|N3R_)p*iXt)qSL9QP4(mLBM z~tG;&wbJ`_UIfTfj_ zW{%f`Adur_Fn)?#0%MNXU4p4~FtOtmVW|agc$p)^BQ|H`!iX|ADlT>{@}uG@QKsxv zV^li>ITXIFw2_ADm0yqFNCF3a_z(R2nTyZI5wqXm_H>^)R z)`7pXDciVNh|C4pWG=vFaW7|=Zz1qo`Kkj`Bb@+@Zaj=VAg^`cNR$?0m0bU2~Cz=V{{Q-{wJpep)% zUJxUEG-xljVE~0;80hw)o4weOpf?KL`~`Q5l)c;=emZm`PL2_Fmq{rjPJ!rt-4Hb{ zBQ)!Dj9^i(%p-i;oQM&la7K)H7Kg20`Bvp4$#XTN5Hfd6V(al} z3ooZwu<8&NfnSxg~bCH~$W^@52Ld%)Vz}ofP}05UK4^^b|bb za?f=YiK{fYFdA>|3{22FgYA;{&Y&GnYnWc%sW{heN+k)MS#|Q;+ z73nRe4d&u&sXv#StDGf~uYVyC8EWtj+9yU+Ug8 zF=h@`T!M@a3zbtYi_(1cm(>4ZBiRS#3^SVmC+HU|2PZZ$*Qv=bD$6$32`x<=V+Eqm*#zQ565)->EQ>Z(xF2#V6P>$8m;3)hPp?a+?t@K(!m z7mlA!nPd~wT5Q_G9i{NBEDx499hrKFoQFzt=%ff;O2CZi0tS!u>fyho$d}F8--_zKYIEOX%>`@RTuibx_1v*( z)=XA0Bhzhg)z-wrt%={0L02kNayc_AgyW9@viYx}?Gx1YJ!}S1oJM`JRoiH3=GIkD zO)$07#$=>FCccFCo$ek}u5gjcy$0^#2iyr{_+v)7{_ClgdNR9fsYfrp`gK$%o|TBq z^V1zh3yq(kp+rATXp~5z_WBAfJE82O{}F^o$t3^E<^WzqM<5)Mb=_&%uaUx|M8f?C zN2vO4|3?sh2=mx~{&)y0G~z5~sOmq7Y!i-Sa}8Z3outLs{&JU@q+3U2UZ1V%|E{%pe+_^!r9N$mvXAH9*fb>* zR41{pjO6Yljpnu(UIpX(pTqYePhr?7X%|VDSQS3IiDjQ^{8@d>X`138K{!GC+zjT; zr7&k2i~=(TqjNjF$Eg3Ui2CN3E(-w*QpF-7&NoQ<8@HbU#}PY=#8DVuH#X@Il2D=K z9a9;hR6DY3XFS*+FhpLWzYh*XID2^4T{r2sOYJlc3{7a7U*stIH=soqE@dMKGsAQf zXB?drWw~J6z8=P<0t-FcvGK!N#xY|3)wlh38h(EJx#eo!tf0ow{&&aemqh8Dx7gbM z);RqwQMxMXpAn~@6s0p8-l_!)b);Mz*VZ)}6Fz|t6n=m|_%r#&H43i?vI-E{Q}@F- zVfmZ+4EAU`wSr}o-~qE>D2Z$sIjS*Z&S#OL%rzG)&^q&^G7I)uF9XmOSa1g;`~Z} zk*>>`VS7TbmR50Tgb}9}>dBBDRW5h;WDsZEzdH zWz}na*&~PuX8@ml!4fHJv6c6*)6O}07F)SoDC-fTJ{&Dxm`JaPj(VUb*`KGrIhg$0zF+1mk70j6Lwjz?&gAYR z*o&iC7IUZ^*Ie7$e|xrZr~GR!(s@k9U7i~-JF?I6dxU?UvHNvDn;GmrjtvNYTDB?I zxLL(By^ic?3qh|@gkQZ${O8cq_Ebh!4_HH)?wlGkgU)1XN{oVz*rOk;A$kBa7);q5 zL-e)JmMkl!gM3RC7N4ZqN^12K={Es{SLaR4bKf^m6LBlsVSLJQNlxScTTIc(!k8Ba z5e)cM_uAOhli7K>O@O6?sqZ3igD1G(g68*FP{>;P)ei@SLs3TQB%;n~ue<-?wehys zNgG4Sa+vJcUmi=U?PEjm`MD#_In1a?X^oqxZUw)!R+R}V)J-VH?SKx<40>6Xkjfrs zwvEv`?5vkfMZBsy^-L7r;dk@IHK7wG02tOGY>i_5TDHb+Bs+S`wbU7EgP6N<3H1{8;BJQRq(BW zX)~3}W{OHZi&&_V#3!c4Mr%j9ad4`Nb6E zKvD7stao+1P|aXq8H#q^c?y4zS$U#sFJ^0R+4tKa&8om?8ZH>07};&Mnr$P;ohdZl z00@!>+Y1DGd*pfzc_+^*Iog{8@Z*&6Hwh$a+C4*qWVhfst6&n8SzeR46K}6((h8gs z#6YUGMXe#Ne8rT^(wZ_7lwLT|F?zu($R#`Nt!o!dV2ZPxq6WfHrlOreFD$?W;-YZn zTTOZD-fxkNH_2rJ<-6%QE|cheKDcjhd4=_h=lX-QDdiZSvu@Upuvs;o0saIe-0BC* z%<`#;mDD=b_|6V1FJ~H#B0JVsINw9FLr6>@t{w}d1MG8+kf37x38ZRn?B6;OU(@0 z4Gsru^vu@^ zwy3nr5mBjoD;Xd>q~$%=>(ZYirq_QHeXEPJQq5-|ps;^$`E(-@KLZK$y-fdEQB@-J zMcFxs-E;NrX<8Sl;*FH@HqdPI^DRo*)37e0J7)>DTXl_19@c1zUrM*Jc)Cl$iuQl# zaQ&r)&4*z6Wjq3Do@J8UGMKgstfX8Ni|a_UH`aMvj`W9|0ZPh&!vhS4` zvL8X3nZfFLL3ipCkJ)E5y3ryT?7J37C04#=gi6>%b9IuajHg5rZTjIFo%s!>um7*H z{rkVxKMwb6?3VF3DW6jk8+Tc%#au>N`y;XT$uyeogn2gCAUG5~?Ow%clPQt))oJeC zyoe87Wski*P49L3sTM z!Cl>!At-siZp6nu@-N%*%q42!x7hk%jozJD!Emu%8{?VN2fNv`@{S#)*yUVVX^=-R z+X;m-w5$e`yX`Qud}m_C`4H@;5*sybScwg^%fJ=SXQpL|O{%v=``o;b{zYsgKPze4 zx0!j}OmH}tH$96+yQ1dJpKkazyXz!Md~}x_HSA~DV1}g3@@8f?c2-YSL(UmB40%rI;l#QKss-Fz*T zmTzMRc4B6*ov2Nw_k>awCL_)znHcI20)!2fv`h-7NmtZK)*rxZFCkt#JFH!d_8*8B zPK+@xv8x6dxWxQyrZ{SyB8Dg|qGBMQJIrdZ&a&(6N5WXwe9&MvM(!;pZ8PL48?Be{KsT0j z-OEaBxylTQ{k5%V$L1`lr0`7O5F=6H97+!XId{<@?_M@tORprFt{^C(7y+(h)4SxC zH(f&5bzZ7@ig{8!iIr>_(|j1&Udg@@UaRpkt9=g?4&yc@gxhRz%zpNsv7Dihv)tS} z>ny0(vJr|@XR76MycO$BwS3HS@ada>W2}qnBYN!WOEv$H49J_1YRT~y^}piaBWo=c zFDJOx55Gj_vMraJz1TEA*w{2FXJ2%B^s;emQR|DZs3>#W($TGpf49X6`gC@Woah6?J0` zF()@H!mVP3>G#B)5^=NGd(6#jFt(tE9}``lU8-Jp^N$q>Li>dD+awN6CzgcEeSuwx zdA^GNhoL{NZXmx}8J>oqZ4-J1lpjBP*T<_x}sC_k*eK^I=f}N?8~;ZN-^mE3+PMw934h zjw>symm!k|rqLG!z4^;dD7@~yE7FCgh5e=iBgLkdwvLg~6B!i!D7f-yn{i$iOG`sx zVu|I{RgUI99qHXC*L~R0!i6K8C~T5%ZR|vy>@4%&5i_&$ub4^Lm`F3J+?3FnGiCfx1xbm19>%&AK3BCqn_0NAbsOG^X1xl^LQqMx*w$zm@>v=gOyzf2r|C0}?b;?& znL#SD!14jr&krCx`=TyV8&ZJ5k_PQ=wWq1u!1f>3FvJ;Y(KlW(lII5l%ZMEB_e(-t z!-D0m<0_3Z&K)%#$X`%qjo6>pa`Aq}vV9>|gw#+@#o@YYm%Vsa;SN&KGKLClNkwNp zk<@6hh>MEj`#l_!V9!`K40)geJMZ_`auW+99&`?A3FJVu1Y!wnMIiyUXb(6F{4QMY zq+MlFy52UhMOQfmp~ZsrtMLQ(vMNX^Jj)49XZUDf;UuxZ|C-pu@>P@pWm|krjyY*8 z2CwLGD_@*_YZGFwNo_h=N9M*9T^HR;)c+JLFksAnOP&wbbUjgK)khJPXu9atiHa{G zDiVcH+V!8@IW+qw%u%_JW2F;?ldX+!C`r*(VXCxkcSN3VMl${DxIuLNt2M~48`k_C z_-#=Q5yz07*PukD3p8*UdLftVJ?LCc{!CiQ&fy9+X0@w_oRgboVrL7N{PwA(>v#9i z@``x*()!z}SEl{Aj*z|51BUD^ZL2xbcxvLAX-hlyPm~OEGtYurICRHU%c2Tnj0~tb+tEEgEDEsA5oJJfdC_fHQ7hb?8bk4F&rr_RaO_OT zP{da|;Dj+pH~7i6Nh>gCw#2uC)sezE5vn_EtCC=HuGNAv7He7?bsYha_ zheglbS_rfKw)2DTyW5y@VQN#&t6g8^bfm8PZk$bPHbGFB`wDGj_N+Ny#M~<#<)yB6 zg}K^0N4eTNwTR;w_hlNd86&98^k=!uvY`hiv80~865mE zw;3TLdifa2YjUMSr0P&pWqx5^2ZN2rHw&%0w^EjW$8xsvvtwhY47Uh@oJv73kBC;z ziE2A&t&2DEzFq6!y#@t$dRK73$rvc!?8Wnlc;lDbZ-oXB+W@qO*;PEg>=B-A`i0rXa48%w@%iES#e6>2PtA$@zC)uXH}Q9WI@8<@_tZtjsi-ke#! z8Att-)T3#!7V;^q*4+_Wu(d z*$S_`0bNKpnAe5iIsF>ci&POskUOo(G&!gv=jG!qINbL;v@%-p*To&)F^(Gjk~O-= zG@>sWqH$0;8G^j^MVe)oaLngo+h0?O0f$yw(cKG8z9KI#eSL|C$I2hI&_7}1;=Pc? zpYv55*3j$xxzMUK82NnW2KG`2%PN1aPx47~xoX(?a|22FbD{ZjP}67rT%YsjtPuVj zGea2KD(0%OZZ`-c zaqJNVOtBpy(FT;rxQ6-nmSvZO-j2F0OFhRmvPIABaMEU|){NuRLwytFl$;fht;nF@j-bw54jY&97)Ylzd=;?m|;DaOS%Pb8KlO;`GFCC9@)l$mH z;joL;c~Z~cCx~`}q0dtjWAF_!Y6?fdiz22z2;57c-~aB4(-@?>-K2Ww-k^Q&lAg$3 z-#sMlv7szd6#X)>1~u(cknBFiay4!5qWUV>2N3*0f4VVA z={yQV7xi(2g`0{c(r;pCvhORK#{xMChde~^v}HNAb6p(q({1F+(7r3YU3NH|r91Qy zoA#8O<1ZVT(NFZeZ=0_u7=zqT_Yp5K)oEOU~TFb}?5l88^5Zjz(frf#oOV9`IMx#3{y29N7 zG{7zz)D3>x#mQ&%gBZL<2WtlQvZ}shka}&t&iUa3_i%nAmEcHZu>YRx4j|ntv6_bk z`cOAK^{e77|%q<;JYr z;w?p-wAX=qU21LHg&44^)f|qZkYp#u^AslF$tP@=%4x@3Tc4j$*ZMKdeoX~sIx@U% zBn5?u2!ajUX!x9%Y`o0!eDHha%JT^)YwhCk@DD_2GK>m#mEDM3Tvm zoBF-z-t`H$S=c)a`7L+!yN`Oj*T+6%f;D_83}n``e=p6jdF_hA4d}AF*-*xd9pyMC zJj4JjxcQX#F=6wjXXRwaRA*KPSl2?MlNy29w5$*xN`aB9blw;3Cbh5(4W@_L!dZpu z4<&93^-$rxuTpnD_=PmHs-$l3cARWgs$#41!t!5GDHK>;hp4W?e<LxG6eE%HY)~R#7j7q_bH!ygad)`w!cF5xftzCpufchV z2hOb+Vi5=4jg9W+ZEq{4`#FZm=ke$s=v6j+8|tm{>ZRS_gAX zRPbo>T+jR%P-P3oQ;^8Fu5zh%Q-vo6eD4gvbZi{#~6Z7la z#xDpDaS_c2&o&;VWkw?bYTky z!Wz{RgyBi{WZW9ZE=zgME`O-N-b4+Hl~Uv(_Y3d#CXwgv!K&Ne3RyD|+8qK)3ae4D zTArRA(;VOdYiwwgf$(>`by^g~W_c^OQ%Pwzyo?n)na+aill6e>T&@JytKj;qF**7|3ie@^$$ zS^hcOKj--8T>m`RKkNN-p?_ZDpNstSQvY1+pO^dRjsAJFJ)BtJ{GyhHwZo2j2&Ty-vyr%iB0gPc3G)HWMt=MvFy6m}Ut zwi(&PSvE8M4%PQ*iqeO&IPp(1`g)sA6~I@=0oWkqRs+U`O~XU)f4pv~iJ3n3@6cWA zLmM^|glp5E;Vw^WMf~Z;?zRDF7Lmi#syvS_^v@yx9Q4mQ{`VZ``sca+S?`}0`sYIb zyu?2j`RAqnx!6B1_s^^R^IHGB(LZmtr|T>IaHlCH`cSkHrf^Sw$-0T=7X1-c?hZUM z=dI%Ffov6yhWAqrmR^%>&~U8Sct`kRUQsqart+~j`p_?eckv-)&gYNHDCZjyn98(8 zAHud~oH8U|w7?vo$bWLUNN<>`;fKm=__%7EvM%SXt_oo0P#~shy70Idz5Q10>0}~~ zsCRx5ZkD07jF<0YX~{Bj`dM1yGy40)jxznWA3tgqwQV6aJOiwioz2JhqYu%y&3*9p zjpKZC9B+)zmyYGX(MN3^A?rG(Y|=p0k7Dh}#g}HP{zq=M@EHP1DV&tuwQBi3ekfJiBd9DVjjs`)xgQPdY5dOG_g~@X zIm{R?%rq9gSdmF=uI!z{5L z!3S3_;b$Gx6z26FbD4n_Wlz)ENR}mw|Nr;@SNVZyvw)Et-MKpmuf(wnojaDaDPS^` z+!ef(aF#K-BOkoPFk)8?K7vs(m1xp6e6hTF`-j#t87ukSu1J<5xpdz)543S+l+1BG zuQuI~B?0u~hR30~7$XxUM#*?Ww8$kDFw^=g<@A&W?mA#y@g4B!^@1FJ6a3+H_4zr?sOW3F)g1!n84D&HEd;0#I zeG7g2=O`~{)A=K`!5ZHYuB5sggBE*!!rS$pnD;pSJ1*=sC9quR?_k%K!n!dnthsB1 z%@pCUt&fdB8ym-$0e0nh56jDhx~+69rJm=YENW*w#*+RMI&!@9j#q(aU(MQf6&jbO zc>Jyc{o#hb6pp9_<<}I;J9s;8#*);IYF5ek5jT@gE9b@`<=c>|VM2XZ)vO_=R6e~Q zL*CT6>ITn~XdEMbR%yDYlOO}*Bg+#si29I$YLBQRT&22L->U#5&HLO)2qON@bz_@G z1eC+CsLb)gyMn#a2&ruWW)P=5f@9j<5xWs`)2Uyx4D^ z4l21$`2=^I{tOeSbnPOX=xMD|o+)t)LvXCb#_Lj^oX!{?l`Ty_c5FKJUd?D+q{q`6 zn~NLBrKWM@GRb5)DmQ}nbI54*KPprrKNTK_?2T&>mCwRFsGp?Wo787Nn}H1=`jxuB zy~JFc^%0p10m%i43f!T0ZECZKsNdUmJ-4#u5=mB2)UA|wCs15VyNvUz`qVO%z&FGP-qj8L*zF+~+se$u$!sMyNJkR?=LvBf* zA1q#&1;4QIE{=#d{K@yKnH>F3(gExoBmxevY+#uHD%N!Mb6xhm!hKuF^y?6+7@^7M z57}ewSY>SWzc4rsPdCPZrt>3YW2d^;%Z7FaYINw!HB{I!0Y(~E)f?d!0b-lysekW} zxMw>iyij}{^Fbu~jn-`Q=2JAgIAqf7&p98QHhamq2t<;ML2Cj7?ub6GuP*Z2w~ITT z_Wb~J#bUW=Ot07KONmX6{O|Gdi+z7J5(Ty8VPd6?rMY^d_p%T1ti2{S zhi6Ip29qOcQKiy0iI+GqHYamo=?zCcgW&A&kPi9kI)H< zvhO(>|BHR#i>!eV*8^XraA^-ja_9lSR)RaK?~CK4eQKPvdrQ+|`PYJnx~?OV z9VDOGip7-OtmS?OvyILk_IgV3Xd#>*9*k^C%{H1ZhXyy>I`2r<)b%4f_VHJa-$XRf zPQQkt61F=yD*La|#OPgEd3Z_OyMdV6P;$2)IzkMn43b|8yfm6Ou_tx}*clO+%?wV} zG>d#KKz_yQ((#FrL470hn21ctoHfp5Pqx>>@^6xwN^2Rf7)bStpcW3$s+WyPpX8Hq ztu>0mngeP$kb6c$S6Wk&)>fzTH^75PRz|`w&j6cl*^hV}({XBq$z#SbwunLKFZS~2SFQR z9Q9-9ITV2!rFDc;MwIvVHPfy+!7&`F^kWFX@~wNPJF4I#`d&@Xapz6?8vd-jg&qIt z1^iigt%A**c}rJoSy{z8DAt*%SilbPxBJ=T+i0KctFj*L55v5*bWxq@Gq>{C>@seb z!OB+}1^dq~+zwQNrVR<7GngIUS%SE>@9K2-to`7s*U`(HQQMAW=p(W@YRP zIGHeOWpP%wYE3j)9pWS{TFsW~yFL4Oqqd{Z!I=DM&ym`BC^Z&+39PF36?_XC6^Ii; z{{l`_!-9}SIrnnv+U^8-ix=dQHdl7^9#SGnA8kUOO#ux?I_$Jp?M=?d;NGu|H#Td= zvK@8L@(MC0ey}`jrexU3A6g)s2-gh0Oq~sv+5mN>b(d5;C8~IwdRLCAw>(_pYEm^j z(!QGF*gLWw`q77aZotBh9-~J47upFA3>+(t@g7FC4VuQ7e2wrs>gh5q^5bG*3FIHy z`d5wClC&dLDdN9|E2&=g>F^0|&K5P1JMHK%scTNLu6Vo^4XcXj|95G)?(fmigUZRM zNBw5<;9@PVxz@5>v@DjiXbh0P#{+vEGHtApMg5EzQ4=>j!fj(!NBGH@O*Tv&!>4tK zG~*A<*u{c2Sm1>E7o_;k0*|vXx>v{BS4JO|yZZmI_b%{J6=(nW>?Xkg5u%`_in?G> zR0w-Zvb*F$NEQ;w&0M%Bxa6`4tDB3v8!i?t7E}$cF5CD0y`TU4a$s`KnR%Xho_Xe(XP&v7*$Y+sYFF&c z#~1=g`+6mkVPC%+wWGBFkaxt9ek^4SPJTk!;Jy-B2-^T=MSCT^6W*UDKeD{s@9w@c z0LE$5K-}xwg_7P7B^@pYq=BP}m9ZS>;2j)~BxNrBXpB^rcGIRRnmoXs@$KD3L4{oR zhkz%-lcf{Q<*(Qaplt8{El79MkBbN}&YXVAIzh6lzA5^E7HhW zSmD#~6j>nN+fV$H=PAyIUUq+X1;wQ>%Kb2WNAgI1mR6bt;r?hB#M(6iN8tm4h^LbNmRj$MFY1LJxE_Sm4T)q*0FEIyT~D3tb@oraE@!@ zbdR9P5#3~!?)kmw4(Lr+ZBv4;KeeKbqy290-is&2canV>FWWAZO*r51eYpSksv1*8 z1}bt5m*cEgAtcUiYD@%9q#Z*3LJr}Srv{|Ha_GERv*Lk{5# zP5l>{{{t(llW7LC{0NS+;9JsZs}{U3J}3DHP+bFXl0UCBz7_=Cu3b^SlMgMH-3fa} zUqo*2zWyND478b@+~eK}suk@mt^ipUf_<*W9|8%iw|EWCm$RtSRi-kFj1!!lx{rGfcpuo{Hum0olbQ) z43Wc$+DW?rxM7_lDu})ksoO~(H^4|xA|D-h37C&yn=z*=csiYUDhKpY!`r>MdKI!4 zK;6g{i9qQRFueD`K4hxR9PTqg-mv}PH}x_^V}}OsOMU`UoIUystd2|&ZRqQwKRana zQ`dzGQQlI;N+fkb^MEEcU}WDYZBd^!S+qW7z2=LLx#mXtJ;>%4pHMZ?Faw>_C}BDt zL>y#z2{=%&zY^y85Gsjm%Mt+K0BnJT$r3)A=WHwRG{@DuooH?B*Jy;=xJl7jWcv`} zQ4y$nY*<`55M~_O#Os)Ml0=(i2}K|s1;TnIBkmIj+rvLZg9FB`0gp!;=03D&ciX$C zV(LkoH&OdWXvuyui0-4v9N$_&jWH7g{W^RZ=3}@D9aws7=={m>0OZV$+E?E_PbeBB zwpS?7{X7P>2ii*1??u$1(y#_yJL!UBpo%|T~lshU^wWE9_2j!>vxXVT5{vOcf zCx^OR{UTRn2F&M?jZhJKdkk+vMTRX#j5k1{DNThu0h$y}CTL z`>*(23O;bc=`YlqmhW9&Ye=P(!Y{}RpxH5aCcJa_1SecUcW7}7i(I{1cjsn(F(-;* zDnCR<@SXD^Xa1ch35wibG(%Oc1uaSgMs1K}PD5b@j51rot=1)g66xO;PwI@@cQ}4T zE!2uAD$Bn=3Wt}w4++#wh}RXFc3T{xQlfskGvHJaLNNvdk%j*h%1DRJPk?ool_QG5 ztM#|dyd8+jnT}patDF+NiOQLOy;3>Dd$0YehO9v3BedQ~oYEn<-KaJ?pn`6cME)D^ z(L2sT-q1xwNXqc{d{E@p5W*DA>M$BHxw+fB|71cR^19~B@bytzp`&JY2B-^tq|Hm{ zMN>IDseIKf4RcCeW*nG&E|!mpBvdsOei?YDPiJAzuzhRJUun`xsa>^HH(>1$MwVnE z2$j)dBHvWjfc*|!VddN;+9`OV^%QEC+q-WdYJ8iB!czzlC>>JeE-XwaVITeH%lU?6 zm{#gRsWrhwgB21K>00+8&c$%S1!esv7CHqN`xh!)pk{Rctd;I!@C7c6&w#rOBY0;GMlkCygeZ;p^P5oa55ZJvtNd2V=! z(%DV;GVD3`SIg;W0rVND5ma6G(C6yD!u#qpBQHxA6-0DlC|NgWC@ll%Pjfq*4j?(! z5^|)9rStj^th^Go7OQrt*wRkRnxyW)yETb-f1>)-c|1s8tWZN1d@rMLv5||ccRiL zKLHKt8`I7_Ok%*%!fXI_!*D>jD7w(NcvmLpWVHTj6sA~sL*&2jPMU|B1UT@ON%o5| zW`a_xez?*{;rI(#AL`x;Nc|mtloWXYq!svdin0Pfy=Ly8q9LA`xmVW?xxXv=W~}>C zdm>Gy&q=vW>$7Hkr6LllP-VYQZ(sL9t^>)O0cBWQCPvEK{gr(ywa2COVP`7NJ`^IG zMZ+@gCCjmdTJChM+>!mVw&rmfc>(xzkMC*zDYD|Og6eB?n1M~tJabxuey+AP!tO%hUQ#0U=N%3U7Tu@N&ql#{(iSb?} zt-qq3@x~(bUQcU@p4P+@)8Z2EpBA^b1;SL`gJG=Gofb0l4F$YZuOdoqd#mXsg!ar0 zc7cPdOz-&!*dyeI9VTRA$ZDuwhun?PeU^vU2F?lOTLST87Q^{ap0?yc!*1jX4kbCF z6A#suVrTUGJidXEi`eJ!SPthZ+CGnqh<)8YkDrQnE`f-B9{=WzforMWzv2BC@4OsD zm0Rs+=?NdtVR;0C_zp^rPKgv(6orn?;2j9r-6^OF*(^yprI^A_9UfvQs>^wl~xEa6J147?}2J?<%Ge$fs zZrHz~bKeS@gW5|)d6%$|AMbSOHFLX2oKG=5eUeUR0#hjg_dHDXka}OyN zm@^Y|!@=B&x8B4#`ZQhv;`a#=r*h(PF=YrxYO9cNo)~zoM1Dw|fJErsQ|O=Jgz!^M z@%r>~DD2nW*3YOi($=gwGlf)o$~r_ZimYdnt1M+rBh!9m z-K^xtdG{&#aam{JB_3HnO8uK&*24%<$a(~2sFO9UC?8O8S?|DFRll;%$7E(dvYtQ$ zIlr%587b>RENhaiS0f&>zKd=g@X_`@vId-(pC{uFJtx~aiBH0Eovr|Ls@*E37YLnO zv^07_nGQ#qW@XGY9|w0}B9D@>xA8+T04q+Td96)9!L2t<0IZ;s+q%)ik6c}jLEQmz zlN1N=W6Zmw;jh?%-?7&1m;2c#yo7uQ4^j9n$jPn1^!^%uCr$nZCgoJmrEmG#FuYRB zcOAXR@{OaHe#`d_=SwNyL;IqY?^n<_V*P~W8xXyGJ3fvq-#-ARFW;Z}JC*Num`c=_ z57kHWLDb&2cQ40IbADn3y(ICM-Skz z#@-MPcPTPCgl*dVIDq!#)bBDT8@G_Pt;Mg!|0q77U$Xit1HUa(tz{(dr>Fu z4J+qtz%iNN?Pusv_-=BHIhWlFI1zo|gK!wCoxO6-S`l$8>P{?rJqC=3v724xzt=om z2xmMIjcHWxufHXKRdS;!-zFh3+5^Ko$&D-P9zA#)nir5Le<4rag(e>iP(1Onfhyo4 z>IHedQ=`W4@fnPkkqMQ7K1L=m{L;HD<9irnD|_Z4IOzp;* zDhJ=DEJ;x7AgDu_4H1Is1Q!t%#v~UZkHYAgkfjvVCCbDHZ(xcHlxfsYxDAyJ?CRBU zHtW_2DXkMyxS4_GEJUX*yn% zXFV?ivHGCR`D!vPC0gjWmEjhxy()C@9ik3L_}E7k4qIq*17B)OR#{Af-g6rurYY39 z@N}Ff1BC{B+R&%B;fNhP;4IvsPruH~i07mH89sU%=EH(1Sh3=An&>_jgz93)wBe8) zglW&dcsCx(;O|G2_ayqgid5Ry&%Ww}qfaN-Bp-TO))josn+|s&arNp8P`;N&SjV)! z@Jqa}JZHssSI#ybUoqQo9EW}_{p;~dKD^{@!>*-W$G3MISNwU!`zyA8{t)=WStb~M z9BN)!p8nDWHy^rU#jdYD!f_nkDcA04TCwXAES2$bg-BGAR^TXjI&;ZDyCmz57~UTG z+_Ds+zuZW}H99~JQ}%)-02+2-Pv>$Yj`+fXhUtw9*5dEL`8EtSD07+zr>tm{kCR+v zMyr2J86wTFNACKhlPht$zL_c&ry;GmX(yFj{Y^i$9_68iVvCh}Jjzk%?KAM@P`htU zN&_b9jfPcEzQeb6mg9}@6+@BuUNP7qZLb(5(t&Ma!BAOU=?eH|=q#`>!rRqkxGOZxiS7<9tGfWHq9jND%)e|$hRgA! zEFf~aBg8Bk%J>&RYi%UbXV$kR*qJ{2Pe^WW^b`MNWIVA7{xE=}X3<@Pq4k?$bA{lC zpJ{?tkcxwAXfH(?Ek4nVznB>j1^u<~izs!E)N|A=wF5FLW27tlBGM-`N!TUGqQpW z8VQqyvyVu_)Ri$Yp+Gak-5B6wN?{G?ude&EuNb}0=;rg4O&aBd~vQrG_H<4Dq|PrhfLx~?=@ zRZ#r`zW)MS)10sOPUG!`YvxruQF9P?q;S{Kt+0ovMBDqTa4!8zwqNKG{mMtY})afUZqYt8XdN2v~hFyCj^dNPSAYI6zH;6S7-?UH@o<4o<% z*gcWy7xzwI6q$|_f>X)Za63VIcnE{y;WU&^-9am9Z0M`oAnEXX^g%a$Q1DNbYWWBP z_;wp+IYb+|8Pp-6O-G!$0|^SF_NBj{mF*i zeF^FM7i6Z|5&gG6(zeJr(a)+q!~jSYJv0BZPjBlrTe=qpKuMNk6*W)gJB0|^N}On? z)FE*#Z=TBOP$LP#Zs=_OaFK#MbbW)0cfN)Okl%*E4$axoyry~0 z!D~}c1nt779ckyHS1C@J#jeF2@82Dkg}P3`N^)z;M+Wv213kWMn8p)_j>HE+YYe5w z3~Ysw;P0z5OdE{{N6OYgtUBe1L2R`l<<3<0qG9q|sqA%Q3eNldgYoP~QrUe;Ul|a! zH6`T_sY(A#dERjEAoi1iDPIg^FAN;DY!KTs2-z@ZxM2(C+QG*_M^1>{Og~YH7kwC7 zg18-qln)H7TbDef6w%WsZ8xxYmDs*9BAffpGn}#7m~xLX>1|`mZ;jv&nCPu;Ao^6M z80lfd;PLkv4nQ`9C|MgaJ_A3{obnR`yVrn~D3a_YDfO&8WdRG|Y$tjj3h**Pr!rIuKL78p3uNhT$3Fy=N%fXspEZvZR#VL)qS>uajOL%2uWtA0NtI zOHDz-q13X+)7gQ6P4}d;rv|5dJ(PVoIOWh#c5raYABVDM(bFsjn}i4Izgw-PHAQf1WI%f zr)O9g+hlmduq27yK{N5l7=L2Rb;#(H9~oF($~A1Gj$j{6=&b>&EK{#CHn90xY0~a6 zJY&ESOE*g_M56 zO0%IjW#2H?blF?O*sF$=r_W^X7*ZZMlWjM?V?fl;Qyw!sH;jEgAmw*wvLBt6vhz%K z@HFGcfJ*(+h=d2yo;N%+jO`qfa`P~@cgUGvoyj&0Jqs~k4gJWlb{IQ6Oyea&4g*I` zzK$)`Nr?*?W$7&(L=Bqbyw89N5m`ko4xpmcWz0GwJ^sIZL23AvfzLP7sxw;Y1Ti{w zZ8%O0Oh=$Zitil=PvQ~`O*@d!EiZ!KQ;y?=l#3>p=y4M6J6;Qix4{fcd>k9W=(mVa zy9|bho3YfFGForKNx&Nr_8|;;HKVl!=Nqz}2&b<9G70#74K0n0o}i~`fpxqkv&rvg z9#6pA;tPhn0Z((FzSZmTwKcaRw#geU9-Md=c6b{@-X>Ffo7dFdY#QC-4UHaW8a>Zj z-$eJ0_8@=n=;XI1uiqQ;BB4EiwE9rvywPl`yOuT8hw52Tdt1oc78+l>sKZNztncXX z`x@&*zV@~W3&$^5uwZ<1d!TiEXTa}mYiw`wHnFP8np)QC4b5wBVnop!2(p0px=wE} z1pJ2jpby0h1$=ESE>mNB8y-6wDLYehpuN@9*6H_~d_hxNd&o4u-tTK-CGNsvR#jKa zirr=IS~sgItSu^G1}v{tw3`%m8vI^UNo{Rajmg*A;rF(JW6q+fxxKTkiGYKlb|0G; z3U%;5K~~pxZCm?-HWL^(1smsiTk8emRB#jHnN6@{T23FtTqcIUkV6}U3O-$?B7b|( zi?|ZV5vfu{W!|=y&^$yCCxpySXRZko*d#WAv&)5g^5v(JGG;cLEoQ6PX11HN%-QA~ zv%~DPm@O8I)nc>QEm@XqOOC~1aazq*i`8niS?$&=YqmAV>aaR(W}C%kwb^WTTb3=` zmSc0+oOZL_Vz=6DcDp^xo^8*uJM7LZbCxB`nq|wfXJut&XXRu$vYgrGY)iH^+m>z5 z&dSct&dGLUJ9ErAmK!|Jd(?2ar)wj;;ka5$Y{(FyWS zWbFi+6H#0eCdO(5i=Y9fP&?@WNtPa&i>Z?KHepW_W97caKzp#gIb^D9^ELaR)HUA5 z&VVnp$W#?*54AV8`{`l64|>L?)cgE^Ku-0I*LC^=Uemn#wkE%K5Gxe#O=?7Gn=j;p zeqHb7S{U-Rb$U&0UN1D5)78>V%{*6^$p-}|?FxBKjR63*Q3gRkYp@YOt=?d;z6Hd! zbW^aiu~8wSi)}(fh2EGN7KOY)YO(E|Av8`Cm^XDQiW-DQcLq(Y26XkH)JowfdmFvJ z`6xRxp@?)-^9n$>eQgl-IONq4Xm12t02Fv=Li9i)3wAcN`aQU5L!v zgp#2mA%{Ua{@Ys$@222<*-Z#7X$&^2hFFusuVpn=Wp?dU%62<>S?QVF-q9FnIGB=Pbm zVo-~p!tvz$Kq!OX1VaxqS72iE(Q4ZRE|;eqT~Tv=r$6L@IR*jV#>?soxkdIAm(~G5>%gG$#og6<*4-q;}>MxO@U4{{#GwH4V?k63kIgCDF78Wjp;!9 zqwWhm5gPyapy)KvET{Vdq0V~$6`kI|BE_bldkUDwG${?I9t~d2g@~#+Wa-F63QHuE zm0F(3yl~7yf|I>jN6_2Z)QH}~$sC|s-7-w4K^ZJ|UB{a`V{W*;6m=0nfGjjs|w@QhQ zZw!PcPzd>hp8Ak?p)Zu#$VN2<+f9oXo9LF8XSxVJPq5u1Y&yy?mYju4aA$3-llk!v zFRY@z0v5L!PgkwZXuVYlKU*c9N8Tdthm?0pFT(T7%KLk`pQStpb@(!$lf4(;Cg|A| zx>u~oX#FX|=LnQn-AZw%=ilp|d((ML!Pm!s_f`#8AFqF&sL*!-f8g?r))LUY2jNqM z5uitLlNGv~asLKztAIm!zl$`P*Ji~31L=C2^4SP^LE`9SLW{Wg&5S*JS4Jy^PY}+! zJEQe8+(+V$YQc4^puVWR@sV5KE%^Daxhu!s_GZDii+)lytoXfx%DqcT7peU3lCGRZI|_@w)0Xm!U%c?6DPMeDa4@OTQEolY{B_BK zA6%LHTJZaStURkzhY|6(b;Z8BpM7_IuI-UWe|O=RrOv!Zju!uW=tI`~?_TxW)R(Rr zQ`EkxY3zVq+((E&jCeWHi|<*Jc=Dtliu>{%;(pCBeqXXIvyjsFoY~0l%Rac9-@U*7 zHQh~~4aUj1ch4`$q5DtQp3{o^q`$2<{}lH%=kMJ5KJNC5zPL86h$-b~8}{8i!#=-= z?W$;L-Tp)o%e!Olfti0PnzZT{3(tG{tm3MFeDwZ-bEXyF`MdG~zdf>~82R$6l?B;+ z*2n@Z#4=eEZ&eI~4UfOkLnfyKM$OaQ+17|ST@}j@h>RP$$;5|XNLP>y3>U_;ih67Oygq8dnBGMW?lCIFpGuvI7NOR zx(|A{&G5CAR(L~d4C1mi91&e=arEtC-9$Fp6%Cl+EY2!FTnAXLkVXLUQ>vn2%;))6 zoglF$WU(o|jK>=YvkiM@!j*__c3lwE7VyP0488 zfGOxs8=58uyp8ihrW!cF=(fh00=7#`7JH^O6PAUsQ~8~e-zj}L)jm$ygH!hORR3|R zzdYq1obsGJ8;J?~MTX)XQl=VN?q%4pp@M2xv9j@XE}(#3e0;@+*t_!{%d z_aQ{UoO<~`D}muk$qm<6GsEIk!?|h6$;+XZI6IVwuGf0P9Hwwc>dnT9iC0SJ+n z3z)q~A7I3TOiyA)f*^dFqI+q3Pk21;YI=)?zZlVPA^lluNGkqQ28q8O(X)2+gwMrY zO`jp~`{Nr2X>-0yfJgW$-jrLDZb@F6V!UC{j>0z!-zubRrVi$?WdM5t@Dud#*PfWp zNWfBPdLcvtK3j59f6e{z)N%LSfQ zkJlC-y^%ME!#MvzlS^%UcqPDlNRMZHFfKk1EDMJ()#EkCNAC#q??OGEN8nNU=`vhj zRmNM!Y4`mF+rH10?IQze6y5_qmc&@{f|tW#sl&xflZ+j2?4X8XLfSHf3t#UEtzOfbe`ekdy_O!DtJ~6C?9VN-}Ur((QE!BcQ7z2+pj7bKjD*G&$*X18KJ?0?&6B z;MvZe@RccmAEtw!x-==NGKJ?$WgUzBtiSB(r6X7JoJ>eBL3#($$KYAh^`%L3lrqpn zsU0xa0fv4DD)~MgEv4-xUBI~$Z4dB7cLQL3Z})^x$FrJmX?%4zX>~Y!wjQrKK0MQP z;c%WFZ&7@ByVi%p=jrig#fLZP@x=HnS(O;x=Js$@osQMk*C&X#XJs#XbK;Xr73h`d zWux$D1D?z1$x~ufHg5{R@1z)~BtT?+SYfpSY{Esm!0m$9Kj(;V|}LYq+ib^6l31Ep78~@J%*1 zdD(Ls-=Oaod(qSRpv1nekIs7|ivAvfTt@*e zdC3+{4-^{}r44+IuQ>a(ebW!a;iHttBwZe)%b&)l%j0_2k?2}u>mb_h$>@X$JW`n) zs9Rn(DQoartLS}{GN+{ZD#CtaNW+Jy;tM5hb=ON8Bn4C>=-`?+mk3VEn@E5^8k=utQV zn(2DHviNj71N6?<;A;>Iu`Y^4>87vCa^|joV_L- zF2-Hu6K(qXINP*8kXU`}#t$};9aL$?X#>|kd~)?D^(|4n+LNS5^-VOpFpg@_mrvN) zx>$Br@|%2nI8477rOM};6YGu%pu8^8Hr+TTOvR%ysUwNkW-L2&0QQo;6;g49`Rcbn zH35`p(wJ&0?kXPi=Y}}-r)zO^KO`2fyM5s>|HetS=gUtlA1T+pEs4=fdkAd=<7%~x zNt5`TS}Z{&y$dWLh%S>K?PFL0?^rtaS{n^?N{r>7jw$J?-L!GF7M&Un8&%a6G ze=*t{K8~;b-5t(OT%zH6ts=8PoAHCssB-Un%n-cR+*4=$_CI1U%)b*pBI%JzFNU8db#5o-G@jAp37y**ug;n3PtJ!j zffm)tVd%~jJzdnv;yCT?VXP$->2Ys3vHq9%wYX8K>}u5sTjN1t(|cq)siLlUVz8KrW;7e8xF8?Sd{vo1g2id?wH! zUgu(7(XOWl+jvc!_IQIgF`A*^$bM!LP(MCx9#KGxX!ce3zN7}NgwK)i>l48n(U=&X8UD&3z21oC-|zf_toOC(8xq0W zUEOOe5bs(x)+G{|TiDr;zd+@nOV^heHtG5j6Vj+ZTZS3>A}WqSNx`;)qn zp2*$=KkCz@&o|C~Ck=QcAGJKne0P6#S?b;Hs>JAZPw(Z+#JOIv2IJmD_Ff#Xh>jOU z?^a-zLiJ%t=P1;ooOk1%Tn`6C>K*zZ<7#2lqvTVl&qwOs*2-|Wg7UdUmygiBqIh+0 zCTvn7YcKoZGtUQYwT`h_i1rG_s$)NFSt9GF$6+H*#>Sh#8p&}_1Ab^0ca_gL#z9ga z*TFuV%=(!LWC-^d{1PwjdYVRMlTm;2F#()#*MMJI@7LqXJy!kUs{F# zd!ml_sNK+|^V`a?+@SWKa=zwr;Qs(hmpl~?yp(OF*c+X6O)7PL>i$gXZ)YN`gAeoz zBXDlg;m}&$<3?^gV##RllwR{Xik}z@Z(f3UBe5PCvF6aI`Gmb>bO~lcR2fMhgVr-i zUdc~lup(syyFM>YyS@gtE1FJ3siVg>M4|5}3x~H8eM=;L&jug{lqrk1RSEVr8XR{!#$$ED31?!9PIGi-ncX4!%YL-h`soby;q>dv~Q2X ze;%i&J1@R=+yR*86t2AS*Rmn2Wh0Z2|cNlA25p~%AKGT2RtJ6IbSR{J1Mn-e7$uD8iTk22$`%ItI z=OO!^O_(FSpXTVV*X03OC;ceCb;xZ?67xm(&gfP4IOm_zP`8P+m&NeYqRBdzPp}K? zRf+7AoC`i9#%Xb`A8df$M||@V=l+G=Sc6VvOi=ax#PGJcNp9pBqaPE8h~drIVRUl5$zMp(lJeLO(y|&LE}JrSm1mU>T&3 zFH!tpPk1xnk}tkRv**Co@V}U;L4-tg`QW0Qkgj z@>ekOvaA?q8s`gnn~+w9a13xxg8PFGu2UQ1J&Lp;sJpSat7TW_(TUa?gtL);2lcb} z>GGg{_Eyo)63<5vmSDVGio2SRu}IaSbl^XJf^;*|_adEWs`!czL-|)BeIL>j*&8)7 z=j7^$WI;5y2C!EXbX9&zmG7dz)rS62>T4iI{(W@w82TzITXGAWQCVMc`e;p=8-CM&@E&J`ub!=*f%-KE+2;CdB0;EJgYQ`gF1ncWL@M7is?n%>Ldm zdj(7sSwD!;x+-hgHtvF+_>o6)7=wB#YogVp(W18Td%#^maDUao8N~)!qD4BL`m^Y5 z!-O=_>2#!@nS>Wf2W>FvG_fyx9HO@%^gPrPewV%}UaF&0!oNX&Jw+~{0FG!jAmOP95!J~SjOV@9AuGX~`6Vj-?ECfEuHTkb_ilsiq zDciLuE9Il=P@MB5M}e16T~11DO>ZIa5}9`zo)-?Eqc7id(Qn48li_vY@O64Tqc|WV z7T#vyMXblf`3qS|kHlMudna_z1l*I=qb(D|;T%0)FuwZff^Sl28*@@}=Vr#EG4l(v?NY7ui# zMnEm_E|2J^#U@zlAL-Kh;eW>{Q1!v&m^B^qeNSQBm3%``^T9A?P1>lk3 zBvM`-@E2$wLUO4tAER*S`}0#|A09%RjyMBCIr}CS-Z3Xw22IsR`Cfc}m>KjE*^j$1 zL7O}meafW~^%_ zGXJ&{HZPI&#f|8D5?Q;+Z9KVgl&p)RsKW=*KGgPvc453*G>llbCONCuH!6$ctP9LJ zjMdYObFVmkBb~^4O8UjU>LSiLm91k>&L&EkE`%-Zy(cqXThmpa*xJ^C1o37kh&Qe< z9OggXB}S$WQl_#$%$?h7PABYGpcN@kIiL7ax&|f5iM`M*l@U~%JNkqGd;R~4{3u+gK zA(x2rc+tDWIAy;P=eXwRxrv>x zJmTJ-a3yG~GBQr%!X=(_5lWCAF`iIlAEiux!zfNI6Rjr_-ZrV75E z_~}4t^Z{o=*o1H#Yn1(cCqyuN5b`$mggv;cJd;m0L-=IG*HMIpfQhzeAy(aQ7~N}r zKhA#C0lbLykT}oW+zK7#JW1K~zc=w_Eb*)ICI67*I}iQoowz680_RWWA^Ox?rFdhN znQTuYHhJ+$;+eoF)z8)o!{MLc9#MZk*6NRvbZuqzb-Hp>nJJ{>`^Fb>PksrGy(~BB z!87ss<{24@efP2tyr0az4ik8!GLMCREXF;e%yFJ4WUox@9IoXF;+fA*Z2V!ueu!ve zIx2rI!U&{C>l-P3Ho|w19<9w%`eKB1q(_XWl*L-dx;Ox@Z?1 zU>9d#PlTGrZADU$xBKoc>eBbmyMEbpI`fSAi2I)&9 z(!Z~!FGjotds}`Vk^X*MeC-8ZBKoooc+W-9dsgKq7xB}vmnL%0np;h$@_ZlZha&Jl zQPZhBmp|DP4n?GkgZV}xZau;SNMB&UgS4kf*YUkPvHFj$r+W3-M$s@S-&}+-Pxpj7 zaaZ#-3I(C`*$CGoo%BRYe>8&c0h@cmll1AzJPP5jN4N;-1^RSltWD`#5!^^$txq?u zQ1jo9_-Bz$?L(!n%(oE!afFwUeziW`D4YUH9|?IKL;C9x>96wqW65n9_C2NQ@rpTG z%(3hS;HByD#PoekywFMFnLvZeSOUBvJw4cy?}=_UCe13~w&`(=;t)~FHy7anq<6{!2u=*OZSe!eICd4zrYhiczUNMH0)|7TH5Li#eKhxI%dzg1;0 z7wL^J_wer)RUZ99PpFJbkRI$O-GuZFNMDNd7Ti^Q)L)WETdUcLv^Tf*gvsWsFh;R( zU_#UZqz`(fC%i+Sjy#MnYjUD}c8>w(wg@@hqRMG3(uZyD30w7iBxR~~Rf6;}ulIys z*3&RPugYN_(zhY~u88zI)%4{^&)(4!ej+0OM|l3@fb%HQx8wIxPRHIxwT$vSGsbr| zs^7{(E9|!%sH2xOWFTb_%Pwr( z3!RRjD<-*!uUv$;kxpk^sO2zC9Xt6?Q_PT6_1P@fA8OB z6YWVzKR=>w&Qa@zWR(9|Pvn`}M$xEZm3blXt^&TwF9x3EtBgbx(fv8n4SKr9f2-+4 zckMq=UfflD-EUtkM)X5S@2@XfkMt*z9%1_xnU6%;R)l+y{yFYy{>Fc(^!Fp$f21c| zACWGcS<;Q;2u~vYQa%4tH_nSZ^N;A!?*TpX&z`8i*+Ti1A$>d2>F4lNeq?^#ee+uk zxLZE&3E!%RPg<(h+j_+R{b)~kdPI7)n!XkB7k=3j{u#)r^o&2@1 zQnBQ+4|vi1aTD^&MQ8&*5o;M_--;sb+m8X0q1Tfn6W7;Rw3i)^Zo{eF5$y+&p2#}r za^TT8P}MDE{$1v~0qNNh{94uaH5+Kp{X4oZAFDh^fwwIp->p1f6Y`|;tPS@>esf5& zygE{r?*nF3L>}jb#WUIw+33gHEW*AaFj>_hkn;V{B61mo9`Gs4*jCWK27vJvQ-g!^oSHiTOc)*(EHK-V7J zKSk(4NdE@EJ&oW(s6ekWEsQcDm=TH*st`I5Rw3*} zIF3*Z2YMC4euS|G=o7+Dgk+f62MNAy6M!#O52PdP8OP!H_!;XvdWAN_sDEZ|d}WOX}O2{N6&wZtop8gRwU#t}4*p zSlHAQ@CJj7{UE8d4II?_eb@Kl<)=xd!Q#n9HD%uVrpb#!UN;8X2a@nMzYi$uPAY4! zZ&LUJ_3tE?cltv3-^){K{9bPddpxDqA1w6y+Z!2sf}W|c zY!f|!;pz4MPA_|s-heLN{+Ke|7YKFM`%#(@WQSkyk}+3wdLbe0TQKMigqY9Z@dg5I?TjTEJwAvCmD0)v;<>$n zu^WvZ@Omv9n(XOp<4>O?*Eh5S?_bIFp>`i*UnZkcd3nxCY3}F@HL`P4nyFAMBc*u( zDjiRmDJ{@|w)u=zrvS9x?`>?Sw;3s|3hvyLR&Q%#YX@WX{HX)wYM`gq_W54cNKZj8 z_ztB6yaHu$3L->i?6#C(D9|{M^n*W9K5OU+B_pl5lb-!vEIIs`p4y1e26_s$`x$#a z1-JGE-T-?6Pn{hdczPveesf2_*A~K&H+xeSGzK}gffY7h*XavDE4)qKHqxe`RKqh_ zv9~d>s3TMkb*pbdsfQtkG#?t@2{|k(YKOuv46(DByDbv(BBtqPFKB337ULDIpcjTh z0bfIB$QvwVZL9?TIaIvbdtIkD7%GAOdILznj4q{A!eLjE5O))g<9U^~HMb*XDUYe~ zw#f_-cOQ6x3bc7cMgI1n(#qI_T5Nk;8`KbxyVW?NQ;1zS5|h&?t`F50&ae0R>l^%# z#$GkG8eC5CQQSvr9MrwCgX{wGoyBI<6xM|5q4lW8wXBi&2to^?06%8X9HP(eVx(pD zXx=^)hOxUDbWDAHk_Eht(6G%ch| z1yOWQbD+M}i?%@7vP`6TTRTJkpa%pzM1k9r0OF%z`~dNtO}_a}J{x`u9?z}qP4w(f z_FP#pttOP?@iZ=6Xt7wV4fR1^qX$~(YilWOtO;2xjW8XaP@vuy3YIpyYwGdGZLx8( z)Wp!>0&WzFElw~mdlTveIoyyaelz6euA0_(4J^ZdoX0h6$$yjwaRIxYXdXdy1dzqD z1o5+Y)$!_Js}sy48&;(yG>>QU!$k84b~ZqV+}A)FYZA;O$5ZZ6RD<20U>?4OZeAaM z?Tzoy>p3{}*0=Vr?KUb3sW|)o0MTBY0^Qe+CegQzxU&LH4V}$YkMY4b&TkO;FFpO ze^X>3P{L1(nqF)n4weiNxLK-rAQ%)SdMSf20*##Un@sN5JWMdQ#Cmrwk)yyZ0H7g{oR%repUl| z$2R0}XJYu-_3*1i=fT*I{^LBZVQc@hJfJjozP<0M#PU&1W))ic(~0IGs#sJmwB@Y? z^MOa=4b1m)1N`g6@^Dh~gl)#)r<%GF_FiK7phZ@4$-bX3KKU1-O@EMZ9s+;ge}WJ7 z_;bSe^V!kFaCztOWn#GXHHz%NN*G^sTouD2`-+q5!l41wflvQW@(^7l+jN%aN_4O2 zvqJL%?F&2&^-Uf=`U8QVi!_I)x&bb;*9!+8`rC?8Srt&U=(hGIFA#&|=x^zbaxf>f2hp zl)*lcZkPDJw)vRXfNTOS7|}oifcd?E$&xT6yXMX|KKX)<*zbo7|0rM_dYJk^pnj33 z&AUM9#i%a-B;cH?tbJ`Xci_Pc48}kW_5S*{MsGtua<4Ias%t##Up$W-_%VK8n>U)5 zBgQ+`kg84b`4n%l)>CWtxY7Al!`bS`fq~7b$@0`%JZ`rz?6c1%-SG!YkzcQYm0L%n zU3#RoppfMe`rjgPqj;QsxRg0)TuzINO~~~}oK7IBXWNGk#-`kN*674bhRyq~=gQjY z6&5HQ#-8;JzWEkvRE>Vj0eM1;I>cbt&903C2PN)k$3zIm#X3mr8R`p53azS`9=J6+ zY|z)21@^;pJXbc=SCQJWd+6C;HJ|#U`|#XWe+~Ny-4|TL9zKT(Q!nfRx-Cp>HG26J z0`?p#Y20UlvWFVyv8REgX{p11K@KdKJ{eeAafjMCMH#MB5Y;Bjag%|5Rm zvlS)sJ=BgF5ZF@w-bRy0>`MOJ(HWfANE0KS0T{N~Y8+J*hy&+pHBM4y%%jG&`7rUt z>eY9JImET|IC!xNFG2aPFdI_e1#dU;cdBh5)B56nahT?=u5g#xtb7p~B!(mZ|LM>g zoZlD-3692spJ;*4<0)+C0w$g?qqL&5!d;tLTvo=afODcSqsHoyQfUHgwBYwOv@~L# z!qc?CI^H7qT?p7y;pAihIR-;bjh9_EKAQ`16=axbK4nJ+b4&9|HHH@|NFz4?Ioi1{nC!7{{hmc@jrX}6`q(rW3n++%sj@*7LH<#S7q zWwdpswb6RmHqbuKZnaOgm)I-p)9qK=JM1^uSJ>Cs@3B8)f6o4v{ayQq_K)p@vp&c! z&uPdB<=mL_!<=g!D;*~1<<3RU2b{xP*XG@rw=wVWykF&Y=MBiu$e)})H~+@`d-I1C z%r59GxV7Mi1=|YVE%>4PBj z(@St0X0EYrvDRkK%Dz5(L-xV!&$63xmgX$ac_!z%oKDB}j=LQ9IezYV!Li5jJI5D} zZyaNt)11F@?s4`wSG(?XJ?Hw3>pj;|*YJtoo#>pHKk?y-rMVTk?YXbyzMlKn+_Uq} z&CAUz%fBK&kbfxuNd6fG_JTmcf`WU9{v>>Vf!md4pLvz}4)fp4pPC0-3N2GCEtWl& z-&qXSQPzvBQ>`~yms?j`pR>M5LhPDuI{`-NF!vr4mG%sMA~boQm$ z)@)aHS$0GAnK}NP&vNc{G&&bU+K)MzE8BIC>zM1ziRBaTocQ*{zfSyoVp*;? zw=?%Qx%+beksHpvGB237H1Co8kMkEm`m73j8qkejXmMIfEI!LEmIp1bSw4gY46&YV zJs-SfTC=VB)+yEs>vZeY)@Ey)b-wjR>n+yXt#?@;us&>k3S7Txebf3I>-*L}SwFUZ zX8qFIV;x`{VmsS*zU?AgrY+l+Z<}JPuuZpJZELo*p$2cX-D11lc9-n|+rze}Y|q(V zwY_QkjqQEgpKKr7KC^vk>#+^653!$ZKi__lJ=30T&$my3{>`yB+uQ6x`*Qme_U-n) z_D}5pgyx-{Rh|{dO3j{@JuiDn_G8(5vj33%RrUoruAIi4K+Zjo&LGD{j#@{9qusH{ zag*aA$2P|Yj(<2tI4^N#xxRKiIMI>o&MnWqJNN$F$8w*^eIfU~+;j3S$h$Ppkynsc zoOe}TM_y;%EqM>;{W0&Oysz_;^9SY+%O8_(&2PwW$={OyTK>-b-{${0|6u;`g7XV5 zDab7NUcp@jj}|;#aHQai0ybBCZ^6t%%x9U;F<)=~vH216Q|1@U+t3CFSgy4MEq7TS zwrsY%VA*Lo!#WcBkZHA9UDiTtnRSM>#oA$AXuZ$+g!OsrcIz*#??J`~A>(hXM%x%$ zmaWwO2m85MS7v>ZH8i_5+lo?8&bd5iqVsbXl&%AF(zs>V@MnqG3wpjSV7u7!UmDYhtAVoXSuAd5?7VW<7#vL)b+S)o9kDuKf3+_87HCL zjGAbhSUT~FiBC^_YvNaEvuEa>lY22*(7U;0r09Ex*|1N~o8K|NZ%zaLwA|X<`ME1| z@65fRz*De=+R`@0HsW@^d9nFz^S@xDF11=Asma#Mt<|s*4c2R{0qgbFA6Rd*-f6wp z`cv!U)@NZkUbnt&eb@SX>qpj4t^cx4vsKwV(7!uukJz5IZMAK;?Y4br`wKMh3tMs& zts|>PdN<#Gqx}~9?e@Fu57_@?|I&VS_5<0&bAFRE3fk4;Sm@a9I6W84?GZ9Bbv;(V zx`fPotcPspI@aXfoBtprhCNvTd(HfF>nql8a#Qmz%yZF)IwtJX!Y$RDW==N`H;*un zG-sH{n#Y;VX1jT&dA51Ed7XK^c>`?YqvlQK&1L|b;b)@lF3DL2OSUR!T~3*^%3152 z>74DH>uhq)bNZbf&X98P0r2EEzTF5Tbzd>$M%|a8_G?`;U9(+tT}`feF2Ae86>=?fEp{z&Epsh*t#Yk#t#z$)t#@s3 zZFD{A+T_~o+Tz;f+U?ro+Uwfq+V9$yyEAuJ?(W<@xqD%+_UCrx9?0#^J)C%a{HpwU`TqQl{80YF{3ZFz@|WkY%3qVeE`NRg zhWw5BkLGX6-<yl1A{x6V#31vuO241-^6ZlaQsQ_c}(t%)DlA11H zNEc3)+95sz^ZfhSO4AnPYJHA8gX~G_z^XMB-;$S9%(J+8ky_hliw9d95 zR%pFVCd_Q$J%!(lrv>L>50a^OqQAYZMF6H^pAnw5h~(4wb0mf#Recxq(vmq;Q+p@v zSuv(2%ctbzW`BD15p(!w%NwR@_k*j?qWD0WvA&0+=}R*l=!50tTgs3}#RqRNWt?&{ha zeZEQkV?+Z_*1(J1HMO28g=OFde0ru-R(qzF6|oczq6SGdRb{2MRG1nzKueMAPbn*$ z%1c^PTZoyB(=>?k%IPy%s_xxgURgcMQ(jtAURYaH;t>b~HGnB~pjK2~^v>Dw4&BM)m`l=o&pRv zuYekMzLs8DRqH97TE{NXq6(*1mKKxTxvm!$7gxg*Q_0knRnG8~qTcbR+-9YkV59m; zcCgV}ipUn=p2{kyF14c~t`8S#FiN%5)K)_#sD%tIi3_XRGp(X>Mg^Ku6&0msGNe;k zGntLi;Lvgk%SxwKxJgFS(J*;lkaeX;YFiDvNP{P_)fARYVHZcn6_wQ%W2?SeZi1U! z%P!GkM1dkL!{qW(cBu}e`0_efkGcvpgEDrRmQV?+SUQDUDpXoc1wI;9DJg=Q0(RMto1m|Hb)LI z2Fp`XTf?kc@>J+(wJ_N=9%1xKQ7oGVL6LP8QvPL?P*f;bX*smo-X9cd5N$z%WkrHj z6&6iHO)7dpl2ReFBOz;NRk_RDHDHYLt6@2j$;6A<6r)s^KO$Q2bxbSO126g6z31|hnLhz6kRtT1d*HGt|AJfI*RJw#qq z2-$tHd@Y$b(yE%0x+#-cffg+^%RYG)Og6Qr(wPv{BrTojPA#l0fk3R(b=6>xdIVE7 zMTNB_E+utxWU7K{7pO&%i4s*wEsji8P#pr*9hoRmmDDL(swj}f>X=eq=qV~Ggo3cC zy_2n3*}CMC-pN@Ot1h`zOP+2mo&rl#T*qy`u-4U{5*Wm)Vs^O(S2%qpNc5-o(@p>w zsrqGoAazbfc|;;gthR%Sh!o;Pwx!C56qHl%rBp>E5*jy`)Iv(#MbL{Y`Tz)aHHhj6 z2+F@#7BzhUdS_9qK`5Q?jMCZ?4`j^hw4}na8HKZI;Do_L^uRBI$K%Lh(=`BLV9C~( zxhvQVEup5QbV{v-&D3J9bW=|-vlb4gN6@M$X0x<(bQI;4XdjAArJjymsU=S-ggqB+ zhh3#b>-uERjOx-_H=C^`a;cPCJkv`HJup6Vw3LcU>Kv*HOREdvrLe2D6zMsVdn|lF zPv1o01wlv2L*bs~Tpf^7kSll(!0P*^l$4TBTEiN&B&F0OW7eoe3q>reR9v_k{Kj2` zU6@%^GIcWZMnqY(SzcfUnVjg7+n)RaNe4)~Y3OgIiNu#M-nt zvZmEV)vR5MDuec5j392NLz&=wt)>G^zWs8NZ?7c z-xw4xdX(HYBCyk2-DesN~XNu2F`GDb7&?3^@5Z*4I}FNXMy`sb>?~U|97f4=+yOJEdg3fO~Kr5Chi7<;oBjn(~V{V5%6#UpB$#sYm9gv zYNUfA4EzsEG16RN((MMr=+U#LnOpK^%`#8OA3fTLQzQ(|z|<~I!wKVye8b{Y93HhC5;rOIZ)Pk=fGizA2Yc?Ke z%M-p$tj9+mEgrGo&1RjA-DKm%TEJ{RtM6$=@`BmEY)AI^1=;rT{1tE_e@4p(g*7H? zrkz$YPhJ1h68JBy+7qY}`|nVt-t>fqSu-1l(LDAPIU(wCH_y>yr7@i%s;!v7wGtX^f1F96x&#FxD%up zab2stk$;%PpBLjVEgNbvxAA!Dv`rXoDKEWlcj2AZ5eY`DJ8#6>Ie64!UP8=NB_@e^ zu#=k(DEJy=1xzOYW*$Jeh)j}UI2hq4xAQpqlSv=1DsMz5$v_ zUcW_D7tX(;awqYn(!P0ph_t;JtO}U&zL_BAfD%hmOESEGzeH8LWL?nuyHXd6TF8Em zN1b5fx`g};4}{J0VV?E|+6>R7s?`OYFrLoKPRUrJVax;+F2lYB;4tG6zfHn0DQAI2 zJd-5go9iwqXW~W3nVupqDQA+dkTdN%=zASNlv*ysJiJkk+Lam5Dpkn2P)pQ3QC(zU z;M!kZNI8!LfRJ-*J^H!E4q9y1U2aHYD>g@od?H0gadb5!dSj2&LkyI37jf_5pC(kz z7ckKI$ZS;T5aQRX`3z9w=|M_isS1O9IK*nitl2H8Uw}9*dx=HAz$suP*4v0V{ws-f zbyO@mZc4yNtP7FhY?YRk)0clFt!XNZ#A-uK=q*VL!#~|6vDT_E66+U;*{5PX1RN=E zrb^>4DvZQR1<)oHi&~MSpgm1cVIP9ya}K*zS|w3A9IwJitTMzL zfE=}YZ$?c1=^{pyu@f=-(9sbWNe0@8*_WSg_VvlrG4=qCk? z#5#_cNnc5P9p4$|&-q%_U~R$txt ziwYyL<^pg_46Kh-7>VUU6Mx}bNsBx)?UE(@r3xdlGBI&iyhmc0fYO)4wJMCn`T{YF zUzJ#RiGnp7U4(#s1(uWjG(drL;|QNIqL%S}Rl-iIoO7Wcm9NE4no1sW1}j zHN>Q;<%;enOhIu4jKtc7nDyO~Ru?$zYok5|3j#)BorbPv>sE;s-P&BQ!bq%c#MHhl zu~0F(OV-!43<)E#9z)EeS0olpkM5FKr;m{^63dU6O)4#jIEv(ts4x<%{UWsGW0DqL zqG72p63c%v=3rGDbrrDsTG3HsC5*&+2Qed5tmrnX1ELi$5^K<<@CLt<9BRD~2}Mey zQ-zUOe?ZLfFC-QStFYQr@nsT5Vm*qOt)ED&E@1W5jkm{17>V`Cc>E5PYT2UOjm%65 zBe6OVV~SyIK2c#L)~pHmW;%v6o>pNb7JaQW@_;N?2g(H}PPwEE-%w#B*3A}J?9U_? zlroBLj6xSGU?kQHh%v>$sEYQCse7H?FWt7>V^9V$%L1v5JA!R}W`r zNf?RsZ^X>pA+e&@*ZtWNMq**J1UvGk#ENdCeyqYstiL1XSd98AbVwM9wFWU}wN*yf z`N2*JBe8Bmj41}zn<|XN8sLKG`DaXp7^~OZ>L|qaKY8s`!e7O=v zVx{K6gZ)%uxlvgcDwLSoKD$&HiS_e*SmW&y3tedxT5}2{jKnfdf;x3i8T^x-lf)Z zu>q^2DltjxWfewZ)wvm4r`lf4su8Nh8Z<@1NUWC-lNJN34Wbn=66?GYcn*J&^@S#? zQqZ10P+=t2s#5$S*A9twhFT^)hvP4oFcRyRh}jdPePvIRFcRwl#Eew^4VdpJ9I`SA zBeCWnW~?gt=&kYt6-Hu}l{2f63DD8eEA}^FNc)fWeAl*&b10BvyVE zP9#^cqRVi<3L~*PufUjEt*?tg3reM2Qa2pc5=LTuiI`2FNDiax{LgA6jKrE&i!rsT z^Jhh+^@<83u`aD+Y(tE4y`{oPEYEac{Z(?f7_?GkvDEs`o*`i*R_aXnV>=~Q^j6ud z!bq&w5VPbXiFHj>TF=drFcRz0E76<3Cb2GzDvi-_uLO+5x*IXaUYA(WYuPqi!bq&Q z5wl6H<>**#b0mz!I{j)`Y*q3Yc1F>S?JA7K>hNI1@jJ;Ol}o#%Mr~1HB-ZDMS$t4p zT?Hi^s-j7(hv!NdiB(&VF>IH_ie9d-R2Yf%;|9j&svN@kP&Gn(`cQ?DSR)!S3!(N7 zCSZX{<&qrUsKQ9BKO<&~D#HxGOIYpcM@l#$nSt>D!zvMazBeCWOz+nvSO$|yIiS=W| zq{ryLK2~8QmNkT#3e~q60q**0)cq=q#7gRf51?YDt7W1GS*{ipMq<5*m;>KPX`srZ z==^u)OBjhoCo~_~A+e&5eBb#0*!v#%s>=HRJ3&Jwr9?#~n>uwV;Wh@$A{(#~lYxs( zU5MTNyRhlqcHQn^*i1Aks%2DIXk?gZRAgvmSY&9^=qnZ(78)iM71}DQrBtN9_vbw4 z^PKbC&$;)U-QA7r_xC+7h4J3|^SnRL=lOG<^E}Uaj^?n{xyz9+UFW?c|CVm%u+=Fm zFcaz%!!K(NTTQwVz43PT@KoeW#_&s;!&Yzn0JNTAtMgou3+Wgx)*QCF56G5XY;~@u z*2TCPDh^wH9mpPSg+Yu*4>0K_=CIW!AWgqut#drJ{-Zf;Rq;X8LtQt#+t>Fshpi^v zj2P-@cx!!7bJ*%hAbWLhL$%krxE{W3C3D#7Rv>HkaK4IRBFpRKTbRREp9eD5M{7WH z*sAhY%y{@{J*zovRsW$-s83tXf`_B=zq&YIV^%STt-c1N(#Pt(A7&0){R7CZmpK}z zKtx6({t@P|)gd4Uefr+;N14M`KL*n5qgAn*Ic(JjWUr4_(Z`s>R$l;8H;_7Cr+u6` zY}E_o$UjnB9rp?5u+;~E^y#|c9m5wihpjH_MV)^6Vc2^;kTo5Kz3b(g>i6X zb z0a?A(<&m=wgmaUaFCz2)gi`!`EdC#rvj%_4>u#v;c$LdyHax?Bu8a34lmS!m`J?N% z>c`2}Mj*^OzJ)oX@e4B@Vm^!i<0ms`K0)I87W~PDDWxzfrv!gG>2S$C4oKw zd^rCFXQvORfWijhRQ@amr^JWz5pZHYoQJ^K8yvtseF!n z8uv;cPA@oPQF&6OQ~DXquljKIfz#u|srxLRFMK#32B+VL^EGhtj!W%x;aaR6`*7X| z&RQQ%FF3RpB2|2T4bJE{FlR0bidvDnP>j|!`F7mVG-n1d6svtP=iA_{_TjwibLhi0 z$Gh#U1Luh5ltD%MQ~dc*s1%)x%9po4-vg&dbG)_M*P%=`$2;#Q-2s0z$2*hc0nSPv&g8qW9;Z3pb>q9>3}}wG&u4xKedbv9+1sCc!HH>3 zrDt7zas%R{Io|%vx*MYu&GFXyDmVqWo2M$%H+>o7Iv>s*;B4^WoP7^QdOni$8xDjRQ!+8;$l|G!S?nRkuj(41U?t?EUr}pPZ;LPyh%=(HN1Ek8=dT=)DbiB(n zvI!$|&G9bNW50^A1a6P1wC(|?)`#<^uVE~qIo|$!51d_^+t1Gsr}gj&I}*U zgw2Sd59jmXZ1&;o2j_t1l%jpf`_2>J!2R^iseNv{ANNzu@s7{s-^ALD=6J{FFgUw4 z$2*-TwqQ(x$CFfLI_Ck5NqjgDfYal{dFz9?fBA481E=4I^MP+6hT~KFJY_3l=)?IN zIBR`4pZhlIp%3Q`55bpH*&pxwMJqU!n&Vwwe*$Nf=6KhipM3{o63rGt7#;=7nx^5Nus4}FUd=gZ*ap3eSw*VUW0qf9l&+vgX+ zpHd9 zg%jDI8kDJQ@3a30V|C5(_UBn}Hu`WTKZ&ur59f>EjK{o$s)ycM$L>O3r#ar`z6hLN z&GAlW2RMD2_ z7I0_>WU4s-3!Du;oGX5Yv9S;50dU6UvepdLG1+g-dKzV_Io{=U4>+qd$2*8i&(;T)s^EoxENDSrwB|v(Nd|?{SzBq@C z;9%fsrK_;zKqv-II;()}2SV10^F<)^rUcD?D~}!{D?A<3??>f~)lB@Lqxk|j`|zt& zoKt><-uOG5_gq+Wj-8(>G>6r11hQUR<$GFf(Hyq=4UnDMpD~7&%4aC_Z*b~#zTO6o zb1`S~K8!$goZsva@Dp?9fipv=W7Z$y@M^`wC#$F`yCztz)%7_SJQ7tKr&IW( zkq)hTJZ~Vh>TxA180jc2TJ^ZfKxozDY6H0gS_ijt>5PLder;du*&fZ|IG^x5;;h?_ zcdMMLIc#+ekm$Er%iC(1=CD;SkkPs(d>+1?zz*uz?bjT(y5!dw8|yePfCb$V)y4U` zUUS&$%RtuZc6tFDSbwwCW17QO&jYE_(O3rdaoUotE_i`CY;_%w30jNVmvgbz&oqav zrtC+{eT8F4HQc$_>cjh)!&XlN>BmTp%63%F#rTuC&QCLc!yLByI*>y@WvjD1txoza zbJ!{hWVN=6z{=^PSoKeu!&Z^sp~dOeMD(f`Zzd?b;PE*e&gigqyx<1ls^e% zgU)*{tk?_Zr@w0sTP^%OYQjG_@8@}1?bRH%dfy+A3vG2OtYmAtO>@}l5g@rfR5Ie4rH75(7V?CL37w@;*0R+ zFl%{RwQCMreILl?f3nr-NJ7T&w3nE}R@VX9p`+nl!=KX}wkrP$u275J!t$qb0PuJcOXgM{U%d76s%wenjKo04?#k;)dEege9t80Mt>(+E8w494o zSArAL94a05!trb)IJ-6H3?~u%#Odq=hfZ-f*Ui;f0<4@fP<%8VaV~zZpISL-su7yg zOAwRS&G+MH`i(jp0Y4;Mv~E5c+EhnIVb)+$5FltXoKS)yYL z)o2d=%jqR-YN!|Kl$_7$P|bAm&gnb>PRxfBI)rB;AI>@8?Dyf+fivNP)c$-5oGKsA z{ot(DoVm!CjL&g@Lk-uQN>9!la3)@u+Mnydsqx`_2b^9X&besoeLkFSaE@rs4A1iV z6F4RLseN9E9zCWx-swC8&SoFZwF4MKYEF{+15Pdm+oLJMIo?`T==B$Cj(0jA181!d z=O^Io(j0HC`7fi_x`_Sp*7__sr9Pae!Rhwlybbq?Ek2x&fOAlDynX&RIC;3WsTg|u zeB)un(1-IhIBPY>TkD#Cp)Z%CSuO91u#$On@p)1lE$CEyaS)WfrKcn=MKI7Bb zBkJP&*O#Ea?nkO08iivd-52*rJ2i)`=&TQQF+%5fmMkI?+R9sNhvu-=^FZQw#-K2%y;xKO)Wur)|6vYWwE;Qw zBwKlFeO7bWie@3y#mKk7>Hj{ba~l8J`kU2%r8#UxC&Q?V5jwxcL|%o}gmIKIa|(_m zB6Ny~X%!lih|uXDCWp>BF%dfJ!$jyD4-;vCddasrr&I7tU0L+l=o6a5K7SL)JB(cX z4#;SqbjJRdIh;-bknI!P(V#OrOb>4b=MYj?HQ_@1QU_K4v`=$5<-%7HRiMhMz|-mz zn!{H6fgI3U-t}kEYs_J*p90zSJ=S^@TDrKjho{05#bK+7V^uywx+c(5wz`;e6|A=5 z4ytmo4!@MG;KQ23R&;KLnGT)WVItpz)$Tq{`AYm!rhG_qIORz>IiXc(naZC!Sm{cq zb9%Gpu+>vQHfXI&U?ofNR7{2{4qMd%>HZ;W(Fj&rt4n5CSAA*&vV+F@EhplM6S6z%;dPX8bCn1=ewMb{9u49yhjOwGB!zt5w z1!g*Q7J-SJgR!BB(CG~(@*+~6`xDM7-DRYD@d?af^&5e#)~(6AhCiV>Z1u(yb3#2B zOQ~At^iSjwm&$uJhppBC8T|-b>*Gk(QZUxW$GC8>++#=GCl9JZqO=+(sty(4cT^!~ev(7Wv>vI8lvd70Ho zS^9j*Da>K5JAmxdHPgGry{I{CRXjc?RH<8mcQ3J0bJ*%fKn8U0=Uo<;pUNDzqBq^l zoYEN`CPF8Km6gf{w6|i@tX*pwqYXl&c2DzDH$e0Z|Ivy%Zx;XPOdOH zbSj03>?%z}=rjp+aeQ_nV%_@QL=8!n`$?xUhpnyvGFRUR&w~}$Q0J$QYYtoO0J1}u z;Q5|b|JEF~qIZGS#R$FUYa*B6@X)-0)U|h==5RVkfb93F^Vd&c4qH6~q{qi<4kj!W zhpp%xL(^wEL%>And;k-n(+Nz3-c~jddK1}1=q-K|p*QqRgx!W_ zQFgkHeW&KI6`dxbE=KMLr}>H0bu4ribJ%J=kho9Hd{A@P>dg~zckr>gNpskW-V--{ zrZw>p1hjY;cq)GP@ z=fFz#NcU+DThY78>SE;Lo&FiTe2byymdgg}JCdK2}Yd!&dapwW&_;IGYH)Q*0vizOaeV zTfHViZ_%0vy&-EN^d75;(A%aaLhpo{2<=$-B?^Svv})J1V_~m>(2j*?HNtOYs#zmg z<-G62PzV&)#j8vCz^Kl8ovO{NO9$|KdZNPPthjjPsFu}pbg&FAtw7B{y`m&We zanYpO_;L8X#qnM_T8}avgN|{u#i7B6lN7hTAA?is!}$+5-9DU4&dCXF@!?zv&Osl} zMsRZ9p4#W9z^V1&P&us8oUQoRaroc7{)KePCa2cA;9T6heK^(NZ1v$h08YQ=%!MQJ zzH{<HHF$tv;L+@^V5)G=~P1vTj@fPDug#M^%OWIKAgP# zoKVb%(*({Y&G9bxpMi5obG+ko%-e8>os!z;_kvUB!?_!rbv~RI!P)J@c`II-A5+Z! zc-OHQIAxmSov&@+^!RYzcQM+959csA{XU$}V(C8*&yA|w%RJli#rQZuv*vi0*SEph zqB-9A%AbsO;lt?xCl}ACsp{b_aB6)x)t8`M_;9`m&Q2fBK5#6mXWdr5|{Vv_Nw>od}RP$Y^&qD^shAeMq@( zqC4f&rzIkC6;G~q1zDw{Q}orvxd<}PPbZ3-R&-jpiO@;lCX%UH{Y=ep2AM~aPyKS< zPtM5%dG?gg=Je$9W>h%y$>kISp(mH|8sR4wRS)S&VLj^mn>p~--~8l)L3c);T=qdh zJ#nBb@VMy7r80+~T+qxtu4jQYjpKB@pIoj(onMurm!M=1;Q#HKvl9QJe$ctNCwVsp z{;DUT-`)Cd-6`1Ak3*~WRqg@GfI1BB0k&%nT8i^)I|cREi{NbjHK#)lv~q-h{B-7U zi^~I&e~7JaF;Zmp_i7GXtpL)$m90*LmE#m!eO7bWY7>x2CvoI+VMR}>>SAAafHMx0 zGt{#wY!{F{K3ad!9M<{|5Go<-S=f>|uOugQk)5*gaVC(hhCgqxy>VjKAgopb*=(e9 zmq4}y`GdiE4#-Jot9&W-;!Ck6{#G|~HISDKqz6cGuA6fgkXi$I6v$>>f>@mMD2oBj z;rN{U4y3GWT^{l+OYp0j!&Vo+6L;Z#iaRRjgRpW+kjwop&0(vtGcZ%C?{Q;bsl zs5xx)Z6E` z|H}HA=YJ-!hdH|hhXCp!xBB#u7b0Ra-pOMv?=kJQ;B;#a^=uqVr<`s9XS?QL!0AyB z9|UK>heK_B65JR~DmhUE$Sg&`q1{Ml-Mg6Mt@Rghc54p#?8F*jv##?m!#MLYPRBc6 zTfnK+9B-`)aW7btg2Q)^M^LeyJIDubb36*ZBk@jX<-N=;*SifqtU25UsSj5dBR>Zx znoH^A+NJqVAU`ya+|ry-{W)$9_0MKHv%opDll?(gi4^(bI4{#2R=*d>njf>3_kHI{ z&0(v4AX`wWNg>%AmnY6-4qKfMAA3mmCg)<+Zp~q~Ek_Q&(;T)srUIkE=UB_UbF$Vsn!{G~ysR!p-U-ew z-P`2hm&^$1$hT__Tipd@lkRQMQERUAQ=jIr)$f7q)H$W?FRE6PN9^`{)-bXZBPTQrBQHUQc5eYTTVaY)=f?Tz z1DeBDyMgrR9_dP0jmH1#;%L07k~wTOA4us>S!*unvbKCqbJ*%RAZv8KsC~(Nojsp9 zY;`S=x`$Z{!yebg9)3`B*y>IovG1m~dP#HGYU%=vSADdu)Eu^o0omfC^-0ZPt9ya$ z-AP#RRLM)<6*1ju+@iwgnX>-(;T*X49FTEs~0qftzH3A>SJ~K zdzr&lML=?WqEW3mY}F2Aw@*D>qd9D~8Az3nhr2X~t^NpPoR8I*h0I~AJRqgIkMiy} zuGbv4`Ua3gKGFDz=CIXEK-TzJomkBrwz?2V%*Sf3=CD;0kX)Z=tkN8|`Vx>0K33Z` zhpqMisq?WK&>XfpxdwH^Ctn4c!&a3*R{B`AY7Sd{49Fp$diXWXVXG&ARQYKAQFGX8 z)Rkz5I$ z0U4*QW_sr9Da~Q4{{mU5t?wrw!!O?IcLB?$LMa^NWCxPTX%2wxq zi!j<3Tm4mY*y^PB;f}V0t-Qyy1)9TF^MS0{&Q=sdR&aj0OLN%jB_M0{)2O$HS1)1? zTm1k?t?pO7t&YEjIc&86$gZEThu%+QcW4eU^+ed0ludbJ(f|NVm?{LRiU>@ZFljRxbiMpsnzT=TTl$-_IPj z>H$)xt-NEnOLN%j^e}cC9_D;`M=Y}E&(Nk?OXXEesuF^8?L2Ga8=YrVxYUmw&Q zw%P!s@@2L<(^Ko$n!{G7*W=l92V30@tK;#%y110*XbxM&fUMrhRvQ z`hUSz)b~oOV;Y#lRz*NcbmY(Sw5rk^wrT+~<9n<{k#{c6*ZrEqR(}DKtDllia!l|O zTTN+X4qJ5s8LywnE_QJptL>V@R-q=$8tL*n1y(W|?V7_@&jK0nv6>rU4qH74WTTJO zc}tkXR-Xd0S(n$lJw5!s=CIWtfb{vqFn1|)*y>6kleC94&nBa>T65UyAs}OPA4PS; zxwyQZ)*QBakpzt9`64yN)?*br+BlAFJc9XAWDn1KFWxJiPnEPiqca-4CSf zXB@-%h=rV!c};WJYF-r4(B*~24&4@=pH^rNTYVYGdYvzC5BoHSt$qWf@1N{p3AAKA zyt0)!Y}E&3jh-?jd z!&biqvR=0@Optm+{tYqau+@b?^7}Z3-jQ$A9Jaa>NZiNjMa^NWDL0@u_OXg-4qI&k zQmdnJsb?u4(j2y$(t$Cyz7w76X?3;cu+=gk-P(#~N@b0DR&&^DdMEZ4>eXACMR!^X z|8zAt^wk6U_oy5i*Ett+Xl3?sbUPNu`ZcZ0K4BoVGW#Qq@XBm7mrHOnlFoCSMk>5_ zr5Ha`FP3W8{XzWxSc_vM0YqK2GP@;*_oe999r@QGUYXVFAUOv(bDBdxJd6M7oPQM! z>RaTs91+`zBA}i-*>{c(kQr`vij#-znfrF=*LNbFyqV1L?j@cEXR#0G2smqfIB$(( z%Q9XN+H$2&gX04INTYM);Q zr_P5{x(qAVKAh#??DpZ@1ce>voNgb^Im zfm2eR+UK?4#C$m0!P(@)8P$zvY9CHLI1}cuKi)eZ?gOVrbG+mH4{&;YIPYA6yRZ+Z z4xA%CoUPy#V<~Dhl|qtlpX~)F>cjaLI2(O9XWxiDLOz_?;EbP}+Mi}{Dt$Pg1ZR~G z=Rt6``*3~<&VUc+2so1}Qv3Xt58yf1hcgSD^*)?NaQ66cJ_^oQ+)7fF>1J@sd^kS? zr^ko$PjI&SaL(+(Q>_mt0!|(tD^mIVac~y;EjnGfe#aC$VyJ6{)k1ToYc zZ>>APIpo6``%%R3%G5sJ0#2O|=Ud>c^WpproZUX0{M8s^UzOUQx!{!gaC*S$)|^uG zhdKCPUHlBP6`XCF;~m34gLBA-v*=@p;nk^q{vkMZKAfVDBZfYlT5xvzaJ~V~nA+6- zyZ}zA59ioVAcj7io50!P!}&Ql2Yoo__vVCh-9=8QlY+y$op+7l-Ofwuua9tzSARFR z)wdF~57~VK{vH)t5^wHmyB=@ipxajn&+SZ@#&bJn8uTxo+o8x&TN>qrkA7`ke4;`> z{&g(=_vExR)yM1eig2q`>N(?yiT|Bzvf>mwKHJDtm(NRDqLi=yrpWtI$XD?Zj&ly( zRn3cYv5zC4oHKnF7Wk~v$vM$X1pgBGlBJ{1PS<4-velDD~ZxZUOg!)FIzD}s;r=?ye)K?1i4MP1RLcJg@^;)6cE!5Wu^~FNH zBrWwCp&l3NYlV8Lqi(mj6M?9AE0Xs%PCDG%xU}Mt?l|gADdz&3iC3n3n|uhU)|9-r zaeU@>>hjsn`xz4Hq%~}49=CIalRO1#;j!taUG}P{8)ZT5X!cR-Xr=Y9=F@djCDhsoHd6wz^n-EBv98D=-4I@BZ}e zlF6a>l1zl&IWmz~kj_>+9hLha@7mMqznM;ux9{mBXVZ#K{WTH!hW^{v;7R-kTwb}L zvrR~s@>b2^_|Q4YX3BI1vWZOlH0I}Z%BSO(%y3e^M{_vk6F-BeJ$ktM_;_{;NpVh@2I&axT=qzOux#P3g9g5mO_^6!E;7<(T?2Fa^qB)%MW$2tI zXe%0nIwMB5`i$nV)o+08*E#jJntD5P*oxk2Q5Pfh#)^s1+bAYNZwU2QLehFEWC3xQFn8Puo(}T@u$kT&wJkO?t*lJ#0BJ#%b6A?Pi zSY2%OeW)KAU=JV0FX`T|F0L)}KhGStqJ6OHVubd%nh5P*H4)mIY9jO|mx<8MVH2TU z!6rgGeocgS^O{JuovxgzlRfsLEXsb!<@F{z*Xl1WuWk&C6^BdblshmZ?PK+T=CIY} zcVhnMQP%2#2tBE)i?#B;z#O)cXRFdl#p+^?JgN9kvusL;IkY3uw4xoGCPKS0O@ww@ znh5QpG!fb%X(Io3PBO)VBOm1S76zfcoGf92X@K8bT}xqm%#SnK^?#AwjRYW!Wy zVJmsUFzq%p%ary6nh5Q*G!fcGX(F^k(nM%SqKRbNX~rXYcCkFEnD!`|@sTGB$@6k) zkD_Ts`wvZo_7<85?He=^dDhTKo&y}@G$h&+X!=b1{Y*rjg-d(qOiqv!YiaMCX*F<* z4TQMu$TMtd@0@8hlBe1}j@I3Dk{YEZe%X*muKU5+J(fB6!8N934t)jK%*B6T6@7?% zB%0UYe#rT0!k3uC@hJdO`9{_n$B9~hv(`Lt&X`Fl=h~iJ4TMI`q@Y;sK;|0Ar+{=D zRqMI4T^2t9=YS7q^;b|2>yrD-vwXAkEMM~3-7UyIJyAJp zNoz(k!fko&Och-{NdP`y+?G)dRo~(i15@Psg%`(OOQOhG{-jt-a(w35U6;@H>~2+x zydQ;p74PLZC!e{Ux{V{BoHKpHTR1*+moYCc_j;Xo`hCTw#BhHV^+%N{?kS1Cw3GY^ zIGbluxr1Y2{{Zr&ft-t!4`@V2wF`F0lIzM;ZJ{Ko$KL4EV^a@VQ^zf39sZTzk6l~Z zb;Odl6iiVkw3M~zPE_0BypNqVaxDe!__h?sXKpDjpY6QA2NfyV8qiV5SMit}&X-wM zlwZ!pL5_Tima=ssr-Q*#!X@&>DNiqct1eU3BTb!zk%L{z_F8r&tFzU#xo0t_bV;N> zKDnR(nFzi18uhEJHJN6z#wuVSH_j~6K)K0{mCdl+Oi4vUlziIm5Ql-KB#liv%XqD%*bR=?01E41gG)JYPLRt6yjx5L%;!R!;z}RYL2a(AqDw(8Zedd0I&T ztzMyZKxpj~T1Spa)EXB+Ypu}QFSO`vL$g&L7FzvSMD{DM^+Ic((Ap!k287nm09qS` z)?T5tTWB2;TAKoBZ5CR4gw`&h)i1PG2hiFov~~-vokHuN&}t5#wOwfK5?Xyii{7g> zYRk0Z09t)QYp2lKA++`jEjsequO99aT75!myU^Mvw0525ueC>L?GReqgw|f6wIzVo zKB2W;Xl)f*dxTarfYt$_wM}Sk5n8*2R(=4jexbEhXl)i+yM)%kQ~k?pKxl0dTAPH{ zPNB6afYuSAwOMFw6k2^kD;hv+^z6j@@+P6RL1^s|S_J{L#tN;CLTkOy+Ag#XVT+Mp zTOKd8HVCbCLTj7Q+7du(qR?6|wAKo(twJjrKr2sZtrJ>ngw__JH7S7BB%!rdX!Q!M z%|h$IDgNbEEVR}Lt<^$nlhE1_Kx>B3>J?h6gw{r(RU1I7OlYkZS}TRt2B9@RfL5i@ zS|zl4gw}eYwd>9P#l-NWX1qbz_{lhEoGS}~!u zMre%=pcNHbaiJ9zTD?N65A)A{{b5{a#e`O~&{{3D;sLaJgjQ5&H3_X%LMuOj)+(XZ zEVSx`)=HtZ4@=m7G3*suO+st2(CQIdy#ch=3avV!RV%c*g;rSrt@T1{vCyg!T5+Lu z#e`O00IkhJt43&53azNn>J6Z^RcKWSt+_(0S!l%qXl)l-l|rjb zXf+9~ssLJjLTj$jDivCFLaQu*)-It{CbVV*9e01wt!dXw4N` zw1>(sUq^)2B%zfjw9155UI4ApWr@#U`9dpKXq5`B{a9Y~%hy<;l_#_&3auGJYkdH% z@j@$CXiX4WB|@t)(oLFR%neDT6sciOaQGip*2Qmg@jhF(AtUpgMQ^z zDYQllts|p39ea(nc%sniNu_1)mv|rYuJ%hTZES3DTjY} z?9L*NylB78K!E)={dK(GrW+QcjD&cHQlpMxTYbDUUf+R_3p0`PHM-pHpK0+b;o^MN z0Y@Ps?{eoO?;t&d-&-;CNC&^N_7TzZDS0}|W9KLP{88<5JlfgW6>~hM@6d(2o5J;> zBiNl~rDG#EhC--^3L&lAQKl+i-gSdGo4{FR<(+q4eH+LZY{c15;>71^SYZL!b#Z)} zfvNboerf+GJWh5~|#DQGX~W^4d%N50|O+>)!$yV<3M8 zQZk47UZi7jj{9m(=u>mu$T>jXUExLwfy51D7LdY9#i2eZ6uK73Sgj@F{10?u)~(TE z(;tKB$8^5D&ONaEjrF?UmmY;RUxwX+fl+bOt z>I%v!<%>OV{+9VNb%@FLO4`<$tUn|kCJAQ5XkJ@LlI{RyhZXFLq`RqMT;PP_v zbq>-oQ{j9?@f*J}K#+XJQ{;O z?Rr>he?npF9@i9_i^QCkQiS+a8b~P+ol~R`3RMA#TjlN@L*g`nb5WIQ1*%2hj?I!BHIACq zZ`>=*vLGX>t9=2=bgeGaZLpv+a4v3xC+ae#-+c%1aW0NeWwojisoG!+W`1?GipxDm zm5-yOexiJh$C|i`4?4Ysi+w&v`y7jOMjCY;WcriHh4MLh{dobL2dsR7V;TMx$OSd3 zwkYJ-ucNjY$az5Ce5IQ+1IT*~qzcHd4Wu5(aaXymZU)k%5gF&_5CR->ixlF|)!YSYYLpYB28xr}49z1K~Fy`q6H(oOT4+rOpfy)$(X)f8 zwO?paBQ`kGMyJxUYw!DY?Uip2QI*?_+DjLbLOsmGpXP{>ez(o$U|;|ax@C{+37Z2s zaBA^qLT_xBX%*)^=OU3xChPpuwm;)6f2dE9*KchOUa*4Cx%d+yPPqPNbFjz)PEW#b z)jyBe98BzkL!%2b9q!dTbXi1O8Zbdugyd9Nuf=mQB_3ERs z1JLj8xl+fuDH@Hm#XDBG0*y3|-;DQjtvGw%J!M%?1k7tNWzmG(SmQ&_T&aB3q{tU3 zAHe_HQ}xewd%w+{caIt1vyk`I0rIXmR2IXZ_l*JaJ`f=9v;w6@?`q~`S!b-Hr7gaM zOYTDCeQkieD-Pv-HcZVz%XGO91jzd&@--koHIRpaygBUV z{20iw4Q}LlAO#x1II4wKC#aX8{*`)xP^cfAOB&r)M}UM4Wb8LEM`R%RKwfTgTg?Ho z2zAWKMLm$WAo32f9LQH%+{kS}p1sbEd)pr$KrV{9ksktirqzu+2jsUMZsadO zUg&fqIrn4C-=&aa^cYf=DbR8B7{ zA&N8MqW-z;bmq)Y_^tXU^<&MtKGR!*rcZpYd`8#jrq-5D*HogN>YEXbx)0jXFq?$d zJr|t&m}8++fD9POyMYwmoETM=GUfC`@R0KCTpZQafUJ7xp&lfvlp;lJZGecaN3Bym zz$RGGPtL^=`=gH7(x!NOy?M(6eLiw};1;_^dH5V|Xu)z1ECuJVFURIkR68lULe$L9S?sGM7L#2>kyDn+v%thd=<#5^<08PI`Nx1q2C+G znLtjy%gs3-NQFkiv8m|K$<(c02+n02*eV<=m`eA!UeHKcmBLJL9>1G8fJ0XRIqM!b zvIxi{2C@Xmo%gyqHvl=*6`=N(;GU~mH|=P|Rsh$(=^dzZu-qxGGg zElZ3igO4E^n>iXD-tcpQ;*ihOQp}6vvktITf?nw~bXqkbmurFthf<}y?+K9i^{t%u z5?Gjtao*qIk@u+U9`SkPJ@2b_O)!%nSM+#8aVYP2X*%J`bl&sM;JT5#*V+>x?-e@l zEuC%k=AIbb<1DZ&Mcx$yV;kn^XeflDF)bk$&V4XbH6b1#8e`l1YeKCV4R-QfhO(k)Tr}*_=nD{yvH;OoqNC9n?`XqpfvZh~ZD>=9XmFpPIF$EG zhCT1&aq@ubGn2QAo&b4|>%1>->`ctN4ebq(cf}c*yf+2N`_=$?zg6eG9?P=fmiC75 zlCHMK$y|6_&g~tWi~0kR|dHkYz>h2{s4LZjL!RV z!+j!w6EofvllCo(^Ym(y=qIiRhgA-;b>5PZiAK1g_XfC z1NoZ4`38`D&S{9!!5uC19tCHT=J5SX`9pDDk4({+-nlr=C@$Z2sy+0WH>MP+ z9u5SEb1cT~bOS8RI?X=kK1lhZQVd#p*~uu=Lz*9p*}aQyzdw4V}v^G?lYn>?HxkBDlPQ`LVc`I zpCr`FgnDgS>it4}yihL|>NP^WE-m##LVbczrDX-zwBsr=>nxs815= zl|p@uP+yal`WT^JAk?db`kg|3U0Uj6g?h12r~PAQGy;i8-FVr`s zr9NJ$&k*X1h59z3z9lX72|~S8sMiVg$AtQ}wA6Ej`dp#jEY$Z3^&M%c=Lz*np&k|L zzZL2`(^AhD>QzELCe-_d`tG#UCkgc$p&l3NhlTpywA2fPdaY3J7V5{~QPS=K?D72m zwA71*`eLEpBh<$V^@C}tmkRY}p}tzEUnJBIrKMgb)T2V3b_$q1?KDT-eqLUupO@tx zMgFezSe*`k>9yZ^cCbtEFy{i?#7jIOdU5P^nF4-h^x~+e$RgSoXXPu!w*VZU_0Cww zXFKorrN}!!=Z;{$iq~+Qz1})hd7m2NQclj9K9}o;*LS7uynj#UJ=#cbSJX!%)+8*K z-A}gUgjC*hF)zWW`S%~ene{C-zk%T5I_3fF8sZYPkkf%&V{nRqEH#ihK>lJQ&g`5M zdHN`3!m6S@yX(w~AS~8=ge7YI!Lv`=AFqh1mck{Z2kgfKtQQ|K_<(jED!f zd!N>iF2cOaq^EvRsE^||$Q~9KAiHKyTPg0aL~ zJ3xQ1hdBlKha_&&K2v+A)+#vx)~Xa*B|@uKXvG3(%@A5uLTiT5S}e3y1<)!JS~WteRA|)+ zt#tvkDuq_9&?*yJO+sr^0IeFKwODA)6U(8>#-)ho2Rg;tZ$S|zlK18A)kT0KImS!k^mS~Onu>wDJ=t(8J6Dztiq zR!smc+u^E3wDZ;!(K6RIE2^z6So=V$2@(iL* z_fsR~se6R_fKdN?hSYZm_1!}KkWhaqL+aaw`Yxf~FVy#CNPU}7-zn4&3iVwXQr{}n z`-J)dq5fEg)VB!r9YTG-P~Vy%_02+kyHMXJ)bGoX`eLEpBh=Rm^)_c-D`|UQ9H6&Z zFVwdR^*us;O@O=yQC}z2w+Qv!LcJ$L>T8AiW}&`IsJ}l$>T87hCZWDls4vKndaqF5 zDAfCe`a3eDzFMen5b8UGdR~UqR|)m?LVdeXAD1EZl|p@;P~RrhU(HZ^?-A;2h5A;Z z{!)h2yM_81p^hn5a|AMNcZSqyPR|_M>`WZj6(2;OX>g|9h=1D1kb2rRLcLF@9}w!- zWk`LsP~R@p_X+i~45@bu_02+kmr#Gn8HW!k@-d;lQKrvZfl0r zHwyK=LjAB%zb`}T8-)5Ep*|qg*JVh3y-?pR)DH>u+cKoSPN?q^>NMj4xsbEMa%+av zdxiQAp}t?J*JMb2l~CU%)b|SYNf}aKDb%+L^*us;LWb0Pg!&etzFVjt32>JQ($~d> z`X-^iQ>gzUL+VXJeVtI>Ce(W~q+Tb~*9vutAqv{n;^L0Fy&quPSbL2Oyin+eSXraJ zMo7x~Um=wOsTD|*Kw<)+XAm=GdLA?pdNwza4FaKg8^y7Ayc9LTUn8ee_lr9|-M9@- zQMa%#Z^-6aBOdHac@U>kyirA-#($yEOd$N7bcHMc!u3ZX ztw88X_(B-IK z2xOOCf0WfUAeDI6jB3;|)~WR^;rh@%%?U5*h(z$aW^3OUN23B(>RYso+$gj@4P-MW z`Kbhz)*c`{B2vhof%ME)YxD}4ipOxC{Z>dB5dLnQugN& zaJUsHt35#CMw|}=sWUvB^X;4v&j=~2dLSF@8l{lsK=>PK3V9sJeuJ|Q$PpvuvGxHZ zPFY+6WCC7kSLZ??NTGQ^`V9}8f$+CKl-2`4cwDEDCxEDL4{_fA4rG;~e%W_W%0`@T z1+spYTm4=jbYV-0U0z#(@CaXNJqcv9{dfSs z_)u}K2eQWS`I|uaeo8en($Ue@9x5>E;nU!#Z_#qfCqJB6=ktM>t#Sqs{vw!CUks!h zZ~m&f8t#ZRE-NjxjvH{w>l5IpZz8kS_koNx%IklCsBg#;hrS9C4L63UXG8U{qk8Oj zQ5IT@0#*#96mC0Ol|T;a8cv)ZAoR+h!?_*Es#)$5+zUi~b%i}V{d;JqMpPF7359Z9 z=`;h$H*#?!5CAUD=YVW6(s>>T?e=l<^;aPM24@kb6M0op#rZlQ`wh;wfbbKd;`|H< zT~1Da4@7;Dhx2v*_tBFW>eGQ7GTLAT5Vii!R*Qg`DYpYLb8$0}Jfo$2ABftY!0G%H z$Ts6%@DdO{Wku!UUqIAXpU6tpgd0PL4WHln2zF5#J-`AW{YEYtfKfsU~wMNQaK-6iyDCHa+{~J;^mZAMeFF3hIDSsVErICvrK+w3YHF4$7 zQ$P+FTKzyKVNjbBvTD?lSXaC;6sj{K{~vG;pW)8?g^wwZkTtvinF?frPB|QJ?~38u z7v!vy(^=rC{Rx&3A5X(&Xq#7;U3z}aTh=Nm}N=%YRcg!fsgd~E>IJBxEcs*eN7 zGsZ2?0hwSR{{S*k=bfxx1;QgnmGXoi;#@53Bt-MEbD9ripV2OAfgCp4*An6w{(J=p zT~0K%1EKFpIVtY~!gIMw{eZA~Ss>?PY3Ya&v0@;-My&KZ z$ZjKF&k+azIpx(4q|%7tVIaICNTqz@agNVOJ7f#KoDf#ezW`8zNgc<}hc+4Nqy7gRqZO0^8E-`F3Lxq$id+*u1%&2lA!qyZRUiX8s(?e^ z1wxlIR)2!hF|>|<67|sVc^;6%267{iUZmr+xLzPTja+;VNC{e;JvtKCq4y#bXh1)Q)s}bs}sR7?{OCa*=f|?cL6bbiEDuDH9Y(f5cS<#j@YNj zO6NTsrtcoiuW1J2)Wa`;GsbwfdJqVWGm$uW;ZAIT7tbm3+4B)t9W?y;FA#J5{KlUk z8b;)+fy51~F910NWu=ZELSF&G`&U)lc?1YuPMQ7-2=4_|oRfcwK1%0{p5IYqA@yz` z#Rq2}b<&wC>Ww*$*g3E=dy*+YOszRUa*dw00SK=+EA?(5dyN|PF(7jdjSb+8 zGyK^MWRih=7sys4r_TUs(kbJI&|iV@djU%Q4ZlRsX4KvyAnOfeIgoXR)*2uM267jW zjfT|=KtOSo&H#`xMsG7}FMKwvE(gLp+?0n6KsIZwu>HxaQX@VeC5}-R+kuoiR!bvz z`Dt0G+pu~P9NtB#v|a+jDaPI}FZhoiauB%x6)3eEwoWzFR_cZ9YX`I`6~QXa)Mifk_i!n;{i zI^{s->fTu0%^O1fMot^SsnJ@L&iz2v8pta^c-Os3`S@QU7dr3w3a{1Itu{P74V;Na zO?W#HbEf^BK$;D$H9+Wc+WQ6|r3U8#!TB+e8QLGR|E1u(Xd|IeZm1=PMw3d3*nIsL z9P{b;;(Zu(>y)h#HRjdV7&*O>I7V4~0!Vz8yO-z#LXR9yzMcm%-iXhCDIKG9PJW)O z+)qFgfk4WY&P6~y$i?=BhH@%(gbU&m8xcL z2C~OU=Lxbh(s>n#`oegwZ8h@+jFAiv=L1=3SlteUE|(UNCPQo7ew2j~)wcoJZKSgR zNS%?+QXury;yk&;fzajDmQMm%sXe5&+=5=~fKglS0B69^GM{d&b7iqCv{$D?8c)D# zqH#~z3#7^@or6G1jFkTkWRJl){x^v}UjSqi6r7072C{XwyIouhWTKHy3t1Uj-vBa0 zkMPOo?*W-$aE|#cdI`P@=bQ$P@`l)aodwQXL%kjdT~3@=0NG`5J|Q^kfz%m3e;tUq zHt{%+u}0na6_65pjg=yT6;&W~Iiuw_{!aCf4ss!o?Z&g!EFkzsDF!$A?m0j+D!cl*_;w zt^J{%zqNf?WP{=J&EU{(1gE_21Y-L0O(5M`i+*<)i24>=u9Y{m{6D~FgEI-pfZ@+| zK+Kd^0C7e#^gG!DtRpL1oEcL2#V{HX%6)hOjwAlnV( z79eX4t9ytu${jJ&!*Ceq<3~E;`9_={h7~k@vMg`iy+t2V|x8hwL8!;_Mk9)N?fP6#h;eVa0f@PhwML}#6(D_v`h!3Y>Y9Ld+7zu?c3q88qqc)% z?n3!F5Z-yEO7L$$4(X^;I`vh{LW_-buK5$%yAi_{AWeopn}FmRQGE!=4BfL)41Wy7 zocaG1kV!h_SMaaNk!EZnsc((oED%~p3fFhkw=Ioy@;_VJmbCNF^$iUjk!Ad^XiJ+m zGEzXF>gG@%OG~V=j&@8p$K&;l&5@>%{b^x!aB>L0jD#DluL*-nvuza%Dr!m#i$dYD zXmoykOB=B2czs8_D`uf#iHG=;_cKH4(;9g<-gu)ce{i9EZg|eZne)rTv&!F7u>emy z;igDOWNAxhJkp_}5MI(ozT(q_crQmbY{wGwp52cUNOv zofMO2b?hi<>ud-7i>gmG9MC`UFBTx3so{kU;W)PTgqtJvP@G*p*jzgA^n4qOdavDYlOXJOyVv^Jn7?p*E%j%;oP4gr1 z=5|!`@FF0n3A~bPB~w{AWqBCQpz(VA2B)P|T^jAG52Jp^BQ46LXn8o+)!8h5y>K3) zGd&z`?CvfsEG%lM?`&zL28Ki`8fDz7>k-}Za+M}DG2PRos#K?2b76ISN^5 z2wm1HHmH>a;p#{fAMr**sHiRpmj|dYV3ik6VMoF(t+8lD_3UtEL!lAt*M+ND7~0uR zbqy6))pYHeE@^6h4b)} zT}uW#{1M5xTpH;b*V2sv_@$haqovLPsE%KXF?d@ieJQ!ZUCj{UHu`#UG>m;$9oTTx zQBl>H&gihb9J#HU(}GcGO+mOOTwNAMbFV41B5*Y2oe&f+X=!V!s7fbyH1tEBtTFAv zdB`BuP>gjmnIbz1|FY#y?dl-1$|YB*jzY`20=3~N-N(?YSn93-WJ|#$8^h}nP4-ml zl&)rBXswY+IoG*tDRB166|j+Rj8hvhb=P*(p2xNPQ4GNp?B+OX0kFk6`_=Kb2*z*m z!s*WAJdY~$#86td-)R^eR?o8Uy2CBP*@36Slap9Xm)I~0=xhvIi8Mv*dcHy!Wp;37W4T?8AyR2d@_oD)8u2 zUcL-t%o0ow7ZqTjzP!GpNsr30e6qBB!L;yux`5)AT2)iH~ z@E3KO55R-3Q_d{K$WI9s7FsU|gd5tsa1T3*Ps<*Ta0Rc9M{XE_TiS4oaCR1;ryl7+ zTFLd16<8&0<(uA7c0q@tIzAPP%+W~2<>{@pm6v0_iIyp>rHXP)4%n?WQE^<~% ztb2#PK{zXKY21s-t7(9R+e*@^j#U~vcSq9$S0J+GDX54R-6L4Es&B+1eoI>%uVS}g zYM5#jZsdg?8wJ8~SJkr?NvkgpS6q&@MGSJihnxsM5=&n8_kP~r z77gctW%!cUS#TuqbkQE`q*zg<3}fY}KH3?^?vaYLc0ZJtFQ_gE7fuUTB&1e@O1H3j zW@4=yad{2_rv1ZVnj#OkEJ<(P-L+I<=R)Rsp4yjzN2l4=k^@i9A0=(hJZ{6;(hbw* zEG+JHV!ssbFV0=0t-UE?ZPT!C?XMqyvoy%&bYwP#lRe|WVLFa>3RWykXS7&;1*{6E zbwsSqh8>Y5*jw4w7^y)2QygCri(rkS#Oj1bK*h;W;WVB!sqYNiBm1;+hoKe^;jKZH zwX{i1gfcy>8l0Id>N|!wzNOVF#P9#cx4cW(J^0Uba9q`=s6bD_^W!)6%U1a8$18X3 zKORa7E=T0ls>dyeHxj1PT&)MF)U&n2r^p#~Iyz(Lkk}y`pyyQcx|vOo-OQqXrLdSc ztK;RHmZfbNxRzt)yKp)lp(9H>upz~o->7ekS2S1?ELk>28NB~lSO|InQ@wJKEdv(q zRu+cLSZ~difF-QMqM3_P{*by@njO3p?G=x#v3Q5Gc$xSpky()}Ed9il0zK!OEj7Wz zK^;cSM`nwg9%};G=$Z~48dPDphE@yI3ksFj6_lsHY*6G{EXaJi>@=37?T3|$6jRaV zm^G${K##{c+LEiD=hVYb=92Sp(Rt=dcQqzePG%;_$w;ZD%rK_?Qxrmxuj@hW*@L35^`HarFalLuE2^Szdg+HzP}HSK=OyY`NVO(YOl7 zNa2-eI)lKygcy#swMWYsXgPw+B!_11a0WMpj@9m@xXZDN% z-HuWtPz`{#B2>^ag^s6na|q)F=t%Wky$eDA_GrJk>gwYMkqK9EU|EpQ0C1M9hx{OA zZ4vYgqCJl?;<7r+!?UzoOcjJ%qqFpy!3Ano&>3-5lCMqTZaCQ8f@&jG0dz*T*vsTow&@uy;7z(XzBTZY}ic zKGNwyvuqO8-`^|@GF}42aTiNoFERFYHw!~-?PG50XpdPn_jR&sA)wPb+*vfRrIAZ3 zZxNuifNb@RgXfytO6%sAV!j1)-JX+P!>7ZUf&%Y5pbZv-A2-m3~cF>D!)}4jW}gB9)&b(HM639?%{WZC1IHK?{`-CNsrUCLtjvM_|xFr`k5 z=~ZZgUJJijwrt_+t}DdqIP4_DjOxNL&Dr5E{HKl)z*ar{OCKj zh2hx`(b}pX?T1mom5pp^>qZxu_?m!on8@qK-7E~T^$23`8l?TR$=3X<-xE&qn2}|- z)eK}v7n3t#l;OQOjZy4QqY0`8`?QsjQPLU9qJia9+-;ih&54fo6|bvx`oMl?W6aC08(wzXYdYXB7fQIsh=F7T)PT9&=a~>2*c?ek%mLi=qNOv zR7+#JVECQk@VNHPEhJUley#dwEzqUf4wv*L-65sL&e2ZL%--ER&k`7Z6(d8&XX=K$ zn$#Gjb5qrcS5~}+DS6HUok^Vh8<5tql*u-aS|?NDqdYj0NgWfIv9#DZOvj0(<+KLx z_R6vtzb7s)XC`r%`?~!d?OmN|chiX@+W$XpPJ_!e7kFatn>bfFq~5_A$*0(BUY2Al zvvnUhN}h0F7P#Nj8~z<$Bd4Y_$O{K)9l}b}3a(e))c|K`DY+aQp;OZe3z{PKH!o=V zcxG6CNg1=I<_9q{Jq)m#hKK&h2cbkq;JT`L{17!l1(2Za$~?cUk>0i}>m5=)g%h{r zOr@qB9PZ|t@R&b>aypAn)Y2Ma*hQdEh~gp`Vqz}$Jf4Twx&ooAA4Ne zscO19c$fZ#Q=~Fq@rS{~%mz}G>M*#e&dbbL{T~JoIgt3?4`zt19o}glSZAFNH^n+q zI~<8dS|d1=wHCdqQ7fruwcngwXn*MYsA)Tycb!>>8{6PtsZH_lhFvV4FAAr54-TZ{ zWXvhmH189GFI4{i;?a?IvaZWCy_}~AG#*Mki*y);oNS>Jw-$4nBhgr-V+ikL;Eu5n z10CEn%)37|*~>9ciCYNWHfR_G%1EoG%y3$PPMzQBzWE(iQO<5=ht>3W)Qs16Ffy>` zof8Y2ZYgPZ_-68{vyfKw%FA66!!TGiQ+H<|ar!vD-rAa+c8NHJFl_0k%0yaakeCOj z7!vc4spKbjG}XuJ^TLa2@Pg>2k?zJwEZ)-I7IN@v14jo{To?{_#_QuPjW{2!CEkMf zOmD=$+S|f7GD__}>uR+AUBFW}C1K$4`j+UF0(@|(4X4TDn@c!jw6VFq1BXj>;sb4T z;C!U1;yOJf4sO$$hRq7g<~@~H%$iw=>~uARE5gyP`u13)E!-TB$2vokmo_$rRX}j+ zRYNoqnjC2kFX^anjUZfY%de|iW*|+`s%6z-1ELOQsy<4NI)_LHUd%J?yhzsjEAE%V z{nMon3Ux#}BlPB!+fl2Nqd14-9rZ2o&WgtJqG;UuGH;Pgwa{cvr*A~!BNccHq_MgP zQ;|L?Pm4y{md2Zjo=6?(Ph6_QMO`IkerIF)LVWTI8zm(zi}sQ@%MC5~nqdWo@YV|{ z+3Yh8ITZD8q>EnqV0-~&>cU7Yx*`zCE7BvKoBC=@9?ec@sva4#c=*to(L`N)u@ahg zil#c)M>6zQGo#V=MjVuj4$doPgH4fMz``a9>PN7Qk1vQDnHu@;<+gNVRClTA25yV! zQQJCkpnGeDdy5@1+Xf7uOVNjirulWpa%fh~X~9>>@$7()>6KX@(<@B$qnN(um)^(x zXvqu-<3Ktbc{-0?-${scwyeB+)vA$hiKqoMdzGyra_tE+ZWpqr%br`D)oEeVY(lLY z>5_H6ZsQ&>jC?=CAB}N&Q5|oK(6=In=Up|d!6e3hc!aDE)f%NdYTUaz}@l% z)57oRs_$q*ORmEEmPY1A*afeCc=#h=HZ<{6Fy=n5V>Il+bCMjNC&|EaUgdC zKw0o2dU~@qv?O2QoQ+AVqzUN{=bZ7Qc1I7LW481d zqa)n$yFnOHI|2oK}*NjcJwAhS% zY0)TyEb5NjRn7S{q2X=z^qp>J2lLUqgyG*ve>l&Gru&VQ%uNF5Z_K%~>P!P<_$(`$ zk)r)$?u;F+r*PcKQhf%_?P3=7@Buzx<}S(XX@dS=1y;L^->K5oo_<9)w8IhaNqI* z4+ZV1nAgux(D`IgcJ>~$W7qy{P`1{S!G7Z=I|H5K`!Q~ZosrG3oZjVpLncd0+w}<* zcUZD#m|)EU4)HT839&~{nCTCXBq(Id1815iFea{;dYwdt^6?O9NFGd(~%%0Y79OA9Z);X5UcyPpEOT7=9 zV{>h(UZ7+jI$w|MeRKC_+qm` zWXnAXci|B^!Z@Ln0u3U(8bD?b^mTjXnrj@|IlAsdN8tQhAvavd$GR$T=8k=JC5k5i z@o=BkO+p;~YJ@0@x`?#fUgE7H^$D%+>?hXp#9`#3w5rbQEu*~^WivHHu>0svy)b@3JE+aRwY3wqyNm@C@qQ{UJa>Fl%3QMYIE4uS5>oCE} z!YRvfNLO1VZl{AVR!&zxcT!9%3rm{1T3c6Cb+l7l=Hdu1oOFd>Oz%(!Bw?6oM3xUu z!ppJlqr(cPbab`FTUsOGNJmF|hx?a-{narGYGG|{wkk%zkf^=T@kn24v)*`x1TR*n+K zYbI8&pR!s6NWTx7tMO89)%B|f~ZSC=Jq%{^_5!Ut8I;N_j zO1nCo3Y-!5_&BM8@%W!nA zb0c=DM*8s%uH??xbmv}<8!qmZ9ippBUWwF;70cSMk66b}IQg;bITjA|NFkG{XDkDl zOPH>(WRY9rYS+SyEA3I1LBWwzMs4Z?vF}@UjZ)TYdD+ z5<0BA95voPoBRqK)Q8P~`U8GP(*X_x<;LU52M12!7x5J_WU_5ZJDp1&=3{z;^L<5< z#yNnXpRG$g{RW$|L&2`1lwDc+bvRWAnp9P1ILY&7ig61XA(wC3#w?GR;OJ-CB7i5w z_9Yebk{1*PL<{MtM2r#BuyO?Tj9Bu9n`&@^(=9ze9x&9@90$=wTYUt&8tc$S&*3cO zu+?%IeK!UNz0rgK+qB1#Q+ zk`({27SB-iT|w}^ttNeP^S>kem^!20>ZCoiYetD4U_76}U7YHqoN(AYL_g5Xp=-s- zoIkPVMiZvBy~0QHYwkpn+}jdqR^O{1vGioDkyOxGFL|y)U`uOy(CvPq*F2n?kjAW< z+dSnIibqD|44FH%p!p0kt(8`~t~n~Vy)0d8p2{fQl#vKBnUq>E_!FD|gp%8DcWBmw-KFPh%{~^(x3JP{=gG}XHp9AHc2DT+@|EDNUX5P{tQ-_rsObN(~=}b4`Qlh3nMpRjv=m7#n+pXCG15_ zk@S>E`x1Lmkva+UgHiS`UFLjlN^xhry#@JOP#rET!pIw655p68OWV?lMwtv=y1}XV zF;$S=wTCkc55fsDxYyeck|%C`oP<`A zQ#k3(DZz)yIwMzhM6F6S`15&m6JO-|cn|hIqn_4RL|Ym!Z$S;j%v{x+nsC)TOwLtR zVI+pRf1GhhpF^7(uDTA>{^jsITwTA++W6Ae&c0?oQ7+Dmrp)D^`9w43F20&t-?lV@ zZv|dYFZ<%J@+jJ0%89ulXJ^o&oZTVSC99D;Z}|PP4*MvDfDhxg2NV1~tl>OWhrWu1 z+>Vr#F5BTfE6Dnq2^Hc9$mlGg)emP$HPN@e?20+;I-Du07a6*7*tIM}sj-7}8@jXw zk5`fU)`qSn&Vf@Nk6JhY2#cQloHb}Omn1)<1%153Yc&;J?@OwY*6{&UzEo85Ujhq^N#i~DsjeW5S`X|&0dzH`7hTHDHBO) z*XVwoR)XeOG6TtImxlK_4-YA{Zym3fENlqlxhCQ|@l=h5hV$t!l{yC?*+XGDCKBPe z=RL!kMl7dq-dfe$`>8Tm0_=u0eDxIbdiHZaK6|^E)Jh8`%bb^`YYHN`ocao@p8oMT zvcTvKE{8*jLvp+0!DZ`wU<~W@9H1`Wd{hhEJvgRXIdRWT#5neOC* zsc?n{*I;P(Pd(nV*1Jpw)nE*3?EvBtxYA#WMP|JCNBV=G6*Y|A@`)#=80DFG5{k1| zXRu~&Nuvf-UWcCFuO%4g%jo4{vnr*PPztvK-yxjtgErPtYs^glVWsAF(2Ti%`?lWT zb-Z)d)$t(U{;Wn?DJ6F-p-)JtL;7}uGB@1_V3)WnGGUX~G-Cst57}$qnz=u(Fd_Lu z&kbp*ZFt|A$>QhpboZVmW-a;7Ft;xCR|zkOx_5^eiKf`~WX*j9C0pB$+~gtefDxOT zhAnlG(INXj_}x41@*CO)9Cu17cVN)Eo3#nY9a!qp2D>IB;+Mf~GDG#vSZ#2J28|@u z${FoWF|?^s4K^@p_eg^3(c8gslpW!zaF-h+w!y)ri5fnfQ#ER`z^#XxGn|6f6pFj5 zCYuOSdzuHgt<0SdG=RWkSn6A_rtfwOap&9N@GQ_9Vm{4VEsQ7RZio|_hJG5og;l=)+oaKrWpLHa9U(n=8~6z}t%WbQB#jQ!>If2+q>MDFOG+zI zXD!J{Z+LIFR9DGk-R-y*g4}K-y9)FfS6gf}2JoN^|nwB|5nINOKB4?POeY>FzX8zzOqofx8pelv6_I?NMv| zC!c~&gPS#G2-P#-B(ghN)bay2CUYv-oy_1;aZLxi^Zx&;yRzoCab=x9bW-t}Fz`KM;{S7UUQ=9i}7TX#1p3?yF**)6Lzk zO1z;asyVtmC-9|zp=9TF(@6(5$ceu!a)LW>NKC8a9%>eSK^)=lbLTbdl z!s72dL6+hKLGcyOe~iu&dB#TiXahz-$d{R~@(P4BMe=a7+5a#EW+4OxdFFLsG}_%@ zHgMG~Dp@m=T=3{_(SsWYr&UhZ9k9`}yvmnZj{LMXA+5RNs&7O*O^=S|jH8D`5GC(s zu=qaN)^H-}rN_Kl=g?qKlI01kkxS|Ij5_XAwlNs5Qwd}uj|WrxE$s6Q-e{>72Sdub6q@?6s7fzs;Ap8o$XA zXLx!CUWWwsnUWYacRD{f(N&UFm9O&Uw7u%vDZRnc)|nuS(89j+U=ht(m*%3FS(n(FLf(i zqX3?v%>@W2X;r0e0a) z+z`gvPcU&y`f!}hyPV$STd+MzNJhoMGbYEg!fzI}86 z(`K`AT_YGyoVNnej z?=eX{x{vl!+d-o}v=Z*Y5b>aUSKQu(U;#mEE)fm;NHUh+g9`Kze7O47A*`Ix)~Qko zoH!6n#EKG)_2UvTe$eok*uN#QErqsua|2KK0jt*iwZ*avkKsvX*hYCXnIU0dYXbn$ z?nR3C6;#$KPl|%i0<6laZm{^H;-AQ{K$ph$S|y}99)WuY=7#rVS#wJS05G_^49FS6gtX;2<9HmEeI!{^XtvcydIyyHiMLs zmlNEM(3ZHivSwrKsj*M@)px=4qhsyYRTH$cu4%~`H=C|oKosAbjm{uQwXUOI7HNEV z+TPeNi!_GL-9EBc7HNF=zP+(u7HNEZ)ZW-Hi!?s!*df0x(im|L?Q{0ZnvG$1j-sIW z-fVPsu5TU_k=rt&n#WY=!fp+v`^zAhH_a?2TP!6C1 zUcywTw7}ub2ZLaQ#hqc_qF6*H&RS`|NlN2UxTYsqQ@jR>mv-r9Csy>rBu?*B(<~K< z)^P>ytucR-z{^j)OS{8PZMF|~#0Zkk=Xe-$4Ue*RD7OL^slR;?3SOdAYgem8k5r0e zBJmluw6TLVl|cw>Kz1mUoXZynwZL1f2n)bNwQ$s^bQ~j{{ZnLe-mfn^H(-cVtai5J ze;OYIU9f%!VuTPV?471cbWEOo96707bv#P^c!=i^J&5<~M1mvd-dh27!OVoI!3qxO zMFOF(6qts%P3Clw{Evd;2vvAh2$KY`Cn>6)x=*J(4VnvF)W9Lk5QK zpS&=$4<5*V?3{-J)s*B1VYujKZ;-H6BqVK5apg7%vkx~M^lAhgu@wHjlZ&n=?K?3 zz$#&TweHcW6_1xmI)?a@QJ!A7wJ5t%I;OPvYPE+nG{eTkk3(QecAIBEDeiOh1MIy` zP>IyE9b=8-;uFb2R;n}Ji+*)Q=fR>w!kQpJ%gTyieE82O5E1pGy}lWQ4BnrWO9-n! zy5q%HD;_H_&4fG?6Mmw?64V`+xX8&?ySKMM{63(UV+v|9NV`XS3&hZ42Bo4+$m%U3 zm_7_J!3~)01oNr#CqCCmjftt-M9(!G({=CO(sPZ}m{{)^0uBW^*d=XSOLDV5QyX|c z%85=f3T9ac$bo&Qq(?=wX3QbuWVc0YCGm^+;ZBXra9~=BkH(l5u`J86G^grY+YLZ( zhDGn7gr7|ltyC=Yd&6ZYHW2d9G`Czw*b)HI)~cp!UM9?Ms%Uf`BEJz-?eII!84|ef#g2ME@P>cfoJpJ?S@! zn2`6bX+|b5BaQ+8S_(~b9D^>YRz<;$;I-2dvlEq>>JZsEB0-r2*Qe@B07vRWNH*SC z@&b|BMBDbLXu4IW5|lKrRCqB?x{x{PIK>J@b41h|5jaVcgK?Ho*v9*OnO-9}qnM5V zx2~`lsD{LQ*Twq2fTdWspenG;-HlEVyR?D1m26$d{8%O|mFhoMJD^M|Voo>2e$8-Z zibNcPu)f~1fq#paxZaa>)&X9xs6zpoBkI9C2Xxc{)__&pnhelUKP+r$NMIAh$W7Es z28jA^5=7l0`fii0#~Fy{9jJvDMbuHj%o8@~Suvj{OCkY6SEe^56~=ayn@$KT{Fu#v z4hJ`8aY{6e*|}N!klXne$C3RtIa4qQrM2JW$Dmm>xz&7IT%(j`{hs^)7FqMFMKQi)PVs z?=mzQG8z|rf}2h)8i>_PNb^^&RnavaS6f5g$zi`_FhZb5sQ}cVGo_%Ym!o!e9GU38 zVBDR9^IH1pzNX<%BwE+p!wBHp@BV;4?qL2L+pw^+UQ96B(IBeWqo)`_Y&L7Ucunwk zuoD4>iWqKxm4kXJTHCJ@KNjvQ9jE9Ch#sfr)ysy*H+D7yI898oH|yr&xY%epB{EX% z>Y7vW(Q-I+^2AZjvUipqRQ$AlwbwB{j2xAUV(T`{I}s%tLzXR;g6^ax!q=O=t%QXD z$B$d3j8_U`UgMR5*w%QZBQIF2 z1#mx(HC{=^rM3*!V`eheG~SCBGa3iwEC?QrcLd2=#+1b?^#J)Si29Tr4InPk(JQ-h zxE91`#w!JJm@Sq3pvicp9(808WxNwVS~6besLzH3(U0+-z>l_XZ4k}a(vug_*oJO? zbfV~K=O{lBp(qF2xt|#M57;K8=Vqv+cVi#qHf$3M1(blcO3oNf-*G1q!3FvCYa9#0 z6U*E_YKwcq8?`AaKthZL)@^C#;^8E0&F)Ruo2&(u>t?wj-nM7Bn(P$hXD`j8Psp0L zCIjf5A5IqbCc*FRq;+8#VRySqdSNV=>~EhyEZGnH$&UL(Q+cg|z3sg?UT{+fvh?n- zjbRN15PVriC&@`aeF%_T0Fr5+65pB!-;2-@LwCCp+M;yi%JdAl@tR<|QLT)rpYu9w zV+kE0FWwZR(Ji8ev|>TZ55s%ABV4?R?GvTqbu<(qpsRDFiR|nbMT$g+eBKz2=#agA z0Ry8ej(1o5ZY=5{mPqnCp zJ$f2%wcJ12cpz_xWPz7iwosc8^$`nTQR~+^ZpFAXpTMcvoAd}zSCE1^(rYg(vFH&# zSGkIj9tXhL$nJ~Tclj{ILUsBvLr8tYc5oB|KO6ZfyW4L+vk}K*cbDBDDc7Gjc`VaD zzB{k44hNlA@7dgFlTWuPaI0v4lVu-Y|-=RQSROdUGhyW;N$ zM}Hx~^tXJiaz<0+NkJ)J0TJfp7eaYKj=q|c+C~#MBSi`FCuf{JSp}@`+=IJX38~{( zKVWq{D{x`+a`N6@3;YKmuxNvYc+OXy_~|f0z+W+rnH0U-1|RyfPE22J{G~&^Un4G} z#&w>>c$L%6O$Z0sZCc^c`LtNqh?P)b zwe4{7EmCxZNKT64#%m=e74H-F_jEx10T>xj6``^(jIO(<1@Q@&kw8@484&4|+XrR- z;diVIxqWNN?F)p=EF4Y;lt;wJC0V(|ZTLZJhhWkRTv|9y4&HEJk%}pz5ARiM&f_W{ z;e=1lfT&#WSlgCL97`(H!BsB;6tgrh38(1!+3WnKSei>zF9+QvXfJW;$P+*bD^%R{ z3!)Pau$Q=OQ02cS^YWfT#>)*Q{J_#393_|6V5E7@k9Lhghg%=>xJSKxJ09+1@8XF~~%+o+I2E7DoCzUu@{--D~yvhVnM~-~V%daC~b_ z7N1hwDJN2M^;h$=v>}Bi5Min5GIVUM){M01WvP&$5taNWwQ@N}fb#5`xt#m2Qf2)y z_tlexZuqnv3k6K<%4EGSz(Q*h{k|mjEHo#7NneJJB4K(-%jQYoFLY~#u=_$Gd?MLU z&hEcT-g=pU_Yq+vHE@Eq**zC-KC^RjT zn|XPSBzIFJxT{GDa-ZmNB772weYpH_X{D(T2Z!`&J+JZ`>Ohv$Z(WXOjLHgm9jl6} ztZ(zA&NK9kSOq+#Le3@rQT?Rv^fRHi=;&haD+C_Y=qOJX<+PX;`P5WlSoz7iWPw-C zs>fFZ`Kr!0_#fZy1u(0;IC^)QRGa0xSlAoG1jK!+ZJ7 zcHm#U1OKAcBEXXG7bA@T;qQ-+-_ixuQj44bt#!>WWpy^4 z0xiUHxzbNCCeU2H&PNY90fAZ%z|@qXV^qp;F_ zhOb^VfRf;0AQ)if0Qf3@KJafMAiPvJ$$VOF_*grbvOBLy9{ipKzw-q;tI}!lkgRAu zFg&ug}KeE~00P&HUm>-MHd`(nV&$~FhHh)ry`FmB~pUB^HZ&ul2Wh#P~%*@}{ zhql|P>lVi_v(;y-Y@XJ2F$0&OQ*VCF>1R;`oA|FZ1C1!k>tqHFOhxzjP%f^M3=4Cg z)%*je$k0o0H_%`A3w-Ma6caX4O?)W<&pgQ=C@nIPeOK4j1pQToOlTdmPD(5*nrJ@i z`qtkGM&h-A69Z%$>`2feSzH6+`;5WIQ9}R+pjliaXkwke2It40Tme&R6d$}wYFigf z7G#oVlfx4<%~xOp$*tyY3d?Vh)n`%P(Gnu`WJsuu?DG_qEfd>nAsPA|( znlCA)*TvldwWtf6Kwv1lyOgrI)nDFIvclx@&u>>_%;jP-`t$Q2$>r$$k59?@ zcydKEn;Kc!!Vd zp?j~$Kv5z<2B$8Fm>HSpz=rQUd8o2-^@wcy1Pzb7`*cE_Cwh#SV?~dPC5QPXX>|i! z2KivMo)sfUuOL~j3p}~4`2k#?B{5b+^eUE!L@(#K{`~RN(euDv3Z^AANJxZ^S8LiI>0iHrrr7p=B2sU9+bA)TK&n{=#K zNDQl*70z0%yFo?vNgf;-^`GqzI&yTm*om06agcU*D6d9(4Xtq?E^Y%fMkl~Nkw=QO zw={#e23fMmYUZP}4MK`{pxzu+)uUIT4`8Hu84 zuUq&kZjD?{xC^pw?}}$81&1Y99`mN>H@kVdO5{ ztT)&7BgFAVa+g;%nWb!P#wXFo|6r5hE{rplMyb}sv99hATq$-Mza;Ihgt!1qLtC;2pAFr;;uh7j3qFc;w zpN^C%w!>sztz*$x$8=HOK(Qf@FHLl{sc+|4Fl^APBrdg@o*>RDOmAP!2oJNHtEizF zGs|G(1;ZvHa5Xu2A9+(AMaXG*1F_mD=gcxKb{$IWYR8OILf3UQB2N5Sy+->LMlvW` zQW6w;55~PEiz19#NYR0R@9V<^f06BA2%+Z7{v>tr+dZ=ll7H<$a2Ruxu(0dQPguVo zVGqg)j0D)^S;>=b$aep^8n^8MZOi3#7i;Uss=P{W;j*A(b(4`TNG%i6y+&nl%=w%IOYI^_qT&f5 zS47LduC>_XxX4Tyeu)T?-dys;+Vy{J-LNbYWML(FKEqC(fyu)3V=PJ}9Yd-R_+C}% zBVYVewhM>)thiJ;S9Oa)P7Dq^g!G<)wKMb%TSr<$26iY5= z8(ej49F%Ql5iIqx#E>4T+liAa3C*aMmpE)+in*q?ikVC)G}LVi@Q-|W+I>NieB+DN z^rDFJIzTEl%BsQqygBvcA9O2O?eFN)X>+_hfe1|*WLWpHc%clqmfK&IMg;h9XtfLI zg=D!=CL3k)gM~p$AcR~u22*Xf#I%!Q)}XzX>rH2LlIkv zQ}nl$b;mYE|HGS(JB#aI+2g zNn^8GkeYF>VR>a81}=FremgQZXu)h|Bh4z;f%K>@~RS3WJq)B}6J z9m;ZOAQ}tEtzMWtfulp%&Xtv_y!)(i;goe-G6#eEvpJOZdyrP)WNYJzH?#|3Ack}) zg5-F&vx)JryH7!Jm>(Yb9tOWOdNpyqO_o-)*UF(-NBA#P^a^~gzJ(9SzsB-vYJ(7! zIRz8%L8GN2r`#ciC74bpM#S2?3VbEFPLc`HIl1I*$fkO zw`8_E9GwjYynj=X5eCbv1E6%M7rS81*!6mvfrFirmJE=1c5H0`ErQi6n4uAGd=&*6 z76!t4B@6u=F&Tc_EtSIVtGzT(J>VKZ=#A!4#Ltz- zCW!wq2aq+ezb0oB72+`50cCQBGx@yON}cga0;Eb2PO~RRvmQ!V8H}btbA*g!xb~0{ z+9iE(iE%)&_{?ChJu9W!2ngocisFlg01;Q-V>*K)W^C>nG8ntLS*&F7L>Vh#`GCDs zC@g9qqR0{11f)DPmkpXXKv8~Qc6!yy`zvmS?rMcRRfa2`lA>=WevMduOq>|FVJZb> zQLjK^4H0;LzmK{41`JFH1yv9&PZS>JJ49qOeYS?>C|+Utlc67Y7#+fqMqy?_v?AEw z7FUPq4pvcV+%sJmq9gn!n$Pq%HV(mQr7Ciu3y;?-NzgInlcT|EC%vssBJJ5#PR783 zqI;drFYX+@@+PzskI_SMuSN=><0xe#^PL5!&v4+J-68suqVJXCh(_-h$8}Nzu~Zlr zj|eVBHW0J7%7Y&m(AmyH+PM|t6fX4$X8~ZvDJTx2Tt|gP!V$u|9#?DW`!YyXAUFml zc0y3k1-;XfTDDCxFr;%cJ5phOAsgq=K1BS%{ca!#$h~rJSSe2ms#drhj>HWDHoU8t zwyznpa$Tsdfk|{3Lj7QgmvkdzH1mT1hXd2jQAm5ReB0^?#J0+LO~#fHg$>3?C_@9n z0ZGFJ7m8!ZlaWdiVJKvWoxOD)R`;~~AJC&2?!{5T`baX=q9Sk`+^MOyA?;Tq9>G&% zO&kfx{tB+OAn2k)aZ$S6T9AcAUfpo98BiGe#1lehX6yepYNs)0nev7l}y&1{}l#3hox0ukZ-4gIFaCgXU9b0R)nW>dUv$$`&ES2W%>P z->^xL4y!GymRK88n?7WKi6szcf@~$OZC4m*zXM;K6p84pnuQ&tfAGsiEHx(6y0jM; zEVd1>jYt)wEnHv_tekW`OIK-DtRFd6TuGn>-O2OZcvv;x!i+FhiX=&9^Yli=6Y`#c z22ute&8^}=tjWy-Zfe0tSmN>s22So^KZQ^tEm&3@G0H(`m%<2EjxkY6wh@t@_p2h$ za()&TA$-6syvK<~&z}wtf*&v@*f7yRZX*w+_9`|mT`+Stp$na6O-WqduS;?o zAlz(JaDGpEQykG7BSb+GX;SV}$Hk-cYThnvcGp9O%uzE_hj9>u z*!ONw&d3ltm`dIz7<4j)ZJlrx__2VgdQx z!H$E@T7wJHYO44pa1P3KEpE(E8O3UVoNB`XFP2wv4Ku)|&dClyI@^<&HLW$u@*5kI z;BM{&!C)rjDvY`g{Py*xw0?V|V`<@!;O{WYo0Ag;$>8*91=!;}q%HbaFAT1A>&Zmu oevK%d{AZfd&8b0n6vnH}*dxzKFp2o0={5V%Er<8GnzGUV13hkh^Z)<= diff --git a/lualib/ltn12.lua b/lualib/ltn12.lua deleted file mode 100644 index 7822e53..0000000 --- a/lualib/ltn12.lua +++ /dev/null @@ -1,292 +0,0 @@ ------------------------------------------------------------------------------ --- LTN12 - Filters, sources, sinks and pumps. --- LuaSocket toolkit. --- Author: Diego Nehab --- RCS ID: $Id: ltn12.lua,v 1.31 2006/04/03 04:45:42 diego Exp $ ------------------------------------------------------------------------------ - ------------------------------------------------------------------------------ --- Declare module ------------------------------------------------------------------------------ -local string = require("string") -local table = require("table") -local base = _G -module("ltn12") - -filter = {} -source = {} -sink = {} -pump = {} - --- 2048 seems to be better in windows... -BLOCKSIZE = 2048 -_VERSION = "LTN12 1.0.1" - ------------------------------------------------------------------------------ --- Filter stuff ------------------------------------------------------------------------------ --- returns a high level filter that cycles a low-level filter -function filter.cycle(low, ctx, extra) - base.assert(low) - return function(chunk) - local ret - ret, ctx = low(ctx, chunk, extra) - return ret - end -end - --- chains a bunch of filters together --- (thanks to Wim Couwenberg) -function filter.chain(...) - local n = #arg - local top, index = 1, 1 - local retry = "" - return function(chunk) - retry = chunk and retry - while true do - if index == top then - chunk = arg[index](chunk) - if chunk == "" or top == n then return chunk - elseif chunk then index = index + 1 - else - top = top+1 - index = top - end - else - chunk = arg[index](chunk or "") - if chunk == "" then - index = index - 1 - chunk = retry - elseif chunk then - if index == n then return chunk - else index = index + 1 end - else base.error("filter returned inappropriate nil") end - end - end - end -end - ------------------------------------------------------------------------------ --- Source stuff ------------------------------------------------------------------------------ --- create an empty source -local function empty() - return nil -end - -function source.empty() - return empty -end - --- returns a source that just outputs an error -function source.error(err) - return function() - return nil, err - end -end - --- creates a file source -function source.file(handle, io_err) - if handle then - return function() - local chunk = handle:read(BLOCKSIZE) - if not chunk then handle:close() end - return chunk - end - else return source.error(io_err or "unable to open file") end -end - --- turns a fancy source into a simple source -function source.simplify(src) - base.assert(src) - return function() - local chunk, err_or_new = src() - src = err_or_new or src - if not chunk then return nil, err_or_new - else return chunk end - end -end - --- creates string source -function source.string(s) - if s then - local i = 1 - return function() - local chunk = string.sub(s, i, i+BLOCKSIZE-1) - i = i + BLOCKSIZE - if chunk ~= "" then return chunk - else return nil end - end - else return source.empty() end -end - --- creates rewindable source -function source.rewind(src) - base.assert(src) - local t = {} - return function(chunk) - if not chunk then - chunk = table.remove(t) - if not chunk then return src() - else return chunk end - else - table.insert(t, chunk) - end - end -end - -function source.chain(src, f) - base.assert(src and f) - local last_in, last_out = "", "" - local state = "feeding" - local err - return function() - if not last_out then - base.error('source is empty!', 2) - end - while true do - if state == "feeding" then - last_in, err = src() - if err then return nil, err end - last_out = f(last_in) - if not last_out then - if last_in then - base.error('filter returned inappropriate nil') - else - return nil - end - elseif last_out ~= "" then - state = "eating" - if last_in then last_in = "" end - return last_out - end - else - last_out = f(last_in) - if last_out == "" then - if last_in == "" then - state = "feeding" - else - base.error('filter returned ""') - end - elseif not last_out then - if last_in then - base.error('filter returned inappropriate nil') - else - return nil - end - else - return last_out - end - end - end - end -end - --- creates a source that produces contents of several sources, one after the --- other, as if they were concatenated --- (thanks to Wim Couwenberg) -function source.cat(...) - local src = table.remove(arg, 1) - return function() - while src do - local chunk, err = src() - if chunk then return chunk end - if err then return nil, err end - src = table.remove(arg, 1) - end - end -end - ------------------------------------------------------------------------------ --- Sink stuff ------------------------------------------------------------------------------ --- creates a sink that stores into a table -function sink.table(t) - t = t or {} - local f = function(chunk, err) - if chunk then table.insert(t, chunk) end - return 1 - end - return f, t -end - --- turns a fancy sink into a simple sink -function sink.simplify(snk) - base.assert(snk) - return function(chunk, err) - local ret, err_or_new = snk(chunk, err) - if not ret then return nil, err_or_new end - snk = err_or_new or snk - return 1 - end -end - --- creates a file sink -function sink.file(handle, io_err) - if handle then - return function(chunk, err) - if not chunk then - handle:close() - return 1 - else return handle:write(chunk) end - end - else return sink.error(io_err or "unable to open file") end -end - --- creates a sink that discards data -local function null() - return 1 -end - -function sink.null() - return null -end - --- creates a sink that just returns an error -function sink.error(err) - return function() - return nil, err - end -end - --- chains a sink with a filter -function sink.chain(f, snk) - base.assert(f and snk) - return function(chunk, err) - if chunk ~= "" then - local filtered = f(chunk) - local done = chunk and "" - while true do - local ret, snkerr = snk(filtered, err) - if not ret then return nil, snkerr end - if filtered == done then return 1 end - filtered = f(done) - end - else return 1 end - end -end - ------------------------------------------------------------------------------ --- Pump stuff ------------------------------------------------------------------------------ --- pumps one chunk from the source to the sink -function pump.step(src, snk) - local chunk, src_err = src() - local ret, snk_err = snk(chunk, src_err) - if chunk and ret then return 1 - else return nil, src_err or snk_err end -end - --- pumps all data from a source to a sink, using a step function -function pump.all(src, snk, step) - base.assert(src and snk) - step = step or pump.step - while true do - local ret, err = step(src, snk) - if not ret then - if err then return nil, err - else return 1 end - end - end -end - diff --git a/lualib/mime.lua b/lualib/mime.lua deleted file mode 100644 index 7fdd9ed..0000000 --- a/lualib/mime.lua +++ /dev/null @@ -1,87 +0,0 @@ ------------------------------------------------------------------------------ --- MIME support for the Lua language. --- Author: Diego Nehab --- Conforming to RFCs 2045-2049 --- RCS ID: $Id: mime.lua,v 1.29 2007/06/11 23:44:54 diego Exp $ ------------------------------------------------------------------------------ - ------------------------------------------------------------------------------ --- Declare module and import dependencies ------------------------------------------------------------------------------ -local base = _G -local ltn12 = require("ltn12") -local mime = require("mime.core") ---local io = require("io") -local string = require("string") -module("mime") - --- encode, decode and wrap algorithm tables -encodet = {} -decodet = {} -wrapt = {} - --- creates a function that chooses a filter by name from a given table -local function choose(table) - return function(name, opt1, opt2) - if base.type(name) ~= "string" then - name, opt1, opt2 = "default", name, opt1 - end - local f = table[name or "nil"] - if not f then - base.error("unknown key (" .. base.tostring(name) .. ")", 3) - else return f(opt1, opt2) end - end -end - --- define the encoding filters -encodet['base64'] = function() - return ltn12.filter.cycle(b64, "") -end - -encodet['quoted-printable'] = function(mode) - return ltn12.filter.cycle(qp, "", - (mode == "binary") and "=0D=0A" or "\r\n") -end - --- define the decoding filters -decodet['base64'] = function() - return ltn12.filter.cycle(unb64, "") -end - -decodet['quoted-printable'] = function() - return ltn12.filter.cycle(unqp, "") -end - -local function format(chunk) - if chunk then - if chunk == "" then return "''" - else return string.len(chunk) end - else return "nil" end -end - --- define the line-wrap filters -wrapt['text'] = function(length) - length = length or 76 - return ltn12.filter.cycle(wrp, length, length) -end -wrapt['base64'] = wrapt['text'] -wrapt['default'] = wrapt['text'] - -wrapt['quoted-printable'] = function() - return ltn12.filter.cycle(qpwrp, 76, 76) -end - --- function that choose the encoding, decoding or wrap algorithm -encode = choose(encodet) -decode = choose(decodet) -wrap = choose(wrapt) - --- define the end-of-line normalization filter -function normalize(marker) - return ltn12.filter.cycle(eol, 0, marker) -end - --- high level stuffing filter -function stuff() - return ltn12.filter.cycle(dot, 2) -end diff --git a/lualib/mime/core.dll b/lualib/mime/core.dll deleted file mode 100644 index 8de58050f0dbfd70eb4320ec5afb96ae73baea3a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24576 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 diff --git a/lualib/socket.lua b/lualib/socket.lua deleted file mode 100644 index 211adcd..0000000 --- a/lualib/socket.lua +++ /dev/null @@ -1,133 +0,0 @@ ------------------------------------------------------------------------------ --- LuaSocket helper module --- Author: Diego Nehab --- RCS ID: $Id: socket.lua,v 1.22 2005/11/22 08:33:29 diego Exp $ ------------------------------------------------------------------------------ - ------------------------------------------------------------------------------ --- Declare module and import dependencies ------------------------------------------------------------------------------ -local base = _G -local string = require("string") -local math = require("math") -local socket = require("socket.core") -module("socket") - ------------------------------------------------------------------------------ --- Exported auxiliar functions ------------------------------------------------------------------------------ -function connect(address, port, laddress, lport) - local sock, err = socket.tcp() - if not sock then return nil, err end - if laddress then - local res, err = sock:bind(laddress, lport, -1) - if not res then return nil, err end - end - local res, err = sock:connect(address, port) - if not res then return nil, err end - return sock -end - -function bind(host, port, backlog) - local sock, err = socket.tcp() - if not sock then return nil, err end - sock:setoption("reuseaddr", true) - local res, err = sock:bind(host, port) - if not res then return nil, err end - res, err = sock:listen(backlog) - if not res then return nil, err end - return sock -end - -try = newtry() - -function choose(table) - return function(name, opt1, opt2) - if base.type(name) ~= "string" then - name, opt1, opt2 = "default", name, opt1 - end - local f = table[name or "nil"] - if not f then base.error("unknown key (".. base.tostring(name) ..")", 3) - else return f(opt1, opt2) end - end -end - ------------------------------------------------------------------------------ --- Socket sources and sinks, conforming to LTN12 ------------------------------------------------------------------------------ --- create namespaces inside LuaSocket namespace -sourcet = {} -sinkt = {} - -BLOCKSIZE = 2048 - -sinkt["close-when-done"] = function(sock) - return base.setmetatable({ - getfd = function() return sock:getfd() end, - dirty = function() return sock:dirty() end - }, { - __call = function(self, chunk, err) - if not chunk then - sock:close() - return 1 - else return sock:send(chunk) end - end - }) -end - -sinkt["keep-open"] = function(sock) - return base.setmetatable({ - getfd = function() return sock:getfd() end, - dirty = function() return sock:dirty() end - }, { - __call = function(self, chunk, err) - if chunk then return sock:send(chunk) - else return 1 end - end - }) -end - -sinkt["default"] = sinkt["keep-open"] - -sink = choose(sinkt) - -sourcet["by-length"] = function(sock, length) - return base.setmetatable({ - getfd = function() return sock:getfd() end, - dirty = function() return sock:dirty() end - }, { - __call = function() - if length <= 0 then return nil end - local size = math.min(socket.BLOCKSIZE, length) - local chunk, err = sock:receive(size) - if err then return nil, err end - length = length - string.len(chunk) - return chunk - end - }) -end - -sourcet["until-closed"] = function(sock) - local done - return base.setmetatable({ - getfd = function() return sock:getfd() end, - dirty = function() return sock:dirty() end - }, { - __call = function() - if done then return nil end - local chunk, err, partial = sock:receive(socket.BLOCKSIZE) - if not err then return chunk - elseif err == "closed" then - sock:close() - done = 1 - return partial - else return nil, err end - end - }) -end - - -sourcet["default"] = sourcet["until-closed"] - -source = choose(sourcet) - diff --git a/lualib/socket/core.dll b/lualib/socket/core.dll deleted file mode 100644 index 9cb49ee8acfee3e3b0b501a894f3f5ec6ff6e512..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32768 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 diff --git a/lualib/socket/ftp.lua b/lualib/socket/ftp.lua deleted file mode 100644 index 598f65d..0000000 --- a/lualib/socket/ftp.lua +++ /dev/null @@ -1,281 +0,0 @@ ------------------------------------------------------------------------------ --- FTP support for the Lua language --- LuaSocket toolkit. --- Author: Diego Nehab --- RCS ID: $Id: ftp.lua,v 1.45 2007/07/11 19:25:47 diego Exp $ ------------------------------------------------------------------------------ - ------------------------------------------------------------------------------ --- Declare module and import dependencies ------------------------------------------------------------------------------ -local base = _G -local table = require("table") -local string = require("string") -local math = require("math") -local socket = require("socket") -local url = require("socket.url") -local tp = require("socket.tp") -local ltn12 = require("ltn12") -module("socket.ftp") - ------------------------------------------------------------------------------ --- Program constants ------------------------------------------------------------------------------ --- timeout in seconds before the program gives up on a connection -TIMEOUT = 60 --- default port for ftp service -PORT = 21 --- this is the default anonymous password. used when no password is --- provided in url. should be changed to your e-mail. -USER = "ftp" -PASSWORD = "anonymous@anonymous.org" - ------------------------------------------------------------------------------ --- Low level FTP API ------------------------------------------------------------------------------ -local metat = { __index = {} } - -function open(server, port, create) - local tp = socket.try(tp.connect(server, port or PORT, TIMEOUT, create)) - local f = base.setmetatable({ tp = tp }, metat) - -- make sure everything gets closed in an exception - f.try = socket.newtry(function() f:close() end) - return f -end - -function metat.__index:portconnect() - self.try(self.server:settimeout(TIMEOUT)) - self.data = self.try(self.server:accept()) - self.try(self.data:settimeout(TIMEOUT)) -end - -function metat.__index:pasvconnect() - self.data = self.try(socket.tcp()) - self.try(self.data:settimeout(TIMEOUT)) - self.try(self.data:connect(self.pasvt.ip, self.pasvt.port)) -end - -function metat.__index:login(user, password) - self.try(self.tp:command("user", user or USER)) - local code, reply = self.try(self.tp:check{"2..", 331}) - if code == 331 then - self.try(self.tp:command("pass", password or PASSWORD)) - self.try(self.tp:check("2..")) - end - return 1 -end - -function metat.__index:pasv() - self.try(self.tp:command("pasv")) - local code, reply = self.try(self.tp:check("2..")) - local pattern = "(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)" - local a, b, c, d, p1, p2 = socket.skip(2, string.find(reply, pattern)) - self.try(a and b and c and d and p1 and p2, reply) - self.pasvt = { - ip = string.format("%d.%d.%d.%d", a, b, c, d), - port = p1*256 + p2 - } - if self.server then - self.server:close() - self.server = nil - end - return self.pasvt.ip, self.pasvt.port -end - -function metat.__index:port(ip, port) - self.pasvt = nil - if not ip then - ip, port = self.try(self.tp:getcontrol():getsockname()) - self.server = self.try(socket.bind(ip, 0)) - ip, port = self.try(self.server:getsockname()) - self.try(self.server:settimeout(TIMEOUT)) - end - local pl = math.mod(port, 256) - local ph = (port - pl)/256 - local arg = string.gsub(string.format("%s,%d,%d", ip, ph, pl), "%.", ",") - self.try(self.tp:command("port", arg)) - self.try(self.tp:check("2..")) - return 1 -end - -function metat.__index:send(sendt) - self.try(self.pasvt or self.server, "need port or pasv first") - -- if there is a pasvt table, we already sent a PASV command - -- we just get the data connection into self.data - if self.pasvt then self:pasvconnect() end - -- get the transfer argument and command - local argument = sendt.argument or - url.unescape(string.gsub(sendt.path or "", "^[/\\]", "")) - if argument == "" then argument = nil end - local command = sendt.command or "stor" - -- send the transfer command and check the reply - self.try(self.tp:command(command, argument)) - local code, reply = self.try(self.tp:check{"2..", "1.."}) - -- if there is not a a pasvt table, then there is a server - -- and we already sent a PORT command - if not self.pasvt then self:portconnect() end - -- get the sink, source and step for the transfer - local step = sendt.step or ltn12.pump.step - local readt = {self.tp.c} - local checkstep = function(src, snk) - -- check status in control connection while downloading - local readyt = socket.select(readt, nil, 0) - if readyt[tp] then code = self.try(self.tp:check("2..")) end - return step(src, snk) - end - local sink = socket.sink("close-when-done", self.data) - -- transfer all data and check error - self.try(ltn12.pump.all(sendt.source, sink, checkstep)) - if string.find(code, "1..") then self.try(self.tp:check("2..")) end - -- done with data connection - self.data:close() - -- find out how many bytes were sent - local sent = socket.skip(1, self.data:getstats()) - self.data = nil - return sent -end - -function metat.__index:receive(recvt) - self.try(self.pasvt or self.server, "need port or pasv first") - if self.pasvt then self:pasvconnect() end - local argument = recvt.argument or - url.unescape(string.gsub(recvt.path or "", "^[/\\]", "")) - if argument == "" then argument = nil end - local command = recvt.command or "retr" - self.try(self.tp:command(command, argument)) - local code = self.try(self.tp:check{"1..", "2.."}) - if not self.pasvt then self:portconnect() end - local source = socket.source("until-closed", self.data) - local step = recvt.step or ltn12.pump.step - self.try(ltn12.pump.all(source, recvt.sink, step)) - if string.find(code, "1..") then self.try(self.tp:check("2..")) end - self.data:close() - self.data = nil - return 1 -end - -function metat.__index:cwd(dir) - self.try(self.tp:command("cwd", dir)) - self.try(self.tp:check(250)) - return 1 -end - -function metat.__index:type(type) - self.try(self.tp:command("type", type)) - self.try(self.tp:check(200)) - return 1 -end - -function metat.__index:greet() - local code = self.try(self.tp:check{"1..", "2.."}) - if string.find(code, "1..") then self.try(self.tp:check("2..")) end - return 1 -end - -function metat.__index:quit() - self.try(self.tp:command("quit")) - self.try(self.tp:check("2..")) - return 1 -end - -function metat.__index:close() - if self.data then self.data:close() end - if self.server then self.server:close() end - return self.tp:close() -end - ------------------------------------------------------------------------------ --- High level FTP API ------------------------------------------------------------------------------ -local function override(t) - if t.url then - local u = url.parse(t.url) - for i,v in base.pairs(t) do - u[i] = v - end - return u - else return t end -end - -local function tput(putt) - putt = override(putt) - socket.try(putt.host, "missing hostname") - local f = open(putt.host, putt.port, putt.create) - f:greet() - f:login(putt.user, putt.password) - if putt.type then f:type(putt.type) end - f:pasv() - local sent = f:send(putt) - f:quit() - f:close() - return sent -end - -local default = { - path = "/", - scheme = "ftp" -} - -local function parse(u) - local t = socket.try(url.parse(u, default)) - socket.try(t.scheme == "ftp", "wrong scheme '" .. t.scheme .. "'") - socket.try(t.host, "missing hostname") - local pat = "^type=(.)$" - if t.params then - t.type = socket.skip(2, string.find(t.params, pat)) - socket.try(t.type == "a" or t.type == "i", - "invalid type '" .. t.type .. "'") - end - return t -end - -local function sput(u, body) - local putt = parse(u) - putt.source = ltn12.source.string(body) - return tput(putt) -end - -put = socket.protect(function(putt, body) - if base.type(putt) == "string" then return sput(putt, body) - else return tput(putt) end -end) - -local function tget(gett) - gett = override(gett) - socket.try(gett.host, "missing hostname") - local f = open(gett.host, gett.port, gett.create) - f:greet() - f:login(gett.user, gett.password) - if gett.type then f:type(gett.type) end - f:pasv() - f:receive(gett) - f:quit() - return f:close() -end - -local function sget(u) - local gett = parse(u) - local t = {} - gett.sink = ltn12.sink.table(t) - tget(gett) - return table.concat(t) -end - -command = socket.protect(function(cmdt) - cmdt = override(cmdt) - socket.try(cmdt.host, "missing hostname") - socket.try(cmdt.command, "missing command") - local f = open(cmdt.host, cmdt.port, cmdt.create) - f:greet() - f:login(cmdt.user, cmdt.password) - f.try(f.tp:command(cmdt.command, cmdt.argument)) - if cmdt.check then f.try(f.tp:check(cmdt.check)) end - f:quit() - return f:close() -end) - -get = socket.protect(function(gett) - if base.type(gett) == "string" then return sget(gett) - else return tget(gett) end -end) - diff --git a/lualib/socket/http.lua b/lualib/socket/http.lua deleted file mode 100644 index c020d8e..0000000 --- a/lualib/socket/http.lua +++ /dev/null @@ -1,350 +0,0 @@ ------------------------------------------------------------------------------ --- HTTP/1.1 client support for the Lua language. --- LuaSocket toolkit. --- Author: Diego Nehab --- RCS ID: $Id: http.lua,v 1.70 2007/03/12 04:08:40 diego Exp $ ------------------------------------------------------------------------------ - ------------------------------------------------------------------------------ --- Declare module and import dependencies -------------------------------------------------------------------------------- -local socket = require("socket") -local url = require("socket.url") -local ltn12 = require("ltn12") -local mime = require("mime") -local string = require("string") -local base = _G -local table = require("table") -module("socket.http") - ------------------------------------------------------------------------------ --- Program constants ------------------------------------------------------------------------------ --- connection timeout in seconds -TIMEOUT = 60 --- default port for document retrieval -PORT = 80 --- user agent field sent in request -USERAGENT = socket._VERSION - ------------------------------------------------------------------------------ --- Reads MIME headers from a connection, unfolding where needed ------------------------------------------------------------------------------ -local function receiveheaders(sock, headers) - local line, name, value, err - headers = headers or {} - -- get first line - line, err = sock:receive() - if err then return nil, err end - -- headers go until a blank line is found - while line ~= "" do - -- get field-name and value - name, value = socket.skip(2, string.find(line, "^(.-):%s*(.*)")) - if not (name and value) then return nil, "malformed reponse headers" end - name = string.lower(name) - -- get next line (value might be folded) - line, err = sock:receive() - if err then return nil, err end - -- unfold any folded values - while string.find(line, "^%s") do - value = value .. line - line = sock:receive() - if err then return nil, err end - end - -- save pair in table - if headers[name] then headers[name] = headers[name] .. ", " .. value - else headers[name] = value end - end - return headers -end - ------------------------------------------------------------------------------ --- Extra sources and sinks ------------------------------------------------------------------------------ -socket.sourcet["http-chunked"] = function(sock, headers) - return base.setmetatable({ - getfd = function() return sock:getfd() end, - dirty = function() return sock:dirty() end - }, { - __call = function() - -- get chunk size, skip extention - local line, err = sock:receive() - if err then return nil, err end - local size = base.tonumber(string.gsub(line, ";.*", ""), 16) - if not size then return nil, "invalid chunk size" end - -- was it the last chunk? - if size > 0 then - -- if not, get chunk and skip terminating CRLF - local chunk, err, part = sock:receive(size) - if chunk then sock:receive() end - return chunk, err - else - -- if it was, read trailers into headers table - headers, err = receiveheaders(sock, headers) - if not headers then return nil, err end - end - end - }) -end - -socket.sinkt["http-chunked"] = function(sock) - return base.setmetatable({ - getfd = function() return sock:getfd() end, - dirty = function() return sock:dirty() end - }, { - __call = function(self, chunk, err) - if not chunk then return sock:send("0\r\n\r\n") end - local size = string.format("%X\r\n", string.len(chunk)) - return sock:send(size .. chunk .. "\r\n") - end - }) -end - ------------------------------------------------------------------------------ --- Low level HTTP API ------------------------------------------------------------------------------ -local metat = { __index = {} } - -function open(host, port, create) - -- create socket with user connect function, or with default - local c = socket.try((create or socket.tcp)()) - local h = base.setmetatable({ c = c }, metat) - -- create finalized try - h.try = socket.newtry(function() h:close() end) - -- set timeout before connecting - h.try(c:settimeout(TIMEOUT)) - h.try(c:connect(host, port or PORT)) - -- here everything worked - return h -end - -function metat.__index:sendrequestline(method, uri) - local reqline = string.format("%s %s HTTP/1.1\r\n", method or "GET", uri) - return self.try(self.c:send(reqline)) -end - -function metat.__index:sendheaders(headers) - local h = "\r\n" - for i, v in base.pairs(headers) do - h = i .. ": " .. v .. "\r\n" .. h - end - self.try(self.c:send(h)) - return 1 -end - -function metat.__index:sendbody(headers, source, step) - source = source or ltn12.source.empty() - step = step or ltn12.pump.step - -- if we don't know the size in advance, send chunked and hope for the best - local mode = "http-chunked" - if headers["content-length"] then mode = "keep-open" end - return self.try(ltn12.pump.all(source, socket.sink(mode, self.c), step)) -end - -function metat.__index:receivestatusline() - local status = self.try(self.c:receive(5)) - -- identify HTTP/0.9 responses, which do not contain a status line - -- this is just a heuristic, but is what the RFC recommends - if status ~= "HTTP/" then return nil, status end - -- otherwise proceed reading a status line - status = self.try(self.c:receive("*l", status)) - local code = socket.skip(2, string.find(status, "HTTP/%d*%.%d* (%d%d%d)")) - return self.try(base.tonumber(code), status) -end - -function metat.__index:receiveheaders() - return self.try(receiveheaders(self.c)) -end - -function metat.__index:receivebody(headers, sink, step) - sink = sink or ltn12.sink.null() - step = step or ltn12.pump.step - local length = base.tonumber(headers["content-length"]) - local t = headers["transfer-encoding"] -- shortcut - local mode = "default" -- connection close - if t and t ~= "identity" then mode = "http-chunked" - elseif base.tonumber(headers["content-length"]) then mode = "by-length" end - return self.try(ltn12.pump.all(socket.source(mode, self.c, length), - sink, step)) -end - -function metat.__index:receive09body(status, sink, step) - local source = ltn12.source.rewind(socket.source("until-closed", self.c)) - source(status) - return self.try(ltn12.pump.all(source, sink, step)) -end - -function metat.__index:close() - return self.c:close() -end - ------------------------------------------------------------------------------ --- High level HTTP API ------------------------------------------------------------------------------ -local function adjusturi(reqt) - local u = reqt - -- if there is a proxy, we need the full url. otherwise, just a part. - if not reqt.proxy and not PROXY then - u = { - path = socket.try(reqt.path, "invalid path 'nil'"), - params = reqt.params, - query = reqt.query, - fragment = reqt.fragment - } - end - return url.build(u) -end - -local function adjustproxy(reqt) - local proxy = reqt.proxy or PROXY - if proxy then - proxy = url.parse(proxy) - return proxy.host, proxy.port or 3128 - else - return reqt.host, reqt.port - end -end - -local function adjustheaders(reqt) - -- default headers - local lower = { - ["user-agent"] = USERAGENT, - ["host"] = reqt.host, - ["connection"] = "close, TE", - ["te"] = "trailers" - } - -- if we have authentication information, pass it along - if reqt.user and reqt.password then - lower["authorization"] = - "Basic " .. (mime.b64(reqt.user .. ":" .. reqt.password)) - end - -- override with user headers - for i,v in base.pairs(reqt.headers or lower) do - lower[string.lower(i)] = v - end - return lower -end - --- default url parts -local default = { - host = "", - port = PORT, - path ="/", - scheme = "http" -} - -local function adjustrequest(reqt) - -- parse url if provided - local nreqt = reqt.url and url.parse(reqt.url, default) or {} - -- explicit components override url - for i,v in base.pairs(reqt) do nreqt[i] = v end - if nreqt.port == "" then nreqt.port = 80 end - socket.try(nreqt.host and nreqt.host ~= "", - "invalid host '" .. base.tostring(nreqt.host) .. "'") - -- compute uri if user hasn't overriden - nreqt.uri = reqt.uri or adjusturi(nreqt) - -- ajust host and port if there is a proxy - nreqt.host, nreqt.port = adjustproxy(nreqt) - -- adjust headers in request - nreqt.headers = adjustheaders(nreqt) - return nreqt -end - -local function shouldredirect(reqt, code, headers) - return headers.location and - string.gsub(headers.location, "%s", "") ~= "" and - (reqt.redirect ~= false) and - (code == 301 or code == 302) and - (not reqt.method or reqt.method == "GET" or reqt.method == "HEAD") - and (not reqt.nredirects or reqt.nredirects < 5) -end - -local function shouldreceivebody(reqt, code) - if reqt.method == "HEAD" then return nil end - if code == 204 or code == 304 then return nil end - if code >= 100 and code < 200 then return nil end - return 1 -end - --- forward declarations -local trequest, tredirect - -function tredirect(reqt, location) - local result, code, headers, status = trequest { - -- the RFC says the redirect URL has to be absolute, but some - -- servers do not respect that - url = url.absolute(reqt.url, location), - source = reqt.source, - sink = reqt.sink, - headers = reqt.headers, - proxy = reqt.proxy, - nredirects = (reqt.nredirects or 0) + 1, - create = reqt.create - } - -- pass location header back as a hint we redirected - headers = headers or {} - headers.location = headers.location or location - return result, code, headers, status -end - -function trequest(reqt) - -- we loop until we get what we want, or - -- until we are sure there is no way to get it - local nreqt = adjustrequest(reqt) - local h = open(nreqt.host, nreqt.port, nreqt.create) - -- send request line and headers - h:sendrequestline(nreqt.method, nreqt.uri) - h:sendheaders(nreqt.headers) - -- if there is a body, send it - if nreqt.source then - h:sendbody(nreqt.headers, nreqt.source, nreqt.step) - end - local code, status = h:receivestatusline() - -- if it is an HTTP/0.9 server, simply get the body and we are done - if not code then - h:receive09body(status, nreqt.sink, nreqt.step) - return 1, 200 - end - local headers - -- ignore any 100-continue messages - while code == 100 do - headers = h:receiveheaders() - code, status = h:receivestatusline() - end - headers = h:receiveheaders() - -- at this point we should have a honest reply from the server - -- we can't redirect if we already used the source, so we report the error - if shouldredirect(nreqt, code, headers) and not nreqt.source then - h:close() - return tredirect(reqt, headers.location) - end - -- here we are finally done - if shouldreceivebody(nreqt, code) then - h:receivebody(headers, nreqt.sink, nreqt.step) - end - h:close() - return 1, code, headers, status -end - -local function srequest(u, b) - local t = {} - local reqt = { - url = u, - sink = ltn12.sink.table(t) - } - if b then - reqt.source = ltn12.source.string(b) - reqt.headers = { - ["content-length"] = string.len(b), - ["content-type"] = "application/x-www-form-urlencoded" - } - reqt.method = "POST" - end - local code, headers, status = socket.skip(1, trequest(reqt)) - return table.concat(t), code, headers, status -end - -request = socket.protect(function(reqt, body) - if base.type(reqt) == "string" then return srequest(reqt, body) - else return trequest(reqt) end -end) diff --git a/lualib/socket/smtp.lua b/lualib/socket/smtp.lua deleted file mode 100644 index 8f3cfcf..0000000 --- a/lualib/socket/smtp.lua +++ /dev/null @@ -1,251 +0,0 @@ ------------------------------------------------------------------------------ --- SMTP client support for the Lua language. --- LuaSocket toolkit. --- Author: Diego Nehab --- RCS ID: $Id: smtp.lua,v 1.46 2007/03/12 04:08:40 diego Exp $ ------------------------------------------------------------------------------ - ------------------------------------------------------------------------------ --- Declare module and import dependencies ------------------------------------------------------------------------------ -local base = _G -local coroutine = require("coroutine") -local string = require("string") -local math = require("math") -local os = require("os") -local socket = require("socket") -local tp = require("socket.tp") -local ltn12 = require("ltn12") -local mime = require("mime") -module("socket.smtp") - ------------------------------------------------------------------------------ --- Program constants ------------------------------------------------------------------------------ --- timeout for connection -TIMEOUT = 60 --- default server used to send e-mails -SERVER = "localhost" --- default port -PORT = 25 --- domain used in HELO command and default sendmail --- If we are under a CGI, try to get from environment -DOMAIN = os.getenv("SERVER_NAME") or "localhost" --- default time zone (means we don't know) -ZONE = "-0000" - ---------------------------------------------------------------------------- --- Low level SMTP API ------------------------------------------------------------------------------ -local metat = { __index = {} } - -function metat.__index:greet(domain) - self.try(self.tp:check("2..")) - self.try(self.tp:command("EHLO", domain or DOMAIN)) - return socket.skip(1, self.try(self.tp:check("2.."))) -end - -function metat.__index:mail(from) - self.try(self.tp:command("MAIL", "FROM:" .. from)) - return self.try(self.tp:check("2..")) -end - -function metat.__index:rcpt(to) - self.try(self.tp:command("RCPT", "TO:" .. to)) - return self.try(self.tp:check("2..")) -end - -function metat.__index:data(src, step) - self.try(self.tp:command("DATA")) - self.try(self.tp:check("3..")) - self.try(self.tp:source(src, step)) - self.try(self.tp:send("\r\n.\r\n")) - return self.try(self.tp:check("2..")) -end - -function metat.__index:quit() - self.try(self.tp:command("QUIT")) - return self.try(self.tp:check("2..")) -end - -function metat.__index:close() - return self.tp:close() -end - -function metat.__index:login(user, password) - self.try(self.tp:command("AUTH", "LOGIN")) - self.try(self.tp:check("3..")) - self.try(self.tp:command(mime.b64(user))) - self.try(self.tp:check("3..")) - self.try(self.tp:command(mime.b64(password))) - return self.try(self.tp:check("2..")) -end - -function metat.__index:plain(user, password) - local auth = "PLAIN " .. mime.b64("\0" .. user .. "\0" .. password) - self.try(self.tp:command("AUTH", auth)) - return self.try(self.tp:check("2..")) -end - -function metat.__index:auth(user, password, ext) - if not user or not password then return 1 end - if string.find(ext, "AUTH[^\n]+LOGIN") then - return self:login(user, password) - elseif string.find(ext, "AUTH[^\n]+PLAIN") then - return self:plain(user, password) - else - self.try(nil, "authentication not supported") - end -end - --- send message or throw an exception -function metat.__index:send(mailt) - self:mail(mailt.from) - if base.type(mailt.rcpt) == "table" then - for i,v in base.ipairs(mailt.rcpt) do - self:rcpt(v) - end - else - self:rcpt(mailt.rcpt) - end - self:data(ltn12.source.chain(mailt.source, mime.stuff()), mailt.step) -end - -function open(server, port, create) - local tp = socket.try(tp.connect(server or SERVER, port or PORT, - TIMEOUT, create)) - local s = base.setmetatable({tp = tp}, metat) - -- make sure tp is closed if we get an exception - s.try = socket.newtry(function() - s:close() - end) - return s -end - --- convert headers to lowercase -local function lower_headers(headers) - local lower = {} - for i,v in base.pairs(headers or lower) do - lower[string.lower(i)] = v - end - return lower -end - ---------------------------------------------------------------------------- --- Multipart message source ------------------------------------------------------------------------------ --- returns a hopefully unique mime boundary -local seqno = 0 -local function newboundary() - seqno = seqno + 1 - return string.format('%s%05d==%05u', os.date('%d%m%Y%H%M%S'), - math.random(0, 99999), seqno) -end - --- send_message forward declaration -local send_message - --- yield the headers all at once, it's faster -local function send_headers(headers) - local h = "\r\n" - for i,v in base.pairs(headers) do - h = i .. ': ' .. v .. "\r\n" .. h - end - coroutine.yield(h) -end - --- yield multipart message body from a multipart message table -local function send_multipart(mesgt) - -- make sure we have our boundary and send headers - local bd = newboundary() - local headers = lower_headers(mesgt.headers or {}) - headers['content-type'] = headers['content-type'] or 'multipart/mixed' - headers['content-type'] = headers['content-type'] .. - '; boundary="' .. bd .. '"' - send_headers(headers) - -- send preamble - if mesgt.body.preamble then - coroutine.yield(mesgt.body.preamble) - coroutine.yield("\r\n") - end - -- send each part separated by a boundary - for i, m in base.ipairs(mesgt.body) do - coroutine.yield("\r\n--" .. bd .. "\r\n") - send_message(m) - end - -- send last boundary - coroutine.yield("\r\n--" .. bd .. "--\r\n\r\n") - -- send epilogue - if mesgt.body.epilogue then - coroutine.yield(mesgt.body.epilogue) - coroutine.yield("\r\n") - end -end - --- yield message body from a source -local function send_source(mesgt) - -- make sure we have a content-type - local headers = lower_headers(mesgt.headers or {}) - headers['content-type'] = headers['content-type'] or - 'text/plain; charset="iso-8859-1"' - send_headers(headers) - -- send body from source - while true do - local chunk, err = mesgt.body() - if err then coroutine.yield(nil, err) - elseif chunk then coroutine.yield(chunk) - else break end - end -end - --- yield message body from a string -local function send_string(mesgt) - -- make sure we have a content-type - local headers = lower_headers(mesgt.headers or {}) - headers['content-type'] = headers['content-type'] or - 'text/plain; charset="iso-8859-1"' - send_headers(headers) - -- send body from string - coroutine.yield(mesgt.body) -end - --- message source -function send_message(mesgt) - if base.type(mesgt.body) == "table" then send_multipart(mesgt) - elseif base.type(mesgt.body) == "function" then send_source(mesgt) - else send_string(mesgt) end -end - --- set defaul headers -local function adjust_headers(mesgt) - local lower = lower_headers(mesgt.headers) - lower["date"] = lower["date"] or - os.date("!%a, %d %b %Y %H:%M:%S ") .. (mesgt.zone or ZONE) - lower["x-mailer"] = lower["x-mailer"] or socket._VERSION - -- this can't be overriden - lower["mime-version"] = "1.0" - return lower -end - -function message(mesgt) - mesgt.headers = adjust_headers(mesgt) - -- create and return message source - local co = coroutine.create(function() send_message(mesgt) end) - return function() - local ret, a, b = coroutine.resume(co) - if ret then return a, b - else return nil, a end - end -end - ---------------------------------------------------------------------------- --- High level SMTP API ------------------------------------------------------------------------------ -send = socket.protect(function(mailt) - local s = open(mailt.server, mailt.port, mailt.create) - local ext = s:greet(mailt.domain) - s:auth(mailt.user, mailt.password, ext) - s:send(mailt) - s:quit() - return s:close() -end) diff --git a/lualib/socket/tp.lua b/lualib/socket/tp.lua deleted file mode 100644 index 0683869..0000000 --- a/lualib/socket/tp.lua +++ /dev/null @@ -1,123 +0,0 @@ ------------------------------------------------------------------------------ --- Unified SMTP/FTP subsystem --- LuaSocket toolkit. --- Author: Diego Nehab --- RCS ID: $Id: tp.lua,v 1.22 2006/03/14 09:04:15 diego Exp $ ------------------------------------------------------------------------------ - ------------------------------------------------------------------------------ --- Declare module and import dependencies ------------------------------------------------------------------------------ -local base = _G -local string = require("string") -local socket = require("socket") -local ltn12 = require("ltn12") -module("socket.tp") - ------------------------------------------------------------------------------ --- Program constants ------------------------------------------------------------------------------ -TIMEOUT = 60 - ------------------------------------------------------------------------------ --- Implementation ------------------------------------------------------------------------------ --- gets server reply (works for SMTP and FTP) -local function get_reply(c) - local code, current, sep - local line, err = c:receive() - local reply = line - if err then return nil, err end - code, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)")) - if not code then return nil, "invalid server reply" end - if sep == "-" then -- reply is multiline - repeat - line, err = c:receive() - if err then return nil, err end - current, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)")) - reply = reply .. "\n" .. line - -- reply ends with same code - until code == current and sep == " " - end - return code, reply -end - --- metatable for sock object -local metat = { __index = {} } - -function metat.__index:check(ok) - local code, reply = get_reply(self.c) - if not code then return nil, reply end - if base.type(ok) ~= "function" then - if base.type(ok) == "table" then - for i, v in base.ipairs(ok) do - if string.find(code, v) then - return base.tonumber(code), reply - end - end - return nil, reply - else - if string.find(code, ok) then return base.tonumber(code), reply - else return nil, reply end - end - else return ok(base.tonumber(code), reply) end -end - -function metat.__index:command(cmd, arg) - if arg then - return self.c:send(cmd .. " " .. arg.. "\r\n") - else - return self.c:send(cmd .. "\r\n") - end -end - -function metat.__index:sink(snk, pat) - local chunk, err = c:receive(pat) - return snk(chunk, err) -end - -function metat.__index:send(data) - return self.c:send(data) -end - -function metat.__index:receive(pat) - return self.c:receive(pat) -end - -function metat.__index:getfd() - return self.c:getfd() -end - -function metat.__index:dirty() - return self.c:dirty() -end - -function metat.__index:getcontrol() - return self.c -end - -function metat.__index:source(source, step) - local sink = socket.sink("keep-open", self.c) - local ret, err = ltn12.pump.all(source, sink, step or ltn12.pump.step) - return ret, err -end - --- closes the underlying c -function metat.__index:close() - self.c:close() - return 1 -end - --- connect with server and return c object -function connect(host, port, timeout, create) - local c, e = (create or socket.tcp)() - if not c then return nil, e end - c:settimeout(timeout or TIMEOUT) - local r, e = c:connect(host, port) - if not r then - c:close() - return nil, e - end - return base.setmetatable({c = c}, metat) -end - diff --git a/lualib/socket/url.lua b/lualib/socket/url.lua deleted file mode 100644 index f05d91c..0000000 --- a/lualib/socket/url.lua +++ /dev/null @@ -1,297 +0,0 @@ ------------------------------------------------------------------------------ --- URI parsing, composition and relative URL resolution --- LuaSocket toolkit. --- Author: Diego Nehab --- RCS ID: $Id: url.lua,v 1.38 2006/04/03 04:45:42 diego Exp $ ------------------------------------------------------------------------------ - ------------------------------------------------------------------------------ --- Declare module ------------------------------------------------------------------------------ -local string = require("string") -local base = _G -local table = require("table") -module("socket.url") - ------------------------------------------------------------------------------ --- Module version ------------------------------------------------------------------------------ -_VERSION = "URL 1.0.1" - ------------------------------------------------------------------------------ --- Encodes a string into its escaped hexadecimal representation --- Input --- s: binary string to be encoded --- Returns --- escaped representation of string binary ------------------------------------------------------------------------------ -function escape(s) - return string.gsub(s, "([^A-Za-z0-9_])", function(c) - return string.format("%%%02x", string.byte(c)) - end) -end - ------------------------------------------------------------------------------ --- Protects a path segment, to prevent it from interfering with the --- url parsing. --- Input --- s: binary string to be encoded --- Returns --- escaped representation of string binary ------------------------------------------------------------------------------ -local function make_set(t) - local s = {} - for i,v in base.ipairs(t) do - s[t[i]] = 1 - end - return s -end - --- these are allowed withing a path segment, along with alphanum --- other characters must be escaped -local segment_set = make_set { - "-", "_", ".", "!", "~", "*", "'", "(", - ")", ":", "@", "&", "=", "+", "$", ",", -} - -local function protect_segment(s) - return string.gsub(s, "([^A-Za-z0-9_])", function (c) - if segment_set[c] then return c - else return string.format("%%%02x", string.byte(c)) end - end) -end - ------------------------------------------------------------------------------ --- Encodes a string into its escaped hexadecimal representation --- Input --- s: binary string to be encoded --- Returns --- escaped representation of string binary ------------------------------------------------------------------------------ -function unescape(s) - return string.gsub(s, "%%(%x%x)", function(hex) - return string.char(base.tonumber(hex, 16)) - end) -end - ------------------------------------------------------------------------------ --- Builds a path from a base path and a relative path --- Input --- base_path --- relative_path --- Returns --- corresponding absolute path ------------------------------------------------------------------------------ -local function absolute_path(base_path, relative_path) - if string.sub(relative_path, 1, 1) == "/" then return relative_path end - local path = string.gsub(base_path, "[^/]*$", "") - path = path .. relative_path - path = string.gsub(path, "([^/]*%./)", function (s) - if s ~= "./" then return s else return "" end - end) - path = string.gsub(path, "/%.$", "/") - local reduced - while reduced ~= path do - reduced = path - path = string.gsub(reduced, "([^/]*/%.%./)", function (s) - if s ~= "../../" then return "" else return s end - end) - end - path = string.gsub(reduced, "([^/]*/%.%.)$", function (s) - if s ~= "../.." then return "" else return s end - end) - return path -end - ------------------------------------------------------------------------------ --- Parses a url and returns a table with all its parts according to RFC 2396 --- The following grammar describes the names given to the URL parts --- ::= :///;?# --- ::= @: --- ::= [:] --- :: = {/} --- Input --- url: uniform resource locator of request --- default: table with default values for each field --- Returns --- table with the following fields, where RFC naming conventions have --- been preserved: --- scheme, authority, userinfo, user, password, host, port, --- path, params, query, fragment --- Obs: --- the leading '/' in {/} is considered part of ------------------------------------------------------------------------------ -function parse(url, default) - -- initialize default parameters - local parsed = {} - for i,v in base.pairs(default or parsed) do parsed[i] = v end - -- empty url is parsed to nil - if not url or url == "" then return nil, "invalid url" end - -- remove whitespace - -- url = string.gsub(url, "%s", "") - -- get fragment - url = string.gsub(url, "#(.*)$", function(f) - parsed.fragment = f - return "" - end) - -- get scheme - url = string.gsub(url, "^([%w][%w%+%-%.]*)%:", - function(s) parsed.scheme = s; return "" end) - -- get authority - url = string.gsub(url, "^//([^/]*)", function(n) - parsed.authority = n - return "" - end) - -- get query stringing - url = string.gsub(url, "%?(.*)", function(q) - parsed.query = q - return "" - end) - -- get params - url = string.gsub(url, "%;(.*)", function(p) - parsed.params = p - return "" - end) - -- path is whatever was left - if url ~= "" then parsed.path = url end - local authority = parsed.authority - if not authority then return parsed end - authority = string.gsub(authority,"^([^@]*)@", - function(u) parsed.userinfo = u; return "" end) - authority = string.gsub(authority, ":([^:]*)$", - function(p) parsed.port = p; return "" end) - if authority ~= "" then parsed.host = authority end - local userinfo = parsed.userinfo - if not userinfo then return parsed end - userinfo = string.gsub(userinfo, ":([^:]*)$", - function(p) parsed.password = p; return "" end) - parsed.user = userinfo - return parsed -end - ------------------------------------------------------------------------------ --- Rebuilds a parsed URL from its components. --- Components are protected if any reserved or unallowed characters are found --- Input --- parsed: parsed URL, as returned by parse --- Returns --- a stringing with the corresponding URL ------------------------------------------------------------------------------ -function build(parsed) - local ppath = parse_path(parsed.path or "") - local url = build_path(ppath) - if parsed.params then url = url .. ";" .. parsed.params end - if parsed.query then url = url .. "?" .. parsed.query end - local authority = parsed.authority - if parsed.host then - authority = parsed.host - if parsed.port then authority = authority .. ":" .. parsed.port end - local userinfo = parsed.userinfo - if parsed.user then - userinfo = parsed.user - if parsed.password then - userinfo = userinfo .. ":" .. parsed.password - end - end - if userinfo then authority = userinfo .. "@" .. authority end - end - if authority then url = "//" .. authority .. url end - if parsed.scheme then url = parsed.scheme .. ":" .. url end - if parsed.fragment then url = url .. "#" .. parsed.fragment end - -- url = string.gsub(url, "%s", "") - return url -end - ------------------------------------------------------------------------------ --- Builds a absolute URL from a base and a relative URL according to RFC 2396 --- Input --- base_url --- relative_url --- Returns --- corresponding absolute url ------------------------------------------------------------------------------ -function absolute(base_url, relative_url) - if base.type(base_url) == "table" then - base_parsed = base_url - base_url = build(base_parsed) - else - base_parsed = parse(base_url) - end - local relative_parsed = parse(relative_url) - if not base_parsed then return relative_url - elseif not relative_parsed then return base_url - elseif relative_parsed.scheme then return relative_url - else - relative_parsed.scheme = base_parsed.scheme - if not relative_parsed.authority then - relative_parsed.authority = base_parsed.authority - if not relative_parsed.path then - relative_parsed.path = base_parsed.path - if not relative_parsed.params then - relative_parsed.params = base_parsed.params - if not relative_parsed.query then - relative_parsed.query = base_parsed.query - end - end - else - relative_parsed.path = absolute_path(base_parsed.path or "", - relative_parsed.path) - end - end - return build(relative_parsed) - end -end - ------------------------------------------------------------------------------ --- Breaks a path into its segments, unescaping the segments --- Input --- path --- Returns --- segment: a table with one entry per segment ------------------------------------------------------------------------------ -function parse_path(path) - local parsed = {} - path = path or "" - --path = string.gsub(path, "%s", "") - string.gsub(path, "([^/]+)", function (s) table.insert(parsed, s) end) - for i = 1, #parsed do - parsed[i] = unescape(parsed[i]) - end - if string.sub(path, 1, 1) == "/" then parsed.is_absolute = 1 end - if string.sub(path, -1, -1) == "/" then parsed.is_directory = 1 end - return parsed -end - ------------------------------------------------------------------------------ --- Builds a path component from its segments, escaping protected characters. --- Input --- parsed: path segments --- unsafe: if true, segments are not protected before path is built --- Returns --- path: corresponding path stringing ------------------------------------------------------------------------------ -function build_path(parsed, unsafe) - local path = "" - local n = #parsed - if unsafe then - for i = 1, n-1 do - path = path .. parsed[i] - path = path .. "/" - end - if n > 0 then - path = path .. parsed[n] - if parsed.is_directory then path = path .. "/" end - end - else - for i = 1, n-1 do - path = path .. protect_segment(parsed[i]) - path = path .. "/" - end - if n > 0 then - path = path .. protect_segment(parsed[n]) - if parsed.is_directory then path = path .. "/" end - end - end - if parsed.is_absolute then path = "/" .. path end - return path -end diff --git a/readme.md b/readme.md index a3005e1..767d7ab 100644 --- a/readme.md +++ b/readme.md @@ -7,7 +7,6 @@ Lua scripting for Blockland - Install RedBlocklandLoader - Copy `lua5.1.dll` into your Blockland install folder, next to `Blockland.exe` - Copy `BlockLua.dll` into the `modules` folder within the Blockland folder -- Optional: Copy the `lualib` folder into `modules` ## Quick Reference @@ -96,7 +95,7 @@ When reading from outside ZIPs, binary files are fully supported. `bl.datablock('datablockClassName datablockName:parentDatablockName', fields?)` - Create a new datablock with inheritance ### Classes and Types -`bl.type('varName', 'type')` - Register the type of a Torque global variable, for conversion when accessing from Lua. Valid types are 'boolean', 'object', and nil (default is nil, which applies automatic conversion). +`bl.type('varName', 'type')` - Register the type of a Torque global variable, for conversion when accessing from Lua. Valid types are 'boolean', 'object', 'string' (prevents automatic conversion), and nil (default, applies automatic conversion). `bl.type('funcName', 'type')` - Register the return type of a Torque function, for conversion when calling from Lua. Valid types are 'bool', 'object', and nil - all other conversion is automatic. Already done for all default functions. `bl.type('className::funcName', 'type')` - Register the return type of a Torque object method. `bl.class('className')` - Register an existing Torque class to be used from Lua. Already done for all built-in classes. @@ -179,14 +178,12 @@ TorqueScript stores no type information; all values in TorqueScript are strings. - Tables cannot be passed and will throw an error ## I/O and Safety -All Lua code is sandboxed, and file access is confied to the default directories in the same way TorqueScript is. +All Lua code is sandboxed, and file access is confined to the default directories in the same way TorqueScript is. BlockLua also has access to any C libraries installed in the `modules/lualib` folder, so be careful throwing things in there. ### Unsafe Mode BlockLua-Unsafe.dll can be built and used in place of BlockLua.dll (see compile.bat), to remove the sandboxing of Lua code. This allows Lua code to access any file and use any library, including ffi. Please do not publish add-ons that require unsafe mode. -## Other Reference - ### List of Object Types `'all'` - Any object `'player'` - Players or bots @@ -195,4 +192,11 @@ Please do not publish add-ons that require unsafe mode. `'projectile'` - Projectiles `'brick'` - Bricks with raycasting enabled `'brickalways'` - All bricks including those with raycasting disabled -Other types: `'static'`, `'environment'`, `'terrain'`, `'water'`, `'trigger'`, `'marker'`, `'gamebase'`, `'shapebase'`, `'camera'`, `'staticshape'`, `'vehicleblocker'`, `'explosion'`, `'corpse'`, `'debris'`, `'physicalzone'`, `'staticts'`, `'staticrendered'`, `'damagableitem'` +Other types: `'static'`, `'environment'`, `'terrain'`, `'water'`, `'trigger'`, `'marker'`, `'gamebase'`, `'shapebase'`, `'camera'`, `'staticshape'`, `'vehicleblocker'`, `'explosion'`, `'corpse'`, `'debris'`, `'physicalzone'`, `'staticts'`, `'staticrendered'`, `'damagableitem'` + +## Compiling + +With any *32-bit* variant of GCC installed (such as MinGW or MSYS2), run the following command in the repo directory: +`g++ src/bllua4.cpp -o BlockLua.dll -m32 -shared -static-libgcc -Isrc -Iinc/tsfuncs -Iinc/lua -lpsapi -L. -llua5.1 src/bllua` + +LuaJIT (lua5.1.dll) can be obtained from https://luajit.org/ diff --git a/src/util/libbl.lua b/src/util/libbl.lua index 62ea1a6..459ac25 100644 --- a/src/util/libbl.lua +++ b/src/util/libbl.lua @@ -106,14 +106,14 @@ local function valToTs(val) error('valToTs: could not convert '..type(val), 3) end end +local fromTsForceTypes = { + ['boolean'] = tsBool, + ['object'] = function(val) toTsObject(val) end, -- toTsObject not defined yet + ['string'] = tostring, +} local function convertValFromTs(val, typ) - if typ=='boolean' then - return tsBool(val) - elseif typ=='object' then - return toTsObject(val) - else + return fromTsForceTypes[typ](val) or error('valFromTs: invalid force type '..typ, 4) - end end bl._forceType = bl._forceType or {} local function valFromTs(val, name, name2) -- todo: ensure name and name2 are already lowercase @@ -167,8 +167,8 @@ local function classFromForceTypeStr(name) end local setForceType setForceType = function(ftname, typ) - if typ~='boolean' and typ~='object' and typ~=nil then - error('bl.type: can only set type to \'boolean\', \'object\', or nil', 2) end + if typ~=nil and not fromTsForceTypes[typ] then + error('bl.type: invalid type \''..typ..'\'', 2) end if not isValidFuncNameNsArgn(ftname) then error('bl.type: invalid function or variable name \''..ftname..'\'', 2) end @@ -557,11 +557,11 @@ function bl.array(name, ...) return name..table.concat(rest, '_') end function _bllua_call(fnameS, ...) - local args = arglistFromTs(fnameS:lower(), {...}) + local args = arglistFromTs('lua:'..fnameS:lower(), {...}) if not _G[fnameS] then error('luacall: no global lua function named \''..fnameS..'\'') end -- todo: library fields and object methods - local res = _G[fnameS](args) + local res = _G[fnameS](unpack(args)) return valToTs(res) end From edf31c178c1926fc6ed54a0e4649efdbc11a9bdf Mon Sep 17 00:00:00 2001 From: Redo Date: Sun, 5 Oct 2025 22:31:21 -0500 Subject: [PATCH 2/3] allow calling namespaced torque functions --- BlockLua.dll | Bin 374823 -> 375335 bytes readme.md | 10 +++++----- src/util/libbl.lua | 37 +++++++++++++++++++++++++++++-------- 3 files changed, 34 insertions(+), 13 deletions(-) diff --git a/BlockLua.dll b/BlockLua.dll index 57a349acfbba67d687287175e87d983812396b16..6d9a7bfe89d91ace1eb04c9a7621caf2563289a8 100644 GIT binary patch delta 7814 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 Date: Mon, 6 Oct 2025 00:13:00 -0500 Subject: [PATCH 3/3] fix named ts object method calling --- BlockLua.dll | Bin 375335 -> 375335 bytes readme.md | 1 + src/util/libbl-support.cs | 4 ++-- src/util/libbl.lua | 15 ++++++++++----- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/BlockLua.dll b/BlockLua.dll index 6d9a7bfe89d91ace1eb04c9a7621caf2563289a8..58d6e4573dc1ffa06b4c883b730660ac21e85ae3 100644 GIT binary patch delta 6743 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 delta 6726 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 Gg#0f{Kh>=O diff --git a/readme.md b/readme.md index b06faf4..1e5e5c2 100644 --- a/readme.md +++ b/readme.md @@ -25,6 +25,7 @@ Lua scripting for Blockland `bl.varName` - Read a TorqueScript global variable `bl['varName']` - Read a TorqueScript global variable (i.e. with special characters in the name, or from an array) `bl.set('varName', value)` - Write a TorqueScript global variable +`bl['namespaceName::funcName'](args)` - Call a namespaced TorqueScript function ### Accessing Torque Objects from Lua `bl.objectName` - Access a Torque object by name diff --git a/src/util/libbl-support.cs b/src/util/libbl-support.cs index f2be6e6..c4032d0 100644 --- a/src/util/libbl-support.cs +++ b/src/util/libbl-support.cs @@ -1,7 +1,7 @@ // Private - Utilities used by libbl from the Lua side -package _bllua_smartEval { +package smartEval { // Allow prepending ' to console commands to eval in lua instead of TS // Also wraps TS lines with echo(...); if they don't end in ; or } function ConsoleEntry::eval() { @@ -28,7 +28,7 @@ package _bllua_smartEval { } } }; -activatePackage(_bllua_smartEval); +activatePackage(smartEval); package _bllua_objectDeletionHook { // Hook object deletion to clean up its lua data diff --git a/src/util/libbl.lua b/src/util/libbl.lua index 34c6357..efd5889 100644 --- a/src/util/libbl.lua +++ b/src/util/libbl.lua @@ -303,7 +303,10 @@ local tsObjectMeta = { for inh in objectInheritedMetas(rawget(t,'_tsClassName')) do if inh[name] then return inh[name] end end - if tsIsFunctionNs(rawget(t,'_tsNamespace'), name) then + if + tsIsFunctionNs(rawget(t,'_tsNamespace'), name) or + tsIsFunctionNs(rawget(t,'_tsName'), name) + then return function(t, ...) local args = {...} local argsS = arglistToTs(args) @@ -921,10 +924,12 @@ end -- bl.new and bl.datablock local function createTsObj(keyword, class, name, inherit, props) local propsT = {} - for k,v in pairs(props) do - if not isValidFuncName(k) then - error('bl.new/bl.datablock: invalid property name \''..k..'\'') end - table.insert(propsT, k..'="'..valToTs(v)..'";') + if props then + for k,v in pairs(props) do + if not isValidFuncName(k) then + error('bl.new/bl.datablock: invalid property name \''..k..'\'') end + table.insert(propsT, k..'="'..valToTs(v)..'";') + end end local objS = _bllua_ts.eval(