From e13e4d38c30ab17b3678fac1fc1b41ceb4040960 Mon Sep 17 00:00:00 2001 From: "enrico.eth" <85900164+enricobottazzi@users.noreply.github.com> Date: Tue, 19 Dec 2023 06:57:01 +0100 Subject: [PATCH 1/2] Remove `N_BYTES` const generic from `UnivariateGrandSum` (#233) * feat: add `decompose_fp_to_byte_pairs` util * feat: rm `N_BYTES` generic from `range_check` * feat: support `RangeCheckU64Chip` to `UnivariateGrandSum` * chore: minor fixing * chore: add comments * chore: fix typo --- kzg_prover/prints/range-check-layout.png | Bin 82128 -> 80109 bytes .../prints/univariate-grand-sum-layout.png | Bin 1243095 -> 1087709 bytes kzg_prover/src/chips/range/range_check.rs | 115 +++++++++--------- kzg_prover/src/chips/range/tests.rs | 104 ++++++---------- kzg_prover/src/chips/range/utils.rs | 61 +++++++++- kzg_prover/src/circuits/tests.rs | 44 +++---- .../src/circuits/univariate_grand_sum.rs | 53 ++++---- kzg_prover/src/utils/csv_parser.rs | 2 +- zk_prover/src/chips/range/utils.rs | 2 +- 9 files changed, 200 insertions(+), 181 deletions(-) diff --git a/kzg_prover/prints/range-check-layout.png b/kzg_prover/prints/range-check-layout.png index bb1ae4e69c7cce31b886e65e84539a96bd223a75..736e963f8b5914ac111eda7eaa6a6d04169446b1 100644 GIT binary patch delta 10641 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 Dn#;;( diff --git a/kzg_prover/prints/univariate-grand-sum-layout.png b/kzg_prover/prints/univariate-grand-sum-layout.png index 1308203d37268c10889893b861c13bdc5284ff96..e9541d1ec1b4d5dd0222c4cd583c9977f48935d4 100644 GIT binary patch delta 18063 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 literal 1243095 zcmdSC3s_TUx;6~bmT9eKJI<78(PXC9vK_1Gj0aRgvS)f=w^q~EY3V2??Kmw{Q3Ilq zki(+2N*$}TTBQn->9$H+2jig#NRox3pdzG-au7&>0Fh%(U<{O7Z;MnwDs{xc`yC*$B>TLqo2 zh@bk3UU>F*e~?EGcSe5v#0$Hgc;Tnpzus4w^z5_myz|cMufacA_>b@M{~P~oz>iK& z#;d&Z&hyVd`$1*FzK2XNy_1}^F)K@K!b`sNr_%b@l2>lLeve-~#6x?I96deo^}T*! z9{cr={P@P}%)CGR*pGkBqozNrui#hWt)ziiaOKLI#hJR2ylq?o1ddzxB(}%8^|g>gP2VF3jw^k)~7c zNmlG>Ca7kM+1&Sa%$cVjCcLRc4YjmzfwQGnxR-g^)^H$nNE$pOV%#FqZVZhWeCF{n zv!8lod)m>8zWwk^*Vb5xZKK3?T}oX~D@pN$!<2=g4lT|vw^Vbz#|Dp9?i{l_H2*(N z-C40y zse7K(oeJwxGEZ_0KGEQeC7s1Yu$c63Cl@3q7B_2#o9P3Vz|;}nMyYQjkM80%yvCH! zLneCYlRQ<=@m00u-^WNW>sMobqqTLP-yV)REq6Z7h*I?OPnciZOj@`_f=Sl&Cex>N zp+$6UWqQ}y1Vdv&hss^Abv&qb;6sEL*JOm@st2+(wk%B`p9omO^_HHmnf2_C|5fMz ztKBu*?y4oiwQ%QOF3z7#UC0YxsMBArQ(a3^U&9?5_?r2uK`UZtJ45Tjmvmu#fI9(C zDJR|e4P+tl?`;;>EQ{;Qq{M*)qc!2TbLIrJ!|<3UiT7=(H;EWcDt@%CjksvWzBFUscenA@8ltXDRd)n|H*S<>A8NAoNT2@l3v>SYo zP`s`0**@LJ^S;H~B$xYP`5sL1Xzl%CA~;CWgVNI*w%LjYPeUZXV~}VQvUb{RGR7-o z9~5&h_2i?;D?OqbF*7PA9MQzncM1yg$xr^FdWin;j*C3!Q<;3KmRxm9wxMsKVRSJ$ z3Y(KJ8p+5@$Qo&fh!TZI?DPmPe1<3JogrRG(BVABpNFZce%4Va4D1#Ka81hxM3z)_ zQ|d~%!{`q`gw-hv@38oHC`T$%4H8R6?bK9LQKCSg3R`&$W?!?ENHq0l5xy+aF`oSR z$kCwoi8*7Ejr07NTEl23$1M#*#y#Ro(1aH-Ne32WbeCxc%gQZIYi-4VCd;g_;f}fs z*H!fH!T)r z7mt36+qrkex&YRZTA}y2pm@iQ9Z90#l|0SpL6Lv6$Pa6@Smd4~+8yl=>X@L||ADyW z#*OYf5df9c^j~)>sfQ7lcuJ+A(g5+drr-@7bpz^--V!ocMn-0H92oo}U#2JvDuaWs zIG?OK4~b$?G{&nNu@KlagfoV4Vs>MWoPCXXS93F0^Oq?}BV{K~y4_Ih^3+4C6ldN! z*_x`VNo`ly4q!Z-rDms;JEmHkQ+b|Oc<28iCbiF{k1g~JqY9M~AxtVq1c&ff6N9k0 zP%pclJ83XbCq%}c+9ULw#Qqn=-I3-&gL!beqB<5xN~yH>N95{P>5fS7vo=Y+jkwYV_Vnlj)r`=l^tuSu^MfwpV0AL9ujn?D!D2 z4NLac*ma$j)l+KYM1hMCKZf4DE4bm#=*8U@2r3Bwk#N9WSy?&hcxmZISibi3>Ivbv zw33cYQ=+dU3u6PiHe}chDD1Nz_vd+grF5^LSQgkTYi()ilv>Yio2>OIv_6c4c01-d zR2X95+6;QSb%8K&Q7lw?hh~+vyE>yqZ~TvNG8X_{`-(xbz}!x>X##y}rDEb%@*kD#iK4A;5;t3N~!n@5JZzVg}(lJMse zo#gc^SFWrr>(~S(fh*F4`wC=2h3g4^i`i_RQ{?;zKI^i|v6(kzQdoCFqB9*x$fCo6 zj*gBGAr4PNpIcYn^#C3H+2Q_+VvXxh$ICbLU&Z?zE^U7PzA*(MW(*t%^6Y1~jJJo3 z_Bu+~yG+=-N7BD%c^Vt=YKu=z1`5d5o#rLWTXd4O=_xb&^R(Egoe*Rzqg)%WX;Mh z&I+CrhtFZwDwRrmpvZoaGDA+WUy3vIfQ}xB#`4HUJrmSHBUsoWx9-r5zNj083SDFO zNbJ{rP@u4v;!{m7hil7ou=xjJ-xf#6YqM0fS?cDjUd5mLIMlZs3NH!uKxenxqiT0f zt=!Q6)Aa6h+v2ki#%JeeDe|!<_J}S(1WJX@ZQ`CtvrTQbVG|29D`AN(V(OaM0Npj> zBdZ^gggtoFeu)}6J$Mv9zxTv}0|)T)Ev>Bq=(VR!OxT1dr+m$-Rn`OM{sThiWRVl< z)LfGl9#E%&2Xx@-!_P3;`=2ao+!1f~!vns^b|DEoquSyYV3jb!R<_$=*O$SPOTH@g zLYdo)x8y5;jW3xu(!8+)c0J7qyWR*f659K!e3AejB7A}$I)QyMQR!V%vQenzO_}oP zt86>177kULq01LCFP~E6Ku32zuG}0i-)su$O;!yA=5EDOv3g*cXv8Yq8B(8vz`%my zeE)!mpeeJRDz_{)TwAPeu&E|;090(j+vz<4l>rw4(!#&GGzi~jW}(=2(m$Tt2`G`u z;rMfKy$p14u)=cY%o!GQU_rxf7IAB5uBwE@xoKP{{ydMm!kaoN%<*DSvH{-)?G11y zk+@{CslO&xraF|IeJEaIjo0XW**c?Lk%Rp(e1%87GUB_CBy?d*P)yR}qn+O#6WKW_ zPkt_6-J0(Vx6lpta0B!bX?8nc#7~O_Z%?TOU;!1(!FRR~d`rZ_7*ZY0Zg zAj`a=aY?(qSTj(}0`?9I)dA>&`7~zeH+hQ7oNyHfP@4W>lXa-|BvhFRKBWg%68l?J z4xe%HnGeMN`$l}-0JN|U)RH~hjW@RoJQ{|S)T0dKiZgm)dEt@aZm=~51T``*X zh$9HTnD==8$PwRf`R?BW_9ohWiTwB9-47+zI0BPd@zMi}HV$0tZ!G3{zD#mPut)@U z)YWe9Fb{XIcpzp7C$>OeL4^e&DgyxLF;4pTH;luHWca#d7%vRifcZG4^YXqqIFI=8 zld7=(8>$oZ)yuTOKS**gh#7>OFfPVeEnNtl2nh7tkh-H;-H{6$`}a79Uc|bZNwRp32wN3g5+Dup2`}&o*m=3MW_xEtf?ef~C)~J{y;2wAHK~7# z^n%-s;Bv)^75cwuU~|Jb;9)~3Ym!ewmkCA1 zab0<7>3QnMudaXjM;ByVApkv?**C&1Xr7p(IAer?!LicZyV9TM{;XE8HQJBQfODpF zcE0{6t4nz9-|*Z*yIY7rFR)tYU7eSG?Vw+`(W3Sl8V2Az7Q9 z}C3wwa!PiPzk3??u(h7;)f^~6lp!# z)P7xHKYN+&IJ9wKx3OKXY<5Pl(B#7;LHBrL=XgNGsSZ&a^xjYys{hZKU7I&=MsUV{ zU0;2k?0G?)eHFpIOLP%IfWEEL&<4X7KG7t zn#eV+UH7RAb5f8q{C&wR(!TnTY1NckY=2?MqId4h)^zgYV^|Z*&{}ifS{943=?0+J zzu4Hb7-^_n+bE3ByM67M9Of|=dq;%Umkcf%@x1~wT=mnA2o||P z<=mb>d*vd5puMfFQts>qenD#-tTd)Q>xjU{#eV58z!WpN8HGuROK0pzgEqSBWa8bcAT@oa#gbB6Dp`y1*Js5 zaYXVQk;voS`5Ly+!|ir4-6KX?V4rPt5p+Ok38V&Qrt0eIN`SJdn!Z#dtvC@3gkVF8kiC8cfaD%r9pVTsK9 z;>~ia(r8n<3P<$rhFb*7W?mROr*`xOEm9|oL!nTZbE={u@HsE|IhJo?u%wL5Moi^v z%N03T9f2Ynmp>H{EP?<6P^A@9nG98uA)Ex|OK~L4-xtnv{x7z@-44Cqpvb{WgOIa! zyca734AwRc0%roJ)mwNG`-q?z(SdOF+_Q2NG)~*vkW|L=U>d&$z07yxV#Rr80__TBqi}cT> z&Rbsy4HP*A>rVH7|3~;AJm_8N&?ZPCz%WAQPA*!@xP2KE9VhMjxunY~9I+yc?!9_waafFWjGvucJy4Az%^}Z$#s{vI9P+0` z%#V*3bx#v^qb8!b0zVjjnB%|?g&&mGjCa5f{u(Fk`l$9zZEM2?;j4V=DmG(B1Y*fi zd}e`&ontWo1XUPpJTBKITMsbP5z#DB&SHAm!31-pVoheI8!k8P)*MOwch_5NL~82R zC<&vZCAeJYSuUtTippKcMw-L%aj4$r#<^8_F<l5gqvgGzsK6w`2bhMc7gpiENa#oNxt+H% z4GD;z`^$kBLH%MqiNy%Ecpk?AYxx{VaDrPDL1(n)m!?(6-%tSn^?{IrLmZ|uBIYr` zlmE;eLfAuoi(~}yYeExH*HCW`Dsmu@bBRMN2NS7*p1;0yxihSSPQl|i5Sj|AfY{bK zBk;za+7>f3!Qz;p$e}1TJsn`QEQEt?cm;e5Oot9!)?M;5X2%4}$I&eoi_Ox5vxg$5 zIlH7e_+?)3-zCR5!M|~`K{WggOF{sW*6^7pp|-_w(t$n(egLR1WI*nGu}mXUde}Mc zeBs*P`9c;4zi{PcB(+KMWtqCI3^7l#z_iVlX$Nl@*mIU{L~`K<$OF>f?zAFPr5>u)u#7T3 z5pW*8qzQ*}QMij^3n-9uDQd(T2E=cn?Ugijb-d~sZs)sVq`63R6a86!1aonyFu?a|gV&19 zpcU916YW*wJ>TXEKaKuH?I(ocau^?y+X;eBqvG?&yAeqW9Z{l>Lx~_=SuH)FB?zkE zsiiI?CD_~8-iNdt+{P16gliW$Hjr#K@4+O{bAjoJBvD$p-*GEQ#S z4W1SUzYurdk6BLPxQMm2ftdRORyqpP0^}EqGfL!$!mPVU{(1jl#NlBiruf1C;zNuF ze@Q3kA>C&2t5DL7diESnGLCVAo?mggB0<8I(5e5*qC~f}wkitB6a|QMIyKm&7@VL4 zdEdXBi{B5s!|sBrxL>hu-2? z??-IHdHUffCL2FF1e3C@-3~NL$kH{{{GM%emB_oQu6Nfhat|7~A_us0q_LIt&8j7m z`|^N!VJRq>0k#nrfrkAFJ@wXiRE~gtJx?)-r4@igxS#vx{wHY<4TR7-nJh1~=T#)A z;fGkP5P>XmfMp~&=_Bn6>1QDJoWD=(o|Mr$E-R2#_Huh6BqSFqEwIC;2nfFZET(D7-nGv61M+6foL~l=7vgFf-rc zD1X5$L^AdZ$h2)h<6&a9td`2P&5USgk$IY^1N!|_9bA5e%W3kx%KA`I5gL9Xp zG%dGAju=DhxSfDK`=qX8xrrY!Do*ydn}t2k-1=I>;P}cWC+N&gC`N(C=L)NC6svCl z0SYNB`k47Wpf>7H$2;%;to|KA)iYezze$b-R1M7h|86CgvUJbiq7!dEYLY*Yzfv!E zV%}ik-5c$PMHPOB7?-jw&VhFrbEcu8Vc(ooSiCxF9Z7isEWR?PY3qJBCQ~iNO_!pk zOr7e~l`Suk=e+t5zhyIb^q2JXL!Z98-=DPr^b$aTD{!KJI^yAK2ND|)EWEQ6@+V=y ztXy9u*kjl!JZ6nS!XWE|V-}5g3z6E8-44_%w7CXbCcXLZ&4WOj@&YJKqdFMC$s7B9 zCVE3`qd4}2XLbPCvo6@QvX;EMB);QZR69ts;l+=?&-@bSX(-Uoos#GXAokcHfx%%9 zuj%#q0zSpJo4M!6FFyS($S@|vrcv!+DhV%M2b%GR7ha+l|7SMP^6Xa-Z}xH+p$d{A zST9Ck{&5zvTINd70Lo6C^6PLS+&%;oQ#VloI2+f1B})(<;L02$NfTN01*k5*Ab5RJ zMtnFvVDqnwQi0J$SV-Z?i!HB1!2- zbnG)L`ON2B+L7z#fim`kzX;%ckZp69fNP`?ibax32T2s~i~x46JTy|NBk63(F|1%T zj62UuagmyAhO3h`2D9x&`<@5?&rr$ z0*dw47ixhNYMS^T28pi10@S4uhgh88zT1Jne|nZ#j#MAgIY>&7@IZkqB_JX@!fMk? zvqR^Bcm_!uaBXHQCZh1WSV>nW6s+2;9KY-}3`wc055(MH&yDM?R?#M4BSyNSCMq zj05lwlqkN{s|#-^>`0X@7R$6QxgSsO@ki9z8V}V^3{mQIS!;`1$od@bE>PKk<6WRCTdh| zBKNEv!-pPu<&GgF=tKPgr|vrPD%kUs8#bJaDg+UYiG0Ff1AYywVkXJ5HGmp7bfP#| zSy3OG zw_Nk$49r(%M3EMOxF3km1n!&1-_WBPjC=*?{)THv*3{cFxhQY- zM6Pjbhp-f4Y2O+B##2b4$ef_GKF^Bc7_;s`VRSigd5Va(@ZbS~VplY)V4)kVi~Q>s zXx5;Bb$E5ehgLD1FL($8Mb%2E={QhKGUBfBgtnMP{ z5=t-PTlABd+uE!e9FpMvIZ&s!#=Lp^!rwcP=_6wtlT@f3^kG3U z3V&dXLO7+!*$t2nFf#KfH~4L?u_jIbfKQ2V^@BLUujarS5}$_Fu34i8YGsbeijy5~ zwj-hpK8i&S*p;!l8Qbd&?a=HOg14h6`dB@27$X{ue^pU2kvp}uV%rX@~-NWYHYSuYx z>Bba-0%i%RE3ya7mNwB@@PQ!8h=ThLk7Hg0!Mi*1#Tk>%P)|4`Kydjzc&m0E;dcHH zp3Qyo_;DwiFxvTZP`!GDHTr&s?liDti@2RlD`dUTJ-yQk9<}-?us3fFz0e&A<$TMc ztdS{W=)CJ=ESt3YC`ktq0s^%IP13DnJ%NHMq;eK_6CZuY&7jBqP50GWUFF zPJ%qZaF)w2aXXPPk$@d#f6NeOqax>WkEjuO_jjJ;IMBTXv>d;FycbQw0!V+I4>e># z75Lb2HU!=U1Sd3csSvcmX_Vyv(uEfz z$vl5fg+(QV)gG*X;Y&~jo*u>L_${B^F^4m&$5O595JZ@wSe6YXQRjc5y<`t6^u3Y5 zx=OY)FPK3Y(SX_*Vr?$iNP##4nY!AY85%BgM_`=_0I~g93~phuJSSsHz_j6>f0h4D zlYA+TBVb&An%jviMIc{=5;pEWfrL8pjCc!Fn!YCO;p!^#I<^x4#VFB(+!E(cUR}cW zaV7)ii%r~4B=&ji1dKNcQ~u6r%)8htgYFh%W(2GLPa1?I;Mk}p|j!q?H|l($WhlaJp7{>97V!2{%3Ca7Al6R2fG zkoaRE3Wop`iNI90H-vP348IC=mYD!7C>RW|Yp8bPxN;!Ks$198P*|lMqs5{F zF#|}>1e*U+lJULC)ngy4tlPZ+@UsQ~kv5FJMPvc#=`g+S7IsDnb8MsdOkwef+i7e^ z2m)3dBhYI%f5*v&m0c;h50Xm%GJ1PPt8z^IkxPv)g+_*t zJqAV^#umd4_T)nshgiUIU@KrnMVw*u5kP)xT{E;U$fjN3{YkiWG0d)u%+uIl>c%_J z{J2Z5k${Y~D;o4<|8~?p^%01bZwVa50B7krhFjb`>f~bi*~#)q#Gt(_Bfb=p0Syxq zxSe=$1s6qX@QiXC=)OSDXtn!fS(y(dB=lBPvFy9ujYm!0{R6~4;8PgMqq-*zsV);0J6>2gnh=;kRe$XwLmym!?ET}KH0Qzs! z*SEC;E)nFhRvdKS(N>%Wz!tE;)Q{#n7TRDG$j=mod*WD|9Xegz5y**{A*%O8gWDMF z$_0uXG`J)0nTPeC0;Ai%0d`@ZAPQ=I`26G|$9<9<6sQ8A75}BE5e5x@3rgjCUoE$Q z{i=aNvx5y>^X*yf9{(g>Yzxb$N?g+KxW(*4cGR6 z0K=0TS?vyXGL}MSo{0*Bm3#V_Rw)@fY_jupM%o{L{iW(7=J0j|OU6`Bf+=rl2j*5y6dp9{$XMAdoVkv9D zsjpwc?ZjJ09V&#LxyqxJVChB+-30J+#0r6k31bbZu)z2f!a~MUljx*@QWK(Z^g%8c zos1v{;Wr>%-$0ty%nxB`;;aXgb#EkYJpo4vZXz6pL4 z1GTMFfI`j#BLz$d;oHU!*8GBI3Xs)pqtN;lhkjPni1akUT3$oAU(hq+S;-Sc-Odv$ zWCjnaJ!o-$XG#*y4Cl#i)q%nqv$A<5%%Iq6$EZF3=nf`6U>RtbvewZhFV27fw2Y$FN05h89#Us4 z2@}G}RsXU(pfX4@TY+i(8?51;=ml_G;s-|D&y84L(OWKG3Yx3VgYIhmn_xrNjot#8 zGkP)S5jci>F7C!rm=!NDkP#WMgBr{q>q(Z+1`43UvchnE1qA?aF24olPF+RcVI0^`S9{fR^+2 zlq5+G&P*J*+lnEGcRg4E$}OnBBZ>C_|C&lD)itMhkz&U2V&Q~p2L=#|EsCW;-wh*# z0)m)z%b3kvlL_n<1vESNOau#>2}4sz^^0wmE|k?o=r^=w0OcnF)bki76S^*fAZUQ{ zik?ZZ1e)$<`9=BFyDwnbLk}#&|X70 zoqz@ie;5{rz7bnb{LfbhFb@JHJP;vY3MdU94H)|^i{R)Qmg07FE8?LpluXcMj@BRW zPv&V4Z?lbJO9s3ns&OMz$^))$hxI~cHlS4%)EY~cMO|jjPD|Tivmp;lfWKx(G}2KZ zbIsXp%LtD4!@(`e zQmj?ok#LX`=o*ac#c9$DlDV6QS=l+tqnquZItBTL0)9U*vV4R0GtH)-$54|E$FE8E5lfKu0jYlLhp@xqK= zY#OY{&(`i7q+~lqjd)BN?Q^UReAla&5T;PL@MyAfM4)O><@RIqM&;9H!`Z`E38OSy zcTtH^T+w&KSP#`&CmeVsuUqto8NI9%5^)BCFo+VVb+o^c#f3m|T2BfGPo6$%6`lQ8 zE>4^P;26LNm%w4@-7%}d{DK}4wgmGA&;yU6DuJY~*9#;#)^+5!LztA{E=Mg3p-3QK z4{)FlCwncBiNFH=D=TzAx*pJKo0$y+xlA&b@BAs>iH!~urG7hP6x!nbXmbFowIm0* z7qr7A(bEyq1hAr_(z+%1kBc}4>;41v@VOaO_b%X-&=p9dJF)-tPE>PIsH(;40L)Lg zo<*ULSAwT3U}w*J398`CMFLo{;m|4CWs2c^FC01IUD-I*WP+qM;|X*a*4i( zg|_M{RztcDy}qXA0iXcDB}(B4gaWr7+<9}Eg-ERoqFn~x8Nd!jcu+_3B^oeswkL4n z1jV%mMBHMax<88PgeDKi-gKj=@`@FgmZ692zXlf-X)((%7ootEBim%TaU&c3lSX@m zWw$om1KMVh7Cv|{^Gh(5vT`xr2{2%)=Zcb^)#JeeES5%em*Wsk9W{8D)6=dk$8n!V z=^LT90gQ<2nm6j-+E&|xDGL0VP=3uf#_PZMaL z&$H*;dbga$z2vNiQ=Kl+b<}o6a6mf%+`)%O2j!ZbQxm-4Pb`8Bv>Jf}Qm3U2;#r!I z(Z(LW^Z9&=Gcb^tcSfVC?tM(>d`y1<31!wEhX**&>h@)+D~!i#wcdBNUR3ar4N!c( zx`dTM&~A#uugUEO!FmYEI@Wgu(6=WNpT4N}8D8*PtXt{>&58p?`+FY(b)Vuz;o=UL zM$G$j!JXeRQ}DF{=u-h$4b3|dnyznTWCU6)=qT{fdMA{|Y=1S+XfV_>u`o9wc~j(q z!*u}X-~?qis1o?X2OQfGJ@vl&5EC^tG9m<5QTC-}MXqZArQl@-K$Mr`Y=y`Z2foEK z!UdqvqL$dN66SA!uDD`d#oNHy#Q?j)U@u1V0(8ff<>_z1*;6bC_<*^>(a+J($&_N> zgmMoDU5D`{4ftQ_>FEFqFe33K7P!`Mi0{>KeoIFOYo37H?nQnXSVl3_UO30BN5qT} zHUCvV&x%YsDqsRQj%)Z2D8bplMO$CV{ersGv6-G`to}l3uBdAQ&X5ZSIOMATv8aC4lc4<9;~ut1-X3{ni!c0d~Yd zc#`t^ixt>TPxn80heSG>EgW+i{mxIJkqC)_{1B>7SJ0|(#}4z3bDU{)o}~>=*_)IguDcVBEf8qKE}=C;_y40z0$*fX3U#dZYx;KCp8%=$mbIk6$&r~JU8~P z3}1dcMuQ&nwBP^mvb#L>m`(qG{P;T{pYwf znb*fZd2xPnBCq?mFI2@E`f@3kT{Sh?5V4E>s|SzOzsCRUiMABa`!9U|&4xF3MX-MY zXM9cCi2pl3_iDsHNBr1l`2W|dipGTD?X)1bj*+p)?D}^o%R@}~?-toN-c z_K#=PW^{|Br&4rDv=#qIzO;4yl(?fo=8QKx@o2L(J8`G=99gq6tH|Ih8XxB8&uSk0 zgxI}i;m*m-?@shCSQ=i;{+j>BtY~`P$Z7YG!I#o0YF)kXHo|8vuF>J=z=y$ir?qdi zwJPluRm}R<^#*Pr{^DNi0w?c@6?hr;S7KX6;oiD={1cTU0;N4M#xFj#eB$kVB2KVZ zevAJ?e$7lIy)%j6M49vApac?T$yZ zdP!b5?Wz1h9etIj4>e?l7w@eD_N$*`R@*A1pVNPM`ZcYXc#H5Dm9iqV}NSw+?W zaH>ITma0z7t=$&wKd)t~v$E^N7x$)km?{hHS!N!XAo7-&9jh$(AG0LPDsym$h^{j_ zLN#x7Z@Dy@q;@3h?UkC5Bvog=i)`1?F0KB0tY&C^MV}O2-q98w>>2&t~DHI?TQFB}#PY$m(a7Eh+A zJBs|2nM(#26JepfsCclX@-^hdnVTT;&2eNOE=~_W>ia%)-qkp5jN^dWwd}-nCL5p1 z^}5V|eDHb|Q8sqBNVATD1*HmzKc!zMa-&5(!FYu`dBQekZdONzH=pRr1OM1LAVZ!x zO6-m&u7B)rE+5=^k_?Y0HguhxPEQ~EZKQc+Rv`?A{(~TFILAGe*VMYpwqe6JtM|cv z*CZGRV^!V7WOJ>myVBS`Q_vR=+eZxL5+L854J;O`!X+~AUL8GM>iHzhoLYW#MOrxe zkKB@z)0tfd5588{BdVWTX7PEXo`cOPSuVBcX316XR+;)_nF?Ml z_H|y5sP=B(eAN_^e7~Ko{}*nlac!B|{U9$;D%Nzb)&FI7Avt=k))IV278sDaUgKRP zb|$PN?Ste%lCEN;C#3my#Y+7#26ol(eQF+NAC5VGef`Rc0n2bR(JN;B9D1a^wZj^B z%0eHI+F!}je49mtOd_YVtieXr8M;?lg2U3Z$J*}pr-sLxj(q-U1nuWAbTbhUPxR(- zy&o2swB%?PkD4e}Uphc~7Za+E3B^nwU;B;WB$yY159DcvHY;)ne`PUsSsaEk1|DIs z$k>)FEo_GYIoqY9uJWW=)%|3kE^e)Tjow;mJj2o0brBYqM-+Hh>()Tg@a8d{cAt;q z^G=iw&y%b+Joe(YyMN}Rx%~heZCby7h0RU(N}R`Klvg)>Tbvp+aA! z_w;U9++mO^h-_1bOU2)B<+En(gePK^~+$v{$bV6 zOI>fJfLnL8QLMalAiiB5#MRJM(m&%kIE3#TZD5;4qN{Bz&LiQ#$i;2D6H+|Hl{$U< zK}laP?|%K60=;X6p{rKtbebaQE_;!8j>y?I=#d9Uomqr7UQyF%hcVF~q9{1lT77*z zev=l)GU{s8Zmm2d3lC_`nZCg8xGb~BVD|598=>xed$QV-k4gX3{C9{@ve-y(ZIn?H zbrf79Ave0N*64r6;+-l@`l&B8NXol;%o&T_&Knt?YV?K3^Nrd~&G<(L5-OG9bKW-6 zJ!tSR77oeifs6MF4v5OT2GokSSjLeh4(-$WhdtQ>br9TLrh>u+71dE;$|CgS6Er8k z&Qs0JXe=;XKavR+OB>&;Zmu|bM8?e4!Ru5y#)YdbiNmRy?y}}V=V-sxP77u0yL%>r z&>OlYr30dr+07i~xg|31>$(PNcA+KIAPekE(>b7OoVT|la?dK=g}BnTeo^et4k#Z#k=MeA)7;)^se8#fLf72O{W z>cag$SQ%#oNkfaQB^+6{h7qplIOVm6L1Np*0Wav?^Wq>c^k%1>@qR^y-9&lHQ640q zd8kA}wHzV4aGx5dVu)G=T44DOvLA@uf#5(C@Hm>M13pO~c; zDc0LoS_XHBwF~Ku(!ey3%BV((wN$#lj&_-}j$G1L#`9jW|FWOm&rvtw&(MyptGY|I zSPUofIvO>7aT=w8E7l6ZZ0CM5Zs|zaBNaIB)Ar{pDv}JB>qHO9H^(b_%d)HU)ZJEXHXBBY#|T znfB_6RMdoGOK_?r1fi5Qk+U~X?aVa}Cm44=G2&|`oN!WMGikAi+S?LTb|105STuYT z|0p4Alh40xxQwthE1mhO7EAd0Zelo}_MeVj%G67R?FadZ*!U@Sp$h?-x8#({<&z3?z0l^WHDU|fMIam0xF&ed@+1rN0zENUOu{t zcR4e7N*3%dPV8-nT_>Pm^A9(#Bpw3Gd7$wJD`Sn+P|5Tt#zez`jzrC$Lc^ATM-raS z^TrdN9%<;1$T+gKk#OgWZr zd&y8W6|3sboY@uAd5@&lg)Z?Tzps=jfKuoWL}3F-9m~^1zra51AwZgWp)azcjG;Dy z-j+vh6xyXDKj(#-WX$qici$$Pj_HO2D$xW<66IxCezTo<1WQhpHr!*P$CBDd-;sF+QoL$Q zV0)HjRc32Jq(S0`p22w}KlJ6^ak*kYkP%Y<;H`uRTPjb$U@b9wZQ zI3fM$%4A|VneG`c9ION*#vz@Y1|(D<-D9h*#gQ&xXSs=S$ms7?&!=lJN$$^ zXwwACTKi5&16xG9;FMcnQ0%_|?tpEf#NioPce{5$EjO~~!L`Hv3zi}Z)OtTn5IGN$ z-felr^Uc?#p*^C&`=%grjJ`&IFwhF~D&5|bwL8~FLT}10yaDmGOcZ>^7|tRFbx%;( zLu=LkWH<_B_=i<=o;8c978&I-FgG zhd!w72*PNgu8iSu!{5eo8IG7~7c=wQeC-=Y5Hl0d!fe<2R}sEuaRC126iLCJnp0Jw zWm;A47h3-(7XPr6abI68zeiNaL2mEeDTbX3)`^JjHBHO~A9JHjT`kUNMJ(3PM*$R> z46$XLaIeq!k&oDtsnm{Mk%r<3zfb4?HNOU4+G8&YUg5cV$5e)eKH5#psC~(@s1c*P9W%OYF9Z@vPZqgiZMp;im4M`3^^t`QgHZ%DUSGq-}+6tHr-Z zG_|(>N}k$*_%BW~+KeFm=IJ019&u8~A1!bU2l6OR6M|VRBg?Guwj7_;xiwatw=4t$ z#Xu5q0bW@qqxO6uW%h`uat`w~oS^WHy$!ykCG-_9RD$SLut_x-Pf#Y&5M}Ivq^db{ z#?@wY7DE)5xgvh}09r@+3Yf4-nXmiIW?pu+mFeo&hWahpMaB#)(=s4u2yt#a6m_0(yGp+s$)2gYsKx( zeyx8Av}SQ(eUKNRrEuuYKVx=ihm>k;)iaO-XKk7rWs&##jC+4XW%@e%ZecKufg^tO z&!xTR%Pse)5GBpld)IGMf3l`4?+Fc)MF%GfU1>EL!IL67_ihF6txPzCcK41`@4e?0 zyvwxfYhlykp$CdG<_{7*Ap*{2cNG`iy#mfIYOK`TV%5zYP2Xa}&@=@X`yzFd6L49m z5^~ol_7tA4OIj+)i(9%TiY<+JP?v7D*(VMclpPy(_M8PZkB! zU@T7Eu#zg326prPf47f=BU@0^&dHd5o@k_@&D6BKe8{YvT_{u!ox8ZUvnx;k=z^?G z`M1eV(`Y$K+_+1ada}d!TEkWvL)%8wl!>5BXyoNk29@JX{YN3{Mu8E~(oXA$o*J6W z%^C!1$Tutz$Q{qfMpkXL&Tbrk96JRal0dn z?oox#zl}t|q5>brt-oCynh$SExcidb>m%+5rkhqDo?&q;kp`X-x`z3MmKEF*jV+#W z4XGY_2II8pS;B(Nm{D2^}vAh1RatI^MM_ z>PzEzft%54TUq$>7Pm6O@gC1RU*@RMjRHE1wa`mM)O@@DG~o{sp}n%u{xX68G|5yJ zkJGyTXs1r_nVZtUdC>!!-WaBQ$?#<1aH6il+cS+v{mmZUtF1`a*t@qFjvmRAU#qvf zie#hMHR3JnXZe(6zHFG}45YfQOkKZ%tLnfVZB^l8!0<`>PZEw&sk55!)-sOOy1=U` z@LC7YlZ0P+>qfHLH}M?Xw6uipdnk{l?ZNYQW<L~9Ce#Hns5C7Ht)lZ3(F zSpu^}nO$M?#bpT*V0$0)Da!nv=6~LV^@?x$PKf>A_~017VxQE%&%&J6g+C$by0{Ed z>Tk8kmW4hLD@|!f6XB$*=w<@hn+lXbf?{o=h|v(?+bRoQ;<-MN5wJ3@zjzYJKz`l9dHMewHq0e{_?7>(IEJ;~9AC&>H8EyO zxKtFS=}INYyYG3=S5s$)0A?P!zMh(8p}v9%(Uq!kWfl3$Q{Rlz`upvk^*YB*J9AVT zrtS2h>do-JsUdsWSL(CH2HU*mB2~{p-YCwNF%5PK+T8Wk74%*^eGLegz#LH^L9A+@ zbL>5F@H1Va;0?|BX5uoCJCl8(L)y?Y1v0-^yeMORD2DKIjNX|Vzlrwq%7>yvaOkje zhqNE8l<`KYKofMNmzI`xMhd$c&0yQHy$w&KVFrz^Bs$2~&Rr6?%L-LLozXhCH`drc zlemy%q#$ML4qms1`=qn;no_*~lssyvVfR>v@L5y%N8&VHp8kilUU;|k!ebZFq1o9Xj*Ho`zRNM4yqJABOQe@->`C0(%lPK1s? z^@dG`bEmCGjAv&idJzt;F?O|y`p;b)mWEqJ{u?@fSE^umUFS04ph4>G9E4qQlyaGU|Dr&qugFMUGLv^!rjI3R0x9I$qt&30x>6(={^1 zH^Bpza9!_}$0CG|YIENNvwx2UT-(+*vcH(T<%k3_n@c` z7_V(1>Z*zQygptPiaW5Ng4!+$MN30J7ll)aFz4cQALke@i;%kjzG4 z=?E%cy#Fv*@cwCq-ukS3&3@Me%jh0a&om2tHel$zGLWTl^YfF^W{0Xc%7S>gH5uGt z^bQ$wSSu8y+-n^$hwfb!Mxg4rF2R|X(M;km?gJ6`t24BfSd4BxwCWVGI{kNZPYxl^t$uYmWJPaLvOz3q}^_F>0rxqCvrdg<=@ zO$O44b)iAy@Z_>nk7(WRTD(alQzpo}ojRjDinbWK3XHB?RZp9A0a+$kPBqBr-UTmJ zMQd8x;I-T2)jY-_Q-y%{?dlpp{pp$DRvGifj`~2phW62YI_go!z1wq~csRWk$C;A7 zgR;Pg*Z|Um$i16%pQ}x*p8r2>hxhuRUwoP3vAe&l72Je-;#hju3fGpVWVXf{TW12h zBXlDD^d9upz4^-XwfevcvPR2Xv>NFnnxDyg4$2f2$*PBa%9;{iN>=q(JL(rYy7_@) z*fQW{;?S%kmliF0;G3^9NZ>#?s&JBOo-edrq!vWzL6du6fnwkn-!8W>urlys-@eAz>*nPjs(+jBUY|FP8|voV-(b%AB-D}Ftmw3g zx{p*?q~U(6rE`e{{>L3Ag{N87AG>bR$`_IFsWYBEm^ZcUwC$)HYSy{rOft1SJKphO zlKE`rX;6c({UJu4F72CCWj6nc{Tqtwbrj?*E6x-3yw%v(H14zd;NFXF`MGJbNUrCz zXvle{t5RQIT(UQ9_Tqv%$;i*SQH6qy50_J?l)B2UYc+jSMGH6xuHT>MUp?ZB zA%gyR`R?TI6K(4Zw#)P4jv7XufY;}Smg{GcuIMR8DiF?1md!F}Dp~2oglN?wa9{VtJ z`c5Pz_Wh1TQDC;r{qB+8$0Dxwoyb>isf~yePmQ{9ZC$0OXijrsIYf8W3d3-k^OWjF zEiujEnBVR9j~WGjDzh^M+F({W91j~75AmX2#%_w z{LDucL-m&6JUT4qvf^#kG@iN+CCrhELBW_0jbQgBYJ)nppbm@-=@3n~tr^<>>r(e2 zS$Y448NER9@Iw#f2{)}7gmE~E$4rveQ$-nr9aYn~it(m?=yxlX9Tz9ZmA#j*+Lsgo zngaVbKJZk^#w|S{q(9DGQm|tDoAU=(JZZ8{%G2L3zqX1C|AQAM*Y29H1>w2kskISu zXeAG)yRQAF)7v&;7}>fkwji?;6+tXR547JUF6;hz-NKjn^l#u~Y{$5E7#FIZ{^$pR za*q%x6lJ|Dw8zBG;dcJ;X@F{ZD=jVZPOcuV$;{rDul$*#C5HI-bgyx{F8np$Ird>L ze^&RS5&f5CmBUTShLp_i8-q*7$vmfY=i6NG@|YdpB@^jytR+Fq{3-waO8cU$;f--1 z{5&9Wz0HkmSDLl})BL35=~c6p?lR2|5wp7%1)+b3hqk!Z>-?YnpvvT9VR3vPIv^6> z{@)Z(sgS_`n5z)o@&nC8KpG5)RQY9rZ?3PO5b>^s{z!>aPE*r3`L_J*7A*TN0oQq9 zMa~Zbdw<Cq1W96ZNBZhjnG^M>b;c9JCS-!gRKakp{^HDxRuJ_w`}R+U!tqo2 zkuvox^Il|A$8iH+uE;5nRXp;GtPL|ciku%hoAWWasqfwj`@WxdISQ=D_@ zHAaZzj~m4&pNfoE!X5ijUZlSDQJ1cq8Q3gx4T}p~Xe4U2!Q+;o(H`D{LKM@PrwRd8 zMj-o9tQjgZ+7pPbJrd9K@}aK0a$pNR;^MEaFNdh(!kaXHV-2+4kVIHU4`@%cd^Rj; zXWBrTJjf0Gt(Ku0--GI5`?LEg>hD&~iWTEK3ykh%kHntr*bZ}LvRHF%6>q~aGJMx7 z&Ji(D@`%_s{||d-AJ^1*|9udZwNBaUR%}tSPA%)4q@Asx1hTDnOD$8@dbhM9q}Exc zr~y%V2suaVlv%53wMr{W+A>Qmg{X);CI^d>DnhC#5rKqfmj9$5f#^~oXUm_nKtTJ_nC-t@1_txbTHj*ImepF=(YwnxjcuT z71)W}MLca6YOG)M+PH}g7UQ}|X!>nuYnVY^XzJ{MkHyUpiQ_@!l&R;Nx?o^3Ao?)3&d- zyaBz*15H{lf9gYT9Mutc%*B~%Bc&RcAKTZ48d{cT)s_YGqSD=eb45}k9LkSDE~e{P=5GRyrIetbm@Wi*&4S%JCu z!Nuy0mUdcA-#8>soCJqRy4Bd2eru(6w)|v&AE<-82L?7yLQe$zcLvz*Z)Qhv`*)zi z2{5HT0A=0D)Eefwgu`Fe;vv9BymK4|eos~z1N55V23cq4PW&$;Bqni49k z^{OaUhc;5qzJ91$TN~Sc!k?Dox@7K zq%&wD^uEUDeA4TavCD6+Jts(H_)Om=QQE++l&f%Y!v;?#ALzKg&4k7$S_dhf_4rb` zR(T`IGPtGjYMblH&-FuNhaUPb;aT=?g^qTdwmc=_RP(J>9O`5;I^%an>z<%yvJK_7 zJab^B@&-t+e9$V!{S5q0eeMdDz;I}D)@QHAFA=B%6_NKH0#p281f=Z9;I@CpV{UMd z!*7+s%hThHc!8&jtANIet83?K z*#i_5+rq%_YmP&;g;Y>S@t__5YJ6`Qbdwzc9=XR_a+Ax_Nb4n_0|2;o{lY z$!OI*73=iI2kV-&WVY728&&fjoTA9lhP0yLZw{Pe;KUkEusj`K`_Q+JgANbrr_@Xf z@soFWOc&P%pQKKp31iS^V^xIm6*T9L{HkoIhKv3xs^Y0_wFDHM>=&Ub33a#<9$arE zG>8sVazscq;>9)WBDVJoT7-&Z$5$5I!ruKhiKcCkK9%R>6#X?ktnbJ^Uo)zIv0jsS z2a*~-Q;H5jLYeO{>WY4oq5c}6)?NP7@BOq7f=0J(U99G6rO44LX-Or)88nB`LE$d~ z(IM7;^zt@C4DQ~llCg^PJaLxiYfXgQDUa8?eXKeM)&+o8f5yd=8IA|X=45lmAq(q_!C z2zoQ|>xMr8kwj)_b*+LA9QxKp1w?C2b>hJxShsG0hArCX zd-a)JJEEAIgNhQ%Ph)#8?qJ!@^PnjVW}^_SjU>p--<_vG zk`$XZJC|*%fGQ)X3|Q7|UYd0-KWv+Q)_p%HXFIf(xzns(%J2G2HOuuGZ z{?r6FmekRdgp6>4SkmvOjk${*Xk%zlch`j4AFJ`gW;`TXccRPCecSfaj$z@Ff;*uK4ZR~P9 zgOs{|>>$6&z3K{HkY-n2I`ln4(Idx`U~qif|sRr=4>ua zS))bOw4J83RvYZU(|QvDq8^VsL>Qx$>GSXbb6hj|pk(OHdmpS%TAwpsV>6$3UA3d~ zuCviX68*mA1*js|o;onQX%eOrU^WXzN-#PO^LY}&k?2Ecp5U3^ugNhfgCDh#1Y;r19I6uX}u z_XxZu$;iY?!xxGgko?S?2hwuXcDg)m@wgwHCEwel|3adF8IFsZ;h3VBaX^ETHK`H_ zL3g@*Dk$eu!MERHF*$0c9JB?ja_SLF-CJ`M9j>RQPg2}m@sKRjZ@Rv~#l@)^%GAq; zG*+Z`Sp_+@#*a}0UOKRVV~1)C-sqdIeYz;xe``y*)RMJv;}tRNn0e+Y>X7AwN4#S! zo3+&AA|@lcbl?O}^S*XyGavNyRyo=oJU^+dU{cYMRSzl@e$vJTT+^juC>b(se8w*3 z!A{%9_IWYUdn6vI8CJ!gJdr>wQqCsYsu!Ulgm>SX86EA%$yEw+qDtT-9j<=WDQ|tG zSOpXnowWY?=G1StY0WDBS5yJ)^FW{Twk@}2{46i6n=eE2ageY=*`tY|d(blJ*|5Gr zep%O}nq=t1@k{hq(10U)qbqLpE|Mbw%((^ws>88p4ba#xA1{=7Idvy!uU4CXQ7$x; z>pl2GZ%G{21Jv|BC?F8fb;n?b%l5RIjqZ+bLRU^tFML54iI?752B%m<1zK#10Qp>yEmVh#FZZxv>f(%O)U zx|P{m=XvyQt^*dAIpLx9-?AJ(<|p^pYYWhEzx?2~ zU9(>`a2WJgO*pa_pboA?s_D!~zuu(YTJub0mb5Dmz5m)!)he_PYVEC}l=5gX7L+Na zLZrYKY2cyfquEb(X~Cw=3wH$JdCHVqhqSOJwH@M77r9}=ZYz|INeC`|;NymuBid{q zndUe}O{nF{-@GtPb4WcsB`Z1QcrK^+08&Qf7jgQY^06b8cWGhyYV%^PZfRudwK+)i z5FMY2DmzH44MM6F&LeuFqLgZ2A&-Lgo)0u3nA=EQ?~Pw*3N>6U=C~W(u$1%PLJ2Cg zS+H{l7YYSb0?;9$4-|876RLi=7@3#jqzV|B!MNrj1w_GgU34zG4{_~TCoX&xzhd_6 zU&TLxw91ZmqqX!IwpF!$Low%e8DMdPN^M8t-CpX*^sg4B`1_=NZPMyxeDkwvvIZKp zA^~*ctv4gFpk<>%-29-l!YHio5T8Nr8#Qg>60jg<8D8S6EpsgW1v~g^SM8Xw$_bb_F#PD42kiBfEGQH0TmrVKr*|@8x|J* z1VujDP9>)m2U%edb)XIJTu%_=yL$qt<;9TT=>Cqh*oVsF;kX{Zm|rFn+;f z5g|1-+F`*gG6_9PKt2+BI~7x?ZJrgqPegVmd#SqT#P&Q9S=ND68u1HJ5gW~X+cg7$ zncwwv!p^}d|E-Ba3-2nll>^cg3zAUu+hH}l(CrMBE&o#cDKL$)h#T>o!AnpP0`ZlE zZfA*MR}5V{AxxAPY)P3ZD;1Hr$2GAc4tytvS^OFuk5nd z%`gzYU+?YsaeL~!9b4C1(B9hNGxuIUD)V?paLldHU}1MKb8yWpOW>Sr_y|levO|Q( zZfra3+p5HRBQbEJISL7#7bzn@RoDu+cG#7j`i@sK^}Bl?|+*sgI7SEW`%f3opI3*JD_O|_N3n& zgha->w;Jlr!zampd-US_el!R-GV*ws|6`hDxJDqSjfqP2AH5^^r6=D7AJEKzlfAG6{Q@R!SEn>Sub1@hv^03H3i=n$kJ97-e|_^k0);ru*L=XC)GdN$Yd z;EtfQS|74YZCe^U8LlHl6~b77h>npDw!^gHwfsHsFjzA|jVTzgzN&mBb_X&I*z(m@ zqk{g*XMoh~3+pMTZ-Wgh7wfHwc;JoMxlkmA)liRZ^ggq%kDd*jNJ`2nXgPVmH|a;i zw~BCt@Z|V`CVshPm#TkS^7h5#>&a@Vugcbc zKgrbov(56)jsf@oQ~cUvvH-@M_b3A585j74F`t8ppSS>bN5;ri8)KaRpW_lHM!>`) zFy@K7QT802c7?)|7y)neE%pkWATA{U`yQj6ZE1+FnF8NR!ihS{Q&eqT_FfC zb~0UOy3#@o{DV#k$P4FY%lG2T(Epi-I)WEw#>f5rkxA1eKG5ns zG`<%qMY&Fr1#*bX5Yi&Lf|gg9{BTF6u+6f+>cX_cy&`+7Bt@M}HH)m3>@K{NN8KfD zAa=uLv8*aO-2k73)fR>Iiq!grTxf*@d>zU>>AA&@4>n%HKjTp+xR^NEcB~ld5Rva$ zY@aq|C;Bi4e~(}H#xIgGps8K(#-3n4+Ox)S(}(`8XKuW9=B_h(c%1}-NfyN zMOz0k049~$kH>yK{zx?x*j+E7GYia&r%f36?uO>5+7AH(h4}$th`=2O__j-Me||@y za$tzGEBB8P^r7ihRh@o@F}E)62B>QkH%v?=t?`nps?Pm8>svh6qZ*0V>Z4XQ_gY_Q1xm^cghlPt(A0Jf&?7`1VK z>iMy_2tM5)InVI(y2^^C&S8FhB)os)GWoP*gwJ^CZRY9XmNZ3Fy55HaKGWl2)I$|N zxaXH~NO6%u^sLo8+i{_3g&2Ea^oe1%4o@F+6cA7a*J~;qIXjR_4MW%#WR3&}`8_Uh z1pp6_eqh)TTe51#sLlM*6vIqD1AVA^X!+rW&bo4$(odb(B)$9N)-NRV%Ro=bzF0kg zn!-wT0%WkZ6*+Bsx;JbfSGwIK>*#->9m6T#NXK2UfdylVQ|$E`J8Jl$y{h;oMkZrY z)bgQfd7(DgX^KFCH>7rS9fJ0@N*|+!_O?*RV%pTsCeeBND(KOTHe+U(BS*a^UI0Kf z&3feZgsCAH)H-1HKLi`2lpW5tnE{62mQrlE2AZ}l5a4`{iy(DUZZi$4yG%~i4=SeL zi^cGyX}%a-GE7EImmRdiy|t>o8<2lx6gWK(AdyjZ2-P3B_3q!#H_gfAlb?w(D6Lhr zAy7mZKdr@-y8~6esc&DIQ2$m`c5zB;#y~@mSk38%c4Phip({88E99IB)l2VXTcDVC zoi@5Al780`mbgW*cC8tqSdvwVX7I%&5w5)Yu-!)uw8;SBz;DG@m?M%Jk%JP1>$JHl z%sywH^L`?kD_3(!H63*)Z7>=eY!x`DSO=mBDt?)>w0jT018U{_0%$$ULD6)ZO4TMH zm}m}^b`l%ogqMq!qGu`0zor`NOy!j!_nV~kY^b)3!3Nte6&G!El3q-BLrsVWF z%bK+=tmcvUtr+z5psl=qW)q*OlQ@g1#C;GJG_sJR?)#FP+%y=zVK{v)10M?6xQP!8 zg-{nf4V0X4FHmD0(%+<5VtSyTN|jfrpanS14dKL!?Hy+-?`- z1{e)YH>ii=p_>LeJUgE@ECT_U)>^;^0a)0FJwvWoD>~$<8+T>oUhZu5_XU{jbn&>G z*2>SJ`t3M2%P_a$%ShXiUAyM9UE)}v%)_%B<|1^-Fs`C>fDMuVt0r8n6Ry@_?!otVwIa6mI47z4IgJJ01LKJWi7fgR02sAjSe#I` zKUaP-u@MM&q)kjq*Keo<-JDW!%XaNpb8T$JDGSmi zg8B|m8L&3+X}cJ|NeVB`1nR@CT|gY~hzzA!o4Y*6+j7I&5{oex*bDb2kA_VX9M!s-VvD zz1$tc{UNruHLC)ILrVG*i>4OHF7HdckCh+P(=It0S(~!!C62FH%RuVoFa@M{D&OrG zLWU`5Fsq9N`quM4(l$M#8&Xh1{HpFVT#z-^4+2`$p-JT9ogj^h4{aJ%<|H7a< zSc5yv1t&K-RS{$_U^%X2rZt8eIB42;jb8vk_SDTK`k~-w0?YgBlDJGg5wv`I34jk# zgI~1@O4O7+((yIFIi>y?Cq&HAAYmZe#wAN&3WR!=is`*-8tqGt7mM?Y5{PeomJwf6 z6czQc^J^1vxd(4ZzP{?fjHr&_O`G@?w4b!y2WKSb?loy5#s3V5S&>?5WR4sy7%`A~ zkI-jH`xaDOTMJE5LUE7P3ahTyOdWNkBBsRTbVsgCjt+q!6n)DgO9mGZ^jiDtmInS% zBF+RwrVi}m{<&uedZa2gX%Nv!yb_dNA4R_hQg!gu9SP4v@;(6Cl)A8cBCG80{!w-- zFF)&rNL&Ky{%{b;Q|(A6ILH52xO-D9B9pvYV=7L!((MQppIPHpeV-Z?$}nmm0F z+Aa%Z^jhazR?ViGS+`tTp)1$1tZVqjseH$aT%hgf2LTS3k&&05KgCCfEQ=D`Qnqm# z*GQt3fdQ-we_ems#TA;pXK#&5|GCrp?Bh69oVqIrJApPdRx{w4s;X`v@q`Q8S%)vy z?Z)A_BKwx-j;dWbs}^K#+IVFrMa|V%BDj`}#mGv$6;MWOdVrNa80F9*azaIYInjoC zqSBFZ1KZQsoBd_>zl66q0=2g1ky=}bx&xrDaqXP-_ZS_8sXKzw4~^1*>1h-8)d~CR zf1rKU8?pvd*WE3nEFCSQOgIpS{gnTG4#W{qP;uJ7_#XRt{5QKykJkJ>F4GJ9Tv;I7 zkT2gCjEyQsKCc5=B~ZckK@JG`z!@3V{cUreVx1_ZbK%`R^YP)nE+sMCl32E|jRsM> z=ecvf<4jI~kp{a-c70u4cYStRPw7@9(r$ zfl=(6eq3A3Y&g0qzYBc6ZD(BDT-q@o>}!)Nci4}EyowgMGB>eIH@$%{)W`+zW&V+> z^s7#MTru9k22W&`lW$@JozqUF%Cw%5P`_BV`dne5?QE`U$yk$2hIa&V5l$&TD>x-B zgd7WtrwF^Ui$I_hRIk$7Fuqe*=CoRTq9uQNaDkJe;`*Dpr5oXBo~{jYAF|V2SP(Bz zAcDcb!s_i^lb;WW+BDw;D0!Bs$K8Tf(9aq;lPl9gx5q$INMPoiIRzm0Q_~mr4yqZb z3?l3nqHDS_SfMHq@_mgod7`D}erYqRiMw*_i8>|^6&~n0JMNO*Y;2qio-zvlTL)=_ z7daBF!SjAbBac%zKTIT`6<}ABgT&Fl(>Wwc`TLwhZy~maPzEZyR?tU!%Ld}PFFxeq z!lTvMcK#vcaXJq&vyIw~s2Nh3!!ovN-P+=IcfRBPn-|vyMkB`*LW|!!K)d((k8|pw z!L0wZahy?awV-8Lc814m5_v&hkEW^XOitAeZ@jZf9DJHW+Dxu#EnyO>ZPQ%)Gyw@h z{$KEij+p{RnuP+FmV$%xvc;L04e9@#3wZ?RQ8O{b&26TmF!r>I#<>8%hLkN|09P0N z0?^}Zp=#QQ#He38fd;OuRThC8MSqh*kS%xP9niZqjhG-V*|1hUC{=fAfjSH=0-}m? z<7PrkrivdRG^z$wuQ7m2bwRP3JJc3*pkrPyP_w&$_<_u0-jKt6Ch^!jgaBO)H4%iy zfX7bfsIbRNhk{qAhl;p#IKd<%m&A5*kp^*-p1Q|RbK(yPgfb;R(_h{j5vDB%*bAfc zmi1)%(_d$SfUWv|ACx0H4%HhUOu=?Kauv)Kt!Fi$pl}0t0*+gng*57O6dftZb7P;H zGUET>-f(?Y=jk04uAMS~nLmhw4DX)v=fvs{^EQt6(Rn~vs7rrJiQ27&OJ(G^u?W2r zg*&fUmJASFw=IkYN;~q+c(s)J(mS^8FpET%4JW@9aMi#wzvkXx^PH|lO(&rmx}{3Z zEI_TePke~PaX!K)m(R@HKkoiF^zZEHapOADLUCcArwg~9FXX#Ba-e~UNWBnx=cqxX zsev*(z`Fj@b2@3`H0yb-tqV3Y^Z((IFINtOlpTH2S80_IF;R>1Ey^kw|&sx zb~`%Toq?oT`&;l!1IoGsud+B4V!#h zd;GKQHMk`B)|0Fs1y}nI;<&&nY&Jzcw^en?uI?3 z|D|T0Cx7TD3utY|ZH}zF>imdNkw4w>KNC{_?9yTdc$)8M&quY?8NTPAd{>Y;1Kcom z`>vS5R0aBP(T^;Mk?$0=b3~&C0^*OessSDd$rsK1u~O|sTzeZhJ&;nx0qD)0gH7AE z-tuvOe|7a3>%v{pzKs`wwDn_z)MJHp-xfgQhrT6IzjJ*2*y!h)rh^`H00Ckux{+ty zDO3xu_M|IW6ku1bvxTWoc#d9A4tKb1l`YP?Mc*LYeUwB z_ZvqI6WFNGz9(@++yugun7M<1H~BM7OY9i8j9tW z6c#or%1Dh=SEr?)*HWJRI^y7c0>&VHY}nEQd1S_b-#nyyUSeD0l-V=S6|1*vy`@TD z&A>);p++WPR~XBQs{*_-%P5%#E|Rf9Wn+&s?eV)q-SNPClPj*qV>d^hf+@o)%d$SM z`d)#0j0qvdMwRU&s$~4ZzfI>kTFDzHHJ#9UPl(+o)c&LUe|4I^Qc zkS6JFk{%O28H!IDvot{=mf!RDs$XFyP0ZG=9#Dq)IvEfx znL08^xgS9`7wFhcX-KU;s(0rFj%Gmy(7T-BmYL4~v!8Mb;h)<+BA~z2khgR6tw~H8 z&dOxwgTq#ASO#|RX1?r0>8*I#^>Ex#zE#*YrDjN;eme?s6^b>pn;cig)SGk=c>}N> z68k}x^(2orTzs>dxQ0~h7(&X399Mj6-j22s`<#e_B;8R!6D~ANQwx@@wiTmi;hfROE-q7vn>5#D~mmu7e_+ zL?qDVYcBHo)@XHs5(Z!;uZ>=!YDy)rv0`E&n%EsyzvqJp$~N# z=~9oc%|f5)3iB3WhYHjyJcAe4RKt_KcEuWHFXGwiolKAS#kNlyzwA&CB1t|hLNU-o znfH|!7~XcO-GL^fa99=ivJYCh^$_z2aREa6&}jwzsZTraV6VvbjU*kS3|p3*v*mEf zi;f;E!j~hNXDMh=*!0Ujf{f%;Dk|lKe008{0)Fn?rrwdkhw1Cp{cFSYF%Wv>Z$z4N zP|g!|)3&uaPN4G$5`Y8!pv3+H4T(3({AcK0&ag)O64JmM#NEK_BJC3URp1`kWUQfA z0X2nR>JfrxU|J756z-@DIjA$!Z-g7f9Vn)$oEYr!*MA-zrdg??-e7LW%LX!5MT}nD z`hQ8%BGQ~{>2qSig`CZ{lE_pGW@7Q1$xlLlC&CYyZ7+sW?@Ih_D@V6&7&rUkW@6Zhs~_PX{k z04qNmI6Wird0L9*>mkW&GH{y1Gzc_vT~5@bU-hZ7KEpFV8=2Ca4|oWl5!)eMUjYEE zKEzF|MCelj8IeHb_(S-l_c$ivARi7j|AqtfRxk7(J)P;ul`=k@P+Kyny8GklH=^*9 z;5$;hxz>!>j)>FNpw-=SCUB*kN(X5f$iMa5<|PuYr2W+TWC|X^7AQx^BR3LM2%$ot z8>htDjh@^JtZyw&Wip*GAwk2~=CDPu=&M?Q?&)1y95^o3?U}&oq1z!H0<=(OtsxDu z_gvX!U~IU|Q)|`&&mDEhO3h^}5wGR4+c9##G|BAxVqtwG7c#t52{0i+eyCJqUs;K$ zEoinGb7lN}TxsUN(@ikdm6-*&+O7>4bNpNHh|w!NTzMl9m> z)U*K*#X${b2!}#mu%nY@Qw|o^93b^W9SS3QX&X}+zy{we1`X^%C%NZdCyFb-5V#*E z0b!bj@WkA{4)r?O?Tj^!qiph%0FI`?SFktZ?z=MXu{-a|KS>|OI-=;UvvW~Up_`Z^ zWentkKv2>k^wi|Q3v2|#zz%18)gU}0Ct1{EJQ~AQ zF$h7_K?zOmFmahv7V;pxiXVYqH=nE)r#ZOIm%YXdMTK8=Y^J`KEVjwHjL|NVQBa9| z_8QWtI?TX8+3*a|}_UTFN1 zd0)#E@yR{nG`C@K0LM>&bsGYWXK)Q~wKfZVOV#ksSjoLN2oGYefOk7ALa$zjR-rw( z-SXK^X!$T7{|}VZ-)Br0*dzbX@Xi!J9EI0r%Gy4wKk)%%^f)oLH&5r^ z4eNk>qhv26>*eH*4<#8GoHGf1r&+tkhj<`(o89`X|6+t2ZTyn|5l0lxF+AM*k|^~X zwD*wJG^O9#P}+UwZ0SH(Y}-?nmsZMmAb41r--=Be>vlSs11J?LK@rolQ^fp5(v9Kz zToDeb_VWW>O1e*`rmx#A2i2K2j>Afs^`M3}D9 z8h7$9jr7G#;(d2Ce7}@XX>7}{*~~BeU4$ug1bc#Dd&%IqObN)o*oieH67b*aPwb9+ zN|7htR{32)7ATfON+Z^>fssLUI|NNVVntAArw$(p^4a7q(ZLJrLPD}okZecrwis!LncRVr)KX4O ze%NnO?5S}PIf${~Ecj(>EpIu6ZiocJvdegnmA1S8X5!HrIGR70Ze7KZ*go}kk-O5Y z1-`+!oQ)X#9di6F_(#Qhd|c!hh@={jMqDZsdpz-D=5T++ptN-ssnPXWjcvUQZV?#Kod5u)Kw-r+WsM(V}{G1wFOy>lFz z6ltwLjkTRdu?Ggk=z*fXx(#!aLIMHbKZ~8LrUtndXMz*7x3^H!b6IwspL|?!Oa0S{ zjV^*~uvj-C6c7icc9niF8_4O89|kttfgqC+}_W_?ezcvxgZnG$~0JS#> z{MI%8cWg8rf5`b&aJbu z7Iwv``}e!ZI6>l3cX0Uby^$$X6&=WTP`PNcl#C}F8J?{*geC`Rp-0N-zG-fA2!!fH zLZ&TIyER=vtf`OFB5@3CgGong(=?Xv%B#Ro_>CYpS+EPG1<(-c`0Izh*=D+L5(n&j zoh&+6jCv69mqW6K=Z=>@?Jsv54uRJ%RC@5ut}GmA=&m-KwL@jjC4DG3i}=>ZC1*>E zJlsBUCFwe8ru;6nafcpDJ>uHzM9;8yirefG3(6pM7jDp&dc_|2V%w5`y{m*H0@{t-6B!63 zl!4WKhRu|TKm`$ew|@QbgfU>0=09N!aK$8VWjK?HHFcC zV!K2{{I?t(1bDIKgGf^Iy>E+r<`9+7y}&tcw+$K^}${;?ZR9>{Z~c0 z1VmF+cdk3tV{Ia^%ZP`$g|NM8-XO8P%%b$#Yo^1#zp7^$KjGOf$kk;@8;wZfZ&MFM zA(BB~1lF31*=l_EJ;J<5m>1x7l-9$ER=lFiXD;w2zSW&9yO`idGjlSbffLR>eio^TWgQj$FczLY%g?pXdvhlxjLj z?3?JAic`#du_e?IF&0J7GrYpOgdae%OQ#sWH&fUdj<=UL3oWG*`V4C{H13eJqg-}A z0J95(R{~`HHPWxvA~oia9J4A@Ke^|S!)W|!{JpNLOQQ|!B}-Qo{hnUb0{QD=-TOQe zl;zd?y1%kTAQ7o^=Q^Kfdf(BLf+Un0K3STHHHKqD0kWEwWHH&tCLbG}^O@D7RJRE@ z{sbI9C}n6Z>%S6??+NK+fHWAKALdxAf+Rp31vNr!bIr(X7l3d`6X_5W=@8%h0pL{L z$z4eG{5LVcG$(5>Mx_>IT6H3@=2S2@Adt36oX8$sTH%3jJN=Bz?uNX!Agn7=o|pzt zz5~UQ?gc|5yhs+670|aJX%!`Vw~T{0hi>0Etpt)eIh zgTmYg0yyopz)JTK5NyB@ixU%0InMDNC*@34KBscLXxQtQC2K}&iYT&iZY+bBnfHtlx6`MCzx;e%a_lF2P)}Cqa=jSjgD_Sqf9@ZY5S7xsD$Wk$op-xP?S0h!b$p1jQAj#hx%{mkS(+$IMjaH z2XkXG7!SAi4>>nw__Mq5aBOP=>*G+Q!wlWa4ow9$aB-Tz$>u{5IS_tJ0ZG!9AysE` z^m;{b@M~C85Pcom0k8Ux&j1*h>7NV_N}FXcmXiXp)=okdoN3cWb&|5w8G?fhl%Nfy zT41E3?>L>vsbc*gFrDTc#8CVIa#lp;wIS~yN^3?2&#f^O7o4=6gUKAl$ zR#+C_YK~l*xP|n^%|0^o0?hhIWVs&_d1*6+wr~b++>dp7vEAQE%SU%QAhhkA#96Y_s&xRQW*~iq;{`pu>5aWgnk8Dv7 z_WH@FLyH&pI8~KdggLH~?HJG&-5o#0onHL9t6V%0*W+R!3S z1Lqxtd*MBMMS`h|b<0@BB8VTBSnZ-z=+NCyHSd)vY|W6?`c>!`P*xwNx)`sIWce4I zJNGcBG9dkyK!$EH+i^vUgQ4(iFv1^l&CZ|ocwp9N=~Y3(E+5<1#Y6(ePd#f#_`$BL zuB;S3K2dJ2!@E4|M{52`^3Rb11@z2qz%9Iu)OCT!)FG)Gygg?49N3V*`rPTKyv-I- z$$jDibSt#<9s)R^LnGs+Yf5>_8cBcOT>ovx@`@fm3gu%U%n?FsZrUK$t=FbPvy^3n zNb#Ox#}$YY^B5h4-Ah6tUWB%ZIWuO-_uhdq*dxt0v1v}x5n!SQuZV8)lQ7RqtiXB9 zb8)x@MBhFyl*>***YP%JjV&ZWD*2ALBzB-70D|c&ZJ})spZTj(ZWG6}#uM!sV*S~2 zCq@`+%*2OKtcNFyIjPm7Lx@P7B<ln!b31|43j?R?Y9DYA*qPz+9@a`9K~_*oN0fa;%}&EhKIc7ITN8Kv+9cYk9<{~e zQyp%D2UM3stiTI|j z?=cCAio6?JsD*0kq%tu#~l&0~BhcYBH2Pj+d6agyVjg8HO3D4h&A9$ZT8NG{~cxAdk zkm3A}MR2o zpyAj2Z7IJRun~J}HoF$|>%I%+9ZNTxgfY#?%UO?QAlk6JqBb}GNW8}jSv8}4`9H06;aynIV)j?c@e5H& z1Yxb06X&xk9`e{KjLWJ4-AaPv!eUD~yav$|apBUYQTjj9U$jqI)O{uh?^jxpfD7Re zCc#@`A=~nfsI;fRIOd>U!*{GBU!^HhwQq_wW)YeI%nYxMg(~|q&iEC86QR-^^R$FM z$`)2F&y9Ejb~b{>sFWcHavF0r-;LHz1;lxD%8F$5HpDu}4lbQu(OJWpbh9aBGWt%5 zy2>A$nb0?+&){sl)x651@OAaCQ~i+(p)$wc_%XaNx#^k3wzD_3)UI3aRf%elI}YU@ z@I+v{Z9&Iw-8|-n^fzQJk6hGxcj%2eBvx;S~2DS5@hg{mWwq?JE8jGikyN>UfaVf1uW=i!teHw%@eNRr;(xmb6Q zZTtbs3PVYY`nMlRYRn=`@j#m3Xi!}kPTGDXQ*co}?nx;ffCp}OkN#D@Wffn)SYoT? zS!Qy{Lxk~RKJ_RP$&G@?nAh)6sV3O`|GU}zo)}t6if~37rj6kKwZQ;W-Pa1bQwx45 z8+!GQRPVX9@r0@dM8Mp4yj}4AgID|pah=C|ERG*v4m|i~2{7SbeX;HJE5^RKIlAL& z!y?3%NLN?{g_$WQGZ6Hr#Yd=?1W)(axBn4~K=-VKK?2wH8;Xv=JnrprZ)}9)b9vZb z$WZHJN(P>b%|)}j_c{3q1m%b8{}SH(!|Me)57(Ibt$^BM9FhLTt7aIVW1vd(XEnW_ zNP)JLGpMV_3GRn?MQe@BoHNg}(nTzSzyGgxUaWrCci@`lyt%G=PO;jXV}HtruH)N2 zLRb}94=HU#YDostB{dl`ZPW_|R`=gL)_n$!<_#P00_Gk^%bQ@n=G*HcU*C9TJ6pq` z$Ww5?{D^(@`0?7@P*Yvvv9baciVuLfu`~4tJ4|T1c5xgu7z*nWfaPh^=mYt@w*3^pj1;kDGg(+gwakX)f%OK9V zhwj&G%b#3kAGjs?SM;PJ{?en?_gRjj5I&(5$U1ywP-l4JC#ZrEdZ0c?I4ELZUEKmG z7EufRu7G^qr{b#xTyu+xTOX6*?c{ZdVi$+?$+Msk-0SF*Rq2s?9Fkf4Kb zQnd4dCzz-LqHX9|7S=J|6mazMKtC6z2!*@o0^ra2dSRX3_+TB-;vpM)HH4)JHyOD`!4AEIF^JP4xUVNPS&W0u{rD@1j#{i~3;q@o3np)g?9*Eu} z@jIMUKfvBpA*FcQ^&HmFd6s^AaTv8ZP(UW9wV+}R^0kzrXg;(WzOTCeH~A-yd}UnJ zAJU3)I#I=4)x0XbIe_rfxzVfxe!FzQjg}k1m7GWPLTg7U!Uv+TK^oi?S9AQSkA3LB z6a!$6pW1hb&s-EURlqUg66Uf)EW=BDq()C5yhA(fmK1dm`H7b5LK5mwDEFfeR1WlN z^ZiT@iFEV)?0S@CD!mX9>IlGxf+F@VQXYc}bi>OklT>AWq*z6*@w+15YD=^z9I@bKt-QGa9z3h>3e_7naz#&WzG z6E#|DU**;$@}Cq=F_9YZ|1CA3M~`AHobDWiP6P}YK|RDa0r9W3xUX#3J`D|gllTXJ zD+~Vdj^LPEp}}A|U=FUCWeJ><9hP*A2_7Zd`?e~v-bk!Jh;|ebIxkX2eyXq)aP7MY z@+8l0czMz+c`qz55fLBTvxdWY4L06hfB`lxI#7S2Wf!2|j22nS zpBD-Nm4C8cKKBBJfR@|S^ZI|O=xA8E-;4;*;4>WS(%^m+JlkO@_zzbFG2x~NNLnI3Os04~BbY{(we$&^) zvU3m@!2GOn%j^JpzVrVPUmo#d9tDJ{85#jPF@N^mQtYAsVZ?x~dd-MB98h543CN{o zA}%1Lt*UQ2*Nh?!hNVjVZ6e(QVo0vF9uY&tFZ(*11`JqzH1^`TPHw$~zQ!UH<>__N zgkCQEnoPgCNl}u4FZ+z!w~J^Os!d7Ub}!-s=8s(SvjpA1H|Rl9`~Jvyk2Hed=!4?4 zDv>ZR$Z^y8#XcqTVKLSrV$QG~vcwNjKEX>Y$4|9nftdU;%X-4Ww&Ve-op0L1Dqme- zQ<9)gs!vYY7a1!Fr{@A~fYOJ^x&lNU7p9r^p$^~B5%Ix=w#dal?2uzOqlCSH*_h1*iu_u^I*gytG<*Pe8wB?qck3Q{q;0PGA0%`AevC^u7-^J~65xF1! zsvmzT(8_Jq6>s>~@zNlIK#0%-sIAw^6yMm=vTD}><_9%7+s^&9V|NJ1@2~vgJbqxr z6u>gR>63b>IHgGJcwg-}s35bEIHrAfSpt1+CJXOJYyiR*O-yAzLXs(&B?S9q`KF>( zql}+RDt(L^5Jl28v#SwmnW~mJdiMt%PgPpd*T$Y28$5uzPCBM(L+R%H-^%enBSXM7 z{a175P@+k#ANo{_x!TB_he*ghk)qty>6T)~fgY-K6#;SQ=6p3>G!IEm2SG7gtnAkh^>%3KF#eYI&N?1*aVBc^U^tV& z*XpEdW}&mozHwGHo2t;xxvL{$>!E=Cd1k6D+>@_+T;h0@Z#|7P&^ug&Mr7-U%I_XE zp=dVz5Sc5jjwhbhxyX2sb(|C2{c+tZJnF<|L3QZ9{f&sEB7ur@G*K1LT#0nlwVgLW zU+0@*p-kUayDAkaPRHukWE z)^MV#!CZ}K63}eK;4KJtD_Wy9K8{lVT%!C}n;~R+AN1!7`um!Qntqgv>?$$j7}P@? zNOX&&-kCL~VK~Z-yd+{;kHx8-1GNIeoIPO?7-sUB{XD8(pb5hbopt3hrJpz~$-$@l zE)nJkJiTRlF4N5xpOqHs4`}UEMcBZu)D>#;axMiz^;8&AYD%aYD(jE*bPB=8T^Ww6 zfPn9ePMBpS31J@$K~`X9KU}ZRf&_U{Tu|S*NQHnBOUe#~{R94z;MWY3Tm?a(YC7tz zKxhJ0AKOvHJ6b~{DR~BADQ20kYJb-2JlP>5ZcP*qZLUnlNd*@|X6kyV8fp7lwSABm zan1E@0^JlxkMdD079WdwhMJ_*?eK{1t=Y2%giNGrtgvXo$b#o=>~uoE0AG5bK8HoN zx=~j57nIjgW2MZXJsIY=n;|^nx`=*{&45m9!7}GnPh`=r6t`^GMuLEq>1A;>bxn#` z2+T&UO_0^%DFfC9K5ZA{H%Z|o$k%vx*RHN&VMk;r&Dz}MIbLTS1}Zs_y{32cbg!gxK1wx)~4)wq&8gUKqAS2^iJiw9YgLk{Z-v(peKM^zgJp9)?jW}*8z0X zV1CEjH#RU|TbNtL!m3C_egX+OK8S8sK^`)38lc@5!>N>7RtF31H-S)9S;b0Sl%SFA zYu5gMR6tuuGvEFZsVUdBv5W^s*8KPwx3qpyP#(SRb0%dWE@p0ZA3O` z?Pt&a6*1_C_vx901wIK%aCMCR%?Cu~CRfIdbK27WX5^RvS+b)Js>QShBF2!V11FV{ zwhD#S3^=J7%eeZvgdWMr^KR(ecy{z2?qVI<&!EWqoKFm zFmoiW)AFDh^zMCp9{>U_b!l7JXgr2>`O+`6qx@}d+g#$U*}3jUvftuNs*%N1eLrKw zMy?xYPoEo815mY)nlqVdjgwuk2|L(>@^V~FdHtr8_6v&>;3XtKnb-*2Q_?1;rRz6T zw!oKzU~g&wDA#Qzj=UJvSp}Z5u6`J77{zuwql}w%H|Fmqg`k|hBDBOHBUkund4_p# z#I$R3DC`GT)m&}cFgq6_u9SFA6r{{BH(V&z5A#eH?<$#FU@`?UaDNb17$w{tl{SDb zYh!vSXZHnT*srY;zJ~E*~7PAW*Oe+<82O=;ZLRz!j@T+^Nb7aJMs;@ z^nzM9C_a072?G*NmD*9n^}?VP> z%D>xMrho@?DSZNR$J{#vz%5PP*icFz(bCsJ_-9+hwS`2cH!nK1Gt&N{B$V?Sc2S96 zfhEmM3wc6JK6|eV0!6cw40v&&Ioi6P*DJ@ZK{5(5ymSdgMMbTiVQuv)<1@UTb#O)) z(=RiG!!l3&^l}iM-*bhko=j|fy30@2y8!f7i^=F7TnxtExG?LZJa42ICt77~u7xBU4UoQ$9Djpm-C432z5ez z@5`6r9Up7{slO01_h5nRJuE>E?Pw_9iD3QN^)OMFgA^oS#bz(I?bjj?vw4Q|JD{7% zP)|O#ROoojCu?!>!<8EwihrLiN1g!P{nXEugT*ZZ*jIsNsuF=oVbMbWu;kk^ZKwJ@ z6X7LXiM8Jsl}#zJ9f{w$W)`egI66H`f1_E;rib*!Eoq96;#aH|v@C1QSDA}aqT%h% z%nHUe*V0w&#cy%o-T3XZ(MWr~YG|00au?6Pzh?-x;=gExjqo2@2ZX*n+bg{Gu~P1j zp2`gEd& zrU!fpooH)6+FMru#n~XyBO0%S`GPgY-*!71+ytzoZ|5R-??89V zzjXo8>AhpkEF8e+ldKoTwq3<(<;pU;x_)$hdUOKwKQ-2{&foJN6Y%gY`^w)O@bHhr z{ClN$WjZ`Soxx|Sc^-sy5f0`S%POTh<>;O2cv&BJ+MUqgSN(MlIodL_CH{RJK4n9qhgi-0VdP9Y5nrnUg5OA&kFUamW zl}|56+03ow_{rrDIP4O-H@>2-W;Ncieq?z+q3RD_5fh~?p~70BQutr3>i>QHS-@v` z%gD@IA3(9PPb{kjyRRuIyL+SsZ&&>8PAjn4wJLa?-r)vLu3Vjb5EmyNn};g3tDzu= zY_^qYp-8-Wn71+YEDg1=Iz-QAU`79IAmZOV?Sg(@qIM^P##Ba5tZS(GJ8pH~UwX&3 z9cGc6wbbLt-9YuSm^m8DH8%5k*Ht^(5Fy96fh78U%L~E`SAE)_L;0vlxWgN_fU|dj zQk`J`#D_?n9k2|g(Ly{o1>V@OCzsF6+}|;;7gi@-P?tg55ATNlojpB>{UA@Yey zTsuXO)e`zNuu!xMDz5GGyhjqh`)v{``O=}_6+A;Km}Q~uz}1BkL%MKPdfyO`JMQyA zQwL@@O~P~n%!UG1FggzNd6GtjceLNE=+PKasXni0YmCs%l}^Dh$ZWSFoEnb4Sjp`X z?vyz8h*D2yru^bgqt3+Z|0f4Pc(~K$H*4KoOg>ke>d!WA5ly{U6o1j}=xOkh=q`(d z#TM)k!8GO4kn}dgB5-X;K&Ej0&#f9zaC0GsnS>(8KRp0qU-x~S1;(38&P{Q&S{w%S zhNT<|hyNQ66g-YbUaF#{hv%5jdNsbc%sF@fu|SI1HKIUA{VP8C-H34p_$Cq z|6$~1@CEaK?$mlR1^*4~^|mwr+u7@wPukZe6oqYmR!!Cb&qM^)IzEEICxbL~z^xwx z03Ge%ljY>1Bw@kc%rq-76!}LULR++iQ(vB_=od)!2;E;JYZc_4Y%zS?uNsu9JHd!6 zbZ0E!=pRrFQxd<(qr)fQ{u6Nj8ApmfNES+hFvu9h8-3HYPZve|Z*3`;TC$KZ*qx2% zXh2xoBP09UR~YI?Z)D}gKDmr=gz)5`IR^E56bPL`1#NsR@X+LntMM4{HtLjm{;x+> z^B{mv)Lv_Y)woTR1XB6a9nmpSsh-$iCfx}lA_W&PA*ZzEZ2K{-J%?*87u!#;+4BLP z5IE?63^e>bakHwSwhNMt9rKzv+)n3QSXD=0U ze%GuW)!=hRh55)E;Nx=yn&An=xBdbp%>nMxvPm0}%75fw*FpGSAo24{@^8KUr)Or= z!$)uC&(4Javs}gO9(>{7EIFr_j}h^Y9-m1Z{aoxy33W~EXy7|+ad?}zS!j7qY>dH& zU~ROL80tDP`N`4i>G)w)O3Eot;ui1s{+QJhH~MirM_db4``(yUEse-PpYgf3NVp1c zX5oJ!kB5{C2CT0tU&)r27M26KYFkVf@7E(2Q4=)!7k>B8x(pM_`%!f{Goien5VMX> ztfN}JG1BD;>%oNe;145?%h7t{Nc{j{GI_LQSc`tI5PEn#QM_kIBIQQ69b*qEq#-v6iEsnPe>xEbpoqr7)k#9$;cWMiyEZc1A% zktZIrDogt73V|23lj%Csl@@B?A6y8ke(noM#g7kb`5)>ChJH`%AMYsmM~)Lkv3`3e zdwVZIfdC88l?yFd?6)N5qioYv784l5OFi!bLtl%TGMUaiS*JJFmr10b{!lL&iU&29 zdZ>s?&*d7QD|}r}G)WxSK(89)=tO({?WOV~eQ$qXlF=$x6{Yh$*yxKD&dQ+0?yfSK|| zV<`+;k~uRw?c&oYLSQbt;P~;kD)&6@&MNG!N_iDIi34WeU>xcib{e9au`R2-F6FrUPSSF);d!OJyw;(EwET zLwBzgNZ<{i%X69yJWLXvQeLB@h7Mo53H>99^;y_Lmw0m`>;q=`&_9n8TGB7{K4bgU ztksw+E>=!`P{Sq1Nl8Q-2ZScV&k@#%oS4ULE-e6f81zL#r(^W>PL$hR_~jbORweo? zw3&97SsQSZR%V|c-SZ%6JGcaBN(mt<g%D@FTfV<_HECH|2<>Fie??qj*-H=U|B8$&X=ku zhfUr(lY`{DBPi2GRB)t141b6h#&-(23stDuTr#T znhSK%fN4eP#jd;lT+!r&4x+FqI4IQpO-Lvm6iYY8 z(z6EmLfkk8n`A(80F=uEL=Xuy9R*(83}Z7YeZu>FYrxM-d@$QBJ~iO59&Ryr ztwi#%Agrybq|h~O(*x`Xv{|=cQ9z&E)QB)Z`3GSj;naAR zF(h2Id8~dahaQhxw3xxi+xy=uu}_$~%z87caWoRlltjpCvjlb*)`iHqgI37N!+{iw ziQzyBPvpgS4y4eSr|BHOBP=^4jyIXE-)C0%nEY~-Y5*|yTbjyO!EUfmgE?&{PxgwulioLlalfAgN2#)oWyhvY`cLp!GGUKH&n zaS#D%q=TiJyJ*iQmNsJT)R?sF#G~iWhqLLuY(pAO$2Hva$i+cJii8kO^hk~q)dmL+ zYU>d#*M`}oguRMwd6M0AhC}Tn;!R@-Y98G2fbXI%Dn*xrSn4&rA@Vr~u=yjRsYQeu z$@3Yu7LMifutw`A9C|wWC0`rvEWqiEtVru+#-$|ZAkQCh`2JxjIynVM+0O})o1nbI z4I&C4)q%_uDBQka`iR2agPu@tS6cD~wk$Rf$0Uv`1mweHZXYXX&BB!cC_WB31R|JU zUFqY34*CXd+k8;Kfrj3-Qf}3+a6AcL7Oi(0b?KtMp!Ep1-c@#`m*cKy*>6kjEy#q@ zd^X5^IzMGcxab6fZXxVoHR>uYt*xtjKhTco_(}mpjUcYL)OD2sA?<=2Ud8(3O3PN& ze9X0R7$>+kWXC{6_)tF&Zhu>T zN}5tsnJ=t*bHpuGy&LUjkgSlOqZBS4EK*ec(EbiT{Q%wmr|9okcJTZ7JJ=6-3ll(3 z{o)l65zqnreT)hdBSOU+%^!*7?d@#C^t&P!Ah05N8XpMcE&i&GiEP(Y!a8&Q=oS2U zlP7Vj(?<8@v2Ck{)^q3j+i*@!dmcyEj%rkw1J_vi9M>EB3)aQQo7Tk2k|t#3X7d_FjExZV05Y1AcUP8=*}BFC=T5z^K^G889ty-z z!Vdy;5GGR9Gnw7p;!*g%M%boIiWB($<-(+TI9foYSIGQyj=3aUsL6twT~V-&wn{Vm zk@Uv^Dgniopm7J6F5R8QvP^3RW<(->?DrJa}VEsMST4D&iIKoZT!UaPu@&^%2e!J9QdHK6oAe- zT=Q?Vm@c1Qdt^yY`}w6he;=2*RTL!p+T!g(KNcR4Hzl&9&N{+=Qs@5oa``%2D}}%% z49l&+rY)L!7JZ;1=U}Oznr@e{TJkY96XwYbkI~oxfMbv^w=(Q!rQ|Q>`JFy@&hb^2 zYR|BkYM;jy{a7$El$&ao^D zA19S8eG`t{AFJ5Z8v_ELVNib%By&LJ<3|tb@4k7)!;G$j_*BBxi&NVHJ#cJghG*U% zP{zO%a7T7f7@m4APUKCdP1s=8ckOe*B2`vilPS<3I*7ZQNf|&X%L2$keBm;aU*5qb zk0?%|Wkvm$8j**W{c%{60Y&-d9gKTSt*HHQmUS*91n;im~x#i`eJpql>HzMg66vZ{#U>x(is zSA>bo%DN?aXVOU)ImYaisu*>E1c@8 z@e=)`nHAZ^&iTc)4YE44aC7%Sii|dd2+8SLh1XcKb`f;bTZ?CH76UcpTzziB%k4m{H4lzw|vw_%L zIkN@WpLtbW~J|UR>UCWYsM}J!P=KL1NVar5MC^cFda5qei?mIw?P0rvYAIpmD+868Y zl;-3`BEvca;NAv7^)joE2nm33E%Y4G-}jvsWvtGR^p(tz9C}W^8}d3H7;T|ZEC<95 zMDpH3QAijtYR-K;JE>~djvcF}wl62NdnFJp$gz$jA{O)>3|wwQK0U+)!oa6HmI8E$+WW@Aid>d+b<>$#T$-)uHOeB za`5E)ve|y~wyn=iy*R19;|tAe%U&3rd|c^1&7qD-)x@6$hK=0t<$3RXWqRNB3 ze&Aq#0|UTvPWY^j$dc;nwG&PPBC3Fxy)b=i&_c-gt+#lQyzUV@&r2U0vN{}>eh zN0ndj*(Cq-DZoOw6SEN9eWUMHr4l$ZK^r%J^=w)f2s`fb6EN3IWgf*h!<^?1dj0{_ zV^i3#AJ_j*>Ud|sUh>2?KhODd-of_6yCTN_pE9yDgAxxm3qb;y?X=Rs|re$ zG8^mbd*YjfHg>XxhaI<3+rl-RdH2KtfPrOjfCm5J@qSAS9N97cXLpTN`mYV#BHIp? zb_{RpEZ1TlAq!SHnutyrtGUV%w;w))ujAaELO?zA`w^XU^sWhO&<^l}nGxuD_d@wIYeMk4ezN+&@TKS8aaV^q2A&P(9ngn6z}Cx(xUH#CFwgY96Bb9{|b!z(`~r{vTrcuRt91kZyhC9o_nT z*nF|t4@5f?3JJkI#ake;Egmn>{*rkMEx!>QUur~l_@ zss_pcq#;PClcJpBv`F&@vE)&kto>D`;Ww+CE2GU*BzF5!-oEt|@CByRbEsw>-H{=; zR=^rp*jc*4ll2-W%1a-pNm5DwE8k%J;cCD$D0 z2^HZTBa80C^5Z!NwRO*KcE|iNH0RvpiOk08>MvIPZZwtD2pO&%`Yo38P%!`NjN;4L zWSiLCkuFf#5GwO==FOd^bfCR1B~V?Yig3=fDQm(Qz)W{p!$OH@H2b0ZLJU|Hj-+&Xn@O%|5f?kiXnPJI zaYd#Oxw8VH%xbm_%|&;is(|fcd6`N7q8Y_ud(tO>q&y0g;Py*45b8S7AYi=g%Gn~Dd#nA)eZe~d3QE`6T&9qffwHZVscCPQIVFH-0LAdNB%Jy zq)5*5I{V!H1%wx*dnWZ&ktg93c8AdGC8%Q@9SW|;OmVSP9>=NHZkSDmV~)>zkL~3N zl;O$dl?*prM3oA_OPxXikL|uR z_;eLy3_~=XSX$I#Cfw}@&hut@QX{Ix!j}|X4f3umqzwjzf*Gm9**x;aW>jWE==r{( zGb0YPBl!gX(Dq z+fw@`vOloX(hVA8@8JD$HrD}`+f`>gz*5U%k2b1q9TJjpWaly7QCUlQjZZl_5>ojO zYV?;`Q4BQ8EyKyvVo~5c&-FY3A3^N;oELyHeyLqzd`q;B0|VFv^{plQQHAdw6TqCr zO;9pz-G#b~IF1$M^Xw`e{S;~gm!QOx{A;nUqc+&`-`Wu>AW;oRTzYfxZUE8Ju-9hT zYx8})Hve|P0Hf`-Fc}_ntO08w6s!2(?2ytV;m{@?x{y1>D2;#4Q&Dho-jh8G*{;;) z30W~L>qV4dE3tz_zN~_ET-z-ruSx_L)3(UkVFSYnoDA^(!mRZ}SMqdwpQx zHx%`%B-Ac~LeJ%6`4Sm~OJ|9CfcX#g+FOPk!fj#Er){qN@brHMYTsN}xg^!iYP=fI zxJ3yd^r2S@FR3?>-wAo&fYOwrbu;87bU9wT5$pb%>qh0wwKF4qFybRi7D+Z$03|-0 zg!XpgEG^dN!g?FzEm;LU$PW{5@&w#VTx*C?zK-#LLtHA9#X38sB$_ReT2d`SeHyYe z$YDf*#rw@D8UQJD^VnivW{O!2ky%L6yWfs3W~}{d=`$5wh(axQkHNXNR!`EAnr`Wm zxVnfBs#XDUh}M56yT+^rUl{mQpLPvcpl@`V&x{Yt-=4-Yu5NA=1{V_ln`-PLS8me# zOov;SQVH=?I`TRv8TDHBR?WGyoVQ50!y_JrJPeO`ur7V)5x-Dp%;cJvv+ReNmb2ov z6pxMfIIFD^v*lB--#}ekQDYib3!b#uXT~;eRCgt=UA9$uOe3PQFz%6OH-g9%tdewb zp1Ydiw4hBxf#GDrHm<`dvFC8;-9EBf#@uViTAI*u7F^_E_WcSvGha|DCRIB3PBgnT z+&Vg7vxy_a{yM;-)?jtKn@d3BqMp5eJ-3(&k+p)=Q+ocC@KTmc159>78^oy}BaAbo z?k||*1Xtr_wo1ACxK6HZM6vg{Aw$*;G{u!TOgM`BxbdR$n!ZtkT5;r%dPv~Tl2@QZ zAWK#Eyx4-?DLA##x!6|6H78CN>2_I z!6X|Qx92_L(q3@>C8o)Z{5v=ufe9gko&v6?_tb(=zrj&hNPzvJ=H|X}Z+lb^8Mrf^ zV=g4fD3-f^P*!tNL4T?HTi%3;x#fwsZ>y5Y@YKr;isGza z4ZQIQ_5s@q0fiNUZo)7QhM3lK1&|41M%h3+&B*8zl3@b#wT`UfxMnm5i>$scQp;Jis8}*p zNf?_XsUXb+UnZv6CFYNsrQao?*i73aVv5o^FQdD9ZsZ?*pMRB)K>|0+=VHfg=&QyF z$co6G$HEhFjPUY zpkasiO~Klvv~iwSAI+Rc$EPn?ByY)(8`A`B4V>9{e&iDJI+toUzE|b_Hu7;E%9-wK zy8Qd+J@D)ti_9w}Rr&?&!@3T#Q4Y6gJMb`ru^kbYVG7~!cB`6?3(FGNY<>0VF%d>RB;TS(YKh5(SkXe*+ zM=U%RO?{ZQ0Ms`tW@(qcpin<1E*_bDb7iO*@o;s(-2`sT@;j>k}f7D61fj-1hPHXPDL?GS*{sKjc;BapBNImrvZoy8E~xh_F3 zNo*zY0?NgKs}>m5d4Wm3uLJJ5up4P<2718sD?haJB%tJ{>^wdq8`~j@=OC&J-*c}N_P{N-Gw_gt-#jCl zCXt3|2VgkUMHg)p%2q`8*uc~6Eqd`F80LqNmU{&F_eslJ&U$wc{2VCwzH%2}LZ1%0oqjiUhvDpoS;9`tHi}{6v~dcVAJ@_J`Nb>Frq;-Fu3+PknQX1(`G;t^q{s zi8%aO{Nm2|>56R0mJ(E|1}R*mA&Ssdv0G1sQWZ#ZWftPCulRxM0wqbvD1<*hd8&2^ z%=Mvu-aqrt`fSZ0mGl-LkvQYOiY|FE&Um!-kh4ajDRb?dYr!7mg9u_)TH$7S2Cdm7 z9=8Fq9WY(D#rq%fi-^dG<#!)b&)%|Jrnb7ap}R8q^g~aD%wV4ebyh<}2(qaFNhi{d z7Jr_|)l8jjHPi5B5DhGtB8F4Wd9JY4_b(HVRKn3hA-vgJf`;R-f%2{h)~Ykp8)OA^ zK4xi)iL$<0{GOLAjQyJD{OYu4wB3cSt%W_E8!Z>XEgZIR9gPAY5t#$DnA9cjMhp_> zgeSot60{M-QzZuV(h@;+Kz4h{kT>x!{XIUcFg>L(Cg48o{k&F3ig)n3w6Jdy9j%@{ zFSYIXhC(RTp(W;aOKNjUaqATPmhn9jq9KnV#V!qjhH1;JK5*w7ai56*#hMgf#Ca*T zgc-H3CR_+wLgYY)nwz+Z+QWA(4l2Ghg=Iw|SXfL;oY2vTXw*G`*S@>C2q!h3KG6>$ zFt-6hCbcW^C~CR6P<#>A%olZ`-Wx2<9{55331Io+I<5Ry`X@PV5_87T`ci_<1{xEz zFkc#|bq!|-{6sPY{_dsTQj7ikj!L0YR-GX;dKL1@bp;%ddh2|O?JL`l1bU?L3(>Qp zYIT&2??d7Yz^AbPN;q|5BOZ)hNt4wS$u6Q(vJc==+ zVfHDwJw}{r-T@CoRbO2eu^b(D@r%`#rVv^E6qYX`^ftueyI;DWA5CtU#&_{jo6!Ex zoe5bI;erEkw;PxEJy0_J>zoq@FPUa&Bbp7g-i#i|s>UUP#xOiY??cKB5`{ttfNa^4 zY5Y7Q8WM=l*BMbL8|nIAjy_Nk=!n7CYI!!6Z-iyT6wH{7+baO@O{0e+lsQ10 zFgddZIoD-n^P}9LEeW5$3$|mkXaBM8O-~&AGx;iV6-O_txw#?bn=Lx4in|F)G10zG zb*BB#@%l&CX3ev454A0LDLR^ zS(?CRppX=82FsP5@w*2|{xz}N?y?SmUFAi;eqVvP5;tvGW*PDO5fErG<^^ynL@`=l zo>vkg>qsMwI>AIbxJlF?W0={Tf^+BU6&GB6GW~TO^*bHu&%KWCe}LJ8dFZaFjBnW- z=-=iOTXlglWpH25I_tSUIiFc-xb<%kECy&mN`wdGEQHr6=s>^SS0 zk_U5*QnY&|ZsbgAHc4rdS8g^L@d;tYMfw<2ZnRd;tI!D6Y~Gt0z%frt1J+8X&M& z6xSrkuU8H%8tBpB8kQL60ga%MD?cQ=oglv%gSm?~3)@FlnkxjIae(m7@0-xzu9lGR zQsJ&z2+fo__cQFLIF#}7yXE)|Bsdh+C@H(xeJ!|Z^+b9DZk&&~a|rzb}KB z)lCPPZaRA|SKpkbdTE?mLK)OZ8fh-ixDKg%^6AW5_t^mG^?A$k>poSpE*alDHnl6c zW#7KHr_O-WiU3FmIaOUzeCst;+f;UM7}ge!BV~SwoIH^H*|ej$8P2Q|ffBe>o%ABM z51j4?^RX%&-*y2jLCIa&>05$i(z<+BvpP;Em1f*-eEHqX!teO5kn&}@&J^=(6b9$a+J1%cS zrld8C_$Vg<$y^6*W;Mep1;Z%?@{3Tf`thd}pn;A?{G;|A1eq}_&l3*{=C+}X@ za8^OIwrDu30BjoTe*#$rktMVL;4y!qo>ZUC^1{GU2is*?Yu^hty2PWX^TG0A9=SLD zKs>Qw1gzc6v-40wiO8HLa3CG!JSTGGiCuc>h2Hag%o!$ffom_3rxIBq$X?<+LpYJ~ z4(Kr=6EL|-Rl50LIgOt%;a7NX2-a<&H%sp(we^gU9k* z7N7AI0Q`z|6f5jj07{LU$1*&R8yav*lU=L#k?vsd^CgmRJxkbYS;wkeC@4tKmn97G zbqs&shZv)=Mt2>@t+A9|$1%Lc-s3`MLyK2Qy(&pr$f3bO4G}rVAjOt!0y{RMw5~H9 z6@eP}_aNKWNLek<D8G%*u`kAVq0e)DoN4**h3`O&^oL^!9+^F-l*9r`T@GHNZGwXt+>R>i4Av^{h=B$RB;+L9*tPXzm_ z19(%X5(6Kvx;!J-U*4|8TJuFDGt+xU%(Uj*qU)p?a&gcGrmvV>m$NhQ>9j7SL-WMv zkTTVu2MzhG;C@Fi{Z=%6PJX;@)8>L_E7m0N)fS@jNep5;@)q7R+V(ty{8Z;Y zC`oCL6DBqfD4K;f7?U)QcJ3v5-r}@;66!*(qx(hSGcvb^>j$O&pK$EYgJ{$e#YUoN zbRJ?;FRkY|EQ}h(g?!O*vCD<0TwTd=KNp!5>-f?ps!zwv43Z*b|F8fUc@Unsfi&Ff z*ImcWCfpW|^(wY;?DYiqenB{dAw{IDO{)}vk7I4#GOUt^btC>2aPE(VMfW{(t0YY1 zU81SU`Qyyx*%b|x7z@BEyePd!&7fi?x4c6I3Zv z4s+~>3HpN6{Si2w!@NtRU;4wcSqng&?Yzn`0^tB zA?-nQc|KMX%LvW&bslj244gP=Mdk#EsyBWFY(S5(c{a{7-W=yQA#_6RlEQT>SB~q^ zF&?A}Z#kwS$6}6Ps&io6RF2tdxWrc0#zb~^@KO}vPGofR@Q-||-TekfVO5fI2jR-t z9c+zmevNox2zqzrM?J2``rYpj86MX|(*GZ7T-*4i;VG-w+kCqm{wd?Rpl4uK^);U3 zNX?+5>xZV#FSGuX>GOUcejob0U#Ii>taL!nG~0KrhX{$~8Za=l?K;p2aJPxZ$m$#g(Iq@;9eq=rHEP@<7e&5_6fjdSp)5b5);RT43+onclfi;i^ z)*qlUjA9#Ch5GmOP8@-L)2MqV2p>Iri_`vE=qyCOtpAdGI8uz>wD}Ej$~WkJ<&_PB z+iMFu&VJ?J+|F*9UUFqo#WqC017ZX`O1C4y7m2)f8^8V8u^r(llc#wxP=LOxqU3qT zmN6SaV>F`lC0NJZ?HJ*D_lj%;!iuAqv+i2*wtK%#BVVx-JaU6+2*1vFR?)SJ-S%<8w=zrU4j<9)s-aqA z8T2TC)fPY82aZTs8bl^;3Q4|_p7PK}T~shK`Xyi7Q`m#(FqAts)MnvWj>DH0R-(+m zzCvxJ-oP-_HtLv^*|5y|ml)M0lO16$fMvo_=W&hWg%F6M?79Kuf}Cgx=Ky>@|R6&0|d7Rp~`HZPc$A4a)Q46~NU5CQ4rc8Qokh zPSN|8s{dxwW#7MSeI9;}msOQD0Jv#~r zU@=OW#R+#>1;Tf;q<03a{(GSmG2D6PoN*7P;BpFLh$8;G?vNM@e_ zFONydvaG}{Lc%e|dxitVhq?ZrCp!WRb_fBZYFW<4wFB)vAVvNVxf7$dT`u2qU+zSJ zpZCxFgXB*5K|I30W9~$7)xXH-F$WyTbO%#n9;Y)pm&Xlx0c-l>qDkcTu)WtDBho8j zqbJun_Hpc#j+#6#lEoyA;w7Ou9#17tWMZO7HE6BYn1RspW=x zwh%Sz(7sFv=%-t~ih_KJEmG{=eXz5&mZLpUk?2HtFO;U^DhFIvgCvp5(r%ASZm*Cx z@bN1I#42FU3M|bfGgq?KrhG-Atqt;lyOC)%Hya#uJCYw0*Z|***ixk4MqfoJsm@aF zgo=4L;5k!yc?=)L#s&SMrfiiLPlF@H(y!X@O2FJ=5v`LOvaud(e530TsrlU!vAbCc zkP{(cnuvS)ou4&}qy~>e0gzxk8kq-!1PW%9`=fBlT;ZMve$dbeK&3F;nH)++P}vgt zFcGi^BOy*6c8(D!XBRp9)=pg>$MJEd+33+5jA&NZ?({3k@Dy-4zM_AgWlw^qTJ_>qw|zK=84px|d#pl--^ zhT|d!qG?^wITW>^48PwPd=3>$$&_N_N}^XrwCNz^7w9s0Dam%WGx8#rpfu{Qb?y!h z6c@;MVOtpOe6{#t#DnVdJiMSb(e4ac$TGKt?^93e`bd1C9qMRkcOQ6iP3zgjqm!bH zZ{#m4K5avLbTD1%-NnuXnR)g?!kovVkPjP`ueQ2o^a*#yrB1)^E;{jF`oH>c%P<_B zfriMf5WdT@N8xVBd5A+HAc0TQAo9Kf))}5E$>u=oq}nAHa^=@5qn@>Y#Bk?DaB&@9 zt`3$%_29)Piv2+A$3*$whXx=1_=r0X|Ms5*ti9mN|KqTBSXqT`BKgI-4DuTrWdt&U z8UYItJ%0KA_0#yK{M5Z!QPA#(vZkXJQW{VWJD@id0OXjB^*yfWdXm$A*<-;21w_V) zG60D~NjTv}l+Eqlvs6c&W!hD1*5*fcUf}U{;f0Xq=#z^dE4VZxS=3i#`?($h3=~7t ziBBfKkVwSAG(u$HwF!~ESHRRRbzhNEtqci7Ex}$@2oC5VWCPJ3MT^lRRjGY8A7+U` z?!5>le)F?<{2gf7M}fQX<;TC-VtF9ZAGR&xg03o+u@*g+^e9jOGzx)2eN1svPApyo zgns{RZ~j$VjGj@4JzkuM@I}q&T;P<2$1nk7;lCV)NU~7L%KF5f;}Fq?YN3Mxiq&W<(hNa z>n(G9Mu=!Y9S(N-T^jR$OO5Y(ypLBHWYwFkV7rIt@4SyaEkD>pV)elS-79%Z!HQfY zvt=N^zAr1!k+A5NXChg)CjMi|-@KNq8PG90rT-|b9XpVCbXsrd(deY3*p-*|@YBb| z0yZBz3g#N|M56n`)iL@6+#H5mLNKbHW8W?$gw+~>l0m|w|0YwI@}mD9_2xCUX2{rx zWDRip{ejc#06^A_zKgJCM{Ig1xP~q4)BpVG4-$1ZTF_s9R38m!#G75}$67^jVL~J1 zwOc;XB=+_6K`#38I7j-UrOC;sVV9TY+I#mq^ywxZn=3@1_`soqeFk4)v#{ybA(LNB zOm^ZS6!Jcl9Y80{dw>w|TWW0s_vL*xC+)c~jg+$H;=(wF*{&y5sz z%x1pa0B0d{t}ya9jk>`EhREv>l(1Eht^Fmvf8Zo;#0TFY`1OC$Y4C{FfA$aNNc;=f z{C2z(SQq4{Hs>XXj}z53@pLE+{#P`sBM}pj~&c)1Uj@*~XEYB9yyp$d`XG z`0W28JG9wL2!J#8)d867fbeACF7sfNo%jd+iKGK^wtM8}7Hn+)n&PfE`qqKyX9xC{ z_q_7X|I#!2>Dk|U(On;bPPh|d;Qi&pwD@76|FF=1Sm-}kzVJ4W{KI(x*#3KE_ZoA# z)Y4xN8Bl%WOD<_%^Ld7@$oM(pqumS;o17Ghr@jj9e7;bfmDoc z&{_)EVy$KNzVY<4yrvW@0Ce;?q&Z7ts0C-+Aq61NL;YuZesbQ;n_yQKKvXS&pSII~ z($)@uFUYWSGISg`7-R%U6P3r}bu!Hex^h*eCAE#{PYd{P-5hwE{hptb%M+JOQx<~T&|gVb=Hw;A+D631Wbzf=>walrP5wX6t49oF4NxyJX&RwySyg-+qN zE3kPVH?yjwz^kTVw|EuOtodKR#xO;4M$JFkm%=gF}0*GoO6xcJCoCWoJB3aAUD46B|sp9 z?1mynobXDJ`z8}}ygOaZ=~9Z?V{ue1ixG9~UVUyKmd|mVU{Mfz2s?;+W*@B5t!PgI zWjdBg&7vp2@jm^B(w7hl(*kt$XxHxOzhLve*Qd{>#^0%SN{#z;&QTJ3m(DU>V$Ve! zI|q_yF<^<+&}&5!5HnjD|lPyd$lh+Vv{O*Z5~QFR6+$rP--?* z!;maL4ZCu;x_`dB`+0`~Z3aLzBIaP~!(!^syp-}99kq|^7>WR|kC1Ca1g%-PvO>^W zBnNp&M>w1-tS1dS7TkTwF+Wz|&hczJCvz+xxoIG(ElqF-E=BPh5)j*)L zX*9!;7b|LAU;N(P&H#?_EyfjWAMAw?YR&BoQ3%Xo#gz!d&l6NChIr0HUEyI#@~|ZN zdr6W-m@y3_mWYh;#WrYQhlHF%jcS=`-?{L{Wdh7um;Qn0`SbX`NDt|;N` z<;=f)?cf`O z+1tZ3|6yke@^L|B{b@U*Co*X_V_LelKkhX9;hjw^4UVN_(Ke z=ILTr!ZW{O9~aahv?EPMq(>SI3V_Ur8p5fYP!xST^j)xA>CY`e!;nj)*45<6Us!cb!{IKTpsJgmo}tKxgblXI|lnYodzb(C!c#H%HT-+!jf97 z$xZSoeP^%?5s=0JxyPcbAmPrh@0degWx78qLs2Byr5I7w?1es&{p+T=Knt1%{2*O} zEE(AoJxR2le-wDY9;VcPk>0qs1%FD)=8@9k*~w+;okTrrKhe=+skZ;-j4 zgdaa%`$}HZZWrWszw`cDqa|q)84sp=DwObYq=J$o(}M$CW0xwv8Jkl3>&Ndu((zh>+ywvEj$2oj5vI*t3e$QVjunO+$+4 z85?9F$z{)TTjn&~!xvw{)%}O(H=-cEeL=~onhJ*T^qQmu|7)v-m2D}Jtsmw4iBqrb z06P(_U#{w?dAo9E`iZJls8Hs=FmvvxM!=ORn>MapnKZ80K0mt0>*wxfj|WuS|G zNY%Zbvpc^Xi8QvGG}EdyJagWEq!3o%7k@qaa(2Nhynn; zpya^f73GMtNj{5FVPZt{c%%6vvAn&VZJ7S;@PcGN&vo$!6C&NYg6^!u`@j?48bn&T z&QlV1HIa($gS0633j@6mR@D#f-tZe#%a`=#H}RXsX3d(VDM9K(@S9SP7JNI8z!P$i z-ULeU_}n>(pfcH>pW2{oUGD&u_DVPl7e*F9|9bm7PlM6)Ze{!Z=O3Mur$NeeL!e?J z#WfVQiy##O?!^G6<7Kg5pG4Lo)Gss$h(R_wU{a163Fqi{b zEv*QyOti0$2H;B4;pyp7-P41dNIuU?$%tJ#Rk`fo_i=BqANrqP`e}T0vwnw5{{{W4 zJ89H$DZNTQpt>C~1~0nm(2CK(`c|yDNA!I9+_}-_bNgJDbNeb^e=%}*3Y+{gKyF$p zf<1WaE}cWfwLZ?Y=vff`3E)`QlUar9&P-Q}f<&Db+}422T#!?@32xSn_1+odiFhEZ z&B>wTh?`yssagy- z_$ph=tZ2zj-xQN|Hlc>OZas4w*Lgj5@w#hUnSF?j?4jEeAaMrhzQGS>5z(3HD3*;@*Bn6&}Mk1!W@b8 zkpU=@#srejrMyVB>h328OdoeZW|gShcfYWB-s1|zeB6B;+FmGW*MU~0Iy#rrb0M{A zOPIs<%snFcFO>lb^^@>?hZi8{IwEE}P`XjuSsyz7_gyj{O6p!sltK+gtZFYJ`edKd z@ziF3kDNgeY9n}GZh~)}Xc74^Fn|gDXY7XvvX^D6K$#S765m9Q&0;w9Ar*=H&5$p& z$#6-ovT*argKyU&_`Yr4Ut|JGjZ)XI%9A_&+sA{anXZnUvFs5PZ$Lc<7= zo-cBsWE2q;aDrZ7rR>6EKQK8g2>rzs;neEOtrw8)sHEhPS)Fxe$T zn}%bm-mz#+XGftjzyGze_JNY?jd*|4#RsUr4+)+tU*DCh^J#Y=7vwJsDE7+FFS2y; zlIk1q8ZCm+x7!3R1>hlyZ*;(N@ za`ix;y-ZBqUQ&s68;Ig^ETX7#l_z=dfE+8D{9gK(2i1+CZ`u%y`fJgHmwfPZP2r@d?)P8qUj)s#PaS z5euH785FdSaNlNT83-^=p9`A7+6Id0A-^8(82x&Utu{Xd{#$fNpXxhaI<3+rl-Rc@Gej1|y$HHv1){BXx}b+34isO803Fbxf-M z7nl|bx<`IE;*J&{Y~o(L1gWTcXAQ=*34`|*RHRrVhYbSv=~O-5iaS4s9TLM9kztR_ zU^By;(db8G5~3$@-Afq#da3>|qUhSo(LR6og!lzE@lLzufEy*f#L4{jdqQA_B3ACA z_sdr7_k+-t_mRg>A@RE_A?AC$F0mHhHf-neHo^w}4*YC))NYS|R|fyuIr<@Yz~Ps{ zG%%rkelN+H>@f9Pf8LLudp+j5rDL*EvzrxT+c|Z8# z-4+K#sx7-pJK$%$orJ$dx54PrzS6 z2?SIK?#!|^3aPd$$B_G6u0GEn`sez$IOK^9{PHMh(-2hc0V&>MUW%6{(C{ADLGS<# z!f*1070QpwNKd3M6ohRqR~nz6rXwk?!JO4(K{aAz?go^aRp(Ac6*yN0) ze*p%-m@<9IH;mqXS-*%&jnT`!U=LlA|*qp-Km#{|&PMX;c+WakXX zCnFa1>_}NiSQoHJAp52OUzQ++Dl^;}{vJi@J!dAe1XU_11H;{fwy&}4a54f{q4qG< zAl_^vs5T;~x6uE{ik4`RTr z?Hu+P40{ZIDjowU@{;G4RECLe^I9&kP7whT4u}a^gz4?yHi0 zYBS6Lb{_)z3));zp6Z8O`{H}A&u?Kvkzp+-6~ zZvdRbk^z`EdmQ}FS%_|)13Hu_b-!DzsR@67wcK0h|lN)oOfl1`^4G`EaYe9Lw z3ewCyCj?-nh=fR=cu^~F;jw5d4LONWXv|34 z_&7q-kYF&Jsh;fv}@J2o>!m_G*p`F4l2vH_CMqT#Oe62O(JILP_-2*0x!CeT?eSqeZ%(Kfpi{ znfPu9iXT$nEI>Ls^;d;|GIUj3lZN2cLVZaPr4NcD3?arlg*CHu^pcU>mU8EsV zQ8FsJYo*)@fdNm#mqpsr2Py5F&jz_q=cnul7oA|xuo(jtX;*1!ZC%~_f%ZSg@)b(K zv2@2yiG%d$d$hRV#w+b!&d|8hvQ;%7bL}Uk?&lZ|Yw&g5RPo!mDFZ8vT;k1s(bCfG z<2)F~uuQJ?Ymv%31p<{3{!pmNcVC060c|M1l9r2an(O9RL7a-#nSq@fb{(&v|}BhFbL*+aOzj)%H#esHhHAIS*bjA#a0!sO3-~ zc!TJcqT;HooP!C|=7;zpjcUNr$Ssc+kmvc*qL!QG9TSp4%zVpZZu+)G!sEMWJ=?HB zrUBd}Qq1b#=DL;?PeoduMv416|IflL_1I~EvCJug4vA}>S0=KWNDB;pCsD3%{l zxPVa}Sa9#Rfgs*nx0m=0+Frgo1qvykE007gi${*ibgfhH?)mP!zs!t|vq;Y65qD1G zn$~2uAE~_2arQ26%7*(w3Iw++u;=fB`lDKC+3serpe=_b#Q3oM?dgKUF@69mYC+Db z;A@8}0Vm2)E9kaFlsEQBq_H}`xN%B!$G5FCidCKnhmw`-p67I~SGkrXc%or8Wo!x% zt|I|i3Fpt-QtpSK!grkYMujh3^}k4kFIeYAoe#9n5-=T&*}BHIf*+5^ zt}4+bECI(Z_m03V17bae`L@)yiD@#5Tm8?U55DIkNA4RB3iQmHdr0;` z+#e4n6q`1FV)`d5=b}kNl(1{8_r=0}Eu@)(w*B)7t(+)SV|2FT+_g1i_c(Z3j zwmudfkT=C!>;=PeE3j#crrw)F?C@aiy6?z_MlCYnZlE0Ye2aXxXS6Qk#`xYr{ zBR1ec1z<*Tu9zz>R&;YEqipwTF9Y|VVk?QoZZFR(=aJvU z`y<|k)s7`Q$A)KmN%Cy;j%=S~a2I=r?<<$__G1z+aP>$w*!9+dboqUS^SaJqmCz6a z_u4eR52YD)b?790(33`f>*y#K$2!|~9Zv`W~ zv|xPt-h1Hkb=vJ3jgKG$-IU@RyZu?l9r#uaV8#?Y_a&4&z7q@+R*Cx^YjOP(0_uceA>|>GbE@lVi^N)YaBSKbgt_hNUjl;fhKjJWlb;f&ivnB zX7ZtVXD2nyqlD%6m@c%I5>xW!IMEpp$)i0Pu4%w1q@49{_TdYGa0SW}uHcETN4x!S zkwx4@?cuvp6sBY!1IU+&!+I_>d1suc2Z5_Soi(UG^9l&>h8XA9F|5A?Uqo0c5_P_U zFj~3{EA2{)c9-8f#$Q>mY?hY*1&OaQDb>Hu9OWfBgZ;__oGt$h!^ow=`Gj*U%kn%+ zpMY6{W8KJklrHFsL5S@^nH%e|;h=#56?k~MjEs===^&+5q<~nF5c!oUC>zVCcpZfI zqdnqv$6?Dv4~qxc{3heW-7clNX7ssz3<34GZ>V*1t!`_eV)m z-sR>|uwIO`T*(IyJKe&ioe~bLGlLv|%g4J8Cj9#a4fJcfkB19E?{JY5Qqff{7V1%m z<^Z*j{%K@f_v9;HwtFFx0NQfgcYVL1KNGpZ~W ziydlPE_?WN)mzL%pL3At`itOS-=)X?kMwyXRGl+fJ?WT6YY!jH3qa`q0$!IMA_d$P zb704H%aD_s4I~MWSs0h%291Q=$+%@}3Km}Hk=5|rh$U~Nr$1gYsL(gf7y#`5djI-N zST5ZOIDo(agMJ0nD#kJ2f9Gl2w27H8B?lkw1-@tOvFOm}`gnts|Ioom0+fo-??brD z1AyLvQdI*3Vv_%Ply5L_uH-e(=sA$WOB~ ze)j;?x+Zqpq~^VBQ>h1^{G&=}DE==HV@8$?21$(Bvc~qQR$E?vG;sFZC3{OZ_t>AZ z!DQ5*4B<%sGOqNcKY+?(*g7z59k`=*99$!T_;EN~VK`l4I9_8|kUk(j_ZD$77_dUm zQ`z&P2Qb9QJCs=yg4e|iqUBLO0X_E){UywCClu!UhRJ-_*Qvk2{D+NRchBy3d%QeK zclz1>t4B{>CsnFbqjHsMNFhjQgn}bPIhW9z>Nm+k9pRol0){770Pjy1*j2l!nWG*s z102|^{%Ton%EIjS!H9y2Gyl_wg4qiz+mC3zS~6}xrSukkvES@RG7Uh){W#XyDQy>- zF89>3O(&wAYT|@;3iFTmL-+A|DJ0PeYSY~%v7|Ab`P2;R6Hzay;!s@;Ym1k^H%n{h zxjx}I)m-ueVA4p)R#^V7!0o{C2AaqW7G>f*KG_~?$_7<1%Phk;LGE>^5n}BuNh%wx z-Ydp@(j|6$BNeo&xlMD=z5LGIMi!C( zpS^RBYwEuLKZwd&r);$?ZK-6Pwaj&zT3f+#IqUk}n03lpzb&m?QsQ|U1Nk=AQiy>Nra8m+N)cbR89hY%(5X<3;lyzqQ z$3x8A$>p{r4s$a%ibM5r9Y0}aj7@vM4=#HG0}QUi)V*A0{($q%3c|4vcfLka&m(Ef zGoU(L5yf8xw79`qnUwx?3(tGEfCU{qc#C)&rv z4&)a1*QQ0ZPA4pvqDpsBP0)8h9VoxTo$}e3fC84E*KxMsBK~2=wO3*Wxbt6GTJSq&E`o>2^dIpk(D`57(fQx~ zQ27qO*Y12kd>^8v0Q?4fSO}5h9fhgoQY6pxc9xUj{UGfuRQDQ8-5MPe!5`QOviD(M zKwgIz{1Vpxay)ee*&-|`0#pHLj-V)QX>XdsFbzbg!@n+f^l&#d%+&(F2`JRrA^^>h zj%o1}l8=H8NGdjDDEmW|yPwrs5upk(w@4CeYzP(UtT^<1`t#90g~ATfw!Oa)?@}Yw zQyuBNxfh2FHyh-sv(>zaRnVcDMw%xF(sjP9fy2;pc0l%YA1A!;$H6iT?=Ht2(?Fbs zK+G24NP|&H=r9=sxGZ=+gwy%DBb;}gLN(q}=#0iilT2K^4iVdIs0aljQ9ev<5Xyn< z0PTkvPMaAS^nUDfhjtoVc?hO(& zn-$GA*dgP_=qRQD=8E2RA#^Zq|Dyl!E`dlL>`JUncANq264Jj0tP7*HI^$7w9R9Ek zKo&Kl&Wy&}C22*(e-t?<`2*EY+RZNFLojY`=TS#6rFL5lZp@6j)m$$`H&7&IIah{Q zT0rw=*B8fPaK04vF$%}YBt zP@^l79ns8mI*zt~n$k)U7r+5BHB(%hE2=toZjY~RFXp6b2liqb1prc;>khc0OAZST zA=}d6#Df3%!Ts>ye)zlY2OrVhk>=k5PX-zqFHtCy`qJJ|lrJlCTrnVtp*KuDGRsro znToZbrY7c85cCPD#CL(~=05`7Cn@!Xzz2mhGbo%WLdVlS#-VEY?9x5%r!C;3v~5T2 zH-f;63I(=i9s4+vMaEj*l?}}D^<5a)62<6sF;!8_PHRNchP36&EoPoMN6?&PxtMiz zXhlu?{=}t)aPZz&JcXW78=uZa^MVHfxH?X7nCb=#7Dj6-LGfL`9MZXAY6@T6??GR` zuB5+N#%w2<8cfo7xKO4LF4N^o`U)j5=jfp>NIK0Jd%{ZX0qfwCzP?p_>Y^;wi8WsK z8O^g7pVzFT0Yal}+TjZ{#>t31gllv0tbRbST6-b20W(e|l6y=i392_&1V3qT%q3_ z6&_O&8a%&4l=$*AbkR&OS}W?mVu34Dz^As!QauD>2-9J8zusXwiBvlo*uct`MzMb} zi8-5=V2;<6P9%$c*5$FN6x*VYt2H3bD1(lAVD7~gkXxqh!X4J5$Gin(iWU~)s+cMc z{TYu%E|LKL*@?FOa&|lEFcU%#Z$HMsQt-IeI$LM|4Qbvgv%krueybIXwoL$#YH*dD zu~fbdSy`vuX|Z_7SJ4q~2E$jy`e|n__2!G$;W&4>OM40#RdXUsDyIqWDj??zn}g_ZleM2?L{cu<50B&QLCsk zeA~>~6le=->Pubp&o0TWLT^vU@O+4p_3LzKAHu@=fkBbnMfVvUpkSlW5=Um=P9iNH zNt>5MSZj#td8+PcNvrf(Aa*m3sSyK-7n2;Gl0B9s*F#!3CbIiWNbQBKzL;qnqD5io zI2MoZVDWVSqj+h|kV9DDV*N&a6YY!aAk~n&X4^a%#Kw(I zp{ZS3MBejRib+uNg@_$>kVaKj&PkcOUfVZ&2ttAXa8UXRQ3?NhY4HcE9?;_d9cb}h zAz>k37Hp`$c=72v5^IzEld19ELzx8!eTC)0DJ!yTkcr|kFPDj;`I$lY0;m0fd*OjY zht=~%R4{G&dmTFediO$D84}SL4^8pgz500UnUiyTE!HW6TC+T6`5+#p<0j8|gkRLX zab^ds5xLaE(g+A=8x}-ogDRkGdSJ>VRrhFNHDDfGKe49OmGj4eo0s`8V^LPjr1$3a z#yqFe{8(B#L3m?%pb5$CbOZBb5WQLai?y@U20`;J5b&cL$CcZ2Y zxRH<`Ix!@r=ZSBRUQA8}?c1aJI)D6U>n+M1a_5&^!^kfKg7VR-e6QbTRSl`~-(OM! zWxuPj$!!3U7{@oCkzZ&SSjAy?LD)$}bTWYevo6lR*G6$dR@MHhm)AQh=2=VJ=;?)Z z)7Q040F`_&-mA75v6MzNep5OQd~~xA!LfMQWq=OqF9tc_RDT9y&D0K{KPnoU% z>imnz!$yGrgZUTLEB>DRi?&~{hl)LzFxt`5YN7JVbhH6N_|S?;E3d5JGqrL<7d}vg z0zfAO+Hc3enBpXZd47wO{foR)f*W$BU8f?$1|DZ-#F2og?btB+P)Kq0V3*9y*?OmC z$o||F()l8n{h7Pu08NND{gq~Z|0te1aNhxspG3fa@6P-nVU8+Kwy8`YsZs#}H_Q-D z>Z(yv7J~>Tm`O~uy_7j?-pWQDSp6A9UOsy4=2Ez217|nfiuWQ-hh?Yg4nQai+W_2` zoIvU)T5C&2EQ`M1%?$^*4k&#FIW2tWh3SDwbAMlQ-p2#AKTeQMqmjRQ{uO^3_CQl5 zR4~&9)6A17(@5qLoFnBqm%1h0Q?Vj6G%G5t=ddPZQ=9^286cCA@WlAX1Lnq`0K6wi zP6Uk-4rEk@*+Pkq1Q)<2TW4L#HN5G^YA{;~$D!msQ{3kHhe-#k;Anw>I4EY2sU)xC z1)j;3Y}ilQcGy4nRd$DBD^AX7P!zEM%WaPgx4hb@gOY86u0**0MB}ZcVe~P9H&kT* zN{zk*{~)A2Gh=L`g5~Uzp~~flYKbBfG~)Q9es25?Nr%!QCE?KM7yvl4zr=crc<|p> zAD=&cpzEgUm6rRQrl-8%G@*+g&!!P{bj^*`vmmC#&&&OF{*g6J|5`rl?n)Ou`M0=M zH|7cC_qYwcKW2@MRA}TnT;&wB{x2MJ&W3vTmWN-R zqdiK>joDoWw}Aa4zlW!p!W6QYG!B*6+$KWQ^HSKFTuu76nWtP`Z^g6$}R7OF0~ z^+cw`9yv=|%d_so20{sYCdtMTaAH4_N`A!s6Y3mLt~;M$c*V@N8b7gZmnLLEYJ1MQ zVkkSJe6KC54i>E$G*zbiWU(THaOnxPB{XtU`G*W+P@yOE;jFl?W``U62lq zLzC;B<41aXJe}zseeU18&Gp{HxhLS+n> zM;@NQJ*5`9TssRRbR`gd$Lf8RU73N*U$Q{*dU5QEVS`5!J4`cLwRM^`%_FCLLvg3K zi|xMz>lH3O{jQ2`?wl6iH8bk0W-8`LOq_+{(OeA)K%zZ#W9jOdjXL!Cb*6QE{quya z5}C7pGwy7@@>-T+z?1YCc>Q-ejY z)_)0RUAgm;oN41A{@ap>UU7c0W&H0Gj~&rFuQ;X%omd!c#k=Ieg^zQrmvj?Lt3yk# zF3H|li9&yCm%8>0s8ilpA2&PAgI58H$U&|ndZDfi-?CrMK$KzzGV7ZD7Kz>7inaBl zg<-a%y#Y7CMMZUQM7+ol-Dn^;R=wP)dli-?&^fM_+)l&oP~cBOO%L>eW?zD=uKV%v zVVktQ%Y?8;uEo$L4qg3b8@OJlOxa)XF~S5&E*=-)_5LE=O9e538=H{V2kpZkAiCcr zQfUBG6f!u!7SYoWr}|(}MC+5K?;(|XQJ?#d1;ESawhvk*ql_Le9Q7dA;6biIG4M%b zo(6uD==@yaxs_u7BVJ`&12@oVrMfKoTPrB8XoCifu>lbPC|&f(h?Nhp|G)JA-E}T| zRh@Km(ocpN!=k@bJ?qUk9ppfasd1AtYo})8Dr*aJB`h4u3Scxt83Xa@NF`who~Tj9 zocHUav^yfYN+5-s(dJ6Js}?@=-cUAz9kf_?j0iuuG*6`(GA{W1uv{oS5eBjn|8qkU z`W;s+U|oWg0_l&eNXz1KLxf4ev>=^E_ME*;{BbZ4p^-oG9g=X}Z7Aw|FFk(nliTjT z%xV4Tk1le4`r7=|bECD6_pnjSzJi~Kf04VKsZBrm5_D- z?-~uLYT#HKpP9XPeCf4BNgWz<2K*WXLQ=2l%pbtwpZ=;u*E~t*)bdTu9DS$rc|^75 z9vFV{r00eQ=m-dQI6iLVSmkY`)>1#6Sf#$`QQoyq_uwQjkDBD8(%zm=F=LlT8xoRJHEPElVe+79l9zF} zdi(6qv%{5dFwT{M@O=_?p8cM$i#2l}%+}xaxN?c#%*3C8BOWWSG^ajYxgFnCq76#} zjgXBuJ0@Q}oqeu;!_z^`)<0Gy9kOM*{^XuqI%U|&fS*b_1Pvd*7k1acrupupkI~e{ zqXWWG;brQg-m9m9UbKbnIMtCFKEU5It1_t#`|TO@ehbi_>?4|xS(%CPe*_Jb1-M&! z*&0_Wg3nH5e;DreZT+#U;Ct7m;F4?S1v~3pf7zjC4-`r?QuY)mtKYNjWgX4Tm zN9D_?A9HL+oLnnX_4Cc!I3=<9b~RN1!Ww~aM^wB#l9>*DINA`Z>JRN&yJIk?vL7gG zVkEDhX~*hEe3;T7j6M|!Pi-?S$NKV=CZjTg0++%`j^!<$12q4GlaraVbFlI9k4h0h z@FbLdeyy^!?zQIjS@HcrczZC>Zd7&!DCxbzd+Y$Hb94?rh}xgeD{a2n&WeV`GRZ@; zQ6o~>wgX2h(|%KTX3OA+%TXZmKB5hW?8E{53{ow7O#uHDW4_LQ5!jGdd8weK7N0H@ znNjPpg)O|fp=s&X-RuvL8R84g2ccj#xbibM?-@US%!{#V$h9{<#&h~aN!r%tMiJw^ z8o{K%GhDz>7{O+TY2gTAX^!hYG!vImnGmYdoC&4pvPuVH6s?sJ27}7Wjj%Q4VvUZ0 z3NA&{Gtc%vX$6oJszWKE0?enU$Z630hk^mT zQfYgQv`phgK4PVM31QnP;dqT~vl{&qL{+9aD=ZC!vDcN?dB1!Bh+1G7HExfZVv!>5 zgi1!3S~>KTn1%ok0($pp1@$QGx>>9)&d=ksv*lLQ7N};S zx8+yq*@s99L1v*zW)9R*M;mn>7wHC;d9-iyJ^B zf%K1{&6HTJDK)+M*aRnHV~;vB1}}FR2;Y?s@t!-Y1YLLXxO;hjs|4Y@$)%Ekgi%L8`s2Z3U~*r5Lz25 zZ`MMN<(lp%-LC6t0w-3I%(Siyp=&Tm8oAmnfuK;j6Eyu93NkYc9xEXs??@VgnHzxbdpoctAJG0IUpX~U&-~z5VpN>~xY%BrTJ%3o8&!?v*U7OJmR&Ma^sRaEx)D58;2cUwj>m z3o>UbNdOM!iTl9+OS|%uUGp@00z&=J%HQc@kV*rQKi z&1}k(#=2hV@f{={;vH^ykk?=EX-rdnP?IY?98x?v%=uBUPnWjj8yYPV9M?Dl9RwAF z&*(;m2xJ>w4Kwqhx{2$G45pBmXP5L|O?IVkEt*_JT}?(p_vWQgx1}A(^3f=)dAY1m zL`OMmmxUe`rn~8Yi(X@Fsx21lTuB~IZkMd z*|&4(0u<VF->~NltZha*ZFcxuBt4Z97`}`j z)Quh0Jl5!!MsR_%E=yW}!g+@8JO%>y<6&i^Jvu>QS_lC-uWL{ULCnzX;%&J`fyb-o zvJD#}G!0Ot4}F%dkUB3SUY7jrau28Pf=`%vra%Pth#I8qNjS|!Dp|F%KS1)=DsUCC z8|Ud*^cXIdS=N?$IK~9ehnRh+f%*ah#W8z1fnSJD0py<_ZoMI8KIF1Zq~rMou2G)E zVcr67r>BgP)78n2eLUOr?Ff<1{8{Qem~@Egld`SQn4>mx15vP97{keC;6kmfi?t-+ zPQUM$f^wSnV4*nXA;Dxvm+2mxN_OSHk!9vy2hHGa?n_p9m%k8gcd8t_msVYCUHx?K z@%~+EJSW=O3JKJ1asu}8%okj2QAvF!ZfXL52Tjtw!IIO_;t!%zfgjastrwxt0a)e{ zw$r%2fM+OI32!wG$-EuN_>nGUZ&-!s5XeUq-u+OaxI>Nq4(o-zWQ117cFshWV*Q~Z z2)K)kxsC6*%o+HIkGDFT2i`X$-AGl=%bDVq3`KQ7so{AVR`C}L@tP)MY^n@zz8%)7aPo<-8fP}4L)G9bvd6(zjqBeQku%p2tT z+d4L%=VWxuk@Bq_TxXxI@R;~~uA=K@b+)J-V&Rbn3DN~kA4BTD)DE z6fg6-R=_usu*j4PsyW$9iy(Aw%o!?wA*tSNDuVmm2(hrp;o&?u&#Ro0tXn~%TWRsh z{g;p`g0#=VlHqDV^KF)trG-ZK})*3m~T7L&KOj$%mo>}RZjnv1E~Z| zh9K1%>;x)m&fvKD1-A~C0&&qC!{4&Vj&Sle>e};_9k+P4dXm3{LRk-q`Qdh;RNhAV zHrOTkq$9#D8ig9_F*E{Em1!1ROr>6-u5W|*hE9++YN9n3IVD;in=yfY=^?~e&} zVe2_;d8mR4V8G3KEr6)cQ=Wf5e7}ER+XssLJgM+TwQeArZ=wjJ8WH?FPZ&w{xuV)M zqOS@YGQl9%K=M#)F5$Dm8cZJ1xsY66)BWaUK;Fe$9t#xr)zyLv?k*`lTvJ=J1?iEq zYhZFN0l;(6;&nb;`-@U9i)D)ICtB-?401f=V>zGk%R*|JHMNDm%dSM;0{!1A!)|9v z7(cROZN%Dw*yML_#adwAd!nWN*zz)Hj;2Aj;=FlXWhf3&g7RdF?iIYdRP>n$cmYKI zr2b7oTMAPf)NO0+`*_afEr`8P1d@R*%bw5`_lAu?#)Ax1^-1F5*tDhvEytTJ1;Q8! zNJO6q!L`>#&D?n_!^%c~8?B=2d~NMG;h>4((?z?wOt4G;Sqp?={=Nlx<2?IYyta{F z=94*@;Rr#BY}$g9tSAUI_4*JLIKxhZ%?-z`hl)EZ07X8&xo0hJM`1@z1QReq?2Q9w zV}{pl$JKe6Q1ETBZC|Su{I?b4zUkbr5EVYdV5$D?&*5QtG4%KZ%;9`xw!B4dh zCI!s-TFW@wQJwSS3m4Z|+ZYlOdl9XlhJ4${AVlD9*VIh*{40_wCZ@Yfs_^mpA55z7 zf;0u=swhSB)4BP1$o#P$o)rHENfrLpqf#GQ;Qk*78()?hzBw*jK+evbHZ4EGHl1WD zw)eX>pNIm007G?d4K|+=Y(wriF!qd?0`B%KALI?-*8k&q1B1~t?6H5cljDJY|BjR6 zpRC^>61%WJxLY{MOv?#Q>&T6;TX;_Jjr2ny4{i6K;g})yJc&^1ib#)2b)-3P>BQt@uyNLJ_)Rs%j6{KzD*)L!WxcFXt!~+C?=1;VJsmCS*~@1y!0H%bEC|>;a0cGs<2A5McCUM1Cw4T&S}Z!#Sya@uheMDE z-}apR>*4}02zZLutcp?^QK462_Gb|x4dq`ZLu_LD(uK1==t`&+l%Z@M6z-!aF0d6v zNrGF}Hn(od9{3_O0tg*vY6sAM1T|KG0luNWp|rd=tYd*d1iYWM$2;DTrhJPUd>GZ*#wbZ10T87kfI@ zVTOlPEfccLaUY-ex#F1p`rz`BF)BP-F<_waNI|2{;|B#^rtjYhZUCAdxlF59hFibO z?y#Ql$1i0lYDyI6ke?GR6Q6wO_F0EVKL9dvz|JzV(X^6p?*YaQZUY}lq%_sE6`q*Q z+S*()4vZOIznpo^+!Uawe;xv+-3K_N2d7m%lk^Se5b9+NuQ2I4`YBx776*UGC0eTNN9O$`=q44H* zAR=In>xe#K9<48F?K%7uPuEu;h7|GoL-)NwuF6U(l2f5Re$wS~Y?m@CXC`$XoC;X2 zrI$;T>HrM3`9$9&rQqPLS$=1=P0iGzbx8WI13(5i%of-6iPBe{uP7?xp^$>Aq2)kz}b$|^SN-OYh zQA@g`B)!3m^E9FNp_J6;DtkWW*h)~xc#eTL$2~E~-cONiTLzX_*l7Cv_EfcT?odd9 zSNRKpfxiIWVe7AlRq{VQErx6aDE>^Zpb;Q)vna3k=PFHOebe&F!n64U+#yH9Fx@}p zv+os-@I6jLw8HC6uRC(cZWJDY^!CG2{D_Jbd(wkbtNkcMcxJd~As!LCtx&E{NH{Iq zWNk`oJxtQOnkk>=L--7sYI{cN_|L&-M*lL({BUn11G{4#(ckQsD(5!V*Y_nfiLLR% zE&-lnWzvJYcnj_m?co2r5dj!efAWwpN9{bpyPJ*i@Syk-S7z~xE&h0K;^1-)X+pfw z&Bk*cmk-X)=zd}!y|XMBy0=DYVA;ewkm6y*{k?x<)puARV_3|CC2jegBH)l<|K68J zKhW<#FfcrDa15fG-QI-{EG+*j3kwsJGD=OKx|r`=${9@Qb10O zIZ2OvHjMFjeb3kJ%wr}zn62I3BZH40Ht{Z`J@dr(1oppOwPjd_A2rV(9(5DpwW98h;Av zpgS`BKf2WR*)^#zyHP1uAdz}RcMh?is`ft}omQRcxGlvq^W~-QjiuMKD+vc!_}}6U z_+aKLp7Nb5wrB?u*7F^=IP6C<`{(svX~_O)NjGrl10)dEW!X`ZKkz3SCC>>YMwQd1 z!WVqpf>q0z>l_x`t(T!umG%wn9&e~pNbqD&)TjhMVmfPRt&<5Rg^FIGy)NqWS z@$40qnUy^YB`vuUdzJr=C)w8#9M^$jMzMjpyqB^zIZHr0MjHwx z<*;p4Ns`oW#h-8$GJq-a35T_Fw?E=UO8ddAf_k3mRp-JN={X$7K2Sv+53QVsq5}@F zFO|O_Y0SXQz*3LsorHZ@C9zSs8Of=&XN`?Jh#Te2t#R?}WAWW52Z1+lvHva^07!g{ zTMOyN>4BT7D#e#eIDH&(bte7$#7l$5NZ)@zOhLlgk;w!8)gKr$vu(B*vTqiTUa0Ju zZjVZa=A#HCeElGh54b~M*Yc_2$grOMQtD#?R);wba;eX1_YAEov59x1E8jvDMl*s- zwM=eq-{*2>0N!+>9>i5&Bls$~SwN9TP*mxqxgZE1R?O$`_kmwxzg7$TGbbXK0uCZC zQ+A0;7FG<_1M@{e<7VCPuPb}MCsBXt7jxQyPmJpD@YbPD_@r|@K0LUtZ0JHkj!D8i#l;Xa=sI^FIL3a*l+?j zL3u&MIFI<~RCZ&E+M24VN!SfZ2H|$t`$-`P z-b6Y(_Cm^BvmuUbf!N0vRNW2A?pzs^tbns`Dj`%^@dA2g3#yW#lQrVZNPXR<1AJ$0 zf{!cqw*!iJ9UJI77X^?46(0M^T2+b{&WT+V=KL(N5a-Q=u zKDApueLF=XX4@#+L3dP1@Apl5z?~U5+Y44OUn&y%(bZiloHddLjp=SF^Y-@wM44aDqfC7!gV$#GSVL<$M?qDf>a#hV;|G;6^i4_a?P$oCIpErcq}`nC=pG zBQO*~F39R6lt7|DbxQhvx12kpjRZt9sCGQo9HRGlVTjF5&5?e?jyI;5`O*{quh7N3+)-l9rg=$#&0xK&Vm9UY0Re zqMTQu+Qn!=zK;aGI0g9pQkBgD#m*@UFvE1hfG9V4H}xJA+XgRB6#TYRh*EaAnnL75 z$Qcj^csho+=R-{DvY^$b1*J6b3~$Bnq|j7r&cWKNU|GSuejR-av^=_*8s6;5oUq1t z2n0{eZ`+XY5rcf9l~3nlkOyyb6O#}yFOx>Xv+rkrSc7@cb@zC%F0^?gi4`pAK)yLK zkohKSOR_bt{XRJd|9UEVNoi$(SS1x*1%@APO2cDb2m8sY!Ceh@BlTrhnpDVQsibc! zdgi*}zUP-f=0puA4XdyQA0&K0E;Mwl%fv zH&*smp}0IMsUC$GUF~!sJb}uuob2fs_c_D|$!RjvH69fNt2DXo=iH0;F?x8srO%`+ zCI%+q&l-?Y5+!9p3EUI%e{xopN3Fl-N#l&ngO$hZY0@~_l4_8ROH8gX-*AG`a{4S2S`yLurFz66x;mL%Pm^?t3}SHB-(Q@Q!kpQ zk~E9dUgUroGsF;#zo+Ph(NpA^+Vk|ip9TGI^X)WAdvfQFKwAz;HN4pd&(2}BXyu*i zH8^&=@LIu*rMss@YeLqp<(D!6iZ-;pMp0{5%k-;sDbQc$*a0DjRwf@9(}JS<*Vm)R*YW+me7iPE0c~x} zxR)?iREGNm*dQWX4zY8QfbgVY^0jiO1^xo}Y!d(yo&4=8bD_wZ8xNWDGW#VGY&+Ro zCX23Diuzm64Lq-8mLmgk5y_<+Ik(1GA&@z%Yz4=*jBlLCcfO7><%FT1G}UBeXQ5Z|{U zuRNX|q81Sb6zP59dMSFX^;4+;F)H4kkuL3|#YbAQLiNjm6ow zywl6K<}7_abM2ZdTWET^*18b0X3Rt8ij8gU7B17r5%otq_2`BzttlZ|5eiT-IBrtT z&5p0@J?r>OWRnv)WKgqTjNnA)Rg8NtL7>;rC`?IrN&4+4=~+DMUYMX+{bHSEB6v^- z>ptwO5$tJYPVI(`MNd_(N=(z3$=i?NP<<#^)IT+%KU`jHX`jxaKh-(+%ThX`#Yrtd z2~_Yb9UL*Jb^-6mI(CtLZvh)LkU|sj*snD=dvmaUXs{yNQHusMhsVPqXyj9hN`D#`{(2o}Cb(DXTN8B(T(2T@Z^`3Gg1YLi|MLJRB6EeX_0$ zg%=`;vx6df{Ru#xcI)4>d%j4}^X$K_0cB+Y3}11HhU6*0q@rAp`?ArdZQZ z@&sVx9L3nzV4`8afczuekifPi5^WhQ@|GQLrY9pt(ic_Ie!l&z%vs|y#S{jI0B_D+b%%bL=h&9DIP*<_ z`&&+d4++w`w8IMeCkvY=hqZlFs6V8Ic^fW2aO(numoihvpC}ak0R3b=krD2EuH{Cz z#xJD~>2p?|R<0Nb3p9KalO7q~`6`Sv+%}tUT$R^xuU+ zd|y`tVHROYC>ypL&=+J83@SMl^__{)%}=i04g#o$N^dqOALmyg;fRk^bYoUobz$rz z0P5Y#O((`O`9U#KS!Pep>@-SF&e3>}{x<7@>vHDI<7Fs@GktIFZtu0L!*WsNpEq)g zjRTsu?XukQ$UR?XXK^1A3UO&*i&Qm;Zmlk!nErKfUq^iFoU%(xD%0l`jEyLeSq$V4 zM9xUj%T{U!CUyptUV7g9mukV8;x)ywK9x~xl8F-CD*})ZL2rIy{J@GpZ{&FeH~4e$ zFD#!8SXRj{jNMy_G75hN;Rxiw2D$A3gq!&dA2iI%b;W*q;HU-s2nv^gYCoS^sxxlk z4;3COQ_N~ncfh(=;$BDbNma`8Ij}i9JM6hgXiN>(16uoh^4Za01bo!AK^>k z>z|WX>~NP+(Ta!>{*XKYLLQz5QRh*B=EGqF*9sxJBBFCRxr1qo;;2?gh3&ISe{l4e zxVsD2q35u&qd{3qiCSWYC`WY0kjp2LXs$xJu7CA)qbv?t4Aghw;?aQe!-p4rD%;d3 zmu&*(ZtJ^Oj6Dg{^xs8AM~rtlt00-YRjUj3!RVC^hUX>fSRGy zMgKP6=J|(*I!~by2GjsIZ2LbbZ*OsDjtGS+Ry{R4@abO^o_Rb9?};meB2}AY^d*4F z?;pa5Uyx|8mpP6jgGm}x)=mr38I>&Ju8l!pIS9Cy6x-AkZ{aSVcsz zOTUOJ{lI9Y|61d9qV7Nv0by$nlIkZ89(_9zMJIc`=bmm~L~iA5pk?eO&D&MWl($_L z@dm=+FBMi)|FZvKcbNt#gaP5Q#s)Tk8EPe3r-@wy!!<(s60z4G@#-5DkAZSKTF*W5 z&YCO2bF=#c*XY(XCQ;(D9FDOCE%;oivS~^(OHr{f+=+^blG~KzgZ96A{^5mHvt!_B z>AqOI1I^&a_m_*Vv5+9yT8L}7XuCDm)?xU(zP?^`Yl-gZ%45AfXm}zUTXu%mJMzl> zye@4+$Elq1o4$B^gDm7EjkdTh=7pHFPjc_UFaa6pKjBt(E?iorVs7wVVH=2^t7u45 z%o&m)) z*943ErR+5w+XTt1(k5nS8uhMU>G|g|3(~c^dKa)j4sF!A&%F?X^B$hjB?R5&YA$9F zY;-=+YI=<$(S$7C6KMZi4D3NE!1RmXJNVq}fXW5er*k${f#ICcpCc|`3( zsm6qw<1W$wRQ;D1Vw&b?;SqlyNxLuJe-+?w**eB{K2>1fNh*FUeVCxFqIVd^^@J3 zP|1BDO-Xk(>lekZN`@S<`|h62al|x5MoUG1N{YB8LSgF*^+M} z74)LQ*m641^kFZl5tDrxN^2(UJ2?>6)2xRNqyz(2Lz;6-6@CD!d%Y13@N*1JJG(u)M@WdN=%sd39%Bv?K-qKWG8~g_3d^nks!PH* zPLUfw4r($W{7%7sw1`J-+cdyXjYpvtT5B8EenOC17;FQNhX$>BrhCUlleeqm?e{sg zP?hsMdJ^HdUO$_0R_WQ&13LQ2dXMIY>J@x;u^hlm=1eqOB5uIzkipmD(USpXh;c4Y zhGeDK*M+M=OM|SK9a5@Y;Nu~#V>1N5W-2_ySU@9Zs_Tg9cerHkTofp%&Qm(XQ`wcs z8<1V|KQzuJczwq>dyDn{ucF-fFAk~bK@gv$yWR@1OLl28NavwN6BnK0E$Po>+5xz# z!l+5u30(=-aY*OL!E7Zm#}O`fMtagASW+H}NIuk+Fi7=Jf3_hE8}|M8v0z^G6=Po zIRO!CPrzG!En@4hWyUz%_-2uRp%9R>&-S+Zt?WuzvjFdHQ(On{#le%P9kyZo>YsHQ z@>9LP@cOT&O#Bnb{j7hJq(Q+k#q)|zpRQM(rL+qDRUPvi9qrA(O6<9h`DA49fHCNo zkLZ6Rw=W~^1{ys2%e$&)R^;N0FtzHz0y)|(_@GFb(Gdac%m;3S!ROZ?H25B8#REIW z13$_GL(UMpd{9*}h%!JjapwPuBZ-b0xF|Q@fwSLnRhbVp+X^D?6j%lo*y_9GS?m%@ zi$MuR_elU4nGWN8=)>WZnZM(8Pejv`9?aI?FdoL3}Dad-XujJF#35K5M(r` zsU|R)Rr`C*-w=0b{XcPK0?cszx$vv~KI~JYxc$jXF>6r1?r{Aq48syIF9K1K!3AW)re?eTw1PXcj zAepdFHFa?y4d!2Yd~ zuRNf*m8iTCi91U+iaRD$nJPuMqX8UWsC~M@c}+(DfeEH=@|eAH#~zOD7>^ma@P~`U zbvX^Hxf(TNlRB^XSFfDLt|JB(;?CowelO-Y&1>AW&%Y1tp;0ZXvl3?(emMpkUi+{xK`A2-2e24VayVRD;h_Ehd%O%v6qP7wxbk#c%F&6L3zz_TPoVPDT zwg?w1VFu6qk&}g_^_WDb@4JD=PtRcY!f&nph`#2P*SjZj? zWM+)y^mFZBO5v9gr~e_2y#R6g8+Ax6Swi%8#XDAT?AK(r*#c6m%_I6U2Fo$bnJS{tl)+y2=}V3BQ$CYFUV43&u$AL)Vp9hku=CzRBx3 zlhAm&?f^h=!|jfM#e_Mu)B^9JdphtJ9IDMv+#nE5ThOSJvu)dPr!P(rcu}Fi)~sWp z#d9kT{gVLpi-xHUeDw<25t&nvzG560>ICm zH2LZZ(t4N>f;&o$6d0(cV;eZabvSEgRsH920eqKFL4-gqWzN0 z&m}YK z4P|a{QN1Fwa;<-rihB!Ti|xiS015A|wi(83B}fu$YzP(UtoRPp|DR2L6=mPQb?Xej z^`yd|*KsqxtsLu|mSAL}0UW}IdidaD3_pZw^{C1Fun?ev9j*`@{Xa`NDoA? zE-EJ7rH?=<^L`ejE6I*Cpr1qN=YVx#v{q+43Q_S7yR+wLyxkcWT*{eX2%bl=luGTk z8r+x}b*s5vSSb*1jl?YH+}+2Hlgne=kG=Atd2aXRGBi4jEoYi7!p%usgSI?I;v$qQV)@x(@Hr zc?J=!Nre)-zl79Y*b0sCZKy|pS!;-D3&>e0WQK6r-awc`(qK7-pY-!t$4r^^Ns@u8 z`ZL`@lJ;N;)c8dOPa#N=8}<3@z?NfC#Tw9`XQ6bHkSsGcKogd=q<%@P1vzO>r?^BD zD*9`_kEdgJKE&qM#%AOgWnk*0pI2VqkwlucJRVHy!{w5|I$g; zv`nigN9Q=F5*^DFKWj}x5=XRJE`=a$h-j9O=vmF93*rwB?kA;Z9^3(r2X}z$9{c`x zK<+)E76W1E!TRqKu%Q+m&a{8Ub(Y1*B+zqgwIcK>EXaG0jCc;*Wk2vbj972z>RFK) zc}a(0fe_E`iZ`Ghz8ei~wB)A0?~vaB0eV5*ASZ3r@n&Q$M}apR`8f>Xj^OkBB;@_kH^lTze?*3b`%k8RxVN%o=C?a$75!!CTxr2x@EpN zB>=S40Hu}ay4#R}DdiO_YCh)Mj>?_S04WzNqqC%Mqdj|Z*wW;BUrAj<>A3*nx|G%P zMHFO~wYK(nI1dKoi16s~@G5IP_r~#kRrBU`mNCqa@0Y94+}%X#K|&yH9vn9iugC2J zUwB2%ItiM^5hP9toN~`b5I?V>Q5aT+Q0+!%7_1f;kVj5=qH_Dt3~#i{%+m_?gZ?XI zF=WZf+26=*52ZY0_2C4sQ@ZJjS3wEDQjI+ID$KCB(UwlEkw zuJr)ff}0tc=w%zD;%C4Ck@F!MF{_p*GcM(_JrSP>(GVW&94Hzh*5Y|c8fwU15My5> z**L-mSt1J|;Lo$y;XV-^ra8Pc;R)wo;me|p*!^rO>)j5#)rpDcd_*YDBT;#^3WZ%T zX!8hZaS^Ky4!Ai(8Oz#Expn4v@Gj}sL-EG#tqD_u{XSCz=^A0=q4hIfpGC? zmU>-7=y>##BClT#$l7aaMTh~W~d4=Lx&HJM$8-IKRGhKO*8ZusZecBt^5PK#z ze+v*bibW5v8&?T6E=JZGNDa>xx|i4~L>Q zrnEW{%-nQ^ifPxCUVxXQV+}(VZt{#r_(k0tXLj7^Ue2W+mPSAj-tbk(PU>wcL%9;F zZUAq@fng48HCr-8pG0~=6~pxtYg%17e;n9am=7}+WyMT-Z(eWAb1Kb`rKJ;uHh)_M)aJ+xRFv`EjYZ|A4uH?)(7D5`?D0d)xrD5ck0q4M2`$bmOkp1HQB`7Ku3AjKYHjZyTBfrovu!_U( z8ZlB`X&c->{r9~nnNY+p)PJ6mSD1FZP?)85cFL*kG8)W{JHX0g}VF#7}bDOjsN6mlqwc-2j-J_4V!v`$(|vPPiRt_)FH7 zTaN{LP_F}}sL!2ty}cTxR#7658kWJN;U}tBOFn*fcEeb?_oec!Ge9tJ_!A&O>zeC} zG!`m766-wYSz-V1rN=z~@UJzoXV66BC;7&Vg9#vJR)+m^7L_jf>_y%c|L{?wf2`-E zUz-HY0cskxwQb!|ib+LU$C5_=s7ruY`ze9r-ctmYk*^&63M#oE)KH5LWdX) z8}L(}|BbM#L2a0ZP zIKXuv0EE-RcV3ttm^AnICFgxSe0iXAxzzZp=U?%6`Q{~5Fw+LJ)sr^ZE69-J%?7i} z7A|#5x@WwX8-GZO@WlAX1Lnq`SXkl<<#v>Qpub%iWHE9%P8N zYrxU1qOSWLD?r<*fzyzF2I=VxGECiF7(>*k*WIYm4X7bBag4-zPleHVoy-2MrKt_GYzI^p6z zAOT$~lR8`EO(~R^G)^P*Xqow0i^QY)JVj*`!tDK$emZ7L6f{dntEiGI0<-X&KZ}O~ zPU_RSe1wOCeL@K!6gVaHlUB>=K;Z|`lD-m!HOq-MyU-*N6p;%FXU_h}Ue_M!FzKv9 z`Eh+`9gt)87yol8vX};vP?H~6@?!xUlo8>)m~`mba4^orLe&zPbjw~^6gzMC-Y;Oe zvL6LUf;FAcSYZ0B_L4&(%K*k$(cG8=-sDPbvT1XLJdTNv?G?e$G& zPiOkqn`v_{+XI8UA6iPd4fex1m_8A#`JnPAo)}zD$U5C0V2@A|@95wZge}FJqM2{d z#v7d5^dHnW6Z1na5vtK5e?_1$P!6}@8F<0D1aX&DM5$N+sXXK5$%oLWL$!&@B*#%X zxY!*qr9m3?$p%>xAJe4-x*wqrU+`oakktCf^_QjMLaSu2tH))MvS2ZGZ@@sT0>e*j zTELmRo_dhGxUZKVLVueXsv~xfl>`b^WR$E7U|Tq;u@& zc)&HGlwF~cR#ZIr)wvy=_i<7f>*k-C;B2uv2XwTBM>|!{!1tU8H-&a(DS$fTIcIR* zPV7GG@L&be|Fnd0)Zk`+2>OM#3FcG~_G=tl0TemnTlevH4$lFD__~f}Ptt8j(`l6J zLbcXTzWJ%Bw1L9}0~O#runEJ%jzv>$$A)U38%tNu49kUQ(xH{7v#IZrM;DPOy$q@V z%`IprfDDd1$8U@id(3h`!f#lodde0M^w#L|0j^*4)yKCT+WV$4l%XCv8j7vxNfF)y zoP`#tumq}P!I=s=RG~%2P>HILZA3f1wd-c32jh8a;jO(oc^*c~ z7Q2qPV?gtZK;079XoWVlK3;+;9gQzy>1I6uGi)_)UyK=+ru*BGh z*>8e!AJoJ+lp$0Qp9x8CkEpsI<8@qcJ=Q_vk#(d365)Uzl{i!9i03l-zKOdfbJYG7h z7>tujjl^Tlz`LODaiszzgXdPYYF=+K>A^oT6jnjG`s0V2`zNEMI~$+vx%As#s&9HU zQlJM&n6EtZmao*qhQl_+&r_UbW)8 zOdf$Po`XxKbHr7^Kcct{JjN`L8IFh-A4*fHtaZiPy5=CuN|(vwi~&KSNlfF6>>Agw zK-N%XwpzG-uKEyUj@Q1~Y*sYe0I5K);OP}LH`b+myGdth=5GLMNrb1NpKbedg8om{ zkk{dz?g|4z_a9PR(A^xiAB8v&q%ZN7`mN!8)DsVa7lsx8{Oe1>^MLRdYy>!+ZjMw> z{t4Uw=wCo=8IF&8)|+oS$gxxr#!b$wotllStS!*KcP`wvtg&RH&~YV+(HsiB>obT? zM-6xTanfc~G3WjIDD94jt`g?9AEV8cbXP5W=)EEHf_*480YsfDSW;we_FF8Qf7NHu z?2zGq?uDIcnNuM9|2NnG#PNdXb%vE)ySDo2qrlB8B8T3WSddsO=xzaF14BV5#9Jfv|07S% z7-{K*pOnpuR=l@IVizcP=f!(1NMD;2dn(a;GZ3Wg+ZI9mbJ%QSN2;glaZbMmy{?zI?4?%yD+9rYS1A)XEoT~E^CNulc zhwudS9uf9%uXDv^*|3jbe)!XJI+hXLykG~I(@xIv-l0|(AvEJT7PF@ac;jb_MYE zG%px_wZf4TVSB#W8i!e@N9Y&YdD>_wE;aW|#x{dDTy8}M2c7 z^P|4x(xtlA`E;Eh?T8^RRgwbTuZQjr_JyIA3=)(gsbbO-tO?)&0dVSqn>TjGk;Yv> zVmw5cK;7&>9(F!cD?i8b^E%EJOq|C47;2Pj7F13WZ2WrlCvW_TeHzNrq#C~|jp)1( zIPe_buo?quh<%0(3W~seteCW^)p;Z+f~iG&Q5G46~&s~QCU=3cFqLDEMjYI>a?~7SiL6okX!>t>ci%?BEUbeB2Ltj|? zsRlbg@c!Xh-NII6QkeU?Ue*Z|G5cSk*bWNlGc~!qKlz^<^Wr<93KyV%1G?Xa?i%hn zpD@Hh)(M=y%DT0>U=XSVj-0#EN%+18vTTzEPJ%Q;y$u$nrZiAl?Bdr zl~4zb?%;VV5fU!7Ygz(iJ-l=$(c|9;C*Sqb4>g&RW-Em73QlNuDmzi#_d&b(O|uF1Y|u@9BL z)Z}`{ak8}l?+lW3fkF-1=C>P^n%>{GNpKnp$p<?-em44JIn|#l#WEz zG=S_lc6pr(7fja?u?K8QNM$^Dyhn*sImF@+LnSZFwOhYMs_%7(5uvUeAX zn7yB4AS{#f&f$q{pzB6~_hpsMGCOlv>tITk| zYO)kJ^Ejbr%pkiT9Vr7&q_DCC@#R9O)~0y7OOZj51e3bQ_@9_X?yk}ib#TF%P(XuX;v}++KNv5saP1S|8^-!!pM$6Hxav6|f zLM}5PtCXdXR@791q%PIe(hwCfT#}h!l!y@`*9d`3F64fh+~+=X{!btYlga$L-E-RA zx}U!KYLfuDJbC7MzR&;n{{MdW+)(0pJ;z>DH*+|kgipQ{Q2wRpOWFHM=^mnS|BCDrQ=YPxYenES6sj038_o19rkM7*Zne3P5O0 zUpX)U%XYWftD525cRa!Kk-?)al0G#(6laeqekkYZ(p*z*v{$vdTQQ^6bir+EuQb=> z?rl>oxf0awr6|AWnjH6&)~iB&4&hV0zpp64)s*kmCe3Jzqjka%fl!U_XH>@IYIOGn zWdxnA+TO!2mNu8GdY4%>CO6n?53Y+$Ezzb)=eV1#&#SXbbs_8glUnP~s0=mZAyvJ~ zJX)(K?U%K1o~d1pfmSu<11W3LZ2Ok0O|hD4TCY=03(sXt*k@JO%F)IK7J`Th-7SDz&%#Ft+) za&p0*n>*}Uk8Nw;x*X?^qTJt~R9$IlPU<*ddtcj)GuUU;f6wWiHQKh-(iN$_iy}QC zI^drlaU#Y(v*fyqZSF%z^OpD2+TZ1`60Kg{Qfh3~E+T4S)OAGf?}cFD7U^#gv$i(;9fKEK2Fr8eln0DXvDNtKf{eao0+%1n9b3*ELHmz^Z;r z#*ei>QF}af^*wQQm8u{#>vpfUlS4gv7(Exf)=to+hT~JAY#R z@L~{DQ%p|iea`VoyM6Iye}%byqVeC#)D^-1vl+I5E|&Xp`j-}m_#9UbWXVxK#k6ge z?%%3YM&~TCnA9NWZ+6&2>{n{-)A}M0>{Zb=89ty9|6urtajp zmhn~fYGA|AmHimg5SWJGi0~gOFr7&F>zjtqtOR41Mo4>pnA15;HAuW{)a5Nhqb?bS zFfiKTb2tnk%K34WbBt;psP%{sGj=8Us`IKk_Uy8BeQQwZMAoq9;NlJnMQT3>dk+5i zuYA=hQ`p7&zkg@pU!wE9M(=|=-|t=WU)cFRYow0<@6q{wg+&Rz95s96;K8RCFYfBi zt-5l7nr7QkFk<+?UNv(oCSuH6iJ1%Mm7gytdtB}HjqrU`pj+`%w>I$5q&+2S(?~}j zJ<(+I_rIw|UO2M;`NX?wz;(FUoptub;(UKgj`>h);U|63*@Nr&zR7=)Q-t9N{|$yC zyz%7Od){-7Q-aOv@+{TIXVeb&|HEXtSFQhR z`y-;9g*I(>a7m;iTc7HfY=~Rsxt6V#gk_7&eQqtwuIj@uv|aE*q>ar z((cse{GNJ5^~4HsqzgYXs$ukwcvJsIllI0#y2gyP`JU%9S6@CDnmq<;XWi#vkAYit z4y@JM6Z*6_61>~&SDL#gs(N)|?Q4U!fdL5&NLcC7CJFtS2P6!-5nJa!8TvmSwZHyf z(HxGkVgJ+TaP<7TZ{dsYuS}KpJ^VR$tPDY_-1{!_ZEv?N{kC~UVK0PLF6evqeg(qI z*YEx3%euf@4iD3DrOz*Q-`5=-YP5f)V~^go#p>Fm^S7zSJZ77@X{EU})2D`FwPcwK zUkn=>5RjcSIHDlzg(W?nA!8q-cFL>f9OI`Xr`&XX$=>AVP6h7^KU$KbxV>uNaP(1KaQ4i7CEkFqV7G5prH-#%^VShX><2&D50tv!Z(g?Klhtc>>^L>^ zpVf?j6~ki^{Cgxp?z`gqW2>5`>n=+4XjL9m^WwCj4_QN>-&1)IHzQ z)tKXbF7h+``3V_ElfB2(Zp;Ml@vN-BEgm|aJ$Da|DERgZOS5x^rZ$A%@_bk4qpNE# z+!*!jW4G9+-IlF}MND|5T^)sl?QxU7(xEjEy*O-Ql9~xIX_ooas+UZM2M^+9*#Eja z{!E8qZ_Aax9Qz*~nPEECuG&U^$JY0p+P3Wd!vR~>bv93jp|>isv%xb}JLf`eLI}M> zVQ*Ezy9NaQ{8{N<C z+*MJR8mmyK<&f%jQlwg2d7`rJs%ZU{Y0Hv()SiRy4D2y@aNvKlZYh0I8U3#w2;5&V zbQbx4c1fmZIVu&@(OS_yZE^mz|EYZEk0QNYw&Q&-P5AnW$e!2qP6gBVtF>Ki`NnB& z({=zTp>M3tH9E^CZ2Y4C0j>3`OPkNA>%Lq6t*xs(2fP}oFEExQ_?pU%D=OwDzNPml zKX}yOdnMBEjN0(Go?Nxd+*KFps?zUMJ)|R6H{Foqy2qAQwr*G5a~}tfAvke;iDN~i z?^JF=q+2zw{Pr~WwgmTkrC#rez19fN2aOev47Ri}TO<> zrkgPO{q*>WsS1@j3d%gF_mWdB3#l z#`IEhdPTIFh-|oJeOH3tu|n(1oLV zxI8|7=gVKb!%@DXR81XKQ_q_gCANLV(0y}${}x^MR(p)x1!XI2d;vm}8T2Xy* z#K9Nz9<8VU(%b~g6?V7kRM2wYq-W~Niaa~^ef{EI60MQYmj{~D|CenY@D9MYU#>sz zcsk1eFVi*-UoHK&4DG-GP)C~V_SIXo$3y^i-+vfTpR*N-KW#fp;_}-kW>APir8iJ)P^` z_V(L6sRPXHErQ~$~p;0zTs5y_FVJ3e;f`ZlllKQ8;7YD=kwJhjY^S?K$Mv}W)TPiJOty<3~ zHKrmt!TpMI=6$I#87{{GOZiqcYGT}I5`U%Tx<>mz<2=n-+z$o^xtFET1_NczpC<(?DCf;qft6x7S*$bu253YkkOEU;XIeaobd(yXy6l=v1{a zM(dlYmUf1oM*P3Jcr)-#cqIRMZQ#yrrOn4OGde@S;Z+q%{3)^4_{!C3!iZ{KyX zJ^jGFFW&S~mR~htdFi(U`#JVT_+*4Vk7x2M=~vn!9o*`6CLt!;;UhQce7a|7DKq>1r7T%|GE*jXS-rd{47B zB4^vZ8ErP78fKt4eZRIDvfTX(gQ;bU?U%jdb=?zH{4tpyxgo@Ui3t&%Az1O9)7;t) zs56BF%?uljXA8!J`W&G@#ewC^Y+K@7i~VZ5l}~FKv{x|qp++?vnNi+6&sdXryJ{uo zbB&MdUVLbUYq!p~el&Of*vd1in~^U4PZ|bsq(9WIico_bCRJCZP1~k|+Xsi2R@bPe zf-{q?-;>~Y?FTcKtJiJmn=8(!tnPN^_==u;e$EwYfWA)BEbe(eyeRpbOz+BqY z;=$K}>D|7k9Gld>*A?3)c|Qx+g&3bO@|4WHt#a(Ly7M) zJ=;{@Dc|>NHGiY4nQVFD*4$8oJ0{M^@}7zGm#B7%_V&aW?KvUEql@tld>(7aub|U5 z+K#e0qD9TA?isIhEmj-6l76<(tM*B6iE{kGR(nt2$=28vddI|nw-bM^|FMf}bKd;! zzv`Cn)7-Rt&-|}%`5so?S^c}yA3v@}e?MyS|J?2U^R|8u4;$I~U3F|ibiM!Aa{nJ}zuR-`ZMzPwID57##T%Xap>|hT`jA^2 z5}{hHIaROICar&MqI0hPR;^3!z(fseM#Vm@F{!aGI_=cFl-EnOK}$Ko&Fz1Yd;W&> z!BGV!b;Y{c;Yi5H)P{1Hv`gHU?B$j7jNa1T-5q(>raHCbHoIGG9=^J~S(W{Z^!@db z-gt{YdGrAkbrm9)*jU-)ux`IRBL&qknE!jBvB!JPWIWFcdXt# z%OiJHSi8^Xq^kbPY8$huaYJU>RWmxZQH)XcYcqX5o9jcHze9g-%)`FW(-Lf|0c76G ztp;aDLXlFFx*mn$KPZhIH_`FiOy}8>b@lVoy`=+BVivt?pYGkDi4cCZKWuGTTxUsD z!wprAmyDkEraH9?FgGG%o@!A)sd{`|d#t`kLAeRW2D|q3cp=~4egCKMQJ2=(b^ZFCA&$eLD9qRWBP?1k-gejHZ=}pd(55^Z&l~)#8)O%hn_}~lACNQQR7{7se|WB_p=KN z-%@+9Z_3>7Tv*k!X&}aFjle=qS&5zI9z6Sc!VHeD<$tnrzx(LQo4TH{_3l?Q4%P3h zx4`TwGd5|NQuTWrtO8uNPBzbUB+Fd$#);QoR5#P2wy80$&)&{cW33|6J@M(&?P-Vd zlE-Po3u1CdHf3*Xziq7cC+BRBMOdzxxyt3ZZ_*5{!{?bl7+#6VjF0KQx%!8ht3TCR z^P0;l)6YJ&ui>3{_q7ep6wtc0?VmVj>5`*sH45i#$oGD6x!TvaHq-y}{05_`D>u`m z<_O*~ZIr(8Q&q#%Vr`D3Rv8^z@(mRWE^m}?P~$vR_d|{87SAtgU)=ScM|Fn$=5pV; z*PVs>C7-0IL0R`EtMfWx+qtU}yC0u4=3H9&b9s4JcB=WJw^UzvbJ4fAeyO}!8Ot9Q zFVcHnD?a0%X71i;{^0T-<{uVKOB>PAf6SLvSI~X)Qm$X#ee#>Xncc1$dfc<}$cDxF zv#wF&2h2Ac%5pP2(PJb1H|dXfeYFXZ10x;6KJDASblUuB6~$^Y=Q-QR$pXs7*JuxJ z6I6%&Do>uiPHT&;HDb6nMl~;0E&Agch9?wgpEM#&`@MJ`tZGm*5%040Pgi{b(~^3$ zbmMEX`#bg|+8-b4UUKzcdgjHr;?MKUiWA&qdk)vdwXd}1pMK$$;)aI7Devvy4IR)(0(<3BCGH~YlVqYWprQyXW_Svb$O*Bkd}Qqp)eD#PBIbX(R- zKT5f|r_lA2@btz4&nJ5ShvTh1-m11c5?gAt-YNF`toEsM#ufi`(IKzutlVm{75JZe z^^v@Kb>SSdCa?X_NM4@d#1(|k3LD`yebd|8-Fz#X6wMXDYa3{r*L&` zq~o1@@88`YrsjG$-_5PMXY)f9r)Dj)L}<5?_2Cabs)l!5dEni&w~BUam7y`2#!uE+ zLQng6Vd@_p1u|xm=a;S8NTPyAZtVGJMLb4ov7OiEdp^^;ZacLF zUA1m$TW-lRI^*xkJgv9Cr0bq#ab{^Vygpmi_p40f-$XrY^Y!PbYOR`Kp`Hi!`JO)! zk>S`>H}n3~3p=R_P3VLw)3jgT0kx zs*i;;*6Qm~>$#?@!$Qm{xYC~1SCQJhVw<^nvB{HZ^xMo`J56o|SJTFS1_HHfE`wIF=G`hye}i=KGz(tIh68Q-`*;ZgjX!^=cBkuD2$7 z^N4f&jVEgrMhF~!ks90S33X0pJU1`(o7M5g&Wesgui56@tatd-o|7M_F-F3qh5rxR zOy+FAw?AH0jjXO4bbV^GN`!Cz$SL0Mw`DSfTBP1>l9 zBGTGIY*rJu9SN&5e>4~E8*6s4|Q+_fUdv#dD8e21gk&)2^b zV(x)9%zCW$86!F`mVuou+J)Ppp3dVlQ+wCNIVM+i{3_F2ulja*C#a@Ls`B9XsQRw) zqxd3iazn{~@xFwx;+=)A2L~ntYIDduZ3(`kU3Ha_{yS|yd|(I@dP~2}riGzh0;Vme zyOp0x+I7!CQ>4%sIk4-!Z}!k;3Ev$h-%zs=Vlop0g-bg|zW0Rt+?n$#G{yhit>$#3wK;xVF*mz(Xd8+C9|ku=bPP{#_^z7J&=WTF zZAP6`UwK!)TDzW9-SjWhZ#N*W;d0+`HQc4s8vnw;bb>Jh4Wmbl9B52f zb9?os#GaDDcGP!~rqJHo0 z-Dk@8yE}?HkJ^0yWb=+O9JRdgr)pG-reFQv(?*Vl7gbE?Xj{_1yThCoRoHXDaxBeM zytOC)b~T(r4P6-8ofB%OMDVzVi&L=GKs4)-f(7o4mcHpj5kisjuxRVk?NPqd6+^Es zg`G{;;>d>{wMN7EKzeo(u$5v+VF&I)xmeZs9PA}g<8-ufGNG>o-h}SKJH?p)y~~y5 zDEDt0?O0s=m~Z0!F>4Y#>KR6$_7*TZXR!D;IIZRK6NkNk>;+^m;Kj{hqvbF4F*ZZ8 z8<7O5wi$FQWkWPO!dc1){Q#rZdRWR}DTAeq&-+pa7eOw9LtRWpITYLlxC?L> z;4TpK1a;Xe<>z2UpWEOl*Z$!JHtqu41-J`v7vL_?a@l=v#0n#~LApfJCi5~w7Tjx; zHklQJ>TdMwh%f)OKh}H^ATj!(yLfj7NB|@N5&((eXV>7j5F!W>ga|@p#PeI=y9g14 z2&=-Z3R4^nevBVFE2s-l7oaXcU4Xg(b%D^Uauh}=j8GV%Fd_s=2B=XQqclcsaIo8L z;9A_JXhCt5>M-STe8Aw0^3j&&=paE04SI-RghH=I?A(PB!U$o6FhapHXn2JJBZLvc z2w{XqU5FSg_+f-FLKvYT4KmvO6d{5TL5K|AFh+eUr94h~obov3@!^Nh;J2s_Qyr!{ zOm$dbhC3;bQy!;0PI;X2_-G3emp+CMzz5(1@ByQ)#9UhJ#|Pj8@B#P$Ax1D|1|R{D z07w8N01{Gh4*7k%7oSWFRuZFlIPfKx7~?5E+OJ zL`JA>VT3S37$J-hMo1{`VT3S37$J<1kfZ1!0+IqrfuulELXHASfuulEASsX(NJ=X2 zf}}uFAgSR><|uDrgfK!FA?YT95dukpq(D+2DUg&<-9(9@#86@=F_f54-9(9@#86@= zF(F6I14)6TKvEznAx40tKvEznkQ7J?BsEG+bMT;mq(D+2DUcLMN~&*zq(D+2DIrFz zIt7vfNr9xKn+Qk>Bn6TJNr9w5QbKVLBn6TJNr9w5QbKhTBn6TJNr9w<90ig>iJ`<$ zVkj{oN1?<}Vkj|`7)opqM2)sK36cUyfuulEAStQ74Uz&$fuulEgQN9EOH?Q^lo(1( zx{IR3P+}-Clo(2Ew3V2_kAb8>QXnai6i7-a?t!F0QXnai6i8~crKn3E14)6TKvEzn zAxD9vKvEznkQ7Kt$WhE2M2VrqP+}-Cl$ccCMv0-sP+}-Cl-OV`dz5nlCI^#)$w@H+ zCI^#)$-(4cazc!l3zLJ%!Q^0aFgc;T3zLJ%!Q^0aFgc;T3zLJ%!Q^0aLXLvT!Q^0a zFgciDcI6<5sP7o)E6BO#( zI6<5sP7o)E6BO#(I6<5sP7o(3K;aL7X5?5GRNe6k-HU5GRNe#0laAae_j98z+bp#0laAae_j98z+bp#0laAg&c(w z#0laAae_EOAxGf^ae_EOoFGmRCny#8ae_EOoFGmx7{?8VOPCx?4kjnvMPYIf(FCI^!fauiGsCI^#)$-(4?E1AJ>p~O&PC^3{6N=&M6qr^~RC^3{6 zN=&G4!{lIcFgYnkz~o?ZFgchUOiqXqbd!V0!Q^0aFgci9WXf;d5(AWl#!@Z$t=f;d5(AWm>-2{QOl z-~@4kI6)~!-~@4kI6<5sPEd#uI6<5sP7o)E6T}G$^=+IWP7o)E6T}G$^=+IWP7o)E z6BKe3P7o)E6T}JP1ce-h6T}JP1aX2mL7bpe;KvE#1aX2m!C)LW94=vUFgciF3?+sVLx~CXZI~QP4kjnX2$&p94kibagUJao zf^Kp!IhY(w4kiba6Uw_VIhY(w4kiba3ohyorE8cROb#XolM`|jOb#XolY_~@q94kibagUJcy zU6>q94kiba6LJ(&XJK+MIhY(wPRLO(IhY(w4kiba8?Iyqzl9P*iJ`<$Vkj}GzKs$? ziJ`<$Vkj}8z73Ou$-(5L7y*-m$-(4caxgg|M$kz$CgUP|MTqSCI^#)$q6|M zCI^#)$-(4ca>JF(;I~j>C^3{6N(?0?)wfY%C^3{6N(?0?)VE=BFgci<6eD1AFgchU zOb#X|#0a{{!Q^0aFgchUOin28!sK9bFgchUOfI;nJCv?raxgiV986BgQ7}1}983-- z2a^+W6y4--f;d5(AWje`C>8i|f;d5(AWje`IJ5*Ad?;{&I6<7C6eDngI6<5sP7o(3 z#0Z=qP7o)E6T}JP1cmxGP7o)E6T}JP1cmxGP7o)E6T}G$ISMC;6T}JP1aX2wj=~Az z1aX2mL7X5?P%7}_1aX2mL7ZSPjvEe_FgchUOisFs!sK9bFgchUOb#X|ly_lrFgchU zOb#X|ly_lrFgchUOisvAOr3?v!Q^0aFgYPd!Q^0aFgchUOm4W68T=MX3?+sVLy4ip zr1~~W3?+sVLy4ipg!(p24kibalVSu+4kibagUP|q9 z4kibagUJOKb%)Y5Ob#XolY_|#ISM8RlY_~@E$P7o)E z6T}JP1c#O&gAWBx5GRNelwt%<5GRNe#0laAg&2Vo#0laAae_EOoS;zO#tGsCae_EO zoS;zO#tGsCae_EOAxGf^ae_EOoFGn6$Wb^!oFGmRCx{co2}%WioFGmRCx{aa#&N^p z5+(f(_$We5Y!wKR9ae_EOoS;MmY3E~8C zf;d5(pb#T)f;d5(AWje`h!Yg*+c-g-AWje`h!Yg*+c-g-AWje`DC8)dAWje`h!eyK z3ONcVh!eyK;skMmI6T*BmFaxgjRE(()_$-(4caxgiVoKW6{ z$-(4caxgiVoKW6{$-(4caxgg|M=^C4CI^#)$-(4=90iku$-(4caxl5!N@nm|C^3{6 zN(?225|irNC^3{6N(?225)xayUVpAWje`h!d0w z{5V0JAWje`h!Y%If($+sI6<5sPEd*wI6<5sP7o)E6BJ?uP7o)E6T}JP1aX2weH$l; z6T}JP1aX2weH$l;6T}JP1ce-h6T}JP1aX2mK_N%s1aX2mL7X5?5GN=V_;G?bL7X5? zFc`-ThfA0oOb#X|-9=$?FgchUOb#XolM~9jFgchUOb#XolM~9jFgchUOb#X|nlY_~@ zf(FCMV=5y2;@Lae_EO zoFGn6D)8e3ae_EOoFGncXbCd-P~Ze{f;d4bM&JZ-f;d5(AWl$-5ja7dAWje`h!eyK z3iWNAAWje`h!eyK3iWNAAWje`h!YfY6iyH)h!eyK;sk{pg%iXH;skMmI6<7CRN%)6 z;skMmIKf~XHykcuaxgiVoOBn3$-(4caxgiV9869q@51C@axgiV9869q@51C@axgiV zoRFiKIt!D7$-(4cazc)R$-(4caxgiV+;Al`_$`zeN(?225<`he^=*_GN(?225<`gz z^=+6OOb#X|#R!-jOb#XolY_|#F@kP#FgchUOb#XolM~9jFgchUOb#XolM62D4y9|D z983--2a^+W6if~#2a|)z!Q_M-MK?K|AWje`h!eyKN(FwLAWje`h!eyK4lO|j9}1ix zP7o(3#R!}rP7o)E6T}G$F#;!u6T}JP1aX2mL7~2l6T}JP1aX2mL7~2l6T}JP1aX2w zj=~Az1aX2mL7bqFqi}*aL7X5?5GRNelnVSfL7X5?5GNRn!_DW0czp5l3m=P912c;WWTQ#?=cJjL@AA3B(-r&}Ikd5Gm9R=A6< zI>lBewmPxZNm>bIs}ozD*y_YqC$>5bVa!oBkF(QN!Q^0aFgchUOb#YDRLTuL6filM983--7kWL4PExeeqL&y@5-16j6oMqp z)aWLM6h(?6MUkTW1>t}cMT#Otk)lXZp}>z6MT#Otk)lG5+KCgy3E~8Cff(_h!HS3oFGmRCx{co30{^QN3PJ~ z1aX2mL7X5?P$=-@1aX2mL7bqFqnJAklmtowC4rJcjsi*oC4rJaNucD&Ww-z~2$O@! z!Q^0aFgc;V4U>b(!Q^0aFgc;VjT6KP;skMmLXN@-;skMmI6<7CkfZ1)h!eyK;skMm zI6*?iWEhPB1Ms+f^a~JB1Ms+NKqk2Aw`j*NKvFHQdG!MNKvFHQWPnQ6h(>(!T~9Y z6h(?6MUkR{a6pP8MUkRNQ6WbmMUkRNQKTqRRLD_CQKabSK#JD>krkzDKWq5?gxV*-k6bgZh*|4jvc$HysoL~=l*Zy?WuqIu=vax z^<_s^dd&o5&5lWZziV%AuUNgk!uh)1bw~A9bMw|o-lq7-SA3sL^=C}%?FLTlf`i4!Nr$H$9sDeC%z*Y!;>bxp|We=?_Eea3F9 z_q;WutM)I^vZ1txca-)r@Ir(_(TGA8-liqiOulku^hnh1Zt z!QXH3yDk3TCb({wHR+5iqE2exqOR#X5w6n)?`eBVrrq&Yg!`>ow!)tE#-{a$R-_js zrxn;!^X;j56{&ev=XUFpd0uCZ-#K%$t$&%VKhf5gnBVtEe%~xh&#b)Z9rneR{>725 z*CL;q=*Y9W@{%(uk{9MzwD!5`biO)$-Sot|O;*Pyi)*Ll?2OKEQ)jr%vDxOh+0b=! zq~~B{dU>pU`I&O>x$+|S0gHQn(W&{~rcB@8l{ZHl>!RbdpFg&$F1D(7wzW6k*OKp3 zuaVjvI@b2~ZZ)SRxLw!Fx)%UY>rBDjx~t+uFZ|>dsEkYpYB_;Ph_PZ&PxAqUiycVBc0!`UKH1`$fzA8gRjAm=-#7u zC-{34l6If5rt>lJcdB2s+hBjjV2?NT#%E1i=u&@adiIHja$G0#y=U{iAL>0H zPKj;4-{iNO{14>!KA?`3?n^gWdt$9UPv!SNWpQq`IMv&+#mUCTWZ$O|-cPktqH^HC z=Ek-^sqel+-~9!B*B3I=FHByW>HKx3^I)XsJJOluzwz&*##Tmpk41VnS{xg5Jcn}% zAO8CDkL|UY-P0ECe>X8d|3JsRj~WbyTb_4!9IzdK{Xunp>~Gywr+-@g{(Ce0Pe<9G z&ha(p__X7yUQj!>uQSEy&C$eyvt=-SFQht&2`%A!PH)1 zY+rA3tT!E-ka0{qz#SbOz7CsD{a;6E`X{C7=PNSK>-~LtQ=|G*^+EMVHuZl-^+%tm zKdR8q;_2m?OQ*TD-^@fqVOL39TgfEXr|W$mWqQ7EwI`&VJ+Y=D{YXW+c32LpV^W;& z`8Yqu*Oh5fANiTbv7&mqzGwPsV`4{r;*BXS>ddGP*E!BE&c8CTaaCgY-ujp4cNE#H z)XU#cl+sl@(b6^1uU!nveQo8F)b(wZ`fG9O?Cd=>(csZ84(sE3U(0jygxp>*n9gJb>S?&E&1HR$J5f%)Q_U?nPTdmlH=HrIH4}9I>W1BpJW<$BsbXOM2%^7EhVQ^I2(JzdFa=+OgICo3SN&^_F$()+KmPCU~{K z73Fv~YUVR-pQ#t*R!eDGVd=qx2Xl=rxxSCpZ*)TX!3npj-^LO3mG@bjPvovGcNdns z-;Q*@ZSWj2T(QJdt}Y6*%yqNkyv+%wO%*AdcC|jS`%J6F*E&wUGW4F`s>{ILadmgc zxp(VkeO0?|+p4Rp)hndL(t5z$s$N;{l!J-tT=c6CuhTi!nJ&Z|FYMO2ce~A|J@eA` zXfGGt%$X@g6=_A<8Mp1o6UExAWZb~TL|w!;CzxC(v`hSs*8OLe91`xWUhCSh%EGXL zE0p#^i7D1j{DEtZJ;Q20zq)a|dV%M6UX#;#jji)WTUh$Xx#=H|`bWjym&@u0PFnQ| zmffk&=4Jc5{gn|n-gtETEc+Z=?;MjW*L3gZxOSjn5EZR*i#j3vHffuoMkXJSyUAlCs_LHe^$<~{z zzN@;KaSh+hbgJ`sLupLIHw(Y4ZdRcaLZ9{fwPSqmN0rTu`t=oGE}r3k;62;E#_ZO7 zOLq8M8S1*Zz~t?V(Iu5?XyWRd+HAJ`AMeyY{Jy$rEDwDzG)>+R?zqnK^?5~){_UEu z$_0JjRcF_K@b7<{Qt}@O{*;k~%LaqVC?iouqKrftNq7LEj6@lUG7@DZmV||8bIM4R zkv<1yB!Un@NL-2MHpp#|+hD*%(h=)R+y!VmMcXOqCh~il4$*XorbD4CbE+8+EoW#s zL(3Uj&d_p3sBhD9hL$t5oT24RXj?RwmNT@Rq2&xMXK;c-j#9>)ej7l^5ewM?@8Se; zf;d6Sz3E~8$7=aVS3E~8Cf;d4TM&JZ-f;d5(AWje`DAc!c zf;d5(AWje`DAc!cf;d5(AWl%oQ8+=IAWje`h!YfY6iyH)h!eyK;skMmQh^^Qh!eyK z;sgU++=yHWlY_~@ z$W53WOb#XolM`|jOb#XolY_~@DcI6<5sP7o)E6BO#(I6<5sP7o)E6BO#(I6<5sP7o(32yYL7X5?5GRNe z#0d)ZZJZ!Z5GRNe#0d)ZZJZ!Z5GRNe6mk?!5GRNe#0laAg&c(w#0laAae_EOoS;f(FCMU!Qy2-)hU~(`ym>f(_DDT4LU~(`ym>f(lpq?8T ztYLC6IhY(wPRLO(IhY(w4kiba6LJ*Yf(FCMV=5m>f(FCI^#)$q6}% zZgMz5oFGmRCx{c23j8=hoFGmRCx{aaT!#!e9ymdqAWl$<5ja7dAWje`h!YfI1Wphq zh!eyK;skMmLVX)2h!eyK;skMmLVX)2h!eyK;sk{pg%iXH;skMmI6)yt;RJDlI6<5s zP7o(375H(2I6<5sPB6g5jmVWSIhY(wPP&W2f(F zCMVrRVRA4zm>f(FCI^!f%DXT*m>f(FCI^!f%DXT*m>f(FCMV=5rq06TU~(`yn4FNK zU~(`ym>f(FCO4v-8SpMj3?+sVLy4ipr1~~W3?+sVLy4ipg!(p24kibalVSu+4kiba zgUP|q94kibagUJQda|44lOb#XolY_|#ISM8RlY_~@ zE$P7o)E6T}JP1OwM01C9qy5GRNelwt%<5GRNe#0laA zg&2Vo#0laAae_EOoS;zO#tGsCae_EOoS;zO#tGsCae_EOAxGf^ae_EOoFGn6$Wb^! zoFGmRCx{co2}%WioFGmRCx{aaaB(AYB}@(`2a}WTqA)p_983--2a|)z3FTdw983-- z2a|)z3FTdw983--2a^+W6jNtmaxgiV986BgQ7}1}983--2a_97&J1`LC5941iJ`<$ zVp4q@C5941iJ`<$VnTfzCI^#)$w@H+CI^#)$-(4cazc!tn;c9ICI^#)$-(4=@-9pc zCI^#)$-(3T>bZfz8YTymgUP|b(!Q`YE z0h5Et!Q^0aFgYPc&`k~|2a|)z!Q^0aLU|V^2a|)z!Q^0a0rlL#U=5Rl$-(4cazc)R z$-(4caxgiVoRFjFCWjNm3E~8Cf;d5`z>gEe3E~8Cf;hpzb;y9@ffK|D;sm7_ffK|D z;skMmI6)ys-~@4kI6<5sP7o(3)VFbhI6<5sP7o(3)VFbhI6<5sPEg2EI6<5sP7o)E z6BKe3P7o)E6T}JP1aX2=fgdM`6T}JP1Or^$h+GMigUP|MTqSCI^#)$q6|MCI^#)$-(4cawE!_0q>&3P+}-Clo(1(s&AvjP+}-Clo(1(sBgpM zU~(`yDMrBLU~(`ym>f(_h!J#?gUP|U~(`ym|Q?TH!xVkf(_$Wbskm>f(FCI^!faunUxayUVpAWje`h!d0w{5V0JAWje`h!YH4hYUC# zI6<5sPEd*wI6<5sP7o)E6BJ?uP7o)E6T}JP1aX2weH$l;6T}JP1aX2weH$l;6T}JP z1ce-h6T}JP1aX2mK_N%s1aX2mL7X5?5GN=V_;G?bL7X5?Fu=u)$dxcTm>f(_x{Jc( zU~(`ym>f(FCMT44VRA4zm>f(FCMT44VRA4zm>f(_$Wct4g~`F>U~(`yAxFXFU~(`y zm>f)QL^(6yU6dF~3?+sVLy1ZCZIl>F3?+sVLx~CXZI~QP4kjnX2$&p94kibagUJao zf^Kp!IhY(w4kiba6Uw_VIhY(w4kiba3#jJ?25XocOb#XolM`|jOb#XolY_~@*w@GeRWC5941iJ`=#`Zh`o zC5941iJ`=V`Zi1sCI^#~VgyVMCI^#)$-(4=7(q8Vm>f(FCI^#)$qD6Mm>f(FCI^#) z$pzGN1A{e84kibagUJaw3ML1WgUP|5pSrH=7fH)Q zKR22tZwOC$-ca-Vq+g{>8%wq7|FK&26-U9n3-VV_3U8h6f9;WmZ_JMQcG<0OY!JcW zmH*xywYt^ddPA4;@k4v93-zwot^O&dZl}euF=19({~gN;yW-=j$4y%4?JG|3oziDq z$n<=)eL|G^!tCgbs`=*n`R0=kc170A@^?n)`b&*%o_Xot(@)LHXtjB(rg$$TBzk_I z|MxeEKU#VCLCXbuPWOvhd%F&0rmc&1?2S%Yr@fKVa%Oj=Yn{&Vn=Ml;j-}TA?4qJ% z_fgvw9cRyHRM;Gw!?(vc$Jy-0>9r-sruEN1S*!c#;8W8d?+$bCoLhE5O5>@%-xdC# zKwp^RtFF$_x1XwNdOI_AchL>$ALe_{zUaKq=J!=}v@I!bjO2eN5-?dD*!r z(y=!BR-Nys(dRnrOwO#GPqr+se@CC@sWY|Y`&uSe)i1o=dwP71W2wdOw)Q33u1r6h z;P1_e@iuSWeP*KNvyB-iTg|(EYxCCWd}l1qt+S>j7Cw>GIKHa-hQzv?GQ-wn`nw|i zTW58oIHp&m_iwe_6VVx-kkL}%Ib`^HY1g5;Ql0y*s@nbAZ|ks6Oh|dZ+;_yfU}j8= zDaCQ6!F&1@XNIYJO2Vw<4%hbW<>@`qmM%wEvUjsB#X2wJRE6o2MaC}mv$_2j63k6` zR@ZlO=VYA9_owdG)viixJYjU@`Y$vmShpRia(tNBwqufS`HIl5;JN;de^dAaQ--^} z*ljGgFX&O<`8)c~D|KC2rq!*^p6E$BWBbt?JD)B%H}>3$uG)vnv%gSSnQUyVEzx=I zHufi3+dkB%C&e`y6ZYB62G@4$7w3=5PVH}t@HXen$;&vL@A-J1=WKp#_u0j3Go8mG zy$5yf-FlDPV#>F3Qw`{T`xnZBzXM|F;Mk**UuZ@tM8Ua9v?wRFF`JIQikp0R$avAtr_ z>h?XwrJkltU$xFNPGEd}mTL}P*LQMv(&XAY^@}%qW34M=XWRT4)?{DjTlp`Qz1O(1 z`u&=k^J!^|7H7R&mbuzn;on)gEG^6CxY2iqeZl^d6|ScvQa_C@YCT{)Q)%(;$S-IyHLNr+-vY zST`%K&g0a34p`DQW~Cq2PX74~hPbW`#oGUvQd{%v?d?T<4_bO-v!?a!F`rvEsdu*e zed+uA4gRKwa`y@a7yoSax{UOu=G$xXd+wb+cIKXa&KcI;+4he1$G?_!+aD^5_sp8L zH6y}vA>7otE@69WTVI8xRGm_`Sm)vVuAj$u#(Z*jM$=+Tf0VyOm;PCV@5`Ot5ysAm zvHfr7JF3G?mFmK@DyQ?B^{vyh9{*Zcp>Idz4TUZDMP9og=HA+Oa<|7`SJ;qcy2tK* zsWi5uNMAoUWlh$B`kSlYOe&9aoP2X}@-u5HR-fFlW`22&sVpn?O@rTS^`Ex7i#D!b zZ}8Mc`Q|62*OruTyXU=!3ya7pAEf;lex9%IYf$Pt00)V0X`Wb@|lywOV|ySlkD6ea{$5rK6JnozCx`U+!^e z*Sqw#Oz&rz{(8OfXu03>W?o*VX-D*z-e_KEsheePx10PcO*In|8(yBjEXL^Bp6IJz zYxi~7e9x(`6XmJbS2elkt!}z+pS3yfuIe6R*923Wx?oH+xeLaW*geN0i|PuDttZO2 zr)^rVE1dfHk6Tl3y)V@n9@~`tV3zihneg!D$zcPR^?`5Zp!&!6m2cbE>{u}^&089C zm7`Ygd}+%0G+UCVt=!mO?oa>6PEVn4(WI4cJ(AHG;VI7aICD(><=zGQ)~PX$gBy2g z|E%HBJ*h?UI@k0_=SM%O7-R4rkGdhfJkon?ma(-U&U3z>l7IU5He3{ab&q z`n9T-*ArVNC)!t;n$)eQ)zn&Wbcw-Ko@TK>cs`}Bv9Nx=(HG@;Kg#R1S{$3AjTLD{ zS-+iUY`V{KLEU3_8#@|}+5vfW`}RoRnuwY2J-pl!owgw>_m3I_PZ~=d819e&i5x7GRvxLrxM%qmsz~?P3m^8ecRfN>HI89&yHP1FT3yB zzuBGf(c+@hdaKc`{faUwB7HTRrp)nt6rNtJzMHXzz8^*P?Kbs9=i8g&qxN^qjdXpg zOFw&}s`o?vt&UHkO+BW)?hd=-sO{GIX`l2}m`?As+$&$9$9nFvzJJ~H$Ez}$j~|&b zXSwCn%*2^7g*A>9lOFxJaB;Hz=<|MDm-0l~)})wq zp`)5_;{7qjcc))BFLvVxD{opuydIfJFwvN3Of)8XzZ5MY!7Q?fD-nQDKqw#-5Gve6 zcH$xNka$Qu${IW`+os(FEc~{ diff --git a/kzg_prover/src/chips/range/range_check.rs b/kzg_prover/src/chips/range/range_check.rs index 96c9b0a8..0418249e 100644 --- a/kzg_prover/src/chips/range/range_check.rs +++ b/kzg_prover/src/chips/range/range_check.rs @@ -1,113 +1,112 @@ +use crate::chips::range::utils::decompose_fp_to_byte_pairs; use halo2_proofs::arithmetic::Field; use halo2_proofs::circuit::{AssignedCell, Region, Value}; use halo2_proofs::halo2curves::bn256::Fr as Fp; use halo2_proofs::plonk::{Advice, Column, ConstraintSystem, Error, Expression, Fixed}; use halo2_proofs::poly::Rotation; - use std::fmt::Debug; -use crate::chips::range::utils::decompose_fp_to_bytes; - -/// Configuration for the Range Check Chip +/// Configuration for the Range Check u64 Chip +/// Used to verify that an element lies in the u64 range. /// -/// # Type Parameters +/// # Fields /// -/// * `N_BYTES`: Number of bytes in which the element to be checked should lie +/// * `zs`: Four advice columns - contain the truncated right-shifted values of the element to be checked /// -/// # Fields +/// # Assumptions /// -/// * `zs`: Advice columns - contain the truncated right-shifted values of the element to be checked +/// * The lookup table `range_u16` is by default loaded with values from 0 to 2^16 - 1. /// /// Patterned after [halo2_gadgets](https://github.com/privacy-scaling-explorations/halo2/blob/main/halo2_gadgets/src/utilities/decompose_running_sum.rs) #[derive(Debug, Copy, Clone)] -pub struct RangeCheckConfig { - zs: [Column; N_BYTES], +pub struct RangeCheckU64Config { + zs: [Column; 4], } -/// Helper chip that verfiies that the element witnessed in a given cell lies within a given range defined by N_BYTES. -/// For example, Let's say we want to constraint 0x1f2f3f4f to be within the range N_BYTES=4. +/// Helper chip that verfiies that the element witnessed in a given cell lies within the u64 range. +/// For example, Let's say we want to constraint 0x1f2f3f4f5f6f7f8f to be a u64. +/// Note that the lookup table `range` is by default loaded with values from 0 to 2^16 - 1. /// `z` is the advice column that contains the element to be checked. /// -/// `z = 0x1f2f3f4f` -/// `zs[0] = (0x1f2f3f4f - 0x4f) / 2^8 = 0x1f2f3f` -/// `zs[1] = (0x1f2f3f - 0x3f) / 2^8 = 0x1f2f` -/// `zs[2] = (0x1f2f - 0x2f) / 2^8 = 0x1f` -/// `zs[3] = (0x1f - 0x1f) / 2^8 = 0x00` +/// `z = 0x1f2f3f4f5f6f7f8f` +/// `zs[0] = (0x1f2f3f4f5f6f7f8f - 0x7f8f) / 2^16 = 0x1f2f3f4f5f6f` +/// `zs[1] = (0x1f2f3f4f5f6f - 0xf5f6f) / 2^16 = 0x1f2f3f4f` +/// `zs[2] = (0x1f2f3f4f - 0x3f4f) / 2^16 = 0x1f2f` +/// `zs[3] = (0x1f2f - 0x1f2f) / 2^16 = 0x00` /// -/// z | zs[0] | zs[1] | zs[2] | zs[3] | -/// --------- | ---------- | ---------- | ---------- | ---------- | -/// 0x1f2f3f4f | 0x1f2f3f | 0x1f2f | 0x1f | 0x00 | +/// z | zs[0] | zs[1] | zs[2] | zs[3] | +/// --------- | ---------- | ---------- | ---------- | ---------- | +/// 0x1f2f3f4f5f6f7f8f | 0x1f2f3f4f5f6f | 0x1f2f3f4f | 0x1f2f | 0x00 | /// -/// Column zs[0], at offset 0, contains the truncated right-shifted value z - ks[0] / 2^8 (shift right by 8 bits) where ks[0] is the 0-th decomposition big-endian of the element to be checked -/// Column zs[1], at offset 0, contains the truncated right-shifted value zs[0] - ks[1] / 2^8 (shift right by 8 bits) where ks[1] is the 1-th decomposition big-endian of the element to be checked -/// Column zs[2], at offset 0, contains the truncated right-shifted value zs[1] - ks[2] / 2^8 (shift right by 8 bits) where ks[2] is the 2-th decomposition big-endian of the element to be checked -/// Column zs[3], at offset 0, contains the truncated right-shifted value zs[2] - ks[3] / 2^8 (shift right by 8 bits) where ks[3] is the 3-th decomposition big-endian of the element to be checked +/// Column zs[0], at offset 0, contains the truncated right-shifted value z - ks[0] / 2^16 (shift right by 16 bits) where ks[0] is the 0-th decomposition big-endian of the element to be checked +/// Column zs[1], at offset 0, contains the truncated right-shifted value zs[0] - ks[1] / 2^16 (shift right by 16 bits) where ks[1] is the 1-th decomposition big-endian of the element to be checked +/// Column zs[2], at offset 0, contains the truncated right-shifted value zs[1] - ks[2] / 2^16 (shift right by 16 bits) where ks[2] is the 2-th decomposition big-endian of the element to be checked +/// Column zs[3], at offset 0, contains the truncated right-shifted value zs[2] - ks[3] / 2^16 (shift right by 16 bits) where ks[3] is the 3-th decomposition big-endian of the element to be checked /// /// The contraints that are enforced are: /// 1. -/// z - 2^8⋅zs[0] = ks[0] ∈ lookup_u8 +/// z - 2^16⋅zs[0] = ks[0] ∈ range_u16 /// /// 2. -/// for i = 0..=N_BYTES - 2: -/// zs[i] - 2^8⋅zs[i+1] = ks[i] ∈ lookup_u8 +/// for i = 0..=2: +/// zs[i] - 2^16⋅zs[i+1] = ks[i] ∈ range_u16 /// /// 3. -/// zs[N_BYTES - 1] == 0 +/// zs[3] == 0 #[derive(Debug, Clone)] -pub struct RangeCheckChip { - config: RangeCheckConfig, +pub struct RangeCheckU64Chip { + config: RangeCheckU64Config, } -impl RangeCheckChip { - pub fn construct(config: RangeCheckConfig) -> Self { +impl RangeCheckU64Chip { + pub fn construct(config: RangeCheckU64Config) -> Self { Self { config } } /// Configures the Range Chip + /// Note: the lookup table should be loaded with values from `0` to `2^16 - 1` otherwise the range check will fail. pub fn configure( meta: &mut ConstraintSystem, z: Column, - zs: [Column; N_BYTES], - range: Column, - ) -> RangeCheckConfig { - meta.annotate_lookup_any_column(range, || "LOOKUP_MAXBITS_RANGE"); - + zs: [Column; 4], + range_u16: Column, + ) -> RangeCheckU64Config { // Constraint that the difference between the element to be checked and the 0-th truncated right-shifted value of the element to be within the range. - // z - 2^8⋅zs[0] = ks[0] ∈ lookup_u8 + // z - 2^16⋅zs[0] = ks[0] ∈ range_u16 meta.lookup_any( - "range u8 check for difference between the element to be checked and the 0-th truncated right-shifted value of the element", + "range check in u16 for difference between the element to be checked and the 0-th truncated right-shifted value of the element", |meta| { let element = meta.query_advice(z, Rotation::cur()); let zero_truncation = meta.query_advice(zs[0], Rotation::cur()); - let u8_range = meta.query_fixed(range, Rotation::cur()); + let range_u16 = meta.query_fixed(range_u16, Rotation::cur()); - let diff = element - zero_truncation * Expression::Constant(Fp::from(1 << 8)); + let diff = element - zero_truncation * Expression::Constant(Fp::from(1 << 16)); - vec![(diff, u8_range)] + vec![(diff, range_u16)] }, ); - // For i = 0..=N_BYTES - 2: Constraint that the difference between the i-th truncated right-shifted value and the (i+1)-th truncated right-shifted value to be within the range. - // zs[i] - 2^8⋅zs[i+1] = ks[i] ∈ lookup_u8 - for i in 0..=N_BYTES - 2 { + // For i = 0..=2: Constraint that the difference between the i-th truncated right-shifted value and the (i+1)-th truncated right-shifted value to be within the range. + // zs[i] - 2^16⋅zs[i+1] = ks[i] ∈ range_u16 + for i in 0..=2 { meta.lookup_any( - format!("range u8 check for difference between the {}-th truncated right-shifted value and the {}-th truncated right-shifted value", i, i+1).as_str(), + format!("range check in u16 for difference between the {}-th truncated right-shifted value and the {}-th truncated right-shifted value", i, i+1).as_str(), |meta| { let i_truncation = meta.query_advice(zs[i], Rotation::cur()); let i_plus_one_truncation = meta.query_advice(zs[i + 1], Rotation::cur()); - let u8_range = meta.query_fixed(range, Rotation::cur()); + let range_u16 = meta.query_fixed(range_u16, Rotation::cur()); - let diff = i_truncation - i_plus_one_truncation * Expression::Constant(Fp::from(1 << 8)); + let diff = i_truncation - i_plus_one_truncation * Expression::Constant(Fp::from(1 << 16)); - vec![(diff, u8_range)] + vec![(diff, range_u16)] }, ); } - RangeCheckConfig { zs } + RangeCheckU64Config { zs } } /// Assign the truncated right-shifted values of the element to be checked to the corresponding columns zs at offset 0 starting from the element to be checked. @@ -116,25 +115,25 @@ impl RangeCheckChip { region: &mut Region<'_, Fp>, element: &AssignedCell, ) -> Result<(), Error> { - // Decompose the element in #N_BYTES bytes + // Decompose the element in 4 byte pairs. let ks = element .value() .copied() - .map(|x| decompose_fp_to_bytes(x, N_BYTES)) - .transpose_vec(N_BYTES); + .map(|x| decompose_fp_to_byte_pairs(x, 4)) + .transpose_vec(4); // Initalize an empty vector of cells for the truncated right-shifted values of the element to be checked. - let mut zs = Vec::with_capacity(N_BYTES); + let mut zs = Vec::with_capacity(4); let mut z = element.clone(); - // Calculate 1 / 2^8 - let two_pow_eight_inv = Value::known(Fp::from(1 << 8).invert().unwrap()); + // Calculate 1 / 2^16 + let two_pow_sixteen_inv = Value::known(Fp::from(1 << 16).invert().unwrap()); // Perform the assignment of the truncated right-shifted values to zs columns. for (i, k) in ks.iter().enumerate() { let zs_next = { let k = k.map(|byte| Fp::from(byte as u64)); - let zs_next_val = (z.value().copied() - k) * two_pow_eight_inv; + let zs_next_val = (z.value().copied() - k) * two_pow_sixteen_inv; region.assign_advice( || format!("zs_{:?}", i), self.config.zs[i], @@ -148,7 +147,7 @@ impl RangeCheckChip { } // Constrain the final running sum output to be zero. - region.constrain_constant(zs[N_BYTES - 1].cell(), Fp::from(0))?; + region.constrain_constant(zs[3].cell(), Fp::from(0))?; Ok(()) } diff --git a/kzg_prover/src/chips/range/tests.rs b/kzg_prover/src/chips/range/tests.rs index a1ceeca7..970f0f52 100644 --- a/kzg_prover/src/chips/range/tests.rs +++ b/kzg_prover/src/chips/range/tests.rs @@ -1,4 +1,4 @@ -use crate::chips::range::range_check::{RangeCheckChip, RangeCheckConfig}; +use crate::chips::range::range_check::{RangeCheckU64Chip, RangeCheckU64Config}; use halo2_proofs::{ circuit::{AssignedCell, Layouter, SimpleFloorPlanner, Value}, halo2curves::bn256::Fr as Fp, @@ -85,23 +85,23 @@ impl AddChip { } #[derive(Debug, Clone)] -pub struct TestConfig { +pub struct TestConfig { pub addchip_config: AddConfig, - pub range_check_config: RangeCheckConfig, - pub range: Column, + pub range_check_config: RangeCheckU64Config, + pub range_u16: Column, } // The test circuit takes two inputs a and b. // It adds them together by using the add chip to produce c = a + b. -// Performs a range check on c that should lie in N_BYTES. +// Performs a range check on c that should lie in [0, 2^64 - 1] range. #[derive(Default, Clone, Debug)] -struct TestCircuit { +struct TestCircuit { pub a: Fp, pub b: Fp, } -impl Circuit for TestCircuit { - type Config = TestConfig; +impl Circuit for TestCircuit { + type Config = TestConfig; type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { @@ -109,7 +109,7 @@ impl Circuit for TestCircuit { } fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let range = meta.fixed_column(); + let range_u16 = meta.fixed_column(); let a = meta.advice_column(); let b = meta.advice_column(); @@ -122,7 +122,7 @@ impl Circuit for TestCircuit { let constants = meta.fixed_column(); meta.enable_constant(constants); - let zs = [(); N_BYTES].map(|_| meta.advice_column()); + let zs = [(); 4].map(|_| meta.advice_column()); for column in zs.iter() { meta.enable_equality(*column); @@ -130,7 +130,7 @@ impl Circuit for TestCircuit { let add_selector = meta.selector(); - let range_check_config = RangeCheckChip::::configure(meta, c, zs, range); + let range_check_config = RangeCheckU64Chip::configure(meta, c, zs, range_u16); let addchip_config = AddChip::configure(meta, a, b, c, add_selector); @@ -138,7 +138,7 @@ impl Circuit for TestCircuit { TestConfig { addchip_config, range_check_config, - range, + range_u16, } } } @@ -149,18 +149,18 @@ impl Circuit for TestCircuit { mut layouter: impl Layouter, ) -> Result<(), Error> { // Initiate the range check chip - let range_chip = RangeCheckChip::construct(config.range_check_config); + let range_chip = RangeCheckU64Chip::construct(config.range_check_config); // Load the lookup table - let range = 1 << 8; + let range = 1 << 16; layouter.assign_region( - || format!("load range check table of {} bits", 8 * N_BYTES), + || format!("load range check table of 64 bits"), |mut region| { for i in 0..range { region.assign_fixed( || "assign cell in fixed column", - config.range, + config.range_u16, i, || Value::known(Fp::from(i as u64)), )?; @@ -189,77 +189,49 @@ impl Circuit for TestCircuit { #[cfg(test)] mod testing { + use crate::utils::big_uint_to_fp; + use super::TestCircuit; use halo2_proofs::{ dev::{FailureLocation, MockProver, VerifyFailure}, halo2curves::bn256::Fr as Fp, plonk::Any, }; + use num_bigint::BigUint; - // a = (1 << 16) - 2 = 0xfffe + // a = (1 << 64) - 2 // b = 1 - // c = a + b = 0xffff - // All the values are within 2 bytes range. + // c = a + b + // c is within 8 bytes range. #[test] - fn test_none_overflow_16bits() { - let k = 9; + fn test_none_overflow_64bits() { + let k = 17; - // a: new value - let a = Fp::from((1 << 16) - 2); + let a = BigUint::from(1_u64) << 64; + let a = a - 2_u64; + let a = big_uint_to_fp(&a); let b = Fp::from(1); - let circuit = TestCircuit::<2> { a, b }; + let circuit = TestCircuit { a, b }; let prover = MockProver::run(k, &circuit, vec![]).unwrap(); prover.assert_satisfied(); } - // a = (1 << 16) - 2 = 0xfffe + // a = (1 << 64) - 2 // b = 2 - // c = a + b = 0x10000 - // a and b are within 2 bytes range. - // c overflows 2 bytes so the circuit should fail. + // c = a + b + // c overflows 8 bytes range. #[test] - fn test_overflow_16bits() { - let k = 9; + fn test_overflow_64bits() { + let k = 17; - let a = Fp::from((1 << 16) - 2); + let a = BigUint::from(1_u64) << 64; + let a = a - 2_u64; + let a = big_uint_to_fp(&a); let b = Fp::from(2); - let circuit = TestCircuit::<2> { a, b }; + let circuit = TestCircuit { a, b }; let invalid_prover = MockProver::run(k, &circuit, vec![]).unwrap(); - assert_eq!( - invalid_prover.verify(), - Err(vec![ - VerifyFailure::Permutation { - column: (Any::Fixed, 1).into(), - location: FailureLocation::OutsideRegion { row: 0 } - }, - VerifyFailure::Permutation { - column: (Any::advice(), 4).into(), - location: FailureLocation::InRegion { - region: (2, "Perform range check on c").into(), - offset: 0 - } - }, - ]) - ); - } - - // a is the max value within the range (32 bits / 4 bytes) - // a = 0x-ff-ff-ff-ff - // b = 1 - // a and b are within 4 bytes range. - // c overflows 4 bytes so the circuit should fail. - #[test] - fn test_overflow_32bits() { - let k = 9; - - let a = Fp::from(0xffffffff); - let b = Fp::from(1); - - let circuit = TestCircuit::<4> { a, b }; - let invalid_prover = MockProver::run(k, &circuit, vec![]).unwrap(); - assert_eq!( invalid_prover.verify(), Err(vec![ @@ -290,7 +262,7 @@ mod testing { .titled("Range Check Layout", ("sans-serif", 60)) .unwrap(); - let circuit = TestCircuit::<4> { + let circuit = TestCircuit { a: Fp::from(0x1f2f3f4f), b: Fp::from(1), }; diff --git a/kzg_prover/src/chips/range/utils.rs b/kzg_prover/src/chips/range/utils.rs index 14d1d248..5ace9d4d 100644 --- a/kzg_prover/src/chips/range/utils.rs +++ b/kzg_prover/src/chips/range/utils.rs @@ -29,6 +29,41 @@ pub fn decompose_fp_to_bytes(value: Fp, n: usize) -> Vec { bytes } +/// Converts value Fp to array of n byte pairs in little endian order. +/// If value is decomposed in #byte pairs which are less than n, then the returned byte pairs are padded with 0s at the most significant byte pairs. +/// If value is decomposed in #byte pairs which are greater than n, then the most significant byte pairs are truncated. A warning is printed. +pub fn decompose_fp_to_byte_pairs(value: Fp, n: usize) -> Vec { + let value_biguint = fp_to_big_uint(value); + let mut bytes = value_biguint.to_bytes_le(); + + // Ensure the bytes vector has an even length for pairs of bytes. + if bytes.len() % 2 != 0 { + bytes.push(0); + } + + let mut byte_pairs = Vec::new(); + + // Iterate over the bytes two at a time. + for chunk in bytes.chunks(2) { + // Combine two adjacent bytes into a u16 (2 bytes). + let pair = (chunk[0] as u16) | ((chunk[1] as u16) << 8); + byte_pairs.push(pair); + } + + // Pad with 0s if the number of byte pairs is less than n. + while byte_pairs.len() < n { + byte_pairs.push(0); + } + + // If the byte pairs length exceeds n, print a warning and truncate. + if byte_pairs.len() > n { + println!("Warning: `decompose_fp_to_bytes` value is decomposed in #byte pairs which are greater than n. Truncating the output to fit the specified length."); + byte_pairs.truncate(n); + } + + byte_pairs +} + pub fn pow_of_two(by: usize) -> Fp { let res = BigUint::from(1u8) << by; big_uint_to_fp(&res) @@ -57,7 +92,15 @@ mod testing { assert_eq!(bytes, vec![0x4f, 0x3f, 0x2f, 0x1f]); } - // convert a 32 bit number in 6 bytes. Should correctly convert to 6 bytes in which the first 2 bytes are 0 padded. + // convert a 32 bit number in 2 byte pairs. Should correctly convert to 2 byte pairs + #[test] + fn test_decompose_fp_byte_pairs_no_padding() { + let f = Fp::from(0x1f2f3f4f); + let bytes = decompose_fp_to_byte_pairs(f, 2); + assert_eq!(bytes, vec![0x3f4f, 0x1f2f]); + } + + // convert a 32 bit number in 6 bytes. Should correctly convert to 6 bytes in which the last 2 bytes are 0 padded. #[test] fn test_decompose_fp_to_bytes_padding() { let f = Fp::from(0x1f2f3f4f); @@ -65,6 +108,14 @@ mod testing { assert_eq!(bytes, vec![0x4f, 0x3f, 0x2f, 0x1f, 0x00, 0x00]); } + // convert a 32 bit number in 3 byte pairs. Should correctly convert to 3 byte pairs in which the last pair is 0 padded. + #[test] + fn test_decompose_fp_to_byte_pairs_padding() { + let f = Fp::from(0x1f2f3f4f); + let bytes = decompose_fp_to_byte_pairs(f, 3); + assert_eq!(bytes, vec![0x3f4f, 0x1f2f, 0x00]); + } + // convert a 32 bit number in 2 bytes. Should convert to 2 bytes and truncate the most significant bytes and emit a warning #[test] fn test_decompose_fp_to_bytes_overflow() { @@ -73,6 +124,14 @@ mod testing { assert_eq!(bytes, vec![0x4f, 0x3f]); } + // convert a 32 bit number in 1 byte pair. Should convert to a byte pair and truncate the most significant byte pair and emit a warning + #[test] + fn test_decompose_fp_to_byte_pairs_overflow() { + let f = Fp::from(0x1f2f3f4f); + let bytes = decompose_fp_to_byte_pairs(f, 1); + assert_eq!(bytes, vec![0x3f4f]); + } + // convert a 40 bit number in 2 bytes. Should convert to 2 most significant bytes and truncate the least significant byte #[test] fn test_decompose_fp_to_bytes_overflow_2() { diff --git a/kzg_prover/src/circuits/tests.rs b/kzg_prover/src/circuits/tests.rs index e39f0370..313a3e88 100644 --- a/kzg_prover/src/circuits/tests.rs +++ b/kzg_prover/src/circuits/tests.rs @@ -10,12 +10,11 @@ mod test { use crate::entry::Entry; use crate::utils::parse_csv_to_entries; use halo2_proofs::dev::{FailureLocation, MockProver, VerifyFailure}; + use halo2_proofs::halo2curves::bn256::Fr as Fp; use halo2_proofs::plonk::Any; use num_bigint::BigUint; - const K: u32 = 9; - - const N_BYTES: usize = 8; + const K: u32 = 17; const N_CURRENCIES: usize = 2; const N_USERS: usize = 16; @@ -25,10 +24,9 @@ mod test { let mut entries: Vec> = vec![Entry::init_empty(); N_USERS]; let mut cryptos = vec![Cryptocurrency::init_empty(); N_CURRENCIES]; - parse_csv_to_entries::<&str, N_CURRENCIES, N_BYTES>(path, &mut entries, &mut cryptos) - .unwrap(); + parse_csv_to_entries::<&str, N_CURRENCIES>(path, &mut entries, &mut cryptos).unwrap(); - let circuit = UnivariateGrandSum::::init(entries.to_vec()); + let circuit = UnivariateGrandSum::::init(entries.to_vec()); let valid_prover = MockProver::run(K, &circuit, vec![vec![]]).unwrap(); @@ -40,7 +38,7 @@ mod test { const N_USERS: usize = 16; // Initialize an empty circuit - let circuit = UnivariateGrandSum::::init_empty(); + let circuit = UnivariateGrandSum::::init_empty(); // Generate a universal trusted setup for testing purposes. // @@ -57,8 +55,7 @@ mod test { let mut cryptos = vec![Cryptocurrency::init_empty(); N_CURRENCIES]; let _ = - parse_csv_to_entries::<&str, N_CURRENCIES, N_BYTES>(path, &mut entries, &mut cryptos) - .unwrap(); + parse_csv_to_entries::<&str, N_CURRENCIES>(path, &mut entries, &mut cryptos).unwrap(); // Calculate total for all entry columns let mut csv_total: Vec = vec![BigUint::from(0u32); N_CURRENCIES]; @@ -69,7 +66,7 @@ mod test { } } - let circuit = UnivariateGrandSum::::init(entries.to_vec()); + let circuit = UnivariateGrandSum::::init(entries.to_vec()); let valid_prover = MockProver::run(K, &circuit, vec![vec![]]).unwrap(); @@ -168,7 +165,7 @@ mod test { const N_USERS: usize = 16; // Initialize an empty circuit - let circuit = UnivariateGrandSum::::init_empty(); + let circuit = UnivariateGrandSum::::init_empty(); // Generate a universal trusted setup for testing purposes. // @@ -184,8 +181,7 @@ mod test { let mut entries: Vec> = vec![Entry::init_empty(); N_USERS]; let mut cryptos = vec![Cryptocurrency::init_empty(); N_CURRENCIES]; - parse_csv_to_entries::<&str, N_CURRENCIES, N_BYTES>(path, &mut entries, &mut cryptos) - .unwrap(); + parse_csv_to_entries::<&str, N_CURRENCIES>(path, &mut entries, &mut cryptos).unwrap(); // Calculate total for all entry columns let mut csv_total: Vec = vec![BigUint::from(0u32); N_CURRENCIES]; @@ -196,7 +192,7 @@ mod test { } } - let circuit = UnivariateGrandSum::::init(entries.to_vec()); + let circuit = UnivariateGrandSum::::init(entries.to_vec()); let valid_prover = MockProver::run(K, &circuit, vec![vec![]]).unwrap(); @@ -247,17 +243,16 @@ mod test { // TODO add more negative tests } - // Building a proof using as input a csv file with an entry that is not in range [0, 2^N_BYTES*8 - 1] should fail the range check constraint on the leaf balance + // Building a proof using as input a csv file with an entry that is not in range [0, 2^64 - 1] should fail the range check constraint on the leaf balance #[test] fn test_balance_not_in_range() { let path = "../csv/entry_16_overflow.csv"; let mut entries: Vec> = vec![Entry::init_empty(); N_USERS]; let mut cryptos = vec![Cryptocurrency::init_empty(); N_CURRENCIES]; - parse_csv_to_entries::<&str, N_CURRENCIES, N_BYTES>(path, &mut entries, &mut cryptos) - .unwrap(); + parse_csv_to_entries::<&str, N_CURRENCIES>(path, &mut entries, &mut cryptos).unwrap(); - let circuit = UnivariateGrandSum::::init(entries.to_vec()); + let circuit = UnivariateGrandSum::::init(entries.to_vec()); let invalid_prover = MockProver::run(K, &circuit, vec![vec![]]).unwrap(); @@ -266,21 +261,21 @@ mod test { Err(vec![ VerifyFailure::Permutation { column: (Any::Fixed, 0).into(), - location: FailureLocation::OutsideRegion { row: 256 } + location: FailureLocation::OutsideRegion { row: 65536 } }, VerifyFailure::Permutation { column: (Any::Fixed, 0).into(), - location: FailureLocation::OutsideRegion { row: 259 } + location: FailureLocation::OutsideRegion { row: 65539 } }, VerifyFailure::Permutation { - column: (Any::advice(), 10).into(), + column: (Any::advice(), 6).into(), location: FailureLocation::InRegion { region: (2, "Perform range check on balance 0 of user 0").into(), offset: 0 } }, VerifyFailure::Permutation { - column: (Any::advice(), 18).into(), + column: (Any::advice(), 10).into(), location: FailureLocation::InRegion { region: (5, "Perform range check on balance 1 of user 1").into(), offset: 0 @@ -300,10 +295,9 @@ mod test { let mut entries: Vec> = vec![Entry::init_empty(); N_USERS]; let mut cryptos = vec![Cryptocurrency::init_empty(); N_CURRENCIES]; let _ = - parse_csv_to_entries::<&str, N_CURRENCIES, N_BYTES>(path, &mut entries, &mut cryptos) - .unwrap(); + parse_csv_to_entries::<&str, N_CURRENCIES>(path, &mut entries, &mut cryptos).unwrap(); - let circuit = UnivariateGrandSum::::init(entries); + let circuit = UnivariateGrandSum::::init(entries); let root = BitMapBackend::new("prints/univariate-grand-sum-layout.png", (2048, 32768)) .into_drawing_area(); diff --git a/kzg_prover/src/circuits/univariate_grand_sum.rs b/kzg_prover/src/circuits/univariate_grand_sum.rs index eb5ff7b7..69edc2c8 100644 --- a/kzg_prover/src/circuits/univariate_grand_sum.rs +++ b/kzg_prover/src/circuits/univariate_grand_sum.rs @@ -1,4 +1,4 @@ -use crate::chips::range::range_check::{RangeCheckChip, RangeCheckConfig}; +use crate::chips::range::range_check::{RangeCheckU64Chip, RangeCheckU64Config}; use crate::entry::Entry; use crate::utils::big_uint_to_fp; use halo2_proofs::circuit::{AssignedCell, Layouter, SimpleFloorPlanner, Value}; @@ -6,14 +6,11 @@ use halo2_proofs::halo2curves::bn256::Fr as Fp; use halo2_proofs::plonk::{Advice, Circuit, Column, ConstraintSystem, Error, Fixed}; #[derive(Clone)] -pub struct UnivariateGrandSum -{ +pub struct UnivariateGrandSum { pub entries: Vec>, } -impl - UnivariateGrandSum -{ +impl UnivariateGrandSum { pub fn init_empty() -> Self { Self { entries: vec![Entry::init_empty(); N_USERS], @@ -31,7 +28,6 @@ impl /// Configuration for the Mst Inclusion circuit /// # Type Parameters /// -/// * `N_BYTES`: The number of bytes in which the balances should lie /// * `N_CURRENCIES`: The number of currencies for which the solvency is verified. /// /// # Fields @@ -39,20 +35,19 @@ impl /// * `username`: Advice column used to store the usernames of the users /// * `balances`: Advice columns used to store the balances of the users /// * `range_check_configs`: Configurations for the range check chip -/// * `range`: Fixed column used to store the lookup table for the range check chip +/// * `range_u16`: Fixed column used to store the lookup table [0, 2^16 - 1] for the range check chip #[derive(Debug, Clone)] -pub struct UnivariateGrandSumConfig +pub struct UnivariateGrandSumConfig where [(); N_CURRENCIES + 1]:, { username: Column, balances: [Column; N_CURRENCIES], - range_check_configs: [RangeCheckConfig; N_CURRENCIES], - range: Column, + range_check_configs: [RangeCheckU64Config; N_CURRENCIES], + range_u16: Column, } -impl - UnivariateGrandSumConfig +impl UnivariateGrandSumConfig where [(); N_CURRENCIES + 1]:, { @@ -61,25 +56,25 @@ where let balances = [(); N_CURRENCIES].map(|_| meta.unblinded_advice_column()); - let range = meta.fixed_column(); + let range_u16 = meta.fixed_column(); - meta.enable_constant(range); + meta.enable_constant(range_u16); - meta.annotate_lookup_any_column(range, || "LOOKUP_MAXBITS_RANGE"); + meta.annotate_lookup_any_column(range_u16, || "LOOKUP_MAXBITS_RANGE"); // Create an empty array of range check configs let mut range_check_configs = Vec::with_capacity(N_CURRENCIES); for i in 0..N_CURRENCIES { let z = balances[i]; - // Create N_BYTES advice columns for each range check chip - let zs = [(); N_BYTES].map(|_| meta.advice_column()); + // Create 4 advice columns for each range check chip + let zs = [(); 4].map(|_| meta.advice_column()); for column in zs.iter() { meta.enable_equality(*column); } - let range_check_config = RangeCheckChip::::configure(meta, z, zs, range); + let range_check_config = RangeCheckU64Chip::configure(meta, z, zs, range_u16); range_check_configs.push(range_check_config); } @@ -91,7 +86,7 @@ where username, balances, range_check_configs: range_check_configs.try_into().unwrap(), - range, + range_u16, } } /// Assigns the entries to the circuit @@ -138,12 +133,12 @@ where } } -impl Circuit - for UnivariateGrandSum +impl Circuit + for UnivariateGrandSum where [(); N_CURRENCIES + 1]:, { - type Config = UnivariateGrandSumConfig; + type Config = UnivariateGrandSumConfig; type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { @@ -152,7 +147,7 @@ where /// Configures the circuit fn configure(meta: &mut ConstraintSystem) -> Self::Config { - UnivariateGrandSumConfig::::configure(meta) + UnivariateGrandSumConfig::::configure(meta) } fn synthesize( @@ -164,19 +159,19 @@ where let range_check_chips = config .range_check_configs .iter() - .map(|config| RangeCheckChip::construct(*config)) + .map(|config| RangeCheckU64Chip::construct(*config)) .collect::>(); - // Load lookup table to perform range check on individual balances -> Each balance should be in the range [0, 2^8 - 1] - let range = 1 << 8; + // Load lookup table for range check u64 chip + let range = 1 << 16; layouter.assign_region( - || format!("load range check table of {} bits", 8 * N_BYTES), + || format!("load range check table of 16 bits"), |mut region| { for i in 0..range { region.assign_fixed( || "assign cell in fixed column", - config.range, + config.range_u16, i, || Value::known(Fp::from(i as u64)), )?; diff --git a/kzg_prover/src/utils/csv_parser.rs b/kzg_prover/src/utils/csv_parser.rs index 4f2403b0..9f3abe89 100644 --- a/kzg_prover/src/utils/csv_parser.rs +++ b/kzg_prover/src/utils/csv_parser.rs @@ -7,7 +7,7 @@ use std::path::Path; use crate::cryptocurrency::Cryptocurrency; use crate::entry::Entry; -pub fn parse_csv_to_entries, const N_ASSETS: usize, const N_BYTES: usize>( +pub fn parse_csv_to_entries, const N_ASSETS: usize>( path: P, entries: &mut [Entry], cryptocurrencies: &mut [Cryptocurrency], diff --git a/zk_prover/src/chips/range/utils.rs b/zk_prover/src/chips/range/utils.rs index c246816a..1b20a29a 100644 --- a/zk_prover/src/chips/range/utils.rs +++ b/zk_prover/src/chips/range/utils.rs @@ -2,7 +2,7 @@ use crate::merkle_sum_tree::utils::{big_uint_to_fp, fp_to_big_uint}; use halo2_proofs::halo2curves::bn256::Fr as Fp; use num_bigint::BigUint; -/// Converts value Fp to n bytes of bytes in little endian order. +/// Converts value Fp to array of n bytes in little endian order. /// If value is decomposed in #bytes which are less than n, then the returned bytes are padded with 0s at the most significant bytes. /// Example: /// decompose_fp_to_bytes(0x1f2f3f, 4) -> [0x3f, 0x2f, 0x1f, 0x00] From e7258f97b14ff867805c9c199c915f1ce343b377 Mon Sep 17 00:00:00 2001 From: "enrico.eth" <85900164+enricobottazzi@users.noreply.github.com> Date: Tue, 19 Dec 2023 09:28:57 +0100 Subject: [PATCH 2/2] Testing to `v2` (#231) * chore: minor fixes * feat: add `test_invalid_poly_degree_univariate_grand_sum_full_prover` test * chore: parametrize `UnivariateGrandSumConfig` by `N_USERS` * test: add `entry_15.csv` test * fix: rm `test_diff_n_users_univariate_grand_sum_full_prover` test * fix: merge conflicts --- kzg_prover/src/circuits/tests.rs | 163 +++++++++++------- .../src/circuits/univariate_grand_sum.rs | 17 +- 2 files changed, 110 insertions(+), 70 deletions(-) diff --git a/kzg_prover/src/circuits/tests.rs b/kzg_prover/src/circuits/tests.rs index 313a3e88..3cd04f4d 100644 --- a/kzg_prover/src/circuits/tests.rs +++ b/kzg_prover/src/circuits/tests.rs @@ -10,8 +10,9 @@ mod test { use crate::entry::Entry; use crate::utils::parse_csv_to_entries; use halo2_proofs::dev::{FailureLocation, MockProver, VerifyFailure}; - use halo2_proofs::halo2curves::bn256::Fr as Fp; - use halo2_proofs::plonk::Any; + use halo2_proofs::halo2curves::bn256::{Bn256, Fr as Fp, G1Affine}; + use halo2_proofs::plonk::{Any, ProvingKey, VerifyingKey}; + use halo2_proofs::poly::kzg::commitment::ParamsKZG; use num_bigint::BigUint; const K: u32 = 17; @@ -35,27 +36,9 @@ mod test { #[test] fn test_valid_univariate_grand_sum_full_prover() { - const N_USERS: usize = 16; - - // Initialize an empty circuit - let circuit = UnivariateGrandSum::::init_empty(); - - // Generate a universal trusted setup for testing purposes. - // - // The verification key (vk) and the proving key (pk) are then generated. - // An empty circuit is used here to emphasize that the circuit inputs are not relevant when generating the keys. - // Important: The dimensions of the circuit used to generate the keys must match those of the circuit used to generate the proof. - // In this case, the dimensions are represented by the number fo users. - let (params, pk, vk) = generate_setup_artifacts(K, None, circuit).unwrap(); - - // Only now we can instantiate the circuit with the actual inputs let path = "../csv/entry_16.csv"; - let mut entries: Vec> = vec![Entry::init_empty(); N_USERS]; - let mut cryptos = vec![Cryptocurrency::init_empty(); N_CURRENCIES]; - - let _ = - parse_csv_to_entries::<&str, N_CURRENCIES>(path, &mut entries, &mut cryptos).unwrap(); + let (entries, circuit, pk, vk, params) = set_up::(path); // Calculate total for all entry columns let mut csv_total: Vec = vec![BigUint::from(0u32); N_CURRENCIES]; @@ -66,12 +49,6 @@ mod test { } } - let circuit = UnivariateGrandSum::::init(entries.to_vec()); - - let valid_prover = MockProver::run(K, &circuit, vec![vec![]]).unwrap(); - - valid_prover.assert_satisfied(); - // 1. Proving phase // The Custodian generates the ZK-SNARK Halo2 proof that commits to the user entry values in advice polynomials // and also range-checks the user balance values @@ -160,43 +137,12 @@ mod test { } } + // The prover communicates an invalid omega to the verifier, therefore the opening proof of user inclusion should fail #[test] - fn test_invalid_univariate_grand_sum_proof() { - const N_USERS: usize = 16; - - // Initialize an empty circuit - let circuit = UnivariateGrandSum::::init_empty(); - - // Generate a universal trusted setup for testing purposes. - // - // The verification key (vk) and the proving key (pk) are then generated. - // An empty circuit is used here to emphasize that the circuit inputs are not relevant when generating the keys. - // Important: The dimensions of the circuit used to generate the keys must match those of the circuit used to generate the proof. - // In this case, the dimensions are represented by the number fo users. - let (params, pk, vk) = generate_setup_artifacts(K, None, circuit).unwrap(); - - // Only now we can instantiate the circuit with the actual inputs + fn test_invalid_omega_univariate_grand_sum_proof() { let path = "../csv/entry_16.csv"; - let mut entries: Vec> = vec![Entry::init_empty(); N_USERS]; - let mut cryptos = vec![Cryptocurrency::init_empty(); N_CURRENCIES]; - - parse_csv_to_entries::<&str, N_CURRENCIES>(path, &mut entries, &mut cryptos).unwrap(); - - // Calculate total for all entry columns - let mut csv_total: Vec = vec![BigUint::from(0u32); N_CURRENCIES]; - - for entry in &entries { - for (i, balance) in entry.balances().iter().enumerate() { - csv_total[i] += balance; - } - } - - let circuit = UnivariateGrandSum::::init(entries.to_vec()); - - let valid_prover = MockProver::run(K, &circuit, vec![vec![]]).unwrap(); - - valid_prover.assert_satisfied(); + let (_, circuit, pk, vk, params) = set_up::(path); // 1. Proving phase // The Custodian generates the ZK proof @@ -239,8 +185,67 @@ mod test { ); //The verification should fail assert!(!balances_verified); + } + + // The prover communicates an invalid polynomial degree to the verifier (smaller than the actual degree). This will result in an understated grand sum + #[test] + fn test_invalid_poly_degree_univariate_grand_sum_full_prover() { + let path = "../csv/entry_16.csv"; + + let (entries, circuit, pk, vk, params) = set_up::(path); + + // Calculate total for all entry columns + let mut csv_total: Vec = vec![BigUint::from(0u32); N_CURRENCIES]; + + for entry in &entries { + for (i, balance) in entry.balances().iter().enumerate() { + csv_total[i] += balance; + } + } + + // 1. Proving phase + // The Custodian generates the ZK-SNARK Halo2 proof that commits to the user entry values in advice polynomials + // and also range-checks the user balance values + let (zk_snark_proof, advice_polys, _) = + full_prover(¶ms, &pk, circuit.clone(), vec![vec![]]); + + // Both the Custodian and the Verifier know what column range are the balance columns + // (The first column is the user IDs) + let balance_column_range = 1..N_CURRENCIES + 1; + + // The Custodian makes a batch opening proof of all user balance polynomials at x = 0 for the Verifier + let grand_sums_batch_proof = open_grand_sums::( + &advice_polys.advice_polys, + &advice_polys.advice_blinds, + ¶ms, + balance_column_range, + ); + + // 2. Verification phase + // The Verifier verifies the ZK proof + assert!(full_verifier(¶ms, &vk, &zk_snark_proof, vec![vec![]])); + + // The Custodian communicates the (invalid) polynomial degree to the Verifier + let invalid_poly_degree = u64::try_from(advice_polys.advice_polys[0].len()).unwrap() - 1; + + // Both the Custodian and the Verifier know what column range are the balance columns + let balance_column_range = 1..N_CURRENCIES + 1; - // TODO add more negative tests + // The Custodian communicates the KZG batch opening transcript to the Verifier + // The Verifier verifies the KZG batch opening and calculates the grand sums + let (verified, grand_sum) = verify_grand_sum_openings::( + ¶ms, + &zk_snark_proof, + grand_sums_batch_proof, + invalid_poly_degree, + balance_column_range, + ); + + // The opened grand sum is smaller than the actual sum of balances extracted from the csv file + assert!(verified); + for i in 0..N_CURRENCIES { + assert_ne!(csv_total[i], grand_sum[i]); + } } // Building a proof using as input a csv file with an entry that is not in range [0, 2^64 - 1] should fail the range check constraint on the leaf balance @@ -310,4 +315,38 @@ mod test { .render(K, &circuit, &root) .unwrap(); } + + fn set_up( + path: &str, + ) -> ( + Vec>, + UnivariateGrandSum, + ProvingKey, + VerifyingKey, + ParamsKZG, + ) + where + [(); N_CURRENCIES + 1]:, + { + // Initialize an empty circuit + let circuit = UnivariateGrandSum::::init_empty(); + + // Generate a universal trusted setup for testing purposes. + // + // The verification key (vk) and the proving key (pk) are then generated. + // An empty circuit is used here to emphasize that the circuit inputs are not relevant when generating the keys. + // Important: The dimensions of the circuit used to generate the keys must match those of the circuit used to generate the proof. + // In this case, the dimensions are represented by the number fo users. + let (params, pk, vk) = generate_setup_artifacts(K, None, circuit).unwrap(); + + // Only now we can instantiate the circuit with the actual inputs + let mut entries: Vec> = vec![Entry::init_empty(); N_USERS]; + let mut cryptos = vec![Cryptocurrency::init_empty(); N_CURRENCIES]; + + parse_csv_to_entries::<&str, N_CURRENCIES>(path, &mut entries, &mut cryptos).unwrap(); + + let circuit = UnivariateGrandSum::::init(entries.to_vec()); + + (entries, circuit, pk, vk, params) + } } diff --git a/kzg_prover/src/circuits/univariate_grand_sum.rs b/kzg_prover/src/circuits/univariate_grand_sum.rs index 69edc2c8..d23fc82c 100644 --- a/kzg_prover/src/circuits/univariate_grand_sum.rs +++ b/kzg_prover/src/circuits/univariate_grand_sum.rs @@ -29,6 +29,7 @@ impl UnivariateGrandSum UnivariateGrandSum +pub struct UnivariateGrandSumConfig where [(); N_CURRENCIES + 1]:, { @@ -47,7 +48,8 @@ where range_u16: Column, } -impl UnivariateGrandSumConfig +impl + UnivariateGrandSumConfig where [(); N_CURRENCIES + 1]:, { @@ -103,17 +105,17 @@ where // create a bidimensional vector to store the assigned balances. The first dimension is N_USERS, the second dimension is N_CURRENCIES let mut assigned_balances = vec![]; - for (i, entry) in entries.iter().enumerate() { + for i in 0..N_USERS { region.assign_advice( || "username", self.username, i, - || Value::known(big_uint_to_fp(entry.username_as_big_uint())), + || Value::known(big_uint_to_fp(entries[i].username_as_big_uint())), )?; let mut assigned_balances_row = vec![]; - for (j, balance) in entry.balances().iter().enumerate() { + for (j, balance) in entries[i].balances().iter().enumerate() { let assigned_balance = region.assign_advice( || format!("balance {}", j), self.balances[j], @@ -138,16 +140,15 @@ impl Circuit where [(); N_CURRENCIES + 1]:, { - type Config = UnivariateGrandSumConfig; + type Config = UnivariateGrandSumConfig; type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { Self::init_empty() } - /// Configures the circuit fn configure(meta: &mut ConstraintSystem) -> Self::Config { - UnivariateGrandSumConfig::::configure(meta) + UnivariateGrandSumConfig::::configure(meta) } fn synthesize(