From 81a6d8eb2162bc0190010bf9b692394b969f3b3e Mon Sep 17 00:00:00 2001 From: Zach Deane-Mayer <581590+zachmayer@users.noreply.github.com> Date: Fri, 9 Aug 2024 16:32:44 -0400 Subject: [PATCH] Test reorg (#308) * put 2 files of random tests into the correct test files * reorg-mopre * miss one coverage line * 100% test coverage * some more reorg * remove redudant tests, but also removed too many stop cases * refactor caretList tests * fix lint * re add cases to get to 100% * utils:: * refactor caretEnsemble tests * refactor multiclass tests * refactor class selection tests * done with test refactor * tests fail on some machines, loosen them up --- Makefile | 30 +- coverage.rds | Bin 175137 -> 175079 bytes tests/testthat/test-S3-generic-extensions.R | 203 ----- tests/testthat/test-caretEnsemble.R | 365 +++++---- tests/testthat/test-caretList.R | 800 ++++---------------- tests/testthat/test-caretPredict.R | 197 ++++- tests/testthat/test-caretStack.R | 465 ++++++------ tests/testthat/test-classSelection.R | 68 +- tests/testthat/test-ensembleMethods.R | 115 --- tests/testthat/test-helper_functions.R | 444 ----------- tests/testthat/test-multiclass.R | 175 ++--- tests/testthat/test-permutationImportance.R | 281 +++---- 12 files changed, 965 insertions(+), 2178 deletions(-) delete mode 100644 tests/testthat/test-S3-generic-extensions.R delete mode 100644 tests/testthat/test-ensembleMethods.R delete mode 100644 tests/testthat/test-helper_functions.R diff --git a/Makefile b/Makefile index 6513f3ea..52d08fb2 100644 --- a/Makefile +++ b/Makefile @@ -3,21 +3,21 @@ .PHONY: help help: @echo "Available targets:" - @echo " all - Run clean, fix-style, document, install, build-vignettes, lint, spell, test, check, coverage" - @echo " install-deps - Install dependencies" - @echo " install - Install the whole package, including dependencies" - @echo " document - Generate documentation" - @echo " update-test-fixtures - Update test fixtures" - @echo " test - Run unit tests" - @echo " coverage - Generate coverage reports" - @echo " check - Run R CMD check as CRAN" - @echo " fix-style - Auto style the code" - @echo " lint - Check the code for lint" - @echo " spell - Check spelling" - @echo " build - Build the package" - @echo " build-vignettes - Build vignettes" - @echo " release - Release to CRAN" - @echo " clean - Clean up generated files" + @echo " all Run clean, fix-style, document, install, build-vignettes, lint, spell, test, check, coverage" + @echo " install-deps Install dependencies" + @echo " install Install the whole package, including dependencies" + @echo " document Generate documentation" + @echo " update-test-fixtures Update test fixtures" + @echo " test Run unit tests" + @echo " coverage Generate coverage reports" + @echo " check Run R CMD check as CRAN" + @echo " fix-style Auto style the code" + @echo " lint Check the code for lint" + @echo " spell Check spelling" + @echo " build Build the package" + @echo " build-vignettes Build vignettes" + @echo " release Release to CRAN" + @echo " clean Clean up generated files" .PHONY: all all: clean fix-style document install build-vignettes lint spell test check coverage diff --git a/coverage.rds b/coverage.rds index e427756365e82eaac41071085f0880033d11a324..247b11a103a8b995a6bf02d968537fb35025d478 100644 GIT binary patch delta 103307 zcmX_odt6NU|G!E%Nq4QnbR)ExbxE#sQc_6`+O&#hFQ~MP&{mq6Q$#bRZ3r!4ifEP0 z?uw$!A(L{+j9O;ZXfl-~)yy$a`k@#*0|2ZIfNc3g0bfBN(FV^hDZ#I|j5CA|&%&}`GcX8d5s za+|g#eFF{eHrv(bo@-M9y$*=o-qG1KME(80B!L@TY+02_`9j`!?E9^=okixd8w)e_ z>Y*X4)|I`Pa(DO<)s+7qm9Z?d@JatEmQ7~iae0wYWC58s$?pn9W{?Z|?{vhzX-|{f zMOdH9n~|92tBias+0wHsjIl-=uef_bTRWA$Cq%hV-uUR+%au)+v;n>DkNgrhqDK|m zS2&Zsu$_viUY87eWENwY_TzNK9G$LMw)8{yG}ipg7TAv?n;|e~M24rf(o6*|O>#GR z#xb6GqH?=DBbR5J_;(OGS8@1}-z#4hS$n_N#m*k~*Jky)j0?vs?aF4{$7WAKrZma- z$?2xWtH%zyDYF!-6!*8xoFlVgIcP&GzFmba(5_G{juy&HSxdAnp5OjHW{FHi&zv%P zDk2}lepeSaOm205zqM^R*EY6-`S0ydb`DG<-R?*c-PDWUnv!sEr*zDd7xL%5u9nMF zkXwsV%AB{lwx;ZicA!!J)L)h#uta9-3zkLT(eecAbCSQ-=4jsq<T3Wlvhxc{L|!=dRZ;v+`#YPnG2=7H*Hx z&J97Go71$0x$-K9MR0yYYwUg2gMFc~9T~NMs+gz!V5+^wr>!RUud(Mcrxxb7SLw=Z zM`dTud5W9Fw=jEA|1zsubX}-4%uBx)zu6ntEIW4=cI&As%%0yrk#}Ao`m>xq$+Lz9 zPEA+O(flJt-hy*mvTAKazN{609dFi{rjd^^%qvceop4e6GsvdMv=0fPN{Qm(C9OrU zjm(ctH+^+o@o<~8#*-HYZYS29X(Ow7oZ-pX1y=E`;$g1V4ZP2t!#8V&<5)dDqyAix zZ=GsHd4rbEjo+wNdx*$_aE5n93mz#Kz@}MF;L!^?>zmhsI1}Ig`fFT>^CywhsQg);@W{J;_FPZa3ToQ;7pVNWvmfr7OGI%6>ydg}0dpTiO zR`;vwUDnF`|2nT7={=n^o$V1**kgAup|OVw`V@V)C4b9@CR$>YAZyqBWZ%cm4G1tpcxadC6TG}LHM zX-RPwtl{uI>lEv9w5xygK0*CB*f&}L-qje6aKz0T4~3<@!0db0a)uo|PjCV}^PN1& zWIyIH`Scmeka~MHofvbdgm~bEa7CaOqabDhqu7(>1}f___;HCP_Pm%$cfZd2g|`m$m!K z?~K5$BTZ+S^s>7RyT6Y?^)#O0P0na(3L55dJPS+jh9FVPtr#)1!EKj78+r3gvm(l%_}E+8&% z%~kpbe45fWD1j!?`+`fSEU>Aa4Kof=#oT< z_nu3mpZQm7`6(E>Rm$@OafupAKE;Kp+i}PVrrFf#>hBf94w}F=jeWd9E13ow23<(A zt<%-qE3V=oSL{cwEl$tGEP5Yv;Xd=$;$nq@wu%osd8+7WUbtSmLH{NkpQ|XS!@o=H zIK=Spw|%rx(Lp;^+Vl+s)@U-7L$`P}O}8eIwWjCGtN9zS-%IcP%1GTH`x0mmLzWGH zG?RatLq8g6<_nr@^y5c`JB5ym-zl7IwDS8>arf1#q%dq>bkU-#_azm>z@`k7d) zFmTFE*p2+l-^%weR|M8$*RJ)lFBxFRu+UW`IK+qf13p_m=ycWSPR?4DI9z$# z6I2-8Rb|KCVwq{y9PV4ZH8Noh_9KXTSukiP10r+zz2Ke=$vW>nhtOQGqq0qmW#W%^ zZmd~0zsqLmb_Un+`^eQGAL^YTQuuhWa_RQjFychy5AhacF<7e%M`SATQfXngd6sL% z3A_Mo2kfeR|Hywgz9=o*6Uh-jm%Je&qbD3)?18P`gxFZOV-u&*hg`MYhUc#1mRnhO zPf){pLZQ(c8`sLOgrgVW*&P{H=$6Aos|ih3&1VQHZ%OV@GIFVxUivqJ%uO!g2YO*iI40TlBcN9 zz7ctkwazj4g)HNHqTZd-ipC2y+tBll7mb?Gj--V{Hh~!8Nt^L&nD+W*68@7sZpwaU z=wKDeLG#)QK%Px{TL%pB9yqQmzJ{KAe(lR7vr)@?OpqeM!Ex3 zDE{axb4fII9&RYfk>U)R)Q;F3eB3MzDgro<70y^E?g&$*p~XU@PjeYY^_skZFKmWq zqe?D*8)iuT7~cIcR^Uq3qu>8%)`FMHS+-f;V7vH>h|fncmVq@Jlg>HYKl^Y1cQ7Be z*Z8&#=d6X$YoDl`Ph~jlC2;s}!_aurhbX#5#dQ&l&9lBl{m?ma2MH16fI>IFP7XydcJli^bjqc7B?R#nd_qRsz>Gv-vNIubYkw}D|MepQuhlzltOXiKuM#xFNt zj$1ElhACQ0FNWRAJi5CwJ#VI7h2Uac7`$% zVjEI_ndsY>X7Hf<)~VkmtOrFl44oDni41ebeCpKQREDegBkv*-$Zn*8RzDV|f1fuK zGZXU750oqB0L}@xN4t=2+JVXQni`%s^fYJup{}=&*B)gf_6;S?8E3VAfNr(IY?*CS zL35mQMkK&f?}PPmPVt6pKjnn54D&dLKg^qncq;6wH+?R>dJZm>9kAu@xvnzD)KgR?oaA&QhH>1GTSzu`|+W( z?pPj&t(rC5&H8nhwD5Ltq26F?Dkq*;7dvYfw7ELQ8`A0GHmXGE( znI(@L|D8G4d(_&2c?Y&rUVb#O8~~u`W#& zJ9~BipxJ&n|}DwTNf!M6pIb$b zA&VyYMmcPa%~fc=zdl%sIB3=oQiC%h+dhx_9Nsb3+hrz+Rrxq=|R!(!c-?$&>>ki z0R6i2_UT{9oRUI_=1boWz8)&mzRSA-L5`F~$n&V3({(!mq)5?|eR{r#vA4oY4fnuW zb%(>jc{KQx8aB;rnG-88UifbY#_4sr3IEZsO}eNpHMb65x%KH5Cw?)g@gU5mY%?s| z`cdlC=t=k7Ks=N?@r%GBfhq#tx-PA#A)QP15o+o3E&?;nQ5NR-wFyq$^gVElF|XpC z><57H=w3Y?@7`Kgl6Va#v{8BAz;JX^j&?l9HAcJp6_n=QUkXaZz3t+9#eQ#WX)j<} zg&YKs!VGJrWlsGT?P8aDCsl&AKch4jyl2EmKw7!sLw6MV9iV2Lh=k(Y=A&pZ8(e!FDIQ(MN7tq9v?i}8UO$=MHiq<*S&``n!^;^Gb2Tv;m7#50PEaSfA&%ffBVc9}^z>^nsEs8b+*X9TzK1M10u^7CI!%5n5|8D6j{@Z4nL7ors?(o;?AlhD$oLDsTu#)w7y2FJ?v6ZG)9R) z6MNIoLOe&!kQMmcMK#~I4%Kb;VczyNioA_?i^_uj)Mrf7?D-$#jr&S?=~pp|lPYQZ zb+|QO=Ac>ER%IWLvErmu0)A!-sbIYo206) zSM}1SCMwXZiw!pV33Sa|=W`XVLb>Vvm%+ME){a$$soKU|< ze$n2n0Bzi{xXQ_&&YUv$t<7(ml{`poc~zO-F?*fYRl2VJigsrC1V4Vo3M>2|Xc1Rg z)YbXg6G3GptLW9G+Ut3LA|)#vk=YFe>Odz1XbFEW8(J%uOxX|bc!BBU_cmk};xjv7 zLJMxp(H_oCSitCJBV15x9F*NT_gFs0ca>ium5pph2a*S#U!p8E(ZpyMdt)pBye1g(>e%kslHHKmYctjkg;+1TbkM+|n{2~Z4Oz%j zIf3|zvLn+~JHFy9kwu68i_fz=5rOLkT(N5KM|0*lK40!?audJgleOxmt13G91#$(X z2U4ny?+C=cxsERizC%0JPin`{9UkZl=ylo8+|dn79JP{T@c!5b_`1cTKK*xtE<)7R zo}-up_&y({?V}63@v{wUyqbn&4u6YKqXQ<%jjPlRR9Y5f&jbXf7L|qqR6SWde_gmV z1fc3VHGGheqC?npk2<~KyR-*4Dh~e_5j08D--yTvNwoX5Tn$(LkBv5R=&)&*{=`Xq zD?nI`6#!AL`Y<;N-T9;YiLoWZKnFS|bFwCl7l)v-9CTTovfJr#!h>0KJ$0jAV0|cb zE@_>A4CNoa$Q0k(=5ilh8z=Sk;B5w~aTZV^7Lg~IXHIG6KXg+q461>u$$bwa$j6$l zh`+qZq<8ocN`$KeESpj}Q5dnbr%b)AEdkt)fXH$MamZ z+SmTLW?(FVL-*)GT@Q2^JjOigP2t79+rK9Ia>3e)wCr; zsd9mdZd&jie1fQ|?!pYyzghg@UrGca=+WSTQftjFxya-S^@HI`11adMY-%JrEXf}B zJZN`f%vVT@O8#J2s5IoPa~AM8jjpOh0Io%TfMAWz!>knFyunUQ#U&<=Le*nzo0EsF1Y@Pq;S3U1a^7jxT~8TJ%Q`OpfI#>&w3 zCi;rwYl1p5{Qp`~Io7X~&j->ETYY(L1=v2`H%i`HyL02p)cG59f2?&u*HrM6M@pVj z_0`X8xm4de?Ta6NJOl(Vln#3cEdC2pmNslYaI)#NST6e>l*Pa>bWrVZK()55os8_x;rr_|!FwJC1Dtp^-M zPX1-+nY)+%BM5}?+~v?8P4QBl%iB(Q#p#EJc{bSlUfJb^ zqz=hu!4%a{-g!z#Toe(G23LEUS-;AY`L=&QHxO{Z`t3l+=w{O`yznFFYTeIirR!k| zDS6m?)rZBNEKl*PUw#z z8c@U5>c=$eZ~wPzU=S%OJ_huU%$8a(8^p|dT}0kJZ;L5biD{5Bq!*f+m=>tKCs6;S zC@`?08JKsk%MkjhKc*L&mU#LjTrx%;HQ`E3Q?S4tA3aKVPOt0L*;5ELnAf4w1f|&> zYdQfC&Mx^C7qAp|UILf!KKz;8%p_%5Sn|Z6C(#yR2N;>s!2SXSOW$+r9WENfh!x6k zLZ&7U=evPMyl#f-99Ym|7tOyQx8T{z%RvdqYrP>e4KSD+_|%RuuR8s>kd5!E#J?|) z?F;UN<9*<`66}uGK%s819A!;!@+yLTA)3^NP=3|fxefIIxMMb8Zq%Xw+z-2QvaS1T zgHG|J+TIp<53y}zPu2{sK~q|gy{f;^Isomu_i(dxn3y9D2+1akucPpZhPaKHo$$ON zviJA+-4RBt5Z_aYuP%@s3Vwl0!a7PPWcJT^146`Hho>n>RcguP$gW<SwO(CPtZjzjosB8h)-zy}@hhyob{RE~x68jb{?oPUXmpUA6*^A$W7Y_ht4&5;r- ze-_V4V-6;!=bS=Y zZDpYJGVc=b%T3u1fNE{H_F@FyeOmn!))M=r##xB4O*`BoUlL5Hm1jK0vRuNc3AEW4}3*|0X{1ZqaRv zxwR@|Qo55?bPWGB94Zw!e*8SM%{_M}TvV2K{b)4M5hcOs^j^k4BN&cX0f zv|fu>En0}2bc5lcjOxMT^+%TUs9n8`nB}C)eq*pa;j*{jq_`ulbIYKNcU<7rE~_rh z!PjaRsM;eD~t5%pIU`^LyYXP`v)Vk?$DJ&+^*Ja|B{oqsCOxb9y;RDmMc{J?TuF5o~BiWOsEPfm=FUjq$4`XwEie*foyma)ZY zb|)E&xRYZwB%jeML{0h*^m}(%sxFh=kWY+12Ev-R8$S`RECAu}j;Cr#^G6-HBCk3$ zD-$dz&Sv8~A<`TUG_LVr!pJl*po|+qcve_yFLFKt2cnf*e@yNrjOwB}1E?*&9E?0y zu>RFTyTH7XZW6B_$ji1+-pTom6+b?BK`61OV>WR{ueMSkQB%sadxC~}0hq`^v$ib` zJhQI;82FC0^3-sd)-|-FSXb%+3rrGEzqPEPEgXFVb0zliXyUw417N}UK85Vorq4*l z=g2iXjPYrtJjPP)N9YaTNn-(sU^^};%!Y|6r$BYW?zA4} zf>r1ueRRFbG%U_+;e_)nKI}fVcHlRl{>SUd^963<#!ly(W-;g216bUQ)PX`lhi3sr z88oVc`>y%GFn>{s%w-97XdvwAnV9YC6M?Ztvb2W;kbPV(4oY}9amKrfNl(=02MGUt@S8@KX_X#D@hjAg-n3ddB|UOcq8{|*@SydsP+q9QG|4+3-P zk6?Z??hOxx^aT#w_;Qi~6pPZk%|dJ&3xZ8$9n0u*!T4pmBw zLy?o(`0`qEvVN!E=uyy8{h7CG%3=B>zgR08NN89X+6E+KR_#FFMj+@N5gab4I}tPE zDq%_~1K`KT`0` zGA*l){~&B_uKh4A=71S}8`Sp~i<@13|A|50)D}gs)T}Q~4{)w7$o1m&}%PLdYEDKgL&=U{p)oT~Y8BNzqdxrH4KEWo z`c{^67J6-%$~(?j3R3sFFwQIsRW42A=QRB;R?`-bPB<_lkvMyrUBB|&*~W$ZlZ^R5 ztcfL(uErbdL}>uP&jfJELJku|La^h~=m>gyQA(V1)fRnIthC#cw<&pOd_@|m5Rj*y zXmmLcg)e6}g-9Dccp=Hg!8Jr(%W#0~*sAM>jF_G0iF*gr;Mf5MbN&pM^} zh+9S=$Hg6Z$Z7SEhq2hx2-D7;rH7>A6zd*UduAuT93B|Uv%**X%Y%Y$xAhf*+2hjw z0K$IZs5wrQj-|@GLEW@Y)L78KUk`epN>fAJg@nzs>&FZUa!{v!24iG8;Rum&gvACK z$-{_Qm7P2fK_>K(^MJE1+b47LM#)P@4xh*8Vc4?%f`sZ|T+!HBh5tDWXTv7^Oa~=A z6^{e{Ey!q&${yjhi|UG><8x5iW4}ZA5jPZijqOgdXtruu`ZT4V)oWJto0Z8~ zI^XBTS1-%9;nx>O)gFhNE{dCdQ`V)kfd2-#Vw}rs?e=wr^OoFoP@Ty8lNRGnh;JK# zu(F@Ir6c9@W_c;FBwXqWW?0&fllDVZn-Zy)T|TtqJ1S)Wpg?QRP~SG-s{uk{(2~`~cCeLku|Gns6>IIzo-ZX2O_%r|fe(*T^2XN)c z2_S~G<9A1QdY~bmG<$I=Zo{Ej)lHbx@)9^SH*sk(7;4*n8Xo-Z1L=}5_C;~XD_-Ga zstL>w?|X4`DbCYRY4f#Ie?U%YKj-`|`KLZcYSLB(MoPE!U#$=!L3DgtS|AvTfv}TV z{aS&(_dj6QUu(iN9NYs65t0u~mj~cUPUB3~2@@u^lW2xCcaAJrPA^x#Fjr5GxkkWm zp&&*=5RG!cF(Vke`Ab(s5bTCWKO_KDm4#YY;+l~F+B-l{%YO{KP9q>xs;M3wss&}n zM#wk2Vq@rHxpHLA;(A%VJv>*@yhwI_^TXJk#0b(54yOk3AmeHEyG{CfPvhP8i}v7s z*LwYN0Q#KTWNx2;1FDWCyK+;u!)TeqH|Mua0Krr)n5yf~q2Q#=jPxKHPVyQp;!;gI zu*rXMN6mL_RhH_>>-)>}dNvp^{sb7k`!ft!Mjcf*a(Xat;lo9s1(3dq^i@?o{-dwC zq8XoFj9nw5Cd>(PWh=|BAQ$v2)2Mk(w#g$I(G9JDU4|RVVt7I5PA~_?eb3-8O!W$g zqy6ni*Xv`Q!gXe@kb0SfgIEIZadmIOn$=G; zw$|oTA8slSoFb~3HX?}>KAf%^H#>^c;t4TnMvnMMApmCqr>P+pzgu`UllVaOGF4*FLaQJ&Q*X;wsj#c@}lL%Qx^f zEf3vQBVdOg)(}EjpwiVWqggOX8uP^pas;?`in1{`E=Ff8Z?Fr^9LGZ{k-%~h&n~PZ zi9Cb{cF3mzf?l$YyH#h?+G+xh(e{c5P%V zqlHOQ-3MR6;uGAFC4{?VTS2c(1i|ckT3s<7`W)7&c_i^LeoPCZ)`;I#tR|;y)O{~q zKQLI|n*>al8_}`HBG6aPsRoPX*mPZ84h6=1Mvs7`(?$k}ZFn;^e_|70aQhkDZ+}H-J?8e3V6jxo_>NB6eL~ zF-z5AQfs`lg7Ee5Ha87;UxqH;NV}EG0GS6L1>Z{xLGOcEUn)9}d?R4JAfTK|dRCZn z2Mi1lj&^_0Fm3thnWWCW8!|h2>-F7c@wy8umdWwoI(SjaZU^zOh|@ndqk|SSkhCpN zRKXg$^jmPyFzE*DZ$Y2v&g`TW=ph?@!3xT`L*Lb|>%@{K);tzj@RJSKs{MXxNlEqK zIf@5q^$kS;rUM{x^U>->@Y1(s_vWhfITWUZV0FWwv+0i?>YNeWV2xB!;VO{0O!I^vqW|0%OBj?P8CoW2;$ZznLrDO}n)FyB5nu<_B(1o1i`YwevRN z2K9@;n{p^XgqN8%v776QwR23E+S{Hz9Vxyi#^Tc?p_w+a^h!7@hzCQGu;-G2N;u~^ zXoRr+ME2s$PMzEV`fv)b-gK3?|U>EXy4=Ri_bc$|H5n0l1INp2|c^vMVZ}B+nUa3lX3#f3hLk` zBky|Gcnr7o%f=ril-2wYg4#STi)x9N(@c9_!RiGax+^JUOM3S9n(Ai#1r^_vo=PcL z#)17aZ|PQk@xW|*8$Dw#ZAQx;^K&-?i!j}+IABixC2S0Iq@Q=qXN{TAf7uqgD6+H1 zu1B9|dqK;zLRWDwmvCfZ;M&ITgC}OA8{1awm1`C%?(J<{=!A%l)l*UqKgC7I;rf7u zp=)I26A6QZwA`kd$s^b9QEBISxc^o9#F*b#?^b*lCuJ$Z!{XYK%+(`6+5tuyUD3ZS zDKuYJVvvjiAJ>`#_wK5wk7J#CW~_{syqrJ9eF64$u2z=w7D_=8KRp?kp-?0Y-CW*2 z7Qk8x@g_ss1})UE63_jFtRys{aCB|2*FU&-8kF1QUtUih$A_pu>ooH0k#8DKeZjw% ziacp^#ohRY1{vXk5CQt6(r%HsvaEH_K~;da5)-whatKW4B9+6_Kef_;vA`xdeb)>A z*~>%JW9X$E3I@-|q&Wf84JiqvLY1gZ=^bA4_pokkH;-e6Ekoy8gKX3-b z8~9C?Z;seVZsjD>x~hlXgYu03EKjmj5BaA5s$beRI8{B6nnK`&Q<;%T!}wiBM8dL% zzde0d`uiGh2hs#lSjl`>Bt7cxb56gAbZ397arZemvxH0tTjVc2$_~ zQ=7q7sKl%3-~qHcWrb(C2LHQvKblHVwx_L&c;ARyaqHM2W%hPFB6dhuJmgNkR7Tr% zOhF4Cx;D@^B!uJ4YVl4KUZDi(fI<1%y&m;+k&C9uivA&c?vQ9205@p08h!oMzXZ1f z|B_A##>M-MTU+^daINz7Gi2Euj8b00-xW2~? zTt^W>T*^SH)=vvG77|u^be91}>YX6Fnq^R+jT=JRfYE$0T{DQGd398U`9rRRms;15+>_r(fn$iDxY$0q>IQR`~W5{vS2d zCWcdcGje6I=Wf$v&YJygRa4bE{%`_R0PamTAKcrpBtyuwQ@sT>MMeN*#8t@~EosV+Zv{J!NdB0MTF^U7Gb)A!t{yOiGSzH@zgY=2%t$g;nOuyfZ8Y_J?hq9 zQ{LbYhux#Rv;UB8%$LO7L1ky4)?K!Vuiu7s*F{p8`iyv36MQ3cj?(GT*zwJ2F3J*c zZsc7+?9EAJ?;>rgXH2Cr|Dv1XW0hAsZC@q-R!UwIa2=9=+t)vK(Z);92AD@+ojeZT zv<&d7d1tD-1m|pr_Fd%gY+kOXJsk^J#-=%oyQ(f;0QP{zzQ*lx0A!3eFNC56AjfW> z{_E|hhQXs}q0lb4=JZn9ohho6pfY%$zTH(a2aJCbf*Ahd&&Ul?a9W`UfVG{}j_MnJ zptid@KsGCR&HO#Pt@~|E_3B+aK?aaLfgu$Ro(wqU=K&Z}6&yz7xtAmKnRm`FlJ>Fj zG;DZ0ChC{1PICwIZ+Z@9D>jKYY`f#obdChd;<9u68&=4?7~~(+{28xrMo!!Y{L5#} zZ#QKR5ZHTnfyNtiR9Je(NH?I-ihET@W1eD*75N@9(ok@sE->Uq+lVMp0cW*24-!Y} zo^ThwwMR${yWItY4)7EPd3V7PR{2JG%;9DIz~hCd8qaF~ZTjvieF$C#bX^3(v&UUuTkRP}@=+#Hw;w#ws7 z)=NaX@X9V2N(O+N5Q6+7W?&pH6WbMPIbFvSC3Ie+;J5BYI zhkuY-^>>=-(S@AspMhFm45o{f6K^hVP4o4jTYVZKxn{(Hr+FR%hvX4N{Y!u^hvy=G zDha4!^UQXJ4`nwt7(%Ytd>SA7ofsP%!kT&B7`%8BFVuvo%eGe*=GMVG#< zW7#=nPzkMfrE(;w3%Qk**U;z*AYm(hn#kk#U=E7ixKvC_0$Bd<)2cTSdg`gO^pCt# z`omM3yd=CTPWDDnI+KF%1xElcIl3aV1_1|74&P)2hG|`QcZt5moBKs+aHyi7QCWXa zMqb0z2g*((^xVzhC?(Ar+ur7!#X#K@Ozy%1-q=L1!87KTFBa8n>EZt8CJl{l4q080 zf4}K}4}s+yR(LnnOW> z!x8`{bG7ls|LjPP$du&a}zD!7&0*IF=q(=N1MDbxX}IoZjJ^Qz?hUKn zrfJ=Wap3Bv#ehV1HiP2^KhbbCV;%Q-TOu=g=a<*YUaY*e!uP;d5P6}MaAFV*>jGX;{lh~P)}Wk08+ClpNw%EQbwaE1bKHIX@SwI@KDpyePv9!0`6m z-qL8Nx(EUxn_xUl2RxPSdV6vsI0&#EyUXmMGQ1DYJuzmHW(j%?(CACN(4uhKh1N#B zd7Um{#8Yt|dRoT1q5@|%$>ms&3HJMsvJ?0p4RC@7Z))9mts8tn^rnY^U-kCTymC<9 zm`iyzOb-C~-a`9yT;0x*Dg6_mP@D#jE)#lqj@F`g`ak6H%U#_bAO*Tfju}hAF4MgQ z^UA5nPifvg?U1W55}}D+G;J zXx{*cK#F8AgJc5AdTGJ{?+o=e_WnWy&zF-u?dy_e{nL;X25jY2Pu9^O9t8~8j=*1& z9I7R>l%qm8n)G2GZF<)Jpd?!N(?NThD_{WkanWS9Uh5f^GtSzf5^VsP)gL-J`GT!2?#{?Wo-r3(M6tUo|ORbZ5+W5_yt<(;5Fcl zDRcfH%Td9)oa#!)T}2MFh1s@c?}{R zCMjb;gffu^yI_hxc%DQYWrl#~X43U+jnSkZ%p>uAI{i1wiJ&VoV|@cPh_a@<7;kN1 zk_l(!G3}~H=DWcljbf{7hJlJ!C1frEI|oHE7MD|HBDR6l=4!4UGQ1-oI}8Au4)bc^ z`WrW;;_yR}Cpzl8X+fhE34Ei7b^>~h-a+SwO@f*zP z{pIJN9u6Ij*M4SGz5t!NJ9oR_I^(VN+oEE{4d{wGZfc!s2OQ`Lj+juv5tI6*0RZb$ZVjGrh3|kc^Aeqih*2VemskjaJ8Ou+N+pG>6mVN%1Q<{~R3IlaB zs}9-b`oVSYWd1*l#k#}NCy)HDGR69YdbN5;cIvszE`PJq5u7fDOqaG4azJxC&0Y7; zqPs|p1UAPGv^l5Xw-4BA!`9yjHylnMehj%SZMh%>#-b(Mg)6pTzs}5{^hW{X%W3TI z(Y0yC1)mc1Kve`xT6Fizeus>}{&9fPs)38r+~l%A?V1kGZG8t66CgZ0i=S%JT{)e) z_H_&3g5_{^x94c|SE0G_4^ZH0dGMQv9e*}XS3Lk(wk-{uzB zWuH|0L)x_KI4cd5r6PWD02C1A@C ze4*GxuUO~YbQhFJ?8!~$#aSQ5Ue)n;U|RvKyke1f+K}H0v>(4+q^#AusZ{k^e1k%i zvpLO1Nj1SYw>j54;71gqV_$Z}-ZXL^B;~>@c8kDIKq7N|cH5PhbMg3}z;@&coQic5 zmLqWDg7)_ZH^@2$LxH*i*TQeG!4@xpt!f8gk_tzHqZ&n#8~_1I$4VU_GJq+Go=vy; z6xV^s*OT=D%tUhx{QZah==O>4^S@NPEE zNjxa)=Fozg-bp4-Yk~wT%Ew??C<;8_@ILHenbsW8Wz81-{^_5dXnMl+bRVM~INPkV zyT*73&O(mx_UQ~OwXVnF0IjWhgjh9Qoj}|WQGsDLI25@Zxy!(cm%GBish6OogfaZN zANlD#S50Ue;Pt5S*e3-1Nry=!96bek9+-x?v?W=njbo)mknrtg)9REp_aK=)7Rn`q z-^Zimhr#lV`^!P)8tCg5l4pGC=8a9m8M>;vvt1K{VPTn5Uou~zZm zfQOOo4lnF5o>{$1ru8PKF?w{p6!HS_8ghjE%BehvW3cJJ1C$Eio{@n-Y#R%h+-aoy9< z^8k8`zUt_+68$V74$+*HWjU@~<42e<5J1P9GkyXMaT!Nu(NrJ@2MHbmZ4A&N+k;SM zyWzh4BO%zX?La)s-xTY0z}rjL7jD6>7iEn2il5>Wk&hD$KQ;}K!wkx$|Hajfi!KI^ zfJx1M){U&jVB+|K-KQ7$Cb@ggZ&-9z`|-sDj@55FKMclMus^y>C<3qNpB>T%5Out> zz7ebxxIo@y;Ms9y!Z+e>AWMXr)G}|EF5Sf+*OYo2X^H0!Ag`Pb93U3`X;;nnxQ zcn5PE@`HNjh`R}&_#GIxSAa=eva$3n5@rtyzXS<$l!3veZ7rNpnEgFap-ARNNd*cd zmF&$o7;bcZahMKf#%{xN1lYP+O>Y1d$8Y|N3o}2U=ug}7Twk?|dbXTAfEd>QjVOfef+#Gakc3VWX(NP?Tb6G76;6~Sp<>%tib@hf;%IY7 zlvUx1Z#~$Vkk!p6u-qs}q2R51|1%=- zQo*nw&Q;@HIo!4hV4Kou9S#k#(rGn5t~q0T z2`xdh4kjZbV+Nqfsv=$E;WrL24CkT`P3neQuVDaVZhJZr+AJIfIxhQaz! zV~KMamK^IN#%CqIAy^DM)R|tw+M<2}DloUF*wQj`-WAdtgC93p)vIY@j-KRgdkm8a_94GR5qPvj>J z(ym&$Ay!BCWfZK(TPLzFsocHlC;JNm$uLM!uQP!WkF#!7h`$lV?iJOH#mBvmW~+DIrz-1-nnEU^gO-Pg>2%JXZgW#VBQdV zxkLg^0ImLs+`PK6Viza7^dtY3rFF<%Y&rk<-m8kmT zk`2Nh(SmdMzi_DkoL)as*pNjfwbK1>Hj8X%2U@GnRmBTO6lcx*!n5M{oCm4Nf*Q+# z_Pt@Vv^)!K_GN7GxUe4cPaR=n8_pD{{fj$U?()!8F_>YGg=SmPV8zrZ9y+Q8z2?}v0q1t+toAh@j*~(urlxmULNhXQ`N-#YNl+>Y* zc|Bs|@)eW&sZ-6R+EIpsh@2_nUQ|Yo;ULcZ?F4u1&zcI*b1%qX1;(J27UVNre=ETl z2PRzekWF%bW^1Lp^Zlh8aI4qIXmNQfAJfG%0Z3epcfUqZt6Rk*Pyjm*rf$@RTPX#r z2EUFW$MumqssAPl@`z%u@26&P_41^t_4I>0(-I>}C~qUxkE(h=Q2Or_iq!&0%2+t< zQv;V~AT<1>;L&Gs_B->S@m;QSQk!HT9P!&in`DStK)Xk7!e2n_-4Jn5c?Oq-&LN?+ zenIr7jtuV9O#X$YE#nHlBnhJIN$4hRwkRjARoeLX+gG6x^45fA?8Za7&@ob-;>jr) z{xxMWlD95z#>S+I9QcTiGpBEFBgC%F*yyiJ+jdQ6Gp3s=+9r~WAdkN*N&8GrPzE~> zCT`R!|FmMXckYNfiee5kvAhY1J``L3kMbduBM%cNTyh6+pn+m3d2vd2jj+-#7xYiM z!0~&YU>dW4@_SitJvT5h5W*G9g_@*Zc2839S|<|E$O-s9sbv!~AHZ~`!q8o!II3W< zD!f*>s;8-JBxYC3*ry7DW~D^WS9%i9*)KNgG4ouW2T5E=k7b7=kzt)`TNRu{=g2^^_zzT zvG+p9BAG6goxZ_3NPY`XF0^+pnFX{;Y#dVmho;(@~|2#$cqZnX~7NY^0ycF*Q` zI13rm3>BU#v0w{lLJ@~f&F2DI3u3?tR0+c&{9Ep5?CRR1C8DHXWgqcGv`790_UWk&* z6o*0t@c^8NFA?n!>d*q|aWG%dH*Zf;ncQUy^@*PwRh(3CWPu0;347?&bcv8P_UAVi z6khpXoCFDd!S4p#cN2-Q0XQRkLkx*}LK+0h%vBZk*tv}`%p)02n!Ouegb+^uJ~o?NPAth)bBOJ*u%hmA+&1w7>&TPFg~M_E)Mg1joNg^g_br?cGGi*m#tr625_ZxcxMGBxiBg6vpTpiJG($Aic@Uy; zD4P$3W}W&7sSvLt7Lv?1l2uC1P9|SC9W(6@fE~bCLjuMA4BdnwW!+z4v$nsss0|!m zqdj*&gm157jWXDOC0cS!rG2cT`>rm4z5!Jg-%Q?&X}VJ_8FB00IQvae|9q-+-+mlH zeTqiIT}(lftL*ArevWKYHW&%VzyQh{kVF0j3bmG-({v-;06*02gK2FdQDoEp@?ks# zl^nLcoiStTF85B$(8T*Nb^=<91K(#o+5}ABL}H@o7EIA*M_2}}sXg@0WcV>@a?$?U zM^ufnM5+&2MRmE)dKS`-7*BdbDLL^Bxx7XpNgeQ6g@1w7N-<(gebajG3y;r@Lh)f{$)a-cT>QKbsf z#d9F+as7s46Wa83mPJl>w-2)97+(5FTk_ufUZ>H!l%Xlx)!y@aD=F@O6p&SBjDu?L zd510AZbK8hARB^4m=QKFy+Js2lyF`Rc10uv1_)bmx&Mut83p>kN-@K>UFJ#kXZ--5 z9Cu#8ZAf@I6x3rW?x_iXwNrhW8K^qi`Xl}fpx8jEr$a>;7(k)@k_W?mS7jdA6iopU z1NlJ?8}XUbQv}mOM!=;Nu?Nq0Q~nJjsC4L*6t`SA!rz&W-KGBhA`x>08c;`G?h8?M zWh%n}xd@%Ujk60G;0Ld|mv`=Pa*g9r-Q^s>y1dYr0R}Z83~C3?=K;oy-dtEY$t(~% z^pfuJFLnB%yjB1Be|Lg1Ks2J@b4kQBBBg4{`k_Ji&w=Kwg~ZLZpbf}ueIr$CM#17D z^Q8Ve@2c!&sqRT^Y-#rmuhUX$-EdkW9Xpez8djlQQFvuv6pJ8 zd6l6NY+^q3F@%1@0Al}%?GfXo6nNs8Le2eX#oO_}DdcKch~(da_g&b+mJ0V6ZG7rL z#FN65mA*P{0}-R(If3y8?z;h>_2-QI92&75APgJJ5(f$~TZw;we(>aMK*J8RV7%oI zw9wSRWP)u4=;yqlDY7>ZPW*&oC5bT9mwTu0)%x#V(?Qyql4MW)(5th`^)Ls#d~v&Z zm41bcTU?6@UQ}L-L(auow6oQ*hi`aI549N1N?XreD#W zydTd5_I~f?4g+m;Zqky--hs|j`MBRkao=<)Yk1PK)+39gEHpG}5%-N*9Jws~%iP#J zr|$#SeY=v6uhU?ggkWrW_e}(!9KzO7o`c^ST$}Xz?#E?$U}B`O4N#x&csUjl3ssy3aDi{sOugv*0*9P98vRY^HNX_jf#u zABJ?Elw@^dn=lhaEESP;I(amJ^IT!l`0%|xEtrHr9w)7&;t|J+FGlWj`oT_ocWVoI zbFo~;T_4)jR_E+V240bFk=>7T5@kY(rkh8s?C0%%{B@vfm?yEs4gFw48}-|Li0~g} z_oWVIb#feU)PbHr**@4&Ul6i)`{!0B#hAsq*Zdo?lM>8aQ|@f`ermHP==qUq{a-z9 zr#^qDam z+$O5N2u5)D@;J$uU#$RsFKAvintNgBE#}G+r*r}Kks{GOE)VQ>$4&2H_3?0;w8vA` zL4Y;iI>>s8Tja5nzI)T~g0-?2N!9{4P^y9dr^ZGM8!|oKKAZWq{q)ng} z{vDj4WVsX{sZMe61@@X1w0yw~pz>SwCnwmk<{kD2JDTN`m=T-O*#r}~>e!ASqCqGM zggTLr=9+y|=0wW#P>D$zcty-LH*+JM-I#L)OU|7(k}%6rTuKNwD^+p z*6X{Qjx=s!(@^+@-BW4^w#=|^(zB)aWMS27`X+5(c2CL-r7Nd|m+#y_t_%TpHnRg7 zv8U5H{wrI^{Gn!02kzwL1)EJ&jHC3U^32tE4Jbqog5T|D-<*z*261F&*Y*p3u30dEDrgNvDPZjP}zmjJH??9VgVtSy5SC4_UfdOEe zYNe3k(iw5eI!c4u+SAe_FwWx0KNlJEzZ zULC$OP~`f(bvia3*1Q5(Hq3wgzNCN*U8jNB#y;e5MG$GK|W zX|^ZSh`tMYJ*aPtrnJfL39vaxyhqL(&4S=m!n+8l2jgmJXY7*dPYU;7U2Zno(8Yrp zjhz9gV~sLw-#6iW@?)Dodcbz7A7{ztii?t=NlR+)NWU?P$$?I;lSf-)?UC>sN?H^^ zCXMd6>+9By=ikVnXbaDKKQ7FGoZELGdFo*c;#u=&i)G&KxELPvv8AiY6ds0Am;`qF}?*{>Sk)I0E^Y8 zDyyPi&S4{SP8fW;_O^1xP_43^TV}F4H#Bz?h>r3s-GXf2y7(HyIOv$ylR<|a#|3c{ zxK@dcN+$nnyLT~U%AJgRQ>t&QW9vV@R%Rcs^rSMy-#32jhRzSL;v?TwyHWeSiyv<2 zs>)7ZXV~7Swo0ZUHu8Yxjj8>^T3gfU!L$P^`@1F3Wdu(zxjvA{T?s}UpPIOn-!qnx zng3YP%}PO;$?B3_INK~33cio}n;6<^qj!N&d;NRRJo3|p9EvO-1sNPPM8tcc?RA%u z`B0{+PQ4vLm5|s!;m>N1U2E4_&*WU8D(852n;!4hA70jBCwHZjOHG(FUP#T zd%ojAG_uiFU)V&UVV)wz5MGATE#k(Lq5a)Zz&xWaRcHXEwa9)eo=f}H6MV5vD8GkR z-oqDS6WT+~!`IwG2fh|h!Y%sF8^1>OBW;4DAM{o^IRN*28z!j^Y9r3&eYHKYl9Kwf zW*lZgNCvFyWO{zmO~#cJ+d*dt)|tXtQ={=Mx|3Yt(6agyTG9TH?i*ul!?V^2+183njo$Qd*?Tg`SLk zj~J~OrAEk<43S!ws>YX4!K-9CRBU&saNQIq7+QobJs~c%{?W|X&qKW*f!c%)^5}F0 z&60nc!d2-+GIetgLG{kr;6TUfoG-}bk+R9O>6{e?n$W}Skd#6_S15P>R}*}`kEARx z8ROd}Y>=yCbV{3$Ikbqw*!EpU-PK{Z-Ld>WkbRB}4#X>c?Q03s;gTca}#uvzJJy5lvN?7hY4Y*Zc;rA?!n%4DMQ z^aA|b5-0O3oMR3vns{9?^-1V2^z@XI7~`{@Bn+Y{rjou+@Wo%rk8Or zwXCWiIAu@S3X)~jO5L^upwN(w)D4}UI-XR-YlgI00X?E3sKIW%ILYvD>gakwk^ul- zJT84UXDZCGAJE{7Lg=yV?NGasx#__znx#_l(1NW>r%m`E1QYHI!moM4RnDJY6^iK= z4VQZ60z)*rZ{AaKb_gp9NRko``wtU0S}KR~&K}KdzoiPkL;SiaxCaHJYC-sy<$_y; zVk^Vuj5Z-_n~`nLBwyaq7GadY5)?=py z?Sbh2m)EJ#kAW7#e*4>#wl);P|99UD3)=~e>jq~>`GckJ_)kqK%WOkeLK#;8t?8jV z1Gi@%9`}ds{0PrsP`nx@P`AQJ?cdPB?46->OGoSDxCz*oqSUJC!Q&uYg+5Hp21^wX z=lc)o#9wcGsAIc)I)L{T7y`S1uM!ZCB`7_{V_zY&zAR;p*1FlYyLAnG7z-CRAWd;- z_%M}`D@U)}m_sxY~@nDQ8{rth{|Lvz7Myp^OvBwyIL5jxJ^iOH_bJ`~{ zxrL&+mWTq^3zeVOsTZMPs=J|QMo|#exSt)uw}0A_@KrHrdcBx8oEJV;WYf7+hLuWS z{xE!ml%|JZVt0W^qKoX5+1cAPTwA(%?-QyrRfQ%|UclCP(rnN_IuHJdQudV6%BHuI zs&j?|%#g=eD2o@RjRBN`<&^gS5IZBuCgzsP2qy1yB5R&h*v4`7^Rym`Lfi5cW)!B6 zb7%LiF+_0PU%{NRYR-R_1t8gxqQg|_RSY%>$al3g5ONr{^a}Ziys}Q!qLz=oDtHBk z{wSa$Fa{e(O{l3~T~`MDZ)%31n{ppk1L(u!L3lU?+hu4FXSuAptXsKVy{LinJ9|S< zQZ+lfu)qb9TPztQ;vi$nHfkJU8si>f`W0msf{ERV^a6502pyE(+Aw35PM(x|UwDfD ziUv9XC+$x!s7Wy!5p2e?YMc(%085;{sO5V^{y@m5zm-sSohlf9BIpwosg!-gB2Y2r zpjstK39(9+QbH^$vAM&c(JpF7Y^rZ*l?fay!M|MO@OjwxQqhrg)2 zKKD}a*aPjE886^)agC(NN@_PA3mR%2=@kI)O!@BGlKkRl%@`F3$dorJ%)a_^f5=#A z&gK61_@S$$*5kcW=Rm9GIvA&u_CE(q{>OeyA5<_i2F0EejTqMHiFD72@wG@L8~X{n z11iu1m!E!nIv#{jCG2&q&rd0Hd#};H9Ywj3g)EN%{L{bt3w8QChrWtDPCkBq4eD+yM9Un4l zti+Bl8R6>&M%yWWCK|ifk+6Fr(F&^uL8kB!CW zQ0@qr4j$51k&U(~l0ARU?p<*StZUhK+ciH#P9~oVl)#{@O|P>_B;iFcL;5F9uPn&L z3W}4IyPd6so`ewOz7#QG%{>dFay$lo7H83s3FV}V$Z1#v69_ja7_h*}kzkv@X&>1t zavG(ADK|FzUpPwODwqhBk3aRE1o0)nKVMtz+^$kCR&Ix=8u_$6@QRP#e=6Jt;NWYB zu!O7H>%sqx@Z5qb5EssbLZ5|7tcve<_rNK04VkARBSRR}yGkmt>k@h#agGXnE&%ZC zEU_aPMhfFUAfM{VFG?2+1AXA?E04a;J+E;sFkx;)^JqQthT zAx6GY*o$)hX(5Wd=nk9k`qR&y{$2A!21Wwx*;hJfsM=tHz~auVr%x7_w}Cd zOdug<$vy%)FYUfdeXia((JSE6C7C zdy)HKmS!y}AJPbC>KUq+#c?NoY7kh9dM*3)R_blT)CeEbsJzhf*#QzRSAuQN+>joP1eo}eN|sIovY6$&JHqiQVbaM1FbHJWCp(g z?1@-wiGmRW@=$nl*6F{T4qYn>=$`iOC3LG{`~UDC?z19a#0gE_(>r);2#|w^G4JC& zdcp0$$z$|HE`+P-N#u%2#Uk}QhSQ-HV~82BRoRW628xZ8mbJZgq_oc2iu=ue>I7y? z@wmp3oSY*S{KU1eS=Ue;6}E*8Hf+#S0UyLJI1eJ!YJzlW*zH_#d=~NvUvhE2+r+A; zH&XY%f4c8^a^pD5ac{6aKNs2_x{*40N%KP6+QTS9x*YhFv)JBE z;cm=R(Wd+U4v^}(b}=_f`vn=6WvpR!8n;FUZMLs&odWG4rdXU9jtAu~!N!>^cQWF& z(^nQxt<(rE`?|**UQ{qW(Jtj65#MEeB*68yWoI%Cea^cy7qI`~tq2PGFTt;tc zQA~DCC(kUn-KUi;?lXU#wDE#kb1;J$7pY4wWd;goigxF&pZ4)@=J_9E(UQE=9byl^ zhEmqA02OZ{dTDFK>%q>28(!^IWHg-jp`nL?i%}uh+w#QTS-vu8pT>B)sz6ZFu(kMc zjaM@)V?Vf94+*-D+Z)@=%!TG{umIM*$gTzrXr7fGVte{n6S?n{NAVy0CZ8bUhvi_d zGN}w-F>g^9#@MYs-RROMF7zZF=M1i!<%_CNT=;^k6=cgg$0Xk48vACOXpwf)Q51PK ze0JXT{;F?tBgYWSnAs%BPmALRs*((OvCp>?73R{O@ivbJ4l0*>=irv{VXNfYle<{% zhP+w1sI8RIclP3tJSfhq$7 z@J^t7>A?+f@wd#|Yqd)j2C@>f+a+-WHWgt;ywH5Me41XoNs%Z1Wu5l?9N%4E4=F93 z<(jJ>TAz0E-R`If>))Gf`G2o1?BK4KqTPm0W?FRAZ(rm}xyt+b_`-|aqlqltRx8E3 zHey7+QZ={R-j1`o&)CSko7H-a=d5vA8^gPxmHpM1ZZ_+;iuHV%va>nUa;;XI@HC%a zAB7Fc5{N&MfeAg6;v4!KW$o-IxGTXaH zr4;-Hf3G95`?Rx?{*!)K7v0Kk7yd;BvkT#R$1e2;&wf4@-|iiRzAmHw(gKc~cHv_z zkuICMi1Bdix%Wf zZxINi`I})MYluz7BP-!g<>Ss$k2fr?@!@5NaC4-K=P(e>c=<3Q-~op|R*?Cod@~$e z!aS~FRfP8atBl_VludBMNB;yw^q2GmGlAi>jq!q^_jixvNWLn}53D@r5Ian{o8ddw ziy2FaW1=6qOBe#9mp-`v9uD`~q)5(4OtPFtIL_hH%Osiwi4YmYhBl{bv{}E|PxM=C z!t#k%(_x*kOW|j;%Sp>^3=St&DDlxpvv-L74+!`3vwd>V0u$sl93^I7Lu+nA@Hdot zG7}&cP7Fyj*?Gbkmv3PU-JIYRWj}}4$qhd;8WMgOwA>_h&w~-ot%d00<_o`rw=BoL zkIt337rhl;RLzymSK+5U@!NAX{sH)p<`-l@alhsO`WSa)&wFvoht@Vt*n?~2$ifnG zXRfsDilhPwT-jS9IcH_Ht?{2FitVjjU2F(GOoFxHqcPU08D)0F2tI46(cJ(!nhf~X zL+{qJUnRCObMM9nLdE@ldsm{6U*2qDiEEA>AWtQjpn=Cqo1xgOJs7#MpZ1#6nU;4( zY1y1|MlVD1Y(F=er915^N9a8`LD}BC((NHa*aXcq;^>3x^m;)UAe-?GgUG#jbQWfl zEM|YDm1Vvbwgm_T^mzN17Oii7$Sg(Hxz9;*V{vuepn`Rl7Eg};z)c^BeE2)8McbEj zJYTI{>1gbEsZaKr>zB}Cb1Ywp&Eg!I<*Nx^B%R5e%I%vohc%4wV+J7=qlS;nQJmIG zb&N6c!#Dfab^ZQE++SH*uLYs^9Dgr=nq;X+Nk3VVJeX3In(s&><}-V^N55{bbc2(R zIf}mK)-#^|U8UbbmjuXd*1^FC)lRKy;p2UpTs|JvMQrmOm#e+&-D>q2F=vw3;nsX?kdJMCG!*je`|u*owJP5oKVc2jb_Rl&0BxJlDkb0h=lB*= z;cDsbTs6KR_~KRW8fnh~Vcjob_I7oFnYYHZ=&hm#pJLpi-9oGfa~hO0 zzOk}qvOOz_8*^c6mAz3(Cc-m1iH&LJSv_~c9ddVKa{h^naEKd_ zWtx5+p)c1ko{Vkb4yltqG#+#pf$RPbY;2s^sGp5RTyjAb zVimq+8RM#C!602(@xqhrUFnF7vlLaOit$Zmgd-EiGJaoLS6m+)EK=nz;p~AorJ^XP zMs_hY=cgLPH{cpWo0!e%I3Ts13U1VH?FR20l6E1F7bBwGA#VK&kj5I>gyzd5V{ZKO zHKovcQ9nMaQk;C3e=&+tRi`EoJb7jg8)t8vzl(jQD)LdIv=0Th1aylFA@-8tBCnMN zYdA%**SQ@!)gSL@sZ zGp&EJ26pLf*v1%AuUj^*FTEI5g%+_5VX>E#96dY-&4JVh72DZ2`hl65p(RNmW~yEqtr6SYe|}mtR$A8~ zc;*+pT4YCt^7Vak2tmTDk?3-EHP3|a3tNaVi8pbvnnSu>4nK(|->Bo&)V-BlTc`P@ z@%SI=W_1Mb!Fz{dmW#SHE~=M)k~duaI!W{%{HL+T99Be#EPaR6sf@eGsK$yuCZuVf z+mC7S%$0KO`bom1I1>YE2a>udA-g)sJ+9z|r-m^>Glf{fG$RH4k_<T;t%_!L5YN zOljnJa&}$tmFylHmLdIgm*Pzyj$c$>%3i_1ES)ASi|#V{8LS;nZe-pvP zp5ny&6^nhZ>!`Q~#{uJpXJnUfvu_wZq^}@{X}rjV+;apPkAIFKOO{;_9O@&_=-pn) zp4&%8kv9ABj(F?SXv)=!;F8ACm&0>}!$hrjUNFwS3f}#s-Q2r1C8^E7WLOtDDSV4o z8@!8Qm0%siFv*gk%*~DSpg1{+MrsT+M7EcbfZ-&X9Sm3CEsW;Mbs- zsfQ5X4q?p{>g0wAUUaCFn^^U35ceA_oz6kLi6f}jx?NR0d)U~~mlWNPf8F@|-8!h2 z{!xa{;h~}`=AjX&Bs+(+E+0qL;yH211X__`C}lP%D$b+$AS%`+lF$84xk8`N6PMy5 zXHWiC@T&1*AG63)dxFX_VY7U7GB9k*lkCRcKH3XtIjyOJY(-7UO3|t9xoOn33_wtOU-2~i@5NZU|6Wdp{|TDs}? z7-hCk5ZfKv)OPO5;)#{wH=+EG(b(s@4sp>zIJgn~iY>+c37<&8X}#+E(xNH&ZU|7A z&)gHoQA{9_ZAgA!cOk0;WfzX~#**eVgzp*D-kVic&gjy(&%^e&CAk$3nYKfcc_%V# zfiDiD^T^Qg*L~12qfvMU|ACOX<2#L59R6vUh!%wno0b=+yxYt>gWa4Yk9;Ir)Caw$ z`7|}FetUUsU&<;uJ~7Q^@lTHmSYecgEPRL74W4~@`9o}0Yjg0Ce7SVKbnP51=Up4dhIAYP`q9Y*zGLK@Y=BgXqDE+la)c)Q(DZL)OD~zx$TZBAvexw5lDcxF z?>Ofbm#6go?Wzp*4q~HA%Gpri!#rcr7Dr*SSi|LWqR_j#G#VolG8ksS9bK-u-KJ`$ ziJtlNuu-3-wCGdB7YxN)Up!)s7L^OaARb=yMBQA~H2SWm5*p&>yefrY#7&|uPR*rxQtWL`N$Jw#g?)`r5qpQo9^=}yC zvbvY^t9%|j9Yf57X6e+4{Xw%JkgP49v;k>Q#y@lCS+#I~1+;F5msNzW$Bb z6`<;#seJ>Sah1<;^zf?x>h>BDqRGUs_zxs^uPu(XYHAk1f+pK-aR3mZy}(d#4(c2A zqcK6hV$h51TtVeUDv%@>X60fFonHARH*;HICbb3*-guTKgY^g5Iyk|K9c;nN(o5} zF{y^xWNoDwX+bcs61?_LQ#kk9cZ1J=|mByL@Z5wo99#RH*jJ9LYxolNE;Ytizpn)(y@ z#Me~ii%-acO@6zrJeT_%^{n)+hzPyOJ$1fkLW?K%Y7R%A8A$%Tta>t{T#}?xZ1vlR zqP`LG;3Ky&K$HwVNZbwRJ0yx0{AhS3am^I{rOa$z8G({tZueM(@AW}J#1wa^*PUgO z;ZKsAsdC-8{3GO5?dF-j!!v~b9%=JW%)@8r){~j{;G#2O&16-nUrOS0uaomd`*WXT z|5!a=hjaJf47Up}ggeq~PRzh}Z-K9Trw_tLs+X(+u;C=~in!c38;(uNYB)BuF4Cc+ zLOfR{Lr0GUVbE~L5UMFE=GwDP2y-96xo%5<+-tpin@-5<9>p{mt8Ds`fPj ztkmpw6c5`bhug=QS1dGe>kVejUaM8mtXL+ej0q_qm*||135q7=AOf)QV^Qm&YA2N9+Z57!7g17v$cZcUXKSZ=CCc7aK=K0LwoPBmoaqz?tvaa)kFoY9)6Ygam2e)v~9LP zGn>Q5Rf`sN5uSDC^?Gn(BOt1-3&@g=rnWzq9{m z<(T+QX8|#5r&FL(rV&@aTs7~Xq^!SsTk&Vk@vgxy<9I}4lm*QNNYF6hE;PH8J3K$R|wz;M)E997~p6x6zz{TI~s2g zC(Lu`_Q)AQhBwTjovOO&*G-jefzUE^X)OlGZ+_jY3*Yiwq$)Uy-D|r9(r!aIt#XC? zlgM&X|ER|IHKcLYe-twQ_QI;foqg!!7y5!^RoTN>)@Gz_6+@bn! zC{qT_evZcCwm#NmJyj+w;Y0Y^tW-CpDIJ+!Xt@DvNS$WWBywu`iSv+}EYGt(*S$sJ zbtG?{^yOYQDp#NWrfxFx76U#iOz9BZ7|9sfEeY!r8s8;|(7G9Zv1Ezd^whw!tCaHmH&iOK?>J8 znq&#XT(pNxUg{I0w%n%IBzc4xa7S8asDG^guczx;^rxo_Glrf{6_(T(*~cvWru+_p zz6whUpMZ8WFvB^Hvj#^}+yRG1ZN4M}K}L9c(pIwIrKgr|`EyjA&_0HU@cg}784C?> zn&GM0kZu`n>`5=i%Y&8LPx^f}JptfzMHMzPwh=Xa)}29XNVTlQ53G}z$*!Z37e>(C zWcFW3pC^hIo2V|$<;RRymV?Iuf0to^@MmdUehF!Or!!a+w8<_{Y^VyxT(n|~lMu}x zoQpq$lp;kx*UMw%fyJ3M{Py-|UXgRaVEg<4$<8PqL~V z9o}|31(L4VwUWEB_{KN;5ih*TKDyT#Q@_#p^|R7vMt6T=JF2|1b7RoV9bDcWN!xDb zkE!rk*Z5U;PC8wYdsqt|b(t!=y^m`>s)j%6rQ)TjNd9Sa7KXp9>yjL;6MG%^fshSc zir%u@{q_m@Wei9-u5R#mNN9SH{zE|ZSBoWYmHVSz;7vb%+CKkPa>DFw@Ri0a09A$V zV5ZU!(7?19pnr1cseyG?(6^D(rBj$@+_`*Ndfko^M_G2}YgTK3bUU1JRc&0uO0&z1 z3)S;Q)ww6hoU~2F6S8DBzk@>g9cv4(Gg3q^p%QU3M3Sh@|EjAkotgvWUe4YX2j|sM z9otOr?t&@h?xFeGK-D|t=DW&k=CTA;)(vdW#|t5Knh<$cvl`!$D-EoX?cW%~OOUyY z3%@9K|Hvhco2Hl9adh~t8`A^iO_RJO?v-}FH-7Le))qeAs;J#j(*BNK(R_Q?woZ=E zs~!<5mkh>ZLmYn@@xz8x+;(_~vl}N*5q!UQ6l8QuYb}m1kgj+w{je^;QW{w*{jfP; ziB$VK#A0*6IB7Ked40eFsY_`{$A$oV>6_Qo|7S?=mWKGd&C_ZxbnSf|a(_eD6~6nB z3j2b4N6Fh`F0Qb8=#ABuKJlM@tvk$OX&OphZ*9RD7d|z7i`r>Nq|?%mj_cditl<}J z-M1AHP^w z!+2fykp}opRF`TE;T<_ux|n&21JAvz?jz5BG+KqXq%PF;bnd}+|K6!gNcSYsC&FtM zN4T!|Ik{6bd&^a>Bjbm~2|Z|c>xrh>90@e9SakS=ytIDd+!OZrSg5)d#0wWdrj}Uz z9GM}hs#C=M(4$f{#{B)6`st)_v#TXGOrg!-bo@4ePc*7*qe0mwR@|lX^eGOR5>7h? zb}t`p-^@WRToHthD*%&J3p3+rFFiGB7EaZ59g=5dZ)9@^4(bA0yj@$|m)HW8ko;6s z_{1Gz)NFJ9)fjXqyBwP}2zZ7@v0tg(fyw~~c zc2m;2tKl5J@;KPF<`Ngf$L-(>_i(h+*)B?%PY?%RS3Csbb2c*4j35>>6Uf~nTR@0O zRvblkXy*+s$0q=Mz@d-=0GvkD3CVM+{9Q^$b1*tqC#6+H9dPWAZN&0| zZpGyuVrJrpuQwe;!4=BqNog#*qd#-spJnK85GYJ1%Wn2VZEKSfKJG7JMZwzMLv|zj zlDm}k?=Y|Jrm)~6{$OSO;+uZT1n(Slo(g!Pb*emU_+Y`Ht&J;r;xqvAR(5D{hn*e8 zhicj#ch^!O%8noElcRmgto!nYD-P)4Q5W3}u(m=~8gRc9QZhl4-8~!rB)iUiF#F~S zirdn%ZY;k;vw(U5KLOY+G_CnFNblOo09&t@?x&7_=S<(;fMT0%jBoT|*{NgD*}%oV z^#?aGq-eu|sdB*(sh{{(Da>#wou(q}cQ!e@uC%La&X#WQUf(XS``2|wdi+-HgS*kVvEwrmT zZ%uHmG~n!m8C1KaB56k|26DKF|ctGr3+&cOOQ}5^~$7Y!5XEXN03N1^2NN&2ae` zA|&@Yhc;pP5{mX;>!_b4WW6Cy6gFP&O98+#i2{w1E?gC8tsebth_`Qfg~f`6A^hxg zHOB$vNy48Pw*-ge4|1oUhyZMmaXH*7FS(yP>%?f>2afwb3bejSju-v-bnpw7dH(h| z@))yQSWE4wT54Y;mp+QL^$v=>?ZTc2hjnM@P-#T&^O6O#N`|~(mo+r3@iTEPte5zm zXT7fbhSu-HeQXV$RE>z_-geI!ry3ez?0gO z*u;O9UR-i`;>!udHc0Z;)X@f!Uqs}n>>?U*bPkXAGLFJ)w}*3L726d+t70jliq*=< zU&0xE=_9@nvE|bek0he;(s2K~0Rmn{sa$*aXd+FLG@#wL8O6kcQP(V78!!+3-IlcX z@!!cWE_DbJ5=<~-4i;s1>&qt4d|k9l`SPC6(yIvGmi%Ihw4hXaEBW4nHMq}_e~PXw zi&yG3hf;9R*_%nP#b@+-W)PE?R&ESfF1306#DCT`m3_0addoHyNB*iYsZZ>3oD&0b zrI}m3;J6{F>TOY^L-VW)KKvVNZ&jWwj`OGT?>*+Q1a5 zJGGtJ&NLLP(j2+ZtdslP(x<2?)GB*Oo}XDfXFqZ8==ZY~%^xrAh~&J-bF96Jl|c@z z7hd1o*yYK$dTp5eWwgkyIsE?Y<3pt<`zE}OzHSgaj5W&f*G9m63u|W`*OiVt@_qM} z4dSYAhxTWj8@tre&-v9)mn@J(hb} zDI_meP$62iVs-IPj|NuHLa8p(2g~0cZ@;o>E@zo^GsTDO>lp*P(5df9+5SfX{%Z=K zqlxA2NAuOy7EVK^-cwtzVV?)lMMgaBB~Wix-A^|6I`7^2Mm=T&Mt^jz$n(^603342 zl-X&c>a;74?6%3bDn$_Eq)&YVmsTg;TZW-Sdmk${zf&N#P(5x~o_<+89HR(}r00rSINBQlvX_+<~~pYSQ3| z72FZIMHB&&jtL#YJ$|lbEZsU;(Cx=>;(<|7MC^&AuXIeJ2&Tcs%3GiySb9GES$00q zVS8H;L>^Vhg+?iepU7RJoGlHKByW-_q^Qj+f*5PN395c zqb~ORT||{O=fa2XXka}c^Zo2gSwjJ+yZyKuVo#@be~+B69~Y=93*bg!{$L&dN5q0tsp^A2GU@Zxdc-=#XXH`-0y#PchlGl=q zu)vq~4BoWyC5a@AsngtTvxe53Far4YfF1ENLwUdsH_jKFfFfa;`jp{(8NH)soC!=p zFEGa+Pem91&Ay2w$}5&L{X)@uakP}0Y3TT;E6^UXY*tA+S>bmH>;2SmTZSUT887HP zw~x?&uHr5qBQHv9eYHuuw@NTG)*N3Pm@QyDgg${`$~eC5Rbr`BlcD}s)BFN&LEa*s zM6tf*n#=*>R-4&K#QJXvyE0CSj%-NiM*Qp?j>w`ey?fQ5Npxc$%SZ`4Bb{e zA;?FC8EXtdXeGuNBt{@fYOM;=`evw`{k8lId>_74jmC}0{ncQE)EMB)Y!w8@gbweE z7B%LdKS9uD;}m7%-A}~5f`Kj8(toJose$Xthy%ovV2>l4$>9hs%yem;^x~bbYFJpmlkww zkqb6(IZ07Dk27a3C+rP<-Yx3e#+3w40Tf>FICJ&pPO`{EY4ejKJih6+hmzRQnWEXW z{h_V!E~uN0`H3Gi^)7QiR(dLJU=T;wknM45#^^Vl?=LM}lfXuSXZ6gW&2sTf@g;0t zz9jH~uH~Y$3$V|lRmqXafXe=D+^wb2H2`JSWN6>&Kf?E0v5aK*l)W&wi3VKo zl8`7OWH!tCDSAHvK|M5qR=K^0hv>JMme*Ptk6wDf-x{PUAW2W!B*7fH!R<}*;1ne@ zumBab^G@Eo7=Zn#kpDCflpnnfT*uk&?7Qss4Lfy?3*DRGi^kF;wmIqI2i27$_zC|f zv`0g}+2n7F@{}RjK)hZ5o9(Z1Y@<3(6f9eL7H!*pBymcs(!vN+k;D?Gpkr>xD`!=l zN5w0HQi<6CPk*M1E*+$4@mg~q}kksi5EZq*SmS(<)8AsV7FcWXr6Bx4^ zfRu{(l(XRUZ0#n$P{BR|@lOlY12%{#P0E6f^ktYl z+*;YL{yCjl6M0o)t(~B1fbgmWmH9Qkm)TT)0{Wz&SrRVHXSr8y9Nejth1larcq{a| z#PUVClEb|xZ?(-DF?-%F>pM}hl)R&-2`~DcMd;&gf27wdIfvB_UXF z8aPOqU^7TFx2YtTd4c}g&H!v4+`F+>Lk0Jk`=Ti?>0(d}{m!(w)p@vU}cPT+rr`xM87~UjoN81Ef6&+c;u=7|g5Xp_7 z*lDe!^n2Pf#`uzYr;2tpYr|lyRB~Br@J1{n$3m2Lyi9r~c(4@ESXf+@3~E=&MGs(C`}XMqeZ1y;&CZsJFZTq+NvV2lrw6zG!-#0B{T94%7N+>VQH|I$e01 z@VUZ2nw%k@S|(T7|M)8j%U)R3qTeT1O_Ux9%%&n!=^olDYfJdSO@pWt$sTH6YRV8& zQzS@=@PI@wNrrO%Wn!YdW1_CK;VV9M!}b5#-TRU#Z(F>sM7)( ziR33{7h_WaL+iu_I+6m{ebWXBwpX|8QY5Mkp+Bu;5A>x4(IOtK)DOpjy-93QB*|;x zxRQ%!1tS2SORRGZ9x9yVt6JolAoqEwK%L||o{dK|o-nHaKfO;gP49=^=Xa*_wI*Nr zs@8$To?`N(;hKX`vyWn096z8rbcWl)H_Fxn;2~A;mL$1mOG7RPE`P#~Qg+<4u%-8J z)_ver-BoKY`QfX=4Z1;(Au+F0zO{Cr(k!2=j&YYR7X~5wzCb=Uzlu<;f!SjkAkuP06%Z9zsS!R4x~APfh&vO>AI!eUokTIf{jHauP}AtH zf8)Csa@|`L>$}%~V+UdP+76InG{`z*E+(04HVBs{qm}`Rh82k8g0OM+4^$;~(yc-? z2;C=leM$chz^XgUmDjlRX2ybNv$O|5Z}<$F_CCfYI32xY`-4k{dWvJpq#esivOkx( zxPGbNmKv_|QHe+O>*lc-=k!n1ML25X*-ZRwH(!b`5iqD=wb6ctZr);{g+Ydssq_aTQj2kHn?p9)rSRne7H0TkoyS{?^ zfg{)Vdft!R6rQxw{_ahzL}vC{pSdbFJuE7Uy^+36rCDjW|`b;^1_ zdAso``{WUI^lyjzINPhIwQp4Mf6CnuB1=?ci)sZEnia+S@SIK67A{+5v}%EyQ=J1* zF_UB3Bii&TQKgzgY*SSkj- z*u-?+qaa<8UaPF|M5@_uB0=30GsgjK?i+@ss`sXKZM=|`Q;mEnVM@(umkHaEy9UXE z8SFL6f344?3iR32neQuj)Je!}x39kn)6Y@$Ex*%wgg)Di`Th`(GY%Q=W-Ca~os1Z} z*&=j~Y3z6qJ3?2ExN*GKoc2UPgh2l(OfPC9>p6Av=TwUks8TXwk?@`0TEQi`W|ee% zU@VS#RGYhG3F+3{r;%3^s{~@6XuVvs^?5e7VC=VqNR8luvJWJ!_-rX$qYz-leC~87 zL2i0Y!jPoIO+nK@vacVGlBJw#0unIYkadYK+RCNMU(ve)LCiEJco5(dG#G?bbd%!50o-B?lttV`>>UWLs^HcmVuckmi?tC0#A%R? z`~0eHx5FuK)BRt>56FVmdHbf8Eb8H({~#a^{(ke)1#dvQ_VlX!LWvJ)llM+UXWSYI ztQ=4}{1bYA0S)@~)gZot4T*nyt@-t(pgUjp@pn?s7vc4W@l&qZAw)LeyW~)J-Xg8$ zfi`x=qVBwS{fC;s__uwRn!AC3*ZGrFmcVS@gW`Gl-L!K;?RUzph8Z7PXT-tLfzFbK z!_@Y{cgBg`N55V~Cj_*jfsg36_YL81EWorC_gn!%X*F(j`yTgb!KZu1`0T*79ESw= zqomNxQ|Mw?a}BdI5%@^!=CyZAPL_=ZC;493{-?H(Cr*mQ9S;+C0mU5iCT8qpIi>Pv z2Bt{vsr=_BOH$ub`r~FIgZX^UrST;rT^>!fuVn{7D3E|Y+gx;MfwD9titQb0-cPdl z3xuEFH=8^o9KA#5{aK4u77R;fkeE7th}W7>l%m}?_?t0Z;PCoo8-FqG`}Nh-SlsEY zakhC+5FT<_z-xZRc4&?x3a8Jt1i6d5x>gJ6JOFOc(HNVkXBq!=bO4O;iI;=lRd zCCuLv>)f)R_nWmGqiKiUFXuHf z9YQ>-8$fH@7oO5Bfl~+b7#xO%21{a61Nd1zs^bsann|gcx^f9ANVu&uI<>eD3mf!Q zq7fBAxH*Y(m?y(Wr^);aKRT<*9%SE+m+7yXTLeQHc07?|^wfr=mz(}#(BpR6BR|o)Xy9gZ7yL2yJ7%ApVC(Aspp_ept^WpT;&`IgQ z9I1z`1oJh9cNNts4#C^ng>sBz9qY=p5q8{HP**Cvi4k05qNa~!{D)5|(@q zV+uh%o`CKO?4aT#3`;EJ&O23@Fhofue&VJT3{%ilA0s-Ya(&%cqGyG_+Y>I3uyqMzi2z<^Y1OFEgpwitsKxX_UG)`kPyk5C^Soj(@t}{)_3a_7RRp$ zl@@;2{jsFZbtjkdaI`4{Nvkk%`x@|xK9=nHq-TUf?85PkZBblp9lOZG6)LuB&oG_xi|Wi5|W}`7(KjfMc%ELnpa?T_{BL&mq$+PpuUalL;Er zuZv@-M^KsX=L@~gA(JhiUQ_@!Y1JJh4H`b&>rA5R4qQkbPU<7MkhlQynhc81He0}b`M`-6eo&XAq0O0z<`6+qdzr#r?9UbS{p^_x`|12&pn zz57Xsn^qwE-imT|Ym&Zo`+xn~=z) zuuo;A)EJO`4&fRufIdeXlPm)KC9oG}xECNvc_q@3oytVv$-7MSdNno9gT;kTO7kz8 z$IH4{baO;bQ%GL%twS1#JHkNFBdM%DAWL^>oxT!*fb44?zM}Hj7qD@cbu<-AvqP9g zI*K^J*?d#zr6MW1X=q_Vs)S};JQ1G_9N(fa{ir;3qDD#`i2;4DHWykL!q|?};`<94 ziO3ec$AFI>^E&u93$36#95^Rd1DAbk4^j+^&UlXqZjArwH+c3ujy^t_>DSK5{&iXQ zjd&RU$54M`>DEWNj0suphnAd2;D9^e8<`JBFUA3n7)T|q#gZ>WE6OVGS4Vqt-0J_@6b5>P*El3^#4nnL<^6gjCoevYX#`AWZO$#*7@bxf9YyA zzd3w+Hk_+#F4LP}1Ou1Djr+>aUx{+?zEKZr_#e7m*l!%zmZ_4PQ|N}8#tu?Rm=Uq- zqbqquN<))DyOm4a-aR{*f*<#bbHAwcOT0KD0-kqQeM>UDNoFRrbK&UbBCMI$at`A) zt5H-=4v(qcsztokdt=*9m1)JE>crkw>#+XAVhJaFbn6_MVZWDO7v?mxV-D^H7)L5^ z_(!V~kEN*f?ElneUyd>)CIvQPx7wZoB8xdoO&)QnQ+i7;w(SP7O%M?UZZ{cYmK|p} z@Vvv29y%+4uh_>Bq%rLSFce7~i=sWV2K7w~?4uYXEvBv}jKtIa8UX0^a7&=Pnn=oP zIY5LOPk;!+0y_}Jl`BXCR5MF(=L~Rk^@a)9`)0LhT**rk_E{&~gnSeS6NF@8%^VgFuE5KidTz7&cE*tP_ujCxk=#jp-3%teq4iYQF z8)`voH-tFCg@7#I>E0=sP&yX9L9PioNW2a=d+?pw00SGvB}Xj^DEZjK=>e4JcH0@! zhvy=_^}ga05|IS3<4*8NMF3otepz|u6ZawbgYHoGQs<-Sc%=qLX3f5jC~rB$ zVMD+9FuawtdmI40v)(5pE5-i8kH79R`AO|~p!E>e-5$Px&B^D}_j+w>H37-2LUu2% zHMw&fw5w&r*^&;DH=MyMxF`RFo7W$`1XFT5>QAa&PCn317M9Skh^p?Y zwMC|5bm6S`v*!s2W4?7!pF!kVLwq;1&i}dIMB{S>8^?)KPt~FZBR~VYe?qDSY72nXb?!CaoSc_mBUMa-WYM|; zFzjdwvF>8f0u%m1FuvU;XrxIrp9t?E&SCF%anPPerm0@IQDpVR_N>1&F()TW+2DkA zN?+tY*JV&1Y51qkrMY>)34n_hT8i@2*J%M*h;S*`8Ag+e(FvWu57@+f?)OkSooH5d zgn$)U95`n#mYS5cv7aK_`Ib)uDpAMXJ2u!~)?%W)Ql5wi6L{~J}1sQ@DnkUe9iuw9iW6-CuhxRw~6GQSquW2 z7IsC!8k#BGXAvfh1oQ*`c^UtYe&><$iXcq{Id+`10x3KFQhV$0VHKbmoL-SvKP3*C zy385rbH4Qj0Yl=Uu(=_ka*!?0l0h1qezWYrp4fuCLEp#H$aqvA4-Nl>a{f58wuFdB zO!FmqeX90qZks1b7oi}@gg->Z2{$LlvpFctXV#yHShAfyx@2q-NnYSlo^GaZG%x$Z zgX>6oG&m`WY^9?%yHSI@hXh-Wn1iMyiXD|hmNip5jv{^Naa?`T4OCya2qfae%N9pG zTZ#OF7 z%?!zuQzFGb33WxUD5;-{Iim)V?k4#7)?ZnfKt=jqGTcEx(aQh~>#91Y4a_M!cqh@M zNbT_qRlRo7TLBeJX}IYqXW8j_S`}$~%rhbfKsUfLk|RiCkOO@Jcn{wde@qU933=r^ zvbaJ20;xD8Qped;ZFpG}sKi@Yxovts4t@>?-Xi)sw|L=o`URYr>SimUlJyKRc%x~U z70%xzL>*uig|i=<8)A3bL8~fyJ$5mobyql_tT)X(1CU!5F9@5|tXq0T5)G^)0t#3t zaQgo%a6b23h`P^8PvP~V(`aQf)8Xk2wdl8!;2u)!RIzC=mz<|}3*~-;oYy+BBhms=+TG}8D!mlim<_z(dr_YVVo?{=bLiee-`6G- zV-39AbLeHLuTnrp2^%X}%rt3)l{is#at{ZAya>7KkG4kO{LaL2e~7YV*jAXSNp`Wd zo1Zv)p;o2JZ;K_b!Ff^-K)|2}N~xKOg40SYa3Tj#r(_@(v{k?+DvJNdCaxn0E5hwn za}z<07pu0CQl(_(B%NwC9J%_hp@RAf|vktS?Ix zEu)f8X)U#~jl+)IP<_!FK==I&M@dCBntToA_gX($WB`~P8=I~WAb>upw5ryB#L5Tc zse$cb{lbeo7}c z(Wi+ofUXh$Xm#@8!#Pk@hrmYur+p{95<0vo`LflY&YY&mUWpJ_xj8{$nC|65fY1I?m9t~4Jq}^bTAn@*K(r2G( zd4^7}7&|O7ICh!)?1PYb_5%`^*cVJgZGZ>|sH76TAN*qX1q#63` zMmu5v1PbWn-{b|y%J99WTIxXpF#$|zvONgVqszvMeE}QU{=-OIkMaId`+@F#J#dM{ zrTZcb!17by)f#gF>(@A%^JKS2?({l!J5(}M3FD5sBj`vTTs;D?-Uo=h4iXseSv=T1 z+Oa68=ve3j?R;Tf(CI{kk}tLy^aZpjVL%gmYr1_^($H+M={Q}cn)X!PN3$l;SFJot zeDOKL0roM@D1FYZwZyZ*be(F`6)>5Y{e}`Wr0$|rK+~Edzk;nTd^@^umq2n+^fChk zM+=8SO-@=p&Nf9R&yV%o*}91B_Vd_(54PK|O@8j*x>IC|%$k34@#B|}7ut|}J3!6u zI^pl%J|m5B zb#vz>WpwwWlRKSp&ts^Y=~Xq#V}Q`~#-|xc0>iY3u$>jUnDhI6w-3x0DlY8jZyP|8 zk#T7;j+;Bewkl0(?E z`aOvlwbM!=8dLNXN0*5@e7k#`^5**GAU&*60|<~f%~sB;HjsukWlB*ae)P7{V@}FU zrh9+}jd(J03=Ny#(~j5A1d3a3@bcDwoiGZQgkdd!Dkm8b&SLM(Q)!@1P;64?sTigMzI?#I0MTrXhvwsBYblA)am~JzjK{9W?|j z%{iE@RZph@Uv1HqhB9dRzK>ia}a?U2|Mq2e%nLmlPBaU>Dl9jG#_1AQjz& zW3qUr9j6P?Bju@d3!UpMx36mki0Bu2=Y3_WoF~{9MldlIbqr`_d_|poo(+?N2x2n` z-E^kvz^2=U=Cwe@>Szi<%MdBBvKFSkcg)A`Tnu))h;=r%5R1tn>QA2QJ>4~W(`aGv zOQid7Z`Cf8yuqU%#7*Rtr+lZ$ELN~rzlc}}9;xJ@7(EUcvG_51b$w4d&yt-{A)#0Z zE>Fe&!V_3jr#?u1!TJW!1+FnFK31mlAI1vJlF;2?fy=!076SnwEkNCwztK)KJ6klA!u_Sb3A24YBi z3nU_ZPo3x&d_$(Lob#9LMKo^Lsx(-EWO=asSe)%>QE^HM_XeP9#!})OZKCC=1H!C_ zPxzlkizjjPEua3bCgzohyJ?pOR94@KvcIQKBPReCQsv977o4pbVJRC!qvAT(fyBID zks7Y3qfhPA5sOQLNi(h1DTTBur~yGR-Xfs~GiFs;;D&+0NI7|Am3zIBpg*yl%8Cuz zQ%C!bd^wxm7HZKJN6{@WB#Jjp7h>UI#)I2}#+igeK)}0PKi~$;uOt1Sjm|v03DKCs_-siz3dKoFF6td)qvqAP*ryVt3_0~*@QNX&WsKwa*`R$(Hv}H3f7kuJZS2CcX87>21keI#yj;q+4Saz-r?P_K^r*jQ zx9NQWh3pCSt$w;KpvXE{ zpoh{YN+X%NIyEEGDp#B@#tLsS-JkxnPsDjPBH5aV{nM;2zYb#aT(rFoTRj&{PG^bt zizA;Dn&Ml)N*r0|lN9+Py4lJXH%9tV-s7M0AJ_T9*G)g@_rGMZ9fskcESSZT#PWHDn9-Z6OhZE(jZ6 z_;5_JB3MFw#F`#jzcaT#U+wcXIz6;3wo20M0c!8^&zBxq=r_pM~7wjhaM}!}#S00=#jf@4BrIH&WCqM8 z^CmqerPBa}MDMUzUKb#Scx-akdhsJ1^qk|+8lcEDaE+q4ev*?%_CZqa?gir+^`Y{& zz@>0y1m6n{AZ&QKq$N(sA?HhEQ*~=|KggeKpw&immE%tRKA^bJ<}>08{Xq>Jp<;!J zbl=zM`GQCuuzI>M8+ZN6HK}~_a0WQ8h{g4^-os*X;Xm45ksvlh#n(=JQk;qc_p4U# z8T41m?&(dX(>X~xQdG$?fw&*_G%|+32lQ2E@qE)UXTXhdw)GQ?mSkoO({Pz?3Jkx6 zf?^2Pl4~v6iL$nGP%nU|C=-Sh;s(>WeyLdt@M88wueCi#wWd%Pne2-8MVL@_p2-WXaCHy@tT1!-SR)_~)Hn@R%pTEeEF z<^dAHPX1VkFvqWxv!U~0afi$r4UvibS>*-I*iRp@`E>7UvwVzh7)8OTACG5G%b9FB z5N7qGe3>Tug7(3@-6r}lEd@5h-B;d%d+`v>#=Wtb8U27=YKzV&Lk$BIiuX=sKjaw) zzf#Y%lskbTf$=~ooWe+ZLhHBRgJnY!mL?{4PVaUS6+wxkS!*A~4Z+1OSqQFZh0lT* zW!zpGiPp0pZ{Ontab``(Yk9|p|J}E7+ely}PH~>$xKr}ru;xEiXP2*A!!C|sXd=Lq z-{bN^hbImBchgQb%Qk6#A?Kf&Bky)#?|^=1@6?LpK#`vn%Uv)3PgsndUf?;vFm2{e|g1;ra;4slk*Gfy55-KVB=)-~}iM*yfC3s0p;+%9&F# zHDQ{M5US9w?o0wd=Ot+SmJVgtfzVJ_wVC`w|Ky27<+=m0Ok(bER`C5ekjUg;*`V3o z-EoeQNoIkpttP(AhKxjZouU;@wtyHbH5%npZIrKx{K^^Poj!;D0ZN&%aDtS3SR`e6 zz}@P4d1yM^t%Z^t5~IjTcJlbfZs%6DS%LsJ){j+Ma2>Oe?mkFsh9nPN4`@PECBSjp zql7mhHzs0!)!w9DP)TXvLsbPie!HlSkOhZPq|pkIk9Xrgw$OWwVwWmdX0m{ znDS4TiO`OkaNi^}mdD_%!X##~M)0Efu%6wLl&e|79btb@OG#d9(ld|nUWmxNb`Tct zQP&6G1^c_(*&qnmSjQn&E`Q5qq$NYdout(DyyV&(xngw(eS%;vOT>GGA)R=Bo7lKW zMfcJ!w_cgw!YzNH*@1#j>n+ay1wE8tU@lis{8jo;3r;wVbONS8#C0H{)yhqKU-}Fi zLR=luf$J$PyVqy^ggYp6yVqwYq551iWmxhK6s^#Cjnsf5*pI+T4ZtRV^6=Z} zI!1U_PYSxI92xG9=@Hk`hYo9GR9+-2%tg3X5A=o13*ev9yx#y(1#9-5t;QYpd|gdse>S zXR_aA?X!3YB9b6oX|fqyrL7C1hyHR8h5-4S!@0*;_~-pO_-}z0SlSxk`b{HUP7@g+pxK~t63ehTIBG-pjZT-qfTQV4F9CMw?A^^ zCFsPrv4Tfl)>3@0xX@1xj$=gxhC7)&^Y1*GNASxrgZ>H%xd9Vk|DNi$>wU)c3)|%DHQ@L%PG?Jfv%hc=dlaQ zbeU5Y?E}PhJ834jhNAZ`@mlxIwq$=dN0_gW zq}?Zv*8NEoNI9JffGwGv3i%H2IGI*DF99*3RC;URur$xBU%!E~o>f`!j$c||r}J0a zRS=V#HNkT@C+nLM!9XOCpqHf1zJq_ma15#UA&-X9eXQk1RZ~bKh`@k+5{OIyBgjM2 z2vYr5T0u7>VE~^yR@|6e4mUvBf8ysJM|LDc;+tl2jC%s_5$Tf=mz8S#L}8m8JaO&n zs_lbZvYO>GmqVsX0*To7xY8DwFV;}Nio9XwBlM{ePnHqsN)4T z5t-=rb10u7U~7gwuUklqE>Y zf;R`xVM2dePi(G!+YBqQVG@ukk6m9KCIZmNX-KOtooqX-*r$tm6Y>q>CBFjj#ckfz zii)nnH7QrM+U;*sJyG&`YS+~(4--SzN(SdsK!Y)c=3O}+5e#jB6TIu!*z^v&3Kv;7 zz#UqXk9*-m88>m6?p{ca_-3H~~J zGQ`e5+L0tBmk0}iDL-5i1R<`4ItM^?(5MGmM`7wGIFlL$GjCB(5i^!K6HSvTTLe^> zSf09@lt3pog_X>L^A7CkhEK;y@3H^RirIb%GeYw6@%{2+ms?&d!}^Sf;*+q7e(Ub3v+bNmY^G z)&heK_Pg?D&=TBkn>P|swYY=Yj}L?gZvyOU9?Z|**~KSGn;{LVK*f!=+2r>-f`7Px za0!P4=0A9iog^`_R%i@hT%@+)29L8=)&Ho{h>;*f`Q5v!f4^M ztTLiOAWlSspwEh~s;;$y39tOlmz`l4W|Hyyb zFK4D|bNu4iddn4^O}*Wc<7LbW{^?xQ9Nr2GFLJVKkcQjT2}F>(GL^&%lX)5_gVuwb zJQM0^_(f}kAMchvVxOQ7x|#l<)g!>UrOuiAjq{mzF*-nIjrq7v+rhyhyA2Kl$`de9n<`}VY%qtDMru-XyKkJZowlV!PbYxqE1s<(; zr9Yg9trm>(HRWWRG zXEclU@8QHGb?QO*RH4AN-jXceRiF&|ruj|ONrH0_-xT|!lVd#4?i5ly(RRLe-*?Hy zZnHnXOZJERLdFkrUYP=kIdWaF=wr8+~S$<|J8KZc`t-*y3 zHer>RM^M35l8jAd+bJI=?~s(c2*zX6L1RFOSyb(bkw(+|U7Tq4B(@$Yt>avvO`!kR z%lVIfj*dQ}o2{OHt0Vd8wv z$-u?Zvry~{mZmT>3yLH~M2$+-$fDfqHs`K6zVpSrDvry?CZ>Y?5(`$1euM4uga=&A*;+C<%(02 z`?AVD?9zk0Pr#|k#qn84xV>j)KnpSX2RJ z1j$x10RRP?EbUKaMF2Jxpl6>=?OuvrIQ3#af{V^wP<2DURp$fEk+&vzb3*aezp=d0 zU6B9$pFMzFy6Br7k&w>#rAmkacE1&te+WQ8nW$8Em&Xfo=g3)-_HkOn5m%G@xsp)x zc)?W5Yw!TgJ}=Pw@hJF$08nlCQpY*L#Q!}wFEIG=!1aPa|Hp%>AIYfjJyr1t5M5T% zniteblzd6UOYN7yBPe81l%X$6ef#}lq85fVfJWdUl-5L%W_(>FDHoT={v>sI#N|Lr z)K6rLG^)!+ndVR9g_H$d-vAr&16TGK3kktjRy&=YBBlW*H{?Q!qe{VHX8&EVBRmg| zAR=vXu0fyF*>mt`h)Ih=U3QbQhJGYXIqBf6J_tCYZ<5wk!r{{1{071lW<1Rp*q@`HwN*ffWV?2) z*I+UEyUny287DIHHU7-g92oaO{9g)#+nM(!`GSk#W-mb&Fkqu7DT0YE2un%M@>ptz zeQB*+ei5Y3qm6Ne;!3gyx&{J)^RIk|BSQmU2w*jU4?IExNsHSoUiRIgYv_)Jxm-Fh ztYRQDdh#JdS5b3*FA)u_ygUP!JWysIf@VDmt}C--ZhHS66#B`U~c>;>H$%KmK69i9#>^nmhoiW)h@abD|rAhI8li%tMT&zG=Ki z1G=)R`5}DK8wc*yCdotNu*?(a=Dsp(6b%_Y1QIZf+1`jwSbNdFM++gXIX>01$c)y^ zq!{4!;A$=I>;xVFfUA8mRHXrFaqCz+4!45PB3+1LX30L~Qs_4>s#Y#M&4xIhh?`7@ z0Fm#_Z2$VEcQ27mU7|OnQyQy3v&UC_)TtpqHN55q5G_SNumew#O|4+7A!Zc)-5QE zqQw?-sb?|sJtwsE$*A)I?GL4A2^lt?95oASra7!X8BjSsWtf({>xL_JEQ%D?GG^Oh zmz28?3YK;kFZ4u+XR|si!Hm$t9pa6V$L>%vR9bD@`Xe^VQqWWl**^0D$(Up#%WX~8 zsAN9aI$~f#MnPpJ2(=z+ysupQFG_~iu0qCUfm;CfuAn`0PahE-_^@{dm7 zWR0@6_lY1u{UER;H}w=Y1L(1L$Y;vg8zeDM4nZ#8bZmudxP)A4 zpeY~J??kEOhY}0o9Shi5=j~R5O?x}g`VBHa7f6pj;tGD3f6&>%xF3gn(9M-D_zDVr zQ8>L0B<*hqD>B5{2PEwUJ9XSe+}prCx(XxLwLVnG(Z;N`VmRovKS9O<5Chgy`90zf zEwV{SY?31Wx@TY#Qe9Mzy+T5i)9uRVh9vB6}qWkvAt=crb8XhUDzVAfty|D z>HF6*C4}qg9(&I-)qq<3c(FUB(xln<)gN9RHGda033A)XB3t>7@`EIDf~G?o-gQBx zu~X*RLCoO2)pZVBQz-|mE(5A(dHNw76zX1jZn~*8>!&`}^*6^`_Kbq?^{jgaDhuTY zI137w;~+CVx{)Fnc8(-h9QZwXR7+lZZ*S zI{aaTS4n}j)CB?G+cfff2bZ0mr7eR_228+B5ZJJ`$^=Zpx+o`MD*V!|fF1>dA@p-5 zGrJ&{9y>PMKp--M%Qq2-2gzr$V?rA?MB^86gIFFUunb|kWYPL)mWR&JNaLif_p9M- zM&$Fot0!#{q{kXs<$8rQnzfuAf0V}f zD)3KA|1p7A%mKKu;njn7fi7%m$VhcyG^ssFlU3_Mz^7e>R70`8;nJEQB zgs&+BL?0kFIQ`@Qrjh60JBcV+0ig}On|e;r-~CgoHH57;S@mIHPX&~`NB26A{9pp1 zsf%V`#LsLSoS}3DS!kW+I(XJ@6ElQ4ppbB?@45u}LSw`TyRQ?DKQx=^1TjLGDH$Ua z^CL!xC9rm%p5v+N`_d_!s{II`3j!KQv=24;hJE8=X&YzK98$`@NWi z6f%c^=3|X>*{VWQcocuFBmjF1vpD{fyTumZX8mKc&Y=*7+mzmgK1lXbEf`|}cnIO1 z9muO8LJ-0{yy9If2s84rjRY3 zgVdNNMOvzLfyIN-H4jIez*+o#J4v2qnJ`Xo>(7egmS1HSL|$z?`A7L>rfYx%Z5>@E zxgN2TVXuvcwIsL6q7o$B@cvr><|%|2A@(*hl=h)|b8u`~Xd@ixM?hC8k6c8?{l|o} zXPq}&q*bKs!?#VKO{RhE-o0~a+`q1RIO`x-`ijH8HFg~!wYoEfo8Bj{K_2?X=8-eF z%y;ZUmx>&_(Cg3(Umu{w#!03Fq7|jhBPHOglVaB8`Qy&vKDCh4`HBIVDDSX<2XPQ_ zlnyGT11s64FKixM5ljnT3K6%(3Cuft1LUl(swK~J(;=Ju@F{kF+K7XHQ~G08VFvQs zFK;v7XnNHtW=Py0%HzLnTaqJ)bs9&5yEt9vO#?H~+Mq%3A@w7dn6NyC*i+K`V<*#EGCcvw1+05H zY)8mUc0%FKlg|`xdw)7#06SJ*3VIIr#srayoo^ZVJxTd_T@>pkCq-JUU+g=VAQ#{v zrf+)Ddpri2l?V$}E`hRH%PeUF=EWnL_`Py0%mYC7Ui1D2G%3OqXmYun1iobARU?-& z&e}L+wxbu@u8*VxQCJFiB6%SP0iq~CUd3K zE@U+Nm|#*@f;4Iitk?6cDL3N7m=d>CD)nQ#e<3qF_59WniBKqd|vCX8r*KMh%A&xg=G+Wg+5?^XRlm=Mxr?&MbNL!{ug^^r_<13oNK`dYj?{x zI?c^C(-E_E73fP%i5Z!&Wdq8F=(vmc3`s-oCDQRAdQASpL&8}_vk4aY3x9@<1`iA5 zl9X=yuY$X0*;93zc@PpS7PP{_@=do_0%C+(`t)Xn%{^2wQ)6p_7R%8T=F|Yb6MSKI ztQo!p(BK%dv5!d(1mHh0LoL;swP+^7DfgP`ocNs$8)vp)jIX+lgR7OnaD-3O$sV`G zke=Js!YJ_mnyE!6OK3e3X!zsEeFEs_YEV#MUEtI(fu{gK^o`Dn{E zm1-%x#B2^`%!iE~(xg~EXKYH7%#-9~{G*KR^KASBwz-QaO5MrOv6k5`!^!~tKTEOa+!-?CJp?WE;?~Vdnqnu?$9Hq~dhLB(H1NfCpJ*ye) zi`z8;hB&_5$o%;{7H}8)gJBS*471N2UP= z?1GMMTb!$3ucnCjuwdketWNzWkeT`L?*&2!n2GnnR~?8ohv_*5WoTvFgaPc6a&C9% zKZ5HYkWyZM9cN-6eruZ>C12+Hlwk-VIWY5c&yZqpd@me~kHPZwfxOIdFouz2fGXU4 z2l3z)ZJfjt9|o<#_9L5s68wUIat-3n*F0tDkuQU_FV6f0K;F7i6KQy02ex~0nDDTs zbqTE4tHz!zc{UHalxNs-DE@MKDl-R!==QJ;XE#;`k%BfmbS=hU5@ZLW*;FwZBvt4| znlu={uR?ZKKu$0bupE-~?&(+CWOOSG;ZBqFaJ3 z-Uz|M5*vS&p*8w;9mi&t0PdH6xuIq>_LA>ZwcFzk6Tw6lBnFuvSb^BVaCkd`#mpxevjY#uinKl zckVr}bIx-!=LU7ru5;uZrkLNz?$ODjGmas@+#u>HkJ`5Y9N=+f2rrU#odphJb#Ysd z^+8Src#J38{__}TEt&Bc2X$rS0E=7(&ybQ%D7_J+DqV1%;;X=K?Gkw|sMEoo0G9IX z0+?KSDX7g-j4S<$$iY2mv?bXCOJ}pX`Uof{}~xu}=rf3{Dy3M#5H=xCr!F zA$4J8pGo#Zs88Tc*tCz%!# z0(Kc0b;LI?6Ba7MYf$7>W!FCyP@+RbF*z8KQV6;tAN<&PbTyKQ^Ijp5-8?m;It@ug z#m~0zM?)8O^Jg3r69VAVOHU!(LnV5~&j*t87sKum3&95YFhfEs3Crv=r$hT>tA1JS zDS?xHD&_|fzeDS!W!Ei;oq~aU`W8-G>Hi=>1pJvMnNL@tRoMKlo|lTWMVYFx6o}hW z?KSEre!(`FRkh1l>&t@&Z$$u;_9v1ZwwowCuoP;CY|UJZ2RpS@({bD?3p zbLFo$n&Eur!&~QV*Cy(OY|EUD&qfjm5&GRtY&*>bbRLzM=pjaMme!77>2o~#2N{!ZqA}!{e_=1+F2HeYl zroV$HeylZ0$-Zz5gQVDvtWqvROcsndGHB~Ytwcw`^a)>3Ng2tC??u!3ED+WgF_TwL zHCWk${vd6tApTGBR*wVF-`c8?6lH+)6s$d1EB zNkapmgy#D729P2M0&X)xN8{b8mEeERfP~DnshIfQnDtU1hH}BA$`7DysFTp~*JR=~ z(b=;gGZGx5i;e~5I-<`>Y$l|Wjv{72=`-ybJx~RI+p~-J)hYTdZG;jk%qH&VM6>Ul zw`+DD+uU2O{Wx|r@ovS;0BG=cC35kko)sg>3dwOTN|SZoQGFi<_}{Gn zL!Jd`N_gvmGnb(xaD*jKhv5bn=1b7xrp1<7a$3U!-$5mI>M}yCm9wD#E1@7p={CeD zl^qrP=Rr_h4xCpiUrtrFHf?%X=i&;mP&_~vMXw|?hoZ=FxmzvEF;19K4IKm3&~Gd< zW|<_G0&&T0pKdNN277Xj@$JA(7u0)XS%z_o2;YO0eXX>cDTv5MHUJ`9_vw&7`>8!z zY1j*v19jeHTu*7D?TvQwUL|AL9pKjGIU8XS#&0zO0L*R%083niOau9y4%F|TRrLGy;fdCU7&M?$%x9sO^fzT71^HtJu}Wc7uhjQW>0*?17$ z9fP3~N0K3;eK0JCCQq#65}^{qn)qxkD7hNtG38*ef3zv5h%y%hmnE<1T6wH8q@w6dU(YJu* zZ{w?6g&*#Uf6P@}jN{wsCJNJ#FxpD9Wuu{NHq2vbnbeAMh}9BmLMq4+#lw})D3vcT zw`*QPO*?@ve34z3_I9Ty(~b)$zZ_|F;hl0PQ2B&hbCQx}>GV8I48|cs-d(8cG(FhK z03#zczcdU`(_t(N0w~eH9FyK$Mi$x4WK63>+rnJ&2G{KRP@X5)xKk9gZO%d$B*o(& zqJQndFLJ$LdTxQ+kvCkPr&{nI`Gxl(DPhrQKtT(agLyFZqZoX#+Ej;0e-qrNF0a}@PKSxu?a7PgjAq#D?A*f8^M;5IbgWA8LvccOeb z%odpuU;!)IXAeK-(KQg!n=qDRg>JCs;stM-UykNL1|}WSE3%1~{U5kt3s*i4X@@=g`U&qC+JSwj)>m27?A; zt}x(f^Cp;dq&)DY7ARGCDmB_2QJgtU;2)$q)FO z@(pm|crF6FBSjGbe+@I@u-Zj)Ai+^~1h2{f*9oB?vU~&pB;8&%O<_vl=(hEuh60y1~KUi6O)*{f~ECsw&dT@{g zEWmckh}I)h^brwqP~E*lw(TnX-OvIS#K`wj&XbY`>frskPML&VHz8FlF~+*}gB%yV zO%jty;P;(}SD2=@5p(_x0C?ieK#m1n4-{KCyoW>wsr0ZXgXNCceUdEPx4tpY)9mQC2Gu zk%vG`G8GzZ-r@6GIGG+$-X2D0fM+z&WSsHK<$4(0K9)bpLKu2gV}#biq$PwT*Yz{q zX*WUD1UbCXz7Zw^X4elGeFeOCSbq{4P|zCb6fjE};OS4WkVXegGK72^bW6B&DT5cD zI3$Zk89JIZ2Y5OY42<<}z!$Ilgk~AO77*S? zSjRA4OyCCy5{&_+xd$GZ+E^k#It38ne1V3I$pDZY5RozWCtdh*D@oK>TzT~~wpFaE zM6v7`OYc&!_@DXY|D@omSGpfHfki?w7LPCctTyxe8|*{jmdj|NCLnQX#4z5>gn$J+&xe$mw@tt!&7O|VZ07i2iY-lh z3YE6T4loh#;ewMkW(OCYPUFsZiUA{%8}BP+zjJG0O{{MX4r!H)sIQdXH?K%Cv!J=# zb5GURN#)=Y{BTAc>lNwGOT$+ik^ecg$+JK{^AnadqEa0>R|a^SUc?4LI>H1Vc$CDR zji%L5#||`G<*tK-)MCoKVanb!VhDmH5^WKFxV`X7*PR^szvN!2O(Y2rxlARd1b^5g z^8zBv9jde@m=BPBMDX&1G2F#7FSl(b3DPApa1-WGr87bM%@J<|TQWyhpXea;#bZrc zuHDZWM5uIh(}#g^?5IYU^u8OIZ-~#jcWZ#odVp?&dLe^V?P9~J;LA`5a@71q>@VMx zHDfXsv zeX8tNBCI6rlpXOo=;%>0AkvW2u6=PA98WAu$dnk=n1~xn6qP{tDTj=*&B+_>sB-6z ziKfHB`MmGVEBf-?pkHml?lsGyBa<(yWQ=TuR82w8N*m>zf7<+ghTOUZRVMO-Km~}I zz*KcEszc61BV7v}oLW0us`#wTpV)DA!G*6m(4C}B^@*a9lsK4C2Puy3HE&r+FXRUh z`ClQg9fZ{GnAy20ocK$IKtEI4Lm?D#o~1&a8ZZz1`W^}dU~Nt6C1!jXsv7Ddo6zdkZ~+aHr}B3URPo2Nf8uFSu6#6#=R44CBk>P= zhL&?7vW?IAMh=MC1~}Rn#!@SuozPB`{jGhGEbxLHmJt-V!qO^!mQ_JsnyFeumi^j7 zzne8|8z=9h{*oP6FQ6br(27SE5XEi-ZejjMhJ~eXIwWey?%R37l5sbkQrNgmiRwTx z9OH*7p~^X3w0X>E?O(8Q9vnOg;Z)bJ(c)ayTzfpRzEmfGC0#tIg_@J%!1Oo3C~!}6 zu&_Xhw@Cw2GHh2sLkmE2(CTD|BZx1SB;s|Gn~JF z$ers1^EZDD+#iII9lo|4OP|aJ<0%4a?^1T?uW8p>$0p*$_b;(;F<20ZQ0GDvjPTg& ziPAsTP*>lQt?O1i0y~uG3F1%gzrw271m?QWyA6YuLS=pAa{{-ngDjfoiX5BNzo5ak#pJ^r{1{w_YX~2Z@2ZFK zq^H~+sP=247+34kr>$t#FC(x}z$L#p0%?WXP_DPyHE3HcqX!11nnQlRvbC(A+?}K5 zw}@{EytZ|X;!vIY0;JfO32g2(^Jk8$NGx3nj|RGED{{gh{1?C(#w)OEp;ceD8&Srz}|UU1(Cqgr{ciX zy##*hA#&(HJ$bO(xY|mJzv~E!3t{JYg;as-Kh$qK$p|Z z>GGHqg_54-WF8S^du>c`*SPYJG{XGG(sVR^AWUP@8&QJya$0wtQJ8_i4AHP{7@c6t zq##?WkIwk|Xm@$=1PD0VNVI{zH{_bP#>EHRxFyQ@fM>k<(t3S(76$6lPX5$IIH({V z8pqlm1&W{droH;2RYEQW(=p4gRo}!1h~)B%p>(;HIm_#0jAMq8TTg&m`+Tq(Ex0}` zgXLtkQ?yv&ua#6KJM5SfsXe~** z!chyl%~#ocA0r=22e&x8m+bWK(<%y`?rwyMxXEdeJlJfR$l~g&$pm9j0YH$@Kf2Ct zU>T-hbxJ^|cZOu~rYSL4#C;^fIYDY{d2|ka2`Iq;@EGK~btQj0=1Ht_OZ-G`0L~QJ zO7RlqX);G1^fJ}E#=#=yh*hwN12ZSQ;FqJDlO;sa>sRE!=-QOHDsfG(EwO}Kt z!PbB5WiLD{Utk1W3PXFrR?w85RdY2v+|7#mO70CfMpc!fo&iS$#=YR2X5lCXtj#H< zV^pSAYlAKTVi=jNds?pt+dibmbvYbAEae^}v5K0B)^SmR$n3ies6&^?(&PO7xkM=w zOs0X-P6o337$HGD49fd?TW|JOb(aI>hH7GJBJseIbJ=dl17fw&hXt~CagXFZS;nCnru0s~wED(WDo53VQr~`@>gX!Cmr-e4K zsb2yL_8iOUoQN*wGj=8*x*QoUdoj^%UkQ1o;JAgWA{9D!Cc2OZ{|ll@6#jtiE}T`} zJrj)qVNam=tW{M9{S6@n60qgiFBeTr8Vt;0nNEm)+*F=*WIfK`B@7f`k0+bJrJq>* zm%N;ycm#Wb*B2&A7U{;!s<}Gg@$kG`_2#8Ya7zO#VA<<38zeC`hpL>t&GPU_og`u6 zRX}UMIVomva5nZKt1hQ>K9~du@fG9l=U!mVTew*%m#DXRdW-SotAOB>kuM!hHs$Og zw{FOVYGA8=Mb8=N&iwPZ0%*sOfEG6ZtTimW+%L*2STfe9Aghj68r`AghCkeL37>yJ z9;977dke6-;am1!R*o-qhW2nP{S)`|LFsp}RL1jApD2*+R=|3XilXFNItL*lqL5b? z;}iWe4phRauAorn2sSqF1a%B#BDWr!Z>)ZJJYZk&ovenO_&}NSv8)R2!-T~~s;1t! z^==~yM9-Q&q+G?UKo|@>g75*Bjv3Qh<53UfGH(T#tc@t+)*;jQXuv5>q4DuW0ydsh zsZCkiBe++cSjw9?F&eLsO2u?nyHA()bf`+DF=_LwlYOfV;MSxsWv^TPDCdjNX=GlQ zb}8so(L6dEoP~t=iE|cRhY%(a7FhyDy?jtGs!`Bja(bx-g^$ZcOwme0`&Kabc?4{6Z*TS zlgOT@d7i*wf|a>OSg;IUbdU)QHB;;Z7Okgzgh}AWaynOhiIH{hv;_(< zhhIcSLIJB>LC|w~=RlRP0Dwwoc+f&y@M1XCHb8XFtVYVH&RgnrA}XOa1T7+Cya4Gq&% zv(II^`x0}X_cd)S21pkYA&Txna>+_*paTx37Dlvy)UO*`&%NKz)U%(S(uAP8M!F%OSH48M`b8BW){HP+ zDv*n$5Cado**$pCk)geiLYj?@AQJ)BO6bhkQ|M}6R&7CsBE;2}>EJ890fvy|GiOi- zWkv{6-;w|{6LdGz!mx)~!^}=$hwWP;y^<_RHGsGYq0l3@uLHR+<6v$9sv_E|e*+*_ z6w(FW;WRB*nT9D$;uy7fJAm`OeKF;O(AMZg7tIE}>mA~Cb1UNSYL~0PibRsn&vMIw zi%s9jwt`7c&ObObh(0w1 z*zQdWB!yF%&F&zbrR^7-0544j2JPZAZcb)M7(mFLKF(Hsi`#W$ zv&j;?u(4^r#ZUk=d4)K273%T4`w2+PK(=hs8zMls8_QHJ-vd_=UkPt>T<6*3odQqd z^DVVaCzo?9uLMvs4Zr_-B?gzKi23lgDI}EK)j3oBV>A)I z&HBrnM8CabydYO_(xU|LR)ipuBNY4B(MsDn{6iT9Z~b>~5GWk>53&7%=pc+$Bsu5Z z9PO15a>&tEca^N*556L$?>b};;NV?yXct^qd{swZDsi>f9$H4^%)2&P3ATmR*c-Rq z((qE=fDzV$j^O7$SlH)Fuf7Zk!_X_+knk=*|zybk9 z4ef=?zor~30G;{T3FhW5`@^81R#1)Do5tH@eg@2Ags0T;tL2|@QILQ?6Gnch)QJ_c zXV0j)Yofeu_+Fj@lTj(idtl{AmEVmdOH}g*Ujy0tBdJVq@FsLs>nY6%>pOLTrI0t9 zYjK)s0m_i{^cOo!K(p+Ava1^io#7ZyY2eiYa2ZNc{TB~}ZhekRd|>PhVC(;l^qdLN z)1Sy+V8li3IXG%4r4k#Sv86e!R{~$cSDAP5zNtND?sQAKPRQS2ty(i45Rck)8xMhz zEAK840`GvtmrA3y-nxNhad_@2BY^e;fGJ{H)>z*VUCA;09km0kiP&Ww+kOo9` zNgUzez*!yUOY!QzQIvy3cl zz^40Np!zkmi#HLXyU~jh4N0z70yDuJIZuP%x$r~k$-}o6|01rQ+AkzDE-DMUQ!dfx z^5cfw?a#u65^m6dXK~6e1xq8@D?&yTSTGSLJ=4&y!A5fS+lK=f+DAG8D0>*?I8c^> z$rE$NcCU&R%rsrQTLVW9dv>fBte#7!(+9Xj95o?*74+7$nA*(_= z1DGLgqQEjqmK{Nj2}=$3hMbv((F-0k+3Q7!nIkKg6aH?MKrs5MIdwE2jch zhD1vN?~F4XsrMudh+RGt!Alf6u}&VQ&uswpLdXlX?p_-&TklhbA$Nrp+!U`kddBulM_I4f{j@gE&AJpvP!7%m%K{nRB}0;dEG4E&+g|`b3V2UPN^V4fgOlex4by z<>7$M(6X&DV>Jiod(i7H<_TUOh+G0-CH*#cX}<}i>&2Vvk1_%pIED@gMsM0tO|vZw zZOO+<8paHFPP>a#Ppx7*=f@?M?6n2hMljAsyX@;Ax84Fb`MR>Kngn68nPZN z7CQt4geag#wULJ?A{%}YqSngUisNd)|(&mG(hD-5pErJu9h&G?2Z+C_$+ zO#199e1uM={<$-H2NeY{yWvBWjZL{h7&hy9A8T}|)!|GNH0^X{wrRgZHT^^L-BDXV zn?|3IWB*)R1uihfCEt2A-umr;n~Nn_zS^+$z$Jt6&EVFUyPW`={8@Ym`b1Ioua}hp z(G$!w)pYGx2JoS<0$@LHrA-IuIvV44OI#?f$uKy#Q6I() zC(!iIlXLrTpI)?h>n6iZ-9C@shV;|U_X+zS}& znEsHhQuL9fV6+#rruYjO#mgf$6Ye{}R0QBayL==aHtUo*RM9c!f4U@J+R~4T_|nyJ zj0QOA@-~y2(2}M{O68-{4A3wb)nv}*XZ*pnhLt~}_?XMZpUJXqu)P@bS=m0Xfq!H% zJ*oWcO-LTP-_;7@F|1&f9Vvt&`L(49n1`4a>VPnvSW046ED_?y_{L4IWXe)C#+dhX zp|owA4R5cCP(zjsMC3nHTIp?KK;ereQW49BB+E!Au5S~^5}^|#&=emhhkO=n_Y)IP zgGuWr^*BDB0=*7HHNpnyeh;zc7@!<}z-Tkot5xdX(ky~{4LNU3tpZ(i2!2h-Itet7 zcSMm{p}aE;)Q&^`K&{9YG?f>_Ga#gBwL|FGWl_+W35U+o{Z?b-A6H{G7M_&3W36Oje~=wl!1W#huIbqOO= zWu43qXirup$GF;inUIa~*&+dClo8t>MA@(Mn8z22mo2w7i9wHLpfaFfc|@ci?3n*j z$?J}jUT~iKHwceyAtMRHb|5NF@jE5m(nj+^FhxFW289RyBD#Dq8YrC+?q#sPz=m}+ z+C|g&!dGuS-h){&m{v#jd^P^940nunv@FHmJ9 z{$ZugB@|0|qW!U@FXIwyr}z-Y{02l6;oLJ$-OFy_sY2t8Dm0^)2E@lG9WnSh=V%AX z0x590R(-V6U_J0Jd!`g9$V2S=I)aC}xQV;bGhf{35=^`KZ# zi5|Azf{9Qqkr|Hvkj4X*uQQEZbNs3OSHEr zNukKe-E8(IH(yaLAA<3Z&!82#RUi$ z!6Xn{Nml)lDZ5%W4gU)Z@@>{bO9q%fxn-rS9k?+}n7e@V%zzZsGhFwNEx7O9W(%~ZGhiP=za>rM;#u&S{IC%0awikV)q5BzkR%e~ z2b<%=OaEf%ip)I1l)dN?rda%Ygq>pA_6}<4<4Z;{U{3%fKUjYD8eEdWzDxf;YbJPR zqeqMj06OdfilS#&qP6Hk;V$;D5f6|3h^3=MbzxgaKwQG{aVI>8>k1mB?vk=L{_VHwwm^UHAwBJi}#9gN-_hE%m&@`_2&)zx7C1&UyA{~IH(oSZAL0LV<%9+^~; z<-w#Xbs^1$2Xg~e5|@1WW$beJww=Mq9ID$*r-U*Orq9z%1vlGL3OHm>J#F?wYyx}0 z3>y*%k6iZ|7UAUxM9U(60WFJ`%8drcE2*DkK#nn;>qUt_h^2%)L|hMIAoXZRo8}$E zn8lDj>^!qE%A(7#!R>*R6X}+{Jc`m~1@O!Slk5!YQfM?(JLsH#{;rG?cPZRO2~_*HQ6!gZg*r7xm}B@fF-KNit0wG)d+ivfl-#=jMDY zQ5BbMF%O>4)c{W<4U(c@|EQ$`K2 zCyA@~__&9lM|q<^@-bst1}}B!a|(TB<(Bn{+}==0rv=I^1Op(_!>ua}=E7`JVXK&g zg1)8YVe>YeSWx}*7$Dx+L?oQOc;_zO1=9SlEl$0jJa_pVP%78Txy-}Yf)iuU!_EGn z>Hr`6HSoB%5oW}fBS!~<5w3ytMQ0;w<9Kuc>9igW-34L5vp ziUn|6Dwp&KKKMcR^`q_p4NVnnq&L~DeC9m|>w$jD9bD+UXMOiX&olwzwAZs!yud;G#VwA0jqMerc=n}kFO z(oP(QB-jVU6*Qu1z=#^2)kD4(cn6FX%fcgBcXb{UlwI7ZseJ^v=SGmFz)EQ&aZ}!S z8)5-I05xVGrJsppu&AX0C5SyL4O_Y@KsMD~f$c@UB^<^-%a2=Q;6ds6RQT1_k|>^w zySYtFlaRCI_~XK2hT>&1!d28<=l1YIUN-Ya5lHt)Yw|20-RqQEy6avf-R~LN!kGtUZW-~d*aCBNLgQi!jLETR-R4-n z2X;X(5!j57z?W!h&52E52r-Sk9OzW2YnW)+ljVS zll$QMVTOSJwFAlYOGwB-2m<4YHn3eEXDUHj10ym6MDLB5Y#9AIj$PL8#ORyBPi-b_ zU^$E~z;CthDc0qzfzs;?uW)i;5dCKMK&-z+y6e~YGri(bIQ>UM%ak?3M%J-CL5Ew$ z{Y>4+ImsPF^c?W_;!$qC&AG`P?58)$Yw%Tmj?wSGCWG^Efc<2Z15TP`HkDFrx#Koi zWzc}-r=(5>%3L})gtXGx7)cE|Ari0SY=sG6(%pxBo&inZZSa5)jhxj&5U0S3!?zpq z0+=QnqoW^5znMU>5M1`8!IYgV|5XHW6;Z6>2Uy20(Z0sdJ1@Br%EfQo;iVbV5!Q?kKw{1ouAZik$5 z&N%J?cS@XAyZG>9!Ru$wdLUcpIo54#)7bL%HcYS#jdlpQI{DIC`x?E~vC798kk(qt z;x+W7K*_wED#xa(x6!xo9`29N+=&G_PuYwcqnJ`zNq(&YZm6bz+E#4Mgz#*kRdLhHupc$M%roaEL8(asLFFl*456A%x{&nn)zCYR+fK8%sbk zkr(j`^>jwJ#$2K)+lRgU@~}zDTzu2C&gvXuPsN5v2z+S4?l zB@Hcf5Ucglb?r!uIIql*aQK%&h-C;8GFM)dLPq6yQpE^jH0CeJi5Q!vI}Tl(d7uB! z=(~@DfzLO3o3dQ3emY3Q<_%xoH*^d`_QpbRctj(zDqxwO!`O}?`eED(lv zBr@}w&E-Wv+#2!e#3xrmv`>-h!%3veussJ~wtf;U0&1{`K*_h)TXg!adN9fWfEmV+ z)(<1ukyvCMd%h=>RZ28ubkOJFGcs}Wy7Bt!BClfdSs)rP5`e|4L% z^hCh?1a4jH_bp-m)zz%u14sFu1v-PPgXp2oM8eJi2K(fiDUDbs*KmGQVuz`_<`C7O zNJOAL`q(epFbtDk?!fX%AwDhrJ9ByVOy>Sgkp|NwXSz(6*uG0t8`i?X2smPE85=9( z;p9ctEa4HQ9vQR29tOi%i0#T(@2MZxdPUEp@fJ?73_=7$iyVYCo#fI)D9bk2B5IV4fv zC+FkaFlAT|4g{g^?D;c2RV4IOhjKAT*k}yMqM{kl56n1u-vE1!d{H2l zz%8+UWxG@ZovAwQW78E6?OmffNo;FOOa8m&kE4KfPiDg^Z;*cW1Ze4S#%IB)Vzov_ zKD-Nl{RCRp(P3Ffdqp)^)T#$9grSD({In@ry`fU8JO*7)64@nc7`ZOH$m_t)(|Z~f zBnq4bpu0>)f)ACh24Gzg@~tvJJy4;0BjL@kdQZ~=W^{|wpeHZj=7jC~3f6LE)!xf) z0=k6kb(U5qpFJUzk5+amf!&KRpWd818W%P;K0K@I!@gw7YsOwOOg{;ISe5C&l(-(k zWheup-dRVxPJVNKP6;IZk+8p!9*L?=q(ya(26bT`m}`!y+L*)#a+#hQU#IEc9qANn z^4|9^N^hv{tX!WtA;hL7KN(&@PZeuNu2csDiUBz~P{g4LTTG9K>d4~-UT^k5hyXAB zda??JRBf?=s}hRgH##z8jpA1^2D<(Xbp4%x*rN~medAHU$7UB?nWi^@QJPt2C;wC2 zVgmMt9@77VBK@E*qYlkUd^q^O_-Q)N`>pQMmY7cISJJ9ABgq^eCTI*%$2UQ zlDG4i@|Pvxp#OqP1(fAi6eAy!fGA+&^8Es-0AXMx5Y|ox2iXq2K^z-e;If2vhApvu zNCV2ZH$iNK0!Xa3BNfqPhkSzvPy2({?e%NOmuQtc&Ry zB*-MH2|6(yH=1agO9;#x*%yM^Z3tvTjI9J;<5a51Si#T#{t<54V~ z62#Im>5y-ZukPNQIxlz=xZxG6RPLOtRtDEmbE#k|BST>jorWCP7=Fad1XBK|uR_b* zoBpuE{Q|rvOo6@jv@|3UV4sw;N1LF}&PN?jHkg(3l$)6?jKa%Lu`11-fp#&ORNY3s zX^>Ss?<-K&y{mT$cBsITl0UtwM->InRXZ{;z5lK3ydD>ltrsQ9V5wP;WZkV1-kWX- zCT=+;r(TF*dJdSXTrYDel1bAQ2MnFgcyKWZ=(iK)T@X=M$0m3lxYkj2o*@bJ;IC&a z^T(sT$m?u)iOA#oBs`n{QVwps^-=Enbn1m95$v>$UUzU;@S%QRNha|}#`rjAZj&I( zKG@}2j#YP}a;MiZ;kD@#?==UN+P7sx*7ww@?j@>~2U$(Za?2;Vm`#Na;(+yJCOR^%}jUnvlhP(ilIX1boSgi~Q6#H~^WlHcI$S{7}4 zrExz#!`LfzWH9wEg0CdpYe3kWQ^6Ph!Hct+M<6}`_$o=wfW+3)joBOeH#WdtuBZc} z4S4eTkI-r9dTT6Qo~iSL+AFbRn#K!V%*^e8U4S_stR@%YY^cDIQOi)0MI>Ze|KNuy zBS8tYs~kor`gS?^?1U~y_3Exc@Ew5BhEGY}iBfz@v0r6)S&%4|_}9i!N)X~JsyBk%1tb9?-GD3tkh#DrKzibuyJzIx1x`a$NXnd` z9;*y-lSP0y9|G1|R}-RcvZcU0oMK`U6}S>yQ(22@cYI?-fT=`=z_J{dB2G9Z(c|oh zb5MSCdT5I~iBzt9b&g3PB}5#c+X7XxY4AJ;8ly9q`?T2}+`VZ}xS1fVPuCa^>!wA2 z)uH0W+s6YQWc6U1bcyu+f~;GdDuMqC);a*nLpI-Fy121QXp+mY#8Hm$UAYb#LRgUV z^n;b-K7;HA0dcWi<-<+Ede?Ef?4xaVXYDw`qwo3DU4_kHzt_go0HWw6Pom0=HY4Rt zwMD2QNlZ0vIyN1b;_$B{r6bD=!u?1TOk;AHKnxI7AGr3yVo`>v&{rPEb$+ri_b#Mu zq`>9elS!pt7pmchzshFRGMVTr@mGicxY(u`GvpR2R1($rkMH zSx$d87}`$1ISV~gI(yt{!) zTk7Um4Xd|H-PAL+(~g=7J8rY;&InUaf}j;m&5G~dB7=p;?GTrfyt2adzokQ=CChRT zb}U$Y(`1&?xfMI+%$pUzy?0@GXZ6z;DSH|n< zPKgT~rbQ3F0WTQmU^~vUSLbd@ioH(|JH6ReFVjSO^)2lunWvYMj$c?i_|Y%vYg7Fj z$$8uI3M7d9*%7|kT;bv_k;yK)2u|jNRsLp2Jk;mV=~bldA7nAE#Jaz-)raMlrhHB5 z^K{L-IQMIqY(uqluH~|^4~v(6ys*n<#C=0WVzK-ldbdyRM10rkZS!2!k3QJHy_I;N zRrWjO=Ip!;7ng};Yh?>Rtev;i?AQD(T6~xD zxTexVB_{T&m)VW&QBvO{XTS1#!Ty*b_j7N2>|c*>-=1h1S+HPE);6(Ex&M(5jH>XKT#G}{b4|Yr;L@2$NbJ^a~IrSdv=@g@fV+--LrA>e|z}3 zQ%!iu_OUPJI_0a~9+R6(_r#i+dY-~gYCF72*!fOozjaN|QYZT(N4FaPTGyj&zh8v6 zy=>lH!CA%4eLKA?Lb8tHU)a}G?jKnfRK5CZg0ufX>}@UL$eAeOin2pR&DBfW1F#$Z zG*WNvhmFDb#64HP*J^z!%MvY2OG~0`PcK{Fe<0?Z?1~+ql7fCJB?fl?5fj;wmbnQl z?K-r7*1H95>HW*Tg(VE#TRd+sE%AQc=N_%5_lpgDc1@e_79RVORlj%IfSD1t`fr0A^DW=+YMqiz z$u7r&#vgXkk3TG8E?VSuD=Viz`b$#0-^$7(E0!#>oId@B6BEMVO=Ry-{l0Er{q?(n zJ!>Q`sasu=e{Y;DvD~iHen*vWgKwJplE+h$8Ec%67nr8)%9HvcrSe5WKH|Zj4ew|B zKdf=BSdX2kv(oVEYvcAw@eYSXIKMtZHSGTIp*UDy=Y1QyOn9wTILDYjX_Rn!`kT-7OH0;@ zEZRpIIHZPMw_x@31nqjUwfX4pxqFkYW)+*Mna4g0rF3pt>G9CPyXAPM>Vs92jk!D1 zW-a|z!^8g5dRW$HEya{s|Ik0{T-%StABW0&S5%76-gcfUH5R%sayQROWx0>>18vK^ z%RWc%iZx{D2G)EEdFofCuu_1@_yo6VcD z+_$b@xp?Eczy^UKvA zoA@I4Lv$&#zgYiq+G`lHrIzbW*W3JOspOKZGgATP*&gL>gOp42sx-ZgyJtT+pqxUR z5VX!p_syc-KZ8}R%s-*b)@#72`|B#cCx{x#@Acf0f_NdpyH0-)sb{qB;=O-lZu_6CQI&pu z;nR&gySf4^+Bd*gKVdqXVy&n zrk9zH{RNW)eYEu1n8t(KM(6g4+8C{y+MI7Ef$JSvZ9De9ZLP_bhg)Bzo;$cWze;&XQ~st^NStT;^lMKx`*<6>I2L^eY>$Dvn)6CS;wr!Ers280 zEVsRnlcwXcE}w`tU2o#+{Ac=w_tj3npl&e@xy*|6ewmMhnNd75>SM07%sd;OolRxw z&nm$#)3EGMn_u59*?uw?b6fbvZhKs2N984@!H@*IiP_`UE7#xAe_NEB(6@Ht!Rx@E z-fGdCPOpzvvD)$F+~e~?2`|igeroX6&r6#UJmRuqgI9O$$}n>JG`UUb^CO9m6&l>I z%!H3VpT;-LkzM6wdVXYEfA85pUOPQT572K-zoL0> z!>zLi9>1y!3lNY~1pW(!_V4UGXLHm(Hkf zIoUb>!ZQ3PP>V5$mbsVn!!beVVbUJ6xpsBvizN_~G=W$D+Z3;Jhx z9EqkjjotEJd;J!uG~GKddHYFY)GfupO5F{y3QmMa|x_2hiESD)M>_QYbR+*WK$ zzu%Gipfa1U#;-lUjQCGYl+>KJ3<_l!;58(A%4Yqxr)xUnhvPqbDS!B0)5{fG`&)fs zrIDIdl&XR-FgN7r)q#i&gOXgusm(lCeVzy+ooHNkHvCpwu-%VyDOXZgHzeDIW!voA ze=cIhj-Er=uT8{wuA>{b8z`>~YrB}TA4{lgxT;&Ia@Bp#c~540SdWQh&qHzlmHl;Z z?CK9JJWM9_=fyGUb1g>iSFSFv?;7{`ds6JobGuP9$%^d?hQKAUCw3vPYUzL#RrY}eB~v3m;&EGo@!K73bfGFN^yBF|-Y;J7hc7G$!4V&hZfOziPDY z?0;1k{3Ed1eK{WKu9BDT-#zy>X7oT_M&brxpkJ*4lVP;~vA&yo&gGD2HXciV?Z%wH zI*Q5A6)@+4i8Tvl%2Xf5OIDW`7A`oFbW-JgqPJ+Qd~mpf+~Zfr$MzlEu=i@?s{X5{ zoed2R5hfpHUTuAnzt$`7olQ5jKkwHvN5e&{_&-J8EBzU>u<1XXS{^v9FVW1Nle(dK zp+)C=PY7`{>j{E8RO#OWR9i7rc8{{P&jV4Yh+yC>cph2=jpu>&i57i9{&mKmd+%C_OfnjWbeJL;CS1+ zCD`xPEt}Tx&dB40vcXyq;oAU+>OSVh9XJ#9IHv&6* zRcQOlE!fcPMUh=m*BZj+Qe)Z`r*+OB)Wj_7A(6A@W{FHT>7~x448i{CL#jIA(+4@_ zJcl!4cDKT9ZpW_Zx;N1>oTu>KQulfE1K$I>Pt^Jj7290R3$gxUR-AR=*RH=O7Vl&I zmv-{qezDMkjp+b)dte9eI7(DREok{;p`d+0a;M#qRq69+r@#9oF6`AU++VDyw?FCG zT%Xr}dRoQSxZd|#L&)iDxpw)Jc}9zP)gr3$l;R%kj)YWKT~3_GgR?vS8thm;N2_0b z<+p3zV+oSNO?puo5?1bC)}EZc{Y-`DT*Xi_JAAX~V=yn{WB6T0;1kTtQgVd4r#fcC z=dv4`>|s;fDUx0IIJ^H-%Z`(G(_)&;-u*uO^!&kw4E0>aC|qToxU*5(yXD7|l{}eZ z^sd@bU9b9yHi>n$g~4~L*WSBuZN26FyH~!h^EQt<_~TFdHW6*#?G&EXxWXy7uEN&u z5sEHprQ)9cPg5kVwtzBfCb4H*#ZXwuiQ6+>F(vZ+-n`q@&_?vCg=vV{>Kf z*GKQVlSCF};TK}Jn*HZqLApqiS+rdxx$cHil_6(QyUj)W69*@4zPvu`Du#tu<`sFq zA8u&9*{9T?6}W9>)0+Du$?;iN{zM8thIQOv4JFpLspiE`*EN|v!irQ!vMP2S5M@P_ zRJGXG(f8l8G0VLq7*HN~k1ZK4u;@rCc`0}1%5U57rJW7GcKX~}KlT05F%Pqe_S{vw zg7zC%3QtvS(e@Vo^pMT#0JDdESk1Qg9(ew=3(&QU}fvo`b}TS^A?JqsvMI!JikXy`Ryx%U8S3nNggtf&m86-!(_Go zs+g;AH@vxFwR)WyMLR93E{W^#?aHsH>!aJ!?yKmY9l3h)p_gybGuoFq6_<}x-z(Yr zc*n`7o@?~17Zd~+kdmEec`~-t+{ITOig}PNaq(eE#6=V7*^_S;>)V~#?PfRe^1_y* zt7@&j=f{eTFn`Eg!}ld6ocK9?oD+w?h575~{M!|4Wq$k#x~MxzTVUaH^y9rvc}pKV zn-3ihN}W=wiuU~0IGk;&en*q}(>!>qLrj0?^>a%ON#8hf`jBgN^0aum-FowLilsNw zYTr3Aexw}#KZ>p~FwQNA294FmMw2vdY$uJ4#+GUWXPRl0X$kjk`NDCvCDjs; ze%57eVmkWt+w8Tmomm|qK?-xgw@GIahV`SA7j!=Kmq_0j5|R?T-O z&E8Xdcs6?KZ|gQczSuDTB0Z@xQv;;|eOUJ;;ap805XrrR7oYt!_oj^D@s_oNS}5hu zy`P3tibr(_*obF?|M)_Xi;a|64H#A`J;c#iLzAfB0=v{UZ$QE6QQ8SP$+0lJH0<*< zLzQ&qrikLCZj9B519S!A6I{L*s2eZQGVX-xnZ%f{}V(x1NF&=ZnVN-}edY0RA z&WjB~{41blSnE<%$L3TES|t!Wl1jr>V9%700jobmb2A}$g(Qh6E;?)%$3Ga5kX-*_ zl!aX-<)CuwYL$ox^&-S4!GXOx9bV_BkAw6D6h(BlvrB7tyU2)83B!)46Xh4cuK6x%ZXe zn{Vw&lY?7|jMdeT+PW&_?BqF49IIxdmHu6fsGPFXfVI0BG|9(QCId%^qpM<(1JY)XexL)TpQN}hq3Iq=jaDCA|W{M^mVzy zG3gAPeg5s-^^^Qh()(Kta^&~QufvK`OcZ!4)`R4Cc}mp6_#$ybnaK0S+4aF!f!>OL z^`~we>8w<%_fo5t-5l_%h_tBujD-I%`@cEVerb`;;b8KS^66%DS&6pO-HhgG`KnU- z262MEWVwpaxk$igc!fXV=a=z3{T0hH<^&0jVW8DuQH-3 zO3|9x*GiZ)(yU~NU{-y)^x~>0Krr=7Ec&-s9eM-R^HmAA*sWAKFaZDex9rDDF_47y zaLKlbS&9d$6dm=hJ2g{~>rGtmKTI$YMYI`N!cSnIVuR+>Qx@W+@$ir@3>@2Xh?PpY zLs5cS#(Q{?RtVLI5(DotG$aFcldlVjMmhnL z@|UTY9HgXMz!U-(_-A82d?pSes$ZfryVq(}r!prRwEXzR>=iemxKSX#UYYA^5M{1( zL}#t4DtPNvX*`S*Ogrn}z@Xf-aM>)U&5LzH2UIT3*s#x3s$EScbty;V^mEm_fIn8z ziW!V25q=GH?xht+zYSO{?;uk8i+&~EGTi}c92o!701-6#4aw-NsHx~AWeP58Vq3D& z`zcK!!lc4NL!vZ#k^p6g4=>6GLbdS?n+JBvP!m#=UwLr{{#+uF&AR9~|5~W^`C}n+ zNsj4zq;?Isy52;do;H-=9C355zn?nNxxv=&goo7jiBs&= zE0KxH=Xo@{tpCbO1z6OJGIzrIqj}R3p&rb>gEVAMjvo;;hkn7-#^ZdT#y1*dtxgBOpn^lK;_X6A+C=c5_KxcXx8TgXcLVl9nQ z5&CUNvzB>U-Y7#zCA+_5_bX(y=npan$^l=MQ?z+TO24|lld!ZxcY&xXG4O6gB!7zJ zS4njVOsb05UOQnQs?Ag|U=mmup`Q{(CVX?Mc!yuJ?9Rgp+M4Eifj=osswwiQE4Dk? z!BWDv9r8BEL(Pc)br88B(4v@!|Mhp2SgGO+#alF*$Qh~HcF~S?%pBZM?nNrL(~rj z`X8g!_!k>PW#Dg=#)$kwg{K-IPdSi*Tc|Qe`uUvr*I8pAMfqW#{#y@}8@-hyGWoB<|5&*%4U7DZQ9pf)ZNAK>DPMrtKZ)Eg*UyVFtjKX(!x zI8P7dbthzLiM2ElXA7Dv5V(qJNjd^PX(%n7;c!Dsn(z{TD_yIewtZ>M3Odo{V@ueg zA?R`^do}WHN$l$$$*u~EqNn;|DtAn6+8MUoIV9$@6JaxB?vP8qjy|47`!$R=w{dxl zaW-QadDv-zE?fQEt%$J1Hj~@yzeq2vM&Yc1T0iJ^7C-g5;&!3)Kiy2j*Z3X4NwICW z`j_;S!*5-_o(|OKHZcyyb2{%b(FUcvRpKjis7 zafC@9S~$U0bd0M#5(z>H4>K8{dn_HmCs8#B1S;_zZ8)2_hbH%mL? zSeGvKiS(!WypFqLi=+tWMZ(t5Vf=N z@~saHUJejFXm|WoUvcDsplhSZC}w2x1jbvT76Ec&rq!130@U&Iznb9(Zc*@NaqZbp zh?r}Og@bw|8{c(H8XAVajb)Uoul8Y%EpTIevNp4)Fh1^?U><%4A7jyM^KO-4oZb_gjiC5x&mX08AF$9Wda$ne(YJq1mzO%Dgn>nu-9;^>pjZ47Dgws4Nq<_gz z3v&lWio=q_!m}uQ)o}-yfp>Prmlo8%2!NLZ=7e9FgZn<6di7*<07zE9D$}1DDCx6K zNjMzz0t}Zcn7f=bxoxY3>t836RH3{umP@at3%wz3DWwUj= zPxg|{M(Sp5_;EDs$~W|3I$QCQqp(sCqG@|G+4nNr*YZZU)Z;5-J@JtL(7%7j-O%7# zQ2q_upT$oj<9GxLH!IZj`< z_Gb5|ai&&~(`bf}2YXtCF=Q~-EW-tdaB5!47j|SZ^#Rd)1?w&F34L>OzwNa=h0z^C;ZeiiU7#uUh* z`{z#;Wh)5HQH?GjEC}VqW~cRerGAh6-ir4(in%(!LF|g_Y`Y+1oH|I(%pwN1&u+yN z4#Cp5QWPg5Va|$Mmr2Ge;7xn}{yciNeiOMu;|gUNrF3aPRuhG%4LG(P>m6qhI0Zwp zKfyIs9vVv)U5p{4$F}cXciqBNkBFzQ? zfsIKUGq$7(u#I;lz{DhsfGhGt=8+`wls%=l&TW{-m?n5A)d#i&&+zJFm@f74RVB8f zhO2d&1-{=|R+C=od9anmtB&JOVbMyysA^V`-Lbolh!bLSnBcuOpA!lU=_3`4vA<3; z|JBHp-rvz$fgNf7!*}r$z-c_Jp`I@{^BPecdlX@XQsRyJW7`tz&u^Y;_Uk+%N5U%h zeIi>;LgO3X`F0>kbVhrDx@XRe^ks)!XqA0nsyNR`)) z_D}@af601mZBl-iQ2inb<3`MZ23_AHtTuVP$G_;OCSo*5z~q&1$TrTydgG3NIVHmF z7YzB8pus+oafmd-T;A}9>HIa`1Cfux%EL*@n!_BB^neCFT&M9HmIn%h#zyyMM#Q`N zWP-XwEj{Yvr_YzLbZ6CjmE{)^(BD@>jFY+ZF|7h+e>aexB1-jxW6F*=|7G6dcBGK< z(IJT{sd8=qtpgo$@JkYR<#Z`6C3pC)PuzKtfn)KZQ{|$!(J*&r`=&{42no|#Kq5rg z8+U;XFD??$4(?Big><}`8ZVhl(1&k$>xwl|EOXV=&r%)Nc^3Kp+e+34nA(9!4R4AS zA#o8L>z-7qztBxc>~grqj!+$VHHnB7w%Iji2WJbjd7K4L&oA^9!`wT@&9@LcjN)~4 z342zh@z%FQq>tzpEdv2^L}rg1_u>lO$A>g!P)Z9x*?k$w^zlw^GuYCSz}rH^G&?=H zP{clM>q^DuG`YXmW%PF9mF+|0qix=*2oN4V7ZgFigk$s&q~eKq`W`el_spZNuXiZpN7~e~L`tK5FyfP4y`v{qotS31rWRsL6%y#Be#r z(tBnBTBs(Ei@B4(K#AV-UATw}zx+TPn6{oz>4?xC&QzK0Zp(^7C86MVK9T#Ogim&9 z_U(CE28ww-dI>qbtb>RBbF~@9s#@N%B=lm`UNdv4rk#wOcQvDF3Rza~B&5!VP0@10 zf&oWSl56tL`_LfpmZ$;&_$NBv*{oM3`JK}QD6Ne})S>lAjo`?mua5kO-@-^hjQ=}> zfaTf*@%0Us5G{JviyioUo`&@R_9=^!`E+$l(Cw^ZfnD{cS*){?Pwyj8;|IVwmlfJ` zX{(yIg~U1W&D7~hLh4fB=2Wi*2Fkk8ra)_K>pFnsO}=b!5jNVQzYD+Uy<+wI>;F0? z5dVN$$XVrnzri2d#~D)eV6cJO>BU@c6v8Fnc{0Q>48}7elvcu_aL2= zTs4Dl9ltVp%UdD=yXxv&n#*vn$8uUs8L6g)q`sK5w7}p19fs&{Gez~zmFnFEPW_{AHOt9NHmm_Cd}L?UTAa4sI95e4 zDyA}-j*?{_*$wDBZIP4_duP?wQ<8t^UX7cW8{;62L(tvsB>qMriGtSrCF~Lj9P~$1 z6!edS!rmARD?N7&N(PfN^sD$tN=)sg`<@*xp2Gz z4-E6wf9?!UXyr>jU0Qj3qmsskR0vX5!U+)*wln6p?v{(JI8)anNe_YaRC z(FnEuS(-dXd~LZ97{6rvx-bAc($~n3$*(vOHf75eqbuzu;EKzEKsbSw~P zQLl`46k|lG;|*&_s6Ya%DKbFqfR&gqds|qqne+!OC)HNT!k>a4N0=Gs3ia@+iWFjX z4(qMBHzVR31s`e6U*u=wWe#o)+F+PB%x|Anz11W$558l+I9H>pp_*z)n;*hMT4Oyb zW&a|D*QKC?{rokW;7^P4H!IrqHgrv@><-D_7w zo7a}*;>=3A@w!zD;ows6Y->bz3nrl^?UA!U`k};%9zz$wV?t4r2k?g9aT|l;VGz$8 zro7VZ`|39Z^z}c(5~!oIAr*EP_&ibcV&>Az#I_dN6crs2<3`d*sr@s&f6Xp*|M=1c z#FgSm=VV3{#texb)Tn2nC${vOmt*v0uN36IKK`K&d2#7rm(=U5kiPSP5?-($g3QD3 zgCvVK*O*v0&Ywxro(1a33+T&Pq9|lwAGaGU{*`B(g;dJ)fN2{mnz2JI2R4-l#PkX; z18l5U3U09ymM)JM&kr&PyyGnSm-;6%~pz%C?VaWX%t*m% zGa4`?|H`*~n=?^NgcVEu&e3K1$MbDq@h@`iU-C{Q*^l^3y#|?eg3^rWmq1x#s@2S2 zkZvKgYZ&^GJiI{DH)V@+X=Xl3l&K0B=;F4hd8kTen~{0;Z?g*MTgqq45*lQk*qN!4 zw^kdyP92(YX3ZzNEf@qoa91&**|=vtpGwE!+3aC(E#E#FwogfvyTp+AnNvycgC4@G z3z?}s1;Q&L5}h4;+IQ7le_920#jSh#cOZr03@@5*5?=#PRG`s><|NuGJ&8U!Zvsku zt8Mc2vZ+(PPkkr2(Gn4;=;o8R7fEFEoP0Lxj*=t`#&qLyT7DW0N&YC;E3zkbTIT-s zH>yuU>n$Z+n%io^shKFvdow&!`N1-Q0XK{{DJ|e{{ zOd1DJh15^L45?}XI%t}yWXBk*&Dh`XEKW(uD8gAO=&`wA{HgBMScw&B~|aI+IHS%2B?ECX%pg*6?Gz5Yn3&bBSE2 zLe(90$%Shy-?skb6KMQZ|3<&S^)1tk@9rgpDw;@TlNG}OO8Tzz{tlXGb3eS#9>gMH zTqa$1K<04sw^@JVs1$wwETiF`SaeSJ<&ordo`)M=2^!U_{xY*$bu9V>&oV88F6A+B zx2-UTmpt@*zqTYG2gk&H-}|TF!9njFB0!{Q`*iu~C=0@{Up(gk_t-Xvv0Crj5fOh+ z7G0v+l9;8Nj>v~n$^jvi2vFXroHD(t8jV(wcyT;`pE z#B2f8avdv6yG7^z8Z__$1IdBYs&xJ{zs6TS#%hF%{9T|Ud7|sPyxJ}@)Q@w6o-gVL zbtD=*zfz!_q!xu$-gEB&1zPUW#9tJPh!TrTM;A^+*}0QKzfiIv>P1IxW1M3hrg_%p zGT!Q=Kk(~j2bWq!-IyP!fQUCX_6~WuOYV^!#*W*!x$QkJZ?S+Sia)z{a|0%#GC|$L zv$lcy#gc(%rOPHg^kRBG@F2>)`(PiWS*s!RPsaU$!=+N1jwMMfOi-f@==8ySxxZ`M zGI=-0?t$%ha=4JUD^&-LyA+%NpyagFZZM$qnFU|TuOm-A3GH84_NeQg^$%Z>xN=-k zct-bgBIA~`8AhOqsG1V8Bd-yI1_K{vzMEPOzA}$4n~7??6kg(&GUU;K?BP%xQ(XYO zk9-7^TFRJCY2aaTQmF)kUqVOw3W6%{$sq(T4Y^4MO7!DI6KSQo^nvDQZg&d`p};%S z1D_-n=k`c|X2C8H6+esdFt|`RH35^t1rtmt=?AU)^MO*FXB5~1w20uG9Qpi7kui51 zdzVc?;xMb#^#_J;>Z+ye1t8w+mR)(ubORmtVCtX)>Wh53t0~n=!amD*_lczZ%FqNGi}#FWc;v(snY(rfh_ys zT92Ln#8?qTvs>ub&=Yk`9PwH?e-kz| zR){*>I`YVIjM^{!e&>()%UWlS$7{^!Rsww$s(t za=0<#D~>@94vt8aVRB1)G~$UcO%oI3Vc6bym|pZIp=~57QZfX82q`^Md8i%A{Tq1e zUL>Fa?>?meSE@LEMvo)GBUKld4Q+VU)5)Zr%ug#j7q_g|wUtW-0mZ6!))H5qr5d^- z_tfR?9c?zvyS~O+X0to?N8RGIKX#K69xOyvW0M*Ox_N~@+w`t-{8MU~!F7|)N${<$ z7+Y_BrD-qZ)v8Rk9ez{asfi+~y12bPHw}O?3Ok7P{8M z-|ATk#>R=q0IZ-gnJr|FeZd~u#s{{)rxt1&9R>*LpA2ns|H>CPr zLo6ImXhR%srnaNzI(iMA;uE>{xRYC;AKZlRyY1R^t{d4@XttIf*O%^m)jfA0&^1uD z$u(QW+c|ir&;M%o$z*c$Hsx(@V>a+$VsHt0qGUJp&jm~{sD}DFsa$$|;;aoda&++h z?xxOh!D^v<+?OM1h_89Dlf>k$sw#;@p*RkihF%N~33YJ_t%^wbvkGfNwn=}lyQtDr zHQCo2PQb3~Y$I~4E^33jt1ikZaUTd9Y5md7;BD7*!{{a8A$Ypa_;pmG?=jB|w*_n3 z>Lsd+@=aqUN!MFKF{8`dpp~1jX+uT;X0c;^K8lDBh}jupnq90V=!Y}l3ZXF0KVp&Y>9|iq5$6w!EF8+EB|RJ{_Kn9wkEKa>lEdl zOEeC8Rp{v}tS5uv+sv;u*Z{s=37q}?S%Qa{RwjPY)GcL0KZ5`N#VyFHVe|xR<;M8f zipp{c%C({58^=$~^0@_Z>fv*LJE^Z%XU_rycMY=3tE7ntfWg?G!=lmAK&E1gE3-;Cvn6zS0cGlh0uKt-ZbVD^Id{03>_BzFi`jx4 z8UwabTPio4 zV7X#6jV-k6k0`SX@0-AbWRFOy0^$~_vF=YwRne$Wvyzrr2j9+SApN8$;)8ah?DD?` z#prN@zT;xQwk>_^y*w>6?~r7K4E{X)vGMSMW@$nfDLYzD$pXfQ=(~=*k-rZ*`5TQC z9;v2h^GZ0wPor{k3!VnrW8Fd)HXb@XXm5yl=Ual#|B`d?21H-@y-^(>VRHiHDm%}i zk(^fE_8<13C0+&gfYaictV~OPzBRG~8<}%_2dhakjYDxh_H_=AhkajaPL>X*1hsvA zQ9?D`Zk3Qf$1dE>dv^2tF_$~!e{dQ>uUMZtqmk(_$+SQ|XYMrbAQG;|WnqOJhuFo> zM5D@hguvxoJ0B?bobbXgd0Nt=Uy&V**+X1jE7Q4gC zCD{e<#U9ndM4g^WjX&EHAA%e*vMuuSZ}o-TLr0naLt z+Hek27V9tyZ{`RCQ+aFJz$xfC4^W{{$deE{(nuvTtM`@Fw5uQl(27x6S?T92$7x_N5Q=HO(NM2t%`X z-oA5YEHZa=XrbX`_<63Crp?_#BM5B}qlL^2+p5=Ebl>mowqiQA0!ws$yI{=N^3qbx z@OKkjf|YxZ_fFt@I;gdY=Y8@oy+axdV$C;M^m48}OCXB9(LnQPMEq*g1^e4`$El@pPDYEdRtfYRW7CG@0%3%Y&y=PP4*zp zIlS2}gEt?}uE@dWWR}G^E@4C_j*^-82T@ z(>f2O3OLlQk9!V3IrK96u9pdDjO$94fpWmvbg#X*9p{wW;%bMc@+wh3p~Uncw10XX zMI>QPEqWQFiCT;Bn4@wq*DualN%o|gS(by}bFaCs90VE{l%hE>5il?)X?)a5SXMWpzMsd~{iL8mmDk!K$J)+Nb7Oj?9eT02$*b*! zE39Tj>EJMKbqbdpfD|TSIaV0Ad``w;`d9YC9!_HxU@Dwd^x)Ih57!~2K5qJg`KlIw z4lLUVYqM*v`6Y+5v`=yiV>X~-UFSZ8CeTl%f)#U4nv+lqJFC?!&Ctq?*o3LZcu~8e z#Pg01LHGx}n+wCO+4Vhbn_HVVSTJa6rCeA<;M4++!|*TZ(w{z;X4FS$LpXxy(f15i z1PYEs5~}{@AB=wo=`7%e_AmvFBkQuG!hnkg<0u_CLyxVEmntET+9~pnBd1)hybZCR z^L#{J+nn6v{Cs(*#8F)+9lM^#$*`Zeo|GQGYD!fM7yE0gnG&zXs!$*1WK~NOsDUH# zGcOI#y~dlW5y<8|ueEoRvk4*l+@~C&DIc8s0=6{R>r|COr6J$g*=hSu>O?8Y+JR$@ z{{Z&Gvi2W=aRr@&+I5G+2ku2wuq4+zT0b(|MM^^=$(~Z9CKn7i#@N9wsXZA%`;&Ix zqWRMXMHP4aW0_q-NSlo3yKGhtxF64G)MN{4CJ* z)j9J|_`f02!xu{S#rWRBr+AFB)(C5%K~~Q7p%azW46!`vJ{vY5AAy30oTrfWE(}Hr zPbmg}j$252UJ2@n%B(sz!J`o-$j3(H_sqDp9&}c#R~%X>htOoVuyh1qIr-%JsSvtA zt~s*PeFN1U%QZ*~_7c6kem<(|_a&%^LflyM6p!Zk!=%JyE`HYiLES@ZjW9* z!!m@n8OI$`bmyczrC|X~e~b*)(dU`S3=d#F)U7n_9Ra`W538dQbL4BO44`v{&3>lX zBb2l7O9LZWYhCdzz4@pERhzG`i{aGk`tA(Ldj|5Kn5SPJYU55+Q#b(jJcb10>9Ma( zlf6soR%ta4SY#3xvUAanor}oYaO_`ZJGQM&r9B7S+6?zyXR? zWK!D5imBO}7eZl)#qh3CB*uz~PCT+*{mlOe+<+I$JbZu+eOChj`E{8@nt!hz9LFEy zx60e*r$`FJc7gAe&}tVfT7vFG9QMLCXsW zmx@yx@A-q0=$2Udz zO$J0j(`SmT3j8h&;fgKwOqx8-!i}yjSA7B}8l5nR59dxNrqbCtCR=2kMC?f>i{>7* zfW42^7(T;33oDq%iNanr#M9_DK-FOv|7>;aVQmT?;Tt8bA2$CQ;tGD0aLefLj~F5R zZ*i4fSO8~mHe+>S|gSzgi-Om2Cvda)IKi zrEicKFyw8&m46E-n!9vyYFRIR=r+oI`7L7i$m-PgB-+UCSK{uWCG|EHWHk=#Ctts` zP5p<0a?d__6B07kPZjpBP;c6P*cUIQ!h02CD89OM-Wz{rj!12YMHrT$UQXLAgR{ZX zaCa)nYIzJ$GmN`Bie3l?FFRl5*4DNAuwI`SD4{$eC$(`aRJ9IF~OEAEO(Xs*EFNJ-GCWXMdcT zH}WZS@7DM?ZRRj3U4qj07Xh3`*gwur2GzbWyd|aZ`ZQVSJYvN>V%$r|iBKdE(U`lK z7Iw)o0`*`zP_{HiUd0(AMi|FEdJ$R_JO|^{ph_fMURM58HkF7YOFS;B{bHnUSu@&* zo3G$TR^tHFEP@`)yc~e{$c>B^`^-$YmAQ9URMK8_;bw)xnxUK*e}I8&B3T7er@g%Mttdw z=EAd^0X(j4jQgD*O;4KujE6=|KXa=zhub!h$yIwe6sgYA2mSjHo4~^^B+ykSGuow? z4bWV=_W1c6iMt}&%ysP=5>T-ZijO6>VyHIqkVk33jcrK~|+R#$0}f z-8Pz;Lmn(x(45wI+JRN*0N0k(Hv$r1l^Ys8ecA*S0*E&JAoqv&RpM@=p0A?H9(o== z>rLuY`d0M>1lR_@?y`|J+p@E!KC06~F(GZBH^pE8cv8(y%wF-S2kRR%zBO%9I@70S zn`O@hum0>-X++k+0jNYWPo$TjM zF@uHGuMU8ing&N!@C4gybbctveE0Y)eCQ6~2H&|-M2=&58`H=?S0VAC*ta4N(rn*a z@`5w7WK-nyLo z8c4;cTWCXYT7ct%K%Q~W3((wd&I%k9u>Q9Q^S^YhK@C((pAbYSdQavnbbtzE&2X(8FLsT4!$=M|o{!K2)=QpH+hxZTe*$&NVu)B{ z0w)*{Vg~v&7-v~__I*UEV2A0WoeDUHS^1?#Es!{_C_MjE1e!jU10vZ}{SD~}1r}0q z$_*a`gATT%fqn{Wg5cZM)oz~}i8Z(~4R?UWDKVX~Q^?dG`HRp5#?mM4mu>23U)nEnd$;Fbi7*uf=o zB)4hp2^Lv1W7lD=USR2C{4E6DYzt^RSTEQx@+riqV63D&pa3e;&xNpf%vr<<|4}n_QB^Su=6h)!Nm- z1`8LoZvVZ{{%`}lY9uVdW+$76uktujC*|&p@t729)7yZBbfvTuAuT>^nW(J3$ttj4c^{F?0}x>^^@!tu~T3hVcv05E{!2EFo2IbIZm@~ z6qqw)A$T<*nLqsNxvFvBZ>38+i)`AN0EPFa!NYb!YK`B%v`i zII|UTF`C$u{>R?THC0O5J!FLk)Vk|J0F~w2-j8;iuW5bSez?i3ofGEq(5@cO9m=5y zx!G|3TOde>SOo{f<~P>#vRoptr$8!$Na&*4ZwN?6V717OwZ8LSC*Y~*xM37QU9&JV zxsKLC%UopfPU|AycQ%>kswslBpGY*?X{aAW3Oco5vp$o#E4VRDHPQhV5g}^~+t{@K z0%HnST%&VEW>XPlJouIYMDam zBDH|Yw&zhjcwOg0E_9rrfmnkt?FEPkx`-RWH)WFTqIT7}L?hSz7W$I#* zn>GKnDmeaqY7C#a00)rM3(UbZMt6)$?9M)TJ$5+VFe)IO&v|f1A~;iR=^eZcL#f==S#cl0IAJqUEJB@;n-N!VIDArNY3kpxb;yV5ma`Zx|v3G zQVGqg_iuLa5gepwLQbIRmxl*ZxA&KVG9Mt*ud+e22|bQkM&iS0-k^%TjeEuu87!=lLzwXMD8@C3pHA!T)f=U}hD z<^_?+Wi0yL^r6w1tQDS=P%}LDnG1{l#{4zK0P^x5mM+g%N0FgH_bxDV3$7L9rrh6m zZ?<6qhEt&ew&iJ{wXd*wume&L>pqPt;jnvwrYd=HZ)2S_$~U^vL*RgZdlj7dJ55ga zPOvb$*5OtEEhR{&nPGzR4jas=)W*6w;Xxpi%XEgw8$cznk<$d)y-V(%c`55yoOA3H zFOuvo76G(5q1Jlv=ugX9q;YTI`)k-#B8_tJ#_j(ZGvk=T;=wi|97+nl6)5pR0cvn5 z6}&KtT=Hg3j9h$IxUY}A=j5O!{t9pcu;OG1PG7=iE?Vz=u2Jnj+ZZ^q*)LtffN76^ zTkyI~3IS@;nyHpu*3Awrtl^oZ2)p>W#v~_8>@)*mwu)?tZ8p_@d6HQz^7T_0q}hCn zWT`kB!9i^Twy@ozK+_z-?F@$=aPLMbk^KwaM`Yu~9E5)91LOP;O9YNB8r6cpXh3xt z%@DByHpcee|G_CKt^lyks(q=;2%d@n!$r^P=~@G!jIjfCRqAc|j^vsTX|kad8JT4NjxpM3$6K^QX95}QBwxR$%Gzjy+Xz+?|hZKR6u zC+d{+%lTUuLA`N@OATVa#w`gRXzuTi2F(n|18<|dnR#F|5YF*GpZi&|NX;i_7Qa|> z{{r3oKgr9Ddple<4ITZiTk+66p(UPrz7=F83qj5&V!z0l{-f<_9D58N4|2nwF!p`s zfGhl<#o5xucdH6GP_Q*N{-rnv>`@C%dk?RWxGz#blg9>V79Y@?isIY-3bYFdnb8L} zeSa%Z64MkUefC(h31Mc@`_0l1e^pv~%(t=1YT7Ak`UT4#g?}oS=Rurn>Jc>RHCZ=N zpph8NDtpHy`#&LYcbI6kvpjj$jY8P}??mpP9mG7(AHkAlO!FXQILsL37Y+scppvl(zJ5dbC=65~ z80NO$08;F?F0Eu1K3Vc#2JV(@c&St2g$Qw4mXqvNj1tm!v8 z9mx*6d(!NxP0TjSsT}(+cnWG$IWs+T*f#pqs$(L!5>{Dawq6|(kUIaf@#dgRjvXFx z=#NTQuI(4_`|f5$hJ-9OW`E_(m_h0l0KsD}h{#>7sr~CUAObQIJT%6EibQMX_vWf5 zv&gMkleSU8Y^8&&L8r3IoUwP#(k)gX;%5^ELCqfyacdVww7dg22$=C|+6p)T-4*85 zk~}M_y}kdXdX*qT6j|*6Wl7ns+-GVAW3cr74Zuom+Ok4$`oo0&{5<$HjvGKG5zpOt;7s!4EttQz{k zwg#F__H}w2Snr;jxX_~Cty*a9LSsP}a9|&Rb=UrtaD$^rW4!7!IqvSU=wQ0Wx=5fe z>RQBEF*=5$cdltXG1MFkXdUopf61H-m((g1^Q96f%g4R`m|Ua*68bI{pMXBvF00?+ z1XS!&(N38lCoMftw`f(3_j591-?QjvW^jtNu@8O0{<64su~0Gk=5v~#ZtP8h_i=(V zze9Bmx&@5d5^#_}mH#rRg16`&qQK|_K^v@*HB7cBAa0dCbmM?Qg=Zd5!tJq|53AQ3 zPbJ(W7=wEV0ZYXLqgcGwR0lWD!=YfkQ!=9nk9R+lz=V~nQ30Lj$GQ1k4TA}s zEDg4v!puJjGERmJBJsU(t33!L(bC!<`-ON0QmZ^lKrKHoWCM<2_d|gb%A8x$Def%C z{zw1AM_v(j0K2$Xd?1ZfsT&%fI=G8lm;g0&Q9A46!U2uUxUM4SeT-#M7m`tU^D1>> zb!<3pWR-{|8N6lp>bQzcz#Paq4GfRhh<<>jtjquu1!S~1ngP~EP zAkQ@+7z?n$yZ?n5bg73mCW~43OpZJAcXTRRO3=ndqT=Ed__2Rl!wKWj0pna;EWjdB!Zo<>M=Fj)G^B^PV}KLsb%1KvzXtUOoK^A(>zAzqvt= zUnw90Sf&CQ91AZ9q{)UyAOh%Ql?@F*V*x2z=GUqCBg6|1w7$X+dE2&%*c}Q+U>;p@ zZw01HHkuUtnK6#SW8GWm0G^H>bZ9>6%3k-Tl&+xq2h==c;Vx$2L~~mM@iKU<6B$+e zyb0zuZR^)Mq}E_Hu2-*xb#eghYZIGB4b#S|Uku2+=h~G^#hVE(GC0wzDWvw46_9PV zHI)x_`~pSf5240?;-Ul?qjFGZmzlB+p9NX54O7=o5u39O!GhcdV@8F;p2#^}=dEJ? z(6XixLJP~^z-j?k#KD0(34XyM?oSrt?P#LQlX@jL8-z$HD}7-c7(!RSgJjJ{6U$e!4Z zSwB7zFHE~7Eb!b@6p3JLocS-d15KF)Dw_Xkc9==myiAE)W{lFk$$V$ON2!XUlEz!+ zA>9Y$4zh@TW=lhW@x=C1kkx(tOm?oDux9+AbrBfK{gr)_61g1uvUJ73Ioa2M>JH9s zuH^tR0CNvZ%&)lj`}LS59q${fD%wHoIoWc-xzB*;xd!BS7qVt7sJXAyRUBZ|aMJtC zOT_LpL$d&LzZeAq@!JWMPUu*`m!y`x?PVMAFDqzDust^K;?@EBxuQe8|>29MMOkbWa|J5(HaJx|7 zcu&1oI-NyI0O8YEg?e+Xk)J#!=A$ClkEzKAhsvm240Ro~5k)vZdWc)WUc&W(+_r__DM?xr!IGoD2PIP9m`&uB%I<}r)8kLcu^ z&cAMG?ck)1`yPF1Otb0zn-sZdCcX8&8)niE#~+JXjb?j)azagsiA$)&Sh4Tu!C*w< z317E3EY0vn8Eda-bJ}w&8@rtOS%LUr82Fk8fIBPw+T9D}?OJ;R+cPJJLe$6q@;d-l zzFl;LpC9nhS%>VtvXyAW+;_n$BF`JafSQbBX%A&L%W};bl!ii{oy?t+3xkgukX*(l!(m8U z5j7=yl=0ac2*UUuoo)Ogaaa=Iz<4886z<$X3D#T_l)7)#3OwjKAq=0Y5bExAJ%5x5 z(!m)fWK7`E!*m+^3>WzslhXZlm%|oo+XD!G$(x~wi&}auk<2oCp=Z7{44-~AW#)7K zY;BG2CX;ruRSDIJdbg3)`B>2DuXu6K-m9uQip?o&{u%>rFMV`?b_xflj%!03BuN2y z6N9&OS%?v9NQ_zQl;pzd1P5B`1w}pSuzc7EDH!h9|C5JqEY1z^j!INXhS! z8JD4l!m8;3wx9n3lpt&03va=iI$fwnzZz3ET-Lu#PjlZJvT0iP5q-VZ&>v;mmATa# zYyXsDVY@>6KZM-uVWvy=LaApgs53a_6Xd2#_WDERUZqERF>cZ_;pC-4Zd;bum0QL8 zq}BtAo2^!q+&28p!P3(v0Txfa{wEI}_TO2mu6LNFdbd0vSNp797 z;5l#nlu(Vf*|;0)%f;)fYs>rCdw$fVIr!RgqkO`XIr$TMO*z&E6m) zFh0b~xAwL#5UMqD#x{-&IDB>TAwq8I%x3rcE2(EJcmSHG3)N|rArJXzTBTcVl?OZ-^nbv!y}==C zQ$jT~vN7z0G5s?iP!T?$|DF<@c#e|W3iINja&LRFCuc?hr=<*R{k%|(<{8@=c#H2W z3-v-33V4YMh22;06gn1!GF?y_er7BvY?GUXoOVH()515jK0~F}i9&8q3uc1Dm7eGX zz)fDB@z{8gkek}HseFD&>wke$S_Xbg$Zd^aqtPmw48(YqUVD|a5~z-*HcEG(xu5)f zS`VDmGGX)2gldeI(eEcWW1Bm*9$0uE)6}U#?#DJwKL=UtJWzne1nxHrx#{OH-z=AE zeLCDS-lCA3Vss2KU~IM(AE{-+i3^n6R?^ID;E$*bz-zQjII&B~ZGU;ppdcJIQ;O$! zgTu=IRme?C?WTK6&C<|4vW$f|XX|>Q8ng0PUSE=Rvw=XGki~eMUW>m!Q>e~*dGiR@ zOLK+Uto6XFwM;nq6`>j{%xJT+c6Z8>tb1a<03WYq!sc6r91Uos<*vm${M(8bXc>5$ zkdrHmWefAF+&bef6@P=U^=6@C!Ll@!muG7|@LVkeUn}Hf+nDc@ZK%P*c&%PbIPn3c zBVQ#qN+$DIQ|4DZSzLf;NEz7pMIlGM%$Ci7h4)7CT-+9HeM!jCP^P&l<9_X4z-Q{U zgzcXYay`;yp5Ffs6-Y6o#%G0U^sqC{*W!-sFsyrS`9UKm)_;+MgNoiHbS%u#M(-P% zqYK*rCeIS8p)#K=liSD?XUmk3?QR5~q-Db9SA=S`(3lcwGKmJA?iC^iqn`Z>Z2S)) zN2hDc5eMs1&-etrmayFssxi%t{D=e7Lc^ptrC122x1KHJx`j4vw9cEfn*ld#HzRCc zB;~fy#_xx874vw8Sr9Sl#g8st90fB8SkwddX8IBRUoU)o@xq{&%=kS9`bH|@%l$q` zFMrHn7~+fj_(G~r35oSnCcSoZ@$5u=JJp8F11Zd;VSfVB>$h8-u=GLtZX%y0rvE2F z#LV_wq5zKryw{}yu_#GEdhxl%i^C-5`|c7?_z@9>!O-nzqJ~L?=bZLtVtg?%Kg7+1 zL2Uc#D8g0XXw^PFqyS{Q<)DYB2p*!Hh=u3^fnW6)>A}U!NjjD@ArX^Y#K#TYH;EWC zi)NVlU4LJgtqb{swthh5W&srf&e2{gF#B>Go5W*7+x-rNmy3Ybc)MVUlRHUW`8+xjPR`4Mzu@p!w z?)5+wSBKnrLqFB$llB6l;ZB*oVi3It*F|V%NPj?5#@(vUfNmpQNS|LyKSE^h3}|0s znXuFky3Df4VCad2Jv=_*LBJi3CWLOv%>L!LX)tc0KE5|$X8m&NzJ2D@QFzXy@9i?P zemTuZF<9gi67##=9y4n%33xst?qfs|!x$&Bj_e=^SvJ-!@$5Dz`7c<4cwr&5S01J930U_Y)H5V&3N z7}FiGfbJ#mtrrJAt^ucIh#7hrk#&VZSCN$^=H&(JK*iGwdpt{k^OQ72AgI8JKi z6Qi$yXZjsY1zlzpcb_#GTC}1`UZWJR6?SvvDZcGfU`P7ERADOm8?5~+lvhw+J9$9MK25@v3uwOZ^O~5_ zr->>jXrIS~pQ}_UEp%zcI>*lhJlE`ETE@Wa0|R$JtdEcNc@>J7+4V+N6u`6f(GM{8 zgHr#>ujjc1JlA(aER12kFb?aPiKq(MQ;b9E0-=5WilNZY#I%qH{J^SVX`h*1{{&+wk$65sfMpcCN6QS6{ZV4lA{KCS@$?cis~Xr?0AM%ZdSY>c zRV=a2Ff^I>nP&<{KrI|}t44Lm%?cjzfTa)lSeYVgmq~Er;4unl&mN{|V%9|o>OwCX zh)E6M=j+|@rE0ar+|98zL4Omm+6{h}$0nYb&nrK=EXZo=#N0oG^Gp$g4y&H~EGTS3 zm`VZE^Dty)`;`=Tl*R)UFofBbx6kk+7;7+nc3BxG+>J{w=V)b#vsU^;bY3P zBI_fVEckzYkbQm*yF7Hd1*JHkX%uXzlMlu-PlVipqHy7E&{9G5EPvWX!-Ho%p+~b! zFIVczcOPT^jP>5BH_+$0QN@r*@r}d+OmqR3Ypm9x^(p#2FaGYgM~Idruowhh9FyE=Hbphjdr6In0jUd&u?Du!hmR<-S5 z(8{9M?*<^d0>&CII4c}6&%yyStHO@q9EtY;tWP>nQgIvEwLZEUbmcyibz)4};3D2b z0cKPWP6uMv(d6@>X9&AI0=t;*Qf3wU6e~Q$`C&rDu+R3D)qncR23&#;nZTJrIt-ZA zDRs#xwqcCLU!dlcReB9MKq8MG(&F&M!8fLYZD3E71a^7PIVeGktz zt>^=3m&ZsKHh#>8z7H>spS$l$_tR&81o3RmqhCsx9d3}skT+&+KW1$|Ng`&IDtW|q zYNTB`A&VmERex!FL6_%|d{T=^?TB-&V|c;DIs)$iE{(BRLg0SI%o<{Xg2vAOi}AeD zs$1@3Wg_NxdGe-Sgr1aCwG^-1-~r|hVhLGsMAl&<4mRSf1oxnA!tEC4^M)}MurnxS z4WAiYPHEMM%^WsaE5+y!b|+bo@G}NiUq(nhIJA3LgMT3AFOG4`%z^|Tu6igzknr`1 zE@|{5(43M=C5&CM?5yDe%}ccS5LsKE7e_esW|;Yyt9`377>eS+ZaQ?o9?#fBRv}f_ z2-pG6433J>KBl9ts8it#d!7ScXaZ(-O(tUdm=zQr+kPs{KBD`4O+Qq10GEaVGy4k9 zm-*}%=6_PR58I?)H6Hqy9*Nl^1BS;l;`g=r@k5SII?XVGk>d`{&_h?i?inr4;@QD)hv->R!ft? zlm&x599EJC3n^xjI5*b&DcpAU<_v;}$1yc0dRBtL2A7b3_{c!!h|ArX2|aqSiXNHb zw$gM4PYO3reJr$(X*PerGZ#pR?h_|=3HT!L-1cRUA~C(bGWz7RnH6W_70yRL2`g9Z zo_|alz1&Zb_)K;$I5%s6xd;Q07Z7%ZS6Jje4{YN3x*J7(W>qsP8$sZii#DYtEzOOg zYRiueK5(B4&?_*nrBS8i@KZ6*JXZw>?7OUA=YLPB2Y>xweHd;uUg?9}I~zlXi~EOl0%wjr zo=0JkBt5n+?EVY=mF^6?;GlkE7EP+2e#n|4c$lzKN`oi>9j<$$2lfYMc*4qDV2`WN z6y0a;r}CMIrrs#9PSdp5_rXGZJ+#UgVcR%YEQZ}!JZiu-kz;&nO(>(f}UuXwS~ik#0TQY=Or zS|G|>VA$=H`%$+K^r{>c2+k+W0}fij3=2Wlj+wIRk3N}5 z$AlEbYyt#qse_||Qg%TFsok3yaehPG&6f(~6VTio9k$P~+14HS%@cf(n6=Nu>_i}* zd1d2n1ge@gSzq#H1qgX=qZOdnw{}SA{t5HUgAJC)z%3!jDN+1cEIZ@N80|wSO*PRw*`5m*D(Sh#Z0JZfl+)iNhRYZ8c`UOvQZT^L*p8 zc`(D_hnOdwuB|I%0fNk)pd;8@dOd*O7CwaUh(REBfXr@9~v4)8_=Ee(tg&m8!?gK1cD&7O~?MU4M?uxrkYX@f5@y zZw2HTVJVqJY1gWDWzpP$+T{zg37k2>au2P~4yy_?o1Z!H%)LSuw$H4}iLT!+Sr^D$ z86>V410?47a?IU;J48xLRyxQo8B#zri6)O+$I#n}RXR0zttQ@wCXKZfzw$$<609Bg zLGCI@@k42JSeq+XT7OuDgt^5j2Z`M@io3FGr2}VF6!F4kRV%WvCkOnod`29+v0dti z62i=~p4ipVwOI(=qVy?+cdB>I^qGSD#ZS6X`A zfS17__x`0wI*6-$1(^>b)BR#7e~C4zCP>&Hn`C*CVSpS(>!l&zau{dxT}Zbab*ucm zejvfTP*Xg6bPv5s6UXP(5*(?fU_Dwbd)2lt>to>AKVD5gAiWjyHG zN7`-GWbLyL7o0U=+(Z{Xsn~iWf#f3*SDguJ3YcBD=6@gWMR_U+Yx91EqQv*iJd1Y+ zi7>0;!>&+p&fV^Z>`)7Ws-@TO2i$8A#N!h2ggQf#FL~8AeOG=Un|8af?ft5$G!%zK z80XQ2G>t%def)!bM64dNBN5iC=_M*K>5A#ejLUI&Xg>J-7E125i1A)DefvQ2`8L2gmp)=2v(L=xS>!Lx zQ;g8ZiP`7!9viVpG}doM2M+8R;8`|*o=F>{mEvkgcb`?;{y?=&kb)6eH=2YpM+l#h zAZJ+NpkjTfu>FQsl!TexE@0&>4*G?3!G9j-0H)TS#qneCK6J!Bl6B!3?8VjTMXZ7# znygO-Nd$u&g3@jT&Y^;{32R8idj&XNQfYUwfd&p27FgP6vNdR~^W|=Lo*kpA2s=;F zu8Fk6`Q2k zvjgK)BNhDd;IP?TS=>C^D@A&8!0fOe6vtCBT9Y!fK33h@*dPUsjx6l^;1| zHvw~9@KO>nt&or%r{I~7G9ukRitOq|ozp>pQ*y!PF0`J zr?3zcQ`D{4;lT@kloYOy;6I6c`}G4AJ+p~?%urzV)wIu^Al3m`8;EGAMt_n0<^z7t z;JFzHBM;2}id%(2Qz#4 z>OM1Mt_D@vA-Ri6gDHL&9)GZITAA;`*$?1Zo<$NOcQLY#1WAC*^_4Cs&kecEG3Pngd-ejM^9&EYko=o!$a z%+x4EvML)imDM55QwI}-`Er-f&~9g+(>*!6W{^ssA{(`G4ooCwn12-V(|Vx8+Kc>P znDcVYCbG}Wt}^h`kNte2fB_Ix`q4skG;Gw=X+K6kN-I`fUeAI!Pg!DdDpUAio!DwFz;f#|&-~~d_N%tnldR)psdj0AMKQEB7qkOhmT>GDB}7cI+o)oA=zc3* zkh`Mr+Vz~c%dsFxseh@be#Cz5$iCcX8|Y$o0Aii>dAn0pdP$0gK`dT3%=bblz19XA z5SM;XtAYc*l&Xmxe znJf9|ycvNC%#oQp$mp;3h9OSI4n{mp2||{4%amF=^M2w~Z<GkFnF(r%{6vCCE$k+ zo;lQgOekQs1zb*fkR1<_f`y9*xfvz1ojtx`cd(13hkxvho;^DQr#U3dSyd($Aw(5a zJxAWP$vkr&_F(J9l^X~-`A0bC%66ITeVv=0c{VcO?gKll?Z`Q7VbSOmW;eumA;z%{ z>NP{8El8|63!=gKX%;B)vER$DSdK%S5Kf!Wm`R-B0s)Snb&pGC90itLmRU!vWWYYnG+gh9T( zrnJ7MseN~Zs*ypSS;AUwQnA0MD>)e5K{7_bQK8WO#C=Ybg|@0uM4$7LbAMdPbIUs> zgFzCHkDcLuTp1A#cym|4*^9Dfq@>`aU28H%*ng9Wh^A7^F*N3A$X4xn(0y#lVBv~{ z+5NClPt5RikkA)(*$l7Tz{1QIWs=~eAm*kXw!KZ~a zET~+=B%IA$^}Rkq(e|7%zo+9eA9MjWI9BW+7@UceZLs&TT?Xv1lZ+l&k^9;cZ1_qN zYkwkUA7i_p47Rv)+PHOo&piE^Ym-dJh}mHkN>wECs71NTm?Lz_99_c2OBFH><-FpXgp7Q zR-C#J3->L|`ncJ}5f)q=yr;18>=(b!;l{q~BW1$?-w;*AZw8uv9>3uYqG7jU-rz)w zemqFyr>@(J?Dk<6RL-!UViSzjt(u*Sl{?}%7Hu~;21`bMHUJiFFzXW(MK>IrJb%TG zywv_gVou)!&$mipD=e6GF3S7KU`HkI->Wc{B95#?xz*+)y6RViS3}-20WL{f@MOXf zYG2YhNtg9NjuG}bELT|nhh`v+spqMFF%O8?egX!ED8Y5>0B@_V3{8uRB{=4c&0^#2yvy>#l%lV3H3E?D+uu`_9#OlZJ6Zelksl^ zRcYUYBpJ!uOrY!pht0^%!gqNbIfXwatvWbEw#RjI^^${gu|1-q2^;x0cYk@4UxoF` zXB0%-b7Stg-Bg(U`c%?7!#q!dl)r$Pb!OH>y9S<9x%KLdK)w+9*18s@I9A9$jIa?s zWG;D9@Xd#ZU-Pr5RN-JNVO0x&&%2G_738ju%*h_e`s{VnFidYbf(rhCYUeCZL&W=d znmB?ifP>a5E=$`V9K_&rpntW(dSQ(YJWu$B%K^-8!}81m8&1zmi2_9UvWrWrP?k)G z9)sjVE_(GvQ?s(&Q)WdQm4syMtI zxV$QIxT>4v*>QfzdAs&trq3Qyc8}_zr8p*tsNxjb<906}m|vOOt7n1df1lb3O%y1;y{%Qj*~bx2>)1Uw@t1zJ2e)+HLE*aM5<$ z3E#-}AM~*OAO4fu7gkr-=Sxq!vF)<#q~Ol2%PSpv9yHA^?d{ALTZ_M^vyWSArjvKL z&0CJ2TiVkZblA;Xri-1 zMwpr5Q>p3G@_&1swdKy*ZS$Sgxqb7UJ#%YwtMhBqL%-R%V_|Wzvv2P9`Of0P()`>? zXL;rLrRAk<`Y(DWyB3z_L`af`zHN10zkO?GeHHgG*RlP0XO09oe&77s+&2FAbm{4z zcztK{`8zt%v_IV~x9Q8SzVK;J+e$Lsu)Ivab3Bc-m4B_r@0mZaCjZ{MYag-2eM|Fe zTaUkeX4pLO7I)Fpx^3(6OI*1^4|#dtWy>q`tN7Qxxs}`ZEZ?z2#r<=rK;O%~A8xE$qbs=K=lr95u&o`iq?0 zPPe#!Zhvj}ZFelM+)l+^bNlx%9;Dw~oLkyk`r1>jzVe376RACEa6RS9i!Z$f$MFx3 zX%?{j$7DL34oZKVSX)^yck=f9(zY9)R{rCSH(a(YE&Z{x{l--qsXPR>uP(2z?4B|^@YVf^VvO|u(JGugL~(fmX`DTJZ^FB&V%RxgMTmWT_4DP9Cf|r nJtEYdG8w5C;B`m;Sz00{R+g97e)Pxh{pbG&qr3}Wa^(#G`13cy delta 103380 zcmX_odpuP6|9|czxrL2tT#95hTPl^BkxNKSWo4tx-df6PR<=cE=1^piP|22RXvLP8 z-Ay5yQ+7nUjHqnLFlZWLE{3_CIp_C2eZG(1e>5}A`@G-p*X#9sK3~rlQUAiK{}%qm z|5k6}LeIBfLlV+Z>iFzsLgcPZRu`PlHaQ=>mmqklL$hB$ongDV_h zExyD3X>Pa_t@4tj{X0-pv0t*iF-a7x-E@bXFx|3UwB+ps)IWbI`E|AB@}PgyHmxml zy%$p8Vg4}2J~GiEdTZ3yXM65^-4m!Eu-oP_ZRN(Jbx)?Zh3%R=YO^e+2%;=_t2gzS z5~#j)?&B1cS(!w4`^81!@!(ST!jo5gbx*Ce&tt|UvXLeHJY7d<$(n-G!j_T24Mr3; zY5VfgFHDwE=msh%Y{X8RPcx>a{C@QnO^=qcr>#`=ZlpFVrtOj{W2E*J`^u=psiw0r zZKqV5qzviRgT@QQ!JVZ)ttM@7A_m9|9N$M1l=M1;?lfwTiBRxklyi(MYSC6 zJ|hg~vCX+=ZNkMu-_tZ>!PU{GEVdqVr#n6FG2f7rz6z2JK5ojQnH`x{g+FRK6>~5U ziIm=b0Z{NH3l zre}IE^xCMObo39ug&Eubs#?=nJYcJHxxvAvvm0a){^N6-lg-Z+YPXN4n!efJ+H5;g z9=$60g6pJkbI~(T;gnf495pmOQXWW6aTg21=w4NF$4e$wWG9xiC@Rx(Nm@)!lS&Y* zNj3APTj~qWN$({Hm3xFvrr=jMuGxRPM>C=3=8&LtbAekZWL%XiDIM{%B6S>HDENWJ z4%oaH5(FX}0wyF@%H}owl$iQIcWD~zqPfK56B0Awb;FE}R`Z9{nKzn?gB9LPiYwEx zr#ECw^J5Anmu_5D2G_E*p+SOAWIJS+s`b2_@~`&S6n;+I^`2hkQai;9)aP*;bSkD% zUUyiW!E3Tv!#Odk=JAbx+oOtio(V4DI5$ck{&k9*D+wNnaiQ0(Mjg53wgUge(M%&* z#G{ra+?ayQjpMW6aX7atX``7NRcmuNb!!^=j$B_WY9M%@o9u+YO47}*;5{^wt8?}< zhrgVewq}?M;#gGw#5qwtWUVu*#(rBU2nYygr)5!#R9>;VXga6ak~P(^YqGdXjiC!Q zA25^Ky>tI6iek=9C0vS$oWdNt`uC_d=twRzQ6&_YMuo1rnHU5fsg}iF*eEMRXZnOB z^9+ls4$KFC(gZhj7V&Q(1jd_;t2-R>X)7DS)gOv+hG?$frvpQlZs1E|STy7B?~H!% zpxP--Q%kj6!AC}D#AWZ1WVd|L>+4$ zU#cx<=ePQ{SD+7jsCi#G-R}GQU(TaA_@_3pSHf6DjVWhYG5a5cAXT31vh#ICw!YQ+ zKq`w7JK~*%W3BKtk}hU$Y?-uR8?5$7Kbx_qO`|U5&4};m zn6_NikrBQDC*4POZ)Bb5MEZ7_#Yj_D%uq1hM`ixVD}FcKJiYqzzi!|(VY@ch7sXFr z7{C_D{gS+MRMQoyTk|%Mo%)TLeky3%#d|rtWZSRH;)Cga>Aa_-Iu_LowUHLI=1cS; z&-9M9!v3tzt8YdlcpQ`BElq(}*k}D5wtcv|_y}|TF`xA3;^n=_ks*6&S5)3X^!}-k ztIOWnz{|JEpMQ4_gtSDDv-z~@+DPe##SYf6Ir3)2F2M#iLE@#EJ`<@#6~q{^^RR`y zRY{M$B3ClW>D4WPcWx$XH$_g$n@^WeOky=*TZ>!wUTM9;Vn(00zdfbiTG>I-jHc|f zcfb7JK0rYkTb$j$u{_NG3i<3aTXL?Ij^F(62qzDny9nQ=I&-h@$v6_#x!i?oov8K_ zZ=3nE`3LJ^A#_%eU=yn}wsXT49JTXiv-PE#@P;>EW*27$ zS&Kye0!d%HZ9>onTB#>_L*Y$SgHz~!1V0E3POoOU3lqW%BD=2i^ zD*1Yh;4wQJ<`|#+hx>vS9kftY@yIJy>w%ulywc1MAYJYmVAtAGEgI(oGcH5LnfBu+ zpqv`wtR#ha_G28v4yJGKky8f+35A(!$Ln)0k@&YNY4dC+8C;e=`sCqa`8)qO_W2B9 zvx7C+^1q!j=-Bd%ha{bJXF9TvvxWjKJ~o4|w5%N0$t#vBU- zM+5F+1EJ_$bczMC!$i~vYz+GKoTu*hI%>gwcmv}{CV8g5gtDqpaY3zXE(Y<8HQA6Y z62~$UfVW``7 zCtSj}Nv<^K#n`SPj`32~!vy7_t`~$UYBcqOa*V5=vAybDIanSoMB$B4UATIQQ&X`R zzVxXQKFCB^tP$fbHpjvmx%F3z+0*s^p=a-t1=h-n-I~A9w0x@R!7%ac_7rkf+l8K9 zNTd}qSG@AolAW1$(q+5YgaYllagj}|2Kf_DJt;gaHQ(Xb5XVIj^d}nbN1lln@(l*i zhPNClOM5uSR|~JydFR-p)V=D1U%bLjtb~5YEX35%#OXhtZ+|j%vifY_AzgIi+{PDd za)H)od}Gcf2(r;lvbbt2L6`((Z^GWr%ZNhMSiK@3iGaoK5PZUlRCU>#pf~ff4YGdQ z8;sXC7xM)RwtXR|wT-A`)+|Ng&R8gd7C1zyR^1tkpqW+O zq(p(O6D*TKX0rNHl@HlTT$hmVZgm4&3QGPP^RWm>Z<24_Wp{*;fZW)PU3f!Xh^`(l zcug+q->?=xw_f

L{KPVpx7A$7l02wcxwXQH?&I+15==Mv$N#E>Iae&r!w>f4Pb4 zB!{--T!QPoz+z@t*lT#TXw0{~=M#-pZ8^mbMCbvH(AX+sXVSIT8*{?^w^BF64}6lv zIdcqpHCXzQq)x(FaO>k(pqwBr{zLn_Donkh>fPtaR^UYA0IV87cKl2H;jwJcg&oeC zKY;|}@$j2aWN-vs7yqPSEDgfrryYMwe=v9{QdqtKyo4T4X?2#kHcF{`!Es1jxlYZw zpQx*j5yu^@V$}~GfSVz3$`=^%s3GDsm#TL#={)Rk9?cF_e~&tMb1uoua^7;^FBb)V?^zn%rH^@du5d)_9MhBJ6cnE)zST2U=Qk@2RU z79KlIw+9%)CB?%Hgxe-zffxh8a4Im zS%2y25xZn&-6-@|Gj@vZ*z+Xq3TkPsY{oAfmDjKDut!7wdgxyla7D$~S5S%)FWdj- z^Y!W(ucYLFq4y<3_eKTuBe)7s8V_1Q9kR_Q&lU%27H1P~?<$vg6lAUki(V_B*eJm* zeh00W&EdaUD>rl{SjTEe(L<^DijRQW7mFTIvDeOAE+MXLR4{hpf%%+;nS+2r>YS;D zjYt_JD1uht<=qqIJ17IXTFtysqLs1$Uu}S}9~{PJG*}p~uWre)#~fn7Qxo%5l-ZC8 zIx^{o)VWTaR>%B-yf=<7eMvqGU2FFBk2i0Wu`j{>h1ztmp>Vd!xN@4BsNwD%s&E0t zL;+oBw#1LRBA;f|tA;9MG;8IiE|KjOT~k3O4gW}y%EfHg)U=EIY06^nUU=>SXd$0^|VS@DlGTz!=2c2A;W>cbNOA56v z;BaOjrt?fKj`J+@IiQ4xlFnhJ&FmnMa>IC}S#q$d_%wNiTu@dFW#-ay=nKJ0hyc0$ zT&cqLfm{dTNui520-xvP)4*-OuC<;%fAxn3V>u$V6rzS1%S%Lg&=Q@eHDeZ|@O|MqiL%1~q+hjXE*pQA^&9Elx+69> zG=D*y2iK`)2MM1jRtC22!RdYMAWe}qck6ldIb{br`31wq*>7luw7FqL5j%T+ba9vD&xN|vjj(O3&opg6v{t1JYzUp6HS{#MC7G&! z47kWKGY31pPrGf0{MP^{e5Z*&aLtxOV3Vj$;08NkM~B0x+rIN0ziYae>G36AdCPYq zwR7R%s{I6RhaHcfn_v;`>%zWNg%^D zol&`0PE(RpZwm$&WO!MLeIjRnS}wbry&u{Ly|ontwW*0iIlh71i#>8kxlC&5uUQkT zT|IW$%qgGa_I3O~p;-lswqQWLq#mp2xMrzd6fg%zHP5aA*Me_?`R7QoFH4i%xaWG> z)2w9{{tDt&^vYj{hR&JNP>Hk7J-{667?A|1mL$_Tqpep}u>s}+J6^wmx2}=?$)?Ff zzSQ4Ikfi=Ef^Pm56f!ZkOE{I^q`KvlL$|IfE3RYF>K3LY-(eo~K1LXy1}G#Gq-RXa zqV7l(r)`&A%elnV0&F^fM9nIVQ5$yR4dMh!FjfVT@WBi zhTv!#nVUyTg)5BI0Rc(m8GGe<7Pzx}!JQrAZi^k-UXr$;p3(C+{|DZ7mm9Qsi3``Z z`T8gF{-H4!z{kYe%?k-r6}rw4Bmp(6hSpjoOdrysOHwF#2)%Ne#(HQ*S%vD4tX+up zvB>4=vzT}sI~GtV@L@p$gQ1Yo%yZ46K&FK>cA+3OA71=l;ArLwStbkMP&Oi2)i^(9 zR4VTa*AT1Z2b>#K50|txRK*xL-40MgcCv_^{U|j8SyWlXZ)DJmn)`PGI-695_1ylE zo|q`hWJG_#-e^tJwBLMEejt9cFO%_mvsun2D8nS(N$CiI7g}U8H)kj)IuZKyXKeU6 z;#P<4kQV10EPd~Ly>5Ra0zUAs# z@TUytL0jRu9bi7e zmR!-J5QVgdOvJS07rL;`8+Gd-);NtM_(|V#1xjauoOZm3pmYxbT^T0 z2OpEI+g#@?ZDR`Jj554S<_R9%UmO+AfgBI6nT7vR$i4e&=J&qi-Z_cj$Afg?J+MiF z2)b9vJnYe6-LzPqoAU)0aWD>GCXO4^`WK^j_b2w~9O{O#Z=AU9c5cF__jd2I2H;h;nrdJWv!nU{hwi8rpUyCr`*qVZg>G(bV)A)KKLE0AenJRy z?1l4$O_zEU1gEEhd({{Z2eD6A!xTME*H~d~ex~vGJ^vNdZHI=Qxq{GK%JW^2P^wEP z$lNr3*K8epP4#685pYi(xOI7Z=5CVNs%0s}Ec)7CT-4aX6n@^eki@Z0Q7PlCFUF?K zi-J@RLG5febXBS12lQ|k#IDVbsn(6ju&0n*jOA9Sj&&s%Br`oW%cgmNp=t8o3es4a z2_WG}R_crZLrV+pEuRC|_1vDhd&zY6=IvN@(j(|XR@7>Uv-iOkNg=Fe4Q8P)Lp6kF41EOL~)=zolN%>+((BVG#<0?_BT6)H&TC*+!_mjpZ$ zND8z^0Q`iCRk!?C5SY{|6I(8e+SQ}-}Znwwf{DdimsA+~r)lCUu4LCCL zP9fAEhEP3q?m;T}5Bhc|5dVS;h8{pt>xp?OCYyY>DM-!UuoNlkN(1a~;X`Va!)R^7 zaOYF`+wyIe$Ago|139#93=L%~mqEf+XSN<{G-B6jD_Dr;j@ZRmlTDC9poak}CnXwl z(l^SsNQru!<`PxM2z6n63K^0;djv0P6Wa08vY;*L9T~i|Q;<=5#}OXK7~3T+cum@U z{_m0Mxe{N4Y2?;_mm4Fm{1FnQ@Wud+(r-kgpFJ@iB`gLd;)5tcM8i5VoK4Ugt(UQoBOp8#IbUknDmZJ9lB&nlL-PeP7nYJAO)@c#XOhhBy#|g z)LK`jQ_tJtYH~&6XGk?VxIo%elR4AOvjLJ^HS=uf$usl7PSo z?P}e0i+qD7Ydxom{nqDGlImC8M`j6sK`eIJ_83{_?LSHOc<)d5mVJPKxo~a=sqiz- zdgmX@zP2)Bli0lrtQlQ)r;>&Wf)H2dIrfE>M31?E;jlz?e-sE0r42P)^Mvq+f*PDS zUs#I#p@xq)(A$jLZqyT#w6Tyr7Axh{?^42@9oKT&>_cZoVII8qU_~fjo zw2&NMouBLcWtiNKZIu>mfUhe2Q~0Lc=sRA!O0 zA0oI%_HX!gv7cEN8ZOu%KGrprZE+DTUhPtb1H$(Y+`1*ric5EMPN@u1-?5Py2k#fJ=`6#A3HE2Sk&TL z&K4DD4aYB-)g#-AfeJBklS?@-8?KHCBpD^nh0Gmp^A!h|^xIxxER{r@JPdF;<|=f8 zvKpD|!k%Pah+mlDRaGV^$D^DGNY?bMmnZYC=?k>ZRs64pP30gltS&7<5Ag-H;VkfXw8gw;*h~QFjIBgqQQnbvdd!&}Jd8ViNw! zYghWDCx(dO)fbg4%ZQ6$xKs;>SKJ+r?Guc1**h`L# z(uAlU=o^$_aCqA9#UM#RS>?ZV-y=x6{v&%Mn?cZgM{ON=8s)0_3s6Un(WWzsYun<7 zf`If>%Dv!$AD^uo+NY^HPGY{uSxvZ5dkXSU*wr(7RbkYPEqZcsjy<&0eD^URfMFIq zsDFXeYSgCu>5CFyn^>d*Pm3Q|*i}+{#C4Mv^$*jv$M3RedIJdMQ^Y0iZ}O|Aw0Thp z`X%T>w3I3i>oP_JM(Cl-it=>>;~gawk4Es*__!T_6!7mVN9S7jxy*xjx~&u_jYmKp zhrbk(Ye69MbK90CiaAG`pz|vG$~m$lIpW{7I7dMaf4My)Fi3z%T$!Yj4<;943gZma z-v<;zY52$8h2(mgmuRdhr>DDfODU3|OMMJGA+0_Wfto8%9sEhxKnF^5`zg4NKVka9 zq^yIaYW|fr3;9k!3IVYC338IX@E>QNqk2%koLS!`f(()wD?Nr*@rZ^4nloo4`-Bzw zz8KLB^E2~C{BWA5^6#THHE%DW0dD_r-_Qvh4qD1Y3;6X5r=LX&8_r2y7ZjwEVKd~|iP8g>Y#BXt3Ejv#6By;2Ee!f7r8 zy+LR}n=pensCi`qTAUtCQzY+^*Npq{+j7#P_!NSy^D$)D=6a2AjlK{GdF<7T(B!&~ z?F;0w&Mz?cXUl$+r@Cq`F)f{OH8?63U9oy*M+vy1>bCHqyZBb@0LbkKLRLQ(e#x9Q ztw*<2<7JU3bO8EisV;=o>LlL;1eGpa={W{8z+~N?F{rq?a|ic)Pp{~2;dMt4Tg7f% z+r%l~ScpKJF|!_4u>CcMz-7Mvg$yoKuy@JgA`&%}!g0ybUTA+ceI2&!qM#Un8<}KW zRG0~589yB%v@ym{9~!t5LYOLnB8W_l3j2jw0$$=gs*iKkFR$eL-(Z+^XTiU z&QJ&Mm*;05!iA};s#T9}Uc@+7%5GDdhO<(4IA;>Re~nY1g3l_bA+os0L^Y-f)%=4x zxvKA8RW&(dZmq9Ugs7>S^Wv=xBji#zw&PmHCi%(RdUPO@}GShRQPX zwK#f~D%QCP>K&$_Ujd~50d7=YATNE@q=J4|?f<_QzQB8qIx;R*LthH9Z9;OGtb&p_ zPY$MUlxYORIkRH8WY3($3ccGdh%ck(9kZ$GkfaK^3oX#e$a*qPGGo$*5A;0sa z=a7RK^OUl?tNE5ZovGXyw5Iy7JRyo77ul7&G;ub@8zb8*qi}YlQ{^{P0lGse`D}}7 z-Lt1;+cbzcZVoC2iqlsZ+}{9UZUvIim74RGiJegegC>%o0Q8@efl3Y6fg+1tSN+uM zi}Fj6?@&$`MmZhBL(c+{0nL+Uy0C#-I7<=M>L;y+DCXqF^4NfnNo5V!ZC-__zV4qr zkrN6}%7pF#@e~$Pe|-YJMWwX;^2UBdm7+qPf_eWBS+uDceFU>WyhX_+CH5tw+d7 zx$xK5{Cpr7#R5onl`?;GZ44hoD%tOQwt9;xhJC$iqJPgAQ3plN(WRHxKB+(hss-31 z?u~kCD7`L~*AIldqmGk^Hnk_FS{*lMBW0Ul>fM^|Z~lC+T)xw}mUA}uHnA9d!C*dH zuTfTdJoe1~08&NIB>VZQ+r&bUM$5oG9#HSHfS-HbZgr*xu+)3!Zi4`W3sr~xuMna+ zc10RHl2`8mj=bM|8|aS4uJ1k_$HAi+H_^=7>E;5vnB1K-5u zgNoF4=~^<6ZNSqMUgzB6h7K+60ssuT9|M#i3G1R|EVQ@b4t+her5ips>JAQn$YOZ1 zOjZNu4K#&WGl?1wF`yw)2c3Q*iA~YEa7;F3@y*hf%ZmIP$o;nD{PbCB^Q3iG0$?O< z*{Ur-WSQ}p+1Uj;L+Z`o&r28*s*!mrvcDI4ZG@$)cN8 zm2rmg2e!gHD#5sP9L@%f_r(VzMxCsD4KsYJav>UM@TOU#`b)%#U5k4q>Q18bwy$L|#-ver3 zJrergZNhT=l~v&Sk3kmLzr5}G@&kaCSaQII60BwHDbXKpvIKNRwIl|53>uWTbxPaE zkOk7eUW@_J>NI^#NgsAg7;gipEqf>3qUTAmBUW1o`jy`P;qcX8_|8oGo|lv)blU}$ zqwobZdYfvf-Uld5f-Sr#QFr$Vwncc|M7;}$)*=wL7(0Y+A$G!Uglg7dHsgHXM_#>} zZ|A%^9y-b)M<9dM@fZMb&QmSW3Ly3Qe$6=IQAhQf0qtkwUZhrYLO8qt5J5F|5;PV; z)uuUf7ylPDFIYVTiZ)PYee*M8@bq|DwbXwK+W-k%XOc_!?u`f|38zl?S=e2mGjz}v zSG|MMRx+BgO!7_aV89fCWc3sxzr~zYG@OGzn=H=PZXWM5^JZXiLoqmJ8sqgZ5F_8; zYt+7Bp8~#(Ptd+02Ruhd0T!H$#m-WmM7&|=(%k{0O2DB5ewJsM|rJ{rh`bTtkGzr3)T)aiZW*4Fe$e3`s>fIxw zA2A0Z6PGdXV&SjYcHknwt|Y*l%_7*;Laq1sGf@4|8oc^>%clLEAWS^)f{@EzgkMG= z<#SxVW?XBclhA66jW7)KO;vNQl>5ljkme0MEg3L5)Xrx9QsT!J0|W6QIyeg<=a_x;rmwSeQvD zd|8<0Rwd@MUUQtnAp19h(>Wlm?ZYh3qe!UsUnHQBCNSb`wifp}Up-q|JG2<6|KV5% zFUH^&bj9_=x83V;Sgb0?C1YtMv;}S{qs_9nOC)5U{>zm`rulbkuLHfY}q@9zY)#8EhvwE?YgO@4I|kW_FR|9>*$FX&a# z3L2xMUgpv_RZZ}>;JwEdYwQS8d$m}wEZ{E0T*-hEk(!~4?@MsS;-CApK^E1tTK#It zLu!kG{3ZYly)_Xnu7He5oS92YUP2Kq-wfR>0cjFhi)TkbR47x$-D*|6YvX)IOf~%< z^q7>qfD<}f>v@tacLZqJn=zm7hqpuft*GXWb4C&Dq>e+Dprqd9p8yMj&^c?Yg>LS9 z(^S2v@&)G}eJB(NdN0!=OYi^E?eZCt(rnUJf+Y}eMEVli-Ev^)yDkUYSY#G|pi#Wh zUURijU|Dy5{#nl_Lg6@h%E4!vEp`$V&qpg+9#-G$lDd;e>JM!iR)iKjLFXQKFC=Co%zZsRz+A8&+l2n@@0%7I^iW#;=xIj zehD%}xemvJ2iZL;@&|>Od?W(}a=|en!2~S_-WFRdNDAw7n$N3hv#^aSYCi^os+Kc}8x`b@kNG6AfCROCF>PJqDIZ@wl!m;z^kqk032fNsH3=bsbQ zZUb@_AR`V|f}M$Dc@Ft~+qB-@#jeHBuR3vR2?Yp`4=<{YIv11U-Dm7d`mL{^&pIBG zZqUTag~F-qZQS$6eJ9?O@PXY4#+4Z81P{7`0RZ10kT@^!N4|srk?<|-dw5L%E?4CE{a;DoEk=m~gUTPqal?dAT89qZPzXrOJ> z*&y*?n*H@~&2uu)vrbzNBbc)|4b*XH^?B0rYHVFKCaF6wPfnZ`cs!2dE~RPMH3)Rg zYLuL(nKkLM%b?4GQ>bU!&H(#GxR8n88LB(iK2e)=1*TdnH{!JqW!}S6hofvZdkBKU zhtixuwG(60IBxbURi$8BgK7ccyS^T|$YZ4b{rX`Av~xP{ha4=phVfDk^90bDgDK(B z9|_Dfje>B3A%Td%e&vc5k6;Udf2$VG!kkoabng6KHGCTLOAnr5N1nz^(u0p;HRl|B zfjnPX&(6Pg>->kP@(_hJ^kxqE`P+tWB_--+WW*t3wQImd!L1AVG=sGqxvuZ^QQ@H3 zUS>_C3)9GDfPc%;#G8l(srNR{#!bSnZ{9jl5(5F3&&vARmjKBiQ!KWADQ35-y=29nJrI%;`T7BOwcxTN#P(%MoJ@J%1Hc}hdNRB1f{C1tBgG`pX z6+2nJQ{8^8T@@8`I;2AKi>EB<@!;>@^exdJuqeU;^>`KuDYvFB?~%pM|5o6)K)nRCl%g@* z3PCgdI8Ak#Im6=K1lP_f+xsHi+A*Eowy}~%XaL&Nyb_o$yQcZ1l>PwjSCxEr5?&0G z++=Z~h{Z)_OV%)|a|Knvghey|_^dNR7}-TWvD?oqbPN*Q!U2@}bruPd3y%R9h~V9cNHffA)rm)`-%$r8uCfY!&AiqgxNzdXnHW5OtEpfLv>+jZm}c>D zww8RJ6c>hV0>bM7TkyWjC2bRI;K9&W#~J7x3)pWZgFbV9b=U&wy%D<>lpG2Tl{>SS z^@y<3`JBZcr?5cYLunQTRXNp%HQcR)Qqq3_)HXv^w%-_W__aw9y9qRO?vgZmuAXz++hNx zPTI2A;caRR3X($y{0XRswP5k58w$pi<^+H4)=G*1z%3?_0U%@9d;ix^40hdf<^aw) zgEdJ88jbQ33rh;a)JxzKdJKf>j~I_+L|5rf<~Nt`U^4wBSUAvjFk<0Fcs3uhE0cKZ zJ=Dd7Om^D$LfhZK=K3dfzCn}3DYz6;)$1`ZnSBcT*73CW2etcS%4W!)tzHxha8iRE zx-@(hCbGV)O>mzAs%=gSU0gwl0cGgC0`)H*D5GhQM7)bR=zO*IE}45Px_S`x`hp)vj!)1 zR4e$aN)86w$BS0ISj{f*`x8OzkwwyiK^C@Mb$P_Db{~rD9b&t%?R!LgHt*Uw5OnBn zuDp;YHQzn>#yZz5NHU3ir*)`s1_uu}JMx z`pJP)ED{oPh|f3ag*2lZZq@a<2XZ%8-edQ<<14+8-$bvT4e8r(Zes}^c@!MCC$Y#5 ziDRin@OVd~dsmaOLhP2YF8Mcrdws28i$q=FlSA^K2hIXrz$X;S^!Fn7{j?JiL~8DO zGX21&0j=o$4vqPr$nFB^me<5=PK(iVC1nhed=n&`!HvnPRYsawZxP}~xEOM?VL^|2{E(7HKE4Bi zEoelyPp?$vjyRlAoDjSH(0n9qXZl?Th?A*3dKz?Wt@J+nbDP*))L$Ft+V;z>xw$W~ zzsC6~n||7R&;h+Z|7Tw<#L->9mr*d551VYOzcr{u&q3SL<9rUp+RejdkWKoX{LMdV zDMqx+fPxqsY?1V*sM2|2&2}fc$&bq~Bbh7GlTz)HSddHl-CN&;BjJw*FRy@tw+eiw zCq|O_N28;^AxELnBgrp9Qru-6qvDN(yyZMtkM8?p!G(OtN42rUGjb)GJo0zV7~qH3 zKt;Oqj3?PXlDzwN=;0#++Q)J1zg%o#%WSgAKdI|w+STcCsU%-pxcIcd^xc!)2+3&p z?a#i4g~|icw;staRal1fKIDEgQRLLfoI((!U>W|aIhL-j zZD@(qkJY+N{4zk!g*MygDaN3iF<`)(x#@hiTQzGs(=yfL=GiU*c4n0 zFmdz^s}rZ;v0q-i3^)Ulu(I;TE5}B!*!4_>$8CJ*2huZjH}WZqq^mv`K{Zxi&EnF% z@$6V`O%wmDgD(+}B-Nw^fSd>Mu`;~AC#+;{fcC$v6@YXAI90ikVj}#BS0AkmIu?u` zdvTF?q^<@S)zPdaVRiM71< zK>xuwE?lF;>Ad^8{({!EU=-m*HQB2&oPE0e5Cv?=b+VNip$U`+vLV=%Na`ST{WOnn z^kFsQm@D@(NC&LmrmgLwz35tfOT~O<$MSrjt{Z9|)NJ#tl#mNX>KW^X6|`XO-R1Lk zE!amlu6reoZOq$#5N$Eg_=QrZI!l_r>#8+T%!xLoSQY?z?hM$YcvI~FvmE#ixEm`a zgq`?B-76&O$Lnj?LyNC73sleax5jHP4d%nk5@#WA!Ihm#+`z31gDCz~OmeoGzoHki z>czev$2u+}(CYMOWYC2heU0(bM-f%Rz8r^_MbwQi+zk~d*}km^Dgu;kNcGKxt${{G zu3EF5$)6=x8tL1vsg6RGbAS->-MQ;PsTWxZ7LCtOw+OF0 zjC#}gZn^_t|Jl^C>tsjVzx08F`nR19GVufOF1b$f?MCcUqpO$<3owAy3Z`zRDui4M^~Ed_c7ib#f6LGxMuDL{IPUlTG}DD<^b?Oklk?8l_*r;_1J6E9t859 zX#!{xGKUz7mNQ&TV~`#PZ5URZ&~?4_aB^*Hz@(a^m#{dwsJZU3*MKIm;vD`S?ur@F!zgA;^GV`&>|UJesH$ z?4oD-*O52gWr3Y~(z(&*t>bd#!D4xBsFt>I--jf7f09MwEF}U~3m>?F_K!J>V-&0F zR~%S<%z7NaT1{B&n_qE&?kY^s6Gf@+o&7SKzQdo*Ed=0Lw+c6;c0t@TDMsUfAt@wy zoW}$SLv(kK9~M8O`^sr#mF_YU=W#3$^uH~7V7;yWNz|j8PBqDYXcN4w+N#VM7voZT`ekE)M4|5#AL5||Coe@*ND4|EExek^DO6LsiM zT}xVY@61V-&}HE=Fj5D7vA)Ams5~vn-YwfEw9Jy^?k;_4`8t$-^w^m;;PHa$**5Ge z4m%azI+{Dsbw~T>BZN`2`duPp#oX*yve~Re_@MT6AR^2K zTOvP~#YI;Dy-4P_3)wZYW}(2Fmu94xQ|=eGLI#@oyVR@CtDe~HftPsfMHdycTF8%9 zzM;HeyQEM6&Q;Oen6dr>=Hf!9Z2C#S$5y3Kfa_jo4Z4es+*qGAGlt_9fL@FVX9~bS z+X6Rmy{?>j=fg_bUC=#z@L`E8HOt(SL32ohx>EHR=zHL)Z%@NQRjE8dFeJXax{?T4 zx-!?5%oCGVteF`t0l=(J@||!7pJ=i4;4TlcqutgsUxr=+0RK787t{+HCYu`vdm|~}P zYcEewe@C`7m_qR>z9_IV9tOAjgP&aKUE&!Zfp|R@EWGSmTue3KTCVR%=D{oI zcwh!>!H)*fVsxs0#Ka})>MrsB+V@*~G{j_h*zG|?Ws8Qe;pmucCULg_mAt%+~?c3?t%@4psZk!PT zcwupY_IQw>SM&pLL{>aSp+aDB@X%F^D)pMVET>{IBe5XE2zbjJ0%35 z5VdGEvmTraKcqMBgQUAfLChxZRlk)&QA15GG{XTDzQm`2{$CvKIjR6yy+UwAv+Mnz z>J{UupkiVT%`iS005FqNPaXywmZs{qEH3mvJ5r#~VL>uu&s0C9L#HP{tjAD6I}tf} zP~BD4JV;eDtC+$51o*QJ$;)6X;~wUf0v7?&#EhVO{9^GAiwJ@&#Mq^FsA*HBC2&26 zJ2en%ToMaLnLMe_F^h>bLnJhM68+`{Sw<=AH&UomV^x#DR5``I&N11izHN7BUX`M9KBgzR}ThZLT4|;9`Q=TSvo!j=OL{T$ zDeDsRo=xolR0c2}5aO-^@x$hAY+r>_&tyXK=Q)_&2>n}+cjfmR-nKtnQ`tnW0~e1S zfgBxaxk$PZ)oLX#!co&@&LMk1UCi?ZhK+NXOY`1*;CUBFYhacFfYWExIKYbFn3tUr zBr6`uSPAhxbY-RT4rI+mf$a$8>zmLM%Dtq=Y(q|>=!bisezpRd$8nIML{?ObY7N!v z$e~s<`Gc%@s{Ho+Kfsa<*#fJ&Bl-2N_}AAh)n@^9sy;D24=w_*-CYLC!+Y16fUY>e z)mkd?F!@SIE+T+1NwWAjEdet%_%C9BNBRX};E6Yp?!1RqttDa?GyWW8M>op;t`U?8 z8&1(BqqKA2!O zeEEm;z4MGes5K^`(7qhlTI@BO9s_4>g6g$C{!`}k2PFqRp;7Wh39Sbu7j5^U4V zq45h@zj33-h_fvNtvGVC7uFj7I@*7q@*(w}B@XyBA>M@b?7HPyZKO&f8T|Cn2Z+&@ zR)Pgrcg!E=MrAsU`v6!TD2&AA_+(y_p+fBYuASsjCfAne3F8L+aK&%o)r0(m^bbmFY2l0aOAVQCOEf#N38Y$pFGXMczFGJfh}; zfAhg!i1=>2_ZA>F+00^G`I4LiUZKwIOW*+j5q`+$SbiMr_h4n#AyM+DZ(u(k@$AYJ zN;bZwB#J$dZGhj{lScs=PIOCneQ^ea2YD^d`YFXKzS!;HbfF8!;^U{JLDe$h6kq_` zV}@p3!2hbST&QfrCvj)V5rU+sBU9eH!jjfTVrB+Bk;yta7CQRDv6KMb~UAX0J5sN-$B#u;yk72t$lwMK)>9!W(I|F4Ql2ph4_nGZ8@`fVmKTJYsi5cYi)U1p-P>=itJWNq{4Q}%&r8WW?`-PMk;}$ zM2rMYvpaNlawCvuVcdEIts;4{qZnQ?J<=`nI&8f>@8KO-D-K?(w?dQo!x|bY_+Ic8TiP+8=I{D z^7TE?9iio-&<>MCUEKR+()Go^Oc%>)$i?$9ldeenb9B!o{wnBP<`?O~ji3QObqNT} z6?@g%QBc$Z=zgjY|C;o5GOx#En}0&~-<(gIeDDYoSX_3U7QCs~!&Y}KIRZ5t+pY=; ztl4})mHL=$yuQP@oBcxgGOx`H7+-qHZ?AdG?6qcu162`c(k+)BdJAXH(3$>q)DsRk z4eu*QZ_ES;9gGzdKzJ?$^`ATAnz9vcF`1y0exRK2{g@8E2ECE_(A7-3#6OTUT2q91E z6>qNH7dd%s36y3#-fz^1*3Nv3OF6cxPB7hl`ID06<$vAsY`pwXw{f0rZF?=e$rWA zUDVf1V6pYvi?J7>PXT@quT8N8b`0!W=p)%^D`1j&r<&$Lii9@bqxiTX?=R19d`4aa zU}fJUuj81s8E8K@r`#xcpTzmsMQl@aX^H1C7u0ivZFX6>NyuJ|9w^yfx8@#sukuSN z|IDX%;44HeBW#0rskiq{5l#Txkt=X2-bX8SeDj+vP5{A8oWPx` znxmSw{X=;Gf|EFIT)WQ(fH~o?sTu(RFpRgNfQ+&eAcl2VU(?CS;gw*>7z}QxC$9cN zgWQ>(ziiBvc=L$P!-zw}%(ap<6U8X7sU?9bmgy%mXZdO$kmM`6`i&JjNh=HYfKy(; zX|`}y`dw_rE*Ml{)v!|-R#c5W4n=*i?=Et{U!-W%MR`L66D$B|xcS%;l|yz+BN{WN zJdnaZ4Td5on=bLO(hovAeEv%y0>q&gxi>Q_B@29;E>O@2H+=L$kkUr z2OFb1jtl#CU@T-4^Ub`-sU0?z=YsEt!{}=(X%IIUxdDm}y+YNY$I#9m8fAmp`diN& zTyP(L?TjdMA^Xp&jxGzRh(I*Ks+u7};ILKC6c#!}#3>BKyFK{0XFA*e<@`qMDF0Mht#H-B&y11m%Ek424Z*X+wasN*N+d0NHfb zBL&K){{~778K)?IorhsdEQ8il2)R(>C z{R>S@I_w~kD{oSDE5Xt2CI5=VkuQS>OGe_T5rAG?E8Yv=T>BchMWX$a2$QvVKb_*n z-1y7#T+TU_1=y9ze6nxl1oUt`m|;8aWDtveP0ZLwb_3#2k}K0zs{fB**((Sb2om z##6hG>p(jz7Xof1HF&*b{UO*GI8}& zug0F$^-lL^2-jw{S$9qMt9iZ#ExLgK;C-`aj!r5A!LCujkSmzcm`?&p5VUJR_wA_ zJ6VjOVzl*&>iwg-x&WCJOR>2K_{*r>(wYt@x-rD zhJya$eQwp9BcKlF-u+dz^0404h!{)3CoF zUS*R(Z==0M{m$w3dG)#;Ep|}43HBLQ0Lh75Mp^U`U`*X>WJ4Wx0}O(_QxrL@-3aj^ z`F-x(P9V;c_7ErjM(>qSz-YPu!;7^V3Z4Lx@^MMwttyQ97Pgk}uY6H_{QuGP?eS2p z-~UlkNkUR7<5Dg;a!Tb?%;-v2MN-I|u8N$gBxKA}C*_vtBB#XYbWy|{l@QG?4LVWN zsTk=pj1Xds!QA%j{ad@w_xD#`$jt2LdDeQb_j<4QQ~fj-<_~+BrP>ptWu+kL9+awm zJiktTTLxYxocaIcNXY$1SZAtifdyj06CtonWhPAI0^~jm1=7=0Wh4xh@rf^zucmFU z5vj-^V&Sj=tu(cD+XS(GGHf;@abl8Kr|NRGV%HHGH5r+nLF|KtCLO3(BleW2Q&!}qKqc)sCd0T(7`u8(7xW81R-S?HAcNp5(>3iU_G~(5pOuS1pW+O zP%frE9mtW8LBkd$Hm^TB1Hhu3w4kt@TQYNE@VYjr0HrJWzd(7W5NLk^<_q(|k6NXp zC~c2d25$m%2aTxGi?$kPuC6*fjQz=8^p6G6`+2xaz|;HV?}0B){aG2TN#9>64AwE4 z+(@)`#N12CTs_F`Ejv7n67Z^%94+{N2)IU{*LAcT34~T(e}EdCPpQF$LC>9lkIKG)`r;VLw*v6WC=%2&R1_y@o zcd;Q@GfpXwTfOGa_^|N|oGK@Vp&wNd+`FLsk2poqJc#WvDD7)C>t?S$eL4B8g*7yT z-<9pMgBhfH)Nz}~`b#f1!jtC```u$2DSW9HYH`JREoWY zuNDEnw8^szt9ACm-C-Eqn-p0^M63*gnkeEHpd%wvLWy%tB#}B1oMx+t-7kjGpfGyt zoOV(4*4tm15t|vHp)@-n_j-QTO!9_Os5=3D+k$VF2lRTIL*cK+vmTf40)6<8Xk&(H z`N?XRh~qD2yac?}E!qihgqN(uGL(j3-hk%4Q{+Gg55F(F^!P~|`(^&vAz2oDMa}F( z5Iy)zzKhv&5S>2vamKs^_Igh-eJ7+X=tQtT9$q4=JQ?7BMjdsg9K2O!$)I5bnmZ34SB2WPQ5p%2D+!N#sF3f0C?&ucPfIug|3&|dr~E`R3^!_1i>_Hy};imjg)HHf0x^@Cc7fXx}UH;qxH%G?rR;dni0@z~$vPbOl+zBI}-m30H@7pD%GNST+9T6t847N9nWT zPRw~lAhfr)*+CU-y_-8CT?_UoXa;k z6#MVhwtfCD0w|%pbPmV*@bpG5rT<<4T`i!bIFe5gedRimWx8qt)TO+M--j6+*rA?0 z(pXY?@(bvPBqGQFB$muHe=A}-x)?Gu5NA>c?fZMCh)FkXbB)(Tg4$*-zm%BvHD zYEo~4xOyDfv4PmH;^lGJ#<;obaC!8el+PqS z4iB)_gxz72Q*e=$U+_BoX)8AAqsUc_>5_&o`4{fdewJcgIu#sz(-S$+{p&HYDK`1# zaJx}8>kK;<5*^{qUY1d>;3i2YeusZxj-l9Ei)#h}9NzL{H}ID>||f!d198 zOj0uwhqQ}h^3t(K{%IC4HOfjLqVq;SB1&cM15F&zj|JV051Q6iwqKq23+4>PiUKD6 z(y`JX!8Y1U4bSW1X$xw=C1pIJpW!&qies*%t+)fiJdaj1=Bi|@MDZs%e=kabNnZoP zK0|wJ?l7^hoio4y>Kl3xMoG)YsSf20V}YF6#c3?C#8A(g&9R&;cj{wWuuK$VUuKPg zw#sBsHwBVSV8m4qavx_O_Oioz-HOTB0$AFo0?1ODI$KGI6NyiM#j_Dff6nIuTkEzF z`@38p9E6Y-O1eqjy_eD!G==|21R)8R6aPOZn@$+Cwhon8`2 zE_D@~|$MsTaI)zA-|#t=(igYE{Eb4LOo65aR82Zpbyuz&nHwdaGlAXzLne@G0 zd^4G;`wd6u%Ij9}7XWV&2Wv^D&*7N8ZSm@h<9g#2INTDW9P7*G8qldJb!skJn@TzX?N=sL)F=2R>aIDAX!v^3zbDCEz zZej5IhPs*Gm7Sst$9{Vv2LzZ`Z4^?e4jBX-1Mx}88Ng0&xX_8E0sbT7UQX#UA-4>m zlN*jKmO;(t1YBt95k^F+W9CT0iP(s&_9sQ4S)ngyh_Qg|xW)N(=*sgDDjao<) z0$~w!J}d^`6EFpzBy41I3Q5k9nCoU`5CKWdsc&UVN65L9;F;U4REA6VmTk@i(_Z@q z0T&^*;u|z?Y||{JYEHFgmIUbLcGKy+#o97lF1(9UE;*om?k!5&mxZSulldyA_Wx=z zXvJ_C;P^MWeY6O@jCmx>&nN?Oi251h|7J|g-X=2DpK9Z*xwAkdBc#Am985PhJm)_a zVs?CIXx$>T5;yr>|BO#hT)Wg7+FV^?DTVtvw6(N;l9>4~t&>c_NdqOecaSMc+_W;p z@EcC%f5)K3KH_7_Fl-*BJ->Hu^WGC_o=?PY7oJz{&+Fh_PQN1qzcTQN5)B;y_U+MN z<3eMcdFk*nP(S>B=|kHc#|)TjI9O1ehggJ7D(O{L#IR+P%g9eb9{^{Z_4?mYq;~ za5Q})#u|DF{Nz!;QrQ$>zLE! zZab$S(DkwGKrvPudX3+e{7DyzLwfuhN^w;-nZW?2eCl{w7HYc&wD>O1e3$m_JADEd z-FK?zc2`pu?$lK+Xg#`)n_9DTI`sZstogGJwA*jwuCM7!sB#5?$37}(Y?1`%4XG<_ z+k#fB1AOsHpjOK4eL34fRSx<;6&`wr9kQOP&nWt2(#sC{i6d^FUnhPWbd0=khpNk> zM}w*(m@fS}fC6QG^iOgh22gCj$|Y!+-3Y2o@6G20ub+r&?f@B@6+6 z3KEJZl@7a%kJMQ~LTrzI1QCj{1}}h~1mB1{`>OX1bFU1v+dm@`HmKcKetu}p(>bb!d6lJB=|b*m_%krJaxK>gQL&va zv<78_54Xz%=6)WM>=ZFbSK>pg`gdNY@6ejt;mYKH81paDU8X7)z&pB5hlQR5#v5tk z^+3k|JR{4jSQCKL?-01@Q;b;>7qn_j-fX_v%f9+T!PB4Af=1l~wiSeEGVJ&lim{SU zK<}fc7htGw(G)%mu^4;{2P7uzq`WO)^CiO^u-6^--q^Mnf>~>j-)qorf0`Sd83=Ax zC&9xC%$z0<%@190tbbD*{o26e;*Qw&=5KgtkylJxO#Fj$)rX*runZQT+&69(FyTG9N@$e7VGrhfX;j*O2w zeoI%koOEeQGf=W!XlCxr_i^uoTQOMimj=E&sYC zV3rhJ-8{SYKC_&+PJ_n z?CX^Oyl@z?dw;Tt;Y}r?ZIM4X~rs z()}noQofbym<_BATqvXjGj~kH6RxixnREa3)Z$p3r|}0}u4O~6#?HdLS1)7XkBi%0 z4?{ja&~dY(7>*GyT?v!E`%``jm(GDNn6-AtWdcBnij`}~89Nwoq0{~~C=)=O9BmEF zyG`WvaVN76ufn**>7$Zx%1 zueM9`f0xgFDbgQOiFN>kR5te_y*HV8dPuZ%zI9$1HqQ@BbJIq;_N~7nP8ccF1Dy;n zjL326*QGi*s>;=$YoLNgI^cD(jaaCiH>J!FK@mph1W~yu!k7$CGA~vgeF@!bqA;Rv z4z%(k*w%YWIw78&8vtn(C1%XBjfdLYmwa0l^f?zmL0n$?qJ1kZuticmmi7{8tqq5n z&c=kgL1|Mj^&w`aFA9Y{^QhnQvMlWmqh(B@xe0QOc{F|!7@X>)qxq>TTevK`uH~Mo ziN}cIigA{E)+H_^!um&ZNAsH3bu%3L7gNR_WN~dvYCs`AT+6Q zqo`&dQXZTh?@RR^bYMcLNZY7ZcpfqO6F5y8SxI4KePe7XV6DWIxZl2g(aDM5h$SY+ z?S+Dsab3CSS>#K?)$yNxPRN9MDF zC_BZf|3==s;iP*Ln;Gtgp`pFcb1IXBm%xRXd>r` z{}VEf^82LEfxNO_KnHl>UHd*iWoF!rNk*om^#D*Nnq<-;=K9(rF?0ZJ>5D(MO_DJ5EF&Jg zcr8Fv-CI^A_9m0=F^`fbc_oo1F%1>7MkbT~0|!iJS=tg7t(DK69-EL6XaH!zqomej zV7p%=5FgH5#uUXK*n#eJ&4r0UDaP^jB+XPj?vXaS48CEPsd(%mdrHS`lh+>g$KZO&vQtfr?$3cDCTA7|7R*lD4@eKQ<~R@7Ob|v7B0(kaN%$aS$N zXQwBV(?q>h3mbyzh1;cwhk+=54f3|!A(y1fw9c}>*?)l0L2l%nZGKujCgg~Xax7}Q z?VPLfd}*&g)LnTACaH=T!i>dnwex;T{hb7TFy5k!HU?MBku7qs!K1a7RInbZq*Op+ zQyF$f89xPUf^v9~Ksf1uwtnKjsneHoMDst*Zk;lLG?YxDG-BHH$3_a%=!Ni>mw}Z^ z#v7xC@-3e?W(bYGqxWQ9`3gAB;#IhA>+T7p^^sVrvh0qG1onvwGXuS%SD7_j)lF}) z{23Qy?=PZL%jrLjO!zRWbpZaW!WarJBB(d<+;AukEFA#QSyp_#-?-IoRPcf@(CtP! z&qZ6vmRKo_7Bq2>%>1dDSyS@`0dAx!$VuObwuEv&idTJss1L_51J%0^`0kd?NGjp; zS@d=tFo52T-lVzonCMtZLRo(&m4PlAO>Ca-n!KkZ;4q&RM1f{1TeXKav z0N%dwop_adk3oLGt5u5p{w4dzcHU1a0Mz|qmFhE zx;JscNX_nnCw6q}yrT4mnCUUS%yVuUo+lY;4g6wAU1ZEK0~|~>5o7lNGg)=xPkxOwjRIF~D79Rg$`0~>hggN{(lIe* zODq}{i))V`5vRagms(N6gR+AQ{B_WC)r0lxdf14 zSLNc;oiD3|A|bNO)sHR*zt_`<bj7|W={;Sm|3O>)do;GL98an=KxlT= zIh{IIA~8~MOsh>U=PnN!{Y|a$`;SMR5Y8I5M@FwySfe!ocgJE(VItOrpBjL(qZ@c* z9c&Ak`Bo%mf_~y9;4lftK$QYCruNRC2pR-I5G;cc>5T&)%fXYCQJy~-6>3fB5kzt3 zG(IRB$_BKV%Gb||rtpyo+5+EuFOZH3v3%$A@MveuOWwExZP`nT|D;#vKgksveqK3p zn|FPQ-e93_pf+a*#Y_AA{Jgy6%dF1c&FJ_^@fNeDy4&p6m(kMS9!?)TdvY7G|J8O@ zX9uOmniwM5dq>yeU;gZY2C(#nc;_3se_j$K<84ryI$!2L6uhQp&wRumsq*SNOrX*W zV5Ant1K7WeLF0#9#>*mQSxem_r+<45;cDN!MUnm>@L;Zi(Tp6%Uyf0~@7Jfudu3Sw zg2k9+Ookd`DH6A3dFjYpx&8(^c!#|7(6l62R(#{;4I@J1GO8^G zz;ONk5NhJzg3>~0X&af-!yDX%yVt5O`~9%8O%3Lzl;_%{Z(N!coon> zpII~pYyfT)K#2p+u|kt|5#$n`jUx4K>pD_u)tik?KA#k0`$80zsm2H+kATu`c3q!{I7CTcsb^581?Mq-4Q!W)YdF$di^^- z+6hK27SgYM^!lIul&hCD6Q&i?btr=r(!2d9Gy~QcrvX?Y#B12jz)sFs%jop6LdQ1! zY7MaI)ALXGrx>a%p#gL>5~%UaRx{pme9o*;!W@`DGsLqZ+FE(Kyyn&TmsZ|b6y+aA zMs|YF=2QxqqJCq_3-}CK0{Tabm&DH~RSV(1y~e`>@)y^WZJIHnzn{M4^CfFwDeCL~ zKgHf9J9F5TsSA_$r9MkXV#b2T_%XQS#oZ|nT?w3iI{8rW)ZuRyB4CYX9-dx9E}<+7 zK(a#!sX+y`D-pYFpnVA_VM@BrIoe%@Y5I)b`|!zMmbuJGhZY${&r-#wzG1P_$Njn16}8YEd2(83-$l* zWjG-KS;v`dmBG(i@WY^NmLv!qhxktYnha1swv!%57^x7F#r7O}MtvgKXpS4Kfdh#s z-#*eo!swDB;bew~->;5&&^?_^?jX&tj?_S4G;HDZf*q7nZUk<_kkHZ@q=Wh)g_M0@ zBLHRno)k)m3BW7S5n-b)q8?TN(0xk~Vb@Qi%BWtEn0i!bGK`efh??v7g%eG zO*+uqZh}qimIwawWiirwq%8AhHv5|X&!Z*#l=)fe8y^?w4HoGX;g7ab;o8rJV9nv5 zm6SQ>-Da(KmVG*NXK@@x-g6mgE^7S6cR@Q?s3L(CZ+HLFYS|exQZ9!L7fDkInsM{&v`c_`xS8P}$H%&6sJpJrqN;t=^tf;Lk*s8V z&1EL^tZ!fD+-DKYH6w+#_?r#dUp2MTHQHs{DS;u641iueP{z`ms^mQ$iIRvI*fYo+(ZRxNpF1pSN#He(^=Xn1PRqsYy*nzbKavq$DOG zU8Oap5BM;+ccAQ4!1cBG`)5X{X~pY`T*}=2eiBRX)JN+d78LA{2W4tU*GFgy6~#A| z)I}zcW2rd=jWQSp5X_e|HML#FVh{?5h18&a>JZZ#M?EJ)$khU#&L4BMS(72P)`g34 zUrF>Rm%<6!_w|CO?$tr+r`Ly~p%nqQz66Zo-5Pj$O$k_i;OSZA(`Vsev`q|B6OD1R zx}h;wCgs_4kSBwF;?lr^x|vL{9Awmtoy%qEFmyvovXo_~XnK@8Li9;+hKlj;K^))u zO2Jcou&zyGJz`@)pS!?olT?7%?veVo48cV(o?mrWshWlrR}{t!=tTw9lOXqH|9E&DY*%bLaW^a7ZYxO@B?o#N%w~&8acpx5h{yD;f9)giL83aK8 zd#^D1jOf_Yr*o&14x8qXm`i^mbytZ>G^ic@pO~^_Mc&Y(Sjf!UoiXw@8-Rp`C`R4jpHNg6d4sYR_JAp#5abDetyV?q zVM;x^>k(sNFa(_p^tRPs3SjWvCIhp8SR=FQ=i{Imq9<6 zS@C=C|B0=_0Uim{zlmqOVIGC`Ju znRWzp0G~3zd-Z{LpXk}330K$h>K~CiIHT2B`djB{Z9zP48`H}LF~IBZnB^!<$|FwG z2{8YE53Fy+>d)F$gy(nQm6}f6D35@}gs-0Xe+FrXfp{^@Qye31`@ee>rB9Vt>WZD8 z`4kdb4oGNIrW6J4D;AxY{w?xUGxnCqA2xvt9wOLxW!PoqR4|dOe@Q+DWZOTRGd`m> zv1ma+#Fx>r0iH|(tP7z3Ax*yJV=mL!s9xZuFUiWyME|SHn6|YDhn~FRrtCe0tI6${ z{^@{VW=CCOQQ~t3Ska{!1sOz+l5V3!s2`;o^nIzp_ww_%kb$uF!oGiZ@0jZP@RuD|8jhQMY7^{I zx;0qrKWpgf`eN+N{rg+s3s+Ya&+<#blWRjimP8f%F$=C~qA<5NCN7CRs$Uw?`vk{N zVzrH(bt4BQi^xeA234xZ2Bo~F#zEqjgsvSNM-!yi|tOy zLi0R~36r~DnbkzBgKWWFK4~ED`nANil@(d4iYjlGU5Ife$4UA&e?{k~ESo`C23U|c z-wDEro3B&Ga^410-f(47OmSfmmmFt=34hbonjh;y4D**eJ# zaz+~3pMafGISWg^5#vj{gr8cU&@YGMmD?G0HgpH6koG&GPjdghM!;D25%ZIyu^ji9 z%_p!B_3dWSK-Y5lK?3@56&GS&gXi#yfNZ8XDPA94D16NY@dA5xh#YxUO-qp<8Dx(< zZB8G^szfc??!<-gq`f4W@TAGYX6b;aGLR5c`$e4WwnF1T?rtMbqKk!{M*eBFwkT;4 zeN;}Ls(x?7s|9V`_5wL}=n(8s?)2%jYvd_y1m{;_4Zcjr{VrderP{X5>hS`6NAXg| zt6L2Z7APO?j3Ta>8N)8uEWcW}uSS66H-^{_*;b2<3EzNT?!|?&7Jjnep#vRfl^XBw zbBb>4+H)1J_@&Ctk=HG>gnua}r!bA@zP`R%bMMlxj7@*5rniXfn~adzx&z<0n9Mu%*q0a} z4!bHp1v`^>s9?5Vuq^NNW#m*6(aM#CY3iG(Z!U)8CQXFZ#{ZHgsg8_QPEY<%DBdZs zOkmVE*0KUh;#-BsOI4*7vY8GH6m6etEe#oCtT@%-)tDPEbW2-@O-|1{MFd!#U{HBI0<1&(+X>yYxRu zq#Hgm{Mw~sMcRP&OtF_Ha!rE4dOEh((q4?MEW*8>4QtDerkP)1GdOf4Io%_7y3V!q zImf}cGsuNXy;k!Wa!yx(Qrlu+Tr6|3BC0P;^DiXpTh*HN9Wz`SINYnWw(2!nzFQ`? zWUy||Jh)b}O`N|{BMz!k-b}1PFav2Kx?k8RHIiI?`)2~zh?o*I5#1=P zfiCDC2nZ-O*}S4hnc%ftWinu12^*QbU}vd9D}RVzUb&)3A?FHKq9Se7 zZbQhk8*A&o@PbGF9vtzmYT})WvD?~fPli<7?-;x@PNcL;5gu*qijIxEh5wSm^3oKq zAwzQBVP9HX7_S!bvpT!}8Yit&WBX_47j)3Zh_ov!YK{IQe9hY4`;OFYrN@6uUmvV* zc`UGcq-$_VsyQmJQu6eTmS!o@yH>Z8`nS7Qs@MY-&riRT-(W8p$bR8nf0?CNcJlWcS6r3Cnl|sPJ1P?3h51l zwy>o$MA;#!36nuAtc~?v(M~oxK+&%A; z^A9rNj&r`Pj_`EPD!<}#AI7HYgNq0YW0&YsnRxplKc!Rfuy&)$?x3U;-&3@)@J4Q5_9C zWixup9Lvvd{yNZA5r~KEPFy7^<;0l^;k67R*$kyYFrX3j$ABLvy{kIK=`q&FbUVZh z6CaG6*w7Oo3DctAZ^h4NNOwi*1#7;Bwy(A*-YoooO664WWXlU zD>Y{pY@Asu-7TIhc`e;jb3PH~{{w;;b+;k*)`4aJ6X(Htk4N}k$)`%YitCr^fwi?g zCQ4w4eax0QSC``N9XM_Qz2tja?L&(iZW@8j>eUYuisjFLW{ooo`Fm_|#&)oRjRImSUM4lw49LmgUZFI5Oi*}FOv)y&SY zVeCpwMPZS!SMUhU4UW*($KJ&6Kq^6_W$O+Yc3|`2!!r!w!}o^C$^DYyxAOuS3%+(l zSBv`qZJl2Tm?}pQ=@_DVx{&Wte1+t{#Ph_`F;}jm=u_g=TH2d{^iyI(%dLnsS4-EH zp!_zPehqQSo#`=WWE+LBt|?>g_LI9f?zST{alPWjDAz2`)`X|x+J<}&8%7~NRs%AQ z;5@Y&ISO$d^RAi}xLn0d5xm#bKfBM#EMCmvt!nWS^K>;qS9&M!bNZul*y%L+n z(TL!?9NNToMQ$^V!bq_Hbnm|5ZYGTc^s|_5fmqs;5bs?zp+M?Wt>mn#I!Wz7+)Wt- zFUVd|)!5iV-fQj}D642uBD;}&@OH`TG0PsM4f1VgsCBdu8a87F;ubV^tGrFVUOALwMOsurk)~?22z)-fQxh+=`FJ zIRkl*$gM9egXT{qj%;p0bH7~;**1!5yaw0D3u=GCPN&^c39N z9p)e4p+!)?Js~;Tb6DjNJ9k}@qPzz$`pX;8tLN|~I?o{yJt%x5PI&-}OCFW9JBGwY z?InKY)!^*O_;bNsk{nL48%TV1dYdT=oD}f3%PQxJxldYY`W>n-j*Fd5c*DImbQl#Q z?`Aw)wb}(&6|0G&6}5lw{>=pORB_4Xp7jpcQ0!_3-ch`mVMiSYt-xvLur|2nvbXlT z%Dh>uPE;)%B5$^)+u@4FUF`j*Nptt_6D8|Ukw!RjYAMy1m&a}1}7<)EDZnl}Mdv>}^NkNS8UEo@Uck*{TDdjsOv@FNtF|c=8tE--& zMm0pM)tjF%w&Cj!QL!!pFEjhJ4C(}ySJljduKKt9zMA6+*sI1KxO)~}%T_kSL90EJ zva{xRB6U5FYme6y@papFT#XqE_J~1U`^H*%slx2EEu!EFoZ!An4 z#NDqdr%3`CyUfg=LzIv!wn{oStF>Ee4(<+p#_S7gk2?WRhny%Wg`wtL+vApa8Z4!7 zqbW}%w56YwWHJ*7G}isV;xu7LtME?j%N)QVe@i$6S5 z8KZHy*+AZE0Zk8?;f;d3(miJBr?9bLS@o8DkUKZ`EHb7s}9t zyN_Kyr|qS0ou!XX7Z#<5Le0~yFf|iWNJFJ@mn{~}Hj2A>&a3f137RE$`hM*L!{s!l zV|kgMzSSFTn@Z)99&qH`;1Ex{moYf^YXU>qDCyuj(P1N!{I%}1K<{?*uhOc~P=^f* zKT)f-?80ET!W`<26tvTsOcbmSE+QGmmi<^;^qT2!Hx!VeyP40pdW~A!225B31yQ(` zZag=gN}B(&=f9Z3KP>d4_2zTqDJ zpbjD%6v}58wJ!4CD(E+!kOAjMi&Xi+?GNWO#LMwzbT~x3hP6A$dosON>7V+ywKsf^ z`p-KF2<$xS7$dn_ymp>u@9hs24=f>q?G#&w^smU=H(*{7$ocrt35+QN$pw;{%^)6j z>e#Sl$9Qs8fCV=NQa851mw+7nf$tko&ou9*o#)wy^cQH>-*&g1n>Ce;`->r+vnHNa zba_ee$Fb;2;V}39saIEl@W9ey76ZO%3f*^Lr9J+BXH@*QEJ-X+s+8&V2aGESk=+W8^ znAL1M%Mdk60!)HjA^HVfjj?=mveQc$J++$oJxp5}Mjhl|ed$sfs-7!4jZG_%a;saI zsmfJ%zjCYb?Lmif0O|K`W?zNV{KcC*il2Z&A_8SB3)`oRuTA`mxjYs%Z$7j~`7k(w zz1ZXvgNhd$09XW9D-t&f7N1730YO+cRn%o0GmW2Q^kA9IiwAg+-^GE4@+mNLR@t-J zgN71S!!9L#txPD}LO)U1snS~&ZY)l2DSHgN^^HJuhH!1ui24O?$4a%~Mv|p(vftyM z{SNWQiPU|oWkKbE8pZjBbY}++YQWM>Y&8ZSMtJCSFYaF~OZ=UK{#53jz>K=GUigjh zJ}7TKXXqKd(qwIG;iHxysEtjlwmV;keC^u9z%)G6_fL(~c{D+;gtGtDX+yg5L z#MJG)`nSr@cE|N`In>X6)LEY;F!v1bRua)hvdrKJvNB6K_idvopZsEf93_M!mBJ67 zQT&*0nKVSsm_m-LRjeP#QxiUTW_ohGKKWaKg}5#`bosD0pw%bILl2b{)-W7LcEcl5 zOp%S>tmV^cr3Xtw+gzebM;Mo2b2BU)xk48gU(G9c2kWVAqfJowwQ0|8KZ-PS=l5V} zyXr}E_CPu?mkWO&#!+bzz7RfC+@%=H%Nk~XZ>IDa^GBH0MbZ5#o#NnTNlf!TlSlvH zv1va!8U;lSDQr6;Ni_2yL+Y7 zrxU+8Fc_SRN}wiRldiIvfWi#gO}`px(O8sOm?q{8rthGBWFZSXV9-JC{NbYvg2+fS z!S+I;B-d6M7GS(_TDizO>JqUjAe)x@UI0{-Hb|8t$htKWRS`xMobx7+ZDDWQ%l<39 zPKmOo#S$x`IQ|`{dgXoFy%nDq&>E#vzARxMJ1}YFo;}y&=O{ z*mk^E&HptVYJht2R0vuu`;g88O!^wCRGYeT&c&BY(WV>k?(i;<}ec6bxe#@@Q< zl2SLogXaI*hCg$w&}Ub~`ke)xs~}`0N&=3T%D5KY=mcZx_M_~5G@oL|-6FE%Sro@X zq%=D~oJ$_?|A&vp8ola`TU2tomDY>GwN#wh10$nKj+w$+2pY zctp@u(W3rzN~wGIE2~;5b$ILtscG33Jf(OsvCK=2;3kJz?HZ>h{SQszudPcNz?ktD zqS{r;<=YXsR_9I|R&Wa^887>#dJ*v}+;3!ZGi-R7Nic?-M9Kle3ri1J6%#{7va2y^ zJ{oNIBFY6!NTZ5E|NLJ<@Q@hn!8G^p3j{v2wtwfT^dDs^ceEbx^G$@i1NdWN-l_yH zqw4;eQ|4EqbCWn|BWQoa_Nc|NfKH%2fv( z8>O56SJU~YQ)q1%%Z8fnH5Mo6KaEv4)^>fR%CvYvVcrwOua>u4mv~XV16kZ}u=!9z z%)A;WbWV+Z0bKK&Y|~wWZ#^V@zgt+%_!g#BoNIQX`U^V%W8S`tUPu!|PNIVW;iQ}j zb_N#)v+RforL5@z^<>yy;+^K{vx~iZeo=0}hTR~fDNl{i_^smf1Z}rR36BacC|~qK8mR9;7?Jri3CxQb~v*esc?uD2lv5!EWx9I1F*9uSiLs)+ z+9q>5VL^`sa<0(&>$q8Y_=2ngc^mh~wFZ~yOQ@#`k}iYcOYD`@eBe92{bF*QQ;<6u zUXeR4S1&hn+AwiDurn}f4sLow%{Gj;7e49fhrh*}9Wtp=e&IeZEOx)Y=oz!CpqCeD z_j^<*#7og+UgB|IZHKsM8_FuAiwkSzcK50qlPtnNK&*p2kl~I+b(tkBBNr8 zxFc+snG$1!j+r#F=rWyvLb0x7=_bE>9H`jL+XAr;2hO#^K4!gFZS;&9-ps4ahJYH} zFmnI7!msIt0s5k@#G`4D2?UL; z>K~j%^Q+IKJ>lLNboL^C8!HuDT&L*mi7ysYcXjc-$YkmG^Py{e;U=!p=R=SCK1`Mxop(Lr8<|8Kb3SyFZ)7q}_q=O>Z)GxV z67{b^GEMLNvLN4XY3Np(!FgAI->lgj-QV~Xb22s3y@!A7Slgk_8GGKt>0U7A`drqq z0fo(%MLz2V!cB3bNB;as=i0d<(&q5>*o&`*Nu%FJ1h*bf#%5NHcRyfP#2X;m!;}x9 z8U9c`_hT_PS)mD5%rTAX#1XixMW$IJDb<#lxSaYM|EB6*T(Ybc%H0w1JXxIA zPyAAtH+-4gR8rXnbOIi|7C#P|8ZHl9;}Fj*=6n61|4h|Scc)XOZoJ@A-cWpnnp2|R zCOuXvi?^ae3P4>3M!OAp8r}~kh|4>@5bf*#aLABEQy_F)0-7X(ps!{(H?}Ai$_@hQ z!!@(a^||5W3T$z1PuCgNL_k7?Vgtd$yrtx5wB^S>rNK^TVor&XjjRQ8F?Bf#FSYu| zB4sM{Cz({$$+Qj8ZPXemWZE03-i@rPoNKF?mwW``S2&ysHp!hEmfKRt>Fb z!yN#;P|_QnSlI7SM=76Rt53edLNNXm&^gO2lov!=AS!|_lg+(L5N-{;nrc!9 z-7G}s(QlJhwO?Qeh@$v3f$LrJ8o;*g66fNjSlHe-O%29qS#4ST5MFRWethFRe8=V! ze9_ClM3=n)+g89^QPKH}j)oRGp5$(=D_cW+x%Li%gNqf#m1QwRQ(iD3X8T=+fM@RY zDqlP2AFPxcyF^_!8VGsjy$kaZ@7^ishqkzM{d=vG3MPYdo?67B)vXeYdB zCe4w{7wT_w)gyH8j-bD2&H{MMoCnOtM^tZ1N>+a!AOEW(M7}ap?l>q~?;EPRuDt=; zdQ*x^Bpm;Z=CY#!?eWlMAtrBsy%!kVOR@)>!qv$ED^TxUG&afHRD@r;hg@yh6FQmp zzkL|=G0V1WgBz)3Z4H;&3WVv`cCAH}+RhHBPK#{qkW=%wHNOWXfz> z^zVz79cRj$_UyYRE=+Mgci0(O*YG63VV8Q7_gBc^GVi!w2@l71%(DDE_h=f)I6(-M zXO9v8CLP}OuRNTG%cli6A=kqm;J7#}hc3W6)?@S3q zCe7n(21!DAKT*~)y|*2veEvL>%HOJ?4D-V$6vMS@Htm4F3>rG?{u;+j7VeOB4h2^qyc^^S6ejm^rGw!XBMK6;3{R#fX49t$6J4_z|9Wd zuei0zj#&B|=hC$g9Z8tpdGYnxQH~PnpY08qAJz&Oqqw7i4s!Xxo=7)$KVT#iKHIY2 z_fs+&f8N9PUIPZQ@v|3SDGH@EoCF4~KyKS0q?shQ03tXqMCqV?P;*u^9enLm-N=Lo zsR)&10zdjsr@6$x_%R~ZRgDewl3}L2=+a@WzHCjvGK`$#K2-01KRxdlX~=sQmUWU* z=l?0dDKOhC*^4~0y}e>{1a_YcOuqN}B=*X`msz7raMdH8;B7C=L(8gm$0PJ~!eJHklY>Dp#Y}=a>0jdGK*BBbg zZ~@+kj}paE9VQ%Slo(QQm#$9QqR4{0bh6V^#x!hxjp46ZldrkRL415NbD?5{mxec0L`Q$a=%L45w@co4LT zurohfMdBG$tLW2Rs#O&K6>VaVDiD(Y(4}_tZ(+T1ONrl&6O0MkNM5scKzJ00D4!oP z*h(Zv@(>=HQIZEmWA=*mYyKZk?;Z$c`v3oTq>{#=(upaON}BB;mBWNWR61x?4zp={ zYm;=6Da=(#sAM}zVzM0+F-fS%9Y%_3Y&D2w7|WE?n5HqOd+z)9y6xxt`)8Y#jG4Lb z>w3MOugCLwS%4}`BqR#r7yGE`m-q}HS;}VJ4On^=`|icoZNWRgpgQO)P5B0iVfeDk ziYk27V?ks^T#v?}KYC~1c9p@M`0*^nf=`fV!Z`Oyx@|wpGy z0gbvS4FL`Es3jjXwG2AEXvR6VR7sc4z7V$5<#w_t<)?lbB6SSc1{xgz138OH$_H+zwXsbzxPbD-*+OUi-FYGL7S+RbLJoP4Byd(MDJmtdb|JHvPPkb z|5o*LEAiwDld^xplQ{u`Z4y`@n-ly(HWA$xl7%LZz!e~ImK zt&P#}?q-91C9^{KCVLKo_cG$*HD4(jRXBA0`7UCG_!I3Ig)Zvm%w>tbXMYgOuCiAgwqv3)R_g>}wSPLdu)<;1qo}Ql z7?bWdFmcI0NjwfX&xVl&i%qVk5g{NsHP~4d&xXQ^>lriZ+DC^-xs~h~XFSY;JN9cO zPupi^>1JBvYSU)SL^cb``da9_%Q)`lQ>oWl%d&@|Cz_*r^N>})C`Yu5UsDRnZfIVn zf!#e#9<@TQ1CA#WJ_%jJXwevj!Ri}5C39ql;fu+Mq3+*f0&Tj4@ygWnkXYAn)Vv&i zTEwzjy*OpWePo}H>m-M%`>UfCb+UIYir&J$2slifU>&Nz`AKyt$Ywd$? z#$xj?9NK-ioN@n$GxUP!e;~ISY$gZ$nj&Q4l5%76*LK&&*__#`hIUu~*_>ZgE81J` z4OYD-$66fQDfT=QVE|ITYDs&`Y5j0(j+1Jr-8DUlJEnXzd$Xo|N7O>qrFO@89y*u1 z0}~4h+ZktiG?TPs+L6A6)HH~@u58SCX-$VVxbg?H|S~%y~FG+^IUAW&3ni6|3VSWgWTajQq7)Q=BgWZJTJ_6ym)R#ti&Mh2ljnGao)Yzy*-(y8YtbboDK&at( zo2iysE<`rLdUb*dBQeyd5od+O z9QV2S*!N+cAfjUURVt^Et$>US%Q{naeikl8g|n0?t1bHq+a9I;vyT zc{rKga#ur5DA|nDABrr#ah*MszSDB%HV!TDjQOqDCB!K%Gh&aWld0sYvuCYe(T~E4 zC_V-6t~y36NE*bi$paQLrl~t`zJi5byDlw3VSR)%5tDw^cltJ0ytiF@MnA)?%p`_6 zc*n<>H&R4LF(m(?JS^5(HL_j*qJ`*Wnw7#1z%~UwS+gl~yTSqbOr0Iy07ihdPQ27Y zwr(S6Xg$Pskw@7mZ%L!(xVR|)CG$&^5id%p*v5$Za&nbb@+u>_4NPyIm3uy>5wrYr zS-d67$+z7#jnhX zC>eH|pRJpz@%v4-IeW;rbQq;gya9ChFpb-lC5P&b}PcFM3eg0sF(Woq|R#_ zD-=1L{gG-MFoGQ6heSqiLM>#j5Ay}}5T6`n+^89!%Q8j89JqD%CiSkYm(J`-H4PX^ zq~))0smq4m!+*BR%p6Q)*l9{+#1HbIYAPHa-2KTmtF~ob1tA*fqF;a49m1P0D@rV7 zih^?5D4MtOv&OJ`aU6_76{H7$8EofvqL;Pg`*nIp# z8s^_XX5x*&!quI)N6eRzj!TZXsG~x@D63AM2yT=bqN&%)=?zlrRN^3;wQpn> zEwYIQ__Z?<*2&8d@qc8K@v}2Or1T`-9rkWT!fO`Ho`Z;2n$by(ZVD;ytn51Rn7I;~ ztBT27(~g9-niO@`H2S-%f!xiGT=S9now*v+NL432sx0q!jCmJ#JVL39COBadz>v!J*UAOy%alTq`Uv+yNld;t0 zy`V-#Kd+A3SBsa93zVcBNyg3&ahDi#re`t}PSbBpi)7}q<{sY;UE%gb#EhBiA?%5= zd!89_J*?~(M{=si^Cw#*NND<*Fq3Q?0q(WB@%Y zRh4(B*Zx%ivtgvuj*>0hXC5Zq z4DJVAb^1paY~w=95rtN^;)VqdR)H<#ylRGIzd%`%2-m1qSz1~3s$=eB?wuGE&FXVk z9fhUb#YhVbl|uU`AYjr6dQ$8Jxcx*TmwCv=xK>%>n84m~0N<@)5B2&SAb{BIS2_!ASvg~Z!BtyS( zZjZ9?r#-mBs2*NXtzkKpqF(_R#1PMKw)Z@$F&e-=Boy9(Fui?24%rHCw z^*VQb*@Rubid5&n=FEh}wV!+LF(r>XZiOSW%Dl8`W_OV9Xr^6<$fipaHh(13+-ZI* zHsklj4v+Q79k59pfl-#Gync49aPwF+a&YHXZgWz7hvniO*AWou8p(*&%z__ z4BYh2%W^lQbDJIsuW^^IOJLYaaRis1cV|i64YMXC50*UdQ9qvZ^DwZAatD*f!{6@X z8!xMZ&zm*W>mhFLb&*?)$+4wf5!S(;f%1|qTK%AKqS#Xt@u#@-kC+F~cg4^?aK&CR z5x;YOfs%i>e=MXAvCG8u6I3Ow70j@VDE;CAhoyZ1EzLQU~$#)5PCH=gK9 zTzfwKVn_&sB2mOmYHsEWhfN&|`j@uH;etw&zuw{vXN3&8Ic#c@W4kXk{WGrdhh!^0 z4?Y#2b(&Dq^V}37HQM6{I^CmwzWc->b7t2J%<_$L5ubZ~P`hzQfNgdk>ya!Mo#q-^ zTvIxH|NLe@j8U3Zyme5zVkrlJK?qXi27<>BBo{?MDzKd&M5L+3M{5Zj8n*u8OLE15 z*~P{nNK%jH7w?1)N0bO+v_P_(s14lLv>fJzpS?KU=~;y23^#q6LX;Zbw6$*oWeOo9 z);SsENTs7hXjdO=5Ey!VMMyNr&>Ye-c-(zyuHo>4_b9iY*OJsf4X&~lQwG4Byxj?2 zPE2&xzHb!D%e{`7%2w~AL1YSh&fyOjI6)eP-O~KaM5jcMx!ff-e=24sSeBn2AD-W*ImWi2loJv_}nniTq?S?$~W`4Aodx*4_7D^=dH5CIFNTSE$dw5l3L zR=|xLWc}o1b^PV!)Jhv2_Ixt26jnkLaaaAXwIp5qm2ZzdITzg#k#KxY@SEI@rDA7b zZ5Nvbj6poub*6+w!M2UB<7@AnET1Syv8~QO2dG#><92HI5b_i5EL%V-LL4fYbx8O_ z^e0?hBCnW9ej@H!MO1E6IE+wAw%|+ii;06NKSfI?BZp*xlm7)Qp&K2aO9bB{cN%l( z)r>=clDQT*@ELNa7tFw$(_WD-i-tfM2ny#oSq^QbV9sl>%qvCYd1pOT4!ajg&75iy z&D>6qvFE9G6+^zJjD#PA_F_|^aef!mM`jOKuwb1gK`BZFXe(u|((_?I#yj1sTF|I+ z*cY?R5;yO|%;EqbQ^s~wQ`)CYcZxmr*{L^D_kxrTD7dvHhm?d@pO*Sy_lT`wb3~Ry z=6LfY7lalLtpYHm7~}judK0njpIxT#&4_#K-G-vqAW(Fnb!F3QC55~s-?{l}ENe&! z$foATo9wwJWY9e_4f)ETbw{f8>>a78zY%&}x(>4fQ9B(*0TTZt!FiA}Fv{VgOn8Ek zi-&CRT%ZXDJ)w~#ZDhhbVb%xGK3rcG85oK71p*&)vfj|7n7O<*Bce{Gxp|r`Fzu-f1g2`>)Pyzbt-%)_s4>lILx{_QC44 z|F9UIMBN{px4Nm0`PUlx6vHRWkg=To*b%Z!mpp zPsuFR2k5CR%Pm!Q?Irj4yipumHmc7{=dE+^b?0U*qJ}^j7!AiN&q4jy zbgwje=_%$oi(`{ytrhf9v|T^22e9CuvjY$U;s)+kR z9GkBqU&nPDF-L)K`ObZQiXNKfv~QKH^EGz_va}}F4%$@2tuSGZ#TP&YZNfCi{}{aU zfiD<^^zbzPH{JGu#$-tqcl3Q}Sn?6<;HtSM+-cLZjl!JhIa0yDv%a!V55@tiBb2*# z#h|C!B5!5Tvs+J2SejS z_v~aOGhU0n@9$K`Q1{Fz+2P4Nd`b_wco-?bR}%KH+O0rslP$!-Z}5rUSi~PO0ewNk zb&kkbI}bKd%*V;hTZ+vPnQBK6JE5MJLOqYujku$$wYmT5zL|>UR3(+-VvWid9jiXe zLobj6$D(5wA(@O_ftJwhGO;sBjJcB7C<{<*?1|Y!reLk=L+>OlDJB?L0p;Y{vT5)_ z_TfAG{8eE=;W23X3G=}c_>FC0S8^0G|4AWFVO3x?gpuYgGQ~^%i~~%%HjQzbh_zqx zl<9W0t4@b<7K{#Tgju$LuQ_2ZWv zw!Ccp!0L^o2YrtUb*~=%|7erVZf*2uBiVge0a3(^dF2z2eLdSR-MIDF&(C0A&EA3^ zfsc%GIn1gSc#zn2@V;$sK{xaoW!v&)@_jKiYgI>@SZ#nYX)ieC-fBAyS7fr(n_{={ z#%E8PP7bDkt7!p0Vf7*~PY8eT78Y-UHwpWbJ#wtrQ!6`elFbmmI{{Tczz8YG2GwK)SnIFWftfn`VM}!QYdz?j;I@9o=FN}Rl zx?hCOrOwp~{6lnHH@* z&JWAd=vJX;5zz(a9TC*PZ+5XK^^-4yOq||~U2R%Cs06w)ih`q}lCJrR96%yez+Unq z^mlv}hcT#p9XE9|*~d6O8;{R#VCpBD19pY$n=l{+DdpBA6US-8ydI*ieSObbhV|md z-zTf;vQ8qJymK7oveE^ieWJ@DV2SJ7-_P{!yGI#4mdmC-Y@@krQ;Z!a0c#gV7Eo2g zVL+BSW;cs?Gjl`|H?8l~(%JXPmBeImZ2k8y%F2!6;$k1%czRVb}O-!FSt8o*T274g1^{I$Gw;{VUh*R*eiz|r)rkbMsQXS_`(T)` z%1L($y#j?n($5)*QXNak@ut|DKi>u~9^U z776^iJI&!-AHf!L7(54@o&0Qf|2vv46V^LnPpW6klyB&qAM-`s3bRV=a_&b__Za}wu*$cp z@U>-gm!g}gAso(li)#bQ4^KlKc!tp8WiUTnr|xr(XwlI}FAM=Le<^aP3p|h?Pu=Ks zxBoau!SZ2XDf!M31==)>KuNiZh*;Q2L`LB8l>l=;@8vF{!HYZ;GZXG|^a}p@&X*^) z%h2^{C(6g%*Txq1-T&}v_+EdP*;odq={l)3cy6SjA7Vpv)E-8x57`C^D8^Nd**85| zaH?rG_*NRwRgkWU3b@Zn+T#;0_;tYAs{YCJDAUW4RMorelz&)80W?E(LHAFj!F|TO z%C@>TgarRPG1Xph8v7t@W>Rej*K`2{k}myHe%!wf)C^)4lerXq)2{#RoqB=b-M_?0 zp?ssfwtY1Q0&31pQe^1@KD?^t0O!5PJDD{TcN~`ziU!Xm!^5UTGnOTI0DyO5i6)=X8?1*L1M7Pmbn6;Py0&+p*c7Q6S zBYec_dbj=LuOTh3fhm!P^-{}Px|g~P9q{e9Jzj)68o|s|cQka#s={RTNVzfrghhWj zFb!4QvG?K8!4Mk?$SyU7+F0uDrW-P9nMt6e%^9M|%AvWzP)CO{#H*-5;fIP@*q?!Ky$WPO;2%4@8|Q7v3|vZGIz& zabWG{{z-xo)hVtA%7bxZ;Rw(){9G{n>bH$kX2 z`}oGe1ZXYo=Zyd_7JXqlTxgv@!A=6Z5GD0)mzeMpLdXpRtdgWwAZn0fwFB%R$2{-h z9_O)y=0*e`rLxV7{G>en`T%|l${4z3+l27D1j&$1g6@_ymY$h3FGlA)Z)gm@4c6Bb z*iAG{<1}nrBGYsy^F6mpgHLw?dE2Zy_#D%qwpTt3W!-{fZ&rcI&P#lyhg_b`?hpw4 ztJ|opp%L0YP{4@TpuUYN8}xD)Sq|!w99v)ZMJN^}e@Q7vV~3}SBQ>O%TCybnI6+Pe z6ogX4n+y?9zNsteB=7|sW)n^g4JrJ7a+{!wS`?%B+YRPpUvkx+6dr~-@zP0{84&a& zGg$EU7QUBsv)UPvMGEpLRayGni?KlT-F7=clT&E-J|_uKpK2un%pia5I>8cu2rI2O1o5cF^#YBSnn+4Wf&_xf>c9;mQ^uqC_L!ktQ(?>NFC^nich zPEE75tA}7AMI+WnpPvP6^L% z(A#Lo!HAjDDcb5$Hp^RrO_de-RkAvB1lc#hA+w8P4dvzNuGG*IKF(mWx`8c*RfA{K zHu1i4nVmT7k9b&0x_y1970=r#L3};R;|=$OLw6&+-8GW@^Z2u$aU?9MZRpwC!s5N- z5V2wYD{|lE&_C+Bp$J5Y>=jV&K6@KxLCeVCou znIpM+BMruTt1)+NXwrw%*n2Rd^-+uWs`d+8u<9?wX6yt22YDQMl9`*&LyiIeMjZMJ zV2!WTH+6Zi*?TAVq<&e1azwSmlR&WH8QfPo+U1_l(*vVa8#iF;`8;YUlIH;q&rNFo z6aW;K{gTUyhl~4GJGn+nUItCcVc*Ua5E6=jBkrm{o82&Ei_O9A(LjV# zD|)|Wm&C}d;i)5jVsj94H);m8$xkGz`+eWnbq7korc=5Fzd251t}C6Zx&qTjNpOgk znm)#{`44;4C3{hyfDwXI+Ok%Q)W(Z1lAI2aY7W@iOpaPULK+UkiGB%yBkMn;S8kfF zZ@mq}#inIfUM`k(RutISM6Q-yeZ3^~%4)9aQTxqh>&@qJ^i~dix%Wvazfo8r+pvDW zzD!Pi!!9@6ZE)1!otY3aIV(DN>kG7abWLXJ7rP|Js2a!b_YQ8r_aBP6x}j$UAA5r8bT4#qUNIrR&vJVVF3mTqaoxA6FPJ45 z4P-%Q5oZ()TlE2e`0~6H(6lp`6q=&N>tk-`Ht_7@*em=*tnp#j1M||1FKNd9Po}2onRe&l zK{jjBaQhudb?G_WFZb=4l|>x&WEg5FY)44f=}wy7C5Yp_W5iTS1ts83$l>WHc_SE(O=r`48dJAo3x~gFKYY*r9PZ=$4b9M@3%AB3=L&g~VoZ7*{`jfc7j6lB zrXp+}1Zq6cyyG-9&wy_K*Yn(V_~K}(=WrAMGBM?-P#zZMAUn`FH?=S*_oBbnQB3!` zc$?HK!=EsVH;v*>q!!T63rWQ3osC!LzeGi~%#x3=SZei?d{2GSJ=#7X&8r&phX&*v zRXTTgshv>ho!D)!v*&s^i*}`sqK~3`U(`rLpVjJ~M~=i{U8Dby7S--7h*Usz1E)i} z_%*V=F<;P27SquETm|o+lmIhok^TX`1BD+sh5zdrn16x~znZEf?t7_!5(_9iRo(MV z^axa_EhKNWi($+yf%JD>7pFzz3+X{GIqqcL&Zm(H@D!vk_#gVY_1KYy1Fhp=TF{GL zki`ehV6~cQ9C5aIi>_*Fo!7b7qQqjs@kRKQdhdng{DM90Jm{O8Z~cG~Hk#PQNEzH?rE`}$ zjPe;G4}i`_6e#=(K6fzUVT{m6%TA)Q1@LTB-YEdAdWc3 z`Y_$u4E=n$?~6CAQ|cF!#c^Wou_Li4=%S)%IjCugq<+lw!8^95*rL6$4{pF&S5AX> z;=hoMi9z~kiJ!nMi{xG3yV(eyr4e!igbF*Np*LPq#To$iQx6dH6Lv!Eo!STH+ZVcMY4hf8|}Gjl}hQ3z6bI(tbEiM>!PCHa^?-!&NQc*{?z$U3k3^-z`<>L7arTJr-+?chIrv_<p!ymmcMw?+FczY7W%sx^hb}iL5QVU9}6Fs+~$K$bUDKP$+kx zdhin9Z+p(Jdjx6O+IMy)Y@#}RVp zbQzG&7k?fN(91-*r}Tp|+4EF66t1)`lt-?Qx%%(m@H!HVy7#kVM~+%j`?#u|05mCSU0`8kNr$kDn7*r{fqL{?R= zSpy0%l?D0-k>MX;Sspvyk$e`9LRSM3)PUsyY_7mRPbD(mfywEUHetoiJ>eOH{x5fN zR@pvNfZBvsLk!4wrCoSd%E|VKV?sr1Lk3io%C)r-bK89T!vJF*eVOP`z2gVmx%!BB z>R+@m9>yVW(9Jg~sMDVGtL4%=;5@i_-GW>2d6O;OMo=WGm!+~-UHiy|S6*Z{8lr)O z=sQ)r?0wznMlG|P6BfnqGN1k1oOD??8n{w7sJO6@TH=nZ)_>zy?pF2wCbD5HEk{!N z1j{!pw_w*#hhRz;-Dw|PhR%?56$wUW4DD|jhjXdV!=vRvB{v?FtUTTaQ2D;={9C$1 z0xDrPs4HD}3mj#3Nhwi6d1T9q%KICA4xW;IoxL{(q5>?4MGprA9qNLNrX^Gb7cE`| z`8OG&mg7b((+RhSmslB3%#*;L#-VE>Z2oJo!aXbCzSUs{;D6s|SA_fvT03}v4i$1VmBlUS{AeC7Xw+E{yW&aHvjRYf3-+@t#JPt~vl;s^Cl9Qb(q$ z>yIZkWx*VW?k$r;r$qOFg7yu4N*a2fQh~P_IX!ei?xZ>6xFxQJGI%$KI~yGjgDZ#Y zRW`0x(0G-<=`{99*e!Y&0^Er`xd3(wb3bxh^`->uvwa$C=xOn1e*S;@QWTJgtK!%+ zKMCt0cz-3YneF@g9RvD+s=k3H$=(4wH>Ei$zeznvgYR6)fE5Q^RxYhf5YY@vcWD`O zTnuY_JJAu~D#K#~U1Js>v&c(X7vk^nyg}-Ho-55!<`(B#b~w@)e`NMcE556xA)xjfrhtFysm^MYOJLT#mG+3V#{U7fgXfM61DlhtTu&@5K3GX8hnY2ofKpu!ZizQWI(Jp__HVRxWk0#H^OB zs=xn7Oq)^kvdSXdVF72le*i0DT{oRcwq1CSy6L~ghEKFW*BTpZLb#P&nw^(QqgmUh zq@c=cY-7Jh|A$lz0mWCz{WG2jDBV~&bGI(mwJee9hWkA!Q=^Wvu542Yg>3^Paeo$oDS%dJX_bD4; zEAH3@Q8EJJzQdGP53@p$6WTOI&Ley5%7J# ztV6kb6%0&SdH_)rmS8~xyZSrfDTV64Gt=PxO}TK*7hwyZ47sUV?wllVoGg}@NYC~V zvw9ZCwr0{hZXqUD3>qCV_A=3>audG-P4vjVXqE2fr53+$%Lg|rO$w;xi|ZA$8iL>I zT^?Y7zi=Zt7JR#-{e{;($}fO9_o(Xd5I;IKeDFq3{Q9RZDIMVC6)Hb zs@lwxef0O(B@q>xR!G8X#agPSMOA_-qK!hOeXjjsaIqsBa7CB1CcLPU)}5r(dZkZf zKbA1YfNU^c&=e{P)gkE*T}#i%F-lK>9m$l42?& z(X<>ReER;RM6CcMj^EtMawiYi6pzMDL98t{(?-GFDqT}H8SYlmmII;G-5M*UtN_vt zWyXMa4YgJeB_2u^#fgDq$DNZ(+@c>5+VlN1U_w5m=-`)8Ydtm8!9-S_HMr6H6ht{u zG>}9$7heY#*t(l^&%_K0oA)$93~;$Bhs!;Pm^u8c=?{upp9oj8vyj|T&^#_rU^ z2bi1s_;4LEGuc+puKwT}B}wn8OdoNA@>i7GtZS~3G=8?!)!`E_ii!a=!jBa z9$adI+0F;F7%nbImQdZcIX)70)fF7cg;t9CHbX{?b3cd^Sxwad!9Wx#oHIR@>V>O; z-ORg2niTj@vkAEZQB8mk_}rzbqYH58~OjD537UH|Ono&C=_(&8LS0@@`yjG5&y&NOsRVc^Mn%9EJ z`s%e3x*u&_Kl6;#5Qt!nl41ZDXMV^PjcfnfqoacC9K_c33;79A4wwOpM(p=*;gYk1 zM+=n~I@Br~**qv@2}{%_&gpfS7~r{5B#l#>`Ux7hauR+<)?5KyYrk&w+y{Gh&$Z~M z6|66pzAf93)19h`yf~%q3{yWxn$mlAFW4@+x9Q$c^=_9z@BDaxNP4&%%Z$90rIQ|o zc`k-*L`}@Mx6u7`NvNz^d}6HC67%XohteKZxh~2hd{h)$7x=Ti%m#N<+<5I$FgYS--34jPe7>iBtIQZh66$bFMGs(1&qf~RJ^F)I zuT#7(uEvhPJ(0J^AC9-s=$1OA|LY`_dCv_-+E9P-6iB3q550T4WOeX4tO7Wl0YHj1 zTHX`R&}=HiHriL5QO`LqN>`oA{eZn&#Oj@c+N|iD~XBX&rs`R+D#qce)4^%b9mS$f>p@&xC><<;y7GH zf)gRBR0}3glDI{Z2Az;0y>8eD5_}V$gteA3f-sUPBS?H?;8*6Ptq{Np@In> zq|RijpW4XJMiBNCZC+x`?S}@h?}Vf5Mg55{SX5%`bbtXeCc{vvp(f}uktLFjz0rqu zO5W+FLu^vQ>qs5AQ9bv?CMONnJR#`@7CqsR-l4deh- zjZ&eIm`us(@i1VHp$5#A+a;cowE+G8Z$GdJ89fo;#H&loDWswm{EZ_Z=f?knuu{~$ zzn@2`I$>5_CB_l=U{BgbJb(%gQ)*%)u2xy(9B~)=kq9xFcuusV-snL ztFOwAF2!N%N2uql!ju8Ht=*T{Q|w997+3NGF2H8hBonY)LVVucqtifKN@ux4--GW4 z+WH2f*zM%pD=rIlt!_Ci*{b z#+(0SPkDB!r{r?eJSwsdZ-$hQhKQ?P2cM-Vo(+LS(uGjjmmL~O&B-b|n z9+U8-wR#d|>WemF94-2xoa{J`I07DN1_T51jzQL`OT&wjrjeJ~$PUu#gqzz$!$UrJ zn~`>lZY7jj;5k>1oXql2UpMG=nn-vw{;u8~u1jab7Rl&{Ir*e%4lv)eEY(#1Fj3ZW zV((>Dm1Soge&{^o0bUy)89V`{gC^%`49mZIju01HdqG1JMMH{^#p!UwlP;PW1ZrvHbjy(JXUwM zf_G8+-iv%cZ}DTfrAh)OOve<}r~1A7IGK#&u4lstgZZ3Hps8V;eH2(s$N9l(>*ZKC zfTuc}r_3YxeST_uKJw};NmSKBMdok9n(|UFdDwY~Jpe0X57pC!S!&5!{D?#+bW?Oz z(xL{XK)EEN1&=Iw)#He zjG+L-D||E(o9eWWDHB!jM$=ZGRF$XYfZdwe~AA>@66PL&%~1a3SyQ3_Zz zw0Ci&uoCX>H0DL@J%R!a?jxSHi~j1AAC2q8-_`V+!ie(R54>{_&7$4(TLUr(v@5s& zL>kO5zxpO>Cm1V&_^A-yW%ZutQovF9A1?Y~1C`tlt(81_ig?=-&cQL*5|BE{M?N2K z2Q8!Q^zuC~n{apGrv(EGslPc4<*r!dhJoCL@=|9kv31mH$h;Qt;NgU@34uf|fzsMJ3*$43s{F-?+=C1$gMaIol>l!s`kEDGJs%-E#~ zFCk!XHK8>Haa_L2NklUW9u0G$JQ28AAV_WP4x~REBi$?Fx1c-bklriX1lmY~iS&4p zMBDKrrQ_A#?mG}@at9kJIErg1ltyHcmrNY(DYxBnFfpYFmW0$)KuntUa{+}l03XG- zS(7`TlwDRW1b;x}Qe2q-D}*V8-ARTp1qfrZC*NHrc5@bL$lXvhlHadHdp7PI42AlG z^EI;j?IFSrWUzHkGrg5{`GwUV;~_+{Te>O)QRT~v_LPg)(*0Vwm4(_EX!qA!Wa`YI zFu$=G&X6sg23Wwa%oiz45vrx=S`H5_*MH@Py zSl71LwWov-PPYc-TW&I=Oaw=Y)JM%^vig`AtP`1$tp?~c6`U`48BB@UQtRMxLWs@> zF+Xn57Z%{6O-(wgOYp<=6V1SLg5o2cCm|Sdk#itARKsbu?k(!w0-I|%Zb5Y|Oz*Nk z0h`*S`wUii?HJjLhaW|Ul(8OtUt#hp*ct<}EcxQCN`}WKb$e!m61I1c457}~=rx2l zY6aOg7a9q_f-aol5``;-{F0Q z0|~*(XY`$}aiQ;cO45BUI&rgZkR{h7xsV-V+ojH|9PN`yw*c-oz+py7y;4{dW&B04hHW4n~s+SPv2#Xnzm{TPRlJb3Gx)@LEl zT-}MT_=4kIguPwed+>_(^BXaOr8iKVM`g5TtSuXjuY#);^$+MF3lOeorP|l55%7Dr z42&E!gE(!eHboS?q$6tl0F#a6PzEiy}T#RbQc(+MZwHrVSp6te0riC3#Illo??t+@_d{ z;EM2tmA1QPQix*(7lN@PJPU%r--c|&omnrgAqm(zu+fE@t`}$*IWXf7mPNHRiHL^K z+H2|pUK2q*KVcwv;!Zi_5#U&@+$wyWR50lbl>>}^gHZ$83|VNH>5iwdywli?rOe@z zUJmCsl;8dDB!s(^%|vBxb$k~7m8x#0I8qQ}ij|ASE-!UT3g2uiKHd+rL{Jf!TJ_&m zhMl(7N)^zxIAXWQ=L;aV9<6ZZ=2+on*Ca<5G7%)mmyZWe7ZhKI-odVaPNZK3mS{t9 z>S@f7I3Dsvs~lL@Ek+3?ZxbZZmPe4hj)DFz75a}Z(wJSZ;P93DZW_p2o zV&7VV;^35k-622K-xd$1yk>f*(Us?0X)tiaQWE5U$9^)u3Re`V9L^PTzMW!W_e2uvzwUW#xYFZDRi&Tnd(E-S*#p#WulcnwAs= z()YQ?sRO=AG!W)44+s)zuAy6XE@ogm-U)k)8MGq=%Y-{R=z5RRP9_Y@nX_thK9i}Nf_`#YSKt+Kx9C{sDo9e zjx`Yx*PN$gczM60mA$ z^xM$dGP<`?U~!^*=o;0T%kEQM)>25p(BPMce)<`+nzuKyeC=f?>aRcKES>7yJa8S( zkQw>{jgCeL=lpP3rcI)5Gx^l_BHs$;#xyKzQUV}cUiKOrMSHnQ_O+cAr{8)>wY6Pz z3SFHR$>~qiC+yhuyTo;8kiNyUTdE1|08Qr2DPO9hwKL~>WJE+yJwuKIs6zCqP)`M@ zpFD|YNGxO5Zx#2RCc#9&AwS7|2U!(yH;hH&a0jSkIEA6x29bzbMOi0{N01Q7r6cZ# zh7B?+$PM4g@Cp*l#2D|}SJwkJklpZI$#8Z&9|U85^$SygUa0R4Ey!)>L85oG86--c zB>KKyr_Py*Cg{A4v* zQ3)($zpoQ5r_;12>Qocf0X?y9gXWQBjo2FY<$sPE$(+Qy%AaKJ>EJ=`>8hLTJm^u3 z3aZ*+a43;vg?IvPh*u>xx(CcBJ1(oHo@buvY3zYu@VW30XP^U+%SvZ1CEj^fPJ4I> zy+v1=9u0=NBZby~8uw}vWYxsDlbLQY6R8edP)*4ds@onhqx_WF^^ozBF&-F_Jnk|| zTn{zjo%^BUQX*0$K>QNQg(@+nyUS`B9%N@)?tX!&?ukpm!Q?P}%CmAGD?I0KZHq`H zv_kJ+JAA#De|1o&I9GjvyK^q54}FDzA|Gc5;FK==aX4*ym!cl5hcgj29r`Ej>dRAb zMC!_;Hj$BHW!#>R^R9Ebw9{3oejFF)371x7_{EmT%V<(&<|%BHx2W-?MQZ23E=V>K z*(CbAf7k93T&-+8i+zQ0-8OyzME}A;Ub(p+$k4=+;lDjPy#H~SzGXGSOgdvis&>D} zr0ys<)uw#W&_b}M;<%yIw;akS@|AblQYvGqdj1ZYY#Ry?O!!bfy3)${(%WD~uflS|a?f?{1hpDL|0v%wZ z4YBTb{3eQ5UpB}Dqo%SZ`d_D3xichAo^&ykyMO%rs*^HjM^m<7?m1bi{FuOZPzfr) zpYmhUCRh*1B-LCv1BFe>Y;hgzHkH~G5tR|)FCJaLyOs=?%eg5=*_w?oRhQ|@zHdH> zO}W)vItDKcM3J1Igw;l;T3P|>1@REVJ>R6LSH4e)0Tf@m;P19TifKDZOjKM&19s<_ zX6L1-Bj!_p7sRT6li!8jc{r8+RR&~>_u$_%)&$DyrP#^6yk5I_?C>{TxA~1mWul?GnMC#E1Tbeu_nqROxR1RiD&N@0liA+*Rfh69umCF4s*@5%IQqc^h3RNqajQOIUy76_AhMf_eqj>sPU+N`oJRxUE1i{k+Tr3C$46;j2wQ&sS#%rVuXWT;hioh0 z*qt72X+6=)KX?}AI)WN_m?Uv6BHeTmvol>GSE`|LBt)YZk@E)UU5wZU$LpbHGEjuM%3zNwxzrR>`TLR1+t;n z_Gbi}IkcQ|JTQH!ALwh!J5;2SP(QE=exNN_cvxd1TuD8l+~=F9F_B6vF5lz?b%fxg z$SB%?2zgk}9Iw+pX!3-?J%aN@eE_qAFBCVG4*G+`s*Fl8$9&3~g<|H#FDVl2NgEw@ zIS>t3-Ba!nD>iFl-K91m+zQbsp?u3Xu5WcYWeMOKN5K1t)ib#lV#h=5ZISc>)aj&; zm?9{`?{QiuljcQO4bUaZ%jzl_^HfO)r}zPSFJMtQwm6;)@#m6IHu=*A%te`8o=atxRhC7ij^ zXM6rV{Srejq6(jwBQaG+X=@WDFR8D?0cuq0nRG8hntKL~@{{ti$i4YL?O}4l+0M6d z`wlrZXdpKp&Y;xr=21YnH5|euONPizIrGWy+Nw0Cs_g=4tlcppBwuE}l74QPdYb0d}5w&HNIS%br9VxoTl{pxGS3P+e^abrh^Y=Z&dCv{=OQkm2I2DB2v0VDrmbqo5#>Z`P8iv9afjWIOzb%Kj-h5@K5kBSB(k zCfmYKkewB4YxLi=vt$d1j&?XuYPd6H(uj$>roLPYIl*N1k=^f<2F~ry zNn{T5Z%$F{Tv7uKFLh0jhd$3qo;9tq$1#c z8R~z@mTk)->m}=3Z>TKVM?=D}Wx2!3ws+P=@hVQcYTmUkMM?B=msTU|$h~6yINE8N zwZ|*wfaAnjBB!f4P8S7~@C4|McK1r{EbGtT|AK*z=x@I59YrE7l(*+BYaDf2iF6N4 zI%TnQ%g8>*OYBlOwy85I$}M3&9HFrdwz-d|V{MGNld6?h2bFs?o2EKiR~G5AH{%=p z|39X#JRYk4`&W|6GNF>tBzux5M3|&f_E0Lzlor`iR21fhWD6B#E0eN>%A=B$O!gv1 zS)+_4CR<}n%rMLSovZI3zvr*#r7|;j?meG#&Uya@OgieUxY2I%> z2Hfa~8$a#SHb-x;1Is{1-9ZmLN-2vq!MF-#K%X6BKiOsq=$tTgg9)^U9yqMqar;Lo zeqZ+|3eeMedKUKF_W_?cjIh8buK7(H?KgY%lr+Hqc?!!t;F~}ZL)hR@z(NT7q35M1 zwIWIJCM#gHoMA|NXk!b#WDscDIHCEqS>e#b&9j00mw~1qm3TOjbn}O5N9mQdfLukPruEcXqAl_NvIlT)~{{gcYa3?6M$QfbN+n!y2u-oZxec z!>Hwi90z4C1LW3Dn8ZK{qtf#rCF|xD8_V^Mw*(-@D0UP zj#F3CUsSoEEk_LencyhW!gf-gtF(hkInNI8&+)Lht!-2@l)4O82p6@-@L*?qjyPb_ zgsE+EdFbf)!8KDd zn0004oyxR!cx%&|F*49Gk1MA)B^M6BD+=y-PUk=<*+{YKig6gTBjXFD^1ri#;;kDB$v-+&ORH!QIr0jO=Gpn;?MraEBTUv?3s^ALaj1E-$vtSb~{W(H<(ZI}X0W);TMg zvGyCFv#`ln5M43;1vS77R!4=CD~l4&e~zTVMbQ?<==R&Zyhz<>&h$E-Le3Yc)C0*i(eIiFF)L4M%PitQ*PSYbJ!R2awHTT7SIdf&g z{|3N=YM6^BD^PRl>TmRFd*y#Y=gp0&hiOT+^D@jOkf!vP_Qs>PhB#8l5K;95PS7~T zgcI7X{d;F2ZEG!M;7;G# z;g6IE4NwD1=M`YxHy*T+^YSU}r4#8XEqg&VB%zcgIxN`bI&lC5U&%A$Yp>ksz6fmv z?GCtUNoyd%l&jA;sWtNvpm`HpAhMMJkqvJ#u9P&bNzgbGhU8B>{)cSARfc-}6;1F7F$}MHUNH+FAAK0$rISzrtWSGgj%HFOXk z?ho%Qjg#M>8SW1o!^%Z8d1K_IKdUPrlT~dkpeZ-;? zmEs(IjTx>e4`MP50{c+hg-~g$%|G$;xz7Y8Q>nWzqxUY3rFzy+mE8%Rz(ciwI+tXe z&&|Cx;1BD84wePF6Z$s3K$Z235D!DJDLVfuw#@v!hA9#qT6&~%P5p=_ z2!J{8Cpe!+vVs+`=jfyz2;G!YNuDu~q^i6aj@DU!9kgv@v^^ljqfzJ2Y-N|#5W(TI z4GgfG{MBCYyQ6p~{hE&dW<*hXJL-$op!Wi~uobgW))$kqj>kw)AVA@bac!@6iP^$>tvmO(qQ#hfo!O;`(S z`EBSg<93Q2=1Xupc&!uF;3UaU`OOMmIbbW;pInBw;=jij*GLUA#Lf6ifc3;U+KfTW z%}T>|8@E0~{GqI=vYHIRN*9azK=;fAxR25{2#!BZOge`mZ)(T0VZ7(RQef(0`EvY_ zYA_?Htk{El_*3HUcwC<(t=dn_cI&WIfCZ6sSir5 zFQ0Wl%o?Z@{KSn}!W{_R z{5M6ZE-{?4==cE^T^&mmuEg6I$78b_x)sag6UbXZ5Fb0TRWMX*dmYloXK6z)kQ z(QGlmceI4sUN8iHz60&LQp)K?Vmu{*3&}^L5I5%#)1Ts%?|FgCQb@#~NHOSd=-_4H zdz8qQ1QwtmfWQ=6_==LShHre_Y!HS(upq{KFO%%Ko57zrDei+MKXpAyoHDtMB&7(h zT2CD01U~vfNRp;P#KpKk?SBIRMGPCrsg4M=wC9M^bNn4lZwUG&m;;-f=3LF6KUPBD zelMVathjEq9i|1$;s{18FC_04b=<>$fi!qE5+(#1?S>#M zId~biMno+Zh&&ZG6&niKPyQo(P@3Jq3xgq!0o&tgno^b-6KNzo7K}nm!9P0TIR>UH zb|2Y$1Rosc*?{>02_^s~!R*?|=L%z=z4AW+9urCk_;KKcM=j2V93#-^*aC>+k8LJt zQq)Jm!vqKP5)3i|<%Zac?GWEhh-4)2Lh}DIian5z*eJt?S<{J%WFsUsWMRP9-?kQ; zWoQJ@X#DEP{OLvisL5)WZ#){dljzLqK-Gh>S_Og2|u`rtIzQ zpLXjc*m;BXVAySh{B>yiMo&(-D_r#*rb0uoNSNVg{$=cz`1k(9_rT*g#u57^sSOZQ z)57bsWb$4U?#bl;uydGO`U9C2q9u)xe z;t1TlkQ4zJ04tmSGF5EHN6-&EViqU?+RH|>k?~kh>8@#WInR$o*Z{X3s1Pfp(ppJZ z?~A|wSPaO>sdXXcqT+wCr4iW6T(<8)mz_?KcwIvqEu?pazk$}3@-R5Hs4mE2%z|Mj zB)2Yt0!>+2Yo+_(hgL5q6yrTW48dG7cG3B@p5Pz1dhkrG9x0~YKMw>nCozXK(*Dx| zU2@dS#YNEE5vzH(-}ij{HU%t0QuK^s(1-9SXqzeEcCrNIGug1DkvqBw5q6>`o%H(x z=?J;(1|iTcW7Demvn2@3R!L{DgjBx6ITS`x%yNTI0fQnfL>S9)4ZU{&)gi_(4MF5m zNf8@vatk=&2a)AQrrBsGkf(C#tdC%MyzuKL7Gp_}G$UwHj1W>b`s;8_(*L>#FL^xVREf<11BO^X2rwEi(_n5rhwlJi20qBl zp2yhTY|iu}%1aGw^Ti?InV z{LXZIjHujB1vofO$Wi|EYJ&=Ej#FsNx|3JX+#75GFJ(mShOhcEv zFn>64$mYhNNur9hta-l(GD%t}Mknc#K)&XX?G`GxZ@(;7xk;`EpmGo4dyqTbDpLkf zLx~SCjygmaI8mds`CycctU%P9$dqip^C|`a9$M{)BvTc8(8C)5Q7)Y&?t^3Yb`Mh8 zT{>kKE}_EX1t(yXdM)%g1YmvNfiCzm7{0h-T44&GfD+De1*1F_2SOj&KX+CeQ05Rh z<{2Pn8vUiZd9XiHOTP4 zxBROoIt8VGlV3{-mcE#PJQzWHV5D2h+%mXc+jm-Os(9R+fy)vm92FP}H8Mo9WI|TJ z#)X0p4u^df4Oejhqfj$)?@$jNgpf@aB4p)69Z}|m{$0u3?7Rz)0JN~I$C5RqS7Lx= zfX#6s$MrcXSG()cPbc8PvVmRLrvjRzd4@>|uAc#w@+xtHh22_0gF^O|WRm)<4#aKx zk-{*A1R}427%`~@VcT7wBb1G%qVHCNM!z-{0vx&bIbh>VVbqeY14U$p#`d6K+C2eb z6>;r5-5FYv2cd=%2Y+CP-5=CD)6R;5U8Vkq!Szc7YF7;IODEeK_@`>|w&!#BN_wOf zQ|92SJc&!r#i@G2iYS+VGGH0g_-U414yu-<@~^O#Z-5(Cf%16>M#z~^C6;HvTF9b# zNJxGK;WMKo1LRnbk)aIieIHVi1F@bW5E_o-{FSj_y~K};VVgxiC4C$DtTKfI?=n>k zAGo)Q4BHM(HPf1oF=w;TwUP%oj((51VQC zz6qTAk^|5K!yn$#*iI%JSn6{^L?lrxzu60bDfa zh%qq23W9gV&_|(N6Y^YleqWFP(_A_#~fcvCRUQg7*rR zNxkYo0yF-AK)iVuD0@RRfO-Bsh1mJ+*O>tbm}QD$6}L%>xDpt^+seTFyAa4invz8E zcZ)mh0&F_pio>l?yilLKPlp;PSMEPe(jkhn*ara53A5;Aoi^08GnE!t!%loW)=wM( z=QvZ^9&V?ayV%1;TiKk?s0B3O^s*m1s{YGi%X3dVOy??uX}s|_2TCwFJnZ+#T!6qR zfL}FJ4(5c;3#5QG+}1Jef6zEN*yD5sIQ28G*wizWeC0~oYLWI&ZvoFB+w>jr72#m& zQW~WUJE-^?e;Kn#?e-WS?hPB$#SosQZ@LRou=MRwhVmOxUP7zt)P*bE$9zGZcps#a zXECeM!@fbB5VskD(bY0Ir9di)xr_$okiu3|aHYuIqDcZ*3J=DZ!@CC~!Dmu_Z|L$k zcJF6av~iazehIq8SrhFCUMFfELk-_*KC=t_A46dRz5`s)tvSp)NLHvAuL$A~cN$^z z(sc{oF-xD}J}3X6J^IY!uGl5)+LaoRKuGAMr7b5&bLrq_A^J3IfIob7N(L;3kr&-= z@I6ESDD{*?S-}si#OU;U#-%DNwKu{dj<5ZUDjJ)LokKR2LIMfMpQp)4Gj2#YaW^9!l>M%AUfA`Ox-90Yo`&Jiyx zXWoZ%yx|a%i!EO4mN^!b+}#ZJ2Jh1cyDpZ_1d1}H0ROc(EzqHevbaa5PDwuzkm`Sh z)cuL3ECu|BvYf>=g@ifaTM4)zc+1p4g*0|3iqP~JPXUfe<0pq2%co1qmTgf%XtC41P_Kup(6h~>m2 zR<^tbgfQInIi8sI)^pq61Fb3h0IQ?ckPnpqqu*U%GIRBbseQx?FvK zqq~?EYi|3_n?P%St^Hq>6sO7UGD-aGs^aToY>{+A3os!HWMvu9{+iJ98=T zBIZjMy8LpJlpGEuL5b*zEAX6w?yRV&jt=b@4HM9o0oE$JMH&2)hOEwo_5vY8%yub3 zl0~om%JTg0E=aqY$(zCI<|hG^g=u1)ATRBhTT^dQ@BJT8C}#ki05?Kp9eJAwB8M6B z2%ckzh#chA9S^n2AsHj)_?c?rpF(C1#YeBdqTH3A&BJs+4amV&Y6TZfXT)L`1&A>xNikG z#db^@>6!b0hU{>kbI_nSI8}qHY2OmYnfYFzW3^oK@W=a@j7CiVb@>prIx` z0|VzK;(-d$9=l1Rqpt!-1cc~(A4&WTWQ?6@kCtM7^w4N-ScLuul1sM>J z0hi4lo&f8>_?43L+Fu652dI%_oM`?G7}g#HsmAO}J4bGy@X zEnrFd9Az-8OlA&z2RGHxbu`E;^q;y=@&tpE*pwpU|=!h zNvyN^xR*e|yy7c>bR}3w5U^F{j28>mI%^VJSdsbAF9=}jjv5olwcw^J@Wudt3zXxa zC1#o!I+%tLmw)N$8ifcgvB969bdsMYD*;C&8H7fLw;1KM`Ov+)|0c6yf~3LxUoLbh zR6C@TB6Ho!B$;brZ$i1r{16kI2OQ3Ke@N960gW@PE9dZar8l0*TfNjZTFbglNIV){FCpq(ua*JEZFu(LJ!Gs*PK?6Z_>kyksIapKpW2*rU{v2Nn&Oh#< z4e{us8CWGqa|}P>Q@Uu7mH~j!@C;iM>+$@}QFK4Fw)eGtFX(`9*N-RI=spHHv1;%! zGZ3B9;va{(7Kvi98my;?!=SnEU2;5+p7@8X5wJE(cP+HYGt?B7SUSe?9!U{{gc4ZT zINrZWfq&*{srvRo;9V+}g*oXBI=+mdmygY7+_kA#R7j)l`I-CNF<^k)UpO9O3GqPS zSjmiSbtoh%LStD(lw?|}_YtFK4EHr==qkcVxneaDF0A%q0-i6kgA6TW1vv9MAFSx^ zsCUjk}_{JFgfBJ~2DqxX0BRkR%fIZrC)p@=v zVA5?aUh`3V4|l8Ot!o66Gb)3}pwH5j#zQZn^@W1iM@NCnP!I3uzjz?H^^0g3wLS}g zZE@u6A%5pt7a5SiLo^W9o_7jU*71XM68xXimemGAg^-h?MoS#x>r3@I@lsEOY9CCe zWMXZ)pXCsh*;rCs!$BwUM@z&@MU*M>L7t5ZVz4E&u^otwR zjo?-zyVR@oP_xy9--T>c164Jx>)@QM&5ZFOopel$Kt93TwH!-YE01M$Q-9G;L3%18$Gh9zvQg+UgWZ2U~&J1+l|g4R%6?I(fEj`%SY zU((bM-x_ycH*%Vg8E^{fSCA|`iatt$h+PVPBCj6%D>yLLp<`-%r9ycubaCqW5bYT>1IY#rpDR}QTVT&Es2xC^@5;WYXDX=7HRKhCma%_;G zn6BoU!h0rca$hpcr(>;PF`QDUGVBPzU1NrQtxhi%AnqAYW?^;inA-s1rG@*9wPmKwEVR#EqA>AUG)IZYYzh2f9@@Pd*J zsjx83p3@X^qSL(lB%{&hl&sGQ+iAt!2BDY_CYz^h)L$j5JL6!!DZ)k;S zYSJwNYmE-&1=#qoDXqu=?bvek=sDHq;=?K=YYc=@&Ju36b=zwr z=B9HR%~U;XvkpBSq#UM$UwUZ__^0sQ&Y?XXIi}o(KwvN#5!W4H4+<t7)pe^ugj>hPJs{%tJBgR$z7d@Br-FxwM1W5dzKOLkYNi&r!!15DIhcu&oY@ zY&%&5VjQyKo0xg9X1AUizk|-F2n<~&j2Ey5I!L3w!5SKpHWv1+ZW0Sv!yG^jp@g^B zgG-A{P;F&*(GEuONd$R!U;_OAKsUv-frBX(BNs7K9nm+iEp%19Lclibo2KM$qc>BS zceuY=O92zP8u|kK37+RN%Wp0K4c)CD7Jvp?n~+3(i~GlE49H zsZAiTGYl%_GuA*3q){QQ$fLN1$nYMfsLtBJ8Gsrwm;K(DfXV?1L#XR$vGd0?$o`Ue z&{XSAXftBN7NOS8y~I8lt}#{-VJR5LIvIe>*-t!K-i2_I)Jcg&liGNTMzT4R?8qGf z5(H<{H#AT~Ah({D3x;PdSbm(qA_D~!Y<})w;fJNq$?Y6+mH&PLX5XnkGQO3i*Tw zfDT%+xhG{=C!ae%FZzS4nZt;kO91eOUv0NaGl~M9XxsrQC_LB?l-=!s(y4DO2kQ$T z1d(NKQ2)t@&b6tzH-!V!YQh%JzJV6FV~7Vs!N!9-u(@PCC%=45uyc#&@W8)_Zc~MY z7c3fh2edRJ?1|)zrdF-z`}K^NzxYX7_;=2ii=}g2`$9Fa*WuRA z4-gmSa`{urC15q9g@B87z``|nu&$GItfQmHz!1(TyfWlR4Ce30o@Su-IfH+HV6YMM z+TeOZW+#2@#acpi@WQP3Y|_2$Fxjq#_0iwv)&$LLbZ+~WQ@RycKM1IT`#fE+C@G}(4qT4uf^{yT;zjp0SUtHU4Q4{HM5h|O#E?Obzz-A) z-w*iOt%v(2p~~Mv(Cb+5=~$xGPeow&;tLcoFiaU}{$IUdNPvTK0`)#rX1F8zEPdr5 z4`FidWofr9cE#kdP+uAjweszS%kQUA`LkoT3|wN{_@>)@Ks=d%wqUi3_h$!Y&m#zl zQLr5%ucxSS6h0vqjU0y78$4W{4QLqLuU8Qs`+uA2P<2o<=!0stI2t}KXHiKc7Qijo zwG9vW0wR3wUZuQ_Gn%`IE<)G(_q51hy&6yq@c3ZfxH9n4B+d9!HBb& z6A$fEl8U<+_Jv=>Fhz7%R{Lt_{%yL4XAPmPV>b0w?N-<@3tq)iBd~WVUlNGk4!Zz`4VGSloL^vx(lTHpzSXy#zY9xLXE2sgLUQCYDbv&%b~Sm0g2;wHee9SI zcql<^Y#BF8Q=26K#VPP9k6X9l2K2)9=;9I!ED$*o@_eI^6jZUqqF)=XG?IpyRH1h; zpUGT~Z)34*_mtI?-36QbG|dT}LChR#gG|U`fde*ua#p(Fl>LWPE%1-3b88b#(9 z`i0gY2*3ry{ADV|RfZv5y7nJY^};My-nHc`Fj;}a)IDX;e@1evFUMsH*~=*dEzDaW z6>UStwE2cSAr2o*kx7d1zpTMJT!ofE^C9WK38-f@Md1F)pXOU%z^}`*g?72vbU<`U)l<6YI`3U zp{EsW#ZgOP*zGXo3>R9Po>PFSI_9hp z$zs?{%FNsSS>i~q!K6LA?0j>f(Iwkev~`S8cKaG)r#Zg~J5-zYHRf}};5S~Btn>zO zn;0|06bpvu#wVNr4m1>6)ZB;jn{@n?F#7`ZxrMQG;ha$Fu8DS}n%M8nMAfjAwsG*y zjRM(}T#VP;KG=Vua@enygI~=Gf?w?cnU;nNTx#eTZFm8;Hh&0aqXON_awUGSdh|x4 z_@hLRU07CIuN1U=yx!Q!RRilO=E?+?!XcEdLjX2^#yiosZ;0jfjGKb18|KJ%9R9Xv zjGsU-oe?OE(6Xuxu7i==2-Urog#hbVxU#Ifaw_%R@z8ZoBC+cp77L4D^rq>~MVNL1 z&&5`3B70#(m4gv=GmNN;wXi7{C~P$jEel=DNB2}yDADtHjVn9AS|6;G=7LhXM==)Q zSNOh+&^_n|Oa{9TK6FFeL(I**K~ft6*zsUQiD14Zi0y*q$E_49waZay(vxH~&)zpB zBmJa{jX6t_MTTd>-gI*@TtxyLV5yA2x|V1x3zuzN5`^iTLZ?#q*XtF4jDh}Mv~FwM zg#=0r_)1RluIg}_Vh}@c6vi3O1Ypwrt)2}9&d{L34tG{d>OHa&#>Gy7X5IN)P(+G1 zxdXu^XaQ^nB=E8gHsSi^g#JP03c{d^K@7qv5rPnvT=cwJ){r+pNCf&eU`2TZ)quKv zp0Twg8rVSSdkp_0NyAMw?#PIQIO#yq&%S25A(bN%XPs1K|Pre94>xq}+wqE#Wp zzg80KNYMnEo-F>)T7+_t2g2RwD5F*sG_X9gicjz|KELRv4mloD?B0$D(DfV(0dEE$|8#Iqkiryd@w?Yo!CPSw-X!U1hafrfa!?997|nS*R#Lco=F;F;r!;Q47p zYFmk2-s%H$KWnX?hMBy0XPReo>#ueL+-UjH!72&J*&EKM_!a5vzN3$>5i*a6ych@T zM1$7(FELYRCyM>ULEpMBjaX#_UdN?#GV>=ewtEmZ8O`}*e2Mbr*Oe2^{djp1<9yrldbg$+Ot=;f>xonU?X&Uy0;CLhajaAq0KZYJ+NS z1G|c5cWb_KyI&wk&_OMfy$vBinOg=K#hC;bHL12Dj7+EBkAI9rj5rAV>fS^{$1v@$ z_QnO{IocW1I!5T2rXR}b(EC$x*HIjEpw)kWh`SP`-VED{b%pe%*2)icvr(Yb@4?UB z#tNFC5*!i!hJ_waJ0w1v;-G-1%beu~CyYe||Yzobix5S&636e5o&s5S^1bQ&y<|~E}_|PeU7;$ifnM;)h z>~fZh{)+j0eLGn*(;!FnlO z=yQ*CC#$x;Xm|%R)DY}faIp`)JablDSz0!POp5Frgwm;Q)6J zr7H28n8a1&MY(LBwn|B^1R#OqpvNF#{yGfU{)|6GDKcD10W9rNJoa$om4;aeSLS4! zAc7)U$UXHNrNxx(b}2w>xX%gTYKNLJ{ou?(_Rpsdp-WJ)A=WW)6g>CtK|y{Ifp(aS z%-{6@!;oLNl6p}9*-p$KEx8Cztlp>{6%wcB8nAA`4UY5x$k81w2i2pv6Cu5*Eq=g1 zz$TzP-!`?}^aHX5_S7=c{^8#^wy8Sl?otEmi4noaEIxC^+voFlI3S7IR^@oFis{Wi zD3wcbM%z!aUyX|Q6T?LwT2;vMd_bFvi1KAd4v1ivhxjtd2IrRsGKKletF*6wWBFXm zKWYF+tRLy7P8KHOfok^XFE67HGiHNODae0=hlnPlLCzw8Sc3m0{}Dm~&jEVVsAFAT z4H4*sz1a|8=7*WLwPE);x1<%>UVFBR2(6N4;F)>CKLWMo(^>yC^i|ymL~l^DIo{4L z-~!nNK{Jg;X{JfR$wifvbW?J$==5=Cv)L)vEWuTCxVCqRo~5 zbMnUQH57nY0=EQMhqyl#@CB`ij}#fm$z^Mq8m-6LD@*G-qmVb?2!gHh(924orDG!d zM+{ivC8SDWoF$E%x3H`ewl_g<%)Bb-&Vm+#BFppu-_!?{<=ywEQV}SF-}m@puFJH$ z!LliT{M*W~g0$JW3E!7Axf(up@2cV}rGmNC?kgbV?BV!jVhlbR4a!Z9ZF}W$Xx9RB z5N{0<`x9pyO?n753APU0Sa%n{f)iE-?y`Pa*q@tfEGZ@$QCQnGc8Q z$Cx02{7Z?`L}?xtASMhGft=k=2YxlTctO}NFxi1sn=K9`1?H2dVKXo8qvrpoa6%8Y%|0 z0oc-!fCw}a4p00zP=U6a7!RC=v<><#GdaR(_{-^^(E4T z+tKGBhn881qsfqJIbe5e*QULei{o9jH=*6&gH^K});*%Dv~PT4XOE`FVT(W5hB_3F z0$huYgsGTTl}=v+g0ag^f_om$H3*1=ZsDjeir|5qbG8_Bw&Tr%P>LeSN2PbRj|Ihd z`+;I-l%3t?za~T(_E-LpOE)Z_VAwFp%&O8RlknHpt+E@I3G#McEk5 zm=WKe#ARp0FGZH}QPE(mLFKj$^;00)joySfdQd--MTfaPq-MiqRx0xlrm8;a6-M3KXfQ?Hd*RU2K45avSDZMGggN$)(xM2GG zmqeNu@xWKXF~voru>xoTD@uOo3B-rM(%!_U@~mz#7+8dk{1}SmF9BmYw3^d+^}@VA z_PPqpSTLPxQEEeOP{iW+bo|T2{3h1<`C{x3mB80nVK^0T8f}0*D0`>3BdFdt(-BHG zDp-We*f$)_j*JIb1!RA}DHP>O$f28)ft|p84)38N@}OiXHV+C~Ry{l<6>A{?(>I8W z8nz}Vi3oJnKTtADa=MQK3YyFez-1|VHp+g-)-_w0Yt?_!JeM{_P?`>RQEy#b7|f4> z49L?lR0A1y-s-y_Yq>s854-9sr3T|(<7RMvsix#RU=I%N;A-IUv~tr>4KwNv6C9D0 zbtw=_ClCmO36q6vzU<-tc+hXNe{R!%>D=-(nt(sv&kEW9@F;c~7OS~0?U=!j5TBY$ zL(8mB7~W#~1VZ2EGGm<0e4Ywk%CsQoq9~mm^Ar_$%={Bl?5Na_f=<%NPbK~?eVyv$ zt=)FP$35W7%bgN~23tE0Le ztO2k-;P1jL^T~Fu+>>676wKpW8wQT||ErB*O{-+|PuXxl%r|$re$Qajo>VK2KrN_S zw#ee`2=U=y@1{_j^^`BmiK63b?P@i8$0$>Oyxb;;Zw=(SINR#4QCecA{%i2xjF7I{ z-ekKJ-baQcUoZ~eS`gLhs#ce+yNc*vIS9uKK`ewu`M4e0HNMF$bk<{6H4zfRrMF*! zj2_V^16|MpntIZt#_aIB=$_dLKiL&33E10`UPIv+SR>;BM_B_!%2y z7F_^)xk+Kv332YFv9Z&V9hU;~4bq+2?Szfr&@Z@JPNFd03gZs{*PT6;1QV0t-ib6Q z(*!Kjx)1+lCnhL?5`aix+@++L6gviON#;dW2>#=nt{I`1fcIN-yI_hmy>uZ?wITi? z7EEckv2P5TxI+`CIlXWOA((X^PtBsyUx{Q?>TeB+;Y{jMs9Ym5ORFB99x0X0jGV9L6DdEIO%|_2lhM2&O=C5M9 z!IDBqznIyr0K(1VXy4XZEa`)0R{2xYlzEo*`nM3NQdl%FNNK22h>*uoi{V+JX$Jq+O5@V^L z$VReB1Zf0bX`a8QV$pHS8Sdc;9Fy)r+U+M0fYIDI8@9zh#=$3^j1V^ym#}u>jI{@7 zl+&c<6n*L!%tNAul0N+`BOOaTN{8&SzxOK6tiasfK=K_pGS;i9@%sIqR%fkjJK zMEp8|Tly!aZb|gV3%?e>y)LA<$$nAV(mm1TKg-{*F}Nrsp%(Y@^s(8%Yb~Vv{N8{T z(rjQ#qS(6q05n4#nJ%5g5D;rxlN6L&w$riTcTHuD!h`~LjH zaV^t=YmP^EHr!a^+PGxL`r>q_tTid0)_ir^AwkwLx_9|!xy{J<==Y^jSv|dxsLNvW z@*_Nw7;{kwleP#Y&zqh46Kvj+F;AnN!aw>Ug7Ady{}nm&VtJzdNNb>8@$p?tN2;Q| zhi`U2k(hH8lW;T2(PD2;9ke3G=F*sDN9PY-OxYl;ExD~({m~@SoP6?+y+!zOnfHki zoyna7*EPb4JEo)LHIv4TYV&$OJz1gadcM&1`qQHJ2lh2h#|{nqXveoZyKh&k>GG=c zU3It>@x9q$$CzrcZwqg`{{3+6z_N`+{e{o^dwgCd6jQP;*5~M_tsZ)uP`AHIPjUao z+Nj^=i@WtYgWcMfd*^?y|GVSdxkJeho=o=Fz25G*(tcj0t7}O_r-IK)`J)@i5 zJpL&>C{(g#m!)2GPTr22QxZ#Ktk;xfJ=8gJ((y}Pk&d32{ncJErIBD(Ru~M;<4gTl>^&pH;J$Yy6{x);lH`;n`>UrO6EmNsYi`9_B*@b-bmPKE= z-p5q=r4GD(Xl28ypN=9kr2L2XvK2j$Ht}eRxU;-NQFvTH#0Pr!WFn8(W+u8fuJ{Dh)zq`Y>P=B(d9oH-sGJf=l z!y<{_!=ay~TLuF2qWq)Rw!Az1_WY>T=oXK_Ri}i)vvyL1=XS@L=kkiglgbpD?>*`H zV6d$z!rMu<;>>{QxALJCX_8(~ni@ZH>@tjgx!)Edt$Zn-w>~ar{g&;k5w);d)r_=` z?GM*ViLJX|a%=SCrtu^%)chTP`j35A_WAJ3TQW=pV*|9iV&YZ8jX#Bl6TL3(+x+RF zoL&QmKVx)SYvanl=d0fpC+&G({Hfiv#JZrhp>|#NT?Nz5B>rr{lKF>0A4H`}Pn(UV z@vna|g^>Ews?(bJnWhiU^4`!8+4TX5OA`*i;l9uA+%foPM%yInRPvjL7Z)EYy47lT zP2hLkvHUQ_`pv1kE-!C!(!CLiI(_h5W4PQ3HN6MT`g>F9PrDD_X3hNm{-^ELq>*b+ zq)|J`>5J7#Aqs`?(JjXDrMu~bXZG&QZLyJ&6+BZ@<<~#1k9zv>}6*)jlE74~87cy(rlm?zM6UJJmNq2r zrcG5xfVA<(K%ll5<lMex)hz{Il6~*C~y}VHtVLY_+Awr`KqdZhONpzr_CU-<03w9DK`=+nFDv zqt)ebDie$j=$4+E7J;J#U#vR9d=X? zQ>2_nRYy*)KX&lMqnAf@;*M!NYH+%6>O=gDsinrX@T;nK?>DaR={wpOxaOM8G2^i} zw`1Y8%a25qA&U2 z<n^M_l2s7Ng>j>kDy-5ubPK-|*%m z$NxyGtT@Xuj7jkM@^OeUQlIN; zpz`w1tdV)k|0c#nX3j1tQRPJ3^xIqiaygOwXQlk^3(wMH3^oqyK3MW~)05>2@_)-; zj8+V&jwl=}Ja;<;(?URa+o^t3JGR;0CLd<1_trQCXV%~)q`Hlxz~SRF3~@%5u6Q-mP3EV?ma$SJb3Wbx36@sr!Bor z+8H&Ix3-uGS0FDwKib^*D_vI3Ox$>5&l&Z<6DhGlEw9^5@8ycMSS!{xh3-6a&*S)N z6@%9*>8trMo#DeCMNI)LEtz=xm3>z2ImWvzGSeii^O_&GPiNe|EE~JB04G-SO``tD z@QpWQZ7Ij=k9^_Q4-f2$sD=1R-V*DWpPPmhEo@zg8f@^xTQmoqEo);tDX)4)t zRsO^a_h#bz`tOgfne166_RT|is~%H>`1a$+e&NK*IM@3^)`giz)NxA|Jt3(oxd4?kx% z-6<&^I7Pc=^Ys4h`AI8>f^ZF=3%XAdjkZ{3?~E5M$hQ>{**0R3J;&Ll7hPj!c)Df% znSDz{SZSDX+aPt)WolcFF0-FGPGzyqmE>(#_F4aL+qO8QOlM|N8&6n!=i zicl&{Yo~knUDZ%#&t)jC^~hqeansdR|dve(?^>vl6%$}dLKdzH%KJde!25O zX=x?RATjE!Q(qCIBIS`vot{mL>Ae$iiMlEmcQ$o>ud*$0u+Glk1FIE-DuLQjok}^y zPWJ+LW(ulmGVbtEbM5mVwZ0|v$=RM2Ka^xU_98ZhnzCPSv$oJwt9nfHPAk$5zw^zxq$~C`=+igd-lq{C z-O?QOz6o|bYb=cP*t^_s`f==%>FLRc z)x}>*Q_vV0`D&8^MJK<=p_PesVPo+4lH4X-g!CmzDdb$W{?*1C zf;8E^?U6aJPT$iFJJ^;G`h18ks<^em-K{dz>F1s%PvftpPnHHzREGD-{5rWmnKQc) zEvgBI6wym3{T}N!eXH|PbUDBE+s*4@>ibWut#+TikGxUbyTxm|E$jLk!$-xuoVgX-buRWzo->bs{_TWN zsnNIA8!4wR<|*;d89^GfY~pp5m1kq#i0U}@`wQ;uZMKWbz;ClQ>~cT~9WU|=Y)jkm z>X&p0ep`gPf8<=X(-@EZzI^Um{uTwNhW*Jzh3}_>raTVPQsoBlZmSxa<9x9rJ5o#g9o> zY`8m~V$E*(e0cYC4e6)Zh5De`rjb8MJqN?+K8jRIACBGOp;QzeWZr*jQiD!Y|Du|G z)Pyu6cKHV(VfN>yDVq~r%k_8vfs~@esWIOtWuNYI&r$!|p?HnaEtOO8RAGqp>ePdK zZx)|y;e=iwOocri-tgl!zwFs3->QSggB!nhe&~o)O@4XKUc0YgDrUpiN5h(?*PMTTY*;m|xC^;g zwL{Kk%aC8y=(-WS@JgZWr>=@@y*V8tcKoPZPJfy$d54I-{tNzp(aC=kvc*GFkJT%$ zUYlKf&tWg!CUo<;kG^~Nak9RB5tlUxs?u%ID|c_Bo{kv&u=R}f2?hJdx(=l&vZ^s| zm2PBPtwp7t56)O2cc1NR?iAW(d%}EI)-q%<_t>rV8u}_a8rPhSq`;RG_DirSfdtu+sglEg@x4zz@J!~5m=~!@IacBIA`fq1@i#$hLb$ri_ zs%9c*)n_05v3V;wT}`F`A4k_5AIICoo20Ru#x|NXjqS#^ZQIybjcqixlg74f+qT~O zz5m{QZg2P5nfc<`o!Rb8wd9au=7HBXKjqyVV;rcR#j~HcxLd4`x5PMZIX5{HxrZ@- zVqjxZZyqKKH|SLCJ5Q5XlBO^kftpr@^S=G=ZOFXI=CloqY(6(L{?gG~gt%C9l%EI_3djAfmcJ(os3yD^>n?^3E(8@=>7cBmC4}k$pX-+#WvIGJ0pI@!AO9y zVMPOP#3G4tQe`Sz8|%P!$cJdH^$0@k5VZ8_D!)Et2t+ue6I}a7>C)l3C#h&$iHL)I z+#|;48~b-pv0ofvbut2ypUHfOae#pnV&(A0L#G<2?!4((i9cX_A|%=>zdTfb?q;a8 z9_1)zj7njKV?Wb9K(xF&NJ#Gm@^@s+pj#`VKN|r*Uo__g>@A5sI!OsE*0;tA15Wz~ zE9nO=U1xB0@tsEYRdLV@XcQq!M(tMM>}`7twlQ+d%OZsFlVC8{1X(r9*8%#Z4%a$q zitzf!(I1*Mx|2r(?x1e-^=TuWwS=yFYGSJauxJ0S+4*at5nXgUTOQ#VHwDb!Xj*iW zV}~R@yw!q*V^v^`ipj9zBFup1?HKDuxkK{N zzuR+v#}aIH6VnIaKtdFHFy)(UTQo<Pp=$mun-;@RZ!I>`7H#rzep#wW8ft8!0 zSZrR5@hV~y5;XFtt8;1JXA8!Ny9fImPjB!7VVJo`i<3;n$)L)9P<@H~m^HJR-0*~k z#ACnz@oKgNgZ>Fr4fE5cRPpUZm|ZD;_+lBVg40# z?z#C}nqR5)?!J;c3M3NlDefF<|1cL40?V_iW6)U=;?eU9rd^gqwPay;;uyd5k@X1) ziIi_iG%MY{c$GNhsEKP_I|K(6@qDj7q<1mRv+0-;?Q4 zJv0-I!;*fWt~q?D+)b;$tS9X%XtxO!QMkuE%q2w|z;AK*L0~Lc!!HzfmGSCL#=?X6 z9QE|0HJVGedyBa!IqyoFIrS+|^{M0l)&0uY<~3Z#Yk3NHBjfCcMQh&yGEylpW&c3H zEnPGYU8yH|(Dv8nDP(SSe@ngWd{J?+a(emN=YAdURYnBR%Qm`-|LX*W?6Z$IC*F`j zm+UzUB%S*5EDE{B&|!`!Z#X%?HBy836N1)Y!gC0)H#C&g zM&BOo>sIJxfIpY|X+Tu|UKn>`5^0j4%5B@3^3~8ki3z>A6|c}`8*y3Z`|q|fa8>

rf{i#KP8x+9_$)5(ICcj5GE-~O4M5Q(1v14$$q+oFhTD0AC`%nV~+4OnAjtnk;~ zzX_p`>4D4c6iKhq@1}H9c$bXQWg02LfZkHUUiaHvi(d$fa3dzeB$i*y*CjNi$z^@w zfOjlAn#Tx7WM+W9kLn)|ZC3UPJZIjTg72|4%kT70V%p(hQI&6`RFfD}DP;BjbBfNstR4r)sv>k%arb4Vp(YFek=A=coBV z9j>H%bADx#*c7hO=Gu8N!TtK$pS|9MFJU_(l^%ITrp|RJ+4#sa&3>9)WowUe7thf9 zUJpvqFWE>V&oInb`cR*USLY|90vxU#B-0ME3v^m+jgMbj><6_=tzbQC2*57cOMGsR z2DFzUGomq@xVgZ|Fo7C^w``y5Zh1FY*WD)YO7;q$KM!&}{4*inkyqS3jB zE0&~v^GbhYz6vBn`!s*~lM>OGQ(mt@Rw{h$4(TD{EBM`4eYczc4tj}ymcdUt(nd*? z7=R9p--#W)DG0Dwtb@e#l2G9+-;pfwut*Bk^J|6cte8!q-31JUg|B~(ae%y7@M|ik z$QAuYbM=76hbOwVu>&uVOK;1gKeo$Y_iUK?ZIe!p#|qmAthen-(^NNw-}-C3m4{Ma ze`%Pynfo6mt1Q|gc}N3Os2z%(Ojsi-Tqm_OxpcPxB_b7;-A;B348L~wocj9kQ>Hvo%SFOulm3~qvvf2aFhuV|7E?r$#3rf&a+H;Hh z9+Wi9*eY{WM3nX3rH<*Cj-}q}*rKzSAFrj6r7o5|;cX~$Q_Wz@W|@ifzzhTAYqBHJ zL?q|rY4rQ%O8s|LFGV`2E<$P@oPMz%nsEHMw7^`?bzVT<(rfeV!la)gnCA%pq8DDd zIyVCxtD^PPT!qWObD50nTX-rh3sMaXZN-qr=%%LF8yeV>$~(10Cl_rDx6IV{m@Wrx z6^G0>cQJ|P@-rxHI}; z3IQ#*8sPz~;MieIcOtFqSOzR>EmXqq;ue230}Y;o5zHf+((a;C)Mkl#^zt=6Dit+W zc0>22=YE{)hwq z_Iag^5#8S~%lgt?ZW5g-z~}Cbg0fi0lk*qLhimRQ zrdvDJA^a3Fak%C8(c27|D`s9Al;iaso)YE8j*7#=(I<5i@+s+Oy?UB+TbL^WbhCWqJY*S<(rvG;SJ`-lYRfsOicmmgc8BLUus`@Vm1$4 zr&@4QiHYmv!x+ixG%F6Z&xu{WoTORt|57qd`kS5H^(iyZp6gx$f1HxW7J9&8k?7l{ zh*{6XPWA0p(Q(FkfQ`oFpTEHePO%rD6{0WP%)=gT(xt@CeUn(GdMMJZRY`)2Hv zj;#=t<_^;id_{1S%Oz)JC2>s}3kB4(zCrHONa|3}{Rr)Z{zB&|dk?0dj0QivlgMxX zs21z6c?oK%m@g+E3VfNjcc@hX6->D|R)i0Vrm3|fckgu4NtKy!B4lW2nrQ^?%yNF2 zXi^?;D50CtA0vj6h?9C%gX4XxtC_G3zw68_mY}`RD|DCfo^@V^WxfW}M=zS45Mtsw zzhBy$I~@HvvOPhS}pZ$p8>B{-h7U4DG_MZ1u zJMM1h{AxKB!;mdahP+k`dDzV!8#v65uQ=$Vg~7q_!-^4@ zhK9CvL}KC{*vs7*NqUZM&8;(#4qgAvrazGMoZ7M}T8wc;6l4ElL(Seenk6k6v}4aF z5rr5W+pnod>t-DW{vpD_A@v6+@I&F}Bk@o;C$Y$BoWLGMdd$(U^&DkZh1H(w6R1jP zhy4DbTPN`GT(27ATE(5FBu--zc?gG|?^Q~>81szNYD9_zk6VlIuIYl5y;~JDy^rI4 zgr!0&Lw;jdVHL2qDwgGf*__T`RQ_YS(9BzScF<9{Ay|ZX^FNZ2xGig~+2B|1;rF`bpGDRC#gGQ;v0hFxnN|6B?8LIn+W z+vxoY0Z7uPt&{P?ff?jdn$)BSRO_M&v)JPEn)uU8jlizt`A;e07HU{P@FJLi-ym` z@fMi|r9{oZ{U3U8&)Z0bikVVkT*mKfUa<#-YIen2pjpL|mthZ2M#r{Rtrt1PT0r7U z-+P99BYp&AQ^1fUGr2fZS!N7*k5A|C^|OYkL99hnOr@V(7TA;q&kLz9{!0d?w7hXv zM5MWY8uZ4{7Qj}6(kLQo*!?yT)FguDS!LDgZtg9Pr_!fA-@KBP_cE?(G~Io#FiDpa zhwWLEfMJ$rBot3r<~4)vLL??nT#r0TJ*V3QCBI?|iW_n=X_HMnCWyIN0e6KUDYmLY zp`h)G29@H~F$$F@B@DJal?_9aeQn;-ufA;^F5d+I5{Xs?k_|^?Ze!g?Zk;4pguvgm zhh>`@xTNmri$X7RlB{GQ*nLG*uobIK0dh?cfLFS#h(rBi$iKW-3EgSZ!fI1sn_--H zaP(f-%rue*ByF)?e#9PG4=uSlUT8rEM=U3!I{kD;6V&Eg>oOuC$Z-TMcNFndktnWp zFkVOGepnX+mQdq!I+sT%D95oN>ksu<@$+S%^`GLz=P!S%bL+6)o5_Med4mDGb80cuk*b!UyLqvEld5fpJ z>((9ZU8H1a86d(8dhkl&L)jYj{r{Gx z!*`+JClMzdu?; z?Z;EV_&UkI66+RniUPq*0L4od;R0qb^aNBeTWlZwxM3E5T4u{1E zpYZJ}t>EDgd(F2641Y%6ZB=poH(|FDCu9>tRey@H_DhVgP7?dsPpd!xH05)Edl97w zd68{Yf}CLHaMs^VvK8)q=vztdYqimW##@oJWXGUDd%;tLX{(1aV(0@HFWIKW9ccE@ z?@oHJ%^q=W0?GSRtJill@;|ZFm+Qme#Rz zQbOMk+biC94>!!2&VySO7AOPpJ0#gFqAE=kw8ZrI%h{75`FO{0>4zfquQXI~B7-#$TN11q7m%`_jTKY1oE=lv@7z4xtU1BZ+r*itPyPcTfhd9uQKq&TgAjJ-^Xg;aMoGZOcuZ6M)!{ku6Ml|%rE6l(frtyufJfu%~Y+5+k(WTB5Z;7Y$jet|eQKJX?`Sc7IQ^VgS4 zDDgb3N;osK)|;Byr2s1{F8FZXA8b}z#KLa@tI_Br4d$3K%(le&jIQDf_Oo z{JWi7{-)lczS7kgD=Yk5@}xKUFc1ft|KUZYhI!x|=I1Hdb*^q@Sz^ zpiT!v1QRKI>!<$?C#h$Dcxr?0uZGMetZKKA&X_K76GFvjQLE=kal@fDHeeUHQu5Vk z5=j46Q@!u3?dD|>X7Z?BYEQyG?sjmCD2u~Y*k($x^)=zZ`}h!=vuzkHWYfVoYCs`T zVN_^qN8PrwWm2AeXpznQm?yZf_2!%pxGQmXK=})W_h7Ql;a8G`JIge~$fo-99J=3C zoKF;KdDu`El8=7qYUo+ZXJj;}2z@V5qIS68Q#ljPv09 z8wrZOzgiT;rj(pr5AMj!7gvT&V2m*j;@Y|EEJtfd0Q=_MGVAn2IkwdK@<#EW<$$cW zA*lOQu;>acp5?oZ0qX}iRAr=la$gmP--`j97yD67` zj4|CC2b16aG0BSj88EvT(p=L3sU zZ-GS048bTmS4&(2c8htsL&4>Lv36YgG^#b+sD59T^RnbSwU`YRlf^Sq!75-UK=Q;Q z(~q?5p}b^#*DwE>+$;w@F8xD3TH_0)r+Xb*vCGUj*e?ZrsNb=`&)@<8bM zl?W~XZ9Ih5aOMrcLqlOV0}qWA;ceNWo*##?nMQa=DD)fIA*nZ1oxc3N-ahzDKtW~x z&n1-st9ILUkuXpVwvX8SIqR-m2)U8KCOGGD{#TwUDA50RB*%(R!}%+-#S~~fAE!t9 zr0d)fiGR;P7S?#@;(oy(7W8Z#tGgty${Grc+7%<{6f#mLf?6BNA zf&|gk6xp>Ru>f61ubWpBJd=w&CwH1b~rD| zQQ;f~vj=RJF%L^x*EQ=w>YvQ81t31lR!h*)A{qZG|G_%X*dVe{>$uEtrk>~WM^z!f z;32g$plZD{bo{-yW*lEV{RTT3^FlM%WQq;p@KOti$3yb5-xx=4wV8|!X{=^ABkOa=rFsG&O!6eJ`;&?!GbEtq{5`dD1uX6wv=k3+I(u`i-gX zrLy;LEyJrv%}3Qc3&ld$H+tJn!^;%x~HXlWtKul1oqF zav04V$DKYF<}&j{bHZK;ShyC7Zt>XWeIXh^o~ zrb3J44pG7MwOJbXh&<2_bRZwR=|Vpu%FjE0JWY?h4Ps0R=D_D_I0&u0#c!+~luCKZ zGNnUNe0zfU`Y_HBE_8aLtvLF-;JKXI)(QS?dbMPskBDB`I~*DmRu!ltUpe-RF!um< z!@Lt>%)?{oksYmEk}sa1FW>XzB4e3G9yv3#E_62{HIT)ISSF+*s(8?`8878 z_`h2({++Z)A~pY#%&h&@WcFSWE`b)^kJRY*tLWpdC&R4ar>a2yx<;qwtA?cA4rq%` zxaFWbPAu}aAgiYOh&d_9Ldx8-nhDTnwmclombXcL<-xx1a@K(Qu+7CWz)Q~D;ca<- z-heQ+Cr~clEH>_WC#>ChI@yOn3tA>o%uO2mA@b(#AL27d zlHR-Awq}f$JjrIJbmCD>R+*f8;Mzua)s+hns~S*Hf@MjA=x_N|C?g;5XuzTEbE-Ud z!e;LwimB}t_0rtQXos~8g=cn~kJpyirXk)+s3VjKC*xn%gDTd8*~zE-0H(96zu6hX zc=*fogv{?NZ_lQqlT}+Nr!u_Z+dwn=C2dM}ate6s;_#k`6_KZO<^^#eya^cFmu#jt zRxLjv+}gSxl=UfT#+GS)Vqo%W3oYxXCKbE)6MyM`W*z)eMq8|`>VPcmjGg*KS>|t8%ra$3&+wV1YF~985wvfC1wqupAf%ML7 zl7;?b2!i-rn5MQJ?ly;OXFU=w{>(mUhA2!;bQ8w%^k-@tP5c(KynwliJ6E67wORYb z$XeF&ga@y-j4b}4W7(l;Z3=;Dz%eGTH%hEOy!qhF83N0CW&b<;OC{QPe$DzZ<4DyHu}PC z6Fpbi*gAh~4$BW+@>BTgOjJq!l|6dYro!#M*#tF4K><05E`n9#_4e0XBfl|vT> zh8XFI&ncUZHKrFbyfN3$uLntX&s$4WClGjJB9fBdRe-aa70U_;zScZk_~EdCc$FtH z$fv@2{D_VbdtMDMv+^sj<5!GeopgrzX0`ks-yCG@J4(QW*=rOY>vQfbyze_xcWur@ zPX`ZIA2g4s>X^~<_ZOA8vy$!5R-2~k-_q!dd)ZfzCjE+*wQhsae0`LP=mg6Gyn_aa z`3*Ly8cyEdt*FX%Rt)R%oSs;|u#+5$0Gt;#XHT=;j;tjg+Aifnd&8_VOSghs@ zD$;q=&&;#UvSy3d98!=aqBu+* zTPB$Nh)4J|dj~P~xS|u&VQ$gw6~dT9=Qykz+N(YZb}*YpskcAIQ%dB};#azH*#bm1 zs6;Jv!f>q6(z_Sa4uZ+!InjXR9{#eqC< zQ~>W8jDXIV$UlmRay{RqeC{=k73?ZZg96VpafZ}33QgR2#fEk{?@}LeJz>bLp%Fpf zGCt`%Ga9?g73$kOLgB+`qhVm@RzKz zeMjN(uk)y;ChkPAgj02Jj&})^w~SZK8c-J~rFC-=mC6^(n&0wjsO}?9?=*TAa04yI zMk$r?w(N(3T3&MDN^y3+@z!k+uy$s{ zwyuO>I2<1fPMhz`yh)~%XB>ssM(l{5G%+c`W0-5cLjTRd`92w%E8r%{f@WD`vL zxm|C#iB-{77&)NY5%f=Ky}VO_Bv?&dREN0<=5?$?bDk?NI<&?P(!FB5!XB^a1qj)B z#%;CyyPPmye5S{n5rX1pkKKM#MD6?pjS~#Du_kgEm(p+sfekIOIZ%` zb79=t2i@>fDB{IBc;qz&o3up>o-0~9LzR!5m{~{P=JqWIe2T8R22k8V6N@G?Duz9? zRD3$y4*6aWAqf2jx~$0u@K{O-nJ^U8G+P6;2w5nxzy(5K`=gR==`Awp_6(?cQF=VH z79gB;AfmGAlt>d8+*ikDj6EMJE!3XDE1);>L6QF$h=>1DGTktj*!NGliX88?afUQ` zm)$xMHJr&fl&NUv3w%*bqby1(G3epesu}elxdT<@(kf3t=++U9-~jD(d@_xNwddKr zmR815%9e1VARZJ_54Nb@UEcG{-_6c*c+`;1U>o^J_FDK0OIT%{5_Swh7v)tElSfg+ zA*p*bYyitGKN?ukiR$2#v~kO?9yNQn;kRgky)XtTIHAFO;M3ORw$tVIhb>`X&s$>1 zTKP6>RT9`?eh}l?g#s=5J!ft&amusBF4g6u1u{e-CF37{Z zwwo4>;lP!2-7=ZjPwfF7UUQI*TADZe9pASs2Y#*SzDsU2&~R45<`jGpNZ?9?jyDm! z#-oEU4P0{qOBt3DW*{gq?m1v3HcdRR7J+`v+2Fb2rbCO`q}Z#~e3lSOi8jN(asqv@ z{&(-eEcH&}hWVptj>%@$5_WYG(}6qCUBL07PyxdF8p`K$v|cJyx}Jy)ow;}R%vh9?5hycl^|o=RP_?$<0puxgh+vI|X?PFyt;gLbP0aeiLV)Jrt$ zhB%p@YL6G4^!IJambYJ`XBhQw*9D!^EKJxCbJyJj*fub#z3t6k#~md}kATz2?K>_S zm@8^f1g}=^J=EjlYF{4KpMtR+H3Xh_#JoPNwy!&&-8ZQF76BHic5knO6Dzi^xWf~= zQ!n&xLX85qn}KVtn<>zbBo&T=HAhcp@Em24Itm0FURPs*2B5<2L(DcFkP1C&kdfQu zQ^-~?U+2y+t%z@fGRyQ&=#n7Cnv2}3LvTobGAEVm(RTrYFb}k#gFzNU3@>y@kH$6i zT50bZ$Zcw)K;Uke93qPcI#SN^=SD5N?3ED>ROKRLBa}Ar-kBZ4BO6AP$&a6@aCV62F6xGQqkS!r1N}e^H%<(E$#3%oHhIw&VSiL>cr0eNztyb%bX5E z2qjQ@yyFT+4YJc7cPE?iR96}ITsOv~GaxBO&>BLx1t-C-0+f6CSQwCKx7Xs~vI&gY z%2>s3?2z&vRkeo5|$c!4~7n*29p-Kp1;@V%xXS#i<$`L)&N>TWccPy;5Q{M36JEd-+#w> zDiLHUJTo+ozdE8g13AU|E8#)U70(95qRui*47)BBfFIjl2KJx;-QmBEs5EuJj}`Jt z3RH*y$szT;0d6TKOROB5DpRj$xlCH$>1;b@b&MkWL}sYn-3EOaO-aEJ{#T<@lhd&* zp-uKeV_#%xDxmWI27+aPk7lpl_$v4^arNMt1a^1DPbpFt!-2)>Lsm37oqQ%ex<0-F z)#_7hNLtpBRSD|+8oR`lmf|f6e*PK)0l`n1)8oLRV$vyPESOhiXq5mrwz0gWZ75f{Gom>6J&W= zEosrx>C-qEo4Hs{EJ+vd^1fvX(fa9_eOt#foCU!vGt#xNE;!KwIhNO*Re9fqr~%a> zQ7i%<`O|pf+mc%x68e^61H#%*Py%Q&QbTcIXRUGW9@9YSzb*!8J!YrY`0}6NrV8Yp zn(Ueo10jZB2NsH6u_E0G*q<#ibt20=`xR=DtK6v_zR|Ia)%Pm7oHYl^5+4m#_E{W1gN#tRyOo>%H=3q@EFcv1If1hm9GmURU-`=FyZ{ zQGiPUlpzXW1E2gu=8$w~CR5ymvj@*9Y)&eG=WccoUgPxG&=zh30egY*6C)rybUd`h z0zENqOGTgqBEdlzA zu43N7DIiKYFebE5?9h^Yd3Rko4T1`iTuzr!v8Lhm_I`>mi$S~~bNI$in!N)HTTZ}e zBj>(rXL#&Wa>zPFs)$x*_Z8$@rGcPFi&9A_Bc2xesB)&|My3KfD+g4=vtc;eD^mm< z@5))iLEv6w_7NHLimJ{OAuksnGQs{98Z%3?ynab1c?)o-Ci_u(JpaH+cKPs*{L04Pm~^x>4hbE~`-mWjx|Kt?Wcp<9|O@O ziM`}eG^LNyS5Ny&KjWcCti_57*W7uQPJ+HU@0JhJM4vK4>WS_%NA{mTL4P>=xdOVu zE!O5)Y>x3D_^mSD!VO&0Vw9$Q8EyDb-iSfmdjB~ss_hE=#a*W@Go=k41C;;|HZD0C zw(Fb`DJl$}G{SEV%kn1EU>_|GuFJ=+4+2F2dN9;>-i6W`1QRK|?u_U9_;-jkJ{J+tk?1tdrib!7_LG>$rpv`P(E zF!5^i69HD*luCwu_2Z6#84WX0ztW(9Y%D#INcbR&yJ~p?E^`KZ zn>pUbb=;e2){EOGsu3Ljh>!l219M+j^LOnPGP>>q2tgLkC921?G>5YrBL*;D0gwdq z48%*^&9WS6KQ&gERQoli@gH&_9En%a&Z#N^R9i0p!KnoCVDc!Pt1a~-E7e#FY%x1@ zJ)f*nXeQTw#j?Y*Uo93;-t;jD84ELrkwDB@} z8f1=wUQ>ab`POHWcA!>a4!HNVGSN1U%_?E&5zo4xbtYI)eQCu|6{$#0l{tJgdUX9+Q{i~Sz{HRP8vNU}dL6yVUT z(pWA1YRY|UqbvgsCr5L(=i{rr{p9H2^;r~7X}jwe%don<|GP@HA#=1!L*}VXvk-`^ zB9O~YNa@5LxDaWU@Mvz0v84jyW}gB>?&B*nr@U1LUz*HPt7}Axqt2OLm}tgmZ8BG} z;LYVCaRX1Jme``I%Ti54ycAFUk}aPdQo96fn*NlW0pE4W@C)UH7VMk_{4|jlB2o$s*>Kp*xNxz zIXL*%fkoD-)X0-l9(vo%`87#1q}c-^sW-pWlk(gX=Gg2TWwx*CSfwY=H(h~!z_}T4 zzg*M@&zQbJ=uj>m7~*3kd|p-mEA(>=zV=`^=(%M90)AG_5~Qx5_-qzufSrx$DDT@y zGy3_5FCg8q{Uj`CQ}%fvzRf1Vvzz#zwF2_e7Szwa*4z6A5znciI?N*cYRbc>qwD&&FuGX_S;JrH@jl)( zL!O1;u?5=g!TZdTi`0so&f3$H_;#`mG5H_!ZVJjsBxB(Ol4Ud^`eC2BB%-~*xnv%5 zBkXv6dXqg?|JC0X&vA1VGQ)ZPDDn-HFKUx3+R9( z6g)%00A(Ox0aLrc9p!+ol@g1Dq1WBK_L4TWz0+g$R?;|H)UJ<7QNeWHy2eH??blHZ z?p;DQB^j#Yg9W$8bA-s6^SzNfYQ1#NW$bbVVjrp}R|zdVI+3yZx>c}J#{AKinr-Y6 zR8K)5VEFi>8Iytycb8mY@}DrMpm@oFhC#XQ{{TiK?IWTP^oR#d-=YI8uzuzN^M0vs zo#Ll{K|+FqgcuGWp3v@Xo6xAYR(>wHv_Ya|7*jq|QbF&XLp!5VV(68j6H-AjD#(&B zHhsy$qJHAPeRhV727?YW)Y4 zaKQpFWXol-nWBA8r|}u3&oQt?+A{N8>GBw0?EcXezYR`{ka@rsxOQn#7#>5OPWn}D z30PqdIZ`m~{gQMv^SnaP<f*AQ^MGPY(V#o zUI3BDQ^AX9j9WKEo{T7anb9s}c#g~sJ&u3dNapARv+Zx>85K?N_((62<{j<)r+)Z! zXfjWNEMrZ|E3MWpt!(D2U*L6cc|%X*qg-3*n2?kDIV6R@VDzw!j|N&ewN3+B$1e#E zz05za`?{dAD2yi{{|OC^YxzQCIs|N`1h9k`SzsgHaOUD5GLD?pO_@cpI9x{HCkCKg zirQpomT`!r&FWE@mfu5ZEa!s?n?#@m^U#nCqCE4J+7Cb899T1?r6^emod z;R3{;WduVBn>53Ck*XJD*(AVo3s&KvBBhgJ&%@~evh7B-q`5%2aY_`gw6q@nXRf8sp6H5<<}Cl=>jJ^U*RH{6qp7&$BXa^#WdzsRI-| ziW(Fd?D9k2<4aPXKTJ8+L8kJn*K?)*HQ8|Q!9q( z9q?m!S^=uj2F-y(&X7a%09grq3yKZ`pi;`qj(qsq{*P9Cmjy&(*i{POjffu&{U326 z9orVbWI-(dwNB8c<%2UAYbst=G2`aO)l$|9#R2eOMfcwsWs#XLuCbNy^#ArH3S;sdQf%SYa__sMl3QQevN0VT@7ap>Uh}i;GeL`+ zh2a25u-<;TSoGLx{tq6NhK{*?EhBv%EGmF|JBUbf2^m~)3~P~F8Ep9AFPrPY0uCD` z0(sVDTD!Z+=36eIU?F}?W+@`K@@Q8!nu8;STM(cR&0Q+j`5#Y{8&aSA*ZlcO41%8x ziB${u`4}VghtG5*^=F;#osD3%A>oj-g<6z0p27mPrSY?N<)Lu_hgZuH1AabUiEFF> zTuRVRji$>dhcSl_NY(WGkr~)1y&F5tHm{qA6gUISy_KF8$JwsvG;**Yg5th$}ZaZq`xW{an`#`m!($g=h`Px^5Z z$AoA&`R>AR6=VsrP57U~TBGH5OD9=|6J*i$TIHkjV0lOFKZD2ui{x}Y78tbOmVy2`M=MdsMzo|ZvtIuzpwJ`H=Il(K{!>?pn)3i&+2 zKQ=zl@lq2Vzx0Hd|K^jI`McFpyaA^f^WgcKejy5q7Ek?`Pe;sZVZrlCEd#1w4HoPw z(OwR@p*uOK%ZY7UC}1ZAs>UGC$NOSsFg}4C6Mr%tVvNy-wXu3Hd` zs-dUCM>_pq01_eX-sg1(%2I9jB>f6lOpSe+P@PE9NKg1Rb4Y$k>wkd-%h~&)klVWS zq|x0v+TDO>>9vGopH!-$*sMZFGu>xB?Oecu(`o#>Le9F+%xsbwtp^5L2EI|q&G6X0 zh8R!PdSKxw>G30k-1KUg$;vyl9$0t_*2GCdHTu;mWy5*de}<>I?+w{Bt%r!dQETXr zFzw2+)f#L6gkoX4LVx?;h1~36rc3q$sb?&xGdSfFY3X<8pb_?q{6RGGX&&LN%Ibl*w^794N~HZ_I>Z zq1^g{kej-)C4Vtl-?YTILCe7VgxoYLuQkLd#>`SJ6OP@Z^vIjz#O2wQ?Xx=Sx9`NT z-#&NfL(Zo9zg6lP3)!$ZjTPjk`akKF#Avppp0Tgj61IO+$aPn_>F+D*W`$D<_)T(O zuhlNA;P1Lqr7};Z~J_qS|evwHuspx@P9w!iEkNrhLrie1-~ccYTWD@ zMpt`@-aOFPGVp^!Zg(|PXVw{wv2gh6_@ji})S0tJ8Fa6|l6uC12cUV9P@Ps8@{o_D zRm`0*4|_7`fv0MO*42- z7CR3VU@?LF%|dSaIj-@_Vx(H14!4XqFXW~elZF^DHrtAi(K6xK`ATjpX=XO?hg1gO zRxJ~b?ND-B9!pRVj+zO@GrYlJ<^Lk&rln?_httqKvW$f|XKR~KjahkBUSDEt4QOaW z7JuUrdM*C`452#f<&7g;FU=KZz19P-(lX)rSA=S;Fr&@Ny1iSLWS=MI3-F0rCTzY% z$kBkt<>ju$JN(;<=W7{wi;$Bmi)HukvfMi34i$s2^=6^N!Ll@iG|$$0;F($mzDCH& zw%L+3&7f`6U}3ykuO%FNpVA{=B_}15d4Gg!zUgIN@?>!Vo+4#n<5z?n^)g#dTPnOa zlIP;KVC#!Qj)pQPjRyI;b}!&F^jgC9tA$*TG+ki`^mY|UF{8$3glhD#Q_a`nj_fe3 zd-ndgkrV64!9hiD5;`2_=#!06RGgy=+W^K-6RM#yA1jmFDuy`n-HpIwv`pCiihodz z7Fwl58gsgSg^0nZXa52l|3k>p>DqF{!9J;HJX^0NYKWAU?G^^ zdbW`37Mkg2ev@`H;Ck(5gzXE3+z+RlKIa!`y8w^TGVr}Zj`^I6pKp9lFM7O8o>%W( znc6m;_NPOzz$YZ;$30=$#e*&K+kdA0en?j_kEfXh5tCm0xZ=f8Fr9!!Jz#ITAJPBy z!Y39l40_45-(#R}q!PZ|?}PO6vj)QuU);wRQhiEDte-OJwd;##C*s?wHe?=1VLA;H zkY2yp>V%~a(svX2EHV8*2_j~;=Mn{Y9N@h!6^KPi0@91mEM6QYG2eHWcz?o=h$sw( zZa)(>Od>qzv^O2&i;4LmZYB(3+gC>st^!A^_UR!7AloemJv>G55bZ=PL>CDBs>etV zE@n>Bv78BsnB*cpVd%a|#F$w$&CKum!faizkFG}yO%6uAFJz_{`&BLEcky)mE?SD4 zDMbfP^EL{rKggF8Ptb70=zmjPX0~U=osoIg3Sr`dtYajmE0~86o>O$I|xB<$hw5f1|Ha5N!wQ-5amFUL)TaTE3N zy$Lhxms9ucGpCNia~^$fmznj;X-0~{BA<|$-|hC8S$j#q^AT|$BZ?TtIFWT^2SLc< z@lD5k=RP$LSmi^Hc*GLN&?S~q`x03@7C#U09wsCb(f65IZzkgQ1n=?X=!1CZQN=?K zx;&LaL>YK~L<0M9#eaan?SjXc?uZ3+FM)5pIPh@|I4wiW(94LdD-61dtSm7vFIWdE zo?h7FSpuA=RJxj08lsBp{gh|_6tfB!rV~t*`8+)|@AlBciA8uA5uOKA)mQttU*NJAVO>Qd#t9F7U%Rv`HNF zdfXX%x`^>4laK%5^%^q?Sb`o;tWW9&k$uFWOA+hg4zLV#yFBdd{nih8J`8auJRxB* z5N7R(5nmo*X@;ouMEZSD#r#PNa~}*H1uRaOs;<`8E?Nhi)fr-G9D}N4jbd&mevBBj(>)s9yD}UBGekS0#W*5^k24)`^xC3H+ ze5}u_P{hoxH?pDto~@65fUzHx`d5BE&n@7&z8hj;4D*F?SkFvERmh%V98wnu?ekX* zg?>7wg*@N~&J9b`U(~aYX?&M_V-&DbjZ6E?^!l@np+w^O3;~u=@E$EQMD|CCNsCy( z&BfD8%zvzEU}FJ*-GJ+f#R*oi#5%*!WZq|_z$Jzu<#A-MAT^^fwVm`0@=&~TI zsS|Vm5Y9723_7TK?z5n<31KP)P|w4VneA6n+<#FT4^+SqW?SAq!;g@kV7{i4s@-R1 zS98*UEymow2=Ew#AbW;qm1jlPM=)9N|N0>N{2X?9=yVH8aX`~3*ia`QjAxz*xdlbx z!rh>yg6dhci-rf!dP0w8nO?5cm+wBt{2A-LQ*WTpb)$+Qk>VSP1(@gpEZ11AL+exY zdw*iI43tHvFTP)GY4%w&CJtMKSduVRUC(lY2T<9-plnncFQlhpj1mt}fYFX;)3e&9 zK5hXW1(pChPK0GN>f4q2h?|wUF4Ck#b(tMZSA#zTvSt<@4Rh#fNo*U05qEX)Y(b64 zekQVB%)OYo-c$_BG^}dd!Jw5zuip(oc7FwoHC}L5IAWfK17=o*9m6>i?*Uk!bfBc- zHnMAdbT#P8eJ1O~n6kk|yoUnJs2-dS#H^#q=Rwa9c6kJLG2NxiD)cEh3nS#|ohSMpo^4vu2huK&kuGffm<@d&UK~Gn-<9sC&;AJF*_ubclrTHk zAc-Mw%-Vj;+J2Hm%qms#i0#x!yK+JnMbfL%_JS_YBl)BjliCsITF3B$iFE|t0bCkm zv4p_=ikUUU1O<(q{}o%p1fKvf_xW!$cfx z#90aMLED7eEzai+V=7>0P|6xUGq{}6su7zxY_e90(I4zivLNAS46eS6ka}=v_pSy( z%wHVimYD?!K3w%sf*|4R6J65iN1!<+l}Z@9V%b^41)7&=@gcIdJTH!L=zmQ!^D$TZ zR%I|0#ev;)=zcw(v5Blgs;&{R1DqKg6`_4hM_o~;!fEzA2fWY(%#P%^OC_J|P zRG584_xYNBsOkVN4FhKO6`n8i*)hzeZXdQuziK@6F+CEqMFtFyXUN|eVyOo8Xm0GK z_NNl_a0h2)BZ27l*?Xx}t2-&)FtaGCkRkVba8YMe{^F?MG~s#9*}E_L$iX(UT|*K0CN!rATJ>73a_xpeID4v^L00h z`pl|kR5pUZGZ$@2OMhCL8$;EW9~*q&J{O=@U|vh3O3C4;VxD=f60(Vt$gaovDJwMG zonIBXldpwWAB1w8|UD*8>`YYXOcELgY#(ylDR6YHWHAV0+VWpG? zQ2;tv_eKxw56tj{mASwkSD`7o&)iStGZ9U_QDB{>X|eBvh4^}Cl`+D$ajsYlyRmrG zfNRJL)?V&W9h#q^p-2yq=pHPcxFX(>kHu^j3VZ~d4&M1?%=?2VGR+eKvx7Bqrl$`S zjbR!k?Ugtj-vGH?e_kk03(!)x*{x9%aPq zbPU#~v0z{EVxJW`pG~A#j5f4Dl()dJ+bQ=qOLK)}R}&p{(a4W^4vx%K(BA@kkI`T=9vd4By}aU z2XR8tz(RkZlBLkHL+i!4A3R%tF^`13s<=jG0I)>>I}JlVu};WYPZVzz=K5~H%sMA< zY@N9}DSv}*7i4|beeQ_;D9>1lu|P!Cp&|Am!qtm;17@s`fO}Oq20yJgprNM(DK+_O zUO8z?XB>E_0$v`f)X1RAqoSMS9%zIgld1>=TQuO=q(p07z^qbio-V=pqYya)+1=JW zLlTEM#@cGkewm8-#^?FQXY*j1!w)e}I$c{=$bSL^nLR_jpv%lU5n$0M5g=2Q2r8YQcaMsKQ_toB!9yI zIf~XxL%!uO&gQ$2ZaL~!`FZ_7f_b5)c=qTXdX*-Q&#NUkQcb~nv|9G6ZC}>Mz_WqS zhcOb`he4Fcc;*qxW7Ut)n$aLoJG9dHqTlPZ9`#wrs<3tYd`&;jGgEw;xR_bJ0(oFJ zSKSfl_G5b%tIuf{ev;_D1OYPk4u86C1XW9~-w(LgAc)5$;(rNsh9qC| zs%`qN{6IGCc46E5Ra0pw4v8?%qYG&of%N+L$N7j@J!D5BtXI=ZRLWXs$0YnRI%z|* zEGw3S5eaRME#k~O7IEO$ubj7INj{?iAnra|!=ZdtDaIiu+A&wfH6_C^jSuc1;17c5 zSv@IR@l}o!b{3&uW$_1}$$##v}_E1>L79Qsn^M5Ks&piNH%@R#t zL@rQU2&hok9L1R%Htvp z^Egg~X(F^chaz^%fv1?T5J8JLwWmTG3V3~EuEWnq@EXiM;c|QkJi+w{=Lbl@3;Onf zFp^p=@&*eQfVv%U9-;53%*fYShZ2mlxHbyJO)sF5y ztG4}tYMUShBeHHZ31yBDJ}p7cu);yb`cPr}4Xr2%GrL{D%2^!r3+aMA&H+rVJ&WVV z;C<+beI)C`GuVr((~DRIK{Q#P43Y>2IRvHM2%JL&XA{Tga#>wc11inVMU1eU?)nq z&#b~*!`WO=`?FTXfC97YL!5>jq`3n<;Ez;f+k~8L1D?(NG}w69* zy0yno^T!%<^voW*nSBF^dqu?Qax4;pOoCBa!QvY`*2IpvNvpkC=MDAi_ z9SM>End>WEPM{C$eqTS9$b_F?-RJz@Y8`}^+kbu`l^5%7WL@D@Va2dfvx~E&1FQSA z$Bv#bpLP5=TZ*fUCqm}0k4#qiMmR=OZ}Md7vUIdPX`L6A~YPyLAf+L3*^&o;S|%>+^P} zs`Qc+4TD&`ZkX?dPd3;R#&;CK@{mhY{d!n(4)lcoa zwKz*Ofv*Pl#G52QmHu;nioA46&Nw1uN##5oO3q5idv&2a(H!3c*_}vidm+tUHv3#FYxU9y9sa3w5RH_@dKW9;s6`IVr!03o)VUAP~{D6 zRU@V@Kdd+tAE-Ym$Uci^ zc@^0yAHGDpE7uxM_XvZ0eSb}9eN9vQ?g&*QgFLf@wcMm)e@|C(FuH?ejDVv;q5X;b zoG1%zRilVL=OyRarPLxq*eZj|t~-N`JFhT9FzOa=HU} zp7#*+d23aLd%Z8oDgA;^3u{5J+dPAwI|r{l_b_g%s$3;KN)Os=d^L_{GNIGGuI}WjuEqiDwL{7wkWq42HhlVAL&&neI%w1m|km7ZC1|;8|yYn=Q;2;?m+I=Ss1n z!N-x%y2LA#T?O;|axPMCQ*cVHZ_hxF@s)8@^o91AS??rY;tOXG@X~7EH^2@=aJUM1 zKJ7)qtPVC-GT0rI+t7HP_N+K{Ar|ginDue9iz6(!ICxKC<$u{PexJjQec4CKh5^1I zs)*kVH2pk&!y81yZpFO8i5C5Mkj774w-?#%!z`$rVL!zt7^_<~I~OZ=#BnUzZg32i zjQnf>EZSh!Cn$<;I5>HV9eJt!iNu_~2cB=0!d6%?>s*xglfjNk-oIC2Dn%SwiE^vW zM|9P%2(N~`XMX}*lD6Qwz32>~mPIu>KFtKpIoeQ~hEd5V8FP3=UC( z>(&9@R$UpI78gm-%RM*=4uPw%xqQw*00**JoiM9fC{lKNq->9H!gZe>OFyjkC-R1h zg!h383z+P4gq*QfIHL^5;P^l0930N66V9Revkw*neu z2j^mYL`4%e@^9|)Ccg^nmCq=MxaY>)bGxZ9`}L`$b%uGK1Sx+3GwaN(hjtA-r*iAn z8G(Eu@_(&$ElP2$kbM|oBYMbO@}%IK4-dZPXHlub!B)bm766}j8^J5cT_2f~J&^U; z>!x9t-f{#L`~lU@S)PW7_wh7w1X%zFtyNr>wm&$C!RJ70h4sQ39eAGb4VMF$-G=3v z1vZ?XnGywv@MRa5R-r7J4m}3RhsYC7D|}fz?tdaSSEf0V??>#aw96<5hz*Vr!}hAE zSGo5(zwIoF+xPn*TUX2;U#8-cttPCh+11jC@@P{MGT9dvZpgkbY4a%-7R-0{hr;?D z^E{&^^o3PP>dOG~^Hp(pJ8*ebGor~}VovRji z&EmA)p$ps5RClUd`s0z*-J?z2bW^uis`;Ir>uGveUR+qebN#w!&Fs8oX6cS~8$0VR zm|C}i;Nsbth1pG4&D=4&M1NgcoS*HS+kc@eXZEe&s+~)-blH)!duHb5sbbxo^aWFU zaP^km_}kRZ#XY!S@DrEQo$ta&FOeU(VqtMV38i0tu6}j)o#(E5-mP*$@%uKEWH|el zm6g5A)0;Q%o?E$P-ws@~8F#`rviZk7Z2u?!&N#oyD}!>u*l$vfQo4M)x_?CK0U?D`E;#oEr?a%ZNqb8+Fe*@d}TnzB3D zvBdmaH_xr`Pwm+^zcROXepX(LFg?wuQq!m9_c|+!ot0Z=JIgbBW;?rPR%VuGSEh!3 zv$KD0e!jD3=GNKH{M^Fq%u;7@>3_(D#f44!FM1|B<`!l|NRo!WZFyF|ePd_eGVWof zWBc*W3<+@Lp4pX|P5kev($hbBTW9@w=XRngf2vz<)0bU!!FAVdB$=MJxJbWqB#pGC zjYsa9y=_JQy?e(VV)J_zW>+>IdF#U53f0mL1NO}Cpr>`q#v>QFa)}=D;(wk?7nf$2 z@vl8IOSkS?+`mA@y)#Snm*u^)^YqEx8;@L}D^_lqp}*~;r*z9)d1yU_g`~Tn$2hez zL(NOKup0-Q2lV4J)EqnMFLH7_-QwPvm7TZjUtGGCiaTcZ?w!Abesg|iVRz|k*Isqm z(>hP0_N2jeB4<5!Ce-cTsoBWTakz*B$+5X^9wHT3lTD=^wxMpZ_2Ho0Vg6 G= 0.0)) + testthat::expect_true(all(i <= 1.0)) + testthat::expect_equal(sum(i), 1.0, tolerance = 1e-6) + } + } + } +}) + +testthat::test_that("plot.caretEnsemble works", { + for (ens in list(ens.class, ens.reg)) { + plt <- plot(ens) + testthat::expect_is(plt, "ggplot") + testthat::expect_identical(nrow(plt$data), 5L) + testthat::expect_named(ens$models, plt$data$model_name[-1L]) + } +}) + +testthat::test_that("ggplot2::autoplot.caretEnsemble works", { + for (ens in list(ens.class, ens.reg)) { + plt1 <- ggplot2::autoplot(ens) + plt2 <- ggplot2::autoplot(ens, xvars = c("Petal.Length", "Petal.Width")) + + testthat::expect_is(plt1, "ggplot") + testthat::expect_is(plt2, "ggplot") + testthat::expect_is(plt1, "patchwork") + testthat::expect_is(plt2, "patchwork") + + train_model <- ens.reg$models[[1L]] + testthat::expect_error(ggplot2::autoplot(train_model), "Objects of class (.*?) are not supported by autoplot") + } +}) + +testthat::test_that("summary.caretEnsemble works", { + for (ens in list(ens.class, ens.reg)) { + smry <- testthat::expect_silent(summary(ens.class)) + testthat::expect_output(print(smry), ens.class$ens_model$metric) + for (name in names(ens.class$models)) { + testthat::expect_output(print(smry), name) + } + } +}) + +testthat::test_that("predict.caretEnsemble works with and without se and weights", { + for (ens in list(ens.class, ens.reg)) { + is_class <- isClassifier(ens) + for (se in c(FALSE, TRUE)) { + p <- predict( + ens, + newdata = X.reg, + se = se, + excluded_class_id = 1L + ) + testthat::expect_s3_class(p, "data.table") + if (se) { + testthat::expect_named(p, c("pred", "lwr", "upr")) + } else { + testthat::expect_named(p, ifelse(is_class, "Yes", "pred")) + } + } + } +}) + +testthat::test_that("We can train and ensemble models with custom tuning lists", { + target <- "Class" + + custom_list <- caretList( + x = Sonar[, setdiff(names(Sonar), target)], + y = Sonar[, target], + tuneList = list( + rpart = caretModelSpec( + method = "rpart", + tuneGrid = data.table::data.table(.cp = c(0.01, 0.001, 0.1, 1.0)) + ), + knn = caretModelSpec( + method = "knn", + tuneLength = 9L + ), + lda = caretModelSpec( + method = "lda2", + tuneLength = 1L + ), + nnet = caretModelSpec( + method = "nnet", + tuneLength = 2L, + trace = FALSE, + softmax = FALSE + ) + ) + ) + testthat::expect_is(custom_list, "caretList") + testthat::expect_identical(nrow(custom_list[["rpart"]]$results), 4L) + testthat::expect_identical(nrow(custom_list[["knn"]]$results), 9L) + testthat::expect_identical(nrow(custom_list[["lda"]]$results), 1L) + testthat::expect_identical(nrow(custom_list[["nnet"]]$results), 4L) + testthat::expect_false(custom_list[["nnet"]]$finalModel$softmax) + + custom_ensemble <- caretEnsemble(custom_list) + testthat::expect_is(custom_ensemble, "caretEnsemble") +}) diff --git a/tests/testthat/test-caretList.R b/tests/testthat/test-caretList.R index cac7bece..8d2ce95e 100644 --- a/tests/testthat/test-caretList.R +++ b/tests/testthat/test-caretList.R @@ -1,13 +1,13 @@ -# Test caretList +# Setup set.seed(442L) -data(models.reg) -data(X.reg) -data(Y.reg) +utils::data(models.reg) +utils::data(X.reg) +utils::data(Y.reg) -data(models.class) -data(X.class) -data(Y.class) +utils::data(models.class) +utils::data(X.class) +utils::data(Y.class) train <- caret::twoClassSim( n = 1000L, intercept = -8L, linearVars = 3L, @@ -18,627 +18,106 @@ test <- caret::twoClassSim( noiseVars = 10L, corrVars = 4L, corrValue = 0.6 ) -testthat::test_that("caretModelSpec returns valid specs", { - tuneList <- list( - rf1 = caretModelSpec(), - rf2 = caretModelSpec(method = "rf", tuneLength = 5L), - caretModelSpec(method = "rpart"), - caretModelSpec(method = "knn", tuneLength = 10L) - ) - tuneList <- caretEnsemble::tuneCheck(tuneList) - testthat::expect_type(tuneList, "list") - testthat::expect_length(tuneList, 4L) - testthat::expect_identical(sum(duplicated(names(tuneList))), 0L) -}) +n <- 100L +p <- 1000L +large_data <- list( + X = data.table::data.table(matrix(stats::rnorm(n * p), n, p)), + y = factor(sample(c("A", "B"), n, replace = TRUE)) +) +################################################################ +testthat::context("caretModelSpec, tuneCheck, methodCheck") +################################################################ testthat::test_that("caretModelSpec and checking functions work as expected", { all_models <- sort(unique(caret::modelLookup()$model)) - for (model in all_models) { - testthat::expect_identical(caretModelSpec(model, tuneLength = 5L, preProcess = "knnImpute")$method, model) - } - tuneList <- lapply(all_models, function(x) list(method = x, preProcess = "pca")) - all_models_check <- tuneCheck(tuneList) - testthat::expect_is(all_models_check, "list") - testthat::expect_length(all_models, length(all_models_check)) + testthat::expect_identical(caretModelSpec("rf", tuneLength = 5L, preProcess = "knnImpute")$method, "rf") tuneList <- lapply(all_models, function(x) list(method = x, preProcess = "pca")) - names(tuneList) <- all_models - names(tuneList)[c(1L, 5L, 10L)] <- "" all_models_check <- tuneCheck(tuneList) testthat::expect_is(all_models_check, "list") testthat::expect_length(all_models, length(all_models_check)) methodCheck(all_models) - err <- "The following models are not valid caret models: THIS_IS_NOT_A_REAL_MODEL" - testthat::expect_error(methodCheck(c(all_models, "THIS_IS_NOT_A_REAL_MODEL")), err) - testthat::expect_error(methodCheck(c(all_models, "THIS_IS_NOT_A_REAL_MODEL", "GBM"))) -}) - -testthat::test_that("Target extraction functions work", { - data(iris) - testthat::expect_identical(extractCaretTarget(iris[, 1L:4L], iris[, 5L]), iris[, 5L]) - testthat::expect_identical(extractCaretTarget(iris[, 2L:5L], iris[, 1L]), iris[, 1L]) - testthat::expect_identical(extractCaretTarget(Species ~ ., iris), iris[, "Species"]) - testthat::expect_identical(extractCaretTarget(Sepal.Width ~ ., iris), iris[, "Sepal.Width"]) -}) - -testthat::test_that("caretList errors for bad models", { - data(iris) - - # Basic checks - testthat::expect_error(caretList(Sepal.Width ~ ., iris), "Please either define a methodList or tuneList") - testthat::expect_warning( - caretList(Sepal.Width ~ ., iris, methodList = c("lm", "lm")), - "Duplicate entries in methodList. Using unique methodList values." - ) - testthat::expect_is(caretList(Sepal.Width ~ ., iris, methodList = "lm", continue_on_fail = TRUE), "caretList") - - # Check that by default a bad model kills the training job - bad <- list( - bad = caretModelSpec(method = "glm", tuneLength = 1L) - ) - testthat::expect_output( - testthat::expect_warning( - testthat::expect_error( - caretList(iris[, 1L:4L], iris[, 5L], tuneList = bad), - regexp = "Stopping" # Stop training on the first error. This is the mssage straight from train. - ), - regexp = "model fit failed for Fold1" - ), - regexp = "Something is wrong; all the Accuracy metric values are missing:" - ) - testthat::expect_output( - testthat::expect_warning( - testthat::expect_error( - caretList(iris[, 1L:4L], iris[, 5L], tuneList = bad, continue_on_fail = TRUE), - regexp = "caret:train failed for all models. Please inspect your data." - ), - regexp = "model fit failed for Fold1" - ), - regexp = "Something is wrong; all the Accuracy metric values are missing:" - ) - - # Check that at least one good model + continue_on_fail works - good_bad <- list( - good = caretModelSpec(method = "glmnet", tuneLength = 1L), - bad = caretModelSpec(method = "glm", tuneLength = 1L) - ) - testthat::expect_s3_class( - testthat::expect_output( - testthat::expect_warning( - caretList(iris[, 1L:4L], iris[, 5L], tuneList = good_bad, continue_on_fail = TRUE), - regexp = "model fit failed for Fold1" - ), - regexp = "Something is wrong; all the Accuracy metric values are missing:" - ), "caretList" - ) -}) - -testthat::test_that("caretList predictions", { - models <- testthat::expect_warning( - caretList( - iris[, 1L:2L], iris[, 3L], - tuneLength = 1L, verbose = FALSE, - methodList = "rf", tuneList = list(nnet = caretModelSpec(method = "nnet", trace = FALSE)) - ), "There were missing values in resampled performance measures." - ) - - p1 <- predict(models) - p2 <- predict(models, newdata = iris[100L, 1L:2L]) - p3 <- predict(models, newdata = iris[110L, 1L:2L]) - testthat::expect_is(p1, "data.table") - testthat::expect_is(p1[[1L]], "numeric") - testthat::expect_is(p1[[2L]], "numeric") - testthat::expect_named(models, colnames(p1)) - testthat::expect_is(p2, "data.table") - testthat::expect_is(p2[[1L]], "numeric") - testthat::expect_is(p2[[2L]], "numeric") - testthat::expect_named(models, colnames(p2)) - testthat::expect_is(p3, "data.table") - testthat::expect_is(p3[[1L]], "numeric") - testthat::expect_is(p3[[2L]], "numeric") - testthat::expect_named(models, colnames(p3)) - - models <- caretList( - iris[, 1L:2L], iris[, 5L], - tuneLength = 1L, verbose = FALSE, - methodList = "rf", - tuneList = list(nnet = caretModelSpec(method = "nnet", trace = FALSE)) - ) - - p2 <- predict(models, excluded_class_id = 0L) - p3 <- predict(models, newdata = iris[, 1L:2L], excluded_class_id = 0L) - testthat::expect_is(p2, "data.table") - testthat::expect_is(p2[[1L]], "numeric") - testthat::expect_is(p2[[2L]], "numeric") - testthat::expect_is(p2[[3L]], "numeric") - testthat::expect_is(p2[[4L]], "numeric") - testthat::expect_is(p3, "data.table") - testthat::expect_is(p3[[1L]], "numeric") - testthat::expect_is(p3[[2L]], "numeric") - testthat::expect_is(p3[[3L]], "numeric") - testthat::expect_is(p3[[4L]], "numeric") - testthat::expect_identical( - length(names(models)) * nlevels(as.factor(iris[, 5L])), - length(colnames(p3)) - ) # check that we have the right number of columns - testthat::expect_identical(dim(p2), dim(p3)) - testthat::expect_named(p2, names(p3)) - - modelnames <- names(models) - classes <- levels(iris[, 5L]) - combinations <- expand.grid(classes, modelnames) - correct_colnames <- apply(combinations, 1L, function(x) paste(x[2L], x[1L], sep = "_")) - testthat::expect_named( - p3, - correct_colnames - ) # check the column names are correct and ordered correctly (methodname_classname) -}) - -testthat::test_that("as.caretList.list returns a caretList object", { - modelList <- caretList(Sepal.Length ~ Sepal.Width, - head(iris, 50L), - methodList = c("glm", "lm", "knn") + testthat::expect_error( + methodCheck(c(all_models, "THIS_IS_NOT_A_REAL_MODEL")), + "The following models are not valid caret models: THIS_IS_NOT_A_REAL_MODEL" ) - class(modelList) <- "list" - testthat::expect_is(as.caretList(modelList), "caretList") -}) -############################################################# -testthat::context("Bad characters in target variable names and model names") -############################################################# -testthat::test_that("Target variable names with character | are not allowed", { - bad_iris <- iris[1L:100L, ] - bad_iris[, 5L] <- gsub("versicolor", "versicolor|1", bad_iris[, 5L], fixed = TRUE) - bad_iris[, 5L] <- gsub("setosa", "setosa|2", bad_iris[, 5L], fixed = TRUE) - bad_iris[, 5L] <- as.factor(as.character(bad_iris[, 5L])) - - # Expect an error from caret testthat::expect_error( - caretList( - x = bad_iris[, -5L], - y = bad_iris[, 5L], - methodList = c("rpart", "glmnet") - ), "At least one of the class levels is not a valid R variable name; This will cause errors when class prob" + methodCheck("InvalidMethod"), + "The following models are not valid caret models: InvalidMethod" ) -}) -testthat::test_that("Character | in model names is transformed into a point", { - reduced_iris <- iris[1L:100L, ] - reduced_iris[, 5L] <- as.factor(as.character(reduced_iris[, 5L])) - - # Chack that specified model names are transformed with function make.names - model_list <- caretList( - x = reduced_iris[, -5L], - y = reduced_iris[, 5L], - tuneList = list( - "nnet|1" = caretModelSpec( - method = "nnet", - tuneGrid = expand.grid(.size = c(1L, 3L), .decay = 0.3), - trace = FALSE - ), - "nnet|2" = caretModelSpec( - method = "nnet", - tuneGrid = expand.grid(.size = 3L, .decay = c(0.1, 0.3)), - trace = FALSE - ) - ) - ) - testthat::expect_named(model_list, c("nnet.1", "nnet.2")) -}) - -############################################### -testthat::context("We can fit models with a mix of methodList and tuneList") -################################################ -testthat::test_that("We can fit models with a mix of methodList and tuneList", { - myList <- list( - rpart = caretModelSpec(method = "rpart", tuneLength = 10L), - rf = caretModelSpec(method = "rf", tuneGrid = data.table::data.table(mtry = 2L)) - ) - test <- testthat::expect_warning( - caretList( - x = iris[, 1L:3L], - y = iris[, 4L], - methodList = c("knn", "glm"), - tuneList = myList - ), "There were missing values in resampled performance measures." + testthat::expect_error( + methodCheck(list(invalid_method = 42L)), + "Method \"42\" is invalid" ) - testthat::expect_is(test, "caretList") - testthat::expect_is(caretEnsemble(test), "caretEnsemble") - testthat::expect_length(test, 4L) - methods <- vapply(test, function(x) x$method, character(1L)) - names(methods) <- NULL - testthat::expect_identical(methods, c("rpart", "rf", "knn", "glm")) }) -################################################ -testthat::context("We can handle different CV methods") -################################################ -testthat::test_that("We can handle different CV methods", { - for (m in c( - "boot", - "adaptive_boot", - "cv", - "repeatedcv", - "adaptive_cv", - "LGOCV", - "adaptive_LGOCV" - ) - ) { - N <- 7L - x <- iris[, 1L:3L] - y <- iris[, 4L] - - if (m == "boot" || m == "adaptive_boot") { - idx <- caret::createResample(y, times = N, list = TRUE) - } else if (m == "cv" || m == "adaptive_cv") { - idx <- caret::createFolds(y, k = N, list = TRUE, returnTrain = TRUE) - } else if (m == "repeatedcv") { - idx <- caret::createMultiFolds(y, k = N, times = 2L) - } else if (m == "LGOCV" || m == "adaptive_LGOCV") { - idx <- caret::createDataPartition( - y, - times = N, - p = 0.5, - list = TRUE, - groups = min(5L, length(y)) - ) - } - - models <- testthat::expect_warning( - caretList( - x = x, - y = y, - tuneLength = 2L, - methodList = c("rpart", "rf") - ), "There were missing values in resampled performance measures." - ) - ens <- caretStack(models, method = "glm") - - for (x in models) { - testthat::expect_s3_class(x, "train") - } +################################################################ +testthat::context("S3 methods for caretlist") +################################################################ - ens <- caretEnsemble(models) - - testthat::expect_is(ens, "caretEnsemble") - - ens <- caretStack(models, method = "glm") - - testthat::expect_is(ens, "caretStack") - } -}) - -testthat::test_that("Non standard cv methods work", { +testthat::test_that("Target extraction functions work", { data(iris) - models <- lapply( - c("boot632", "LOOCV", "none"), - function(m) { - model <- caret::train( - x = iris[, 1L:2L], - y = iris[, 3L], - tuneLength = 1L, - data = iris, - method = "rf", - trControl = caret::trainControl( - method = m, - savePredictions = "final" - ) - ) - testthat::expect_is(model, "train") - model - } - ) - caret_list <- as.caretList(models) - p <- predict(caret_list, newdata = iris[, 1L:2L]) - testthat::expect_s3_class(p, "data.table") -}) - -############################################### -testthat::context("Classification models") -################################################ -testthat::test_that("Classification models", { - # Simple two method list - # Warning because we Are going to auto-set indexes - test1 <- caretList( - x = train[, -23L], - y = train[, "Class"], - methodList = c("knn", "glm") - ) - - testthat::expect_is(test1, "caretList") - testthat::expect_is(caretEnsemble(test1), "caretEnsemble") - testthat::expect_is(caretEnsemble(test1), "caretEnsemble") -}) - -testthat::test_that("Longer tests for Classification models", { - # Simple two method list - # Warning because we Are going to auto-set indexes - test1 <- caretList( - x = train[, -23L], - y = train[, "Class"], - methodList = c("knn", "glm") - ) - - testthat::expect_is(test1, "caretList") - testthat::expect_is(caretEnsemble(test1), "caretEnsemble") - testthat::expect_is(caretEnsemble(test1), "caretEnsemble") - - test2 <- caretList( - x = train[, -23L], - y = train[, "Class"], - metric = "ROC", - methodList = c("knn", "glm", "rpart") - ) - - test3 <- caretList( - x = train[, -23L], - y = train[, "Class"], - metric = "ROC", - methodList = c("rpart", "knn", "glm") - ) - - testthat::expect_is(test2, "caretList") - testthat::expect_is(test3, "caretList") - testthat::expect_is(caretEnsemble(test2), "caretEnsemble") - testthat::expect_is(caretEnsemble(test3), "caretEnsemble") - - testthat::expect_identical(test2[[1L]]$metric, "ROC") - testthat::expect_identical(test3[[1L]]$metric, "ROC") -}) - -testthat::test_that("Test that caretList preserves user specified error functions", { - test1 <- caretList( - x = train[, -23L], - y = train[, "Class"], - tuneLength = 7L, - methodList = c("knn", "rpart", "glm") - ) - - test2 <- caretList( - x = train[, -23L], - y = train[, "Class"], - tuneLength = 4L, - methodList = c("knn", "rpart", "glm") - ) - - testthat::expect_identical(test1[[1L]]$metric, "ROC") - testthat::expect_identical(test2[[1L]]$metric, "ROC") - - testthat::expect_identical(nrow(test1[[1L]]$results), 7L) - testthat::expect_gt(nrow(test1[[1L]]$results), nrow(test2[[1L]]$results)) - testthat::expect_identical(nrow(test2[[1L]]$results), 4L) - - myEns2 <- caretEnsemble(test2) - myEns1 <- caretEnsemble(test1) - testthat::expect_is(myEns2, "caretEnsemble") - testthat::expect_is(myEns1, "caretEnsemble") - - test1 <- caretList( - x = train[, -23L], - y = train[, "Class"], - tuneLength = 7L, - methodList = c("knn", "rpart", "glm") - ) - - test2 <- caretList( - x = train[, -23L], - y = train[, "Class"], - tuneLength = 4L, - methodList = c("knn", "rpart", "glm") - ) - - testthat::expect_identical(test1[[1L]]$metric, "ROC") - testthat::expect_identical(test2[[1L]]$metric, "ROC") - - testthat::expect_identical(nrow(test1[[1L]]$results), 7L) - testthat::expect_gt(nrow(test1[[1L]]$results), nrow(test2[[1L]]$results)) - testthat::expect_identical(nrow(test2[[1L]]$results), 4L) - - - myEns2 <- caretEnsemble(test2) - myEns1 <- caretEnsemble(test1) - - testthat::expect_is(myEns2, "caretEnsemble") - testthat::expect_is(myEns1, "caretEnsemble") + testthat::expect_identical(extractCaretTarget(iris[, 1L:4L], iris[, 5L]), iris[, 5L]) + testthat::expect_identical(extractCaretTarget(Species ~ ., iris), iris[, "Species"]) }) -testthat::test_that("Users can pass a custom tuneList", { - tuneTest <- list( - rpart = caretModelSpec( - method = "rpart", - tuneGrid = data.table::data.table(.cp = c(0.01, 0.001, 0.1, 1.0)) - ), - knn = caretModelSpec( - method = "knn", - tuneLength = 9L - ), - svmRadial = caretModelSpec( - method = "lda2", - tuneLength = 1L - ) - ) - - test2a <- caretList( - x = train[, -23L], - y = train[, "Class"], - tuneList = tuneTest - ) - - myEns2a <- caretEnsemble(test2a) - testthat::expect_is(myEns2a, "caretEnsemble") - testthat::expect_is(test2a, "caretList") - testthat::expect_identical(nrow(test2a[[1L]]$results), 4L) - testthat::expect_identical(nrow(test2a[[2L]]$results), 9L) - testthat::expect_identical(nrow(test2a[[3L]]$results), 1L) +testthat::test_that("[.caretList", { + subset_models <- models.class[1L:2L] + testthat::expect_s3_class(subset_models, "caretList") + testthat::expect_length(subset_models, 2L) }) -testthat::context("User tuneTest parameters are respected and model is ensembled") -testthat::test_that("User tuneTest parameters are respected and model is ensembled", { - tuneTest <- list( - nnet = caretModelSpec( - method = "nnet", - tuneLength = 3L, - trace = FALSE, - softmax = FALSE - ) - ) - test <- caretList( - x = train[, -23L], - y = train[, "Class"], - tuneList = tuneTest - ) - ens <- caretEnsemble(test) - testthat::expect_is(ens, "caretEnsemble") - testthat::expect_is(test, "caretList") - testthat::expect_identical(nrow(test[[1L]]$results), 3L * 3L) - testthat::expect_false(test[[1L]]$finalModel$softmax) -}) +testthat::test_that("c.caretList", { + combined_models <- c(models.class, models.class) + testthat::expect_s3_class(combined_models, "caretList") + testthat::expect_length(combined_models, length(models.class) * 2L) -testthat::context("Formula interface for caretList works") -testthat::test_that("User tuneTest parameters are respected and model is ensembled", { - tuneTest <- list( - rpart = list(method = "rpart", tuneLength = 2L), - nnet = list(method = "nnet", tuneLength = 2L, trace = FALSE), - glm = list(method = "glm") - ) - x <- iris[, 1L:3L] - y <- iris[, 4L] - set.seed(42L) - test_default <- testthat::expect_warning( - caretList( - x = x, - y = y, - tuneList = tuneTest - ), "There were missing values in resampled performance measures." - ) - set.seed(42L) - test_flma <- testthat::expect_warning( - caretList( - y ~ ., - data = data.table::data.table(y = y, x), - tuneList = tuneTest - ), "There were missing values in resampled performance measures." - ) - ens_default <- caretEnsemble(test_default) - ens_flma <- caretEnsemble(test_flma) - testthat::expect_is(ens_default, "caretEnsemble") - testthat::expect_is(ens_flma, "caretEnsemble") + combined_models <- c(models.class, models.class[[1L]]) + testthat::expect_s3_class(combined_models, "caretList") + testthat::expect_length(combined_models, length(models.class) + 1L) - testthat::expect_equal(ens_default$RMSE, ens_flma$RMSE, tol = 0.000001) - testthat::expect_equal(ens_default$weights, ens_flma$weights, tol = 0.000001) + testthat::expect_error(c.caretList(list(a = 1L, b = 2L)), "class of modelList1 must be 'caretList' or 'train'") }) -############################################### -testthat::context("Regression models") -############################################### +testthat::test_that("as.caretList", { + # Named + model_list <- list(model1 = models.class[[1L]], model2 = models.class[[2L]]) + caretlist_object <- as.caretList(model_list) + testthat::expect_s3_class(caretlist_object, "caretList") + testthat::expect_length(caretlist_object, 2L) -testthat::test_that("Regression Models", { - test1 <- caretList( - x = train[, c(-23L, -1L)], - y = train[, 1L], - methodList = c("glm", "lm") - ) - test2 <- caretList( - x = train[, c(-23L, -1L)], - y = train[, 1L], - methodList = c("glm", "ppr", "lm") - ) + # Unnamed + model_list <- list(models.class[[1L]], models.class[[2L]]) + caretlist_object <- as.caretList(model_list) + testthat::expect_s3_class(caretlist_object, "caretList") + testthat::expect_length(caretlist_object, 2L) - ens1 <- caretEnsemble(test1) - ens2 <- caretEnsemble(test2) - - testthat::expect_is(test1, "caretList") - testthat::expect_is(test2, "caretList") - - testthat::expect_is(ens1, "caretEnsemble") - testthat::expect_is(ens2, "caretEnsemble") -}) - -testthat::test_that("methodCheck stops for invalid method type", { - testthat::expect_error(methodCheck(list(123L)), "Method \"123\" is invalid.") - testthat::expect_error( - methodCheck(list("invalid_method")), - "The following models are not valid caret models: invalid_method" - ) -}) - -testthat::test_that("as.caretList stops for null object", { + # Error cases testthat::expect_error(as.caretList(NULL), "object is null") -}) - -testthat::test_that("as.caretList.list stops for non-list object", { + testthat::expect_error(as.caretList(1L), "object must be a list") + testthat::expect_error(as.caretList(list(1L)), "object requires all elements of list to be caret models") + testthat::expect_error(as.caretList(list(NULL)), "object requires all elements of list to be caret models") testthat::expect_error(as.caretList.list(1L), "object must be a list of caret models") }) -testthat::test_that("predict.caretList doesn't care about missing training data", { - new_model_list <- lapply(models.class, function(x) { - x$trainingData <- NULL - x - }) - new_model_list <- as.caretList(new_model_list) - pred <- predict.caretList(new_model_list) - testthat::expect_is(pred, "data.table") - testthat::expect_identical(nrow(pred), 150L) - testthat::expect_named(pred, names(new_model_list)) -}) - -testthat::test_that("extractModelName handles custom models correctly", { - mock_model <- list(method = list(method = "custom_method")) - class(mock_model) <- "train" - testthat::expect_identical(extractModelName(mock_model), "custom_method") -}) - -testthat::test_that("extractModelName handles custom models correctly", { - mock_model <- list(method = "custom", modelInfo = list(method = "custom_method")) - class(mock_model) <- "train" - testthat::expect_identical(extractModelName(mock_model), "custom_method") -}) - -testthat::test_that("as.caretList.list fails on NULL object", { - err <- "object requires all elements of list to be caret models" - testthat::expect_error(as.caretList(list(NULL)), err) -}) - -testthat::test_that("predict.caretList works when the progress bar is turned off", { - set.seed(42L) - N <- 100L - noise_level <- 1L / 10L - X <- data.table::data.table( - a = runif(N), - b = runif(N) - ) - y <- 7.5 - 10.0 * X$a + 5.0 * X$b + noise_level * rnorm(N) - models <- caretList( - X, y, - tuneLength = 1L, - methodList = "lm" - ) - pred <- predict(models, X, verbose = FALSE)[["lm"]] - rmse <- sqrt(mean((y - pred)^2L)) - testthat::expect_lt(rmse, noise_level) -}) - -testthat::test_that("caretList handles missing data correctly", { - data(iris) - iris_with_na <- iris - x <- iris_with_na[, 1L:4L] - y <- iris_with_na[, 5L] - x[sample.int(nrow(x), 10L), sample.int(ncol(x), 2L)] <- NA +################################################################ +testthat::context("predict.caretlist") +################################################################ - models <- caretList( - x = x, - y = y, - methodList = "rpart" - ) +testthat::test_that("predict.caretList works for classification and regression", { + class_preds <- predict(models.class, newdata = X.class, excluded_class_id = 0L) + reg_preds <- predict(models.reg, newdata = X.reg) - testthat::expect_s3_class(models, "caretList") - testthat::expect_length(models, 1L) -}) + testthat::expect_is(class_preds, "data.table") + testthat::expect_is(reg_preds, "data.table") + testthat::expect_identical(nrow(class_preds), nrow(X.class)) + testthat::expect_identical(nrow(reg_preds), nrow(X.reg)) -testthat::test_that("caretList handles new factor levels in prediction", { - data(iris) + # Test for handling new factor levels in prediction idx <- seq_len(nrow(iris)) idx_train <- sample(idx, 100L) idx_test <- setdiff(idx, idx_train) @@ -656,79 +135,122 @@ testthat::test_that("caretList handles new factor levels in prediction", { pred <- predict(models, newdata = test_data) testthat::expect_is(pred, "data.table") testthat::expect_identical(nrow(pred), nrow(test_data)) + + # Test verbose option + p <- predict(models, newdata = test_data, verbose = TRUE) + testthat::expect_s3_class(p, "data.table") + testthat::expect_identical(nrow(p), nrow(test_data)) }) -testthat::test_that("caretList handles large number of predictors", { - set.seed(123L) - n <- 100L - p <- 1000L - X <- data.table::data.table(matrix(rnorm(n * p), n, p)) - y <- factor(sample(c("A", "B"), n, replace = TRUE)) +################################################################ +testthat::context("caretList") +################################################################ - models <- caretList( - x = X, - y = y, - methodList = c("glmnet", "rpart") +testthat::test_that("caretList works for various scenarios", { + # Basic classification + test1 <- caretList( + x = train[, -23L], + y = train[, "Class"], + methodList = c("knn", "glm") ) + testthat::expect_is(test1, "caretList") + testthat::expect_is(caretEnsemble(test1), "caretEnsemble") - testthat::expect_s3_class(models, "caretList") - testthat::expect_length(models, 2L) -}) - -testthat::test_that("caretList handles imbalanced data", { - set.seed(123L) - n <- 1000L - X <- data.table::data.table(x1 = rnorm(n), x2 = rnorm(n)) - y <- factor(c(rep("A", 950L), rep("B", 50L))) - - models <- caretList( - x = X, - y = y, - methodList = c("glmnet", "rpart") + # Regression + test_reg <- caretList( + x = train[, c(-23L, -1L)], + y = train[, 1L], + methodList = c("glm", "lm") ) + testthat::expect_is(test_reg, "caretList") + testthat::expect_is(caretEnsemble(test_reg), "caretEnsemble") + # Handling missing data + iris_with_na <- iris + x <- iris_with_na[, 1L:4L] + y <- iris_with_na[, 5L] + x[sample.int(nrow(x), 10L), sample.int(ncol(x), 2L)] <- NA + models <- caretList(x = x, y = y, methodList = "rpart") testthat::expect_s3_class(models, "caretList") - testthat::expect_length(models, 2L) -}) - -testthat::test_that("caretList handles custom performance metrics", { - data(iris) - models <- caretList( - x = iris[, 1L:4L], - y = iris[, 5L], - metric = "default", - methodList = c("rpart", "rf"), + # Handling large number of predictors + models_large <- caretList(x = large_data$X, y = large_data$y, methodList = "rpart") + testthat::expect_s3_class(models_large, "caretList") + testthat::expect_length(models_large, 1L) + + # Handling imbalanced data + imbalanced_y <- factor(c(rep("A", 95L), rep("B", 5L))) + testthat::expect_length(imbalanced_y, nrow(large_data$X)) + models_imbalanced <- caretList( + x = large_data$X, + y = imbalanced_y, + methodList = "rpart", trControl = caret::trainControl( method = "cv", - number = 2L, - summaryFunction = function(data, lev = NULL, model = NULL) c(default = mean(data$obs == data$pred)), - allowParallel = FALSE, - classProbs = TRUE + classProbs = TRUE, + summaryFunction = twoClassSummary, + sampling = "up", + index = caret::createFolds(imbalanced_y, k = 5L, returnTrain = TRUE) ) ) - testthat::expect_s3_class(models, "caretList") - testthat::expect_true(all(vapply(models, function(m) "default" %in% colnames(m$results), logical(1L)))) -}) + testthat::expect_s3_class(models_imbalanced, "caretList") + testthat::expect_length(models_imbalanced, 1L) -############################################### -testthat::context("S3 methods") -############################################### + # Test error cases + testthat::expect_error(caretList(Sepal.Width ~ ., iris), "Please either define a methodList or tuneList") + testthat::expect_warning( + caretList(Sepal.Width ~ ., iris, methodList = c("lm", "lm")), + "Duplicate entries in methodList. Using unique methodList values." + ) -testthat::test_that("plot.caretList", { + # Test continue_on_fail + bad <- list( + bad = caretModelSpec(method = "glm", tuneLength = 1L) + ) + testthat::expect_output( + testthat::expect_warning( + testthat::expect_error( + caretList(iris[, 1L:4L], iris[, 5L], tuneList = bad, continue_on_fail = TRUE), + regexp = "caret:train failed for all models. Please inspect your data." + ), + regexp = "model fit failed for Fold1" + ), + regexp = "Something is wrong; all the Accuracy metric values are missing:" + ) +}) + +# Test plot and summary methods +testthat::test_that("plot.caretList and summary.caretList work", { for (model_list in list(models.reg, models.class)) { plt <- plot(model_list) testthat::expect_is(plt, "ggplot") testthat::expect_identical(nrow(plt$data), 4L) testthat::expect_named(model_list, plt$data$model_name) - } -}) -testthat::test_that("summary.caretList", { - for (model_list in list(models.reg, models.class)) { smry <- testthat::expect_silent(summary(model_list)) for (name in names(model_list)) { testthat::expect_output(print(smry), name) } } }) + +# Test combined regression, binary, multiclass models +testthat::test_that("caretList supports combined regression, binary, multiclass", { + set.seed(42L) + + reg_models <- caretList(Sepal.Length ~ Sepal.Width, iris, methodList = c("glm", "lm")) + bin_models <- caretList(factor(ifelse(Species == "setosa", "Yes", "No")) ~ Sepal.Width, iris, + methodList = c("lda", "rpart") + ) + multi_models <- caretList(Species ~ Sepal.Width, iris, methodList = "rpart") + + all_models <- c(reg_models, bin_models, multi_models) + testthat::expect_s3_class(all_models, "caretList") + + stacked_p <- predict(all_models) + new_p <- predict(all_models, newdata = iris[1L:10L, ]) + testthat::expect_is(stacked_p, "data.table") + testthat::expect_is(new_p, "data.table") + testthat::expect_identical(nrow(stacked_p), nrow(iris)) + testthat::expect_identical(nrow(new_p), 10L) +}) diff --git a/tests/testthat/test-caretPredict.R b/tests/testthat/test-caretPredict.R index 5cf0eb38..2463c580 100644 --- a/tests/testthat/test-caretPredict.R +++ b/tests/testthat/test-caretPredict.R @@ -1,10 +1,28 @@ -data(models.reg) -data(X.reg) -data(Y.reg) +# Setup +utils::data(models.reg) +utils::data(X.reg) +utils::data(Y.reg) +utils::data(models.class) +utils::data(X.class) +utils::data(Y.class) -data(models.class) -data(X.class) -data(Y.class) +set.seed(1234L) + +ens.reg <- caretEnsemble( + models.reg, + trControl = caret::trainControl(method = "cv", number = 2L, savePredictions = "final") +) + +ens.class <- caretEnsemble( + models.class, + metric = "ROC", + trControl = caret::trainControl( + number = 2L, + summaryFunction = caret::twoClassSummary, + classProbs = TRUE, + savePredictions = TRUE + ) +) mod <- caret::train( X.reg, @@ -13,15 +31,162 @@ mod <- caret::train( trControl = caret::trainControl(method = "none") ) -testthat::test_that("Extracting metrics works if there is no SD", { - # In the case of no resampling, metrics will not have an SD to extract +# Helper function for testing +expect_data_table_structure <- function(dt, expected_names) { + testthat::expect_s3_class(dt, "data.table") + testthat::expect_named(dt, expected_names) +} + +############################################################################# +testthat::context("caretPredict and extractMetric") +############################################################################# +testthat::test_that("caretPredict extracts best predictions correctly", { + stacked_preds_class <- caretPredict(models.class[[1L]], excluded_class_id = 0L) + stacked_preds_reg <- caretPredict(models.reg[[1L]]) + + expect_data_table_structure(stacked_preds_class, c("No", "Yes")) + expect_data_table_structure(stacked_preds_reg, "pred") +}) + +testthat::test_that("extractMetric works for different model types", { + # Test for model with no resampling (no SD) metric <- extractMetric(mod) - expect_s3_class(metric, "data.table") - expect_named(metric, c("model_name", "metric", "value", "sd")) - expect_is(metric$model_name, "character") - expect_is(metric$metric, "character") - expect_is(metric$value, "numeric") - expect_is(metric$sd, "numeric") - testthat::expect_true(is.na(metric$value)) - testthat::expect_true(is.na(metric$sd)) + expect_data_table_structure(metric, c("model_name", "metric", "value", "sd")) + testthat::expect_true(is.na(metric$value), is.na(metric$sd)) + + # Test for ensemble models + for (ens in list(ens.class, ens.reg)) { + metrics <- extractMetric(ens) + expect_data_table_structure(metrics, c("model_name", "metric", "value", "sd")) + testthat::expect_named(ens$models, metrics$model_name[-1L]) + } +}) + +############################################################################# +testthat::context("S3 methods and model operations") +############################################################################# +testthat::test_that("c.train on 2 train objects", { + testthat::expect_error(c.train(list()), "class of modelList1 must be 'caretList' or 'train'") + + combined_models <- c(models.class[[1L]], models.class[[1L]]) + testthat::expect_s3_class(combined_models, "caretList") + testthat::expect_length(combined_models, 2L) + testthat::expect_identical(anyDuplicated(names(combined_models)), 0L) + testthat::expect_length(unique(names(combined_models)), 2L) +}) + +testthat::test_that("c.train on a train and a caretList", { + bigList <- c(models.reg[[1L]], models.class) + testthat::expect_is(bigList, "caretList") + testthat::expect_identical(anyDuplicated(names(bigList)), 0L) + testthat::expect_length(unique(names(bigList)), 5L) +}) + +testthat::test_that("extractModelName handles different model types", { + testthat::expect_identical(extractModelName(models.class[[1L]]), "rf") + testthat::expect_identical(extractModelName(models.reg[[1L]]), "rf") + + custom_model <- models.class[[1L]] + custom_model$method <- list(method = "custom_rf") + testthat::expect_identical(extractModelName(custom_model), "custom_rf") + + mock_model <- list(method = list(method = "custom_method")) + class(mock_model) <- "train" + testthat::expect_identical(extractModelName(mock_model), "custom_method") + + mock_model <- list(method = "custom", modelInfo = list(method = "custom_method")) + class(mock_model) <- "train" + testthat::expect_identical(extractModelName(mock_model), "custom_method") +}) + +############################################################################# +testthat::context("isClassifierAndValidate") +############################################################################# +testthat::test_that("isClassifierAndValidate handles various model types", { + models_multi <- caretList( + iris[, 1L:2L], iris[, 5L], + tuneLength = 1L, verbose = FALSE, + methodList = c("rf", "gbm") + ) + models_multi_bin_reg <- c(models_multi, models.class, models.reg) + testthat::expect_is(vapply(models_multi_bin_reg, isClassifierAndValidate, logical(1L)), "logical") + + # Test when predictions are missing + model_list <- models.class + model_list[[1L]]$pred <- NULL + testthat::expect_is(vapply(model_list, isClassifierAndValidate, logical(1L)), "logical") + testthat::expect_equivalent(unique(vapply(model_list, isClassifierAndValidate, logical(1L))), TRUE) + + # Test error cases + model_list <- models.class + model_list[[1L]]$modelInfo$prob <- FALSE + testthat::expect_error( + lapply(model_list, isClassifierAndValidate), + "No probability function found. Re-fit with a method that supports prob." + ) + + model_list <- models.class + model_list[[1L]]$control$classProbs <- FALSE + testthat::expect_error( + lapply(model_list, isClassifierAndValidate, validate_for_stacking = TRUE), + "classProbs = FALSE. Re-fit with classProbs = TRUE in trainControl." + ) + + # Test for non-caretList object + testthat::expect_error( + isClassifierAndValidate(list(model = lm(Y.reg ~ ., data = as.data.frame(X.reg)))), + "is(object, \"train\") is not TRUE", + fixed = TRUE + ) + + # Test for models without savePredictions + model <- models.class[[1L]] + model$control$savePredictions <- NULL + testthat::expect_error( + isClassifierAndValidate(model), + "Must have savePredictions = 'all', 'final', or TRUE in trainControl to do stacked predictions." + ) + model$control$savePredictions <- "BAD_VALUE" + testthat::expect_error( + isClassifierAndValidate(model), + "Must have savePredictions = 'all', 'final', or TRUE in trainControl to do stacked predictions." + ) +}) + +############################################################################# +testthat::context("validateExcludedClass") +############################################################################# +testthat::test_that("validateExcludedClass handles various inputs", { + testthat::expect_error(validateExcludedClass("invalid"), "classification excluded level must be numeric: invalid") + testthat::expect_warning( + testthat::expect_error(validateExcludedClass(Inf), "classification excluded level must be finite: Inf"), + "classification excluded level is not an integer: Inf" + ) + testthat::expect_warning( + testthat::expect_error(validateExcludedClass(-1.0), "classification excluded level must be >= 0: -1"), + "classification excluded level is not an integer:" + ) + testthat::expect_warning(validateExcludedClass(1.1), "classification excluded level is not an integer: 1.1") + testthat::expect_identical(validateExcludedClass(3L), 3L) + + # Edge cases + testthat::expect_identical(validateExcludedClass(0L), 0L) + testthat::expect_identical(validateExcludedClass(1L), 1L) + testthat::expect_identical(validateExcludedClass(4L), 4L) + w <- "classification excluded level is not an integer:" + testthat::expect_warning(testthat::expect_identical(validateExcludedClass(0.0), 0L), w) + testthat::expect_warning(testthat::expect_identical(validateExcludedClass(1.0), 1L), w) + testthat::expect_warning(testthat::expect_identical(validateExcludedClass(4.0), 4L), w) + testthat::expect_error(validateExcludedClass(-1L), "classification excluded level must be >= 0: -1") + + # Additional tests + testthat::expect_warning(validateExcludedClass(NULL), "No excluded_class_id set. Setting to 1L.") + testthat::expect_error( + validateExcludedClass(c(1L, 2L)), + "classification excluded level must have a length of 1: length=2" + ) + testthat::expect_warning( + testthat::expect_error(validateExcludedClass(-0.000001), "classification excluded level must be >= 0: -1e-06"), + "classification excluded level is not an integer" + ) }) diff --git a/tests/testthat/test-caretStack.R b/tests/testthat/test-caretStack.R index ad127f5a..8f8eac2f 100644 --- a/tests/testthat/test-caretStack.R +++ b/tests/testthat/test-caretStack.R @@ -1,85 +1,85 @@ -data(models.reg) -data(X.reg) -data(Y.reg) -data(models.class) -data(X.class) -data(Y.class) - -ens.class <- caretStack( - models.class, - method = "glm", - preProcess = "pca", - trControl = caret::trainControl(method = "cv", number = 2L, savePredictions = "final", classProbs = TRUE) +# Load data and create models +utils::data(models.reg) +utils::data(X.reg) +utils::data(Y.reg) +utils::data(models.class) +utils::data(X.class) +utils::data(Y.class) +utils::data(iris) + +models_multiclass <- caretList( + x = iris[, -5L], + y = iris[, 5L], + methodList = c("rpart", "glmnet") ) -ens.reg <- caretStack( - models.reg, - method = "lm", - preProcess = "pca", - trControl = caret::trainControl(method = "cv", number = 2L, savePredictions = "final", classProbs = FALSE) +control_class <- caret::trainControl( + method = "cv", + number = 2L, + savePredictions = "final", + classProbs = TRUE, + summaryFunction = twoClassSummary, + index = caret::createFolds(Y.class, 2L) ) +ens.class <- caretStack(models.class, preProcess = "pca", method = "glm", metric = "ROC", trControl = control_class) + +control_reg <- caret::trainControl( + method = "cv", + number = 2L, + savePredictions = "final", + classProbs = FALSE, + index = caret::createFolds(Y.reg, 2L) +) +ens.reg <- caretStack(models.reg, preProcess = "pca", method = "lm", trControl = control_reg) + +# Helper functions +expect_all_finite <- function(x) { + testthat::expect_true(all(vapply(x, function(col) all(is.finite(col)), logical(1L)))) +} + +###################################################################### +testthat::context("caretStack") +###################################################################### + +testthat::test_that("caretStack creates valid ensemble models", { + testthat::expect_s3_class(ens.class, "caretStack") + testthat::expect_s3_class(ens.reg, "caretStack") -testthat::context("Does stacking and prediction work?") + testthat::expect_s3_class(summary(ens.class), "summary.caretStack") + testthat::expect_s3_class(plot(ens.class), "ggplot") + testthat::expect_output(print(ens.class), "The following models were ensembled: rf, glm, rpart, treebag") +}) -testthat::test_that("We can make predictions from stacks, including cases where the stacked model has preprocessing", { +testthat::test_that("predict works for classification and regression ensembles", { ens_list <- list(class = ens.class, reg = ens.reg) X_list <- list(class = X.class, reg = X.reg) for (model_name in names(ens_list)) { - # S3 methods ens <- ens_list[[model_name]] - testthat::expect_s3_class(ens, "caretStack") - testthat::expect_s3_class(summary(ens), "summary.caretStack") - testthat::expect_s3_class(plot(ens), "ggplot") - invisible(capture.output(print(ens))) + X <- X_list[[model_name]] - # Predictions param_grid <- expand.grid( se = c(TRUE, FALSE), newdata = c(TRUE, FALSE) ) + for (i in seq_len(nrow(param_grid))) { params <- param_grid[i, ] - X <- X_list[[model_name]] - expected_rows <- nrow(X) - newdata <- NULL - if (params$newdata) { - newdata <- X[1L:50L, ] - expected_rows <- 50L - } + newdata <- if (params$newdata) X[1L:50L, ] else NULL + expected_rows <- if (params$newdata) 50L else nrow(X) + pred <- predict(ens, newdata = newdata, se = params$se) testthat::expect_s3_class(pred, "data.table") testthat::expect_identical(nrow(pred), expected_rows) - testthat::expect_true(all(vapply(pred, is.numeric, logical(1L)))) + expect_all_finite(pred) } } }) -testthat::test_that("For classificaiton, we can predict the class labels", { +testthat::test_that("Classification predictions return correct output", { pred.class <- predict(ens.class, X.class, return_class_only = TRUE) - expect_is(pred.class, "factor") - expect_length(pred.class, nrow(X.class)) -}) - -testthat::test_that("caretStack plots", { - ens.gbm <- caretStack( - models.reg, - method = "gbm", tuneLength = 2L, verbose = FALSE - ) - testthat::expect_s3_class(ens.gbm, "caretStack") - - plt <- plot(ens.gbm) - expect_s3_class(plt, "ggplot") - - dotplot <- lattice::dotplot(ens.gbm, metric = "RMSE") - expect_s3_class(dotplot, "trellis") -}) - -testthat::test_that("Prediction names are correct with SE", { - testthat::expect_named( - predict(ens.reg, X.reg, se = TRUE, excluded_class_id = 0L), - c("pred", "lwr", "upr") - ) + testthat::expect_s3_class(pred.class, "factor") + testthat::expect_length(pred.class, nrow(X.class)) testthat::expect_named( predict(ens.class, X.class, se = TRUE, excluded_class_id = 1L), @@ -92,9 +92,14 @@ testthat::test_that("Prediction names are correct with SE", { ) }) -testthat::test_that("Prediction equivalence", { - # Note that SE is stochastic, since it uses permutation importance +testthat::test_that("Regression predictions return correct output", { + testthat::expect_named( + predict(ens.reg, X.reg, se = TRUE, excluded_class_id = 0L), + c("pred", "lwr", "upr") + ) +}) +testthat::test_that("Predictions are reproducible", { set.seed(42L) p1 <- predict(ens.class, X.class, se = TRUE, level = 0.8) set.seed(42L) @@ -103,153 +108,51 @@ testthat::test_that("Prediction equivalence", { testthat::expect_equivalent(p1, p2) }) -testthat::test_that("Test na.action pass through", { - set.seed(1337L) - - # drop the first model because it does not support na.pass - ens.reg <- caretStack(models.reg[2L:3L], method = "lm") +testthat::test_that("caretStack handles missing data correctly", { + ens.reg.subset <- caretEnsemble::caretStack(models.reg[2L:3L], method = "lm") X_reg_na <- X.reg - # introduce random NA values into a column X_reg_na[sample.int(nrow(X_reg_na), 20L), sample.int(ncol(X_reg_na) - 1L, 1L)] <- NA - pred.reg <- predict(ens.reg, newdata = X_reg_na, na.action = na.pass) + pred.reg <- predict(ens.reg.subset, newdata = X_reg_na) testthat::expect_identical(nrow(pred.reg), nrow(X_reg_na)) - pred.reg <- predict(ens.reg, newdata = X_reg_na) - testthat::expect_false(nrow(pred.reg) != nrow(X_reg_na)) + pred.reg <- predict(ens.reg.subset, newdata = X_reg_na) + testthat::expect_identical(nrow(pred.reg), nrow(X_reg_na)) }) -testthat::test_that("predict.caretStack works correctly if the multiclass excluded level is too high", { - data(iris) - - # Create a caretList - model_list <- caretList( - Species ~ ., - data = iris, - methodList = c("rpart", "rf") - ) - - # Make sure predictions still work if the exlcuded level is too high - meta_model <- caretStack( - model_list, - method = "rpart", - excluded_class_id = 4L - ) +testthat::test_that("caretStack handles multiclass problems", { + meta_model <- caretEnsemble::caretStack(models_multiclass, method = "rpart", excluded_class_id = 4L) pred <- predict(meta_model, newdata = iris) testthat::expect_identical(nrow(pred), 150L) testthat::expect_identical(ncol(pred), 3L) - all_finite <- function(x) all(is.finite(x)) - testthat::expect_true(all(vapply(pred, all_finite, logical(1L)))) + expect_all_finite(pred) }) -testthat::context("caretStack edge cases") - -testthat::test_that("caretStack handles different stacking algorithms", { - for (x in list(list(models.reg, X.reg), list(models.class, X.class))) { - model_list <- x[[1L]] - test_data <- x[[2L]] +testthat::test_that("caretStack works with different stacking algorithms", { + stack_methods <- c("glm", "rf", "gbm", "glmnet") - stack_methods <- c("glm", "rf", "gbm", "glmnet") - - for (method in stack_methods) { - if (method == "gbm") { - stack <- caretStack( - model_list, - method = method, - verbose = FALSE - ) + for (method in stack_methods) { + for (model_list in list(models.reg, models.class)) { + stack <- if (method == "gbm") { + caretEnsemble::caretStack(model_list, method = method, verbose = FALSE) } else { - stack <- caretStack( - model_list, - method = method - ) + caretEnsemble::caretStack(model_list, method = method) } testthat::expect_s3_class(stack, "caretStack") testthat::expect_identical(stack$ens_model$method, method) - predictions <- predict(stack, newdata = test_data) - testthat::expect_identical(nrow(predictions), nrow(test_data)) + predictions <- predict(stack, newdata = if (identical(model_list, models.reg)) X.reg else X.class) + testthat::expect_identical(nrow(predictions), nrow(if (identical(model_list, models.reg)) X.reg else X.class)) } } }) -testthat::test_that("caretStack handles missing data in new data", { - models.class.subset <- models.class[c("rpart", "treebag")] - - stack <- caretStack( - models.class.subset, - method = "rpart" - ) - - test_data_with_na <- X.class - test_data_with_na[1L:5L, 1L] <- NA - - pred <- predict(stack, newdata = test_data_with_na) - testthat::expect_identical(nrow(pred), nrow(test_data_with_na)) -}) - -testthat::test_that("caretStack handles different metrics", { - metrics <- c("ROC", "Sens", "Spec") - for (metric in metrics) { - stack <- caretStack( - models.class, - method = "glm", - metric = metric, - trControl = caret::trainControl( - method = "cv", - number = 3L, - classProbs = TRUE, - summaryFunction = caret::twoClassSummary - ) - ) - testthat::expect_s3_class(stack, "caretStack") - testthat::expect_identical(stack$ens_model$metric, metric) - } -}) - -testthat::test_that("caretStack handles upsampling data", { - data(iris) - train_data <- iris - - imbalanced_data <- rbind( - train_data[train_data$Species == "setosa", ], - train_data[train_data$Species == "versicolor", ][1L:10L, ], - train_data[train_data$Species == "virginica", ][1L:5L, ] - ) - - model_list <- caretList( - x = imbalanced_data[, 1L:4L], - y = imbalanced_data$Species, - methodList = "rpart", - trControl = caret::trainControl( - method = "cv", - number = 3L, - classProbs = TRUE, - sampling = "up", - savePredictions = "final" - ) - ) - - stack <- caretStack( - model_list, - method = "rpart" - ) - - testthat::expect_s3_class(stack, "caretStack") - pred <- predict(stack, newdata = imbalanced_data) - testthat::expect_identical(nrow(pred), nrow(imbalanced_data)) -}) - testthat::test_that("caretStack handles custom preprocessing", { preprocess <- c("center", "scale", "pca") for (model_list in list(models.class, models.reg)) { - stack <- caretStack( - model_list, - method = "glm", - preProcess = preprocess - ) + stack <- caretEnsemble::caretStack(model_list, method = "glm", preProcess = preprocess) testthat::expect_s3_class(stack, "caretStack") testthat::expect_named(stack$ens_model$preProcess$method, c(preprocess, "ignore")) } @@ -261,7 +164,7 @@ testthat::test_that("caretStack handles custom performance function", { } for (model_list in list(models.class, models.reg)) { - stack <- caretStack( + stack <- caretEnsemble::caretStack( model_list, method = "glm", metric = "default", @@ -273,107 +176,167 @@ testthat::test_that("caretStack handles custom performance function", { } }) -testthat::test_that("predict.caretStack works if excluded_class_id is not set", { - ens <- caretStack(models.class) - ens[["excluded_class_id"]] <- NULL - pred <- testthat::expect_warning(predict(ens, X.class), "No excluded_class_id set. Setting to 1L.") - - # Note that we don't exclude the class from the ensemble predictions, but merely from the preprocessing - testthat::expect_s3_class(pred, "data.table") # caret returns data.frame - testthat::expect_identical(nrow(pred), nrow(X.class)) - testthat::expect_identical(ncol(pred), 2L) - testthat::expect_named(pred, c("No", "Yes")) -}) - -testthat::context("Edge cases") - -testthat::test_that("caretStack coerces lists to caretLists", { - model_list <- models.reg - class(model_list) <- "list" - names(model_list) <- NULL - ens <- testthat::expect_warning( - caretStack(model_list), - "Attempting to coerce all.models to a caretList." - ) - testthat::expect_s3_class(ens, "caretStack") - testthat::expect_s3_class(ens$models, "caretList") - testthat::expect_named(ens$models, names(models.reg)) -}) - -testthat::test_that("caretStack fails if new_X is NULL and newY is not and vice versa", { - err <- "Both new_X and new_y must be NULL, or neither." - testthat::expect_error(caretStack(models.reg, new_X = NULL, new_y = Y.reg), err) - testthat::expect_error(caretStack(models.reg, new_X = X.reg, new_y = NULL), err) -}) - -testthat::test_that("caretStack works if both new_X and new_Y are supplied", { +testthat::test_that("caretStack handles new data correctly", { set.seed(42L) N <- 50L idx <- sample.int(nrow(X.reg), N) + stack_class <- caretStack( models.class, + metric = "ROC", + method = "rpart", new_X = X.class[idx, ], new_y = Y.class[idx], - method = "rpart", - # Need probs for stacked preds - trControl = caret::trainControl(method = "cv", number = 2L, savePredictions = "final", classProbs = TRUE) + trControl = control_class ) + stack_reg <- caretStack( models.reg, + method = "glm", new_X = X.reg[idx, ], new_y = Y.reg[idx], - method = "glm", - # Need probs for stacked preds - trControl = caret::trainControl(method = "cv", number = 2L, savePredictions = "final", classProbs = FALSE) + trControl = control_reg ) testthat::expect_s3_class(stack_class, "caretStack") testthat::expect_s3_class(stack_reg, "caretStack") - pred_class_stack <- predict(stack_class) - stack_reg_stack <- predict(stack_reg) - - testthat::expect_s3_class(pred_class_stack, "data.table") - testthat::expect_s3_class(stack_reg_stack, "data.table") - - testthat::expect_identical(nrow(pred_class_stack), N) - testthat::expect_identical(nrow(stack_reg_stack), N) - - testthat::expect_identical(ncol(pred_class_stack), 2L) - testthat::expect_identical(ncol(stack_reg_stack), 1L) - - pred_class <- predict(stack_class, new_X = X.class) - pred_reg <- predict(stack_reg, new_X = X.reg) + pred_class <- predict(stack_class, X.class) + pred_reg <- predict(stack_reg, X.reg) testthat::expect_s3_class(pred_class, "data.table") testthat::expect_s3_class(pred_reg, "data.table") - testthat::expect_identical(nrow(pred_class), N) - testthat::expect_identical(nrow(pred_reg), N) + testthat::expect_identical(nrow(pred_class), nrow(X.class)) + testthat::expect_identical(nrow(pred_reg), nrow(X.reg)) testthat::expect_identical(ncol(pred_class), 2L) testthat::expect_identical(ncol(pred_reg), 1L) }) -testthat::test_that("varImp works in for class and reg in sample", { +testthat::test_that("caretStack coerces lists to caretLists", { + models <- list( + models.class[[1L]], + models.class[[2L]] + ) + testthat::expect_warning( + caretStack(models, method = "glm", tuneLength = 1L), + "Attempting to coerce all.models to a caretList." + ) +}) + +testthat::test_that("caretStack errors if new_X is provided but not new_y", { + testthat::expect_error( + caretStack(models.class, new_X = X.class), + "Both new_X and new_y must be NULL, or neither." + ) +}) + +testthat::test_that("caretStack errors if new_y is provided but not new_X", { + testthat::expect_error( + caretStack(models.class, new_y = Y.class), + "Both new_X and new_y must be NULL, or neither." + ) +}) + +###################################################################### +testthat::context("S3 methods for caretStack") +###################################################################### + +testthat::test_that("print", { for (ens in list(ens.class, ens.reg)) { - imp <- varImp(ens) - expect_is(imp, "numeric") - expect_named(imp, names(ens$models)) - expect_equal(sum(imp), 1.0, tolerance = 1e-6) + testthat::expect_output(print(ens), "The following models were ensembled: rf, glm, rpart, treebag") + testthat::expect_output(print(ens), "150 samples") + testthat::expect_output(print(ens), "4 predictor") } }) -testthat::test_that("varImp works in for class on new data", { - imp <- varImp(ens.class, X.class) - expect_is(imp, "numeric") - expect_named(imp, names(ens.class$models)) - expect_equal(sum(imp), 1.0, tolerance = 1e-6) +testthat::test_that("summary", { + for (ens in list(ens.class, ens.reg)) { + s <- summary(ens) + testthat::expect_s3_class(s, "summary.caretStack") + testthat::expect_output(print(s), "The following models were ensembled: rf, glm, rpart, treebag") + testthat::expect_output(print(s), "Model Importance:") + testthat::expect_output(print(s), "Model accuracy:") + } +}) + +testthat::test_that("plot", { + for (ens in list(ens.class, ens.reg)) { + p <- plot(ens) + testthat::expect_s3_class(p, "ggplot") + } +}) + +testthat::test_that("dotplot", { + for (ens in list(ens.class, ens.reg)) { + p <- lattice::dotplot(ens) + testthat::expect_s3_class(p, "trellis") + } +}) + +testthat::test_that("autoplot", { + for (ens in list(ens.class, ens.reg)) { + p <- ggplot2::autoplot(ens) + testthat::expect_s3_class(p, "ggplot") + } +}) + +###################################################################### +testthat::context("varImp") +###################################################################### + +testthat::test_that("varImp works for classification and regression", { + for (ens in list(ens.class, ens.reg)) { + imp <- caret::varImp(ens) + testthat::expect_type(imp, "double") + testthat::expect_named(imp, names(ens$models)) + testthat::expect_equal(sum(imp), 1.0, tolerance = 1e-6) + + imp_new_data <- caret::varImp(ens, if (identical(ens, ens.class)) X.class else X.reg) + testthat::expect_type(imp_new_data, "double") + testthat::expect_named(imp_new_data, names(ens$models)) + testthat::expect_equal(sum(imp_new_data), 1.0, tolerance = 1e-6) + } }) -testthat::test_that("varImp works in for reg on new data", { - imp <- varImp(ens.reg, X.class) - expect_is(imp, "numeric") - expect_named(imp, names(ens.reg$models)) - expect_equal(sum(imp), 1.0, tolerance = 1e-6) +###################################################################### +testthat::context("wtd.sd") +###################################################################### + +testthat::test_that("wtd.sd calculates weighted standard deviation correctly", { + x <- c(1L, 2L, 3L, 4L, 5L) + w <- c(1L, 1L, 1L, 1L, 1L) + testthat::expect_equal(caretEnsemble::wtd.sd(x, w), stats::sd(x), tolerance = 0.001) + + w_uneven <- c(2L, 1L, 1L, 1L, 1L) + testthat::expect_false(isTRUE(all.equal(caretEnsemble::wtd.sd(x, w_uneven), stats::sd(x)))) + + x_na <- c(1L, 2L, NA, 4L, 5L) + testthat::expect_true(is.na(caretEnsemble::wtd.sd(x_na, w))) + testthat::expect_false(is.na(caretEnsemble::wtd.sd(x_na, w, na.rm = TRUE))) + + testthat::expect_error(caretEnsemble::wtd.sd(x, w[-1L]), "'x' and 'w' must have the same length") + + x3 <- c(10L, 10L, 10L, 20L) + w1 <- c(0.1, 0.1, 0.1, 0.7) + testthat::expect_equal(caretEnsemble::wtd.sd(x3, w = w1), 5.291503, tolerance = 0.001) + testthat::expect_equal(caretEnsemble::wtd.sd(x3, w = w1 * 100L), caretEnsemble::wtd.sd(x3, w = w1), tolerance = 0.001) +}) + +###################################################################### +testthat::context("set_excluded_class_id") +###################################################################### + +testthat::test_that("set_excluded_class_id warning if unset", { + old_ensemble <- ens.class + old_ensemble$excluded_class_id <- NULL + + is_class <- isClassifier(old_ensemble) + new_ensemble <- expect_warning( + set_excluded_class_id(old_ensemble, is_class), + "No excluded_class_id set. Setting to 1L." + ) + + testthat::expect_identical(new_ensemble$excluded_class_id, 1L) }) diff --git a/tests/testthat/test-classSelection.R b/tests/testthat/test-classSelection.R index 62c4e7fa..af631e2a 100644 --- a/tests/testthat/test-classSelection.R +++ b/tests/testthat/test-classSelection.R @@ -1,28 +1,21 @@ -testthat::context("Does binary class selection work?") - # Load and prepare data for subsequent tests seed <- 2239L set.seed(seed) -data(models.class) -data(X.class) -data(Y.class) +utils::data(iris) # Create 80/20 train/test split -index <- caret::createDataPartition(Y.class, p = 0.8)[[1L]] -X.train <- X.class[index, ] -X.test <- X.class[-index, ] -Y.train <- Y.class[index] -Y.test <- Y.class[-index] - -############################################################################# -testthat::context("Do classifier predictions use the correct target classes?") -############################################################################# +target_col <- which(names(iris) == "Species") +index <- caret::createDataPartition(iris[, target_col], p = 0.8)[[1L]] +X.train <- iris[index, -target_col] +X.test <- iris[-index, -target_col] +Y.train <- iris[index, target_col] +Y.test <- iris[-index, target_col] runBinaryLevelValidation <- function(Y.train, Y.test, pos.level = 1L) { # Extract levels of response input data Y.levels <- levels(Y.train) testthat::expect_identical(Y.levels, levels(Y.test)) - testthat::expect_length(Y.levels, 2L) + testthat::expect_length(Y.levels, 3L) # Train a caret ensemble model.list <- caretList( @@ -73,50 +66,31 @@ runBinaryLevelValidation <- function(Y.train, Y.test, pos.level = 1L) { # check exists to avoid previous errors where classifer ensemble predictions were # being made using the incorrect level of the response, causing the opposite # class labels to be predicted with new data. - testthat::expect_gt(cmat.pred$overall["Accuracy"], 0.79) + testthat::expect_gt(cmat.pred$overall["Accuracy"], 0.60) # Similar to the above, ensure that probability predictions are working correctly # by checking to see that accuracy is also high for class predictions created # from probabilities - testthat::expect_gt(cmat.cutoff$overall["Accuracy"], 0.79) + testthat::expect_gt(cmat.cutoff$overall["Accuracy"], 0.60) } -testthat::test_that("Ensembled classifiers do not rearrange outcome factor levels", { - # First run the level selection test using the default levels - # of the response (i.e. c('No', 'Yes')) - set.seed(seed) - runBinaryLevelValidation(Y.train, Y.test, pos.level = 1L) +############################################################################# +testthat::context("Do classifier predictions use the correct target classes?") +############################################################################# - # Now reverse the assigment of the response labels as well as - # the levels of the response factor. Reversing the assignment - # is necessary to make sure the expected accuracy numbers are - # the same (i.e. Making a "No" into a "Yes" in the response means - # predictions of the first class will still be as accurate). - # Reversing the level order then ensures that the outcome is not - # releveled at some point by caretEnsemble. - Y.levels <- levels(Y.train) - refactor <- function(d) { - factor( - ifelse(d == Y.levels[1L], Y.levels[2L], Y.levels[1L]), - levels = rev(Y.levels) - ) +testthat::test_that("validateExcludedClass for multiclass", { + for (excluded_class in c(1L, 2L, 3L)) { + testthat::expect_silent(validateExcludedClass(excluded_class)) } - - set.seed(seed) - runBinaryLevelValidation(refactor(Y.train), refactor(Y.test)) + testthat::expect_error(validateExcludedClass("x"), "classification excluded level must be numeric") }) testthat::test_that("Target class selection configuration works", { - # No error - excluded_class <- validateExcludedClass(1L) - excluded_class <- validateExcludedClass(2L) - - # Should error - testthat::expect_error(validateExcludedClass("x"), "classification excluded level must be numeric") - - # Check that we can exclude the first class Y.levels <- levels(Y.train) refactor <- function(d) factor(as.character(d), levels = rev(Y.levels)) set.seed(seed) - runBinaryLevelValidation(refactor(Y.train), refactor(Y.test), pos.level = 1L) + for (pos in c(1L, 2L, 3L)) { + runBinaryLevelValidation(Y.train, Y.test, pos.level = pos) + runBinaryLevelValidation(refactor(Y.train), refactor(Y.test), pos.level = pos) + } }) diff --git a/tests/testthat/test-ensembleMethods.R b/tests/testthat/test-ensembleMethods.R deleted file mode 100644 index cac9430d..00000000 --- a/tests/testthat/test-ensembleMethods.R +++ /dev/null @@ -1,115 +0,0 @@ -# Are tests failing here? -# UPDATE THE FIXTURES! -# make update-test-fixtures - -testthat::context("Does variable importance work?") - -data(models.reg) -data(X.reg) -data(Y.reg) - -data(models.class) -data(X.class) -data(Y.class) - -ens.class <- caretEnsemble( - models.class, - metric = "ROC", - trControl = caret::trainControl( - number = 2L, - summaryFunction = caret::twoClassSummary, - classProbs = TRUE, - savePredictions = TRUE - ) -) -ens.reg <- caretEnsemble(models.reg, trControl = caret::trainControl(number = 2L, savePredictions = TRUE)) - -testthat::test_that("caret::varImp.caretEnsemble", { - set.seed(2239L) - - for (m in list(ens.class, ens.reg)) { - for (s in c(TRUE, FALSE)) { - i <- caret::varImp(m, normalize = s) - testthat::expect_is(i, "numeric") - if (isClassifier(m)) { - len <- length(m$models) * 2L - n <- c(outer(c("rf", "glm", "rpart", "treebag"), c("No", "Yes"), paste, sep = "_")) - n <- matrix(n, ncol = 2L) - n <- c(t(n)) - } else { - len <- length(m$models) - n <- names(m$models) - } - testthat::expect_length(i, len) - testthat::expect_named(i, n) - if (s) { - testthat::expect_true(all(i >= 0.0)) - testthat::expect_true(all(i <= 1.0)) - testthat::expect_equal(sum(i), 1.0, tolerance = 1e-6) - } - } - } -}) - -testthat::test_that("plot.caretEnsemble", { - for (ens in list(ens.class, ens.reg)) { - plt <- plot(ens) - testthat::expect_is(plt, "ggplot") - testthat::expect_identical(nrow(plt$data), 5L) # 4 models, one ensemble - testthat::expect_named(ens$models, plt$data$model_name[-1L]) # First is ensemble - } -}) - -testthat::test_that("ggplot2::autoplot.caretEnsemble", { - for (ens in list(ens.class, ens.reg)) { - plt1 <- ggplot2::autoplot(ens) - plt2 <- ggplot2::autoplot(ens, xvars = c("Petal.Length", "Petal.Width")) - - testthat::expect_is(plt1, "ggplot") - testthat::expect_is(plt2, "ggplot") - - testthat::expect_is(plt1, "patchwork") - testthat::expect_is(plt2, "patchwork") - - train_model <- ens.reg$models[[1L]] - testthat::expect_error(ggplot2::autoplot(train_model), "Objects of class (.*?) are not supported by autoplot") - } -}) - -testthat::test_that("summary.caretEnsemble", { - for (ens in list(ens.class, ens.reg)) { - smry <- testthat::expect_silent(summary(ens.class)) - testthat::expect_output(print(smry), ens.class$ens_model$metric) - for (name in names(ens.class$models)) { - testthat::expect_output(print(smry), name) - } - } -}) - -testthat::test_that("extractModelMetrics", { - for (ens in list(ens.class, ens.reg)) { - metrics <- extractMetric(ens) - testthat::expect_s3_class(metrics, "data.table") - testthat::expect_named(ens$models, metrics$model_name[-1L]) - } -}) - -testthat::test_that("precict.caretEnsemble with and without se and weights", { - for (ens in list(ens.class, ens.reg)) { - is_class <- isClassifier(ens) - for (se in c(FALSE, TRUE)) { - p <- predict( - ens, - newdata = X.reg, - se = se, - excluded_class_id = 1L - ) - expect_s3_class(p, "data.table") - if (se) { - testthat::expect_named(p, c("pred", "lwr", "upr")) - } else { - testthat::expect_named(p, ifelse(is_class, "Yes", "pred")) - } - } - } -}) diff --git a/tests/testthat/test-helper_functions.R b/tests/testthat/test-helper_functions.R deleted file mode 100644 index 894253fb..00000000 --- a/tests/testthat/test-helper_functions.R +++ /dev/null @@ -1,444 +0,0 @@ -######################################################################## -testthat::context("Do the helper functions work for regression objects?") -######################################################################## - -data(models.reg) -data(X.reg) -data(Y.reg) - -data(models.class) -data(X.class) -data(Y.class) - -testthat::test_that("Recycling generates a warning", { - testthat::expect_error( - caretEnsemble::wtd.sd(matrix(1L:10L, ncol = 2L), w = 1L), - "'x' and 'w' must have the same length" - ) -}) - -testthat::test_that("No predictions generates an error", { - models_multi <- caretList( - iris[, 1L:2L], iris[, 5L], - tuneLength = 1L, verbose = FALSE, - methodList = c("rf", "gbm") - ) - testthat::expect_is(vapply(models_multi, isClassifierAndValidate, logical(1L)), "logical") - - models <- caretList( - iris[, 1L:2L], factor(ifelse(iris[, 5L] == "setosa", "Yes", "No")), - tuneLength = 1L, verbose = FALSE, - methodList = c("rf", "gbm") - ) - new_model <- caret::train( - iris[, 1L:2L], factor(ifelse(iris[, 5L] == "setosa", "Yes", "No")), - tuneLength = 1L, - method = "glmnet", - metric = "ROC", - trControl = caret::trainControl( - method = "cv", - number = 2L, - classProbs = TRUE, - summaryFunction = caret::twoClassSummary, - savePredictions = "final" - ) - ) - models2 <- c(new_model, models) - models3 <- c(models, new_model) - testthat::expect_is(vapply(models, isClassifierAndValidate, logical(1L)), "logical") - testthat::expect_is(vapply(models2, isClassifierAndValidate, logical(1L)), "logical") - testthat::expect_is(vapply(models3, isClassifierAndValidate, logical(1L)), "logical") -}) - -testthat::test_that("We can make the stacked predictions matrix", { - out <- predict(models.reg) - testthat::expect_s3_class(out, "data.table") - testthat::expect_identical(dim(out), c(150L, 4L)) - testthat::expect_named(out, c("rf", "glm", "rpart", "treebag")) -}) - -testthat::test_that("We can predict", { - out <- predict(models.reg, newdata = X.reg) - testthat::expect_is(out, "data.table") - testthat::expect_identical(dim(out), c(150L, 4L)) - testthat::expect_named(out, c("rf", "glm", "rpart", "treebag")) -}) - -######################################################################## -testthat::context("Do the helper functions work for classification objects?") -######################################################################## - -testthat::test_that("We can make the stacked predictions matrix", { - out <- predict(models.class) - testthat::expect_s3_class(out, "data.table") - testthat::expect_identical(dim(out), c(150L, 4L * 1L)) # number of models * (number of classes-1) -}) - -testthat::test_that("We can predict", { - out <- predict(models.class, newdata = X.class, excluded_class_id = 0L) - testthat::expect_is(out, "data.table") - testthat::expect_identical(dim(out), c(150L, 4L * 2L)) - model_names <- c("rf", "glm", "rpart", "treebag") - class_names <- c("No", "Yes") - combinations <- expand.grid(class_names, model_names) - testthat::expect_named(out, paste(combinations$Var2, combinations$Var1, sep = "_")) - out2 <- predict(models.reg, newdata = X.reg) - testthat::expect_identical(dim(out2), c(150L, 4L)) - testthat::expect_named(out2, c("rf", "glm", "rpart", "treebag")) -}) - -testthat::test_that("predict results same regardless of verbose option", { - invisible(capture.output({ - testthat::expect_is(predict(models.class, newdata = X.class), "data.table") - out1 <- predict(models.class, newdata = X.class) - out2 <- predict(models.class, verbose = TRUE, newdata = X.class) - testthat::expect_identical(out1, out2) - - testthat::expect_is(predict(models.reg, newdata = X.reg), "data.table") - out1 <- predict(models.reg, newdata = X.reg) - out2 <- predict(models.reg, verbose = TRUE, newdata = X.reg) - testthat::expect_identical(out1, out2) - })) -}) - -testthat::context("Test weighted standard deviations") - -testthat::test_that("wtd.sd applies weights correctly", { - x1 <- c(3L, 5L, 9L, 3L, 4L, 6L, 4L) - x2 <- c(10L, 10L, 20L, 14L, 2L, 2L, 40L) - x3 <- c(10L, 10L, 10L, 20L) - w1 <- c(0.1, 0.1, 0.1, 0.7) - testthat::expect_error(caretEnsemble::wtd.sd(x1), 'argument "w" is missing, with no default') - testthat::expect_false(sd(x1) == caretEnsemble::wtd.sd(x1, w = x2)) - testthat::expect_false(sd(x1) == caretEnsemble::wtd.sd(x1, w = x2)) - testthat::expect_equal(caretEnsemble::wtd.sd(x3, w = w1), 5.291503, tolerance = 0.001) - testthat::expect_equal(caretEnsemble::wtd.sd(x3, w = w1 * 100L), caretEnsemble::wtd.sd(x3, w = w1), tolerance = 0.001) -}) - -testthat::test_that("wtd.sd handles NA values correctly", { - x1 <- c(10L, 10L, 10L, 20L, NA, NA) - w1 <- c(0.1, 0.1, 0.1, 0.7, NA, NA) - testthat::expect_true(is.na(caretEnsemble::wtd.sd(x1, w = w1))) - testthat::expect_true(is.na(sd(x1))) - testthat::expect_false(is.na(caretEnsemble::wtd.sd(x1, w = w1, na.rm = TRUE))) - testthat::expect_false(is.na(sd(x1, na.rm = TRUE))) - testthat::expect_true(is.na(caretEnsemble::wtd.sd(x1, w = w1))) - testthat::expect_false(is.na(caretEnsemble::wtd.sd(x1, w = w1, na.rm = TRUE))) -}) - -testthat::test_that("caretList supports combined regression, binary, multiclass", { - set.seed(42L) - - # Regression models - reg_models <- caretList( - Sepal.Length ~ Sepal.Width, - iris, - methodList = c("glm", "lm") - ) - testthat::expect_is(predict(reg_models), "data.table") - - # Binary model - bin_models <- caretList( - factor(ifelse(Species == "setosa", "Yes", "No")) ~ Sepal.Width, - iris, - methodList = c("lda", "rpart") - ) - testthat::expect_is(predict(bin_models), "data.table") - - # Multiclass model - multi_models <- caretList( - Species ~ Sepal.Width, - iris, - methodList = "rpart" - ) - testthat::expect_is(predict(multi_models), "data.table") - - # Combine them! - all_models <- c(reg_models, bin_models, multi_models) - testthat::expect_s3_class(all_models, "caretList") - testthat::expect_is(vapply(all_models, isClassifierAndValidate, logical(1L)), "logical") - - # Test preds - stacked_p <- predict(all_models) - new_p <- predict(all_models, newdata = iris[seq_len(10L), ]) - testthat::expect_is(stacked_p, "data.table") - testthat::expect_is(new_p, "data.table") - testthat::expect_identical(nrow(stacked_p), nrow(iris)) - testthat::expect_identical(nrow(new_p), 10L) -}) - -testthat::test_that("isClassifierAndValidate shouldn't care about predictions", { - model_list <- models.class - model_list[[1L]]$pred <- NULL - testthat::expect_is(vapply(model_list, isClassifierAndValidate, logical(1L)), "logical") - testthat::expect_equivalent(unique(vapply(model_list, isClassifierAndValidate, logical(1L))), TRUE) -}) - -testthat::test_that("isClassifierAndValidate stops when a classification model can't predict probabilities", { - model_list <- models.class - model_list[[1L]]$modelInfo$prob <- FALSE - err <- "No probability function found. Re-fit with a method that supports prob." - testthat::expect_error(lapply(model_list, isClassifierAndValidate), err) -}) - -testthat::test_that("isClassifierAndValidate stops when a classification model did not save probs", { - model_list <- models.class - model_list[[1L]]$control$classProbs <- FALSE - err <- "classProbs = FALSE. Re-fit with classProbs = TRUE in trainControl." - testthat::expect_error(lapply(model_list, isClassifierAndValidate, validate_for_stacking = TRUE), err) - testthat::context("Test helper functions for multiclass classification") - - testthat::test_that("Configuration function for excluded level work", { - # Integers work - testthat::expect_identical(validateExcludedClass(0L), 0L) - testthat::expect_identical(validateExcludedClass(1L), 1L) - testthat::expect_identical(validateExcludedClass(4L), 4L) - - # Decimals work with a warning - wrn <- "classification excluded level is not an integer:" - testthat::expect_warning(testthat::expect_identical(validateExcludedClass(0.0), 0L), wrn) - testthat::expect_warning(testthat::expect_identical(validateExcludedClass(1.0), 1L), wrn) - testthat::expect_warning(testthat::expect_identical(validateExcludedClass(4.0), 4L), wrn) - - # Less than 0 will error - testthat::expect_error(validateExcludedClass(-1L), "classification excluded level must be >= 0: -1") - - # Make a model list - data(iris) - model_list <- caretList( - x = iris[, -5L], - y = iris[, 5L], - methodList = c("rpart", "glmnet") - ) - - # Stacking with the excluded level should work - invisible(caretStack(model_list, method = "knn", excluded_class_id = 1L)) - - # Stacking with too great of a level should work. No error or warning. - # Should also validate it? - stack <- caretStack(model_list, method = "knn", excluded_class_id = 4L) - invisible(predict(stack, iris[, -5L])) - - # Check if we are actually excluding level 1 (setosa) - classes <- levels(iris[, 5L])[-1L] - models <- c("rpart", "glmnet") - class_model_combinations <- expand.grid(classes, models) - varImp_rownames <- apply(class_model_combinations, 1L, function(x) paste(x[2L], x[1L], sep = "_")) - - model_stack <- caretStack(model_list, method = "knn", excluded_class_id = 1L) - testthat::expect_identical(rownames(caret::varImp(model_stack$ens_model)$importance), varImp_rownames) - }) -}) - -# Tests for validateExcludedClass function -testthat::test_that("validateExcludedClass stops for non-numeric input", { - invalid_input <- "invalid" - err <- "classification excluded level must be numeric: invalid" - testthat::expect_error(validateExcludedClass(invalid_input), err) -}) - -testthat::test_that("validateExcludedClass stops for non-finite input", { - invalid_input <- Inf - err <- "classification excluded level must be finite: Inf" - testthat::expect_warning( - testthat::expect_error(validateExcludedClass(invalid_input), err), - "classification excluded level is not an integer: Inf" - ) -}) - -testthat::test_that("validateExcludedClass stops for non-positive input", { - invalid_input <- -1.0 - err <- "classification excluded level must be >= 0: -1" - wrn <- "classification excluded level is not an integer:" - testthat::expect_warning(testthat::expect_error(validateExcludedClass(invalid_input), err), wrn) -}) - -validated <- testthat::test_that("validateExcludedClass warns for non-integer input", { - testthat::expect_identical( - testthat::expect_warning( - validateExcludedClass(1.1), - "classification excluded level is not an integer: 1.1" - ), 1L - ) -}) - -testthat::test_that("validateExcludedClass passes for valid input", { - valid_input <- 3L - testthat::expect_identical(validateExcludedClass(valid_input), 3L) -}) - -######################################################################## -testthat::context("Helper function edge cases") -######################################################################## - -testthat::test_that("wtd.sd calculates weighted standard deviation correctly", { - x <- c(1L, 2L, 3L, 4L, 5L) - w <- c(1L, 1L, 1L, 1L, 1L) - testthat::expect_equal(wtd.sd(x, w), sd(x), tol = 0.001) - - w <- c(2L, 1L, 1L, 1L, 1L) - testthat::expect_true(wtd.sd(x, w) != sd(x)) - - # Test with NA values - x_na <- c(1L, 2L, NA, 4L, 5L) - testthat::expect_true(is.na(wtd.sd(x_na, w))) - testthat::expect_false(is.na(wtd.sd(x_na, w, na.rm = TRUE))) - - # Test error for mismatched lengths - testthat::expect_error(wtd.sd(x, w[-1L]), "'x' and 'w' must have the same length") -}) - -testthat::test_that("isClassifierAndValidate validates caretList correctly", { - testthat::expect_is(vapply(models.class, isClassifierAndValidate, logical(1L)), "logical") - testthat::expect_is(vapply(models.reg, isClassifierAndValidate, logical(1L)), "logical") - - # Test error for non-caretList object - testthat::expect_error( - isClassifierAndValidate(list(model = lm(Y.reg ~ ., data = as.data.frame(X.reg)))), - "is(object, \"train\") is not TRUE", - fixed = TRUE - ) -}) - -testthat::test_that("isClassifierAndValidate validates model types correctly", { - testthat::expect_is(vapply(models.class, isClassifierAndValidate, logical(1L)), "logical") - testthat::expect_is(vapply(models.reg, isClassifierAndValidate, logical(1L)), "logical") - - # Test error for mixed model types - mixed_list <- c(models.class, models.reg) - testthat::expect_is(vapply(mixed_list, isClassifierAndValidate, logical(1L)), "logical") -}) - -testthat::test_that("Stacked predictions for caret lists works", { - best_preds_class <- predict(models.class) - best_preds_reg <- predict(models.reg) - - testthat::expect_is(best_preds_class, "data.table") - testthat::expect_is(best_preds_reg, "data.table") - - testthat::expect_named(best_preds_class, names(models.class)) - testthat::expect_named(best_preds_reg, names(models.reg)) -}) - -testthat::test_that("Stacked predictions works with different resampling strategies", { - models.class.inconsistent <- models.class - models.class.inconsistent[[1L]]$pred$Resample <- "WEIRD_SAMPLING" - testthat::expect_is(predict(models.class.inconsistent), "data.table") -}) - -testthat::test_that("Stacked predictions works if the row indexes differ", { - models.class.inconsistent <- models.class - models.class.inconsistent[[1L]]$pred$rowIndex <- rev(models.class.inconsistent[[1L]]$pred$rowIndex) - big_preds <- rbind(models.class.inconsistent[[2L]]$pred, models.class.inconsistent[[2L]]$pred) - models.class.inconsistent[[2L]]$pred <- big_preds - testthat::expect_is(predict(models.class.inconsistent), "data.table") -}) - -testthat::test_that("extractModelName extracts model names correctly", { - testthat::expect_identical(extractModelName(models.class[[1L]]), "rf") - testthat::expect_identical(extractModelName(models.reg[[1L]]), "rf") - - # Test custom model - custom_model <- models.class[[1L]] - custom_model$method <- list(method = "custom_rf") - testthat::expect_identical(extractModelName(custom_model), "custom_rf") -}) - -testthat::test_that("isClassifierAndValidate extracts model types correctly", { - testthat::expect_true(unique(vapply(models.class, isClassifierAndValidate, logical(1L)))) - testthat::expect_false(unique(vapply(models.reg, isClassifierAndValidate, logical(1L)))) -}) - -testthat::test_that("caretPredict extracts best predictions correctly", { - stacked_preds_class <- caretPredict(models.class[[1L]], excluded_class_id = 0L) - stacked_preds_reg <- caretPredict(models.reg[[1L]]) - - testthat::expect_s3_class(stacked_preds_class, "data.table") - testthat::expect_s3_class(stacked_preds_reg, "data.table") - - testthat::expect_named(stacked_preds_class, c("No", "Yes")) - testthat::expect_named(stacked_preds_reg, "pred") -}) - -testthat::test_that("Stacked predictions creates prediction-observation data correctly", { - stacked_preds_class <- predict(models.class) - stacked_preds_reg <- predict(models.reg) - - testthat::expect_s3_class(stacked_preds_class, "data.table") - testthat::expect_s3_class(stacked_preds_reg, "data.table") - - testthat::expect_identical(ncol(stacked_preds_class), length(models.class)) - testthat::expect_identical(ncol(stacked_preds_reg), length(models.reg)) - - testthat::expect_named(stacked_preds_class, names(models.class)) - testthat::expect_named(stacked_preds_reg, names(stacked_preds_reg)) - - testthat::expect_identical(nrow(stacked_preds_class), 150L) - testthat::expect_identical(nrow(stacked_preds_reg), 150L) -}) - -testthat::test_that("Stacked predictions works on new model types", { - # Note that new model types would have to return a single column called 'pred' - models.class.new <- models.reg - for (idx in seq_along(models.class.new)) { - models.class.new[[idx]]$modelType <- "TimeSeries" - } - preds <- predict(models.class.new) - testthat::expect_s3_class(preds, "data.table") -}) - -testthat::test_that("validateExcludedClass validates excluded level correctly", { - testthat::expect_warning(validateExcludedClass(NULL), "No excluded_class_id set. Setting to 1L.") - testthat::expect_error( - validateExcludedClass(c(1L, 2L)), - "classification excluded level must have a length of 1: length=2" - ) - testthat::expect_error(validateExcludedClass("a"), "classification excluded level must be numeric: a") - testthat::expect_error(validateExcludedClass(-1L), "classification excluded level must be >= 0: -1") - testthat::expect_warning( - testthat::expect_error(validateExcludedClass(-0.000001), "classification excluded level must be >= 0: -1e-06"), - "classification excluded level is not an integer" - ) - testthat::expect_warning( - testthat::expect_error(validateExcludedClass(Inf), "classification excluded level must be finite: Inf"), - "classification excluded level is not an integer" - ) - testthat::expect_warning(validateExcludedClass(1.5), "classification excluded level is not an integer: 1.5") - txt <- "classification excluded level is not an integer: 2" - testthat::expect_warning( - testthat::expect_identical( - validateExcludedClass(2.0), 2L - ), txt, - "classification excluded level is not an integer" - ) -}) - -testthat::test_that("validateExcludedClass validates excluded level correctly", { - testthat::expect_warning(validateExcludedClass(NULL), "No excluded_class_id set. Setting to 1L.") - testthat::expect_error( - validateExcludedClass(c(1L, 2L)), - "classification excluded level must have a length of 1: length=2" - ) - testthat::expect_error(validateExcludedClass("a"), "classification excluded level must be numeric: a") - testthat::expect_error(validateExcludedClass(-1L), "classification excluded level must be >= 0: -1") - testthat::expect_warning( - testthat::expect_error(validateExcludedClass(-0.000001), "classification excluded level must be >= 0: -1e-06"), - "classification excluded level is not an integer" - ) - testthat::expect_warning( - testthat::expect_error(validateExcludedClass(Inf), "classification excluded level must be finite: Inf"), - "classification excluded level is not an integer" - ) - testthat::expect_warning(validateExcludedClass(1.5), "classification excluded level is not an integer: 1.5") - txt <- "classification excluded level is not an integer: 2" - testthat::expect_warning(testthat::expect_identical(validateExcludedClass(2.0), 2L), txt) -}) - -testthat::test_that("isClassifierAndValidate fails for models without object$control$savePredictions", { - model <- models.class[[1L]] - model$control$savePredictions <- NULL - err <- "Must have savePredictions = 'all', 'final', or TRUE in trainControl to do stacked predictions." - testthat::expect_error(isClassifierAndValidate(model), err) - model$control$savePredictions <- "BAD_VALUE" - testthat::expect_error(isClassifierAndValidate(model), err) -}) diff --git a/tests/testthat/test-multiclass.R b/tests/testthat/test-multiclass.R index 8a825633..54d4a5f0 100644 --- a/tests/testthat/test-multiclass.R +++ b/tests/testthat/test-multiclass.R @@ -1,16 +1,23 @@ -############################################################################# -testthat::context("caretList and caretStack work for multiclass problems") -############################################################################# -testthat::test_that("We can predict with caretList and caretStack multiclass problems", { - data(iris) - model_list <- caretList( - x = iris[, -5L], - y = iris[, 5L], - methodList = c("glmnet", "rpart") +utils::data(iris) +utils::data(Boston, package = "MASS") + +model_list <- caretList( + iris[, -5L], + iris[, 5L], + tuneLength = 1L, + methodList = c("glmnet", "rpart"), + tuneList = list( + nnet = caretModelSpec(method = "nnet", trace = FALSE) ) +) +###################################################################### +testthat::context("caretList and caretStack work for multiclass problems") +###################################################################### + +testthat::test_that("We can predict with caretList and caretStack for multiclass problems", { p <- predict(model_list, newdata = iris[, -5L]) - testthat::expect_is(p, "data.table") + testthat::expect_s3_class(p, "data.table") testthat::expect_identical(nrow(p), nrow(iris)) ens <- caretStack(model_list, method = "rpart") @@ -25,20 +32,9 @@ testthat::test_that("We can predict with caretList and caretStack multiclass pro }) testthat::test_that("Columns for caretList predictions are correct and ordered", { - data(iris) - model_list <- caretList( - x = iris[, -5L], - y = iris[, 5L], - methodList = c("glmnet", "rpart"), - tuneList = list( - nnet = caretModelSpec(method = "nnet", trace = FALSE) - ) - ) - num_methods <- length(model_list) num_classes <- length(unique(iris$Species)) - # Check the number of rows and columns is correct p <- predict(model_list, newdata = iris[, -5L], excluded_class_id = 0L) testthat::expect_identical(dim(p), c(nrow(iris), num_methods * num_classes)) @@ -47,48 +43,32 @@ testthat::test_that("Columns for caretList predictions are correct and ordered", class_method_combinations <- expand.grid(classes, methods) ordered_colnames <- apply(class_method_combinations, 1L, function(x) paste(x[2L], x[1L], sep = "_")) - # Check the names of the columns are correct testthat::expect_true(all(colnames(p) %in% ordered_colnames)) - - # Check that the columns are ordered correctly testthat::expect_named(p, ordered_colnames) }) testthat::test_that("Columns for caretStack are correct", { - data(iris) - model_list <- caretList( - x = iris[, -5L], - y = iris[, 5L], - methodList = "rpart", - tuneList = list( - nnet = caretModelSpec(method = "nnet", trace = FALSE) - ) - ) - model_stack <- caretStack(model_list, method = "knn") num_classes <- length(unique(iris$Species)) + classes <- levels(iris$Species) - # Check the number of rows and columns is correct p_raw <- predict(model_stack, newdata = iris[, -5L]) testthat::expect_identical(nrow(p_raw), nrow(iris)) + p_prob <- predict(model_stack, newdata = iris[, -5L]) testthat::expect_identical(dim(p_prob), c(nrow(iris), num_classes)) - - classes <- levels(iris$Species) - - # Check that the columns are ordered correctly testthat::expect_named(p_prob, classes) }) testthat::test_that("Periods are supported in method and class names in caretList and caretStack", { - data(iris) - # Rename values and levels to have underscores - levels(iris[, 5L]) <- c("setosa_1", "versicolor_2", "virginica_3") - iris[, 5L] <- factor(iris[, 5L]) + iris_mod <- iris + levels(iris_mod[, 5L]) <- c("setosa_1", "versicolor_2", "virginica_3") + iris_mod[, 5L] <- factor(iris_mod[, 5L]) + model_list <- caretList( - x = iris[, -5L], - y = iris[, 5L], + x = iris_mod[, -5L], + y = iris_mod[, 5L], methodList = c("glmnet", "rpart"), tuneList = list( nnet_1 = caretModelSpec( @@ -105,10 +85,9 @@ testthat::test_that("Periods are supported in method and class names in caretLis ) methods <- names(model_list) - classes <- levels(iris[, 5L]) - - p <- predict(model_list, newdata = iris[, -5L], excluded_class_id = 0L) + classes <- levels(iris_mod[, 5L]) + p <- predict(model_list, newdata = iris_mod[, -5L], excluded_class_id = 0L) class_method_combinations <- expand.grid(classes, methods) ordered_colnames <- apply(class_method_combinations, 1L, function(x) paste(x[2L], x[1L], sep = "_")) testthat::expect_named(p, ordered_colnames) @@ -116,58 +95,32 @@ testthat::test_that("Periods are supported in method and class names in caretLis model_stack <- caretStack(model_list, method = "knn", trControl = trainControl( savePredictions = "final", classProbs = TRUE )) - p_prob <- predict(model_stack, newdata = iris[, -5L]) + p_prob <- predict(model_stack, newdata = iris_mod[, -5L]) testthat::expect_named(p_prob, classes) - p_raw <- predict(model_stack, newdata = iris[, -5L]) + p_raw <- predict(model_stack, newdata = iris_mod[, -5L]) testthat::expect_named(p_raw, classes) }) testthat::test_that("We can make a confusion matrix", { - data(iris) - - set.seed(42L) - n <- nrow(iris) - train_indices <- sample.int(n, n * 0.8) - train_data <- iris[train_indices, ] - test_data <- iris[-train_indices, ] - model_list <- caretList( - x = train_data[, -5L], - y = train_data[, 5L], - methodList = c("glmnet", "rpart"), - tuneList = list( - nnet = caretModelSpec(method = "nnet", trace = FALSE) - ) - ) - model_stack <- caretStack(model_list, method = "knn") - # Make a confusion matrix - predictions <- predict(model_stack, newdata = test_data[, -5L]) - classes <- apply(predictions, 1L, function(x) names(x)[which.max(x)]) - classes <- factor(classes, levels = levels(test_data[, 5L])) - cm <- confusionMatrix(classes, test_data[, 5L]) - testthat::expect_is(cm, "confusionMatrix") + predictions <- predict(model_stack, newdata = iris[, -5L], return_class_only = TRUE) + cm <- caret::confusionMatrix(predictions, iris[, 5L]) - # Check dims + testthat::expect_s3_class(cm, "confusionMatrix") testthat::expect_identical(dim(cm$table), c(3L, 3L)) - # Accuracy should be greater than 0.9 - testthat::expect_gt(cm$overall["Accuracy"], 0.9) + testthat::expect_gt(cm$overall["Accuracy"], 0.95) # In sample accuracy should be high }) testthat::test_that("caretList and caretStack handle imbalanced multiclass data", { set.seed(123L) n <- 1000L - X <- data.table::data.table(x1 = rnorm(n), x2 = rnorm(n)) + X <- data.table::data.table(x1 = stats::rnorm(n), x2 = stats::rnorm(n)) y <- factor(c(rep("A", 700L), rep("B", 200L), rep("C", 100L))) - model_list <- caretList( - x = X, - y = y, - methodList = c("rpart", "glmnet") - ) - + model_list <- caretList(X, y, methodList = "rpart") testthat::expect_s3_class(model_list, "caretList") - testthat::expect_length(model_list, 2L) + testthat::expect_length(model_list, 1L) stack <- caretStack(model_list, method = "glmnet") testthat::expect_s3_class(stack, "caretStack") @@ -179,15 +132,10 @@ testthat::test_that("caretList and caretStack handle imbalanced multiclass data" testthat::test_that("caretList and caretStack handle a large number of classes", { set.seed(123L) n <- 1000L - X <- data.table::data.table(x1 = rnorm(n), x2 = rnorm(n)) + X <- data.table::data.table(x1 = stats::rnorm(n), x2 = stats::rnorm(n)) y <- factor(sample(paste0("Class", 1L:100L), n, replace = TRUE)) - model_list <- caretList( - x = X, - y = y, - methodList = "rpart" - ) - + model_list <- caretList(X, y, methodList = "rpart") testthat::expect_s3_class(model_list, "caretList") stack <- caretStack(model_list, method = "rpart") @@ -198,16 +146,10 @@ testthat::test_that("caretList and caretStack handle a large number of classes", }) testthat::test_that("caretList and caretStack handle ordinal multiclass data", { - data(Boston, package = "MASS") Boston$chas <- as.factor(Boston$chas) Boston$rad <- factor(paste0("rad_", Boston$rad), ordered = TRUE) - model_list <- caretList( - rad ~ ., - data = Boston, - methodList = c("rpart", "glmnet") - ) - + model_list <- caretList(rad ~ ., data = Boston, methodList = c("rpart", "glmnet")) testthat::expect_s3_class(model_list, "caretList") stack <- caretStack(model_list, method = "rpart") @@ -216,18 +158,10 @@ testthat::test_that("caretList and caretStack handle ordinal multiclass data", { preds <- predict(stack, newdata = Boston) testthat::expect_s3_class(preds, "data.table") testthat::expect_named(preds, levels(Boston$rad)) - testthat::expect_equal(rowSums(preds), rep(1.0, nrow(Boston)), tol = 0.0001) + testthat::expect_equal(rowSums(preds), rep(1.0, nrow(Boston)), tolerance = 1e-4) }) testthat::test_that("caretList and caretStack produce consistent probability predictions", { - data(iris) - - model_list <- caretList( - x = iris[, -5L], - y = iris[, 5L], - methodList = c("rpart", "glmnet") - ) - stack <- caretStack(model_list, method = "rpart") prob_preds <- predict(stack, newdata = iris[, -5L]) @@ -238,7 +172,7 @@ testthat::test_that("caretList and caretStack produce consistent probability pre }) testthat::test_that("caretList and caretStack handle new levels in prediction data", { - data(iris) + set.seed(123L) idx <- seq_len(nrow(iris)) idx_train <- sample(idx, 120L) idx_test <- setdiff(idx, idx_train) @@ -247,32 +181,9 @@ testthat::test_that("caretList and caretStack handle new levels in prediction da test_data$Species <- factor(as.character(test_data$Species), levels = c(levels(iris$Species), "NewSpecies")) test_data$Species[1L] <- "NewSpecies" - model_list <- caretList( - x = train_data[, -5L], - y = train_data[, 5L], - methodList = c("rf", "rpart") - ) - + model_list <- caretList(train_data[, -5L], train_data[, 5L], methodList = c("rf", "rpart")) stack <- caretStack(model_list, method = "rpart") preds <- predict(stack, newdata = test_data) - testthat::expect_true(all(levels(preds) %in% levels(train_data$Species))) -}) - -testthat::test_that("caretList and caretStack produce consistent probability predictions", { - data(iris) - - model_list <- caretList( - x = iris[, -5L], - y = iris[, 5L], - methodList = c("rpart", "glmnet") - ) - - stack <- caretStack(model_list, method = "rpart") - - prob_preds <- predict(stack, newdata = iris[, -5L]) - testthat::expect_identical(nrow(prob_preds), nrow(iris)) - testthat::expect_identical(ncol(prob_preds), nlevels(iris$Species)) - testthat::expect_true(all(rowSums(prob_preds) >= 0.99)) - testthat::expect_true(all(rowSums(prob_preds) <= 1.01)) + testthat::expect_true(all(colnames(preds) %in% levels(train_data$Species))) }) diff --git a/tests/testthat/test-permutationImportance.R b/tests/testthat/test-permutationImportance.R index d6211c23..2aa772c4 100644 --- a/tests/testthat/test-permutationImportance.R +++ b/tests/testthat/test-permutationImportance.R @@ -1,21 +1,20 @@ -data(models.class) -data(models.reg) -data(iris) +# Helper functions +utils::data(models.class) +utils::data(models.reg) +utils::data(iris) -# Helper function to create a simple dataset create_dataset <- function(n = 200L, p = 5L, classification = TRUE) { set.seed(42L) - X <- data.table::data.table(matrix(rnorm(n * p), ncol = p)) + X <- data.table::data.table(matrix(stats::rnorm(n * p), ncol = p)) data.table::setnames(X, paste0("x", seq_len(p))) if (classification) { y <- factor(ifelse(rowSums(X) > 0L, "A", "B")) } else { - y <- rowSums(X) + rnorm(n) + y <- rowSums(X) + stats::rnorm(n) } list(X = X, y = y) } -# Helper function to train a model train_model <- function(x, y, method = "rpart", ...) { set.seed(1234L) caret::train( @@ -27,7 +26,6 @@ train_model <- function(x, y, method = "rpart", ...) { ) } -# Helper function to check test results check_importance_scores <- function( imp, expected_names = paste0("x", seq_len(5L)), @@ -40,24 +38,37 @@ check_importance_scores <- function( testthat::expect_equal(sum(imp), 1L, tolerance = 1e-6) } -testthat::test_that("isClassifier works for train models", { +###################################################################### +testthat::context("isClassifier function") +###################################################################### + +testthat::test_that("isClassifier works for train models and caretStacks models", { testthat::expect_true(isClassifier(models.class[[1L]])) testthat::expect_false(isClassifier(models.reg[[1L]])) -}) -testthat::test_that("isClassifier works for caretStacks models", { - ens_class <- caretEnsemble(models.class) - ens_reg <- caretEnsemble(models.reg) + ens_class <- caretEnsemble::caretEnsemble(models.class) + ens_reg <- caretEnsemble::caretEnsemble(models.reg) testthat::expect_true(isClassifier(ens_class)) testthat::expect_false(isClassifier(ens_reg)) }) -testthat::test_that("permutationImportance works for regression", { - dt <- create_dataset(classification = FALSE) - model <- train_model(dt[["X"]], dt[["y"]]) - imp <- permutationImportance(model, dt[["X"]]) - check_importance_scores(imp) +###################################################################### +testthat::context("permutationImportance function") +###################################################################### + +testthat::test_that("permutationImportance works for regression and classification", { + # Regression + dt_reg <- create_dataset(classification = FALSE) + model_reg <- train_model(dt_reg[["X"]], dt_reg[["y"]]) + imp_reg <- permutationImportance(model_reg, dt_reg[["X"]]) + check_importance_scores(imp_reg) + + # Classification + dt_class <- create_dataset(classification = TRUE) + model_class <- train_model(dt_class[["X"]], dt_class[["y"]]) + imp_class <- permutationImportance(model_class, dt_class[["X"]]) + check_importance_scores(imp_class) }) testthat::test_that("permutationImportance works for multiclass classification", { @@ -69,13 +80,13 @@ testthat::test_that("permutationImportance works for multiclass classification", x3 = stats::rnorm(n) ) coef_matrix <- matrix(c( - 1.0, -0.5, 0.2, # coefficients for class A - -0.5, 1.0, 0.2, # coefficients for class B - 0.2, 0.2, 1.0 # coefficients for class C + 1.0, -0.5, 0.2, + -0.5, 1.0, 0.2, + 0.2, 0.2, 1.0 ), nrow = 3L, byrow = TRUE) linear_combinations <- as.matrix(x) %*% t(coef_matrix) - linear_combinations <- linear_combinations + matrix(stats::rnorm(n * 3.0, sd = 0.1), nrow = n) + linear_combinations <- linear_combinations + matrix(stats::rnorm(n * 3L, sd = 0.1), nrow = n) probabilities <- exp(linear_combinations) / rowSums(exp(linear_combinations)) y <- factor(apply(probabilities, 1L, function(prob) sample(c("A", "B", "C"), 1L, prob = prob))) @@ -84,174 +95,120 @@ testthat::test_that("permutationImportance works for multiclass classification", check_importance_scores(imp, c("x1", "x2", "x3")) }) -testthat::test_that("permutationImportance works with a single feature unimportant feature", { +testthat::test_that("permutationImportance works with single feature cases", { n <- 100L - x <- data.table::data.table(x1 = stats::rnorm(n)) - y <- factor(sample(c("A", "B"), n, replace = TRUE)) - model <- train_model(x, y) - imp <- permutationImportance(model, x) - check_importance_scores(imp, "x1") -}) - -testthat::test_that("permutationImportance works with a single important feature", { - set.seed(1234L) - - make_var <- function(n) scale(stats::rnorm(n), center = TRUE, scale = TRUE)[, 1L] - - n <- 1000L - x <- data.table::data.table( - x1 = make_var(n), - x2 = make_var(n), - x3 = make_var(n) - ) - - cf_set <- c(0L, 1L, 5L, 10L) - all_cfs <- expand.grid( - c(0L, 1L), - cf_set, - cf_set, - cf_set - ) - - evaluate_model <- function(cf, do_class) { - cf <- unname(unlist(cf)) - y <- (cbind(1L, as.matrix(x)) %*% cf)[, 1L] - if (do_class) { - classes <- c("A", "B") - y <- factor(ifelse(y > 0L, classes[1L], classes[2L]), levels = classes) - if (length(unique(y)) == 1L) { - return(NULL) - } - } - model <- suppressWarnings(train_model(x, y, method = "glm")) - imp <- permutationImportance(model, x) - check_importance_scores(imp, c("x1", "x2", "x3")) - - glm_imp <- normalize_to_one(abs(coef(model$finalModel))[-1L]) - cf_norm <- normalize_to_one(cf[-1L]) - testthat::expect_equivalent(glm_imp, cf_norm, tolerance = 0.1) - if (!do_class || cf[[1L]] == 0.0) { - testthat::expect_equivalent(imp, cf_norm, tolerance = 0.1) - } - } - - for (do_class in c(FALSE, TRUE)) { - apply(all_cfs, 1L, evaluate_model, do_class) - } + # Unimportant feature + x_unimp <- data.table::data.table(x1 = stats::rnorm(n)) + y_unimp <- factor(sample(c("A", "B"), n, replace = TRUE)) + model_unimp <- train_model(x_unimp, y_unimp) + imp_unimp <- permutationImportance(model_unimp, x_unimp) + check_importance_scores(imp_unimp, "x1") + + # Important feature + x_imp <- data.table::data.table(x1 = stats::rnorm(n)) + y_imp <- x_imp$x1 + stats::rnorm(n, sd = 0.1) + model_imp <- train_model(x_imp, y_imp, method = "lm") + imp_imp <- permutationImportance(model_imp, x_imp) + check_importance_scores(imp_imp, "x1") + testthat::expect_gt(imp_imp["x1"], 0.9) }) -testthat::test_that("permutationImportance works a single, contant, unimportant feature", { +testthat::test_that("permutationImportance works with constant features", { n <- 100L - x <- data.table::data.table( - x1 = rep(1L, n), - x2 = stats::rnorm(n) - ) - y <- stats::rnorm(n) - model <- train_model(x, y) - imp <- permutationImportance(model, x) - check_importance_scores(imp, c("x1", "x2")) - testthat::expect_lte(imp["x1"], imp["x2"]) -}) -testthat::test_that("permutationImportance works a single, contant, important feature - aka intercept only", { - n <- 100L - x <- data.table::data.table( - x1 = rep(1L, n), - x2 = stats::rnorm(n) - ) - y <- x$x1 + stats::rnorm(n) / 10L - model <- train_model(x, y) - imp <- permutationImportance(model, x) - check_importance_scores(imp, c("x1", "x2")) - testthat::expect_lte(imp["x1"], imp["x2"]) + # Constant unimportant feature + x_const_unimp <- data.table::data.table(x1 = rep(1L, n), x2 = stats::rnorm(n)) + y_const_unimp <- stats::rnorm(n) + model_const_unimp <- train_model(x_const_unimp, y_const_unimp) + imp_const_unimp <- permutationImportance(model_const_unimp, x_const_unimp) + check_importance_scores(imp_const_unimp, c("x1", "x2")) + testthat::expect_lte(imp_const_unimp["x1"], imp_const_unimp["x2"]) + + # Constant important feature (intercept only) + x_const_imp <- data.table::data.table(x1 = rep(1L, n), x2 = stats::rnorm(n)) + y_const_imp <- x_const_imp$x1 + stats::rnorm(n, sd = 0.1) + model_const_imp <- train_model(x_const_imp, y_const_imp) + imp_const_imp <- permutationImportance(model_const_imp, x_const_imp) + check_importance_scores(imp_const_imp, c("x1", "x2")) + testthat::expect_lte(imp_const_imp["x2"], imp_const_imp["x1"]) }) testthat::test_that("permutationImportance works with perfect predictor", { n <- 100L - x <- data.table::data.table( - x1 = stats::rnorm(n), - x2 = stats::rnorm(n) - ) + x <- data.table::data.table(x1 = stats::rnorm(n), x2 = stats::rnorm(n)) y <- x$x1 model <- train_model(x, y, method = "lm") imp <- permutationImportance(model, x) check_importance_scores(imp, c("x1", "x2")) - testthat::expect_gt(imp["x1"], imp["x2"]) + testthat::expect_gt(imp["x1"], 0.9) + testthat::expect_lt(imp["x2"], 0.1) }) -testthat::test_that("permutationImportance works for multiclass classification and various edge cases", { +testthat::test_that("permutationImportance works for multiclass classification with iris dataset", { model <- train_model(iris[, -5L], iris$Species, method = "rpart") imp <- permutationImportance(model, iris[, -5L]) check_importance_scores(imp, names(iris[, -5L])) }) +###################################################################### testthat::context("permutationImportance edge cases") -testthat::test_that("permutationImportance normalizes to uniform distribution for all zero importances", { - n <- 100L - x <- data.table::data.table(x1 = rep(0L, n), x2 = rep(0L, n), x3 = rep(0L, n)) - y <- rep(0L, n) - model <- train_model(x, y, method = "lm") - imp <- permutationImportance(model, x) - check_importance_scores(imp, names(x)) - testthat::expect_equivalent(imp, normalize_to_one(rep(0L, length(imp))), tolerance = 1e-6) -}) +###################################################################### -testthat::test_that("permutationImportance assigns full importance to perfect predictor", { - set.seed(1234L) +testthat::test_that("permutationImportance handles various edge cases", { n <- 100L vars <- 25L - x <- data.table::data.table( - matrix(rnorm(n * vars), nrow = n, ncol = vars) - ) - data.table::setnames(x, paste0("x", seq_len(vars))) - y <- x$x1 - model <- train_model(x, y, method = "lm") - imp <- permutationImportance(model, x) - check_importance_scores(imp, names(x)) - testthat::expect_equal(imp[["x1"]], 1L, tol = 1e-8) - testthat::expect_equal(sum(imp[-1L]), 0L, tol = 1e-8) -}) -testthat::test_that("permutationImportance handles highly collinear features", { - set.seed(5678L) - n <- 100L - x <- data.table::data.table( - x1 = rnorm(n), - x2 = rnorm(n) + # All zero importances + x_zero <- data.table::data.table(matrix(0L, nrow = n, ncol = 3L)) + y_zero <- rep(0L, n) + model_zero <- train_model(x_zero, y_zero, method = "lm") + imp_zero <- permutationImportance(model_zero, x_zero) + check_importance_scores(imp_zero, names(x_zero)) + testthat::expect_equivalent(imp_zero, normalize_to_one(rep(0L, length(imp_zero))), tolerance = 1e-6) + + # Perfect predictor among many variables + x_perfect <- data.table::data.table(matrix(stats::rnorm(n * vars), nrow = n, ncol = vars)) + data.table::setnames(x_perfect, paste0("x", seq_len(vars))) + y_perfect <- x_perfect$x1 + model_perfect <- train_model(x_perfect, y_perfect, method = "lm") + imp_perfect <- permutationImportance(model_perfect, x_perfect) + check_importance_scores(imp_perfect, names(x_perfect)) + testthat::expect_equal(imp_perfect[["x1"]], 1L, tol = 1e-8) + testthat::expect_equal(sum(imp_perfect[-1L]), 0L, tol = 1e-8) + + # Highly collinear features + x_collinear <- data.table::data.table( + x1 = stats::rnorm(n), + x2 = stats::rnorm(n) ) - x$x3 <- x$x1 + rnorm(n, sd = 0.01) - y <- x$x1 + x$x2 - model <- train_model(x, y, method = "lm") - imp <- permutationImportance(model, x) - check_importance_scores(imp, names(x)) - testthat::expect_equal(imp[["x3"]], 0L, tol = 1e-6) -}) - -testthat::test_that("permutationImportance works with very small dataset", { - set.seed(9876L) - n <- 5L - x <- data.table::data.table( - x1 = rnorm(n), - x2 = rnorm(n), - x3 = rnorm(n) + x_collinear$x3 <- x_collinear$x1 + stats::rnorm(n, sd = 0.01) + y_collinear <- x_collinear$x1 + x_collinear$x2 + model_collinear <- train_model(x_collinear, y_collinear, method = "lm") + imp_collinear <- permutationImportance(model_collinear, x_collinear) + check_importance_scores(imp_collinear, names(x_collinear)) + testthat::expect_lt(imp_collinear[["x3"]], 0.1) + + # Very small dataset + x_small <- data.table::data.table( + x1 = stats::rnorm(5L), + x2 = stats::rnorm(5L), + x3 = stats::rnorm(5L) ) - y <- x$x1 + rnorm(n) - model <- train_model(x, y, method = "lm") - imp <- permutationImportance(model, x) - check_importance_scores(imp, names(x)) -}) + y_small <- x_small$x1 + stats::rnorm(5L) + model_small <- train_model(x_small, y_small, method = "lm") + imp_small <- permutationImportance(model_small, x_small) + check_importance_scores(imp_small, names(x_small)) -testthat::test_that("permutationImportance handles identical features", { - n <- 100L - x <- data.table::data.table( - x1 = rnorm(n), - x2 = rnorm(n) + # Identical features + x_identical <- data.table::data.table( + x1 = stats::rnorm(n), + x2 = stats::rnorm(n) ) - x$x3 <- x$x1 - y <- x$x1 + x$x2 + rnorm(n) - model <- train_model(x, y, method = "glmnet") - imp <- permutationImportance(model, x) - check_importance_scores(imp, names(x)) - testthat::expect_equal(imp[["x1"]], imp[["x3"]], tol = 1e-1) + x_identical$x3 <- x_identical$x1 + y_identical <- x_identical$x1 + x_identical$x2 + stats::rnorm(n) + model_identical <- train_model(x_identical, y_identical, method = "glmnet") + imp_identical <- permutationImportance(model_identical, x_identical) + check_importance_scores(imp_identical, names(x_identical)) + testthat::expect_equal(imp_identical[["x1"]], imp_identical[["x3"]], tol = 1e-1) })