From 45e5570959ee3cbd49bcb0cd8616548966252cb2 Mon Sep 17 00:00:00 2001 From: Ian Gulliver Date: Sun, 28 Apr 2019 17:50:44 +0000 Subject: [PATCH] Remove the nested read loops in FastCGIConn, hide complexity inside StreamBuffer --- .gitignore | 1 + Makefile | 4 ++-- buffer.cpp | 19 +++++-------------- buffer.h | 10 +++------- example_simple | Bin 173960 -> 0 bytes example_simple.cpp | 1 - fastcgi_conn.cpp | 38 +++++++++++++++----------------------- fastcgi_conn.h | 6 ++---- stream_buffer.cpp | 26 ++++++++++++++++++++++++++ stream_buffer.h | 19 +++++++++++++++++++ 10 files changed, 73 insertions(+), 51 deletions(-) delete mode 100755 example_simple create mode 100644 stream_buffer.cpp create mode 100644 stream_buffer.h diff --git a/.gitignore b/.gitignore index a96a5b8..da27681 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ mirall +example_simple *.o diff --git a/Makefile b/Makefile index 1e1d157..295f820 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ -example_simple: example_simple.o fastcgi.o fastcgi_conn.o fastcgi_request.o buffer.o - clang++ -std=gnu++2a -o example_simple example_simple.o fastcgi.o fastcgi_conn.o fastcgi_request.o buffer.o -lgflags -lglog -lpthread +example_simple: example_simple.o fastcgi.o fastcgi_conn.o fastcgi_request.o stream_buffer.o buffer.o + clang++ -std=gnu++2a -o example_simple example_simple.o fastcgi.o fastcgi_conn.o fastcgi_request.o stream_buffer.o buffer.o -lgflags -lglog -lpthread clean: rm --force exmaple_simple *.o diff --git a/buffer.cpp b/buffer.cpp index 2b5cddc..03313b1 100644 --- a/buffer.cpp +++ b/buffer.cpp @@ -23,14 +23,6 @@ bool ConstBuffer::Discard(size_t len) { return true; } -void ConstBuffer::ResetRead() { - start_ = commit_; -} - -void ConstBuffer::Commit() { - commit_ = start_; -} - Buffer::Buffer(char *buf, size_t size, size_t len) : ConstBuffer(buf, size), @@ -57,12 +49,11 @@ void Buffer::Wrote(size_t len) { len_ += len; } -void Buffer::Consume() { - if (commit_ == 0) { +void Buffer::Commit() { + if (start_ == 0) { return; } - memmove(buf_, &buf_[commit_], len_ - commit_); - len_ -= commit_; - start_ -= commit_; - commit_ = 0; + memmove(buf_, &buf_[start_], len_ - start_); + len_ -= start_; + start_ = 0; } diff --git a/buffer.h b/buffer.h index 627054b..8a44ff5 100644 --- a/buffer.h +++ b/buffer.h @@ -8,23 +8,19 @@ class ConstBuffer { ConstBuffer(const char *buf, size_t len); [[nodiscard]] size_t ReadMaxLen() const; - [[nodiscard]] const char *Read(size_t len); + [[nodiscard]] virtual const char *Read(size_t len); template [[nodiscard]] const T *ReadObj(); bool Discard(size_t len); // like Read() but don't use the result - void ResetRead(); // next read from last commit - void Commit(); // commit read position protected: const char *const_buf_; size_t len_; size_t start_ = 0; - size_t commit_ = 0; }; class Buffer : public ConstBuffer { public: - Buffer(const char *buf, size_t len) = delete; Buffer(char *buf, size_t size, size_t len); Buffer(size_t size); @@ -32,9 +28,9 @@ class Buffer : public ConstBuffer { [[nodiscard]] size_t WriteMaxLen() const; void Wrote(size_t len); - void Consume(); // discard up to last commit + void Commit(); // commit read position - private: + protected: std::unique_ptr own_buf_; char *buf_; const size_t size_; diff --git a/example_simple b/example_simple deleted file mode 100755 index 0783d69a52138a5207cf55c199600f45e5d7b2ab..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 173960 zcmeFa3w&HvwLd;-c?=IpP>~2KK|xZUN$Ddk0x9j#Q`$gm2}BepX*z9U(7^5Tp;1JeIJmGzHeqkYvEZpiTy60$ z{FMKpbq&8y{auoPrSiqX74O#h7TR_nM?2#ARzHTEft6;wY;>ulVBlk+ra~ZaR(;*- zd2`OHUvox%T|-;@8SN$W&X_mn%$CM8XUn|VKkF{NxPr|^z6>cOeKP(fC5gY#?4u7J z9Jpn0M&WINlkx+BO^2NIp0xvC3>^8sqi4=s7C5_h9j2yX!x{aNdf@@(cgdkF)=K^`U`)5hZ_iU`}r4 z{HiSZmmi*`KGspD{tF-!netygDs%oRS;ifKTxRO$8VFgY{3El}e*87 zS^ED>mifLvOaFh%LWe`MHOnN{tob+`Qss-e>(8sryu>F7kT~;dTmGUq80sf>z zx$ze*9e!x&IsQvszunO7Q>Op^i*)|crk~S+5BnK1^tArleWw0|nU}5qGthxDRDQPZ z$8;0;AnXY7?BA~QA2bEZ(0Sb8e}TzQ7`io?{w?2!Z9j%?R`=cudCm*GKTvYhB0HqO zqagnrw_|Ckqay%m#*`usBh8WK#l_3&LZR~IHLK1Ji`{>(4GO zuWoLMEN&nZ^YgWt1^^NN|Zc!jy(Qr*&!h=0_g z6^-l4A}uY|>mrMbIb5Bubk6GPmdNbl#kG-|^_Mi6Y8SNC)vt*(&%dy-`LgQf*`cf7 zVuJ-2N3L1b+FaML?t-~B?d`?IDJ_fVhMJoj8mD1XS66oNs&KIn&CrEcUmfy|=`UN7 z-l^B$h1IRq^>1&AX}#@>8oFa2RZ@B?!mZafMZ$FrYa3Z> zRqFyQ$_;f5z!UP0eyhVZ)%Eq^wuVT1Q>3OfvWC1D#4LHTB9L`P3&LgL4Q;I$BeY=y zNVq}z%r=j#-OLZK3fD9?T^lN|v7Ib``^Xf}1vWKY`QiFV!@Aa5jT04EdwaMk(%jP6 zP+ecwdTsb>=$9)lK7b+SwA5V}(X#gT@mr!b52YjQRJYWIS6|y2X(?ZR^#+nHjjgl6 z;+DEhoIMb{i_ZpW>Kh>d;Wf}IdIkqD|B?;W?Lh0mX|Q-USK5Y^%V8i6Oje3#hZogj zD&g8X=ydj1s;+@h2u;@1m(w_a7pq$5X;m;Uyh`NTtfAE~cMVuctu?i* zxGYmeEIzUi?HjK#q8N@eH#as@$%L$$}1fGcqg9uuC z!jN*pSk}X4 zj?_}2G&R=O)m&RV2h(hbMAn#WsKEo&%TQDh4ZA=NuoEm%O$ORPqXVa{8ZZCt(uyW1 zjV%YD2Id)yK};L2vFo!rBK#Cqzip!?I=2OKYmLzXb~9byU2@>cGxJ*V>#N4L)^Ow6 zaC3FTx`@_Skn9Ckvg;ey!F%y3v+Q0=R_S(EVL7$o0dxTO2kSTjh1Ga%=)k4&68KdI zh5%*G$5rwAXx3AmzD)jJ&86`6=7u$4jsBP&f&sH@`|XPV9KSv@CQBS4y zxUQuMuD4Mi2etsyot{;V^(`UUG0L}k5dh|CIpVig`t=*MOV8bKO-)!f!^O<6(fKWn zHR~g-f!fx_hI;w8C4l{GYq+7cu?f|%A#MmjJ|QH54UrAd0)cCqVM4DCtj4C6Sv4D) z1Tl=epmE=jgAMm8df3%;MtIWJyYLc5z^FW#ys^mW7MYJUgWX-FPLo zd(-Fa+5W1CB+S5h-Aw$8AclNL&_zx`X9NzF(>j(SU}5TM7zi8|I2^e%)PD2xZgDdFtr@kG1T7xe~(( z1PU;2`A4q>TJH)xggky&=M7AgakT>cwH;T7$k!o($K3K6fe)JYMJT`H^It-w=&-<( zCQsL&>8l?MoB;yZI9>G=BUeWTeqrj@O8SVv3nqP)qz@1L&7^N)R#|M*pK7OCr&eGKjh2L_vPDIHH!;;`31iEg}(d~efdSc z{15x`OMLks@#UBL@=x;RJHGsrefj0S{EzzbD}DK=`0}fK`8KxA;#yz+EMNU5U;e4S z{B~ddX}3FZ0jF!Ib;jOtr*l{E36~6e=l%{wdry7=|K^@hif>HUvOGDl7oU@V&2$da zOg9{gU3!G`GyjUP=FeX>OI19g_YI)7&B_n)7;`FC*MTI$*Y;>);2jI=_{D#mNq#q>6J`#E1MjW^hHc_3!5C2^aV_F>zeGB z^g^b&Wli=M#N~XC5OAbl;BBr_ZN)Af;0;aj;O7=^7 zA=BJyC3_`3n`v&bk{yyhm1%CRl1-BSFw@*pC95QT9MjxNCCerKZl<|~N|s9caHhF+ zN)}0a2Gb15B?~0|dKuCT#U=A3{a2>BrAh`Q{U@fml}b+jL-@~hDbo{3S2)o>IFBzd zyDR50XOcyMfU~{KetY=S=G(G(k*T-r;W_4;S`Q*$`NZ1X6K`&c?ajtwK_k<;Z zK=EIeMW6Y!6aAgj`NCxRrOQT#3jSOga7KrR{zNd^I~O|Xn4^~G1YVK)Ppm!Db|vX} z2?lb`<-e`(i3?^>bB8_7jJ*?Ud!JbAZ%`U|OzLm?PXWVk&UB)a&agV)$r*8;d9(Fs zw}(Sb59#eY&i(BQD8sg6Wg<6VA|nSsjhq}apY-~FzAbfpq35RE9l$iY@eL>1HtEFp zcb@t%2<7x3ucvKtJN2!q0{vriKZD+pKj1_+c1J@uN838oH7G^aSgftXiB)u~%ORdg zWh}$!M@eKC``T^1^(6DBp=s+MMX3yd<@qAf}>aFF3If>Wr${L>Yep7__1* zpFpolJq3x*K=0_rsll9+a&jLUf+VKOkC{&a<}szY0Z5KSH%>UwR}~d0y2kerRSvFT zumXQ4(w=Q&p(*6|n*K`t{i&sFD8velE8d6(j}>~yfMe|V6iw!F3_PYTLS@S}rLJdD z=dM!2u!(5d^B|;Bd^n4EsplXh-khe5AFbFOtJod=B}eOg3F6)c;%ywyy>+cj45W-5 z`J*5f@ZR5|yD7CBn$dZ@#IEgVNs_9A$P2$%2XZr}UVz0%0_c|{X?&yrbW?vuLGmz@ zquvEapm?ZzxZ}5={;-~ihi&c&ffRX)f+`&8MYO^fkSH{vz5*+SFA2?NQ$J7WON7rM zA`pj<2n<0e@z=R4&#XtOziGFy4s423S4Bsio-(zaK7kY6k&iX(M4w&}>(bx0(oI+q z9dV*PL3~rMzlQSI4*7l_zel_1I0%d4SFyVh6f;XbJtf6cz*uuIwu7Ci%drT+wLy$F zDYNNP0IKNqy?Y>maL-N%gH#FSdpCfVo2u>yZkhc0{bRJ|L>gcF1(j`K(J_ zX`@aR<+X!jsN1w6>r?mY%qnIc24@s(5Tf-MY5V&P$lJ7wV&z+z$yp$bC@QW~PoJ7q z8&_viuptQQ7kh{_IP%7;kd>7w&1n0*PUtzhDKk%XH7U@easIV@hmL+(X9~_0#GmTn zQS|REIHRAY>nm?P#o*efub55WfP#G5l>i!vbcJX&3YhFQKkn~t43=OC=94ubppn*ZGc4GhRT+xRfY^> z(Xw42ew>1Lr>+lw7L@P{c&Xq204~5O)&`xRd9QN2&@ud%=rB=Ca+8diPpVtBuaU44 z09yDL1E&(r5h;i+3Z@A6&$IYzd6vIwJwgcwK(8fi=A+j^h(G{WO|N5h!llciJ@-^4|f1I3u9B}k+D-bh+bGyq1LDx)pIneC!{5o zT4Ypxk42>M58)hn{-H;oKj)*uG#->XpHH!f_L+l?Jdw2a$(yg($Cw$y-Cv}YPou|wt$ez@ zar=Wk%~P-HWe*?Q;#(y1_3IOCIYeW~HVTpe?p7pJ*?+<~#wxhXAR6z}ME9oe&QH_N z?T>QCwOOImPxROzVTyj_CIdK7k7My|oZ2&N_nz<8t5&IR(2pZ0xTslA0z`bIE@`m}+PC*~*`C_g3$FEAQPl9sZ z6+`L>_+IY5n_)jpPC4gKS$lDG<@BzYlv6#FzDE&DfQkE^Tx zB;%vY(4e}MbxmZ)!O2BX2DMpYs6 zLweR2_Ixb-986-21Ywxs3D%dugtvUHzIJH|TPpOp0jeU!pYiA|^dQYeDJW+aLKRdN zP#=)~4M0GnljZnCR$tHScXmTX_jo;XO8e5VK<9F^Zki|ZYZ`3KT z5-oLybjr>$w72wsEB^Uux+4h0bpB;)&;Cb;usLBQIm7-4_@}NfBTvw!>JhY}D9NgV zM;uVU`h!_Z!xLnWn)M>mLMJP~>HT$XRFD>9NWlKKNp%u>N^)-whDi>_Q0h!(z!$XL zx%@M_rEPNaA!t6;eMlNVDPLL!sQ)`RP6V{?DN8&Wno1VPP!v_8SgDubjep>eG8qUU z^c7-|7&%48jQ-K|A*z)BQG`jg5Qmi7tS6zI1*5rlc!4@_+Lgb~-K8#lDgP3=OsD|% zX&86h>WhSGV8;j#njBiyA?P1(`_qHL?0POWp1P8tF3fQNb20el$#}$<{sw{>W?fFV z&;LF4SJTJ!H!2KE#g~|%lBO~ebs>V{31JF--S(jI4_^Q&(kff|nzqhv2&Tz{#%DA% ziJ4Q+PdRD&WDfG@>~#%2&nHDzNN;L`F%f$*Aa%_OzP|BuAEQ7{=00{5tj8TYJAQ{a z?M^}FW)AJyPk(${*1Ip>jdU9Rntx&w_3}_HS^;9+d&IN!=-geNBL89wv||FFW?YT3 zEuE8CXdKu=*hkghm=~)UccL?#82(4@@E;F$aweVV1$huTaci8|yQPh>TkwydXXDy_ zGk6_ifR&lUYNnVvSVg^ME6=2#vfCHUFL!+j@wuS6zGxPPCk_^zaRII-60g4ZJ#>6yI;SV=j50hnUDF6s()dcoAZ>7JTh5pB7Jdq^62$X|3u;w z22ZN_L$xe}iQfE#_gUk2n%F-3KKv$_J9*_3Wc!r2g_B*jX^(Zp6XbB(_zPEJT^R?hmR~t zYLt$PfCT0@A6{nAi6T}a-sUw>QlJxzM`WkKB z^(Xz4KTBzMe9g1T5A2~{V-?s&is+HzW=l@q%+=UXt@*lJV(f>-A2OjHVFX~>emO;c zppuR3kZ#m~Z`b}}FA;rK75&BvvWJwle<|zje~tY*=zpR8x{fAgc;X@5bxc&N#Sb%-luRNdq;`dDU%XyX)^x3aF(W|T_bq3~|)qWMR5LMlEmr(zL zEZ2UO|9(IAD=gT1_Nx^3Ybg&jpy&Tzu~(nf(Sbbweqfq^_1|N!I(}&dcR%)O+W6Yn zQa5r#ZZ{V9Q=Zv zs>F5Q-Sv;9M;c=M1Boa2{hI@6Kb;=`3-AFwvc=>4@lfr*lXjr3yT730hUnB$6i8BD zHtjnV?gP;57jZH9;eRO(|t1zoHP@aCImAc?pZbTf2>q` zI8BR>SbZ)5I^MyWP>jF0k!&8(Br}B=F7UYSQs2lg=PR^?qfHyoIa1^-cs18M?R6Vi z`j)%$?)pQF8Q`!R^Qh%WJjLO$_Fc3IJrxNCAsC6Ri0g9RXh19wb>iw);*3Asz(Kg_ zVSee{Rc?+qTkVv!c*vv=QYIC zY@CX=z2bQ!&r+FaHMc`9V@LG`?rz*SiocAbd&mnIznw0j`XMIg$;jWI#8jhl4O}wg z|J2pZZSPxjF|T$@aSX%8b}*^#B9Wq9{+r$j^$;?PfBN|080ax-Uv)3ee{dUm5-p-R zxRkjl_wJ!Z9g}-ULiYt0?HRInV?_D#QIR&Ftg#yn4Wa|s#n1rXiJhAl8gQZ$xkm>c zmKn)S_3fw~co-Hi5Go#0@5flu7MUx7JC3SP3r1 z^$T6L^IFBC_(Awr?F5pYQ=rTp!;3mz-aFED4U8&?<6a!PS9jT`D(#>kN(VAQoUV3M z*7T9D=_KmjPS?yO(Vh`YA{m8L>Q*n4N6{|cc9q%0&#`1+mbyt7^Fq56qfH;kz_j`$ zZly`4{If@Qno5aoHH<;mj&@Z7)58O?&?{@B!@1jDQ>QXJ+I0o8N4q}7IpZ_ZRmE>3 zUDX<_)}Tg%H5x=TSgXN04Qe&0)8I22tkXtC|0YwefZ2ide|M>(=p91Bd7Xtb-uc01Ztgs+B0{F=t19i_S*q{YoF-x6lu`|5lOsv$(ZDBLY zyD_>ev5$3-3Xh{_h$xTcDWHd|HYDkS?ZU>J=)c4i_wf|fdtG_r&#O^38ZTyu7(6M zN-jp{18P{jKI56>E<#RpTvIv%bdvY^voooJp(jvlQ%bGOE9FjBtW2$#jZN!W_w>}d z+2(UT>!K=zTnvOd?`aYRF2Ko{fM-uP?JmHStqXwXZyXSBH1u=*@L3mAqQu~YK>t?! zT?J!aD6P*hf# zOe}uW{L_KXULtPL46e*oW8pQOvI782fOU}$_M-w|c26aSa`GjSr$(+Q= z{1yGXwXkNS>95gcyp|=S>Nb#HP#ng!Lug7$g44M(xS|J_A)@k3niOvdpkPH5*EQwY zG(1E#g>}bk4IguDSFB6tiKfSts@PYwr<|atr&7RHN%6|PxDM*mBtT3aT2rfmmz^VP zs}n)l|#X8`s5?6-b0@HK0NjwjqI8e--8LH-VZSNV0s*KQX`|(2la4BK zC>Q~eE$hDG^|D{|`Ro4pvda&pib$Zxn#{_=E-MenVOKui_`w)e$YSGfGCw-M7K8M7 zl-~bh&(=1nI(0qx-Tn>D^mxi=9|KMHvA+i~^z&Y%+nJAhm2buX)8kqDjR$0iKY$GB z@rMFTodUuTxy%P?Q07%dO99bPH*-A-wMJyWtK~pA!$pEe0bWo;aD1ojzn1I4QuZV1 z{NbJ#@j!Kg3<9R_C;m8{-+6*RaNoy%igTM(vLD2R7MqC~{-)vQ^%vv*8TD7W^Vm0k zW2WDhebmp4zsB!)Gv0gl(cZT|#LZ@Th);`@FP`AP@8+w&5Bf0nfaj6PgK6^VlMfT4 zAio;l@PxwPo3a_V=a<>|eU`8N?>X6gT}nYd7Zdga%l*+ zT2gOE>hab_r{GzA zwzncJy*+$SLyhjxtD>(qhhFuD#ELhXYf>Eo|KDeyWPPH4K3ki+WyrK4!R-9XU3rxF z6j;;4gB`{L$5dflnO>Yuu8Xn9Iw^yT*|FW#$C@8L{hqsRo(iBGL)&AURQg-qrG(>Ckx7R7>A3TrMB0OQ}Lhpy`wG5HZ)aP%pe6_&LrwT4dQkvLyS)RWw5#KDuUQV08 z=zrah--zv2|A6z9E>Cg$mS=s;L<@<(D6SG(dGqye^^;NsWWO7S$I;GNIs?-!GBR)5 zr^+h|v)ZG(*hltq@vEq6M%9Tj8qZ?f`)%meo14dPzkT3(N$=mThivN&<>)wbfBUnq z2U0HhWbpUE6}6uD^9DH}sE_HV^7nYUqSNB(e*U3_J)aa!Y!2a~qkBId)SXRl@A2=34A(+r$dM_2-!o8Hbeu|1l zXLSx2#t+HKVOUtUSlrF2BWkTSi%F;sOQZ@Chs|awi;u*c!k`=bwIe?ilvu;0+Ghc&o zO^=eRzNJTEEJ5<)w^>A(rRM130$Yr2BxtJNppmc3@@-lCsF%$gn5ACByfMW*TTE8u zZfl>RdVxdkHYi^GZjhICH$k_a##g|T zXq2e|D8AjO91YzgB#njcaifu*w|4>o4b5U~H1GXz(*65B68 z4Og~)@qlTIp($7i^)oOYdZ)}<$+9x9dl4Ep-{x|R<6#`D)p=;Efa<6 zD~SA?lAtQX<7ePKX=HfM&Ar^%6K*q=3E6{54;~@7wFJSZh+qsSGFnNfPs_lPE~J_I zkc=(qAk$CLL*cG10zCZsYzSRjegpQQ(>{b4JBJFR8}DGtpV!DN`Zy)byj%Sq88MW_ z5Ic+RRCj2KK-c443AuMmfErTciN%*V0>$FESAauCiI4!KUE4S(TZSf9B7jtfdi-A) zeS|>7kk|>5U>UaCXR(F{zcb$V^(4n5BmPRWPo!#XzZF9YMk&0_Jq?ML3cyW=gf{ ztz4h_EE{dwHG~2qG4W{GgPCOHx8K9Cq?yPFYsmoL0aD4?(r*Z(3>AtC1(q&aZN@6} z7os2t)+S%){*kWpX0-PVw8SGe?Zz*E_~d0ux{b;Ul_)HCRPg<%4*A|hrboN{ zCv4;Dlc*pB9g3Dc3S`FBGHH@ByN@C;3Sz-E?2;p(LonOiZDY*JedzK-a-MN&UW4$l z%vtbeZl_HDXo-Dt=1xxZ$<9CJM0@T*h3FO@6Xo8#0Qd@ZVqMJcR0l=7zA7bmfcPmT z2S>a5q~r@TQS!BeT(UAg0|zK~+mt%{<-L0!XQT>S*?(1kI9f>9j|u&&n7-|emby<; zXYfrmof`)|>JEasSm>m#9O1kd-FejQ-F~}ET^6HOH-I{d6pihW@9&0qBEJLqn&~|o zd(}UY>8Eb5`ZKGg%1%&ZN1v-cPLA^PnAn-^_ZqYjvX*84D2|qZeFsS2p-vDsOsV;k z5aDQ70~Vf^tqYM6?c(}%dUi0|>Del&?ax^zB+SVFB&+}Mhnqd98Z9Xe)w&*q&VPT@PplS4V-H3F8UaJCU)#tY2J2>34ReJ8( z!n*1Z5^)i}C6DGt0drMY7ER-#l1>I>}y&2Vd){RhKR~hb3PZtSkbs2*Qj4cC}pN zDcq8b&maJ3D&(^Q-;YOjk}#7R2g$z)cPWezVf%xbJgXXssSt-1Rk9dM_h5<3j)Yn2G+i99#h4Wb0%e({uE%)NO#ay;m|0iy6pa^=P;&-+>(#Bs;EcK03 zOAwHQTE|r+zBH?B%7K}J3MdrOk+VuQ2Wt#mR4R5DzQ|MfrhG&>D3j?qJ)t=HWezs^ z18XCpc+TdsSG&s|&fO-Ljwt5p5ZW0`E3kGn^bk9SF~*CyFu;Jihyz4J{gT+A6L{(3 zM%bFRKJ__dxZzHRl%W&!kgnE?j__9+%-vS@5LQCY=-TM(YoiqpNu}>gCB5&0kS5pCg^1r%5`K zCFg^#wU82REfnpkJDHFSq0empsC%K;2SE}*&*2g~upZqU@cv3yrs7E6#eXzvatbZS z{NvFb2eBs!5=>Fr4x!%DcL;#2EUq77Sw?rpbj{dS$-DhqY~|f5Llap<+kgl1C(xB0 zjNg$}j&X$eI)s5W{D`hgA-8q;9d#YlefUr=CaMCqgcf9`dQs14+}DQR(Wa8MI>nm7 zoVE!MBX#2USX_E^RAHN*=a@U5$^SYkiUOpRV1yEm zuo;;Y1@$tq+_Z~J3CoQ+|G^x*2S9xZb$szR6Av0$dPrbo>7l6Ytx0>IbuHc-jcQnh zxMjX^3eva-X@wKNC;KrTUdgjIx@bmvxXX+GW^cdQYk$yNYj3Wwu8k3wGW8e_T5`9I ztD%38_^Brx2LGnC@g2Mn7x)i|%$4=4E+Kyzv)8;DliqZ%kH(UFnR5AoIy zc!FgLH$zCNz7?zl%sLbZ)hx?8FK;5&AxUqQJFkI)U3<`~B6Qy=+* zk8|KBa|dD=^Hg-wEX^0Yd)xOAOZ?zlnVN#+(Utl6WLskMvr^ z{KZu+I`gxCiF;mOfH`^mxv%^!@u#2F_RF91)flLlkv-n{c~<(s&l&2@Yz+)Q)8*;a zO9bB;ndAx9%gWOvt7XDhBtIoy@8V<5@YFqa4Qe4HOK_*)6;%%h$s_4>`9yrDK+V_d z62du6e%12Btnn1-bvu3!I`+==60rY^2!+RBwYgk9VzNKCEhw?fYLA~FvR{7q%nl-1c)LFItx}&8ubZ#F5WQ~sRp73V*p0!I2A@o6;IEGpIDKD5T`qM3 zAjKrMKt=iGpS+9urB^^!;Uy9yNM{&-Yf@IEq|ymNvu8K~_9lOLjp z@v*9VbQA=#hT3vf0GVMnv4dx@7ry%l@}?nD?0qq{5=#*bWOWcja1IX&Q69#1_g!%F4>{ZpI3LMIY|0G1?7Wd)BDlyPQm(_tvhT^dBuxe|DHTV z(Ui-c8d0fp|9!6~xr|z>N4`V_&FckDK7<4vQzpt1YBim3KHE!gD3p*NmMZeQ%HDe2 zhy3pMJ{2^$5pJ(P-+AxeLxBhDVB zH}Uu@I)ruts_J$vOWfF`$eYl6pYwC&P3(<*pPm1GKrQIoRg7w@JCbZB%nj%Xb+;C< zNp;WHDD$p=t>#iG^R%Nt_XsK#7I3bM zpXW?x=I3W!JpAR;$8+yBQG*`X`>o2qFn!S-ApbpiS}^RoD_ zO&}%Y9~w{mIvnS58!k6w7*N3ZxeOydJnHeaj?i{^b0`R&fJPZa`vG;kK9fWtHV?6i z0Y1>6@eB1E*^!I$O(viqac^!W-q%ap1aF2fy3=pL?^8K8T%=z8JWMPv(1@_Hl{yHt z^y^-9vI$v6=iZ@C!agNU{vaF>5dQ4dvl1N+3j|jc>C3q`RMl*QeG*0(r@Z~usu$jPfB~VVOvO=v}GTp1=4s?iLrN}gkl&dMQI`%x(RiQPSANvsB3jX(4)J* z!0pVVPoD6bvaS7vQT2qbl|{Z&_%rSOkH_k^up`=^5P8qAKe6(~=~Iqp{Z((gL0Wkw zvT>Lx&SjK<3E5`Tb$v>meH*x}-x14V6#W)^@-Z!j-jWo0rH^md-@f*<+V{bzBx&0H zZnpQAbI&eSjQpmLm%d*}*}q;O?BPDu?q7w85Cpt=euot5Wk%jz=~nh_YCozgO{k}- zmn49K1Ie2tw@phXn(8zpF3DQ5S}p(gg|D~A0FSsG02lZ|o{yM8DfGnbXKt?^@w4@h z`z2xyz;fA(P|zzT;|mcaijKrlBq2}SnW3R918D07%UAI5C|ZH|=1z65o+*fiTMKyO zi)bd0gqjH|;M)fYA%;vCWk^-%j4@z~Hi%9>__~Ns938|#vO$3{L_Lid>77r9`WRF& z8=zqar}?}!Du{{?0?_~p6F7;&Oyq!xqYrSfSP|xg?$IYB%P;&GFBrs?>yN=2; zgleuHRE}qG;I9YeSq=vs5Ms*xQ#)v>6yf)co**-L#yk)$y9cuwP~YiBE8ZQ!aSsn% za=Z9GkLmOSG9&6=(6u(R75+{B!#sq+xdJ2% zKA?g?RXZL%N3x%RFVgq88E6NrJuZ-iLS4jHQ0R9jD;XM_`1lN=zl{<4+~G8P3Lj44 zipgI6#vVM?2+fLXbLu{Jz%6SJ^v0i<5XgrwyloN-P+>BYpf<*bJw9G8vVkyI zSonb#9PT>N3lVVBhb|WXs;=ir&2&cih8 zl-hC&OK_z0J*gt~ht$`ZpbfwUQi-)RP_4vpOf|Cz$U-EjR;6-WHA_p#3Zl|C={TTU zI;dU{X2TD~Tk&r}Y!KaGw5OO0*-y&(mqf>S3eF3cI>>A1=h25WzE9e-3(yPkRq>Bv zNJAUX8gYi-gz$iqB$2V_Y)_hk1ym)ZEyN1EeO|hn7XQWceEbmq4C7uxVv0=!A1}~} zaS#+7qixYe457iMDoo^05^wohW zOFAEuQ_`{Z{OsY~zX`c<6q*{o}>EtoBdve2ex^ zhAF|6DC3+#cXs=y2hC#tgqUyH{%r#OZ`uB#>x}lV^R3yx{}fuK+dt&$PO%UnbbkAX zc}kI*$r0YF{nNvw+rPhX@V8_Cq?-eJ*S3Ipl>eye8gazfrhc;j>e8LKyQ1`Jz zEJ82m7i^W~dBumN43A8VLlS-VL(@m%G#q7~nxv%C#%o>e*JnQcPQ9n=m*0@J{yynZ z%XXy4OE}7yPLFGWhBve0^<2~F@e6whBJ{XZBjTgSkA&nI70r zzZ0g4rLirnq`DD*(F~A{zvImJzzuabzx#RMk3XNClZQ?U9Y-Y|ucqO1v7A zqz~z)q{kC&k7L)H9&>Gv4>5;&;h*T*uaGkMmym(Z5eK!wc+V&MIXOg!K(BRIr%l%n z(jJUSZT||}r?qwEN#94E#@`+oULJkQ+i1Wbxw`n>-^f%Z)lWrch@rl~_&Z6<8}po= z)?VJ|Kwf zFvqqstxD}M(&HZVXzoCrr4boaZ=!P%f-zoWy$imSo6^N^h3Ikl0EM9$W<`4 z`rj?xN99S0uVCJIg&0>L@FXEwRYDf?-Kum4ug!ix(n7&uee+u zm5Zf!>(R6ykeOg;ZI=-n6jn zDXm4uIbOyHGBCvwjAF(wO&y;lYFX;|vVoCTTsb-tp{5XahR85NVY80W2o^BQybG;I ze#Ty%X7FODI=Nn^Di^cWO5G%1_d=jvVnhd5*?n1W=&U^HSUAE`b?@_rd4@*1%M)~$ za!6b83D;<-n9S=ccKgdg(;yemLGc&o7~8lQHRZm(EJMl0u2{W_ zf#rmR*|>M{s5<#38BwVZ;ESh_-TQP+TK8fzrOyx)P{Vh|H2TDTaYES3j{~PZeD761 zgK6UAkcm0Kav?f)JM!F>+#qraZ}7{!l?K(s8t2LlHK2Hh&KzK7q0a1c9@~jk#1B|I zh&!7D>TW$syc<7qrgwJZ<}IC*&>g_2;y(2WG?$B+BcX3|AY1Znb-r{Qn%rE$&2p1( zzg?cH{3!<&lTK_lHrjC~wh|)20lD8p@FhyzpH&~1Wx{9nDnJI|91y@Qyp?Ee?{*2u77(7sEMYCHAxr?-}TS8s{5%D;8r7lTs^Aw1ID4T+NtVK zM4{f6XYq$&AJc4O?Mc#x$Kp2L!8-W!-RC=);&1j3{jA}T-)xBw~zaSUnTBd@I&LDQa|nf;QEvX{`&6zLd};t=$AeO;#;Rk z8k?m5>ixkizfa}TGfRBND~E9^$bSEjJbMfD{>XoY-e~;x=$+Ca3%#X|kKU60Z=m;~ z+3suR$$Ardkz`==sH&!5@|?AEs7SN^P-k>0e;gVs3cuRP^1tQg9sGahn0oe=`@$1n z`_a-OR5ez?Q?CB?=#H;G>DKhhEx-5iewDxF9*yUvFacl`dIc%LmBacKjH}PR@yz+H zShFQ2KIprDX3uw1%7G7h_3+CSFHHMA3#=IOGa>r?DjFLQmbwrdG83EaAhzPa%Y0Mf z7pRBh{yaS6FpKS^EpagViJL;`aPAKz`pY!$2O=xm{Xj9dzIHmMtk4H=995UT0UW83 zs8rW6;R`8Kv6}lhMSk*n{y?e7lRZCh?-THD$e8M8oI=|H7>g0rCuz=!52@^Qa`4*% z`i+WDxuFE_?THEfvwvf%SljG`io=J^czzI7NQYFI*)G#iO zBq?*~!o-Y>KlFk+M!Z409;VA9hxO!7+ZPUqjw>jGv~~QB`x_XAziMt|9l-~Ax7p@k z2Y%5UCoJ7O*p|EQ9zXQ&5u-g+o&-E_4gnOS@F{?I9Z?ovfW_iYjH#P-W&-u`M;zn? zWK4Zm7mOo>JB};4`lyGV5zbFuLYer1ls6@h_IjKwo$lX?jG*1I(19AUQFR)>PxE&R zQsiImkNi?d!g<6l3ZfXS=kW@_PPIpO;++o_X{KR`)e4q^WhC)JKd9j5tZYwlTZ2dg(w<$=Z+cw#2NT*rkJx}Hjb*$ev zHH|);pOzP{p*sb6A^{P75{ZWot;-$7BVQ7#8qvQu1CCp1ozSx}()zqwcQqA22O9eH zC;O*}x{KE@Uupb7U5SZSD0O@tl#@(;dVQG>l@*qr#RcY((ra+pt)9b1%p23_XZFv( zEdEaV`myJG`u@0)awuhqGuXvKiO*oKWc!;&Z%b=go1w|#AA_{7Qnto3(?{0(KIvCF zT|Ud8503^JA>Z%)E5ueyCUo79`KfdJ#zuLGf-9;7^dp#(pPaus~gKiEzYmtYgNwc?kf(qBiKQijW z{goG_OvUIr#ryMiOsp{nzL6pmMU3h3NFdBLT z|Joni0iLoxVU`byAW|9Pdrqyg%c4(?NAq-g?av?BpZ?fi`80nTJb4d^>$3rvN|U24 zJvPzDuvGkL*C?!nS7`lX>N4`y+Pbv+eL6k`+GX_5uqd8ZaD}j@=^Mi(TdEV|NDQil zIx!^6h3C@n&*m{NyMMMn`fb`hE*;QEfICB73cuO7G)VWBbtR+7KKLHA<9}YpXVkn6e~d+yxn)~*Sud7CFYJVNdnN2GI6znYo|o(KW;r-C-Rh61 zJ`%c>VWe)vU~W}^(Bz?mopdm^TvA*VC6hT8#wl}2cbIr$5`1^xoT%>x_H0G`aj)w0 zI-~xjx4vl?Ic)BOP1U&P;UAOw8`AbO_(R+0gu(j z`0mQGzGcxNm4}{-_9W&1Dw4x8tGbA0W#t{+m@rJxPc~YtF;+T>EqmBc{{ze-X;{`sW5k zo|o3MO{j%zz@4zU_$q04(*-;3cNp||?(_cOl~KvKunOx84!})<_tm+xK%&QZ^@8*# zcXw!u87!99x)qSB`uWz6=i~c0x%w2S*Uejo74bcx!5sJJF5+MV8sg;SNMLJtfYh5j zI{~F_PD1UT68iVju^8lcy!+3T%1#PHwsos{`nFJqDdGDCLMq9JWZcDx(FW9QpJs2| zaWU#GOF(VD-SVvo*d}j9BV9%JuMYPx1a0)=Absk+UM^R(laH&fc;^8iyXU6k0^-D- zjD4kmi;6mh1No(4K;45ZEe$=bTvJOvLxCu@^043M6&@to+ST@LAWZvo{q6TJ{;V73 zrTTZ}>5JF6YEzgVB#W{~4!4b|=Ux*AO@QJ<>fdz&Dj!zo8J&O(=~EF1MV!k{{53iJ z@Zv9!E}ycHy+_3)eFJrx@B_SXpQpJ0Qy6jm#>sNE_ey-ru)knm@w4@3reEMw;vtv| z*tC4N^zjzwZ|5FYzt@7vc@L^TGQo=ikWyn`6Y3eAImFD9Wfo8)`rLm=+h-wye>r;m zcIn~z0N#GL(Brk;?~;DR4e=ef(63KC`U-8Sl%+rOd!D1}B#j{WIwHSUqF0iCtN4N% zTxagD>`R_9?dSaaMRz`kafRhV7B!CjaoRNhF-tsM`@d*r{2z&*(D}dt;&M&|s%I4) z2N(%X=yI7Hv>7A4+9?`SA2ty>0DGyv z+vsA#tyohYOVqt^R&}qY@}%1Nl1u^99#P*$P{DMAMnncSc@b-768qZD#Vwp{8>+9pT-}NSL&B6@s)IWPEY&gm(Gko zUigTJ59kFIr7tU~II{K`FSPh%kFS)w^5l-kHOuqcG1U$c)WrWds4pxvLFR<|-sM6h z#2ZE->U_qr7&ISJ?mIix=1+jUI0Eq+symrQM%v%Rz=m1aeAE@zDwRE|z7Mz0Tc6gk zbL01yIncCL9~DianA1CAok)iBkM?T}k4g(#rt`FC!L)I{B z3C|p!Y;x;6$oFbRnZ!ipQFhJ?onqPyry{&VEr%cjHN&P`g*0H(h?*yWb@RlP4uA47sHt{H%s2oZO!lyn1SBOB=7vp5Q7bf_oTUqaId=^Q0TI+?kBoo=9nuyZl4Ftu zl@&@P=W0bds4BaJ(4Y;Fina$aDG<1z!s< zSLs5q9;iWx+%r3z{W0$LURw|YkGQ{J+6$H!r1f9r$}4?>`D6f&wzUQaO-AtYTh58n zi2GaD=+5k&OR}7DjD7vxD8cW1YquD5gOCirh}VGe#sS}qI;diovLm?7xFv~t1L`>G z**>!2t!Cb$e6w39nNVGqrS1>*>ko=Of9w8WfjfWEH{b{3ftmfUSum}b0iS2Z%tqC< zoRJJ={WG7eo zcx)WLKHEYZ#?>SAM^BTe=eRR#*g2<6xz8C*s54f|te}+q=Li0HU^?zZ7*5C|4cs#R7wlI92j7r&D;wplc7QwU5JJx{;_Abd+q@QO?w9pDc8sGv1U%yylzKsp!m*YG zC$9z=QHN3>^b^J(;gqy}$k(&O!()^Vl99X}Rlg!7^=V2PKgp-` z@2iNl>sJp@)FFY#J}8W4++zY_pK!K6Vfpr`4&}i;6O~d;yojf~7LxmdKDF$Nc;fR} zG=Pr9<-_f=ifJwRWHq90%Pt}7apk@IVj0H7e|Y8nJQRt=G;ezxQ>RPi5ReTzGervw zpd-jVzvGY3MsC{GA!PBzSBfAnpdk?R{5fcQZr~D%_f?UP5Cq;Aco>?Fg!bAWa$^f< zvmc=fa^aPP#y5xDpFvA;9zB1?>bBU@d?%WL{$4qdUYb9RKUwVw4}Gwj=vmO5JgZei z*|_?Vgh0!%xQ4Mbo>p5Vd=9!$7ep^A1dY(^{K{{12T-hRYP}=1!a2kE;qPArX!@%^k7!(VK6fGc)zf*}GpP@>&FWO?iQsiI+Bc>s|EG zfC%f2IC20-CXg6VKQO{-ey_zRtiQ9unyWqb?84fwzS^5AtR)Z!Ob~PJ7h(SD3K9UJ z%x^81u}vtG!uoj>r3&kfQdw;MfHQMZP@cxt7hBWzw_uvFhn+X(V?g|_LzkQuU(E68 zjK$i)LY)^#~#>nZg;qQM0aV^kJzADo33o%1DxlFZY|JZE%~s0vI0lcyrg zFuqmiBa17?=E9aE+vTWW_*_xc6cmmGd$jZ2jACo zC%pCI;-B$8o3YoDnr-rnT;B@W|s`rF|@$f%qwjN*n9OPm} z^z{|dJxii5E!z9u=bg?ca-0RfY5NnV6a3_ri$1mJ%0-`E6vmXp{Ez;6ju(r8zLqT9=sO*wU zL*YeBmaGgcZft0cG_;;^>9tLfKx?GE^{l3Pj2Unu_4SPf*EBZQuL-QKZmFvYx3o6b zHLP2>FkBX{X>35Mt){i0p{>5YprNs~;Ogr7x=b~jBh{^uz}o7T)|z#7f=hi}3r0j& z1&s{_pIo@G_{xQW#kG-|^#yCI>*^zG78d9l;g-gl_2Gi^&Mhb^2=IHPwQyEi&6Y?j zOB$P63;m5wFIaWSitwsS7B3H7%J1Qop^88TwAD?as}~(xXN*tA%3^i*wVPIa1PTR^CuWFswS_{^# zDJ~ALY6S`xcKY~!QsVAm#vC4UmadC=Udy!+6UtYE$Vw_V>KY=g;fB`6rou%RhL>F&x^y1c zIgJjQ9lmTzuFIdad~hky5V@v+BSvak>lzyt7JM>I$ZF~vTOz{tu;r3hy+BIWq%|Sw z!u62`!?dPIq}f#TjTE@1xvn*GweI=!g2uMi@YRu;mNVB>w^kR<@?}s`3$;99U@lko zy{@&k;4~}6wHPqcJS(8#8RvlsEtrf*gPXZnH(nua3uP{55v;}H46lx?t7`}wRWU1Y z%IdbY;WJmF<4ab5=3~=qoL4yOl!CH0XqD9wsDOroiz`;F2&8m!#(66n>w&sPBbAxb z`;xkrn(F2?g%<55Fb|r+Ob@&PL0TJ|7cOj$v{16#G?Wl%3>8%qu4_P1E99!kCd?-MHr3a0{tg5Lj3cI6O_?RW~(7pjE?V)lFe&!pOpf z)fkP;{n)t$Bu`m&J4lKpi7Bm(G;1ZNi!UdK-SR-r@iWg^frl9!sQ*HQNC)`+yuEwJ z0s8=(aP&R^Sc`N5@DApmzjtpQp4+J`-MhC0Ft`X8V*m>QgE-Ks1uO(?2Xp|Z0Gj{@ zF2F%0U;=O)Ft~W{-bujx3lT;>2JHa{03E=|GtduU9>(tjECP%JmIEdLt1#XaU$AS(B7Zd@G0agMkz;@=B0WZLIz#+gmAY+^fz##VZQ-Fnl z`HY_dmH^fQI)L4PwSWVFalkP^1*iZ^5K9Z=5U`!GHNZZ=TEGFoZomZK0ATRr zpf_M4;3QxzVBT?{7hn-!I}R_(0s8=(02N>#U~m>*9cMzy#nJ;1u8#VE&1~=hL7&U_M|a zUq>N7VQB`0H**e0rPP=YyhwXFb-G=n2$rAcEC!&KEOV}IN%sy0x~3Z7zeBcRDj)p!3}5+SO_=< zSPQ5Cy8(lzp&ei$U>wi^oC2%`%x^$@z!Ja#z)HX|z-~YVr~refqh2H00}cR|1C9YU z0Zsw-0+!&?(jZ_Z;5cAA;3Qx-U>@v1A7ByS7+^VI0mZMS&SyctVzdXW0?fZ2atBxlI0je(r~vx_%V%Rez$QQi*bA7y5#s=s z0FDFJ0!{+*y-@jQqhG)h!2BD)U%*1Zc0dQP53n6D4mbdq089W*0V=@!IcRqy+5?sV zRsuSJ?SQp_eSqD7`SXAmUN46qciWE18ISP9qxSPR$>$meGH z3|Jg62*-R1un;i+Ch!-q1h5vc9k3U$4{#6=KSjMa!F<3e<^$$~USoj$fX>b65A^5; zECL(=j00~4m;elRp&ei$VE$a-16Tss4Oj^{0N4%~2kZk(0LB5Q026@ux1c>>Az&ru zUklg)H~`pBx&RIVD!>WA;H{v?eAEXl0CWILncj@~0Oo%V{WAYH)GI;zEuaHn$(J!M zU?pGzun(|r0q_CrUx;>J!8m|pfV@^(co*h<4(I|{3pfBc066wl$O&Nn-H;PN2e9O0 zs0UaHI0hJS&@W&u@%b9)4OjwLj&W-N+d2N%F+N}%a0*ZX<^!Mne)I=e30Mi(4%iOZ z2N(xT047-e4YUIs1I!1$3BVG-DZom=;5X3@upO`vcq%{#a0;*+u=ZP6hrm|>wgcwh z1AG9x0poyufC)hU{^As10xDz~HyRFF*${cpmx% zECd_?bO6TyYXKEtH{cZD0AT)oShs*Bfd7}hcY%+js`AIHlMDnH#tiZZirPGcpfGkP znLHGsXC^(9%(Iyc5T2b((lZI<(IlOj4B#4(#kh(_M2zx^$ZAy7sEGL~U{r*tsBs-J zy69#RF|Mdt7u~pjHUICq=iI7W)m5Db1OE2^pZdU@^!J>5?)%(xA9ZU6v;nm60^|d< z1at_r7IX}>6?6`C0JL}n;XzA4CqNrOXF&Tv3u8z>XauzI6Q~E!V$d{bE9fBT0O%;_ z1n4B_9Ox`)@h4GE>!24j0@?tY0PO=!)9+6q-=G7aW1u6TQ=k)|bD(s`Zt;4Q!~G~X z&;if}&N5Pk#F30eg@1lj;P0@?>!{8@wtEdd<^ ztp%L|Z3UeJ9RMw^K{(JV(5g{{2dxF|BOG)HbOdw^bm|MJH_+k-(2nCs7ibuC2s8%T z_eIzr&@s?{&>7HS(5eSf@1V7y)1ZBz)<(#IhC!!5W1usjji6OuLU_;y&|%OK&~ebI zFQeW-i@$<;+k||9mVnlR)`HG~rU`!t^#ah;^IP`!vfQ}M<6ydj^yg>UQHv&2g+WJkj1JH)Y&<-Fs1)2b@dK~eCwt`N9 z4uH;qj(`?#Mmj;OKuac2-k=SjeV{|2L!e`zW1v%@Q=oI8bD+iFLU^R36|@R;2($ro z0<;gb@Y@IvS^_!-S_?Wye9+>pC|}Sj(8BK^9B372A7}&U5NIFh80Y}#6zCM_9Ow*a z@iv5e0^vccKpQ}ZK>I+8zl-t!tpyzi?E{?#9Ranrga190J7_CtEodKTE9d~|0O%Cx z2=TvL_LGHg4Ti#fwqEtHfcAklfDVE7fsTQ;{t)>FodBH!odYet5a~RK@Sr204WJXCeV}uoL!c!; zLU_al`L2gP&=Sxw z&|1(5&{ohX&;ihypCI3$CI5I;QK!-t#e~x%T zTS2FZ4{BWmK4=)U|)n3|csYe1q14PJ<4BT9-l&Gz>Zi8UtPXf0^*Z;@}%63_wATF?>D0niE15zraX zq2JBVpL03V_51nxt)L~K?Vz=w?*<(MJqTJnJ3oKQ7055>d7urTSJ3bOMEXF-Kvz=u zKg`eH584X)Jm?JQF!+W4g?xjSfKG$9f?8K1J)mLG5zrXu7-%DC>+?uA{RSNYodBHx zE%_tr=_*S-$1|})*X^`IeMO;Ht~|1EFmz;55%5#+f7Lnj^RE{fe_6}YvgbiIB(i6K zM(}^%Sx8#}{#aGCaaHl=mmRaeu;04i6>oZ7*%_yiD8+#)w9>DipNEOJtaYo3ZqD0q z>=AkEkrL(;9J(&CRi*IA{6tyI%I9?AHF5Ch|9-^%70`n4u62%%o1kOe$|I0Kl7T6- ziqD;&znA2yOu5@^IZDqA{!f?9&%YAX)^)K;j!G}R=TH3CnEcC_Pw_l}|A~(-X%*C% z@lc*PJrqv@dd47kBL24HxzLFx4L+rJwaMS=@CSuoVe+qa_@m%gA^a+nU&nk(=M~_W zfZvP13wD|5ya+;0I_DtQ54n$;dh+g8iYOn&d1wP`(C1D5HBLIJz@IG*&PN0I7Q(A` zrt5!?lgHM&rPLivE z+#uQ+Tpg=m!jNmV#ZW_AN%&Uix^uq$A7yO{~+)wEN|3->u+K4AFX-7oq zIS9GNa%p$ZnR3mx9F<=h@r^+)D85sKuj2cQsmC2(4dlXW=jS^pU4<7J_F=OtzG=v{ zLM|x2cMD(XDGt_Cvcj@PbLcq;J;Yy2=_xVvIN4YAk%pcL$h{hJc70r`szdPyh3}VM zD!&9pXNB+ApGbev5vU)e&(993_AmSzGyQLM(w_i-2I2ksy{dok=fH<6=;S|- z>WtgtAowK}{`IBuzW{%70sgG;1M`0*Y#-wHOaB>2@JDqas6F#QAPB~oX@Q1)pApFTDf0x4_6aFtue%{ZO0L4EAez{j#mL72$gnw7?JG~4~*5-0qy@Q*h6apqG#wt_!|@ayq+LB_~O8Zt&cW*|2Xxl&V4hZ9fXQ5YY< z56WkW@Pqng?E>Lj7vK*FA5%1^9P(;a0;z09z%QzXFY4lNviTF>$H4ciZwfyne7N+6 zes)ZVUx)(kNBHwh{(deWD(43fei-~T{w}!5DCayfUe5TLfSwu11=)|Z@Po>6Z~^|P z@PqpAB=}Q^KgfTY1%D3w)6INd#rdRiC^`mZ@y6hCj0iud924NzBK%pV{@srLH24kR z2c>^d!Uyq3!LLGiWW%XP=?|3tN$_b8IVgX#68;V|eBSLUfhzwiVgC_6s2@ax|3))> zFXxZi$y3ljh45G4?}8zto!kH!qd)dRPtlv$f3f?0-Ud4zL*U22Ut`A8#_>=($G}g3 zA5>0L5E@R*uA<(RkKj=%U=w0H2|VDhha;;#aK6#SraY7lulKLG{!R#sv65?R9v8@Z%CbNdGh#W6*z`nLZwV zR5@5LWBxjmPi+;yDg9ya=|h4+_9`a)AbZmYe&L(v=g&0tH#z$I!7m0ss2vPT_#pl` z_;WeRZ(70!^>>=+4{k;VIe(;0JsaE)5GrZB?TZJD~ zj|1RS{6YPF1pGnpgZldf_~YOQ_4gU!`{j@N`)%M)BK#!&E_lkQM^Ar`pd58=LGme;0M)H8vFt9gZlg60^vs`e31T0@F{&Djy*E^`>gPT`a7Me8bSD={vHv2 zP=8N=KY{Q;{XGr-6!<~yU{Jyb`46KK-j7f9cm?<~(0?KRF0d|k=EXEeGsfRJ$c1D6 z^`z`S_(kBW`D~G)$1|Uep~00v4qJatdD9#MKb8FlzZU$U^6X!LKfC~cd;$Kn@Ppcm zbprgU9O(-$z>h7!r?YOk^!E!N-OnjMV?A(K_(67a9Q;yK=`2kR)hr?;`_BXD!+*EgTg0-A87x`6joFT!gcg7Yya{GfJTjD>_ogb%96D)9Sr=xAJiVo!SAn~pZ`l9;u$gGLA=!7>5Ote z!nfdW+it5p3g*+<n2%)vCp<5&Dg7njQ~J?u9KNi_QaK!i{^`xw3&-CD z(?9mR-X8u38f$!`Ovlk_|a2JuHpPm!U=Q}2z?)4Fqh{&l9Fl#}0n@agP( z(0Dg2{IkvQElxVNf?tSo|0hbv8D=_Y^5%@|GmuL|uG-XN%v%c4kp{u{Yk!pA2M|7t zboNm^aBNcuoPo3h}I^cxsGzJbw2W2UAgW_)x{u;>I{Zaf3%4Y%i zR3GFg73?zd`44ursd$DVNAG?FrE^^PLH_A9_+tp~SFe;0>s0i&9Qwn;e?7_Sbu`(> zrtmTFNq>>k zMtUB_KWW(C--Mv&2}4i*UV9&yhn#x7RXJf*v}~FGvsJZ(#WR;2YLo_CCGw{A)N zaqy?WzW{&R`i*_`Y49oie(gr(2@7e&543;8PjY*)^&9Drflu)V`D=}$f4`Z&Jl-Iu z`1`?c*gHSJ+r{Sv2bF*D>0PHF`!Ejv5cq-iU-*9EsXe_Le0ry<1Ai9`80|!z$#DFq z5;y`8l!M=Vkn|jco&@;!lAa+`&y9A2qx__yX9{u+_}eZ|<2=$J_{C^X+gYq=l z&*!0s_-Y(}&d}o-hXeab`o5m~9ktgYOw3zzEO!NolU&2#d_BbPc3zhRt z!hZ^X7u;!-b6$_jzJ}p=j3J#t@x;KVcZGxcW25l>>YLKmFZ{su58>BC*3O4=iFHs{JtFe>2ttC;J?WXzt5@XM)2tl=Y+{O_Cxx? zpUDybF!;sS1egCf_$A;Yn@;%{`}Wh|SAoCEo@krO2ChS zAJk83!B2x9R8OtoH|EekAmM}h(Fpj12v2#n(`U@XCWIdp{|xy32p?qc3o$_(1%I`v z-`IyP5x!qLp>}W(`lk_IwS&3fc94dinV#T!90b2G6I_m?;Ljoaab`N@dXyzzbH80Ba|NK*$P>^{_~9UzZ4$)!1@P&6#SrhS0N4LH~5cZl#d4xp7;-d6wI0V zpiL>BCz9M#kQ+ff^&!X|f4Ncqf3f8#zkP@=4Sm1E-%fshZTHt9@MCY``H#crg9#LV z4E*7J{_|1dPl4Z$@Rzyt^8t9`&q;Wg1t)%EpSZXZ`VoGO$rpQ|>R-bDmF!-vkYP$Abh{@gZ!sq;Rog)e7fT!F#q6JfghOvYWP3k2j(CAR`3J! zFZ`hNH-g{S7rfusFY#Y%)^8pku%YrB27d(c2k9Rd{t0Gy<2=c<@Ttw(?T?pB*#E)8 z)mRSw;RX0H;RpHYjo?%I>&*D`ob$o`;L{x}t4zM(pACaQ0e;Z>*0}J4)-R?-f4!++ z{AVhYcY|O2R+--q8T~kqHam^=FAU6S$YJ{Il%uf^M0a)cgCA7Rt>6!Wf4Ujon6J?t zAH(2xntXLOiQm^L2Y(j)E#Mc-8tL@BucPid=?^YXx&wvotO+V_x?^Mx@oaXbgBL`o zJx0JULHJu-`~ll;C%_*9Kd7A2;L}|>F*Cg3hYf;HcjsJX^3^*g?B|VwU--7*{yqtQ zG5A5{JPUpa_^&ke%f2Vo-JQa}6n__3R~X|LjkQjDsDdNf2t7e|p+We5WU<-4uU6_!Hn`Il@W5aUNnA{3-AUOn%f@4?>%VWXb&ZgI6Ix)Wy_ zazXV>cjXYj)=Z~yexB~oDY_}R9O!Nx;s^En!Wb0i;Fo|ui}-`uL2V8`mBaIhpTcj) z-vtq)96akb&z(j*`Frg2 zP`)Q1H#-nKzn%fV=$$$0pByakgVI?d{0@lO^^(UOmEx}jKY{R@T>SNRKWzoSAN=D@ zzHzQ~K=?uNj|jip44=miyUIWK)6l=h(#b$}M(-vfTZ z^F}`Noclwl-B@w7-FFB3mto-_G~>zpzFpoi@C$Fjx(dqE?icyzQCX_-qY?b7_XNLB z+AsXeT>5#QdIqp_!0$u&PvP%^{f>!Vw5k81N0Dgat^o@X@2LEzXzwsW!1o)%iliz07Lmm$t zRL?Wu&w~HBi~n_1k5taLfj>OR`^p7XW;xSK`%XDWVBlsTNALgJ@#LRn*LMQ^x%bV_ z-|C8o#(M6bY4H1Q4W4fff-h!v$78Ze;r+%sYAfRipF#S{DG!etd7ynhZYrwpUjaQ&LC=Md zv&$-v7gb45A^7dk(?fa=8hSi?{P#ib`5gIqGzUKn-D%o?vb8UVjBhyD@a2d#5V2>)nPzp;;>0Y3r# zYQ6S(vkctl)Qd2|o`PJ^I%@>{!VmiQ&l<#?0DlhQucUOWUsd$py!fi(_vFV{g>NZ{ zuPS->irQ6?n~$hnRrU5GH?4|Yy{c;6s>r%kCF@s(*RLvu{Q6ae>h3MNGq4EpkeSgB zejR6_F6)Zk8M5{sH5{_ikg_b`g(p`Wuy$aPV?O`bP{CQpZVE|2@K#z_1FAmuGHW9i z!SMTB3$||K>z^sGhC?U)p}=}5^oITw)_>;}ePV_6Z2rr?w8HvZ{z>0lVSS+B_pC(e ztS;JR>!dh}V%ONe=R-$tskxx>eOV5^c zmak|vbhvpXMLTRB#pnH9w4%h}pB*~Y`T!F9fzVM8heCIU(8|6aItgd_EA;Yv zL)NE4E4~p5jfTRmc$O39RY%o0@u;*J`NZ#&kE(X~DCd`--WjUE;Lh2j`dw+kiA@~U zVO`4gU1QN2=n4OGw6$}?z%ka-p*a2=&1=5r7_^ox`1{F%nr|Ls-Ff6L{QZ|BH~;P! z>zu%0Qv)c4*MD}TPi`pk;$RFW!fS749k*tb}1ls0c$RqblUxpw~ML&sVr zSg*Mdb$dXqaIg+^w3?M&Rsw5xN{87NNk_5SHt_qLl^blG9EVe;^Pv)Jhh^XC1=byTHP01TH{}=O?~mlaC-i|8)@KVwkVR_0b{UYKlUAJN)@$^M{8K|Go!tFg zUg)+^)&Jy$eiu3ce-GrHHk_}6kiJu_FGBGbLp7htxBeW0(fMZH>v5IVY~F($-xlj2 z{x}#~`Nxno9r_nk#ODiE{;!vDK6Hc{nWPL?gmuDHnVS7= zK6KQUl6Qox9@U>I-K#9rbI*oHL)L>K<&vo|$FJYx(viz%c^ePM9<)th8LMg0P-5NUSGa>6sp%vc`g&qopbqAc!kA}{+9zdl% z5PBx`Kz?W_AFbFTPWrG z+|X;S>n-d09n+!Ew?kMj{Zr@_zsa-i%6kof=kr#)J3sX2ywi0El{S~%Jt1_=Ni|RB zgu`(-=zXK>~=^NCZB3NrX3O8d`cO%tEi+7Au z?dzyZv{DuKOVxMhL&u<5TKNB{&x5GAz2kyu7fJp$2;LSt>a!%ji2kB7efXclC2+U| z4wt~;5;$A}hfCma2^=ng!zFOI1P+(L;SxAp0xxk1^skMn7zfLlCgk@^oQ%I)beOiQ z$4jv~;=<{!B6_skxmcSuf3J9%`}fN{zh5Q4SF#uuL1OB!W99c5zv18NtQ4@38`dd~ z+M~l?Me3Jjy+Y`i@YUWfFl_Cq=Z}Az@1j3u@?u1+73yE?_pOSlzmAaKi30wu_Sk^c zNCd|SzgVc+qm#dhNVc(8!s(M@v5G~pI#U3-BPGm9LTAD;^_RvQhy;h zy;rp~=#{rUIGH4(^^g-bF`dwbrnGrl#xu0Ecuj6~kBr>(Q8 zoz}@0dh%h_M)G1=V)<5{^{6kNZ`&6$P`*`QX}jXaSJ?K)jUQq8_1k<{58dD0@`aYR z8*cn4OWPMW4(lfU!Hpkdg?;grR?Me<@~vYnZJ*tGaI$AMWWapU_0r|Xi<=br?p&s>?$U4qlKwdV6V!ReY>^ZBOW^qDL3 znG&2nYh^ya5uC0GH6Jd>)wq|)jnkbbR1WmnDf2l)aQe)Y`BVx{pM^4?&4SZspv>n= z!RfP3=0o2^qj>2vPUiD=!RfP1=5xE?^qD2|`Gnx~c{cN*omSFMpX)K7?+H$yzcHVG z7o0vPV?NIdPM<$9pCi#eNk4t=!hBuwdbIp&;5d?eTI730{!YOY6)}a}EBOB-c+8XE68MFrXVio561+%obw(1p zt{1#f;??+=&`CRxbQvTe(C=y zaB9zV?W_54{Hrax=GA{nZKov8U}yF}M}n$K%R zp049GpDMxW`b_iLA~;<)X+GL+(6zGWbCt-`wRz@qEpTcNMVXj_b$c5Ve6ok}s08|} z;G=@;e!T$`7t+%xctYggF8Fva>nRibals=Zzee!C2;T3Je=}Sel}?e@cH<7gBi*e3 za?$hOf=>%xB6tFZi}Z{OuG9Ys!DH959v z#&;>MWxe`1mQM?=>v11&%2$!3=hY&A7w}wmfUZ+CpOE^o+8XxY+78e)hvxGc=qG#9 zfNLSlNBe259{emN1UrChvdl-@6T0@$e7-LFZ}8}OQgFKd(0qO^I9;z~K7SRQt^+ck z)heN@ExO*sd|oR!U3XzV+P|XfCC#T=nD8&Jvui z!80Fiw;%G9^BYC}36K0X!RZ<|^Jx^Eu4OZy9>M?O!EY9PrKjFMB={*F{C>gdno#q3 zMDTMw@;?x~#)CftT-n3-#gv-uqU^L2#BRLbjqeeB{8l&qDZvx(WxQPU{8aEk4}R>4 ztUn?+eyS%T`1oK<{cd2`Y7l%_(#hjDjtdK(7W_1kpAtMK>DPF{Nn)=AKUL&Q1s@k& z+tqgg_p@X704MuHuXCHv7X+u*ugyo>AG+4Ve6;;(@!)#?NU!&r&*P$>UUxO0e-)fw zFEyXv3r??-noqtm`0%?txVBgHx}y1*Eg6?HE_RntH)D%#mIbgJET{J%%?{5(DmNZ9-?;?whOpakif7(UI{osMQt8ZI?}}o+kY~XOjl|64 zSba)=_IlLYl%C_V*0pXGT$hM`_)Ihg5|9`#w$gBGjKosSBiXiFUxCx_1%Iuev9$TMb9t;QiM#j^R>0FAGaL$7AZZPUri8`{nCFkss`1`B4=L`*f$W zp5ZSu{(#`SG=3T5x;(!ic;a%#D@1-Z22je^=p&5lG;9*QaR=jX6#2Ua@BbR(b%Os! z@bQl@uG|vvPQe69mD@)df0M}f2|l}laa|7oE_h7h#Yn84H=eCKF96MPMDzj9bF^245TyH)W1Z?hhq-uND126g(~M8Qokxe+0f7 z>5tsFPW{HRp?Z#f9qVb_9^>B(Tg@7;XS`1Ehk^U0|ED4!`)8JiSys>Aw4MgWj~0CY z>!o~lGp_S>^f~_eU#D=)mv3Zwy2GEI4Zv0Xj>pt*t>;sM7d^_jZda?$m3T#7+l^Ae zBT}BaJ-k)$A{iHS`t#OExqXQB_o&!$e}Uk`pJtryV5H}>f*0KpQ@?dO{~-9_R~gss zry74yzWSv+SE*2z^)}#s<^KVZ4@-O2?RHwpWBo+ZPv4NDCl>M7({_(#h0#vD`$Qd( zr}T_|A*RA_RsZ6Xg;B;Qzsoq?)k4q5OBo-O^xws>^|Z!698-uchcnAWzt}4b6Y5C| z-Y@dH9Hs;>61+*|Usuk08YSLS1n(AnRMM&Sj00ay>p8PAC8_(x_eFmEUdDC*&0EX* zr$6P!w+SA*j&b}{&j;}b*|E`IGJc`p9~1fUM#irf{7W!&s@@-FT&JHd`zJl=2N{_HB2A8d*#$%M#%P4LM5jO%hMtY-N{g7GyXzg_Uy zos6S-sHa14>nDusG~X?F<3YxcXL0LnG+;{q;Kvx(@$MFUd_Cj3{R{~{8E0JG31Q)R z6Zu7}tgru(aVa+I6~J{GNK8Lfz*V{Ji780;_v-{7-Oaep@2c}yzUY&T0!p768xwQtY`ECjO+4WBY603#?KP@iv^E;j`2~!zYLt( z)!;C>Aa7yQJlyUs2o}UOl>cRggdeTzAx*XQQF{5~6 z--)U4_plmkLhweh8#qL^#akrplT&3`pA&rYe%7Pg`HbL^ zEsSgb>f8%O&qa(MZSixn;Dh%uuJwFe@X=2(zDDG~qj71^%ms5Nr61{hfRP4~KNC2m zKP~n|m&4V9Pk)Hzb-CRm`0$;KYxzG4Ui4MQVII|UJ{mB^YyFb(69vBK@=G2SBbzZE?81IA$n)${RPqUSoswVwY3PVvTm!ML_3M_t7739;L!uo^2W`0zoN z?-u-j1aExYt*7c@*3;O?_$4AA#~-Rah#f#O)RP2G?RHMutuFufiTw0WVoL5Hi(B7^ zz;W`oN&XC+^v`a$A21A;_E^j>W<484`0uClws=`!6!e#c&Xq=T+Z^bCdN+_ zeCSc6ColVaUC9+JU$mX&&l35B;Elg#T-VD@f?JyyKS|_2qw#%=-z|9PO40um;6(N_;@|bpDyylf=_>xahL`5{6O%@t&Hn*{uTIfd9b(Tj7xD^CtStp85BL} z&g!Yt_#-U8TJT4J`_ zV~p$mQrJl8LBF_(@$Mrn^_&5m+STA)jO%jPBKYJt8Ar0!b2So1^42cKwO#t2;G;E+ zzn;adSMQd5)iJ(a@J7L{-HabE_;&^G7rVVn@FQFN%d-+Vr6=|c)}za3Oz>$LcXVC+ zN$|^(jf`2N{30#G3-H!wRHGpUB4!u>9+U`EezWdBLw3?-TqXk&pB-{zk!% z-NW&Qf5P}Zg1>ez<3*l&d7I#2X>WSGJ_wxZck+v@r$Y3+vX%9WZ)RM#&rO2QN`7@c zUL$zFv@6{n9v3`(5$nwI-x!}8%DF}}v)=PQCwzMt`O!L4?Y|25-L!7BtW`Y7WU2!25D#`_r8 z<^Ku6V?SrSOymnXq+(DoIMr9tAmjIne4WVmOaIdHpAmfaTP!~y^4D~-{{AZ& z*YaNxJYCDUwx3p)e|ydVr+zdnBuf?9cM)2zdAC~&k>HMt5uVOu`ME-ffi;|4%dO5$F z^;@Dxms_vklb-T?TJWOBSB=kL7iG#(?{k&l4ga{w~X( zEP8hJik=3>w+a3!!L2J8KTGiZeJr1tU|gs3Qo$p87}xo|N$^3z&lEie1rL9ow2feuv;4_i#HLE@%Apf~T)z{o_(Ty1ji~@W~A< zuhV(z^(;Soy&LZV?pN<)B0u>A%Ws!>@43NW{`0`8d>W-+)QG(G7RJ+(p0$Fn7d#>P z)#ZExaM~{@_v{zEU*wC1IXybR4+-8l!??EFzXwisEZomHeWRD2f`8!jSU-=c-@4yj zA$a3g8DFEgmi5nqr|)81x7%L`K6)YJr6Rxat^Vb6C2%UA;cu{fr^s*VXMDPe@e>4Z zd>i8tk9{5yy#LKCf1=2LUGSny7}x3li{Oo$8Q1CGc%ziV7Z@KEJ)ac3U*vWBnG$?- z8_QoT@}al0p8hS2ze4ac1W${7(B*SIaKHBU0g)fv$$BP5Pti@Re^ByOFZdqdRKMfz zVtM)&GCjj0Kj~@bNBtw~8NVQ=L>}VDa-+;C}V^Ly<2MJq;p%&Ob>y zQ>_0q!M`MUACd3>8O!VP{4c?a{@INme~YBY)85`LxHZA@I-ND|VflVZr`G>f;C|)# zZzA9LP1d8!=Tq;Mc%NWg*YBT!Q#<;mi3b_SwS?;VjmTS)&et$( zHNKDaSX){CJi$LE_^{NY&dalchsAE_dO7)4)-!%S>(S}2(D*vWZxsC>1WxIUN&D{* z{1YPI{}Gng<@}VA7a@Zj`F@T!yqo3Qg?Be_((hf5dQ{{SceA`s=idaM{WjxgiJlMM zCivih-1@NKgGt79dVVSR^!<#l6Zx}0$ogmZGyZD9*9ks;fN{7(>bViPUwz#s z^42)Z>+<}o;Db*w{wY>t-8#ha7PT<0>-TTKj}sY_gg+$dyvHqH3Y^xv5^v!gX}h!+ zIHj}y7c76GD0_$K8NZnETEU+Y+1zzX_hcpYb;de*8WD`K`4RDg5u4Q?hp2h(AcZqyj z@^yvi|GeNaX(wsH{}iC7=$|>>#ydFPK9N6P<4-fL+sW4jkNl8vZ3lLIO!7O!c)7*T z+XbI}nDI4&PYGUh72~?So$+zj6M2g9%S66rg!}K{GmJM0o&-+imVT6R-F_Yu+f3x6`Pq3b%gN$zy{9(Zx#op?2F8n07bFZIvJa9_S=!aR4&es)!7kz_q z?Jqr}<$ulisKi@~frj*qf1B}h1pkoWqf%~{3;w*|Y0lBXF{-0jGrR->rjAHZo~I6zDMwX6g-h+JSzAjf?M}6 zzDn>v2p-zn%JjQjs+$?yb z)bCc24?oEAiO;h`rX0u zx<7tAK>iydUnKfsTWb`ay`HlHxaz;s-rgty zdIX=A`g*nCQ-V)Q`RnpI>&v3&a*p?CkPX0E@yF`9C&hoDp=I;e>yom8T1i$(# zq$hj-_eS89{?V;0uiL}71-C9>9BS25^bqSQdY17M1wT{a^1~o+4#0bXtNQ&I>(S>$ ze=7L+PZ-zb_Q=Ej{7UfA%NW<~=Yp@Y{NzK7 zUncUa#u<-D`n7yq@I(vCpDFTB3SRU%#u9wlm*T zdLaK6#`Srm^SbF$#S(D+wa{&#|Z_Ir}w4>G=6@KxXUua|RyQ+tct z!ScGDTqXFp*dJY|pA>w$hUIsN{_hALlXlfAc+aGi&ktE%x2vBBp4j8Yi+;fJ!|UAm zM!{p}Gp_xRe-u3ZBgPXJKTm1=0OQ(T9s4hm-xkJKi~M!K!}7OD-YN3KKa453Lzox+ zko6?~jd64z^?VpO*@2=587~$5cOoBaWL%d+`k?5!gz*bR{wcx7rJZQ`Ek9!U*=Cm4 z>3>@Au+&$z=!rbZ^8FXGd|2>r0jG2(zRdW!g3l;iei-DWAG4mudstqlXRF{5(fI{hU-@o%47fUEZTX}A1)1LW@&`Qa@rf3d{-sNj=#Gp_sN zziWB1W4d3z@~0B7j4v08o<_kFm$Du-WA%Jr@YzQg*X6U}Us+E=+NZ|9EBNG-EZ-;N z!qHDjyqCN6G;4ep-^G%dC62?b1I!l zW}0@lr=rxGg2dym6#;UTRY9A;&hU{dNW~(pF zE|1de7)!HbEXyvnvg{bkvSaiq#_Tk#&DOrQGAq{=*+uA6g4IzgxoPW;_3O4KlRdq= zlXYk#O&#g>RI;ay$eQMK+Dcxwy=>3cx~&ym$#hqDCQiVX`b>3lUFU&hOH-z)I=L;` z)ZCov>8ZP{yrZeDGhTK^G7^vP+_EdVkEH7}(emWR-p=MsTUTdtcT-O)T9#Z7lI&>e zY}%XZc7=;Zpsyv>lj-g{5Z`G=1U;2)otf0$?xyx+b600irl~Viw|ndEXk4Xg8SzL0 z-0|$(QeT#YvZ~}ZPG7Pso$79))Gs4D<;c$7R0f4dY41j{n0Z=;!nIJ?*4dUx?x7;> zf<{x}j{0cwMNxWaOTRRVTy%D2lBte#<^X2}TGF8yWF@BxsLR9wq4tsN~Sa2b@UYb+{$_os-;T@YC%uzNjCNNSz65r3g1uAOa5Hg$J59Z04+Gu;QQJ>5+msbouUN5=sKF@AAhcZs42Ht%gy z*4aC-`;59iQ1)XDS43NXghsEaNTLDOSG((RSq;t^f$KJtA;MF$tGT_WyR0YE60b_i@Z6JbZimsT z$57tfzOSjht^wl_Jt(D8H1w8KUs8HsLr+@q*wRTGTUOdsV_ka)GKt~O-JQrESfG~R zBcP_KpGPPKDxb<*ZB4bq=Us%=MosTTVECYJ6H7(68HTSWy^CBrR$it{n$7UOg^~vc zh8n0Hsw>l)>ZY_(ij|*RpDBZLy*Puee2y|zfl2sk9T<334Lg<#iA5WX+dhc0Axnv3 zCyiH2h+-!ixhfiQk({LDE*hk9VGl}FSMKTR-rv;S0t1qHAq`bE6_vqkzpcJfcU_em zJIWmkWCM*aNMo75#^oz4bt$wv{epc2hAb0ZYqvo-yYTj5yf#Z~aU51MSIVQ`Wt8=y z8ZxO1?W%X`@Q~`g_{Gs1Tv@iqzR%jj?kvsdJAHlHXe4{BBm%<=UQ%Mx%Q$c~X-Mtj5IS3B63UxX_gm1@05J#D0Fw|{Lb?(iyE*J#vi1H#lg;t@Goa$`R3D$BId%L>! zVnMldLu;z}n(bYg?Y-^ob%`zBQuojEu4H0Ma~npF9dH0CGh00Inw1qTb7w`RGgp9W zr=)ykebQ9Ev#UL&N}xVtk7A3=O^(5=+#Y+hwUc@eFnHPBGaB)+WIo+ET9(~mqGj3E zDC%Q9qL{gR=l4;cE*Y)zNlUel)rw}PrPOB)q14ABXO}>Ewz8Wdu zLuYe5&dc#_J?X9<>KCmUSXfC;vJ_ulQij)DfHt-R613V$%X!HCo-Udw@P+_jxL+-) zOjBDsJgeHKo>sLh#VbW{MV6XKOwh{HO>NzETi{RQKbm{eL=Iklb0*r80lx}%7HfN% zt~%mFz7?^mzeyHL$6YXO_+(TnNemPT=_tiaLsoYcuSGGH_DUn!Qe?DfLW@|ucoL_A zP?7dvF{>)sk>Es8Zn5&+f|cUxB#SD;hbr@}Quuk;55Yc*T7XuyjI~v5E_FthQ)qF_ z7_lI2&pjo2U6yDOm1Y}B?rTf!_iHF|IK9+bpb7J89zP80>C9mqim~3cPDVFa+k( ztXiAjt_%d#w<~*;e$pWOUD}=`(EPJ{z3K<5s>smTA-eSHFZ4uUD6sC{M7sm<6?ih% zhIRNRSU;^CYYox0Ep6oX(KbR-Z6VMm9_{0mR-o^;balukWzq@Uv{zMxy@If1Iqj2L zeekrO%@S4>)G7#16?fLJSGBCGcG=N7ONJ;W_fk8RwoLYQBUJ0_&OqQ;;0nW(spejX zn$0p++QKfYjIg9AR#6X8sM@HCH@W*jCe@SJvabWf9EP}c>+6!yHDx@oXz#Le8`eRU zhq)tN&m&f*4Zizw5<{Dd_&-9fCpXrm+9WAN!^Y9R-eRp~E^~&ViQ9J}Zr@U!Oz!RMr7gW^S!Zg0(k?{tmf}?%O?^1y za2Ml#otE=V4>MEVdICM3$R!vTI-9*cJJG;7R3$z8B z0BKs>T56Yx!%U);u+s&L>2k>EH#KYR!$Fi>32iF2JN4N~gMb!9h8OFgs2H_>MLr^; zLtn##vj$}9kRN2R10JGXt8l@|rLM0PW4+WYS2U&5)WBh8sKX((-j)zWF=W*{3fE(} zB zJ?Mdm0xh4kMWeFOiz$0&Gr4z4ix4>vRS8kisxV* z9f8s=KiUNy+>1swZe6#j-Z{J%+!B^&Shbl(79vTt0NdT$yj-7Pvzm~`(pjJ%N zYPN&soad$WvoWO63A>h*qS8qRe-hZhbj{S!pNMkX1 zgYk4)B>-wFWXm$y)T1}tm*aEL#=Sn2LX8QL*vARHrpK9zI#VRitjc$|_PTOB&oPcM z@m$#`JC93>j5%q+G|pKb(*DqLvW|S}8J9UrT;fqivOsIG;hDl(zPGKNCSl6QROYt4XFui%S)&}S-c+ZQ|B`Im zQ`gYbU4a9n*i?e^kH6?VFwJghvt2qq=9kx~W1;BErBR@2=G9Ewd^F0m!4p#JjtEty zxlKJiZF^NDyd)W4tDHO>Gt}!Zm|&=-btH%SIJ%r#e_r0iMt4)1;mAw|%N?F>9k3Lw z<|WRoXnXy-ptb0A!Hdy~mFRB6`O)qa&9E@mx3@JPKpLQK;e~4Dn!#&mZ^9ZI^;wj3 zx-He5+TVsV`gU0-aoSm1Q`)YBF|DWOfr%6f4l$J{x6^Q=N5eWSdOOSEyJ@Zycm&(% z_t`T8WnM}pfpFEEufZWjWmjmu)Cfuq$L*hb%>&ZlJI~fOpE~5SmC&I^c*Zh_*(Z9I zcYu81<2~$PyzoA*3>EDKU=&`=FrUlbp&ZeE)R5;{9Sdkuxfa8W6F_x4uu;{5?egB9 z6gJOXzKCZ$<>YziG&KJ%!$C6lA`dU)?1ABtm!q2WT8$g+{ix@9jnn8sC2 z6W1mAWhm-Y_KD6?*fS@s`aKiOf!f>MX$Ux?9GRk{u8j>bB4l;&%sNy^Y9i?`dF`f!4bSuz(WjlzQV zq&9SQ;5EvYt!R+n{ffzM@_D-|!bC3gDjdg`xsUtOw&q;a$vYcUzTaM}^D_Y_et z5G+;m0$Wj)=7wbOlGifVnO%F?2~0c1Wp=vtOY5(wcbE--Wp^*_o522IWJtn_*-LqR z!i6iM+Ie5rb>s)l)A#t7tlq&aqK{;{^y{{?RN>_N(76T9=z-Q(Un5(ei(8A!>SDBZ zWUPep^fD-;)#+ZWT&VG92gV}lvc6>kmkL)7$iXbNex!EmQAXa40A41*VnqjXV^5g< zOWN3Qqq42xD+uffA%;itGD_K~;1{J(uciB(PigNs6z5auJ_U-%=}c-1JeRY(h%N06 zs(8t^`mH`L>nw*e*UDkeeQHRYOq46FnDSg33u)yZ+nqH?C7NZ#Q7#D-yH3;L_af(t zeC&>!rfcT|tC?6qjh51GDD_#KVXZg>E2^|^#w)5heEx-8OSj9u44(yC_n3d+RtgN! z^i}}dCfixsooiVJP2X_(v0$;Rm5^wZF2yjNHKUDtx2UC&cm{wd4*=R5Ej7-FT}-?B za!{SRZmobLXCKu|;e-knL_+oXEH>(h0 zQ3pqw7Z{w~?_$!4CteodCXh^ZcXxH;0Ec*Ia@Kr59o*3C1h&V9T=?A*k$b+g%o6h+ zVXMFqHrR6uz9bs3*Oy#IU%)(VJM0Y=a?ifx{%$(9qpoR@Q?8z)SM>hy=B%9!RFZd| z!($K60+TI0T{t^Vw~FwlmgwOknN|y5;~&*y)s6 zF7jWM?ZGeEe>a_Xb9{|B2bQYqaj0q+9c@B$OY^B1@pgS0!=lQW3)$JCQH6s;VsviL zIf|UR7VkrtMhYX2YcC69G`67VEEK)k4$p@V7sYqux&uCvOlQr4);nkfL{l^0!JsWs zTCY;OaG1QKM9}dZ2NKHc{K>kpS~PQx(gjBs_`-)wXK|+z{1-Zs?l=pFm!{#>Z%eYD z4}Spn0ibzQs$poC@d~XzaqTjtGQC6{`>qBpG~|2DU>VF{DGz|;#~rR3H5YRz1*E=(w z0B_J)Euo#Y<*%0DsJ1%A%I8-Xh+o`_Ctk(lhY3fU&53ed;5D0z#Vdm#rGd8;;kC;d#>Q<+j6{wPYRe z5|yqEy>7s7O()|Q*3q?8hw7CUI0@?BAoWV5%Q9qbKOVYuZyfNz9XYD@Y3mCY{HT=~ zECaWt$sf`_&~`W!>Z%_N;HIA%y#KvPmVERP6B-ab`vj=NEGJtvJ=#`>`&2GxWYxBd ztIC{~7JOE^s<|oM)ZCUiz_n_0g_n9AxZ2s>!Ych@PvqdlU%Y+`^+eazZpS$^<@WR2&)$v2!v%|$ij5z-8RHkxog_%F@{taNUW7~;;tBdF>)PV?vC%qiUYgBFYw^9atq|hj=l-f zp6Uf3$>Fo^Y7U@Xv`S~`>Ef<7ykvervO_a2dy{Ax^8#89rX3}^bo(xruxozP)M_5KtsAJH&?_%0aF1UIgFPb0Nif+ifRGQ`I$@ z1!EV(J6EF0@!s-Gr)AI(^gGAK^xMC6L3R(fY*$nP^8}yW5hTKQ;YeyKZaR&Tq#TgO znV%?~`JqG7yr=4#@>Qt=JUD`??Pt!3rS8Uu*PCF|;wY+Zbd7V1T5^qd=!HO<0b#3! zcaP~pXnu|$kkDY;SGU{t zf~J^y0ZP5hhD9&Cp&s_Lf`)NAe&V;_=^E9_>8RdLxze0o-KnGNG}P!0qX>(EJvJGL z^+8tbf9QsrV;dvKzJjhxeL$hw{k{mVi0w)?z*3=q$s0P$Xqo0w1lJI~*mWtCfEtV!+;6OAU3MOM0V0rOfclJxg7<8^C>4if+yU7ht(ck@m?0{F@v%Cgm>0 z;G{0TFzxvWf_NsL!E+en9GiUA!agmta~-C<7*BH?{Dna=&&(`!@TT?6fVKh$9j_Dd zokp-*sukNQgD>I?$}i&DZ?3FwFtTpET!8#6)#X-mx*Ua!S%g{0cFuDiu`n(ML}@Lx zV&eLBZ)_o{!vb4u2Tix*Wu2y$xdmH}WfT?9PH0gajYGeM;A!i*x~DzG^*z;r1bGiy z2F@2r)-|zR#Jn~;q025r=R7(s1!5j&UoywnTqe9TX7&D#dy=FsuZiO(A9dX>l-L_= zY7b94MPMw$nmfv9x6WBev|BHVFRrexl!HObX{9=ei@hGRLoKx80GfS)2wuEE8hm@+J_J~6!1Zi)DD0$y+D@SxO=J54EN<^dah$tiukpbV9Xm60xN zSf!deuwzATD8}xbXLicTPgYm^dCq#^%WA527v_KS>-8kx>J)JWv4%>&gpj5v1z~`W80P1=g0B=G-V&Pi+5Dj)vMf+ z^>7yG(NPF>iwAGgP@%f~X>TNcm8&LxOLwq&4a4wtf=7JnfqVjIId(K?w5N7=ctIlj za9r+9JbjiZn!Uu{gjq~|7n)E@dqST+HgCUnMn~U81be(&P9?+U+kFuk@N7bwcQ!kg z*?U9@?O~C=fZs(0u0@OGyp4fDNwyZ$8*u1W+==aC3+^Cv7~20164kHOVJY!+Wgh}> z>7kfy)!8TQ^yw$_bdhJCxsV3W$$we4*OSqplm8gJ%(WHtQauBA4-3wM5i*i{mEDyP zwYUzWr&iX?eGyOYmeLwr(`~e4+6}5BleknLXfa<1vKN1|YVZI0Q;>8Jw^eQ|3+{&t zwJT>YNZowMK3mpdE|k81*Yq4SKi6R|$m`}QxOuge_Bb{>}Wx`p!Am-Gd$Ett@- zb@Vz*6!GG#-h9(ht_i`E17+`-abRG}nrt-Vd>qO(>+KtMY5(_iP9IMITLu9mDOu0X z{eCyLF4g40_h09^6B<(-KChr$v}Nq^(&g~Vk2hWNb!aL}SnyNVaF+5loSj|vSF{}q z;dLKmHN{yCaLtec)>QRHec3A*jvnpBFMmB{GxdLV@$H+pjDd9twniVbbze2T_^Fby zPGFyi@ZBL_o*j%Eo*8|nufxIx7nx*drYq|L1M(XFPFFcpF6-X5t!jg9ojR`TSeL8? z;tj6*+sx`dJlnxnL-8gMeZou6@?V&>a{4F^0&S!(yW?x%YD-kF1CcAR_-O?~*|u-# z&SRABvV-NzS|yRMefhlao;h?&MgA^04lFpEQOFygXEBVZXP~W+cbhS)>hayZ_E*6d zMaFkF<5-)B1Q?J-&*of4qg+lG(T9}ic3sz!6-P*~;rhHcsorg;g>&YqgJH^vT=HxX z2S*Y#qm^S^8^~{yyn2_h7n@0Hh*)Qet5sHg4Flg_=UOEvqnK6~XF9yr+!Z{0PR$z3&^PLG{b&-R!z`v9N&ajR}aP8&CbQxu7P#QJ(4V-Xh53| zdij0HYSGc@egiSr>(qfi`o@m;DlN5Cv1IK?G}h_mzyb(1k1FJ?3T&+FGomo?3oV>L zOV)($1s(LmjaNLYpu-GEfLH|-tyDc3JGF9;V`}(T6pvwC0Irsj<;5Pl8#b~1>2txR z{rRxX%bZm$eZ#{Z!hPKpS8*J=j^kVn<$V_&*9yX`P*oD#on=mI9#f90ciYtHZN9RW z+_epdM);eW*h8Y>#JKosp_ZAz(v;da=8(=nr1wtgqw;cu$Ei9WR|DaF*Z7ukc8L$| zVuW)H+W(ff&DA<9zsijQab2?XqPH_trM`YbZ%-Q+fmHBLJx{;>SC%bWHWsnz!ggA2 z$HJgqiL{$Z@IFmM?bDdwI1SjJ(Kk#-^$pWrO+39?9j+PdYY?G zdHD_rm^*uRu5c@{`YahGJl9=LPCYGkdWc2A#F0 z?ll0pM4eY9a@|RxKW<~1;FtEcNczUG_jYTzdOVbSI|?qJ^SPZtjc7S8eh5C@;xdnh z(P(bR*QH*N-v+M$*IQuL*VA3rlWB>oA+=#EZm){tT3-R}1F7)pFc$=ChjXov-C6y< z!i+1mmy&Uh@=X$s0ki4T{nb4^G%nXvCX-~*CbaM} zGK_hOwz=-@bKm4;?}8yO&cfUx7X7_FL?6-M+p*}vVan11H7kYUvUy2whYZI?|M9HGEIysIDgq;;-yh38nmd;`k%`u? ztEvj2*@o-mdCW8dE-m%{ z@?rLD*Z-AhY;@rZg(-A;{Tdd10$kk<&u9JCM60AFmQGu_8WN+9laU)nn4GZl)tI=6fnI2qTLSf?bf!*T%O^jb%z{pq2W_2 z#x|M$3LI?#t1m9(9);xvKDTwTE&SrWL9*JaRm#So>qPNlTa~;6O;*cknE^+Y^ngn) zt7m^t-*L!0fc#!S&;W%CcA;PiU)i+}cR2>}f6K~h_8~d-ZWT9gYA@_ZC0#=zRR+p< zsq;wlZaaGEMszwCdM`sK*>L&*xiSN|^xwWvysI~p?Anu5XGhUrv(k?mcDq^bzUz#9 zOU-t6kzUjTAcPThk2LmM+GhrEW%3HD$fDM=DW7{ zqI(0bGc6lzSK0K*0*a5`35wdUpc=#B@=Tgua4^2qLFU5amH1B+y#5v3I>QNJGXh=g zP5uA+Yp}sHc9-v3S<}|j+|=FT9bHi)OYOHg$5RZq_IRpl+kJ?uvbn1x-PD~@mzT(e z*iLT^7_B^;kbHp1+=9$C;=M@y%{iCg%uJ1!65JLOEp?IWYc>Meh#dU5V33GR#Z=DoR6q8xi= zf|IWAtSq*r2fL2h-&VnEZ1^uzS^+1erK=-J-)Be9u-8oZqmfjAhX(}gLECq<$_o^o zv|WwKSnwUKGD(wVbTK~dZM&P3%{{%i@wH9grLgRCYGjD$!x*%=Bg_A?!mgb*bAMy8 zjmT{-=@ouwVv%*S=ml+@skcn!G9q~TD9eENV?6UOpV|Bif4hvQ8v3G4nts|>QL6ho z$k^xZE;tV_Ve~pWO+b+{Y)7E0*{i|stsb25^*UzyLy~0Gls%*Tqa!YGrykECu-1SD z9$5`HKi8CFVwr6n)ORE~+C#HLhT=sIe73?dE5KMFlXPTJow?Uv0P66)F2Y-03w-s- zbsxSeM)v~uk|#38#$S%>6xebaS6>9xwBv+tkyW{9*~X@x%!W;M^>m=Md#xgRIe)3H zCG{*U8KIE1i*NVmTxV-w2D19&3+nC8;W_0uAz8c-V(*MEZy`0uIuz`S%WpnBkS*_B zsd`wUIJzhr1a4K#8UyH3a($)T?zsJql&2BPkc4S(&;F)#9c~?hNvn2!J&N`~ahWJ~ zKJiy)SBCzgWmy~$%Jio3J)8EnYf`jhM}{~GRPE*2H+r`1ZcnLKg%PSsbNL0ACe6Z* z6OJtPrr;=Y)7VMYnLqNG!*_0_t09rzrS?6w+Kv@>95wQ;Z+quu%UBPf(_TI^C3_oJ zy4W((O%q`IyNI~ekqSC%!R!#5Qt^=JW90a}8SU9+eTp10x;CB6jR%*bg7i0~58Wq> z$R)z$l;lroy#Lx9Czx%&K@>UQtFH&?WzFBGGR?>Pg8GuhIuWD zDV#)iTSrQE192~Sdt37X6>p{UUPuz(J!;GJh*zR}o-(TZS!+IOqnopFUKD4l&<@+M zEV#F?FNtsb^>lUO)IsJza$m%|I_P?jNuM3V)GupNoHZI_c1Ip5dk;(PG5BsoJ)L!? zkEUSbXK6Wd{0w*PfC4n!|S>EmtS_eweKHz^8sz}^Bv5z+>O_B_GA4k zYtraiCF4e?W<$$ZVh^}aYN^FXQzc3}%FK3zWUf@DPUI#svYDr9tSxKBUiYT8&RzH$ zvGU(8U5YMUNJh&x(1zxYbiHc4Igg{EozvZ`YJ*Nb|52xJEI0R>kkPEudFWhf-e(WB zv?8PLD8_)PzPkN?{q-fPW_xgGF~w)UgQtJ0?F3bTHcgsum^;lv@#sm6d!NO5nN}9@ z{uh>F_NVX`oG32Aj;YSB@8Dc&r>mgv$ab~_zOzkh7Z}_Ey})QWyg1lAOo1}Wxl?Bs z;ME%rVs)~PP7teEwz@H!M(R2otyR|1cK6856OWIN-D0dJr>1VF%$jNP5zTo#jAu{5 zqXQH;&4;HN>b-&&c#zLo6nC!`A{*2%;FF3KuG=Z!rpvW84;yGsiS(U5EvZaXbF1g| z>@`t!g`;^yGwVd$lIPCKXLa51MC-|m9iNPIwl4n!p6-kJrSgk9_tRGn@X)l5Wv8qDEEaI^lzW z^r85!w03u#t#z|!ytIdJwNtko&x1TJp9>(2iuD_uWrX>E+q;?&If^J;Sz}xg67^z0 zNgB-6W;bqd!Aoy+G&_n}VvxBF!^~u7Vdux0j%NMA9|E3)y?FKFWiMVOHzVZcRd6pN zf`^45EJAcaaQ)tU^}4I8dv|_z<6gFz>FTcPud2H1@4Z*=RV5=1O%>t8vWXw6DX0&! zyaOw11;LoU0YRSOUa<584dJpOHd6?T4^bLZ;*~B`Q%Jh3Q8(Np(+Ambk2>Lm9`RUz z&`4;Vs00UF!JmfkQdVs3#yw( zr7WnWmoM(IdI9%Ilk}QoEt}|dF2^m=Sfr-t5)wr{=NNQAO3;(|4&5uLyHY7tuS@h= zvuimYniy~BtL!%lG$4JnT~oFfE1c}ecUEHeK?PRaeu9vEJeqkwuI>tQjkg6!ra_Rc73_4fF(qf3N*4^*y`cf z0|@;oi_o`gE1mqP!M#bA#PUZkt_UbD?#-z8E|}gOnUN?tyd9$QB&urS4X$3wS*rYG z>g%ZXkO!9OYnRGwhEyi;zFdM%$PBV*BG;%K%NTHph)3SA$#v2BwCtsGJ`9ln>rG%AVEgGIK&dqvSp8_wy)ksvnkBNAvMrYQy-_)DO^k;b zs{;ee|3$w}AV!}fg}BlYh|?5K#-?p@6B@k#RcKbwhqjGnKl}HWUhDSXsrB;}q{3jJ&OS%H_cf43f31g59`MK~}D1!654;Q0e)V zX#VwPjD0z4WUYh>H*N~bBOcLEU}X;I_x~RyK77GsrD$k=)8IKGdpq$uKF*kSlsY7^ zJ0}SZI%uB3N8dA3rELS_{>^$kM(0N24xZU^t2W1$)x(^G&LRPKu{lp(>k3=Z;5Sq! zGuK>_?U{HaR?coObF>zw@SOb?k-e;DwdGwfI$^>70e)i01H-D zm&3AYAOt4)PPF734am@yfc_e<`o=pqV9b?~^q9MG$Ka$?>;_z;j^iq!*hg_q3C}&I zI;k{GcPG}0-^>> zPOdgaj62P786m)f!j|K zfzvHgSD*MF#?E-Tr4%ly?b*0*PXsBODlX|d&v`ODr-+Q#DJ13{yD__pRWh9ly}psA zQcXBmYh#83Zrm5QrB^E*m{#{p2o=C)xNv##1+qm5mpeB@Qm-;$W32DH zZ&{C)O;B;u9Gae9#^n?ED}L!@#DPl|u>CmSnn&SKREj?<-sTm!kKnKP=yb#((P?(f zt51rnXaD`*K)|k(|J&yxe)RS^LHs0+(fn&V>Q)f`uY<3gj~G!oZ-F*J%0I=S`M05F z+4?8(1rY~T0(Q*0I7#}7*Y|%H;S}#>``nhrZw2CU_LR8v%rp4=_z&SnS+tKCGZWzs z$Ba0HaS#0t>h~TlTzp{hfyD@5I%!;`IItT)639xF2!Q zh5Pb^tv+&tvzHz7CHx4l-`{LUxWln6&fipU&f%y36~bKn&Vz`b-gzLPH=h<)&wl#f zAi%|6nO@*WuS}D#F`HCDokPn{y}reTiw~{~KDaLU9q$A9>3EP; z`|qpitNSA`XYg129gDwX@%kLaO^4pA`!oC~CB@&h_`4RrMIh%0oNK!L9e=93ir@Iy z=D#iZpRon2#i;4(d;I~doBrk}g5T^4UZ2Bbd?;SsKjG`*&8LDlJ;4V_#VW@CG#w76L^gBqVGR%@$(k1`AnYI3+tW&o>H3e{1t!A^Osx+hJxtcdqqa9 z+w?cz;#))G(69Jwe)PSldTQR~NjbNEkd)ScaedQt)%Ph}6ybNimRz0D3|oMAYyJb( C??jFO diff --git a/example_simple.cpp b/example_simple.cpp index fff7ba5..360738c 100644 --- a/example_simple.cpp +++ b/example_simple.cpp @@ -10,7 +10,6 @@ int main(int argc, char *argv[]) { gflags::ParseCommandLineFlags(&argc, &argv, true); FastCGIServer server(FLAGS_port, [](std::unique_ptr request) { - LOG(INFO) << "request from " << request->GetParam("REMOTE_ADDR"); request->Write({{"Content-Type", "text/plain"}}, {"Hello world"}); request->WriteEnd(); }); diff --git a/fastcgi_conn.cpp b/fastcgi_conn.cpp index f5bf8d4..a9569ee 100644 --- a/fastcgi_conn.cpp +++ b/fastcgi_conn.cpp @@ -55,7 +55,7 @@ constexpr auto fcgi_max_record_len = sizeof(fcgi_header) + fcgi_max_content_len FastCGIConn::FastCGIConn(int sock, const sockaddr_in6& client_addr, const std::function)>& callback) : sock_(sock), callback_(callback), - buf_(fcgi_max_record_len) { + buf_(sock, fcgi_max_record_len) { char client_addr_str[INET6_ADDRSTRLEN]; PCHECK(inet_ntop(AF_INET6, &client_addr.sin6_addr, client_addr_str, sizeof(client_addr_str))); @@ -67,22 +67,6 @@ FastCGIConn::~FastCGIConn() { LOG(INFO) << "connection closed"; } -void FastCGIConn::Serve() { - while (true) { - auto read_len = read(sock_, buf_.WritePtr(), buf_.WriteMaxLen()); - PCHECK(read_len >= 0); - if (read_len == 0) { - LOG(INFO) << "peer closed connection"; - delete this; - return; - } - buf_.Wrote(read_len); - - ParseBuf(); - buf_.Consume(); // free buffer tail space for next read - } -} - void FastCGIConn::WriteBlock(uint8_t type, uint16_t request_id, const std::vector& vecs) { std::vector out_vecs; out_vecs.reserve(vecs.size() + 1); @@ -123,17 +107,16 @@ void FastCGIConn::WriteEnd(uint16_t request_id) { WriteBlock(3, request_id, vecs); } -void FastCGIConn::ParseBuf() { - buf_.ResetRead(); - +void FastCGIConn::Serve() { while (true) { const auto *header = buf_.ReadObj(); if (!header) { - return; + LOG(INFO) << "readobj failed"; + break; } CHECK_EQ(header->version, 1); - if (buf_.ReadMaxLen() < header->ContentLength() + header->padding_length) { + if (!buf_.BufferAtLeast(header->ContentLength())) { return; } @@ -170,10 +153,19 @@ void FastCGIConn::ParseBuf() { request_->AddIn(in); } } + break; + + default: + CHECK(false) << "unknown record type: " << header->type; + break; } - CHECK(buf_.Discard(header->padding_length)); + if (!buf_.Discard(header->padding_length)) { + break; + } buf_.Commit(); // we've acted on the bytes read so far } + + delete this; } diff --git a/fastcgi_conn.h b/fastcgi_conn.h index 387fdac..9a8d3f3 100644 --- a/fastcgi_conn.h +++ b/fastcgi_conn.h @@ -3,7 +3,7 @@ #include #include -#include "buffer.h" +#include "stream_buffer.h" struct sockaddr_in6; class FastCGIRequest; @@ -20,12 +20,10 @@ class FastCGIConn { void WriteEnd(uint16_t request_id); private: - void ParseBuf(); - const int sock_; std::function)> callback_; - Buffer buf_; + StreamBuffer buf_; std::unique_ptr request_; }; diff --git a/stream_buffer.cpp b/stream_buffer.cpp new file mode 100644 index 0000000..fbdf645 --- /dev/null +++ b/stream_buffer.cpp @@ -0,0 +1,26 @@ +#include "stream_buffer.h" + +StreamBuffer::StreamBuffer(int sock, size_t size) + : Buffer(size), + sock_(sock) {} + +bool StreamBuffer::BufferAtLeast(size_t len) { + CHECK_LE(start_ + len, size_); + + while (ReadMaxLen() < len) { + auto read_len = read(sock_, WritePtr(), WriteMaxLen()); + PCHECK(read_len >= 0); + if (read_len == 0) { + return false; + } + Wrote(read_len); + } + return true; +} + +const char *StreamBuffer::Read(size_t len) { + if (!BufferAtLeast(len)) { + return nullptr; + } + return Buffer::Read(len); +} diff --git a/stream_buffer.h b/stream_buffer.h new file mode 100644 index 0000000..4537a6d --- /dev/null +++ b/stream_buffer.h @@ -0,0 +1,19 @@ +#pragma once + +#include "buffer.h" + +class StreamBuffer : public Buffer { + public: + StreamBuffer(int sock, size_t size); + + [[nodiscard]] bool BufferAtLeast(size_t len); + [[nodiscard]] const char *Read(size_t len) override; + template [[nodiscard]] const T *ReadObj(); + + private: + int sock_; +}; + +template const T *StreamBuffer::ReadObj() { + return reinterpret_cast(Read(sizeof(T))); +}