From 4062d3cd633ba3a8ef7642f414862463dd2b84a6 Mon Sep 17 00:00:00 2001 From: Mohamed Taman Date: Mon, 20 Apr 2020 01:42:21 +0200 Subject: [PATCH 1/4] Add new reactive Diagram. - Show read non-blocking synchronous APIs. - Show create and delete operations as event-driven asynchronous operations. --- docs/stage1/app_ms_landscape.png | Bin 171405 -> 170208 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/stage1/app_ms_landscape.png b/docs/stage1/app_ms_landscape.png index cc3287492d8e3bdcb971bd290ab0d004cefe9c59..98452ac4127e1966b6392069e9d2dae7a00c1bd9 100644 GIT binary patch literal 170208 zcmeEuc{r5s|8HeW5|zjnSyJ}0XG>)nLaBtYm7N)5%QlwKqKJ$TV<}lG1{q9@v6PZ+ zrpPjenXJ=f8Dkq6%Xxga^E;pVT-W*Q{Byp4r0e3Ed7ioN_x*mqwr3t*wld}2C$ewX zu3fw!vx_#nc5#gF+O>zdmlOES^aqWnz<=BUX7<6mcJbZZ`M3L(VX4oqU6Q*%7mcok zJI{`CKXbgEx5Z#yyM5kuulqsqjIY80p90&X*#nLE56VjOX9j)<8AQqKi$D43WM`q& z%kP)eX$}1k18+LUpB%4BeD^#NyTv7t75IVU2nfT!hgS4+qre3YBXsnjD!_TpZ?MhG zi0SMXGXqWr)R9g-x(+iecZmPouHEc^{^8ooK2ju}%_eLS9Z~g|n z=u+V>qYatyAn(7q0&r>I4cPws2LD}y|JK2O&%#bC`fnZlU#-FXMANliQ?&;XB}K^4 z?Jr`x<8)-JuJw8#QufcUJA#DRxAjT+7*q50yG3%zfrQ{UhXc^Rx7ikmz>gA1a>djb zV(WTuaJp;f7OBp~V*N!C%wj!qv6%~7WaJ4})fO(71*K*#9|Aovi+ocg+wm|)ilzzD zl1mUWd=dhimLkj3Hon6&Kwf4Iurtb`oX5~Nde7l+8@lwasQrlXwBRogs=$ckN+%W= zi9fY4{(a(nQuv}|v_SziT<%raNB*pjAZJB+z55<^!cQxH?X3r&xu<&bD_1s1=CUV9 zu&z|pD9W!fI-P%OE!S!5YOg(_?nq6+{OI2C?cqH{%&rowleXa>MpldezK{$2+b2O1 zPnVYu(C^uQ6_2<4Fi*%_elcnJz{;wCSBiTaJfm;f>m{SF?Ue;HKWpEsqT5>VDLRRr z(H9%T3oh*>Zs91Oh>nuf_*Q|grD+y=-d2uD#GAQ%5FiddHmWf zs0X1k<3|MjD3%FwaG4G0YZ5ZrsL|Rj^rzvfD!ivpyiMXbZ7Ew6d#%?2gt0L1!q1+f zodc;nT|NU!wb-*!WA!fDpHjxzUj2Ma36Uv#o62YP6A|muE0-Ryi0`fki?`$55;$$o zQtd$2mnuF8X4d3TUAn~NzBKG3fcQLa;W z$!Ut8esO_x5rkE%pY0Oq&xRXz(N;XY-eV#;ZLG_*3jAp~Y;tDR4m8c+sGGMSGy5Ht zXlO)CR`3_ba>9bD;7JKN+7DM08+IEeySX_5+9r>B4STl6+VzgPiFv;)8l3z#imANx zEx1qq9A*{cHT|lEvR8%XKq%TJQVZV3#G$gDwuKyH#HmYqhVHfUwoSH6^m##RJEp*bsbwHYSS}DcDL)SS& zQ6Og?5hliSra4_vFh^O{mj(9LAWLp#x(f!&axbE@ykE?T%6`<@UC+CBX#bC_urG0a zUn+CI`5Ef2%?lx_mQ%VJiVKY=_8y-L2Ad7OpOgY?Uc|ubE^oBEMMX$}>K1-DgS-vN zlH_4VcacG)Na1weK>T&|+j~|Y&iR%uYI~C(_+V zAEqN(cVnLxM&nmUC25w3-rcy4{o`^ktx2K^t9qn!j%%b$&4(*;tjE?4DnpW98AArYzps>J&AiCHUP8;AYVYaDy|67rN@)!Dx>7OJ&u z7Rik4xQ`KBCzXdG9~Srzs6d{4@N6k1*{PK+&C98L*~l%5wT{QJ_DKrx8h;RG#HQa} zt5gcu2od7B3Js9XD>lrJaXsF6Z(HbyUgbST#;;io=9v|EV5bYCm2u5sC)gwg z!cHh87W_02uX8FTM5l#%N&Nn~UGdzP!uSmb&ZiF?wUrv1mU)VKK4e~Bbkk?Z4&}M( z@XB*auAKdT2BYc@#WVaqGNa<{A=$dyhb~!#^1}wvXHK=IJ6HAyVu++MPqjjdGHqZo z)fS0UrhRcORZWaNXM^43Xr)%(zHQ_VFWCo`9XRtIx45 z4nJ#O-ap*uxqe@5Oi8TSuJ=jN1DRHzAwEc5bI&6yO50Iu!>XVYwm~PH)cfN@6&|~D zGBMgP%`fwlTqi5LpR9CrrNi}=w4bdUoYAG-xw`)KqP|wd?uLxqYMYCcCpAvJ(umew z3WMqX(_6Pd6w58ugGNzg*9>0Gyn?3=XV^sB)`UQ?C(DK3=LE6)MUR@X-NuH({oZq` z&gyRGcHhBp1oZWEiftlg{OBPw?r#UAn0o!uXJ;R{;jVlI#d^5>VQH;+fTe{QJ?AL0 z{m}5)bIP(jCbF(+*-iuZA$yQzv0iz}O#J?ri1vDAZbo@cduDEuqK&*XI9?8wwRIe1 zo8xA5h;w-VnCiK@I5w69&mN}b`EUg_guiXs@cY54lwho@3M`HQdG;(%1LhH>7`5S% zW@5fd3pwu0Gr4^M(UZg1)iyNth?AiiJmh(|;EJA5IJ@1Qo5=QO^ zJ>CcqY{&prFN}IZNSVBay5Gf5#VvjP&T~`L9v7{!iSUnr=?{4U=dWfan09+;c%Q8V znKP+ZNem(%lp9I_*U?Kh+d18;6T(Bcy+G@fqV8)4x8*Dv|Jj7!30${N9PPk3Z>*jMLFrDNa1(7j*O={NW6&|pgdtBjSU9(^ zom-uFCT5IR`?%k`NZ*@6K1nvX=#U{NRK2XgHr89m!{UykI-kLMo`{7Ar9VE9M?T44@LEC6{>yinK599AN+H~-NH2i{o<*$b z+NG@Y(DhC2^|+qZI^x2#FW6bzFP7kktWq?;^0F~t)iC`sk@Ga96)YN1&GD$+_e0?( zZZ!C65rKGnlJ~?tHc8`@zWE6B3SYV7rG_b`NpKr68T!H&?nh;Gi1JS7+*mTeYA;>n zWLzCBT@w6q%vwU}R=2?)z)+L;fKzWk_V)a8KhSycw_~61?JuniT#=r zqw$N_PX}9u8N(b2b=GN;WY71plIXpDN42SWa*pn2G!zbbrW~0pp;&XVpLHtIAccl1 zBR@8q+t^{E$~Eg2$e!}0Fg1a^g9TpSvETeVdPIoY)RqyyVffShHAXY=J6i>iI?h zx2V(M>B4Q+w+rfwxI}aJQye4{>60|~KO7fH)92v$wdLN~NX3on?2p!I%gOGxu(EUA zo(?W9lHYk?IB>#R=y8v<7Ro%@?3oX%Rvvl_jYTzuHQa;kpT%FehFHdcu)~UOWnZD& zx{4puj~RlqBIV=5!D7t2MFTO|y3c1PYb~#oRmH@9r4NA*WwGm0GY)hjiDLIxR#&X% zgG)FWD02R1bR8xba(eP`lIF!~7Yrw3g4P#-{>446JIg)!`$2lAFt$t-2MRZPg=U5Ryg6%cN7Te#ZZxzVW6tbhw z@{W@-Vts_}Q=P`IaWEoerJb|y-ksncU+T=VJBmB``m}$$7(oi<)8bb<0}ULt1~p(U zNloVwD{%p$*8DCt`JrSS-RkjLi^Q(Cs>eahn1S-tq4qanmTb?k=|{lW?k3$29p+oa`?aIvN^0=YtBe|Y zqgAhv%&6l6u?K91`F_JROw>9S#vBot3vNHbrZ%PqQDec(wk}U<&jAOU@2Z{XNdC7$j3)ZFT(44Pxg~aq6t?t!Hstgq1YV1!zMk)6XXF`NnN9t@0tNVg zWJ)%*6wg<8J&?`I>8```SQ$Q3Z17G}cZd*0-h@s;70oQPco`h8w7GQ~T&c6zCX9H0-6sWZobInpxZ5 zh&g9~N{6wTRc0)|D{^r#RIHxj{Uq?q`JJ_P;^`{{OXp`0s5f5oxhM54ysp{)3(_Bn z_^#_@R_k=qX)*%s)v_l9`3pel!PU+->+pq>pvo+FnA;HSj#E;G**-27L=$&!jbeUa z*&75iYdW0c>DOlH*c&T511@4gF9}Z9HVOJ0&qv6!)QzG_tp!+r5Dz)nJ$?CMt;PMp zTcDuS3GNuBTyS>xfR$HgXfQtv<2&|(S5*&pj&vVevu_-=sT5vQrHv(Cicqt<&}(I- zlfP<~3X6NiTeWdo`zAI>k+?oDxaM%jAp|Y_%ab4fP34U4S-mFS)!gj6^~MB0mdAyW zw@vWmA_X8!=9X#nI;SC2whV8yC%Ol*yN&BO2ujdxY zRxIwJhceR!?;AVzc~yVbCoxLiSRZZ^@(Elu`kla@6?ir;N#3K1#EIh(;xmGZ?2gF0 zC1ISpg4|8-CmiYp6hJpMo_`STA3fGa(zioJA$LuaLm;s{9|^u!Ek^M^o0SH;H(Qj6@57M~ zp&Fe@%RaizJp$HVj;T{_9@msJLmaBE+6^}Khb@`c7TqSIlp{l1UO0(P>1*WyDCLeP zo9v)R=SKnH1G6(i`MAugwT?eh^hI(q<~Xm;GO1WZe!5Yo=%u$aHNtDCbt5^W#ytNw z>%gu)*iNk0{heK3zPQsY)Eo6wxiO00t0jLtZ2buKW=4Yq&pIp7FgmsQOM8}gg9^;d zQ|xF*c<#>G+2Y#_Sb?n*ll>15K$F-L4qwSRp;wx5<1MjGGlA(MV}H&Y#yu2mk7Mux zvPRPr&c_kaQn2IrLLSGu88^Yt;9nURWQpU&npbu9pFlY&UBsMQO@a!})=I9|Bb+lD z4?f}C7$~8nh13;M*oEAqNvk?Wh#nElZZ7N%p5|s{+8cM=okrvMb~VYv4zuYaOAG|$ zt)<_~5OmxjFjwpP;td`}cVvu;iez+_3{StPoBBoPU&qTVV6yi2gW}g1dOM)k37N5O zf4qZ}EmMZTI0DjM~eq3KT(`u()--h1M7G4SX>X|?1k#7%X(M8mI57m^9@7i z_eEDd5a+*lygiVJjq(Uf=zI9?zQ4|W-djVv?kdImA~|9OFM@aFVy2WF9b~@GWwNHu zeo|2dnt>3Xk-f z^TmP1!;#rYf58#34j*!Nw^oJHL$z({(AzxfCf zpQ%a-#eQ%4UR+Ju&o7x+u={bF?4NF_J8F0QT6X{aJa&dHbNFXT?1@srn8?8ho``w8 z6iUq^y-YT-l<$uQg(}A$cE;5^dU2&EEh3Go7bXuQKAJ5F8rI%B2i^S*+pdjKiir%Y zKIzdwx~SB9HV)JM;>49Zk}-z@b<}@fZD6@xw?MeZeXjh@K>pnl8f@-JHYp(QC7u8G zZ~khoJW~Sh30*8(&-Zul5?3JrK(|iMvBJN;_CIEgXAk)IqXf&*Ak65 zz{zM<$?AH50%PXo?CIU-I{Y7C*%|DN!<(0a_5OGy8?HR}i(l(6yRki*BCgvcPa6|{ zHHWXC@U0!bewf#cfBVK)*Q&7_h-1^ZZDu5HtK^IBBPqB=tLH5VWgleGukOTxXUB-N z&*k|~J9@T1u7Z2Ktp6v2%(Ax2o}GOhNjJ2u9CXRKq3jWMdGB}_ z_xK=@#D(Z2V)*4VI*su4DrW12MVqqvIg&A9k(BM|EXkN#VmkZ&*da&dzZ@}&QYEbq zvH!G2+)r;A+*+Q=&(FUwSmDG%@}JqOD&ZN+BvS;G*R%15GHYOqIP12+C>uN_%twO0 zN&306{wt!`r;%wGjK{U>Fw2YbHwk&cu(Ez%O}D75;h!1iQ-C%Xh!;Oj+uhM|KR4KA zk?eA`ox%J-pBl|#ZfR3Ty7GccEh4=mqiOd_6ZY9BNQtZ9Om$0w=bb@977hp784r5t zH{>&ta)T=wdv?73}21lgvnA5!I7BmVw5 z3BLW_=JhoO8T@#qxppa>ZaA9@@B9A!d$dKSqD}`K24mZ}`py3A+P|{^K_f67>N>FN zsnwalEluHEpvs6XsW{04o?m8M~C*DgU!DEZ$9>T z20vzQ)gz8Q-Cv_FJ35w&9U0b7aZ}JxZ{XP60;;Jpf=)S3dtTJM-3E^}!8vb7!C>^b zsi0quAQh|O_rpICt*xz0$Z$OHk%~n_?N{$>=Ec2UOYv*h%WTEJc&k^WFDK^0YlAeYKz)Hk zayi+g1owcwv0cnYri(MsYN|E-21fFZsp)DXbh32vj9 z@5>+qw5Fj{$^@y8fVk&Z`P4n(G_hxWhBTqwq`LQE((=8L+xs5reR1Pp=xm;Xf8HMK z>syMi^&8we-oCcgrobwBR9mW#7M%BD)s1e0C$wX{tVEOd=S)Gcju#d_bq>nv>rnMp zyK&{VWlqj*iGNgW*4b|sorrq*^{9M?`JmZ4a*}?-?ChzOi8<7J z-0Not4Q(%Y5DK1>e*HLlJSy^C33KZ<&}j{4`8eYHKs@6!E9)E`h4qz}{FY3wESrNg zs3VKNmZ-5)TP%9>S4-EYdA-dUk&-eobe@t4K9o!%?Fr3y$uuwa zVltT|+vO z{02fDl;kYcF}$Ucep=dq5Bh6yYD(53Q|~Lh*{F9y<}tZoPGWzk-K!YOdPjr4;oy~@ z{d~UaA_dE2i5xMe5ScZ2fR{I#yai{Be}sX^zH2^1oD=o;B@D5Z1dD0%FgvSZ;*etK&{yFe+qyQL zungu_)nt^Qcav#vL_$J>uAqvunCx~Q{=`IfQ$wAtB4tUa*5LVpcE zr?0P1;PY}Pg~?|;;$YQ=Kkpb$ECjL{FX=dcX2@hPNsBWs%$a zYE6Y36;ZBe;>M$l7H*Pj`F+3JyshA4l@)_Cbuq0!G_IBPdxg_0Gu(><4m_M#O9|af zAp8+Q0Ef(n519Vd#CKX|!vy~K_w0ca2hR((9hMyp&8gKDH)>>VtpSyP3i~|Q=&r7; zzDmjjxSA;~LlGm-a>*BK`fgXQwv;a(T;{0>b_;8*x(2{phOX|o&TKVM3 zN99|~u@=L92FqlZW+oY~f?e*lprg0_h3qg6^^YqQf#Wu7<)Dh-%4>By( z$%PEr3^ihEd$tMf8}HL#tAkOR0vh7ifc479@xE&87CaY<$2EWTj*8ma_>~Ywj-cix z2`a4*&L(f$MoZ0Ey4~A~VAGhuaRN~Sf(rcjALx5Xb4v&pLt0i@W{$Kwqu&ejQ59+u z<&e5wFxQ+HOj#f|OQP)cdyF=$WWzjdd~zfMYB5Lf2e=GNur}fbUJT)-$Qm(lrzLpUF4XH1pm z26Z+qP50>b3HCg7N5?}+uQyCe)Vnq5(Z$Y{vFd2mDJyh=?nz5@*DYXAEr4~5+0ti@ zpi$``9X`P4+uruomns7E#5b1lz`4!Rp;{^L z&E*~U)6CYUV`+O{_$(mjuc{|vHva+3;XJEM@8D=l`sNIPhGU0f=FI0O#TE7{!8(@oQ6ESp=6F@2_%s!Cim|uAJpk>p$91P+|A>7Ck@z7}6eA46O^Nr@k4Sq15?_ zSU(1;tao^&ITW9Fxvakl8}(~3!Xisq{~ZxBj67tGP=Bp4uEt!)d7^*azsDm)hWH5$ zdF>4IYiOb)EqCVO#5=@@U*u?WFdjA17_oF4KnvR&O5i$03&9Vy_Z(q_vg4GB%}>?) z^U-p}Y(}D*kaz8#ow`)36>_uY>smt};DA*E2h6Ms&G!f1&~l0YS)F84WhMQK&FhfI zMa`h+6;DEd2}D8%02o-{*#nI(pc%K~>j~x#Ilr8*_NvGdrC!vljkDI*4*)T)6GlGT=%Nn7+Aj%8;2e9^K81fV{V+Fa z8LyBROz0qP6A*&Kh3^iFw~^`rVBSGy@l7wc-VdJVBD3VYD1tsq)2*LLd=aoSHIZ(& z^acU7fO?v=&SBpLCi>=}aJDW_;k zfnt2KcmPnC0Bp`p@owlpsT1YF|DaAm+G>F&QIVCPh-XWU%sTB?yeW3OwnshD5z{R# zEn4qCiCgo-D6uPLF1QfZ>YOHPv#6*ihKh?VU~Wm{>#cRD$8@uced6JxUGQxi>Ie;S z;8KMLGI)N#6J6h`!|c#bQF50c+LqhBtpZ?V6w6R{PTFU(!J@b~gUnJHGDttzM!Ivk z)@?j zu(fn7;BW6s?V{^&{F-_3qBC`5Ccb4I5s8cO%m)|S*pKCcC89L>+XH1f!jNi48_$%+ z3r|KS6=C3X*bW8yhuRWW3LPSmSPMb*QE^2RGIO#%Wkr=bRQ#)cU&Eiv;eWEh{?XSj zm9*6Cux9-my}-Cvt8b-ii9G%=Sn1NN(>QkW(KHCqQQXp-VPSaj8)f|!IhUR>jv*zR zY8`=XCc?LkK=5!nOvIX>GC0Vb1de@e5!ZAsO_{!V8o=~36HvpZ2Y=RH_Fk&lx$@4S zCxe(TJ}27H&GLN#|xA@QkGbNR`Ov0&`KUGldbeuzD3VBZ*P_51zRtXRmuiu1}`zA zgJb>xQFe;Dg}p>0kv=n{TXRj`-gR9I6dWa&+mm}WbJ_r8+8zi|n>59oe6*So;&4WK zeXOH=28xJr9ozcy<%^dVboiTD^OG9}B}7Qf$yd5fPQ7V?VzGTq=%A_22b#zpwCrYC z5tm%Tp3p`YU26G7E61{ae{{}@v3XyOHrbXsqLtG#{qe$u3od&rwf1K7f#%0TK@ZMS z^QUlzH+tg`bwI@_W|)^!`$5)tA6f9RfsQ@ZtwD*$LOyagJ0Mr06LS+q-Wx_L) zhvC`b+7`LNwsNDKe2aAei9Y<;1P9xgMbj6gOKpG3dB39!y3Ati@vVfefsx$x^KTb7-Gu{3(PUAS#aPKhZ?_pg+1?sT_oU9c+{|V66ZV6`inV=GKzi-3^*XsE?W`iRiHSHQ(CxR5Gj53}D0mLfm~kKj!9~Y?QN_C20j`G`0ZQ z6PD(#)<;O4SUZo+8r=`rv{nFdcBvdR%rG9xbHn)Y8JPY@ar{5!+D{6qD7EqQ%Nvr^ zT#kAlZGD@3PXO;S&8xq!3{6gl+IMR_DohjZ?V#E|nqC2j?OTpd01U1^b8@UZSmAiE z;|?geSsy%KZSs;)5*N2y0X2TL`}sG}da1cs`wX-|4X^D+0HBFpuMVaYzRkxYsHh#& zlcN!qdaw5<>2x^L^|1`{fP4sWrgtMbZ_ z=*gh=C#qzabM0s}EpekW6EdTcKFxYb4}UoI`>uQ>!X1xn5+r5F-Y3K6^|Cb5G7rCq&jfQ@ zpaj^P^?56kICn(U)m3sI*t=b^{ zXj^GgZA#;*Cr~~?zqwBZM=QAh+{PMY6A77VKIYZiw6`aK?L1v>=pWk!L|;jz*OvtI z4obvOJY#jK`LZ;7GK+cwJ=xV^@Dkln`cl2;T6ZFbb*ZbK&Bn`?-^Ydlw%WwAsO1SF-U}-XmZ`~|!@)ry&#WpavYKoHa5|F^r zsskH#xJa#pwNi@)t6l4_sUualtC+eI|9T936r=vx?HF>j@BTxYqvuIt?L2G3A@VYCa!DO7UB~( zGgmn{Q>L_5kSM~qX;*;4Q05)p69Cz{xQG|wZ~b$$AVbZpck#(w{8|gFw3SoWwYrLa zgv^poH%jgUOd;t49+2)afO6V?O@t_m0;KZ3lMD7qv(4+qHXWuBh*jsU ziX?77Gf9nLD_UE-tD$gAIc=)d)8%kb5`s`CJ9R}leHqwE6i|@1lS3V|%V=5q z=oKzGCbnNN0I>Xo_yF;>)qDmB?v+RyT)joz2a@|3*ogCnkw+!T_`d%QR}pn}p<6k@ z^T`gV)t7~X?_>VlYwxsN+Z%G7-|&c5x6Z%&((mW**^b}+`rEYQ-@M7LJ;7E$JOHnu zqm}%3C8wIPlR0?ZQ~$S@na0J?l>$@twrVov`H~~5@EK+^ncf!9nMQr8^bmGw8nF&IHEm! zM%8Erh5s;7OM{*Vg+&3DqG>Aquh9-wEPI1~B44c*oNf)AFo`@`t51?-kd0@X*ZUvM zlRcfe08D5H)T9&MW@oihCcYJzS+bjl zjW#B?*e>uJ);AGf9&WQnX?b1v3krFTszs!tYv>O@ngTA zZp@*Le2>EwvZIuL2{u13=EJ2@`;`+5J_lP)zKs`Vd_b&L*)xF2X9^j47kE<7TEMvS zsk$T$gV@T?rXMEmL(kX&POQ^h$LL?hFV!q|z@g^rl2zO>SpWr=&tDTs&sZ*cer3x> zJ|ktGPH*;6*7z1q&yXbN4N48&z9R4uvEImp0a~`ELX!fs1$g1~{-ej?B1@{a)}3t-i69l(%lC zxu~&%Fl#caK!-}6$c1MXMR-ocy7gli;HV;$J6wTNQHRi27by1ROw2k8mu1ef+mZk37+_#1Axf^K*8TWOaC=H zGXsx$eQiAqM0i@0Rg|{A0@$i^z?8e5B&4!c)!*jNfTY&AoLw4$$ND)ib+bL10Exqc zzL_+kO%^#O{YVO}wd5v?Ge~h0T@WEg!r>Cm%2_H;md7V`hNp4OZ?DPcIhXY-UQ?;L zHwX-2@+=NRT~!!ElLiOFya65O6MTDXk{l+iEvyh_xjyAf9r2UdbPBrJoE8%C`dVZx za8fI)r;Gr?6>TIjB3-U^%=l|lop&{poIh9G5xn^?-R2HTp{mbwhufg=I;_pAO(Y`p zZ0y=SE64{HP@>`?hz@r>BXM9LlnSNQPC(-${k#qJ3SQ#=b z4AmE8Z8=~>^m#k*@P{tG9xRKp7`!Y@&@U~)>xiDjz9d4N6=@wE^d&yPxXlJYtnFFf zQdFP8N*7-adcQ!Cdl4aWG)4Im z5%@SJu_Hi5?NGEKAQyc_fOxB+AZ@wrG#(na!2n>KomTbKH*ZX|VjCtdDL@oAzmS?P z4xo2;p7?tjtJ1xT^W@EWqG4tk;uEmui4yPbK;_ zbirdU0WJeaCdvOM|4xrOmDMG9%Ru*C{xa&W(2&Mc^Ws>G^9ztuFGe`d@+^0y#XWi+ zeN2uP2~yeD(OmbXFE;2uopBRDodFQ-HmQ?V(=znB1TfubpEdX9 z83OBZa}DVhJ)jd-S;VxnFVIebx(1ZSm51zhq;Fz@nT15G*2cAT^%=ceZm`ywdTP8x zC2T(_a$B62W!2f>zk7F4UtTSJd)8JC(0}v0Boi^zR?crGv1JJ})s$^tZGOk^lzVvt z)F0o9Mj3qudiiiG%XFjuMhX?x!KeiBp51&5VY#&)`0G6G-W?}=uuTpfW|-0arPh-; zk8=ScEJ{ZM0IG5e(9KD;H;$eFfI0w83{_}xZqX_m_|6OkK0q}UY@8!a>!RYGt z+-^w&?qkrppA%?}9mCLmK~s7o3}2st)PmIo*zV*ydf^lp?08MiJ+YDJU_f*>)DYnn z{Sjfbn0dFSN}L$KPUDerQrFYlFeuCOCj;X|&=%a0%L6PahLlm#fjn5S);y@gY*0T z&$~K8+|O8UNOxtVZ(bQV(Q&TR%tx9! z;^3#Cn=kGK_~cvw#HYV;eO-a^;d_a9dNNCOu=*@Ml2SnF~#161mI@T}J0j6ueePMB=@#A`Y zj}@ibqYIrIJYYRbNe(fIGCkoY9t%h}nxw6MfW>?agd`M4fU%Uqv^ZtB^hbCzS%;~N zje*bOm@~P-?Yh*aqfPdGHzm9W%YS=Rq9vFA8SsePQTY-S0>3M{@Uv$<8KBOSXr$=l zPYRIxutPHYWyW%%qY8>%PH1o02pE@w)>EHnC;(kWm6pD1Dh*$Moy>~00|Z$H3CJy^ zeXBN5T*G_2Vs?BQ;Dg1K_XLFEM*$G7+?}1_ueRo5psl^OSyclHilsX2%?2D)f}+f^ zW5=4@0T(OwwQbo0hrQCY;~ilij2=ObHuaTvFFU$rlmLI&Nymlz7GHv(9VnVhoA8cu zUxmEI}vV<9} z=RVL)kRyLi~E!I=S!to$SfNPMBs`hxty*YA%0;d+)fZ)z|TQb`hG9L zU&wss1uQGpIV|O~)qLDqM@Wr>Qb`sw#YxE}#44#Mm3 zQ~{4xzKjA)8Xx+mmXM-dKv~b$B|{*5M4P>;@aratPU5%|p)uYkLMB@EfqZhRN^S?G zO3T{zy4^3feWW-52#6BKSCn2qFboQ(N5g<&l>J#6toe#bb^+uT>nf-AhEmD>b!P|b zMo-ZqvKN)GE0C$DpE{1wEdWawycNe6)#7WI3b`Usy!p}dodds6#Rb=b)cqUb^w=C9 z3m!j-DO_x^jA;4W;Z03#bsH6fT!uuqt-*7%SNdd01G~NboaQE+&u1O}kxbOVHj{ue zHa0U@NfB$j9Tff!wl{P29%S3E-%QDOF!k;x2$V0K7aUe<6ewpDwLU_UyoTMK)~Kou z?`drrG5eCgsmFU7$Hd6Y#aN$xCgl@ivIR)QkkPw&b&O#_?z{x53U3Ok`99A<`f}s+ zN^uPVPH!Ik$@J06PknD?d~8+fMD~P0jB>h{G$zD4U|W}W9|sg(6FlDr6t+jK2}Up) z79v@Z(3B3}5cCuu4HmtMwS`}uTytH3H#Vmk=REr@@b#>AkD6?v1TPyR^C<5K&s~(R zhO>wbmxuP&YvUQsMrMJZx=5K8WN3lq`U&EY`AINnRQ45bs>XGr4LhTCc6NpjaSyf@ zi$*)3m2ZC6v*m|z@tDJgVyE!~lsvggOUfFcxP0%-)jHfOSuy&0uIJ8$^1B~^K!jjs z*HjKiAZp;`=cn3{-Zq+M#^gOmVf+P0OJOm|0|)s$7g7ces9Xj|e)}L;g&Lfp`*J-M zYU8Sy}8k~HQod0!SJUtWk<-5fuIDM zB^Pe8k<2%KA=TB$3i)_zRXasxzlB@~|Cz^`z1-{HZ9x*2KjpUr0|FK*J|+o~_F#6h z%$8oFTx{y;$J)3EDZoP_Z0i;_w>k#Qjyko~ey9pB{df(muj}@$qIri^gDBh<)7>?a zKe$Dqy;?=ZRNK%f>i%5t0vM<3p8Aco0>nR!f7Jl8BqMyr{&j-HYYiwR8munn9 z6^$(a0eoFUmZ(Cn>CkVh-o%iUg}ObjIRSiEP$ilh?kU5orAd?)Ra;Gud#@DB)&%{)Om! z()!znUil%^HTfM(tKb8pj+6mGSMP^~HFb6UDb^OV$+z{(Zd8)t?J456>pz4eqE%Fq z4|twdQL;%Xb-Fw(zhG6NtCVmPy>i2BJ@Cx)5VtiG)64QdXos(K>H1Jgy||7es??Mo zyCt1>m|IFir2~eB9x}Hez_n#J0jEqKPS9sIdUa(g z*;eADNuj%aBFW!TPYVF~SsL)CSwH|xE2c*5iff|aHl1bxf4>%WM_X&O7|I-Ql%7+ANWO^ytRek?i^a%^b zMXn?O`Ijv{c3VI>fck^igw>X)P*3GNR5T4*dJr?zV@+=m}_`+4Oe8PHsv!OB_I zE*Sq&>ns%)XNQIm+5`}<)dedJh-Aujgce!(w&_xx0jg@?YqA5cgez@>;YEV=McDV* z`0NQy=!-!hEzI-YVIWU=;AgJx3n0vk!C;szLG_N|ZwGRRSH~bMATg7Eqp8RNl|PHy zeqN+RX1M{_V31eE?p<$rO5(&C)lGkSF21gDmzJIT(vVbAt!-Jq2LLY`nOc(^#nAY* zs+8sxiVF~$At=vh-+e;cKfW}sU3V`5tSkwhd{8xdyEc-udM-mqfRpFzR`I9<@7(a` z3hBM*?f)cy0-~|N=o;9h;u!pT5AH#e?&Dh>c3A^XPp0Df#)AcD!gAyi=k0jR2|*0F zytZ$Lw1jTH0osZtOry%i^@{>*?0ed6^+x8);{0CLUcvBMtvADXZ`ju`6S8E7vSMDX z2wgwbLu7*$>9Q_3d~r1{bgqZ`8*4ccSFvxLr)3z>$$MPu?r{S{*#Y=2wmlS#v05rd zvMB+fiP_0T)`iXu8va)5_~ zK{P8fG<-0R9f&Ddu(ZLlf(?%zJP`UbhJ<8?y zPA7o4ZX=9x*nk?hz%f%PZmIgt^-z)~QXeul^0w|WD%k(JSbMC&)YGeiJxDD&B{x{e z%mE>OmwO%Iv}*kCwC$4!K0ZD}5}ZQCHCF)zhy_AC9RP!jEHi}3UIrqGC~H*_1cs+^ z&S9ER0Ha`311!$GtLY+%mD!>q-CurPD=gvytyeL(3IXS=fb`rlzzKMIbxS+Nu&+X` z23t|Mv$ZG2(7aYdB>9&~#lxooM^(Mo1c>Lytwcs&$KL5}N^gvCOR`Z;4+*Y!jLG1w zLj5ZU1$JGv?0DV-u$9nmD5>rvqWr){2~e{xLy>H&o~<}08JrgK*6D`G{nYk4?;nss zKz&y_1W7sxe7(j^1b!by(+mY>?-_%=;&rb$CL*%F0l2Xy;xw8R*kxLHOaW_2B^&74ElB4{mNoWY*KH`bS}0##tYyM_jncQSb7sd zIm3KrmiKMSlHj`%=d(=)PQf70@fHbPLm)B20`{&9~+<}BO zLk(n)2OAq3#jFVycfBBZJ{qy=+b>;mItZqvv~&%JB*@4no2xU{l$(QbN0OXZUyjm@>enmDPKQn z6>CruY_w=#VcHv!eDXCJVVYh2P=bYDsP zQ&K0iE2c-mHlgq1+h%de^Um%sx{D~2nI%3R!yq3KT@xGnc5uh83*?)oQIFUetqh2G zqUod<1X;B67*1P5P+S8YjQfYX9{)8Bb(Lflzt(+LB&<$8;+wp;6{nvvhCXFEdyS{+er0-zc?%1vT^== z!hpa1Ek~g)6m%}?eo>ZLWcZ;XhoM_Hm)ikV?f%x* z7R7QPIUJzr^v!fx@u%JRZ6M(ry~+g0Q0Ar;xccN=F(O}>UB{Evs+~d*@dILDk~|4G zrix`}j@YwYEgW?PAUcWYxxOj2aZ`UKZb?HK+EGw}__1R##rGH;vrISOLiU<0{Xibl zn)J}f=g{2^f=V-Vr=XP7(A^~hD%}W3cT0EI(9L=9 zeSP=-@Bi5!&$si%>+-pn;TJ3Jb+3Cp074}74SnAcT5i2tPeADpAoNBcAWYkRo5-}E z1!x$XiQQV!8EfYOZ-4`A@-;W#EVn?*!e`PH$OXhx_Yh;9H}i zzv+0(Vl#%VYHn#`=Z?`0a{xN!9X_)>7uQ*>Yc+KuYM*f}ISHcHqs!JBS)l2>4$tic zVq4xBF##YqUD2@s%Fi@RrfbM}k{)T#Te+==BxZVT zSrg?THMr*X-i`mYD($X1FdsipU)#%jKI~9?Gru=e?c2vo$Xdn68Uviq)8`lt10-?G z=+=%R_XC?Di`DAp(S_{H3p3d;znEE~ho+hRd`UTW`vC!& zk>o?m#hgL}TWRt?^#I0}fWWSxBdPpb!23VH_dgfJE(MIwZkV?@&iwhk|LZ5! zsDR_-8c0R@pBMA5hLdpwIxrhM{Bfh|zchT|5%VR1cA{k}@BeP?{k@1npIPtGLTxb5TyLD6tRvN)AP#yli z4&v|6uyZ{$K3Dp5{?kDI`GxC+z)Fd2+-#r!*CYG?2J+8o{XWM3Zy^8ERQ}&Y5IzE6 zGQt3w5PNrTy>vg<4ePjWR2+Drb3L$XmBAciPd3SG<{kP!bcgxcfIo!(;3fGJr_`DQl!^oKzd0lyE-*9D7uNVE68JL!4>DeE*E#@d{@Rfd#}y$m=B*FV zCk$~O>6@wd*MM$1^1O+Y$2Oy0!q^2B=ff1~UZ0W4Tvg?=$zC1p*6{Bm0LL?> z<42xO>i@?tor)gh1>Ajojm*G%6J}iWFYnQaX^I#vl5Q=!M{ZpN_A?7kcJIG7Pd0_c z7wWT`et<*ZkX~%MuG$_Dp3lm-Ta^l*vAw+OdZfRo%N-JKo4 z+X)H+{)s;ZjK-oj2Cj2?2~8(?b^CQY4rLBYtsnSSqr}H1CkqH0H^I|DX;HUqo7|so zTeF0`SH0lFx0x9rS-M3hd>NuB0FxkbowfJa(OclN0jQJ4^KGs&_i#X1RtTv3PS4KP z4SSIY^)np@1$oZPrG$>6`A&w!r6P_mI)x1fZcpz^nzr&&PWsG*)HX7F?_w8BJ@(7I z_pGSADNlXcp3k$71W|+9mGsJ1+HuJbsbvUd`7E1JZucVA?k8rBZ*q*XrG(GQn%S&T z$=Q#Q_U9ZTn{GZ7pVlh*>htKk#sT2Q8z?nwpm*Nu3nZ=&LpL`Itw!4a9000QlE~9` zK(Mlv>NpUMbg*=mvT!4rVBqpgTG@9POt{s@F{loV3s)@2aN|`y-i{}~^S#^fJqgun z5IbM+Z6>|ll(M?LI@N7(gR#B?%JbLP5B%}yM)Tcine*wm)=s+TzKXAJ^TX`p5ijt@ zP**`#V;A&PhAqLz=Q?ArZo?sL%?;;V<;SeGOo-S|@h_HG7PR(+*+we0ynF7>@>UfR zGeiShtN|;p#~qmAgnT>O{bkziBiPTPw|=^tm##W`iZN(3v=S7w5tqEp(61J`ppraE ze@(hEo+D|Rew+vOxN$kC$Y~Jg-}SXJ96Vb;TO#R)y40*U>>bP5O67bZ;oo=WpB3V- zg3QVB-`!14!_KOOT|2E^_VPVVCB1kmkthGjwTK9>u_3-yE#6xrdG$|qqYrgJ+5)?bY7ClaxF8j<*DhdQk-ePAA zun+Fr&Dd0Lt;Q%#z@ree6RqR6yNWY8VwTGrr{%`6d34Ko?0h&FUCzTwd|TbQ2Ou78 z1T90Kr1`6l8vT21Gj}8AoDp(j?nBs#n*JQDmsjciBNN_LJiU*5n<~EQOteBF%+{PY zLV4fyHXHOd8wu*5*Y~?=C~j)w*PYEgTe&Q;Dn0XE$iKc9(Dx{-%%Te;y@4nPzC;2u zJV!)9y}{SVP{H#@09x~&m0t+V<)omV_k*52m=@B>!<-5!=K@$t)2n@hwJe9V2i{7- z%uMbyP86!BNgdYIYt$orucBJSeD)O~>gTeth$^KV|44$*fs^u&T-gvN^73I7!d+-TI?DEHUpSe0`UP_^QHUU!M zYS0C#$T@slXZFI-uAEuiOy-eCqKG1u-PxEu#wM)puC;d5NxYGy_ae0_fY-Pwl=3tc zrUW9p2oe_sp-Fqj;la?uY4xeHUisPSsEB2@ls=O2^7eWoY{YWo#YH4+M0Rm$zQoit z8Cu4ri^&N^440HWXH4=g^ReCYzDk9rE4PF&Gez|qW_THKPpC1E6`XlAeo{|^=WB#7 z;%mI%14ERZijZkEAW?60s(KmZpt02O-_Ws3M4I5ixR1b1Xj{X@$S=NA&IJmate@J% zMLjBwmsc2OHBTb)f6f8_Z)f)k+yVkA4Idpe96yO?(aT?dL})tS4(QE%E%}~&)6%Qn74L)Wxmz|XGHUANGXMG2+JMeW|2*zPAOUW z+?{&dyYdj<=o+;<{jAcURH##xr|YE?AM^w{7hMM;eSH^Q<9kyHFT=nmATJ9xfhsD> zE2==D&IC)+&=ckN4sx1yB+9l3$xo4v6lBCOsBJzO(it6|D)I4qwmfFw#U~ECNUd`e zfc$f(yjv=BMOLDpVp;$r!82w{fj18F}7WAE@0ZtK8-33z)&SJuu7k0%Vrob%C2RaWJVSHfBN>S}I~9$du$?5i6* zD;2w4$49#~Lp>FytoPZXNMIF4*&+2P>NN(i=+`X~qLMeL=qHniNEfoy6F)OVj1WW0 zyve*X&bZK=S#`u0Uw?ms6{Gecv!D!Dp-FQgQb~3^FMr#+-;7*l1Rtz20QU+AwL0Os zyjD@Ujvo$s%>)G(1j8=A)TY;H{d0AGXm67J1S!+0`M?cIiR_{hwK4j1GHFmKupU$?DJ2yqt|l`!Dq8O2$v{(I{&T& z+^*(y2hgpeDyN)eCQ|P+w5OPsEqo1W@cBv%h%h6Ux?pqUR!=l%SU(!`NCv5gR|Yy@iPx|5$Z2C8 z!@^M$N=;M$3npy+-4n&l>))gPtM72B4UFh4Ej@iNuD*4+8bCv zN@6LLdy^%4z;tUrFgg{+YET!vX(u}_=D0amUtL%r>+P&h6g2V5X;T@bk*;!id%gf} zj`fjhTry7Hn7bL$JjUaXzse^*cH$ssX5I^V=Lr@71hL_d>xy1C36FKQ_&)+S16*=t z9rbbJYtUe`tOJ^V2%O}7jR(gzmvypSe0#4k!n`%e~`UD043jT)PLB z!GVs&y^il?Z_yoQRy2_%Iad^?s+x{wXd+G*Au)N-I_6kz_n8PP>`uDQ6N|yn!XcFO z90zK*K))69;Y*}v6m`M&2@w?qS}4JYPe8VH0<}doRz-aQmaWT=IYgcI`jl6Zo&RKW zc6ffY#85X`6|q)L{5=#b(sp1PM7cnbgu+@bjxnxOOQT0s!X0RQje1KSC1r0iP^P`H z{busBeWR$TsK)1(k5#{hTtW!ktQMLyG^9*1Z-Ei&((JSaHP`xTELzO;%}Kl1T|$6M zlWLcNC~dWdvBSa}m?{QmiG7fG!{@DF#bB5^(Cwj5-^u4apCyh0`#i4e6Q~_7ve4*x zj(fQ{j>n6aWy|V3c^?ib3)b36+Bm639-EjS zQotdAx!f7sb1BhAN#zXB?jIgKcW+9rZ;#pNb~HthZ$XE54Zc{B!dhN4+Zn~^KuBy! zi9SZdNUY7v{*v%qOibK}%!Vm#URl9F!+c&OPx=Qo1GDc}?0pMg1nYe2zDspCq$HZC z*e|%yyXZuzzBIS?S?|ovQwx-S%gW?>B21Tp{2o0TkH(CzW=k~@SRDMel6yMsW;6!- zDQN8ffPo}(Vn=-@WBi9{;+s-xhTvB@ zZ8Zg6DzrmB;PLC*gm3OEbymoYP1F#@0m>mWTlKH8UpU94%?pRklf|IvFP^U6RG{~C z8&)Wzwm$xtDV^1@95>Q!_Zp#;+K!(a{)MYdPv^=yaHc|TyYt@O6?9G>?&Z1BE=(To zgQ>4e6l)!Wt}89nIWy^2nEL~82I$l& zK8pZ5&wHO6P<$4?T*U=lmabdT!7J7dl`{h2PttTqw7h~q_Lo@g{y6803duTAku6Jl zLNB2DuyH6?_qSD7zVnb9-c!Gy`ewQur9N80l}^6AH}{+Xrf5Jg+jWfkrA)iXV@J4} zczF~i0D-tk%8Ovzu8|p*xjlRN@%IBB{dZDJX8=z zxKUFQq;aUbzuGBNS`DUqt+<>V$UTRhdBRoY&|dtgXm}gQa;;6?*LG*SI$qa%)m;f} z8HHlm=?;r}y#VArtWfNsf)o|`9XyDmKIln~4X1nN)xLL8j3SdXMHYp`o!!Ot;z&f!J^%<6VW~0HJUa5+r!I6PV zOc$AsHQwh-IJnCy_3u%$^Brj@-8=^_^>5)Y!g9?*maUp}7PUtT_~$f3XSt~66~J~C-kytBFMny`oj@oQ_h^P_$$ z{x>w=Vt}{{f^iZ;_whg(JP<>Q6$S_|NxJNNAK*1+%Z)@_BczXka|+6I*_pruBzKR{ zE`x(nbMyhYS7qT`P){OJ?tdUpZWh{8ue*8ZGo zlVvZQ@fQPS`ca==4^`QKzeATAVL0`C4)#xyJNS%O_EygfHG-2kE?cme#{F^%{Iy%UYYzwrDss?D#*ON zNAvUaPx%QL_2N5(vrsqa4xssL%@hp?BrYg)1_bZXSZTT3Xttq5bkU06UDo@O%qPAi z1#<$eXOz5e6wyj5#@tvHMr+8UPJPc!%Gv&8u z>%j$0W4F<7b?gen9c3DDA$31Qtfs%22F*Q~e>%xBAF2GJH(c2LoI846ujb*R#nD)z zpDXB<*CltIWT|(@sBgmvyGFj%I?^sGB4FV_?a!iP3plyeE1(rJ z@tD14ST@JuCAD9JtHHs-W)FP9Ur|Ve8wAuzqbIftO)PKt^AfW*Pl0+iL}&DxI+2jg zkePBsrb>-dAWw)vnS4)JlDc?HL{nC++YsP zCU8TYaJktafrY=hZ{Or<*ZkMu!F)1x(g_VjNw|yU!=EUq7=0_Bg=)zFKY1xbUMwL1 z{&DZn=GVR9EFI0F^!@FRiUwF#Q~db&SP0q5^<^}}cV?6~4oR~DxQJI$l9))jMd)~# z-RGf^hyr=CtF4F*9PqM6;?YNDrL!u_`@*qa-W7V#wK4c(luAJpo4Fgc=#(;4!{>hy zGQa^x<)B3c4-P+G?Diz`2e_W_;|dv=S7Hklf+_qbe%#|%eDU26KX!}wUABF+N0E;H zsShK*8E(eShGHQb`{xGW2EO2{9L4wSmeKm%!5LS_VJ65fJWC-$zP$84XV=jRU-gWc zejCjbd=T=cP4h5{RAh0g_Nle76NsV6^9Ju4$uge(&iDusORew zhD?l~8C_U@Ve3t8-=z?fB+PP-}V;4 zsda9T-4SkC1>~h~jRy`jQxqmUDTS(cxyu6nNr+v}h(HNj$I`!#^euRBpQI~#<$w|X z0uPz9+wYz?Q`eG!B>?P2;J;>@9+t^ulV0RX(8O zl8d`-7C?7I^=%|4*OsQ9&2S6uMMWQ9jx*tjj!wU2xSCw@se#As>POsEp0o*KeSg#~ z2gTDlYDEe`InCbo-%F0~VgITYSGxXnD+J zs*ODHVJEO4@q_r)F&PLr6Tn!Jd*)uio1sPp8~GSSc6XY9aJ+FsJ5bP;ltd56Fk~jE zlx8(9Xl6ylw2?O7lajO+(I0w04T{n;i%O;w#(5m~A^Q}!&FZ8Gwa!^`lWtpT_$psP zP6gXen8@E=D_Xmdn0Asal(5Y^Dmgin!%Rsm9$&pw9m&V%PBY;L<$Mx}OA}^ZcJvzy zEq^cfp_8re^ld?3`LJU2);$oAbvn)h66`iloXt6t7v5o7!WdbS!Cs{c9){%q*zVuV zqM?}a3qN`|;aAP`w-Bp}3tevdAA^lgL(P(rbIe~DQPVKIau-1JEr}R4s)uerqGy6L zaLu%b9-HP_byLoR$!nj}M(H5zxbC*MW+b$oFA0i_h!7@XA(Q!*= zKgx)e7@kynokfow3sgw6z*wJweUw*|SJqR3LsL9Pym$680GO^Hji|hLS{f(}>aL3? zYZ}3B64LD?aLnM`5h)5Nc`g?C2sKH zKoO5Gy~$K7Jah7YT)YvpS1%ozs z+G*N%_FP)J|EeuUM)tHs5AW7eAhgug7@m2V#4oPUh-78Yo9{ff z1BeYla3u3rdp&dXQEY?h-{!V?-hd7Oy(81xe+BQ~%rE&lZl?GTT>;(vM`At@8xg*t zIs+lE#@sIovc6@FLGWaT*&YiBryf(*#`OqcZZn^1ka6uE`na{fV@#F$Xd+q1Dn6!Z>QnDJzV>U zis2S(*!8y2QA(cN6?e*KlkzO123coB{Vgb?{ybUh-;3FY0|hdqa?Y~F_?z}kJVE}z zoB4(J?<>=Ic0Ye+(e7#rIDe-Y{$sZ5DVzgt=8p(@lXsvD8Nb<7w3<+n2E~rUdt2k< zxNGiuYn7L%2L!<%S-Fw1da7Hx`iHq^3h|FFuNOznLbFYi8lqCassYeMGOZ}on=*&d z+^@WniBPJXZ|&tcA+&4EPHrv*C*ZK1`_>8XMtVZvFqb`QKzZyFanGU-oi} z0QArW^-_=qzCZ4+E!6LBN)HNsGgjs#uc#152psCn%z&&Q0W1lzt3SyPfG-aFLbSUz zPtxQ&t99ARG@gLVJ!kAM4nYk<#(2{uHRh9?6+~!d8jOBR&X1|Oq)fG*AImZ?r?sxz z<@iLaIGsuN+NSML0dTHuuNEF~#gW`2k)EVRc=;B@R*bEfVC`ophrV{3sM&*PGGHDFjtI6r3JZ zt-N?gGmC{P-pX-c;uO|ud7&a5uXT7G zWCSc89*M+*GVi}?f7gF`%YzI@<9_gD*9Jj4Cc>x$$;haaG&v#_CmgBVb{jv>@LddY zdGO%(UO)bK2m_!Rr(^DSgJJC@y=Ga%=2@qY{UGVa7eTAyB6ngnAZ6lfgwOnA?tYQT zHgX$nT~|w}y@7!RqB`yTf%98ExA`{2C^8&XcK*f!pwKEqZ9gypE4j&eI5c zU3ZOiYGbvN{ge!7WMnzO@U2HES^6RG=|QBStw>^vR%hFe-9!w5Jb_flmi zf@_6Z3tC1+5n>^mWaD|0*RNX+Z_G^2+?dtVpW+@$B1o|r{G14z%pARH?VQ9Cg7-f} z!+7s&C)7^;sMp0nG&FsG?-%Qbql;|4N-?)e6QRH>UNW?@h<3_(Zbz*#Ww2NDdx{}T zF7xqB1oYMZmC({!EZV3Yv|T|Te10q=v2Mz&8Y0KY`{QX>kFiNzbC0gjFGcG4?3S9$ zq1mt9Nt&=vJf3w9bS^G-TLt?jiWx4xXO)MScxN9CE8zLvs>#?TN^oHVG-cRZ^0&f&t z?UJBW+2Y0J(~8eV@K`aNBDI zryeIPyF<`zO#zeO$bngK!|tBcWZD?GT3*~PSp;P85188{);#(sE~4BXkx&fk z9n2}`C00d=&K1$`q&U=w7t*M(QOb;F0by;CP4cHd+m5o|MBmV>F$+_NP_50C%L#l#1(zwFcd-n!y!l+MHBd2yMU7ccEUjp_X3k5O`HKy{Y) zytmf`;Cg8grQf+e5-AHKIk3OC6G^%f+fer6`}V38{aSa|{sGlCt8?>BoE# zagcj#cPpjPZv#E#25x$;eC1h)n=>-d2u`qVUzR-))Q^Y|Z*9Xf=OT(l9i)3wgwad( zN$fHJdlPbbfPela5b(7D+#1h&3foSa#fdpL{gB$AscS5-+1pTjku8%;6-og-q+=c7 z_9-T?S94ckBiweS_d0_*3*o+iH=XX?)xm3t1$VfXjbFb4Qr@0@Q=og-qVR|MSVafc zwJV)+ z@CvQSz0hG_WnZ|Nb^qUJd65Mug6ho*_CT<8ju0RX5PnFEe3bW1Mb3`YH*gJ0Eb9gk z!eZhWZ9GPE8WeNGqcui>uPc(U=s0Mn3D$xhIEj3_*_7A@N-_HmdJ;|jI%yw7fQlGq zYG9M{%CJx|<-+M0FV!dR-;OPR3}s^aDJb0QN~@t;-n12=fOOg#fZ z_&AOds!dkxk8K-XbwMdZ8S1oIgmf{FHZUd3rPHO#{5!OKg|Dd#Jf#omYeV4j;zK+S zvCo%dL2A0I z1ZP&W;aI@`LE8KAXsepPjjKEf9~S?vh^I@ePpv{A?}8jn))yy6byQ;zcQI@T8|T

yCY%}qfE;x&WoAeN|D1nzbN)1*cfZ5hbJ9M!>Y(ixp5B98tUc-#N zM-%#0680Hg8(MZnw^mFfs)X`WRpc%dFOs>Dv0pt@=A*1A zU8B1)ly}RQqfe)f6;k!IkK$8YqJt#jTjy-|g5xf_3rQ`84mW2a&zHUV*$eS*E5Pr6UtSa#*xX-^^1xa3|K92&Ky<`O z0)-h3T*BLA9IWR5dMkhdppYr#$Rxxtw{vT-A`a{fhr+@dg6ERVsTejv3%_SBgL}5M zCJ^FPLXD=xU_nm({X!QiVsSv`t8kF#t#o-9ZuER7r3%U1BlcQ98o%r0YV*3HY_tiG zh#=_rs2hFL&#=|bMLXkMD(!JGdv$SXsgN$zDKS*9;2e(D1#prGRg9}~f7k%h;X}R0`{BW(zN-l+{q`u+2aoFL-I`vf z^tntfDICrG7R6a@VrvZJDLna@8oi8}}@9O~6QTcpaq z=Q*W6>bnO6;5XA6Gh>9QEE*dNZ3=ftd_ClqGnb3@w9W`uAL=i8@$f!h;b zM!ntj{Zkvt+2Ujd!Rv)mn@lHGythWxqNW0qS&ye(z3_ifxMyhdhUAaZMVM^4I({|X zk<@Q?c@~~rDH)Vt*g0UMqFwJ$Yi{Zh)1p6;GLW)8A66fh(8#fdOExDD%*t)fmdSFV&b}h2Ze7-O(|QZ5M%$+VjQQmN{Ik@T zvucZANU?k^WlNMNa`i=SCYj#wRfg2wW{-lD{posRAa8))2e+|yx0ipykU$C$h6d-! z(n)~(mv7Ml+%Ju0!Qiv+chIQF!a~7X2l7!%Wn(Ue-S2(56)@#c3!5d*Yy>nmJY9o^;#c?18AR$X`$hwT;)Rwm(1dxT$yppRYh_%Cc|Gba*+`==oLf7&wZJcZre|sB4ZnXXl>44RImv)NuW26_On0fIzbWJQ z2|dhBkAHc75YQq7@c_PSx31#A0}lbg?%`zXn;@M2nkzbV_y@1N(5@qme(q9~*dfb%7fX{l*{QnoTydF=#36#C!IJUm9(~ReQ_Rvb zH0oTgDb40)H$X@n)@&GnO<;(3e$cse{H+Z(bM$lBQ7gpl_;SQUGU672&1FBdML;yO z05O7eI>_kmfd7Q_Bt*JVTnQdy_mWnTM3{12%mNVFx%Vp6ceP>v#>P*87#_qC39UzS z3ki-4MHq5u(d!qm{|X$W3cwzvAXrKf4;1zyC-7;-9LFzNwZVgh zm3ijQ$HcJs)#DD|JCTEPBW@SL*V_UV{o^LAO-7#Ak3OYylEBUnLd-Ab_^X0Hho@Bk zNGKqe3%G%Peb$|?^Kb&fdd0_VxdmGP`W1! zzhU;&AUghMMU7tjIT?Y!k9gHg0qKB%>^|)x(24L}%~wIs z9jvP;30eMd>^>GzI_rd|1(}yiPRm1nP=3R(vA`BATN?wX6#6 z=;MSekss`^Mt8g>3m^C6%jET+)g1v;%Onkl-!u8bE|~o+v*i9q6!NOfYLd*E8*Q+4 z7ceMF1j5jJBUefq4PS?WC`}DPOA~=-f3RHog8`WxU=99dK+J#v4L}{grtwQON@YhrJRDN5TaK#Ec$b32#TQ>FX8IorR$X&$|?|*iCVDESku4_ zjkz_XxL*}pm?Q*PeE%fbhM_N^o%&dR(rm^7AR#-=>XiRP*ZK!79Y5U7jo|V#poDEf zOr-$s=9#5pg?&&k&r=NT3S+)}#fzzRjDD=Z+qKSv51*r1t963X=TgcEkqv6)Xq znVI4@J_9+FR#kqSi~DM~JKR0`9zk+)Y}bQXoQ$Nf3;t>drHLEF`ogmx*CwUf=gDN5 z;kTzCr8tJY{_|rhSpRHUR3bLSejuN6K6BD^Jz<5VG!pFfu2lJYW}0DH0ZG8w2VaEY zTB8j#&oY-ty{D4P~e6sR(#jVi3v(c*duTsYqKwy_x0 zli6cIO@LyrySh`*M9K~4Z`APL_GJL@A@kLqt7w&Wiy#C(szcC z_V}AZ7o!@Kn1kNj^kgKMtPRRZc*^37^DY>9@AzKWT$x8W!Jh=6JZGfJ4Z1;W* z?*le?fW8naz)WXcQYQf>#;+P1h^j37{X1_ESSgLc?RvO})GIl_TaQr}I2qID)ghV! z6o7HnZ@yo%ZAkXh3i*@dW9gd2y2XCg!J6+ppT2O#bt*@$JnWqaIb8gMN*ri`0Kn_G z;5PC5i5?I(XDHhP zVx7|lSmiE81X{}UCx&^bkWoC&{5I7q{HxvW80T_J2i}|oN;pQnq|YzJnjFiDP-Hbf z-;elJC$D|dcstC@P&v_(4p|<9Q4vTzePu#?_2k*!$!6@fB~Xu!Sxw=k)itas3tRTQ z5Xxw!u(mDPg;Cz+bcO${gjU5;_x_}oVf-wu`a%Sz!N3s83{P~O#h^+hqe?XSH%ZZ) z7G~M;7fI1V&V+>zc0U?>hSD)C67qq1P8ma%lXLnx&<%LCE#g?(^LL;jr^D^Sr}Sx^ z#!3+#9{Wf={xN$DIqLTE*x^XyhodWxzn-5Hw(=7(l_!?eduPKW%}x9JGKX%p5kM)R zU!B)LP8(H;C@*n?1vg(!vFr@z@^Kdrjq(H-@tY z7<; zbahmQ&XNk0EA`#p)j8C#hLX7_%sIb>is~SR-|D}E!5KHOTQA`UF2It5kg;bXOHsW5?lWqPx4~` z%*spf0is~TKQ6M^JeLN-gxY8>U8;&@^6$>T`WUCh5FndU9~_|=sbU4FoGR3{n?XTY zfTgU;ipz*R&~6kZxMyGi_&-2sBC&+<0}z7a`Xbzh|2Ry_Zhm)cuU`iWd(vN=4fHaS zwtMG0{w4$ciyg+EW4y$HszzUI4(9E++An#erb0iDO5>>FNoUM4&zl^v8PIs#g#Jy{ zv-{6VkV}PLL<^ty5#j~Qz+J87_b*nm!*d{X;?tXUxZJ#>iFu8n_~3?!oVKlq4M`%% zL6y2VN3oV`$bKX9eSL5CCICexx?3e{*aas}{y$|LsGvx?OuvNo9qSD+C833rk>Zoj z%^sdA{M8I)esk<5q*s-sP1DoTJURJYU+%NSR~}Kpr3EGoZzBY~RrTZ?%j4gh*{)Le zrOFC>So}=tx|_Wz-vR+eW?$iUD04XQVk|4WOtNharVrnLJ|?H`67HSaIYIt1?SwJx zO1cPeyvjxLOU%!E$$Kw6XBbkOT?k9IwM4>0oscCb;+S5X+bw%x4CpsumPpo_M!j$u zh>Ab{ZY!~$^yji?&{ki8ge?>X^S=i!z~x>`No|Q~U?&%_iya42aMEJ{K^>HW9X=KK zbhgHo6q)z-_QZ^_!EgDJsfOegRu^I)8g=e$TVwl7&G{ksKJ9Evn%fZ(E%--ku;OFS z7reBK&8TN6^=;<3W$e|stn6uVTp+cK?d#O+(SYo+vW{8t zHln;?pc{}7>B+s%r-ex(EwW{7XU4RwW;ESH*(1W!jR(y$q^C@x(f6$0@Jd{UF+8Dk#Q`HH}{^p8Rzs`|36dFIQ z2<0?a{f66mTzj{`qElx&>t0G{cQ*kdZmz=R6Yp86WK0ANTP!W=H@g{TG68_5I_90^ z7ARFF#CYRtZFX|)mzR;2&Xbh=R8k6^{iVFMR(qwyogag>f?nbuosgoLLn1?Y!ar6s zE^7EOFON!3;lT36bn%C_4~Rz>`tw!R)<&i$}Ux1S~-uLmoUis!(OPASKZOb(|s z!HUzRFT|18K<)6G{aHjt;FWAw(!YL<4<5dGlu2z58^6j?Oq!rq$;_Th#DN~XKEHIP zJkn^{l ztBrz;cOz8vC!Vg~O6CB`fn*oJH}_1auGX-CAP`Tvm#Ndbb-c!qjC>x95^$B?&ccbe zqDqXUz>EaI@Y7#W_-2e$DA&dBvKFw;x1Na;f}5OW)zr#OR0;wc4B1wuE}s(fd6NKA zI+a@M*PO)$PyBy5#fYxSZdu;_vX_-noXG3?elt7!+NSCqk0WWuA6uhET}1^6Zw)r( zz16wL$_!qOB9aNqk24h0mbMQ{NdK%PIo6#as+u0Exe`DSS5NL6<%yN<>b5-F!i2Wl zTmee3CF9Yl=cLVELEt0ve~kMT3}kB-u}C4FI8hxE8@HQHQTZFEOlcM4;?+QDTO|-I zpSgcjVihr>suao9dp|Q+s{kyPPT5LESMD+yC}^4*4;SpO0AHq<0QMq6Gn4R=w9qS5 z(xaT8Kg;J`F6h@omu1NzIPP-s@CEXDL7&&;~nK0GwX!C^t*9JeVOE5{csD2k=)@TpR>lF0VbZal+g-YE+o$zzxTb zJS>13&f+;lu06%4RMJ01GOn1xP?4C|ybld{HZwC10^L7Qf8rV($uS3EA%QxT7?YBKfqDO~}{A7taMPP~1`sp!ITgq~TKooesC;RnS9K+l*j zY;gsy_M_;;iz2uKB!qT@9WB6~n0?xOwY9gs8`(P8XhAyUsqhEwWr+fEV`X73>j(YTxmE49+w2$_Pfk7jh z9*r-7z_hJN-{Jf#=bPZCRzqE|O+j<@Iv?{d^K*tj_ELtk2T~7w;L)h`1PV)&aqlA+ zd|T5=^z3e@->yDp@#8yvp5{Fg5kKzS4Gkg{D`hhGE4sgh0q!=nF{GB<@eS*pCx*D`Vy-)R*aLdY~5#kuW>0orK)k_M3q>InpxJK~0YP9R|cb!g;%RQYq7c8F1tE%RTD3Y(% z(ApbSl_hef%-`X>Cwa%GGipy#yY66WPz{unqdZ*xlr~n%jd{XcBI zbx_p*_XRAWqN1?U4U5ttA>FWmbR#X@Al)n}OG_w-G}7H2%2EQ-4GS)kOD)|zZ~gv0 z&-2eSv*V024vVk2uY1ou_Z%HBn0M&+Ai)WSkVAs6B#DQw?PugdWrxuYS1D>8W^0V_ z>n#E~uA&)(Y>^`}BDwrex{hW zke1C`9_1Rft0#*(UuZOw5k6tQXMdyvX_Kt%8{+I+MSan9*jpS`PdYGN{%!Vb9RSyr z{dHIY+%PkPo?Q=KI9Br#S)OmjHGHJf*)0}r2=kd>jPBM@UPz60R`gjfujdB_uC2y# zl_*8~QyZ7Y+jcUNfI-{cN6ZsqktBsBZ|*eL#XvM<^?aktjR9vVW%URi zWv-nGW-$BHd}W>yPLomjnJ30Kzj4+6CB&*IpTjz3M7%V%i0Zma1Zj-r-+V;WV8s%*t_}tNXg-<<#?Tcwby9C5=VncWRt;)?a*ful)g?z>7*!zxh97=K(!< zxsKhv?0>sQgd7?>kw#X)gA(qXLk_&DbAscEkT&|dCJursr7m`G$6eX(8d1P@b3y%J zj>;!w8ws_{yYH34PY0M=Xx5)OvQuYm{D%+HM&KXF0~6O-qM3aClb(a zOs72d(sVb+Ip(IZXz_ly)cLZ$-h*`EUxdM-DS7XIPpj9*)6ffX_zP=Nxvnk(m_}QM zFp2}DI?)_>k_fvrJ~WV9E2Mj&sB{j z{YIgzc|2m~BYfbuM^r5^Ce7!k?p-^{)!j1MiCam9&`|%2@n4$NpVNB%Rn}N_zQ^1b z&(+XISud*d+QVUDxh50G{M(dUv!xqVP^?+~yUs>lQQm3KA<=y@CImhcXZwh_&?~^u?W$rOGp-}>K9*mH zt%%apbPe}UqcYhtgYD390sn*PXym=O+U_arx?CB5_+yg`#mWF$5!vmy{riNEESF7#u&t21aeE&<+f@y8#NUF!pwTW!7EJb%Ej+3 zj*L0#-==FnG{hWMZK2)&`!BzxUvU8k!ng0jvF!t#Bqi@Dx9H`ks0lb1vn@+b7^0uQ zsH>cM8XPzsF8Ns%_V67h8UFeHG0URw$8`kJJ0y?;(UX!Ay!wmi{Zjm~1V;GlzgXWo zm|PCjj}c5r3d13R-qqVNj#t8a5H8WMPN?{^ya#7pozU{W) zGzf)&cZaivQX>}V>G4JV*VvQz9DR;Bx*e=kp6;8jG=3a={!u5sHSPET*%1^W$!&hQ z^PN4ycM;o1>c7~`MsNTW_NI;_l4`Fq3ciXLz0%hW=yvoY@i?@GGr(bJ7NYWq?U&@O zjtnS`a60%Vx20EuJpO9Qor*5;7IHj{e8>>JR@L*T*RE|;h8rd^1KJQiLI@u z2bOAfpPaky;mO0GK{@Tq--FwQC$O8}+f znOUX(%5@tn84;?O`HQK>@bnJ94Ps)>)X4j_ov-4`3RKnmntU&E`)d(vu}(z*Sai7l zl;~k@ViTe+klo6kIv6#>5q%mE5hL4~WB%^d=HJdLkij{i#n$5Yh244Q#g-pkNIij_ z4h+0$a^1q5zPk{v(=QjePL84nXKrVSxlEE`sM=a!Vq*5R6si3>pFv!j2$f7<0zEnV zh?M27px@@|B}zVA8$g4=?4)uqCZe8Nu!*F-wcSj_{qy$Ow)pck7MYk!w)^HR(x>W%ZO9Q$vmURbn?cY>;@sPIee#7|{tz%=#&dRDDxn z=q%i>ebzvE{;+zSlbFlGP}_*p0K8;BMCL_7K>;n0ocW83k2BD>L~^f(Bn9ZMA=zs0h53Xa^zw%eG%{8Q+Y1EeXxYA!rl0KSf7?&b?;H(wp6deb=*z zdqf=U{y+7dX&mol7)@t^9P~}1)tE)}8fSzo(ISmez~&(_kg~o#U@>VT&g5A7;i#($ zfM)K`>nSFC;ehaUL)+T%gT1u(p3&#g8=R&#BRK*A*L80XYhEi#I<)1(Un1ZI1gw*5 zy)y2GZzl<6et{8|tw1ETWSa2$^9%%C8~4FQT~R;VU3PRM`b*pRohL5$X}dngV=HhP z`gLZtc1)U$ddF_w7C7)HM}zUps}pph6T?UCcvt2!@Qs6`Bh|AG_A%)HK!tZ7xDoCh z$*j=c4RbU!dc(Ru64Ew2*kAm&+5=`3=mB()e)WOU%A zwDE%KyT0FwvtHLFra-Gx?6eV?_Fsgn`4l78EDQiX2lVdPE}Kp7K7G z^Sbs`Jsn}W!3DbY4syUBxR#f3-1NvTiHU&L#z-s`=Cz@PC13N~n1R`L^Jr3;SXg1D zM~havi09jH*@9Kp!Yb6_;Agh^8h=S=hV{fk9fu6t{C1~d2RhbD7sy7Sfa(?Ye;3as zW$bw8-^T$E)0jh~$8VjgUjAgKYxi6OKY$)LY?`n~>s-e&u+NLBFJ;~`|ID0r5VBVA z(*&3?bxt!N$4nILAU8g~Ih&Ao<5xP|q!ij4S56Vb&&l*ub$I^dKxsn9W~m|+_F?Aj zd;0XW-U}MS|CM9;?O?>QSJM2Qu3JjBW=dmB_ZR`Av%6iU(>Xr^6{${85IL!_$CONN z55P9));@Qq(-_AV*@@+p)4Jg}q4hRp=NBbMUnm40@f3;$1`Yd<)R-fF#n^6L^6d7F z&pX!VoEC@--8~!FWGKBLuQ7(JE(knJwAumMI)dHt3r)d6zMvtpaRt}z_afN;Ro1%r z2fQFvSuQ;G7;J&a_g*CJW!-65Pb6&Zihy^Q%I8{Yk^8A8$fQ{RrILYwvP}CEW|wVB zE2Yd}c8Z3m=CJSx)4lQLBAwb2gLObKjTk-m0U>bE5q*a|q)Hfmlo&E*F2sJ#c4hr3 z@Ie7sjG6fn;PldcxHeb~jGV%IdvgIJU+>-enFEC1J{=p|&_u!hnhfwIkytM;4O=?Dwqj5OOa_dgUGshdlWWUoVApZX!0g7of_3k$3 zEd6)l7f}~&1HW%A7ni%X(np#v#iG4+cR#0`0@M#h{>+r&zYV7TIc$-?VCX_#d9M83 z^Iso>u5EPbuf~m>MNcT4`bq!v~qfa8c)`9lv_?^%fB(u6r9U?T7dKw*87p zCzo`azalx+&C&cflNw_i2wcda%Z%3OW_H z8`i2Q*9CTbdbj>a@GPUbt71_!yq#oP+^)nSZu4B3)%tSaCtnFn-0zg_@&pwD41E6v z{RN0JywTcrz6MP*c05BKpG01nYSag?_W+Skj4@dr2 zK)Z*-_~Tm|csl@kq($86^l%xh(Th^G*cvFR1G~F33rR&R*&EhPE4BCoFuM_a+x5*J z6XIaUulkhD!Eg||!E^M9m^Ens{?{SJfA8HNF-&Uuzlh_}lY8_yE*A&--Yv;juC-sC zOSkA!Uq057=|0?DsyS+qx&9!||8C`BDBMt930iALXE#-TUlXKi)~fX-@%(J$X|G^u z$aQZ$Md~s7g}GLHKBRqNl?wOTf)?}Wo9Hhkjq8YTMF}_h;0$$_a9DghMFeM`a!;Dc z_&Amx%ZoY1WDe65n0Vd(D~6c#cSC?MgSZF6Y0iQKFR{!ICXN?izcZD6GQxiwK8I&0 zqEygA4}z}tK6T$mP@U~B_W|mR(c4p{g{UJy4&(fw8!tS@r0N~UkM3@s*H#>kL%>S% z@zJ}y%S3+9)MC@)Ro>&n!X$h1CeZHttzrbE?WT-da{@roeW|S7k4C3snG`$shoG`U zd6QmF3l>WCW-JQq`8{+TcF@nc-8@m*4em{^+pQh_Cq%10J(ImzQeN%6xRu+S*d-cE z2iJ;k@@RdV&MAE2kbj~+qeS^QJluR?9m-yypA)#*wSAX6Ee-OSS~J%`;1bzbwFP(O63freIp*DCnwAk6I7sSKFnnW`Uu2(g=spTzDcZdo)N=Ey{2q*Mi6HO%-%`+kM2Xk{5SQ3Gq3Dc z3OS--fD^qfLBa37eJG*1x_;*GRk>{2K?dX%K>Ju7tk#6Mi$hu$gvw67-#jGc@y6x5 zu2-+y7p!_Hwt0pTA{`=`Rj%Lh*hJNYRzNLFuwEwPoUA&M%k1(m6mi;fA35+`mD#u5 z_=}JSi`7VGETI3E1DGcf7oI}z&Y<2K8D3#UcPpWIB9@n#ym$a_td4>WS&LIf(P|0W zC!YmI^t#7%I04T4v_*kX#ig+0VzS_?PlfCJ&y_c9)Akp1v}#$@SN9MBU~$otH-~M8 zJqo1r8%A`&!_mbtjW3*bsj_}W_A^0LWgqI6y5% zbPIfyP^pksUpxmcwV5yK#-4r^Sc?3-%4ctOmyLmIEByh|R=!Mr-3$TB(TgAdV_pPP z%6FN|T!+0D-IoZFuR511-@|d&H1<^VD`0x8vzLYCn}6uq-Z3ga&$etV2lRYDt*sZ^ z%8!06)X#B$)sDFAC!M+-j&dGtg3wnp=x-$6SA6BMn1b}vK8zs7Au>zXSX8r}Yy%Yx zWwISk098FbVs4VxT{;`uh#|Wrep~9YdFV;vA}zu0=e5_Ja1#-(*7y=REKWnrh3kB~ zuWTMgxt#=F-$!)Nk1ze1thpPPHEanmR5D5YhG8zmmb&}KzB%xwugn%`d>TH=zvx(B$Iq{HIQj*bXs)+>x!!{B#-3~Kho)@Xq;g?c66^V!R*P^g;K zi>mD8*v|j;EY(>_B+0K5e_Z zy~4p&@*}rE!Xsxp0)#goNPZ8oZ8j-hZ1*Fn%VbbadpDHI)!Q;tY0|gyJrp8y2Po;s zou7LHHV2T&M^B&j05T0|Kwv90^O-jwMhK`2zD;J;{WZ&(A2eTM`NV2C?d7@(|G1FX z9@}M^dftO6pyYT%!Z#BB=#LbzgG;r=z=_(9Wi%LDC@AG3`ZkSSpAU1_G__+%&_>&_ zzmCsC6~5vuJbdoMY_rX=LyKIaqBq^_|+%v$LDjpfow{& zGt_mM2^h~A);W~=han(jy69!DtxLsm`E7W?-)3}C5h@tf>4*>cV2T3y)kF4@-9;lu(+#vFXlXwI&%7x)|% zXCCGs73=3cPOEq1a7Ai{`KxePn?GCWpQ?M!(sf-;MRJP%cCrJA2-?n6P>BH|N$5U= z)brcItiT^~Gy!42fieE`iBVA1%zt;jK2^l0=6tBH?_mj`1*F`(`KE(}RR`C8y6iii z_;paGs2{R+L@czkv-2bB#Wx46eJbv8X zT%p%eOmYEVBdNWl7)GFO_1r-^zwMiZ0H%45X@)nd&9ANSFvUx zoE*@10wf3!(Ge(sfe8$%0kl|CwBm2&1&4CEfdchwB)-+<0UqGvw8YuTu`8=3AZt>O<@qMnH5vH4Zl9qyoOzU-ExE8Hr~vRzLs)z(iEPi`J1L z@P5dTv65}nT%7Ahv$zZWUR$bM=;2771qMoLRy%1}9zO9qH#SW?R2Q)wlICIeO;~LT z$Sqj!+O{xC>ZpZq`0CyT;_eDgrkX4r-_t5twF6W&IW0vFIH@+fgk^Hd%B!;{S1)qi|W6L7r%YGh?AX|n#u%50zU)>C|@dA)<-NI^9egwyWb7-HIN;{-gHwNk!Z;ePbwAZBuVo|i7BT}6 znk+virvn%kDZrfdzg{oTs!h9el{*6ATrLm4@70?(Vf`z5Ar? z_paPT@oFtfuxQ9(;3{U;HO^bOLPRlw?X9mx*SPFk-;p@Fj0!37cUPXy-9?Wk@bN#M z+7t@|GTFk#9 zQ~R^R)iC`|vet$@_&^>bM1f-Ba2&;HdYr5pt4b=+kKoW$5$634y#)P<$^rQ&BC$qqmz zR^((-Q!1!Zzh0sLeUt*fa)5;pEDwYR1p5NaD(nz`3WCxJXuG)m|R6cV>_Dh$ zKUTfi=2VW+q{R*Miqi>SkySk#O#az9YtC}sA?p(ukwA%7oq>{@{K|^*&$$2$H{ZNH z8l*AX%P>a4#x!N4CtqtBQUN^nKF;;PTR2?_$uDF4Vk-pd1VJE(gubm8FtWH>dy-NO zJ;QL{Jj|6B&m|Tr@;D`Ni;4KbXFDZB>2IH@yS)CvM=f0YYU4X?Aw+Dj<3q@5<{bxn zW#YqRK(>oD8M>4JJOA^?0+&iiOQz_nY(?py`cYj9v!<*}mB|J4^cR*;N$%6`{q|Pd zuzPgl31C`?ghZ4=A0`Wg?X5aKE-e-I1w@L8@7tRsGf5B;VFC*=wwBt~WBE@A%rIgN zuQSBmP?%9-)f>Kn(|`?1mBb}K>kc2Q=ZV&xH|ysvdi2JV-Xvsy$i9C3-TmQdt!0*h z;sh-1SUHXNJ0Q;f0ni&a`59=>(9$Gc2@VA0pZO!*xlVy{DjIOK%ae^IZ>W;N1>{VV zz#WpI54hI>aaprJ{R#Y2qko@#3)z4a4kMjksa$!|)Sr{VVt7^F%#S|agS54tN=O2M z86)krB%l5BavsG*0T$%$rw<^9BTag-!kF_Ng^5`MIbBP5bamN2HGY=COt(I#F{KV_ z`}Kj0ZCcsBcmG!Srx=tZXunJKOUyEpppjGf-rmkx8J9X-xT>fv3|l_v@5c$BsR^bU z%EZibzx|!!z%c7dHLGtq#&H9(!>^=4Zmyr=A?bQOr?n9cbQgDe|3=?aw{DcZ=`PMX zW6Go9rbz>CqS*AIQMTj0dW2CO-|qa%3IAQhxTT^rWg@w-Lrgiga&PFn6n`|k*#~&P zUsw>$#k71KbO)3=WOaRc^q`GIcueQ?Wu5>@L}!PvZ%CW!+ScjHL4ntabEUij||d=e+;&AA$3&Q1sqWI8v(iGwq&YY*vMJMTI>t_RP0n>7{i0J z2u7lAH6$>?u^m(2bmXUIqXKSQT^*Tc*EQci&;+d-a7kN=dW@wffH->_&-Q|1-0I_! zl3*kIrsc?>Y3?-^i?o#2SK==Pw+hC2EA+9vD5ujVykvW^oTx<0w2xD`iocSfXC7I5 z{jBi7;0|0hSl0MB6LVgcD~@{9qj%L>s7JA2pvTRT-aamfyeKQAYd!2^;XxX`NeM{0 z2b|bPO)!b?GHp0^D!x=^_i_<(4uN6UvqWPN_q0GuqHhaX!BX@_yheSkul2^O{I48* zq^r0HskY^W1Kq?b-Sc52bdf?^t8y`ok@kM3o&gs=xYx@PUxzwKp^u!~Zy7pF8rBO2 zqn9-(im%*ZLmzb3d0XLm}AQJZ0 z9UnOvf55@O(&%C^g>$f5ujjhfR-~*x`)k4(u&jUNgTM$;3OEb0)x$0f{5xmvnVl+= z0q3vs2dzyUD2%Uy+O0t8S4%NtEbH(2usT!3g|PB;xFapCR>t3xLv2Vr&&2%`tkN*Q zWw+-ZSHYB|l^3kMby@;GUN(i*^j=J5`f{YH<06u-RXOd1iYzYbyzF7ax*Xhj_LAmS z>^*r@X@?_KK+n*Z)rHctq-rRN->`Vxa?Gor;;^_4cD_R_z8WHM*bQ+g+IeQ14f9%$ zduQ@O0u%TI%4e^Djgt%CBt1vi#UHZ$>8pUnVX0{xIGR*4N`*Z3xxbxnU@bB6x+n@G zgW}Y~M+r#S%`m~J>y+1>@21A5W}7V;D-1g@UGN?9{3vpccrsjclOB9|7E+I(ujwNh zzEk)d3YtT)Q`AxI_0&KH4{p3l*S?qK zMqaedUO_}Ac5N@Dg8EaJ+gx~V5vPs27cEb>ksT5H(x`_97Y>f+F%+(S)gA)=PP&)U zEeQUC)iyn!`6`-hBEmM9J4P0Qw~oVxuWd(m!d+d=3MdO}L}Kx0Pt#7i##J(e2D0GuQw3_R=mlHpicDI3b!F~y-6_%Odz|k z97Hg+I#adU&s3;@&|b>{jXTyS+f#GXFz8>DcBghEkjr8ARiA3>nrXSuCGkoRur+MT zs}-ULKmT}WYp=Y!AzvG9lRVwW9DV~gFt69`0o#Yz_xj8cAx1nXY@atVFQv0PR zKC#~sXCFkDw_&ixM)4ySBtg=|!Pt1GT9euVxbr#M=RO^AuR6$C^-%b5JFQ)Jn41Hv zIMIaad=@AD_Yl2UVZ?sSfxHi+&_k0|3jl|x9Hugk;q&7%&#N6X)b99k+hF5J@IWGq zxlfrol&NB{`5@|o8)x}t73z;HWm8~NRW6EN)+7C_Lb?`&iJ(;+wfN<)TZKF3J((ls zS{RDR`Hu_GEI;F6WRWI*cYTCUwh2Z7Zrk%;_5ce2!b?Cl9`!9+S`l!Yg8^Es{oGu@ z6Y$wgOhn|yA!Kq=%V%X9sMgnVN|9aKDAV%hNN*taw*&XN57?wgKt^;Pc@FrJ&^_}r zYH%PE^4wukoOz4qNn{RVKxXmUJ_i)agR9N^gdp%}S3%@~j=Ef@YL*zOn7@FOl++(@ zK&nxu(zyLS68^|#W#cx`H%Cenq>2NsDCy|;*EzV3Xn`y(H2B`VA>`PSy+ zQVtaey%+Pv{DL?*-5B?v;me;Xapy%J?1fv=N6PB<>hQuB3)}Q-S``efx_M>s25T*| zl+!{QdM2-{8JC!m?Yj$+XdtQsA8$d74cPhDS|pE(upFJZwTio%q29Mh3PMPa`O_<( zr!`YhXw08Fdv0p=G}+`LQ+f>N7ghVm#5;l~5xB~_2kV=sZWGHDX-0!8T?UmiYGeU_ zgpD3AhQUZO92Odsf1Uyw`^YcWnF(_nVEOs|{0p$ANv|fLe!VkWEgj|M@~-rpl#I+4 zr3rtj(3i}nrxDlcyevkR#Crh4=-=tb8!@7@AVK*6oyOg7oAlY3uz)5b3a&xZ{uM(NdX*j4VDJVJ@q zygngh+Q{onq*g~^K!3Z}Sftq2%D?HDlaN#2=4jI?HcbsK%!G6ke)~f|lYzHvRM~8~ z1s~YETjJl|e~)TF@1yOH698*f6p2$?IMgmLmx}qV<<&$z4FRl0yNwXw)g|0jL8%x3Ewm5fH+$~ z5oM2?Ik@KlH%(l165~mE=uUMX?RLLzks95EjZ|;6gNwRBAOK+;3aWP+S;RFu%#G{F zGIN5BkLkFNmjkaHeI!Z*%Ie=FF?geUNGx%uhx}ZY0MN|h4V5~7hc_C@U24+y>J@-v z{Kctk!NxH!jY;u26_md6u}>I2d`cch%&w1fF+z^MzZl(?fh|vK{rBW9(a~?*R&y}- zOqOhzE8|=6F7gThM2?wmUAe(>N+p&2C=t<(YnV6cBAr;-`TTpSW5dNKn3rX&ca*oP zvsawzzc3+znHY2=+*Wm5`^M;GYVIR`2$YY~gKPUZ=(#aYN~WL5zugFEc)WUx6($w8MP{36ROV zupJ;*re*y1E7JrN-j2(RC5uOsu!mWlu;ghpA0IiF0V)LTsNaKmmR>gH!Xv{&c%5x9 z@8|;4)wsOb=DTEh_*-sAwLwOBYT!#`Ep>9*3HvKD%a(Qx?h9t+B#+-aQ|XPy-7)9a z4sMA53w}J=(jMi`Ni=D{EgdqDzfC4BE^tN$cs6R3FncEr-V`{Y1 zDBaI5v(V+MVbcJ-cesQ$qoxTo!=vxQ?laingxqK0{U#~>icLP8q4QbzedbX$9O4&J zp^^yeU{D%$Ib)0GDaM2_#J`K}HKPJ%CY=OmKXC7cp(21ufY(MxKP_KlwCaB^E!KpWk$Gqs+y7)4yC|$ZQsLzfrsbNv=JNI_yI3X{R;KCyivTLL_)K8x54BWLuQ`pDpFpmA zu?7JRIF19KiF;bJGrC6B7FIn;#4rH!BtnIdJe#=fP6na ziog1m;EE60ZOjBP2X7e4W5aXfs1F?6;%TdNo%<2C4L%^W8CZ{JuRNlTI9jRldzvmN z>$Qp(wF2-(3FQNlZ-6V(1$|^eh$in{AG{7^%&-jgyqz`D*FsT)#Qb!6oj@ zs$6Tj%-{6!y?(B<-s+>p=jzj|SG)aCIWAsbrqlg7s3uz$r%BLdEXq$rRu1!Rv&Bne zl<*HvTS>DlQ6Ihn)l`>>DkI~~keS|&52K^_a#Dv|_9{j~Vd8j}25AhOQn&c-hCz?f z1hVOrg+HN4x0l_0$9>Ks(AA^kzOot266*4ZD_%p+M`9!3+lTj-F`+cgQB_q^#@tUn zNCG*>Fg8OBMR2@$YI=z+`EKPyl9K)86KO4~{jE`Lx<92+&_)DU!PWZ}%QI!n3PyaW zASgn`uq$|#N1;W}e!ljEx5pbq9G>a;7dN{6;SL2vISl0t2N0RIzuzsW|owPCYqV=nTk4L0I(nU7<%;r{go z&dpnDGZNN47gu~3>Ss4Akx%eFR#uS&e=M{h7kU#Xl~%a6H|kEcd9ab#k2K<{p#8q+ z!QuoU!w6!;IZuPBk^~^t`gimhFr3?&JeA{-B?I`J9nbhaWJ})|XJ$Kk4bgZ8e6VLu zS#xtlbp-vOYi{pdxg6z*^7bQJW@awNU_|n0ELZzH%-o;V79*4=Lq{Mzk^8HiKYdUw zVgc@bK3Gokv02%q@aGTvReoQt?MBa=>9tn_nK~w}@%$|Gcm#mqK&Ylm)+zyW~C+d9Qy^*Q`s!LD(^Xj!LCYdLB^fkyJ;_X2 zHvh^f5fj9B6PdPBVnH>?b;pE3)y5>v^U{iy;j!I~`SLtw&VHkQ;n%F0V1#X}XeC(e zt=6S~^YSapSqf)ib{tO`;IwC9Kd*e59XKV=)$DT5?Aq;fhj?kA=Cmle1+VApuk2JF zM*PIglqI^Q@1r$3w78O^q9kmp#?BZA$j)D4sC%wE_+viHis?(xBw3@B4#9mmp|pOH zRuRDCwt4gLkjEwJ{95fO$&U$nV?ihQ^j{n&#_V{3+_moBU|QiZqizHXy?OWpZXS;~ zd5l})bq%U^xN=BkKYWep-cpJeWB0MoOU?<5Fb>iioNE(4qN;Upxi z0rxQ3g$Bp!_rIlNAo*EzL|yEaVB_q|YWRl3f%ib%+FD-5a5ZLZQ#mjB+^=Y+^-SNDkI_sH@s{L`TB zd#|I`v05k|ukAE;3Cpi@Z0^Tyey_J7l!b9wKgKIRBjZi(;L8i+BQ_;^g$(+LWz1cn zdg)IKrL&i{y#z(zz<&j=N~RB+-NbS1mVoo;?ki1yyh1SX;|EqveYSe&Q<*kWIr$5q zMLI9)zXxC+-h0g(Re?9YQRfuVi8P>Pimrzy>~};@$(K!cbyo^WeUh0bAO&rSjxwPWB#uY=vbF8LQ#waXyC^ zD@vFfoW@CWdq|VTaBRc2Gz*kizs>oK#q>05$zh7qG~bAK{fU@$oHEd4NE4eTfwaZ5 zlXm~hFq|1zSi!fleEymD+dLliR=~utv!l*0zY7_GK)%w)zII)qljGS`943@sI%uUb~y?)xCh zX|kVd`Am059~v`S_E;04pAfT2ppiZ54Gwz#$76D^n6`_no4@_YXwD887!sAOk*_cW zQ#Bd7hMh~5lw>+DUu;PcSOhyMJzYNIa}4{QnJkAu!dE z4<>l`HJ`XPtUqB8jQ`zfB;W)U5e zZVn|!dMmBvrB`%E(%F=w8p-}}Al@2l@}N4r@^;S;-a&33y_&DvvU-t{mBK|O?n;@| zrz#7OxFG%?o;G`qq%@_w8;j+#_)hT8k1Qnb-}p-RH%f78{qz!_aUNnprm*RS`~?XK z7**g=M6B;;jJzz#rIPc>c&u<`blL_iqznxyA^t)+Kta8SMA+EUDQB}NYca(VY1by&?yH=$j}$<|f^54zbJuauAq&0bUgxwRWB`Jm{M3#i z7kMmRsbalctSHxZyN+U_RG;mo1pwXk4snuz52vQG*B&g(j$iLbTYWaMmHb>Z>q$do z_zj1SCTfsr<*Z2*boWbmzki%pRRoRw0FOF-%MS&>wHlM1$K#5#Ri;>R)S_u`;EW6m ze_Qe0z_p3$yuEw^*dfUQ7L)i?RO~#vt1!x zUO6HzC6&_Z??vG4^-WM2^!JJB)jd!)Ksb9DqS~jgq98(nu*9abZao6@?INdov%)23 z?y3GX3O+N~abeiIwduXU?_4un*h}T%M#Urkkr{a;9eega$jL&ni$ta^>9g}rlyN)8 z4c3@ZkAYpT>Dt5eNw?e9IS*I*XNKa}8f~v=jcE@)th0cidpm--(6!eNb9E3Eo>Dc{ zCf}!A(q;#%KWWyEM%?|#yL)j%E2KZy=v~j5wVqjuGM(0Qb)%&!Not7DxnegTQz8KU zqR<-g(gUyL0NT$5Zt}Y8MRekyS+o^8q5*2) zZ~T`|z9-u+*IGXAn3VzG?Qg)rMQW+V!{uN_(tUTHs3(d@dL&cS@=JOw1^-W%g+}Li zpaC&>D1bDkyW%uz2?LNtGQj#d;`(}!vlBjJ0*wWzA7))a7>ABGW;?*&jTHO<{Y%ds z7+{IC8j2_O@!_wijdCzz?84AGX*tH*#gF7(bPEIzjxuL#HlGuG03_mg_<#ri9yN56 zn*F7qEmjbp7(TbOJ3%mF-;vFhw?IdeH$SZ+wHXz9%Z9U3ZWc!)3wbXg78sqm~Ht6IK))jI2Oy}8DA8B86O|wr+S{v z^wY&?2JfE0H`bq$kcnqx+TGv3N&SvkKee-QRfhlCnzDvm$Glk`b>3vsD$=@NzdhN# zm$Bf0Y?%oHksi;JlHz{pG}X{ZMC%Nx`Jc=ge(mzoig~gKh?J&q7}hBcmkHHtlti688+?g%}NZ}cJ!pp81O)r~V- z4PMicMVSc=ov?f{Q-wbPwL|X$+b*|D&)2^?e~^!{wcG!Nl5_%*>eJI;a1Z@%7M(M8aI{^~;ApJ-Apsk)BEh|_%Anc=2@dQB$`|!917;-!MZJeDPR!*J z?Dw@nu%qZxiT%A~ab#7h^@%S``@Z^waE3-bZh&TAca}jDJb8 zkGpQ9$%{A(pEHwv`!+|!vMBn#rxx6L3HM?E*w}<+E~>eYL%`t9^GdpZu+#fgiF=Xf zv)W4vrTPbC-+K)Js;$e}hP=E=x3?vy>+f;Pg%2e&YjS@I0bxQXi`36oyOOKk<;nHQo{1Gee5I0 zL8YSqRJN2hVNprqR$k(oJ?dyqlp~X*a5{Qflvg=|X(JK6Ivj7`u;C#*6MY3_kw!%( zBq-#ORxN}-U+h`#nS4B}sR_bPjonuV^iJ)l=nh?uo5%J#9FkKD_Q;-;hb!OZ zgy;nXUQBpQKj%A@@psh#6LVhUm<(kl?Rt~-4V6=>WRl?AgZKv)p{f5CbF{$@kFY<& zNN{^O;ydo$ujyUt_VSc_dl0KZlsWry*(rkqdO=)1VHEIA%h{Ktknu+d5Os|0;RcFB z7VVt&3^yaCfxTVSp)X3G=PSIsytXaU>{Mw0-;Vbvl8)^|&u>!Ps~v{h@SZB)wX4yEvZdD^9$%9~Qs(lVk%hB*}SgKE63#I5l>y@i$%hGmupCBCbi*qKn^dQa;Ly z?l9bt)1>2CnUfeM27iK++t7}W&J`5OLhX~j{{SQDj^cjTzTg!|p4Y1iu}EI}263L3 ziUHzwS0uKK^0|8VrAC6eljjl7&R5`(q!sb^gfQ*R$wQ z#~2bKtj+DhHR4A_WnvfUX46XsXJ(`1M~OrwwUbMcZWpP!jDR@RJGH6OG>AwcqfJ!P z^!wLur=F{P63#mCNZ}x64BsSKI?sUJ?R?ETI7(Z?VFd&NfJX1K`7QswvxX)-#yG0p zQ}(Y8;M*S;0&rYZXcA+bLa}j+l26%<>HW_fx3~chZtz5X@e;U=aZbi6Paru5KQ_#cE0834|J<`y zn5{{)ruSWjZIkQ8V}>E$6tFRAGL+=EnOV9ag^?yT<&y0$RYa9;ITvu1drb4Cj62T| zehnJz&K(yF@SLJt+?WE}FEZDF#pY<)mupah`4y11Tkd+RN8bP>tfcz+aJEK1^%5(< z;k)T%+F(ukFQL1S2FkY9$&^B$_VMhm3%T#v9(#D(rlQ4g^c9D(60|U;NSG75vxo+| zw9gsww_qzU_ljRNWo$erOZUhp2?vL=$0D{OMhtT>#gvc`-X0q^?7R}@ zUJJ-m4G(nlP$Sp2mD@)M9yiMa(w@~82!EH&tF5RxhgaQYPjaX&cx@Sa%8HBEX(9Zj zzOVtaptQDRy)TPl(CRxe_@%xwyK_I{1}p zn#z6kL@?6^Xj#l{?EIseVSWgzKoKkn=q2oWukMEaJ&P5vK$5Qa-&+-mh1Dyi6!~*U zL?&-}463jGFkHNA?q_Lg-KM9Geu?S=2nNKp_m|m?8SFcrkU3XsS7)ZFqmCo#wvyb-KGi^%F)CF%Ttf0FiC$O6FQ}x(ASsp_|_|?)Q1$XYc*} z^X+2}4w&uSbKmP)z0S2(1PyUySd~uQy5D$gXLOejoo_95st=>#BS*&5pl{q}iwa}Y zi?SCy3oE&Z?(}g+>tCzPa9NpFp6kdTM3m=h5*Nh3@Ugl(QbaK}8OvcyrUIa*cf!Zb z{Ks=rB3F`mIa%}`))vL;&F~2GaCcr(&lEl=$>{dGKZU~vZQ4p6)u1ifVC(=zUdNZz z7(m1j<|)NBd@iFHO*=*b2ROOUP6*g%gS+qSIE<>h?~H$fnW8f-FT9sk-0N$(GXbzT z$2(IT7JpB7zOSq<3p>p<-3lmO>3Q0>PruwCQ!jabnB}%L*~vc}4^VLwo%!~9i+`mz zuj7D2tVI%;B&4vKOD_-7n={%Y4+gE<=%eR@IfGZKBJ~@NcxiuE^dEeAjUW&Wbt`y9 zh=cR~wb93Zq1bLYFhzOYZw;YL3D;P6%_sCRTf`Tl_aqz#EoO zB~{gyvub{kZ#QN=b0!a-&DsVIxeY%R3a_f@gT!1{(g`8$!5$i_4;$QOybh0~BkJ3y z+=mZUTRz_$bzW`X|7p0x&k|h~>h}Getl4@P7M+K7_i@DbevaFjaiGFU=5CB|HmTWh z->NX}zI8*fK>^lK!+1K4e7#Hk{FuQFq{f|`z}s8QgMflDEj{EUaF~$}em3 zgd@;;@nM|izB6{_TwUHB?ptcNCpR-qYF^8SIWZo|SJvgRaQpa#mkQWUm48=}r>SH= z-yF$}{1AH6Z_D1FA@O|M?XDUU5m)LAy4*6u*f8Dir{@gH0dC{BTy?hsbvNg$+ zQ`7Z=T*kP|W^-TyDA+c<&yJ3cYoi76_o(?D7NpK(@$1CZ9Zq-(Vu_*c@34T(&@}r02D8X1!_x-}6`F_kmlwxwthf z&~NbT>yC7nS4ROsD=yRGqUl`&tdH&{{{6Mlfn@~crX8*SBL229E;P3+*4~+xlHxnOuj$aoK}JPM2wLCbfK+8WeD4=eYIQ5<$U}Yc~`|O zF@j7!pzB1F7)K*^To*u~+$YQceyy}la6$g^^9uKg9_jN$h_+BE?hZoA_Bf?;Y^llV zrc1E4q1Pl&tI^6deky0&k`!Tpb?$YB>K>E-AW8UHTe#u=2uq0Tw58qu*4ot*RJL5V zHJ{S>oVmVtF}1X~-+P;~&vYErr9(qQ*Tzfe<;ZGvUW7k<))!LM7^`H=%?A%!BTLwW zTNdQ8ac4IiL3ACPx;)6aQ*j@1gF`_nlxf8C=YAAsz&{#9LvC;k57N>2pwM+_H(Q&b z7)@8nCm^#GzI6tYTiv|;re#j6ss_4>zf#E!&c`O?y$)6f;>W`~<6vD3=Oz9s?>Q2w8fY}fi%^34O-{FGzVQ%Cx&*Q-z_((Gpgpl(o{Guas@o$%W zZ_D;Jiq$v91dos~p7K)=9yv%vMBPzEHEjb9QE>)pY5zM70-0dUhIID)>EjQ@Hu^^= zol1gte)1aqa>Ks^8}3neQ_c!$a=(Ktfj%h1@Kn8ie@m`&m6vwaW5+y*rcs(N%+3Bx zVqcDCEYL(Av#F~qI-=fjEFciU!!#$YULWx%6NW@I@nBa!ZuT&23tu5wu{u9;BPO7l zjb#fL&kErtqYT1ZT_OSvb*iZ%VdQ3Xe#6hZdq`^I|1U^^1_voYC0DjJSbdan%6%4~ zzibC7Hhm2vcjJ8{$2(PJF8bA!MbnZ(s-mh^2Ihy#cGZ6sje}CsT-Y5mpD@p)s`m*O zPl8%jZe@owty8~;N$~gxImQ8+oiQ);wi?o6GcL&2n+v>=KeU7FJO4VrZM0PR!G%U@ zHCZ{TbGI|DRkEuefQc91dx)p+saW*;_n0QDn)gW_y#LJJ9~*bnZALNcIER``2!DGE zO{J~rVyBJ|&yyIY{5Gt`cd7xv^|1z5xJ`zj$Ur68#d;WnTbU z{UtQ=K8mbj=xzy#(`gIu~23-aN^(_P{i@gP9sTt?bKtRhXyR)*HHPWH`l>53bbE3E|k6 za9i3nG`*qiG^>kx(h)PpHI3CDapGY{is16==0axSf~8c!Zrif#5OSE$^FxNU&#+U4 zckyybhH7yNg}mET2)aF&Cbe}-cr#(n3F>_urup4ioZ z_^{sw5X4CN^Jt!iY#blS%4@kRPmLziOK*!Ji?nFL^pF88fjOD~rA8CF@m=%T6aZIH zZi_fg(v5@7nF&8w1$uFT6cymcIrNGbn*GsA$Lv)(1q8I|Fe!+iR=p6E7xP=}F%4sV z#giHsrT(MT{YX)xR0$)u&{8$USoMB%g=gc(c-FA6<0B8)1goq$6G{ow-t_gZ!_I~y zW&EuO>e(lD5#t!{;_1M^*B1AnJ(Hh3OY^-pNM(Ckvg0K&77ml3A9TY*0#%VOzZ+uU zaO{I-*Cs2Fa%=D!;1dI8Zh*K8getA*EGmg_aY*iVB_e7nz>fQF+4I8STQ6$nv|y%} zW(zu4k(wLmrQ`&Vy|YXbZ8^(ZHyKqCQ)#z1DbQ% zoK9EfOJ12^ZRUw&F3mV|3@H4EVt=>@MW*@hIqb|rWruIGkHynW6daqk{wqc82F5ex z0i3?pYU{9oYWvTA;4UdOb6^7#8Kg}v=nL|_QHpf#=&m!2%1M^fVPu@_CFEFDQ&yyi z@r?SKjTH|vmB}a1e-+yazYQjJoJ<7@!(yf1z4F><)QeansHggs*qg_w7>wVRChpTn zRP{`?lLMz#LNDgpjr%{;`$NN17)si0M9HzY^uFEy)Og^7I=L?nkC)*3p5R1*7)aTlg_i<76pqef=V05)k!SYxoUeeSV|~<(0T|If=AR zNWQ;9mH1leX(inmPAAvarz>(Cjwmc^$=%ZL6TCR2Zvjn3F86m~M&x0|v%>jH!A+#u zYIDkeqiUm4GZ-7o9dO+7IRUyGS;x$()iBd@KsD$%t;K%-;+>$x5eaYhUA_L%Z?S1RYn5**dHmk}LCUD) z#a}6F;N1UtnZXwLP^Rs>-@RO$N{*+qjc5tFEbyu0=5$c~eqDOTa7-6fw|AYcd&ldg zDk(yuTp#}vILj*}8Og#iEIJ~709ZPY_qj7Eo8|)5?^I%hX#$j6_o8TYR{1lh^aYAs zSV=*=RmjxJuFI6dgzpQEH)%7>7r<2|y(%u0-z{&R)M$n(@!o+4o8XyOX6Fo;XmoUx zr}5ukkaB4GA3gh*wslDH>yf+Uh#h~Up26jtZz~RPMhp(z%-^22(j|*{x{v?z=iKyo z;x-v12i=toZ&wG(a7K-xs@3phXEuCiwl2%0?hS>|D+(}e1CN+lzMj^@B2Mu{leD)| z!o_toSc9w7T3V#XbATne&Hkb(uq%vQ1>1-5d{U{I8t2mS5(ChkaRlmtc9H5}z!rQ}_K$TifU0uDBfn7V#52z#t zKFzysmbRpb$r$Ro%yB9ydmHcC^=(>>+Lt+A_SGB@$-mj{KGhc}+mij*;GTZ$q)sY0 z@4c@;>~Pz^FW9#^)D6)QbNFS=BUpoWb+TX0VYGTH{y%0ONQWO7)DKAPb@);6dB9Q3 zNZ*E@LSW)bLxOa3htS2QN}NFKSr(=2)ZsoO_J8vNjcDN!s4zK*d;|LO>0(PzNLcAb z=6!iDA?D7K4I_<_UP*|Di(@D&(@5cY7AsVv|H<(f9*I`TLcA|IV_!0i9#`mHrb{0e z2nS9J(*bY#6WAkWmShqKHK7gPxp`KIIL zT>dpb41_W=UgaYIdk+z{dp?j@TO6h*Zg)E#gHmQNU6cAFw`rforO2Bn+}EOrB$XCw zf*&t+mT*Wpox@wb_hg72u>7^1_>Pk=(G>f48+nrhs-8{_(5^=zkR{WVF7;*`E8t== zIfg1Kgz7C|$jH+z;*aa`FpscUzcu8f8v}TS#txm_+uH-jcJDE``N9Xx#I5Q&(y0dP z&n-gOjXQq!bnPJZ-t~hM5P;rQ-iVBHehh$Et`0vue$W0*z<@hr%mL3Wv`t^zsJuwj zZl%?EbU`R6`S~YHkB|{Du~u9k#qe)O`lMU`i->aI_6I#)pbKLWgidconsuHvAlqZG zZ{6w`D>6ccP(Uv*S1kY))(IiHp+A+QZW60a_+pOZ_kj|v*iBi5ltY`i9ru&e_dVk3 zM4IUEaX1m^AyqXMa~PRPoSVbR3D-Rg73EjDx$D4r#K*;w+PRW_5YqI9ikw*0GWAZtOnLgF{)?G`U98q_3#Yu5TzZ|>l^L`lcHw|l@|h8aV_-b;38vfG)pA_Ma-q8a% z05x374kp3N3vCT1j3;gcEf&?FX&k8DTl)9N+*xgul(0J@safuL6&Y51Gyj3AT@Yuh z;sow6tvh6(8cmTq+U^CULsq({c`6~fXr5&7Xb8|P^60|-b->?vAVv+9iyQ$f_SYIO z!6U%2Lkwp{YRfzJ#GJJ)-c;GndlEP8ilCb4(I<$OuUOM3^UBu~a#6|NMIm;e2Wvqt zkpnM&1Y#{AXGb|Zm#fs<&s1xG>T4eBT5Xh|%~(2UTUwheV^N5r34L{abNn&nqz1H* zJ}}?vPVLJmILcr>%Gf+YnOSc%X?d@d-i+Rl(tS&69>rungZ*73NDFx9H#d}`{aq7S zpxS+hUwtXG!Jyr=*5iy6iY)8PKd|VXxjV%v3B6AanRvkw^+KssRRrwa_Ub3ECGz znBC9?CR+bZw1JqFmm!EEWR9c)!e$k-Hz{qx6(rzkR zYqeMktG173_*{!VSQfgwgx9qP7}{7FJaSrG+&eHL!yLe-PM2fV)XQF|P=Z@%a@{rk zGcaq;lY7p6l@=WfORKH!&HBWHf08`LkDkP#E+jg&Opx`|umzRXZKHqV`OtnbyHCV; znbreJR}9I^?`CR`9#y;?OiL2Y?t40*u>5g|4W1J4J_S6*DTn{eEt}gF3-a!XU@lh= znh~|YO9n|p8&I@3*`BWIK{IsSo(d{yJjdlUEbqES&JVwGVRAJ6o6P)iPgL(Lyn)(B zHtsH)&1t9Co3gW`M($MKuKE=HdZP`srtG6ON#&NPKkbF;4|DZs{dZ zqt zO7p_MY~0L-p&7W+-{)Yiw-YiVmDiBq*Saz|H6v%ov=P{EgD}q+->g3V`D)04lkK*mnn~OH5pqZP*7M2l z`RvMlwGwZ}7RDZ=@PE)d0)||t=Z87cUx@_zTEe1tyx62Ql!S$doILnxdsxQnm2Ote z?2v7SapT{sY|w!SH~VR~h~R(S7K0*kDXIM1@881%2goBmy7MULN7E$>Z9HDqYU>`! zJdtLlA0D$Y^&T(A$dIV+k8 zHy-PAi1-9cUagqY6)Zh@%;idebVa~%xza6O99!6lJlRCCVdR3 zjtnrkZ*8oI8erMO_V)HJ`#ZE?sg#H_6W%$+zXeE04qkwwnsUI!WdZ}wQBlI&%=GVc zD1mo*!Tlr0X?UG327eZ|rvq)3cP#Fi){CUN|E3hXIvja9Q_UL?cyO3ll`AL44;Qa& z72)}pXiE8DtGBHNQ|%&{!L`+fS0}(%nyNLwr$QutSzH^+LgJnF0L&g<(scddAYcDG zjLvh5m+dzwiVb)cAgV^E0b^{| zvDvt9*<1ni!5$cm^y0%l0L?U$sEPRl0T1Ul+LAu{7-Fg5wP5GipZw4B@cIDeYN&A; zNnxo#=?8lTej+>U6&OHUgoQ7_&;zi7e$DHgkNZtm$JA4mw&5T%2V-XsgGmUVdZqsJ zVt_$QLCf1f(V`7HE8N?*odQJBenvRUdTmDhOL`@ykzjm`IcTWl+X48|#aJ~7>1WTf zg+txqzBq0c!_EJ#WH9c4Mnm<0`uSOK!C95$B~ZvaB}KYm$=2-;)Z-K!o>)<(P0`}V z{p((uwZKQjhbmlN2JH)FQ_&+ZgBP9h=GK5{vPu3rT7Kg)qUN>;udL+O?b#`_xovo(D zAI;UdY`*)Vk^~bIt7l*YHj$sHk)fc&6WEgf^R52;4wl=)=C->;%~5dF+sKI+?2$5Q zkCaIblDTJmjLgh!21H_a;O#dUG97<Ntc1(3oK;)L<@0QX&G<6{_aQklZxHot&u;$FHNkoxkiAj=u$OLVfN1vm7#%U> zphMI>qumDS)ndO5H@hp+yJ|LGkbB#{93>hBUT z4?0eFr#H#LjGZ4%%(2cc+{@uRWwdAPx{}Zi*l}`THlqpY}+RAt-33 z*q8BxNpP3Daf0V-hGG-_Iq~VqtSJ;%oC}f!(9f49{Chy2%eia@c;gp zLr4n&gH<4LCjVx%>L@_T&52UWalpl{1bWAh0PR`Ow?a?peNGwY%WS4Ai-g16UbL-x z%DXfD`-xe=6MF{S@4SZ%+FJt#mm0uR`KU2~VuJHJ@jF8LsHM*6RnNKG?ApyBPf7&( z=Sv8|#ggvX|5eieZ+63G2E6WHK6TBj2Q-GhVt)XLzU7gUL{9MjyAg1wU$oUdaTG=W z_iY>?4>kIZ=WC?00gJAYZ3hyM7HUIW^$u6`ndVILL~s53Q`{s#a#u$2dMDW6Xil@D zHsJWp7#12^4FON!UHJ3lP%=v*=3cO^g?PAYC&)PuMEWt+W`mf63oKt$`mnH2f^9v+~Z&-Vxv zL7cEtKSMiJpwF9g!Hr)0dd;i<&wtH;a)J~ydYhUmj`PPl~lFIYpAe**gen8mO zs6S_Ge`i4gIxs9SSBphK{_i6&0k=T;4L`O1YcdlQS z*@NR$IT_7-qWxe&c`Hd9hn@!aoe1G&x#n@X%LYiQ5ITlS>F38X%}8@}iiN`X+ZS_> z({BL6eAZcxD}r}|6cloYuWtVz5s)VidU?pMu={Ki#5#_{fb?X}fXxhbZtk`1oHvc{ zwbSFcLSCDx2?JRpyeG}SX^>rm)2I}f3lf1p@+9{hSXOqv6sd#FHQIS@)L{x_!9SYc zx~;y#IhH})VT?&me(PkZwlsL{``vq!UjJs~Brfp6m0DXzWmv$L&rcX7yPAcHo3{NA zeN1aHD9HZJ5Z0d<(=wWS9=w5?Q8ZsbOxd+|be%xiEJ97}f*AKUF5v{mQrpAkG@MuS^*Cl;_o+dz z2?{{2bUYOzMEy3Awwk;&1DHMmO8+e>f&>`;|JFtfDD%uj4zTM_IGc~C13seF7AuxF zRNV*2Jv~7%grRTuVsHMZ8*iH)|GRRZ4jl^&^`^Od@FWU+X*^Cctxwk_9a5JTz%Bul zq|wbeEr7%fy4qc6T{fL_`9b}85AKyYBXxk6lpT+1;y=9-uXw3uuoWtHJOxcX(;F1d zrF31(N1L|WGf2oGv?P}Jww&FczOAJBRfU~mY3rD1lxkD9dh$#13)NITzqagp03_He zt{Kem;`J?d)54d4?nWRcLzjge{xHX?Yor?p>jC!=`tw2PFbB1DB9Cs%mt0O?FgT0iDnWBDfmyeR#_2EG6 zkf8tWb0gf1yh)?*5b~2q4f$bVQL6_0wKHeIDE++rEroEHcp}?A+#ey6^+RG9ER) z^aEuu>;=)Y(nQ6!INL}s!hqv;$DcB`3W0TV^(8iuYBlGvGOTm$HY0f}#s*v4VJ1Ve7PCr4h z&!euwBup$Q(&iH-EZ^aKx2Yp)@3ee7eIL-|w4r&4G2^R7pxiRrBWYUlWb>x^4;?yg zTuCfJ7%PRUi%Jh!n{7N8p%C<8hh>RfoY2H0E0GQ8ao%M_S?`X99$S6YyGPcuG@euM z8MyG0IVMQTc`HojNqY;eYEh7{>SvUAuWq~t^G5fh^Px*&PWMkqrVNI=W+3V zw4N6d!$Ma*vSj0X`byV>a_lrvMv95dXP3xKTSs4HoC&*>Bt0O-g3 z&H_7>``m1A2tR^aRLP6|R_w*x?$^3Mg19S8!t#eiADTNMwS*KxR9Ek!V8kFIgxqm( zn5V;cJ7YTlsLqVd^T3Y?lv=2inNds>qv!2MWC6c>D0%obtn%J7~gNy4g7Q{z2 zvR?mCCJ+g15BN0gux`EI4)SjDqFGIl%~m6%@fB+1^}#h=o0M#h^BcK?asyj<1m#u| zY$&Tg^O~8|fzTaszkcAj8FZcX!#lNpd&c7YaBLg2Y%TR&q@;Ryal7x6E%RL$^= zul$`AOn6uSUff-X{+GMWCvUSxc7?A_O2gQS5^u?hnpAz%O^*x6|AhHb6Za!uSO8z* zm-uhvW-&wQK|z@7L9GD^^HfIjQ6lLf{Gbg#&4^x2 zNtHh*Cn2y@;s4qZH_xSYGzbkzSJZ!UOiA09xbD)vm=d&M_oU@{-mqS|uc4qpKW8*` zraZp4a`He(IJxvgxDh&i6@$U~b*N`KPth-Xc%F<6ld&9FY!I(I!$74z_wb@Ug> zHlo?vYU=yrhF#Z%i|`|@7WRL)4PRW%7Z}?S?+K#(7lf^n(+OjSf9)bp39aDex42LPa&Cp-u0ge9h-$Quh-UdIa zp(F0yXlX1TkV~K`C~QiO!QX7+z+tQY7*m*=oyd1poSwho*q6CInnABgx{{t>fW^r} zo5;J|7#NlrBDpF)b$L#nq<8mvMoEVt$!JCg<0wB|PHxxAsqqZ$tJUuY;D{Bkh-;k5 zG0!o;InYFCF8ZCtri-H0q%2~XiSp2m8R6X7>z`eE1MCM9q1Nhqs*w!k?5TmFSPmz& z&wI(22Dl-6AIwUEF8;*m9!!p}0liUF&1w9E8}%#c2$BTw97vNTa8Bt^^upbwpEdWW zEq3ZC1E@R);X>xF#?!VM=$fRhOGq5qFna#5T+pz-#-|rRX8YaDhFUTV!Tba3+E;{u zq`Tueo_1FU?l+7vAFMl8Y<^ZhjXh-395bs;EX+yh6~0#2OQ%kMRkn7nAg^)F*Rtn( zT#R}@KPz(XlZZbv(F|>vjbo8TyAQ6dKQ8Hbd3%La(1JQEDQggJj+AnwCMqXa5Zvwu zrwsP{S?`;(yY4+bJ>AoN)^C0%C(mw0c{y3WasAydd@?O*DOaXktN_y^LC9uSMc+<8 z&r_bJV%6nIEBIb9G1sx(3H4-=uv!e!Ra4s*>z0WY>>vp_z2!`FbH!b!QNZsBwH}lcz+D)fC2U0KZVwx8+-G;Aolw@ zRsdDsKYe}}{y;1CNko%W^!v19=U3j7 zjVx^I5!nOGza1~GnPz-qSl65>{a*-D9idfFU5pIl`xdP6GOjn5{@jjD2{kCb3&&F2 z)kniFX&U{CvX71>LZX&f_bG$0hQd+9Oq}jS%yj`FyBR2&*|?YOt+1 zyhaq21|^qq;U&zJ1tK{!{A3D)7C#|=>QcKowZp$F3j_Zb35vP&<{hi<&y1(X1H4$sY}y!VmGmz$j~e}#=GC@ACzU3;`nU3yJ>}HGCzESil$+S zP|D3mJ^Joo9%m0`br-V*zvp#bKr4&Ick^cj#^RW&&7**QaGW=M&K1}NsC=T}Z+U;~ zyhh(rSSV`uU69+-YB)I@^m5Y-u`85NY58ekaIJTn8)q4hzwygM_kfs91N%JNq>0<^ zftT-}LdJ~88P7|(lxase&Yq0eigU5xVXK3=bzgZ(3+cl!pLw-wHILnKvZO$l-fQNL zWO^dyp&~UxOl0`tO`(9_u-_nVUXv`s&jDu2t1ZT)=*QFySoyP@xlPccQNx?kgFLKj z(|za?I2LRaMPdZu2*zWH+}6qq4}mCkix+n!<<2>>lzb)+X%*_n!yjAAzd#HjUZKD1 zm86GU9Th`raZvAvjr|@VkC4IG&*Xvbp2=!3h_#hHXesLXge~?^rIQwH8j*Y&U9}@g zJUr}@Iez&(#q?C6NayOC`Aa;qJ${yllfuTTh7J~!KZbaDA%?fMCwn7xKihfSAZ#Xl zFWJdngN=IM5$LegNr#;`y0HGSsJ%-XlqkO?=o(!E#*InCNjZG)QvDNGd=BGcm;b$+ zvXj;WN$+h(;*N6Qwpr0>%)a47)44yE=Si zx4wLQix9lEkby1oA!PoIr0hN~mx)xKZjj?j#hSj-r0C32wql-1s;GvRacC$VZu~%! z;Az=sRiEoAVP_8$ENMR>`&6k6nV+cn@Sv8@Rh|rl$r}ewZCWU9L^q$^d(CREA@TOl z-ezL&jU=ln3l|ROPz&8VOFuI3e09Pg(@b~38NWz}i0b@>X1y#|kA;sa?9a6D6*#d#h`> z?oK&{p#okc?qkdkbeuU+1Eb?<5ch^UiHmB7ZHeOfpA&por#8_!*&Dj~E~ig^U=v*u-|$RX|;6p#y;xhSYf15`QFPPXgToP5)?h zj-OTMOZ|z#0OxP)Wli+8O17f!k!>Rr3$lePFI7##WzxSL^)TO6jpSCzuy4qCJo<9^l^|CMI9qjdi?0e*<;Pr zXRlbTwDY$y1FxqsvZlPA6nO!49xP{1&mncB5nm~&UYKr~QfoWoL-XAg9!nPW^0u{Y z%;|*z(Sn><8WB=%p#DZ*QDeiPBPX5%i>jAPx!4#OXlKt58us&DVdnbiL==aI6^G6X zKW6W_&)I6BUHecmZ=zTqyv#&#)x`M1FPnt1KgLFu*HZSx+L^0RdQ^-u37gj)6FMNa z$ZgrZbcnKH`}$P-H7#`afDRGBFu2Po8WYN|ay}E6QBjr5X)D4}B0Rlw@9|c#UXJEa zGCY)NK^1)tYY*WYPXd)|n*YOPbpC#2A#UeTGheM}O7f9}vhc6J_-Zd|xqnS!3{w_UUCeZnr)j{1ZfIXZSGf&S-Ef+oMYbYKV zBI!&jrP8cU{ZeXxHqBVE?V?_>o&ozy#d{jb{Cb6XDRW#FxVJ^Rczrx+)ib{6*5$>l zw!Q;V^kn%qk{HWabh(s=t!JH+@q$l$nkQcSxaFkZ4G#==hKN~2ZaZnUOe{(}RSDxG zPR!mXf4IhfzpG*$FFi-(a~EF6-%{o218=e2lJH2VHa)$tk_@98epSyV_gWCDMoV|! zQqf})epbOPTma|ghnpG`H=adeOqqOlcvj#l*1@yO^OgiL$E!N?D9TTnNF*`6llo$b z$m0M#fZkaC>5yfN_BT{?TS)oWhu94+RQ?FziOruF-BRi{2__rmEZ7ZBWQ-@=Ft$?E z54d^(($vj!T9nS%jjn7<4J|qd=6ZDWiu(uR;^1P^bJU&hlbcBA+$u5WIH^%3Kl#<2 z>@3Xt62g41QS&q!giz7axMXIV9*T(35dDVaL#1YGRHoZ5r)nA$P^5T@qhEQaO>T;*gsNy&o(Epi|}AV*yguf zy?s<&i|H=Mt(SPH8>9>isCyA*#hH#U)5VazS2QS=FsYBHwbUMun__l)UzCoT+*gYH zAT6~B5loHN&T_1t%4_Njb&J0h)ZT&Vdpxdu?T->ZGCZuT$6-dHViV7}Yc{|eW7GoO zgP^nKZ5C(6OMC3Ie`3Gy8?g6d`Dc;7R0NWasbyE**!j_E_S!!!RM*B{iAGenu@I6+ zy-Juz`yE`B0Pwl?)Vy}wip`8#bLNKn zRueK5qHBBm*A^t>lCr>4a7)TxfB53Qw}1j5Cqa_er>)QGGBPq=4rk*a5meDN~7La%{u}%V-cfTSqcPMOkDt1JydR`^*H7J=!!S#^jw7vc@hb1 z4veIKbqfXX#q^7mT%r0p1|lArrQD4iHS$N#Dm0I%{kZ*VscBz{v%qQbSxcgr%n3np z*w<4wn39FAbUJ4_?}K(8%o)X<&n~K?y+v|e;sdOQNt~Gi{FC2u<|* z-TaO;!IH5Y#^oJR1xXF@fDZ1~d(u+oEu84>?Qlo`($5-A*rsgR@`i>~{V9?Jfznbd zk8~Dx?R~D`bApxPYaXtYA2Ky4wJ%`%7+F?De5`$e-#kwIUT>y^`OTR(?=a~(9BvW3 z9-HRzbqg>4WnRnz{~9a1x}(IFEGdw_=_HtfTl%4!+r-z8(>E<3y=7RQ$*>_e8-E}c z14Xs%0OtpAK`EfsDTS@SuByIYSqD7ThM@|wej1>EXocA(@klnT|IOF!OKG3a!_};Y z84ig43kOkNf5^{OD9pVw6BU6pee9mb2)56LSz7I@m%hz z(4dUR`WNdPqt@Ans<^S@sWNT!58mJ-#~)~FYN~@K(n9_3sEdoGpr9lNOYJ%a09Q-@ zLjZ?41!ykB+7J^Gd5%O4d8Uydc2eCXMkHvfJ0SYDzR`pynl^hi(%j4Li=TMJrUeMY zNRL`$Sx{BeyaLRGJJ*ZNlt)loT%|nB(h(#V)7_2ztHT1fWMcJNp=?-GwJJXoD+FUS};l zPbY#|)ftAL+0WE<^rJMJ8amIEHt_yrTj!i#pCR%wjEp}HNa}++aH3vBo3&mq>17CG zAH_x3c~7u}ocM zo^%D2WkT&rh|BI>|DVG&7#l97U$c&%0SzUdH>soWs7(t)u6lJK?JAS@{h@5|t@aGr zVB{=Jv4dXzHx;X0GG9X66vyoCP0AP3z{oJ4>oZH|of%4g%l$|p>Wz9Dcu@1Z;^x`+fr{7(g# z39qhu26ms0Ehin$NjB%`O1U;fzDexv7l+eAU?l-e3)tvBb?4Y5Z|3DRskAg5tYMng z>a#EkWATx?xp!lL>XknRjbmJzXKV!pF#CLu(%AeJ1XFhBWAPZ4Oct7 z2>p2GQAb;Yu%oy}f>>Wrm9oX}h=e?ivb)7`FQe81Pi`+|YJ63%a=@M|F{2oTeeCh7 zwvTlHflkxbAwv-?AUQ-&EdF((1`wicucJ}Dwb?r1#;aqayEpKi<*#yHVD4gUCYwek zI_52!kg7QkJkY)U1FVEfA9^P4T&B>rdE{|dQkGa)Zfm^ADBiQJ&J%v7dqGNCDE}hf zmSLH23{(52(no?`;wC>rr_E=cI67l@(11G*?P#vTu-OAswautAWOV_%8r`3SPz&*6 ze%z5)qTSk4+ECD%99QO=f#7)daYw_m>8=Z0sI>lxrqx@+ux{%P+>@g3MJ*pT`5qg% z?4?~eMkh5MSj(bgyy(VTsWsid<%pgf*u0Y!?|Aylg+hBHpH8{0iTp~BH}a8|=5rp> zAVXH%mtl|q#0VEQ=52FEuS%K+(xXZ_#8l(O#`t|3A6;&hl37P8dj+^OT`B89KVV4f ze;`5oMMNi)Q_Hp%WTb9m$3-&kr7- ze>9_3SUa=rsVU1yS)&#Yuh8Rdjk$y!7PqLs1RUm<8x-A(K5T)`ybhL z*zwS{cfruT?(-2aKdeM!N6Ny5PYNP(^aD8Ays@4iT??J-QnLRT>9=&|bW zRzk@(u*7i>;NR09ClqF93&K*TKCFHpWipkJ_{DOcAzdPzSoTrpJ21S7`pWpEaqYGm zEt5ioz*kbDeJtU(%R|mHl_mLieNmqC=^jYbM9L3Up-?132#%MD9;&vj5=ogRGcB;9 z)8$YT9Sx{#RlhK~{w^O%R1bB;TPL(<`fiNp^=&EcDgQpkOWvJH*h{nf+}c8gMeUd~ zRUNuB?Z)pN&7B{+3p&i1co`N$-n+KsLftNz2{?py6jRM_cDGLRo#@^KW>!gNk!f$2 z`y|?}-}fdPcd0PElQ(KDt7<5`MnLs}>*d8Od2LQ3Ru-K}<2Yt3yIEg!f+J~+X^hZ2 zoEy&P_v{R)BJZnmV<%|`JW;-W8dUjs=lXGCAEt*IFp8c7`i{z?s9e&1jq1_!)zP1* zg%&p2%lxD}yWBoW6IMufUYDPfW@Elv(%yC@BBP4<;BGq}5{t5?mnpqm8^r@gQ;nYIV+zF^)W{nf>Z zrL=r#;T^s@&^L}moD&ffqwW*a^F6~>3Rr14nUe*3mJ)o<<2a2z)7*k0=)Di2c<9Qu zeW~I}&jngA> zceXCR!Yo?}s<2E*B@i;H;BU1~HpTdT^|WJ{HBV?<(-p<$@Kl~6>RvZ zGA$^si`oyPNICPVgs=P$gB6}Sz*G)=>51sS%C?uA=iK2Sknq6^i8z_eejCCJEg8*o>Xs{$z!=% zEn2zHvCArF`zr}mUf=>0KUJUAuT`kbZOHAAJXB3ZEI*$EKD5G)u$7G1lVkHDFlY9u zv{q!w&{GowV|I^{@`ko*0q~c0fmT9O^qdqsS5|OI& zH-<*tT4$?!#?^!R!lU+4AuPL>4_tTr>NkGUwM1e2w8#MCw{!qD4V6)&3?ra~I@nGg zDO+0ig@9iFS%UjjubvdbPq!cJiPAEjRHY;H$@+`SVqb>H@;1lBvFD|HL!;>#4XiKp zlm@jc+zFi~R4P$gYQT&O-g0E*mmaJTk7;{ufiB@5vanniqEsF5wpoc;`~tH>m@Opn zy)?!3xC%|9t+-E_VUA2-ru&{j*;CeZp5Gt7HrCijZYyPrHx>UVs~QM?B$(|Ih?}Qt zdiJDf^(4Zm3+h0N8s0cd(BSV?Hv9QqfB4tC6xt-{(rc+KUGzt(Y@vMZFe0i)rtehv%NFq<4Hk$|@= zL1$A!=RaQnOMPwsnB&RFO8)k4zTsnJwmXXK z&gx$z(e_La1$)3OKPJAyRV}_YnB}SQgPXv$Iy*$G(!W>eL)SVLJL#J)lr<9r79!*d z6O~l}Q~YE~LMNSK4(cb0J+0+vu-4b%)Es6*&wiRUDxFH`*KFvEsOKSjW&5HKiTGSG z`OtKYik7a8IgGBax!{s4>Lm(r_JveLKgOk0>Jm28JSCZYrD%GrNNL30ae=DU?G5}fP0^nvCT*c80+2s}YB-{3N;t?&j~!2> z0r5|Uu#9MTgx*rVcE_cw#&dcZKWB8;aPlulCaia74)D?9&9bJ?bhZ~TSQ45>OX^u6 zi`;MrppL}Z_uG`Mq1;;5o`08AMBfETgF%WIRN`~t;;+-ie>m+aPnD^JfEuV|O>}oc z3mM%L8?Dl=9)tT$&+}oNbERe-JRCBXLH6Ed=DjkIR5HTI z5gc6l0F7kk3i#K)r)pjbzcx1J6ma_l4&k3FDr}PKMknFN1LmBLO}sZ>SFxKx#-=0${CD2G>FGU(SCL(T2OxpSfAWA4>O2biZaFs>nZ=$bD=Q z{y}=ruL7mZuql?>S;i*1$O|Mu)?Gs@OJI;bw=XR_0f!a`ZA@s}?`yTbA$wRaWdA@w z5WDGQp#8)hc{biqSxW>vy*AI1koTuB{^OrBuL2oF7nN>f@SvhjQ`A?ui#+?030jP_ zS#kk>I|#uwaqA$Z^8$N?-^9lpcos(~7-R+>pLLwCXgYps{*KQH`G67J!MFKZ-ev5l=q^cP-q2kjhqmW%ORDPUHz%0p0^%STQv(saXKC$)R zgbFha2E#$-!Q`dtAMnj? zr2KC0PC6dmpKlIyg*t-`dnn;;>)A=W$-V=_)eI-zZ?ec6@lbs~2*%Yjpmdazi<}H~ zi=QEPCjvJ}zn3_)1s+5EJw>gnOQ{gFWDNJN1i46ds7m%1U~HSFo!W#kS4#gw=9`&# zY5^)sg0td%dv=hbGKWmB1QPIDkv=KBwVUrrcA^M1)Y8PffEv;5>`1IVEcWH zFXz*0+=*_Ftu|!xig%qKN?`JbpH|A5lycf7t*`EVcIu5Ahk<>RW8+N=7VQcipm-SI zLu-kw%5tooa0^V-YYsSOiToOMy!r6}fk9N8BF#vCE2f$yrTRl<|8HW_v9{sEOa&DJ>5+LbQI@KtyAjjEsW}?=@-Xz6aRH z&S{t)s$IG`_^rJwujAc&7t;3OpEJ_M#S+0_7tlFx7BtQKmEON~T(PN%0RRn~uX$99 z=rBnh7|Jj({aCXT85Wc9e0Kjg>}EEocH4k3cp7xhEDYjT1P<0XsZ zcUGlWGANyL68O5IeENY0RjVEu1WkZ7vJnDyfBXavBDy5XSZb8!p2JY;ff8lN6@)u> zw1J4XIi4j=*~n95>!?UeX1=M29}ZI$dIBa5O8_C_hx>(z)9(21{E@_+D6SO)@vBr8 z!_=MD(pd#qZu308A&Ts`1)Q|wj90;w+ENF4iD7wy6VT8D)3G>SWy(%*UDx6W*oFGG zgRNN>eD)Anlz952NzO5BF6uzd3SP$YfC zTB=QTz@g`gmaJfFp!{Auzoh6uGgbo`N4rf)5Gx!pct#HPB&ZN;sU;<}yb)rzzTi#W zqNt7v=xQJTEYBA)S|?;>7%JeAP?fB3l)k;feQWK!Y#3R${7#{JF&dxwl`Cw*hrY4K z5C@Y~zq#V%AqH3jKH{%6(3ax-Tb_@%EEjk$kO<~fFOZTZc+zy{ug(8j`b-|b=i%Y)gNt3BWi3hxCnlJ^f99?D`656vn66sd6y){F6z zIJkQ22GWY}s7h`WRy~l`Tep4r_zYjP(mJLPGQ0mBaCNd+n|G&V^1=ZmQc_&P<>dRs zO2V-iAx)CS{W+Ae zf~~RSeu}vIa+j0qZ!xyC&XnGgFHckdJIsv+dZ>I0P?j@8{9ftY-TYJjToQ9QJ}!Ik zO7pFZg}P|BiVJvofI`rAr7bd&X4wHbTL$(CXj4093FMQe9Fqhg0lC+ElOb@&l%hVs zJXi^bc9)})-_6&@%R@$nQY69sHv}9OcpS@gskCrXRIE7|=0geU0`+1TY~rPupiZC_ z8oTXE<`zp4NU?hI%NzIa321_QGeBW8m+ac-8XX|p1rZZlPYsj^PLRJ2uCTn!<>KH5 z4=9kF6|&jNNb3FcXWx`Y23pN$+ka<|QmxCjfl)0}?%@`6LKJaPwwurKxtBhh0}c_u z`o4eIZOJD;|5n0H;G|U)>xVmX-^gPyH(#a=E2wE8@NK3;SK6)a0FJ(mq;z%}I%`9` z4MuqLvmLA#67)?~jW>e1ig??cXIyM2-UF1P@+1g94xtBpkuSb(m-wFGxK<;!gN>lA zBs&0#M?k+5bL@6wZqZ)Oqu9=037{glQJ|R@4wS(@rva&hdHmUrN#qym^_wb+C7(sj~07VEM& z@v%UweP>-_c5q3&pCgJ1bcSU=dN+XrwMywWw|QsY#T!X-S^W3At?xadGXeYc2Zm;z zj>vyI&DM!~U=lUB7YV&C-o~cHp;@8~u|Fb^|1Q#j9~slt!5*?SO7Eu2EFf~ zNm?@pN_P`d$(h{f#T+=XD%3n^$>0(O<3j|AdB>r}ff=X6(K)pGVowEPZ_md|#E@%F zWZ?D6B>1PPqGNs=7&NJj>ws5~Y)Wm-^PYE_<6}m5BL^EFOu9Ls-;Dy~P_b|q0w<>tJ)gcIAC$NroaC>RcXlTP zi>|Q^z+eH|!h_2uhYRwm<#5yQAnAd!@zQBI^MFK(P%egdBmucllbsA5fz&5ujo?!< za{L=eyxq-jirBZeT|q`O*x@Kz-_3wdbjV`QUfY3qt%;$e80}9CrPI|nN8`dtG;^!k zEMwR%C%g{$FWDVvBF3eyX5tyX0!=DK&_r+_Xu1+G!Q{5#p)?NW%EdU;*8G`SUM>l- z@#nB1*GGSnqgEmPdEQN4EEIP7)BE*G#X3~%R!eV~7CM6dd<<{B++3Uuy+yb=`MPME z0Tj&OJbKzOV?ap3l!~<9Rm;Ovf5+o2TZjrv(V!|e5Z_DC$W+PHpiUU9Nzr|$_;S3n1p z+AgTSZ2E%Sn_m^3URK29j%l zD=;LOo;|Ka1I3dF=3{^ROGikke%-fPvXqbm?O@wLuQ8$>#PVRJCfaSPZMrPmZ7ea|=ij#7Bd$;xw@yy` zE*l~43;CgY$2i%;+l?abHwwajXi5Ea4?a2=o|NZVZ?FhiDU=iFW#anV7&Yw6{;VUu zRl+eGH5Pwd<5|oQRywj!s-(=W{G$JkiDqrT?sIYB-VcXKXps^wE1eJd#<=JR0dUuF zv4~{639&ThaNuS0GiHp_{1nqPIc5)2*C84%B$^n~-#_iUPEY&=)XtpiC0nZBoq1%T z2|YETu~A2xY_=9nRZL%`w!5MJ`E#L7%$)uE4zbDgKb7LG0f*99b4XHVsOz)Qpp}29 zTM9=n;W->^aj7c3*6L|Ds9$`|fJ2x=rbt5Zw;yA+szv2~stAo2+LSiLpvlW2>d4@& zyE74Vj_9v;K=b!sAOY)zqg8612ztTB%M}YJZ+?G=xA-#u*;K}10v^?J)H2!G2! z!Q*Yp?xsi_3{{rXO+`)d{1>yEN{~fx!Wxa`?_qQx5mfGC!Dl;zcxr1KL#e~e6xpHW_-K= zFUZ1qn?pz4sc(l933n`~H>7K&*Y|})DX6+U%xX_xv>_YDHXeuARB9XLCm zLv_-BKV<}oIsKRijZe9JSLdgJ=yFyA3IS`WcM-Wl_rsvn;?mfFMXsUlFC|2!A}DV3 zsb&jDjzQ$xB?4`HMt~V7#z}i7=_T}=3$TU{MY0K&0oE#yuOdGw%-HwYyg6>brK>zYr`g$PEym@CAl)g}faI z=%x`A(V=Ex#<;wcsv+8<;~po?BNrcjARKUyD>RKEzjkNdiH;j;Zd~Iv-s$wrc&)XuZGE~I@Hv!Gwfm6fY_n{LvYUQ+RC1?2FhJHD; zJ;1p<8M6GlpiXLXJP&Ev;&weFN$w!$UIBr@nUK8~<)~$?=vudKZ!jbNiB7eUwnM8U zcKuU>Xc1#jXAvi_i+5I(vyxrtj?V`70PENsCDAbqA_H5%&Gf-RVijOTrTdZoJrMx& zfeY#cK;Bp#`P1}fl454=ry#-12}dT6`!J(c{XVBS@Jatxn(AXQh%91fd!fEcJiVcw zy#$MFKkSOJt0*B%R}@UTwv^goK^z#>U})LR^7njq^d93Xxf&A}XqU6#*zAay!}^kw zJ9CcFpoCc_F~7nH<%x-T5!q`=;{LiUqlUdW8@YD_3XUS#Qmwik+5u>$tZ3$}Hi~l$ zbQ`76jz}OOqtWP2yNK)qha~1)oB+-`X+I zK|pBp8ECsCJmk^@$*t@vfAPZ=5S3OPL)mOvQT@mqmQZj-e)oOT~8m|){@oa zOSDg+git!>n=1TD$3_`x5HWfQ!oN@=tBox${vr8ugC_%)`jc1jCb0KpxT zYP*E^&*-~Wgy_~ypp67#hA`-Nde9v&S@FHIg9rR3k>)X{io^oN;_DMZl$OMd5Y_(E)6dh%(!6Pl-0AO8 zV|5+W9Vut2gbBaN$aJes5lDHnNcKED*i+q(_B@qEbtz}|;(B|O<4H1MP2-R9(zwVX zDLtj2rqsAWt}%g=VYko`FG#b6yCgH!Y8X*&v1+a{t_|0FvZez!p0wkOnQ##sj9L5iygiFAO~!EQ;O{*j5Af9 zxSuLQ+5v!tqz-ged~b;kvPI$o?+qLX^5;Vhxm-`#zdc#SER3^dl1AE-3`4@>swMSV zt@Xz~m^yNnOKk%{bGDWQq$WI99ojyKda#7OFmBVh8JbH=~%QZfby%vHOCo4gC- z8z!4$Lv)R^YD7Tr6^h#27THD(Vr&F;Ya?mezMl(kEZKJD1@7kcb$Wn|^W|3YXQd7! z__Ce^Q}WX*<`7hLOcGly?pkNuvD)E6j_o#x?h&eDuX{K3?R=>>X2ZUED#=6VS67$l&!Ov%Le6DttVPH_n|b zGW=~i8QEQ@lM`2H8ycB%BU{z{vdt%U`rNH~dec~;Tf(lv5cgE=bWeJb8^)-STJQU` zU>xaIox(C#6>40c?wmG-y7w{(R+BR<_WIWG6jJ9aAElpx%lG3JYQhOJ*SY&5A-Tci zM_xcv%X=QQZCpK)%|asNBgvBF|1C=U15ZXka72p(L2EtJ*dpbJ5jO&(^XQVFFz=#G z1bbn8)Q`YBKzYfGdoSV6Ki9fmw4Y=}&6arE6hj*2ZIzy2Oj<&IWNlQ?-QbCjWCD(L zJCTn~2NNQ|zTy1LOqsoynHxPQ=d&D*0vthZ`&Sss>DdXAZpEhDdy7I;Rc!4&SN9d} zltB%8lzrH7+i9>ZKoW_pS-bT1ObB|} zp}(TS93PF0O5HnlmR=jJ2de9nXqK;HjgIbOJ zoBJ|$&w5)m@4;%K=h1|n`i7CV9}gCH^xd(I2S2k{dDB(1OMKSSqSvnLvwDIv9V6=7 z!+gQt;1AoF>u^L*WYV9nxQK5%f#?-V)x?Jf)W>&$MpVKtK4PRKepjmw2127q3Q2pK zVcaErWm!!fHiN5Ijr%ddBC#2FwLAcL(Y5vJPRQ1rz&_)LN490E-?6=UXCzl*g;zyp zB0TPQIvlxOw^l0MyR_XRw7)O?djZ)0kkm-q^{E#0oE&M-)>!uCaJTt#MH4Ng$XjL| z=6}4IE2{(H;Ta|MbJTePhnQVx=Zb=ok${269Ld z8X|0}m-XvOp&&?aEH*F~3r=e7;BGUGI(i>OH2EG#DFP{~dm2G@KeaUS`T zUp?2uuWmO|NJTQZWMl$<(&L+gw+*ZH{ydHqe;w+zjrurjzUv6qL;4;)vcZ<|nozkw zP8a@NS3g_wHISth@Lx&4#h`ndzhvQdJjWv>ZZ?Fg96Aik5Zg+Ae~afRlx<``6?Nu* z{%xKZMhf8X`9^j*_u@Yb0gmIu#CPK|i}6(n=3~H+a^y(Tr|fBnatN9BVP5@xxO3-+ z5nmZBtfWkfj%SCsX->MpN^$i zr%Y>I$ptEuuAfwM!tSKyhx;~Zes1cwyvKt=Z^G;-`CF`%t0z@O(<_yO2_m z_Ne=uVy6+nfp890UYYF)*J#sQ84=6tYv?woik?N?|p5X>L{<7 zz3v_1aoHq;zudEmY!uU5CY8I#6K_-TqKud4_cGveY#~GXT__pm(gzh^jbFr)IGV*1 zW>2xo(TkJMaj<*FmI~jIGlQPNRnY^m51iNP^bfSFn6XRpQ$d<;#S+A^H_s)LeILRI zSfYs7P&W@T;)F0v6^Z*E#2)a_xeJ4M;|2@h+eU5tmG__T`S5T!!Ukk8(1vh)EFu?G zTdd$1HJ%0NKUZcS83 zP!G@7_!4by7=kbD5sz?B>wzEfWMqC=@x}N>QgDaL+axN>vD85oh6dsYOUgV9G5}ux zY(>}&N;?dYKG1dr%5i|_k6;rzIzkZ77Cr1PLKI_#`Hcm)l)mS4iOSj8BeVUU7xGM1 zOAH6Yv5G<1Q^49RbgBDnM}rmp7AONYgK<>E#GVbq^NKY=eQ%-w9mN9Z1d2C_T?j|D zCpenL@wcgzklleFJ|-P1N+KaD^u?l!a~z!7=Cc_gLg#O39!Gbgpui3pNlHTaT*TP} zRrs^C-TjGvGGz7Vv!zKi9jd1awEoA%BzSY|iwKtq?DZ;v2S{^@{>Om{k#7le@}qtv>mTuC|nTQkr?Jis{V4NUu6kf~=P zCLV|8jJ+K1Q7MbE=tieu2Mn10Om@m?#RK*8L497|1_hY<@i)~(_v5lYkAKWS{R`rgEuwx}Tkg_?n;v@EhxM5`>4iCfvH%!R_bRPB9MSJkYR ztP`>8b$)eZBWa>V_vD{!{_qYR4C_iHmsmF2c`hJ@2~Wf|0ZK%0(FnNG{yl$gZ(o6u zTFbS!*lLta-{b*c!D36xUXG z@7EuuD>BCtuM6hsg?%*&C(aM|6fwZQo$es|?ByqsfTvv|BDJ{?wS|3UJk-k_N%Sk= zZzS}-ag!}K^J|*ozC5IL0q{vI9^)C@9&Vk})ENz4XrDGr^JMDNd)s7iN1b}uEgs*F zW9!QRRptq^&*5VQXY-de^Y;oyyzT`;O*!^RT|^*7F8JQ4!;sZRs}D0@6l2xsg-mYw z)Nn7R`WIm&*W2?*@oEZZ4^g*^5<^QkY4xDsmb6+e!g`wj0JG*usZK_K$azA{XT$Ta zw$o1Nbsae+NA>u9)1`lhE}WhlWPkzhr!UM)x0SJ7zW}5?DKy0+I%31BirE1HuVsYS z;1&;H2e`t`pD%aEmu}5B#Jxs4+_*tGY>$b_K!L*l-W+bwm}y8|k-2zK3{0s+BN23L zF(2r>9XhtLEiI8;`eI}oxpeV^_?Z-{#{p}@OPrfxb+xvVJ^2Hx2e4d%lSd36S(!={ zANwfHo&|momMD@K7BUolpSH|%m`*oaz2lg&onp*TkIn4QI{mBD0JVH^qc1mD{Hbnc zcm6@(r^j;=qp^U0XvuS2iR5wBK!A<0Zz;^Q2Z=KGsfScv`iG*_h@^i5d%PAnQ%~@ z{eyjQ_Q+73o`pXeUz`UoFhZfXpziLcAxoN->E@omK6Z$|krRF3+Q~NJ%92I_*|IO* z)Z0r&qj2~RI*~IckZnX*y1Ux?7X*fj%$FhsZ3P?2fNo<;tnoa%At?Niffhk1HJM>{ zC?!*jGZi_^^NNM`?n5Zc7=rBD6eSRpCnlli@jTd;E0NVavdU--y)JRIRgQK z%5B6Jo-f&1IDz%_QP7*#6YS@1l1?bDzfNn&vV2wY` z$brB}Y^{IjXFr+$>8Bgr%#5N?MbA%re2??QVd=KEi9KIN0}G?yf5_sWAF5O8o`Tzm zo|qd`7Bbl#p^>raOonYOf2cV??T^>vqWrW30LPv6Hyw%Yl+jJPUA{hCOgh}y=jyL_ z2FIY2h{>Rv`Mb-2}EP<-6u zZHcTG~16}@>}$+uYACb=pP{3xgIuc{f8=_5Z&NFiXW^Wo@gX`BQQ7|lqZ3EC^IM>rtWD7 z-Ls6Jq7EYhAM{XCO&u{wBA^}2R{gsD zdt&^+PEQ3Xix%=-4oXXq$e`MgW_3868XM1ZRNQ!`O2Ir+ev|zp3QlR_N#EV3UiiC? z0Y^3|4P=>Dt?f)FKo}@%uY?Q1DkzN*+J%JG@`bv6@>TS?8p6Ji6YXwvaPVY)b1N)D z=&K}`^ET$Te;kQapgo`@moeL;TM|a2q%gGI-Q|rL;5jiqb!P)9*0R2IKl*1a`gF~+ z^`$8YS~n$H)J|Sa)=;b%M|_bP(eC`kulR=onHDByXOQFdFz1O407YKNG}V#+dx!PJ zx`7NAhsNx1KMA#OgSe|7r0i51CW!lS+t|+ z3z|RHa<5kFjzUzzj4h`aK#-X6Aq$Y1N;ZpecK$KA zSp?IUR`=-XePf?ks9RD3&5biuFr|>!#CAN?@Ms&3#B2c+;GCq1L8#6Kmd}pm4Itst zuD$-qY-9b8US~mcg9V+inAwTFUfy!VR87MSinXxF63e$8$EeH@`j{OW5;Y@=O&*Y~ zGyVD7*T3160qc=8iSOSjgh~~3YM=WwijNM3`83nCwpkSvSN<&!bKLL?hzov`q|hQ&Q6?#bFAOLEId}Z`nFZKqFVDxv z)#eMY-#XMIarj%{g0E4-!a|4S;`Az7+`#obtcOt;Fu(DNvSxN@Ba-|j35u<#QHR-O zvWH5f5Eb|0_45`)PHMIRI4MKE>zB}&_qQ4b0$R=F>r}3*!i1TwP0f=#FO$=0! z5qXO<=Q!0ui=H()hy1@-d)X0TZh*$^l1XW1MYdK%8u~UY-2wZ}WuOGk%ui1a{-Khs zi94(cU1w5DwWSc5;Qu9?aHMn{(n^T6fHmNrpLC%SMVr$nf+FO)hEzrdE45UvS;lOx z2~O*$H&So}))+>n)E8Hs^e8~B3|`!e0xWiU?>w16Le7pavw56y2&&17sl>>*uV0@R z7S^EXcP^n&(MAfF?kv469WFU=%A3tTxT|x&sS^Gb#E$A6qXFJ*W|yDwuc4GTbSmDQ zV8_p;BZtuC2q=UA*QAH*o97~sx&S0PRkhN08U8Eex5%78w6LTTl<0084sw$mEx!Lh z=oi%r48*MC*n435#d6f#&*9RYKRUV3p_%oDD(0_WH03g6Fgb%BxqK}CX!DFBmD2`q z*Ceuj6E%AY5ZYvG68joX;fX3o;MCiJ2o(Z8au$EwjOyx|O7FAGRjy9}gD_%ozx;*+ z;Q&=RFYox}S^~Qh5!@~}$tRrXG=))+`a{yGGQ`T)6)w@T99phd_7tavpW@_=;v0>TqWo-y58>YhswW1R7u>ncx z1mTejYI-l^Pf{3g?DLQ4feB4_leczri?=7MFyV|Fu(jaST4O+<_HOz_2QYClSz+;d zAG^`-oTY>d1(P;;wL-m-&c^~x!#PCD-h3W@H4yfoz)JKb5JT$eA@deN@=rHugq??&!U4Cf^|jn&rHOX0WtE zUa<&|-O&SDUMFyQoeigoZ*H2YDWqba;rnTVAzLRAlt1bIXlGu5@qPCmHG$NMe=)@0 zEdn4V(ju9q(~68bnp2a%7AZ4(Q*j0d?{G=~iMWy;aFeZJb^M-@Q)i1fMxO;N&fVIO zqJE)K3mqN4eL!k_`KRxVM&B#AF9o+jCl&aLLO4`VO&5I$zyd{AF@)Y;Ub1^}dNTrv z_)rD%0A@H#f>4hvaSJ)Stsvf8_;K`+LLP`fT{O2}trd`uqjS*%?VlcM z*gj2^hu)S6-8^9blKm<~k5x4y2KJUfd;PXW>-kfjre55LicQuzw_J4Ed*sp6GOvmrJ65U zHz^8?-+|5J*=7c8u$Vat$kzIk)$vnM5Vtt$eiZRy=s_(J(U$bNVTJY;&px|Zz`|Ab z$OH;FOXmw$Y9>>ykpc1Ink$1yX$ao*<=J=j^yJCY@i>l79-6xve?ut9x19g!(6Qrr+j zzy&-W5`9(G1xFFY@34rzx;XKGs_h^d{l#_(2EH)a$`1Hn$;iaghyB#>{D=k<(hgH+ z-<_%W9^b(Dz5mK=kz^6(0B1SJuZ1*l19H6g+(mUN;0=tlRcmH@^HYR#wg(09E{6%X z2%@%*+WhJ2Ym6Ex^;4($soyY=c68q2hzdl9N;_Iz`B$LW@a^%c}c@{0Q(96+~80%VMm}AJBQ>RsBgi~^|{CVa( zMBEEr^!nYIvX#7hv^E7KDVgizHx*6U(Ld)mJq_X+g{vyt{EH*g%-&hDQ$}PNmSJxD zne`0#+f_;$=bX0^ObV^7SsUi?+xyhGA zx-o0yXns|<&!hK*rvyk?&L610gC&}K-~!wj?C`Eht}*>b19doSThYr=lr4{S4;D9E zuZ~X2Zqt6LaTBBMC2Wm`HB7I1FKEw7_XFJ1y+6~4F|@y)OB&RfvLezF3g%wKbI0_~ zIqDV{sMiOJE>d}2XkCtOClAe}Iu&;f$N^rsLbGPv>N#b>wdeo#X$o#9Uo*%9~;{Grt(xi;E%NF5cThc{JEtEk9HCi zQ$<4r<8$#suc(Eqw3JatW@pi6 zsW}_vfi-IPB~37k{y%PwCn2*)8 zhPm^mL{wI^EBr?m!cE}4srX~c8JLv;`#|WV4%FYXZI)OazhufVSz(9dS=4+hRsQ)U zS~9p$=sJ7#4YU&-l$pjc6;@1X?1qOs91*l6#VI$3f83dL8PeBjAs{kV6cjA3Uv2UJ zi;S@gwY_Q@MFUnhC(FOPOQGkk9~8sCpTUFmK1u3ihE>-bAuO5B%w3CZ#>N9>+kSru zK(;c{U5Vn?WrmWG>8JlTz?vMQ&X^tLo@10L7DiM^m(e|7DB~`^$wxa@>Tin&)0LiX z2mE7Us#(l4w7Z6Ztt2;m5HpbTNcIuyop~kXp4NQtv+M^^_Ews(~?@h=~E-!M; zqfb5y@XZeu>aUi(*v&kL8NTGd5E5%XIhp-%+k$7em{~A-f}sCgipXXax^bY1B)I{} zBn^;l9fOI4yLdUSs`Wh0N-DeM)T*nYcAHAM)t+5R+< zpD}LnNUSDQ9r~|_0_Add^km^^Vj67TNjI84?RAG^B5@l@wWwcp4K`W|lciPg=k#F- zmQ)i30&B0BnONI4flz63Wf{51KHrcV!z)2ylNXR7}Oc_C$@6L=yqvjZf4?JHz5?YeA%%sd3 z18tjiahocFhOqUiQlrK|H_|ykMY+ak=kj=bdwX}MofHi^i1j?|oU1|+4A<*L^xWJ2 z)_;lb*dg5EwO&!m!@tRyRIUW)m{KJM@USD-8C99`UcO|W`t-gOIJv?N-Y+R4Sn;#Z z6C4?zDkWTyP+wyx5Tq{BHSbPA@-X!>fji}${;_^-uS+kTC5YNdsvV`e zjCrllEXwhz+z2IPdW->r$c^D|So5;>coZ2(0o8bw?kA(7rx&~1&*`Syj11r_HSWwR z4a1V+VuP7N+6vwJAWh?amu52?z+K?;u!nGq0P9zXRutCv1!A9yrC`}wdpAt5_}+;~ zJrqD)8d~9FS>;VGVjuPs1_fG%29(HOiUlYhUg4=p*S6fD%Cecq;qkt?V zZOR+hSITC&>D!klJvMli`WYt2zkNkQxyAdrm{Z3Kw@xtHrL3eN-8A@7!--16~%s$;r+O}Rd>rwA80REji71J=Ix(6 z+`I;Klz(rtPEBtz=9!UJ$+7L)(TzmDRj|x3OOG4@kH9&!lX$`vAhesiaQB?g6go256uVk`EOtC~aA-0frx{bcYVf?Hmq2Lwaz$r5* z%K`acn&Z4EKVMX+uwO?PuS>$9l44{aB$uF(Rf+TW{nG* zerz24sspr`%gab=sZ|{)=pACy3k52cM17g(eW~W69?6W!U3+K9;&?R#(-vR#lsPt= z?>4|{GLj^-Mmu0z1wQ@{Fm3}D2vTZ@(88kvdApXkHqkRqQft1j*|i4B^;mud6=wX2 z;o^XEFRp&YUqW(dO+!`g?@W5=l4QV0qS*C}vlP~HP(Dq=%U4x}gUu~Rs(*)1L${`v zS|t(QvQndn;9GQdPy@4bkXGfkeX1J~bub&x4iLEi|8(kqs7-7=)}t$d!I8bE80Hk( zPYuef<~{NT#uxp;k56j=kQd%DN)Yz{#OHF<)4%sxbTd8S4w$PA4Tm7kbTv_P!=~USLGFtxp5mTZd0(kSG-=VS7QH=T-N0VLKHy^ z;0HGlDJ|vK1+}_tVKh9SQ?L`DqWH)R05Z^df_m&Ov?433zrRR@e&VipoAy{^ZLUR? z51>IWwlBbl6;S6H?KupaEU;TYuUi`am@$+@`wGDR-rTyx&X-v9$k}jIco@DtYPuXI z!pP*X2?vlXzCZ&58p9`*68b8zznmmU-d4CX2#YAtW!;{9_|~?(EH$D1UEHI7aH064 z-dMtBUn;8!trY*Q`eJxZ}`5=Bak9!037KS`japYM?8XKZ?$LO6zC!a*V(^KmdxvKJ(Y$ zgej7Im{g^In>lWyDFG`5Q~)dfTc$d48cQnxnEs`7Ae(PwfPXFditF;U-@pB9HN$E9 z^hQv(DV@jdlv{2dA))V!GWT!m{%t^YBm7`5p$5>9FrW2Gs>uN%R-e!w^XbYC+=1z* zh4Du35L!D|Hq`CR8N4|VnEjlYbxSQm{)cCtQo~YIr(dtt0T|rP14zg9;Mb}G@u-|& z`e_S-i};W`A-)Dk!5M`-yi1Z=Iwm-KpQWho?*DP4;$o+;YWiQtJX)w5hE%{T{!p7xRHlwh@c>}!$^ za>MXo3&Y2V(q7U$jrJY?)t~kKkEsDPXa-Q>uld>@VN4c(RizepNux7j9KC6Qo4?`H z;(OO9$1-f^{j{bcmCM<<=~)s9ky+E4(@uyBe|A%!JDj2h`(z#S?_S&20BsC--^(|< zW+t#*c*=Vxd?Akm%+fjgr3)giFf=sal@;%hR&nCKFLT!EW6jGHlE zj3^0sH4CyiXCotsf0c$;rDMQtea9zp*E4UsHaXA;Cr5uLBYOp3W`*EStXjq8U$O+8Xp!L#l*|KDm&gm4w5Bq z*FBsbm4AC&j3Y`0xB5MhISS`lW!?>t#w))blw;%%-Cg*j^LlStdTzGSS=+JO9y7gd zd>Qv1-x6%kca=(kQStF!lgD;~P+7l0`su5N*@s!imm?vrMeu{>KXWbi5o_Bo3)e~v z%IWuKoFnPk7N8wp5?80{T%=k1gR?9Kr!Ntv7KYdeG*~{4nWRlODGzfnnvuO?*~r*%dQ5Dq|gXGwdIEgG?(w z#H#pjlPLdfQVBMA)>pkhhHy2TrBzL{K#a%n?xg)9Gj)OGdztxN_et*A`G$}Z;W6Ep z4SNR`lT^3MRC|X-oOw%H47hvOfQ(N@02mb>hqsgCaI3(m*Gk(?aV=P5f!1Yh{^Q-d zfXT>%g_%`zPA{F50f2cvX;61CH-AbI=4~897IJ@m{LZY~A-41T$65_&2jqzdc=ALq z^(5kXUc|Cs%~Mo2;y$db%_#Hfn3Wo4@17jJD_B;8n2%(rCM{ulvh}DC;I! z%hu`hj91{znH;8KgTeZrhiMT9Gt}%em4VfX)wZgrW-ITp@L8Vy&Bc>1lCWT1)lvD13E7CrR z);75sa%1|xcoMDf;m_}#pNYL^ z%>EpH(`aN+)UujLXg0CLL~SV()W?P+bULLGa|!&3Qw*`{Q**&1yg`v2v?*RDY4L;c z8mtw%AW|X_2DDGX`gXLn#j^SW%2;_dknrg+5mAhv1HC5JGr9Y?`rNKcj zJ5Kmr-0k^5rF5F)V-Su(C=)Lq;X1d74BwYi;E<&6&N*Xaz^}{)lYEi`#?auim4-N; z`$8Tk=5k_^68FVaqFk0&?_F@^il6QFC4zQUx^t=pz)d@1l#>_)EZW?2IiS$zr{Pc6 z#vB#uquT~e=Q;K4 z#@H{u`P(wy$PqDc7e#jYH#$LmAn_7`@U@=PYh!=2zU~vuUgJF^+Wm+R)Q?f^P!?|s2_4l6Fy>s)INGZ*zv_n*K*7_63uW5P zyy#o3Tknk_X7sTXfe|jUE}Q$K)`kW3YmP+iM+#_JSL@NWT>?qA11-Hwc?BaEo zbw#zKtVMF%752JvgmAi$Ra8!Dsx*oJiUUrDs3Fw9%>@wHP`U&arz%QXVI==P3~TGt zqb^OaSdHh}%r=5qQ-PwECs*NIZ3CQyD~}J4AtpvSCZ-o8A__WbV&)?3fJP;HEjhv9d5t2`sEJAC^~6&qd$B>edub}x;d0nW$K%)32{8cqNe(vje@2LWoo$1CXxqtA zrfqV&KA#uwQ;l0FDBJ3o4ICuLjlTR81iVjFh;X`GDg2zT92%Z8Od9XoWt<~FA-I!t z5{u)Hy4yzRQQnczD!pSc8ZsoTS7>lc6_c$zhJ^?i;{1-kWd_`R`q^EK~R%{SgMBT~%acWMVG{Iy%#ZI@=UZ)34YE@&#i)hHBmk zU)n?o*E1VYSONRndTuK-sulMkR@ma`XxhIGnDU;~JBcWfvx|yJx*GY3?Yt*)JUPZg zy>js_ln%`GYgq67S&!Psya#C^VPs#5jo-adUd*cOANUx5Mz z_ZBV(9W%}u$B6NcjY4c&;odCSf!;)dWUN+!L`Ux+0!8CQ)W*d&##N9;MA!COyJ*^> ze*H+!S$2;K=gRGPVe`TMr*58L_!iSiz?PoX*-Q`1oU2pjZU&72N1E2dyOF>?vufL- zL&2K-a|O-u1>XTmT+; zJZ(d8*|W$ow^2$XCGjv{YfZD_eIhztVMsPr1eQ%=<@hmo1Lz!$muYi|_}<|IVh6Io z`7qo9LVx&Q=zp6M6N;(Nw_3l5xuOC-@fEPL=q03D5#Z!&OAjSkhQ7bP9_87c;Zb<3 zTwdgKtzoz7*I`svoK>up`{IQ&edm%i>ik+1BK-I9gh$Fa zIn$g#ejVtJ7cUg3Q_QcUN37J#W64XyZg;N4)Y`zV3$9p`X5#19c;+w788hk}?AJ~A<9d%c%+!8c>Ct~(EV%R+vQ0U!2HAKnAe6&!`a zg-HKb0SWl|d%G|iT$_K+}?858%cv)KIw$<~T)L|m! zV74*>dM_P881@8w-b3cx8aM{Je+{T%a7)dLd7eo@9}{t{pPwEXwSE!SOFcc|{pbqC5B#J39%0&b6QU**T4^ajY*NF!VXli|z)2pP`0qi$1!lVOK`8+3 zSA4)tJT{qh^^~jOUMSx76SDYtt!JwcwclhjSRx+3RJKlwIrh$7Sr++OztNm5niVkG z`$~KvvvoXx8$0q7(Y$(2U_pqB3yo|BX7YIxU&QkPnQk}{cF{Yf+U#I^@D{$d!V1%G zxGi#i+gWmOFJ-OUHw|^4=wTzXeKz_hHOOx_UCbeO`ULN%{McN#wIj;T{>IeQRKRun zHR$QaeEO#@UVk+CKZErU2*`T$Z6cGpjDWJl!`0E^hnJ?to?8U}%o6yWmO7W3Tt7@) z*#k0g8+f?5oS!%499CL&=ja2UhQ71ptpYaaAu-=sv>W813^>n#Zr1Kp5!UDJ-%L)Z zhk(?y8=l!%mgw$0V92yJ%;1FJuuzA_qV-c8kYNdVrfr=Xc{!8{_KU;f`38HuUiGI; zU;xX^{QOseJ>ytL0Bczw84v>5c^mT^9ezg!CXsd~tL)Qxr>vO6M-=D8nnD^e;I+nE zKFxF2-UlL;9WNqyRQWjD*KWnr(Ugw6EoErFsvHqX8gWa)1=t*XlA^Uzo)Bdc|F|UR zx`o3}>GbS@;f7~%eBn|8a8-^1xwIeKQ&w^~84~qf-~2{{_qpymTDsv$`_oS`3;iy! z&B9SogcddKaX!Nj^d@TkdbT;B`xiF-*}_i<1lo_qI|w|E^I8|mkUJ@S`!C({C?+wMa|(Ogp#PePAQcxwOO>irTI$h?e`(+04z; zbnyH6lkijX?)Ad(k?Oma+l)0^G&s+3hyJsv#VQznz0whqc`{QeUcd0?wJU>&a%Y3` zVwIorYerFYw5#uB+A@nC3pq!^N7(Uf_RL~{z_W|V7~;>zHKMn|Zm;<(mc?_aLtrT$ zphKuo<)1)_672QOCiR`F&w~mN_4e7h#%-^@z}bXa@gDH`nINk50rET#-wetK2^`Ud*f0=p{N+ZWJ1^!=C52afeDi zjj?6KWPQpls-IZ8Q+~ZFalNt}OLuVYM(5?P&3dPDnlrN*MQ`>vod4x^EXoyT+~oGs zzFj{EPZqp>I9Ln0`J20|UMNGrujd8%V~O0-&bjR z)+#>`r~W+gqT<<`oF&;O#xUIjNDY>|>TlYXn_k#;XpucVjlGa|(CyGF>#dgTuf7V+ zcKNjWfh*Kcw9fiSxV~SJ4%S0$wOH@{ANYQE&G)S_$|+$D(L*&9$o)$Dvz4oI@4<1K zO|A#w$(GXqq}mrrVh%NMo~z0=9RQ3DPS-*y^EAt}ZuZM6rP@7l*L!+;j2Umd{&pg^ zUe4%K*JS36%TJ$7m*9QFqKu9Kd1VD9BKzTvGl{;D&RxXC$>z1!!WpUPm>1_;1x!zH zE-Q#`Y;oLz0`d;`=n)8t3(uc=iHuE#lh|&6-z0^j@4MLGn6AT8UTHm+#R{`_`*h<= z--&#v&kItA!WJ7=7&z^g%}=LYwV*EdQZ=6ed3U=jdBe)&aJTD!C+(?E$;;MXNigMV zWcTfyI+S0#C4gpKS;fRl;sI!Cv1c@i=Bq#T3bm>=d6iCFJdLjy#`4;u{unimV;&m| z>~LS3LZqb82FR-u){I|kEqbp;$l(2b_0%=(%AwbBiHSDY>$R4{fzgz1vZ|j5AL>4% zQHc5kgmEVm!#oMs*&e6jN-6)(5j&-$0{z&L4KO3gETe83%26rdH}r(TmO?q4dkPmB zU?<-rW@J;5N-AA0-uz&IC8&b(#^m1K-lK+pXZ=PJQM9pz&JmI8;k??bo!_@{O{@_0 zY(_&R^jQJ<^Ufc%RFccth#@~_0xdS<5RwgRbko(kI0O}Ga7&1vgNw~Nin#MkozK{-y* zp+GC2F|}-9+&s@^dn^UKQxH&>5V>u*oGnkm=h9vJ%{kkAb%z}Uq72S4S?*z(smOM6 zVvR6j?@L|esFAm~o#JwIeEisL=m4r#1Mc6`hKZ!m+{N1jt1@ix$9*K|bljT-Ff*=X8P5@aC?)*81 z=@f;XZ8SvO?fhS0Vy4w8aX&`+MO-5J>QVoym+jKveEPBsruGMoNGd;jC&%0q`%Fdr zja~?T@V?2hPKtwMQ|OQ4WOofJf}tJ$CvRjfPUu;cQfrk&!cCVL*L?v@DUQSc zgOpMVCUdvl(r6|q@E;f^Q1L; zVfdoNNWkNp`_)T;{W{9Vp2+@(Jiy-p=gmOA)4HAZCKg+ap5CDqSr+VV|yUWR_^ENhwqd_Nqf`NE}7VL9X4b zteG7esB<*^ky68aY_Nj~?tC0k*EnK4UN!}MFWzHtCBMUrIR4v0#=U|9i^J76V=1+3 z@)aVYF{94E6q3Q83>wUIskS@RE(r_-ToG}4XryUHM{X~>nTmBAf28#5h#U*%Fo2F1 z$>(dVC4Z+8N0Q!z>`FF(DDO$^rpp5tT^hNpV8n+@c^kDhf2dm*s(xh0<*?nc4U`r6-Cyu4~A?sW8S%O6h)KsZ6;n5QW<44 ztp0+O*+%;~6RbN9;yC+!i_A9r3xyNA}jY9hl&W>rHRSeg5cpuOWpk}k&=w?t|U z1-$g-vnR`KF>$^!>y?K7XdnIUE;JGuHQ)9ku9E95M^mdab%C%JkxtadrIH;Aba2_=`={nL)`3fZ6DW24}(!m~T^@-#r{1rh=Xw z{AXA@B3W5It$?5{`v-QmOo70BgBH~P({tcJa)$ZLhUA2JA&PNNra(a@TpVbf)wJ#P_D|}8O;b=Fk zi2n`x-dJlv8Lp#fMyK?mUD%!UF+vvN)A|hH>SuBLVrrl-c2`iS^K5l(vA$sIs_ZMo zR;iMjlJK_u9eFUcv0jITz=lodrcmQxQudjFUc{G*H!AVANj=vRH64$D0E z=<^s3oIdzcoSI?u!~EHI7$Uzi*T#B>`LF+tl)jxLvx#T5-bzQ`c8VKTs95s?nSy@A z7}r6j|3zwmGw#1RQWiDrAaC6qvuNVg2M{xT;v@$?Em?Wlm3YqTxkOfl(AIm4hlfV? znhd?rw8xy-tex_i4kwi*P~FM9SJ!XN25v?FhoUUUCS-=(?BKxn!j`v#Z+>qlHqukC z0Q1jG8ifzs{tHMBD^>FjSw0H3)1p7qAvILx?z?AvFi@E-f;>8gbFJ#N^6X@iUchYB zWL_}u#3@g3@Xg%Z925Y4#W$UbiZ57ojUGe*&@t>`H&O3f-XFjYiQ{w2Y>B#TK_VA> zK)O~mL@^lBOv34TX7M|X7lYSsnsaF*WuGp!W;P zP%;0fR=F5SoZIcsFs!!%s`x&Jtq?BF*E5>b4drmau3-s+k9Vqz1agf!S|^{ufG;o3 zN;I$r+IpF@+NBW=|7JuHCgCN|C(0jDwqXtb!CTn`y{SX5HoCvA!5)~hyTV;p&PL$O z8q;~_o`?k)ZT?;tJ||?41(kf18FATh<FLZtZBeiJbwZf#OU{u$}d){t#06 z?T8V%Tr6PcJ49 zw|B*mjUcm-ca#Kp3NO)WCr_{bcuN*uctp@NUS&6p50S1ZF52auYPa234rXA3U#cgw z>xA2G{D`Pd{7idxAXn$5s2w~bKoD*#MCgjaf9$MmN4kM}ela=o>pgW=-gSRuB<`?Z zk)o^*=-3tc)t*2)-g*?qU)%^Prp%4G5(D@Uf{fu zop>lHpdT+cg`QiFZtR@QlICre(09U`@GzOYe`m&-KOgtq>W9MgSu9dd00^h_Tk;4P?c^~s zFJtQfyPqZENv*a%KJw!6?exjT-qg*_Moe5viVZ(i)}h)cWGDjs(waqc@(*&(7^C!_ z$H@wLTwEM6p9Ar-XB^vt?0Kfn|Gnt%RTho(5Hl*ZDmaZQjovFePvWg(KF5eu&Bl5d zKBrY9INB{`sM;~l>C?axe9cE)x&rNQB?4!p56O)(gi?6?r zzDNEtB`OD_G>B8u<2wc`5!Uw`BM3C;quQEF-tQ zHy?{to4)q;>Zxx*JtTn0%ec{K<+WQNo-Q#)0cVT!#tSOG4za)NZiXwP4e^S(j7q7Z zCkGdy-MH*A`;cGOn*ePr*_f%w_HA-pWJGYo z$ujP%O#Y0?pEJ!HyJ^T;UK69=lq=+}&o867-T1nORW_tiA3yFGg~<`oi2wID8_4o> z&991ls4H%rysF>h03A#2?|6QS03^@N0gIX4h59l%GIZv-F5>200NqhWI2@B1;qUkJxqPYtF80-Z`X@zt7b%TenP9!3?|4#8U{XN z?EFa*@al>0ncq}4CBPc{-#nIoE}Bd6`RRQ0k>S$Yy*MaGT&$Ktmm1d6r8f7HpDuP~ z1i`~~UXRLeEKcXG$QMjK`Hxh!M2faG?Qtn81haiD3@ zY#=IiHUfQJGBOx zKt=m~`_&l;*=hJvi7PQ7-`nKTgU=rPp806hMN+6;nJ{-;J^z?n(UD71j4Gh-zAm)! z!F92Y%(j(_G8aLV-nph&AX}CYdtWf*VkspOHrfZqDtIZ$@l&1Rq2!}F{E>gP$Xg{c ziY#+_IIMn9AIA3rP(l*9q; zkyZ17sQ&?H^y7WeE{$Re#RR=q@jN04+G+C#KIxu_rff9$g|Kw{$!Z7Xs?Ry*)5AG9 zPG3~J!oX&sjtO+TiO1u#B%oO!64m5!LXnrBAEM)bb84zlriGa)^hF|uLiF`l(My2u z!7!1Yw^Aa`9JUCUTj7IZZ$LKV@2CO})T^gPUf{0mjHELJdz>W%dxm!w?Rt7|K^d}( zm)m{ymke~8-AYU(`AHZ_v$AmCQ33?)jqAtZJ|>wZ6OzNPWZ0Z4yb1HI2ct&OwrOt_YpQ7J%Bmqpew#xSKJW6p%Z1(~ z4BUfPNzip$P7@mKXzV}T^`>QDM(<4F%(?#s3<$zoxLrTd%xb69`lv5a@s1=TpWVo=6#{y?utN6rFPF(}^G_;#f%~#rSUR#434BgQ#?U3-_%k^8}hpS;{0r%aM z4~OMy`RMz+#SvEJX}L=*TdyUk!p2(~pTbsW9N%9Q$vKAmINz&~sha8x(WsnHDhGU5 z)B>7}`(VR;S-w@E0svsruM%*P)n6fVp?aXemw94ZHSj|5mQdkq@Y99h=?y7M)suZZ& z2}m*KxS1{0#*5P9k!Vpl8X?@~eT;;yfWjn`zkrPqbl$G;HEWlGl7Kj*;*;r_QZ=Vq zF$DEz?W178vzlEG`SDH-fWeor$4NW%$^L!{mM9~-TJb{cPlU0(4%Fk=53=t-vSkV8 z(2Ogab%?;O9FxhL7~V3_=AH%XXry?X z%~fn_iG{TJM#9G*q4qlSSD1mP$R5Qvl%w}8L&&X>ohf4|s!m-fq*2?wrxwn7_I6Z$ z>~%Wk*IUZ{?wkGZ-TKs8=8{fHXzS_*X1G82IZU*FsQC$!HfLPVpdMQ;bQEhNy{1^j zJ?3G3esgBQw#i;mO{w&bAkhAL)bzPmxp~&Y^9!U!`Xp?%9OrMZ&choLJjY(|s*NtE zKj&H}P6rT*>x_Upak~sA3cPVl?TN=Fwl6<^pPB%`j87;627Gk+z>mA(Ph8z(yTN?W z#|}F*e2xs3?=SwXmzaoWLtXex+VIA)%0ZnBbk?SR&h_SfbVi#BqV#h*@2@rCI>Jyi zxNrN4mSjonlkHRvk^6tnNwRuZjoOLms{{RN$?+aPz2XlYdz!OA{^mbIgy|Yew zuu=O^MAII+4vElh&s^5Nd9Ypkbz)AwQ^gO^E|7+dVzJ3o}BTM z=}BP^so1z2`Qgzmq!*yh(dW>7TH7Z-1mQ-=#^CMAuh}+H4rR;8@DawnN^R9sAamKh zP=5Ki6+m{8`_rf$^(2H0SLbxfNcnTP*I-7ja`)1BTb;pY6smUQ0L3^w>wMR15Jhmb zp(Q{E(L~xV}P1I8Nw+;c)s$K^fdMgN*wY1xcyEa#TF53}4BX@{R;MC>kjY z2-{n)J`3XyIDtZo^aX}hZg>!zO{Mswr4qIr*Z7Gh$P1iCzjaHrK0*NokXVvK7%;FO z{zm~LVUWEb74#VUT_ivFq89mfqrQ|*wL%IctJK4n8X$`UNlS@b4mEe7zY?=RJL|Zh zP!A zAA63{9E6Qkn7#Ua+qur$b|z1Al%bRRJLrq21i_h42*BBsJ3?BIPpWC+PazxAnI;&b)#Yz`;lY4o1bYmx5+O zub2sZ3bv^|)S8G=smT)Ppo?U9fIl{hY#{X)7NS4rN=vAb!OJOr`Dgagh|+PCAQT<` z_`?w+`CZiBeD0gCK@Wz(UyFEUO?J8>1l*6U6plkbS3SW|v8c8PB}4*r6$(qAyUsld z|NdpA_!_-z0R#jAas}r)4c$Te9y(9W&pi-0uSyj2TT^&Gpc++)eZ>!Xo5 z_iPSnfHC;u7*_)fIVE5gH$~)%+lSjjatbT zyIj*u)A&m;%gZrrG%Z*mMsBG1i7aAXI z)XS57Z|1v(DEqbFf#B^`QqmSBDXjeTf1{DvpFCd6R*1A{GsvHJFR~t9f6Y!pKf?vd z6g$4m0LHhgdsRW$U=QA8r>BG0;olh@#ro%P@l2466iuX_o#v{XE;W@E!s$K`7!7xk z6Y_o99(_+*-%zPgxSKa&bADHnC=tt{&NGG~ZMfWJ45Y0&g@Cj6?C0y~fftk>{6;As z0Z8lzK2YB2Zm3)};csrab`b%v`>yM)$O-wC!;8gN@mFKFUxXi3z52?Sk z^?5Yk4!eX%xvOGVw=~(Y2=VZD`L}Hc4%uiB#y|qaZIeTypuu}B1i$lfOP%9}e-(#p zPY19rAEca4D2gG6+3(n!@fF;P;dy>Gf;{(E50|_Aa&msGkqs3KF9Q7@rjvZpYI(hJ z1ia5FGk!H_rzBWJsr;1LQdMQKV9s81Z)RQ?=JQLR>Av& z8Nf&PbX54{FEB*EIc_-_FH|J*&V}m;yJN2(AkGQ0Uw7mz z`X8ukkKG-OE^NoSryQNeUw8!N&!Y}2^|-CYAIXx0jy_SfpIjWBFj_oJ7i-ySu&a-& zb^OYHfyNqhivkBHJY@+Mn>wPXY%oq8)502&t86<@KaKk@0qB7VQXew#h%w0Oa>#a_ zQuJmc75n5dKtvu27A6HLBd$PRriw|HTIzUqv3qtVnw6ZY4IDp&DDkRB3u64a*^>ucOcmP|)R=aB~2Bt!&xfm`D!5b+5UXnZ@mmQOs^q&6&p3P!ta>yxXWdxnT-BBA zd*c_KRI(!*TJECqP=7Ac6>3DIF=1xwy z3Q^1mB*bC+pWi9J#vuPz%P^*A;Xb((W;0bCCGE>S6&3;+-Xm{n#v|Hr+vBE_C%pma zOtowjjz+PKOw218*p$S?Q19zwQ^1@Ha(~ol{E6kiDc)sI7#_nXpm!l$&&H{dloHXs z%U7D$PIFlDgoz$6-BODnAiP76m-?XLr02ufL<9UIqx4nqWKH5peUYeX;!kph)Ycq> zWjhBHO`@E%!a@>#E$_#TI_8$FG%|{Hh*&1MDCF*T|#FMD_ss`eBP1YYJx? z#O8$aDN0#O5@;%SLEIWvcGR{3@9*W{o1Y4Wt8uNjX9V}AkL;Rjc^PS=nkYd#mPp4^ zCZp5UDZC;3VP*mWCC8iTlD=?!D$p06R!yYVEaU0BaUD7A+(BoJ<7igI`M2RSxEp%9 zLG{nS2@JoZ6Rea@%*LBK&G!RzB%+s;-tZcIba-??lgR?oZ@}hbg%AfEqE}*4W>fRv z0u--`<=fWG1B=)M&MHu6z`*JsT???jMdeyq6}wEJV*qDK0k)x1r0IYY>c4Q_IHZM5 znZG*sH|W6lW3Mhx?*#B^I1$g0@7xXo$o2hOetay8cuzA%J??RQ^;0d+K$a>uS|ax+ z7TOnH(sD>^;OAi?>~0@mnFs0fwwdZN`RPr-NR20=gcHXX#!H!yCGU%AlNE5G$oIUN z<5>JjKizUsPHV^p_f^Is6A;x){`(CaRPrAywb-K52yRXaMENIh_1!#nio~MT6w=7z zwMqre<$}_aB3*kx$Mi6~JR$TDGwZ!%mQuos8|gu_RTL0vJx-$e92W|3 z*DZBlZN+2*WIDjmJTx&8pT}_lKL`a&2AGU9-WmV0T8N=OCF65|0%Rv+=)>L8g}l7{ zT$SmI?Xm2ba{WeX00!u$klrL)oU*H*YjR~EWYq}(9NRYlvQ_tq)kvD@c+Q7nzm5uSZPfPaqObaNn1o2Uv;e$_ zpnt@0*CYtfe>d^pO?c1lcq?H!2a-78tUDb_DAQ|HZ|6uZSG-ZA#;5Ypo_Rkxn?^s@ z;GG9Fk>6Tt6BW(t$~b53xdap(mTX5C2-r@FKr#YQ;Ap>|89zw1t~TGxX_eJC+jtbN zS4adt4h}9D;y(J^+=#nbEbf%Hem~cpTn5~|1*e?%ubk=7mREloQ&<`enTPo=^{XJy zIEn?b@SjNLb{^Ee;$LxOsIB1Kh?Wp>v8hmHG&|ekD9(8A(G)&4{cGLkG()NL61guF zt7mdIb#tIGv0>|fJ1k(YWEKxJ=hux>LK<2KMVgEtI!RuzyUb=06A3w#&{p_Z)`NXL^@*dD4r7Hh*#nK5zau z1?*WjJD4W0X* zF@awv?*{yUw*O?J^T*t)*odyRIKv38zWgRe!-CgYv1I#QV7wYZv{T}aLQDwot46%TzJ~>?{OHFt}-tlauF~>F;rwIbUHKMswPUlmW+Db@K zLAnJ(s~Q3~J6vwjUShPF$P2-~1dP)n0BdYCst(`#tDFlVU?7Rr{&=O2GY|GWj3AnQ zyv=X&zSs?Pn6E)I-t$en1{i{n)4zd`m|%$gjHLS!Ei8d)=vw6N{)@0`t;(YkB?ez7 zPz_(>5YHWmK2*Cne$^^tLlRGJO-{$gf3T47ouTY_8o(me$6>tX?d2<8gHfjnkh}vVKCWnG}RUw^X_a5e-r>)Nb;`r`! zSptHORRnnq|18^csOJbV6I~i0 z4u6z*_^znU=`^i9*J55dKa$6I2Mno6(ew1;k&0B~BvPs^gqXD^UOE-h!KN?+Qt_B})zLwbp=(EZ*{hGA&iWbIsQmtR21>|r zsQ-A~7fp^)sCF%?lAUC=(&|aQu&e{^@VTvlvR10*BK-hNPFZ!`Je~G_V217C8$M5g z#lo)TZ5TcPekbYtmAS?i76sTaTamDHfcHa)c5>gfs_Y>f?F3wNj_W+lTQ;_wiSp!(465|}I;zhRO2Nn@C1Oxy%YPn?6_-anmnfJGJEzh`l1@uUV8=fA zSR~Fe3`vWPEW%%Q!d{ezfN84@Rg@Iuzm(^wGFI5}E=;}u^dbI}QT!%`Uis>6D_oyL zN=C-cunkgVJQvLV&_DL<@_;S}sZ^Mku+hm+EF*y&Ja) z)DyAJWQIVx(+Lnldi>O?K7ITW1CrD{aeG4U>N5BQ!x*LD_z!g%4{W>fn@9Tjym}2h zcH`%@yEH*qIc=P2SiYj7@^etqVIet_LHf>LfJ&O^U7eHfi0w%Eh0`5_eN~X|wFbuu zKHV8<)^7cBafFPJ1Qe{I()Sy!w#u!Yoj_2!CiD$@NP()!ZTFT0ZIM+*!io-*fl95#V1_refBGQEZjSxC|Kf#X|l?H9^L1gz#%$jA$ zx-1(5T{JgG$;!K8HQB)9#Kw(EQvgZ0EVB29Ebcb53)$gcmUlG307iL;j&g~uObi7Z z>=SNHGKX>W*OwURL`=<({?GT6jG`kY>P2b*+-;N%@`VxOjzy6bmU-@EdT=_-aZ=?a zU_S#_mC0In2zAYhfff<&usoDQtpJrCoaKOhSZ-QqJO#y}k=lIh3PO=C5JS5M7|bO~ zy!CTun;41qrDx(wk4%@}{_;*ox-5B-Egwli5 zO-HrV4PRje_z%8k#&1EcnP=p^c03Cz01abC)cfdmWH|&Px|W0>gJ4stQM$QZzM%NU z*ghEjd+A1@8C{&HHM^w6_Z?@n$^f*RSAoI7MK>oim<9sg=%G)y7{YwdKLq`+g4J?W zMgG{;Pa*ic6i>G9(oV-hgU6A9m`Y+biEPVWJbs;MwgV@h++9tTxtze+)?|A=pS%M@ zcR-%Is8lOD8XQ_R#8#|X(a9{WtdPRXEcn3>oC9x70-EqWG?mQGTGQq_o3i|vkx$w73?tUMW^~q#BLz)y^*$b>ON6D%kOxx z5sbQ#INYX^DfF-BkOp}ucmirYFr6qF8nr3a0--Gz2FhaNe3__V0cYkF^?e%V_lh`| z7S{uDG;=kU7;h*+4szL&C9aIVBge}v#=msM&E;bG2p=g#|FMa zW*5j8`{3k1|2o`LOQc38qyGL(y;2TiAweWiTVm^f*E zma8k8&3-;!rf!!hlU4|SHF%M&cdh=QU(R=DcrEm&yrB4s0gY*aAx!?Wgju+*Ks>Ez zNU(q|i#k=VegHm7n4jH-1&ND7p&NX{*FcAKe$KqZqeTf?6r=QPD=b{5p_Zsu&ZPNM zRb{$V6+h(660oR*iK^q|1o^Iav*E5;*6T^mcAsm0UfO|cUriAzONLF-u?lglFv2L?fIf6RI{Z>G{$d`e)72C>lIt#l zZ-5zCj{R(fMAZ}E3=VLtUh0)#vq)E~+mWjPiF~!t08b;P~Y#kN!`$ z)>IklEcy*UvCme0uMMdN)b+@iClzkD_N;w;T93J(l*TLd>Pv6Z-^fOL?J+p^ccE_KJeKbfGV$1 zRcRkOjZR893ORO*k%y;ZwUD3!! zrBhQX3Wy#S6NM(q_~MT(kpX!iMK**IVC7N0307DOz2d$5HNRFhN)A;0U<%<7Kg0Vq z_a#S-p9YA=91o-%-ywqzQX&}el579#d1LJB-BQTMq{2q(1vUfgWwdJJlZ#-;-Q?XL zZDX{qOzLI-=SL4oy|fHL*B`j+Oz|0$BmdsIZ2EF&{Y>dqiJ$X>uS)|jSmdQv)t#>D z?PtSLAsaHDOY)zJM9w$Cm-~OD7cvS8XsId^GJyemL^`r=ty+VWcs8yq2dsz)$A6;_ zlM2RfJ1JGLUF|OV26x?-B=lD68H*CQY?y8@wCc{G;5D@UEVO$#kL*SXn~-uXoJtKw3R~Wbthbfli!0CKIwZ*a+fI*e0P@@9FFWO9 zfl7T;I5PeF&-KqohfS;M@}-S+vHF90y20O>@X=F0^IBq}$0n}-KkU6_RFz%V1_}sL z(k0THO_!h`NOwthE8Q*K2*RdQ5NQzU4r!6@5Rnj&M!Fl$+CI;l-#f+`N<1iFG;C&TehQ-0 zDF_Ie1WR9Y%z7cuWG}>ORkAAv#`Twt=Tyi)%WbL#UQb74-wx~uUdq7DAf*TOblgM9 zpk>@A)T9su-5RUFPgW{ueaT5`6Q+)bHC6Z9$UiVZ>RhKT-!J9rag2ooH)Z7m@IF7Z zBY{^T=-Fy0Ltr{&fr%~BNkZTxd&8~2D+3_FV4-&#xiJ#f5BrHS`Q7blj@48&eQDDi zS}*9~uDbJTf42YKExe9(tjvI4oazQEh}-6Sz?;{w5{HG>mM|ZNtL`ZK2Q`*s9kK7b z-vhKz*<0s+HJ2=0rM0(+=g*;f*h7m-v`Gfu$L?ROelfvweDr|{Jvb)6O2U5-9tpos zhAb9VpcLdftC4ck`^M&Yy4zP$?CYd^7GS`&Bq9p%T7{9kMB^Tnb?EuO3@Wh z`aPOfqGQU=nKFwic_Wt!k+-f@#j1S~)R@UEnFcAWg+XgGp~XbbA}}fR+RN}fMb$aA zwnPp+j4}}l(rN9TZemX%mAyM_i`ll z9xk7v8p;KP3

PwXfU9%x6-PMB=i)FlhB^Ek_}CqdueU_pWVAU{a^A>TB+x~aeJ7V} zO%Rmh5Fa~B}s_?VLcY~hEiOI)#nXOd$=G~>wfxPs~_l* z0=#`r8o!QEAwD(JsBG+r;=`(h-lp48ByqoU;-p3hG?pvN)86F`uF}&o{l*}t+}4hH z3h$u~nn0iJ<4Q)Aq6UuzUR5Es_YQUb_j0@aX)tP4p8#a@7P=C_W0#H>CECa7I%*$1 zw@%WV*`%+>iklp16yFJ|By)1-7#urlWqgZ#*cnhkWazNn`ghXJ~tYAvEvp~k9|Hkj~*vjYnpeGBd_~!D2AnsIMJt=3j@FmO5 zU>xn+FO;iq3O;$mG8hmua~Ap-@MmPz_a=);qA3Mo@N!q(TI-J6`USs;9LWe685#w@ z8{typyhBwIhmjEHv(mRddF02g69GAwh2`8^G);=QODEE+Ll$wBOJkXUB%+8#qqLCu zP}RwFBo0%ZH<=6s%QD2NX?`);_x$YqTwUSey%YlU1*4y4DZ0na9zk3K}b zQi7jiG(_ShilC&Z=dmC?iv4EbBlzP>q*TbFiI_ko42C|7(px^US1aEdnDg0am{3gb z{z7wWwlDJ?0_0%g3t4ynv-RGAQr9MArTWEl!TlK z5ZRQ15@K*@=yMiN#`d7!9A@jV)Cv@dj#Oy9q3zFXf5hfUcG=v4RwTG}8YI)qPc4hg*$@tVeS%+SSk*31Lv#!pModybnnG&jRca+&q4J{cwQaFCt#Z z+F|QQzpTKIvl3YFW}2UH)(h%^yri65oLSucP%aoCzROP z7R>-e#EawS&(_uo7W7My_sf{vZ4?QspOFSB^gk)HKgU-K9~|1GV^4cMI0ylgoAN9C zq2ql-Bf=$O*^A}ks%(-;m`j`27vH(xcu2J z28|FWr|e3mQH#&(BJSi;ZDO_Df=A2OvU70h<3bMM7NO4{w{TVMD7!wHuT&V7s zVTC^NQp-yMPjv9ag9#B3#aJ#;;3zKZdzqKR zCqh5Pv;`FcaC4-KT}Mv{|Jq$nYdpfR+J9#Uxt@>6529*dHoVS(ZwEE2!KB>?u z(=20=@q`H+Bzj3__ROn>Uity}vV7zf$cX;EnypfxVAyEZX~c*F;F{XrHY0&2%}D`! z7zYUmk$HA(DY?joY!lzD_?yps9@qtLM7)w|8iwLXqxfq@^=iU^Gim1xOlFY{v;z_Dy8eb`E%C) zERYdxyI6DiPQ!ZnyAY3&1#v?}patgT+NDFzdo#UTO7;_mf7jPuuo%R$G1h-|=cD1H zY@@vS{#Ys4nIi64Ud7k-RrHhqHssszn|oTjAI5MD-~g_7Y;N0vYpJ*n4%I?dO7YM} z#r5uglOp=q`#}3#Sb97HKLqW1ei*^`>1{v^2!no6*%H4)MR%Ck%RkbR1a~m6&qB;y z6WO{w1^&?r+Hk~2B4Nk#4+4lF+9_h(PhcxhwQ`}1@;kIXdfp*|?Jt4+*X|1>f!znV zvDU3;m;RIZI2vgno^P&5&M1>H2XeUl8;5gfF1boAM;vl7qxA_XZ2{(V;M$O3Wjw>8+b?mPi+ zYq@Log1;>l{724w?IjK^H;KAJhaD zsDa||>LI76eHIXbVab{(b{m`~+u(nD5B$9RbEm+*J@_+(xuk%Yzo#{e@bu#XrYT4C zl%c)F+0PkYdx|AWLp--?WK;17IfLw2@^|-pb}?TD3yJ>&)%B_+Ui0_4*;R<})dK`W zMlkSyo7!VYyO;nKsuEl_3w9n}fmIHGn+udGWa3*Q5f*(Ffxo-bawO(qZv6MA_KZ4P zG0Ct_K|GSoQylhVNQlfB=@eSAx^m`mejGiV7rEClE9qWa;9J-AU)vQ9->w?HZ5F(j zG#Mjs(SOlyfL?*i;by)aS`l8w>Mz%Z`YC9%;+h|Tc~dtHyg{x`Pw6&{P$9lTvP-8> zhUE{;MA7gL)589mO+NuDpu$qK+FhgTGeqHQmiaHu3E#AUCqQfNJ?IyBD+pfVp!D80 z0=~>3UCG*s`M!!(-sIVvbQI;#TMGOX%#(pS=?ed_p_&BM4CC2CjjZeaZ`X;49=XoX z&Wn-k>iR%QOD@`n&lfm~LM-&xw$Y-%lC^?5kyM*#jOWsqN~%NN;@@}fB~lRhULRb6DEK?;Otv||nzjORgmZOoL38nqrufLo zOOhi~wl}(TdepqsXYF4CWYq|Ax zR;u2eg<+cXAHx5axGX}z(lwz8DA_y#bF+ij`M}K>Z2ESwYs`RL;|?LD6|>7{fB_2@ zvXyQ7SdfYy1hecQve?vg~4TBT#W1VoyAC0t1dRHh9fO>#ZO#LOe zzw>XB`O}8??LV*p0kc46=6CAeQ1l1Dr!4Vjt9Ri?vYMZOh~PU}>^fOnDj>>{TQA4B zOcmsf`BnN>X>V~iL9fB*3K?LyIFedaFPL+!E2VZDueRUC;AJ(U;AG5q`^VgNeb#%c zT55Rzv>&}FIWB!o@RXCaS^q!h9!n43PRD;8P4M^+3e;-%Bqi$A5RvW=@%J#owJ_rf_IiPSF`k%vWKm}{^(}d~=<^cSJ@v-do!H>Kn zJ6t-J1pQ8WJQMC|MA3ziLu~Rr7;9s)lJM=gKrv|m0UEHyntqk$#_+#l&ItO?ul2wJ zpKmc|@inJm?YtV)JQ4$fvCj)+&wDPp^6S5;u760&A~_tS{PxL+u`u{$Hik|QfKx#{ z@*P;c)78H3|EU=MNLjlLTsv^K`%i!2_PVKZ8G|1KQcwvx@sarSi{f_8-BQW=QjLPz)Ha zsikWnaLlL^+>&izGkN=;r|PfC^MQx%*cKUGe(=Fl$-|+E2m}=zVBvQL5=ued?e7Wv zbFl-a;Ip@>8@C|t5NjT><>p8PyA}h#G zw+8saWyL7NHtIij{g0w-4h54otWFZD#wA|zH81we1_SUQ2g4GyANcX=|BMO<8#Z{D z{x#L2k_tZfo_MxDgWr}13x9QJYV*$t{7bhia>JMAed%#(2oQlMdPA6SF!3^69-Q>L zvHxW@{`0c|F7Sus!vdgtBN+VO&|vzPMsR6+$DsFLrox}k0lHhU<|*6!5mvx;m^p3z z=h~%|2E&S(<#J2;ACv#^ht|e%O=nx08VMo%z{hQ;C-Lv;z#m;XnzHd!dFOGtqw$E!EwQX zzw)nI=>PMPDY%ZhvcR^#CO{~~Nhj6fNDA@L z+Cvx_0SZZvz=OV1*f~DoARcN43SeYwJRkiZ8TeZc(`*getn_;1l$^Tu^`G<9mK zxpu`n43plJTRgC8{+h!%*Qbd@xGHNbkZGWYe#i^HsrkK#u2?f52m1OJM^xC(4kH8! zq{&fle7*x|BBK9qPvg(*G9m58^Z~7E{v1WINXg95r{n!q9Scg~#wad1FXwH06KFB3 zEU?6sv#8YNP)v2CRAKjHGUykf3|Djx;c&liVT~Eimj)s=rqgp!vS^&)IU6tr2Hf0|F~oSmhe`Y z_Vo||m8^4!h1MjSWtqm!F&c3R%Mo#+Js{2u2dFPz?+c#j%(n1?@IHiWKYB9W( z5rvZ-t_4s;6MfTD24Rv^AXTpe`1Vg$Yo%2o7U0|0bN>ue=BrUalM`>2NPJ$pTiFB>m}jZ zy&^Uk7z-jVe^WL0UhpkMiZM*^x-;u9Rn)BA4V%4_8@CTOEG3zh;!v%si zA@cmx?Vuw)<{tr!I4{&X!~EqE_`k+2l1+{42J!px0ZX{3onq1F+ zc#hD2FDzRx0dvdLW9|j@19WXfC=xIFOR4~qSG@rR;F=eCh>KQy_rVgsRW#~w!|llp zRq4xUf_40Zo3(q&MBI8B&i00n*XjgOCR}7rJ0L>PcS#Ju6AUOvs|Y(IlC^*P*9(I_ zh~OdkA|4}+Ms<0|mJ{Q|pnHh46XH3IzfY(}YPUe}JIP`u0T*)sIx=@)1>S+~^Y=l? z`!l~YTOCmrO71X~PPJn zRje_Zg!wW%jaa4W_DvJtnpfFAY1AY3YcwEoa;|J#03pw+z^%|Nm63bV-bZk^)ZY5@ z+-^&%M5k7)R+nw1j#E-FffKUXDbUf z@yXm!>GC$Z+yr3dIl2!*S{=)&V&G#DCU}XrXVE?<@YlVE9N#WZU+tMOX* zyH6AZU+t)SzWTzE{0vB&n^xMlo8BJoedGh5pA-xt%-?&ABvO>wxMKdtqVr?GrG)tH zh9;);h8f5FoSfU^`}MQ*$EhzvrSAfIql@!F$5?u31Ix&sk@QOpg!qG3PP>Pfe{MGc zx^~FCnz8=hON4O5$tvbUGfJ}S{fp@@(rm9UHie_tu%1s3nIDAP*t^_q($A!@6)L&W=4vURDyAW7DW zB)dRSh&5DMfeQa*ZO`Xrq#2hBbJj9S$S2oPVTG~g%VVfg%lB2~ef*@!-34J`k}UbS zvfUe*i1Kx>|M1yYWn1ADv$at^vbKBQDBb6Dab6cCVZpfdTi296w0+3Yj%QES7FeZe zeZMtb1jI6uUL&vAmS&6^utC_7yWum#%31%3)Daa;!|zfLuwDT&42l zQarRrOiC7=k=-y@_l1T=%u!xkUXrO!60{xKR|LIR1r<%E(}>TX>xqZFvu)pH0rdn{*&VPbW^V^Y=u!9VK!oxDwmSp zI_)@d;VzSi-OAh7UczTBCAP)!W_>CytQdmN_|jsa^5OW7hAQ8lAPkFlcp{KwEjAa) zkwA5xJ5-t*dbrH(klgF)q`J9pA9BM<*2MF6c)9^wxk08H@ zZ)UZYd4KgP&#K$)0 z4Sf%vn;Tn>BwF+!i$%5{(t2|D+^e;_^FOx!2wkSynf~Iuxzt6VX``q%Ou9!j99tr= z9i^cHqiak?|CIkp)lNf-O;*F^p0gRcwIq=vBbrGLBr%6G&N(hchA=!@B+l}ZG(3lM zW*KeNTLsS?ri>%&cAKIe-35y*ANotXv3;migOPW=D0+Ra#B$==TsvH0#6pU#bBGt_Ei`-tV!}Tl^kD zt(Jc7kY$-CjeqGjh+IFK^j|ai^HcO+XzsV)F<;VwYgrGM8!jb|C zDzoiG?Gy-_sC_k_5B;bg+n!$17e(?YkK$J84?we9HB^eXnqbk9%5uap$@1OZSrU~G z6Cy*}HjCJ-`H#hB8wl~WUO*KBBL~$DUzt#)H#08hJ z59J@%ULSW~s#6W)Js`7KPEZp10*W1CW*yoL1lSE`Hc{-r|MC1$yD0&}XmjWg9v!(hTp&RnZ=6i7LSCrYscYDo@C@t_ z5wQ_T;-zIsNu-qI8%M}M=UmLZciZqQ$HKy4j9GZj&%V46(Fn}@rZ1X##i15<*}3vS z-dXqK4lJ?{N~K0#4WLBUm>lr9Mm|OV61oe`|6zq`T20tWB}Mtjoo8nVlob}o2d~6 znAg!ZfB(+TPF}L75gvE!4E28;bTlobg=99PU%RFL8EcQb9R=@s%!?{51}mV(CYjVm zsWBUIj-*(WU(${oiI4ERuht-r9=HM4Q|*lT(3D*$*_DAkWRqpp zB6qvER?V|;?M$}A+U);pV;IZ#yQSr`PKZ#=)H|T2QUcx~M*=d8$OpCytrS##=QNrn z+5nS^JO+??puL~F!|}%0J-`+mx+0_kiSXch0e^vO6~TLW2= zz?aZbuZ{v4xsfU?1?%t6M;=cK@*fHa3$$fUSmo&kyt=A>h4{G154m6Rk(vfDp)6IJ zYOHH@iIE;sMt<;k;fekrwZ1jVRFY#FS|0-Y4l9yU4L1e~z_whOp7?#hv(!k#_*eZe zsQr-{yRgtNFc128{WXSd*iua|5{)%@isP%wWE8(0rjFDPL}?!#K0e)9Gh;w8@ZFd@ zSGy2o}+k%$O+0tMaOCPvCnSQBs?XwL+gnXtlEWm~bAR?9V*!%?b z7&6>PCsRhto#6yI-0^!#LKjf`rX8L{4x{-npQ)H2$>u=rUy#49*hM_V8IOZ>hpAn$ z;7|p@qTUdo85wzzS_uyv$m?JBp^xv2v@x4UmcP0-Px&<>6v-`IDquC#SE%V&y`CXJ z15OGS)({uv<1_^&?UL`0)a#9>mp+f}YOQ)7#+TbyhF7x-ysp3d}tw+7~J^T3<)T?BJT9UAch$C|-(DT_n zum9Hbc!6hfN$gjh4p$=w3(`J*j{~Xc7g_K!OA#pi1|(D!cTMFbWPUiy6At2wFxkw> z7Aw7D`;vI~Ah!tW5re{6Rq<%1_cK|MUI1zi?Vyr{xt_%EMiJ4naiCb|g*9zfDz=A{tEfsA>%06z6Q@Br*T9O@L~L-` z|61QczEWQ`YF^relhF-SxwtdiwWAm?AMdH##{=0MrCEH@IU!YY4;8x;V3nEZ_3G^n z1OTb~2Ed{G{#JOen$M^;SkfmzkwQab^DO&zPmR{U`1vC{zbzEYHP1%2K@*(&exBXb zviRw0K92(f2x85SGEUPSY%Wh37EpXx1rWeemf?AL{}h7ena>!WuUKMKl^z%Ko+-OH zyRg~3C8Xhs{t@l>I%3`P_PV9C^QbzNxzWBYc`4M;yWR*FHY1Br_2!BN- zU>rnN%#iOKQ+wyMvSMaxruQ;=6K<4#9)yjj*OjMI50PsI zfm2f9yCBO-J_MOx1S|Fo4Hf~yw740_`m14D8X9?d7XYBU4~WT47FvCg@MSMhseEv8 z1dnk6HS%6~q6HpR*2Ihau9aZ)^XPVU;)B-UJ~mJ3c2h1op>cPSzP@ty{W6-eA#kvi z(B}^Nr+D2s`@Vnt*1-3&k+}C&Cc(Vr@OdXWQT^?Ex*W`!T>Zp1EPTw2x*3q=D=kiw z&Zy{MDSURLjv=frsY*g((Ddno@g1E;+@>2Y6j(mN~tb49+N*n zhveu~oA2fcM4Tg}8?!FmLl$yvGQ*>4w9(rzrh@c_2`QI@`Z`PW*4nC_)|=hlHXD>1o% z2QKI|;g=Dmzt?(Y?{hpRU3S=89fmXN*$ojASro6=1A3#WF2u?FcSU7_$lW>I{`EjR z7w=RvPkYKzu@pq~B-&5`zdVgAKR?^@98trdK)FOsv{{%4p+JWvOU-;`ZivXlcyO;E z&*GBmR%NGi0~h*Z6qmYRrA-C?<_Qmcrw)ga=>OY*X@) zOemYG`T9GFu!bi;KQE&4;|nmcz^|Hz&nS$iPL*{j%4tazDC9Rxf!ARkf<@cgwt$B9 zUZ(FUX*88^G`y7z=z!oRl>iR<@Du!lODqoxELt8O;`(_nmdmp}z}4hM&CJYu=sf=O zAutfc0rlfpjg=awYa{J4Am5hSn{VNCTIxhlK^Y$(e+(L;0H(PId(B7K8J=sTZ%tB# ze4o=RIJ2TNO%m9>d9eeCp? zg;q#zGfq8IAPO;JfkJ?Wgaqwlxb;`zU#iRWJ-LPLti2O3A;_ zEPnJ_KH<0JYqg{x3WT$6yuikEiMPn{@7VlY)Yb^+piS%q#&=XFHd-h5580r3*f^o-q?V8h@mhY zEb*P0&b5m(aM?%svPcddAbuZIQZhJ!?LgZVo&jus#*Yu*Rx?v=mDIR6VM6H`y44$ z-XT%2E@7@5FDYJ&y>v$v*}O0F8d2ijZxjUnfZpL;zF!N>F3W{xsfq`i zjZUN3P4e#?awWCvU%IZ_i}H^yK6)5&zNm{si3MCoQK|N@u!2tuV2;?J$wGUEp!XZ( ze4l-V_fNm%#t1Rzc$yeLuqy%Pn#fi;$-z@({N3nXeQH@@pL56UnOaOEzY9A1#?6li zQRlk#(GouGs3@1hRj|)4>#z~2a>JH=fYn?AcDy7I<#MtN`lVVlmn)>i-{C^?fFrY_ z&j;*WMgOZO_ZuhQ9L7_g*>^Yb%f%nUik393*Sp`VB!7CC;CgFY=SBC$I2o#~q2YyP zc@Xb@qpy`F*&Gw-?DB$I7}*jv_eT65SOC3q%>{C??ddjLZ#UuiqNn0=7taHrw9hXD z`pKsw2Y)!rd>SME&e)G$*6|@VD4xMz`Z(!HgMJe&m;5|}29LNZQD-NWbf20(b)lSE z-n%kv4W97lc$-?vr=z-zYnF4)^4_eX@K_pf$$EEme26sZ@69tH!58LI|s3aIM_!( z68uoW<8g-HrIqW>3=wFb5!xqFwK(%jv2&u^Dbe_?>Rjv(hp`+K=}y$kPR#OKdBddr z1^uDa4>&Y!F4WX5I+dz#%z8gztWlozWXp`%xJ&O`(NbjkIg%RPa0K?2p>plro5?>% zdlKP66}V!a5>SuqrIh(L@kK-_sRkqjie6bp0sU5r=UN?!p{95r%60B46EI1R(nXFk zZ5_zO|5LN)kq&b5CrE6Gri3ZIxM~R_o}JiLf0qg!J2A|d$i2WyA&E(i*nMvP>!z!A zr+3qM_wN{k8oEMT{jsGpcPrBpq<3)oDTZM>@j=GH(l}g!lOk$CGMrn5frXZJOa?X2^jJbq zWY)j{W%>9y6##!M_FdKRJef@o7NyIg;hf4B1y|`DN)iH+0~3w@0E(kKO(^HKlMDaery#pQ55%cks*n3RStEs4;jc`z>Wh0OGw)zC4P=JKu?q z3Lc=aOoGzGD<)?E&c}#c?`!|M5p(%yM3`i3l`QtMNRi@!G3`d!F*Qjl`mn^qu zZFj%A$s7jNex`>Nbex(AM1|EGQN1THpw8k;8~U8~oz#GA7;n%1MEuZq=Wg)nXR{3S z3yKzmi{jZ`)$(y*YDtGdHz@ z4>rQ5){Ubq&phwieYCVoT(c7=wYDr6I*>N=v(x`RdIFUVs{6%Yw!ak9{CTS;*L@8$TT* zaEJ!zFT(+3JSeC0Ef(2*xi4bt65wi(crydy7aW&Ryt{su^026vh2B&H2pld-@?6tG1!Rt@LM!LUgn1ntPK=` zUfSK>ZLL(hy^pO_Eg9_61!mSF+Q(O3E2ESqFkCbCGH zv@$P?K?^7KibkL5yzlRiQj*NUS zyAbF=FmdEIBmU{pt1yHJ5Al=+TyT&5k^>%O0i$`mJ5)lpDxNq0t6}GajgF4aLt($> z*op{ZwnlpbWeQ+BB0e9B4D-+xhIwT2*u4*PE_lr#tFR@X)&!bVY09jFb(%G=^t^JmGHhv<6 z0>J1RsqV*}z~J)qT+ot@g%u!Mj?Z=>TccwI=h__oYG0cI}5 z@alSu0`c->jJ*ig#Vftr!qpCBxi*3yo!g(N94zJjGVHw*LRKd6YiK66x0mM2jH0-g zaZb`^DeOP%qxC9$kv8<>4C`Aj@iIAVLs_uWnhIlzn5h;#Z9um;&F_wa>>zvC z&W)5=etQpHc2inR7o67?zaXgW6U(pP%}?~_b&VF+yPFnlrM;w1S5b2LkLpt_jzK81 zJ3=1Bb#Tp*KY(8E9qFUI-suvwef$=2-?b{MfDw0*PjUd-ez-lyki&Wc*iN1B=y{Tn zOv+{VP$@k`dR=cQaAr`*nAg`Jk-X0g{cm35#TfzzyYe%W;P(uh;Qrp;_8*ldlEUht zoz47sN@8h{9k`Ab*t7!8qk`vKydyRo+Le61jg+Ab>O>g3L9xyudKLhH&KeqIG)i*q4^CR z9J=9cQLh8Jlx7^>g!pB*hx9rfEwxLJ3l&f#(hkcDv^$$5cQgXCUB2Jo#8P>#M4K~e z^`A@XmOozw!K_X+R=rAsKC9I1CY|CsLvZYPsYqWj->HvihDF2BU}kfzd&qTr{IX_=DnyucK%olqVv(M(SrL(UiEKJST2 zCzt5RlOO^+M;OJ*VAs${FDa$SXQX*m9DXY3efn~9Jl}G@`7>@EXkaw-#8IJt+;bFg z00``j&43k^%u5(-`4u|1_#Jpspvv+-y!<1~uwcVoj#CW~?9pJNneq``;gv)HI&5nTX zN?Zd5=4V3Zi@|9@>kn}H;zoBvOjBzzGhT2Bzpi~wfw*#$WwdqioW_Cc#&0#QHDCUP zANQW;jy<5OVr$6%WrUCzC$e?1+u!7wDcSrE;q!BXeY!xk@IvkVi+8+Uj#Mve(MUO% zh*J{DQ%a_lU&Qf_@8d}%mj?Z&gT%$Y>e@^s*RD<1On)Gi44u=+g?865zQvGqJ`?KO z`vMVaTZx<`d+z;{Q08zYw3azberu+i*@+44mM!wI{tKkl@B-SqcjPSy&*1^`ms})a zMDGHx%z80@Pcg>K+LtYNeezX15%a;=a6?AuVO5^F`lxYM+DT3SYImcKbXWeqFFNso zXq$up9O#843j}~cM|x8X7)vn%X%)}$55T$-jA!tKK)-Chc!`9T7={B~%GyYSbl2AA zB2EwN0iKYhX^TwBO5?6K+6<({6fa~9rt=lA zf){`q6v#Q|h1M|{MDi?n?|zn+@$c7A65h-SE)LH5#iS7FcTd+B&QB9Dq{GC~R2`f% zV)a$GUsmaD6Zt{(%t38ffjYO;_io_voa77AoTJ$wQ6YF>{K&^9(?dKSnaEW{xg?V| zKwea6H$@^;+a0lWnO{GCzFP9GJUKg)`R2*`?T6E`ipn8Q+ij@Q+xArulH4Z* zS`@21UBtMW)sd@5;ajWxmw)luUj$`IS)C~JrUn&VYg{x2^D>r>NishF2$)3JM5yYL zm#@ZtDB56nksF@&K<4EG^wZ%HNqTrhvc!s3PHxg^fUQ2PhKi6=p(?@IUJaQe|2*p{ zL!$i~NV-+9lJBh}>IxFglDIb_*6^@Fw8zcIro=UgOkv-nwV{n4m9!vePs3i<@ch#Q zgG3q?!B-u~co$`>HVlZ0pGR+q@RXKwgf;~7K5Qgbg*gATu`;%dhQ=}(V66s~YnHwj z_414u3&H3&+GA`?m%9Z4Z{q}Y-aSx=Xz;2;F)`*Al99%pP4r;~E56>QYxcyb3 z*3tuizveVi>weYdSt3IQyV`cwW=8(Wi$-I~Vy`P7B3KNe40V?35@RVcmUn}Vdap5qcIIi<9ho?Z&fKiSte(Yajq(tJ2UfQ!qjrcBGdRhLP?EQ4UH0Q-j4%XDBP4B zm#^^lPz1^VGFfB;^xs)x3UWK$o`!H`yb;Jx&z_R$+&YR(Xz<=Dtse#Dc<$}s8lYV% zIQtpy@tcQ@O+g~E4IHi|b~IfJIoZ5b#eyMaiq$YGA)kgH`mTWW2~xms_xlnwe#?ml;WLT>A)5?dPke_hA-R(f5ufbV0@}!0I&RYo@8;`_2IyeS{st> z3A(sX1?1<$&Yfyc1%?vXx%i&fd^oS!EEXb)X)Q^Hyxm0_<*_>{2%F+5d!6|84vg|4 zDCSF<2)u{-pcE^@L)aG$Q@T1a-aPoHG6lxDjhUOB{Y=hAsnNCaEUjSOD+R9mLI)f_ zK{`zN6rqYpx#Tlhr*#Y+3$=l-eJ#>)%=|=~)W{wmm#wWo@CKI2msLVZ0|%xtZikc) z96lmRCfgNaKXEQOU+p#9ejXP_zI7t{);u9Hc{L(OElJz;lllX0*cFc`63E15guM@= zy4Ch37jQ$gsk@0HV@VQg`Mv6Kq2=7@UOCXs8Bc0HPd^tjN-o|ZmmR7@hk^|Yzjp+k=^+FME z5~4ZLdYbLKb%6~G&RQ(UZt;r_q4h!QjY;K4>NUZ38@!H|SiuzLK3tFpZ(tf;_`vFic)Yy1P? z`c@fikF7khOL^|JB%vql${7fmWWo_zE!_i5V;NCewO;U&X>h~adLCLuyZZT`PFvKW zc}Wjs$-2S9+>=9P$?mPj7N|dd_R}@NNNr-n<@?s2T=q$JgvC?E8U19To|zCFcbjE) zX#wfZt6$=e$Q4wd3gmY{3wNd3ZSKwUVaJ*SKL-2JvnRLD=6VBrDlf0{STt=gjU)t| zqR$t3{XGa@w9_C)V3;y9E9UDt@sRN*j0yP;SlaH%|}N5Ybq%+|Sp zY&eRmB*J)Tc*O4K=O3JWfy_@y9Mu(&92^gKy-~k@eN2A)+>3Hmo=CifY#?_xY897a z)1b`%Za7HK0_m1P7va*dyXHZWO#ka*rVb8)nu3oIoF-HVIERZ%NjnH4ql6Szm( z-BKgVf_@F!11|>S2nEz_7P?PLK3wRVXW3h ztKhu$nA=qv-JmlI&9_k|d%^Mh&lytCs%yt`E0+kgHBCGx;p*u6Ra#ip>R4r>z&%GHA-(aT6r*B371)ALI#{ zERT^4$v%PuA3IGppA0=NQ1fsv)a&o&`Qs|p1?vPGbUu(tk#QOMEGR1jo) zQw*U+iG;X6(TOrEJBo&fN7HsjE^hOd@L&dDUn@lNP;yQxGZPqWzCz}WGCQ;E-{t(` zM|#Y-c;a%=LY38e_A+za!>n$LI)^Py_3=iyiJW3|m70d${5CBFNG)=F+AE}AVgZuP z{#rAsV3+9DUtilI!BdaZ@_kFIFtdnUxr_Kue&S5(j09T?h|XItvJlWgKGN~f2cnqK z6r{FZPR++g&{bv_mgCZ@SX+fHy<8hcb-9q~@K{>f*SwN>$H7V;tMrj3Tf3F_!sI1| zbXV!qXNhd=JgNI9C~p={)7ztc8M=&JtqkOSE(nupX_zR49r#(*Myn|4y%R1_CkA=G4(hxqx z`4a9LMFdzVsCYy#UZ0q~K%#CLZ_rUO+yCV3{BGAXxO6yk;0wc^LH9Tc$xEJPjtI$J z#HYf)JcY4sK*IS?*zFA_0N30aSh+(C7ra%i>7&!bNvvX(GTI>Xu*Yf2JY|d^i$x$j z&`l(s+K}VPb91uypy4%rtT0mHrcOg*O6Wj%VS_83f`Fo2A8u3^QH<=-QF@igpP^ znwW06pvzi0S73&_T!rz-RHp;#%{jx}duBEspv7GEE<{c9|@*MjSj4nxuJQ4?}-*@6Q^UDM>W@ zK{X}uRK6y%Eg6epuy+B*)Bo^q;K)C@ZDl9X;v$3a*rN4BRKxSm{OH$&4 zQTpQWK2oq)uz_$Z&ta`b5A{}c*8X?wp)fOfj}P&J3lP8daRWTgRI8>JRdf5T>{zQ9 z`Iu*H^fgwSWj6&C>-(gmJ1DF2Jvjgi_DPdd(TApi|I=_Grk3OO3nZCsy;9hx*=A8Q zCo;uX!gbqxp+8ZT#8o*hzoZPy2fq{oAhDNt9%%3oCkFtDW$*;dRa@Y2J$aIjEyTbe zy>jOVB7Fzj)gv&0Z_r;%ZS@I%@C7I!9)U#F_!ERxe%79R8T9i~0iT|iQv zFhWZI0K&srj_%dZ`vsMtmje-lm%h)Bj!vs?9d{qv32*XbpzczIA?9Lm}pQ_Drz>0{-N-8y8Ql(k@DKNEP z@(d^wY52%0ck;7oi#glxOS`HgTWc@{Uvl?n8>e1NPd1TRP|x4JIzj}=cgiBjYon)i z6YoVLMW+}*n3Ds+9h7v4I1=njMxO&tQ*^w$%dPU|dGEc~+^^uVK?)E=L-W~i8-NJ8 zPSrggj+FFyrO!?IgaC~iE-E2=@_2iec`H*gp=-ATok=SXpoYF>Bi)u;}KBAc~>&< zoY_A(*!!JMYMwA5QsXlsYy|P^{cut)6Kl9JnnVBoJJxQL^pV1STujNPpN0(|g3j|? zLC;zH%t~ECnW{IvXis3>60okEPZwnUM9&g&deb;js@U`AE)Lg)H#@|GxEZQfJDlpN zFc&?*>~MwL0T4oDpI|>EtX{V?h1V&kmq97bUP@Y;KaCgMEW&giZ-7KS4(yN$0JGPt zM2K`hi#9rt8Nsg0uwc8y74#M+4v2Gn_eJE7{{6B5nV;NXT5qP`Oi+7bXUxsbhFM5D zJ*AQFbNo5}wy0!E)(fK|Dw>P-ITunKo^B}jUDfjU7TT;&%v{y1y@SJe!V_H1bWOP1 zuGsp%FUn`BT-hy2tZE{7=uC3$Is}<>UUJNMur2|F?Kd>#Q=UTad(Z1WZBodV8El{_ z+vh3y&nYbXxdUj~%{^YQNr-Po4B(N(Yh)jqC9C9#0;L|1{pOSQ+2`Pkf!Ds#<60ww zg?K4h4(&D>Tx8fE2+d4CozGHHtFfJ+#1WXmc}?~d!;;bhd>5~5P=h>NkA4t=d1yUR z)6ge5DS1~7wPHG}&kY`rjEyBR&Or8s-V7!kNBgfOA4%uc_-k=^=uTn2RwyyLvJy4d z#OC^c=z8n0D5I`>m{bs?Ls}XH1O%i(y2JsI?(VLkML>oYkdg-J?(P9Zq)Qrx&SB{0 zyYYG6?|QG__xt|SOJwFg_c{CQz4l&f)trfQ{2CreeIuLtye!CrH2B-TOohJh*kNK8 zJ9C#C@Nja&%a?i2iaa}fbd_Xs=)YLM7D+^*JKCe^uiEQml~x(ZIsmLq$^%G3ssy>F;t@04wTje zq4@_7FnrWZ9b%GB-Y(c*;X7zssBYRgZnubIKu{^B@S7oCz`PFE7Ph>o2j})aF*WSh z9XE}zen}gzEqqoks-e#E%Egd0X2Me@K7=i9a!u_Yg@Lh&E&LSQA`N*M(7{yp@uLxxGnWCZlU=-w=uxp?m}MO;=2 zwScStEf5NACtdqHuB`(o&?(_#Q!oFD4)+iIs;q-%RJ*`P_)F<=n~y-c*xR12D4@$7^7Lm`Rq%``K9-4 z`J$f@&R?0uFM1R)(zi!msndPZsVyqJB3+yGzL@)BU~<6cDVNP+5y;i6Un4O9+Y?F1 z^N~=n`ZzV#-`}4L$`sRT^RCMtcy#p|OyZOS+}QOKEb$#7Or-zl%m8WYkwb%&SP?!K zaVd9=(}^`FR@=ItNLQ<&-A&1RNvWO_n9VwywULB@SdD_6_y@Am_L@eNxm4wR z!P1?T5Sr8LT^9?r^^pJMwl>u6-62vjNQ*f&>k;n!A@QW4d^Qsa*hNLk zYynu6FE25{Y%qmR&%NpA^sZ`Jp0Gau*d^OLx z?P_SL>qy@R>iRauxv`_KN_5-g^EB}R?zew!j}?9AT8?tD`aiP(FTVfIm)Watya?{`8|2%{E2Ix;9WEYAM>q*6pMi@U zDa$np*uX^8C`FIe#bDhGe6l}ueDWU)d;}zD1^=mnok6D0Om;5Tvvxyn2UXC&bM_R7 zwi|zFO`icHRdJn=YQye=45>2uz+$Wh?Ul)5LEu z{*h%3v@$Lgp)|k<86c5wHC;-UlarICYJyK=vV{x!$1KA``xpB00dSwp5-`4s8)^iC5dD6RnReH-Fx8T{e_Ac-ZJX5Vje+!2*I zI0Wc_x&fN9YYBpmwDsVyy*`Pka|!_hQ^OyD5QsdbSS4=HwRrH_LwH9l;(kkfbvk-+ z!DR)dogN@$d9qX0L4iQ++jMsH(nuZ(N~!LmG?Y|y)GIKN1~AH=AncKGj=phJ+KqnHwGSA`*STnyXjw#$16)| z7!85V4e0<_nB- z@L*247=b?Lq+`pT*q`K^w~F5(gd0GoQ!$3ey_?JTW}`nRP0S@dLoMLDiNy{@h5k&Y z->^4FwSFpv!Z~pEdW9n_!&)!k{@18KYOUf6L~rhWn`9RfU4hMi=i>pyeNICMQ4x$6 zgb3H^dQIawU&F1hg*x09q|`L;KV$edZG!X^-`|-p9Ys?;OU8(}M0qm22e_< zc6JuX1L=Tah7>sFP%<~_T7OJ~Ovjl1S{ws$1K&UL5i>$h!cyev%ti2)4};!+sj`yE z02YD7UapD{Lh+v~WqeCp{yahY`ZndX;78S3O+xBetGlkMRtJ7D(~e`Qs&I_TjNETq zcj_Il1CT0*Wy_eCRj%D~QwwC6lT1^`Zn8M(^1I~L05Uz7>G+FpkpVy9NT=SH3XwGD z-{qxvjCa{Zj;uOFc3e-J)}mrpKDGm7*dp%XolLXMZ0!Gi}0P2NGo+7czTnfD7?${mB?#C?mnI}&IVdLA@xd5ud|E@7FjSio;e6qTI}a6Zd$^pC zg5Cts-0n5EULkAsRUQEIf&ocDksEO3vbQSHnGDHnGych7eE9jPgM{09-TZJjD*nhg zaiDU?Lr_~lrjkBav6>xnya~QxXJ?ZzP&hv$MfRk-pVoCGjzt{eJdTASZvO4yNA4)F zWzeS8YaS^ERrWj?G}E}2AGY#q>AA&x#zGsL^euJcy#p72dfEQ*J0bj3?wy;RQdk^r z{(Z*pw}5H}n&*Kx|LWNeA=EWoGV^wq0>bLTAuyT(7 zlIJ{k`1kMbv0S;0V)c^Zs;a8u7VW&BKjj4l1zEJKf9}3=$xxeUq#uC)moXIzyiy;G zKcv0-|Ly|M<+LDeKw5q;-0Wr#OZ**hefQe>TnDA2D}qgTkn3SH5{#&g0@ofdGH-M z&x*>nWIuHJ;fh4R*?0wML3VYic3xc|E4^|?AI=nwQYFlfxZjq4-x%pEl?mNED>*rx z$sRl~X?M>1-6^&#YA>twROT44v=w`n@lH(oRt<>>HLFBnl?BG?$1o)B`P7{MX^Vts z@Fn2cl>sCb7m_{om2v|9KFj_xR>lG6u9m(uX?gAOzRHWJs zsX=e!%nfs$Ycvj<*Dvngb)r5-kXN6JH5qwDar;flJ~Jbyp>YkQe*=d5qYE%bW@muc zb@Rh2xvrm1><>v=!9N)zu15$EUs3PB%0qfUPD}Hd2MWxw(cYbH!C##Jk*X)+JDrP| z*n)`c#xcz%Tq2A`SLUH9%$ZSZ!u{>Lr->37XD>tAAmf4OYOg^ZmrBf4DjDrfQ^!>}`_VUvzn_kjO_Y<94#El2SJ1j15v{73r zRu z(}RH9J~tp`4dL!=F(Y;JksGWjt0Mf|-b13KXo0JEPwhK}5ehIr&K#)uc(g)d*#4a~ z$#~$77}e9vAb!m0vy3n+A)H!E3lxMbr)ZQAupEkk_=r>V*BODoa=jCKbG_jrk{L3- z*$;ms*=eLld|IWdiC!^3?Dy)Ep7ql--o0D-x_yoYO9GS&=;@q6%2&bm?+LdbKpeW zk2bd~ekvV*-c}OQ0x3AvpnoC~E_HJugvMubON32!_pu#BuUNnbTxbBifCGRho2tS( z&86q*EvDzN7?n5WwQ^@ol@GuNT!^oII}DWZmFMIH{geCxz*wN@?2oejCt8&J`SDbX z(E#W72=ZB9`j!_--OXC#)ZSUz*P!~44hBL_=5;%7-lfFHtr`gicC*z9Tld+G+aH}% z+6Zt=JMuF*V_+Rk)4zCp7s970yaO}_ajqQHgB47{_GqOSjF`z$>choVvrftbO> z$jpK;eN3-meB8$0_?&1WNOPmaY4lGh)c;9 zw=QlcVEf(L1`6b(<)|G#vNVBU$Aq7t#7Zs3hdQAB*u$$1C@H8Ixg8hB1bxGT| zg4?Z3q^yhXtCs^yPd{sWUc945uIMtx&s37+go*1mkqzlK)TN7i#~Q%%`;s4~ADm2w znqhu-K04@r>$itg9kAF8s&Zk{IhYwC?|zKiM^0wis?_~;yo+7 z;g3h`KTh6kjx~VXKpKq$lEZu1`<0v^}4q^XiIf|5&fE# zB2-ewuW33bc|*u3Vt^qEAgP`MRxb4X`gs3eU`3Y#c2k$rra|(%UwBTmusXrrkk)e@ z0lD6JxgKGnBXSlJL=yv0f81Q~VIKUk{^+IL_u#W$sfKTu>!BY>b{hCJDre>3XI2+AUjk3#+ zdR+q}WenMFUm8=f9w#k<+u#vLe?b6*#;*~>YX79mF4KUW6eJ(@nWgF=g>67IXBBk?0m`YlcZdp!EQQ!Ku{NvSGndOx9mDVSHX@(7LB)Xg(oy`sUJQIJ2XwVL zn;)m`@I>AEiM&1|S+6?rPFy&zyv-}561nFt#!M>j&;Yv_H1#=DG9R-D_mPN;cGv9B z&6^H@5C!lq_v|=fZOY5L#q&G`AfvvY+*&oex(&H(*yD^^(yeT?8ZQKzMaiBO0*OQG z+c$CJK-M7og9l(M0N+KT4+tJn)1D-D@97(G1@dRMZ}c*Ybstox`qr&nb?C3)2jb^x z8TokO;M`bvxd+$uPY<{E_@T^cJoq4HY^v|&vH`~e&2QGX6~EDAR-}I~|KRY-G=MGQ zZlIL(4E^+GXc|B*zc3Bo{flGIkRP!LQlJBZj88heYK}yYEZtnzi4HLKUuG5mMc4MT zc8O`wB>l2_j2D#o_;9wLROs%H^RSY64+Q}@CNDd->fPJmoo31N?kGX>t?dv9|B}Ls zBs2WXmP_DK&fvCyj4|OPiVg1mqUj(e`~#Gt3?2pv@I=_n=NFgv{Y*cO9{*}97WZ3V z(70mC5{N8x+w?H&Z^OrVg4ZEGAM)}@C$Dk8_#;FWlylSFhRxbNU=|iX=Rdr==ITv& z9fgldP25>W6;CB|z1MHWIYZ_5Eoz|}24BVpa%<(}`G2ZKM3O-C)_*-$ON>erTH1;& zKlN;N_xKy2&5rWws69u^;DmcO3%#mY z@=6H$J{%&Z<0OS8sKHslWy#-&k^upG7HOrmWhNwq%`nCEFb}$jkCz{6j0_KV$FL>Q zzj^h{bLr$=hPK(yf-uN6yyFVH#nVA*JOS-fvEFlgVYgn?7||%EA>FM3Hn^3@fzaYt zPH{h6!+>+zoSa;)gR@>O0b8NB6(enA{i@f~6U;HjlUZVP4Wd+p`K{3fPokk2>GO8@ zMW@ZVM&dH6PN(o7tvVQ%o!(6l2ebbKiT!B36#s%dT&hsLpxu6c3Z>q5g-V@X4KRcIHjzE(|Ic^A+K%o zc`vI=x84hP=>xVBb#sQ4PE+~!bbu}8l&VuzZUoZdAvKrFQix6paEtLB9pctU;bDql=l`ocXm;GOhi4=gSp4vyRupBRqVXn(V=eN#W-D$tfVSn-_ z2Pl^337seZUg={Fd%5=#N0*PixRfsfTSD$&DEXI3W6?NAp++twI-ok7rqKkW6bA;j#qx z|2ki?z(V#aTE13WD;IocNl|5!F*Yk?eYSX(o3wNI+Xl!i6mp}a#6g-Ap-;U7l<2oS zB@$TO=nQaWJAR#CMN;Z#UuZzpmaj2RfwuozdT$L>-Bn1w{enh>q^M}Xqz3gMsqy~j zR3EWsaU_S|W5^U*Y@&I*zJVea4+tg|Jt7A!$R$V%MQy4rl03Al$}Z(rPM(wBD3mrdH?^^BDI$&C%q`Eb z4h(<~iwqjwR?`X_juts3iU_s=no(bAk|9#wbaw7c56I-W#PMamylN8Nl1-J-&X)(1 zr2ys@${Hr1gc?c8Y>i0j!*OYGDgQ|n0dBZVBLUb10Uok8)sT_A^$$>CrJ)?$$~<_K z=4LD7>$zC*$r)!4%edI%IOCV*>`!cz(wf<6f=))&F6~WPi{n^+(^>(+@YjoF8^e?sgxf-f1>b<;6HB(J%e_ z8|ABd-GU7ajiqum0Nr6=t%HG#ZcDq?dil8)PFBOY$%IY1N{yar4C!0eyEktsZ&5UQ z>2~8H9Sti;bN+BsH}nz%vLu-6S~XQ0M-B4w!j5~gD2JKg5#8nM8bb%+b)Z7wZ~TeQ z2#a!<)+z9p!ln@>TRd!?Ni3JiG|c!o_CAf9hN@)&88As`P97M+B?;)6;C8wU;5xo4 z;!1fx6LvfXU;~pp3~h`G)%ZEvCq;x`SLZp!Nh;0`#Ie_y+r9!qTWNxRD5e=cdOy3f zgVtw)VnjKpTNI~iJV%B_Tr%(L1N@HzdKb6dp1xCbA@EPVr*$+;S~#CI=3esW|A}7yzn(d3Fx++>Y-&jcaDoYew2d&&I@Rb7aisq<;poj# z*5^KYtDxZuM@Jvc`baU^ksURIrC20hPjyB8>eHA;>JQHxm!dg?hQa4t$cBXSgNg)i z#Q4}0Y`r&r`Ybii%-lKo(EcY-aLD6VJZHT>mbtArNA74*Uf+wML+oS5ZnKTy!$m_0hQ~bVf@Ws8 zTb(Sf97WGZeG-H$rh#GfW7~_Y2mtgk7+?3G=@GIJ(PiYXu$1A4M2-< z5a-cZN9kFI2-N{z>1x9Rdd2dj`c2H&l3JnRIm}6>vN>S5;Y1VrKZT{991!Q;y*X$J zY(c6+7cJK-#+jS^6BT#TTXnI{Dd1upWA#cX2gAW}lGGypChFLCjK84^O@tON)0>0> z_oGLCNoetT>g36Rc}8uQc~9bF5~@Ulf$u2Jt2j}8zXj)p*D25uV^c++%kjL)yA21= zvAA#6KCJY3l0Y0-j)87=_T>n~vhr?58OC?R;s!jc#?Pbgz`*u$9ngX>Y+vvOlquoQpEyzqn6mX;jq$B}?` ztK8%(qvHDs-GD`-&?9h^zRd#E_WrDlv8d90uw%I%BBe38j-a;}we|eGceCv~znB#z zpIX;S#<->!@myPh8veJQti~Y2Xx^>ve=aVee2hd6APFysBs}j)eSbpe)9N}}BHQFr_^DP6^3-z7SYt`H62fv9l~r3oJ2pTZlr(R|ivaf&9;<(o z@olekW@P#n`nXGI|3AA#3))eg6W~?Co;gEOZ`$@$h3WiBN15x#YxB~@hoZ7OVRG@X z9972KX&U}NXsxvGQn543xotH5XBMFC7(T@`DHwm~l@w!O89rK4% zIkDvPOx z`i6obJ@(`Ic^cU{O(L0}saLD>BUQFHoC1|_+%fE-2DOHkv4deBnI&JvD*E=NPsEm> z%+BHjLzBTizP~M&1>cUp$A!LVXwRc>Uh=4P+2Sf!RpBR1P3XCuT3teZpxYXx^XdA&b&yd0c6 znSQ&J54S$Zf*%4!d|e)0jUi9&ntOfy;h}%ExMiWZrCn5I!-J^e0pNY5XuY`y)BzP? zU$uRJ8B@D1ujYT)Fg;qg78G>jfE04GB%iD^wH;lYw?{_1sZJKol`n59^uC(xf|uf@ z|8W=Em)Oo99bytLvaK(EFc=>}sT~Dzd7k%S9wk4Ed%RU@A5WNBXcw&$Hw^&MWdIeZT^%{jztp_`Z&L5H<}2e(`h%&<;l8*sxrC(On&h5=RZ%Mqr1+fM0{tiw?<}`U$48##P)J?$^n1AJxcIP=U2DbOE z(24<3vU^6jBfev%jx?vuflTE+&l(G3Slhb0`qw3&TKGE=@tjPKsqpE{nn~8{b4ow| z1M!Avv&wru%ey_zNqwOgcknMe6`aTigNWHsM+w4-Fa!ep)AI1iT>1F*_SQoAgngs$ z4$AMu5+kL7+%wl5m{;xIUn)3z2IC=7GVj{+_ddn~{JTXUm(}1#Im@`7>>bA@byfvLoBsLC zEzl~?&xxo+NO4=8zU=$-8SP%63iCnlR_(N~c=yYI=rXmz=f#$NK=5Hi0}!qoQE7IB z$h7*%b{PPFbJPI->?j~)oA(j`TYZL7@EEy$R&TWdZQXh&OSi^rF*g#{1H1M~I8RXj z-{7kDG$!`|AVG<(?iRvTr43Qy=P?(r*vAThPOFkE*$+tBnPk5zi$h zp@a)Q-lE~Z)k|_eZrGSO)Upn)Z#|`Fg7@HZ>m58sHK_NNs6QhxE2> z1}~Bulke2w8KQ(&ut=tyYDl{LBNtc+q7i0nQol<-jE=rowdj25I?=? zVS5{#(Cu)643MvKO{mo8#vy^}J8KFsF@5WPly?97+#?^aVmQ2>X}nmo3{swmW>W_# z8LrfjcCA|}A#okjo+!L|#a$et=jzI6=C8B7VvsJK-_-QpZ-dWWWb;{Raj&l~56s%m z=F@x46ggvw<*gx2u0+pv6J~~T%qs;VSiZ#v>;^a2u7xO4-I1W870^jbI-cVXKL5Lp z!54D{SmB8*K@#-+w62MNJ32E2-LXyOP9*{*W$-T--~YTASoxdD@LHg`sl_`QhbP+v za2AMOBBOqk?_~OhjoFxuC;oaeAO#ykJUPy*I9JPID`I7aI-{#~5NI`C9H!O_2G(HB^7q%=lgM*kf}eD`shq9*&th36ZvispSOJKJQqTqM zV7{Rrcu|pnNR{csJz$GshUv2TCkzk`%K;-`<#_dMeSkX$+u^f*DB4G0-Wf*K(pCN% znmU(xS+`?^Mv(N*)@IfGgIhx{{n96`dUZ&{+lPQ8&hYmhYR>xUDPrzRid7nFU1GG% z-MnnA-b3Cd{yMljjT20fBxJ{KCtrRvL+p2Xt)o&7Hys?b*shDCHHTtCz!Vl7DW*-O>tx}wVxci9+bd)?qJy4#MZn+IHdzT%>K z{zEt$DUkVzU_nxMj;MGs$5R|*I4KhwZr9}uNk8_yaVh|`W>oEun^8+ zb(>2y-&v_>XqP@}@E-)1NwyYEh40*kFGl1os=M{SPpKgfxr9z8auLH)YcHjVhVrHz zt?(?Axy=SbZ-Xb8qx%S8emv%Z1RX_;(L2wdo_Uv=_v_B-diza(H;PQ*!rE<`(ka!o zgo-zkGU3QHDNb=4U21{B;ABy`Qx;V7p#YUefv>(i)Ulj&PFxdV*w#5gs2yy<0@DU+Txv=pK=Zj&E z(g$l+hvnAjS*7WmPqX2&t3og@fj4HS#MB3q{@QJ5#tn|f(=a|3y;`Vn#(}59GTvI@ z{95Qm?;5Up@l0Q3XPD&Q1`;X6$Bkg+KfC59h;@XN+x9pr`ZHpQX15(vOhh$17FK4b zaocFl!Pe#WS|Zp<9J|Cn`Dv7FP#8}VhDSJ_qrE5*za>=ooQ9qHUjuhV18w0w1b1nn zjLvKbe{SuQf%RCaUIWAYVaJCGX=q7-$^CA~4?53$+%)P49SEmRHB0{2_vo`@Dn8Wr zlx(DB-L3Ftn{wC05!ppq_jGDzP;xC=`I2}TA-^ZZmv8=9cI}n!&_3z3Vv4?CKcdDx|^ZUPME`ZmXP6 ze&Z=Cact*GO30Jb#6;QOwAh_L1n5uAYf_U#ciN_XdNY5Ij&XD5&Ew zCZ9t*iVwaKu{ByTU$8A`^b@RqmE{8l!&D?y?IQ}4Vv{LFP%hw$ z5=Y;!e*NGG9pWDKofd&5xX;`bvZ7q$knZJ^cx*Arp58noE}53j?8?PQ+@`Ep*o(Sx z0RAriL`VOfWHaJH_9TSyU&VY5#)NL&vCF778PTVz&bF)#q_#M3w6|kebnWMSC*UqK<$68MQ+v+fW#cq)KZ91yCU3?`YptjL z2RbiZ6W@cc*I8vx$->%%&%-ZTF7~4Rdu}Axvbm${Oje)0C+E@jHLNjEexJr8A%ZSg zI^(oI-vnwEvp$sOwVhy})>vqBC8d~g=+3bBaXK!{utbdaswO?gzGoFr7gTUTt_y^k=7 zEKE}Ui|EI(yRv8daO;DzI?^3G#!vrS{dK6$nQd4qiJ%MPgJi2)55$2ojA>0K%Mfx> zOwo_%YH{6)zP;MYqz67BS=jTnukW8wcfex)bZ-V1@UbSCMJz2X!5(Oz;!+dQ-2=)} zVcXkQlNE-BrzQF=_43Kt9)Nh2@AXbW&N9Fj1#~E-S0xNz z7M=Th0l1^S5OB)+wfz8yK;Yx!2fnqRgNU`awr9UwC0U60BzX;`gr)5V_X6NU+j0Z+;6^5+BI-!`G%SdAn^{RqyX$ z$~B8q{M7RCi~&A%oNYp=OM2(+f)xSo*ojcEdHVFT4INl49dIIhZP05uV&w5wOdk$I z=eB-*x@1!Np&R-)Y|N{vOFc(bnO=%W1b;#ooWPty$Sj zf0b~LiN>~N^~lgM^bf7F}T_C)h* zsc$KElP1MwcmG%@K$uq#yV{;6i`yelm+3G|zNyO}>$9q|=q3O2LYxqY{zG5&^CiiA z`A>9-SUw>!Sb%VT&|RzFSH58yNe$i?Jfm}mo{(Zt5+G>^(`z54eG&n4DHy8$l-nE?TE>ySoTxa!XQ4cSC3>`Y#+93ubc2oR) z)AKEiBG9i}=oS9rPzt;R{G#z53GD%P_HG{j*E`IQLgIi(0ZIEY!*D!TyVr@uqtim` z*3OPK5lo?yiPM{4*>!6;3g87A12p%ei;I5GWxr5>K8@*|9(;-`eyeh;Z2Ic%Q5v+$ zv_G7CjSUK4Xi|gRnzgKLZH4B_#hCp5&RVEml8ASq5Xp?3VF%u3dYAA@J=iLfRgKBp z1_>aek-EOMoqi9M39;YV`HV&S8p1bOt`B&|>f+*F02GE!hesDA3dI^!L0t&{kU&GN zkZX>uZ+M*!VfR!bvrX5m9zyNR_Pjbj+dcKfpMR)2fcWgq2iqUPB(`~ImTG%1WIi>l zr#sFqe=5{m=7sD{>Kuo~?2#++qr;kI1*KR&KsvyOyw@JK%+iOAZ(sv#ez4^1mxHA4 zvaLmU9mWTWc3KV3CN?X=)lb!t3(g_TD`R7hP7jAv3ymJcTf>z7OZov=0qzsedh$>H zzJjvNUYaFH#Uy;2X{Fm_qj2DOvTMmfpMfJZyYcOBhN$JCmSxzIt_a)*aTyB3HMbY# zeYAbMdm174Z$_e#82N$_=BV;UWTIolYmYHb0$a*S2E+`bdd^c_C_*>8#_OI(NB!~U^^@yb0Ceh5+}DU z4~C`-3B{U`d>VrwU6an4yD07B`Fe-`?j0=YbALsA81BObvx8_m%M1CqNqe`N5T!JK zBV{JNI-7*|i9BXXQYbZL2m7-%kD|0HfM(gZx~RCZ4`gtL#0Nl5Nvpwu>Xmx284;}L zvZQ&1?TqTJT`~)v(jA~o=;zE4hB)=Bx0{s~UV+&=LKKv2>V@ZRhR0XIY*hWq=6nB z<3x4zsF$3*Dkm25>Adw&9QCy4owa+u;W?J$*;WMR0u!p9u?P0$vq})nWehI<7`kxX zK?o=kuYy|FFTN)Z&#@UdAH+KU1rfNAh@BRFY$J3Rmyk_@3t^ZIa^AW@ChB<5b zX9Aa*!L-U$tr)PHL`w1LeU(?6I&DVvkfUfB=W2N7-|7> z1_3qQc4M+v>Lq58>Fg%W0lS>i-qitD{;L;~Kkq%(J^xl(1Z@}87i8O=RP}u6-D9u` z;4vl||EY|s1SI(hkwPu$eT`lROkdHkkuh%{%g7u)S{B_Z_O}(wk*jTT5U*b*7RR>( zM`uG2?RX2*u~L~|X?#2e9o`%;4LhevTiU@C))QuW`{vpz2RygSV$|!H{m@gfoha<> zuc)(UzT-QD1&2ksOu{rCFSZUTiFyX#* z=rtXuYY{K|RHtSC0p}ge*2w)`-Cu0cG}~0G7b}Z5VGyQrzqx^TNPvj`{NS@S@9@7{ z^5$l=vjnXAUhubvV>SXTHW*dMSSCz;l7w=~oD)3igpHd}tt@J9`h&8zX^WuCf^ z+{F7ujzEa~(U%3e{;NAW%A%b}0g$r?|GPNfDHuh_}N-+T~8VSm8|6)RM? zdZCH|T5>f$lX(7neCfx0MdNwWQi=8!y@)qheA+;Tpm9f=%hM^H5o*|WhM{{e7*ku+ z>LV-zDR>_tsMc?MlbI^r_cm;Glia*mZS(eLig=dsga!$^ixLTkV%5xXLNQk0-6SGl z>?C4(TNuo%Q@hVZ}+&f%!I|14OIQ0noV=xN0+FAfv%>8Y65$;QpPB<`L?flSk2 z6=|zkVOsfMq$lDtwoRBRD)%;W|EBJR?dZ0Ifa`5!TAsk17fl>;HTzAEQixJ!xkh-V1$_8I4w~QAFYx5;g_Bz(f&RcT_>tTwn@@~ zBIj4>&>wj4OLYWx^vkUMlAU;r=wu~PrbWuXjSdM;_}K-Run9_g%@(shp>5biA=!np8?_l z254^Efu*xG&xC&jJx~(0pM1X)^WXHm^tvK9cF&~_ZNG;f2fUbiphy$SA1Qugf6CCs zPuPLakHl^+J5SJ3a_U8W_97s2jI;*biLcU2KKp0%0l?pL0p#c;?)U1wq4DBEVH1F| zR6v2&tFrz$JkXbxqPwWLgbz9V#9Dc>WT%R%>ICaWs!T$}DvZKu!C+`A+rFY}JgC(= zzeNYa9GGE}Z&K@A2NJ(?+X8~qE~AUMHUz}*u00JCz>5G=;hHt6&BNy-iLClxHO`i% zZQlR+lTS7{OyWRDC~Rn(@ma`cIgKN##F@v^+6><4xZoEaB|P#{mnqZPw7ryQo0m4j zh(_E6&-CjBLCj9Q^)h->Dz~M92T+qy3(l6D9iT>Jt}|~ z8pBw~W^fwV9{Q%tiN#tz=F_*}+M0yD8Y=yBdYRi+g3Lv?*J6?KBG zO%b~MAHU8(BI(Yk;LECP1!n{6#8HEMkWwm&(gTyS%A$EioQuA(v9Zh6aC$78=IcM{!WZe0j*RsX2nIIU8#FQ=3!51_e5196O!mk$RG%PJlIei38{;I~K$RA^RY9DOdZVD(udp>6lQ zI_}oI2Sl@S1lY=!CD%;K6uiE9IWVo{0~LYiaNk9GRY_)PyybM69!4J4mg4D8b|^D> z_8_*=kXXMt3LhqPO!Bq{!m=;sP3%b>ES@n|;i2(ksYp^pSw4bc>@H^XOu*L&_sz8h z35stjj$w{Yl+e++|4pHbUWoL7Pr5HGDdZ1yz%(>O{ASDW6dHG>7L~}(phq*;fOTT| z0k2nkfS^FNX4>jRoAkEP4!Jv1v^N>E20DbKTdFsSa6908@hL6gc9(~)R5 z)%cG^!J78Y1rN4GFV2hc1xI2#Y!7oWc4hRlA#xM3zG0pb{rZr}k_Tt@8uNPd%_@K8 z#kj1qb>eB0NK+_z?R55kW&zqs#I`}1BE1kX z`YO+U1B5@2zm2sy@|)6XZqO0bXmS`teI248N4NW(uNmy{DqJyT?YsI1le2yE8kOeT z`A7~WG6Z055N-Z^qTWw19p6_#QmM~F+p>3!jDcO|blv2B|RB3w(V z6DdH%`{X_$QqEj zmUf=@I@t`fbIHppx+YhmMob4^5-=)a45qScS7R7@{fU7S>f#&AnWKq0+@Fk!pALd-|uxK+z?|*r;3J7QP#7KqWD3@xIT0-ZYESj)@ zQ6k;)}9Kv6Ck=`tr7(&3JJ66%e&JG%JH@tlC~~6?0@rD6rAN1HhOqp}LlX zqW^Y;gWO9&3`8v}Ru%R;(qCFn$V>_8emxDn&dfCflb8DsoF6Hto@)Q*T$WzBh*#>Z zI++A#11@AAM86~kgP(n=ZtIUBkBPG7Co?7Ib_hQDP*8u?P}VJ+4)q|&^}*Q|y+>eV3Y&q=^0rJdpmf89vijddKPW z{}A_z@w-3KhcO&smy7HV+Y6a?$1m%lu|djbvj1o0&# zSLqJPTZd@RfyzRkdg03ga>b_EWPLhBDunjVjMMGeb^y&wH7pLOt*2i{>IDo2;_5%? z`%#=TS>JGeB_pqbQD-OJ+xEW6m9)QYGY$2UA8R;+zI)+D1j~&Pe7LEVV3N$-&*QuY z-zS(~boe?~x)X65@S<(aH`X3W<$uZrybs@iGbKPy7Kk|nyvk%q*NcMO-&9l8HCRqF zD>=p^me6!+6(byzxs6r>RT{qm7oPu0=i-e1!^7=imSHI#hqZrZW@cH55@O>B{utE* z;NCL?3`O|o&uc=#3eH?AP4OOQ?iYI@Z`uQiRcSn-#{ugT3}PQ!FJso@WO&m&q-&iz0r>TEz@b=M~pV^~QRePunV)ps*=yf74crsc?oH7NDyaV;!Vhg|uUMGtYJCV^w`JXJG+%u+)JwKQaiH2!FFnT~#T>!eJ zEPF~<3;`Ad^BM0iKpoLKsw9JO6F==kiX99Z(Id|UL4gO?*y$%R3!2d~o*9?=5s7q_ z{v2R`KKbRf%{wv__h&XvX@JYPA&KtYQ#fQ)udOlrKO9#Q>pSuOQ!Rh^#gv1O6H@An zY^(Xg>yl|wW*fNQjVYzMay`<PjRuywG#ZbS0dwX&I)ry>Wm*Kf6#JwA~Q5vhM@r5K(=>RcEnA}U)64S zl=Eb}n5Y>lB6>6U8j~)8SQQC>gOCA=1?~qa`lC^9YSK)PlkL3Dhx^-dgRjtNJAQn; zyjy{ihPX(_As@RZnV~qyfI#IbhiBUvU;RkV`3*72iRx;ariWs-2h>`x^>EFPYp9bj zSt0~@d`>5rpBeQCj0%z1Ov6mgZ&6C}8K38xKmQ&)7{BTH=DRTew(G+8x0CBZK>}h+ zQ5kifyWHGf<4E<3--8_TBUd*uL;d^vf$$JfA+~h_!nR`4k7k7& zeXp&y6K^WcseAbgWEl=mhE1GNBij2x-9~{I_IgS2Cp?H`zCkR2@aXKwIVAjHzei`w zxHvf1)zur~p69HkGvN<$z+yYcofH|0W9o^a4+XPI!TvNF&75kr5RiWT(_*BKQj+VcWzP zYhaCAsEPp5Bc&#lV~rXvb9elmS*|RWr=Bc|Q)7yao~O?PFJ73_b(p6VD+tq?%#DVF z`hKWS$g%UNti?~uJa*kGQrzBqUBl`6-Da^xw@Kn*KaNYU z(b;O%H9QimV5AuM;E#YV>Z?LCp;c|J3bck7>&P-*P;Ld>nn*GPC*gx>T$MdL`FJpk zUbploYrRGs#Cl8P+Z}QtK#Q_YtzDqKiDID|J=#z7eN;xNn3_$WQZ|^t$neSNr2)XL zR7VLl!v0|sRbdPEH5c+_PLyNe0gKZu<-&rV!-A+qr8?CE;fIayftJaO{Lx8{(Z@f4 z#3|S+Edqu`H-Do|>(${($()Oe8zyGq0~YVKpJ#+&6#Z|6?*w?xBe!A{8uU}2JL~gJ z4;AS!V{3CfK%bC&`f;VU&z-H>C{OooRxtI$_!qu|Rc*{9Al^;nfc*$k_i03xlm`ND zYE5pXMerv=LPEH5ov)f_o@L3cdofgwe(V-Gq7c_Vt&o~7jp|DMNxH_I+V0yyV#~h= z9+>CK@s>;QgSp3=P7t$_@|lc`%d&)c!rz2JtV1ZG-Vraf&yucG4&IMOCLdi$#fnOF z!aM>D3=w!;&%oo-Awd}1$Cb75ZOVHebZy>vzO|Ag@6JgUMR}{_IL(|Z@$s_qlj1^A zPaLsxKfz>Z2B{%50;%o!gpp4DIeelGzrQ@C@=E9W3*8?}u6{c~U2LD`1Frl72Gz+q zfS3qnEx{_}kA!rhD8K^x_J)C0FTD3Xk$_#XcNd4*QCNeUE2ONg+73Rmxdf?q4^cEFu3xdAJW&*$$fXE8*h1%haYQ6!hras@6L^|kC} z5Dr^4^RekJbi50QbUd)c3H#)6Q*|>#GM6N1Pi}j9pzL?`0AIS;(Kae_N+(WP8b@w6 zKL=HPIaR@cwPN+L!*hYSO_=v3;^Q8I&>=yB_UJ3CeIL{r2SlS@R#wlt6KeI-?+D{; z#>sie9`o*$!*{EG=xIR2i)gQg*Kvnnb(ic~>44~-TM~}UTl&|)AKf6Kr#(}^ zt_0iEo<_eTCe%E3H>K8I^~*n;p{F7Y25KzC$t-o7oT9P{j~PMl@&XH4w#-Arw zH2SO&*PdUTT#=--k9Q;z>a84g=K%9Z{D?io;p-H4oC0OBkFj<(7zc_n0v(iSVYkA_au+Q;f!#VmPC(Y4WN_rKpQhT9NNJi2t>3sOQ6=>Qt8~TtmC0bM)9$w z$PH`lM^0xPYGPwx6oGVpI%B=OgX#8yax~t291&YnreR;C{FlJb2>9TEu zSgzyt7;|agU-jZ`D8xMr-`$b!eZ*68YpO5NyvSQ@witB=7AuM;G)$zo z(bY3AP6A!hKk-o$c#up?x_3oXz!ucf(1O) z^?Oc=4y?Wq%h8mI%C;xwu|hXS=yWF2x?~RGDpDFrYvYyvs&Lf?izeA7=MVX$%wUCD zby4hB#9yz}s4)u*UHQ}Gmciy*^V`YJHntB}#BaOqE;9WkjG>*01UbUCx}x7zG?5P3 zD0%*nAb3}X>@!-4s~KF|o(Ek9=y@N1z*O+{gm`w_%u>E03;;MCL&^X!;;t@IeOD$4 zLAT0lB+6HxZe(XQr4kg!m9wuEv!frd35xp*=`>N-9E``2PFwhOuGj)z!UZufiWj;| zI7WuKk#3Ahj#wz5Y+vCOJLijceN-PwZ6}7oV2{diB1lmYR9kd>{^Xk< zB_s5sD;CcsQzscPZr^JD-yZ3VYaFFxx|eTjJSk*2709HE!Po#%O=`?yAxp z&N7C>V|4PU<-_*sY=>{QRV~!8Fg|r1JdQmu2~{#Zb72`Ou*mEP z>i`rVim3MpVi z^Ml`vd=a^T4QDhT^&9Vf?^bL|Y|#8poQ7Tz9n3Q0rz1My>r=#KR3*p_FU^MQ8m-YA zXcUxwwsiSg?F2i?lQI01`O*u!x5Qz}!H0aF>P}J#m$jd@5wGn{?A2s>6_|<2E=tiM zXRP*@VGq^U0`$EGt(>BNoQ!3H2E>xDD#Z4*pA)D4vb14okKM$Rvi=Qth9Tl2RE_&8ld%}OieM7597HLM1<%=O+B`H=716dO}H zV^R&Ml5$k}tX#WsVE+{_g!6U2yorotZ^K}?#HQWa%%b5lv@(0g)2M+%Ix7D6P5z9_ zj1}AHV|5x9@5_=Ksg66f79$$QDgA8Pt>73S#(gp4)=(#cfU1y#3|-lZ^7I~R=tWy5 zwUKHQq66%W{JfIdL>7%B)syhNsHapPW7joWTk|h2Mxq4|Q#1Ts(YBQF0^AsoQ%?pk zHT$Rxc@XvoN%WS@MC0%YQ88sU6Uesf$$Aq_=oxz2FmY1aCF5^~=J-`#Qewt)23!%2 zx@=s=*%b>_lTazWl6c+ObJ{@Un~V1_F4p8xZ9kCJpkHSI!GA0*_A5lT3wuVg_?ng= z9J*=5=5B(qvh!WD|4e!x%d?dDLu*e4%JZw;GilK#HyYDyk_r`B_JUM4;uc6U+V8k` zHP_fD@=!zb9us@$3s8kA$ zQ7QV4NIZ_`zP`Rk$H!j*l`aC8t><`YK5yKd$?fc&Y|<+z0O#>-XS^_)TqeOkFzR(l zWj?{*`-_+7NdUi*YE1X5F9b@R-v373$(dRG11{ttFHMNvL+uo-2`HNvU1(* zVV#63CiR6a!xFj|Gm@Df*M$3bn09%LT#S3)bB#&?ez7)Zx9mp?LudBeG1 zv|Zi@MhF48CiJV=XvW8~h2*Gp4!cihZpS~kUM+onR?Oaj54vaMpG)%bZKD*jXm-dO z)RfE*p)T@Ok)-@sMi#5VxE@cm9!Gqe4xU>6KY7tEExg@s5Ym&mPh=@*z&bjD5nVf08R2m>EDFjpR%+xE%m^8$R$|hSc5Nl_)+jaczJ73_ zsY0a!e|uJ2kM}cT<6~IqXzx%jb6l&DVO19LIR~&6ql+uMFUBX!_46+a7I!(c=693c zadC@FENb5=#N{&b>!pHKUuh!wL&w7kk+{rkQq!LgzLmXLzxX}1u~ZZCAIH2c2lSz7`z%=- zZPI&@`De={7 zPu%i`s*o@AlMgH!-^NhVrSR3I_^3-M^I?b~c8lSA%ral$P1!a#nbd~_AIT^-Z37$}bdGPr4 zpqnbLmgF8LiG=P9$LfAyOD586$6`8GV6_q?(+ZyrK|Yyu>M@k7M_{dN3!wfNfU&62 z{#^R=Xxa0-nQFleI-AO5xnf(u%}9Rp&}8}S`GW%(Knp7Edyfwl+o-D)Yhs>d;+dO& zolBG8>$Kb4Ah^3Ywc#w=B$6i_5B&keg(UW$Ru9#Q8F?tK!K_01HtGt&3ISRL28Hh` z?o6^4Kfz*avGFdW8B;Z-Wfegjgztd(M*y4LY>gGrDzi-^Gr!U05b@&!(CPFWfYh_Q zzd6?s_AoXk13E_e0~lRuxst)e6$p?QN*6dv5XtP~P|@F6%oVz_*kQcp199 zSRaZsE02J-9xDKVkV?OWcc$9nasYzzk{<)-4)9QReD#CtJg>Hx>;m!|C@L;TbEJ&$ zPtSKJNj9RQz^F#RtW1U-@Iy0sK*LNni;3X6g6RfAH~`AsB?@Z)u3AKaf|N$3`bBG$ z+^fqD3~(f8hR^Gy@%HxJFKT%ATyMYeWN-}{U_-xN)YSI;Wc2zPvct+BBc3QkDFgg> zGAwv9yt9Uk+a@#7raaNB7bCt(-Fp;glAcKSRT-L>*n*e1SMRJr9_En6rOoaBL9q3ja6m5$r5 zdEL(70i+&gr*?de=dE)X4$D&@^zjY2A^-$<9Km9(jlSYbw6TJzUBFpgX1gqmL8~Tv zmkwa#^x_9G&KCkNZ&tf#pPfudl!>43+8&*kza<0Qf4c z;0v;$+w1FP;Ee#}Y6}&o%pt9CQ}HfSnVpJw)BBe6p!`i_D_L2FR(67+k1{AKpHJR= zihPdp=y2LaeY7lhz3!l7HWWhZ-8U2RmwS@{G}ED*dnYOYXf@!0O7*|;VsTL!Gs`8# z3~ddDF}Oqyr|<)M+3F(ZGoAxZ4@v*aFt&t-vIr8r-*d10hf zThoYktRtx#EL@(#`T#1w-=5XUTK{PTc(F`V1euTz-gRLRz~d1jFnPA8JX>jC#_Tib zdru8Hyyvw;Jl5v8i^w7t>f&tKIVb0KKBO{i01!@jo;=T#lu9*%)d{+XR*50#*$O!$ zZd)f2Ruxw@^YXhMV?qjh9|j?SZiV&P9^?vYAT&u^hZjR-|mo zr@2-Hw0?!Z9@|0)>kP$S1>&_B!X5>$bNy`vTu+RFb~PZ?FHOaVVs;k?^LT?9d@%Dm zM8uiaXn>O)5da*ZKY5F(pw)Lk2^jg_THetlVwQT5K|y7{PE}w9hbZhRs&H`@$^6k= zdY!7cngNNI?kb;E2m(GN2wtSsM^nf(&4X4Pbm|x%wQdSQ0rmDw{;&ObKbPmWjX3LU zupbs0lqSrLBr9j08zA}!?DNv2bU*sEY`Fn8fPDCJSf#rnkfwV_Lu%wUc_ie-P0x{O zdl_BG=}L_pBd=|L5%qL)4j+#3SME|9EZ{)1eb+`Lh$Y_nq%u+b+QTU}tt;2P+xBKc z4^?704O5Y#)MARAQyM^@T3+7faJ3{Kg@aoQ=389hMBI@(3yktRF5~7GN*o%2;&Q){ zxLxSG!NqL7D$u5kbrH;%h$U5BJ-I0#dM2~^Ihz~tfA{oqM+trZ* z4;oVwR1>UZQKRn0Oe~%^XBuj+$XLS(`EcQ$k)D#kiZiJwN&r8&YNZ?b2LCPm zv2!pA* z`2n*hB5?d%&v$Mvs4X3CS)+9y1Jfs!%|(&V4L=O;PYt=2{1pRhRtT~y5>(H|DWN$g zDFKz)?6AeG?S1qEziYtVxe}3fZ_cxxSB=^JS8$hv1{$TyS1vzW4Jnj`_*SlwV4ov) z=%@ZfJFNY=!h%e|gHeI}#-!4@Q>$_^8S4W9zw--jIL8_)00(pb8}Y@IL2@;VxJXcJ zMkqelm4Vbs6a4%MJ4%5mEu+MFC0WPjV5UC&C|Sy2GK)m;I@!BXi@4(qmbU{M!n`48 znO-*qJ(7n&9GGW0#^o01dM+C1x%@4llarOfWQ4>Y3N=Ql^iF~B z5CSfTbr>QhO$XXdJknMOxPi&`_QL8-h{&YUQ;+q&_<$pMVg8U^pl$U64+qjaJ~lgQ@8@u9IP#F8{4hI zS5m;|(gquoA=u=_wasTWsfcj0_9gf9qxp8urLdfv#{sHP$M?yr^}|^EvBIrg#yMz` z%s;UJRZ8&*$mVw)d};%QzpH#x7-R?zZImLK8xIzqS(}$uz0)euj>(>J^`g&cs-s-_ ztXo81ansaqFW0w(Pu`J=xRD1$2)cMp+EGvl85BDtg4MgK*HBBnbi?>uNK&fJOj+z* zFjjuL+v0ZH?2WO+d}SNC!)`rCtVB`{yF%WfOy!xkpN5hJXVR(c%v&3$;KRJ!PRJiQY;MG# z#*yR8zyCK^b5MetdVi9WMLUITtluy1Cs$2)0zhtwFb1tX>B^J&=ssotgtdMp;ih)x z6*=a)?m=9}JySY_<3~0Pl>rhJ zQY*d%Jtz1e9*&D+Wu{eYP2XWt&Gro8%$VbJJyHL|vK_!Wr1d`n;!w|kG*>3m zW!lxKBk$b_`n{QIncz#H=UL>@ho3uzrT&SxKve3L`4|=PfO1Vset!N@6{SoX(C2JA z4ppJkxZoYF34rjG=bemI!8tw_>i7H=G5N!}5Jd*NLf@ercmH;8rewVLJY|w01lpCE zQfi5}zyaQp#}Q$(WC4!#%5uP`;bv30{#W_KU&MWZz2mL&lm`4EXFxC#a*pAhu1D?M zsk|D1h3Ve#<2jdfaAc`OlOdClTe=y=eGUEWQ0p$}E2DOVWm2;xmUJScl~SV@N!($*1fBB{xj zj+YKz1sp{h4UW`^7*t0QUI$U_K7t zc`lJyFQVkvNetkqxENMwf#7~Sdu7|c!gd8b4Hmv&mHPu*HZrZF-|US>X?=i2I}pwE z(j3cdd1-u>zbPBIBMksWh6IoAL@bADgxma%iq&Es1IU0v?NkymWkB;yD1EJ`(FLTl zZl)U+L&4k)yGzJn|<-L zM6E6-G5IS6an17dyu3Q_n`Ar6H9Xh7%HllJBV&c?gOVX1ibo(oM{NueUR{y*d9!p{${#DlSYF>U2CW>hc}^Kgz61fwAW03K%Oe2h+WbjTf} z`y>ie;vNQ@Ag6zK#;GFxSK&*PO&RCIJdz+8CGyD0_Oz^CXO(UNok zUV=rfM2A|`-GuifGvBWFGM#skT4Z5%R=Y!FddpF_JAyzgjg^oMH)sVgA2GJv&?bR| zl9fE+a+NsM;TYA@nS2yh(bn^)O1uXSHYPenp=ZlTpleR_D7XFk2m@;yQZzwd8A%ceOOV;>X`eUJJl&s-*hWp`-t{s_8^>FG3nP6mN z9Odq-0A#y>c5}Jl$gnU`pv!`w=GKQKIlEN!m2IaT1)O6tM`a2R0DB^sak7S2ieZrJ z6?gssnEHs(85P3?Ali^avLzr3p)09CeudLyx)jjWF)YZL?n4<{1Sd;$!`WHM_LMK~ z01K=mZHJ#yJ`G&My~d}Yc_Y1tu~=d9UDVqxo%ysNimvmM@nH8`zBJTB#QbEV-(Grv z-*w^zKLtRvG#0mcX3bes%C(A1L>JOpKC6&0ZrND(`n9FLqmR(93-=yeNO0mNNDoQY zgAnj~DjH?iMe(YAQ~LADv}N!GAc}lGcLFKZ(qFrJQgeeHU_eJyB*=}7Md+t_$MTUB zCav~v$aZo`VB&>nq_Pdv!=C#7@O^9HyT!L^%dT+`>av<6tc0VMUo!_xt*!a1!H0;) zWU9#0Z`Avi^26?AlUF>IBUx5r%}*hE|0$|dV!`Ta({FFAy-^T^w9*;W1J4T9-@8^w zs{Du-bDiXYLya!Aqu)a)S#*8B`zG)wa<4{lboJ_66f@g_bCQkVKlliMU=aE)$<4zM zOBqpD+-b^W8TvkzM>&~G_v3u&tnoveNSj)v=jVjT%=Xu$07?{E zFY|+2%0Z%Y>pR`$w1!l$fY}IH^b>_ACe+&cW@}6e7wl_d0;WG+02$^TF76t^k&H|S zze+Ct+KswrP>qPk;zC|C10^wJY<_ecu}}&&jDtyMX3AzG`NtDEGON#SR+mw4%XMmr zGenWX-3XplWQ2sdg<~@=b~Hh*wN(60&c<|x&7F2ldOkWlotRA&T|Tb*GZYX*{y>JShHIf=>Sa~Ydezy(X{qkFGj(?_C2}4IEDc zSajEw53PlH$JK~#aZb_~YphbK9?S<^_@Qpwg*~9Nj>-QdUy_eI*!DB{kPzNA{_kfz z=8?z@|gp5%FVvOE<>wxhA35mFlg{Q`YT_5FsJ=K;~d0Ms2*rgbsBYmfD=^u_lf(9 z*?Z%GM8saFO-}2-<;Vmc*5*VX1)-QaOPH(gBaqaBPdK}+?QXZdz{C`3Gh_K#zoNN) za}6O$P#C`HLqtacy3B&!7oqC5JmMfUW-R?b59G&QLBOyvv_PUj?CyZwU%{v(pYPxo zjRm*eF=SS`K0VpZngG1)9WOpsru>BA>9JVwL<_2e3e6Gfi3$Bd*)_y~BI*V7X8ZG1 zKm>1y$@Y*fv4qdF>;6_Gf03=01VGwpTX8TZ{HO6;P~FEQD8;fDM!3 zSLo_8^jO(7S8TLGUnqw4d1@q_DKrB45yb}P18+0*83!AVeK%7-cCq{x#Dn1RcKN*+ zfNGK@j~i3M({1Cu3 zcO}x!nL%*I&=*9udpFJixMqUr+v-Tt2C>*a6GPG48XrT>b75-2mxvpu#V#=wouf_)+GIc)gn~SQF!n zOHg-uM)O>6+7Q1~t$YG7*fZw4Hhq(P_z*04Zb`rC^N*kaG3YFPNlN#KL8E_ej_;bN zPr%h$l{P-@U&LHGf$g$-o<#Ni#1@e?{w?kp!vYp?O_OsU07vPR*Tq{=3;odY&z!WF zX6s$BI?-*@JaD$ed-|v;WW>zk*|h96y(_aNFKB@hFn=E0zxXXp2*^`pN6$;Tka#C>uGn1a{rcw_`p3||WPliXp!sf^{WZUD zoB|OiYZeO;qq-W66mHxPWdbn=)vAW8vV3*Bi-E5i$wzeGv^%>9Vtm?0dv1vot^jr% zue2E@=%1&eqLNI6B|iSuh4a@!{?OId;Q`pZz4kY#zxjkZ1n|iTq6lV`>cs-53{_k< z{?=ibStafwqW3j?B%-Yaj3;BbPx&UI|Mm>%9#b2D*2D?E1%2}pO0yq6Y8|O9V zs0&*R+(?deWMXNiNW!`cL*C_R{y?xwhS>{xbXx@I=+aC)B)C+BcZTJk^B1cuE<-2C z->(z>$r67M)F%{xs4a-Gzi`4*QrW!*y*;V z0jK8w^|DrgY}SUOU;b`x`HK^D;lnf+_xVt4A{mLkuM>ad^?`QANrHO=JwSdW9b=2k z9Pu5uKcg)VDJ&o)9q;MjuL4_tzeEh&+xaJuEnDB3=`Nvm&f0&B~F0g~T-6qrj*V%D_Wv2(G zQ2qxg|2^~Lur7~~ZJq<}(qFY%|MOh@?>W*QQzG*}ZiM`E>;FA$8^L3mNJQg+#jon5 z|F=c`|4dGw?0_p=&_#;RKD4u};m_`AbZXtm%Chr(s|wWXwiyN0auP%X9+oLNzm8gLa? zo!Nx@-<$XM8^fUi9PDfBx`iR(1*YAWc9{mac`P$`!En*UriAhOaD^U z9pN|^GzP7RCTIsTfihNmVhe720@_8sy`7V_wM(C@0?oj@L&~aIE<$a*203dR2?-p`99bOc=elW1c;&%B6=?s(L3nleZQuZ3dg(35n8hN8 zY3p;xk!;FM04^3h3V(O|jGf8zUTi2t&l-(?ap7SUAMLh~a7U5Iz@LMt&-M z$Hq-G5bk~z!S#l*M7O*ae2B1w4l+_P)YdsoMQ1fbMyt$EhOge}`k0E74H8XiGLuIJ zaQ)Tw)!JFiWgHbEcu!ilw<;4vO-4L z7_iaKgY3hcpBeb#v^aKco6aEP zc@f@01JcUFezN*U$%_9e1Pqcy)cz3dSBm1)2re#i+{#@?uSG5j=vSjYD?pd!7Foy` zO(_Rcc9BWO66FtIMbdgH3&nPrpkY(POi!@GwY>uE>=`&1axx8=m@1-)W(lBF-gyh_adO#{Z@bE--mGh;EKqKr-2a_@_1H7|QAWmC4hWdh!p>l8&}R{!Gffu=|u$_)$BjE`FHCu&dX z!|e|#+UT&Ak(C7VK^rjpczu!I*fW#0GP6vdRdFmfE;CTtbAG4QkbDyU^&;?MXx0FZ z8AFi8Z>V5uaVj*HezQYQm^WR&Lg!=AL;F)6@`{;{sfb+9IAT6W-cUT}+ZK8&YKDNh zvh6mCM{A5As*o0SRA{}3$FFTHBPzhrV;)#>FrLYFUZ2Y!*DHr}Da|r3V-oJjl2z;L zcO#p0`(soiuY3(oPytc#hw-NHDGf&!erMvIBh~YYQ8)7|qdyf_f7CJ(9+YtG~X~a}8$>>U}v|rLWWYMgc$;e$_&o1H6c1%t04^ccplE zuzYCfEV!@=T7Dy4c%m-Vx$q$gWMc(<^KxQp4#K<$L50W@*c%?(a`no{JE>$FmS$9b ziFX@PSt=>jVOJ`qqTXm{)VJErhkXz-jn`d2G5t`Q`M9P}q^c8va(4_4yUg?I4&_m7 zqhugFX9a;maG=_Lx)hJ&Uh$v} zwG0EMdpaPKOfk03dM8yrli+4f(aLX`Lg9T!C+A0x{^_G6?aBsI*m==U`C41zz9U;w zXcYmk-G8Ru(j^_lRy(x+?zs7{+X`UOI9B1w}hmF zb^_l-^=?eKslI6ZDvO=+q1&mMEn3O5mk)fw%#AON8V9ZuiQfgn#$N+^- zY|#p(K>4Lsk3!gQVp%vC%yq1tK3p8ppD-9)ALcxI9zCRhb7brw!jTsz>*A2<`h`Hq z(9xr5B)vCr!t@~T)5&S~98RrCYe8hLXW6;i!7t##{}LyPD1X?PP;ll86w7b7)nAcj z)y8Uq!}>IUq&u-RQURBSWrJcqCXIlox10z=$Hz__1h=2Rwgl~If7V2Ar|&c!DDkiG zD1aw7SyC2~&FyE_=t|NG(ny_63y8ci4P&#uSTnX_a9bo4_7MJ%JTe!7wo;66Zq88S zAwB|i^<2&i+NqSCTNekLS2|v z^e%-W%Ekj$SB9jJOX1y)1&}pyzW_JXxs+bQAZ~6g6@)CNT?%!D(Kd*nQ)`A*%*He~ z!fIT|GPyKaaz^Z);tEQDR@6?ff;uWp_ATnSV$kN~zcp2muUV2W0;(q^QTNN>?8Fhs zb0}rte5e_jw#h;4145}>JUB85R6v;*4Cd?fNwztiPb&=*GX{ResF*|)&v$0v^AsQ* zY-+EMav?wXl7*`2wz^WdQfVxB#|~4mI3fnC|Evh|AIid?+9(kM0+1)UkY*A{8j3wb z!#pxE4V3(vEn+gh#e!1oQ#6R#(;Xu`8B;&5=AcweJq@m1e*tXBDz4v$(wJ9YSS#{B z3dgdjmd855yK2WK)|yqa*K$Q(UG0?vV)l)>9N^(pJYzZ0jE74Vs406at8EdHnV4gF z1rFH4jarqxsR^!eI_e zko;pc)-oQV;ugXl?jp-_Xhj7?h4rQ-ZP_tm76V3J(O;E$N4`PGE@JBx-t(En$9|UT zPkBLzoe2%{V#YvMy%{D{ELY2o4wg|P+u)rq?w3m*jfFZ>4#%D(RQ9GpbRSg&jb@}- za#4n0u2}II)tpu4q7?UH0n#g8+qz5<=B8iVFLkK!SQb|tADlA)J)LLIumcbh#i%juIPWQ;1GQ!RSSxPLt z+tfFrnjdn6Glfu}i`_8}I>N1a74bVkfX*`Crii^#jZLY|pMg-Uos|};9hi?m1*2!? zDBeSQ?*h^Str07HI)jfDE{On2P%Um+ElUqEb7?qXPpxFR1oLXcu?eU_-!yy z+mAne?ssz5zlDrJoQMnI*gs-VqNlLQoR@1xB)HZ|TH9l~I9%*Ki3vKbW-D2rlBsu8 zHIm#yZ9Z5*L^**EVI_~9`z(VE4@VnFQx6gTwhBRVNYZZ63a$l+^NLa}I3Eugf&SI5 zByolpg`&<+o5P3fwJ+a!A_NB0=P@gZ70X{EN%6K(2c3vibsK$z3&zlb&iRNSB>Mgd znS^;kEGktZ!H;PPh!0ufZCbDxLwz3+gkRIskNM9VPbb$e zW>9V}@GT;<@Ko|NUVm*l)Q_q^ZC<=>aJh&a^gKAN-sKwZ&zv;&u(a|=66+uo&7HNA zQoVQAP74zV+CH-~;l5~V^QwJFrFD*+)k1|quj}5|K;MpB?3P_(n5MUAztjV^pQo!s?iEy*-;T*&j1n zQ^KDwT&?u?#h9s)y_S!<`a zu|XJWzJq}vXm}!@fBq;-MA!=#YC_eHGI>+=q=u6GjRCH__U?y#u{Ai76UC9t1|`OG z@x(&C9`jX4C87_RhhMABEnaHczy!N;>@F< zU3GCElKISLa&l%d=@y2>(ChprvUYW>ZxBNB9>No$Dmk0_^n${t_1z(h)YV-niM@q= zY5r--0TKUw__WRLh_T)w7}X-(XmVzz;;t&db-JE_l!P+kl&AXiwtJ03arSb)^|{$C zwne@1zAjx`4cD}3Yvy_HEG~Piqn!WtS#>L%Gr<6QG)qjY#0AklPe>@AV1Z|nn!Elq zpS8{9l-Bc!jlM4rqYlg#x7voQQ_T+^=`B~qbNPFI|0L@#Dwn~*SK)RXLMhMZD!(&< z>el5Zeh%zGqnuAGTw{0!4C#OE1@O`48Pxl$8z5zUzu3;(0SjI>0OXC5CmhZ6FD?c7 z;?N0#6~F?1Hs10Cz6r4KE82#Jl>cUDkgqs2>@n=|9XD9ezys<%g?SRVDClJO`gN%FuOZjYH*{*OU^ecKm@Q4lP!Y6AuO_dEX{E>9U4 zpW6us@884!A&drHNZ^jaD{T6^4oLG+f-@p0uPfVLYLU&=UPeA{tFZ_QZhayMt;O1#2YV_dv7B4q5v;7TF^Q&e6 z!UoDyX=_~M#}gX{a2b$Pzw?U=!m;7uzI-T)LC{TM;2~@08ee3gfHh*e~SdzP>p8o~xSL~ac zn+%Iv1NR;f?6G@KfC28m&V*lV`HCL8|NT{HDW zwzds3E*P639fnIG)%%2C-o{$BLk^%MU8N@*{Ck1j-Q7y*{bsM(SidVR9h(xBj>B^o zLdt(LJTQ4%32KrfICF5b81dnhq+*&&{j*x(B?>aKWvyAMR`pKpm+>7B)N2P+uJYFf zX$s)QnI~2l(u~?QbSwbQs@;$1sv;PllB8Bbsj8`3>2j|be&up+w|(z_vtJgUuhf&{ z=H}+Zt-Zaw8ixb$=3Hiibgs9B4X*O(eyxU>$Gq3}wTD+h@Ekpfi@1{G!C24!f)f0S zOR0c_#Gjn;kHLMnF_SF8nG6Qh#Wm@g<%VLLXc$y)dy{lPdlD`he=V4fp1abneKP89RsiIi@dK6&$FdYgQzNp6iFs z1G=g-@p{LXHds5Gr>>P(Wx-+9Z;tu6d3X{NzOR#$*vALslab7du9ZYYM9cvtv~AdV ztZ3Cs<`^T4v|+FA*0^UL1i;ZhWg;p^+k=EZmUVEwy?vPmnT1@WXMWkqZ+~@Xoo%7Y zkT|%vwZ*BdYPGy9V%7hiGr}F%!IUr7gaib-uQ)lc3TL>m5Ce)F2JTw$#fA~RJ!TUp zSc?~W_k#Yn92B$}`(0I$JW#1Nb0W8w)(WS5U&kug;UhVTwXgTsSz5{p=rGd$sCbp+ zaG*+$WZN5vY*!vI?ie#%>_|%g!68fnB-HCIG(W>a3gY zaERCaCZDLKm#z4Vxx$M;ed+Ggl6bzWvY_XbuH6;Yh!1ty*{i0gnpt141KvPV1+W`A zfW3K%6-_E?{02j8*J4u|yx6Dvga3ca^AeIQO>iw#6XCHMpS95SBu#uD3IMG>+kHGF zcA4CTHr>-5WPs(uY<*pYWm8;wF?zQ z3sDSor3Qahq&$@>2ow-Z){2NglZXUDKne;XFH0l|q*8elY6PiED?vbrKp;E};hg~T zRGaW>h&)pPi3CXuj|2h<`*U`7XLgp}Kj6;2Gv|EgJ2U4ypYTAO3uM$7C=i1#SbdZR za2xPN3@zcQ@1m{9-?tpeId$q(BhAayBAUn8mu(+oWG#_O$u$o!)hXS68($an z7vLEF@LAC{*5-G)0k)vpOuillu^+R?`;{XJq}G=Liw}jQH>0m1CwxAq*i^}K!CK{F z7<6;h=~oAq4Ia3E_Zmdzh@`meGl9H&pfR&i6|64K_6S z)`1=~MN}R*(RnnZd;02hn5A#!-IsZO^bqDK{u9^tmT@bvU0|qUw6>0(Oa)U);=^aE z;^Y%TFMbY~%80w)Iw+bGWf7D2p>|sUkk%VR3MZ4d?nT1d0B6cfib|!5he_%Z7VlL) z;Q8`f1P=3+1pd;zv4)H>(Y-BS0;>b3z2wKWn^~ZN1-sOb;fGMp1F`8TLsL5}e%bQS zM?l@AZ(ANAuVQE`_c3ks|hZ6tLB3qe$Wh)rpk`0lxj@`_^9W}cc|T--Uw zF7#eaEb?mXvB$HvvWmFI>e1}%?BNKEqX$dQrL%o8Nx7 zM<16`9o^ybRb@AZNUiNo&I{Q3W1RS>jeGz|^ev=U+lpaP!lUUTUDN-k;vb5m2eNR{ zm?QrI>WTmU`_B((bnHhT&$sYvKAZtmTyNk;*)gwlcw19*JxrF1_!XDhvM5B*0;bJ6 z=echmRUUZJTmt(v8FwKtP#A}8SGuBDFQlP|WR0G5r3&1Vl<#c;O_P@xJLlh2%736c z2U_J`EJvC>nC0GX*421NoCm6br^Tg7d(Es_DgG+*a?nG|5r^BxNfQ~0Pjq3G&FUGt zgYR;5Z^3j)@~vt&GLg_mdrc}vL_2M)`1e3-^55R0sJ3TQxKM461U;z?GzWA<6%t*S zLMxmlVzEQN{Uy2p-Q8oZziXo>hUBTIVQ@-Bk(oUfM)LyDp!bc5`(!&wOz zcTa=D9bNI;x3_-hHTjeq1(qYR$inUkCgVCpU6gfzF;(RoH8E2nZLtMxol7- zrtzB2!)LYH!W6fTh9zKtH+)Qk&b8r$Z+RI%tu-Y6GXY7xrTZc?6VjD=&z zb1=jDyHd=lae|ZK+Q@3aS>?%2`|7UW$0u9V>TWqSl*LiwGx`eSB+lf?kCWG)xah`j z&o*yEHB9z*g)v8ULu`IqMzUTB1P!!~m`&)30<#D1GMP))~RVlE$9yVh+Lg)%1bdA>%2?V+H-Mc#Co2!t|YUOskCK}CW{Sz}^ZmBFJ!RPMU*suKu3qB%)#(q@0Z#rqImd=Z|T*W#Lyd8=t(s z;q&EIS-O!0FlrD;l9`Z$1i`hhPJaD0DL35$nte1sZati(Y~+qRkAqrGNQ@EL4es#R z^r>0m0%NLXl52&nPet^;*MT3Nu|B-uRJKl|KLWkF?`3ueiv|V;Wb`p>z;>jB z&{eANE%NF!vCMu~@Tg3YRVd$iMz0^{y?rnBYgv0q@><9a{!YYfyU9+{WmN8+pfxyK zHKb`1Iq1Ex-{k`-b8v07TvDFhLt%35@iFDd<}cPKo{96|UC(Zk4=k)>P4$xm_F+1| z9JJ$2^g>Te-gVu)RaYA)c>;>I!WKK=%~zZYw$jr{2>29Q^fIa$daimU54HNtVIwM< zH~P2xonw2ZBj33d;dJ$GRDWfMAt}f?#CfK-e!!It%&mWOGD#OfbYDX;nZrnLIL<~S z>(*msL56xl>7xGo9`P#9rO|XoN zyM;d{-}FLN>vRs#g#nA6P5u%?6e}glvc3NFRHdZ;#j;QNiu#5PS-(?uqt zr=x@>e0+Qo+usT^PAwkOo@O`Lgnno9n=S*(R;GlK0j=pgZJGUF)S=6ILMxh}fy7Ct z?nMj^FH)W>Ait)cw#sesMG3|_b4@eQe-LZD9S^#0!tab4Y@fd#xS{>B#U+|kdw!fE zaCw%89w|6C(yZZhirespkfIJhr6;UtV=iEDXj!oB@J hP1}E;jH}jPBd=Y177_aT_^Xe=a}MDNuX4jB{|lQ6>h=Ht literal 171405 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

eUATRK5!w6 zG-Q4X4_u+UQt%%V)2Hn7^dN^0fe!9N7IG}p7M;M5r*(Evog;lvRFmIklNp^crYr}z z;*~ZTrqXR8@P<7IZT-6;kp?R@+EbJ1~%KCl9{A1~A| z6(+vNOTdM8yfu?;a{18khJrt!xYpEuEc|-Yt;e(8W4RxhSS-VWN{KN{njFKGwjE~XNKJU zbuUaS=1iWHQzDQQ8UiTtzyP^RsZt``hOuFo`31&qZNM^(UH(%u4!Z+bcl;8`906Bo z4<89AAarU6(nb}Y`Kk`E#%i*8sdxV z*Vk?{zkmR-f|3bg44@Ubmyte8GrL6zMrFkO^Ea_EFw%!h2RM)q;1j0b$BeTj_>)7L zL?u%=?A1mw@3|mu#Dr=tq^o{w;_r1bb}}_7&JF{XszA{kvTi#D^D1$C^S6E@VvBUN zk^EDa{2vc34M}8=8Wn+z&|fO+PDNe5y&DRg|BoDI1jqc^ECK;Bu^B_$lZib_1KY=$ zk)HxRA?;O`K?a%avvHsx^uls5;JBM(LzKw2ja3RL&~KczOJ`JSv~4;AXXU3~T|us) zHejKQaoNQJXLSEshW*cVfG=-3gKKH@XQr{D*unA3Y-%P1&M`|e$6o3RrgR6#t9Bsh zbse7o$fIX0AWQEd!ROa4%hoEa#J4%63@ZUMpTXuu+rgaVXif_tmJ8S}3#maUQ{=J?Io>^!i3;%IbFt(2K$^nH#5|*1Iab8J?#rxH{?! z`y{IB-H{%5OINmu*QVr~j&j9evT<^uEbL=vNbRPA%DVd1;3NuVm;}~ozFImzE%H%g zeK%ic<{RCwV}DK3J)6fPy@X$uY)?QCZIsHpFoB|#^;|gj&k>V%7%8#;pa)z4r)4o) z^6=5F9+mwODa?-c4%1VYq{faUZ?bOC9NzD8=@RHPA_eE0r#ar2!c3SRNxWaM-(j|l z8b)CB*9?hWF-^si#gWmT&%%cHE@1_v4MJB4etmPthBX!80cof=A)}UGpMo@A>rFaM zcYpL42>&-H4HvM=FupUjf4U1chh%iCAFid!Okl@S%pCVihQEUj5K1$+`s1xjiTECn zOpfu_SVerIAp9cNa`gVKUB(=Eo7VoM%;|E3uig+wM&p$9|IqsbRxq%OM36}T&40@3 ze{rGn1gX<-vX`%ZTFYWl{5?99g6A3gEB-Tc06H+$ ztca%W)v18*rt!&NTUh|vypGwR)agVmKN5{&la(91T?sJQ8(8_i zJhPVCf3&n1HL$r<2_^WYdIP>I5(W!#aJdGNML7H4JvgCbY33a3$Q>S9tq}acE_X(} zRe8Sn+{X!hvn4_8mu#T=y$pFef_5NoqtI|MBqeen*`|9~lLpBdS;7}w#QM-Ei zav9EU-N8n^xc6?*_3|_QrwL2%{)q>3{X9Ari5&O(~4bV#0H<(S05VC&F3 zqR+r*ao#pez3-F%n9Hz+T0U8w7n%3-sDYWl3D1Zn}gR;uj7U}@ZY%qGU_VCXGH-tRO$>RUwybL zqSHcnXw8_btOxx7;ZaCzUL{cMxDvV$qeRB8MpU!XuW&r<3)KcpV|wH%Xyt~^b2W8t z>|jtO2@D5zo%mW@UShaIso__FC?Sf)Ij99fcIc1)3sa(F2-4RP} z!dQ%&B*OB|xRMfh(7lX|F*$iX5xP3|JW?R?M=ncUQmB~DE2KA0*9a8x{WY}!+QA0i z%nkgn0OSCkX%I4V{6}J#0Agf}*Cn?0>W+tz{^wphN9xsw4#3a(wdOeTuRIiv0}PD+ z>1_WppyjG?4SB_{E|U#8W=vW^*`*5wd-o8~7{%fm@QcL#A0xmp1c)hJ2QS-P-8tt2 zV8}qv^sK9!{9jo_VmhWsrB2d$??1CQB7yWqG|T&{N`4I}tSb5k99P8vJ{ZWxyjw-T zI{8l^Wx6%@sZ8lghT}o^EdX+Ho-Y%wj#!EY(2p4bjqFvTO14FsR0%4E|B1P#A?d`B zPziCBLJ0$ay<-x+U;@5F_fHHZ|KTN?AjK3(3o%%7Ja23%JG z;7#2wjfYnu7eEX=oE6uaz51|}4!QVy+_LIdC&vZ035R4TT&_nLm4+R7GmPg*?Met+ zh7)*^R{eXK*2R*d9Z)&11K~`26u`YQ0h^-ea6*2^ zDj*h+%C+g2AoptEEaL~3s1R?^Bw+%F?dTKJ(>1cf!$|cR zS&Ku9+GUP{<{xpjq$C}&AC~&GQFV9Va(_;ITT8DR2D> z)PK|Ei2inAV&RPsnSI2w@x7S=6ad`W1j&^rIZ0EHBrSKG{F-?y{@r)lHm%y=cr+c= zGQq0{0sE0jeSvy#eEZn^JJY8D{pSimFuow=Qr*Ao z4)Bq170Lp>R$jrQ1D4sZ^6Xi1K7S?`zUP6}$#Z+b^|Y;Ls9j?1Rf@pszlsG9eWYH* z_FMj^-;z~P1+k}Zf>=^Dn|^8^6HT6V+H>SsoTsb_V`1y-M@(`&GlZY>nzlhe<@_eH%ACo&gg4#_=ACelNX6hq35T77fXbV%41vU`n z&UIu6hG2<5yJVMTq(srO;+6mVC^-i8W7BM7rl3z(yn`D1v641&knT{_BXp)j2REI% zDl`5x!UPdr_v{4MBjOh)^D#F+tFvvzhF>hMl-T2k8-r0nnenBElP3i!zpZR-yv1kU z0WwkoMofD;{n=n}=7TbSrPe|P*$Gj5>|oDE@?-6})`+h`e`^6;^$dDgU)lcE3Spth z;Qd`YroTp;+D8!9{Ap}rb1T1jOtj$xU|?M!@Q3z}`CFS<2JO}!eJ+yc0@}$EKMAu{jL{f1AL4kNjeIHY5_g$OgRV ztm!V=MSM>Ix{#3)B~YI?=$Xd%kfaLaKIn!X9rGn^H}d=3@-_n6iOiusxJ?;H3{P+$ zwb+@cXlwtaFID~6D(4;5MY|5m8W6a6jG+Zch=YJ`DVCYArO-(>1?^IYPq^^0u7n(& zL1eQl!aw8CF>9B9Bqw9t|`s z@eF301vy3rx?YEhrw}i1M%1QVq_hoN9n?)$(SClJdt2=oT zkw<37hkH4>xA5ssryQ-jE5$l%vlwZ0i*SQ4Ci|rY0r9L+fI;V-g?uYvU7>q%kN1rd z1P(%d@j4+$NLk+yqZiKKdA2^MY`hZudsLm8n)+GP0`<}layn`GY-jI+`ki4=>TptA``^VXTs<3 z2&N|ETWV;wX-KE3m`1|!?Q_bT;9|^xinZOv@N{QIt+KAJ6;ZdH>DOdqygfrd8skk6 zDHc5?@`fvULorxFpKUZu6(Ix2COybaR|1W5zA?3){%yI$?D37-b%LHxQu`#NzzY?M zGxJge1h&UIasGyT>U&;Lx;#>CZ>MyMN5|sI+(n9M^;_+{DP{NWOMmZ5S-L1y`jMiHL@LHj1Qtkl#WL+A*7ciE~P z2e^q6q&7!d*+qd*STM~sbYSqUWR;|zV(6i!rbMWXja}$GY5cF6h03vlp>25q{j*a+ zsaXweY@&0(flxYVfEGulrQ>%lXv`EvTbkFZp~S*?S}N1y1F-r^ElM?TvC;FQlJ+!0 zp(zvZ?+rnbQoXMA(w{M->Y9BJ4w6G!P8o+o1yloawI3$JyDqj!X%4jJna${D1eyl{ zi1GM(BO0;hWNqwEq*hezyLbB~6WWJ|0Pavz0TFQ+7qy6^{xYNM#$KHmOLz56!Y{a4 zm`7uuvy2mp*PDg&-n1YXH`Z(tKoo*_3e;-N9~S#VSqyt5ZU#@b7xd@EG2DJ6 z#3{6>NB#U;H8tFi`KR=ajj*YJpSm1~&sqBUJ0j*QPaA9jDgpNL-2*A=ZpBbvh&qsm zc<33c?phzO^9D6;G_C@Yq3+S>*qtP9ENR`2bw8MTGb)TaeoC^KnagX3$?)B}qiy46 z2Vygb>F4Zc7Jkm8FEmQ^It8x&sJk6<{nQCzHY!S~G9>=O&2Sch%+EvGZv>CxzF^&> zX&gCU0wq2R3Tn&dE2F_rf9PA-1}&F(kx8vq%x8C%cp`?C7YPsya2N?i#TR|ZxbN7L zF=_!d8pD~CtX4U>klUQkrOQPZs(mz|rdiC~x)2@@;w27sy~@YuB4dr1QrONNM-_a2 zYmPrmnYHbsU7*w~r#a55E!kD1W8f{JRWCu|T39pbsJ}q9G=!d>V^NQtAi%AByqcts z_FRsKGnb){gk`N`BH z7+9_A3y*xHsH9}v9JG4m@Uy-@a~}+x6su4xW$lvds0VRcs1Yq?$H75Vu7_KCCpXDfuZf? z-ye~aaD^`|HCHShW|n8I_uP$rTv20X6_&=GHh(u3ROP6V<~U>`Igy&0Iw8$CmFAT# z?HC%W7&9)aNN2P~MMalY`}$La9`G*)YN~8D4$a?7BcpL6gMQ`;(l>G;JVkGVZ!)y~ ze!TFd^tGx)erxgQ&#>s!xjJ#_sVX@sJ!anSeauR&FZM)*E;9@M~@#%EiEmzwzTxmeZm`@W?*9K zc_W}6QxG#{wGn0ggo62p#JQYkKHAzNf6SZ~(Z5KW6>~h>-%rGJ8gPBO@s4QXEH_^gBWeJi@2?X*iOchbXj zZT9nR#x{kexQ3KfHk&?z)&2)OKW}7roXEKABOdbbsMhVTE6keA#|tLBY9DI<>82k4 z^!5z@xebEviw;OYhp%iVVt;ldE%ZHjO8f(CkT;x#Hf1_EDNVS+JNryprn`M=x7&g*ouLZ)vDsE;UzyCc25~sj zeV1B~=$!YtKGC&_vpQ7A7(BUtJvBgeIM``vBd4&CIMJaX8D0mF* z)^2;)*lUf~WDYT!Em+!%>ED8%2q-^v$EPHulswDAn)018pGwP_Qq4;(cCB%LTIcL! zl^O)^edSXwKje4v%C$6KEd91DR%*w`Io+Ch!#&J|h{*m*idBq|r+JhM=M81?>rn!a znIF2Ra53+n34GSG*AQ7DO+EIvbQ zP3~y8{cei2=7975`ih-k|I&nPfF*4b+AUtgu-o8VlS_QYbeyWp|F{Ue2;#zv_IK*My!g$9S@C-KJT_+Z|BB4 zNd#TjjLzwF%mOD_BNm$YNw|WRzbu?pcQ_H295rCbO3;ehxfqfDNiv$TyB)B_)zUw~6%zHaEzcVXiJhJex zYzb4ra&vhIsq`*4`ngeX0JI+uT0bgrI;Z6aK*vQ=iKUOIEi}38Z>Aaiv%d*j_Y+eF z*Rgah%b#q^JG(3#`*_lHyS~+ep0OGDTPT;f8tF%E-ySOM>n0$}CF`0@O95}~Gf3M` z4ezRzm+~g#+K^f~JdfdtV;!E%FGqE#ocHg zAr_Nro-F0#D0OQMz5hj*_r%G?V70r9`(QO?0~}djGrO)NcJ2x#-*rSS zHuP&58(Y}U&g>!7c4s*uLy~Cc#kwHJ#J2;TI_ zY5=WMn-!~6FFISk1bTboK6HHqnA`Fl<`WBvqxlO-qeG32JA#P_8+kGp!{;Uvdm(*- zvV`4&tT}NqDh7=$=rpFKYHz))H0%`BCj|3LEDTJZqRgcy5gG0HmJQzXB-7{G=vSTS zFL2LTe@%E6OZIKnTwB?od)0j^$ER#4PnY-5?k3mH(YK@W{!{jxgjyd$ly?XSSM+R> zxnV)v`r?=HaMV0)^$hj1+R@Qnv!FOh``*GhzJ83Q)zxP!d=bisV&$}t1)CFT`I~U3 zDqYtu|El@w88Vv*-#rdHK6G_mZow&yS1JCJ8tHi)cK4mbbxxU-_3BW&YUh|66tcc# z--w~PeVdNSb_&yx7uuwBTECDu^gBu`*FCbd?;seCw+D~4Fn;AJ2Om%i3tsvfP6Is( z0`ZW_qwSw7PReq?$@+rD0>-Z^AU=HgRrM81334=`8dW-9JL_#&Z z+|?s@%&@aR@GcB-ly1- z5E9|u9o34$G0NdI3)54RW^}UinHMY_sVEt4*ZUE_)(Tgfz-@r$U&ECiTD7-VLd<4A zowul`>zR8`;xdzgIk+G&qToaRk}P-Zn|z7FV01iS4aKNRwNAatuRlxIcVC)HN=U=( zt2t5=5aSbOX3XtRsL0*ri47U+pY49gHkY-vSR(IdGt^=W4LLg?EP0}9ZvT6ZCMUOD z_q2FA3vGbU4Lz}6x=-I;!5r>dQ`)iii=;qvbu3SCev%*O?r10Plm=otT-NFBq!N58 zaB6YWk#~EXG(DZxxFfqRmh*j@h56o5jL8bP_)xsz;J8M`TFUgT;b^!}kpAqZtF~!R z4g*(CZK}rBYr3kp1)*)v!>bK4d;KfuthhQo)bYKGNqX2AKhAB_RxHe%sS8)QNw|}<7o&Di!)!dzzY|T?BI|go^1S1_M?$wedB zRG=$4sl?fj>n$F3%cD=_`WmNa4h3?_%g%fR0-kuRJPo!hD4HFNPpU7|(6!Js*p=Y) zSt{bw)w0hqDC7~v44HB*dGW14^*71niW`}+T`bM|@!-G;K4*bgF)1i-f9i0ruH zCu>dZLf2@vPp0`+g0i-ANSyh);qD5~?grkA!2R}SCl!ILrvmM~H?Zh;I+Ur^PK-T* zc$gJ3ZhP$)4mE1!$e)#|KV?1|F)*~yEm|B|Rm$sllNhIp<@B}7W1uVWwCbLUCmFkIopu%+X=z;cM?oo{oAQoOOwOC7KbmP?pLfcQXxg)7p&4rkC|y`RvG@OWV&+ zHJ?OyGa@7;c`JbPXm465n?L<1iZD>1y)G>5rj1IoQmnP8fnMfET5$t(D_w@hzivw~ z;I^Ff$3~pHE%>s4(ZagSMI+4FFl(mEr_Lg?jVH1ylH`avS;{kEQpdVlWAXgSj-TRS zr@A$&vC*_;w0y%`i+9g!d4p30qM^0cv-63h%+hVQbLhykFE6f*W9x|H$VKY2 zZT^xTzne5Mbtcu~*(Qlg9;X{SW#6dk7*tpKnc{F=PVWtgDYrBjuTb}z`g)+7hH5s! zP=2``W1Q|{AeqhfVvv%$x8b^QzDd!1y3<&Bq{&a8n%(awE~gu=yU%x51~UfJBy!6- zONPeJQUwTQNSxQPa1iSWqBzI1P;HdxDE3k3M`PL>hITAdcFG1h-XD38MBnt|?!vs+ z>u=BEcV>SuIhi(){w_EY`6MMJ{nId=NOi<`q&$sn)b^E9v$=7^kU~=ykJDC389kH9 zfw}HFZ>>NuqB}Ft96lyz$vQvD@K#Y1vd??ataSYqu>| z$Hr@#dTS;@I)LZA#J~KJ14`DOnG}&Gg=eRzl=DT+x?-x0E`Xf{SUTL(&(T(aps-BE_X|&>FjDx>_SD9%%?aPPd9-hqZ_Q60tVFE5SfZ(zEuB4SW=b|N z7UEj-IftKI0MX=h8n4Z`-4)2QrIx<*@!=>uel12?4tqV=6162T3uEX!N`$YCGIP52 z5W1qmbYUWTF$3IRt=P@})bW#6cihQ3s&k8xmWzFJouhG2>U_ngy{MuA;`xzl?+}AH z4JdOTb35EvEI_eiyjcFrW-vXDHHOrDsWa??zGqpY~j&jmgi_ZAocOsm6+0@k_+3a3(^YMUH$ zg||UEEHc=oTJC(u0`0^4w8t}&`d&wdl5_mqp0yLd$xn5itL*4rX8rUSlfJc@)vb_} zH&C8hXZ*}-yjm|?ZYd@Wj%S|7Y4k~Y57C9*SSkuofru5!xqbB(=qJtd(Z8+tJW^&E z0+7rd|DKQ#j^V@BV-xL5 zd^eYn(0>fEfm7QwI8nxxjlthIaciG0*u~oHUymX0oo8i{s&&;cNY7Y1?rAKgeB5CB zH0TKEf4u`SZyA>589Mo`^k&pETyg0e+3nFV6~1Sje8Kj&qTm*7gADHbT8aZ<4`^v< z9&W#o(hUnDh-g*#g7=kP zFSiZw?G99| z>>a)Z=%J44V)}Em!~;<{(jR_e4}~YI(nJ9}XTS$Bte5wF1;cf*XKi_aFYia|Rz;*b zOY-r;@xVe1?EPr2x$#iS5t?0tno6|w$|_qs*73(6!-6k!u2a>qO2zZFFTV{P{NSn! zWvMK!9xARwFQ}6&;4%2^_bR7;z2}r2pgfsXM9!0({gS%<0v`L(l{Mallks~jl)1SZ zhG)5XQ1XT|Ch~TUl(n^dc#okm#Mt8D8@v!%kV{+A(1BK}vNB|4YJE7jr?k)kk=F>> z-OX>BeCXIN;8<;JSaZ*<;q2KH+tY@%DUBrM^=Er6wQL1nUeV`&Ek1fktA+@p&*7(M z&gotgh=`O_dzGq|9*dx+qo!+c649b^e+D$k&ZqS_zEBl>D4$OzsqFeyF#kGtuL0*S z-+vtJkQ)h@N z%HooB4IHAKnf3Lnbd2h!(V{$2K#&iF;^k<28i=;te>w&)zHc^=VOH#Cr)=C)!uMo9 zr2`t(KxS>4aeK>d@ip1&v2SCEb!vt?2mCQ1Pw41G=EWWRXw6EUK+brGkUnw8tT2;UUaTMhuusz3ln>a?UvNst^-DLa=KYUx*dSe}ptaY|KTCi~*I{AL( z{!z>aD-OWpC|eJCJFwh97q_!1loQzTej|lxxBFymd9p-2a490faR=rV=wvM7mS+?f zN%T$9u2AL_@0i1`9&rEa&U)qQP9;3r+YW6%>EiY0V5qf8B&OSQPu!GhV&LL$?$Du5C4q1gL3D#~0Ts}^F9}Zbhijsrr+Dqj^qft$M z?t&V%3aN6G@q&8Ba;?GgUvbsfTAt!sWYy6AUfOubZj2d6L|9N)ssIFnHdbHbzP?UK zJ|&RlkIPF{_oG=+vA4z_Yo|M0b}(qZI*3r-DE;yNd{(m?hy9uapD-s}`#=RMgAbpe zUakL#^dhlXEYe2UIpIQx{FMYhWnI$H+ke5zGF+%Sy-DzNE80Q#D zba5(YuCLAmVt=k`8NZvNl5VTle3HFmB&tftjms_gJToySFHEij_s*+hYm4z08OmDY zM!R}v$WY0{zTRK3r)tY{ed=g+K1MN{1&A@dvKrPJBiU$UJAr+Y5TjjjPJwU*WPF2c z6*Q9D=QXX*wQntN-WM8dr#_hBv#Gl9dl86iWPjaI5y+8cz_iwIG~+WFs&o~Ih#>Ds zENZ%uR_BA+;e%~Pyz`UO&7w|AXIEBhPrQf&UEyho^UbqHu= zVpn(X{C8ra0EOLb4e+Mt9N;CyV3GE03#HR=0m!M z#EboDw7@xDKH~!lz>7`yB7+42vvq+`m~XQ31+}&E8}~dA@%D~TV|C6MI39JDaVpGV zt}G4oSNi@Mev?voe&lZ`R|lB3!RvtZZv^u`phj@T*F1#1P-VJi0oP&hL~_sj$7D*! zbM$i#EITHWG<3oylt8ljTPubOb^+umj|5g*@ddj?19IWpjYb=M44P@gO}_Q2`QP@0 z8MXuKU7eVAJV`ZT04S)v-^N~m;wA8FzXR;R^IQNaGT!jANY&UBqqd^*1u|IraaRu+ z(*j>Bv1#Hk8(4tZP;V%Rnch;p3ASnv5A{BWLboZ33w-EGGU^0KAUTpE*MtrP8Tkqy z$zY!E)CZV?FPBp0B8YV7HUP|?#$rYwfm{JBy$0UAa-O;I^#ZU<6@K^H1%!a{uK#Zv zFH1@*`)@4(5PALII`;n=@Bdr42Jn#!iuprEup*Qb)5YOl*2m|}lga?&!tB{KusOf| zB@S?d7JUaVfiNr&`Q~8jV~g{D#i|0K^Vqx5V;3oR2(>U47C9>LPnZWvX`!Xg%jlcu z;sF;3(%GqqMB|>{K1RkV(!BLlF({|a0Rd${6g+Z~OveNm`Pn1(>*p^5F{y2ABsbv# z2BzKr8SnqV@BjDoA~|#S5mQ#L&?Hm;vBi3C>uqYa-EA!sA_3>JZV#W*{-2o@y_oeT z>Fv2+9<>84GNF6>3Dv7Wu!2Mop=PnW8btsF$8O45laJ@d;F*?7a8D=ObhzaDC{o~} z{z*5`8U45@9jF7;=~^BcyX2od8cY_rCCH6ze(1WlX)ar3kmhy(EuH) z1HIJ*WYZu+`_YA-{|IPDujNAh0j&u(n?UGs`S*K0I|Fr&Hne1}G9Qc86!&>2>vCQt zxxM~!H;n7(=z+mIn&nLc=c){QOE2y?*E=Y4`n38GN~HDk;M^FX#Fqi)h{jL)TUNvk ztoB>VokoFn|1I-s^Rj~dP1y?jew+$BY=`u^-ETWQ6UanYStmzL?38=Wi-I$=OsJaL zmtU#$WDd`&jQkU!HkP3ldiqS6BehVY!h1x1AxcCdxy*9o?!8Z(9oN=jIsQS*@6X+-&JTinfusM z^!@sVy5K|pIfYQJwRhx$^+5hpX;@h_w734mK3K~|zvk?4l9|Dwt5d2MGFxJEmY!$Z zUZg55Yj#jEICCQ;C;Q9qHox791-r##i|3_Q;6U$C>y{#RQz*NAImG|9ErqKTb% z<8!{u#ZIXm`J{bdG0qEUrxG}IfUa}Wu#yWFr_lsYB?BiU2Zw0+yA^3n%PG$87h$?C zFs~S)bt&~u^wj9S~8V${@o!2{Pi z@IC9kVGBVJXvC{xTi?7VjlH6uZ|8k|M{ng%&3@f_qO$SjF%R>KiuKnPYX)EPwdtRH zkFkaWcJchu|D!?MgunKtu@gPhw3l!@+kV#xZ{1v#u$p{A=;?%0=?iJ;)2SP=-M0N3 z98k@ATO5lZ|qGHsLmDsu;P&G)kEvb8233JkWF41OE-e$aGXL=;?I82Ajt?fpKw$DII>lfwZ&`6~n)mkhF5ql8Fc199G%#r_%{Lxn z-VyAb!3bG}7g(gaSEtmOL({?(osaX)`hmY{rlUj*j%)8`*Z;?b0rHog%G8Z_T#1HlhZ?}tu!08 z)4iO$xfX3|H9o5%r9AFH;32`$JgB#qP|t};KCbfRI#WKb-tk^rcL3m(57|!PY5`DJoh-7=;n6PTGj`=JY36;H+Gei4y(p7wlUvUZj!T= zCaiBCp}Zpmu|$_BveQ^>CAfF&uG;Q)+YPD!{)p2u%V8{sYsvaHLxEZ5ShH=p+AEiH zzugRQ>wGX@SdfgVPB@ppP*shXbf^+mSf5C4^pu8g7w!N4sj*)Fp$gi|#UaeOUB4Y! z2IY-bi{*(fCrza9D^7c6AE>bqhuEamH~KNY*7{R6GOGylN0Qo$I)?Fnz0no(RaWVO+qT5 z&Iu0E3~+JhdO-*6Bvt3BvB&#!OW7$LA6_2w?2)(b0a0?dI$N1cwKrw1w7IT~2nf%M zq&XmJc_pbJ&brt*c#n%tK1TJ}=`?olZrIvnGC2?mn*Njr1Vo>hpqDN=^8?XrCkJEO z0{{a)-l`PIW*x3TBgz^+8=ok0-7IrINw?=7RE{Gz^LMGz1P zQ9`6tQc?i{sS!mPTDnuZq&r4YRMMdvWf1A^l$2JwK|ngBrJpm*0RLy*YrUV|5AVCy z{Y__G*SXHwXZQZ?ja=PPNsH6MM)p>b%2N7 z8W&TGoouv(!Y@TFjVYNf`+M#OynfX5kj8yY?GyX0O`XM9h`_f+77Ya_+I|OXg?&qn z*23w!QCEG>s@3F=Um3SSZR?wH_JZ&a20>b1xa~u!zP#Q4T6M(XG~<*Hqi1t=~I#JcU=Yg|^DO%{p?k%Em%^QmR15IXn~ zT^?Dvlee>8`MWQW!qXgEs8BcN>q!3hN9|*t-`y-h*?v#dV!v#OjY5>|vye&VY8fb# z%!oNEG+O_}UR_?tH{6p3shQOA_^uW+gZ0K%fy_>1>1wE0C&FYvsrPneYB#7{7-|>I zjaS`~+Yb~Mx%+v~PP-1+`CBs$XoO&W5@1U~uwNyQOg7CgQ?n#l zc(hb5UU_k`c6V2qX)rjc>H@#qt9dW${Oj9Lu9@RneejPJs7v&H(~#`9J|y>omJ$(& z=<(WzbP%f_E4tm!U8i$+`mDy@QGU7_>|~Msb2O=M*H!Cyds>;o#h7tRn0D0lgy1BQS)o_#)#WI6C*zXk)IS#N}*h&NhM%owOKmL&P!_bggh*K{qUOm{ly~8Ua$L02L`xBLYqtW2F@-aV( zvhu!a!`D%M^G*A0wU!SAEG|_}v3B^>KFouF_k`@P1!Z>Mx9Nxu~w)uV}84 zW~!s-*dP6>Z|Tk!^%2{hr9|GIjb@qz&istlli6Zr7dj|a9lSXFVmD>?b?DEzJv!NWFRpUUig3m zhPU;v-CJt(Se!R1BHM*9-)$=}rq66Q51v?jUm%WAX7%26UDu#S%pcoSbu-$Pt|{}M zu!MTbWz}n30Jtg!uL$J;xgIYsP!)a;1m;>z$V(c>!jVzr$fWA4>FULU#dW1scrg^GNqfs>Cc;18vdJ70|Bh{T#_zn8Wg#cDe>!y&*Dx;jdKnO)IptV1 zP`CnkI8Ek%)Ob;c`-IHgWfWKGyhz(`%!LT_?i5%@a^+qMt5)8D+9s&>K;!bVTdgjAh4Pr`#@Ay}W)yn>^KLm`Mf3&e$wtv$t zV2J}iBm3k+bUV2cctK24s;3=`HZ6k4Lm2d`aiI?Z(8_@orBZ${4q>)D*Fn!irCjAK zra~jV*Iha^v00vnTn_82`3@7`*)qp|I8Xt+UuHP@jBsleQ<1t*wldQE`-*<>J-xV#bUNefWyh$ z%^P*s5lFW|aZ$!qRE+!zWO02Z;rpkm%L5rk(%|rE{x^x2w__V~VKR)akzE6%I(%RqyKOmK59@vE=<`$4EMzRs@IDe#&f-7VB17%0|xXLM4>Dsv6lw7Iuth`Cc_j zF^_;(f0O?4M3J&S9*D?NZzu`61o0Fcgi-k|e?w)Bn;#yJ%gAL*Rh_RD?5Px-oRTV< z-O3&WQYsiC%=HZ$kG(0$42?da*5QVFTjRylH#MOCOH1?xtovRr_8r*ZQ+Z(4;6wh% zW(ZnuZvk)9CnZWGD%|4YsP z&-11?39a3Ug5p#5PQa(qpkP358F0Tn)<1^ZWk>!fPYY53#J@>0S&b2NOeujUN7eaf z(B^^*@2|8d*CjhQl!r-_gK47o{SC5}hfmI%l$3z=ih?LA;L6^8^cr`NQi^NXh|Zg!G~Y=X0W9#p>-{hN{(sLe)y5Nr)vG<0ycugA ze|Gy_L35YCk&8r2i{ReGs3;QF2^u(fTgk1;=ifOPx=#IxEBhB@2{0+sF`nN$t^`zg z1_HtQx0)oq!WqyF6XH?bN>js^a;Rxcle`Qv?|rWB+IkCtXCs zE(0i5FRsT6DMbrfy@~fSD>t+~_@D-|0y{fIECjR=?>2)|$ia7DN8jMCop!wVJOQ1_ z0I}ZrB5C!Sg!jl?jKGqpx+-4=EkOc+{nX*rZ=w(94GwqdW6cfJf8SpM>H}l?oA3agbVeT?>T^NN&$d(#nfB+FSnAn%c<-B`Tjr%ytvsBSmMOWVD`<6(c?Mq&3i(A?`q z!W!RVg(jPhaz?dKdEJ6WrJjcxe%)p`zS{>KfMJT+t%8pYZk%EP)@)(I&e?JR>ZzaE zO*ym6x4;{*=aQn`=V zmEoB^SRWU1U5i?-GG-BAgd&@Yb|Z@V?l&1>aTjHe3$988ZyC3=WgBOcmd&j{EVCEa z=&z*BBWk#aa zOpmm3j){nr3BQ9f@77|1sYlPx3%e;aJ98^97GJtDU_X-5b(-}NjN{@{fj0A0J8)kd zpHy*Lh!^PFe=TE^$VA?srg z*f;)8YT9vuLcfQWto@+EfT`JimYBC1Z#{Z_c$-kg`(P`gfkMQ!GTRZ>*#1MR=ZAp6 zA{^kIJDWPFNGN#RGldVD*ca`s`4YmFxiASG<3Trq&M`c@l+bef?XT@MP^lSqeb}CG z@wl$)2pJ7mW_ul(2CZ^$NPa+eQ89m@@ddJX_+ioxZPO@v6-KSIEW&&!2ewJ_mFoY>wmM9?c9HX}{*4T}@mIKwh!MCS-%2 zpsSA@6TO87I9?F&S0qzMD&@03#{T&GI`CRbN?1{Sl`u|Zl!pr+K8^B_MOIHie9%~F z$RJMTY5rWxUhGz3n|PNo&1&C(M*r?>jg8$}GFK$f&OIs8`vi-AST0n;BOpixgyL-rZ@u8hCL$~tVhrbbOaWg7BqViFviJ&?{b};=p-CKKATAE|%siuiLW*jpIjV zVwwO*>X*;FR_3d5%I*7Y{Zc<%_ebM;k4vP&RGc#|^z}5lMHb4$bdNd(>3a2pd+^+8 z7sanOQVJLX-9H`bDQa~f;#?eLEXH!Ll1lf}Q^{P%n%a(z@pj(!XH(9x7SecbY|>b< zQWaM}&c^ZUy}9y!y!8eie7MoE$V^LF*|4xD(slLnc$QOs-9Ulu+L7&DId2Qc^%!** zr(|p{|CCPL;HlK13=&in-U#l8w<91O#k-J1qz~$;jgKFE?5==4%AJ-3lCPCs8Ks4| z!9hZ|TX`h_$*A+NhW?m|G>PCGtPB(5SL*ACn_!gXUSFRc&*t?qFD0=*-Z)%vygY+L zN_#y2Zd>`Mv30}?C3?$Y^{mc_8}o6zc=o%&j*n(a7K*55aQCPSp&pUpy`L{jx5plX7Pp%;}$TUAcaNQ)<-8|N)n$iqzB zcZW9P1PX36MqJNKO~V+*3LpE$4_dX4Vfqx0_Np;6;}$mV5JC@W$h$x4w){g=HYRb^ z-_B0db4E(nT)SsyWl~gVE5dy|t9MGaEl;#Rc4R>=H}&HBidL91`O)^RUV*IT&&kI= zUZ`G|@WEUQf@AL?m$3Ob_ zGrX^QxPSa7)yQoT_xrYYF53FvfE%Jz!B2lcllJ$mnJ7O9Qo|@m&-}Yd`j5ol@vNIE z5TGJ16{c`nAQM-T4N@HA? zDv=pcz;;-m3XCsh4vkI8rI+1ZQ{kV@Upi{X)QLzH-x_+Nzad|}rckDuDZZ3|b%i(X z1}zzI0U{E}7IjuvyZUuV%#n??w}%Mbyfyn*9NhM=xDi!5*p-5L1C2wbW5IRDWaQhq zi&sA1vOQK6>YrNsCd+7UT)IoI)6PrPxbQ`d43(Y2;RekXrQcs_A|pNIkpqZ0Q#JP1 zmC8fowJRk#+3(#)H3slgVuFh$d{2mY8O!Jw|d=fhP671fovR!~t}tjfJr zFd5^)amdACEO1n>{0QW;g$ikPbUc+U;;2_Hl-@3PUA~=rtoeFN?V+8MsJF%IJ!Fq- zdXR(OqF5+-lWk4eZ)9s?R zmY4OvWBppspw=w2bb*z21wYb*IfI?kK6;Lr@vESZUhr6ip${GT3SqdDHB6m4rJsm6 zg|0sG`nP4~u+&3OJjL&Nl@a8f`-ne#_ma^1nq%8~JT5rIa`Y-e6!t#&Y!{)Jj%{PN z0~rHd(|3I{f8}wcU0Qgx3?V2G=)=9Z9+SP)qg9-l@8}exJ6=)0G9sc_&H9saYYVb1 zEO}%p@46+^eHYJF)gvRDCa}lX%3+Rkd3V}T^`W>tl^uvRvFn&-S(&uJMa3Xm!PJD$8Mff z&M?C)6p5H`$E6Qjs4bj27tQ&o${?qk9d8(%n4U{K&73+p^jqQkL*^r=a<{% z4F*fu;g>m#ck`0VCj2kXlp#kkP275g9*%)i{}u!%nxRo*=sKvwf9HX`NRTREobW;U zZ;j?Ei^xV7%57zg@BUI86Q5Nw;JCQ$Ho)=Yb`*{8(pbT}S!{8y|J!f#%|XWfy}`cz zOQl&r-ydDR5-hS`B7WCebt*;{NLA4D=$*f$LV^wxondux_5a>LD z^YIqsRr{s(BVNnNXO+bzIqzHz07&AVu%JW! zj7VOCQ#P{288j<1aov59;HingUKyUlV`ztNM|2N9G3l1q+Z$PVG|_K*?_Qd`k@Agsi(~(tNo_>$^ALcIm+1 zzn+34k1La5rJ^{$P4Wil+S{z{9_HEq-p-?~&9~km^Pn^G@Za_#F@Cw(I0r>Vf}4i= z=1RUbS?LbfK2J*Qr%X_;`Zk7*&`60iHgB8`05Fz@1qVxY-AJ$P%e$CAJ}YZR-*?HF z5qZ$7`6>Zn^I4}k3YEyEC6Wcwv8HI*_Ysx&+QhsJb#8EEwsw~~bMOk$|L1S7i zGqIpHHB+`T&R*ci6*E@)nQ}W~F3KEq%^Iv%QPq#_JJ%V>hNX-FkcOxy2=ysI<=%Qi z*LP6J?YPbAfnMs)t0&&E{X9y9GJ^=l8B6@4r{l8@TQ?uFF|Sk@T4w6dA=?I!jq6~R z!ZDw|BOj`+#ck>GhK516%358e&?>|tPRg5dq|L2Si7Y;go~FwBXiE^9?c+&rjN&tI zh#>HlniLAvSWt}k>pG{#b>5UBlg}jSexVb`;|I^JWnSC@blgMyqfJS9k*xUlR zZGtg!-AjM*?IS(QF3Gm!?a{_0fr$g$=8p-t_;XzQ)A*}2w7*>I&&VQiM%!@}{Vxl^ zWD2FFA)Ls_<~}pWWF+Qg)n&M~Rl4*E9uV?k{s7p?oW6&kcG%atzT~@WSlgZ?V7fSC zduS-*@PqPOLheo(gu@~hje3al{5pmzq3tX`BDBxL4QkJi>NnK!!^4>Vd1SWXEcgiV z{AqtUQ<`$kcps?>Z(SpK$Afiu)3-T2%unFwPp;WOIkbR|-LZ&T{qPY;@m+Cd!Cp zz)aulv?r(w7@i*47^cR1y2or`2;|=?Jzi5Q+YGX_pG+MD$UoHx{Jm`J4AA5~bD81B zF~}aVfxdbGF&tGH^miD;$~;L7fDUh9escSC3EXsyx%$J#!xq*`HMRhPBg26ji9-|? z(umL*?JN6QMM`=k>wAB{|9Cmiu`ilx#AuYEehHZ}@N)+#1MhP4QDV>)8BKPb-PN&t z%r&#d)w69+<`J6)&~`&tW{%gaKCebxGD_L4V02UO^gqlgKAJm887*qx-NfHy?DX0C zPc`pl`*+H(M%a{*R)re4(||*V#tmqWrl_>s=A&j_YA2FW+%!fHK`91;YNO#wiZ;yk zSQ)}U$aGxd7z89O|2bEG);{S8;U00YtQ^C1rxYTk5% zD2H`xA>^xaCfuFl!A9Wzfx>WR{P!809_25kGff_Gw{;yoI9!d&SIRQ?ZgMt(Ft2yu z;;MgCV?V3Z{>LOjlN7DDSVq5}i|;X1VV>b0xk0~4>238`P@X!`Nzx?$RJ(FRsNJQ= zG+iAORvWfn+~7R4mM-`0j8H6wb9&e`$*$-Zl5l#!TU&+pHm63BxrprQb%2I5J;9P` z9p-Tb4&3<0w4+)rE-o&WGxR~K#7-y3vfJ7fv{pV~6s|Gm%jHy?3m)aIdXOjt#CIf6_?@&U(Zw|_^{t~1S+TkJziGDlMhL#A`@ z2_&qe$VDJFW%6#F1{`&u{oDlP4a`R0QO*5w=hpU`=MShjy2ABVhi>cRj3)UlbP{6( z6d0BQAKjNk-Ml_jHxg00f4l%;JNi4Us;;7$l?-rIe_AC9{uN?)>^pn_n6`o0SN}fU z1VzejGjn8Ndg)O>2qOa2V0XrHwXG{Ey47u}kD?y@UIXd888RFK=gS@B&fkvq6T*xb z`X!@hy_xT0p&9K}2}q%wXDr{pfN{`MxpXh@%)QfC{rHO>+3EwSQNysKj{O!zIAXxC z6^2NPX?-fpBRRdXWW+rdJY@M zS&$kz-?Dzw}RFmz4@Z(>s zI0h(~*MvS03^KByR5a?#0Hca%aPw)E*Ua?_RgT6hZMH;^#9gd5yp5HTc{A%ygW9PX zMq^|H3^GTF9B(-z*@l5WeweqZ@mj|G2X`P?JV!@^00Jwb!sgwK6uMu;s$g>5N~J+b z)xKj?)a!W{cV(_CW*`SX9a(rZ*>=dg8x3cJaTzZ<2uMa~y=3y}nC^a$h2-Zz6y}9!2p(Pu8 z=|U$+2|t+&S}K!&pa&*~MtINL9Td-!E|fCTY!#(*7C$TxT!n8sf-z#kXtm?*4e;SJ z{HHZPUYx5T_A!XVwwD@)vvdA-9H12|#FpP5$pX6mAn7~JO@j8Xq=J#>{>`^KF z*GpEIo>SvitwSdr!JQ4g^a?#~4~JIH7l0LlE~9h{P6<@^J;I!hYBA0p3~PL}z}vJK zTo=@nO~9u*>bfcKD-#zM*R5`9I`7kJmBwx-M%#fUC0=1Hn|cM$(WLcjfO`3!@!_oR zDhOJ$H~-Aiq*|R{0zb&nQ zu_nDz0M7vt|0>;}59L^UEoe;gZV<)RM6JNkhK-~c}8d{ zyvt;egof~9`cv9xn1b+a@gZi@5QGx^h|M$#Axm%h;gdt&RrEGqfyuFXejghY(ZS$} zNc~O5-KC>y*y)mC!nQjlIP%6XR?S-~Yg?Vd>wx&WA@`!9pnM900n`N5q6eL))I@F> z9{^RXh{zaGVu8#Dlz;~1!QMXx>!){n0prsNjEMg(+SvpTJw;~ikw6r*5dhs^@<6~M zNCQpJSK<~0#_^ho=IgVEh&quDyQT*^KnK6q#{f>OP>S6;Uz-~=ZI*uU);vGS#2uvY zlK7>bKg9PK>=IW=m*79UL{8B0=So5=806x}=IZk)Af*3Pz`AC3hxObd|y%Ze&myA0J_cTzyk1nK|p{eyDc?zV>aL% zYveU4+w`4Z?@s{znP$MSJ=GupspAI}nU*5!SCj%rt~~(;yS!vngq`Ym@Y_=`l$ifP zhyQp5FoO1P7=mZXjuoKAQ+~OA6-7=U*ct1zS3AtVdE^ z1=KIgzeq_DpXk<;d*TQ0b);f(p$hNdPKZoEpW^fk>CDkN#qT3?q6S!o{O3Pyfu%N_ z|Fff?wBWVNHZ~7Vx8&`ej-;-ZFvF=U1Sp3@6aR?ex^wmrqyUg9iN3Ssd}(&12VnX; z^5OYIcfmuqV2$+W53R9+Ep_%9FQ5JdsX%g$MuQs1`D@p~24Zl2{5gFF*{BWHevun_ z@9ZJ(>tO9TIjoug5c4K-muHRn;B8175+owUtab|R1V71vhZ3L0p1P?c;;{P_$YD_cROM6G$O#JC~=#QshxIBKOZ3 zydK#<;7=0z=ll|S06MPiETMKmHRDUgM1XLs0*6g=N13asAo{`{d|fJ}km zf>Y-Tr3CQcVDejoq4S3VkSKmkiiq>?*XM&R392L%p6zlC$vM^}#+B!JDwh z*)upLK%NK18uZi7ACduUJBpG-{)d<^!BOr`wK1JPbRXGW$Cdo@_W4hb0h!(q+hCj> z?gGXU;BZ00^GDW@Z;2EdC7=JKhn%&5cbE5E2ws8ITpmkHJ>7q73wUoSR-F?)r~+Id zYzENM%1UqLKMZaFzII<(F8tJ;1x5wv%LhTgZ8@XU|9eK|6)Zb2RIo_`w=y}c1O5n# z>jE!3w4O}vIyPPvu9-^fI0!mk@t?M`coT3@!Gg1aJclj7!XWz3ODHY=k9R&dNX3tu z;i5xd^DcIY55COzA?muVcL|eN^kEES;3;wYK%Y3fZZz{(a*L0*8pRA(j$LLuoS*f> zdEj41N_X56jP)^g;y2YA2c^8L^0cM|B>g1KGa8&pZ!9zQYrw@)K!;=AKwjT%j{GLk*+oN4u*7M79nEf%pZ!!bhBZ`m zyEMXRC6}skJcL+dmCon^ ztGU7*6x=w*I!~qjz5~Cj&kxa<)%AAdp_c7xFt=9MLnyxd5C6aNxjiLBnX-kO_K@nvMA>7ZpG?MFe?%g7+Jl9dQKg%!Rz8pLCJ%RA!;1t9& z@;f?@T~0kp)a{{?@s#W$qu-%U{at_~h4JLv@%bhSZcvHO)aRUiIptt|G4!*eaP|md zom+F=$)#TNFXTte9t`t9B`V~jJxx$G-V-|w`wn=Mx`ImfTpKF}K-Nv63iQU|iq_Zz zSkn^1cjx7rT~ZXiG$60^Aj0i zhIuAthgfbWhrg3|@0^_x#ssJuxW2^Yc={79F-E47I7lPRF3TS#VDnBV??ZFn!XG3= z(z`yFOl4@c44=s&*DT*wT*RiQx>H&mIwQ>c&(ZnZ6T1MLM5>@FX14Qd#*|3ha)d4e|kJSNxg{g26wq@x=a=9v3hS zuf3v5Weedfs?W7c%N`CzkgiTuN$2_G?bE=ypz=wGI`T-VR$DLodKWpg~Ho`@>BbEA_ zV0D!(hM7M=z75_S02ladtkFTt5oM9^G-TRd#gEwL{Gd-YfOaaFP55;taMy@cA4%Gh zO4vw}a*S{_r<1^ApyV2pe7PW6pFWmw^+Oa(e5l^^?99W`79E5)hbuZ7xa>H%mWPC; zCXD2;iiXt4o$K#3DX@N+H2LrIPu{qfv&pnNAu!9$VY5U%?Y4g3+BesuOdV0Wh-Y59 zEDPUvZ1(W&`73fLl5bQ}z!M@R!v>G_S&dS8fNMDXd4!Hfu+J-IWxjiqR#wIf3-5i z(%ee;ZWkSC+m10e9I2)4*Zmx}h+!Y>c*)}QiQVn~VE>G5_J~;7(%W9SG2u;N(~Bpn z2BmLm!8yog>b1_lOG5T<*u?a>8xgw9UIf2^Ulm;Rhq$q*wWKPO`!=H&JfqYoT zU`J60Ok4cy6wX?NFe`OPRRmPCG=|jglA>-~ie2kHQ zHDbX_W9%qo3b7(44=Oj?5zEfnwlT@7AunDn+A+R*Urq468%qM z78Up%kH4eNI{#WLsT#L$4&R|FEnKgYJW}u4h3|97*ID1YCA%({?P$AaK+i$2){s9W z$uyi&1dYxw&0Fg_Q$pSl0N8hNNo@6Fvs6v5x!@W~-V0j1spE?6l;1PTdRVAdc84V6--pX*cT8&n zwC$URck9pGR3C|n?@tgN7Wf8|AHYplw^iSxCo2Ojlt>I#X8A0WaLPQu3xZ#-q-Y#`v&x-6D;F10 z@n)6P)B<;Emr#X9Y*?0lrw+boc!~EKqgkU7}0*wU2OOlHCdTgWGHhXHB)B=a|9Hi51^kxPBJA%dvq&q#J&HfBlqV zI6mIDLWVZX$rC2=(px3ThY1XJte9Z0||)uFs9~r)lM7$NTA9frj|M@QSNi1kK9FJbZ`vI)?_B0wvHCP)O{MPDyKTQn zNH?nh-!M%*s!n6u``+LtsTm#4?C>e;v-_9qI5zE4Jjr{*DZf8|->OqMz26HMkAXZ> z7Tml|eQJafmoPG)yZMf(QUEo7qVwgI;4@lw=7TkBnk!<+8 zQ*@u*(++hGy%CS%mjeE>1;?F*8i`xw@D2Xv-3rBHnwrR(^;G$L`A-H5>(_52w7vlb zLs(1t*KlEn##xd@F&o&pg*bsb=yv>zm{)F?BuuC4Ese94eNWf2@EscjJ@-?Q>9Vlt zVmgl(T@i@-V%UPT?mTNMLyTOJPSbWpYhl@-w6-X}-Uq{TiwyI=5)2`jt0zL%3{JEj zr!%bA01>y#;}2#7TDH^sTc+65no-!1u>Rb}Z?06dJ=QY&XY@TtY_G9M0ijql-C!#G zkt%AmdC=#~8%r zT1my%4zwBzt2$OUB;-|Voi+S=29z2nM8}kd|G?eePJ1eumE4(r!&diqh_Hn&go~cT z-nmm|w5igTEL^TgcC^(H=Og>Mk$iyk{76p!4@)C5iMwn1`9>>4z|Q>5qHc!dmGBYL z)FiP-yM<}w%1W1`3PziX@OBsFC-c%MMHAo1P)~)Gzc;+zvcEgFrOe#R+5o(g_O7-- z2%+!9*|PUQ=%D%My7)izB@iiJl>DMrJD@dpxFEGn|BJeV%C$IO?9qI3js&K)rln5! zh_%E@n0#IGcRvn`YxJ|w7KV__KwIfCobpPoW^jbh5Gc(W$0_ z6+rg&TzLH1Oa*(fHwq9^(2uHqiaS?dg%OK;KJF@}_joSho-6<2Y5q7O%&eIqWLZU$ zeO4!?!j??=Nol@X^zke1IC7p-w)r1-p?d*?WhbI+-JHC0Za1g=d%Dh2fpawjH5FuP zL|q=%*9q-#qMsE(>~%&Iuu!Z%*PZtS`c-B9PMm5H_}gjy>doz;t3n)y5+|^^IN5Vv zfGG=jXa7o1SW=hYt%)ZTV5yWRD|+Ih7{YBge1T$C`E*TMIJon>{L5D<&;l*N@l*3| zKyx2Qk&f*8*5EvqvoWs0zQf97SJP9%hHEB=q0_smB1dY7@1~;z5jilT=)x&=uFs|SNxITrx|qe0AX{ar_2<6?md z`$ZNOF2U-N23#RGNA150jKjvNA>6G5dDCaRzrzT87+Zx7Z!|0E{>8B5qT|i4 z2z-L{B*E2QSYhYrspf__0L7Hm;d0jueI_QqnoA1Fdb`-;RDJmx{f=}-3*-W9@{@yk zK4Od{q$c}b@O>_*NCYuW)+XOgJdg#_u2Oqp1ZuxPEQ8*p%^;U$I9av#(IMS z_1Ag;!R|2ubN%|?S+w`~y6OY9k8GR5^HhyZ|L$le2>k0HZo&`3vc#-cAb@TAA$mCI zcU0u-uv>rK^}u|bc=)ureM!!dEtj&@FO5q@WDwqhE6Hwm=8%0R0tV=#=}V$h{mKUe zsf@J>_>B%q9RUqn9{+L;L@8w&58qs{P_H9wTAOj+mDxt`$K|G1SBO=Gq+C5-WKF*v zo^Wex(cu0AR%h}0j_S7sX$!?yF=KuC`dg{J9{Hs`k zH6%it?0J`;SA1*M*Db?8ixajD9b1|1`65;7m*n0l6b5B5hPQkm!!wU4KhsJrAm+nl1coZoy5y+@))G|P$%H6QEv}4>uuqkdHbcX>DJckHHF-PG+~aWjq)=xaoXhn@ zAK8CC98Hh2fEuzm{g&Ex$Q_Yn5{Lpm_p%rv?DCl&x&vf^otUm2?XN=QFoza49B*pW zI$L!97(u+m9#g}g8X`6ATYUT>mM={#aZ3np7cxD<+MA%l_TsuRJyv*+Bu~^{bGT}s z`1nrOD7<@`K6G)Ju(0IpBsDm|%C#vHoo2|d%IG%dmcCiF@Xal+=D45#NF}@$xZEn2 z`w3-l2a||bNp`Wpt-^?BCtugpV8MY0a9@%kVcPA8r`dAbk*O&fv8Qy&I)U-*1Cz)@ z#M85(uN|U>87>n-$?`l`?xR}mKTe%uSr-9+1va=j_PCHrc+MQ1C`RULXzaLT2MuD+ zEAVH{O*1GadO6;NI6%+_5N_Ws}!iRG2qudz)o%Hr@qHUGF3#WwwCG7|N zKuhJm+2z9lQ*Wc*qi!Fk0B|ovmhd}@Y(!WvjdxIAV<$3>&=IVv7pn_ubtRtA8;axx z!B}wXPn*^7qdW9t6w~4#*!(dv8KE*sJGpQ&p)3MxC)>0^phJpz{4xB|(_ArISb%6( zjGg89Okv3>;)PLEjq_TKYw?^bLfX(PEYdHm|1fJ#5a9$uhGXb=2%0Mu%=qr|*<6Ee zV#ZV7uGDu3;o=EZTIF&c90siXC(Fo`n%?uv4xCdTrI_BaLNHu@_;8>871R@Oa66# z#idpf$y`H5^Z)Rf&e8#gfVoy=-+P@FRo@Vqh$u@K5>(|Qav63hTz(AeStN9jnvSKv zne%y0^eq^&e+$twPQODVUw4b;2IlA;Iq#aTB!p_x4m6_tuNPS{(6}s4_j94qMfu*( zN>B5scaXuU{`HPmsM}!*sA(~kkLcy-U}72qA^-!!t|XaJA~vb!;F55CSJiBi7Xg_{{UvS z<3rVBi#12a6elKLC_bUmZ(7`&Xv6oB7Th?_dv26?K>lF?i5hLlU1Faa6lz+s00}CJ z#;x>P>sp*7mY=Th=@G_xPi7lidn$6563mr2+JF|yMq{X9`)0uEpe9J%wBYU^Yo5Af z7s2+gMZSE8s@VdypiCIz__E~%UpV*ns?_lO37xJ>Vvk|V(#mCGNXmvz`T=AO@sSsA znuA<@fVXVoA!n-jryHG1@_pZ{Zdp9HRbWqz&7o>N`vfuEWqDZKM0H9f zMR0`2aW^MX-a_IW28)rz=paSocFf_2Dt78ND))YeV(!)6FTRjBAU~ey5I9{Rsm@Nn zAbOwfGOQ*T6P|=vkt)SglXnT^_+0UQIF7QFE^IM@T;56WG(~Ml0=#8qt4B{x9G=8j zj7(q2HL2PGf|~BzRb$J%e}Rn0IZ19La2VTfzJ+XEL3o9FB_ovN^_8~*-~7176b4y` zG!r+Mw`x(YEY8~ioi5BHEkD|t{L#k|ZI^WCfD`CzC60$W80OO&&pN9Qld6spYcGT@ z+4cP)sLZEo+~~)odsPcbY{66y3W>$0cPi|8r5T1LTY{qqp>^?(kQ<9r9P8W}Pf@n^ zwROtpE`vr7zJSrrpJrD7tIZ+3S6FFQ!w};A@dZI%jMI&%G(mRS&}U*k3>dLV%P~4;2Yyci+DuoQ&H*4MHmlfZ79$q2v2tq55A-NNx9{>;8E#Y#n^Ll0* zU4h68t4Q?pLTD3SKFOiTT>~sdqL+dM?jQ{yvFg|ay?-|dd5uF?Wrmev2lYk<@30NP z=rM3YHFW2>nU6vdDak&^uX1d$pLpT;XzKpqPBr)xAtw`2$@hbILJ5S}Em{`9=y|eD z(_TgXWo1B|JY<4ffS(Gbb%Qx{eQngfIPZLSI(qX~*#&!ikYI{klH9r;JbsTYSWvNx z3mzXv?5p&MV(&SvI!3FpWa_i#LSzt0y?pDq61bb`pEaGF3M|Oce;6kD8sJ(A6?K#; zPb7p*Uvnw%>4C^-~&Vpjt&D%dcgR|e|R%@rxzvlwm zzv#Rr3jw229+QbvGtFZ`IV5n8gSxSWoF|{q)?=hMi4SuLgmlw$80}u(*Jp@|h2G;; zWu`d2;yIAoeUOcIpTtO1c^)scW$U?%cFt(AJpRQ0uftPXP_<{p6wKghq0M=jr;wqdP;-FTmvS=olqj)w)>Z_2pCDk~{!wh1b9h zl84&#+(D}5x;xwOAFcAi|OYbo2C9wRkO>yVQlhgVy=~9W+VJL+ob>w zn;LTb6O8aNkjL@mpG%W?lp8Hz(yg@<_7i~LO_wsb-!u3<8f}7n;*edHO0;xk zSBo7p6>Qi!hz4P!Dqb~|GLqftE|D;7nhBaMImAx?%-7o8AIvA-z9CNi3F!bZ?Gya8 zS8)~yHISB<&gX8ex{KaF&Rej5IjOsEPQp^K|2@U+1B%9OH{n&`1j&XO-%(~KfQ$*-;CJ^--VIW1bX*<~r2i1HktyzGiFyW&u@@DU@^6(O{zB-aikAl+sA zJrz=-6CtpMeF+}CWYw>9Z!?~X9c`sKO~m!yFOsc$g7vV?65xHHFi;V;NI|eOzqkd( zxC{z@!myV`J#P2$25Xn8ZI6i+*DOny8msqy8izA(vQ#ObI_!vjEa{ z+j+O&5!6zk2K#N6Y&m*XNG_(+x)w4v#KzB@DolWcZ2eTwZ5Ebq|01>gQj%%^c)~TV zmzEE*fnvQgDgo_!A;&v)3?8>glF#iCfnGL@EsjLyYQ9Oy% zZK2O~cR$Iid>s+nldC%PI4p824;f`h&5ue5X6nrNi3hetie-^#4WfT|K4wD(gL?TAyZUR4X`k_RsSk#-{ zcl(n+Ld$bN`LC*_UOf9m+w}tQLg|ok@IU1KYp#?8_Jo5PP$9@?g|*Q8XL5@jR>G*R zz>p+$!=YPFq1z65CL3x5ruHFMcR^Ozq5?|cWGfgtQrq3c(xo6tfXza~b?wAYReS?( z*esG>A1NYf&vcvJO(TJ`P3f6(P3Vae&EEy`bTNv-JM9G_4W-Cix_855c;ax*dHJPj zpQIAs1yP_5f8w#ya3rrgF?Md^@0LnE;15xh5xnI}eEGzi=VSuZd80pd8+pqYWkJ@Q z*-F5V%XfS*$Zn@ZS=@?2&*HBH4*qO$-ojLM?Gv;u%h2=x=!4( zr7Ss!pMTll#AMEaGW7%N6DU`WHfA{0jJn-VJp2!j! zYjjdHEiU+vL{ zIcF#QXLt%OjDEl->3IF^dOv3rP)eE;&U>!G*+eDPVNiCp$VMs;q) zRgCPoRb|gw%@U!rydJU3(6Z6Myl=C2OsE>uI=m>mL zFu$c0Qghzr(q{Z`n7cpAbj@vA*M(He4eUg6%jZ-!E?sqcD{2M@4Fd&ItT7z!k6T

c1+Ai_MlhwG?qMgMbVO<*;Nz;#z{Z?mZS}lvGb>%y_p*q#Gj|8*61M)s8HqG zg#KxTh(om}4FN`b<;x1VS5d@%8ohsn#(j#OG1^p4K^( zV9-z?UlRinieFg-6e(%zYR_KVBct7?>&v<{*my+TZv;r@Efs!BkhLgkLvu9*LY> zBtV5JP?0jwZWDZPP>NoSi>~0*M&-)1hyB7*6U?>T0J|vlBH>&j`4tNS9fcZe8;Z^p zjVkY0oy}3lu~uFJ=$bV~WWU#&W~uhTo74QN`A@rZbyx=u!7ZCO+Q;Y=(XyB$Jbd?* z=O@SwboVrcpXY#v5TLjTOH}JddeuSekN*B-`_GNXQ6!U)gisI>CqPT&iMz1>)%B2K zd9UaRY5aTp<>`U*{NIOf_ECP@erbdl`+IVrBcA)1qV1KkWA?i({DqtOj%uxVP zmJg`SzRHFUkdPc=`-M=izWVl3W(+)D0yt;&`w~h<=47gjNe%%}Y!51&d?iv6dj^ym zi2`vcIBq}i1;lSKzy)*?zpZmIrK8}tc*C2u-!|_dewP2}CAhO`B-vzim8CQec ztHS2Jdg=y2C#*DD@L7VVsaZg06UwCeZ!v^*Fhp|11I%8(Qy{$zYQS~o2loBlYlD>!8G~ybKsGa+vJ(rx3Ue<=WRTAX;#JQ%1`->k z%ol@EltG+KXvrf`Vafh|(Qt4n;$9oI0Z~JBm=M&I^#S)VJ}Kz$$uujVpO&|t6dZ6+ za>ypK$`|K9wg%c<=e>67a4%11Z0)u+lYNCOtB^vu z)+at$XSQdGKfsU`vWt5B;qG04M{klPmWimoK8ByyH;eV~P2bdT7Ehat?*ot1Y^}G763q%fs zjWAa5o-xW>MXmZ~HTdIOj$L@=@pz?V1BwA6a18t^z*dO@@B`Pu^p71h_KYE!r*2sA-V zZQ2QPJwz28AnX+NvM)%0+2{Y9+IG&_bbuNnsVz|YLFdm@5Mn_A4e9qNU98h_m;ofj z0-W0eSimTJp=MYErn!sE(R+@ZNua!aUoy$g!;aTeL;(WX=x5hg=Pe#={d#F83aTh-PeW7A_ogn`b$spASJQ?ei<)$=4?<1~0j+IJzV+22r z*VKinojp5oJ7oSYN(FzNBu^~ox-am(2*(^H1H;3L{ffS+xWZO{yK%nUu zW$4kR1(OtTLRJzAHiE?zPe-pZjgcSA0IubBO~}xmb=%yFY|Fl9ZjE>FGsm+c5Ovfu z>ppz(AQHI14b}P4;X8a0|I(mAXM}1#&CfUv_u@v*hC=`{yF6sBz-IGK69-8JB(TtC zc5W%G965-&G0PL@U>eXWE#NhBXtcXY20eAuQM(;xaHR+d`u;=t&UzUKF&3WlhYWsi z$glQrmrOGuJa6cE&6Gc5tn{%&2?-3uYTQYMtKKjgmFYVJ5kQfLU^w^8q12d_-B5Vk z^|A$^fuhCtvNw$-uO3g7RR`T&jud4;T*?OOzY@JqkJ3I7PKqyJxq)$5#j|m(IjV(` zy6H|u)%hRW6kLFSit`Sb5u_XAF@%T}j{V&Odsb@zP-|*m!diR;UAL14=^2wlND2L} z04to2&|P-c28o2yiX-0%Z~AK5h$){KO7Dqw5i*(Va#g_;Q9U_h7p7YE zXYSt%e=Gw7i#iz+;r>bBj`~QU3}~O0o`d*Bg2x`u-pa03hnl*%eJE@>h-Cbf|Dkx} z$7H-x99RM{jVD_m>5%H9T72Ql zexY3RL?7$U;VTAH0gE?&+4bB2`WVZFHrh1ggrqZHL%z42arutwMOfX83v(#9nC=3K zosvc#(f{w5-vu5+*b%|PU|M%!!`|D(R@GmTK;B6ksxD`?Q9>YOqq{)%2tdgM=40j6 zlx>J-TS~h;<9~7u&zr()Gf)cyYWqcBZCfe7sTS!No1rXs8ogK$ow&yEH_mv1 zzBRLCGMD|%bLJ}xs=vjc+zWC*wpGfxWn87uxSXC7kNjRF1ZBZ6T$Sc`uD~U4(uM1N zd}~QQX|q77|KMoJg<`Z^M#+LGY5N~Wh)%Rpj3>Z(|H!>lKyx4}GIWev#f28zU>D~q zn;BFB@MNH9z4xs=)0vOzJ|h^SD*F-H*naq<34Cz%y<8BrJUTO z<3j)dhqA4lV<2x7&n#N!YI{Uk7;rsTx+5~a+OV@b^VgqWh3Q`4NgBXiE>gP+_LasjgdAW>yC_=LRe9T;^ zf5-J($aA3jwc%$LantS3?k-lN(s2!-*p59pk%NoEde?efLTJEKXX=P*3p2d!D%miRE>5+`QOQ*XiWoXZTL9s z_5671zgOU}+lJS0*G5@qmI$#IY6yAt5&W@?toib-I;e}77zU#6UyvO%dXtlhvr>I8 zs#Jx=484LmKa)A~1TSz5thcj~v+G_NK7OqRiLjrg*5-~(!X0}dUOJDM;!dZaD8;Nim{DxP2@*4A}Z+4(}>-Pqf7ucE*uXW>2^jE}OuM-ctH`QK!NPNR#QTK77P5fQ^1T}V|=WMh#fv$U7Jos506RzrW*tz>W1ow)$H7e zr*l-2f~vsITl1TihGA122S8+P}}k5rrR)`FC#`>48ZADjeNpM2#kSr&?3l)xmjvRy%eL+tL~6^D__bt-Sc;)8 zWDZ`ujlbC+^IT^;NccUO5fg&>(xlE$$Gf zDJsWdgTF#T%|#!1qgx(&HcMUWXbXD|uH3VZw}b5ixZ|Eyq$%(Z%t42kvh(u2!& zd-~%&aKPmu7W3O{ebTe2tR6^V$x=MIHZ0@2W=RV)!EwKsVx$k&XX>RLl%_ppdhe=U zXgD4fiL$Jb4rm#mzN z%e!G@hqqi^Yfq1#TONcpesg_LDH|xMoVzd1uU<0GE?bb%Oc|@U?Ls~YfP?r(rgO(8 zoa>4d0F>DyREDlbD3}q|-v>3N8-26BWH#3mBR1W`bTNrY3VT|6eDcxa@q=C#JkkV) zpb}yu!eD4kTYsGO@=m@hwU*s3KUD)`#H@2$LbuY}Juk}OBCEA$^LWX<_w!uKGYIk7-4m_5t)nT| zr8WN}$3dQAFlyO)smh&mJ(a}2-ZC5Q_H^P?upnL(D6bR8`K-mWtx+1pVm0g(?~$q?Kygka6RKFj_4>%cj=Vi-<`> z5AN@IWsTDuj20fW@fYokqLcCug$~!uVK{l=^C1ioY!}}B|1OhgC1N@9NGE?h_}_IN z08*_tUpMd6LZAj@)cSNiS~{Pp*Zi6jtJwafp|6xWL=8n7?YeK`GfM6)#Wa{jkc51l zH{rT=2T4^3&RU2}Gq>6GHsn|ga2LOxFLJHYN2WJKg&x^xbd!PCd)+m&A-TvkC8{%%oP-Dh&qrHu+% zn;ZGRG%dl<8Ut&{(EF#;)5lSeui z^VI+mfJt&dDrrwAgPoP(aN{{5$<%p_&WwyxzB=sFi^X^oPJU$G;$M64@l{ao^(!L@}DPRLE!s_Nb&?C&dnhtrd9OE)rEAE`g z>x*Q~I^0vQnAeGG3?FyTL&fWX^8oA#?xXAI>kEB_rD-c^{GEdNIz{;7fjj_?hqs`( zd{*3)fjb$EWj;ni5!O{MMKct(RE0Gkehb>kS!>U=Iwx7!!gO8F-5n2`gwH0eRYy-4 z!XE5Ia>-nq5RjaQ5s=(9?+_f=(WHG34(x!-V!%OZ=zMJItqe;d*bjn{HRfiJj0t$c z`~<^({@Ypj4NY4tcbAXp>Xt7j$52VnT{ll-{ zmsJF;@0K#!besxUC$7DD4GD&qp@u|~==IY+#-go-nDy}eN4g;b5BF!WSN@N!zAAd- zxOwUC6<7iQ301tJ8J2RcjcaA8z<}xG*!F&`LQN9<HV*`!G!#7$+`+%ThYkJ&cnHe_-hX|83L|P+Z_{ubiGX6U;cXAZ@6F)}b(B7{ zx|R|61jK<9|5C(@>xZi-fK9g!W#k*6=3XOSL_OhP)Aygy-TqGlVnAnZ&;Mz#i4%kc zSNb~e>=vO)Vj2qlG2$e*D~KK_ivpNQH1U^$f8r-WDeK9L_X0RTLVnPN2nZff*Wx%G z@3l!b(}7??z1P8V{d<=0KwWPv2GomCRgb0UN0SbqF2eZme`Pl`l@@)3s*e78ACNgR z16Y#~u^xE#pQOo;p~0N%AC-h#uDSE6!C=+DJ}PQl|M*oPcr+?tQlnTm;;B0_s9h55 zt`nig{2*`qAp+4a)cq~#_3uev`W}cs<}qi}1RM3^p_Sx*i{4Napdf?!@8tkGU%Pz; zouiPnZQ!SKNjRv3UE96ZlG1HtE|Sd2hW`vj3ar}r=XbX2P3K60N5?3T8WKqOV(miu z-55~2#QtB-WrqVIUc2yV+(0)aU7b3)l&cCgVO3501BC20C%&zSzhgNOi|>)_^p zY%ZK*;8NR4?=@0~a2Goxm7-rUn}5hKk0gi&*B;==e%lnQ<8JRbC6X~gdSlRGed3st zySn#^j8TLGK`grwc|W}D>ln=d0B%UxL8LTzXu}=~?0BAkK#mh-2pmK#$v~F#S_7)$ zz|wBLng9L+=am;smD@D z-S&b`tHcRjbK;bI-ufZrk5xloc5k`|0owr_ud0IFBq3L`uBDKP?Rh*8myIZo^WOpc zbDww_<7RS0b!&Hp8ubS_8Fe*kKAKU$JAlu8Tp!}L!)oRPHhAvXjU&$lT%AZfr&P(b%`ptD6~Zcw$t{`z{)e^Z@HoHxTZT` z!Cz4I`Tm0@4?hitci_SF{0Mx&(Z0!~vVQObdZ$A@97#5=+n#cMe)n|D)aoV8^_)T< zWAuEP&uQ4Tumfo{8FEfXFtGp=HvoI*a}!4?4ISu!970~Hkq+$1B9Z3}V0L`EMQRD- z3dh<7*W^V%9r&g88o5Dhu0B2WiM}6oW)>WmWt)scB`(VSEr4gmBkl4Ie~X~hsRwD zXB&4_FZKgw=>mm62mXoY0vQEoZ~X~S)QTGLV$Pcw7q^N;SK>ZW0qd~B5Pwa(A9tge z_RdMVBGy4@%c0;CaP)QTOH++?l1IxH?d(D<<1$V9PRqixw!L9G!7mQ?o-us`bU}mq z7t?#vU^2@k1I*9w{X%gT5XQ$}3fxNIRdhr@4}Q#$bf~9#7Y_@YEI+mdEvckp>X81} zQheo|aSM9RIfMGFdgEZeE42fVm!1s>wd7@A(;0}m{f(%5QJ^xQ!W13T!2p!F8H@Wq z%K_0V_z0oSB4AR4a0f3#ol*U&#bzr-K%v5A!h++Vd~Pm-8??jQAk%F#LHaY%)-d%5 zfR*M!iAJ$ujNv{kh&$~`Dw$&E)~wh|&ktja=YVojU+a&lcOa8&6EXwT%c%~BBOe78 z2tEi)1v>ClQ3>nVVQ1cR@}F0w)F{?%~XzrdDF@eqo$8}YI0tKc%WmC6tl`VLO1(^aA*}$c=qFR+A9~-WWR#(@5siU#iOvb` z?~&Ald|dMbQbW+*{nKC9(O8HEArgcqCFu%o?CKnn$2lIq7+85Mg7jW4(49D(%Msbs zJw0%>JkK(`F>bZyaIj!nCw-{Yo)$wE*)d@2!qgGM)DubS#m z0Yd8@{L~~R*{9JcZfcnANCBdMq8CCdQa8I<^BS?+F67)UKP~8#k-lbfd+=CW+LKM# zXDOR`1^9eL1voc2;Vty%CRUCH5Wzt&O#~Rj{mcC1Wxzqj2X`QVU80*hF^Y|R-4+!| zaET1F?Vs!w;9NQUi6Wxm%b@f$U9evnSL=*0N}7m?oDbbcvfArDDOZ2601G%@p0pV- z6+1<*{lh9Njc;Z*6%2I-(JQOqgkBrCj4x0px`90#h6pN$NdXHpyO9Hfg{MFpR0ayy z=jtXmweL;f8W{ko=)xUfhB^bsX=*gu4UCL@Eh1k>eup@IFkkJc-w==O6@b|sLhFMV zbjha2-z?GrhajHsGzRP>Nb$@Z2h>0X2>51e+q0{XGTb2A(f1adAIY#qF8A#h9BI$I z1MnHRa1$!fP{d()KJZB6vdk(@@TGv*r2l!;!UseK%&4|YbF3cew42X|l#BCTYB`*{ zh*TmN#pj~L8bH|&F>v7_@D~Y@di(+>@IEfbD@o-#U_&GIGqCPPvtfo|aIX zZV4@7%qgK@{3g8{_q8ftgb6nmw~HiYM?b1vD;7z1lnRNRZc56nnv{3Z}gV> zE!|P)VY_Yy>*G7{Mn#dsNZncklRjQkU}qO~aHWJCmvUn=syKo-nz|io^4>mJeO=0+xNA zv{rF7H6G^|j!TN8l{21lkKlDY-w5-@xZz$)$Q>uGppc{jLDk3$t?8AjA+ARSmZ7=R z(@VxFmsvK*p1$=H0=YR#NP?h-1w7_i)4~fZ&`%J$py|TlP}J0QCk?$MKIX=jAm8sAEa9tcm7>>Rvw() z|9aHWinRTbA;LX#!ShQ@8cdM#_}&TeNrIxp4-|%vah~26H&6zZO5I(cz=v?I0z!7U zm6&V2_t^Fy54#QCUmEXMV~n{_u}W2cjL9ZoMfcnwAl9mvCT(<5;U~5EE|+v;A?tNd79f)H5l1D?oH56H6JH)X~pIOMIxK%ySy;EJ;)!@}W zEH^7$qaJj)H>@A)^rPB#WZn~L6PC<@I25PbCIW*L;1gGa6e5;)!1L%K1Cm3)@g%P< zIC`%F30}kOGR#=J4O@)lTq)H@n&4!H(19w06sranIAMvbkQkjp6vC-cET=FjZ5AGQirNYxzoQ^Mxv zC|f-RD)-Mc^m0;=+d}u)oWs+%F{F)x^Z3#p_XU%{RZto7VE;+ge=R5APY~ZoD-ta# zYt4^Do}7s_h}#M+*U|6(CPmc;_t7VJJSQ+~%UY52j#?BS^;|CxBl9+Rx-2(H-3nI8`%l>$ncN6mW7Gr&` zaOD0ws4S|piH>Un%zl(l%W){25rbSq^gGaW3|vYIdANotubY84GJ87OnxMwV$G+Fj z56n^m9>7WS)@mkxD*yFsJ}(^L|P2UE;ppV9&b?C5_E)5H;H?QCn&t3 z_ykn(b!CSgK%%cfByP?0MQa8f03>nmR~FI7VCbt6?AQiPW<;uIY~e6E_I>Jj+(*Mu zKHF7PWDVZ5_O>q64W^~zTpV54ecUvkW) z@j2HGHy_scZmf&A?-0})wJvZ`;Fr{GkvR(7q z-Fn*Nk&dzAL~#T7_wz(!@W)Sf!e2pBJ_pg}?+?EMiYlKMGrWgetI}=i6_eLy~ zS$6+)TCH$7TXK3QFjD@qcvGp`MR|k8IXF2rv^Z+9%|flz@{5#>htf{yhQrjWnhWrs z%8h294L`Q1qaGd33h6WZ`Q14OG4<%1>S_VaSD19zK$%~rnWkdMh^^ZTol2YE1-e3a zgIakU7G*;2i%4mBFNk?=Z;Tb|mVVzb^65iH`*AMIHN4)}We0JoH8T3ANBYOlj8>lx zq;T!ohMum4-1;$S4LT26QhOIIT2kWD_lm`$EOa*h38BrWO}k92lc$GcK}inp%5GFh zM2QaBVDI@`!?a0GEN4X|ZACmKT3zV3rs4-;;_?T38r^w%?Bo_SNjhM4MC;J|tBtI! zKFABc=|Ub(YxQ5B2#=~td{_o2?Oh&M$8U+qBR$lD_O?n*X{r(0ca#Lh*+(0m>}>_Q z3x(&?Xdr%;Ol?jRCvusWi3*rTei;2Z7-$jHx5~Y&&%?tb=y3X51erYTxDPKsJX&9> z&HtxuQXmxC7S?JX{-iFj!9Mf1zJ;emlY3cp zs-lN`X(8CpQgGw5mp097OV)G%$*hVZhD)Ytt>|2dO3p`q0aR}RGSRATvSB2Sy z2^t)2Uj9OwNpSH8rk#SoLuyZ;WqT#r9jc!s^XggVBUE?aWlnOYG_9Q~ ze(=rq{7i8ARHyLmd)-l_N5ahZcY8$Rp-=YIxtR3#zVVWl$@^7D<@;Z)x4bXCJ+}Ps zxH4yLFfZu4H9Ye@_uM%6pvpZw)Xx3Z4Pt*FfBT2gRVeOIHo6VK_ z5&xM(?aG8pTg%g?#>0`(a%0EJ@6^Hyj%2~V!K_65Hgo9jB12E6t#`Zr);^z$N-mr) zkl@1edW+io-u*&Debo6k52*UcGb@vM3@aBxH&|f@@_lO+v(^f;N6Mz5gE3|31v*2)Wmv~aXu;Wv2= z5#-r%Df+n=gvmMbQ9}Ep%tzitOEVMYi#t`s<)Z@Yj7Z^WL3{t{!BXKiSTh}^wWM!$={<+Zi1FE$(XhY1@l z-UuQlN1aD%4~NML`DM;FNB1CN^3k)CC2F(hN6rXIPkoIAv5j=j*WTd-DWYlZ9O5z% zo!!HUT;3IC4ePNr9k<=);+pkeemn=;e-LNLWx_A}wzQs17o)rZjdeRX!#&fEqaHp- z`R-Pk4ZGFLr-{$x-%M_vRHkqnhB0^}&m4MdkA_zs+fQ$I#kqzpe0(6i643ZL=Rw#e zLT}M$+T*DyTVEf?Olobimm1A<{jktx?U7i$V@@*oQo;0&kD}nhKA+iY_Ex`^kET$T z-G;ogo1#LBEOpiqt%!Gjr_ov>)^6%|-+*^)O}0cq{Cs(Q4xjV*4v}w)XISPN-Qp*F zK=`thvy1@Ey2?+`(V+vJLZ2C++j4hZ^htM#0p#yVcB>&5rIF+bo9Qp!dpR~p#e(<# z!=gyU?Lnt0-1LEqlc+=_WSvi8w*FK_tE3nC_i}SoPbTgs%c95Z4Um7k2qx-Fogui3 z#)MXbWTHD(9{3l!6;#JU8nijp%%S73Tt*-3_HE-7pMpL~SMORf-MU86y>FPVTMYMC z_DWZ!5R)42O5WAS2RmD@^v;GJ!8RBA)@{-Yk!ONa_O@F=B71+rlt%)@ihaVSdoMzY$uGSw4jV|DuA@Q$g_i_7zvzzJ zox8guPR}(61_GHqWtY_0D%O5=jch2{Xur9bSj$Ab7tnh%opN55RARDQ;mBmxJyxYR z)1R$>S!W7EaL@4S>7UKe)yj*!5`@BTQX|v?C{%7Tyb_|NZ`&J3 z?F5;!KZDE4cUO{BJOKjHCC$KP$r>}G^uVK0So!LI4}$efP4cH$76g*UA`>yw+Du3y z6A+#p?sA#py4gEZ9W_2Z?r_wbc+$J<*F4R-e9>U)n!MK?e#LzVPPwtF$qRC|x@m+R&%@J~Ld?-VH7I z&Sq!z1eXh%XQ4q8UNvqLkegRIq1%}HFM!$p=`F*6kkJxO<5yL_R zv7JR)GcTEXhRfsner;*w33tev;vZTZwoSjgnX}Wd8T&#{akc78Yq8xAi~7@nCnD!( zHzsV_lS@>IkoS6@^J^$y!iotldu!c4{CRTk=wj7~bF@OMG5)D@H1AAC_U!w!;qhg@ zm7>Qzgd}N))vIkxZOD7P;np9@;*WoL6U9BxKhi0)sxGMiD^-8iCa+!Frm!fbwY=?- zfU$ewhavmM&8HCe0w7mS&=ur{rr~lFE$Q6 z`Gz!H%%9lGQ*`92^Q`6snXVqPDst-wQDi!r77mOVWg=4g*mn-gwc8e$@n5zpZ8(h| zQ=F($>Cb%4uI+_{~llPx9l_m1lT$7wIOmr_85ElU>fuFSb0nW38zi=OIa6 zO9q8`5;}d*N2Gaoi!aSKAByZPzM1AVPM&ekHGfghW!ZIrU{*Lf#9J1w>rbW_Y@5;V z-{$nu&NA|zIwxwnXNo_nLcqCgRvM=)WSgZS(Na+aw<6>{M4HTM3gopbT_y`iS1Q!M z*qiZ`-Vkz9$-G}b{7r+_S>LwE1D`rg&rdqbwZ)8MV@ktSm`}G$BUWs3EUcx_{d^+? zd!;P@W{#ynM6-oaE3_aM(#{-=hWV3{39J4$)}8tnTA32Iui7}gNIlYdsRiVha8n5_ z#%}auulQNi+&N99^yq1?$syzlw;UAPH4QxTvo8G@K(Lml>#~(EaBNUV^Pm}+>*eLrrPrUkEyl~``O$DI?j&U~8*T5K zdwOSw!;Bh)8ig}7Bj%pRuNz)WRm%(YX?m{)GA#`9#rol$-jxrG(cm}kej0CXqcb*! zf1j%N`L?#~}(Hz4(@UFqKxWJ^9tVqPUVr@mX)5l-}f6mVV>**O{cs zSBG0MR=4YGSF1QiN0ARabBxZG;*Vnz*}U*?I&iQ!gkljJ_-eMiP3224NaLG#24*a* z^mo&Lh9!>t>=`5y?KJfR4JOQ2lqFN>E8(xNcYX9V4$yBpoQo1!_VGVoGfHAf8}jAw zaviyGdv)O3H`%+7y!E=f@u)g}4BY;Pzv%D=FQtnQdUmkY-wb{9_7mBgSD`ypHnv5f zb^^;Eysdle9!nhwQEoTY)Pf&RrsR*_{1n!cp;9wUOJ408Wq9kIl1wf5ngK z^D*%^p}XFa=2FA!f6{2-@YjlAANebIe2VaH>oqgtYFplPsPdBJFoBQ>Nx!l%@v2fa z3X5Or87k+<=MHZPBGz_~EMCU{EtRsi#37-PbF-xNes93Ao#^}uyk^mq`z=p~b&~MC zSO0MVN}rSTk@LMu65F_XvKmJuf!ogIk8cjZKBYU zVX}MSL|y|?$?22j9watALI23%>~LeKKex1kYDBsn_BG|y83EDZFKoLLwnt|K(TIYD zDnih2e&kWO1cS>L)9|x1RAIz)d zc+-yV0~0xbrL|H_%wr4n0NPhjON?9q8~Drj%jw3m;EM4AQ_*v~+w(>6wJq{Q>$;ZS z`nN&jx?VH*^=GqpXCD2a97R6<6UiJCos!jxzph$c@ORndR-uK}P^RTKvZcbIGG(ga zQcGsoYIW;IU3_~=fnGYu{<=%AshR}pi~iFVYq*AvF~r zZDyv_W-y$5JnPKGxTy;hpGsh2^KckwT`@m-zJH6N2W* ztW12Z_i(N75zKlS;4*{ZUY_spI`QdEhwS8zW!49%WQhCBRC|$qMQ3FB z>UeJbl24g-W(t>XpYV7YPI7!~K$w>PteBU`ZOy{;Sa!YiGjAS!K3#61M)D~aeFP%D z&hNuhiebY&m;DdAPD{r(<7FqlJ`)<3aM#d%GMJ0LZYv(eZRLB2m=w=U7Lh!o8B!MU zbl$eWm_6BZuQ>}1D{~4|OO7Dm&uDDZ9higNAO7&B{C0Yc45Rb=4Pm5nGt;Rk_Woe} zLV(4Ecv9VKT@k}rt>C~FPRYP>2J>+)eEeK?vnKm>AqafA5>s7w?7{f zzdty4Pn4MKjk}t%`>7~o97>)^(hhNn0lA|CQ`XN4PI;Jz%7RmL6RX&h z3S!(OJx@bQ$1w!dsVa4jV)23$tGz>+^aL%FUTXHBs*-F`nBdBZY1~Tpo$p<%#Bmc= zFRHqjL;5Qw`Ql8Aw0>6bPgQY?c2L!|_8OTS|D=-6F?1W0u={)87O(cT3!pr6mskp5 zR+IY8EhBw5dq!gs?;p&Dwf2W{s+%7Ft2IZ{D0p+dc4^WNS~+T^dHYQGQ=A8!>JN8I zB6}(WunvoUDA@S4KpzF>GYN5}=Hf~zMN(tn6Ip)7+n196yb=;CjIy{Aq$ISTJ z?ZOp~q)&MBshfwRq;oEPLzCfWzk=lJTPJ4R%8Sse$L~!al*&_rOzp}R>RXm;7Ou(@+ z|MuIU%R`-|&R|WSSSPLzG_D)po_TXY`4kfKFVA!BM2v)(>WWe?HY`1let#Pc-p0R_ z`1058Jf3!`>#gL5X=zknb&>cP?NH(KcoO_YbtGM9QZl+OjNdV)29?d94XuQj0HHVw z#fm{CZHKnym$!i}5HR!6eEkaK!VKgB355rXX8nol{c|N3hsj;+NeOO8*QEfqgKgS- zZj3~FKE~OmDmEore71kB+4hQlnAY6ObG2-5yjXIW_85FEa`2PBZ>rqrXe>9(+wP~w z>SUo&a%xPS+fMbj8LKzk4|<|`TI>UoJP>PV`@c8!x9*s$V!z~aY?Hg#n9=<4An&k9IOt=Ij>*>DD{W?{>SEFV*IRUNU z@4>1ZpE{b_iAZ+0C~lvyAm8#d(BJTciskD~uMFo^sFGA%tYpDw@^*4-~mQF=!Gm!X}a6#gO0t>^7*#VL?t-~a0 z@Wg7y!_z+b#M(%{F|24J&xd}~3DHZNuOEPhDJggZOH~1_K4N|`#!S$oWqRs6!;^h+ zIg;nxbVSe5U~@K&O;8uUO3Bz47>*|S1BiCzK}TiI9UN*qJD-pgu5O*VaE@s#^8Rl^ zK4teY<3-WX<8V^>UjH)b((I?&T;gSnFoa|>ym)#C;{~WpHV^Ue-?}==zonovP(B8+ z=2hIIjWWAGl#2C+1sZ1)vyZAhst81#pi*X4G)$O+m3v=)tdK)YxDf9X^)OaK_LmB# zV$=D4F}5Ljn0!UE9;+x}!$%l=Ma>jzItBS|I+W~+TS8QL(R1CsHvX3K{5>@p91{!V z5ai!!i?ASXu$i7O;rxkit>lZY`z6!&=1?pssU~(8t%%Ijz~j|hzhp(F^O3}avh&`A zg}3J2akKzsyXu#k5-O0Pd7lvYLU(bn$cp!LOoL{1-TvCaj2as{Ex9;yKB8gPd@8b6 zaR3dnf{l$C1r|MSDqqR($Nf~}9ggqPC21M>1)ko%lEU~38F|Ne2lop>rMW&r&Y^D$ zCT48`Y{Oi6r7mODao%o=9usa+HWs73J9FHm_c3em8HK36K7n>iB?k`BVXWK^h}2>r z-IwCsO`K!-jg1TF)_zb@(Bbi(-ni+&yQ>gQ_D$0*iItHk57caBm$2okpWiJl<_uKcE!)??-w&VGwLRvf15n#o&SX|-LJsjW) z5sXk`1L(4*1a1I2Jq!(l$QOzMgh}!_+KLAk7M|~QhXd?}1cSVTRhG2pJ=j{4Z>Z=T zIj9Xo8KdpM%lLo|PIVZ4N{7;B@Vh^y0qc!JyIE3O&G-at>@f!Z3bj1TA1)}k)C4?U z270jDpG+jc)(oK1v?x_cqErQBOa*>! zv-r661+eNw;RFJp2zfNj@#!fN3a~LCK_`?1$sq&S;AJ=r;b1$?RT1r^(r{53`&~0Zu--@TcR;Chcfi`w;6r!J;!bgJ&@dwTpl`wZz(4&& zy@8iUi4Pw(=j4G)0G8;v-*19$0=gQ+bDj<^XO%vaXR06nj-I7fym)%zHY;W4(O$1 zWP;c%+h~!q%z_(L<|lqW7Xcw+Vkm8NdoGh_I-$k8Vm0M= zqGoD!iNZHQpe7I3c8qJ2LR9;(kG$VAT}`TtC998)kI76DdgbYr9yU>K*`r=QQ~fwx z2jI9aDIi@OIVKk4P(Vf=|5>?xUvsp$);>G>4v1O8aD=VsX=fBn7~#BqB$lg{lHep z!!643Jp9n#!Yr>MAEb-#&W}~aOR{rs7 zGR$e`=O4-fxR!DHW1O-2KHb$ky(F~twh1C2=M4`OaI|vk&|w^ z36t9UtHZU~BRliYE%(=7%0Jy1h(D?65b>xO&2OCG;wkr=B(hiJ>>+efw09`E1#)LD z8f5@OJW5%{*!3@%`*~{cJ<`GTgo>>oG2TsIXqq4b+xuYDS(-{HM=v)-u;M5A?Lkz? z53tp;NeOr6i~S3)jfJRQ^1KBl8tU;hJ48UP4K)h?uuXz(u+A@pJsR5bISbVD@D7Z9 zq?HSd?0ezXv<5cyfbugcLFr_%W260P+S~nsnS{SZT)i{Sd_?{Sd+!+)RkN*)svw|% zASg&i0TmGt$so{xl7onngNWqNWJwLS2&m*NIVZ`X$wA2qO^!{LoO1)+gsf5tJa!THEYiKJkMN)#8mmiXwifI?d$qZ*vRTBP>~#bHKNLp86>b- z(|s(S(C{Lg{%ZBhZ^lG=Vz5tjn!D=(~X{hCv)|x)7MZ&*#?;5)KkQyrhBgA(r$p< z$SR@7hRzBiCT6wruxmuOh_Nwr|4c z`mHlX@I@3CHC=#sj=Dx4;WFOIClS~feKjZn)7|Y?>MLni8o;GPI%G=Eq|8aesHT{=z}=+ z13_#ot={uqf)DS`JdLU+}rg%EG9CW z`7C|7*6cV0@Wi^rpQzU(uyU#XR~PI|r<-uGqbM$REK#}g4EmG|q-+%K=_-azkznzM zm42)q(c70yboc@`)s0olWgijP6?GRHl6e88ud#`ms$Vn5?+PMU4+Om{@?#6ft*50~ zWSrHqRa(uuP|VBwbJ+`Kr&L!vyJUI24#kQMiRbvugZ)Af#$N6x%%|HO2TnU~yu1AI zhp5UTkXgAlO!zTqT2@%I;~l5FU*jW}})BQ{RuAGpvl5{pYxcdz0xa8&t%tKE+_S^KCht9lCz{=*-)-enEiR z1Ia0-Frdv>a!QbDfjpCxIrx=|F)lfx&z1(MFvI z6hWrs*RZ9@v^JqGvE6OV#+r5Vrd;6kO$6L39%(1GlXGZdKW19?k&KD=(YYHB-WbVD zu3-02i=x@Wp~UX!fpg1O_!NSQOE10FOI$UgFfQ@@L{^q`kY>)$osE6U(g2U86UF{i%X5o-D*~8ui>aO0V%T{$gJ@q+~E}nJ-jwPGV3*gop5=)UQ$4|7l z3P?4g)9nkQ*0s|1+Pp%c=PI=a{Vnk_-=K}brS$PUUL%89+OyFypyrzDbsA5){bqe_ zOcr&-v9P~D(<_`f^^l0ztLiRhMlt!z{YQE6pAbwpNhe_K4?L4-Rx4Bs;| z!R8X4h?#o)(05RV6y947Vq~=6m+2IY?xk}+yOTBJupD%Q_2p zwgfaehi0&~MjF8zN}M?EaNalZ%6;)?YmLpXx|6go8kE=?T^WmgKV|1o4otEgxrtrX_LD-3N%q^W%9@*|j{63Txw3V=EKpapW-oBbRgUQF%P% z?D5hLnn5%ZIJibT+YvZdc|LRXbF0V7>7A`>GJ@1~Vdu?O3+3zgqiyU`P(HQ`^?kc= ze)sgC#;;eZp18AIl<#n%>?O2G@W#zJ(Tr^Q4mA%vrX8a4`bCp+Dbu#udC5~vJw9Fu z(V^9AhP);jn$wk|mt1|DhyjNV_F?If`Y3_AuJz>p16fz%kzKLP!5<=LgOW8?tFm!+ zXC%u+VUABZ|ju8LnDq z`q8_116tHrs?<(D{I*{g95=9X>yp;j$6s=G84fmC?2pR~-M|?V)gDk!sS2ED(~FN& z_Y=wYW%hJ#EeG|VvK4rw2=>Pbo1ucl<+L935oS_;01h;AlWk=h53f4N;TBhQF#xli z7Ba3IX!}a(x>Dsri>H8xzZ(dBY&&P$N-}?c?y;*ue5`}NKCc0FG%e(VUUJ!96 z9Zxnne`~(m*l285Q6lDAe3`7E0a1`*r8}5cWz#47Z2`HnMgi(BMYy_4iwNtD`jX8H zJbHLE^?izzP}?|qxAp7)S7GO7AkUQylH;v`}UlQ=j!nnQQDdq=^3 zl>VRxMdCHdQU!q!u|R|49Zw3qb@dzH`?%Pd2?i>@SZ zF`zaACXl@qU>>}oeE^0QfgQZ?01?b!R(F(NI@xNZJg&Silu9a*reauk!;k>4nl!?! z%(Oib4QF(-lN>7`ivC2@qp~?r>7yd%@d+)OlkAROW#;u@synAFs{0rff7I_HR=%@T zo2#C^nA;uoH9h3iJ~dckx850ri|guXzN_hib2{mRO1*s{fQmT0mk-HwRb`X;JZ;4|6%Z%Xgmv~7T_xNHPUrfUbDt3lXqLw z>875ti287mCYK}->p$$&tiu2KFZkI$ny%C7;G_0b+UGN>d`AXrRiWu0Jy)ZyS>%bo zaA{wBpN0$kB>x%smD7WG2b?{a)lBr`<)DAF4VZEjLjhSXANWMuXV2r~Oc8A4N@?1f zeI@r+uX>EWgjB^*T;te4TA4~*;fR5O#x9@6o8Q0l{5naLyz^Qh*Lr439Br!9H1#C_ z@d#CA^;Yx?O^3^O**y)bi4~^h9ocx(!Dv)>ea?@(W2?KxNR@_zMYo#O-?5q3_QVB! zj?*~&^UmK#7g5 z0lODu%6e_C@PBXtDv$wq>3;=y!G_;Dz5rr|W&%^)@?Q*pS^G4}t)yOPyh`@X-)ltz6EiCpdRH2BxUMQiCss$d-H zTimJHZP@ry|5|<6H>c`REfBnx;euDKnC6h2J!)>>m}ZEITz`Jccj6wd9m}zX-ToK# zr)>^JCZ>^IUIVr$7XYQt(ZR}pW=+_a9K6mdK`Knzwi}?9 z-Z#*qdY?FsNvN{%hHi}7jeVlCW!M-}hX`cNietRfo`Q#U8BEoAlfFd9DD3R{2FY7d1Y!dR zswRnw_w%Z9qIZq?13^krgceIl)+n+a#4+=t=t_{Ln#nx2%OW;GkGJNyF1_3m4-YN+ zN{IyJ`lqy4(r}rzz%nUt2E906AaF!`_bhxls3p7OfFO+w#oUa8eZ8L2dG5S$kq1?3 zw!lTH??ik83K2z#=~mp(Z`3vm9JqKq-}Z5QE!acV@#BFqZ5MdbKi^y52L<4adzuJq zcK7sXK4Hzv08qLKnIk6}i~y{Nr1A(yaL&%pe~5-K3&4fTG*&=!dZCa_4GXDYe>uqeP2^4z)v0$Q;SNc9Dq`@PO?31A;1=-qZ4dd zFyB}9DfDOoTGjs*fvTjzt41pcv*7FaLI&@6RX~3GYF--=M6ZoM7@5!bdFT6kF74wK z{#PJa(&Cp=xd2CjM;%PEKy`nblGANVu;Rviua2Y$B?czudRtO+>rrUlTzemR4jo)V zqV9Q2aC|BaQ{l_z;%=1Dk^yEmY|Ua$xh7Y?wuaw_7;zhz*oG)sv628FG6j-Rj#4QK zpv3dwqKKW4do!FhOB8=!vSv?qje+gGxE)`K$wyzf9>GHwfV(jFMgt=v*kFZ|SHZzj zap|QB4hu-p0oPkzaqx@+5A^ENyd4gGD3Aoa7ycXvl|TOgc!53#WFgW<9)wA{{YxlZ z{rxIfGQIq$uV8%yQGQ)#<+hTw7>P(t8@Ly!U$!6kYx)(LSV1%vhA{1KU% zhAZMz|5d~XSP)!3RUY?`-%oaYDDYnZ0P)Q)O1V97M?oCK5j%3@nXkBe>{=65E1m5CMKITyOOB*kk zE?$H{b_qUN_VeyL;$D%?K+zEUYo>|PLrJJeD2L$@>X{@a#?_*U@&sb zy$?9UcTO)!q}6egdOdZk`v8Et2WCsFVYfO=Xghuc+kO9W>O6cbJ>(5(A3O*d76{$& z$Hd;Fw(5UXcF>mB=`<9?f;g|lWCpA2^54R%F6g+2tsz+sPh`^36aX<0PgttpRUav6 z%lgx2F2?V*#H2^M0n39kJvV?5M$T)3BcXN`zUTu<(U)Rj7&(E%O@dMe%xUxR0H`W| z(>-)TlGxbb9WN}!fc~22g69iAAY5DT@bRjj7-)~hU)0xloER%a!yFxExi7=_5U^Ym zbG{dnkms2#qiA~R3QhQ&cT&iH${gollG;^|OLz$!q6i#9k~W7 zGx|;N^F0?=?(!)vG1apzFJ42l1R=3$YM`Wgo}CD&=py{wIh8I2 z`>0OEgKt;8=dV40QCB$NG?Nt#^Ho z2%Es~$YQMq>wzOF0ahk&k@Npp|O5LfNta1s`+HtmJvPibBX!Ze*=$mlHc zY&_;AO4pv8ElZuARVFWIF2$Iygd+^FjScS%8SLaFNNtwux-FV`oeG||H4vh8{f`%Q zok!sQ`-f-j8m2AKW@$3d@TJjgD4`7i>Na+Q#4&ANu%R+d|Bfy1%xW&Q@rzEH4h^PV z98d`NkmwtSKJ1h@DLymzL<^@RyNsp3^OEdva|HPkWtPY3a0L?se=o-X1>$waAUzVbEm-UE4G+trQ;g*_9=2jx;tZ~KJn6It z0P@{2_ubFWR>v#Tf!4{vX-nLZJo91zXpvGakl~&F9(KFDwW5)?JYVML z>XSZ0W!)}0y;8&|CR#4k<45N_bf7M4ksegL8buvr3HY!8y^kZ%@vYE5TrSv&A>AXf z_U15QZanu+UTty|ACx#7-uGoMkG*KIG_@ZvS+D<#q4)G~nq$9gKq8bTOf7y#c&UkC z!~3}eVBuT$`jfU1b1`LU^J=avt}Q-IG7G84EH`oZTh+tYxLl7`6&0QPs(I^L&#u}C zD0UT=EX2eGLB}iO^r+`_IPl!g+Vh;pj(Krt12xjv?xJ6tjKwa((FyP(>x{1=Lpc!1 zFk8Q!ssRae9%G47a*tc~o2{fMi;*ce_3z?j?cTew()$wsTHDBMc5P zamRh4V0xUA=f~K7Hx%Ui6nHJegLIO3V~n=YGJP`rcdhH5f># zE2o*QLRR2D*H*SxF7CJ0OfO5JN(bLH(v#{f>jCLXz{m^ffX~%QjX57WVe&`tEy@lf&(KRKx!$CCl*FO*G8|&(w8-WdZU~dl?A9B zzNrG(<=A)rZqqVH?mEjV%>K&r;rHE2s{EJz8=M&CIyCaZQmms28`oByJ*LhDk~5^&QUcX;qYfgljnV-=zJr1Loj zZp%h%D_!=|2j=)-Ue-+96wR6w=QrZb^99dmpytLMA8w0Am$J0>mkt?$G+`O(f zynE>Q>CGkNemQ(&Vl2;T0O44d{XwIt>5U=ubv9L-b#9zAIxZdA-(a(=w?!*3aP%*N z+M-i{6%TME8|fakKmPT)JlnzS#5$*9x+Ghpz;=*9ebH@XTQL4JY$1qckG@H!dSUKJ zop4Q5f_?^hQXzCtIiXS@h_w_jjWAU@&LtCCqtcr4ZfK58+&X_l;$Z%pRR?S1kW?j>+wBI-3^!L%Gk zNbP!V!yCleh>mmezqU~~HbvQ;9G2|H=t*RRm0cJ?odbHm#ZiZ|Vw}+3IAXu%_goyY z-AW0uOw7>{D>`dI#rA7G+oy|_*vk9bgJ3UiN&udY(HSR=N7;NN@Mm#98E?gRyZ$Zc zcvA4zgkL6beFAij-j}hk(f*eFN))j5Bkv?M^z_lKbjBKU$}mNSJqOkNlowmMF9oHU z%K5;Wcoe!f9jie4HV@`G--lQKLuoYh1T_V7TH$BWxm7s}YiiT0VvrCnv{vx`LdY`(V9MJMr|Z!hYv6l1L$xcC(%VBTb~MECHcrhg z!c*$<<4xAhh%jiCb9qC9>YfjU=%VjZ^zuB_urE zPfDi)Ix#Tu;u{)^0>l&%T?f`XFIkhSqml4P*-E+o`dI;vIv|E8{B6Y-Xkr404&y7`XMHcaGf7Y>_IxZ971t z-2!}lD~lz~lE=H~<84kdH{9ogx}~bQO_^nfZkFq`qgza{3?3HgJeF zPm-J2$n*ExaA^0ro2!u+_Vw{DqUNZMre>(&0W&Qd4McVe+i?2rU zVMm9=PP<Gd*tPJxaDhkU$?$RJtQ{T zFrQoN>RtNAq0t5)U4o*Wq6G<@w7VN3N_ZiGVZ+1ybVhh?0FUHbY>{*xqElllTSs!} zjt*_g$JXi#D1H10-F!^l}OaZx#9N~-;sGCMIj|fMddJI26>=AcIuWDcOWNe32NFqB(Ys>=*YKzKft8NqZm6Vj~6;s7~<8SiJ zk{;E+uJ<%9!6w1Vx8N|uv4+?%PedQxnoC-7#lwTW7kMDvO24t<$PT{la*7$e9t07eKDOh@PLNZI0qO~q`q8I#4I6>96l2A*c)Gq zYx&{wmB*~?4Nf~dpG(E1mA+P#P=MV!73wG7Co9F2Eg4LtB)ZseNvm~1(8v){sKvJt z>k;;H?Tt5i@wMlYr@y|*-)b)=GvqzW3^Fc`HfE-dW7ECA3DzPb!EPQm=g_mI?rqC! zgxF@4T7KlqMyu5)^+$RGfyX&at?g%3&)b>C_|!dtbaEAwn~qCZ%kLXr=Nfvkc_+}T z_CwJ`n;V4u5WDcpt22gsU@^U(g0Yj$WT|~D3ZFt2h%sb7zZ%xvW4s{{N?gD5*2Wwt zT&y@w=AZ%2$G*J#$=>|+J1@-3oY`K|VSktluM^8_K(zm1@29+`Ne&@97;q~bDR#%>sv zx&|4XEWHrh^}pDx41b4>yGf+}Ld^h|)Nh zk5HY;i#wH#BhwtYkDav4p!R9o{7w9!8(-~mujPf+t!a9!fxJR6CP}DK(m#mitKn1o zp>Hx!bj?ClLcv$Ko~>BBLt%V0%&Z6VTofw&E6%EjfG;C+vYhhLGoa#lK+in<`)@1W z=rXigCG|#si%K{ep9=sWEIQwMlC#eAk~<5Aj_O|WS=f-}>wQ1n#=T|I%H7z0bDY}V zbL1J*Q||z))XR#e;wfYRx;r6aS77=IKS|3d*z!1{v1u5p$izhQCTn6B9+3}BVP9qk z#@@v~9@oeraNsc?s%S2PVw)Tl4`xpH4hAU$_F{;;xxQF26OONPhwrvob%JiWUTLz7 zdZFh+dZHzR@4586s}kVB`h3AZbS#0$nlxgIz5rA%98xQ#s=qxe3^?!++KIyKURK8R zcs1k|o>wCoH{&E8>iGz*%JS4{O@Sn1i$`Rx#bPS|P%2X*-?J64&)i17V3}EOsdE12 zZoOxd+=$-Y6LH;Q$RFdD$GkwHR6TB!15J(E?1d7l!xROQ`PbKU)uE%#RNOl0=M802 z-q_ANla5QW$NqD(G|bCEtKPcbhLXUaj-eSK!w!!O>Z-Vm+pD9;eT2&9mN;`Yr2u87 z4~!LOEze|SjRe;L?(%8LX^x@ngyT9Cw?DkNrsZ$;Z$mrViKREa7Q)=$JMnMQQsaq< z&jBe1PpHqvdE1Q zvl>B9-T46ch{`aG%ix!Vp`{wFK>ObuE}lZ@`*_EID&03am$hKlMeY6#XaKEE9uknQ zL?*+m{dSM8H1872V{EQ68hZ!m9F+6VaSwU-A07J~PN$c&pY_I_>B)SRbheNn>Kr8oJCaLOV-L*N-{`m_7ZtsyFN9}yPI#&3&L7H zi{I9#i!n?dNMdd$jV?&VkMHMaWl}xjh^MM&CShn)5ddj(3>y-OsSEq`C6cq{HIc!5 z*&89V7ZVHCy_zh14pzP(R!2(`HMz&AE|$~QRcMPftM@Se=2RIi(nH&fq_|0AuO(NvG`;`u2TF^?Mq798JEfm|OmiDzSy2 zMq-y}swE!)zN1pyJ>A@{#jpuF4h(f0ZY;#^crjr{bUP7yw)F=KMf-!F!V>qK%k%hq zJ7=S!VfPH&3$ygRtN9P_$j|ln+oG=EIv>#8yha`bKCG2eMc`ny8Z`58@gAdYjsZ-> zyz7e3;G?>-O0A@*r=^!)bBn)|Y51sdWOUCxy&N1|953Y)%|)}78HF$zk{}OyuZ{+J zkjWLtvT9sDYTBd2=8;DW>lN_&cv}8v@+-fB$={r~7|u9qv?S)#4rO%Si@tIFmEK&% z4RT&_MRd=)7k02Td;ZnkQYjsP;so=br7 zqv$xe^%8p}DK5bRb*Pt%X(&DF06}`g^|x}nop4-PsfeHy>J=j*n;P}3Ky`u#P`?tO z3mtKlcKRFJ$I0Fa&=t7wV>J&>ZCfTHl|(2ov^-Arf*M zo6Gw$>`f~e`uea!Phpe}j^zX+-&qh)%`ou#sLu$x(9o~@frx-)UNYSD-DdwYXkFve z4QoUJi8bPJC~4GCbp85CEM^j>ocZvojauI4b{qeKPhJ})Wp8MP2{sdmL`?$bMwU8dl{wMGvg8f|EkR4s>>FfP=~yx6L>Uv<@@!;1%8& zfitg!UakZPILtX%r(IRLAtKR}_rr3xwa_eXv$BfTsu=Vc=Md z+@|AKhtjT%jF-daxI~1Y-4BZBe@>s*XaPdzpvQe9nfJ)z%2FDS&2d>6mcPfK(y{#~ zbYd%w7%O%>BC(PqeOU5b3)18JkwO~iBoK{3^pwY#yvT=qY^#b*a``*t={;2rCv=>H+off=o+YbXA)&EIqu82J4C^w)5vg< z3q_Kg73R8&E$CiSI^BMC1#cRHUcCl8l$99r)trcgV<~R~6ttD-Bl4)AVkH%Dqupg5 z>8?@Ude>HhInb{h_092~z*JRB!EnOF&iFh@=04ygZQ>dCWyW`xRylDL2XY`>OalA} z8&T=ouo=1zT`gz$6b!TK`)<)BEAZKP*2g?)=4$*V=La@wEfGER`PUdq)qZDj@){Qf zSnpNCb;|AF{Kks%MHMC{rWp*#G%3aaopl3H zOT`*V>%L?!DaJpeNYCMbQ{9bbr)a)xGfxQ~zX!D^p z$KAV^$fmqQ+8D9Y*pc&y^4ogMGmn7GxcMg=AJL6FfaN1I4I&X1vhq8i2h#iCi*OPO z2oo#IO6I=gC`4SQUpe`B{jU4b&yk4h7YhLBzA7~nth?yOQ3Sa3GN$xf7(n*y3&R_F zl;FF!8h%0EW9#JE>6Qd^d?7fBui9W_L4@2KbVCUec;C%-I}{)Mt)d6ea5o$w#8<&c zy~50)YPhLW^<;;UBkl|bgja~K1nxOc@;a0s*6x26#K>IfnP!K)s8h_>@PMM)KBb zvsS|AF(I0E=)0;{?nUSozr(C`dO{eUo6=I0+Txch8g z#0`24+~4_q7n`L#i1-xa5{PjRdhyc2vd^3D;=|Prxc|xX7(;K-;=i8pCQ*Xh?^*X5 z!Ny`<^_sMsM-IPU;)rT@l=&zCLxC48&A76dv5IuE$MNo$fQWweSqeS)h74p%s-HK! zCP;WkDM)N795mBe!;u#{@Zq0hlJeL`3~fueV&3vUG(bL`!M_5J#u<|657P+_?DSuzxYF8p(BbSKhEZOlP90HCwNw%MVCFgCGRrhEH*?Aimo1f z$EYiqY40htDzAM1=b?lMJ_jw%xx|qh6$r+ zJE)cn!nx39EV|kOTMRDc4X5?Zxgis%`uBU_i9fTwcJ}r1=-H@Q3XVT@xH+s5@9deB zAxk-KM@s;o$0_0k1DO?mfnVxsWphvhy=R+)?0NeIDTy zmGQH{4c1Kx4+Q3Z%i8x5aQL1AhG8!+Gdb8*kajR%kCjslFe%`uPQI^8b08;gxO3iH ztw;@9=@hjny<2}C{j@gsSa+;BRCuoCQAPmXG#aw|4jWl2t7hvXcq$+;#d3!fjPGBg?5S<$|UPa?j$-S@D^l1OFrQ z$Nw+_dJw}!Kr4!dQ0z-`lD?Ht(-=KtmiNFea3&y`;b66ro8NtH@_;egNrHI3kCXX1 zH85Gt>%}`@B{hNK1VuD?T!au6|L5P~zYDrU{~+XaezO;t8Rk`GyGrn z`sX8S0(h%7T>kfe^S;2+&y4}Ilb_(%%Ky{m|GWoL73dr?7NtZ%_}`8Lr=|Q3Da5s| z`H$~{n@up$w>k>nh70}o;|zWUty_ZN4kG_H_y6@AU{VS}{}mUui2rw%O0X0@fn1Gl ze-fM_OHSljzeDjqmlr&c;;13R(C^K(TK~Y6-`9uQ?8CVfp3_-e{mTZ-U%qRyp0ey; zG{A?kA#g1|Ktml`Mz)4@l}CpC#NlTTRu03@SaM79IoP0PfWy7;kqUQnIbwK@hg@pK zxY#}-;n<}pqmr#aSuv%YHv-&)H`e8YADEKfMf~3w%Hduxg6NX!lZO^+@s;9Uc#lHo z%HH(cz;&RJ47coUaqvpo zUqq3{%>L4jvy5@2PJI)PuMCbu3ZITY!mIAeC=~_o1HVC@Gno8{<@l|<0GCShQ_!F3 zhLcR(tz>gQSmfsk?Zj`}{0V*~Vf|$AoAb~KM3>I%frX_) z(yni;5%b75YI{c9+>f!~6r?Q;Y%6E$sVu*5kjweN6D|evUH`M8ez86;kl1;j!NLZ6 zvFJPoI^pDe08e^z`-PKv!pJ#BUgUW=r_$rcH^!lC3~UxgU*4eOzrYikGWy=)Zhqx9 zxieXbNc;59p}DbAjE5UQ1KJ#wiQYzmVFeyDEfJ#Rw7egsA4QW#Z@(5^eMRE^Y#ko%#cClT zUn}>Z{FgaY-a`?SmBGnolTe#A#P6;VezT*}`*$7M3h!iV!S;@e^7wib6>r0Ncph7w z8FN;SfOf$Wv9!Hx!Bg9f@>0h57$L*$msD#i)#x#Msv;XSCa45HRLIT={#Kmr8$UHFj0~GF1u>>1(o3GIqPV$vno${hm7kcvJ&~EDo5NlnGex zrdwkq__Sawd~`j@qNbI^tu}kSe%D?;!U3-}C(hq@b2jTNTD9bT)>27RmIobLa6B4Vk}O$CyVPD!mJlx^k;gy3$RC2}dL0S=1dy!Zp8!GmCHC zT`E^8@ue+L{Wy2%HpR8V8@~A|6(-JYK`5^)kIBynl8PWbxg2~Jy=KhhH>DHs4Mwjy ze#4m3`C5Qm1mt|ju|%tX?;`9-B}{Pb>Or;{D@?8bdbpBi+}(1olXksx&qf=stf~jN zwLf_M)0(Q*YjmyEoO|sdeq~Nc&3X0Yh`&5av)`b)q*g+{n=fpVY`uYgm`|E@GHSr& zta`ojyf=aIijTmCo$98+nm0NiA*mRv!ZszDS+i{w&PdE(+{@~x&Z^HaI(CjbohOt#bU!O20ME1-euXSSd31b+r_S)k zQ_6*<1%uNdTIMLn!kObW6XtjtYo9<~7E@>0Rx61%beyB>PF}tRjKyCrQ;dl?i%mrWFNy1sAf}c5&_gg!Rk#e4Am`FkK7Te1B6zWIiuE zn3FuvFc~E-P(h{sa$Uf#^s>#;4I^(8+fbdrc$&s63okAUXY+QciK*_D%KIy;8n`O3@}2Pr6E8M%Vw5xJzf;X~_|98m&VqJ*<$KBE zO%$yEuI$lxBP+whm4e~r8wtF}z$Hf{r|Xm#ConB!IKf?=qkh=x`aO=})g7vn?n;Ofr zkj&HE-gkVq9;0NqgF}NTa!&QDnl*2z4<@BIe@1~X2q`3fd)sBWqPjBDTA;KsHkdcv z&143e$fh5?CwL;^4~qbGYEGwAnqKsU!xji#x&rJ*Tpz=5o|=rKor|*u=7Bu{2uaM+ zMO#kc6=$yrijbyPY-edZ7D$|cMM=xoUxm$tl!z^q#%iO#WFzlaXxeTNq716{1>=W| z@G_|JygBw+`&U&_R$Crg9Pe=L6usN~sTnuWHHp~uh)lQF|4mXbq9JeWR z+)%#FYe|e)Xqf1ln7JeXl4}KCT7Kf37tP$ZbZG?NNW-m}5xO(1Xxcoap1a_opvUB} zgSiRM38y7mg@2;SM<-tFW|TT_EN8aHaI@({-N{X32eMipdXW0B#p^1TCg=*^j7L~4 zZDSk6mMgVUKN@IF(3)vBfS~zFq$qYxfcK;(f&KN4&UxhtzF=nvviNHBr`#-wn{k;` zl|>~?xHo@D{%KBi|7TE?G8Vs6mNq$O+P3!ISo4(Qr3*GEHf>vmj*HM#4@tY>;tgXm zRv)sMbSKDQpy7al3mJNg-JWD#XSL~m;Vkw=>SdDVMZ1@tY7uuzdksJH$O1tToqp;d zSvgH58kLN+etexF>C~8@i1hgh5VO9SQZl7n1qf+4QNF+hewM@H?`8szPHk-;Q9NN? zWjEe#uL|w6`7oVyiNJ6nu=bMyrxhS_NIgJXrjvTE%j`8m#8MRqw8xf_PydLgyztXD zZ!hSHeQSXXirul)upCqhe;rgKbtu)yCp}1e$@CJc>p8ZaWS)CoNixrV4T}D92KO4oaiUm=jI_0vg%iiO|()(~!}Hj^Yh(uWOC>IDKq9gNs>Ll+sI1z8)!o zr$)6BffZsGuQtC%F(7QZuXFs#PMC-nX2Wdhqr?$oLRMVRU}slM>-9?D3oLakTa7oi z%MRf`W?!Y<%^4%mJV{_{gvWPcC;ZJ@+ZsKr;o9a}K-CwpnwPbc&v>W^7vks>0Ofg( zS8vD+KVbMROCf{0mxjCX91b3xW>KxGYWTI@LMb`rG1;Jmj_ke%o7sGE@VY%l4brX$ zaH+ed^o+h!AFfVAiR&{dP00O`>K^wkp(2EWd-u=ikECD1W{S1x+98EeT;*BMkX!m$5@DF&|J|2Bd6uTqmr9ys)2u8lYjG-gcR+nvoGH_y$+=|CApjuXU>YiF z3>$eKWVf|X^|Cac{Y!ojmZFOX?pBO_Ge z5|Bssdy^W$C7ns&a2u`0M%NvDf9?7N_m^jNj6>y`T4gN@MrB#+qciypgO!pRj6brhAi?yZYC6FS&g^^aS0YEV_e=}UBR9*(Xf-#@1fD}FL& z9#NpiC|{v#luRV|d<6BbB+PMvNnG=O^PXlNy(K_7KK(0^JjT~6q52k2Xj#~%m_ z*dzzrVtP*WgY@f9vU)FcFnxNe-x&J3s1mNXym*rz!a0n6K=T%KKKsk9W3K14K)7C& z-hbH98Pt}{@S?l^(JJl2R8g8~zhCFQmLWp>!vI>>A<*U6Bws_lY}7%Gy)q}^GNIqX zV)@Giuf`I1d6aeuZPP3Tb1McaMlvtt{L9BC(0!X?IMkkWUZ@RHJq<;Jf+ut6B2re0%*Dpx zeH2BR_J~VJ8In;he$2Y9uF=mQ8a}@Cjxf*!3$;8kn~m4LBSSK8?ew8aqW8R;v+&Kq zh2&qH`&7^FZ+_=?eMnIHHp_E@6i=9o9gV9V^t$6K#HtIh40dJvNGsoeNmdz+cbR0~ zblIM?u?idYSflJMvu0^peKKfZFpRbN-G!?s^ed%A3cfbYq)C{q)J+=>d~~hA2>9E( z720hY6u*=-r#~UqbQ#WA*e+93RWw%m0&}mkYJE|`Uc-GSj5DzL2>Il z*qK@YQC9VNANndtn>2~IO#GuTa4x|FK-kcUF8=i3T5=>!hp(w>47TMOUiE~*&okU3 zSgNLg&pT+Ad-NB9QPRp9Ws#AeYh)vJD@Q{fTi!KEMO;qnh}7Lo;Z)FKbq3xAYiY0% zn3t!3gaoTM3Xf7N&@A{;S(aZWgZ3zk96`cKg*I;g;+AG8U?gzRjV``#LNa(p{h1f% zhU|PG?A~d;zw3RccE8k6<14DXltTUz(5L#EXth)<(r(PA&-m!g#+L7J$bIMJoJ_8L zh$*S#28ezQAM7Q@n9Wrv*S=J#)@Eb$q@5lCTk&i<;3uaON=t`;6JYe6`u~lUq3AEsvaYbSC zTB^9ls$PZ1AJ6DO-4`&hG}rwyB>jr9*Ud3fT*Q}!OLo^uZ}D>3+|jTrJD|?rJYE0J zl)iacGNSxN)$EI#F5P*KekDc6Uo47*4nOOxG`$X-^*!!VbQ5hyqKUbVs2fJ&lS*O- zvusY0uG2c~PlFx(!I>gj{g6r?gwYOikraDsOJ5#5HO$cn9a=8Ye)$7_bP(Phx^Dr$ z_$jfIfKSzri*W=JOlvoW{CQ@ZSAvRo60dJsggg-%tk|Zk&UvL-s)|-m&J~6_SuZOHsJCr`CjK&NheRB7 z&Q%%jh|34}<0gH&f7Odvuw}0|+{iasVzOL}L4MU{u;;2puT+omGEr-pJXz)M0%r)W z9P!=x_o`17mTd^a)iR~wm#p``-Wyt}sb>Q|iGKP2u=kcxQGac}xP*jsC{i*EEhQ}= zFu>3ypa{~9q#z;9NSD$n(jZ8uG%5np(gOl2-HL?t*S=oYlqsJz4G z6QMwd%G>wd;^o;3^)z1H@g>o^!wnXrg!p=y6fGO z`$q)^CC}T{L5?5wvdriH)D$o(&VvjJeF_=9J-U-G-ky>krxO)x#P6DIkxVb>oSe9r zFwh2oQqT)uN*-G$e}Y$b4vzVcn@kh9HRBlXwT9PUFE+Ra7EJN~~-y?#^!gu(5W?Z2sI=NQy$=g7VKE=FTM^Ucd08%sA#cXbAkf8Jdz ziM!TyihAz7b=ypG%|JNtlhtn8Et0k+{go+A5!~teA^Y;%e8~O|Jt>i|)e{mC4o{v` z2L^7w5Hn`kBxp0E*`pNtQulgnW&V~4!v)k}SIeTqLJ#QJe5MjG?|-{veR&!LrCDj& z_Xn(;sIgZBQkm=IUh_Xj6CSOU4J_7_$^fY%=vn^Gk(=YPy!N^^BR;7D{dF( zX|ber!r3ig)7HY@);%uw-5-&)LbN@&Bn$RNTnY?xx|WTOb3#&-*YAzYt{XJ^pQ=nm z>w2mNG(lAf_40_a^GX&lGq>5IIG1t&L>S@=B~8Mf|AyvcaFucx~Bde_`-d)Ktm*8DDz{kp-uNa{+U@n}N*-#B+=! zL&!+q0}rlaHQX%cZT>j2W57JW%qD91^&_^YfJeFNO!RAnx)FSyk{gV}qRQel~J!hf(82Ob~Bd^BMqV^~%yX2W$ z_K4j$W&xj4zsgg^E$Z8^CvWEDGNU;Qju)mZ76nSWoBM4m*`oF%c3Sv|EY9Puy)m5o zE;Nt+UfXY^StmVV{G>cecf&OIi;?dPhe-RhWc#P*weK=NUN_onzIXPU?jkSzos4|~ zQCI!20h88d(wF(|)#6~M1H9vmdhejbH@5^PMVvQVO$6-EUcLG0M35{uCS12Z31%d| zjD2(<%gOeYu;~WwOe@Ff_adzYKi#@y z8z%e?B8Esc3(EJnBiB>D5Sq0ar^@panU&*AA6+$-Aa~=*1fGN@Kqd_<~fCZXz=!34!~Rdrb0BIa2bhH@VH-vNR-;(WD9yLbow%} zAh$V9?+MOv*V@UoVPW@_Qe%@Tp0{Y#r5H6e#&UyxXQhRxRKGXE1d=f`B zwBsZoXjT=M;-L+Gi^ns*It-BrzPBb(?}+9@II<6DFi#jMDPW^R-jCU{(UkK>gZ1aj z8T#B}o{>7!^1}*)^UDME!+qkJ9`3ti4{~F*Rf}9r>-0W0g1J!a`;MuvNVSA}43h=T z0|UsC|BO(8>?FWu|5}+s-3R%h5sr)G`@i{bD9gzNDq~_e7m(@SeFFyc1sB8K|NZ|W z+NCh8V8_-UU;Tf6{J*wjCI|8vI;#bh|MN#qK*?)=Fhb%2Yy8`tc0_Jg`MpUM$y5K9CBon=h+$WE9Kw898HeQDBJP$j0fHWeH zP1bJXttW9%f}6GT;LBeDWBF9of0-FXM=x`TTmo>v`jJa0Pa#3c4zg;`K`^)0Qv%ZGAMD1foB0WTG0ev3E3DR z`3%+4!fs;hqGnR%7$!3^6%{}t)7Yy8%Uvk>>ZBgBAiP@#IMySl zh*h}VP~aeQJMtDP#?_gWWDwWGZeZvSV5~&1>~ZhP?>IDpi>4ZQeRgK?T41i zZvGvjj#o&!4JoFrYizbWTgB}k`^YeN2DxBd6j&{BEqk3tV=&O3n@m&#IeRs>se0qh zqK8Imzj#EqdeN!triH|oGnwaIq~CyxPu=gm%YOP1-K+2_|1~*(TZ=*R*iZ?(+Zv>? zkx1r|-ZNs2vF)!P7vr0R;>=RP-L$)W?_Jr2oSSf^XPQCa5hDZA2@%VH;Zv1(d#m?vS1B)Dp{5dW(ju2;Cp z|IFZ^7+14N2qU~2dlWEP)3z!WIuX`Q?AdeIe9w%`lQ}Ru?NPhrUF0bC_Bvn07-F2D zV_FNROuIC#zbi5zT9~ByE2T91 zKFJ~%LI{so)xC1>fx~Tq!+kF&$-X!o7j(GmyV6AiZqCEFzsX`xi>YRB5iYz>O+3b< z#n}Lv_}WcdtywlWZ-G_skx+bXIXx3x+vj>V@%&}DOJ3N?2P}z^fYX++l@06d0-UOW zfiVS(E>Fo5ZCg>|gG>>{&9=z(7h>xVUl_+7r5j^;s*$B8@MoUx)7GQD$Ro=X`&ah8 zPYB6Gm5{A_&WNGbrCb~L3suJG#mAPwP1wP#r1O%k+-8JN6uv_4q=!@^7vu-k*585- zbK4r#=D>ZSwg&S*$t!kxaGbi$qpXDG#<$Q!>|x(>xF$JHmG7e(({`PkspHJM!&-p{ zdkOE}bnf`O^r?^Mv+VMH?l%aIQtOvLQ%BlrSI4GPCX#G_mf@ ztG-svlbBtdI>Y*;z>;g1Z=wy{Ba=bi=+X8sNc~`YM*Jfo-|Dv_nJ3FfTOqQ;+_0CK zwr$$a{Y2cBDvd6Qrw=5J>uEL8b-~F#V;EX%zTqnq$jI1qA*1GjbN+JO225#nA|ivB z5`f6Ye)bAW*%PHp+*0{G>k7KmHTG$qxSK=SKEsH&HXiHl{6({$9mSwV(De# zCA??aSo-x#aDFk%SK`MOAUQusxS$%cX9ssl3tN#Z_83{@uG!Mpw$pSF{KAF@>>yH`LlNo*L}aUPsfX<4vfrtNOVYprMZ@C zq0+|>vwhP}|Af|0F{Qig)Ayu{2Hl*8fTVu(Pli9h1gzz#wQSenZ#4QTNQN#(sEYkk zu%10j5#t%DB1Ic@7usE0Bd6AXyGHktzaT^EkngcTu#f!O&wB^fj!(QcN2dn88{E4E z(?yI=k6Id$$X(rorDc|&fwS4vp~kXGp5>oLAt9@T4nnUo)T~47nvDA6>$7}I+qc@c z{+Ja;$gF4?!;-X|Top5x_k33Ez0CEe*L-hU?~TUYKYFHbot`$#tD^1S?a?}zG=6I} zTFb6RRTXG1L7Q+8HZb3?9f)1RfL)n?*abho&)bZ;-W@E!c|ayiG&!Z?`>wyJ2>o8{ z$I;A}PP>Bm@HrP(sqK%(Lm0;gaF;e~Y9bHxvDdi14%7ZEGS6`e`_?1<$nK6&a>{{h zKQ%+^bD0~FpE`!c?a~PvWxVJvGO1ybDE2iXU#8zJ7>+*T=yBSwN5lFO*6T^zKAEM- zK}rx8vPE*F+=pbq9;dK#UXv*MmPH0iw!aA5Ke%&u{Zq3;MqS!^=^|uLO27~_}@g$DFZr?b9~BEY%%oHQ7$hqA~?vHJ>tSYlVNI(0^x+K+C+9!)ui= zYV`6^gEV#rW zE#QDO8(y;WytVSZ9n3byzv7wp|3IW+ay&7s>5>a(HUeg{Z+hJ1&o_llCo9w9*k?$; zvHN|dhP*)$%i?*fXjM!OsqV75EUYR}sqfhXej)EOe6U2~8+B)_z9O z-t*-=qdNydVa+V?MxHEl_I0t~^}?tJLdF^BrYV|(qjvx}x~y6HsH?cGhG`=gVhL4{ zw~tF$;aGADSY!>;iN$6(_T2KxGef_>{Pgmc;i;a`I89x9dS}n9MUT2MqtiuhZBgo+ zJXV$WtEVPXog((!YPIgjcNTzJ<-|m%mc@T#yB%Q3T22=H4vD=DaDFx9S~X(0_G~u; zmtJdG!&*dY`Pksghb$50($8SL&nfGloK+JZQj;O!$bbqL3=KD(I2ewwxfN5YC>sw` z7BvANMHY#SRuJ-a`}&1b2y3Frseb7IM$BvElhF-Q*T368K6z2wDW3BIzr}QpQu;A1V}V3XzGbBU`(78ZwXe%y!pC zxvV_+#B%kM`<^NwlL}pOUW~p>=HJM;vm*ES{2ukzyinmpSlB?Cj$fl>^?0pZL_^w6 z=CO~d@ldOdqOpnbA9;+2Xwjm$p4@o%$>8qiR(Dm~qDb{%Y#kgdJ@e1kyDY=!ACfg7kV#ifVe8p;5n()I zKMOIZ)&~M<&crzN`WIz{+Xxnb76o^_Z~bG(*&sV^W_<5~V@r0;UgyRhJVzv(0Ilo* z3zc(9fObd^fS-Ru! z?h(=NoOynWg;u+wo=JU=!GtgA^Ktmt8G%G~{gZFrLY9rz`fKk+g@J0Pin;%3>x_i# zB&7>Vm%AlP?}&+S$BVTar5uBE+a2v-aw$!k;%PRiwNKy%d2mRHvV^Yms3 z*wpqdYfCMA_i%j-$aqB0T)IR}CaQ1-;h|yOl0|jm)j0{-bq|bpa(nfC z;y?O0W%hhP6}`0I}oqr*>kO_hP=4A5>1&?&#QyDm{sQ!rIOGpe02$1@FAw1gI z%hRXYV)AnoUtjv~;nec5<+IlF5ac(`1h$Coj8{_p zCez6(>2NV=0`2;}GAQ5DalE{K5uk@eVWuR;~xS98FxDaM2Or0^-+1bNa%xAzZR< zVSvPxEZXaM*)+q#FvPFu%PyB($7_3m`qE> z{0^QFzm&AtR23Awh!4MWar^)THfRio#~{=Grfk^x!0mu=lolPfJyQV6USB>8yp;Fv zvljsY(EE4XO4z25_xSgpsfY#zA_r>5i`LJ7|CuDv^jgPE7W6-Nh_?%afW6K#=;{BQ zIMRjMnB$P7|38_dX^=XaP9ppMC*=8adMG<^ktw;@nhAJ{&_ab=`ue}$DD32IjXcP=u+craA!R+fYdxXs(2Kl=Vi z_z$bHo`I`8SA*2<|KSlT20VZj#H<-a9RTuimu%?F1Tb*y)2n6w<{?owK%0@^-{?M@RE1 zew>XI)>l>+p&z)z1Fkk{N>ARq{6~cFpsQkvxck`gzdlTnz$q`gj5yyH(Yjx-EB z#3?VhqsaMJ=JLTMLv|Lmo~lToBZh~tv>g0fCREWenE%LRH$)by|02>qWFcJm4_W@t zkR|D1U)n#t0RNGk3;q0$LjA|i{Kx$M$1D9`@k*bRzHUB;4{KVa^Hy&!S-1On%aWyX zR`nYM{PoBHXBPnf{paQ}{oH{I?bW@_A|ic3A%l8iP7helOmEa}Rh;@G2aq_|nBLjDS0y7fEpN zg0#p@>@?fIz=aVG<^XC|;ngBRe4v6IXI3no71QL`Cs`&R@|xlgB}n~1g!E%M=Gx!b zL0JvlpSI0OuoeLryy=&$t0+FD%ft&n3f6x}@eG^>JG+zb@8N7fK!p@UByejCZ<|=MXF$1z1T@+oO11hhEi4x z4{p+qf;ZlworJMM810wxo4-f-2;e29>NA{X4}N8pmJAlNUdB-Uf+@!2pAf4e06b9pjF}V)3&F3p^Mj&k zFS*QZOVG$=z*<46{|GY`I?CH&y{tb$Y5<}J93>~i_~G9>n0PYaM}la&f&g@MdAlQ5 zqla(NxZbs4E=Kr|5o&e5^FjOg_iXhYol>h>J}&dY2S&Rl^<1+9hZuKxsvaz zsrpLIy*R~^n7q+Q!O=)&os_m!sZ)I!9Yy$F(_xd}s}hZfQMSJ2@X=+Wr2}N(D4W}P zC%>wmQmmy=TuLUTUW_U;6*G;6v{oE}tsTX$c+Pl&H9MMXqhrFx6($2cm+J}FD{FMe z=}7+43yRIXn96)J-TzdN+yU!%G3H+M02-Ik*{$2I3GICxBk!eY99R61HXLI=cX!0* zh?V&>Pil;NoNAp0E5#73iZfmQ z?q7kX0~R!KAtqZT}xu})1yN%2_Y6PiJ3|VbF?(W$IJp7>j|G1u21-Z z7lgZau5wz+ohtttIeAl_e06p1L4m(9dgv~ft%Q*^-(XTuAGy*%l0`q4l5k%Va?Lur z&sLGuN`)X*sMg~}aQ^EU{=d4N3dE3xMG(x}e~0%c`OpUB7b@cAh{H`_p|E;uwanQP z^fO0075>jcpG(};l*%^JRFx-!MoT#2_=Dny?~~_rKGttj)0(e$>s=Zyxc|g_pN8pe z+2`L5CoMk<4<9_3upuvuGF$c#ib3yC+{Hqt^mke~3Z~QgmusXCIx=|$uWv^taV39L zNlrh#GI>pT*iu-fza&qvPyO}b%hwr+35nJDlA?Bd!9sJywBxeLizXNOM^p;%3qfsI zSt9Q6GH;CNx}N`NW*C-f^r1YZ2A@vgL*Y=7scDWu2=o>xRNm=+_6LK%FM z96DID_D{EewUT6`X#bLOl{Icsm${)bWsb#8a;nzRRMprVyO7Z2bSC8^Pp+;tUbQsB znzJd|QYewCP;J@R-?-wbp1ZE?4YqgzIr2=Fd{e7vW=VYx{_48cZ`DdvC*RucLie$u ziWg`*=~qjD%Q_)B(rbYE3&TQ{9Kjf8n8O*!LM88p3+IsBly2B@Gl3jWy%p&%1O<*;@HlA~>Nd=B>VNIRnOO4qA z=3+p{zDbxnisMVRLoVMJ8`64mp-4MBMTOYauRqAib%7ZbOc*&&Dj-~9sWQ~+rR zG^6jppA`duqPaX6`nAb>kt6YQojyzF^BFAi} zqQahLNniQ>0YYCy9%*1<$z9C#>=3jux{+{GKMSyV(@w*ovv~l>xw2^dlBDMs+ zH5gLZ(y);$u+hfZiQBkxL^!Uy#X7Eg#1cE`FR^t342_V(>(hUG&+2TOE%k6u!>XXF znuR=kn}*plGwoCS@#blH1hy;-^pied^2~4SkB+1jVARrwi_9_{@`69HN1D3<2ro$+ zR;2A-R!ymNQwx0k$R|N@=ltc8$J)@;^-kLI2{~6ab76q(95EZMcC0xBJO`RTmYGnT z$6D;1h0u7K*tXr+o}9S?bTCjv2rLP9~_fLNnrpX zX?+sq7;f?XH8Mv!`Ss-Z>fOz$nwaPb?=+V$fr{(lk}Yzl z)S_w$WdZj*A3c+>3aNHOg4s(!!C>YXS1Mc`4;wVy;dMsm!bm+pRPy%V(iDRmrt>&% zEPssmi*#pGIAd-G@pQ4AfWU~Z+WcOldz6<{fiGzoJ*wQgUr5DZMT<(sfcKjU>tYTE zmY2a*ahTwBa4irIh$QH;!^bWGQB(!%RcuU*Hvr+4sFS>t&RW3!UO)l|r9v+mq3|hZ zA|j%hS_S*Y&orI4&-%qORA!~wNkJt#zI}P_%sy&CqxJVYY+Y^bUk_zn7B7t})d?6Q zFQaY&-URX4br7P4!QT>+*z%=eSAgVccEcS45YE`35l6-ec93z)+?Ah$%C`7{-JG)f zj2F{kf8+J8k8ZxtLl95#ea`v^cgj6lV~m%0`Jxq>7mAfmy$mR4uaSvj!%VQiFf$@O z7!KYf$ibRw@PuJwj)8RTYgXU2kN{uooDvclJJ`Vuk@>IJ`qvA%j5XU@-BTSz^e0lf z!iVa*Tc2wnN%1&Q7Fto^C*xgnDXfA{ItOi*z3bi@)I;-?6?NfnL8IRq6rY8P*UG>M zflirrlk>@B-2n$#{H9z)8it8_y%soxE(OCWK37VnzEx)SOmgS)Wqd``wO;a>@ycnG zFaY5!%s)0senrKW5X^`;hOe)aeH@%5;s6U-O<7@><9FO4FzmnT=MLpOzY7Wm6D>F zbYx=hIE}c?xtt`4wFo!}D>w+Bl3;((e;?$oC6L>jYyoSGq%N46L%7*|Kyba!z9ZqH zwt=-e@ltz}cNPpop*d@|WWT4QNEY5~`^Q?q`JO7bwUm|U(2Wv+{VRd}TN{O4!8C>R zLBBJM3bO&o>k1<<7aVv&dJIAD5$de*;b-y225-$i_Kb&a?RldgZ>r~a(?UTXAM=kz zk0%SCm!%S{`faIRY*%|vBjK@8j5uk8ptBW>a>~*NAIk@$xY(~M^`H>oF-(%;Oe}Z+ z;@;n{zv1_b_QCn@-uKc+In7M_X#Sh0A?{$!efW>B0^8v{Hf=|?4qb#24xt3alsID` zoKFI_LN|%@Jqpnce2~m5#QRVL$WjE90VtRdhtS=VW(P#qHcG1phI}7)t2NbCzg&gm zm%JW06(N4#$q}39_m3~~EhDXdb?wiV$`Xw>)m}1kv;&1x(E0MO`O-1 z_$X-b-#t>{`_eFZ?Dwxp-kZSEsSGln4!I8($*x~_V@rboOMH7tCRMkuMvHlI%9pm# zJ#$l0y}O{c1RJ(KA>74*25hm5g0p{$)q-K)R0e0){BjQmHA#w>3(hX+jI*)nS6{Z# zxF=t^swxONl-PMug+^!hBu{s62^V(E3S9Am0MKO;EP~&~1BoLqCXhJN#VY{;JE9QU zt~4y_2quW*vYynx_(RJ69oK@(u0c-_q7SbxwO;qe(<4K@#^xJXqE-!{9NaD64tgt` zh7`&V@|3#-hRJ){`WkTfe+N z&yB&>T0b7SY#Q>WeE@kADQGwyDr`237pQ?W5bCsoJ_>mk-B#`neAG>{AH<_GeS=7I|C>GVpd7xojyt3-sAst(GXx3PB&!7Csu zoTOm@@5OI%c3@KwU@n(TtE- zccY=Wa%dg*p*&c?$XH?Wng4LB%d?Z~Y%BDT-}>yk>jDT%tF~z9qaT$lIafD6G%kIQ z*bffRfRPel`hnN1<+&QMqN6~sf_zlG#t35!2#Eq5fj43Yu1#@)(86QFsLDRrM?jyb zuwiF&!*l0XvoR6dOu1qDwJM$D{o#Cb+SRJGGdoTPeWB%Pu<%}L`+Jt&#X{q2JsNFX zahXdzae7j`F^2@SnOu+S#>8tA_nO=VHKt7A8> z2y)3oPD)u=Ef|3St|{Q_Z9+^&)&R-wm(2hy&aw{bS0GzoNjx|cu`BbDuq)%zH)^|* zsKcEml=i9fo+Ia*!oEe)17DfYfHCY*<}>H59QhBECkD)3zq*==q)XP*oho$L^t_|@ zb5!nAHkrbxRAS~CN$D{^8USYGjF8wUxdK(mN!NdfgK_~PkPy#fDVuc!Wc%z1DHxp) zDL28DDq)>{a@!i!cc$mhld!nQDKM;G>dU!0SysEE@vGbr{H?XN#u42o<**-wP{rpm zYLrX3V@gT*!j|C@zUO0XGOJSF^BKFczduItL1@;vt0CA%p)U}v9z^tEXg%y=_)!P^) z^C#%5bR{%^fR*#nTtV<*6cMH~W0t@XkXhDW*9r*Dgd((AoeR)s#8g6&ZlV!F;>ieH> z{8sha%Aj1^nL(@B7>nr_hY{+IqjG2Awt=rsFF(!IxkVN;f@B_z*UgXsH|(3fs1$s# zjYdal#C-q-USqlzgKIcdfH`1BtqCsZ7})y-(!NOII5>~CXC+_4UZ#05i(4q2K9G8I zX7P}!U)n@MhTFB4kzzpZQb$L1GYjDCE;hCJf`ZJJt2WCq9xq35 z^)}u9$wq!;){`_`<`!9_)co*x{89B}r%@EjU~^XCl(Zr=fQTv#Z3FTit87T}mzTU` zEnLoT2=`=vRa#WU>j=068q(l6GtI?nNQNK<23=k=`x_O%e0#6uMcqD7RTEmE(=PL~ zlx>CgE!zr;TUF8Yaz|BuvEf;tb1NcTKIj}wPaRyhwev|FRR0XiI#nY2YT2ukk{KQH z@mGM5Im z&t8@N;gwG!@uK<&+uubE_GdyWr>duO*ZZlZ-UuyK^R&Iw@x*K-4C3=lE*I=9KdguE zjij`;oo$`=Z4==;y>VT7OwdAY>WCawTG#1Ue6RK7pI(6Uz9^5V@9aDchrmcv+WERNO|2(E^(L}$@6}j1)K6TM@0xn2s?Xyky$}rp$mNgv#~!8rT3qop2{+5b2^7_H>=m(anrsn?|2wL;aQ8%&4z zg|J$jtr~fPhq;7QT7I5K3rzZ->c2GJzg~wSK6L55H1N^9n3}DK-OGqPP3E4<-?04APS1PTrBT9zwu)#N}waXkM5w4%lcE?`*?al>>t-$z${mw*;HYE zN~MhqUQD-}Z0W;iUvqix%3FGB(*hU+<*HeaU>E-(`I_snVik*Up=bZa&}e~x>5K~7 z>+F}W+?uqkha0WF3g=mUE!*wu>;L7E(ZBxc+j<|3qZroYVAQt)fv~GPD}yTNeJug(h)zSPVhuwLpXql=z6Zdq^Vz{L0E=!ZqpkYnT^;RJTh9O#r>A z4ztH{|A?W9s!#cT*ZV7fZ@rTMo>RSQBJ3 zufhP)FT=DiW1B%Kv5}6E4Mk9XMZ%*6F)?+>FNj`OMN0-`_%8m1uDuHqgONS}9PSkQ z1?HhHvVjm=%G@>p(Et(uMp%1MwPiLng2I0|H%u39dB1}v^kT?wk z?S<~lUZ!u>J6kn5y|4KF@>H9>QaF~I2||>%&txNb;xThBG{#jxx)*lW7tk|F z1Q$sCPQGgs(9erIxiCo4Jdc6LZT8`qas0zU_k+SJg=D98cif7BM%wO=AG&&4anJO~ z!@oBTyv+1ZXj4yzdCc;w4cxItDD@eETRk4BiuWOn(faX-5Sxn$Fx->k*({XntWO6p zY3qcP9@MSgOyK^BaL3qyfZc5-(6w4J7)qpi%!pMdpToLyKi)Bk-eWd*rM<^=KPk5_ zhgKP598wPlZbi(%ieaGx&jXk=jV{~W;_Qd~C@6~aaIltu>#l!vd^1e9_^gIc_)iAdlueBy| zbv>P>j*#>{BOOSjdane&XC!?BilU2~m;QxpV2HDqFHmNXKr!(BL$tANf&0<0iGWSw zjZ`*SO0Om3cSMeNwX`Hb-kqCl)}#l>#$>FFxK0#P5MUTvhb7UftQls-)b+u2)&Ug z+%t2T@?qwUueH@fBj%3%1M%X6m^S52*O?~XAJF*Qqnnox4$-k!^d z+q~sQ_dC7Z+uufwT;5scMu%@qAarDp-nSO!TT6Nq%-K%UTkdwGFVxdIC7pFUz!-Ly z&7;1Rc9waFA9V;=4#jBZ@Z!6I>knWEdnCU_JNnU+X?=|X7OCBjDBgjm${|KW;^xz% zPZ@4K&7<>h(I_f?Ly)3J{7V*imby&gN)ljCqJR;8_x4cYN(*ZC$Ml1ow*ZYq=;f<9 zgHV{=sQ^5L7r3*3t4W0f@)mVXQi&2`ZCG_U--WFYrj`-Z0*gAUL#9H9UuQ(}x2Y9q z1$KX!tMkcM4#52O@~Jz)m7+HsUL%Gtdh5iuzV{;3M@PFYvAjQ>A0J~?t!~#R^mZAr z={r^j`kc>9@bAR^lCwsxyPpMr$e%b29I1Aj;adtUbbd8nojE!_-qY;aMrkk?_c7Aq z_s8WP*@IbIGdkaX?X_KU!O#yHVt>?+cJH*P6s5VB@chJlrY{b=Zkkr z^d-J62p%SE#)HH?(&lC;FyWpMT$tr~HVX`4eJI)xF!n-wFRXmMe-?NWW^vQhJ^2RY zmhCA6Nd$As5MF_pt8pnW(c6U^>i-wf-~cCbw6flHz-%ZJ03(PcaR=dCgLxxDdR zH(I+oDmID5d*43tNTI^QDbh&pxV>F6A4OIYaumj=oxlEYJ*{eHsp`yss+6RcVP6WV zQ)a*s-(~37_jJaUb=Na6ByBH`iYJ9vM59ffHJaX3Qd_`pC2^u4`HbD$I?VJkSM3;*-taV6M+;W=tIysk~3XPCRZs?j*I)Mi!md?YGBjuBj`8{h< zPe?X?s&nR4-M=_RyA?aBm^{-7{30&K2U7MhTcxrGesXc~wg}OqZAK`A~UKp)gY1YtpvTJ_$wMArcuDq4G zyzOL=)$ZgPKNcF5!@E3U$tmfz?cjMlSKiahE6K#ra;~1H$Ai_d-QJrw7@(4#^7hb5 zj!J88XR+7fBr&-H523vJdL1wfFHGjE zBzM2=#p#x)H*`AN>Y%KV%-}2GC2_UVv%YeV=qo4N7Z~lSJH@Xm32QWg6vqd|zAVRY zNgz0Z^$AP>k@x^?)Ti+JEqJFm8cLCTKho5FA@39<^rV9b!|_&f6Ul}0Y?%uuGh8Uo z6Q^Q?y&tZ%k^FKpJdd=UCcHL2VcX zHeePNL=Zw4E*_MILCqO-)^+Kq$U6xdL9YZ)5889ngO^0D!U!-yctElvaMS8SHB!zf z_RTL;N*pKdlxpQZmfGRJDxjDq;$(W3$!S&3(K1rz{VC;BJ$RwB zG`?WL2&+MD+TG<>i$;%Cy3^ISlDvLG@ov}l!NWrOTPN%HQh)BwTTxl}uPpW^eF}J@ z9yeihR_M90L zj@wi*2M!S55ZQCr%Uz$cYBOFsVGcZc3Fp0YkZ|Z<#=>>ab)_S;3T)vO`)v$)q} z)-FGV?ao%?vSb0_sr{5t?n2s|khJsVG*n6Ey2|E}p`gsTp+8fq#JWDUl&zxIwLKp1 zlXur=H^p4-t4f0Bj$Zk$Z4a*}d{CteWq1-n*s?RV`>^Y%zTU`R@4194$*)5UTn5Gm zQEf&K>ufEPn%{aJ2`z2wJ2d4QxEx}mUDD~16ZiafQR0g|rh$EZ>#DpMT;8E!dKX4A z=|&m>Dgp#ImCbMeH;m+fgvoJ{eTJJz%p2AjF7d4|Hc@`Z{SWxFCc<~dY0FcnYXcRc z;-%<4pRH(-iKyS;9APs|iD&Bq1167wsp zyw`U-ix*cn9{FN0=pRDi7Y_rzGH5n>i{Nr%fO1+r(;qf?fL?g`g%JbTIJS-j+5n~Z zyo~qkh#}il=9gJyiw(I;;-Bp*Wih^IzuC-#)(QlkZ8v)s^F7Phi-V%DvPh<6Nz87Cd12FWv zFn4jDWVT$Q<(f&u769AS5nm z8(!N3Eip$~UM=NELZMJN`=D*`p3pNNEcejo8A#*(x&uGl-ZNYV9{LCC&C1Q3>+5pK zPlkjd$0*0my*9kF=sZtWtM{p%pQ*Bn=3fpbwZ#S!sXI;J&S*KIa3JD3_-=uYZeFvl;=v-uI8SipKQ31<~ z+24u0z$^LocLJ{@Y!#dW`}zWSC5FN*?`+5`9jjA5C%EuRGUd78Iwt}KnHnsixIoa_ zWDEpn7pi?+0#&*pT8u1bJZvt2F)N@;lPJ7Df$?(_wmc<}kduNIp4LXRfKS7~LPD8n zbMPHfV4)v7fUO&#i=je*7j#ju|4Cy!|IaV}zf9GzJk-hfI&W`f=vJlj0gd>gu;^~s zeENw*s%p=&fK+Uol?)_@{TF^qkY%HR({qT)fq2@e}U3 z`>x5NaK@_}ht`errm#r)jQ0lHe8DWF)du%c>u%h!JW))2x>v#aZST$jT=e|?H!Xer z>4j~ArNMZWqf8bJ$$gXfHtRKoy1M#%&i$v0*3^#&ly<&H`CD-Bc<9@6r=K};if*LD zTOQMUBu+Ip-rqm{-j>GRuYV5n}ktZAcm5Vf#_KWCnwmBQxJv75|`;<5dGSaJGEThe2 zZXQ;GN7e=SoJJie&_2BmkvHdhIal0FHKp&Zd{v!z?=QKAr1n~5el${N7|*U#qRV5h zK%A6bXgsp8{TF6xxpsiwsGTkS^4|FuUpUYGHsuaiPCZmppTBVL{?_%0SbUqOKfS(N zFL_BrBE&k=XY_xu_nuKrwM*YPy@+B#LFpDiqzOoGL2p62qJq?@KddGSy@7JPxbJnCyj2b#ws}{ZL zST+KDt~GeKX;)>(?r?jjFZGy*R)JCrGO*@2!*w05h`?IgHZxRs#{Z?_OqTCYML zvN3oB@2>;7R=Vrw7HI|$p&zh7qhp}_`XhdFr5)sx6pBS_e(D1}=Ccl*SNGdxu(R~Yfk zZe4agbH(%k000CrSU-eQV+TI<&B6B)d^g=!z_+uFZ%%3jjdpw(5{yn<6SPcW>*71B zU?|Qb^QZxU&TbJ8H<|;o^luHRHjYlL$p{PCZ32D43Cm-gXf=|&nK)li#uYD;(}^?m zA;T~J7w`$1w8;>W5sSDwaR175L)vCQP{Ngx@ow$Y*07lnHvJ6&4s%&k(`uJ^)vSlK zCTEYolf%(y_n{uRC-B7jIMBE8X8MUhsxe3fEMUyD07H7%loG~?HsuYt&iC}>v!Cy; zp8JdM;^Ry{T9ckyplzT={)gskxWD9uSW#FW_q``OUf$Opsj%EEoJ)$dRp=BIge@u8 zoP*t!!CYzQtJ0?290iT0QPob%Yn9biH6!vf`~qATnCmisNmNlB?jKccC9t{JN!^n_ z*()?pd_jMNOC{(hxAnJP-_Qz=CGC3m&dXQizPPV8u@)XZKyMZ7e)1lj>_7b_poLJ& zxEZ^Gv2^C89oSfuCZ_ggx^g!4<9L2V}q z9p0-;cHbwg^xclNNk9UH@Zuj4s+q!oUndZw5@e7%a%lmPloPF{LV~H0jPZ740IoQ3 zI0uCqmH1LVW`vc5(W{vFA)Uu~uQ0D*qQ71}cM8DY^X<2#EyJ&sKRtB;b^dfv(~eTW z^~=W5KuX~i8&me#SD0nIA}-1p{AnkUH?v7&qa3g90l|kZN31}4QX?%5R=S6@tTfR? z{PELIX6aM0`LgOwey*^!>)9=8wKuT*KR)D2V1xaKAyhK%W4HU-sYk=jhrD+z{HB@I5D!Od*a7c}!R5r1`OEX8PruOT9D?cx75n>R>44 zl2yBw$gpjj8GHkm;s4>70CXcN7?qg3VoLxoePl%;x4%uxb#WmYpO0FOL&D*C_rga~ zPwO@G$x(=Rc^h#?{^XSQo(YMy5@hI=tQeKNg7vx`-r^F>ylmY_9j{-k?u!OLn*L=I*XXY^yKjB$b~SE8-(U+T+#a+6 zzFZ{e9Q5JoZ$TJ^0I16Gyyw#AKv$WObMA&N-A1_k<4#3DsO=Y7I-~i`FN{c4C1*V$c!B$r9N55q;RsR^F zc|{TPYxVrEK-m5Sj$dK*V5ocX9$|S;-)GtrTz|C9a)RYpH-4x*GUrEb)*H+Upc)yr zui#F{rsYS+Zz9+2u~th5lAFE?MHJ~BHNLzV_1qEz<(%5nn*@%N*s0sPvq(sI9hAsd@Zg}oF+FK zG?NfCbFUfuSChy4LuIGnzeLYi%e;_4&T_}wLe;Sc_P!4=)uUqa_yF6*&B^?9KgG#VfOb8B$N z0AW}XyfyNB8VIWj)P|^i4(>yj4sA2gXxX6#?@hL@&~V-n>#N>`Bh}5b=Bs=EtOX#w zmyC^3TXL#*_z_ltW#E!AF*pKKf;9A%mZ=8Rw|)%uY7sc_RD~3bOq}LvRk`aNBy+ue z9gS!?-{Ex4w^Og-Qj<+Ym!Doe!!cf?M0*vYjDJTa)|*#qcKzuna!}Q?rN4MF6iH46 zzDqA_>HN5C@5}#<+j~*I+$7dP7g`g8i*hqW>v$P-q>70=j}#Dqw7kB^2$WYfG1Jw9 zx^4M$8av zzJNS~RoTaamwQNU2Ui;Ed-{ToB+VvK4BJaq`Byym)(}kq(ouknInAYFvRO|$5@e`o z`m3+>(H;fLU_SA~wO=a^z@J-w;4@I07G@@ARxA5Z4}y_f`Awr^`}<%#TNkzlxzOL& z+w4}CvRBf*12x`;3Lgis9d-&Y?|eNxUoIVsa?Kg0{*^sv)&1P?SAL~l_-SP&e8WAg zH@KoSCAlaV=T2wg^S$r1wM_QjM;e~RUC9tjoP{-nYb}oIJ7cCJc@v(nN_ZvC$48Jl z=U@$XAE&CvM{{}d`UD`zgOvHMA?fT&_%p9>Dk~rUjy@}0i-3CDdu5-B7Bo{+eh#@n z$4Y98eK`v(q_xZH9SXVKfV|CM3Uo1!Y?}wp$7P&R!r}Oq2GvpB(@66)A|zzf7|jVg zVwiRx+Pp12={=OveuNHR78_a))@@5$Gi*!i0_~T12KDSByH5vCADsd!|Z1TMHSBFN?<(SPjt-PjehPNHby$9qQ|BwwtxhXs25sV}Zy z#+`9bWkggiD-G*EAa`#y^{zv}N(ECi^)lQ6FB7|`GfJ8NxQ!I6`N#)>2^pVh?iURM zo)sQ4K`XkgCKksdo6S=`dXW%Svz!bOXR%X`T>{=+*h6YhAU^2wj{MXBe98tG* z0t!1w14P%Z1Cj7tTfsFgDF0_vWksFW<@+pmxgK!d9ZuY<_Yn#+-o4ie)8ZWIfuI&}xM$JWC0Z!-*)mk$&XCV;K6!2>!eetBX-R8>Ss&@}z%Gfhbi@aO zeGhxR$yR4)97nlEBU}~JYHf;*APlu-p(O@E#WQ&ZGi%$44GQEWWRzudCo1TEzJT~{ z0BrZG`pS}^bhT#YuG&(!XI^_Sql}5F%md0^fPA!CA|NF((hMG|cZ-90m1xH&J6>_3 zdoM7)_bRX;NOj4T)Q>9Kw;rKivx));``~d86!R0>QWSGwfLyw2Ri>DRT)%sI(R>Ay zM8hhNyHPpn(a+ML%YsMpLETPU!+TWxr=-u0< zSrBH@M*=sy5q<(l7VImlK}!e&=WsL*;}v;Q0l%_#6+yHNF`uLZ&pK?^MVOtgJF{r` zGi~iv?_^CDLk0E`CP{rAMY*bno%lj39E%Sd;s6R+)$HBqfESTYd=YWlD?mQe4Z^Pk zaCK|VCL9cCiFd2-bddb#c>h)srCq-8_#R!6++IUVjw4jG*fOX70&0Gcyi9u1Ko5+z zWucmR7?Dm)vRVQlIetYY<0NJ8v~Qbz|IB+zSB^RVhI~Q9a@$PE#fKgrc2km6vc(Bmcux;(Os-7>NrE71ReOHZQuf-=y0uulKYp}S&eCzzuNSaM z+{}Y8$=JvZg*+uyABGCwucrYBwArW1g!oJjp7#aZJ25dKnBvaWvKiV2ZCSC%0I{IG z)mI7P5!gpZy9;L*0ex^AY=>)e(GO9F&?)#<@Af43F7y82rZrLPs-AjVOKk9*<>em! zz$4}Hs>)%c!CFOiXm)2V&^2u@8mNagwI=mkT8;Ef)eoSYI7YyI#Qw(fXD*sGc3>abQO_88QVq^_X5lEhr44xOj>WIstqtD%*d%jyS` z&VKp44i7Eyww8WB{j-9=5Gp4NU70gb>y9JLKp$JCZ+$x6NugkF7&lM^l46qL`_>%= zyDllwrU;0>-?-n#!v~x+rPtEGIMKnQvpqg9Qe1n|UY=g$gCz^d>GEDzWRaPSB)zii zuWv5VuN5f>O)qMiZ$RELQ5sj6TbdAS-?wx=W{ss?HD z?cv3Z1qt;zW#W|d7rNMu6&Ad4d1ErM91^B>iT4Nc%&SDF8(E0Nx!D55bAICIAFAix zG5*6qVtz&a3}*WQ(r|6G8T%~f(OkuWIv-P>Vstla;%_JEWv?%M2Z&pw4eD0ez0NFp zSaK}CR|8KDH`gsJ7kMmva+h-5OfR|o`Z7AD+ea-}ugM$&^w&%!)~|M1^ZTw=Xau}U zQQgB9b*)NmzSsF-0PWt54Ui9azd7Jr(SnKLhda?X=F|D41Du}L-qAf8{K3V1CIyh-5yyfv#*o9tsW z2ShCfd>@4eLuo6^5 z@xi_c`V)f$wKJ=p?}fi_=?ohW>VdOx!+8`;!S6u0T3yG541Kd{(y((yAQ4eE88p0A zP;kDer9?W*fUE-^UniJ#03h9%wbsMh&+rqYqx3&UM~8Nt^i%7;lpFe{!ooV)(99U~ zCicBHGzH$I>r8pgngsV*d%>H7DI#nt3AL4knrqV@!sWoyI+BHRMc~2mcvorP46hwz zU87t^(Cg>_M)iBfb7@6LVADQ`apjHFM}iQ7?EGrca$Csw=#rvY~PpYUwU@s#aQIB=Shj5z|`S3lgH`YP_E z3~^-|`|CtG36g^rq6ze_L~ggj50|A&J3L_eq$6HlcvM3VtC9}Dvc#z1%JON{DOAGQKEDC**>-luM^`MQ;FC z*IC~!|s zLcj^zcweh`Ak2@gZCQMB3#ei$zY~k{t=)}&FK**Lcm)Mis5qugt?J;&``>t^NE5|F zF$TXPXT^~(v;B$7zB6P4@n4=_8p)k35X$SbN=E-o+giWosQ z?b985tV1$G_(VO~$*G`n)gXcxQ2(W(tBgh7$F?7L9zH0-+IVuUPXt>i;rg!|+y?Ix zu)+5Lv@f&1cnK<+&B;(9XSq}$xweiitzF9i`Xi7w57sVTkvvfTK1E_Mb;bcXEwKdz z_caL>O4Z>pP?GfVv$3T}scCITpnBZekF<@b`kvL)4z+l|p$5EUIRkQjZ^c{(l3441t6smO`rd&x9eCKfs7XFeF z1CEwd}yFZ&o3wTp3yI|XM zfyD>>N8!fc)T^`snd#BS(9j(T?yISUwn&Z+p#JJst!}2>yju-WTY%BkU27O^SZO{y zEL%Jhe+e8b!>|?*8T40h^Gt6VI-jd_t~l&a{8!aEnRg?0o|`UQ#;YSp5*$qYwvI!-z+2a&_YOlXtchI6Ef=q$v#OykN>JoOSY(< zNxFs&n&BW#5q~}AcfDU_C6p#ej z)iTa2S2Q@a#`j9qzO;RLTYdM)5>fBzuYz?v4#GwZg#-mZtRcrcGi?7)Y1N&|cix^7 zKvE1iL*B2zh{tDLUxJWP?!L-cp^Tk9ZyT?X+%%hZIG2#(Dtj(v)m?Gz=u>mL$Vu=j z*?_9=NTmpP$dw zden{u1lBKZGoNJOWK3r6E0L#b^^)9k-dgiK(^t%iNrB)?xE6$(%(nsyj+H`-LywbG zUt13*pVwnB#(9=DKgNwLtszw9U>;{1mTt#Zvy$#wPT?g4`BG}scs+8>6&+s2w>uwO z79LLbnIVYs1eS{^-zz}596@i+Qu;AQhgb4oYFF3F74CqIzAQa*I`xQ2zljZ=*|%4Q z4TBn(EuASa#dN?{tRUakc$#%9gLKZjHc4cwx@7Box6AZ&RX=U5qV>!7fvt;D8sCcq ziJyU)L1vIXlbdl5_S2_a@oPI9eJAO+D&}2v*JQ4x=#v!DIvxNnG|GXj$n^;vt0@Qc z?;zyKu_dmMW9!#F-wvP_YdL7n94IDOJZ1?$36?$v@6JRZE@HxfaJ=E|=AwI2nrCs~ zkRv`aJSKq=-=t7no1I_yvp9{&^JGaXb|)ph(|hcfmd9*nv_5#j7%-R3$-N{g<)zAY zEV1jPh{yrnP*UMi?#ocIiQl`s>zabCUR-oK+_v#pJA>&QX3p8>Tu(K&7#-YFPnY_H z&|gl!v+uFMbvQj`KnR}(v7Wp<3>uBT3Z5z4I!7Q z>3xkU^W~??-gyWY7Z$#`N8v3*{_?na)$=b48|D7)-8X;HmO)1LzOnRQ+QKt)Nj!5W zA8L9D0^#9!nO0hAioqK3mlIgBRC{lb-hP+8rO>Qw>Ju4G1VBX z9oYS+Bf+ERh@-lM*v6}2J`9;IgGD0nrnAVJKn_v`#n)JrSLe9SC|MjFD4ujYfB5GLu=tXUmQZxYozdA zlWAUTsw=_-K)ly^9xwZco|R)u`inNUK%V^ENNNn`9#T;Ju|@dV(pYW zqG{{1Mq&WI%uBatz| zQ>GS+cDE-ws1y|EdL}q6>c%}zr*+#12sm}c!T;*AHl>s>R3~uhO?LlmYJ+YVHx+Wh z+~7_s;*$o< z(tKbu5@@live!i`9#Zk<{-eyZr_S>S;-~K?k=(j|{1|?f#6z&=IZ7t2vR{ z&efsM&UBh6@D#xWWgls!_Z(D@FY(=K)-<-<+HzQPh8(Fi!m5}1!2NkB`!bUu|F1{W zaKf773=t4Sok?*O%Gmv0g&A`Zze_Ys-Lljfa*)YOd1^y{uRrzDUXVXFx%byXHIr8o z2#b5YQWdNS>r3hN_jh(>erD%H8H3DRY+khJ`XU{YBXA9ZMC;O{?+2>_RCS^yG>*&! zB6rBN;oQ3q;1kbL#daawJiA*H)s>{TS+L5--N~DOH?MhS* zs4kfdFQ@KN@+Qd#A&tKHx}ZaMzH~9!U0P~7)9c@MG#t4Vw72N}uzu5)93OE}^D&MA zA)rbc|BSP#D&Z*c4adW+IQk(4M#O!7XZ7!P5%0#oTohY*v}QFp@n~Ze_HpN3D;=74 z$yH+NQ7Tarc(Wn4UD>b?I`LwHa{jEumrJNRI`jtTDt9dxU5S3er4q`o@KxK)ng>~> zHEBl8NUo!}+A~AUvG_o@;^5t#GYuQPjEjr1eeenQ{)5>Lvz?ky(s|HxAC}*Zl1PLE zs!JSLvnRDwAJ=&M<-ltXZ-gqJhyw@pw%4wovr*`QqQSmmF}QKrDib5wrzX7i;#B<% zK*-9u!>rrX6;a(g#-*?*mOGm$)~^)uS^@7DTNVEf%h!oi^|1uWsNSp3ixbJaLUKrC-z&!e~*HT#z1DZlER@!x?93mYu(}$*;vO~KP`C#{r zed08(hJ5>Qvf72D5C*RZsy?nj%Xb>mvHsX!aiKcW=j`G^qX6^MGpPI(0~%$EzeV#* zR@WS3S6_vVIBkrvdF?B>4pnAA*LhiJAu5(1_tPS%{A-l?F5UvwsQb^Y?!_eUx;)v& zjluX13fmNy?ZZ3R$E@yAQPXA9)I7wVQJcv^ZccNP$4b{cgZ+9c7Wn=;MNN0EQ0UtZ z!vetcic`NEKR$g=I(M^)s*ka)`Ry)Ms6KOd4eoU-J-V6&iv6-Dk)l+9--ffr$5dvj zEJ*N~or$w}5jb3QwcGz(GKr>!H-x@jjo5=PhQo(ue2LNUc$`Jk@d2Wbj2*g1cg`*k z*mUXe;xndh@smS<*~^tx+@w?eV&Gi|27XWWPVP&2(gH7|V0t1uNox4fqb+Dmpse6##|pVz?xZ(ci} zZme>kt4_e%Zy7YTO6I#ViO~-j^${q8%VJSMWxMk~}lAsSBk1{d`h&J$+@j2tkOw7Resh|Y`ri;%2 z#YY2HPK^dJ()+3Y;+HMBo5eyGuyOd@h#oB)+>7!e&GjOO;KiZ|Q_>Dr4qL7DirJik zY7Gs)dAVqqE$^@GYec3hDMil%LKY$#s;E1mmYP7Nn0h?UcsfJbAQC z{0|=h`#a@7Zg+1NMR9?wnyx_)AfXHLS`}mH5x~IPcLDmc(J1qI-A(c2?^mSGIJ;l7ovuQ zB&SW*7J}_fMCu>2eq!Pe0i8b~YwOeOD3l;TRfL86Q6z`}Y_1=QdBYBP6zU6-{qfWu zpO%hC*1(&&d05Ay-1>o;o-{ya;>DiSq;&4%>OGG*iz^sun1(Nnm3vljUc|G0z)zNJ ze7yg=mBZk{<}C>e=;8f#5=-vMj2{8reRF#xXXE}Qz)lt#NBdmwR|59B+gqJqFb!yU zbx%w-j&_lA5{*VIPu2FRXa?e9_AND)R_wHN=1YvE>lN=QoKEDse`aY}gBP(X92&?s zWeR`lly_59zJ~K|pzEfO!gTI?N`&WTK1ojHDF5R}A^f`VO~ptmno3K6(k8HomD$sP zUXgr#kj_a>moISJV+okclW5WBlQ(;F`7Xa~+dHss2K6=4FY1-|9J#KLT zOLX|^^tmEwKlzn%L31uGVWz-zJ6qArpVF49hG>>C4$t9#2nr3aF<8HKuRQSWmf%Ku z@_T~ypaN;Eb-uH#{~*7MQNOV?WIC?{Ajh{VfE>xPR~dh)1M(K|JA256EUp($EMk~Sc|g>8z^EA*nvn7j(UEk3z_)+P7>mz-KIqns;(Tz@oU z#ygnk%pCs~9_;v{JRRBLKV7w-z2Fk(*`ySxS$qzV{uF>;RuGaxAc5(3{_~kLvmZ1OotxwQiE;8@Gb}m#w6}&GGa%t-H(lD%o^Rw zc+2gAFW>B&~#&G`H-alcKtm=h=P>K8R#fIh&>4CJE9&yp7zlvieG{geg)~XfWuJimagXX^M+Yc>we}7oAs7%In zD2PAh5`WsqHyGF)$gov5{^RUQix?7e(RHE%mC={G=(4|EOV>MXUZgvHfv%;8ZBUHQ z!si$tz{^f`q8Mp`6YNEm^0?|RV0nqRJOJP4s&jt!dKJs zHF_(I+KVp|^4T|dEQ{WDw#>z;-RC}+AOApXe9k582b)C{Pni*#yWX`G_dcX~O z=)9baMeYDPhpC9-hP$Qdhq!Le&yo-mJGD^BTY->xDDxzmzH4OGA6VuGy8dCS-Y*k8 zL=$+XDOIDl?`7q3&4*5*8!C;H`j`sYbxk_SaA5%dMC;*VedY< zam{uFc62n{Ozg{>hKbXQo=R>D{9^bKdP+`GG7ldA_@kPE5yhNjaj;_n3qHV^eK+~O zzr#Jr?msP7fV=^#y*Rb>w0?3Nh8(mAe!1$R0K@#4H`_EPEXx@z%8Mhf0pS=^w;^z# z-@{(`V{ejWav4u{S9_vZosDn60{v9cu0KWg+4(^kHaYWCT^NZ$R-Vi9u#j8qw-_1G z#y+IU`>l|t-oh=+3& zRv$_|*0IDO;k|Ji5k=l09QfN{@FJE*fkKmxyjWKU2jiPgp>8sl%gFvx+qiI;i|d%! zSPAw=8EA~&x5M}gWq;cj`M$Y$etP~&ll!#Fx(?1&le5?P8%S^j{t$Ti0L2C z;PJ!G%AOp-bHC02%<)s@k4Z)m6sfn@Q8i}*_X&K5bJwS%Hy9aKl|Yx84FudGX%TJu z0C2JI+FWP2MXdWK=3^O&sv1+Mt(zyQ>YIulw#B6l{r+p6U#NDd%XNPcB4kpB>>zKz zWr^=6*VAW2ak2`Co*HnQz30QNv`ck*m*{Tqpa_880DT7l>G?HvX~93o zb2Od#WXaD10L!A=C(&2zuZqrTYqF=ILw|^}XHHkC2*%Env?GNIe8e}4=^`yU#4=JV zLdM1RL)n$^>}F%;k7T?uM2ZXyn@N-Ydxs$Cb`x0qSNzPLEq)mHg;=lJVN6Je5UTor67O%O|Lf)ECt!ll;v7-;|MmVq1O&LJC?hDj*cl-$+jou|IPU?e}&!!Cg5207jS#gXVqhU9QdS=vKhjOuop>HPb^~=`_tfL70|`e zEC$StdAZL^N2Y`-TRgH4F4+l&&tEkU?s?Y{t)unv=z(sE9-M5`gLtb}%a~Tig`sx)$ImpkffW5tyEP@5Z#mN`MwPcK3{y5~qyfJ`wb#H?c~U zn@{}6roDPYR;xK~7pjHPK7z&FQiz#}LiT;!t@_&6m$BWzFCZ2l2J3q_~owzIOc(( zfCq_k-HDhG7ksrybft$msuD9E=#DCd6HsB3n&J4azW1ntF=C-b_+DJo^%d9+J;6I( zU@e1BUe*U0PAs=o6&srdrh9%wAG*e^r;^PFdo?&j7w{WFi1=MYt-hoxlR<+UP?=*` zH}p!(<4Nay{P*-88{a?e@hXd#XGo*+X(1!+3b$*{L=LU4R=3YUs-k%;lfUDY3yX54 zQ|3o6_seCFakVa0lUF+j?y2wyyU!RA0hGnyI{y@v13-gmBwk8pAB?CVpw7){bwXTc}3^e=2eLlDK&qp(jL4Nmw!zu zITR(dI9<`0G)(+Dq*`@YlsnW)?EGmw2*H&T>RfFP&Sjfzes4@%kNLwx1X+Z-oQZXY zZ1KdAo7C$J*V4lrW$)oL6j9av1Fy0^e`x=}+xbe}F|sGvu`N;HMpR}&3f1^s3zpD6 z=Zb+n$frr&g|j*p^h?_=e6iLPCq2IxmFgMv=zaB8&(^Op!k;R~n`TOfo&}Qfn44>Z zC+doNyj*2L8NHXQASS=O@0CD@6d=Xz-n9&94WIa2xi`}B@ozyBb&l^-QcIt4Ql}MSCAl6xHErE!g#ys4L+C~z6tIY=dMW|x4YVk|7!JpsWtLd4A>MYK8RPrI`vlZX zr7)5_gO3Y++>`iUAx?yqd?bueo zT|mqJy2r<{YD%q=h@Qi&c_#;Ur%zJhLNmqQnWwYs7^S zEzt#)DnC#LZPvI?Z&Hn`@>isOQ#;js=J|~L*ab@t5x(E(uf4TU`4?95P2-oVXGd2H z+G`>07K6~teM@V6t!wFH_T{xXIR=M4sH4o=4b>{sjV&=@(B>}G)mh3INg+!fhx9o7 zoMe>Rcc$WMt`0b~r>+>`sUf^1-u|wwp?tY0$%$bfYn}Ik;j#8okoMpq^Nd{~2mhqM z_}Q+NsY|V@S4G9F_G05}s?IVrY^ZkcP_FI&8E0jE2FWp^jXbyS#RZ>Zpk?1QCB00$ z@5Cb3R!b4-AYX&&taBLkjXGpyTqGV+K3a!@#FXEWk5cBcU8}?P9GWZJx=S`)40$Hr zj(y~r;Ndsxc_L!*qSAXIEur$j?sY&0WIx}Hk0mT8jWh*W{VA6Qw`B=vv%P30W~B7C zhbqREL(7zh2%Id-JLwhl^-cq-BA3q140b+y#(dE;!gc>rpd+jb>~G6o5T&k^M1Q#7 zqB+>DK}3m_*%H*9%TcDxkuKbrjnlC^Q{bAyg^Ak-eNxL#nSiEwioYKo7FjXg>bcdk zDU9S3{Sf8iuZ`*c0d?J|CVc8E5S4WxG>_=i1fuuLr6f%_aJmh?8%@!$%L)5U<`RJ5 zO^|0U%&bQ7DAkhGtgIIAPy6vL*Bg&<{3)kzX{I^(VN&LGH+l1)g%8r`rd>TU)MCG( zS(}s>gsR74y2Y}-j@z@p|5;l#`}wMmb+`{Bdhc$*3#|p=7X~@1xe5LcQuDY}Mp;^~ zyxm$bvx7)qthM=Ce&w~1?DtnNk?V$O{;9(dB4_hRay5PDyqV#Z$f`AGtJS5r;0sC* zuvFvhl2u`}3u!zvs=E(PRb&%+xue@Xav412qSsuQV|&C)GrUbr5~~6$67cu!aSym` zM`M(!J&>D$Y2(h7&GDTsH+pVG$9SgkxbQWapuAW*($2(g(5kR}c7}L*=@4b_<=o$$ z-}~X%u8Rb_vg%BYi5^UhMiE}*5Zr_RP49}ID5JHo3-);oB@0`KgMuD(|rw5%r<(qoo&Wo9+OqDZc(!Q0$d3RLrOP@7Bn z(O`V5hp<6>760+uyQS-zQiYxs`bJ4n1Z~+z-Y&g*f3F4F?}z=;bI4$CeUaSbFYj{((|tm4VLFE(TnEsthWt zy=_`~@47RCRmOr0o6!<;T#1;y^zHZwd-aB}j{T=l;!dWaV!Z66xWP;gQLu;G>8Iez z@m?qWk9&x!?MwER!#lv10*7ABKfb_eFH`NT;e{6D}bm;1c-6{kbR7 z3*vo&k17|kxHbce)tva`+iI&S)cp|=3H4t&`+WFJ&)|UOaa=soWUMPuj*A}?Xi>H4 zRf`ReDmhU3(}At0dw-d~02(!}$b0s@(`YJmNx_mL&td3<%ceu`wU!2uYR7|&)^=WM z`Tp>!YRhx_*l6SooHl2lti2XUTzjn@Ad1_UP$k87_^!rp64d) z*~#}C`q{g$1~n>nKCe_5i9eNFOH~7Hpr#o4Vxe8)ELdg)qGmnS1|=GkcBLWgn<^ z`*t^|OpXCKa!7CUS`m<{_Mou<&nGvP&9fXv$BDT>1^x2I(fG@cvStcRJx_oUYCM2- z>SGB&*?_agVRCM5{*=`|b)s0Zf6fgv&`?>?NF&+s*@7auLZ2QzzE&Hh4N~@?w@sdhnJ3AmJKWFd98R6(tHJmYm`Uz_SfTiD1S%t@8llm{PTq!MS zg9#jqJJ%coWe9seTh;`|!)3J00FQuuv&nSOxn85A489h1srXE=ed{_!S*BovyQhhQ zVIlUNy0^Z<-OMa*`KQMNBuu;asr)l?pT_m-@kjUGSlhj1CwK#{AA1p>N#Ds{_U!Pj zl>l6PMOc_=VEiKxI=~qOuI4+Af6zmD<|h<>m0~x#&_Xliclds3t`FK7y7M;=hFZHd z-cBo)O`Zqjn6S4w=fV=p@!;s;WxsX=0($QoS&P$kI%sB+QCA|)>s}6Z+Ha!O4bsgy z+`zWf7T6c4P^f`Q&p~@t9|jcNFjMZYaY3C;tK)8@`_p82g^u&`oAt$OUmWXe7F@yK zAPFx}mD9(IGjn`&6ucdgk)INK#~{{v?khbmDeQ%&={Zx!cpyAjh||~l`i=o@boU!X zTTo0pxq$mM{TRD4oI8=z@1_S9;g{ny_OB)VLT<36IhU7DjII52pN^)g$BGUHSd~oz0jhLSseY|RALE6e>a{b3eN`*z zAMp-hmnqpiy4$NfPWyamn|m3^9{od3#CPlU?{Hbm5=c=3^qs3w-$CP7h&}4t z#4EqFImgOYHHi*w-70BNjZc%|V3M?Du7Q>!cyLsahy%=0REy&c6XzA=<6d7kd9Dda zgl4-XU?qJ{q!>DJ+PWA)4A!D$&X<1L+L{_yQ<&4USltwK^#yyybec~yO7gSBwA&2E z5h*i{RV!WpKH*m0IYA;TYt0z^dW^b)?mImr9sR)1qS%3dk~m!;U~(n$AaS?njZ5QM z>86o#pgQ4SA?k6ufUBSyRa5w|x9|-L?^~`lfoTDIsnaT=Z%Avme^sSaRF}f3E8yQD z2NNYtl*FpXaXp}_?F;O^P2zcH?bQuSr)&C?=@Wd`!EdE`L|y>h4a(`0+1H;vyEGl= zKy8+FXrk3FRMpmcg9W@!sL2{nbmLq5&eqD0q1h(2W(tM*mu7@I6?`!sx`T}xx&h5= z*@%||^-3|6z6piq!K@Y=o|&yTOddK#Mx#XAtNP307aA->(l>Zk=1>k+R)KI%bWPnv z){V4k2SO*emJy^act7qFTdy^sr5N|PRQXH3fN{n^-?xa$D+l{?qwmpyn#bGAXJSkB_A{Ole|MJkbbWXI zYk0Hvmx9xBvp+@LXC9#G4%YEM#eJ4cv1h)uUKUY%F}LJZ3piUnRftEi!`+f%r&Tov zIoK?nDjCIM4NjSErx!n__CO)>G$$P+D@?vteO4FRW5Iot$R<_xoCzs zQO`VzYr55;U8w7u)>DPLTtjWPl;~COiYTpBl*_3&XkS;WBB)u z+a-F}PKWy+{cQS!>r8hp{z{-4=XcUbhtm7se39>buMo|OI>$fx!KV1>QN5dnPh6k$ z4XAwHod-sJfDRwcs0u63c7}rMlEyOgB%qqa1aR>#ITKI`I~~Zj4d<;+SfZB~mR4YWri^O5b;0*dWwA5F zdty|N@Pb8Nf$mT7Jj=3c7~=GB^EH}^irYZzFZCy=8nUX&@s|S;4^}$j`$M7Dlv?{e zhe}?lQr*`HLtlRn-c3D#fIrtDR-5JKe7E>JAcXO3cO&w*PVnNmle$DPACZrF@7Y3o zIcOLnY{sAZM7j#=-^@D-sky*1@U4bNK(vHsuaj{MFLtv+(jCfB0-?25sv3Dyos#~2 z?%Jy>`o`03WsxJhD499>X{oZ4D$t}#1~2wkO=fWkrv8DiMsyj`{zoqb6rCi$alEzh zo1ac8B4SsQF`d}q&Vf6e?fYc=8Ja`u_29lE^-n19n4?7E?(m!VB|z9lD-y;E3F^^@ zW+vxF?5zY~oX*o8e6kKg&3}4+{7E1LJz9o)t#)KYSs#F)oCMRuE)3jWY=42$Vc}fQ zoEc4tN@KAwM8yu%u$bN6*qiHCW|1s0e>1{f^KjikYwLdQJaBwf*p0-QZD%G%c6mnkx%+Ncg zbNtfWe>y&Pp#YZ2axP7tj@pCG?r-yqz6uISr;W7u6Zd=or?= zQEr^)mp=W!FHt%+?W8OY$Rx4?|H%Dp{g3fNKtKy_DJ!6~@y{{-k{KbCq5ryw z|3^9iC%*ijQ=h?_aSyq^0x*SE+?f>e=51ZEuA$7Kd9HGE#p7_ z2yDp!NPZHAm+~wBw+DQHJ^yzB|E0kHHwrvB6Dv_S`wF_;lSVkB)t<}kVqb4g_Sk=1 zE<}S8xGgV#a9_(-yWs_Ke?!6&>9di4jpcX7!^L9F$v^c0po*61CNA+KTUuIh^0;0C zmQQ4bUrT-LN1yclbG^Uoz22kOe{)@C zd!BpweDC{t?isXky4QaV)lIv;C{7YTIC5(-eN2sh3|7!Fv-$)RW;k;7v%3UTYQ5v5 z&kr0oD&2Ho-xhqvf2&XxX=Y}Y^z<7agR@q?;CncSxl=SXHD!YsZ7ix)b092CG&C3s zn<=UsM>SGL{uWgK*rvxwDpQb*q1SYc0~f`AfM+=U3+XI;T1Zr(AE{ z7vYN2P*3Y*coz#7h5yV|eo#2sHw%jmBhU30?24xl!oQL;*>1Ga7dgt96Xa^$#3xU} zYw$KXRTqz%sxRTQXMW`OwY>HaXcmgB&tWg%dZaQ@CC@8b^_fBL?(Q}@DcaI9GIpgN zovAbA>Yp*@LdmtBmk>h9cZ%fY0ZJ)AMyOJ1fF9@DC-_4-e^MtFWrj(7jGY%<6O5kV$gLliIg>^dh#5FsSa9&>hZGAB)4uUb2AaqoCrrc7yv>`lv$G|b z5ozK4tDTweN9t`jb1&|#>$!q~GV}`=1y>wRnbU+e(KI&RNeD#*c8i_))~kg@=^*Y5 zb{L=DDq~WO#Y6BYpZuKnH^Oh+m^erqEl`qIrcd~F4ITH6I(JfLwPf89!@`Aat(sv` z3>3Nk^g_~!ln(k?ajYCwMaTTgiL_1=%lV8kU582^JbQ^3W|H~hMR0Sv_8o;TKkvVz zu@UO$mi&;r$542b+Gdg30~ z2uL}D>UQ{b?4$}TG_2#S>NYx-xdU@uoD9co;EWeXtJgkP^p<=a>XL+tiHOvF(Dz(? zPIm?h=(= zb`rGFrlFyscNO7w=Sx10y=VL&-nj__7ipONDzqv5%IGim>3fi!$|(tQ0k=n-S!z(Q;Bm6RAqRooD6TX2f3Q|0M|Nx zT|Lc2+}kCC`=()R_qY0TtNgm%4T^7x^D{HCGoKN25uek)V%b@lhCvFR4IeiggC}E? zUTArewW(}ctX8Ux<>kv^LmN1|4`4!5$hrJ$tZ@ukOe+3zM$|TphV2gB!FF4L*cp`J z65O3V)!wpTliE4sd!BMY){vqm$fUYVVrz38)yEIjLk7O??CdZsLJ{_jE$)Mv{fdgZ zyrhuv$vwqLz-+&yns##EbV&B~^IJZOp-M>D>UnalnwYnisT%R{@Mzp4hgVaPAA~jP zmS5|mzJ~RneP?7h{;sYA-X#@_Q-l9cm^Pr-fq%bfKqFHc!r3=K%TGEmvP+-I&)}$q zhli__I9B&X*PbDOM5uD9e0fO|HV;x;#vQ}==bBu=s^YAR?APaq4*&J$6=%)?TtZR9 z`$O>I*|`E()b6QMr|$NF9Kq;uQy5c$Ky^d6a=JsED!l%vw*E2IMRBrej()ml@ycSobD)F3Ym;2|~I$pQib zS;y!GFt)=j4A}4yF9&ybnka+w66DR@)WGH=idEP8mJ){anJ@aY0vx%g%_{}=NIXF1 z@oK#t`|KuFFP?PubK{2Niwl@LDvy7ZwHU>6ZKX_Z& zkhU{h9~n{Y*r3l4@0NiMibgh~mRdmGIr*2CivT~rwE-tQH?n;0BekBgSuEr+jxc8K7nOd{i7#?j zc9D>(dF)uCs!f{G+Q^T>G7;{PKM0MTeD;T+4lb>Br39}`wbVe<%pHnbph;=$gal&L zeiJbxO?CI!{{^S)o)ET(52k`dXGgBSy=c!i*p1sStKKm8u0XZPr)owh8GL-|9G0D& zvtLqDlK37jf8G*u>(dz!z4Z(XSa5cD;=ZlZFg&Xz|E$yd?v6)TBV*%;tF2dvfu!GC z{$j;{ClY@^B-5pJ?U+(*>yk|M(W6Hb2;P*9$imNN*)ktHQ`IOXjg7ko49=(Qd-;n- znWCWB7e!jwh$zT%R8K3=N_j@0^OFL*LW!XL@NitB)L(|+H|`u2p(6iOGGg4GkRI+fP>vJYUjGE)7iCsRv(!HMh zlhvvg=jYLPZ3S4Q<(RZBjKa?{4(R?re2$nB#8d;*9{xFQxQi>N+72`9^kp6mY}Jrx%?At)C4}F`$kR7 zf`t(0O?#Y}xO0NV#&WGnDQCW1OYf=KH_TGZIOSXmXDE za1`vUIA~J440FfqZ~p_%J?#}D4XgEJ=%)8u-p8(~d+s^x0*+g!3I-UMQoA7;_;lL> zy<3E7U<$7^wYBla*lw&X5g&+|=}a@}&}TA1(1Mjq2(KjjJmeb&pqMs*X#Xm7<_?!@ z_NvHwdk6AGlw4fnM+w<}R!fL#0t8C*gsC`9g>tPfFE672OANN~tuD+ou23Tn3q~t~ z*u5P}tqUuV>qFcuBZv`7EFRTi5-E zYW4XLs-~hbg>%uqt{KdC^BJcdKn}sq)hk-Qd*WEa049vm@uhAD(?*3eQIRLkCY9s8`d#> z0ZqE3U882VX(tz?sS;jLEsGNGxwwq~tyHTqryeM+IR3npgeKyCY~M2ble0a<>X;>R z07{RMfz_4v>FXj*D*0BBu6nSZ05YeCoN1U;Q0eEC33tsstqx{kBH6(V7j1wNGm`#% zq^F@(k`QExJ$^1DL}M3;jatB>i2yAGJg1I?K5Y}1bzZAj)`iqK*WR6K|1?nKp!@W6 z;K%_ek$XXi!2#A)u8Ly`C9hE@_mp%&ZQ-E9ca{c06OKhCQA%A~iN!T@@AA!6%f#;l zsSRw-yCu+ni^Ik7FgUZDo15|GG#ESlbk%;(`w>GM@(K#nN~`=ZI7W@d%=NDhvmQC+ z=EB}>X^9o?QIL@te);w{oRVqcKyCy{Kd579=tYW5naluQY~LIi`NY1xq)6@8!SV6P zn4H!*r)R?IRX4Ii*1m?D^__yTJ)8oHsjA<;=c{WcK=12J%}41jX{hcYcYIB++DX>~ z&S|r5p%7;#EwevsIjYln{0Ir9QL3>w%-jbTD^B0Zk0;7mXc zZv$PJA;gI`$3H1jZ3in})brNjokKiSWHB*-oQVr(Zv+)O)dpVO#ARoq#zm#r@ck2R z%17oFnLaSa(+Z+ncu1VH>Z39Dv$Z)>s=$RW02kINq}5*R)d#%%*&=sU9u^50s2SLX zr4tVEM9r-Vjk8ileeJ4lNADWJ(9aJFnRU!+!>}O{Ec)9tQ9%AP7^-Yyetq*4Q7}S%8@t| zAaz1o#y}>Di8cm)0vW_bdmiihZ9Iu`y)v)xB_Q?_R?@NT=$6mz#KWqN0sqwkKx61M! z&3^npokXqVLIuh4^73Q0zPmuKFMfBSOy&;Vt^r|k`t<49dKVe~)cl8pW&6GY0QyUh zmkwqekd5RxYx#c%I4FJ1bzJryhxJ{LhXFkfmo^V%i%gqy@^`4Wtqf_Yi6902x)c3i zxEV$qoy4MPAl&4_xDa|23Zk%4J@+gVUM@p|+~2up$a8akskgTmNMLx&FnQ(J@X*eA z+pC*xn2q!^a^!skF~=*H>6WeTH#7gp4CDfDpH%v?m&%S=Rexn;c#O+Gj}nu)SK~*u z`~;*?vCxCb`Quc!ma^Rhd-f8EVAjV_4#!_R;Y9GC=@|ETiu)D9UaDoJDcg+=Tuz`B z0ae-i;lqbPfY!<1HvQrXGszt)+g<3$VeiVZ4Sa=!l&jj!lYFimJx%QK(4?Gsi`+iG zlQzX+(2)&IrSM{&}qK;u)invPaHJ z+fO1iuLfC1jzB@lcU83AcyDRP^e&&h0<<#bNKLYHc5LU!-H60Ln~(<|J&!B1`qfuX zRu<%*-I&vrKsx{p zYHrIG`oTIrz-_gZZ4Q}=N{ z;j1w)^%)J@_}7>F--ljlpsHVcQ(t}W9{kfc_}vc_<)d9p)Bk<;>%UEa3OHzzIF-x& k`>5Q1TNJ-kHSG#4ENi50oxiZS5B$L{TsdES?nd-~0RMnHF8}}l From f305180cbd323c1ce498b77ba4342519650d981d Mon Sep 17 00:00:00 2001 From: Mohamed Taman Date: Wed, 22 Apr 2020 16:18:32 +0200 Subject: [PATCH 2/4] Convert System to be read operation Reactive and create and delete to be message-driven based operations. 1. Develop Non-blocking persistence using Spring Data for MongoDB and their tests. 1. Develop Non-blocking REST APIs in the core services, and handle blocking code for the JPA-based persistence layer. 1. Develop Non-blocking REST APIs in the Store service. --- README.md | 2 +- docker-compose-kafka.yml | 148 +++++++++ docker-compose-partitions.yml | 126 ++++++++ docker-compose.yml | 26 +- product-service/pom.xml | 2 +- .../ms/store/ps/api/ProductController.java | 17 +- .../ms/store/ps/infra/MessageProcessor.java | 53 ++++ .../ps/persistence/ProductRepository.java | 9 +- .../store/ps/service/ProductServiceImpl.java | 61 ++-- .../src/main/resources/application.yaml | 49 ++- .../com/siriusxi/ms/store/ps/MapperTests.java | 2 +- .../ms/store/ps/PersistenceTests.java | 140 ++++----- .../ps/ProductServiceApplicationTests.java | 119 ++++---- recommendation-service/pom.xml | 2 +- .../rs/api/RecommendationController.java | 20 +- .../ms/store/rs/infra/MessageProcessor.java | 57 ++++ .../rs/persistence/RecommendationEntity.java | 2 + .../persistence/RecommendationRepository.java | 11 +- .../rs/service/RecommendationServiceImpl.java | 71 +++-- .../src/main/resources/application.yaml | 45 +++ .../com/siriusxi/ms/store/rs/MapperTests.java | 2 +- .../ms/store/rs/PersistenceTests.java | 54 ++-- ...RecommendationServiceApplicationTests.java | 140 ++++----- .../ms/store/revs/api/ReviewController.java | 21 +- .../config/ReviewServiceConfiguration.java | 27 ++ .../ms/store/revs/infra/MessageProcessor.java | 57 ++++ .../store/revs/service/ReviewServiceImpl.java | 38 ++- .../src/main/resources/application.yaml | 46 ++- .../siriusxi/ms/store/revs/MapperTests.java | 2 +- .../ms/store/revs/PersistenceTests.java | 2 +- .../revs/ReviewServiceApplicationTests.java | 132 ++++---- .../ms/store/api/composite/StoreEndpoint.java | 3 +- .../ms/store/api/composite/StoreService.java | 4 +- .../api/core/product/ProductEndpoint.java | 31 +- .../api/core/product/ProductService.java | 9 +- .../RecommendationEndpoint.java | 37 +-- .../recommendation/RecommendationService.java | 13 +- .../store/api/core/review/ReviewEndpoint.java | 31 +- .../store/api/core/review/ReviewService.java | 10 +- .../siriusxi/ms/store/api/event/Event.java | 29 ++ store-build-chassis/pom.xml | 21 ++ store-service-chassis/pom.xml | 29 +- .../ms/store/pcs/api/StoreController.java | 6 +- ...on.java => StoreServiceConfiguration.java} | 59 +++- .../pcs/integration/StoreIntegration.java | 286 +++++++++--------- .../store/pcs/service/StoreServiceImpl.java | 67 ++-- .../src/main/resources/application.yaml | 61 +++- .../siriusxi/ms/store/pcs/IsSameEvent.java | 81 +++++ .../ms/store/pcs/IsSameEventTests.java | 38 +++ .../siriusxi/ms/store/pcs/MessagingTests.java | 186 ++++++++++++ .../siriusxi/ms/store/pcs/ReactorTests.java | 39 +++ .../pcs/StoreServiceApplicationTests.java | 75 +---- .../exceptions/EventProcessingException.java | 18 ++ test-em-all.sh | 137 ++++++--- 54 files changed, 1899 insertions(+), 854 deletions(-) create mode 100644 docker-compose-kafka.yml create mode 100644 docker-compose-partitions.yml create mode 100644 product-service/src/main/java/com/siriusxi/ms/store/ps/infra/MessageProcessor.java create mode 100644 recommendation-service/src/main/java/com/siriusxi/ms/store/rs/infra/MessageProcessor.java create mode 100644 review-service/src/main/java/com/siriusxi/ms/store/revs/config/ReviewServiceConfiguration.java create mode 100644 review-service/src/main/java/com/siriusxi/ms/store/revs/infra/MessageProcessor.java create mode 100644 store-api/src/main/java/com/siriusxi/ms/store/api/event/Event.java rename store-service/src/main/java/com/siriusxi/ms/store/pcs/config/{StoreConfiguration.java => StoreServiceConfiguration.java} (52%) create mode 100644 store-service/src/test/java/com/siriusxi/ms/store/pcs/IsSameEvent.java create mode 100644 store-service/src/test/java/com/siriusxi/ms/store/pcs/IsSameEventTests.java create mode 100644 store-service/src/test/java/com/siriusxi/ms/store/pcs/MessagingTests.java create mode 100644 store-service/src/test/java/com/siriusxi/ms/store/pcs/ReactorTests.java create mode 100644 store-utils/src/main/java/com/siriusxi/ms/store/util/exceptions/EventProcessingException.java diff --git a/README.md b/README.md index f67118e7..cc098f02 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ I recommend that you work with your Java code using an IDE that supports the dev All that you want to do is just fire up your IDE **->** open or import the parent folder `springy-store-microservices` and everything will be ready for you. -## Playing With Spring Store Project +## Playing With Springy Store Project ### Cloning It diff --git a/docker-compose-kafka.yml b/docker-compose-kafka.yml new file mode 100644 index 00000000..06780995 --- /dev/null +++ b/docker-compose-kafka.yml @@ -0,0 +1,148 @@ +version: '3.7' ## Latest version works with Docker Engine release 18.06.0+ + +services: + product: + build: product-service + environment: + - SPRING_PROFILES_ACTIVE=docker + - MANAGEMENT_HEALTH_RABBIT_ENABLED=false + - SPRING_CLOUD_STREAM_DEFAULTBINDER=kafka + - SPRING_CLOUD_STREAM_BINDINGS_INPUT_CONSUMER_PARTITIONED=true + - SPRING_CLOUD_STREAM_BINDINGS_INPUT_CONSUMER_INSTANCECOUNT=2 + - SPRING_CLOUD_STREAM_BINDINGS_INPUT_CONSUMER_INSTANCEINDEX=0 + depends_on: + - mongodb + - kafka + product-i1: + build: product-service + environment: + - SPRING_PROFILES_ACTIVE=docker + - MANAGEMENT_HEALTH_RABBIT_ENABLED=false + - SPRING_CLOUD_STREAM_DEFAULTBINDER=kafka + - SPRING_CLOUD_STREAM_BINDINGS_INPUT_CONSUMER_PARTITIONED=true + - SPRING_CLOUD_STREAM_BINDINGS_INPUT_CONSUMER_INSTANCECOUNT=2 + - SPRING_CLOUD_STREAM_BINDINGS_INPUT_CONSUMER_INSTANCEINDEX=1 + depends_on: + - mongodb + - kafka + + recommendation: + build: recommendation-service + environment: + - SPRING_PROFILES_ACTIVE=docker + - MANAGEMENT_HEALTH_RABBIT_ENABLED=false + - SPRING_CLOUD_STREAM_DEFAULTBINDER=kafka + - SPRING_CLOUD_STREAM_BINDINGS_INPUT_CONSUMER_PARTITIONED=true + - SPRING_CLOUD_STREAM_BINDINGS_INPUT_CONSUMER_INSTANCECOUNT=2 + - SPRING_CLOUD_STREAM_BINDINGS_INPUT_CONSUMER_INSTANCEINDEX=0 + depends_on: + - mongodb + - kafka + recommendation-i1: + build: recommendation-service + environment: + - SPRING_PROFILES_ACTIVE=docker + - MANAGEMENT_HEALTH_RABBIT_ENABLED=false + - SPRING_CLOUD_STREAM_DEFAULTBINDER=kafka + - SPRING_CLOUD_STREAM_BINDINGS_INPUT_CONSUMER_PARTITIONED=true + - SPRING_CLOUD_STREAM_BINDINGS_INPUT_CONSUMER_INSTANCECOUNT=2 + - SPRING_CLOUD_STREAM_BINDINGS_INPUT_CONSUMER_INSTANCEINDEX=1 + depends_on: + - mongodb + - kafka + + review: + build: review-service + environment: + - SPRING_PROFILES_ACTIVE=docker + - MANAGEMENT_HEALTH_RABBIT_ENABLED=false + - SPRING_CLOUD_STREAM_DEFAULTBINDER=kafka + - SPRING_CLOUD_STREAM_BINDINGS_INPUT_CONSUMER_PARTITIONED=true + - SPRING_CLOUD_STREAM_BINDINGS_INPUT_CONSUMER_INSTANCECOUNT=2 + - SPRING_CLOUD_STREAM_BINDINGS_INPUT_CONSUMER_INSTANCEINDEX=0 + depends_on: + - mysql + - kafka + restart: on-failure + review-i1: + build: review-service + environment: + - SPRING_PROFILES_ACTIVE=docker + - MANAGEMENT_HEALTH_RABBIT_ENABLED=false + - SPRING_CLOUD_STREAM_DEFAULTBINDER=kafka + - SPRING_CLOUD_STREAM_BINDINGS_INPUT_CONSUMER_PARTITIONED=true + - SPRING_CLOUD_STREAM_BINDINGS_INPUT_CONSUMER_INSTANCECOUNT=2 + - SPRING_CLOUD_STREAM_BINDINGS_INPUT_CONSUMER_INSTANCEINDEX=1 + depends_on: + - mysql + - kafka + restart: on-failure + + store: + build: store-service + ports: + - "8080:8080" + environment: + - SPRING_PROFILES_ACTIVE=docker + - MANAGEMENT_HEALTH_RABBIT_ENABLED=false + - SPRING_CLOUD_STREAM_DEFAULTBINDER=kafka + - SPRING_CLOUD_STREAM_BINDINGS_OUTPUT-PRODUCTS_PRODUCER_PARTITION-KEY-EXPRESSION=payload.key + - SPRING_CLOUD_STREAM_BINDINGS_OUTPUT-PRODUCTS_PRODUCER_PARTITION-COUNT=2 + - SPRING_CLOUD_STREAM_BINDINGS_OUTPUT-RECOMMENDATIONS_PRODUCER_PARTITION-KEY-EXPRESSION=payload.key + - SPRING_CLOUD_STREAM_BINDINGS_OUTPUT-RECOMMENDATIONS_PRODUCER_PARTITION-COUNT=2 + - SPRING_CLOUD_STREAM_BINDINGS_OUTPUT-REVIEWS_PRODUCER_PARTITION-KEY-EXPRESSION=payload.key + - SPRING_CLOUD_STREAM_BINDINGS_OUTPUT-REVIEWS_PRODUCER_PARTITION-COUNT=2 + depends_on: + - kafka + + # $ mongo + mongodb: + image: mongo:4.2.5-bionic + ports: + - "27017-27019:27017-27019" + healthcheck: + test: "mongo --eval 'db.stats().ok'" + interval: 10s + timeout: 10s + retries: 5 + start_period: 40s + restart: on-failure + + # $ mysql -uroot -h127.0.0.1 -p + mysql: + image: mysql:8.0.19 + ports: + - "3306:3306" + environment: + - MYSQL_ROOT_PASSWORD=rootpwd + - MYSQL_DATABASE=review-db + - MYSQL_USER=user + - MYSQL_PASSWORD=pwd + - MYSQL_ROOT_HOST=% + healthcheck: + test: "/usr/bin/mysql --user=user --password=pwd --execute \"SHOW DATABASES;\"" + interval: 10s + timeout: 5s + retries: 10 + restart: on-failure + + # Kafka Messaging service + kafka: + image: wurstmeister/kafka:latest + ports: + - "9092:9092" + environment: + - KAFKA_ADVERTISED_HOST_NAME=kafka + - KAFKA_ADVERTISED_PORT=9092 + - KAFKA_ZOOKEEPER_CONNECT=zookeeper:2181 + depends_on: + - zookeeper + restart: on-failure + + zookeeper: + image: wurstmeister/zookeeper:latest + ports: + - "2181:2181" + environment: + - KAFKA_ADVERTISED_HOST_NAME=zookeeper + restart: on-failure \ No newline at end of file diff --git a/docker-compose-partitions.yml b/docker-compose-partitions.yml new file mode 100644 index 00000000..366edee6 --- /dev/null +++ b/docker-compose-partitions.yml @@ -0,0 +1,126 @@ +version: '3.7' ## Latest version works with Docker Engine release 18.06.0+ + +services: + product: + build: product-service + environment: + - SPRING_PROFILES_ACTIVE=docker + - SPRING_CLOUD_STREAM_BINDINGS_INPUT_CONSUMER_PARTITIONED=true + - SPRING_CLOUD_STREAM_BINDINGS_INPUT_CONSUMER_INSTANCECOUNT=2 + - SPRING_CLOUD_STREAM_BINDINGS_INPUT_CONSUMER_INSTANCEINDEX=0 + depends_on: + - mongodb + - rabbitmq + product-i1: + build: product-service + environment: + - SPRING_PROFILES_ACTIVE=docker + - SPRING_CLOUD_STREAM_BINDINGS_INPUT_CONSUMER_PARTITIONED=true + - SPRING_CLOUD_STREAM_BINDINGS_INPUT_CONSUMER_INSTANCECOUNT=2 + - SPRING_CLOUD_STREAM_BINDINGS_INPUT_CONSUMER_INSTANCEINDEX=1 + depends_on: + - mongodb + - rabbitmq + + recommendation: + build: recommendation-service + environment: + - SPRING_PROFILES_ACTIVE=docker + - SPRING_CLOUD_STREAM_BINDINGS_INPUT_CONSUMER_PARTITIONED=true + - SPRING_CLOUD_STREAM_BINDINGS_INPUT_CONSUMER_INSTANCECOUNT=2 + - SPRING_CLOUD_STREAM_BINDINGS_INPUT_CONSUMER_INSTANCEINDEX=0 + depends_on: + - mongodb + - rabbitmq + recommendation-i1: + build: recommendation-service + environment: + - SPRING_PROFILES_ACTIVE=docker + - SPRING_CLOUD_STREAM_BINDINGS_INPUT_CONSUMER_PARTITIONED=true + - SPRING_CLOUD_STREAM_BINDINGS_INPUT_CONSUMER_INSTANCECOUNT=2 + - SPRING_CLOUD_STREAM_BINDINGS_INPUT_CONSUMER_INSTANCEINDEX=1 + depends_on: + - mongodb + - rabbitmq + + review: + build: review-service + environment: + - SPRING_PROFILES_ACTIVE=docker + - SPRING_CLOUD_STREAM_BINDINGS_INPUT_CONSUMER_PARTITIONED=true + - SPRING_CLOUD_STREAM_BINDINGS_INPUT_CONSUMER_INSTANCECOUNT=2 + - SPRING_CLOUD_STREAM_BINDINGS_INPUT_CONSUMER_INSTANCEINDEX=0 + depends_on: + - mysql + - rabbitmq + restart: on-failure + review-i1: + build: review-service + environment: + - SPRING_PROFILES_ACTIVE=docker + - SPRING_CLOUD_STREAM_BINDINGS_INPUT_CONSUMER_PARTITIONED=true + - SPRING_CLOUD_STREAM_BINDINGS_INPUT_CONSUMER_INSTANCECOUNT=2 + - SPRING_CLOUD_STREAM_BINDINGS_INPUT_CONSUMER_INSTANCEINDEX=1 + depends_on: + - mysql + - rabbitmq + restart: on-failure + + store: + build: store-service + ports: + - "8080:8080" + environment: + - SPRING_PROFILES_ACTIVE=docker + - SPRING_CLOUD_STREAM_BINDINGS_OUTPUT-PRODUCTS_PRODUCER_PARTITION-KEY-EXPRESSION=payload.key + - SPRING_CLOUD_STREAM_BINDINGS_OUTPUT-PRODUCTS_PRODUCER_PARTITION-COUNT=2 + - SPRING_CLOUD_STREAM_BINDINGS_OUTPUT-RECOMMENDATIONS_PRODUCER_PARTITION-KEY-EXPRESSION=payload.key + - SPRING_CLOUD_STREAM_BINDINGS_OUTPUT-RECOMMENDATIONS_PRODUCER_PARTITION-COUNT=2 + - SPRING_CLOUD_STREAM_BINDINGS_OUTPUT-REVIEWS_PRODUCER_PARTITION-KEY-EXPRESSION=payload.key + - SPRING_CLOUD_STREAM_BINDINGS_OUTPUT-REVIEWS_PRODUCER_PARTITION-COUNT=2 + depends_on: + - rabbitmq + + # $ mongo + mongodb: + image: mongo:4.2.5-bionic + ports: + - "27017-27019:27017-27019" + healthcheck: + test: "mongo --eval 'db.stats().ok'" + interval: 10s + timeout: 10s + retries: 5 + start_period: 40s + restart: on-failure + + # $ mysql -uroot -h127.0.0.1 -p + mysql: + image: mysql:8.0.19 + ports: + - "3306:3306" + environment: + - MYSQL_ROOT_PASSWORD=rootpwd + - MYSQL_DATABASE=review-db + - MYSQL_USER=user + - MYSQL_PASSWORD=pwd + - MYSQL_ROOT_HOST=% + healthcheck: + test: "/usr/bin/mysql --user=user --password=pwd --execute \"SHOW DATABASES;\"" + interval: 10s + timeout: 5s + retries: 10 + restart: on-failure + + # RabbitMQ Messaging service + rabbitmq: + image: rabbitmq:3.8.3-management + ports: + - 5672:5672 + - 15672:15672 + healthcheck: + test: ["CMD", "rabbitmqctl", "status"] + interval: 10s + timeout: 5s + retries: 10 + restart: on-failure diff --git a/docker-compose.yml b/docker-compose.yml index 1b69f94f..7511f81f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,6 +7,7 @@ services: - SPRING_PROFILES_ACTIVE=docker depends_on: - mongodb + - rabbitmq recommendation: build: recommendation-service @@ -14,6 +15,7 @@ services: - SPRING_PROFILES_ACTIVE=docker depends_on: - mongodb + - rabbitmq review: build: review-service @@ -21,6 +23,7 @@ services: - SPRING_PROFILES_ACTIVE=docker depends_on: - mysql + - rabbitmq restart: on-failure store: @@ -29,6 +32,8 @@ services: - "8080:8080" environment: - SPRING_PROFILES_ACTIVE=docker + depends_on: + - rabbitmq # $ mongo mongodb: @@ -36,12 +41,12 @@ services: ports: - "27017-27019:27017-27019" healthcheck: - test: echo 'db.runCommand("ping").ok' | mongo mongodb:27017/test --quiet 1 + test: "mongo --eval 'db.stats().ok'" interval: 10s timeout: 10s retries: 5 start_period: 40s - restart: always + restart: on-failure # $ mysql -uroot -h127.0.0.1 -p mysql: @@ -55,8 +60,21 @@ services: - MYSQL_PASSWORD=pwd - MYSQL_ROOT_HOST=% healthcheck: - test: ["CMD", "mysqladmin" ,"ping", "-uuser", "-ppwd", "-h", "localhost"] + test: "/usr/bin/mysql --user=user --password=pwd --execute \"SHOW DATABASES;\"" + interval: 10s + timeout: 5s + retries: 10 + restart: on-failure + + # RabbitMQ Messaging service + rabbitmq: + image: rabbitmq:3.8.3-management + ports: + - 5672:5672 + - 15672:15672 + healthcheck: + test: ["CMD", "rabbitmqctl", "status"] interval: 10s timeout: 5s retries: 10 - restart: always + restart: on-failure diff --git a/product-service/pom.xml b/product-service/pom.xml index 0ee5fff0..217958df 100644 --- a/product-service/pom.xml +++ b/product-service/pom.xml @@ -21,7 +21,7 @@ org.springframework.boot - spring-boot-starter-data-mongodb + spring-boot-starter-data-mongodb-reactive diff --git a/product-service/src/main/java/com/siriusxi/ms/store/ps/api/ProductController.java b/product-service/src/main/java/com/siriusxi/ms/store/ps/api/ProductController.java index 1e549f1b..fb0ecc83 100644 --- a/product-service/src/main/java/com/siriusxi/ms/store/ps/api/ProductController.java +++ b/product-service/src/main/java/com/siriusxi/ms/store/ps/api/ProductController.java @@ -7,6 +7,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.web.bind.annotation.RestController; +import reactor.core.publisher.Mono; /** * Class ProductController is the implementation of the main Product Endpoint API @@ -14,7 +15,7 @@ * * @see ProductEndpoint * @author mohamed.taman - * @version v1.0 + * @version v4.0 * @since v3.0 codename Storm */ @RestController @@ -31,19 +32,7 @@ public ProductController(@Qualifier("ProductServiceImpl") ProductService prodSer /** {@inheritDoc} */ @Override - public Product getProduct(int id) { + public Mono getProduct(int id) { return prodService.getProduct(id); } - - /** {@inheritDoc} */ - @Override - public Product createProduct(Product body) { - return prodService.createProduct(body); - } - - /** {@inheritDoc} */ - @Override - public void deleteProduct(int id) { - prodService.deleteProduct(id); - } } diff --git a/product-service/src/main/java/com/siriusxi/ms/store/ps/infra/MessageProcessor.java b/product-service/src/main/java/com/siriusxi/ms/store/ps/infra/MessageProcessor.java new file mode 100644 index 00000000..6eb1f9dc --- /dev/null +++ b/product-service/src/main/java/com/siriusxi/ms/store/ps/infra/MessageProcessor.java @@ -0,0 +1,53 @@ +package com.siriusxi.ms.store.ps.infra; + +import com.siriusxi.ms.store.api.core.product.ProductService; +import com.siriusxi.ms.store.api.core.product.dto.Product; +import com.siriusxi.ms.store.api.event.Event; +import com.siriusxi.ms.store.util.exceptions.EventProcessingException; +import lombok.extern.log4j.Log4j2; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.cloud.stream.annotation.EnableBinding; +import org.springframework.cloud.stream.annotation.StreamListener; +import org.springframework.cloud.stream.messaging.Sink; + +@EnableBinding(Sink.class) +@Log4j2 +public class MessageProcessor { + + private final ProductService productService; + + @Autowired + public MessageProcessor(@Qualifier("ProductServiceImpl") ProductService productService) { + this.productService = productService; + } + + @StreamListener(target = Sink.INPUT) + public void process(Event event) { + + log.info("Process message created at {}...", event.getEventCreatedAt()); + + switch (event.getEventType()) { + case CREATE -> { + Product product = event.getData(); + log.info("Create product with ID: {}", product.getProductId()); + productService.createProduct(product); + } + case DELETE -> { + log.info("Delete recommendations with Product Id: {}", event.getKey()); + productService.deleteProduct(event.getKey()); + } + default -> { + String errorMessage = + "Incorrect event type: " + .concat(event.getEventType().toString()) + .concat(", expected a CREATE or DELETE event."); + log.warn(errorMessage); + throw new EventProcessingException(errorMessage); + } + } + + log.info("Message processing done!"); + } + +} diff --git a/product-service/src/main/java/com/siriusxi/ms/store/ps/persistence/ProductRepository.java b/product-service/src/main/java/com/siriusxi/ms/store/ps/persistence/ProductRepository.java index 8b8e35b4..24c97717 100644 --- a/product-service/src/main/java/com/siriusxi/ms/store/ps/persistence/ProductRepository.java +++ b/product-service/src/main/java/com/siriusxi/ms/store/ps/persistence/ProductRepository.java @@ -1,12 +1,11 @@ package com.siriusxi.ms.store.ps.persistence; -import org.springframework.data.repository.PagingAndSortingRepository; +import org.springframework.data.repository.reactive.ReactiveCrudRepository; import org.springframework.stereotype.Repository; - -import java.util.Optional; +import reactor.core.publisher.Mono; @Repository -public interface ProductRepository extends PagingAndSortingRepository { +public interface ProductRepository extends ReactiveCrudRepository { - Optional findByProductId(int productId); + Mono findByProductId(int productId); } diff --git a/product-service/src/main/java/com/siriusxi/ms/store/ps/service/ProductServiceImpl.java b/product-service/src/main/java/com/siriusxi/ms/store/ps/service/ProductServiceImpl.java index 03dce467..c57681e9 100644 --- a/product-service/src/main/java/com/siriusxi/ms/store/ps/service/ProductServiceImpl.java +++ b/product-service/src/main/java/com/siriusxi/ms/store/ps/service/ProductServiceImpl.java @@ -2,7 +2,6 @@ import com.siriusxi.ms.store.api.core.product.ProductService; import com.siriusxi.ms.store.api.core.product.dto.Product; -import com.siriusxi.ms.store.ps.persistence.ProductEntity; import com.siriusxi.ms.store.ps.persistence.ProductRepository; import com.siriusxi.ms.store.util.exceptions.InvalidInputException; import com.siriusxi.ms.store.util.exceptions.NotFoundException; @@ -11,6 +10,9 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DuplicateKeyException; import org.springframework.stereotype.Service; +import reactor.core.publisher.Mono; + +import static reactor.core.publisher.Mono.error; @Service("ProductServiceImpl") @Log4j2 @@ -32,34 +34,33 @@ public ProductServiceImpl( @Override public Product createProduct(Product body) { - try { - ProductEntity entity = mapper.apiToEntity(body); - ProductEntity newEntity = repository.save(entity); - log.debug("createProduct: entity created for productId: {}", body.getProductId()); - return mapper.entityToApi(newEntity); + isValidProductId(body.getProductId()); - } catch (DuplicateKeyException dke) { - throw new InvalidInputException("Duplicate key, Product Id: " + body.getProductId()); - } + return repository + .save(mapper.apiToEntity(body)) + .log() + .onErrorMap( + DuplicateKeyException.class, + ex -> new InvalidInputException("Duplicate key, Product Id: " + body.getProductId())) + .map(mapper::entityToApi) + .block(); } @Override - public Product getProduct(int productId) { - if (productId < 1) throw new InvalidInputException("Invalid productId: " + productId); - - ProductEntity entity = - repository - .findByProductId(productId) - .orElseThrow( - () -> new NotFoundException("No product found for productId: " + productId)); + public Mono getProduct(int productId) { - Product response = mapper.entityToApi(entity); - response.setServiceAddress(serviceUtil.getServiceAddress()); + isValidProductId(productId); - log.debug("getProduct: found productId: {}", response.getProductId()); - - return response; + return repository + .findByProductId(productId) + .switchIfEmpty(error(new NotFoundException("No product found for productId: " + productId))) + .log() + .map(mapper::entityToApi) + .map(e -> { + e.setServiceAddress(serviceUtil.getServiceAddress()); + return e; + }); } /* @@ -68,7 +69,21 @@ public Product getProduct(int productId) { */ @Override public void deleteProduct(int productId) { + + isValidProductId(productId); + log.debug("deleteProduct: tries to delete an entity with productId: {}", productId); - repository.findByProductId(productId).ifPresent(repository::delete); + + repository + .findByProductId(productId) + .log() + .map(repository::delete) + .flatMap(e -> e) + .block(); + } + + // TODO Cloud be added to utilities class to be used by all core services implementations. + private void isValidProductId(int productId) { + if (productId < 1) throw new InvalidInputException("Invalid productId: " + productId); } } diff --git a/product-service/src/main/resources/application.yaml b/product-service/src/main/resources/application.yaml index 3e6b6175..065c913a 100644 --- a/product-service/src/main/resources/application.yaml +++ b/product-service/src/main/resources/application.yaml @@ -7,6 +7,39 @@ spring: port: 27017 database: product-db auto-index-creation: true + rabbitmq: + host: 127.0.0.1 + port: 5672 + username: guest + password: guest + cloud: + stream: + defaultBinder: rabbit + default: + contentType: application/json + bindings: + input: + destination: products + group: productsGroup + consumer: + maxAttempts: 3 + backOffInitialInterval: 500 + backOffMaxInterval: 1000 + backOffMultiplier: 2.0 + rabbit: + bindings: + input: + consumer: + autoBindDlq: true + republishToDlq: true + kafka: + bindings: + input: + consumer: + enableDlq: true + binder: + brokers: 127.0.0.1 + defaultBrokerPort: 9092 server: port: 9081 @@ -16,9 +49,14 @@ logging: web: DEBUG root: INFO com.siriusxi.ms.store: DEBUG - org.springframework.data.mongodb.core.MongoTemplate: DEBUG + org: + springframework.data.mongodb.core.MongoTemplate: DEBUG + mongodb: debug management: + info: + git: + mode: full endpoints: web: exposure: @@ -26,6 +64,8 @@ management: endpoint: shutdown: enabled: true + health: + show-details: always # This is a docker specific profile properties # Also profiles could be separated in its owen file @@ -38,6 +78,13 @@ spring: data: mongodb: host: mongodb + rabbitmq: + host: rabbitmq + cloud: + stream: + kafka: + binder: + brokers: kafka server: port: 8080 diff --git a/product-service/src/test/java/com/siriusxi/ms/store/ps/MapperTests.java b/product-service/src/test/java/com/siriusxi/ms/store/ps/MapperTests.java index c8e7ea51..dd91971a 100644 --- a/product-service/src/test/java/com/siriusxi/ms/store/ps/MapperTests.java +++ b/product-service/src/test/java/com/siriusxi/ms/store/ps/MapperTests.java @@ -7,7 +7,7 @@ import static org.junit.jupiter.api.Assertions.*; -public class MapperTests { +class MapperTests { private final ProductMapper mapper = ProductMapper.INSTANCE; diff --git a/product-service/src/test/java/com/siriusxi/ms/store/ps/PersistenceTests.java b/product-service/src/test/java/com/siriusxi/ms/store/ps/PersistenceTests.java index 650b9148..b01257c4 100644 --- a/product-service/src/test/java/com/siriusxi/ms/store/ps/PersistenceTests.java +++ b/product-service/src/test/java/com/siriusxi/ms/store/ps/PersistenceTests.java @@ -2,27 +2,16 @@ import com.siriusxi.ms.store.ps.persistence.ProductEntity; import com.siriusxi.ms.store.ps.persistence.ProductRepository; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest; import org.springframework.dao.DuplicateKeyException; import org.springframework.dao.OptimisticLockingFailureException; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageRequest; -import org.springframework.data.domain.Pageable; - -import java.util.List; -import java.util.Optional; -import java.util.stream.Collectors; - -import static java.util.stream.IntStream.rangeClosed; -import static org.junit.jupiter.api.Assertions.*; -import static org.springframework.data.domain.Sort.Direction.ASC; +import reactor.test.StepVerifier; @DataMongoTest -public class PersistenceTests { +class PersistenceTests { @Autowired private ProductRepository repository; @@ -30,125 +19,110 @@ public class PersistenceTests { @BeforeEach public void setupDb() { - repository.deleteAll(); + + StepVerifier.create(repository.deleteAll()).verifyComplete(); ProductEntity entity = new ProductEntity(1, "n", 1); - savedEntity = repository.save(entity); - assertEqualsProduct(entity, savedEntity); + StepVerifier.create(repository.save(entity)) + .expectNextMatches( + createdEntity -> { + savedEntity = createdEntity; + return areProductEqual(entity, savedEntity); + }) + .verifyComplete(); } @Test public void create() { var newEntity = new ProductEntity(2, "n", 2); - repository.save(newEntity); - var foundEntity = repository.findById(newEntity.getId()).orElse(new ProductEntity()); - assertEqualsProduct(newEntity, foundEntity); + StepVerifier.create(repository.save(newEntity)) + .expectNextMatches( + createdEntity -> newEntity.getProductId() == createdEntity.getProductId()) + .verifyComplete(); + + StepVerifier.create(repository.findById(newEntity.getId())) + .expectNextMatches(foundEntity -> areProductEqual(newEntity, foundEntity)) + .verifyComplete(); - assertEquals(2, repository.count()); + StepVerifier.create(repository.count()).expectNext(2L).verifyComplete(); } @Test public void update() { savedEntity.setName("n2"); - repository.save(savedEntity); - var foundEntity = repository.findById(savedEntity.getId()).orElse(new ProductEntity()); - assertEquals(1, (long) foundEntity.getVersion()); - assertEquals("n2", foundEntity.getName()); + StepVerifier.create(repository.save(savedEntity)) + .expectNextMatches(savedEntity -> savedEntity.getName().equals("n2")) + .verifyComplete(); + + StepVerifier.create(repository.findById(savedEntity.getId())) + .expectNextMatches( + foundEntity -> foundEntity.getVersion().equals(1) && foundEntity.getName().equals("n2")) + .verifyComplete(); } @Test public void delete() { - repository.delete(savedEntity); - assertFalse(repository.existsById(savedEntity.getId())); + StepVerifier.create(repository.delete(savedEntity)).verifyComplete(); + + StepVerifier.create(repository.existsById(savedEntity.getId())) + .expectNext(false) + .verifyComplete(); } @Test public void getByProductId() { - Optional entity = repository.findByProductId(savedEntity.getProductId()); - assertTrue(entity.isPresent()); - assertEqualsProduct(savedEntity, entity.get()); + StepVerifier.create(repository.findByProductId(savedEntity.getProductId())) + .expectNextMatches(foundEntity -> areProductEqual(savedEntity, foundEntity)) + .verifyComplete(); } @Test public void duplicateError() { - - Assertions.assertThrows( - DuplicateKeyException.class, - () -> { - ProductEntity entity = new ProductEntity(savedEntity.getProductId(), "n", 1); - repository.save(entity); - }); + StepVerifier.create(repository.save(new ProductEntity(savedEntity.getProductId(), "n", 1))) + .expectError(DuplicateKeyException.class) + .verify(); } @Test public void optimisticLockError() { // Store the saved entity in two separate entity objects - ProductEntity entity1 = repository.findById(savedEntity.getId()).orElse(new ProductEntity()), - entity2 = repository.findById(savedEntity.getId()).orElse(new ProductEntity()); + ProductEntity entity1 = repository.findById(savedEntity.getId()).block(), + entity2 = repository.findById(savedEntity.getId()).block(); // Update the entity using the first entity object + assert entity1 != null; entity1.setName("n1"); - repository.save(entity1); + repository.save(entity1).block(); /* Update the entity using the second entity object. This should fail since the second entity now holds a old version number, i.e. a Optimistic Lock Error. */ - try { - entity2.setName("n2"); - repository.save(entity2); + assert entity2 != null; - fail("Expected an OptimisticLockingFailureException"); - } catch (OptimisticLockingFailureException ignored) { } + StepVerifier.create(repository.save(entity2)) + .expectError(OptimisticLockingFailureException.class) + .verify(); // Get the updated entity from the database and verify its new sate - var updatedEntity = repository.findById(savedEntity.getId()).orElse(new ProductEntity()); - assertEquals(1, (int) updatedEntity.getVersion()); - assertEquals("n1", updatedEntity.getName()); - } - - @Test - public void paging() { - - repository.deleteAll(); - - List newProducts = - rangeClosed(1001, 1010) - .mapToObj(i -> new ProductEntity(i, "name " + i, i)) - .collect(Collectors.toList()); - repository.saveAll(newProducts); - - Pageable nextPage = PageRequest.of(0, 4, ASC, "productId"); - nextPage = testNextPage(nextPage, "[1001, 1002, 1003, 1004]", true); - nextPage = testNextPage(nextPage, "[1005, 1006, 1007, 1008]", true); - testNextPage(nextPage, "[1009, 1010]", false); - } - - private Pageable testNextPage( - Pageable nextPage, String expectedProductIds, boolean expectsNextPage) { - Page productPage = repository.findAll(nextPage); - assertEquals( - expectedProductIds, - productPage.getContent().stream() - .map(ProductEntity::getProductId) - .collect(Collectors.toList()) - .toString()); - assertEquals(expectsNextPage, productPage.hasNext()); - return productPage.nextPageable(); + StepVerifier.create(repository.findById(savedEntity.getId())) + .expectNextMatches( + foundEntity -> foundEntity.getVersion() == 1 && foundEntity.getName().equals("n1")) + .verifyComplete(); } - private void assertEqualsProduct(ProductEntity expectedEntity, ProductEntity actualEntity) { - assertEquals(expectedEntity.getId(), actualEntity.getId()); - assertEquals(expectedEntity.getVersion(), actualEntity.getVersion()); - assertEquals(expectedEntity.getProductId(), actualEntity.getProductId()); - assertEquals(expectedEntity.getName(), actualEntity.getName()); - assertEquals(expectedEntity.getWeight(), actualEntity.getWeight()); + private boolean areProductEqual(ProductEntity expectedEntity, ProductEntity actualEntity) { + return (expectedEntity.getId().equals(actualEntity.getId())) + && (expectedEntity.getVersion().equals(actualEntity.getVersion())) + && (expectedEntity.getProductId() == actualEntity.getProductId()) + && (expectedEntity.getName().equals(actualEntity.getName())) + && (expectedEntity.getWeight() == actualEntity.getWeight()); } } diff --git a/product-service/src/test/java/com/siriusxi/ms/store/ps/ProductServiceApplicationTests.java b/product-service/src/test/java/com/siriusxi/ms/store/ps/ProductServiceApplicationTests.java index e8c7af7e..15c80139 100644 --- a/product-service/src/test/java/com/siriusxi/ms/store/ps/ProductServiceApplicationTests.java +++ b/product-service/src/test/java/com/siriusxi/ms/store/ps/ProductServiceApplicationTests.java @@ -1,17 +1,23 @@ package com.siriusxi.ms.store.ps; import com.siriusxi.ms.store.api.core.product.dto.Product; +import com.siriusxi.ms.store.api.event.Event; import com.siriusxi.ms.store.ps.persistence.ProductRepository; +import com.siriusxi.ms.store.util.exceptions.InvalidInputException; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.stream.messaging.Sink; import org.springframework.http.HttpStatus; +import org.springframework.integration.channel.AbstractMessageChannel; +import org.springframework.messaging.MessagingException; +import org.springframework.messaging.support.GenericMessage; import org.springframework.test.web.reactive.server.WebTestClient; -import reactor.core.publisher.Mono; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static com.siriusxi.ms.store.api.event.Event.Type.CREATE; +import static com.siriusxi.ms.store.api.event.Event.Type.DELETE; +import static org.junit.jupiter.api.Assertions.*; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; import static org.springframework.http.HttpStatus.*; import static org.springframework.http.MediaType.APPLICATION_JSON; @@ -23,13 +29,21 @@ class ProductServiceApplicationTests { private final String BASE_URI = "/products/"; - @Autowired private WebTestClient client; + @Autowired + private WebTestClient client; - @Autowired private ProductRepository repository; + @Autowired + private ProductRepository repository; + + @Autowired + private Sink channels; + + private AbstractMessageChannel input = null; @BeforeEach public void setupDb() { - repository.deleteAll(); + input = (AbstractMessageChannel) channels.input(); + repository.deleteAll().block(); } @Test @@ -37,11 +51,16 @@ public void getProductById() { int productId = 1; - postAndVerifyProduct(productId, OK); + assertNull(repository.findByProductId(productId).block()); + assertEquals(0, repository.count().block()); - assertTrue(repository.findByProductId(productId).isPresent()); + sendCreateProductEvent(productId); - getAndVerifyProduct(productId, OK).jsonPath("$.productId").isEqualTo(productId); + assertNotNull(repository.findByProductId(productId).block()); + assertEquals(1, repository.count().block()); + + getAndVerifyProduct(productId, OK) + .jsonPath("$.productId").isEqualTo(productId); } @Test @@ -49,15 +68,22 @@ public void duplicateError() { int productId = 1; - postAndVerifyProduct(productId, OK); + assertNull(repository.findByProductId(productId).block()); - assertTrue(repository.findByProductId(productId).isPresent()); + sendCreateProductEvent(productId); - postAndVerifyProduct(productId, UNPROCESSABLE_ENTITY) - .jsonPath("$.path") - .isEqualTo(BASE_URI) - .jsonPath("$.message") - .isEqualTo("Duplicate key, Product Id: " + productId); + assertNotNull(repository.findByProductId(productId).block()); + + try { + sendCreateProductEvent(productId); + fail("Expected a MessagingException here!"); + } catch (MessagingException me) { + if (me.getCause() instanceof InvalidInputException iie) { + assertEquals("Duplicate key, Product Id: " + productId, iie.getMessage()); + } else { + fail("Expected a InvalidInputException as the root cause!"); + } + } } @Test @@ -65,23 +91,19 @@ public void deleteProduct() { int productId = 1; - postAndVerifyProduct(productId, OK); - assertTrue(repository.findByProductId(productId).isPresent()); - - deleteAndVerifyProduct(productId); - assertFalse(repository.findByProductId(productId).isPresent()); + sendCreateProductEvent(productId); + assertNotNull(repository.findByProductId(productId).block()); - deleteAndVerifyProduct(productId); + sendDeleteProductEvent(productId); + assertNull(repository.findByProductId(productId).block()); } @Test public void getProductInvalidParameterString() { getAndVerifyProduct(BASE_URI + "/no-integer", BAD_REQUEST) - .jsonPath("$.path") - .isEqualTo(BASE_URI + "no-integer") - .jsonPath("$.message") - .isEqualTo("Type mismatch."); + .jsonPath("$.path").isEqualTo(BASE_URI + "no-integer") + .jsonPath("$.message").isEqualTo("Type mismatch."); } @Test @@ -89,10 +111,9 @@ public void getProductNotFound() { int productIdNotFound = 13; getAndVerifyProduct(productIdNotFound, NOT_FOUND) - .jsonPath("$.path") - .isEqualTo(BASE_URI + productIdNotFound) + .jsonPath("$.path").isEqualTo(BASE_URI + productIdNotFound) .jsonPath("$.message") - .isEqualTo("No product found for productId: " + productIdNotFound); + .isEqualTo("No product found for productId: " + productIdNotFound); } @Test @@ -101,10 +122,8 @@ public void getProductInvalidParameterNegativeValue() { int productIdInvalid = -1; getAndVerifyProduct(productIdInvalid, UNPROCESSABLE_ENTITY) - .jsonPath("$.path") - .isEqualTo(BASE_URI + productIdInvalid) - .jsonPath("$.message") - .isEqualTo("Invalid productId: " + productIdInvalid); + .jsonPath("$.path").isEqualTo(BASE_URI + productIdInvalid) + .jsonPath("$.message").isEqualTo("Invalid productId: " + productIdInvalid); } private WebTestClient.BodyContentSpec getAndVerifyProduct( @@ -119,37 +138,19 @@ private WebTestClient.BodyContentSpec getAndVerifyProduct( .uri(productIdPath) .accept(APPLICATION_JSON) .exchange() - .expectStatus() - .isEqualTo(expectedStatus) - .expectHeader() - .contentType(APPLICATION_JSON) + .expectStatus().isEqualTo(expectedStatus) + .expectHeader().contentType(APPLICATION_JSON) .expectBody(); } - private WebTestClient.BodyContentSpec postAndVerifyProduct( - int productId, HttpStatus expectedStatus) { + private void sendCreateProductEvent(int productId) { Product product = new Product(productId, "Name " + productId, productId, "SA"); - return client - .post() - .uri(BASE_URI) - .body(Mono.just(product), Product.class) - .accept(APPLICATION_JSON) - .exchange() - .expectStatus() - .isEqualTo(expectedStatus) - .expectHeader() - .contentType(APPLICATION_JSON) - .expectBody(); + Event event = new Event<>(CREATE, productId, product); + input.send(new GenericMessage<>(event)); } - private void deleteAndVerifyProduct(int productId) { - client - .delete() - .uri(BASE_URI + productId) - .accept(APPLICATION_JSON) - .exchange() - .expectStatus() - .isEqualTo(OK) - .expectBody(); + private void sendDeleteProductEvent(int productId) { + Event event = new Event<>(DELETE, productId, null); + input.send(new GenericMessage<>(event)); } } diff --git a/recommendation-service/pom.xml b/recommendation-service/pom.xml index 8dcc2a4a..a18c5c02 100644 --- a/recommendation-service/pom.xml +++ b/recommendation-service/pom.xml @@ -21,7 +21,7 @@ org.springframework.boot - spring-boot-starter-data-mongodb + spring-boot-starter-data-mongodb-reactive diff --git a/recommendation-service/src/main/java/com/siriusxi/ms/store/rs/api/RecommendationController.java b/recommendation-service/src/main/java/com/siriusxi/ms/store/rs/api/RecommendationController.java index a96f96a1..191e43d8 100644 --- a/recommendation-service/src/main/java/com/siriusxi/ms/store/rs/api/RecommendationController.java +++ b/recommendation-service/src/main/java/com/siriusxi/ms/store/rs/api/RecommendationController.java @@ -7,8 +7,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.web.bind.annotation.RestController; - -import java.util.List; +import reactor.core.publisher.Flux; /** * Class RecommendationController is the implementation of the main Recommendation @@ -16,12 +15,13 @@ * * @see RecommendationEndpoint * @author mohamed.taman - * @version v1.0 + * @version v4.0 * @since v3.0 codename Storm */ @RestController @Log4j2 public class RecommendationController implements RecommendationEndpoint { + /** Recommendation service business logic interface. */ private final RecommendationService recommendationService; @@ -33,19 +33,7 @@ public RecommendationController( /** {@inheritDoc} */ @Override - public List getRecommendations(int productId) { + public Flux getRecommendations(int productId) { return recommendationService.getRecommendations(productId); } - - /** {@inheritDoc} */ - @Override - public Recommendation createRecommendation(Recommendation body) { - return recommendationService.createRecommendation(body); - } - - /** {@inheritDoc} */ - @Override - public void deleteRecommendations(int productId) { - recommendationService.deleteRecommendations(productId); - } } diff --git a/recommendation-service/src/main/java/com/siriusxi/ms/store/rs/infra/MessageProcessor.java b/recommendation-service/src/main/java/com/siriusxi/ms/store/rs/infra/MessageProcessor.java new file mode 100644 index 00000000..6000edfa --- /dev/null +++ b/recommendation-service/src/main/java/com/siriusxi/ms/store/rs/infra/MessageProcessor.java @@ -0,0 +1,57 @@ +package com.siriusxi.ms.store.rs.infra; + +import com.siriusxi.ms.store.api.core.recommendation.RecommendationService; +import com.siriusxi.ms.store.api.core.recommendation.dto.Recommendation; +import com.siriusxi.ms.store.api.event.Event; +import com.siriusxi.ms.store.util.exceptions.EventProcessingException; +import lombok.extern.log4j.Log4j2; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.cloud.stream.annotation.EnableBinding; +import org.springframework.cloud.stream.annotation.StreamListener; +import org.springframework.cloud.stream.messaging.Sink; + +import static java.lang.String.*; + +@EnableBinding(Sink.class) +@Log4j2 +public class MessageProcessor { + + private final RecommendationService service; + + @Autowired + public MessageProcessor(@Qualifier("RecommendationServiceImpl") RecommendationService service) { + this.service = service; + } + + @StreamListener(target = Sink.INPUT) + public void process(Event event) { + + log.info("Process message created at {}...", event.getEventCreatedAt()); + + switch (event.getEventType()) { + case CREATE -> { + Recommendation recommendation = event.getData(); + log.info("Create recommendation with ID: {}/{}", recommendation.getProductId(), + recommendation.getRecommendationId()); + service.createRecommendation(recommendation); + } + case DELETE -> { + int productId = event.getKey(); + log.info("Delete recommendations with ProductID: {}", productId); + service.deleteRecommendations(productId); + } + default -> { + String errorMessage = + "Incorrect event type: " + .concat(valueOf(event.getEventType())) + .concat(", expected a CREATE or DELETE event"); + log.warn(errorMessage); + throw new EventProcessingException(errorMessage); + } + } + + log.info("Message processing done!"); + } + +} diff --git a/recommendation-service/src/main/java/com/siriusxi/ms/store/rs/persistence/RecommendationEntity.java b/recommendation-service/src/main/java/com/siriusxi/ms/store/rs/persistence/RecommendationEntity.java index eafeefb3..dfc33662 100644 --- a/recommendation-service/src/main/java/com/siriusxi/ms/store/rs/persistence/RecommendationEntity.java +++ b/recommendation-service/src/main/java/com/siriusxi/ms/store/rs/persistence/RecommendationEntity.java @@ -7,6 +7,8 @@ import org.springframework.data.mongodb.core.index.CompoundIndex; import org.springframework.data.mongodb.core.mapping.Document; +import static java.lang.String.format; + @Document(collection = "recommendations") @CompoundIndex( name = "prod-rec-id", diff --git a/recommendation-service/src/main/java/com/siriusxi/ms/store/rs/persistence/RecommendationRepository.java b/recommendation-service/src/main/java/com/siriusxi/ms/store/rs/persistence/RecommendationRepository.java index 520f0e90..4f8bf598 100644 --- a/recommendation-service/src/main/java/com/siriusxi/ms/store/rs/persistence/RecommendationRepository.java +++ b/recommendation-service/src/main/java/com/siriusxi/ms/store/rs/persistence/RecommendationRepository.java @@ -1,11 +1,14 @@ package com.siriusxi.ms.store.rs.persistence; -import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.reactive.ReactiveCrudRepository; import org.springframework.stereotype.Repository; +import reactor.core.publisher.Flux; -import java.util.List; +//FIXME to be documented and to be pageable @Repository -public interface RecommendationRepository extends CrudRepository { - List findByProductId(int productId); +public interface RecommendationRepository + extends ReactiveCrudRepository { + + Flux findByProductId(int productId); } diff --git a/recommendation-service/src/main/java/com/siriusxi/ms/store/rs/service/RecommendationServiceImpl.java b/recommendation-service/src/main/java/com/siriusxi/ms/store/rs/service/RecommendationServiceImpl.java index 3cabadde..55d2dc83 100644 --- a/recommendation-service/src/main/java/com/siriusxi/ms/store/rs/service/RecommendationServiceImpl.java +++ b/recommendation-service/src/main/java/com/siriusxi/ms/store/rs/service/RecommendationServiceImpl.java @@ -2,7 +2,6 @@ import com.siriusxi.ms.store.api.core.recommendation.RecommendationService; import com.siriusxi.ms.store.api.core.recommendation.dto.Recommendation; -import com.siriusxi.ms.store.rs.persistence.RecommendationEntity; import com.siriusxi.ms.store.rs.persistence.RecommendationRepository; import com.siriusxi.ms.store.util.exceptions.InvalidInputException; import com.siriusxi.ms.store.util.http.ServiceUtil; @@ -10,8 +9,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DuplicateKeyException; import org.springframework.stereotype.Service; - -import java.util.List; +import reactor.core.publisher.Flux; @Service("RecommendationServiceImpl") @Log4j2 @@ -33,46 +31,55 @@ public RecommendationServiceImpl( @Override public Recommendation createRecommendation(Recommendation body) { - try { - RecommendationEntity entity = mapper.apiToEntity(body); - RecommendationEntity newEntity = repository.save(entity); - - log.debug( - "createRecommendation: created a recommendation entity: {}/{}", - body.getProductId(), - body.getRecommendationId()); - - return mapper.entityToApi(newEntity); - - } catch (DuplicateKeyException dke) { - throw new InvalidInputException( - "Duplicate key, Product Id: " - + body.getProductId() - + ", Recommendation Id:" - + body.getRecommendationId()); - } + + isValidProductId(body.getProductId()); + + return repository + .save(mapper.apiToEntity(body)) + .log() + .onErrorMap( + DuplicateKeyException.class, + ex -> new InvalidInputException("Duplicate key, Product Id: " + + body.getProductId() + ", Recommendation Id:" + + body.getRecommendationId())) + .map(mapper::entityToApi).block(); } @Override - public List getRecommendations(int productId) { + public Flux getRecommendations(int productId) { - if (productId < 1) throw new InvalidInputException("Invalid productId: " + productId); + isValidProductId(productId); - List entityList = repository.findByProductId(productId); - List list = mapper.entityListToApiList(entityList); - list.forEach(e -> e.setServiceAddress(serviceUtil.getServiceAddress())); + return repository + .findByProductId(productId) + .log() + .map(mapper::entityToApi) + .map(e -> { + e.setServiceAddress(serviceUtil.getServiceAddress()); + return e; + }); - log.debug("getRecommendations: response size: {}", list.size()); - - return list; + //FIXME check how to add log to flux + //log.debug("getRecommendations: response size: {}", list.size()); } @Override public void deleteRecommendations(int productId) { + isValidProductId(productId); + log.debug( - "deleteRecommendations: tries to delete recommendations for the product with " - + "productId: {}", + """ + deleteRecommendations: tries to delete recommendations + for the product with productId: {} + """, productId); - repository.deleteAll(repository.findByProductId(productId)); + + repository + .deleteAll(repository.findByProductId(productId)) + .block(); + } + + private void isValidProductId(int productId) { + if (productId < 1) throw new InvalidInputException("Invalid productId: " + productId); } } diff --git a/recommendation-service/src/main/resources/application.yaml b/recommendation-service/src/main/resources/application.yaml index 02460b21..a71f35ba 100644 --- a/recommendation-service/src/main/resources/application.yaml +++ b/recommendation-service/src/main/resources/application.yaml @@ -7,6 +7,39 @@ spring: port: 27017 database: recommendation-db auto-index-creation: true + rabbitmq: + host: 127.0.0.1 + port: 5672 + username: guest + password: guest + cloud: + stream: + defaultBinder: rabbit + default: + contentType: application/json + bindings: + input: + destination: recommendations + group: recommendationsGroup + consumer: + maxAttempts: 3 + backOffInitialInterval: 500 + backOffMaxInterval: 1000 + backOffMultiplier: 2.0 + rabbit: + bindings: + input: + consumer: + autoBindDlq: true + republishToDlq: true + kafka: + bindings: + input: + consumer: + enableDlq: true + binder: + brokers: 127.0.0.1 + defaultBrokerPort: 9092 server: port: 9082 @@ -21,6 +54,9 @@ logging: mongodb: debug management: + info: + git: + mode: full endpoints: web: exposure: @@ -28,6 +64,8 @@ management: endpoint: shutdown: enabled: true + health: + show-details: always # This is a docker specific profile properties # Also profiles could be separated in its owen file @@ -40,6 +78,13 @@ spring: data: mongodb: host: mongodb + rabbitmq: + host: rabbitmq + cloud: + stream: + kafka: + binder: + brokers: kafka server: port: 8080 diff --git a/recommendation-service/src/test/java/com/siriusxi/ms/store/rs/MapperTests.java b/recommendation-service/src/test/java/com/siriusxi/ms/store/rs/MapperTests.java index 3642918b..a2e2952d 100644 --- a/recommendation-service/src/test/java/com/siriusxi/ms/store/rs/MapperTests.java +++ b/recommendation-service/src/test/java/com/siriusxi/ms/store/rs/MapperTests.java @@ -10,7 +10,7 @@ import static org.junit.jupiter.api.Assertions.*; -public class MapperTests { +class MapperTests { private final RecommendationMapper mapper = RecommendationMapper.INSTANCE; diff --git a/recommendation-service/src/test/java/com/siriusxi/ms/store/rs/PersistenceTests.java b/recommendation-service/src/test/java/com/siriusxi/ms/store/rs/PersistenceTests.java index f42eb5e8..46e4f4ac 100644 --- a/recommendation-service/src/test/java/com/siriusxi/ms/store/rs/PersistenceTests.java +++ b/recommendation-service/src/test/java/com/siriusxi/ms/store/rs/PersistenceTests.java @@ -17,7 +17,7 @@ import static org.junit.jupiter.api.Assertions.*; @DataMongoTest -public class PersistenceTests { +class PersistenceTests { @Autowired private RecommendationRepository repository; @@ -25,11 +25,12 @@ public class PersistenceTests { @BeforeEach public void setupDb() { - repository.deleteAll(); + repository.deleteAll().block(); RecommendationEntity entity = new RecommendationEntity(1, 2, "a", 3, "c"); - savedEntity = repository.save(entity); + savedEntity = repository.save(entity).block(); + assert savedEntity != null; assertEqualsRecommendation(entity, savedEntity); } @@ -37,33 +38,39 @@ public void setupDb() { public void create() { var newEntity = new RecommendationEntity(1, 3, "a", 3, "c"); - repository.save(newEntity); + repository.save(newEntity).block(); - var foundEntity = repository.findById(newEntity.getId()).orElse(new RecommendationEntity()); + var foundEntity = repository.findById(newEntity.getId()).block(); + + assert foundEntity != null; assertEqualsRecommendation(newEntity, foundEntity); - assertEquals(2, repository.count()); + assertEquals(2L, repository.count().block()); } @Test public void update() { savedEntity.setAuthor("a2"); - repository.save(savedEntity); + repository.save(savedEntity).block(); + + RecommendationEntity foundEntity = repository.findById(savedEntity.getId()).block(); + + assert foundEntity != null; - RecommendationEntity foundEntity = repository.findById(savedEntity.getId()).get(); - assertEquals(1, (long) foundEntity.getVersion()); + assertEquals(1, foundEntity.getVersion()); assertEquals("a2", foundEntity.getAuthor()); } @Test public void delete() { - repository.delete(savedEntity); - assertFalse(repository.existsById(savedEntity.getId())); + repository.delete(savedEntity).block(); + assertEquals(false, repository.existsById(savedEntity.getId()).block()); } @Test public void getByProductId() { - List entityList = repository.findByProductId(savedEntity.getProductId()); + List entityList = + repository.findByProductId(savedEntity.getProductId()).collectList().block(); assertThat(entityList, hasSize(1)); assertEqualsRecommendation(savedEntity, entityList.get(0)); @@ -74,20 +81,23 @@ public void duplicateError() { Assertions.assertThrows( DuplicateKeyException.class, - () -> repository.save(new RecommendationEntity(1, 2, "a", 3, "c"))); + () -> repository + .save(new RecommendationEntity(1, 2, "a", 3, "c")) + .block()); } @Test public void optimisticLockError() { // Store the saved entity in two separate entity objects - RecommendationEntity - entity1 = repository.findById(savedEntity.getId()).orElse(new RecommendationEntity()), - entity2 = repository.findById(savedEntity.getId()).orElse(new RecommendationEntity()); + RecommendationEntity entity1 = repository.findById(savedEntity.getId()).block(), + entity2 = repository.findById(savedEntity.getId()).block(); // Update the entity using the first entity object + assert entity1 != null; + entity1.setAuthor("a1"); - repository.save(entity1); + repository.save(entity1).block(); /* Update the entity using the second entity object. @@ -95,17 +105,21 @@ public void optimisticLockError() { i.e. a Optimistic Lock Error. */ try { + assert entity2 != null; + entity2.setAuthor("a2"); - repository.save(entity2); + repository.save(entity2).block(); fail("Expected an OptimisticLockingFailureException"); } catch (OptimisticLockingFailureException ignored) { } // Get the updated entity from the database and verify its new sate - var updatedEntity = repository.findById(savedEntity.getId()).orElse(new RecommendationEntity()); + var updatedEntity = repository.findById(savedEntity.getId()).block(); + + assert updatedEntity != null; - assertEquals(1, (int) updatedEntity.getVersion()); + assertEquals(1, updatedEntity.getVersion()); assertEquals("a1", updatedEntity.getAuthor()); } diff --git a/recommendation-service/src/test/java/com/siriusxi/ms/store/rs/RecommendationServiceApplicationTests.java b/recommendation-service/src/test/java/com/siriusxi/ms/store/rs/RecommendationServiceApplicationTests.java index 53059e8b..8461b2dc 100644 --- a/recommendation-service/src/test/java/com/siriusxi/ms/store/rs/RecommendationServiceApplicationTests.java +++ b/recommendation-service/src/test/java/com/siriusxi/ms/store/rs/RecommendationServiceApplicationTests.java @@ -1,16 +1,25 @@ package com.siriusxi.ms.store.rs; import com.siriusxi.ms.store.api.core.recommendation.dto.Recommendation; +import com.siriusxi.ms.store.api.event.Event; import com.siriusxi.ms.store.rs.persistence.RecommendationRepository; +import com.siriusxi.ms.store.util.exceptions.InvalidInputException; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.stream.messaging.Sink; import org.springframework.http.HttpStatus; +import org.springframework.integration.channel.AbstractMessageChannel; +import org.springframework.messaging.MessagingException; +import org.springframework.messaging.support.GenericMessage; import org.springframework.test.web.reactive.server.WebTestClient; import org.springframework.test.web.reactive.server.WebTestClient.BodyContentSpec; import reactor.core.publisher.Mono; +import static com.siriusxi.ms.store.api.event.Event.Type.CREATE; +import static com.siriusxi.ms.store.api.event.Event.Type.DELETE; +import static org.assertj.core.api.Assertions.fail; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; import static org.springframework.http.HttpStatus.*; @@ -22,13 +31,20 @@ class RecommendationServiceApplicationTests { private final String BASE_URI = "/recommendations"; + @Autowired private WebTestClient client; @Autowired private RecommendationRepository repository; + @Autowired + private Sink channels; + + private AbstractMessageChannel input = null; + @BeforeEach public void setupDb() { - repository.deleteAll(); + input = (AbstractMessageChannel) channels.input(); + repository.deleteAll().block(); } @Test @@ -36,19 +52,16 @@ public void getRecommendationsByProductId() { int productId = 1; - postAndVerifyRecommendation(productId, 1, OK); - postAndVerifyRecommendation(productId, 2, OK); - postAndVerifyRecommendation(productId, 3, OK); + sendCreateRecommendationEvent(productId, 1); + sendCreateRecommendationEvent(productId, 2); + sendCreateRecommendationEvent(productId, 3); - assertEquals(3, repository.findByProductId(productId).size()); + assertEquals(3, repository.findByProductId(productId).count().block()); - getAndVerifyRecommendationsByProductId(productId, OK) - .jsonPath("$.length()") - .isEqualTo(3) - .jsonPath("$[2].productId") - .isEqualTo(productId) - .jsonPath("$[2].recommendationId") - .isEqualTo(3); + getAndVerifyRecommendationsByProductId(productId) + .jsonPath("$.length()").isEqualTo(3) + .jsonPath("$[2].productId").isEqualTo(productId) + .jsonPath("$[2].recommendationId").isEqualTo(3); } @Test @@ -57,21 +70,22 @@ public void duplicateError() { int productId = 1; int recommendationId = 1; - postAndVerifyRecommendation(productId, recommendationId, OK) - .jsonPath("$.productId") - .isEqualTo(productId) - .jsonPath("$.recommendationId") - .isEqualTo(recommendationId); + sendCreateRecommendationEvent(productId, recommendationId); - assertEquals(1, repository.count()); + assertEquals(1, repository.count().block()); - postAndVerifyRecommendation(productId, recommendationId, UNPROCESSABLE_ENTITY) - .jsonPath("$.path") - .isEqualTo(BASE_URI) - .jsonPath("$.message") - .isEqualTo("Duplicate key, Product Id: 1, Recommendation Id:1"); + try { + sendCreateRecommendationEvent(productId, recommendationId); + fail("Expected a MessagingException here!"); + } catch (MessagingException me) { + if (me.getCause() instanceof InvalidInputException iie) { + assertEquals("Duplicate key, Product Id: 1, Recommendation Id:1", iie.getMessage()); + } else { + fail("Expected a InvalidInputException as the root cause!"); + } + } - assertEquals(1, repository.count()); + assertEquals(1, repository.count().block()); } @Test @@ -80,41 +94,35 @@ public void deleteRecommendations() { int productId = 1; int recommendationId = 1; - postAndVerifyRecommendation(productId, recommendationId, OK); - assertEquals(1, repository.findByProductId(productId).size()); - - deleteAndVerifyRecommendationsByProductIdIsOk(productId); - assertEquals(0, repository.findByProductId(productId).size()); + sendCreateRecommendationEvent(productId, recommendationId); + assertEquals(1, repository.findByProductId(productId).count().block()); - deleteAndVerifyRecommendationsByProductIdIsOk(productId); + sendDeleteRecommendationEvent(productId); + assertEquals(0, repository.findByProductId(productId).count().block()); } @Test public void getRecommendationsMissingParameter() { getAndVerifyRecommendationsByProductId("", BAD_REQUEST) - .jsonPath("$.path") - .isEqualTo(BASE_URI) + .jsonPath("$.path").isEqualTo(BASE_URI) .jsonPath("$.message") - .isEqualTo("Required int parameter 'productId' is not present"); + .isEqualTo("Required int parameter 'productId' is not present"); } @Test public void getRecommendationsInvalidParameter() { getAndVerifyRecommendationsByProductId("?productId=no-integer", BAD_REQUEST) - .jsonPath("$.path") - .isEqualTo(BASE_URI) - .jsonPath("$.message") - .isEqualTo("Type mismatch."); + .jsonPath("$.path").isEqualTo(BASE_URI) + .jsonPath("$.message").isEqualTo("Type mismatch."); } @Test public void getRecommendationsNotFound() { getAndVerifyRecommendationsByProductId("?productId=113", OK) - .jsonPath("$.length()") - .isEqualTo(0); + .jsonPath("$.length()").isEqualTo(0); } @Test @@ -122,16 +130,15 @@ public void getRecommendationsInvalidParameterNegativeValue() { int productIdInvalid = -1; - getAndVerifyRecommendationsByProductId("?productId=" + productIdInvalid, UNPROCESSABLE_ENTITY) - .jsonPath("$.path") - .isEqualTo(BASE_URI) - .jsonPath("$.message") - .isEqualTo("Invalid productId: " + productIdInvalid); + getAndVerifyRecommendationsByProductId("?productId=" + productIdInvalid, + UNPROCESSABLE_ENTITY) + .jsonPath("$.path").isEqualTo(BASE_URI) + .jsonPath("$.message").isEqualTo("Invalid productId: " + productIdInvalid); } private BodyContentSpec getAndVerifyRecommendationsByProductId( - int productId, HttpStatus expectedStatus) { - return getAndVerifyRecommendationsByProductId("?productId=" + productId, expectedStatus); + int productId) { + return getAndVerifyRecommendationsByProductId("?productId=" + productId, HttpStatus.OK); } private BodyContentSpec getAndVerifyRecommendationsByProductId( @@ -148,39 +155,14 @@ private BodyContentSpec getAndVerifyRecommendationsByProductId( .expectBody(); } - private BodyContentSpec postAndVerifyRecommendation( - int productId, int recommendationId, HttpStatus expectedStatus) { - - Recommendation recommendation = - new Recommendation( - productId, - recommendationId, - "Author " + recommendationId, - recommendationId, - "Content " + recommendationId, - "SA"); - - return client - .post() - .uri(BASE_URI) - .body(Mono.just(recommendation), Recommendation.class) - .accept(APPLICATION_JSON) - .exchange() - .expectStatus() - .isEqualTo(expectedStatus) - .expectHeader() - .contentType(APPLICATION_JSON) - .expectBody(); + private void sendCreateRecommendationEvent(int productId, int recommendationId) { + Recommendation recommendation = new Recommendation(productId, recommendationId, "Author " + recommendationId, recommendationId, "Content " + recommendationId, "SA"); + Event event = new Event<>(CREATE, productId, recommendation); + input.send(new GenericMessage<>(event)); } - private void deleteAndVerifyRecommendationsByProductIdIsOk(int productId) { - client - .delete() - .uri(BASE_URI + "?productId=" + productId) - .accept(APPLICATION_JSON) - .exchange() - .expectStatus() - .isEqualTo(OK) - .expectBody(); + private void sendDeleteRecommendationEvent(int productId) { + Event event = new Event<>(DELETE, productId, null); + input.send(new GenericMessage<>(event)); } -} +} \ No newline at end of file diff --git a/review-service/src/main/java/com/siriusxi/ms/store/revs/api/ReviewController.java b/review-service/src/main/java/com/siriusxi/ms/store/revs/api/ReviewController.java index 0e078c89..8c0ceebd 100644 --- a/review-service/src/main/java/com/siriusxi/ms/store/revs/api/ReviewController.java +++ b/review-service/src/main/java/com/siriusxi/ms/store/revs/api/ReviewController.java @@ -8,16 +8,15 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.web.bind.annotation.RestController; - -import java.util.List; +import reactor.core.publisher.Flux; /** * Class ReviewController is the implementation of the main Review Endpoint API * definition. * - * @see ProductEndpoint + * @see ReviewEndpoint * @author mohamed.taman - * @version v1.0 + * @version v4.0 * @since v3.0 codename Storm */ @RestController @@ -34,19 +33,7 @@ public ReviewController(@Qualifier("ReviewServiceImpl") ReviewService reviewServ /** {@inheritDoc} */ @Override - public Review createReview(Review body) { - return reviewService.createReview(body); - } - - /** {@inheritDoc} */ - @Override - public List getReviews(int productId) { + public Flux getReviews(int productId) { return reviewService.getReviews(productId); } - - /** {@inheritDoc} */ - @Override - public void deleteReviews(int productId) { - reviewService.deleteReviews(productId); - } } diff --git a/review-service/src/main/java/com/siriusxi/ms/store/revs/config/ReviewServiceConfiguration.java b/review-service/src/main/java/com/siriusxi/ms/store/revs/config/ReviewServiceConfiguration.java new file mode 100644 index 00000000..6a04b201 --- /dev/null +++ b/review-service/src/main/java/com/siriusxi/ms/store/revs/config/ReviewServiceConfiguration.java @@ -0,0 +1,27 @@ +package com.siriusxi.ms.store.revs.config; + +import lombok.extern.log4j.Log4j2; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import reactor.core.scheduler.Scheduler; +import reactor.core.scheduler.Schedulers; + +import java.util.concurrent.Executors; + +@Configuration +@Log4j2 +public class ReviewServiceConfiguration { + + @Value("${spring.datasource.hikari.maximum-pool-size:10}") + Integer connectionPoolSize; + + @Bean + public Scheduler jdbcScheduler() { + log.info("Creates a jdbcScheduler with connectionPoolSize = {}", connectionPoolSize); + return Schedulers.fromExecutor(Executors.newFixedThreadPool(connectionPoolSize)); + } + + + +} diff --git a/review-service/src/main/java/com/siriusxi/ms/store/revs/infra/MessageProcessor.java b/review-service/src/main/java/com/siriusxi/ms/store/revs/infra/MessageProcessor.java new file mode 100644 index 00000000..00a44cbf --- /dev/null +++ b/review-service/src/main/java/com/siriusxi/ms/store/revs/infra/MessageProcessor.java @@ -0,0 +1,57 @@ +package com.siriusxi.ms.store.revs.infra; + +import com.siriusxi.ms.store.api.core.review.ReviewService; +import com.siriusxi.ms.store.api.core.review.dto.Review; +import com.siriusxi.ms.store.api.event.Event; +import com.siriusxi.ms.store.util.exceptions.EventProcessingException; +import lombok.extern.log4j.Log4j2; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.cloud.stream.annotation.EnableBinding; +import org.springframework.cloud.stream.annotation.StreamListener; +import org.springframework.cloud.stream.messaging.Sink; + +import static java.lang.String.valueOf; + +@EnableBinding(Sink.class) +@Log4j2 +public class MessageProcessor { + + private final ReviewService service; + + @Autowired + public MessageProcessor(@Qualifier("ReviewServiceImpl") ReviewService service) { + this.service = service; + } + + @StreamListener(target = Sink.INPUT) + public void process(Event event) { + + log.info("Process message created at {}...", event.getEventCreatedAt()); + + switch (event.getEventType()) { + case CREATE -> { + Review review = event.getData(); + log.info("Create review with ID: {}/{}", review.getProductId(), + review.getReviewId()); + service.createReview(review); + } + case DELETE -> { + int productId = event.getKey(); + log.info("Delete review with Product Id: {}", productId); + service.deleteReviews(productId); + } + default -> { + String errorMessage = + "Incorrect event type: " + .concat(valueOf(event.getEventType())) + .concat(", expected a CREATE or DELETE event"); + log.warn(errorMessage); + throw new EventProcessingException(errorMessage); + } + } + + log.info("Message processing done!"); + } + +} diff --git a/review-service/src/main/java/com/siriusxi/ms/store/revs/service/ReviewServiceImpl.java b/review-service/src/main/java/com/siriusxi/ms/store/revs/service/ReviewServiceImpl.java index b4e97209..b15af62c 100644 --- a/review-service/src/main/java/com/siriusxi/ms/store/revs/service/ReviewServiceImpl.java +++ b/review-service/src/main/java/com/siriusxi/ms/store/revs/service/ReviewServiceImpl.java @@ -7,11 +7,17 @@ import com.siriusxi.ms.store.util.exceptions.InvalidInputException; import com.siriusxi.ms.store.util.http.ServiceUtil; import lombok.extern.log4j.Log4j2; +import org.reactivestreams.Publisher; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DataIntegrityViolationException; import org.springframework.stereotype.Service; +import reactor.core.publisher.Flux; +import reactor.core.scheduler.Scheduler; import java.util.List; +import java.util.function.Supplier; + +import static java.util.logging.Level.FINE; @Service("ReviewServiceImpl") @Log4j2 @@ -20,17 +26,23 @@ public class ReviewServiceImpl implements ReviewService { private final ReviewRepository repository; private final ReviewMapper mapper; private final ServiceUtil serviceUtil; + private final Scheduler scheduler; @Autowired public ReviewServiceImpl( - ReviewRepository repository, ReviewMapper mapper, ServiceUtil serviceUtil) { + Scheduler scheduler, ReviewRepository repository, ReviewMapper mapper, + ServiceUtil serviceUtil) { this.repository = repository; this.mapper = mapper; this.serviceUtil = serviceUtil; + this.scheduler = scheduler; } @Override public Review createReview(Review body) { + + isValidProductId(body.getProductId()); + try { ReviewEntity entity = mapper.apiToEntity(body); ReviewEntity newEntity = repository.save(entity); @@ -49,13 +61,18 @@ public Review createReview(Review body) { } @Override - public List getReviews(int productId) { + public Flux getReviews(int productId) { - if (productId < 1) throw new InvalidInputException("Invalid productId: " + productId); + isValidProductId(productId); + + return asyncFlux(() -> Flux.fromIterable(getByProductId(productId))).log(null, FINE); +} - List entityList = repository.findByProductId(productId); - List list = mapper.entityListToApiList(entityList); - list.forEach(e -> e.setServiceAddress(serviceUtil.getServiceAddress())); + protected List getByProductId(int productId) { + + List list = mapper.entityListToApiList(repository.findByProductId(productId)); + list.forEach(e -> + e.setServiceAddress(serviceUtil.getServiceAddress())); log.debug("getReviews: response size: {}", list.size()); @@ -64,8 +81,17 @@ public List getReviews(int productId) { @Override public void deleteReviews(int productId) { + isValidProductId(productId); log.debug( "deleteReviews: tries to delete reviews for the product with productId: {}", productId); repository.deleteAll(repository.findByProductId(productId)); } + + private void isValidProductId(int productId) { + if (productId < 1) throw new InvalidInputException("Invalid productId: " + productId); + } + + private Flux asyncFlux(Supplier> publisherSupplier) { + return Flux.defer(publisherSupplier).subscribeOn(scheduler); + } } diff --git a/review-service/src/main/resources/application.yaml b/review-service/src/main/resources/application.yaml index fec7238e..900dc7ee 100644 --- a/review-service/src/main/resources/application.yaml +++ b/review-service/src/main/resources/application.yaml @@ -1,7 +1,6 @@ spring: application: name: review-service - jpa: show-sql: true open-in-view: false @@ -24,7 +23,7 @@ spring: hikari: initializationFailTimeout: 60000 connection-test-query: SELECT 1 - + maximum-pool-size: 10 flyway: #Enable or disable flyway migrations enabled: true @@ -32,7 +31,39 @@ spring: schemas: review-db user: ${spring.datasource.username} password: ${spring.datasource.password} - + rabbitmq: + host: 127.0.0.1 + port: 5672 + username: guest + password: guest + cloud: + stream: + defaultBinder: rabbit + default: + contentType: application/json + bindings: + input: + destination: reviews + group: reviewsGroup + consumer: + maxAttempts: 3 + backOffInitialInterval: 500 + backOffMaxInterval: 1000 + backOffMultiplier: 2.0 + rabbit: + bindings: + input: + consumer: + autoBindDlq: true + republishToDlq: true + kafka: + bindings: + input: + consumer: + enableDlq: true + binder: + brokers: 127.0.0.1 + defaultBrokerPort: 9092 server: port: 9083 @@ -57,6 +88,8 @@ management: endpoint: shutdown: enabled: true + health: + show-details: always # This is a docker specific profile properties # Also profiles could be separated in its owen file @@ -71,6 +104,13 @@ spring: flyway: url: "jdbc:mysql://mysql/review-db?useSSL=false&serverTimezone=UTC" + rabbitmq: + host: rabbitmq + cloud: + stream: + kafka: + binder: + brokers: kafka server: port: 8080 \ No newline at end of file diff --git a/review-service/src/test/java/com/siriusxi/ms/store/revs/MapperTests.java b/review-service/src/test/java/com/siriusxi/ms/store/revs/MapperTests.java index 0ebd7d11..eaa17b37 100644 --- a/review-service/src/test/java/com/siriusxi/ms/store/revs/MapperTests.java +++ b/review-service/src/test/java/com/siriusxi/ms/store/revs/MapperTests.java @@ -10,7 +10,7 @@ import static org.junit.jupiter.api.Assertions.*; -public class MapperTests { +class MapperTests { private final ReviewMapper mapper = ReviewMapper.INSTANCE; diff --git a/review-service/src/test/java/com/siriusxi/ms/store/revs/PersistenceTests.java b/review-service/src/test/java/com/siriusxi/ms/store/revs/PersistenceTests.java index eeca74c7..24b72893 100644 --- a/review-service/src/test/java/com/siriusxi/ms/store/revs/PersistenceTests.java +++ b/review-service/src/test/java/com/siriusxi/ms/store/revs/PersistenceTests.java @@ -24,7 +24,7 @@ @Transactional(propagation = NOT_SUPPORTED) @ActiveProfiles("test") @TestMethodOrder(MethodOrderer.OrderAnnotation.class) -public class PersistenceTests { +class PersistenceTests { @Autowired private ReviewRepository repository; diff --git a/review-service/src/test/java/com/siriusxi/ms/store/revs/ReviewServiceApplicationTests.java b/review-service/src/test/java/com/siriusxi/ms/store/revs/ReviewServiceApplicationTests.java index 9e0c4f8e..d0f50eef 100644 --- a/review-service/src/test/java/com/siriusxi/ms/store/revs/ReviewServiceApplicationTests.java +++ b/review-service/src/test/java/com/siriusxi/ms/store/revs/ReviewServiceApplicationTests.java @@ -1,16 +1,25 @@ package com.siriusxi.ms.store.revs; import com.siriusxi.ms.store.api.core.review.dto.Review; +import com.siriusxi.ms.store.api.event.Event; import com.siriusxi.ms.store.revs.persistence.ReviewRepository; +import com.siriusxi.ms.store.util.exceptions.InvalidInputException; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.stream.messaging.Sink; import org.springframework.http.HttpStatus; +import org.springframework.integration.channel.AbstractMessageChannel; +import org.springframework.messaging.MessagingException; +import org.springframework.messaging.support.GenericMessage; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.web.reactive.server.WebTestClient; import reactor.core.publisher.Mono; +import static com.siriusxi.ms.store.api.event.Event.Type.CREATE; +import static com.siriusxi.ms.store.api.event.Event.Type.DELETE; +import static org.assertj.core.api.Assertions.fail; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; import static org.springframework.http.HttpStatus.*; @@ -28,8 +37,14 @@ class ReviewServiceApplicationTests { @Autowired private ReviewRepository repository; + @Autowired + private Sink channels; + + private AbstractMessageChannel input = null; + @BeforeEach public void setupDb() { + input = (AbstractMessageChannel) channels.input(); repository.deleteAll(); } @@ -40,19 +55,16 @@ public void getReviewsByProductId() { assertEquals(0, repository.findByProductId(productId).size()); - postAndVerifyReview(productId, 1, OK); - postAndVerifyReview(productId, 2, OK); - postAndVerifyReview(productId, 3, OK); + sendCreateReviewEvent(productId, 1); + sendCreateReviewEvent(productId, 2); + sendCreateReviewEvent(productId, 3); assertEquals(3, repository.findByProductId(productId).size()); - getAndVerifyReviewsByProductId(productId, OK) - .jsonPath("$.length()") - .isEqualTo(3) - .jsonPath("$[2].productId") - .isEqualTo(productId) - .jsonPath("$[2].reviewId") - .isEqualTo(3); + getAndVerifyReviewsByProductId(productId) + .jsonPath("$.length()").isEqualTo(3) + .jsonPath("$[2].productId").isEqualTo(productId) + .jsonPath("$[2].reviewId").isEqualTo(3); } @Test @@ -63,19 +75,20 @@ public void duplicateError() { assertEquals(0, repository.count()); - postAndVerifyReview(productId, reviewId, OK) - .jsonPath("$.productId") - .isEqualTo(productId) - .jsonPath("$.reviewId") - .isEqualTo(reviewId); + sendCreateReviewEvent(productId, reviewId); assertEquals(1, repository.count()); - postAndVerifyReview(productId, reviewId, UNPROCESSABLE_ENTITY) - .jsonPath("$.path") - .isEqualTo(BASE_URI) - .jsonPath("$.message") - .isEqualTo("Duplicate key, Product Id: 1, Review Id:1"); + try { + sendCreateReviewEvent(productId, reviewId); + fail("Expected a MessagingException here!"); + } catch (MessagingException me) { + if (me.getCause() instanceof InvalidInputException iie) { + assertEquals("Duplicate key, Product Id: 1, Review Id:1", iie.getMessage()); + } else { + fail("Expected a InvalidInputException as the root cause!"); + } + } assertEquals(1, repository.count()); } @@ -84,41 +97,39 @@ public void duplicateError() { public void deleteReviews() { int productId = 1; - int recommendationId = 1; + int reviewId = 1; - postAndVerifyReview(productId, recommendationId, OK); + sendCreateReviewEvent(productId, reviewId); assertEquals(1, repository.findByProductId(productId).size()); - deleteAndVerifyReviewsByProductId(productId); + sendDeleteReviewEvent(productId); assertEquals(0, repository.findByProductId(productId).size()); - deleteAndVerifyReviewsByProductId(productId); + sendDeleteReviewEvent(productId); } @Test public void getReviewsMissingParameter() { getAndVerifyReviewsByProductId("", BAD_REQUEST) - .jsonPath("$.path") - .isEqualTo(BASE_URI) + .jsonPath("$.path").isEqualTo(BASE_URI) .jsonPath("$.message") - .isEqualTo("Required int parameter 'productId' is not present"); + .isEqualTo("Required int parameter 'productId' is not present"); } @Test public void getReviewsInvalidParameter() { getAndVerifyReviewsByProductId("?productId=no-integer", BAD_REQUEST) - .jsonPath("$.path") - .isEqualTo(BASE_URI) - .jsonPath("$.message") - .isEqualTo("Type mismatch."); + .jsonPath("$.path").isEqualTo(BASE_URI) + .jsonPath("$.message").isEqualTo("Type mismatch."); } @Test public void getReviewsNotFound() { - getAndVerifyReviewsByProductId("?productId=213", OK).jsonPath("$.length()").isEqualTo(0); + getAndVerifyReviewsByProductId("?productId=213", OK) + .jsonPath("$.length()").isEqualTo(0); } @Test @@ -126,16 +137,15 @@ public void getReviewsInvalidParameterNegativeValue() { int productIdInvalid = -1; - getAndVerifyReviewsByProductId("?productId=" + productIdInvalid, UNPROCESSABLE_ENTITY) - .jsonPath("$.path") - .isEqualTo(BASE_URI) - .jsonPath("$.message") - .isEqualTo("Invalid productId: " + productIdInvalid); + getAndVerifyReviewsByProductId("?productId=" + productIdInvalid, + UNPROCESSABLE_ENTITY) + .jsonPath("$.path").isEqualTo(BASE_URI) + .jsonPath("$.message").isEqualTo("Invalid productId: " + productIdInvalid); } private WebTestClient.BodyContentSpec getAndVerifyReviewsByProductId( - int productId, HttpStatus expectedStatus) { - return getAndVerifyReviewsByProductId("?productId=" + productId, expectedStatus); + int productId) { + return getAndVerifyReviewsByProductId("?productId=" + productId, HttpStatus.OK); } private WebTestClient.BodyContentSpec getAndVerifyReviewsByProductId( @@ -145,44 +155,20 @@ private WebTestClient.BodyContentSpec getAndVerifyReviewsByProductId( .uri(BASE_URI + productIdQuery) .accept(APPLICATION_JSON) .exchange() - .expectStatus() - .isEqualTo(expectedStatus) - .expectHeader() - .contentType(APPLICATION_JSON) + .expectStatus().isEqualTo(expectedStatus) + .expectHeader().contentType(APPLICATION_JSON) .expectBody(); } - private WebTestClient.BodyContentSpec postAndVerifyReview( - int productId, int reviewId, HttpStatus expectedStatus) { - Review review = - new Review( - productId, - reviewId, - "Author " + reviewId, - "Subject " + reviewId, - "Content " + reviewId, - "SA"); - return client - .post() - .uri(BASE_URI) - .body(Mono.just(review), Review.class) - .accept(APPLICATION_JSON) - .exchange() - .expectStatus() - .isEqualTo(expectedStatus) - .expectHeader() - .contentType(APPLICATION_JSON) - .expectBody(); + private void sendCreateReviewEvent(int productId, int reviewId) { + Review review = new Review(productId, reviewId, "Author " + reviewId, + "Subject " + reviewId, "Content " + reviewId, "SA"); + Event event = new Event<>(CREATE, productId, review); + input.send(new GenericMessage<>(event)); } - private void deleteAndVerifyReviewsByProductId(int productId) { - client - .delete() - .uri(BASE_URI + "?productId=" + productId) - .accept(APPLICATION_JSON) - .exchange() - .expectStatus() - .isEqualTo(OK) - .expectBody(); + private void sendDeleteReviewEvent(int productId) { + Event event = new Event<>(DELETE, productId, null); + input.send(new GenericMessage<>(event)); } } diff --git a/store-api/src/main/java/com/siriusxi/ms/store/api/composite/StoreEndpoint.java b/store-api/src/main/java/com/siriusxi/ms/store/api/composite/StoreEndpoint.java index 2bea8e78..8e5142da 100644 --- a/store-api/src/main/java/com/siriusxi/ms/store/api/composite/StoreEndpoint.java +++ b/store-api/src/main/java/com/siriusxi/ms/store/api/composite/StoreEndpoint.java @@ -6,6 +6,7 @@ import io.swagger.annotations.ApiResponse; import io.swagger.annotations.ApiResponses; import org.springframework.web.bind.annotation.*; +import reactor.core.publisher.Mono; import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; @@ -53,7 +54,7 @@ public interface StoreEndpoint extends StoreService { }) @GetMapping(value = "products/{id}", produces = APPLICATION_JSON_VALUE) - ProductAggregate getProduct(@PathVariable int id); + Mono getProduct(@PathVariable int id); /** * Sample usage: diff --git a/store-api/src/main/java/com/siriusxi/ms/store/api/composite/StoreService.java b/store-api/src/main/java/com/siriusxi/ms/store/api/composite/StoreService.java index 53d6aa68..61f9508d 100644 --- a/store-api/src/main/java/com/siriusxi/ms/store/api/composite/StoreService.java +++ b/store-api/src/main/java/com/siriusxi/ms/store/api/composite/StoreService.java @@ -1,6 +1,7 @@ package com.siriusxi.ms.store.api.composite; import com.siriusxi.ms.store.api.composite.dto.ProductAggregate; +import reactor.core.publisher.Mono; /** * Interface that define the general service contract (methods) for the Store @@ -28,13 +29,14 @@ public interface StoreService { /** * Get the aggregate product with its reviews and recommendations and services involved in the * call. + * It is a Non-Blocking API. * * @see ProductAggregate * @param id is the product id that you are looking for. * @return the product, if found, else null. * @since v0.1 */ - ProductAggregate getProduct(int id); + Mono getProduct(int id); /** * Delete the product and all its relate reviews and recommendations from their repositories. diff --git a/store-api/src/main/java/com/siriusxi/ms/store/api/core/product/ProductEndpoint.java b/store-api/src/main/java/com/siriusxi/ms/store/api/core/product/ProductEndpoint.java index b5ae4d31..2c44fccb 100644 --- a/store-api/src/main/java/com/siriusxi/ms/store/api/core/product/ProductEndpoint.java +++ b/store-api/src/main/java/com/siriusxi/ms/store/api/core/product/ProductEndpoint.java @@ -2,6 +2,7 @@ import com.siriusxi.ms.store.api.core.product.dto.Product; import org.springframework.web.bind.annotation.*; +import reactor.core.publisher.Mono; import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; @@ -12,7 +13,7 @@ * * @see ProductService * @author mohamed.taman - * @version v1.0 + * @version v4.0 * @since v3.0 codename Storm */ @RequestMapping("products") @@ -29,31 +30,5 @@ public interface ProductEndpoint extends ProductService { */ @Override @GetMapping(value = "{productId}", produces = APPLICATION_JSON_VALUE) - Product getProduct(@PathVariable("productId") int id); - - /** - * Sample usage: - * - *

curl -X POST $HOST:$PORT/products \ -H "Content-Type: application/json" --data \ - * '{"productId":123,"name":"product 123","weight":123}' - * - * @param body product to save. - * @return Product just created. - * @since v3.0 codename Storm - */ - @Override - @PostMapping(produces = APPLICATION_JSON_VALUE, consumes = APPLICATION_JSON_VALUE) - Product createProduct(@RequestBody Product body); - - /** - * Sample usage: - * - *

curl -X DELETE $HOST:$PORT/products/1 - * - * @param id to be deleted. - * @since v3.0 codename Storm - */ - @Override - @DeleteMapping("{productId}") - void deleteProduct(@PathVariable("productId") int id); + Mono getProduct(@PathVariable("productId") int id); } diff --git a/store-api/src/main/java/com/siriusxi/ms/store/api/core/product/ProductService.java b/store-api/src/main/java/com/siriusxi/ms/store/api/core/product/ProductService.java index 04a8b095..4a36ecce 100644 --- a/store-api/src/main/java/com/siriusxi/ms/store/api/core/product/ProductService.java +++ b/store-api/src/main/java/com/siriusxi/ms/store/api/core/product/ProductService.java @@ -1,6 +1,7 @@ package com.siriusxi.ms.store.api.core.product; import com.siriusxi.ms.store.api.core.product.dto.Product; +import reactor.core.publisher.Mono; /** * Interface that define the general service contract (methods) for the Product @@ -18,21 +19,21 @@ public interface ProductService { /** * Get the product with Id from repository. + * It is a Non-Blocking API. * * @param id is the product id that you are looking for. * @return the product, if found, else null. * @since v0.1 */ - Product getProduct(int id); + Mono getProduct(int id); /** * Add product to the repository. * * @param body product to save. - * @return just created product. * @since v0.1 */ - Product createProduct(Product body); + default Product createProduct(Product body){ return null;} /** * Delete the product from repository. @@ -41,5 +42,5 @@ public interface ProductService { * @param id to be deleted. * @since v0.1 */ - void deleteProduct(int id); + default void deleteProduct(int id){} } diff --git a/store-api/src/main/java/com/siriusxi/ms/store/api/core/recommendation/RecommendationEndpoint.java b/store-api/src/main/java/com/siriusxi/ms/store/api/core/recommendation/RecommendationEndpoint.java index 9fca72c5..a95e1c55 100644 --- a/store-api/src/main/java/com/siriusxi/ms/store/api/core/recommendation/RecommendationEndpoint.java +++ b/store-api/src/main/java/com/siriusxi/ms/store/api/core/recommendation/RecommendationEndpoint.java @@ -1,9 +1,10 @@ package com.siriusxi.ms.store.api.core.recommendation; import com.siriusxi.ms.store.api.core.recommendation.dto.Recommendation; -import org.springframework.web.bind.annotation.*; - -import java.util.List; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import reactor.core.publisher.Flux; import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; /** @@ -13,7 +14,7 @@ * * @see RecommendationService * @author mohamed.taman - * @version v1.0 + * @version v4.0 * @since v3.0 codename Storm */ @RequestMapping("recommendations") @@ -29,31 +30,5 @@ public interface RecommendationEndpoint extends RecommendationService { * @since v3.0 codename Storm */ @GetMapping(produces = APPLICATION_JSON_VALUE) - List getRecommendations(@RequestParam("productId") int productId); - - /** - * Sample usage: - * - *

curl -X POST $HOST:$PORT/recommendations \ - * -H "Content-Type: application/json" --data \ - * '{"productId":123,"recommendationId":456,"author":"me","rate":5,"content":"yada, yada, yada" - * }' - * - * @param body the recommendation to add. - * @return currently created recommendation. - * @since v3.0 codename Storm - */ - @PostMapping(produces = APPLICATION_JSON_VALUE, consumes = APPLICATION_JSON_VALUE) - Recommendation createRecommendation(@RequestBody Recommendation body); - - /** - * Sample usage: - * - *

curl -X DELETE $HOST:$PORT/recommendations?productId=1 - * - * @param productId to delete recommendations for. - * @since version 0.1 - */ - @DeleteMapping - void deleteRecommendations(@RequestParam("productId") int productId); + Flux getRecommendations(@RequestParam("productId") int productId); } diff --git a/store-api/src/main/java/com/siriusxi/ms/store/api/core/recommendation/RecommendationService.java b/store-api/src/main/java/com/siriusxi/ms/store/api/core/recommendation/RecommendationService.java index 2037a9b0..bf9c5c49 100644 --- a/store-api/src/main/java/com/siriusxi/ms/store/api/core/recommendation/RecommendationService.java +++ b/store-api/src/main/java/com/siriusxi/ms/store/api/core/recommendation/RecommendationService.java @@ -1,8 +1,7 @@ package com.siriusxi.ms.store.api.core.recommendation; import com.siriusxi.ms.store.api.core.recommendation.dto.Recommendation; - -import java.util.List; +import reactor.core.publisher.Flux; /** * Interface that define the general service contract (methods) for the Recommendation @@ -18,13 +17,13 @@ */ public interface RecommendationService { /** - * Get all recommendations for specific product by product id. + * Get all recommendations for specific product by product id. It is a Non-Blocking API. * * @param productId that you are looking for its recommendations. * @return list of product recommendations, or empty list if there are no recommendations. * @since v0.1 */ - List getRecommendations(int productId); + Flux getRecommendations(int productId); /** * Create a new recommendation for a product. @@ -33,7 +32,9 @@ public interface RecommendationService { * @return currently created recommendation. * @since v0.1 */ - Recommendation createRecommendation(Recommendation body); + default Recommendation createRecommendation(Recommendation body) { + return null; + } /** * Delete all product recommendations. @@ -41,5 +42,5 @@ public interface RecommendationService { * @param productId to delete recommendations for. * @since v0.1 */ - void deleteRecommendations(int productId); + default void deleteRecommendations(int productId) {} } diff --git a/store-api/src/main/java/com/siriusxi/ms/store/api/core/review/ReviewEndpoint.java b/store-api/src/main/java/com/siriusxi/ms/store/api/core/review/ReviewEndpoint.java index 48dbcaea..dd724f5e 100644 --- a/store-api/src/main/java/com/siriusxi/ms/store/api/core/review/ReviewEndpoint.java +++ b/store-api/src/main/java/com/siriusxi/ms/store/api/core/review/ReviewEndpoint.java @@ -2,6 +2,7 @@ import com.siriusxi.ms.store.api.core.review.dto.Review; import org.springframework.web.bind.annotation.*; +import reactor.core.publisher.Flux; import java.util.List; @@ -14,27 +15,12 @@ * * @see ReviewService * @author mohamed.taman - * @version v1.0 + * @version v4.0 * @since v3.0 codename Storm */ @RequestMapping("reviews") public interface ReviewEndpoint extends ReviewService { - /** - * Sample usage: - * - *

curl -X POST $HOST:$PORT/reviews \ - * -H "Content-Type: application/json" --data \ - * '{"productId":123,"reviewId":456,"author":"me","subject":"yada, yada, yada", - * "content":"yada, yada, yada"}' - * - * @param body review to be created. - * @return just created review. - * @since v3.0 codename Storm - */ - @PostMapping(produces = APPLICATION_JSON_VALUE, consumes = APPLICATION_JSON_VALUE) - Review createReview(@RequestBody Review body); - /** * Sample usage: * @@ -45,16 +31,5 @@ public interface ReviewEndpoint extends ReviewService { * @since v3.0 codename Storm */ @GetMapping(produces = APPLICATION_JSON_VALUE) - List getReviews(@RequestParam("productId") int productId); - - /** - * Sample usage: - * - *

curl -X DELETE $HOST:$PORT/review?productId=1 - * - * @param productId to delete its reviews. - * @since v3.0 codename Storm - */ - @DeleteMapping - void deleteReviews(@RequestParam("productId") int productId); + Flux getReviews(@RequestParam("productId") int productId); } diff --git a/store-api/src/main/java/com/siriusxi/ms/store/api/core/review/ReviewService.java b/store-api/src/main/java/com/siriusxi/ms/store/api/core/review/ReviewService.java index 7586ea26..20321f53 100644 --- a/store-api/src/main/java/com/siriusxi/ms/store/api/core/review/ReviewService.java +++ b/store-api/src/main/java/com/siriusxi/ms/store/api/core/review/ReviewService.java @@ -1,6 +1,7 @@ package com.siriusxi.ms.store.api.core.review; import com.siriusxi.ms.store.api.core.review.dto.Review; +import reactor.core.publisher.Flux; import java.util.List; @@ -13,18 +14,19 @@ * * * @author mohamed.taman - * @version v0.2 + * @version v4.0 * @since v0.1 */ public interface ReviewService { /** * Get all reviews for specific product by product id. + * It is a Non-Blocking API. * * @param productId that you are looking for its reviews. * @return list of reviews for this product, or empty list if there are no reviews. */ - List getReviews(int productId); + Flux getReviews(int productId); /** * Create a new review for a product. @@ -32,12 +34,12 @@ public interface ReviewService { * @param body review to be created. * @return just created review. */ - Review createReview(Review body); + default Review createReview(Review body){return null;} /** * Delete all product reviews. * * @param productId to delete its reviews. */ - void deleteReviews(int productId); + default void deleteReviews(int productId){} } diff --git a/store-api/src/main/java/com/siriusxi/ms/store/api/event/Event.java b/store-api/src/main/java/com/siriusxi/ms/store/api/event/Event.java new file mode 100644 index 00000000..462d379d --- /dev/null +++ b/store-api/src/main/java/com/siriusxi/ms/store/api/event/Event.java @@ -0,0 +1,29 @@ +package com.siriusxi.ms.store.api.event; + +import lombok.*; + +import java.time.LocalDateTime; + +import static java.time.LocalDateTime.now; +import static lombok.AccessLevel.NONE; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Setter(NONE) +public class Event { + + public enum Type {CREATE, DELETE} + + private Event.Type eventType; + private K key; + private T data; + private LocalDateTime eventCreatedAt; + + public Event(Type eventType, K key, T data) { + this.eventType = eventType; + this.key = key; + this.data = data; + this.eventCreatedAt = now(); + } +} \ No newline at end of file diff --git a/store-build-chassis/pom.xml b/store-build-chassis/pom.xml index 989a9950..c0af229c 100644 --- a/store-build-chassis/pom.xml +++ b/store-build-chassis/pom.xml @@ -19,6 +19,7 @@ 14 + Hoxton.RELEASE UTF-8 UTF-8 @@ -47,6 +48,15 @@ ${springfox.swagger.version} + + + org.springframework.cloud + spring-cloud-dependencies + ${spring.cloud.version} + pom + import + + @@ -66,6 +76,13 @@ spring-boot-starter-webflux + + + org.springframework.boot + spring-boot-properties-migrator + runtime + + @@ -96,6 +113,10 @@ ${maven.surefire.plugin.version} --enable-preview + + **/*Tests.java + **/*Test.java + diff --git a/store-service-chassis/pom.xml b/store-service-chassis/pom.xml index 912d7bfc..bc0122db 100644 --- a/store-service-chassis/pom.xml +++ b/store-service-chassis/pom.xml @@ -23,7 +23,7 @@ - + org.springframework.boot spring-boot-devtools @@ -31,21 +31,35 @@ true + org.springframework.boot spring-boot-configuration-processor true + - + org.springframework.boot spring-boot-starter-actuator - + + + org.springframework.cloud + spring-cloud-starter-stream-rabbit + + + + + org.springframework.cloud + spring-cloud-starter-stream-kafka + + + @@ -65,11 +79,20 @@ test + io.projectreactor reactor-test test + + + + org.springframework.cloud + spring-cloud-stream-test-support + test + + diff --git a/store-service/src/main/java/com/siriusxi/ms/store/pcs/api/StoreController.java b/store-service/src/main/java/com/siriusxi/ms/store/pcs/api/StoreController.java index 360eb8ff..e918b62d 100644 --- a/store-service/src/main/java/com/siriusxi/ms/store/pcs/api/StoreController.java +++ b/store-service/src/main/java/com/siriusxi/ms/store/pcs/api/StoreController.java @@ -7,6 +7,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.web.bind.annotation.RestController; +import reactor.core.publisher.Mono; @RestController @Log4j2 @@ -22,9 +23,10 @@ public StoreController(@Qualifier("StoreServiceImpl") StoreService storeService) this.storeService = storeService; } - /** {@inheritDoc} */ + /** {@inheritDoc} + * @return*/ @Override - public ProductAggregate getProduct(int id) { + public Mono getProduct(int id) { return storeService.getProduct(id); } diff --git a/store-service/src/main/java/com/siriusxi/ms/store/pcs/config/StoreConfiguration.java b/store-service/src/main/java/com/siriusxi/ms/store/pcs/config/StoreServiceConfiguration.java similarity index 52% rename from store-service/src/main/java/com/siriusxi/ms/store/pcs/config/StoreConfiguration.java rename to store-service/src/main/java/com/siriusxi/ms/store/pcs/config/StoreServiceConfiguration.java index d84591de..c683e55b 100644 --- a/store-service/src/main/java/com/siriusxi/ms/store/pcs/config/StoreConfiguration.java +++ b/store-service/src/main/java/com/siriusxi/ms/store/pcs/config/StoreServiceConfiguration.java @@ -1,6 +1,11 @@ package com.siriusxi.ms.store.pcs.config; +import com.siriusxi.ms.store.pcs.integration.StoreIntegration; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.actuate.health.CompositeReactiveHealthContributor; +import org.springframework.boot.actuate.health.ReactiveHealthContributor; +import org.springframework.boot.actuate.health.ReactiveHealthIndicator; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate; @@ -9,39 +14,65 @@ import springfox.documentation.service.Contact; import springfox.documentation.spring.web.plugins.Docket; +import java.util.Map; + import static java.util.Collections.emptyList; import static org.springframework.web.bind.annotation.RequestMethod.*; import static springfox.documentation.builders.RequestHandlerSelectors.basePackage; import static springfox.documentation.spi.DocumentationType.SWAGGER_2; @Configuration -public class StoreConfiguration { +public class StoreServiceConfiguration { + + private final StoreIntegration integration; + @Value("${api.common.version}") - String apiVersion; + private String apiVersion; @Value("${api.common.title}") - String apiTitle; + private String apiTitle; @Value("${api.common.description}") - String apiDescription; + private String apiDescription; @Value("${api.common.termsOfServiceUrl}") - String apiTermsOfServiceUrl; + private String apiTermsOfServiceUrl; @Value("${api.common.license}") - String apiLicense; + private String apiLicense; @Value("${api.common.licenseUrl}") - String apiLicenseUrl; + private String apiLicenseUrl; @Value("${api.common.contact.name}") - String apiContactName; + private String apiContactName; @Value("${api.common.contact.url}") - String apiContactUrl; + private String apiContactUrl; @Value("${api.common.contact.email}") - String apiContactEmail; + private String apiContactEmail; + + @Autowired + public StoreServiceConfiguration(StoreIntegration integration) { + this.integration = integration; + } + + @Bean(name = "Core System Microservices") + ReactiveHealthContributor coreServices() { + + ReactiveHealthIndicator productHealthIndicator = integration::getProductHealth; + ReactiveHealthIndicator recommendationHealthIndicator = integration::getRecommendationHealth; + ReactiveHealthIndicator reviewHealthIndicator = integration::getReviewHealth; + + Map allIndicators = + Map.of( + "Product Service", productHealthIndicator, + "Recommendation Service", recommendationHealthIndicator, + "Review Service", reviewHealthIndicator); + + return CompositeReactiveHealthContributor.fromMap(allIndicators); + } @Bean RestTemplate newRestClient() { @@ -66,13 +97,17 @@ Using the apis() and paths() methods, .paths(PathSelectors.any()) .build() /* - Using the globalResponseMessage() method, we ask SpringFox not to add any default HTTP response codes to the API documentation, such as 401 and 403, which we don't currently use. + Using the globalResponseMessage() method, we ask SpringFox not to add any default HTTP + response codes to the API documentation, such as 401 and 403, + which we don't currently use. */ .globalResponseMessage(POST, emptyList()) .globalResponseMessage(GET, emptyList()) .globalResponseMessage(DELETE, emptyList()) /* - The api* variables that are used to configure the Docket bean with general information about the API are initialized from the property file using Spring @Value annotations. + The api* variables that are used to configure the Docket bean with general + information about the API are initialized from the property file using + Spring @Value annotations. */ .apiInfo( new ApiInfo( diff --git a/store-service/src/main/java/com/siriusxi/ms/store/pcs/integration/StoreIntegration.java b/store-service/src/main/java/com/siriusxi/ms/store/pcs/integration/StoreIntegration.java index 58204b82..da4fc814 100644 --- a/store-service/src/main/java/com/siriusxi/ms/store/pcs/integration/StoreIntegration.java +++ b/store-service/src/main/java/com/siriusxi/ms/store/pcs/integration/StoreIntegration.java @@ -7,41 +7,49 @@ import com.siriusxi.ms.store.api.core.recommendation.dto.Recommendation; import com.siriusxi.ms.store.api.core.review.ReviewService; import com.siriusxi.ms.store.api.core.review.dto.Review; +import com.siriusxi.ms.store.api.event.Event; import com.siriusxi.ms.store.util.exceptions.InvalidInputException; import com.siriusxi.ms.store.util.exceptions.NotFoundException; import com.siriusxi.ms.store.util.http.HttpErrorInfo; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; -import org.springframework.core.ParameterizedTypeReference; +import org.springframework.boot.actuate.health.Health; +import org.springframework.cloud.stream.annotation.EnableBinding; +import org.springframework.cloud.stream.annotation.Output; +import org.springframework.messaging.MessageChannel; import org.springframework.stereotype.Component; -import org.springframework.web.client.HttpClientErrorException; -import org.springframework.web.client.RestTemplate; +import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.web.reactive.function.client.WebClientResponseException; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; import java.io.IOException; -import java.util.ArrayList; -import java.util.List; +import static com.siriusxi.ms.store.api.event.Event.Type.CREATE; +import static com.siriusxi.ms.store.api.event.Event.Type.DELETE; +import static com.siriusxi.ms.store.pcs.integration.StoreIntegration.MessageSources; import static java.lang.String.valueOf; -import static org.springframework.http.HttpMethod.GET; +import static org.springframework.integration.support.MessageBuilder.withPayload; +import static reactor.core.publisher.Flux.empty; +@EnableBinding(MessageSources.class) @Component @Log4j2 public class StoreIntegration implements ProductService, RecommendationEndpoint, ReviewService { public static final String PRODUCT_ID_QUERY_PARAM = "?productId="; - - private final RestTemplate restTemplate; + private final WebClient webClient; private final ObjectMapper mapper; - + private final MessageSources messageSources; private final String productServiceUrl; private final String recommendationServiceUrl; private final String reviewServiceUrl; - @Autowired public StoreIntegration( - RestTemplate restTemplate, + WebClient.Builder webClient, ObjectMapper mapper, + MessageSources messageSources, @Value("${app.product-service.host}") String productServiceHost, @Value("${app.product-service.port}") int productServicePort, @Value("${app.recommendation-service.host}") String recommendationServiceHost, @@ -49,204 +57,196 @@ public StoreIntegration( @Value("${app.review-service.host}") String reviewServiceHost, @Value("${app.review-service.port}") int reviewServicePort) { - this.restTemplate = restTemplate; + this.webClient = webClient.build(); this.mapper = mapper; + this.messageSources = messageSources; var http = "http://"; productServiceUrl = http.concat(productServiceHost) .concat(":") - .concat(valueOf(productServicePort)) - .concat("/products/"); + .concat(valueOf(productServicePort)); recommendationServiceUrl = http.concat(recommendationServiceHost) .concat(":") - .concat(valueOf(recommendationServicePort)) - .concat("/recommendations"); + .concat(valueOf(recommendationServicePort)); reviewServiceUrl = http.concat(reviewServiceHost) .concat(":") - .concat(valueOf(reviewServicePort)) - .concat("/reviews"); + .concat(valueOf(reviewServicePort)); } @Override public Product createProduct(Product body) { - - try { - String url = productServiceUrl; - log.debug("Will post a new product to URL: {}", url); - - Product product = restTemplate.postForObject(url, body, Product.class); - log.debug("Created a product with id: {}", product != null ? product.getProductId() : -1); - - return product; - - } catch (HttpClientErrorException ex) { - throw handleHttpClientException(ex); - } + log.debug("Publishing a create event for a new product {}",body.toString()); + messageSources + .outputProducts() + .send(withPayload(new Event<>(CREATE, body.getProductId(), body)).build()); + return body; } @Override - public Product getProduct(int productId) { - - try { - String url = productServiceUrl + "/" + productId; - log.debug("Will call the getProduct API on URL: {}", url); + public Mono getProduct(int productId) { - Product product = restTemplate.getForObject(url, Product.class); - log.debug("Found a product with id: {}", product != null ? product.getProductId() : -1); + var url = productServiceUrl + .concat("/products/") + .concat(valueOf(productId)); - return product; + log.debug("Will call the getProduct API on URL: {}", url); - } catch (HttpClientErrorException ex) { - throw handleHttpClientException(ex); - } + return webClient + .get() + .uri(url) + .retrieve() + .bodyToMono(Product.class) + .log() + .onErrorMap(WebClientResponseException.class, this::handleException); } @Override public void deleteProduct(int productId) { - try { - String url = productServiceUrl + "/" + productId; - log.debug("Will call the deleteProduct API on URL: {}", url); - - restTemplate.delete(url); - - } catch (HttpClientErrorException ex) { - throw handleHttpClientException(ex); - } + log.debug("Publishing a delete event for product id {}", productId); + messageSources + .outputProducts() + .send(withPayload(new Event<>(DELETE, productId, null)).build()); } @Override public Recommendation createRecommendation(Recommendation body) { + log.debug("Publishing a create event for a new recommendation {}",body.toString()); - try { - String url = recommendationServiceUrl; - log.debug("Will post a new recommendation to URL: {}", url); - - Recommendation recommendation = restTemplate.postForObject(url, body, Recommendation.class); - log.debug("Created a recommendation with id: {}", - recommendation != null ? recommendation.getRecommendationId() : -1); - - return recommendation; + messageSources + .outputRecommendations() + .send(withPayload(new Event<>(CREATE, body.getProductId(), body)).build()); - } catch (HttpClientErrorException ex) { - throw handleHttpClientException(ex); - } + return body; } @Override - public List getRecommendations(int productId) { - - try { - String url = recommendationServiceUrl.concat(PRODUCT_ID_QUERY_PARAM).concat(valueOf(productId)); - - log.debug("Will call the getRecommendations API on URL: {}", url); - List recommendations = - restTemplate - .exchange(url, GET, null, new ParameterizedTypeReference>() {}) - .getBody(); - - log.debug( - "Found {} recommendations for a product with id: {}", recommendations != null ? recommendations.size() : 0, productId); - return recommendations; - - } catch (Exception ex) { - log.warn( - "Got an exception while requesting recommendations, return zero recommendations: {}", - ex.getMessage()); - return new ArrayList<>(); - } + public Flux getRecommendations(int productId) { + + var url = recommendationServiceUrl + .concat("/recommendations") + .concat(PRODUCT_ID_QUERY_PARAM) + .concat(valueOf(productId)); + + log.debug("Will call the getRecommendations API on URL: {}", url); + + /* Return an empty result if something goes wrong to make it possible + for the composite service to return partial responses + */ + return webClient + .get() + .uri(url) + .retrieve() + .bodyToFlux(Recommendation.class) + .log() + .onErrorResume(error -> empty()); } @Override public void deleteRecommendations(int productId) { - try { - String url = recommendationServiceUrl - .concat(PRODUCT_ID_QUERY_PARAM) - .concat(valueOf(productId)); - log.debug("Will call the deleteRecommendations API on URL: {}", url); - - restTemplate.delete(url); - - } catch (HttpClientErrorException ex) { - throw handleHttpClientException(ex); - } + messageSources + .outputRecommendations() + .send(withPayload(new Event<>(DELETE, productId, null)).build()); } @Override public Review createReview(Review body) { + messageSources + .outputReviews() + .send(withPayload(new Event<>(CREATE, body.getProductId(), body)).build()); + return body; + } - try { - String url = reviewServiceUrl; - log.debug("Will post a new review to URL: {}", url); + @Override + public Flux getReviews(int productId) { - var review = restTemplate.postForObject(url, body, Review.class); - log.debug("Created a review with id: {}", review != null ? review.getProductId() : 0); + var url = reviewServiceUrl + .concat("/reviews") + .concat(PRODUCT_ID_QUERY_PARAM) + .concat(valueOf(productId)); - return review; + log.debug("Will call the getReviews API on URL: {}", url); + + /* Return an empty result if something goes wrong to make it possible + for the composite service to return partial responses + */ + return webClient + .get() + .uri(url) + .retrieve() + .bodyToFlux(Review.class).log() + .onErrorResume(error -> empty()); - } catch (HttpClientErrorException ex) { - throw handleHttpClientException(ex); - } } @Override - public List getReviews(int productId) { + public void deleteReviews(int productId) { + messageSources + .outputReviews() + .send(withPayload(new Event<>(DELETE, productId, null)).build()); + } - try { - String url = reviewServiceUrl - .concat(PRODUCT_ID_QUERY_PARAM) - .concat(valueOf(productId)); - - log.debug("Will call the getReviews API on URL: {}", url); - List reviews = - restTemplate - .exchange(url, GET, null, new ParameterizedTypeReference>() {}) - .getBody(); - - log.debug("Found {} reviews for a product with id: {}", reviews != null ? reviews.size() : 0, productId); - return reviews; - - } catch (Exception ex) { - log.warn( - "Got an exception while requesting reviews, return zero reviews: {}", ex.getMessage()); - return new ArrayList<>(); - } + public Mono getProductHealth() { + return getHealth(productServiceUrl); } - @Override - public void deleteReviews(int productId) { - try { - String url = reviewServiceUrl - .concat(PRODUCT_ID_QUERY_PARAM) - .concat(valueOf(productId)); - log.debug("Will call the deleteReviews API on URL: {}", url); + public Mono getRecommendationHealth() { + return getHealth(recommendationServiceUrl); + } + + public Mono getReviewHealth() { + return getHealth(reviewServiceUrl); + } - restTemplate.delete(url); + private Mono getHealth(String url) { + url += "/actuator/health"; + log.debug("Will call the Health API on URL: {}", url); + return webClient.get().uri(url).retrieve().bodyToMono(String.class) + .map(s -> new Health.Builder().up().build()) + .onErrorResume(ex -> Mono.just(new Health.Builder().down(ex).build())) + .log(); + } - } catch (HttpClientErrorException ex) { - throw handleHttpClientException(ex); + private Throwable handleException(Throwable ex) { + if (!(ex instanceof WebClientResponseException wcre)) { + log.warn("Got a unexpected error: {}, will rethrow it", ex.toString()); + return ex; } - } - private RuntimeException handleHttpClientException(HttpClientErrorException ex) { - return switch (ex.getStatusCode()) { - case NOT_FOUND -> new NotFoundException(getErrorMessage(ex)); - case UNPROCESSABLE_ENTITY -> new InvalidInputException(getErrorMessage(ex)); + return switch (wcre.getStatusCode()) { + case NOT_FOUND -> new NotFoundException(getErrorMessage(wcre)); + case UNPROCESSABLE_ENTITY -> new InvalidInputException(getErrorMessage(wcre)); default -> { - log.warn("Got a unexpected HTTP error: {}, will rethrow it", ex.getStatusCode()); - log.warn("Error body: {}", ex.getResponseBodyAsString()); - throw ex;} + log.warn("Got a unexpected HTTP error: {}, will rethrow it", wcre.getStatusCode()); + log.warn("Error body: {}", wcre.getResponseBodyAsString()); + throw wcre;} }; } - private String getErrorMessage(HttpClientErrorException ex) { + private String getErrorMessage(WebClientResponseException ex) { try { return mapper.readValue(ex.getResponseBodyAsString(), HttpErrorInfo.class).message(); } catch (IOException ioException) { return ex.getMessage(); } } + + public interface MessageSources { + + String OUTPUT_PRODUCTS = "output-products"; + String OUTPUT_RECOMMENDATIONS = "output-recommendations"; + String OUTPUT_REVIEWS = "output-reviews"; + + @Output(OUTPUT_PRODUCTS) + MessageChannel outputProducts(); + + @Output(OUTPUT_RECOMMENDATIONS) + MessageChannel outputRecommendations(); + + @Output(OUTPUT_REVIEWS) + MessageChannel outputReviews(); + } } diff --git a/store-service/src/main/java/com/siriusxi/ms/store/pcs/service/StoreServiceImpl.java b/store-service/src/main/java/com/siriusxi/ms/store/pcs/service/StoreServiceImpl.java index 1a2a5f64..d8ea44d8 100644 --- a/store-service/src/main/java/com/siriusxi/ms/store/pcs/service/StoreServiceImpl.java +++ b/store-service/src/main/java/com/siriusxi/ms/store/pcs/service/StoreServiceImpl.java @@ -9,11 +9,11 @@ import com.siriusxi.ms.store.api.core.recommendation.dto.Recommendation; import com.siriusxi.ms.store.api.core.review.dto.Review; import com.siriusxi.ms.store.pcs.integration.StoreIntegration; -import com.siriusxi.ms.store.util.exceptions.NotFoundException; import com.siriusxi.ms.store.util.http.ServiceUtil; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import reactor.core.publisher.Mono; import java.util.List; import java.util.stream.Collectors; @@ -37,16 +37,17 @@ public void createProduct(ProductAggregate body) { try { log.debug( - "createCompositeProduct: creates a new composite entity for id: {}", body.getProductId()); + "createCompositeProduct: creates a new composite entity for productId: {}", + body.getProductId()); - Product product = new Product(body.getProductId(), body.getName(), body.getWeight(), null); + var product = new Product(body.getProductId(), body.getName(), body.getWeight(), null); integration.createProduct(product); if (body.getRecommendations() != null) { body.getRecommendations() .forEach( r -> { - Recommendation recommendation = + var recommendation = new Recommendation( body.getProductId(), r.getRecommendationId(), @@ -73,45 +74,49 @@ public void createProduct(ProductAggregate body) { integration.createReview(review); }); } - log.debug( - "createCompositeProduct: composite entites created for id: {}", body.getProductId()); + "createCompositeProduct: composite entities created for productId: {}", + body.getProductId()); } catch (RuntimeException re) { - log.warn("createCompositeProduct failed", re); + log.warn("createCompositeProduct failed: {}", re.toString()); throw re; } } @Override - public ProductAggregate getProduct(int id) { - log.debug("getCompositeProduct: lookup a product aggregate for id: {}", id); - - Product product = integration.getProduct(id); - if (product == null) throw new NotFoundException("No product found for id: " + id); - - List recommendations = integration.getRecommendations(id); - - List reviews = integration.getReviews(id); - - log.debug("getCompositeProduct: aggregate entity found for id: {}", id); - - return createProductAggregate( - product, recommendations, reviews, serviceUtil.getServiceAddress()); + public Mono getProduct(int productId) { + return Mono.zip( + values -> + createProductAggregate( + (Product) values[0], + (List) values[1], + (List) values[2], + serviceUtil.getServiceAddress()), + integration.getProduct(productId), + integration.getRecommendations(productId).collectList(), + integration.getReviews(productId).collectList()) + .doOnError(ex -> log.warn("getCompositeProduct failed: {}", ex.toString())) + .log(); } @Override - public void deleteProduct(int id) { + public void deleteProduct(int productId) { - log.debug("deleteCompositeProduct: Deletes a product aggregate for id: {}", id); + try { - integration.deleteProduct(id); + log.debug("deleteCompositeProduct: Deletes a product aggregate for productId: {}", productId); - integration.deleteRecommendations(id); + integration.deleteProduct(productId); + integration.deleteRecommendations(productId); + integration.deleteReviews(productId); - integration.deleteReviews(id); + log.debug("deleteCompositeProduct: aggregate entities deleted for productId: {}", productId); - log.debug("getCompositeProduct: aggregate entities deleted for id: {}", id); + } catch (RuntimeException re) { + log.warn("deleteCompositeProduct failed: {}", re.toString()); + throw re; + } } private ProductAggregate createProductAggregate( @@ -121,7 +126,7 @@ private ProductAggregate createProductAggregate( String serviceAddress) { // 1. Setup product info - int id = product.getProductId(); + int productId = product.getProductId(); String name = product.getName(); int weight = product.getWeight(); @@ -150,15 +155,15 @@ private ProductAggregate createProductAggregate( // 4. Create info regarding the involved microservices addresses String productAddress = product.getServiceAddress(); String reviewAddress = - (reviews != null && !reviews.isEmpty()) ? reviews.get(0).getServiceAddress() : ""; + (reviews != null && reviews.size() > 0) ? reviews.get(0).getServiceAddress() : ""; String recommendationAddress = - (recommendations != null && !recommendations.isEmpty()) + (recommendations != null && recommendations.size() > 0) ? recommendations.get(0).getServiceAddress() : ""; ServiceAddresses serviceAddresses = new ServiceAddresses(serviceAddress, productAddress, reviewAddress, recommendationAddress); return new ProductAggregate( - id, name, weight, recommendationSummaries, reviewSummaries, serviceAddresses); + productId, name, weight, recommendationSummaries, reviewSummaries, serviceAddresses); } } diff --git a/store-service/src/main/resources/application.yaml b/store-service/src/main/resources/application.yaml index 2e7c1672..fba8a697 100644 --- a/store-service/src/main/resources/application.yaml +++ b/store-service/src/main/resources/application.yaml @@ -2,6 +2,35 @@ spring: application: name: store-service + cloud: + stream: + default-binder: rabbit + default: + contentType: application/json + bindings: + output-products: + destination: products + producer: + required-groups: auditGroup + output-recommendations: + destination: recommendations + producer: + required-groups: auditGroup + output-reviews: + destination: reviews + producer: + required-groups: auditGroup + kafka: + binder: + brokers: 127.0.0.1 + defaultBrokerPort: 9092 + + rabbitmq: + host: 127.0.0.1 + port: 5672 + username: guest + password: guest + server: port: 9080 @@ -12,6 +41,9 @@ logging: com.siriusxi.ms.store: DEBUG management: + info: + git: + enabled: true endpoints: web: exposure: @@ -19,6 +51,8 @@ management: endpoint: shutdown: enabled: true + health: + show-details: "ALWAYS" # Custom configurations app: @@ -35,8 +69,16 @@ app: # Swagger properties api: common: - version: 1.0.0 - title: Springy Store μServices + version: 4.0 + title: "Springy Store μServices" + termsOfServiceUrl: https://mohamed-taman.github.io/Springy-Store-Microservices/ + license: "MIT License" + licenseUrl: "https://github.com/mohamed-taman/Springy-Store-Microservices/blob/master/LICENSE" + + contact: + name: "Mohamed Taman" + url: "https://twitter.com/_tamanm" + email: "mohamed.taman@mail.com" description: | **Springy Store** is a conceptual simple μServices-based project using the latest cutting-edge technologies, to demonstrate how the store is created to be a @@ -44,14 +86,6 @@ api: This project μServices are developed based on Spring Boot & Cloud framework, that implement **cloud-native** intuitive, **design patterns** and **best practices**. - termsOfServiceUrl: https://mohamed-taman.github.io/Springy-Store-Microservices/ - license: MIT License - licenseUrl: https://github.com/mohamed-taman/Springy-Store-Microservices/blob/master/LICENSE - - contact: - name: Mohamed Taman - url: https://twitter.com/_tamanm - email: mohamed.taman@mail.com product-composite: get-composite-product: @@ -96,6 +130,13 @@ spring: profiles: docker jmx: enabled: false + rabbitmq: + host: rabbitmq + cloud: + stream: + kafka: + binder: + brokers: kafka server: port: 8080 diff --git a/store-service/src/test/java/com/siriusxi/ms/store/pcs/IsSameEvent.java b/store-service/src/test/java/com/siriusxi/ms/store/pcs/IsSameEvent.java new file mode 100644 index 00000000..fb29bd2e --- /dev/null +++ b/store-service/src/test/java/com/siriusxi/ms/store/pcs/IsSameEvent.java @@ -0,0 +1,81 @@ +package com.siriusxi.ms.store.pcs; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.siriusxi.ms.store.api.event.Event; +import lombok.extern.log4j.Log4j2; +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.hamcrest.TypeSafeMatcher; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +@Log4j2 +class IsSameEvent extends TypeSafeMatcher { + + private final ObjectMapper mapper = new ObjectMapper(); + + private Event expectedEvent; + + + private IsSameEvent(Event expectedEvent) { + this.expectedEvent = expectedEvent; + } + + @Override + protected boolean matchesSafely(String eventAsJson) { + + if (expectedEvent == null) return false; + + log.trace("Convert the following json string to a map: {}", eventAsJson); + Map mapEvent = convertJsonStringToMap(eventAsJson); + mapEvent.remove("eventCreatedAt"); + + Map mapExpectedEvent = getMapWithoutCreatedAt(expectedEvent); + + log.trace("Got the map: {}", mapEvent); + log.trace("Compare to the expected map: {}", mapExpectedEvent); + return mapEvent.equals(mapExpectedEvent); + } + + @Override + public void describeTo(Description description) { + String expectedJson = convertObjectToJsonString(expectedEvent); + description.appendText("expected to look like " + expectedJson); + } + + public static Matcher sameEventExceptCreatedAt(Event expectedEvent) { + return new IsSameEvent(expectedEvent); + } + + private Map getMapWithoutCreatedAt(Event event) { + Map mapEvent = convertObjectToMap(event); + mapEvent.remove("eventCreatedAt"); + return mapEvent; + } + + private Map convertObjectToMap(Object object) { + JsonNode node = mapper.convertValue(object, JsonNode.class); + return mapper.convertValue(node, Map.class); + } + + private String convertObjectToJsonString(Object object) { + try { + return mapper.writeValueAsString(object); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + + private Map convertJsonStringToMap(String eventAsJson) { + try { + return mapper.readValue(eventAsJson, new TypeReference(){}); + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} \ No newline at end of file diff --git a/store-service/src/test/java/com/siriusxi/ms/store/pcs/IsSameEventTests.java b/store-service/src/test/java/com/siriusxi/ms/store/pcs/IsSameEventTests.java new file mode 100644 index 00000000..debdfe79 --- /dev/null +++ b/store-service/src/test/java/com/siriusxi/ms/store/pcs/IsSameEventTests.java @@ -0,0 +1,38 @@ +package com.siriusxi.ms.store.pcs; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.siriusxi.ms.store.api.core.product.dto.Product; +import com.siriusxi.ms.store.api.event.Event; +import org.junit.jupiter.api.Test; + +import static com.siriusxi.ms.store.api.event.Event.Type.CREATE; +import static com.siriusxi.ms.store.api.event.Event.Type.DELETE; +import static com.siriusxi.ms.store.pcs.IsSameEvent.sameEventExceptCreatedAt; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; + +class IsSameEventTests { + + ObjectMapper mapper = new ObjectMapper(); + + @Test + public void testEventObjectCompare() throws JsonProcessingException { + + /* + Event #1 and #2 are the same event, but occurs as different times + Event #3 and #4 are different events + */ + Event event1 = new Event<>(CREATE, 1, new Product(1, "name", 1, null)); + Event event2 = new Event<>(CREATE, 1, new Product(1, "name", 1, null)); + Event event3 = new Event<>(DELETE, 1, null); + Event event4 = new Event<>(CREATE, 1, new Product(2, "name", 1, null)); + + String event1JSon = mapper.writeValueAsString(event1); + + assertThat(event1JSon, is(sameEventExceptCreatedAt(event2))); + assertThat(event1JSon, not(sameEventExceptCreatedAt(event3))); + assertThat(event1JSon, not(sameEventExceptCreatedAt(event4))); + } +} diff --git a/store-service/src/test/java/com/siriusxi/ms/store/pcs/MessagingTests.java b/store-service/src/test/java/com/siriusxi/ms/store/pcs/MessagingTests.java new file mode 100644 index 00000000..90a279f9 --- /dev/null +++ b/store-service/src/test/java/com/siriusxi/ms/store/pcs/MessagingTests.java @@ -0,0 +1,186 @@ +package com.siriusxi.ms.store.pcs; + +import com.siriusxi.ms.store.api.composite.dto.ProductAggregate; +import com.siriusxi.ms.store.api.composite.dto.RecommendationSummary; +import com.siriusxi.ms.store.api.composite.dto.ReviewSummary; +import com.siriusxi.ms.store.api.core.product.dto.Product; +import com.siriusxi.ms.store.api.core.recommendation.dto.Recommendation; +import com.siriusxi.ms.store.api.core.review.dto.Review; +import com.siriusxi.ms.store.api.event.Event; +import com.siriusxi.ms.store.pcs.integration.StoreIntegration; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.stream.test.binder.MessageCollector; +import org.springframework.messaging.Message; +import org.springframework.messaging.MessageChannel; +import org.springframework.test.web.reactive.server.WebTestClient; +import reactor.core.publisher.Mono; + +import java.util.concurrent.BlockingQueue; + +import static com.siriusxi.ms.store.api.event.Event.Type.CREATE; +import static com.siriusxi.ms.store.api.event.Event.Type.DELETE; +import static com.siriusxi.ms.store.pcs.IsSameEvent.sameEventExceptCreatedAt; +import static java.lang.String.valueOf; +import static java.util.Collections.singletonList; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; +import static org.springframework.cloud.stream.test.matcher.MessageQueueMatcher.receivesPayloadThat; +import static org.springframework.http.HttpStatus.OK; + +@SpringBootTest(webEnvironment = RANDOM_PORT) +class MessagingTests { + + public static final String BASE_URL = "/store/api/v1/products/"; + + BlockingQueue> queueProducts = null; + BlockingQueue> queueRecommendations = null; + BlockingQueue> queueReviews = null; + + @Autowired private WebTestClient client; + @Autowired private StoreIntegration.MessageSources channels; + @Autowired private MessageCollector collector; + + @BeforeEach + public void setUp() { + queueProducts = getQueue(channels.outputProducts()); + queueRecommendations = getQueue(channels.outputRecommendations()); + queueReviews = getQueue(channels.outputReviews()); + } + + @Test + public void createCompositeProduct1() { + + ProductAggregate composite = new ProductAggregate(1, "name", 1, null, null, null); + postAndVerifyProduct(composite); + + // Assert one expected new product events queued up + assertEquals(1, queueProducts.size()); + + Event expectedEvent = + new Event<>( + CREATE, + composite.getProductId(), + new Product( + composite.getProductId(), composite.getName(), composite.getWeight(), null)); + assertThat(queueProducts, is(receivesPayloadThat(sameEventExceptCreatedAt(expectedEvent)))); + + // Assert none recommendations and review events + assertEquals(0, queueRecommendations.size()); + assertEquals(0, queueReviews.size()); + } + + @Test + public void createCompositeProduct2() { + + ProductAggregate composite = + new ProductAggregate( + 1, + "name", + 1, + singletonList(new RecommendationSummary(1, "a", 1, "c")), + singletonList(new ReviewSummary(1, "a", "s", "c")), + null); + + postAndVerifyProduct(composite); + + // Assert one create product event queued up + assertEquals(1, queueProducts.size()); + + Event expectedProductEvent = + new Event<>( + CREATE, + composite.getProductId(), + new Product( + composite.getProductId(), composite.getName(), composite.getWeight(), null)); + assertThat(queueProducts, receivesPayloadThat(sameEventExceptCreatedAt(expectedProductEvent))); + + // Assert one create recommendation event queued up + assertEquals(1, queueRecommendations.size()); + + RecommendationSummary rec = composite.getRecommendations().get(0); + Event expectedRecommendationEvent = + new Event<>( + CREATE, + composite.getProductId(), + new Recommendation( + composite.getProductId(), + rec.getRecommendationId(), + rec.getAuthor(), + rec.getRate(), + rec.getContent(), + null)); + assertThat( + queueRecommendations, + receivesPayloadThat(sameEventExceptCreatedAt(expectedRecommendationEvent))); + + // Assert one create review event queued up + assertEquals(1, queueReviews.size()); + + ReviewSummary rev = composite.getReviews().get(0); + Event expectedReviewEvent = + new Event<>( + CREATE, + composite.getProductId(), + new Review( + composite.getProductId(), + rev.getReviewId(), + rev.getAuthor(), + rev.getSubject(), + rev.getContent(), + null)); + + assertThat(queueReviews, receivesPayloadThat(sameEventExceptCreatedAt(expectedReviewEvent))); + } + + @Test + public void deleteCompositeProduct() { + + deleteAndVerifyProduct(1); + + // Assert one delete product event queued up + assertEquals(1, queueProducts.size()); + + Event expectedEvent = new Event<>(DELETE, 1, null); + + assertThat(queueProducts, is(receivesPayloadThat(sameEventExceptCreatedAt(expectedEvent)))); + + // Assert one delete recommendation event queued up + assertEquals(1, queueRecommendations.size()); + + Event expectedRecommendationEvent = new Event<>(DELETE, 1, null); + assertThat( + queueRecommendations, + receivesPayloadThat(sameEventExceptCreatedAt(expectedRecommendationEvent))); + + // Assert one delete review event queued up + assertEquals(1, queueReviews.size()); + + Event expectedReviewEvent = new Event<>(DELETE, 1, null); + assertThat(queueReviews, receivesPayloadThat(sameEventExceptCreatedAt(expectedReviewEvent))); + } + + private BlockingQueue> getQueue(MessageChannel messageChannel) { + return collector.forChannel(messageChannel); + } + + private void postAndVerifyProduct(ProductAggregate compositeProduct) { + client + .post() + .uri(BASE_URL) + .body(Mono.just(compositeProduct), ProductAggregate.class) + .exchange() + .expectStatus().isEqualTo(OK); + } + + private void deleteAndVerifyProduct(int productId) { + client.delete() + .uri(BASE_URL.concat(valueOf(productId))) + .exchange() + .expectStatus().isEqualTo(OK); + } +} diff --git a/store-service/src/test/java/com/siriusxi/ms/store/pcs/ReactorTests.java b/store-service/src/test/java/com/siriusxi/ms/store/pcs/ReactorTests.java new file mode 100644 index 00000000..65d3ceb2 --- /dev/null +++ b/store-service/src/test/java/com/siriusxi/ms/store/pcs/ReactorTests.java @@ -0,0 +1,39 @@ +package com.siriusxi.ms.store.pcs; + +import org.junit.jupiter.api.Test; +import reactor.core.publisher.Flux; + +import java.util.ArrayList; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +class ReactorTests { + + @Test + public void TestFlux() { + + List list = new ArrayList<>(); + + Flux.just(1, 2, 3, 4) + .filter(n -> n % 2 == 0) + .map(n -> n * 2) + .log() + .subscribe(list::add); + + assertThat(list).containsExactly(4, 8); + } + + @Test + public void TestFluxBlocking() { + + List list = Flux.just(1, 2, 3, 4) + .filter(n -> n % 2 == 0) + .map(n -> n * 2) + .log() + .collectList().block(); + + assertThat(list).containsExactly(4, 8); + } + +} diff --git a/store-service/src/test/java/com/siriusxi/ms/store/pcs/StoreServiceApplicationTests.java b/store-service/src/test/java/com/siriusxi/ms/store/pcs/StoreServiceApplicationTests.java index 4eec94b6..ed55d7bb 100644 --- a/store-service/src/test/java/com/siriusxi/ms/store/pcs/StoreServiceApplicationTests.java +++ b/store-service/src/test/java/com/siriusxi/ms/store/pcs/StoreServiceApplicationTests.java @@ -1,8 +1,5 @@ package com.siriusxi.ms.store.pcs; -import com.siriusxi.ms.store.api.composite.dto.ProductAggregate; -import com.siriusxi.ms.store.api.composite.dto.RecommendationSummary; -import com.siriusxi.ms.store.api.composite.dto.ReviewSummary; import com.siriusxi.ms.store.api.core.product.dto.Product; import com.siriusxi.ms.store.api.core.recommendation.dto.Recommendation; import com.siriusxi.ms.store.api.core.review.dto.Review; @@ -17,6 +14,7 @@ import org.springframework.http.HttpStatus; import org.springframework.test.web.reactive.server.WebTestClient; import org.springframework.test.web.reactive.server.WebTestClient.BodyContentSpec; +import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import static java.util.Collections.singletonList; @@ -33,27 +31,27 @@ class StoreServiceApplicationTests { private static final int PRODUCT_ID_NOT_FOUND = 2; private static final int PRODUCT_ID_INVALID = 3; - @Autowired - private WebTestClient client; + @Autowired private WebTestClient client; - @MockBean - private StoreIntegration storeIntegration; + @MockBean private StoreIntegration storeIntegration; @BeforeEach void setUp() { when(storeIntegration.getProduct(PRODUCT_ID_OK)) - .thenReturn(new Product(PRODUCT_ID_OK, "name", 1, "mock-address")); + .thenReturn(Mono.just(new Product(PRODUCT_ID_OK, "name", 1, "mock-address"))); when(storeIntegration.getRecommendations(PRODUCT_ID_OK)) .thenReturn( - singletonList( - new Recommendation(PRODUCT_ID_OK, 1, "author", 1, "content", "mock address"))); + Flux.fromIterable( + singletonList( + new Recommendation(PRODUCT_ID_OK, 1, "author", 1, "content", "mock address")))); when(storeIntegration.getReviews(PRODUCT_ID_OK)) .thenReturn( - singletonList( - new Review(PRODUCT_ID_OK, 1, "author", "subject", "content", "mock address"))); + Flux.fromIterable( + singletonList( + new Review(PRODUCT_ID_OK, 1, "author", "subject", "content", "mock address")))); when(storeIntegration.getProduct(PRODUCT_ID_NOT_FOUND)) .thenThrow(new NotFoundException("NOT FOUND: " + PRODUCT_ID_NOT_FOUND)); @@ -62,45 +60,6 @@ void setUp() { .thenThrow(new InvalidInputException("INVALID: " + PRODUCT_ID_INVALID)); } - @Test - public void createCompositeProduct1() { - - var compositeProduct = new ProductAggregate(1, "name", 1, null, null, null); - - postAndVerifyProductIsCreated(compositeProduct); - } - - @Test - public void createCompositeProduct2() { - var compositeProduct = - new ProductAggregate( - 1, - "name", - 1, - singletonList(new RecommendationSummary(1, "a", 1, "c")), - singletonList(new ReviewSummary(1, "a", "s", "c")), - null); - - postAndVerifyProductIsCreated(compositeProduct); - } - - @Test - public void deleteCompositeProduct() { - var compositeProduct = - new ProductAggregate( - 1, - "name", - 1, - singletonList(new RecommendationSummary(1, "a", 1, "c")), - singletonList(new ReviewSummary(1, "a", "s", "c")), - null); - - postAndVerifyProductIsCreated(compositeProduct); - - deleteAndVerifyProductIsDeleted(compositeProduct.getProductId()); - deleteAndVerifyProductIsDeleted(compositeProduct.getProductId()); - } - @Test public void getProductById() { @@ -145,18 +104,4 @@ private BodyContentSpec getAndVerifyProduct(int productId, HttpStatus expectedSt .contentType(APPLICATION_JSON) .expectBody(); } - - private void postAndVerifyProductIsCreated(ProductAggregate compositeProduct) { - client - .post() - .uri(BASE_URL) - .body(Mono.just(compositeProduct), ProductAggregate.class) - .exchange() - .expectStatus() - .isEqualTo(OK); - } - - private void deleteAndVerifyProductIsDeleted(int productId) { - client.delete().uri(BASE_URL + productId).exchange().expectStatus().isEqualTo(OK); - } } diff --git a/store-utils/src/main/java/com/siriusxi/ms/store/util/exceptions/EventProcessingException.java b/store-utils/src/main/java/com/siriusxi/ms/store/util/exceptions/EventProcessingException.java new file mode 100644 index 00000000..a958ba95 --- /dev/null +++ b/store-utils/src/main/java/com/siriusxi/ms/store/util/exceptions/EventProcessingException.java @@ -0,0 +1,18 @@ +package com.siriusxi.ms.store.util.exceptions; + +public class EventProcessingException extends RuntimeException { + public EventProcessingException() { + } + + public EventProcessingException(String message) { + super(message); + } + + public EventProcessingException(String message, Throwable cause) { + super(message, cause); + } + + public EventProcessingException(Throwable cause) { + super(cause); + } +} \ No newline at end of file diff --git a/test-em-all.sh b/test-em-all.sh index d064668f..9e02cb3a 100644 --- a/test-em-all.sh +++ b/test-em-all.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash ## Author: Mohamed Taman -## version: v3.0 +## version: v4.0 ### Sample usage: # # for local run @@ -8,12 +8,17 @@ # with docker compose # HOST=localhost PORT=8080 ./test-em-all.bash start stop # -echo -e "Starting [Springy Store] full functionality testing....\n" +echo -e "Starting [Springy Store] full functionality [Blackbox] testing....\n" : ${HOST=localhost} : ${PORT=8080} +: ${PROD_ID_REVS_RECS=2} +: ${PROD_ID_NOT_FOUND=14} +: ${PROD_ID_NO_RECS=114} +: ${PROD_ID_NO_REVS=214} BASE_URL="/store/api/v1/products" + function assertCurl() { local expectedHttpCode=$1 @@ -30,11 +35,12 @@ function assertCurl() { else echo "Test OK (HTTP Code: $httpCode, $RESPONSE)" fi + return 0 else echo "Test FAILED, EXPECTED HTTP Code: $expectedHttpCode, GOT: $httpCode, WILL ABORT!" echo "- Failing command: $curlCmd" echo "- Response Body: $RESPONSE" - exit 1 + return 1 fi } @@ -46,9 +52,10 @@ function assertEqual() { if [[ "$actual" = "$expected" ]] then echo "Test OK (actual value: $actual)" + return 0 else echo "Test FAILED, EXPECTED VALUE: $expected, ACTUAL VALUE: $actual, WILL ABORT" - exit 1 + return 1 fi } @@ -82,7 +89,52 @@ function waitForService() { done } -function createProduct() { +function testCompositeCreated() { + + # Expect that the Product Composite for productId $PROD_ID_REVS_RECS + # has been created with three recommendations and three reviews + if ! assertCurl 200 "curl http://${HOST}:${PORT}${BASE_URL}/${PROD_ID_REVS_RECS} -s" + then + echo -n "FAIL" + return 1 + fi + + set +e + assertEqual "$PROD_ID_REVS_RECS" $(echo ${RESPONSE} | jq .productId) + if [[ "$?" -eq "1" ]] ; then return 1; fi + + assertEqual 3 $(echo ${RESPONSE} | jq ".recommendations | length") + if [[ "$?" -eq "1" ]] ; then return 1; fi + + assertEqual 3 $(echo ${RESPONSE} | jq ".reviews | length") + if [[ "$?" -eq "1" ]] ; then return 1; fi + + set -e +} + +function waitForMessageProcessing() { + echo "Wait for messages to be processed... " + + # Give background processing some time to complete... + sleep 1 + + n=0 + until testCompositeCreated + do + n=$((n + 1)) + if [[ ${n} == 40 ]] + then + echo " Give up" + exit 1 + else + sleep 6 + echo -n ", retry #$n " + fi + done + echo "All messages are now processed!" +} + +function recreateComposite() { local productId=$1 local composite=$2 @@ -92,38 +144,43 @@ function createProduct() { function setupTestData() { - body=\ -'{"productId":1,"name":"product 1","weight":1, "recommendations":[ - {"recommendationId":1,"author":"author 1","rate":1,"content":"content 1"}, - {"recommendationId":2,"author":"author 2","rate":2,"content":"content 2"}, - {"recommendationId":3,"author":"author 3","rate":3,"content":"content 3"} - ], "reviews":[ - {"reviewId":1,"author":"author 1","subject":"subject 1","content":"content 1"}, - {"reviewId":2,"author":"author 2","subject":"subject 2","content":"content 2"}, - {"reviewId":3,"author":"author 3","subject":"subject 3","content":"content 3"} - ]}' - createProduct 1 "$body" - - body=\ -'{"productId":113,"name":"product 113","weight":113, "reviews":[ + body="{\"productId\":$PROD_ID_NO_RECS" + body+=\ +',"name":"product name A","weight":100, "reviews":[ {"reviewId":1,"author":"author 1","subject":"subject 1","content":"content 1"}, {"reviewId":2,"author":"author 2","subject":"subject 2","content":"content 2"}, {"reviewId":3,"author":"author 3","subject":"subject 3","content":"content 3"} ]}' - createProduct 113 "$body" + recreateComposite "$PROD_ID_NO_RECS" "$body" - body=\ -'{"productId":213,"name":"product 213","weight":213, "recommendations":[ + body="{\"productId\":$PROD_ID_NO_REVS" + body+=\ +',"name":"product name B","weight":200, "recommendations":[ {"recommendationId":1,"author":"author 1","rate":1,"content":"content 1"}, {"recommendationId":2,"author":"author 2","rate":2,"content":"content 2"}, {"recommendationId":3,"author":"author 3","rate":3,"content":"content 3"} ]}' - createProduct 213 "$body" + recreateComposite "$PROD_ID_NO_REVS" "$body" + + + body="{\"productId\":$PROD_ID_REVS_RECS" + body+=\ +',"name":"product name C","weight":300, "recommendations":[ + {"recommendationId":1,"author":"author 1","rate":1,"content":"content 1"}, + {"recommendationId":2,"author":"author 2","rate":2,"content":"content 2"}, + {"recommendationId":3,"author":"author 3","rate":3,"content":"content 3"} + ], "reviews":[ + {"reviewId":1,"author":"author 1","subject":"subject 1","content":"content 1"}, + {"reviewId":2,"author":"author 2","subject":"subject 2","content":"content 2"}, + {"reviewId":3,"author":"author 3","subject":"subject 3","content":"content 3"} + ]}' + + recreateComposite 1 "$body" } set -e -echo "Start:" `date` +echo "Start Tests:" `date` echo "HOST=${HOST}" echo "PORT=${PORT}" @@ -131,34 +188,36 @@ echo "PORT=${PORT}" if [[ $@ == *"start"* ]] then echo "Restarting the test environment..." - echo "$ docker-compose down" - docker-compose down + echo "$ docker-compose -p ssm down --remove-orphans" + docker-compose -p ssm down --remove-orphans echo "$ docker-compose -p ssm up -d" docker-compose -p ssm up -d fi -waitForService curl -X DELETE http://${HOST}:${PORT}${BASE_URL}/13 +waitForService curl http://${HOST}:${PORT}/actuator/health setupTestData +waitForMessageProcessing + # Verify that a normal request works, expect three recommendations and three reviews -assertCurl 200 "curl http://$HOST:$PORT${BASE_URL}/1 -s" -assertEqual 1 $(echo ${RESPONSE} | jq .productId) +assertCurl 200 "curl http://$HOST:$PORT${BASE_URL}/$PROD_ID_REVS_RECS -s" +assertEqual ${PROD_ID_REVS_RECS} $(echo ${RESPONSE} | jq .productId) assertEqual 3 $(echo ${RESPONSE} | jq ".recommendations | length") assertEqual 3 $(echo ${RESPONSE} | jq ".reviews | length") # Verify that a 404 (Not Found) error is returned for a non existing productId (13) -assertCurl 404 "curl http://$HOST:$PORT${BASE_URL}/13 -s" +assertCurl 404 "curl http://$HOST:$PORT${BASE_URL}/$PROD_ID_NOT_FOUND -s" # Verify that no recommendations are returned for productId 113 -assertCurl 200 "curl http://$HOST:$PORT${BASE_URL}/113 -s" -assertEqual 113 $(echo ${RESPONSE} | jq .productId) +assertCurl 200 "curl http://$HOST:$PORT${BASE_URL}/$PROD_ID_NO_RECS -s" +assertEqual ${PROD_ID_NO_RECS} $(echo ${RESPONSE} | jq .productId) assertEqual 0 $(echo ${RESPONSE} | jq ".recommendations | length") assertEqual 3 $(echo ${RESPONSE} | jq ".reviews | length") # Verify that no reviews are returned for productId 213 -assertCurl 200 "curl http://$HOST:$PORT${BASE_URL}/213 -s" -assertEqual 213 $(echo ${RESPONSE} | jq .productId) +assertCurl 200 "curl http://$HOST:$PORT${BASE_URL}/$PROD_ID_NO_REVS -s" +assertEqual ${PROD_ID_NO_REVS} $(echo ${RESPONSE} | jq .productId) assertEqual 3 $(echo ${RESPONSE} | jq ".recommendations | length") assertEqual 0 $(echo ${RESPONSE} | jq ".reviews | length") @@ -170,11 +229,11 @@ assertEqual "\"Invalid productId: -1\"" "$(echo ${RESPONSE} | jq .message)" assertCurl 400 "curl http://$HOST:$PORT${BASE_URL}/invalidProductId -s" assertEqual "\"Type mismatch.\"" "$(echo ${RESPONSE} | jq .message)" +echo "End, all tests OK:" `date` + if [[ $@ == *"stop"* ]] then echo "We are done, stopping the test environment..." - echo "$ docker-compose down" - docker-compose -p ssm down -fi - -echo "End:" `date` \ No newline at end of file + echo "$ docker-compose down --remove-orphans" + docker-compose -p ssm down --remove-orphans +fi \ No newline at end of file From 4521fe75aea815f5dbac9d8c5e2973dd8fdc3bad Mon Sep 17 00:00:00 2001 From: Mohamed Taman Date: Wed, 22 Apr 2020 20:37:04 +0200 Subject: [PATCH 3/4] Documenting changes and docker files for more readability. --- README.md | 87 +++++++++++++++++++++++++++++++---- docker-compose-kafka.yml | 29 ++++++++++-- docker-compose-partitions.yml | 25 ++++++++-- docker-compose.yml | 19 ++++++-- 4 files changed, 140 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index cc098f02..284cfba5 100644 --- a/README.md +++ b/README.md @@ -156,29 +156,94 @@ All build commands and test suite for each microservice should run successfully, ``` ### Running Them All -Now it's the time to run all of them, and it's very simple just run the following *docker compose* commands: +#### Using RabbitMQ without the use of partitions +Now it's the time to run all of our reactive Microservices, and it's very simple just run the + following +`docker-compose` commands: ```bash mohamed.taman@DTLNV8 ~/springy-store-microservices λ docker-compose -p ssm up -d ``` -All the **services** and **databases** will run in parallel in detached mode (option `-d`), and their output will be printed to the console as the following: +All the **services**, **databases**, and **messaging service** will run in parallel in detach + mode + (option `-d`), and + command output will print to the console the following: ```bash Creating network "ssm_default" with the default driver -Creating ssm_mysql_1 ... done -Creating ssm_mongodb_1 ... done -Creating ssm_store_1 ... done +Creating ssm_mysql_1 ... done +Creating ssm_mongodb_1 ... done +Creating ssm_rabbitmq_1 ... done +Creating ssm_store_1 ... done Creating ssm_review_1 ... done Creating ssm_product_1 ... done Creating ssm_recommendation_1 ... done ``` ### Access Store APIs -You can manually test `Store Service` APIs through out its **Swagger** interface at the following +You can manually test `Store Service` APIs throughout its **Swagger** interface at the following URL [http://localhost:8080/swagger-ui.html](http://localhost:8080/swagger-ui.html). - +#### Access RabbitMQ +In browser point to this URL [http://localhost:5672/](http://localhost:5672/) `username: guest +` and `password: guest`, and you can see all **topics**, **DLQs**, **partitions**, and payload. + +1. For running 2 instances of each service and using _RabbitMQ with two partitions per topic_, use + the following + `docker-compose` command: + ```bash + mohamed.taman@DTLNV8 ~/springy-store-microservices + λ docker-compose -p ssm -f docker-compose-partitions.yml up -d + ``` + 1. To use _Kafka and Zookeeper with two partitions per topic_ run the following + command: + ```bash + mohamed.taman@DTLNV8 ~/springy-store-microservices + λ docker-compose -p ssm -f docker-compose-kafka.yml up -d + ``` + +#### Check All Services Health +From Store front Service we can check all the core services health, when you have all the + microservices up and running using Docker Compose, +```bash +mohamed.taman@DTLNV8 ~/springy-store-microservices +λ curl http://localhost:8080/actuator/health -s | jq . +``` +This will result in the following response: +```json +{ + "status":"UP", + "components":{ + "Core System Microservices":{ + "status":"UP", + "components":{ + "Product Service":{ + "status":"UP" + }, + "Recommendation Service":{ + "status":"UP" + }, + "Review Service":{ + "status":"UP" + } + } + }, + "diskSpace":{ + "status":"UP", + "details":{ + "total":255382777856, + "free":86618931200, + "threshold":10485760, + "exists":true + } + }, + "ping":{ + "status":"UP" + } + } +} +``` ### Testing Them All Now it's time to test all the application functionality as one part. To do so just run the following automation test script: @@ -188,7 +253,7 @@ mohamed.taman@DTLNV8 ~/springy-store-microservices λ ./test-em-all.sh ``` -The result should be something like this: +The result will look like this: ```bash Starting [Springy Store] full functionality testing.... @@ -227,10 +292,10 @@ Finally, to close the story, we will need to shut down Microservices manually se ```bash mohamed.taman@DTLNV8 ~/springy-store-microservices -λ docker-compose -p ssm down +λ docker-compose -p ssm down --remove-orphans ``` - And the output should be as the following: + And you should see output like the following: ```bash Stopping ssm_recommendation_1 ... done @@ -239,12 +304,14 @@ Stopping ssm_review_1 ... done Stopping ssm_mongodb_1 ... done Stopping ssm_store_1 ... done Stopping ssm_mysql_1 ... done +Stopping ssm_rabbitmq_1 ... done Removing ssm_recommendation_1 ... done Removing ssm_product_1 ... done Removing ssm_review_1 ... done Removing ssm_mongodb_1 ... done Removing ssm_store_1 ... done Removing ssm_mysql_1 ... done +Removing ssm_rabbitmq_1 ... done Removing network ssm_default ``` diff --git a/docker-compose-kafka.yml b/docker-compose-kafka.yml index 06780995..73eb6249 100644 --- a/docker-compose-kafka.yml +++ b/docker-compose-kafka.yml @@ -1,6 +1,8 @@ version: '3.7' ## Latest version works with Docker Engine release 18.06.0+ services: + ## Start - Product service definition + ### Instance 1 product: build: product-service environment: @@ -13,6 +15,7 @@ services: depends_on: - mongodb - kafka + ### Instance 2 product-i1: build: product-service environment: @@ -25,7 +28,10 @@ services: depends_on: - mongodb - kafka + ## End - Product service definition + ## Start - Recommendation service definition + ### Instance 1 recommendation: build: recommendation-service environment: @@ -38,6 +44,7 @@ services: depends_on: - mongodb - kafka + ### Instance 2 recommendation-i1: build: recommendation-service environment: @@ -50,7 +57,10 @@ services: depends_on: - mongodb - kafka + ## End - Recommendation service definition + ## Start - Review service definition + ### Instance 1 review: build: review-service environment: @@ -64,6 +74,7 @@ services: - mysql - kafka restart: on-failure + ### Instance 2 review-i1: build: review-service environment: @@ -77,7 +88,9 @@ services: - mysql - kafka restart: on-failure + ## End - Review service definition + ## Start - Store service definition store: build: store-service ports: @@ -94,8 +107,10 @@ services: - SPRING_CLOUD_STREAM_BINDINGS_OUTPUT-REVIEWS_PRODUCER_PARTITION-COUNT=2 depends_on: - kafka + ## End - Store service definition - # $ mongo + ## Start - mongodb database definition + ### $ mongo mongodb: image: mongo:4.2.5-bionic ports: @@ -107,8 +122,10 @@ services: retries: 5 start_period: 40s restart: on-failure + ## End - mongodb database definition - # $ mysql -uroot -h127.0.0.1 -p + ## Start - MySql database definition + ### $ mysql -uroot -h127.0.0.1 -p mysql: image: mysql:8.0.19 ports: @@ -125,8 +142,9 @@ services: timeout: 5s retries: 10 restart: on-failure + ## End - MySql database definition - # Kafka Messaging service + ## Start - Kafka Messaging service kafka: image: wurstmeister/kafka:latest ports: @@ -138,11 +156,14 @@ services: depends_on: - zookeeper restart: on-failure + ## End - Kafka Messaging service + ## Start - Zookeeper (Kafka) cluster management service zookeeper: image: wurstmeister/zookeeper:latest ports: - "2181:2181" environment: - KAFKA_ADVERTISED_HOST_NAME=zookeeper - restart: on-failure \ No newline at end of file + restart: on-failure + ## End - Zookeeper cluster management service \ No newline at end of file diff --git a/docker-compose-partitions.yml b/docker-compose-partitions.yml index 366edee6..2851cb31 100644 --- a/docker-compose-partitions.yml +++ b/docker-compose-partitions.yml @@ -1,6 +1,8 @@ version: '3.7' ## Latest version works with Docker Engine release 18.06.0+ services: + ## Start - Product service definition + ### Instance 1 product: build: product-service environment: @@ -11,6 +13,7 @@ services: depends_on: - mongodb - rabbitmq + ### Instance 2 product-i1: build: product-service environment: @@ -21,7 +24,10 @@ services: depends_on: - mongodb - rabbitmq + ## End - Product service definition + ## Start - Recommendation service definition + ### Instance 1 recommendation: build: recommendation-service environment: @@ -32,6 +38,7 @@ services: depends_on: - mongodb - rabbitmq + ### Instance 2 recommendation-i1: build: recommendation-service environment: @@ -42,7 +49,10 @@ services: depends_on: - mongodb - rabbitmq + ## End - Recommendation service definition + ## Start - Review service definition + ### Instance 1 review: build: review-service environment: @@ -54,6 +64,7 @@ services: - mysql - rabbitmq restart: on-failure + ### Instance 2 review-i1: build: review-service environment: @@ -65,7 +76,9 @@ services: - mysql - rabbitmq restart: on-failure + ## End - Review service definition + ## Start - Store service definition store: build: store-service ports: @@ -80,8 +93,10 @@ services: - SPRING_CLOUD_STREAM_BINDINGS_OUTPUT-REVIEWS_PRODUCER_PARTITION-COUNT=2 depends_on: - rabbitmq + ## End - Store service definition - # $ mongo + ## Start - mongodb database definition + ### $ mongo mongodb: image: mongo:4.2.5-bionic ports: @@ -93,8 +108,10 @@ services: retries: 5 start_period: 40s restart: on-failure + ## End - mongodb database definition - # $ mysql -uroot -h127.0.0.1 -p + ## Start - MySql database definition + ### $ mysql -uroot -h127.0.0.1 -p mysql: image: mysql:8.0.19 ports: @@ -111,8 +128,9 @@ services: timeout: 5s retries: 10 restart: on-failure + ## End - MySql database definition - # RabbitMQ Messaging service + ## Start - RabbitMQ Messaging service rabbitmq: image: rabbitmq:3.8.3-management ports: @@ -124,3 +142,4 @@ services: timeout: 5s retries: 10 restart: on-failure + ## End - RabbitMQ Messaging service diff --git a/docker-compose.yml b/docker-compose.yml index 7511f81f..af37bd1c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,7 @@ version: '3.7' ## Latest version works with Docker Engine release 18.06.0+ services: + ## Start - Product service definition product: build: product-service environment: @@ -8,7 +9,9 @@ services: depends_on: - mongodb - rabbitmq + ## End - Product service definition + ## Start - Recommendation service definition recommendation: build: recommendation-service environment: @@ -16,7 +19,9 @@ services: depends_on: - mongodb - rabbitmq + ## End - Recommendation service definition + ## Start - Review service definition review: build: review-service environment: @@ -25,7 +30,9 @@ services: - mysql - rabbitmq restart: on-failure + ## End - Review service definition + ## Start - Store service definition store: build: store-service ports: @@ -34,8 +41,10 @@ services: - SPRING_PROFILES_ACTIVE=docker depends_on: - rabbitmq + ## End - Store service definition - # $ mongo + ## Start - mongodb database definition + ### $ mongo mongodb: image: mongo:4.2.5-bionic ports: @@ -47,8 +56,10 @@ services: retries: 5 start_period: 40s restart: on-failure + ## End - mongodb database definition - # $ mysql -uroot -h127.0.0.1 -p + ## Start - MySql database definition + ### $ mysql -uroot -h127.0.0.1 -p mysql: image: mysql:8.0.19 ports: @@ -65,8 +76,9 @@ services: timeout: 5s retries: 10 restart: on-failure + ## End - MySql database definition - # RabbitMQ Messaging service + ## Start - RabbitMQ Messaging service rabbitmq: image: rabbitmq:3.8.3-management ports: @@ -78,3 +90,4 @@ services: timeout: 5s retries: 10 restart: on-failure + ## End - RabbitMQ Messaging service From 09c0e9b4e750a02096e0e2d049ff92c298e87fe5 Mon Sep 17 00:00:00 2001 From: Mohamed Taman Date: Wed, 22 Apr 2020 20:44:10 +0200 Subject: [PATCH 4/4] Add the release. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 284cfba5..8c40e4ee 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ The following topics are going to be covered in this 1st stage (other stages top - Adding automated tests of microservices in isolation. - Adding semi-automated tests to a microservice landscape. -### System Boundary - μServices Landscape (Release 3) +### System Boundary - μServices Landscape (Release 4) ![System Boundary](docs/stage1/app_ms_landscape.png)