From 8b6cf43183130543e9990d38c6f6058fae45fc13 Mon Sep 17 00:00:00 2001 From: willtai Date: Tue, 13 Aug 2024 15:51:55 +0100 Subject: [PATCH] Pdf to text component (#103) * Pipeline (#81) * First draft of pipeline/component architecture. Example using the RAG pipeline. * More complex implementation of pipeline to deal with branching and aggregations - no async yet * Introduce Store to add flexibility as where to store pipeline results - Only return the leaf components results by default * Test RAG with new Pipeline implementation * File refactoring * Pipeline orchestration with async support * Import sorting * Pipeline rerun + exception on cyclic graph (for now) * Mypy * Python version compat * Rename process->run for Components for consistency with Pipeline * Move components test in the example folder - add some tests * Race condition fix - documentation - ruff * Fix import sorting * mypy on tests * Mark test as async * Tests were not testing... * Ability to create Pipeline templates * Ruff * Future + header * Renaming + update import structure to make it more compatible with rest of the repo * Check input parameters before starting the pipeline * Introduce output model for component - Validate pipeline before running - More unit tests * Import.. * Finally installed pre-commit hooks... * Finally installed pre-commit hooks... * Finally installed pre-commit hooks... and struggling with pydantic.. * Mypy on examples * Add missing header * Update doc * Fix import in doc * Update changelog * Update docs/source/user_guide_pipeline.rst Co-authored-by: willtai * Refactor tests folder to match src structure * Move exceptions to separate file and rename them to make it clearer they are related to pipeline * Mypy * Rename def => config * Introduce generic type to remove most of the "type: ignore" comments * Remove unnecessary comment * Ruff * Document and test is_cyclic method * Remove find_all method from store (simplify data retrieval) * value is not a list anymore (or, if it is, it's on purpose) * Remove comments, fix example in doc * Remove core directory - move files to /pipeline * Expose stores from pipeline subpackage * Ability to pass the full output of one component to the next one - useful when a component accepts a pydantic model as input * Component subclasses can return DataModel * Add note on async + schema to illustrate parameter propagation --------- Co-authored-by: willtai * Add documentation for pipeline exceptions (#90) * Add schema for kg builder (#88) * Add schema for kg builder and tests * Fixed mypy checks * Reverted kg builder example with schema * Revert to List and Dict due to Python3.8 issue with using get_type_hints * Added properties to Entity and Relation * Add test for missing properties * Fix type annotations in test * Add property types * Refactored entity, relation, and property types * Unused import * Moved schema to components/ (#96) * Add PDFLoader Component * Added tests * Remove pypdf check * Refactored examples * Moved to experimental folder * Exposed fs to run() --------- Co-authored-by: Estelle Scifo --- docs/source/user_guide_pipeline.rst | 5 +- ...y Potter and the Death Hallows Summary.pdf | Bin 0 -> 86193 bytes ..._with_schema.py => kg_builder_from_pdf.py} | 79 ++++++++++++++---- ...{kg_builder.py => kg_builder_from_text.py} | 0 poetry.lock | 4 +- pyproject.toml | 1 + src/neo4j_genai/exceptions.py | 8 +- .../experimental/components/pdf_loader.py | 78 +++++++++++++++++ .../experimental/components/schema.py | 2 +- .../components/sample_data/lorem_ipsum.pdf | Bin 0 -> 13891 bytes .../components/test_pdf_loader.py | 48 +++++++++++ 11 files changed, 202 insertions(+), 23 deletions(-) create mode 100644 examples/pipeline/Harry Potter and the Death Hallows Summary.pdf rename examples/pipeline/{kg_builder_with_schema.py => kg_builder_from_pdf.py} (60%) rename examples/pipeline/{kg_builder.py => kg_builder_from_text.py} (100%) create mode 100644 src/neo4j_genai/experimental/components/pdf_loader.py create mode 100644 tests/unit/experimental/components/sample_data/lorem_ipsum.pdf create mode 100644 tests/unit/experimental/components/test_pdf_loader.py diff --git a/docs/source/user_guide_pipeline.rst b/docs/source/user_guide_pipeline.rst index 2f2c629d..f8c258ab 100644 --- a/docs/source/user_guide_pipeline.rst +++ b/docs/source/user_guide_pipeline.rst @@ -10,9 +10,10 @@ This page provides information about how to create a pipeline. Pipelines run asynchronously, see examples below. -****************************** + +******************* Creating Components -****************************** +******************* Components are asynchronous units of work that perform simple tasks, such as chunking documents or saving results to Neo4j. diff --git a/examples/pipeline/Harry Potter and the Death Hallows Summary.pdf b/examples/pipeline/Harry Potter and the Death Hallows Summary.pdf new file mode 100644 index 0000000000000000000000000000000000000000..1deceaebf53fe10d0ebb5ae1af2c263decd16bb4 GIT binary patch literal 86193 zcmc$`1yogA`!7s4C<@Xc4N`k=VAIkeDJdY`-CZIe(jwg`-QC^YA>G{|ND6o1iTAwc zod3P|`^Naj#~wP@nrp_>^Vw_9-=vlo5n}=|LoumW*M`S2(b(C^S;?*S%rJR*S)@&^ z40Y{H-3$%LK`heboE#u72#Xv!J12`MIhY*^VrP*hXJb(!=Var8LRcioHON7%>>T7^ zE-p=eeoR9vgNJd*|Ne)G=3-}P^lK&vCng%}?|&c;@?TfvR)5ri*ujv0)Nyb?|4|2J z<@$Ran3WS?BC?bz8tY=5ugfPnu|2Z-t)GKF%n{(}}yDCi$@;bLe1dtVSM z82opcf;id!K{JSx{U7{-IHAzL^9$kvgZ{2J!07(LFNlkc?eBfTY;54a^8se#;P_`9 zC&%CU0JF1#|2{8J$NqO2fZ5spAp3Vf7{){uogUnk z1I+S9!O%$2!IJ!eQovi$>>YIN9DegmR!lT%YEd~cOf*b1F2L0OhzG*tfCsUNnOZm) z+OddP=sFmR80uRa7_vx`gV}%xVQ6LSU;?xOu_%&*z)*gEdj~s1T}wh~{u<>~=)nqRKSFs*D2%xdrqHNJv<}zvItrrswh;P61 z_j{z{0xa?mQT-+ud0jh8dqBU!))tPIR`%qO2L%|I>N{B50RrOZ|5sUB85p`~0Fes9 zq4}psS${JTc6JseR~y4$x?@q*0FeV9Ak_Xv%zCTF4{|1E#3yfop?eAA`7d<-GO#~F zysnioouL&yi;S+F`Gd&;)IMASA>YBy(GVa}#?V36K-WQ+90UYAz!v3ojScO|AEGsI zqX;z8cTlo3H2h_{5AhYK{Y9fN(8t2sm_^0Z(Am%q;M>U1&d^F9==%^|$rb*yLj1b_ zogNWWdm9T~R}pJ{B~u3r!{3ScV=ZBSaEISp3R_z_7+N{lYjFIUlpG59D!BsrLr8fj z9?TXf07ri)fH?S20517Z{GwfxMcB^TM#$PlJg7{OMa0m_ zRNqiRT!=-HMafRr%HBrzfdkjy`1{rHmwXINb^kF8pm~6}Kg6V9Xm9Ok2k;IIEb8JQ zuIK>x4sb252t?V3U<3#axCW7P{37(hFaYj=24Wy`_TOYG1}5kD#UYCr1fcd;7cn++ zj$eEN9pvq-^%V^rG+2Q3oJGmd#eqfA63~>;Z-wx0g(P4sK#+Nuog6T!U&{N9QhVTD zNmtMQfz<~Kd(iSu90Hk8-;L0SyqUfmS@G#TEbimx!%2uWiv4s3#{rtm* z9tQaj6~FlZ7b?X5PQ{pHV^*D`J0@j zb^p^sR@c&yMGX8OQUQ28{iT*a`~9WMgV28OBKTmS4&+>H ztSo{~#=q1DB(xwFVO<*uLsMgu-yZ$Ov;#R47{d0j(isD>`!|abdT@0nFcAM9o&l>T z;K9IPn!n5mSQ-t1IP#l>9_-_nY5+(1tKJ{#Rezg`jg^%}5(tx~`hr%*K(u28Vz0|@ zGy%yk2jHQGmMRbV_MZm#AA@Ci^E`0i;eGtWY3&u>$qL2v9EI3j-T4B;>&k|N8?ZT0lc6Ir~FL zU;uU?lt3U4ftvHz1Yn?iV1gZ}0|OIr0c+30#Oz$Z^?T?G0VZby>L3uH9TywW79b1+ zv|$CV*}&v%K*0ZFY58T=zXZqmE4cpW!2?^r8_&O_KEEeDKzjS1b=W1zUrDAok@a!I z_ZJ=>N5=?NtuzXLI4BWz+W`qblp5h-X+_Ooup0K$%IXiXFluTP+ zX!4XE?@fP0hLkGKv8UJms4nH$HyN_T>-orT$;Tzqe4a`8egui^@LTWO9}BsUrp%vt zl?Qw?Z77eG87CVwf9yp-1gTnxZ@i_$dPZi|emwV98d^%%1D=YDlsU^Kk5^0cXYz8?m&hw8Xbn+jR6J=( zpX_qc$h+s^HUy}jA4DCZ6taDxf_r}`@_1H2mBL4!MKGWi?piJYF-tW{hlTqs#~T_E zMK5E{8A~z~wX5Wn*Jy-0o7how%~s4ge9WvQ=LI~PF^`$)3EDFe)Uks=bkXpw_@W#q z9gZc4cDB@yi&7~PYr2jd*JG0vgi_i#2U89DGxu?<%ui#B$(8hFUsPnIZc_2%4D^By zt$bB*61Q9eu^e{Ulku3H)+}Xcs8nb;F65+QN0@{57h*N@P#VTkHAnfP(KOMU4RVd3 zevad*O5?;C%q`3f7fQQN*y=dIo!WxD1pF-3uE;Mrj6I3O>)A|Sk5?sK7|g|YGm~BG zh9xw6!>rTf{9DfWD|z`pS{D=or09QSc@lvYN}AT=tT>+GQTNN;_z@FirB9`zGua1` zK1#Nr@sg8LZ1-hU63rm5F4-SBe$F)XOv8;<=pL%wN^$qF}C9(-oY#uY8SVPQ)k{zTxt zq)Lu-%V$T?m={%V;J5dM(5mW$#Y|yidxh4#duNp|8B_0XR~W;Zr2Tu6p{x^PJqrHD zDz3`1{>+$kj13ct&t*24Fov#gO&_x(xlr@4e#Xb#qaMVLVQ9%sDDivkO7_aexZU`Z z4;Ov)&bE$BkgUcb%D7}ij-gSbNZu*J%H0c%hQM^fBzH1#aSaR2toNP6g!N0ZJDI`( zyMpBmb#4a!tL>3IV+trS2Ry*WYWKw8)?c1(YUbskYRap{nh2FgH_ z$AB$h$$|~rYTdqz8^KYROe9EId=8Tk_7Uz0{PRpk+4j5~)BUKkw(E_i{Py1VOP{KQ zfPyUHz_D=n&@(FyJiBlQ%v>cB=H!UaQ)HB%d$+p^Q{J$`)a zvTv4-C#b^T(n_T;a5|W#+`gNcOu*B1nt>CcH9u^-Z3I!y+P1mo;CBl<62SbnAU|3@d`fCAsB z{^KMC%5!0}td9XF@s8`Rp=gce#6wk6CvVJsQK>o0ujJViBk;P`0=^#Cd#NWdN6blGf4 zK9HkfaN-HZy_a?spu}fldlWoESn_6j388N%zJ1vG?N&YVI&z2;19?3OjKdM>DfOA# z!dz?p^N)uC9$bjUZ?3fuKPrrnVWm~h;~SnnHt;*VHLHbo;4LPgOdJF(&Lv$&sK#hK zS@k(1{W#qCR>SK~3qG(hbg_6uZ~6QC43n6}r%!MQ&BI>Cl+#kNB6kTYVxA*migw$q zwHL!@e`YlzV_$L6>}Eyq#;(hYAK28QG^Q&3A-+Cf`EGSt=xJMyBb|?kiXRfoA-jcE zh^iYCI@RtQuXYlR)X?bO4qN3^je=u^QXvAW)mgoBx=8qqfSS{fK_auBFBOEy42`hg zgMV(!U_B?uBsio#Y?lB9y%>xdcIO#LsW)I)EYBFl7NSm2jLT-NLtw+s*LNk{=H!=Q zI0#&sBDHl|4O!Xkab!5Ymfk0iTV$}v%Bx>Hh_>#?;GKueZRzHIf_2(;I<913|^B3JWKijOGZ}`Od!9S+3lkcVIvD`aY7=puZ z`2S|*e|dfIKPMVcHXz&kiWte+PpnneYUa z;q~W%qV{(*pLQn^aJr4fs`}x(hOOI{H5@7f#VKZ)_0nEH4S!P+>?$(i^1OEY2*p;>$XybN5_G6rWthUPjua}ggM%c*K4I*TyY&s2M|l_aF5z$`_S;VZbl z{lVn=G-|e_jG;wbwzX&vU%emeM+MBGp#2C$1?H^uZ8S|x7MC8!iqVDIiO{v)lXJ(n z?O#W28N8{825sQ3PReu@4Hg{y^83nYG0l4l3}XpqrJX;$QPa!6;Ir%a+IDR2#>`i% z(|rjmqt<(Aw3GRCN1&%>UFnnCB)9a`n!s+X?hJ`6VxY$l%`q~v44Oo@?68|H+&+gE zMZEPhrdGGpluvE~3rmlfx|AH9*DXeyJhLQk#sd>ZXzV}jzSQg6YYTQfAVga?<&;kY%nz-U^`Afb8 zC@9~5sS&RZR!mYt^}ahewe=l$aLnG?eMDSceVytwx_rt0RIT_0&qobtxL8rL1QK z9ye*6dQYcUGZ>LARx&-8Dz&|q=cN>mSoD5H8V-Sy%`#q)saxdee(FnK5uip zn$a_B&*Hb2i|$J|JMI)Xmy(%!@6}woa`h}X+*7qmx-RVGiM7p;-gnMkP|=~%s1*o( zp?D_BJ@J9bD~-%lkg)H~8btSCQag@J>uPap`9t_uokpX}JR+AJ9p&P0x9A$Y@Eo}! zantst${rc-tIVqAkq~T@t0${12QzJIh>CnMZ-qW3=$w#9ls(^|haOfS=mir;Mdqy2 z+xU=Ip_i|K(X>|Ml_Wd{Gj}^Q3NRvG7=Vo}iLp3B1YS8xeNw>{sXGwlq-}OVko1{G z(td3>>_R*c(dIzMtftg*c$_pDvRxYdbxgirF%g9Qm2HMD0VRHRVGd*ZGSnhQ)=!pL zN+kEG#$(#PpQjYTNqr;J+tTUb9Rx4ZlqDGpTMyexPYM{Xdo%V8zViNn+1=LASSetY z1tEsMH$lx2V4@tz3^rWXn&&wh+mHNm3lph?#gVI36PJwVd^^0KJlxSKx;OtB5*xt5 zwNavoBTLUz?zw{;QDz`Nkgj9vicuJRKD;|8=tvs%tRm$?_SMtANaT)O&&;|RK>~Rk z$6kg+$rUv3ksqGnYn0vUPxJG`f=J#sOyiZB(`zX<$T)fD-}KygVfm&kjtp5odgRj) zdx^(cEcXbh_QMzKPU9atF7He2R9HDumY9h+;zNu(6X_vq&i$J~h{}*_&MmdBQ`6Rz zx~Gm`gIjax&$e4Yr3cWAZJcScG&ZIidZgi^Q^tyX>?MEA|tq;ST(6MfC zg^isB4xWjRAJMH(5UKa<#YhoMOb%I$i#Ozv!V4ru()xxv!R*)Vs_M+aG|7-TZmqDE z6HJe0rFZw?Zc0Lfe`4#vyyc#${5J>q%WISW*#V$zkpFgo1#93tskiv5_c5h3W-AiW zCyERj!-K4IUCSzdX?Jo=nb%LIC93o8e;y9upN_tgsuBVJ@Vq^2cQy`&kliJTwtW}v zfx~r|Y{@d8JLM~Sw|7FOz({2N?M{c99%LJcg_IqZ( zEezr!)}S_M1KBZaW_FrWL4)CjG8_ZS5G5SMR65aN3l>D4_Oq8r5=8hbs&se@k=6yw z`Z?amQF;rrO}o4k2zddWl9&0u`r$^G@s*#js$+8OyzL z%by+VSC>*X@1kD3Nf#-}Dk-dYE+{Jmp>-I zdK5L=ea501F%T%YBz`H#I4(H-s!t#_f=`8tx(o~Xo??$(Jtj31z7#RTHiGzk-qW0C z+iObUsi-#Ph8**lK?aGqQyh#|(g%%_&lk3x6dN9RqCeZ zT)2wv$r2+T?r&`3|72F=^%73j0mmG&SxWK9@tE4+mxGU`S@!no$Rr4@`aAxs6XZFA zrAz(0lHt#7N=$bVKjo}QrWHIh3R^d#;;p}dw@TK3D}`xmltl#FGJsn3It3jM1+UC6MO6-!{dUem@{Ff4jBT=eXz{4|+b6XG78ocZtRk>qRb1gXcrW zJd@{?+=2(1zt-b#cWiZVT|GYRb8K=aN&T>xFx-$Nm)UJ|5pu8PViLw-^X;VP?fIDA zCbiLAs&^Zr@-8iZvMVm$n29k{5jS$~bpGjkmQYNjgn**GM;=zmB3kBtI`m5I{>R`C zLhF^VxaEVVGU7ip&gz7VZ*;$IEN(gm!e532Yq59~t#=3GmW@A?4p^F9FoqvEI z-%8YGT)1Ff+Qd_VssdZNYs}Z^pW%_BJX%F{s-k{=_(FhV%G5vEv8oRLWqm)}?A3>r zPqK}@`R{!)^7der&|rJ1{exPEJsf0gt7DcvQ+FL)t1jUsth%A+i@(SXj;En9isc z#BvP+9lTI1_c6GE>$7mv)9^+`nDIN66dd85-@VXQNB3k8!>^ zwgJ|-JiRUAO9^!q8-KO+xG?v&VcW%pTP}xT@^PGd<40dfJ{_`Goh_*UXq$5mBI7y92h8-z^p`(uw(2(C|W-I_gLt09?^ z8mQ7%y&pU8fQtx8XQc>1{hC*nbGVRdfdY3rIV6ec>pWTwL)btu=4_+c5*dT3_mtQB zW--Jw@TYGy=7A~l#dInHC(gv}Hpslk%fPjc5gTq|V@4#dXo=LJz?G4PG1E@wI7xv$ zT$0zRA|CtAFvFbGaYX4$I1Cud(37fv^O3*2A^+d_2=u=f6s0*UAfxiEUiY3Bx5gbP z`nDJB#|UdXD<+dkqvV=%Do_fW-<9!!>Q!?SWbK7%LJ*sT77N7K%D4-{0}XXCBGi^% z%Qi*PSZ0aBdOF}c{)j{+E6et07;Y8_cKKKuBtH<7^&FNe&L9lKQm!3+K(Ji!O(-Z zW(rN3vP%5yWh}9lT`o72s?Q1IwQC(hyXTtK;@i(>{2Cb_$L|m!k@Ju(O z&M*@jVLhARD{7@b%wqYb?@%%@OdZx3Tb8}gGu>ezxX63;O+YALe=;+xlyP~QooZvo ztWo@lI;yKWb1lwPFRZDAMH}mNK-5=DFsVaQwk6A*An&=&-1@CAdo?w|OC8E`Z9nFx zRY_|C1{;*IW%L<8qO*B!3U8iB@Hm7Y_HS862w8b)A}f5eZL+Fqy)r}|tfh@!3MDwb zl)y1YotenMX3682AjuAZWjOspd*dX_YBV>4DdRpTbrV{ns6O4~!Q?E*-Lo1@uiu_O z=h`ZkzS4QNM*lq^b+a=_%@lO$)|viMMmBrDS>xbCmG>MJq==_o~p|hU?Xn%4#)>E;Lulo6fy- zTNM+k`SQ3l3~5oKrzJO~m(5OG2$B3lwZp1Jt5nBm3xTppwP5&-1a=r@pgdn8x%!vP zQ+=U4QiUFqcRj3O+-VqmV^wr4A|kl2ayby=zDaO5Vwl&bq_ENnK`_JD#8=Rt$?Uum zRY-g5kODIf6~)ge1X-$0=A~w*>!KxH@u}=4JV#uB=Q;Fwrm6oV??ttY3PN-_jV(5M zX1AZHbDgU8B+r1zeXsSn+BzM6gu092OYkUCWA7}xPe_D!zQ($hOVIM`n&y-@%lb|Z(5=AKAD;F6AHi=akOwy|dwjp;J z&0aaQv*?*w^)zZL=S@UO!LaJz13Fq-Pl;-Q7S!aGiFs)*v`Hl zx6sk;$+qgHE91{1jq#nJFrF{wvsQ8KduU_be1S&FR$3_O74B##*rrV}g^ki!M)Iyo z+VJ7JkJA`R^5o6sQ0)nRQFNy5mu(^^c6yux7n)(}7UgU~JV;H-Sb>&&^*OZM#OR^{ z9%=SH!p=pCf(ad&;anb%-6ylXgR8a$HL~u&gDz+#>0LvLztk9B<#W^dqtmqVlWxRv zn(n8Nm<`^bVq*)RXd_zp6TJ^P^~m*+5;KXD*=!Tnxz`gE^ibT|@^^(RQ38ky8`lLq zv(0s*7c@Z@bg2B;3a=?#VwQp?2(($XJrFKwTVNQ%%QyecMjw8m{6D@>@xv&iTx!*a!ERHM|C0YjJ8p}FmWJDucg{ch$kJ~jw2Z48+$uuf@LZe>o^@_puZ5y zq|x>{l%)*h$0%O*{I(yPL+TwuPpKq1l>rxA9AW@MkN7J7N7(KatX?ajcYd8J=Gw{^ z+ie`2E5jE@7vmd;MMZheQ|`rD(c&nSe&Chof;s8+U0yripW6D_FjZiM?c*mbc=l%( ziA(%oHwl)OJ|gnAU)%YH-FHtZRF~IV`epRCx9m0k4b1$Zq=|&5svFGiQA=U!JgE6% zVl8h8b{`XE!%${81Y?1|c8vw4HVFIGT%EqjQ9+0AW?C~$m$?(x0lxdq@|+w64kyab z!g7fH_h4;7C%>=Zk#{qi`sI;h!b?+P z99BIVWmaJ{Q+P#PzoHm~PxTh2`)=+l+Lx&7PP8Vb%qTr|+tT5PXMu>8VvK$M?uOnB z%dHY^A}5n{h|f1)W#Or7_(2zg_G_%DixRQRYe-EwXq)GFX4AKI{bVH(NvUGfpzJ8x za@TPVn&SX5pjN4+l`WYFuU>fDn3_yB@~VAiL_*6<(?1ZK*m=`tWt#zV9NtJ3L#bz6gR|bMwIO2^aFRy9p z9+7l$bhYboD5sC$n7yjVQ~azrCaNb$*z;MMl>;GuYy`RMnMsf?u3@ZI^YpVVP51T_U83d(&+{gS?|9KzaV%85)=f~`>kA7G2o zZA*LDrE&anS@`ma2XzzHlArgxqt=TxC4osM4eIg@~ckJuq2`-GF-gt{9)Le~wIQ zwiDYrCTjl7yVboFz58iLmVII05Q|QDS&az`P7OYSXzO^P+54^!k*}5HPvk!PFuuY1 zN|auh&V7RG*itudfaqnV*WLzUIQNvU1wPguLqfnVgImI+*7+v-!pToh72cWS+`yKs zk40UI%hQ}YKP-<*aow3Ri~PQL?J9ibqS%umH%C&SSchrN`J{mLw3U;=WJv>0YiZWL zooXm|srp1?X?KALNW163yq@+fqzlLKG5+qeFNKHBQD~q#?@{Sh-@ocewEa$eN8OBW zy=jdOXJCVUby?kUGRexHJR%cz*xtOnWy^EVhu@QWdiqjCi84FRJf61aZN|Ilq70RH z?S_ReZ?_Kmz+sjNlBt}w< zM*bqhD(&&Q|4u94^ZQ*^$6XVl`@Pql`-kaIP*$8tq6DPIyDuiLuXJwZ5h@PRWxW#2 z$mHCr&!>rrvU!iIW}y~R>iT##aiM5A%JObHp-C1q8#VkEB^8s=T-69#?zId#`6vY1 z24VO@B+-k3NOzvZrBrz`w&Q376FEkO7-LH8#!;_Ab)aGa2|8L%rITYdj0>+-H$HaH zt4!gY+ight2(&1J*|m+xa=&fwNlnR!=4J6I)nLwT^U%-u;VY_0#4v14v$w@FT2>l% zZ6+K!%%2291^D&TPpAd?jlEfu?^zhBg{G+T^45&N`Ggy zoi3gUw~tU8LDzCXQ{=n!g2ZyVuGCC1!!f(rmf!Y9G-;)5C`E8jhY_@iaqz0cXi!>0 zV*w|pEM{XfUY$^g=mqUALqqGk-pu|;WzmMvMDx5*za|W-y^K;kU95p1d(-$K|7p1K zmbXnMv9-J?`rJA+EtWl3$jQj84H>8r3~xs6Qfl9rDjn=whMaLlgJi~waPBW(iX3x# z>mMkE4>sxc$?VDmi0#2>b8xXEdnot?;iFu*P&Pl_3Wpvy!x7z4K+2b?1FqsOKTAdh4cc!=>&RQy=r!czZgV|$|#~5 zD1EFx@I+whd2IX3!2Qfih+Ma}nfLL@R5lrvuJ23S+0Hm~8^r=VMh`|qvTdx}E-f)FeF~vxQn^Yw(F&Ar zVk6=bTjdX(YDHck6jfAGJ{OM7;!~e7RNumP!Wep%H-`Sr=g_Dz?A*x1hkN$P(W4tn zqM~vRWdq{`!nyueg~ZkN+l3VSMj+;Bf`O{tnhc2r_4P{CZj2V?{?*j@$M(c}PsQ2v zSQ#YW(d?tBSWCM-waG>BmPMeEg2T4rT%W<2@H2u=S(be}bAiLd$(pD#n$YNuTf3z! z`jlzegT0h`e1klnBIsTJU8PY~yuup6j6Tg5{Hp(x!}GdpiQIDPZw3}t3r|hw$DgIr zTPZod(Ig@s3YFFLrDjSRA4wdwBafKId-RR|#lRtKs&z?GTA9G>!|~7C@~~{Ygo)y#OKh5nMZ5%k(L>ez8%A81}tAO=Y*tIbq#U&NG&koR9MpS zKBPcJ2R2dthe(^d`s}7~oVB#=#WcxJJ8i9+3ri1))k9lOx3>g=zJZr_E_&MbT1E#n z0p$$C%j0_b2Q-P6PX}LOFAg=lSE3?qo5fs5XneBvnp;O!JTb9eKa)SRY(inJ=Gx3- zA{kOc`SM$qY{%(*L;S8xe-!Mn`e!w?rsuPC+hMcm`1kW7{vFJ`FO)t8FL*xpv=LWy z5yAU7D1PH?qipz8s~bstC*uov<Gg?AVcW3uyHq2Mg6Hi9?k8hU=Byw^H#^N0-#e<@*Hq_MY z!rS16%8w281rs_VV^)f==}I*xz}t)?Z^$)X+tMKle*uLY1i9?pYOF`paW5gBO2|Xh z$kbC8J#wm1?SCe^5nhS2RvQYd;?vN3hQFL&z1jCU$&4SOE#;Hcr?%prOsNZU(srVH zQw7}&je5-1W{`c98|>Qk_3KhRjMQNQitu+EMz=crp^Ta`LuY*#=dXs&HMY=uyl%1V z$UEOxVygm>IFo)Km+w9ZL#J3SX2^|;t+RE4BKk(`9Rs%;akU*=$a*vgGRL8qUjoM@ z(k$AJ4j=7#&fVG?rJxr)taF^6i@pkgkPufQHlqp>Lu)5A;+Bs z^I@ZQ2`!!(-;y7rV5#XDG9;414A72iay!0LQ;p&Fmc>uQ6NI6li?B&)qjK<=pz7 zYaD+&%_qEUwRN=M1B0Tzy}iMaR#rpWG$WI=nsN2o!XeL*!*^&jPA|1c82+>z_9f-I z3hAmpg3?=V2V#?yqW;nz{`)9yg-_ARd5pRa^_0~wgAZ;`>Su*(;=|kfT39=S-jHKl zuIn&kEc?#)2}a`ls7#kxs^{^DlHBsV1QEKn5X~sy3xCfu;1&j(hEpmJ@{;lI%z+Mg zW-ga?tkXdIOKcKwPmQh+1+Xs{%9k#?%GU$v5zz0Lbe=aAs<=zIbrFQ-<|ZXA+-6o( z5Y2`Wo7Vd@khzCQdV`@Cl6Rh7D}hN#w5-9I2wtz-4Pba}3RH4=1-pc=sGZ2!@w4rw zB+H`=MOmOP9gO|%6|>5@H6t7$T^P(50jQLhFP|Yv<*`=4Fdy^XK5apCr+hS3SMdsC zZWQbRd(Y(Y!kg%D3#xYfjpSL=H=mA%ZB-qfOatRDj;Qg&pF<-hK1qigh<$!kD2;oJ zd2L!;xS(fY0;&1-Vm6(m5itw<;_?S3nE4Bfb*X)&`geiYNhOkMrEAQqs~z^0!?fBC z&gS_0(Il|9uxwSI*#wtVjlpJGdP56|ptoRm-X}*sI(saI4`1_b zh$o{_4ctHx>Z=yK{SzB%7iS}IHTJDrSs|0#F}W9o%T}`BBK0*hx=OaXu4sp|DDLNt z6PuZ$Ym={>Uu}38o~9)A6xG@MtV!i8wrrfl2d^6KM!fT3hoiA$C~2s-DUt5PRb~HK zvQw8Yq^kMtOt@sDQ0Kbv@@5@L;N1YMj3FG=OtWrS-Q&pK=8?LSjm>}~r0z))cogVe zZX9~K{=kv^Twado#gIbTBQ8aihB4_J*D-2iu7Ohhc%eA`?=s4=`3*Vpvu~z#^Y=J- zIBJ6liA`4;B#LLC_)NvA=GC1+_OE82-gT`;1v66!jz%S51Vz6Vw;fU1F03?oArmcF zMlM*SS&(xUlQ4%wB7;0T(boopw>^SbXTj#h@J5fm)8YOaZS0fcgaJ)m6j8x|xMT$V zmpMua)GJfhdF5Rtm8xjB=pb-8ZrManVYSiL&M784Lyu}^*7=Y9f$NPVT(XV95Jsl% z*YV7gJfgeWaJw7p79Q;9$}c`CyjU|Z))(A+ovW`R7f>MmjIr1bcQvXY^kirqFG{y~Y;A7tkOXdxnn$W54AcpS_bIe*5;e|(UYj%63B$H}Dp!ep z&h2K3KDz6yV1D*JVfELnvbL-)9%nJDX1*74`K;=ZjGIQ$wvE_}3Qf$(g))Q3Z;sLZ zu`EUPMSqm-uCpWc71a3F5Y-@BM;7Zi7WTcv);IReNjA$)BPok7vBWHTjnY|n$^R6& z;B0;mLx{$i;YF0sQh_afY=)WD;oSV3HXX`-L{W4b(^0bKb1M1umVCBl<)6#SySP@B z9tq{^D$9DA1$L(9lo=nMb=7or`rSsbO1m1^8>&4QmJ#MnQG7kB!@{V?Hp|h-p~F~I zm47CqHPqa>X!GSug|+;+yr#;UO8c{(IrC9J^m1H78J{ej#T34cy{Y(b?jqXeJ7X^S z7+=gJ5mi5FXR=Jb7<(hB6m-uwkTp`w3#xAtx1uDa?*O5JW`w^U(gYO%!#0{2M;eJA z_8rsDt9tcfzgo6Di8IM4$uB$*h= z8lczR8VoO<>fgygsH;{B7f0T;^E@HmYdX_%&dxCUnbQv$Gct29wPeTCue<|!TgOIw z=NBq22Y}G$_3hqCIDL3k7z{$bDn|0XgwsRLmV;csyoE(gA7#ggoxk{jKwz~ZYS&eD zNxBGkprh8S*=$qSvlH^cBX#j88nHZ-B-FBKN;+OY12z8=>br)TuCkscv@F1xE7wW9 zFYo@I^NBlhdPlG6hqcs}!|Kayo37(;q9jcykEOEDSgZU;zXz#Dh;OQFXJ((3kVb~0 z7IcG+)(L)=w~m+>`yVgdYS#E#!+-Mb8b@cL`m);Az?eFs{j_3rc&h%y`AQa_sQcnw zi4K>674y5=h~kvwb=02;p86G}jHP*wZQ3s*-d%9sXBl(id~h(Y;pg4|JmC=1vR{!{ zxF=4$9;&=ps$(**i98IVnx@~(<;_!e>Z8|OtqNRoyIWPa&b4ypKYIsBvo$}`JsUb# z-aP+7#?ob>9&3a+Y*seqH63_c7E!p_H2WAm!C@ihR7Y2;B&$aHaVw;O3L!3`9b#ot z{S4vgw^{_h`pF@TVotA3l@FTTs+ql7vs~PU%L4v6Y9`;G2$V$Sd1tW3kVkS|csQ|fg z{5pppVRB@cr0vBkOW)CMZ`8|#k&>Y;_+{hLq&304^`FdEb7)^jlT{qd6BC^lq3_nc z-8etMebal-Y-^jJ>DeKfmonIq{T4Beq8`Z&Qocww`IVnBKa-%U^Xo32Bx% zmZ(*qCiU}+EZG)u(8v>`p1`|nhoW1_m;%G(u ztMx>?{2jv7N%j31>b$rMBkc!rm)TRVVq)*GrSR~Rn`2{FU(6+K^DX^KgEU-V=hp!C z8&u#G@;6kq{V_4?9sH!HVXc9fw9cM7Xw`F+e9x^b7xvNU^hQmxd0$d$qt=gfa9dhh z#k8sG6hYSRt_jV_$)?u&?4)>45viTtKiYa0vol~OsuBj_t86I9c<=Jq#*WEGNG^EY zTsAnwyx}e*e_U_Jp_bd6G1=MF+_6rb$<@uFW@*&0+;Q$;fkPv94SB;$_6YjP_??85 z7s&oyL=mT_AJ6)^+sU^N0ar}z?P<;D!Aqjw(scDu%^oqr^i70<9rbmMhg)E5S+31f z663QGhz%$s(e$fYHV<%bHMD;A?K3WuJ7B?KJ?Tb8B-1gHkLnd@HcEM$C42pqzcIYm z1%bJafiK)^xIuatGsytkD6qZttHJImH?EPsV8>RDb^Fh?fBa(u^h3`L&HaS`E8dtJntEnO)5iNv;AQ=KNZq)+Yf+%*lu>0rz63<+Q$q6GRrQ6`|o}1_7YAXN9miRM_!cTJcC&Y(h)ik6ly`7$|@` zH9M@YJ=)A1`z(j<{9)`-9PVkbcRXk>VM7=4lvA03}@QPXzRAw*}b2cP3qFn2OcW#%ZIhP{y!)ucx) zP5IEJ*u*$Bt~vps%A;0~r=u|JaC-)p)Ys!9GS8^*aKp08vJ%y0^EDdfuRxdig31=S zsjI3du43S;0q;I1$%b^q%;uN%#RWJ|D|u0U_XjK%9n-X6u&A>ldwBxSF{6| z1_U$06a;tp;r&7GUa56cV33F$<%S^yBdBuxAvD4-cmQ0_wnhz&?na24WAWBG$~AHuL4Hn?MT)#Z(LxwA zdTyWYvt?!GUZ2xp?;wT}#hPIAvJOsV+1XElYD$PPE@XywHTg|vgk+SR3h_(1Zqz%F zRBb|b(%>lJird=^kccVDGp;f}Q`sbUaAZD{%qP2`DHOjCuOKW#L!Ts!gRZ+68=MOh zN=YW_dq1MO49R;AC|*;N&17$O)IPcWY{M^JDRmqVd&JBQHJJCG=o;!6%=u^y-AFbu z`)ua?v5P{8C-()qU7IDMxdSCxM>tkZy1WL-ivhM>X?YKX;aQ2YI%mpER@$LFBSiml zQF6@5vBw+k$epF0rq70PsTsHS**$aa6ZpSw$tn<*_XL}zp`@_MG#b4Rqe=Q)yCgjK zK{Oa=lbxVjb&b5dGFC7CX<>pyD)F4K{``F2^rB4efa1czlPyo#vl#5YlO)cY`p&p& zbN_G7zGsEUhiSYAZ~bc>agn}8RzghRhb-6*8SSeQ4o}}6Vt*^nAXO>S6ppe&aU8qm z-4-erW3m6*Jfu)xEl=8`E^%uHcg+LS6n*FT_-(MZ)-_LdB_2)qJ?y0bHTS>m7WfMS zR?g1A&<;TI)BOSare{$wG&ThQDXw&azT?X@&RT27hp1g_5E|p!T&!P z?7xEA|3AfGb3P!MA9h!0uxfCya%zG!0PM6Tm{a3-__QX3LjyoiYqEiX$6T5m>>9u0 zs5PMw4FF253FXuP(A1h->>2=^T9XS3Jcnokr^jdjsA`~uY5>S;O%Mneg&m{`Vh6?t z1NZDe=igA)njnscp@FtgU17rMwy4D2FY0&_X*P6fyJ{kbpS`#?O z259^XajgmFVEZ*F7|IGv4%Gy6v1$B{zSabeGx|jk1Rw-JVQWIb5Dfr{4U`-j02&)8 zxikPowk8Au)c{c0KnaWwFaTlW)Bw=gnh;LN!#qIwK-@2swk8A^A3$nrvaxai^8lg& zu>oz_G}(YLen)LONuDE+5^!1 zUq|#nAG||>1*lZA7MB!}(Y5*WlnWLSRRG`)VEiAv-{s{C8t#n@^t>*! z+79(m4Ch1TXSGAI&L0^u7FoWp&0aYTZ4+ovn8o^eu?!B89XjB<3}&~6;|oe<1F?^2 zJNe#Y`<*GHbY95(I7*JW9K{(hhHo-5zF!}){$JGHV{oloqv-kAwr$(CZQHhOJ1cfp zY}@vVwPM>^$<5y9o_hD~^PcX$ReeA7r&*Jg%zB=uX8pz({{jCw3k-pZ8~R#tTE5nP z;yV_a@XnHxmy4N+m%8l)@#2rVZ5lB_m&oU0eC156UXu0&=eViO5Txf*Eia!}i*~6d z>N~&5@zVswp(KK!pr7lCTai@A(N+;Z5AoO}C5`pUl#8go=rKaL+<`VP9S}E$#01(C zYnV_3Z5#~47Adz4zTLrqv$`lkWFyhc`J%hIx)}~^p0k`F_`vG{A1ma#(3vDMyO>)P zXDv+UfFi00{S64q6Qa8F;G+{}%peQ%(sTcb1c%g4GG4oSv%(@6dO?p=zfWRMn^E;S&91A4GK@Hu%*X7%^x>&MD=E~9k-q0Q9gk)&^2qOyS7!&@;B&QNLNi48 zBMGvJug%a)CAyY*zJqoz+nuW~vU&Eh z_mLa^{%b%Vnk=K~w0)*5TEY$vrcu43CPJ*YOgyv_z}+Cl!h~glXNtsDf|q5`k41zm zQKfTqP2kf-`zMqSz;JoVVnq?39SYr0?g$R<`5DnWg(s&coI5|lu@ta70KrbKks;Lg zur_0;3ztqvPo){`1)o%r&R0z}yAiJtT2ry}Q5<>X`X4!BxE;{9gK9^kU*voaByo5j zA`a9#w9%`d#wAli78KEhKr_6mXHI0F+nVV@WukxaV%TL!8Lix@T1Gm3*kiJO1bd|L zM|8e$BQKs6n>d-L33WgC8qI2O2?0shl94FMF8sEE1J=bnfi=QAm-WiPbHbq8N`Q~6@LLO%h1a3>)3kxYhAkPfyN#!XeC zTC)DtOjn|mNSR8Rst85CfAM&ZU@q zx$bT9A*!xFz1`jHE9Z1qVZ1>eXV(|(YHZroYy|!XG)9RDu!J=xE=cf=>x25Uwm!-~ zIXj!5ak`giZwuTbpDVjYeq{jk<@BH@>&0I~XNa(Z{9;EwG5G`AqgoJ8 z9@VLxJ7@DvWD+@A-+%YmeFyyo{KgC~W>S8qmL4>rtueNaD#I^tF6R)rg}IwZS0&#M zw}rEF!j%-bAUqChD=^4DA^B+C&iYm4lG~$rVW0lzX6ih=1n?`mNhmt^{5eX7lxdoT zv^mS`J!dO)8K$h;-s6jpT{;u=mz!*U(TSCCQLWz){WVQWKj&iO_V3?k$^ zq62i#IoOk8CS-5r00m7bK>}oN3}_!c`r!b~RXe#;2MO&gWi$#aTBwRjfB&1vU3>+MVcsHRx zD{s0jt3yKtbL!WPYz7ue|HPK4*=TxYHl$-NYW*bdBH%TET^&d(3=_hdqJV!17hqn4 zz#)ahh(rUxPqW0N_D@rpu*7uN*=$tMZtQJ!*JmBQjyS)`#7;6_TFD*3TtMrsB{kd< z+V23Cm4$|-@)YfsETXjU4{UJw@dl8+JOuC_f-!&gE90ny>8Oo}+bDtq%DGDvGBLud zuBucqG#2&HQx5h^`3}l|LRD$|IC9<*5ckHnTCy}BI+=&l_M3(1*$#-BLvxp+b2pPg1qSFH-XZwhHR=F=}ak+OfEFIP#y1AfSAk zaC6bSL0u}F_qeS>45;0~=8oJ%qGHazRGYG}<%yn;3a+jkhL;9&ng!A$BLn*C;0t zEmdG#<@n8{KNK8ruv%gO-5%&dtkAr?(1Z#?S6~H`88s9TSTcjcKyI>bK1)mg?2i1A zRY*JMB`>d&AqhNU^~ihoWZ@2gb|L=fC|>0Y^X zrQY0O3BupuZMRJeG7!|&H93}R7BZBZkeyIVU9Y!2c)3lan3$G}ELupf!;lnePvEw& zSZJP6a`S zx4@h-+cSHc`5>s9Ylb4+!!)|Nw1HCP&cA9%Xm zEo)seIur3xzxkbIbN*vgMTbS04EuZt#-vamH2&D{J$HAGph43#1vAaQ1v^Tb+^QeC z992`4MfY7)9lA#@=~=PI$&g@AkNaMIpsUE+tx~lU7_t3=M>}} zwgrKDI5_6uy@xv^Ao2EiSst~|#@EN#K=*`EzyE@WyJh7Or8g{L(Hi2B2BXi;eMMEg zeRkvT_1IwDiL}-a0`0t+7IJaM9>ZLOt|vQE>!2i@pZk$E>@^wZn+Y01QunbLuL(3a zGfIiBa@c~J*0QopX4x#)Nw;RL*{XIu?tZLp+mNnIVOS<)f9?($z^(H(qWP zB-NPDjAFA$E?{ClJ{>-i+%S1gPzTIvG}czF=0Fw6F9~GE6E9ii!1lM3qX$ z&CSUtdfu4c@YHBVHY;B_Ujal4~%XWjR%Pd;2rkc6ZA`Iw`yh z9&ucWGC2I+VEkNEds>cqTzs`CG@n*Zc$v{rMPKk|(A zP|KsSG4^{z(P?H{uJxIt+&$YT;2SIe%1x&LAWtJeg?v4f>W=#>+y}uIP~84(Y&`Pl zOK#w~$b~=n#XTxDhOAJaX^dOgOmzq9D!(C(g6?XWm!kE}>$WIv~GX--^86rbY;hNxfFG7`o8Zy zc3v;6Z)R>_lFo_^mm>>I+A*w_mo^mjj+#eeXV5P`QA>FbNO}JXg^BJ>K7l!XKeL)x z=B5gtv?9jScM|>SD=n{UufC?>c~}hjyGM-lxkk051dDpBpR8JuJFQBQtN9GZRM$0s z$z}?y$H7cU_rPFH5}pjGl_<*mSRM(|FO7b1Hm-5~T6h7HBfk>J3OJL?xEWx&P)bK% zt0eRJ`s)1mVa{wdmSYRruFt2;BAmslpS=qUoM}OWF=4ZsRN~WgxZIuDIfH%=&xQ! zV9lR$(Qq<*|A6xkB`@-sy}b2=@_?)2lxfs3Hy}a68Sm1d@u{t@0MhcvIG_y8m@0fK zy6d`+m0M5TSKObkYkNC89rSo4;c6vY%1BAF7F*G3ZK_^AEEbQSGc!};(C*IjY!cT` zu&$3R78j%Bm(8eE2tol%II>G5N}c1qR#+{hP?Fj2ym@J+FRkN3xU5xe={uuh=+FrV zLc4o<>D1uGJNQpvL9E)8TvR4~<~~#3A&@@kDg$)Y1*546y4GXk zX@t^yC*J)t3-53xYB>1?`SN5AWUmiU_(@#wraT}9)~VJ%2ryd<2In7^&wc)V=G=LZ&9xyw0MK_T8#vEwdRN?CjsN=IKUTT30FaL!ja`iYt_pW0#J^!MOq#i$9#SyHYUUV(#d8h}*bp&+Sj|VI6y<%0r zu_}*1G50t%!fJme>JN!YD%g-8)3QYPupiXj7?&b!rqC}7yy<*KmLRctoCN}ODlxe> zmNIOyu${HYw|S6jGE1;_sFVwlb zkWY-5Rl_ZmE>t1iQossh8`eW+kn?Z=fA&pq!(zM}HzvI5I=3XrB5l%mxRdHMhnVqs zcxzS$DRZ$^>=Kqquf{R5J1pTr1}^aP(p_H+GjNPN!;!=ZZg?CP3Yf~WV&lCYiabFw z#-%Me#l1_LE>MRfj8?RKG_ywL3%=O{q~c$7&D@5MAo~){3?nAnz}Jk?8f$(>t7Uag z5SOOwTjMYA4W1pXl!;cSR8Z8tAA-j*V7i&V-tC_E-nYbNM(+mTO< zAB;cF(Mcm-Lvw@Lq^zr!@HXM~;2Kt;tpc z_u2dL{RYw@(o~-`%k+gtz%5KO>?n8E`}$}}W{QQ4VUwSkSf=Zj=Is%8ai~9K~2k~reXZfv6>Z=M84T&wY^W%kpY7OMbRUHJ)9N?7lfati^u$cn9!xsk zG3?kUtsANDJkj@=MqSv6*S*wY5&+3=t1NDHjdHUz(N1;i-pxE(7&F{z@;AGJfR@Is zpt%H@$R}CRNwmkGgJ|8O&DCV!Cub}DMq064>ppS58C{CL(I`faS-+JT^W;_B*b?Mu z!@!sMy%zD!A1D0uOIfGM(Cb}4tqL09-!MAIKRN{ePQck1SpIh_qzp{|Ss`WO{J&O6 z|8_p5zv=NmE2RG=*ZU6!XaB!TkurZ5z5h;;vVE6&|BCkhub}zwQ>1?d`2We^e*rkh zHxK`X-)w)YH#^JU;{9#U|AE-w$o&^wGcx~&Nq;~6w?qGB(|ZTl4o4+izq3_T+EB{@a)T^5nmKndAHR+n2vfqTjyE zq0Pa}`EASJ-pu+xJ@~uk`Y#Xu$7$=9@%8V-^53Hkf9+5}p!Bal{U5_N|2_16Z$$8~g~%S+x(m}$!3+ohJDu{0`&R`P zO8$Z&%Pl*G{u=K1ePqV!8paV%I~(>)#JZ~i1L8~>l4OQk*;u?ZG(N4#Him|O@>4@S zJG3D$pjrjNd5o+QCdob~>zM^lf;L?B3~XHZK~2X8;MqCp-Av`dS#@_gA%0f@ai3s& zzg1`-KiN&e$K<1*5#iW8%02kCG zo`bA1(e06vY_yP(l0QVYncOK-MjUxp!b(-3wSa6X&-K^uFwj(G+6)3*2@Ono3SqHk zloZ|~t+)*xu|nR)0qeY9ks=}K9b37*dS6g@-O29Ox*Ip;2E9H%!C>Q8Ovv_&KAxe+ zzRHgO-6i1vVG!*9{3YPOw6gz?UIPBkV*hc`!L-hZy%7F7} z;bsxOP|kSp7_Z4KJT2%YZ$1{RfNK_-#69jRIq5vt(z^xf0-&7!fZ=VQ(nNv`h~5Hq z^Y4WAy6)kTVc&jz?UYyd?|BMx@0DSfzAj$P{_|w&;gYpaQq+g6hxR6j;jPK=#C(0O)$)2H3bO44 z4jiSzb}x$7|GQqDcFA_$=lwo>zsNtwCp&ItA-Tc}Z@I$PVZA-O2CF(n=9{tvZlyii7bNCm@^I5(LGW*u9*0(X)7e}>Ds}rotb1_uq~yQLR>H8-vEd^c$+BSSk{x%* zb3_MBX0A#fR4dy*N|vW^Pf^QDH0dji2wz*-qvV5v^q+u2f47Du>hH*Frp9yo+5=r^ z5<)U_?saR<`Fp2O+xtR4r+OqL>*qzpEwQ6yqxFNgX{I_wJYwO)v(z3D^RCubDpoCt z(ry%lCY1W2xTg)MTdQURElo{j0?kP8eAz%xjBBag!qwqhuo1!k(Rj$2&M6`iaA*fH z3${y*M(UXTx{l zw7bNP*>&5OJ!suGVD66mOl@`N2k%vce#~GJNpP3!sNWD~6bGTC|3GR~!3H>< z|Eh2h0txfgn1N*0mhh%n@KkC(3>;w;1oud_cT@jQXZ6jF@8Px8N;k5a#MzjidOBL{jmI%QGoB*P;>}aRZ;J8q$aCR?fm3MF&3BPll5K|J?Y2Co= z4Ge=3YjSpmM%&h$;ock8IXRP=qr`IO@OMd8crK>b%c^N?Pd(U1WbEV*U+W;BdmzQ! zpgCHP4`Qaa%s_oD-igXD*8y0V6<9^INLTW0;uuSj>$Y|*Q>Ilbi>JMlK`4flQWKs8 z0BfSQ)MVOKaibqqM7Zl4dZZ^k$D;G9r~zXU|75FK}sqaF)7VCrRu z9tTDg3d9IMX8azzPDj7>L@+(GCh3h!j%N0h1lflM`t3tpQ5ZDZhS& zjUh>b5KFA7JcCRh*$qW_8VfuFbQ#;Gbdg)Cz5(+-Hy4Vg$Pj=&$(EqHlWwaV0e{=a z$*aJ>k|Tr|8rCev2l+aoT;v+6jr`?^;dpAAd=Q!Ex_w4+xF@BEcN}#~0r5&Nmq=JY zJS|y)QNsbgPj#O}R>WxjhM^ZBQ1rX{3VOS%wj3xP z{zg3FnVZmngyV8??10)R!*EL^p5$Z>*osWuLl_G;>>@@!Px>`Hi;NY6HFL!{Y{Ib2 zyvd#jjb6Qz(8}17zTv&Lo_v*LQ(3#Lh;N9blKERcwl@=+-@31MBb(#K3|3{NnVt0Q zeG_NB0`%}HJ}u!cntJu-t%HqIUPNw5R_u6j22PlFVg$hY!-3v3g$H|H4bSX!Vr1)B zA}N4+r?(#67y%=;I(SYRZrCh31`&JB$;^|HKY6qbD5x6=XUFc4j>&hs}5JD4B*Y|4Uy_x zDJHTA_s2^nZ0BZE*+)r!1+8H6>yl!GrAm_g`F#c1cSuaORnfkAeF$^LxyDA|>IHDY z5Zs_iRM;~Nfhs~+ajDEWY8^GrvIB(3)uOq7IXirZnB+`Ck{U3aGBZ$YmPg?mzIFVw z>gDlD_Rc?;Kpct8kA#bPOR9wqdig{PC`P>{qb}4CQPR|`IxDmu8%hCm!A;EfXW7A{ zElQ)3550!5b!znd##3yjPljP7_&O);U~8JfFWR3wQ30u~;Y(k^k*{hFgdy}?^fH(H z?d}B+x-ri!w_Pmf_HfR zt)T5wz#u%zySM;Mb^r!*-83`I`Y!q>@KmG)zT%?;mmK9Yeg^}KLX;chp#U1?_c}ZF zQy2IknxWm3yz}eFTiYb}s&DAk-Y;NywYo_-l-Q@rU4) zc6<|TzC&|pSe%EB@YJ!62jH6KmK0Aj(8}2JZJulgKy&$Q%z$j8guH1AGmKGha`j=BZk%d^F+9s1$J+`0(eYJ>TZ7VaA*p-0IBdmv#$+uv)k4S=RJ8$Zqn+5ZxW)vE zA`I32Qr`Bjyqe1xOxs$rZLgm&EAncl!&A9u)CxQ2gMk6 zxU>N+!mf2yoT;mlC&lGewqJ|N=1Xl#o7}>a^e}5#>DrZ7)|f`1pfcxUQMKdW*JW2! z*~t1$@CzxtAkS4_Zfhb@wf*;9{bu_-s(STGr_uLO(&^-CyH6gnm^8lBD7bkJuBs$( zzS}O)c^YFN5jrW8GtsE&D72E@WtwA+6Z5C({mw#(RofV1|2ak(m*Y#Qr1xFXx^s<_ zdxlEinbD6?AxG0)AD)20ruLp^Rb_YqQ(xx6*^1C@LP4@iFoR?akQCY6hW#G!l9kNy z!+C2041_Lj&X3;Lf*dOs+PEqFl9Du)h#WU0NV7#+&SJ-hOdVa#Zg9NGk}E)+YufO5 z`sKFSF6x)th`E9XrXa1~BCsA(7njV)4XMn?Rv!w7^eRbhB^HZF8SBXWg1UKMKJXz0 ztKNhi+=I$KzgVUaqS~xLqC}NjF$s$;bvwikl*+mu^Bl9afX7S|d}&Ms)6jVo$AVkA z2ZWriZrY100Sx*mqlf#SlwDRn%Lg<*OOUm@E5=D_<5IYo0?r%2V-F>+k^PYQ&3in& z;RP0%8;Z`n0c= zD1S4Z_8^Ku4{6zOlVz?sf|Tnz?i-3t6QN1QpN6KW!+xv2lBaD`F@>dTg1p(?5}Uwg z)$L_RtWGjxhr4E4#T`SBv}q zAUtBBoB|j$HqGn)@(ZMDG>Q+JFx|AuBpba+-S(Q^$dR$hOXGEv9DUjJ3%OgU!lGP4 z%y#%`>>Nd4?V2SCHpo@!;8zTe<0S~GL+PsyE%8Cys$C2puP%uagnx0Noj<<3UNbi3 z3g7IsVzL@gd;ox{?}!A0wBoRa{MrSZ>NB!5x`wO6W+jwAn_Ggz!EI35*kr(KFK1v!QopjnIn&M|B(zAw7~#ux=;xhLMIvXP5(bl3QvI~6J6CMA0UGrdqlLfwqX zI@;L;iYgU@l-=d6~n?F!Tipgafn&)COLTAtB7t5(rVddYZpv5~Rnc@7QtlcGJ zZgFK9&}7%Gt}P|}n^+wW zXfWt+PGxpRUBNF3_bCA#N|Jsv_- zJ_8@4puHL7maYJWa`{Hr2P#3FPcwjU+~kq|?q3vhwARl;@8;@4!$e=Bv|| zHG?<6gcVTB|DpMG?5HYIKxwdoj=PbZ5Fu|>4UBlFBC-g-W30We-=-7+X15~AC}NG zDG4UZSr=hS4sw-WfIFHPX0*}xbMyiwPxp!_Uo(w~Ai2DcigT%P`R)kO)VN-=c9ZBt zVQ{{gVqkU#*AH+8_Gl#LiZYH-iO^4v{vKP6Q)(gg1`1W~JWenYXhU7I4^CgoqYuH# z3a)2G`Ey88O(~4UQ}(pf2);p;FGm-o6{u-T*ik;Jn_!E*N;*Vc%cb>2Z329On0|$| zDcjjsw&Uk%j#+b1QPS^4liqBZEM!N-Z0USMx`D0dxio3jMe$3Z)aQ#IP@{ksf(nF{=hCHVD_Hie01>18C zMRxeqwma2Fr4l8?mXqcL$;tZ6mUI}lR|K#Eqo_Du-eZE{v`co;r|{HtiI1z7u5smG zdcl<^&o(@HO-H)Olgq;0KWHZV%g@;nL1(Mgtwmh>=dH&nJS*WIe6Tg!D>J1_7mpoA z0j@Lzb{9LV@fRY_+N;xyq|QUYy+fBNNu9I(b^-!eB6#&Y2kMuh(~1Sbw_Ah*lyjl8=xkFUeTYPZc55 z-drjvZ^llP`UPB;&7S>l;O+m_oY(Kk%*_9q^vcS_%K48CMLe=Ee4sV3N83-P;C?d*GVTTZ*XWxX?da!M_|lh|4~zAmIRR*NOGo^qY-Fj+d8zox#f zr@nGg0~mzHK+r*v)M_D@s=Lp%SBOK%0Wxv6_!_=Dcd_IM6)XfpCStW4(&IGv=++x+$&e0Jk5E%+i5>hUcS?Bw|yUj<*rszJD8sqvpJr^W=4+Ua*Dd9l3k!!h5Um`?X)=*~k4lIty`xpjMd^AkSlW z28PhO|M$b2DNmqH*r+o&qK%@C^f|^0`E)zP@E$M?`3P?a4yP+=qXprJiaK%EB2vYQ z+m$gu-@SU=-bl867-KUOsX~=9mzX`&;!MN@BjdQI3055Oa%XSVdKsAbvg=`bfSqKQ z7$3>@v?~-uQygDWt+Pg_RJBK*3bA{X!w%`)ipd0jH}=k>QEiGZ-l#%A*ahx(Jl&dz ze8D?QmOh=_*J_sKFf}GX7f(An63Vz;f^gZhmJ z*U#706cgrrz;6b`v-yU@whprbyrDJ=tLcfcr|BC_37rYDp41H#e2~rfwgmPj$ExPn zYE8#RZwK!dqhFQXUB8ohS9-&Rd`@V(nc)jpBrv%qd4lx@e+yb!(gf%Y|D2n3cD_BH zuSDvC`;&b#H|ykZB<2bC64^>uI_m?=`MK=bOZyY3yAA zT}g)>BBAhnA9sn2^ZX14hqS-V%tw&}h|yf(JiDvLUUnK`!gd;cLa>o(eF2^um`pMv z-oh++S?`O;01CVRsaDc0a&Vk0gK233K$);ur(Q$_hWRR$umnBgFLOB zICWZVkwJwg&F$>>v13rSF*sQrJzTyDL(Dl<1GSUV3#qt9S$QIEswrY1&J)^o9J#zb zDWf$}Vlu?s8WRr+6JZ8I{)%|%AOjPXxBtxr&|j2KM$SQX)#g$#u-`$}#`18wNuu-0 zf%=B?vO46EQ~@b>=ZGl8Jm4^~><{q}~1V7a+EIEsXYnoSZrJyvo65iZtY@1WGS;VO1B_m{u@IuX|A7W4w( zD?n+;57R>pCv4rj7Q~L}8e5&WxwfXIjgsoX9w*(6y(T4*Ilm^fx)oSg*&AJSJP7P? zuv^`j^T()Az^ET`?(?K^G5u$Uq=S8-kIGpFz!=NFD4~KEU}2@00?46=Z$;2ja_Zs= z=MznM5^pA)!pjTS-32r!oh_vlFOe?+qn|l3xN)maaWT%K8W*laOP$LetFm~ZFSmO% z8Qcc5T~27I@5|g_e{axR_lsO5;iSO+$VlapnVv~6%XMrtKX|%PVE>&X^Rv^lhC4?l zK07mGbI2KukJpx=*xikkbNqv`FOO>|YO9r8MA`|6K8-|V+)?GZ1Kevk=<`uUWovUN z;(}w{(;oS}d1mI+`{!=ebl_7ktU{KwwjZc9bD+CXyWN?UTwu6?s5COGrpDYlVO^x6 zq<;zY>I4?Sj8Y{br2fh>tEO3?nOSQ1Ti+)QN`y!EVlG?`(j3`IMDibDr##`T)mdUf z6aY@L)3MXd2xD5@jH%eELUPZ9tWNjo&J*_@yPwrvvC*Lv;$>%k0r)dz0wu^je%FfaO8bHt1Q~=~fDFf7pt4jQ+a{`VDy{o7pDRw1^G{m0bAM>SsDxOp0|o?08gkRD@L!)fY={7V41*3FDSX$%TO1|NF{+6 zQ<6U<4U-!gG&pn8#36FY?R_poajSIMAKCx`eNUm7xhw)PE^+}tvG)2+MnnqiPfCYG zxH9r9qOu!agYx@zb7jO4*3v;jYZ``2l(|4($)bDY3c>0KXa27N=l_@|Y1?y9y`RVNeH>*%Eg8z-hugr7dNFJjyvZxr9~(W3%TZ z+H6<|t;`??QcMfcC@dOL48&SPgpDZ(VuPY$Z$tICMt zQ#C<$;9zKrtOI8OHK=mlRHaJ4P_TCF0pP{ZX%&?Q>nt8sv__s;VRQr{ABF)Oc|&lghZTxICKFh5RH}g4zdJNQUn*!>AJUbwOcG(ctk6dw0AG$N8|NgPCGaPZK&1JK zg(n0Xcbtjooy1Yx08X+F1?CJS5I4%UCLcvasZUa*8q;sR^c1`>A0Gp(^n4F22e{f4kyi8J1Wg-8F0Yjjy zFrl?u4~Ks`6t6U#U*oRJ1swrPocjt^&!(Gg{Y0f>-##$0?<&9X_eEY`(S=XH5b&c;~kZMyb%8>K+u`HL*)N^&upkICg$mJRU*%Ys=Fs>_->)cVrVk9v5-EjwCabpMYJ>Tld8e8!v!n~G| zP0?WY*sg`c>KX1)*`UJloET0;U2q6a*>XKez>-Grlt!fLSO}z=0Jbq$h64A90;CEl z(vF;X3WOnRgTP__bU!Z)v7tqH0ji@+vtkWrhK%86?EL8!fJHE0dh2h zw%SvKqQGtC5Nw2VpzgvJ`#*CmBkm*sR7~K6>ewi#;QhtmqT0tDkHSA42ywUJ3jj5U zp2(j4Nf04W+#`$~P+oa5vT3d)B3zZ;XSfSs#Ya2*5)Zk7(o?Jt&abSGAAnaPmUN9| zS0YZXrJ_)MbTXY0sd9f!VvBZK#sj&TCz@0gYTJZY>ve@#$~UOYY2BF6tttD5HmJV+T84AM!4-44 z0&7B^?|mukHPpVZu~*IWT*16gr7t2+q-ZXkC;rZN3s~`kEq)T(s}XtY$AZnnTHtyi zEH`120yaR?X62-Ycp|WW>ZB;pP<4Sb@-0{RE|#A@g4 zdEPQb$i3j*;E#M!_5j!zgESt z&Zu9Qkc*D6(P*Q-*#nN-MP_K%f%65-=26Si6iapH%t;;8T5n+_bP~FGJPqF6ExyHb z>X4RICsf$B6FHB&mWcQ`^F}^LPTy77)Q|#e-y8hm(3KRQrkpm;O{cuvqSN1iK^W<%Q_A@J6q-#JU2=*jsEDM`oVG> zN%O~Dlmux&PTLm;D2WmhrN9oiG8A?MXmO;~)8f6|Zi3d4AW?#j2{C(I(2B(#E~-hb zFnVR=y_jX%!a-CX`6oM!bKjS&XEUxxR8 V@Y${ZoDtAv&d$6zJ%A|q3s?w{qcs_ zO8V<9R}a;XlltlTO0isno|E^RLv6mtz>bJ0Soc^YGaJX^Adz)`hOX<0KV))rR*hgatG5vX(du!~ z20jaKb{$r$RS{bvc=1+H)+(|xB~7QUYkBaVkwIucjx=@qCMlY9IQhbkr6y5B)k09I zw&^vgGU^T;sN#VTBupWP0C-7@#C2T*&XP=pMT?X;FXYm-&|=en{OGzWtSalPSscn* zQ7uEw5tFSG%v+U$JO{`r6YRldNXc`8n!-M%_ho9>E-Xi<3XK@6<;7!~W_H z#5XE}hT2E=NVrEK0ak^AnDbQC)t0gQ!7zH8 zn_Vv+U2_{UGHBKUh*hx5c=6!2NE^0esK7Piq{Q|ZU2zZ&mi#j0H} zNTzywj{|(9?jb(QE{-5P6^Uz=${FP$YCAkAsCR)5p*Crx zuM#<(w)GF#QAabG>Mtdi^%N7E&Q5j)H51QaR0j6dsaGbLxSyACFqzM5`P(d920f|o zvDkY4tW8CsPPRiAg+Nx_Dc|O5i})W0ye-8Cn0Q7|^UoyPcHf~DR8-6$FJlXV2|Gr3 zJZRZ+Qu5PSG^2qZ+G{ zsHFvOEprWf+1W)g_z8fWpv=^8KuW5qs3<8YQ?fTnWlG&efGSDRRuh}3L(Cy{biDGL z8LNH2m7IMPv|7vZS^Od6)`vgx8D~x7cZ0F5_D8-`wf&)MW$EW^2+@6aMP^xdN~?}R z`vt))ef5Udv8gq?YT`Y-@;3a;N7#qH6IeY()F)~DbAeJ3;3+T6EkbusfmNPDp8+%# zH4U+;c!*H+yn=B#A*(oOwDM10#1+mHyn>03h$F20EdzE@bKAxzpbxrNX-dHKEtJ-} z3yCNqEvvXvlB$##P@S5h>@a{lMnT46aH-(~DoU^)Y`6e1imDiNS zR@7Gin-`V4%J{98itl2_(m<`&M2r3BYUC2KHc$5?*E4CKyDs0obwjuh?u=h44<3EJ zmNe@L#%OAql^t>dGkk6k8XLeL?jR_w^z zG6VMsA0fNRRyMtQK)G9UASM8p2N(vt08#Uz0*jNXR5Fz+g?Dul_=U2xFr za?d)SORV2(YGWDn^%3d4DemvS`6ODZGp$vQ1pg1dy3vEog4v6rS}Q7V!dlv(<4d}y zkN)NbwfibG!osPfprEx$UVz39Z{;A?V`Ljxs=7C!FBg#qEu43EXYL|C>ZV-QqsZn{ z+=OHxXPCZ%8zokkensE0QKT4@g-2z4F$JLepZS!KoQ7$|KLXsQ71pT#g)$fy&*4eF)THcJ5xkyt_O5DmaJ52=)s!0>XLE}LnGb_Oy z2cBDlCz0X>6eOYIpu;+`IjS01`dbYS#Z59v^O_tsB7y>my~Dx+7JlBhDpV%+t;}xR z2|P&?h$wduc(RmqKg5=q3~W0sdX9owI;zqN!U+&E25W9AOe|U7)>D#RRH&3XKX&>9 zm(-urzUPU0vtO+xzgitxhXuk8Dg$Sn?Ft*?rXFc1KL^s%Kj`nqli6Lg-#yRjwOj5T zjHg{yW4|wF4}xy5kEq#Oue=Z^7@GQJX$tXGcj3R*bITKLM?vL^EU$Dbe}$67vvO6LHlL{BZ~qzQ-foS}WvsZ;d%-C35&9Gq zcFo^lX?d7HseybR-43nq`Z@HrlMd!0j3xh`tJuI_(S*iM^BPW0LvHM9%Wl8L2j^%^ zio=};0kw|bBNX8gEgdr(5WC6*bH*}hDJfG?5F=$pC4dyRtR z4rnuN7Bt)_IN+|qnywh=>KL*KGYg-MM87m_o$J*2E7MHpSFqWrf`W;nNNOm$Yg+^d^g^z1eK*5Xt}R?6ON=aN zDg%NTGww68J$QOTk?}!xA%C%JcHC%GapByWmvn^68i8;M-38c`-_L9&2U(SNf;%D; zXHCxhb;a-@sM%#XII#!Q*1h>->f#E&1ks8aX)AqRK*EmPA0zh&=S-PROn;d zQrPuL4q=aOaTQ7D;}+#G&Bw#>ayRQ22pLq?a+%S|k$TJ0p;SN#@Ovj_`o( zIPUy92I75<^WF5A(#8!wIxtzMNw^k(SH5#>fO>!Rm;j=)FB4a&ekBBosL)OUr@8>!<)X zr_mUeX)G5g4>`_X}w*bvpd){~$|G6&lPE zHDZ(`V37ovjl7pD8!OXx*Qcs5QJ?52DB7sK3qPzEbBipl>~wf&217ng8aRf(7<>4s zUUiN9PI?#iZqZ#4VmXTlD-=sCXyF$zRp5@6sAc5KQLKkce&dNGtfC^HWw(;4SjeBV zsFKNN&?LNQUI(FR6|Op9=`#^|#PDxL5>)HQLlx60Pnv2Vh(BTXKOu(AwKE%_edkQ{ z&2cKzP&rD@DgrH3(8xGwQi@LIH^-HZvwBXJ-pYm+Lt(wlKhtF0n=XcwZ&JM?X@iM= zTkH+IXqH~J;mo(ahI*5nk7`{?b01BdEc{d%_lqh84vyDykGD>ZzW!Ic85eDPvsmv}0OO-jsrquM{x|dQ* zVRA_%1$HDAzsii3B+jvBKSc*7DNbxFZ?c66p4(g1wz5sG=F1>$M{T~&yXeyMwkQ6i zujg3~63V3zxPyk>JV7SVn1+!SB|lk3^|`~K_a z*VlN!dD!)*erJB_oG=Q@QdPf#r)y5jd`;NzMBokat+tVZE@deYz94+7Jl`ZEA+bF9 z*3&hlp;_2|BvI!r-jhcQXvFz;qHqiIVO4vPwNdc|9vH_)A6TfsuS zJ$G60x)H-Jm8yr8i`yAlUZ)E{lim8s$s5LBub=Zg;qB$o-Q(M@yDoV(Kk41&K(@?y z9l!D!9jH7o6vxg3#P|`{nynW^2Rvq$vqO0YsHv3vdQj*3cc=A)gAfsD>uTft?Du-t!MuUxsmR^Qo+x%!-1h$Nz z;`>?v?ox!hKYmT!LbdoD$&tP6x+|x#1z*{2IXb_<`@FM(J|tEuW+6~SGg_y4C4jtp zvrx*m$Y*{J_f@f=F2q!f&GBDceJdo594GC1%c9Cb3jXX$n!$`(Htum$nu!}hMQ*Xx zK%~M&?fK$2;c{{CIYGtm@+iFS4z-}9i}$CRW$r9_7&zhE=t)+B*?t);K7gO=DJk%j z>%$W~ZIx4=#Cvd)>P|Q8%N=u=q)wG4HEvrtxh=!t%?|>0smo<~MoE!8SqPh6J)p=z z${dbGMnO&Mo6Cq20k@yL=Ei_}3$vvp4$`~H`|JvwygaAoL zws4{iUF1HkND;G*%nvGApFkcH5(#I^kuR(^SKBLvG5WTiBBK)Q4wz^MV+OUl8>3=O zYWg1cb7c3qeu~6+4z144pR|5nPoIp8TL)4$>DoSu31zDJm1cQJv#WuyMVF|Wi2v}W zReGDMY1g4utVcm9FsdaeRV1JwfT@D`C?B#Uuz;S4Bq2|+j9gOeG>#Cm)q%-l&y_{8 zJ9?T@U`M)8-iSprmz@iTj$vf4J5JsDDeg1Y+5h0v;efbsc*AAiBcZ!dK5;pJV<>tEPTO8wk556T8h zT>RuGu!|1RwtW1fTk^TkdY)K1y;yqPX=XmdNjH~*rYJbM2s$z%w%8myos>bGLfD8R zEFeF(p1jl#=l}v}oD`3=f%!o7cAVKtL$i95gwqA%-Vnt`o+x4Nd&S{R4w{c0K=}@Cm=JBr0T>LS9`P z)Nsqg`^J1h=-veyWdmc{oC)+(HS;s`GtKgOqJj`W@LWPP6oS;mUZLj9%}s$2(xp76 zDHyk6j?-6ar&4kJka{#2rLp?c`0`x=QQJQRgmuXS`UUN#;C8xP=zL)r)p<;=8NV=O zr8@SqyLV}uq9d>+a#BhVvHLkub>EVjV8zN2GW3>CD2p&4pOJ_|P^pj~jhg5C*)+xC zeD9X&s%r(muF!%V^f(jFn2~)WUo>T7v`u%B(1_V~oc~81DNN=45)B^~U zOq@`r4qRMsGgddrb)+1!{J4U+opd2##N8&fL)qYJS0r^2Bpc9;q%`ro7)Ll8alVTm zS^8Qa6>Gdk_5;L(B8>GpRE!q|t5oPT&5ZAy3vH5;=z38K4N!+cFamW5YUMxqbHMsM zNvI#uauIM7eg-$rNxI}}m)j%asJr){}EA9-F6oU#Xg;+RomE*L6SC1MR@ z4r6#Tau+5WB`~C;FoIH3VS(z#Nt@ItsMUaCJ~A+HBDZ4kD$^Ta-G766D}!|#HqXL1 zh}UY_tsX<^*E;%{G(T6Bemvbs8#my&dwEo7Zv;rj$Ct5FUX&N*&#rYo0CaqBlfXv( zwj&-m!0a`|Q;FU(u96g|l9enGD~OZQGNYlbMo0-H@L(4oh9esqQ*-AKNv^5C?$zFaY4LuqUX^us*)hK{pq zbKHW{kBWmt6<0U!jD)1rb`q39+io)` ztm+c79Dui3GOHnJK5m=R$To2h&*~=D9%o2lzoDR(u)^Tz0Fh-dS+4v831jk|M;u;G<0Qj9BCR>9RJN*Hfe5|48}{G=9Ml(6>;G$%Oi@m_ECFdWgji)(QB%0`QBpayy-5p=dNoqSg@H-jj1| zf7Gdvf>R)C5Gi6d(y|+{aYMoQoXw%|Tn)595vz6&90~_oys=G$!Cw#yP#Gjep845KF8FOi9#bNS?5B!K zR$)Y_Yp}vN8R*S6z!m_*AMLgPmACLq(J&`&Ec(elzS$i=@hU-_1+&C)W^VP==(7iV zZ{Ei*M`GdiwHbZN-jgVmHgS^O3VT86`!}U`#EPI1>(c$J0dXqbRMaeCldL+Cn*sF> zWsTtEMZDfUYemrMzH#_0=!+EIAy{B6Z)&SyRAOAJbFi#&2TZA7b8t}9TZP@FfjQYE zZfr@qM-9>DvoJZQxbkWxlzSOvlMzUgUM42xO}s+=KD3mn$*A~bgi#Y?#|*TlcbV4| zpb~e`9#QH!R#&OQ${LDf(Lyh!)4;UOev+`P>y(k<;`;_B*KzEytL$;akm~+q z`5t{(%_V4VBPU%uP2PI6RDNwX`P9848C*-}_?(T#v4sSv7 zY^E2uFKn6B!gt+dhE8!&Ms(NR=Phu#L)EpPF zR%7S1R!iS0nNx+Eq0<#2Haa0O!Z;S9IzoCY40)j3eOfkUV4 z8lP7*n^*EQ3m57o?LbFw@oS{ZKJP)tX*058(Uop~SP~`Tl1ReA5}8ln7b>K4g{LAl zB;+qU?EvE-ty*3a9(9ioplh+_Vts0TW~5IH;qsLs{TZ1BR@t%AVD22E&^YDZbyxsz z6s_*eKT#~^u;N%g+a0hIhnbrd9mjnOjKqLP@_n;C*fm<$C0W zpnEKKz-TgfonUX4oq%UD-e*kjVydh`S(f6tS-Cicf4zzC=_(SjTtVc{b zGVCYK?hQsIXj)4Iv^(RdBG?Uoa+54!h+SUDpVtu-5JE|~Px~qJXuFq7>GZtrix9zX z;70H#eS-xON2Ol;*4X& zkQmgB81t2u7e04_pYc?+!OiAp@XzBd{sXI>7yw8PQ@}pAt9qFP0)=16OC*Q|?r318 zsZbT4-!>Q-gs^>~md!i~G6lO>Sz)x2qn~3=lf!f16DT+{Cd_*XB{0I2O7%JA7a7-bHP|^Sud~#Sr{*FGwtB)jD&pelx zS)@8MFa!}zMlYe?7HYKME!dYPb?v{HlJt;EBk9k6Rx{r&LtLW8+)GHdKS3k z1m${Y5{i1UlEfP^i8fg)E^7-lUkiSHqGO@ zi5NklRz9?yK9g-uLbC|F#l8}EH&wCKjQa+Vf%YmTmwOCuaZJ;)I*2j-FQnrt;*pgH z{Bbdf(yT;yx3}QJuwR*Xsc4tpP8h}UfwR)Z@#O|>K>kX?4n>R=av)yvguofibXAOc zY@SWTX}?LcNWj4%5wwKj`f~$0O;7=`1ailLZ~$;f(q8joTP+J4+%DO9OPaG%Vw2)i z3G9l!&>TAzdRK~Jv1PBzX{yQ;)Rf)IvcnWGEtzAM!RU-s$DP-1^*|E>lM4L1keLjg zOWMTs=Frs*k5t;EiV5rM9pdNb#icpvAcyS*H}!~}^@Pn!C4w)&bZP4(07{p|pZBx| zp*6_gcNBw~ciZA;D-;kW03X7o5KTovaDh%jTo{e)y>v8W)@~UNCQ2ubtn)bqXxJta zA|Q*ndAHQ!G-u+>klw(nm^#x@cs)(uClRL-Y*LTOXO;#d3tDmTT=N)tB{X#cawa6u z4u%O{rd`L8QGyWdqE_nOA$Zyk7_suga9$b25uO2G#Kovh&uJ9rl29W#`Y5r_`yq>Q z+**QWGhEVlixAl-1}^EsI5J0isfEpw&6uIhUyxqmfXH@lPXtSp0Vb|!|G4=R^m0Fz z?lGMBF>u8AGt_87f~k9}@&YG1-oexIMft~59jxl=B`P^CAJWGBVkiRx)Zi}r+P z$S@;0($hNAF%hFzGb3N@MrtB6se#=hE;nTheAcQ&lShidCxVC{Ffg>D1&0Wfb`Xo- zz1|%(I7-o_xoPnR={uQ(^ptN(0=5mV(1YejzcogRDB^YN`*xGRc5J&mmNXpQ>e=!= zhDk+GO$ZgE^JGb1(o1q|XKE zr!Rurr^#0k-Nk7(xD)u3`r(sx>8u78RyA>o?PG3UhFPY^MU|3g>BIS26-cAJ|L38M zfx#k*Q&d_)%$d90sfE(%EV>8}MWc^^abII+cXr(CO47-FFZW!-^>llOn~}~@u({gH zAmm(w?G%KI+MNmig=5wgy4ow$M(4!fNG*be)wYO}lXIwZ4XMJ7SXiq*odmRT0Hm`W zBi8~8>i$eJH=gBk=ALk|d{o)2M+O7T*24emJdB&Oca>+Pn>VBP!Fd#Vjk_^oPIp9`pRf$p z`7lu->hS{ zl|-;u>7Vq!ie|qZ(C~Xa&jO-p4Sqk(sRqvMT0)nonid^K&B9RO@iNpnOmC)|#Ze|n z+$Aur2Aq;xGIak=O)cFwEvowy74_urB(J4-_bL3!Q07y}A&oym5=a)%Al^a4KqEnb zXz%X@C`(PZTLv`IBw?VEtU0U>5h<*!lG)ZqED8F$UKJg4Vs)G!h5*&hO_s9VEzN@- z|JM6}y8D?=cblBJ1hyh*2ksT24rIuFNp9-rCX*v3`N@TMzIFOt(z;Q zA_1z=DLSx6dI9R@kAN}=rN+5tr(7Ij$Q(c4$T;9=i5yyXXpsic?UGoOgmp_Y?WT%49CWA>6?l(oD48sL7$+k#&121Iv6kRZc;kY#Xu1ru3R~V zF~Fk71%8WLLC$OHPY?GffsY+D4a>fH%K}nNTj)X&<|?FH02Hr31@(>ETS-l!LwhfV z0t(ruo3Z{|Ua+V(bxKk3bGN2erQi>;4CyL0BS}Wgh|_*Hv>d5|0J3Z^qGjSCeRjI6 z$XUqIzG(wCQ((hg!qd?ArsOzM5^a<xRHqi>ZecF2|;iq;)h>Sg)DF?KZY=s zeI7Q%Z0B8+7i+dU0mSvm2x&P={us6YFnMo=gckDTFK?>h(t9O_cq4mvQEe9k8|C)C zL5Xq3L6ags9vaD9T%9nwIFz#b2C)P+T{f$GnqNx93`ir!$07P_Z5DtJeALd zM3s5JvE(^FdbsNF^m+QT`^R>@X14xX#&`z+vM-JpAJn=&QiK5K-@qejUpda794YxJ z`I3T(0=B`#p-$X~=2oFjU{XlUd$~%^WqeP{=R_w8G2PJk%V9p^t$Tb4GGnqMl6&-h zr~{YbE2Tn88v*kQgNk}3cQy(1MD+cP{-&zZfz|-H%2()4$lSE|ncc5e!f74oAK-e%Q7u zwRa(v9ctVFK{_*1Ee1I=~$26Elm1`mQXEb0BiW z;0|;U78B%yi5!W}H*u)0*7%B$U}{Ko*CCY+JRZa3POC!s9WwSn?~al)_P~%u95@C& zx-sAg$Af^nWTA zU|9P7ZT*yr++fH%8Ti)M!%FREE>MmA5O4_O3|EPo*yzv6R?6i6i4uDQmZO~tdjXoW zmD>gE1y&0;yNy4GmF(WD%iay#2KH%P&Ta<8SX)0n*Kf}u0 zjL!YhyD1}wrdMhy;MDs@h)X+&c!`=Hc@5|}u(O7vHIH`Ohu{Mj#ggdMdD@2hSQlst z9FLA;OUhJ3$UUP6M_{T^2|fn-9dI(sc%jc8Ty^D_VMC98=t#acz)PDr0dm#QTLQe; zMDKuU;glZoqq+7RvmGH~0d6eU;xpSH+6v{@gGc;P!2vPl!=hb;$O^!b=MI_s)+v_G z%FH`uNkx7pkmTO5~WIn8BB~nPcfAPO-vInz?Hv_ z-we18ZRSHMz-LBPn*}=-)68JT17`$URSJ(YgzL}9J6s->8$Ar$&JsoNrGj3MrolCf z#H~g)+Ek!LbzthWBlgvj-_1NOK$qX4- zvRsw&#fDtOX5Vh>yp7_OKJYfxaVO)g4DpO@WM*q|Wa zy`d_|d}D4WO@Jv`ybN?;17V{}u8ua$^J9%Mk61%hZ(ydF?UlZ`G?eF{-c4cA?*pYm zvUSAz-v%C|u7ck{rdeaB@CFfR>U`F?ArS6Qnt$MZT6QVLwXYO?j0zAsGzJvzepSu3 z3T?E)%WpG@4oEGt}-F-~=LsCHrGf@OzsOsDsq{yYRY&*eqr|%keePt_hg; z$Vd>G1UfbT;pH-kPk=%hqqxg<|^ zWU@@hAB8*L0T#g|PmqT>b`g232B|t*N_h_72|eC|IcmghivAMYZ00HISh&-rJ`uWylbH7m07yNd zE!3MOx}o^=E!5F(ynN&3gFY8yECX*E%zj|YU-YI#fw+WYD1P!0b@>9`e}La%uI5;O zr@&Wb!Wp6S7Owf?A2k=8*r43aR-LsDL>BHF(HG&#pN8*tCHH0aQ5hl&GQf||S(|5` z|MvObLH^*UK8x`U!E5Tt#=L^83T8yNxX5zJ8M!fsHlyOKrm4tmc8S?I7G%lw?llL8$7L;nyy0}#xl4Q(DcaGZW_1Vm+6c%w2ayFwLk?aDxV8#} z3zx$>s}KALrbj003c$_T{t34tHL9W*x)9^m%+;kQb31!<2i|A{pS!Ma=`U=vDsTbf z#D3*NPRtKVZSU@Z!`m@+GrP`Z#hbyid&@xV($eU{Mc}VDuR{+)P&Wif0@cppO#p8K zQ18@=qYcLDzE{F^unRhaW%OcMy)5kRSkgjCy;@F-=FJOZq^)Z zxp`VBr_)EC;MclJOc%DjLO}Z)&eaxehU~_HU&G@@fg##L+X&|A?0RFaG*|8rq94#{ zeIKJ4mP^TiHTY4NHVq!S&=|R1TUKd%{mO|GpfrsB@s^$)!LO7Nc;{VEoxMk3^S(L% z?>ME+QC~k{P@HC3wY^l(bc*h(pVUm8fNS~T_P-+H*QsX&VMh>C`VmP9Dl3t(Q&DxxVzCku zE;%I|(2-Z!v^7&#Ajt|hfFV$(HK57J4#T7+GX>T_MZLwGU%38$EyQFcB_$(^s9575 zBBOv`+*iCAEd^{NcxJ#pXlp1u115hLV8cDMWePo9dkeGn&%ih@f}0^vK^g}P$hiO* zoBalIt)1VyXf$V*s*}O| zaP-=H4+-D>yTMk;m;q-IdJ#NDL5z9y6n2lQZS?%U7Ckq6AsMsO0R%O2&j+UZAbuh= z7IE^(?NR}15!Y#ikY{uI{wPNf$DV;SfB+}}!hoY~LT46_T-~o~fJ@8_1JuIT9|)X+ z5==nLRV)Fn1zB_A(BANe2Y~i%O)!T-38WsM*)_8RP8IJM0*UQ$R7JC5*IFe^-DC}Q zzI5IX1j1{pL#X_Xryoe0k$Qb@SUR#Xy|?$_gx_f%R(@^Y1Uqe`1%5n~32dH5vxC=; z7#^H!-PPS6*i{sfjcbiRm(=RpGo`Cm|8zu|CRu(VdG^n51BuQEM#&ji7EK6>h>~ZG z=AY?Pche>GZ&+qiKqeRZ9qwT`@5Q1LGS7~X{wm*k#t*n@ms)xl)~8l~-s}mpW5adG z=i;z9QjieYGaA9C*48b%CiYaPlm9--S3?GwNl@74H+Z7j>XT6*@#P6c^y*GYDMd34 z=JZ6sIA($-D#6T_UX%#Jds`SF&gu(JU+gzxjixwP8%uS>%C6DDeXZh%R1`u2ROU6R z*PAJ2uE#^6{Jg>jNX*0vW~Hrj^*RnkDUN7Nn;TIk=&0`_uX6{xTSvYhr*Zp;FPIjF z)a#L#Sc#!(KAk&%T0-nvv;ZyLRBm7BVsx+?|JgrIR8TaYY0IpN7DZno&zVm66br*L z4=4MyM-c}!yoRwBI--}W#s9d+-h8#$IYjr_Smznvsq?(B$CW{co7qm0!j3_lFkIul z5!YRMeMFc1`FQtSgTJ;}N}HK5FQ?;lvA0oz-+5Cc9ML0dy0vc9)%yK8cY@>i{L^@r zLzcbaWwV_@6LRprLFsA&;hHM@^R~1=SE;eg>pkPo!g`ai8ECsF<1I7WV*c?gisn-J zO?(p4VWV{`a9+Qri@W~SR}u-r$I6?13(H`Up^N2aFn#Pg!~L^3a_{jaMq%9LtDJu< zE0BC%qIZ3yw>N71Qq8rPw|X~_-3CwhrRK$;=y75Rn=D&@lM_Z}J%Q?%J3JGHv>^<2K-|2h~WWh_9i6;tGp|~ae2q&`}vR0 z$i&;spqzBAe~7YdRG!63j0T^BJqa+COO7Q%r5jgPEpw>9nXimmlw71(crUqhE+k9Z z0I<)PiKBg{vS?JXh2RWIUF&6fYcQ$b#50R1oScG~Ef#b-0Tb~U_F)WhW4vedjr#NX zX3X)7T8HK1{0wyWm}R@0!GXvE?tb~OtBvF+hklM+`^)EQC6_On*Zb*^rVq>ZZH%v# z=Hnvv*~|%FM)!HgVMNAJhV4$9llBY^JO|1RPIv2WN*7)1!bG~0rE8DF?U*bY9p_>^ z*U|RY$MMwTA+F2abkFUX=P~&Y_^)N>?QelK9<8@>>4n7pjpwdLgY%2D93vLiE}KjV zyec-ZWyPAW*fmez77wIv!x8vv)T>X(zWGeH9d?H2+UoPcF)Cf`Yd6bvi@xNXWg71v zg>P^!6-b?Nw;%t88x!j5%ton22hI<-hkI{q;+Cm(8#7+i)pn1;YVR(x86|D6!(4}o z9s_}i6gFIMdi&)&b6h2S@KzXiQlKH7Xq}FuffBy2v~T0plwU=pAmpqs@O=?dlvyqw z(nj7DLK_hMl&!NsL;W;ynEvX7%0{f3K zof-$o+B2*8SzW%e;`dP<%iK+us|V1_J@a1?dmFr#&)c9;JbbJ6eY(+Tv_w@&3Gc%= zJSA(6?mjEnz5J^+-kkPO&%vjcg$F4;J1yJ?Z`X4v?K#iV+Yb^`>zioLTvYh0k6!lU z&Bk?4OEmbJ`!U}fN5$bRTs*&a%yQNkliDBZGAC7;4;uJ1KEoyAn|F&M`I<9iUP!;) z1h>5HFXL8dvwU>eeU+AzTDG08Q6NiltbZKj``6zmvumXwxqgGpoRd&!!WY{!bo8-#7?^6xe7aaj#@>?N}qX5uxCsK;q)F*GCZ zr>t2cN%(4}cmV({H>*m98+I-}8uDxDja^rA;9QZZYNGsvfD%V8Lu z^(yJ(6Dgk+LnQ=h6eiGP0yRj20Ks{)C4=za?MWr#4=31D!0G8HBDacVOYjDXUaG-M zVSDks`MUVN>$aHW9NV0J6v|Mb^U-mpcK%^va+AdKI;}Zg*ltoa3g>DadXP~lnom5K ztEsW#+s*!%$V`f%yP@jzedvF&2uE+R$+*9Y=+a!TJ&kfUAK~TUNs`2wo^(t^quXp| z{Ky`-n7Nf$?AvS6u*5IzDWQ{dKuV}>S;h5yd#y{?eVFN@H!vVS9gJy; z4kvs0H_n&${X-~{@`l}3XQYqX@!2AUcVfYt$3FCabpiZn2PNCmyGBvwR7X4AQ*?~W z@};xZB0`^MyA>kGWp5eX^yc+=H58Ul`a(yJg`}Fi;I8)--=_QMA%`#Zw(QM2iHFbg zX;X9qs-$Zv^W$nE^v7WKtBvyP)Aov`WBQL9hsjyc7wRUMI0)5^0pS&ks>7y=ohr{B^p`G31>I~o-84$a*k-Y$xT}=;Igw=h{dxXadaPZm% zgmkFamm<2hpMX5nn3!MwEa?XnLwt*h49o7v%Yi%8d&8eN zQyLFj@xRi0j*GYNZi6GQECz}+Wp~nEpU&!Htli{S+}zgqM7xK4KaQ_#Z!r4SUoT8n zzOL|%d^EON4evHe7%QYPHPK@%Z4k1EVSA?3x-%Vi?gmiK_k5?nHqK3_iEI8o{~h!A zZl2g3ST0do-)69^9!eR+zbdX|D`dMz)agAAY9gD(M8;mdV`w>7xT(VU64|p|xk!u4 zXRdgvD|qcjS07KG3)NANvwvCg(P_K=fMM5hF<6`w<*e{V;Y(vKI31}zPtchM6T0~# zi5WqoB8%X#3J1hMu;VkfqV%6*ph2(h7)VU+F-ZpCgpy!1>A^-#K_@FhCr_ma+g@eZ zWTn=%rx55^z*siObe+Xdt8$p#@<(PkIO5gvwDv=~J#pg3S8OV z(SZM)7IU(FlIeKEbK~jr;`>dfs%L?!OtqldbOf@K*?}xU{FTmZ;RTOz*A4vb4S`dJ zGrGm<3fE>IENOShkfPbY&!2RP{a~4*$(*Qtf4;LQVu!7D*#MX54$WN!`QYSWgm#3q ze}Rc4;p=)xR-=eoZn1Dv^V>DEHe-x4#i3d4!foef@5yz@?pn@+7PEXB56Z<>RN`F{ z5xp&^bn(+b?e6`{>-W)M)rJ6;@-fZH5eSN4YmC}Zjw?MYN_kZ&Im?611jA}?=)`VA zFklTPFd({}W^<)f%3kHY)l`IdsKgEdkgt}&*kNwPKqhXN9{aD0G8cYa0fw-wAL}qF zp0w3cvxnSE7{+L!xB>vCdP2y6W@g?Y!+TYvIIC9QR{_Bg@9DU? z(k^}&mwJacgvvB=FMa{fY4!zBQ5#LdLtI26CUu1(}VPSbF=urbrsE zND?1H-MCG4h-YC2<~C>rBlh~!_`x}9N;XyACXRT-0g%$ zdgo^K$;g6+ahdi3_T{?$ET&!S*%E*l9RD>oWYncRr$1WwQ=|0-HQs?Ln_JEbk!|#v zfRORFsm8tSHNTBL-M5v?Xx=3JwWUkdQ6N(OIXeJmB#^Rhn3?Vfsa_b3Y7JvI0I zW)aJ;m7*W=Mi??S>h$>p6y*0KNv2Q)hD9T)FH4*41H(c(w{N?^l11csiJvlg3<{au zYN3yfW1~qSgT{tOdoi5a&R9;BUSpQ&`+_Sq6JCul5ENT~;K#ZK5nr^*AqiQ#SM%4; zQoZr3hL*;kTAy^rF7DCkf(>OcvgUths)Fd!YRYS2tIQ=oOVhQ)JoJH~@WNQk8yeE- zsRW!N$p@I|Y{H_N+zcbpNrFI#VxWd}E-T(oS~@g4#Mp59aY#krVQT1TBIRu>;e2r9 zEIut`7Vz!0k}-*-@FaF+bWy8GoW^Bn9_?4C*e{FzdY64Aunpx|Iu`Fy%$f&F%T|oK zxJ(g$%Pc1SV7yh(mYPjwbl@E)S5hcwB4c9%4^8;ei>Fj>^pS%5q4liVzR9C7|CF}F zaPztD_+!Vg5Osp;z}u(T2#;UWwKqKTc0S7s1YJ3TEFu!{#V|H{P0i&P>G3J9Zh^rk z2qwC6LMc?WbKQEhDHcVN!)pET?b;@-T9$w_F0XfIVAP=}+Z_6* z&P_P$)HgSh*GQS7BQFq|r;Uf6j55t)>q;H*MLUXC$LmLV0N7>iw0_C(@#c3KHXHBc zF%i754#hKuEIu@tXF!e1iFoVV4)e)_WkvJRiTT{ih8c+~$62Xn$@b_+YFWrw9k}$n zMT0}FVmQHH-R;BOX{@?|a02~dlJBZnsn?C5*B0+)ZH69Rxh`Rq+nMWQMPR*>yi{$;y%ZReD4L$u1#Xof zhI7u**F#|+iPLHL&HLoT5v7l2ZtB?&cB;!we;!K!DX1_6%D8m@v2YVsu-*LWotWqt zg|X!@KU9E~P8*UKh7q$DQwsv=Xzha6vEOW=MO9WxV-j1bX^oIX!lRnVsB%C)J@s9C zmLRSvAfFIp#D~IGQ@e|9iP$*(b0g{i8dS4_moWxX5&`2xkG6|%^+A*OA4s$Q2UIi` zdO86YQ&n>#Co=*TX2$=4ipIvqPWRi`(a_k&=`Z<=k&#ZsO5fCxfa!0>*2YOt(AG_p zhJk^eW{x3M_KQ<dC_L&nf?NV`2QKkH7dJ0v1MQ0%jIA0!EI1h(jz)^aPA- z|4^I$rmSrLI>JK0LjO)!^V-j<9h`X5j zWqHRs2U|wm%SGVM)a+EBU!R|o9;v}ZVH#eBU3OI0L?^%OFI-hV>vVhF?cJBG=-lpq zRqA*a7<)h0$R0d6-t0dWy^NfR?}FdzB8uqj8t=R6{MKpU=6QRv)$#UlxO;m%9LiWl zrsJ)VkrkXHzZIm5`6Q6&=(NJ)_qSjsv_?sfSzh z1b{t9gQq+(g!auUIp+)XcgI54DMZ%98@kqVXSzUvL&HE!V@ld~D%*F>%iGC90+s#d z&)*xAZ#NR&H^oFMPQU>VyItMpzWA)zAn8N|&y0jEgwwafDHL>Mf)jc}m@fQOxbW6|9A=y7*4p7~{sUVo#$&}3- zD)J)Hj9_~ui#|%dC8elEhKrAwk$1rZt1Q7l**3mCkMM}3s1=>m&@p;l*IuOBrl4kA z6SoBnnX#WbfxJMKsuRCsgs5Kpb(%Iyxlira(k?{M>`%kw40ro8RK)UEwu2k()!+Ca z#8It5YtLAOtdtElX2`NjGnF_gP|(zVvK7{u`JMbxW5|>zI29ND^bzV!ox_nsGi2zb z{;4*daN_gOZOTqs0>Kxu3{Iq(G6Ct)dkx2gZIAh7pgRLoVl6~?))#U8_pZAQH@*DN zc79&`yBr0z*Vd(ga)3TXpWmS1uMmly{hEw=9a-um^G3YYrmkkm@{YOAy!7$8u5W&_ zM58jkD6sql*QdSt2P-9HUhwj<{lS5e2Uu`eB@rm8#y282xwPjSkgP&` zW(={o3lVwFl+xb_*lS1Gz+rDG;b^^Sf>K`d?sdn`Z|qIwN|h( zX3Uw-$(-ZH*TeB8I6lal3iZ{w8@1V977~q1D`b%5NqVf%0m(=} z@%x@!Xm(Emjha>bu}&Z1iAr}fmQ`RG^Lj;=oP!$DoDIqL0B6aLbMfAlkjjX}?SBKF z8gGpw8(}NaN$Nll+bYQnxM-djsLui>WAY2cSM0HtT%rvC8+%JUy&?Wi@~pW(D09D= zm=A)%1$Yb+RF77swD>GTrC8gHER@IH#)H~@eHSjHyv{8{(Xh2ILs%2 zmgceNnIgk8P2?Dhf?qv5gRZQYr(z`ScKM%KBlP;SsS=6!Ia}4I#SQ*M zZ~6;!69m-~7GsdEQ#hdP8nkU3sKxKi&ka-yZE*Kbm=3J%xN$xmQy|8>Jb6l4;`1qUGP- z%GOQ@#)AC%QG_!lg@Q>=d0Z=Cou(#7x1N1;IA%6&!HAYh*CHP6ZZPQW``!&zQc_t9 zk@GCcyOtF)#Wu<54j@pwYkJJb=^DlQOxjH)<|ph4#XGm*!hkecxPSMh#u~?Y{Z)II zm+MKbDz@RHrVy}q>mqbZKG_$Djj5JOJd*9Jo0e*njXDmnOXSSvQS2NqEO;r@^%knI zu3NW3=|4$wLLEWq5%a8fr-GPes&3uiyml=$W1c6;dBlobVd4MMw>s56hh~4RrOO%k z<;&;d7M#C+{2n;t-qt?}V5aO!sdt<^!i2OM+iYHngN2pHl}lbvX#OpZWt!J7!Sy! zf{a(!E8i9=8`2@Q_7l3He`|uR(8SQl<^vlQLid%(8%305U)JbFbx5K2sIjdQqqjg9 zeYDc@sP+L?MUYS5^G5Q>rLi-@tZTU>80uZ9+F%-66Ys4!+~7fv?!b%fcLM7`0H5zO+XA?0M>quv|>?_Y6|ZlGt4?b)24V78OkoeVACKkk*Hg z1Dw_gh)-YN4wLEFDW4#Ag!!BY4Y!N%iyZYGlaYXy%CC9#YyN3BE=^36lmmJkD14n% z(aGo3y76KqHJ|+Z!{~(>W((7Rf5DTMWi^pwTwnnP&#?} z^Lz4Z1_H<;$gA(Hp8#xI3V}pQP=^?Pap@fXwd`k8zXoN#=w%JtE(0g7|pK=O>ShmYxs4Gii24KJ}O$&z16-~F_XTVk=H*}&@HKP7ejl)b*!Ckw_8}kQ4s@2i@(jh1)r3v zmMNjufof>@f#OJNE;n(9@guCq`i_Pjn#MPc`?j{n-dsIoh%Q1mpO!D^J!GFKJ^RGt z!lTwPAmb|5^L;@K)v~YMCU{txyeo~wTIu$Gk(XdI zb73!LfG~YX(KOxV20kv4F&OChk2_Rr zK_G)k^4(=aw=E>qGRGDU?=hQm5%rshicrWq-_Z}#A_v7&@@V=y4x@8jvu5nk4(xrR z$FdXO!x4PORL!8rO2uEO`qh(1Ry z2?xIlX@bq>Y|Go^wzKQx#&&&3Sy~_T2su5h6rFT&(7@;?7Kt`V!%gAn^&N8tAy)xt zHY*Ymjw{TjwS>&_MiIJit#7X2)kDqFQM-`~1c&{l8J&=3?99NEPM#P78h-nDz87R&CIOt7>98L z+Rf60BNOa8oh%+N2^JMocVs&L!aDMvW~h@Yt68P50oS4gnGgKshWUE>U}FBM+2J4S|jY$$2iS&>@*yxJwMU~^h7lkMGeyFbrgE|&a zi1EE=0KCLsD%*_%UuUmPJtCPc-~TKGPaDa)ZrvNTz#M=j0{tApeKYGD02eQDh*J z39YF|cBr3rFt`|PtFxXgMF}d&pxzh$Jt93mh1jAcOqKAcmCwX#({$v&{syABQ+@aS zbX9N{S}QPwdbP0}6W*j80(EZkkQ|~Kd{?_`^PlWp?L3#);~l6rvXLL-u{(+$87^V| z54xO?HZ@Ha&CB6vT884BNkm;BSYzbrvsf2VH!eXN$T)DQDS zAz0L=iWXNrzx`j;o7Yi>7bX)k>N!;IN*J~jn=?CWbb$EmmFVun4u;7U;KYCD2M?Z> z+Y~G6yX$C|F5R)O>yD;R+LHldbk8ymu&3D@@(zCbQ%^FAbmbGynkm{A8+Y@OP2g&(K!A` zIqW7K9f$Ry|0GLJdyQMkQwl+T3fa<1MKqsSZ9L_j1R2k=7=@4JC2@T{TUeN1liDd2 zBdjDR`=n)MjdM2i?`$5|MDTD4`aho^Drg8lT&0M0!HS#lzuw<_a=62I*_D@33dOGA560VSk2gBBlHqsLJT89T?f&e zm>eziN{oa;^EmdKJsd4v{XA~Uy2WQD8co?N;eYo zCeJE+2+&m3vVKcWv?&;=CGtj=c?mHCuvWiTH3n9 zyXN5UCR2pF$4JQ}IE$ zrRdlU%xV3hqgiARg5^ZT`P|24H;;urlF>oWHZve>rU{Vf4^<0d$u0TQ%*ZsR4gV+Q zcZ)cOEyq!T0-PeWOus{gHy}isvDk-kJTyybrUZ%tC7Te*hg=J@_%lgNE6W+J7qKrj z?z7dZ8$pzKpHFsw9~z$0c(M_?+Tjc56FQWXS|<1>SG>_y-H&?%#-QFu;|uyu&E!I( zxr{abwjWs)?lYRScHXs7`#~(CP@3tJoU?6O$x%#MD>qtcGBcGmYXR|f6-{+PBsXRf z(Gs+wss%pF4F!`K#n8 zIrC*Nd{{jpmOX{dq(jZ*SeJwE)PNT{w8_`dRdRt6d!|V-j-ajC%yc8w%t>rkxbV?I z!xJ1a7x@BDkpkFEEOE+JjOzaQ0X}oKx|hh!fsqqGy5(U8ZxLa2`;mYx{NyQ1ft8#l ziA*}~WQqn6x?V=dLS5+6F`aM`ZTj+B0!f-JvIN(RGuqYYN@P(k zDbzn0wbXF?tvvyCR^mG0$IX%_1o4H9;UMAI7iu2rE}*>Rcmuv|i~UDH?93VBtFe3@ zE5EEuyg(=Q!U+9IO=M}p zFI6(7w~@-xZU~wuZm5kn4~}gbz|by|;Vi)1pEtl_L-YW``!+1J9-c|GxB$ zqm4Q5hvYdXor)H0bE|v1A?lx477r0@tag!fChzdkiXAejjq27?Fe+;}n{{FV;6n4+ zp-x&uGp1{JLM2I{SbicDDp1d>e1}G}co9B62axu!(Q`LZ9Z+VVxrmxaFQ{H;69N#9 z$$O16%YAhf-OUc|ArYh@cStgW(sl8sW2!f@$^=AyQ$6cn#F8K~>-G&V}Qi4qCT>69Ys?NDavmO~hA zb(JxgRWX8EuBB-Xf_LOUd)QX}XkcGzQ!q(wjw9l^inNtK;Wr)@YBVMmi!GY%lGPUoR*dm@-P!4Wn|h@_Ph+2b z(1Mi#QN4J!n?ERtm%Jrrtchb&(Ty;PWUkuV7u(=Q6b--j%F01ctC@O^D1ACy=wfd+ zt!yK`yh3;yW|Is-Os_c&m{1HDm?u{f1EsMuF0Ko@ky>j8jBf&*xHX3UM~pO%)KWEEX!AWQuj_z)q*<) z92OA}Nu7Hov>hky@a@V*=)4ud>_r903&E#wWO<=+aDn`%^&3Sd{Jx*#L+!<;jAxKi-pp>O{ z4vij0yEXo)(uby~QmTZlcW0ukidhsEDhtkJs&u1?Qu?c#dPeB9?6G|i>Ub@Naags@ zrI1Nnz8((ncqXj>plKWCu0uqun{&a!l62*u@{Mo%y@XM9InE_`9SlYZjgJmf$cL1$ zRh-~Vd*0MNr_1$<<`-DID1cUT9|`xUXJ>EEN;!wO9hB0vT*}dhC5pdv*rjz902iO} z!?)&f^0hvGmC$SYqf8WPLV~t)%#qO$grl~L7qtgjC>|0kdUZwvXq6r;z^}IM#SSY2F^a(s3!v814!k7jtnER;w>i%&m z@jT}$y>4$NKVm}FE#b@oa->?^WduGH%Y@c4GH8c13xjXDoO1AyCE12Cd4u%E150!` zWruCvwVDJ5?h3Ic+5JpBQp>=R{RhTp5F^Skoa4S*&`DX3@XXRAH+2%DyPh>L#m`i!PleNACyLRqkIm2l@mwX@WQohLj!SzY|6uT+29G)>ckV{x1X z0C{}xw^&R|NM$_CAHahbxm7oAB*(H(a_$h%OOx1sK33n1UHcYIax}RK=40nLz<83H z^Lx9cTo$Uhq@J*ov=6YXxG4U}ccN4`HmSRQ9@biwDz8tnsgjkEdQm~c!y3YKe%7%C zsoO0itklFd^`P>Fl7W9a(u`S-DU@r+>vR5x;7N}|Gv~B(66m%< zCrj0jDumxEkmMRF`Sc03xoH%U6+ocso$&8F@F_RSIwzB=(Ptd1ae+yVz}ZHDeCrdi zmeUBC@HdBB+wM-&&Ry8%Pcxx+oWx?i@}sT#EDSUXQazPS5?T z7iJT|<)kM(9^D1zWIUF$dIQ)cX$pgJRyUt*O5r7ZMXoMyeA@72xA`g?Ewe2aNj?Gn zGrlr5*od#+Vuyk0_Aemq8*FA(3NY9B?d*#3y^+IdR5RONR{4H?Ojp2fd#rRySn^FQ8#m}gnYNoHW#>q^%q)p zmoCRG5he#b!$D@EPi&+wLgBxAOy@OF&qo*_qM4d&2?Dfnckbo5@L5j8$6Rj+?r|vX zqZNO_YeYq%N;v|4GtCT9D-y-yXO9QB&3%@t2U2|7FGTB`rK@b|dEXXmAg*QI__oPT zwRtZc(#nhXlj~>l^he7C9ix@onc)Nhz4_?>Huj9po|Vq!$Sa0iPdFkeO4&K~a}HzW zKfc1b?#1%TOM9H92#w(N{$TXF?V~x^!=9U#xH|=z7~BSP8N8_$@rQd-A(+Wve8QRR zfh|_I;Y(O-QSQUO#A{*{!q!dU%}P&hxuwbYR3&w0X1q=%-X=%7Nt8<}>ARhYmY;~e zg@I#7I2@IW?~S8<@K@8Df46A6em_+87JMnZv+qulDNhgdlbhIQy39dqZL3fegcuSz z^Wd>E>WPNpyU#U)mVOyt;bDXT5AZkPu-iv2Umxe0#qCN$$t|9~JcfZ3@H8&BDpfC~IbK;cCfD%*D$5 zZ=1HjeG{=^#Bu1#5Nsy%OS2by`fB_+RSUT6JWU;N(e>NtP=I+n}! z%D&IO%X<4oC5UE}$$Zos8oj6v&zPe`yQjc*##V5L#^59-XXo7eKY8On@*xZeWlZAR_Kx7&`P?@ZR>SfDqR1K%vPzj zk7u*r2q)d*KrsKuYC0A~&-3P`0uhgAA^nxhJP7%I>faH?>E39T?&Z$InZ6*MJ%MFy zo<8Mk48rHO$|&v?WXm7Ay&NpbOtL-<7Uc}RjAq{Ea|R{Xp_HuQiz%y+A!(_`%e26J z6^u;@x}I~XWVhrc@Re48J|i4U@+a71pJzk-zFDWtK^gDkt#Kip5|)1_=Lf~pcNfl< z@$=V$-%F2iySV$g!e*%d0Q?_+1^-2G!5Xg@kJRe0#ee3o)$fhO;}thSH=b`Pus;7e{#Rq_=Y6ry@5#>? zK^Kya7s1bo)ImD)|8)GnhO6It5ucej4gWX8KmVtmb!u;&e zgMD|}r)qq@uD$awWKwvK>y-PRul@*?`%GyzUleGu9rLX|(*(*^=F-E~t!+^c-1|Ye zv9l`~Ng)LeUTe|c_=1x8)Q_skY!}K*m$ql2}hU^)bke$RKF4=PRn7!5)$zU>S zulNrAewDjF;^3G_0%PUi%R7mGC`e>~)5s$&;&acn!w0)^HJe`^U15c=` z%;zZd{rjVHtBreA>+32zQM9Drz9DsARy;_*geLQ``bJ~PyPvzsNH5y|V1zI3X}M3y z<97kaMM%Zn0gI7CmHLE_^C+?O6n~LvtTbdy(gET%G6#80OUvJDgdWYSXZO2wDYco5 z@z2Gr8&J8J`9=l_nU&a^SH*svxH;7;gnMlVu~ug>6(2D>?zQvU)bS6qsH4uU%6{9x zMxhXwPZ=K1E5&LUiWXzV(7&=Aw=1>jdP>X4*<5Ai`5Tw_YBmDu#Z4F-i6K$iI$N*# z(-));64(5f89W5G@^-yzI}W88N*L0nOwL0ckUDT-IQWT)^8Eel;Lkz*hmbl|8(btV&_a#y*Vpc z#7+v6Zg7+V=kz&-35@!F3%O~QVQ~AHM$?izubEEOoi+W+(JTk9oje1J6CKy_9rPV0 zx}UP591eW?t>rH>-zfXsqAtJgoYPy%)OHQIMQa&&mVnWJ!4hjK28oX%tWs4m7;YG0 zsNO$nHe!Vn>3H=6tyl|*J(R?(%$Y82|(Z=(xoJ$)AIO+wE#QP=>C+5%0Rm*^GcSk znvsbm)08JixxSbCnF`KPcr+@!UDTciH{(0vpQG^~Lv@H3iG_N5)8dXRoa{(NofQy7 zHa|VTmxZ;331G9!8gomG(Xr!EVF~=0v}C9Q0=AekPO9!W-zq*=e)ff{8QU6HH$4)t z4hotp%Oy3h&FZl{7NQ?wsnAULjwHhr!TZ#*>?Dtu7fD#2nvBMkn8w7f{+g|MdisM{ zY#vc{akY~^lcJ|ekd0jW6nYHtAuv1LxkW%}{wP;P->+3A+Ip|C^xB2!VCJJ|p|PI% z^sj*CCnaV#Pn;Ry{$2XV{X4Oo#J=i2p<=0BBf^5Jmf3e=Vb@aHsGs-am3kQ6{=9f@7|FWBu_-*13@eAMVfw~paljh|&lrSgb^3;rZ zEfukZt*PqjGPQ23O{j7|E*aK<^m0dC5JpbFC(A@U5=FS@Fh?D~tP?0Wwea?#3#G?J zu9SLVbR3N6pKwmIn2Pzz6=YL*G>axRi?8f3oFWoBZmm4Tgxc&q+PpQ}`I=5mf-?SMo;{aUa5A{qP zqw`^@HRDzbhVBxqY1ql>c6Dj}POp~8+afx5ViU6#coh|8_uAGbjUd^V&^j{(nP|l< z+Mo?Vl}h=HFI!>NzGHk!9Vj)87(56G@k{$iMOCpZ9|s@pPoU~t6;4srCb664nLcyLl_hm zj8~B`_o&cOYpkkn-G>d+_GZ!P&3!z#Mn{WHMx{Y@Asg;b5d-tWG$Xp|dkO4^rV_;l zfS&7Jh~LCLFEcbT$fbj%1iY9lUn_2VGmVQr6-R~*1$|>{Ph;**VpTN}@;VPvyJCR} z=>u&$D}0uc@KhTdvpPDL{~GQS70T~kH@Kn%=?C7n&mIryNzv z+(V;0nJ24k9^P*tVIuzZl`y`QMiAm1**iS9gf_Y8g#Wb^fEu<>B=%*5c{#@&#PF_e z73Q>dqn*{Wa~HL_f)$){CfiukHQqyhI|_?=b9WNX(ZcJM!P@X?qj`unmJrh zs2Hq}?u_ePQ(kV1`%4~)T4v2A`eVOdOqd5OpA!z8fHi7$n1Ahg4+Mk5sw&?iq2e!^ z8OkLeOdT7tdVEA20CJjYS#^}F2za5Cx<%}sq_gn!C#g(r_Hgzr232j-xvvzLZ;hAS zyF0qe?!d?L51z|g(63JX1tXP2i=+}Q=6mXC(N});%Fcd~v6?=I!0qU}j2+J2nji!4 z9@t+$KDb_(ZwhuKG{a64J+x4mFcf3TAa@XV+=Qm5gk&xj2;_~Hz+5mGIW*K0b z@xbrW8{IDg*vVJEf!lEX1Z8BnC(qQYRbdqJtNnFp9;Ye-@t5iV*=| zi>PBs4S;+AZyA)>{1kNlf2Tv|hoW;Uo65vdgcty?lwS&Oq<7;;ReO=?he>1s+BTI`b!$31>^$ADq|NhN#>=9P=(Nhkp4*d zE%xI&eyK zrwd;S&~v13!_oa?_e=o47zZVkKjeYi(sc$vq@oug;B%3u0&rXMwi^9f^412hmApp} z*h<_(0O+Ueu>VJ9!TPc#^)A0c0oc z!2q5lZ(Gr0q;5;mV+tKTL_wK9z@H2G$9Vz9Rh~ZjLcgw%^|D@r+ zKaO4K_&Q=r3ju=zukMz6Yv-k-*ZS^VbN``TXo?+Hz6v*EJoiEnuM7G751tg|V^J2U zz%^<&j@fp}VvNRQWt*@mQf)a`b8-`GOEvNW_{Mn4A4;@`O^Vjsvnu__l$$W2C0DF)nj}n3s zyAsCispx!|h^R_N@x4EkM ziIQs&iY!W~+P;ptAx1t=Rw1-+@6QWLu7NjhwIHYB0!f%pi2RU*xniIyjL_n^f%9(?vWs6Y8}iD(Y;XW)qm&7F_5pJ>^((pih>d$>ShCsNoJ)v=Fg4~cim z2?5QWjdYjXgF5-E>r6)6fmJSNm_F69jc5&Om&gMPhF7>H5w`)kci@Rv{&DF@O;|R? zF{`Ko8oyX$%1Mgqos=}caAW9+)0j`>iITH`$OF@?eZHP(mZ~#V5h1B}tR>X!lcX|$ z8dWMC@r)Q2jbF%BaMn-s8P$%gohm-qbJAb9YD2Cu>F$cOJ>di~e?8outUbvRZkB#w zWpZImPLxx53qf=lO;5s=Uaj?yvId%-m@CDho^X|}yerP3p0q2>?4W2yIET_`1ofi4 zE6MB+QM_;tQC+v(d$MZo-21R430)WAW7I4(rw}1K6s+IOg1mdUAled*$>lY9-WDiT z(XF^b7RrxmqO{@a$W5qC$n+(}DN2t;qB5k_-ZRG5wkS!uk_)n~kh5Ub;Oj*$8(2Y@Fx@+zYjI6gjT&)R^QRkD?g46Im%=yeCH~UHl3p zE}>K@1Ogc>Y7#0!6#35QltRHmY*+&>TdJkv0H9eMM#*V_8;p%hw~!+J6wWo+3ri;N!~qv}SLRK~pU0^bfO{^skbpZ*aVDJjGm*dvs5M4ofsTB#Pf4G>S58tB4vGK^<3$rv#?vsQd$p`%?73 z#&J@kq7*CleweJNI4OA2f{GLYw;E|k7+RfSieI$EPHESc%fQwSH@qJ-7qlX z{wUp8ws8E@KLw#aX-_Qd;P|Fjj(oD4*}bysC+{!BHVyK-r~;`143`Og1rYfl`Ky0+LgM{dPW?=Pt(tE{@jMxfc67lYbUhR3vI3rxyIeG z-l5r%-hth5Ug&_o)UzhMZX4k1bE)&nwrF^jpQgN5pMJG&KIUs$X~@R%nL=m^nOa@K z6NbOUGc6(`TT<4!&nucaY!Qy(kwvNcS$ao7qT%8$ON)tUC<2(W) zgRDOrnkV5WsjFe+w$;(gRYP^4cgo$2;8roDqx=26w>GBv&Y6M3-1QYEK2m_%hy!&rImgI_%NUp^3Y}DF*%|1muI3H!nyE%}RIEIlI>z^vX}Vo+5o8bb zr*J$1RMEyRb{G_j-l(y9+Da@k4aSNghg{QF4w#MR2TqNC33K@XU*P4-VelBB8x$uW z$`Pj+tCxQ9lVno=>JgR6>G5J6#}=T>WGi zjKMZQIv*%Ya*r6!50<7!qm!Od)>g-9Jit)@n&fJUaGFa1r*F7nw(*h?dKWKGZvmPL zc@93`VHOT*R3w`RCde*eHh+j}&^B@Va94`)=zs~@>t4WS4&jfg$zjuas_n-e)Xdn^ckcF$nV1%_9Tx!&|f|{gjR*NN81^B)EU$= z`TYI_c0I;?&Q8Rv&$2$krKxR>!dK#%=s|TL;&;KFEDY!Dw1Jh`^ISVAq!gS-sQ4P- zcjb>eHO|NOPH5|8+|hLUA4#+$?iEG2E`!9WbBL@r;TqsM2)y;qR+UWjk*oI?H{jS( zR+zbA`-9sU-!rpX)S5TP($6VJ#Bw6#xWuJLDMK@*3+P)j>wwXj&{rl^^)92H9L^?= z=#&@ftV;V<8C%pZUeGoFsfzkly})M^+n_B|1GZGxP{(py>%vZv#&^Ezb>UmNChiW} zaU-FEMW}LlLD~#+?#tY90QGp3pq#RI&f?Df)Sq-g4Vf%i(Fn5Q0 ziX7>H&DLR~a3(TRXnxE9STtMC=a!#zRz^;$t09- z=!tlaFP!nz3%z@|V5=)VW=^5rfRtWZ>CEa0o^-+G!s`jlC!9ZILE!RUt5Dy(rha)v zX9MyP_8mP(VrBd-Mw1V3DD@ZT(W^K|#N?ZXc#Dc$&XBI{KQ>U0wxe4`qQ1?SraJc7 zILWv@Ft?cbh2H^0$`u=Mdo4U|Jwb5jaie7xyu zm>i-~@8DHO1u5g8mms9}v2i)Cp>U>D9n6waait`k*H0cH{1!NyYI)-^t?~9e zf-_TNu$?FUosaMT>?wASfq>1Wdb!N0qJ&mtQA#?e>-Xpw#j_hGtaZ$owWN@fX0FhP z^C0alEwUABJDhmB`ty!8vV1o8Om1i+u)ib5s`}(BdNyrWdQ6fj4V5Kc7e{_S&g1bG z>bo#TP_@`bz_rL4o3DUPrfbPo*%k7qg}JnKO<%Xt{KY0dj|^uh>!_)$qqfVq1^()e zG?raqhwj2soKs|jPX{6{Sn4Oqg&gy_u*BsI#ZL?!BO_ePQ<5CkjWmRpbqsHiUvah3h@(?)NhIdsB-X(QrJ>DGP*bc=m#+0cV19V~(|x8F@Pk z8vWQT%0}XeoZPKD>ytaD7hHq#-itK6u|aPG?`G+acOvrlZF}9FxPQtXXWZ_hZwgG4PcM*F;GGU%u|= zVt>I}&ZaLlGc9c#?|P1=0pS#aoo)BUTpM1w4{f#_qb+vwuFCa|nQG?qOZ#ZX5dzPL zSk92mfC2dSnw#Qw*cV2_k9-ea?~Xg~Lf5-$LtPJ@KyJnwpE#|;%u1i{Kb_2dS1 zvj>)QoTG>65p6vVV95-5g#&dxH4TNL@O{6mo!XpBsx$g-zI9v3Q@UqYCNnb6elxc3YGyw5DwPmRDG!la~G$V{rQgzx7|ys2Gb91Wm==+5lSWfq3w4!Ug{Or zVXUP#hz6b$@3I~>nzdwNV-0Ctb97r*dyM(aL}yW{F~8_Wa0enUjLip|3S!81=ums= z<5*W#!;>0HpfZV&2s3r>s#-|6dGNGFY5GW?{QLxu_T=mUXkbBEM4SbMEeGpImRigh z+8Y3FBL?q>5sgnOh2NScDPa<6*3Qn#@!o%(w=JE`N;>=)8h9qN)wn7xvzz_=!YM2L zwJ%@i;aJ~dF88O#pSa5>ho<#HOnz(V@wxhLFW8IA{>H^}cvY#n``uW87A-e)-yNAb z=G6}@R(o*M^bP6TP?%Rvdj9+gRwi++K#%MnqQ34X)P>@)gD-j~(dfAcAef-PLPdd* z7A2>4;u?U;{}~`QZB0lx32KzT||(u94Um565Jfs5b_dwiR%jxptOz6lhgM;tb>PxII6X zbV-2n0akGk4j9-a;GU}oWW{8kgdW8USoxJiS5TJaYPMay?YFs8CbMe=EM*@G4Hbqq z)tZ|-8?6n?D=gQTwypZc2+N>hQ`IZ14qL7Empmq{yk0s{FwB61mS}Z<&H0p>41LuKCX@qO43*9%l2zN|wx`-ayF0@t=id*CQ* z4LJuka?yzNxwLTQZQYp|n0SV-?xLN;%lh5Xcg+}&WHQ+8rg*@#gYR`~;`DNcYk4{AX^i~n^fPAC zYXi;uJJ_cfpS^naam~plU5pwK#o;=8sCKLbs>Do>p`+Hk+7?iYnj^^xz7C2SPsdd3n!oPX0Fvn}jRQAi?S-J+_zs1uaUTN5^hDT*D z$~$N)K0d?g!5&_QYN)tS(};|(ZIm)=6gg)C-Tvw=`CD8N&SNB-PA76-*ss|qvjCOA z-+}1uJyw9Xv}ks=@%brhX7bBg-gT`b%e%*Wf%=N`6h@qiv+d*5zGobrC?);;_CdBU zqOoK+Ap>_aoz$>^O)C+j~sy0%@ zX;)?;8xx}ofC5PiziVdu6+X-DBFW(}G?*3I0eDhxat)Jpm52GMSW?5XwpmTy(%+l) z$6o97>ME?)NlFXnlzY_4X_WgEM@!17v!_+D^hL3~60t$wp-u?qaqvha8PDNh0 zf-rg{YQVBZ;`DJcl;9h}eFn*0^+8b<{lvX`?8tP~J3YYOe%k)8w`E<6<%*AA6BKVm zdKH=@Fl)-Z!RzJJi-I>JW^s!+f|7$>!Hz+{$$TVzgMz+Gr?Uw`3!ym9q{>9AR#)SS znogR|T7Q0yskyVX)Ytasc)GcX_hMw?!|b?vqye+MEp?T-`cY-@=zM%J zAm|V7pLCzY;o}<37R#l^yw}&CC6n5XS3PU*h^@ud&9`)tE6}82Kn+nP(N?1{owz8v ze$;1*HX-tH@-WMafP(7wXBrxNotDLRi%sB?mWJ2@k95=3;5Ya2R&c;tjbBgAclRZu z*I1VY-|^}(_wm8ddf(q8t+eb(?k}oOg(WAu<7r>RYcH0aXGUGNzo*lYLJf77{*(sG zNBErn&w{k1?k+0RJGs3e4o_DTTY9SSkiR~NMskUrA=^8l z(V>7{il=^(Aimv*=n>#vsIGp;(YT&uQLWeABtc+covnMh#LUk=3$NWs?cG8vtcu}+ za17)NTL$p(=-UCX9vtX%$W2C$yH~I`NWZWUiqgn&2FNrEpGBxQe)cm!#R>mXEG^%Y z-OD=Ku5BG|5WOx6lpSBNwRnw~0t_TDl>7b4j$LJ`&K!+)cw|>7MZpYV)pZ-;U86E`z=!!s#!2@V+`e z9Kg~2P!uq`~iTTVQKif{JiMK^6o-tL8_QIYAaOy#v9x z1_Brnj77iCXk`mOK={R}|3U{hbn$u(Vm~VgHuiCc&M=qIQQ}2h+)y?oWdmEg}h>`S?;NDp@xIm0W8u{kpSnFym@{R#(voaS1;a zrsInL_i$7B@^5+!2J{V6nY((gvb|;Om%z4m3sQ&qHZdkX0*HW&{{JedDh-tmsT)Z=ID^TKN2pA-kM)%-1FbxnhVE7{f^3BHXYbzsUldZRHUkP93BE@FJ`P z?b3kD^2)O%vgCyv9e|6IDi#Ea!(_lQ1G+!E&FkcO%$(Q=Hj%cRijU}(Lm&K}%KDPTrFJQH@2)o?7 z60Kh)ggxF^N-Z@4@f`r^L-9{3@PmPeekrckV+hN+63qmTAR3lHv1r9pjBvj85|TkW zx1jfFwpO`3S1i1Zh0Se6c@dR38n-fHS1%;e4rdjE%UY5Apf)a|P~`gX=QZ!bemd;? z8uD`FBsN1Nky@p`we7lWq!xW$nfQqH&l@iBbKTPS-8P#uIR{y}Z~(d???GL|!ot>{ z6P3ES$Ons${J~knFeTh~T(Rn*QUo#+j);PwHO1t1!bU?rwv`hK*kR~&&@o(Z9F`b# z@;oMg!1y+jMT+eO?ZUlLxAk}6l9lZNHfaxnB22(}37KAu*O((YDMOn$k?QmW(!D7M z-ZCy32T*rtpQg9O>Eh#iv}Nfi@;zp>)rmMfaUN{CKG{~VFZ{1k-cbB0sA9ME^et4Z z(RzN|7*hUlOcb|2HP#OH*pO1NuL?-jNmONI6oM*FIxHP{JTaWi_yPByrD0>$(0$z? zH;YO`?9k5iKrg1WVi2A5y2z~)JMd-_M# z?_Il|uBxso4*M~#22`LR9{^X>i_HRmD!dO70;-r+$QSd(wA~R81{ z+oKW)jp1vQ1o9qTq&#?+kHul3EKqv_+zp>yGoM%1yv7)?SZZzGeeBu2qb|4Ln0fC@ zyuR^;Plcqx>&OhWnacc|jZ|4Z?O&3{hV9&dd3=q9z0T`AupmT9#r2^)eamXz*DY5D zJo~*ySxMj-!&SSlX3N#Qb}{y)3W z#!MKLFHYAZ>|tscXuP***rwo}t!K}KWq&&-cyn5F7Dw@T#GKz)PSd{7Q?;X+{T|}nl~Lt@XX$BWxh%DmP+9s%5&XtJs>`6 zGNr*<3tne5v8@YC$WyW}DrhQ+EsTM`B^#OjWN36&W}OnRWt)I*T?r}<{V?zOgqP|9 zC?LO|)Asy)dwo%px%Q5Qu1nd~B&_-JJxKebI`q6m@DOuoqfb3~^9oKv6AogG9tt`- z%XqgPWl++@p=6@3Zfc*=$$2sWiUtbqnFtg%mx}2{Gy;pv+XkpAb62o>O<^?ygMlk% zvhxOf_b)|-NL4-fU26jjkzEs z(Lxn#s) zp^^+&n#!YY%FT;GSt(RyF|GVwK(3Z#qdE^H6X6xi_I<`B>9A438+4>@+xG z&r6&JRFc+s8vRe;&`=QC7-pI`IK#h@95<|0RPO3t+UV57WD1WJn&X?7Qd;uB&O044 zr2dwkcj;pFs1?ZzQ-)Qlm{4>$7ODIZ#_4kJc*USXX|kwMSDqdiAdJ4edN%Nha-NP} zmt449HRaRw{>QOqr(TT$nDml+X~|q@MK}C_9OUM)fd#~kV>mD}AM+s%_C&1aG3q>8 zGEY$+%8S&%itrg`x_}l>4Y~1*xeGHEiH3&t&OiD61>Dn-UxDKeQmA zS1SqK&AQt>p(T#`3Pqn*hixbqvC1NFGjrH%P(ucwmUrg+(Cg)^_EOtDUMO_UbmNJ} zq6x8_iP?%Pt)gh25*7$_Q}TB9?w%(!fi?P;QhBCufW!@7jyqBy$;unLQ0P4nj~FN; zEH|UNk2J4G@n*jh2gT>`FuIYOSjxQWW~}{ki8-%i@1ZrqQOUtT2D?@Mf(XV}RmTxg zj5{hE8nVl_rnG{LUcTY7u*l#|;bqg<$S58osGPI{0esg^$XT>~aJliK+}NInev=E}?Vvb*bE) zh%zD|qKuND?BNf`v{fuG-lTSvwOjBE@32+OYX3eu0}n$WYJ>_306`RbueZ(f zj)b$bFXi*{}Ehci8z|cQe;KrC7Ivd0*!*+{xxvT!Nmnf zxyn)&C~(gM<>KUO5U-{z432e{^8f?niS-)!L{mnWQr^3n=a0G{L}&Hioxj18-5b*W zaOp)WmM_0Ajex)EU?2_++Q=$Q7s@ySqkehE$E*y#9C;NB*8yun$~+QYN7-&f^rQf1 z8zb{&m7+PW7fVayq39$Ho}rUc9RTZnBXF2Fh#h$4a(<~jgNHF};hJ)_Om4f!Oi`3h z!AmI^jdjNdYy!LFFD?TdA2IYP&I&)8FDNlmZ{k(_IK=%6-i{`*?CY+$#A!p z@CJ`;kTLeH7;rftRC+~NwY>B7eH?ky#R%HMiagoeN%0|C~eqD8Z*$thRGx8!-T(# z%b2W3hzfZuu_$W@qghM2ca?yh%uWJwUGs&c9(PKQr$rW2BE=>X(lSalauri-#m+1z z9=eUPi=z}Jqri^&sPIZxnJ}TbsVseI&WV;RODK+sXd6CNYqJv(IL)Pa;tEF2wc1^&eoZ6LrV_AoPp3+)>gkD&6d_voU^f%fy&XX$j}_^8z?O;45E8sdN-8tzO)~vY!G(j4e6Y)^p<&y zCscTb1p2pV8Qw9_3ewV`MNOcZ($NkiL+K@b+FJEgQ*x;5P`ikuUPsXQ`T5J!q!P?E z(IppaqDm2sv9i6?LzD4p^=fN5y)~P%ouYWtQHAzl=o64?&E7J`1nL=dw&6|0>lV~> ziO2d-f7IOi&Zjb;YPg68TWD7l=hnUQ*7yKMdfl@7EPqd(@qG&O(*|Rr=MfL~h zea+OH=%91YRXIp4{MSuP+}NJDv3+5(Fh`z81c=|Xxi6YryZm5sE%5L|FZz$SnThQ# z=gZh$44h$hAtvCr_fe6H{1w~q-ZOYZXAr0NZZUqyxwxRu_|?t&qv-R7L(HY#it>f4 zcw7r1pT|e_&YFb$w`QJik6b9aN=gR0uY`Oa$?^E&^b#pv$2qcDN_J17es^S=kLKvv zj9B{glnFj@TpVxw{N|O74f9!hNFxGeBJ=qgItj(ieT}MC#;U^SsSC=eD|yI5gC>{qYe_@w_c78W(oIWXpm-YL!a+z4_g0+JLaITcNkr3`>h_ zbZ2ipzjMU^C7-2ARk%?Y`mVg}aRYHs>1TMs<6Ahm%wo-*vF1j##DW2}Y@58e&0<%~ zWedxtsBbJY1(Sl!Qg!amV5xI>4QnNqdxgrU2)`?@h`&l@PF7exIfdeaeq|^ur$t4d z|J~gyWU_20)ADW+uW_SI45-_bN*f0))~g_RE|Ui}k!5#b>aR6 z5@Oy+gRZVoSu&4R)k?!(m@FovlwKq)+sr`eg{xOWBh{iw3l>aIX0@+TL}^y4{hZ?<(CE^+L@Uce%+P4Z-{8jhbs z*U^$K&qrrOb&ZY7;prILsK29S-i6PG17ksgHJ@~{;E7Uw&Rh4+L4UU({GJDEeEkXr zADaOX*m9{{EBtuDd<}m(w<_ZPa27=ziD{^SD*0!U^~vN?HSPPGzHW1$_6}x;#~q8T z7zC)~&PxhQ3k(Osv5N=>>a8jPnMZ5YG*cf-d4tYs-WL{#BK(Z-b?g;;G)%~b={FEu_t5Z+cdFdA;goB1@5Q5fKoX{8YZ5 z^-Slj%=@mIK}}~TuXFiT;(IYKYt}G6cWh>`8%9)tN3nQX+D7xnXxKG0UL*?Bo0+z; z^3vi7WTY5T4VsZ((BQzO0TI!My{n?nq&ItjdiqX2_tBtpXI@8SnyUMOQ%(;Ry$6XmhWE@y z$jeIboq<@3IdmyQfXAX%A@z$uIs;rp7*{4|7p;)cr2&iS#@4`ac!iYl=}M)@O-#2sh?h;S4Q`QB_z9w+F0 zuAY~RBxOBlCQyy9sF(up0kO;38{4si8MOk|EhG<;jYZ?ZP9tmF@r7z}(~|H|MBF%& zKz=HPJC?fYQ@0Z@oB@dO`06o{DzO%&zeD0$+=0E`mvlZ|fi=7Q=)(_{X?17u1F$SA zRKKEdUuOF}-Dioz3bz>h}C8!bdW}-L`bfR_;l zcIhHpuRp^_70GreYP#ZPEvmi{d9JY8;ETPo_hu>xXH;VA89^sGdfnkv1Mhm?kf!{6 z%fwJ0r~Wnk;Y#;C>TR?0DG#>L)+o|;SAm#(6S+~D&o*s~Bl7m*2A5$Lw}itUKw#>V z0L45MOjqXKFxh(oa-NGTwu2hg_3vIE&X7VYFsVJH7`MXuD+VvzlMz-9H7e! zl;t%%aoXAY(B_Tv7>}r0gjYkO*t`~7?TTVMyR6D zWS{|&=k0+s6oIzWFXx*JB)s`9`8ST{U1U!T7b6g{>=}ox%DWSI7uKBQEv#a!sLXL* zV`X?4XAPY;Ny!CF0YtPZm?HfTN=!-BL8GSRLW1flV)h(wK0jUa6Y991)eAHg9U{IRuIq-gxXw;EzVx_3Rc5H6foB)xG}c_^2mwMdhhW?~1_3kO=gGlVa2H zNBBLPrH!kI+jLmQi)vro9M5J3I#5Hd4~CuB#nxQ%J~c89@wHHNiVmjys2i519a6Sd zbC!CZ$;iqa#Tuos7w-lYTH5@a{f4Q-{E+w6&dse}2wjBP>IClWahFDLk?V&Uc>y=A zDYg?+j0{2@*+O^MRy4EAL`}L8?uicxLc2{%tj_sV#N%mpiJ#jmgA67&7V_A1Cb{0S zNR&FSjqsHzDvgYE0a(-p7iVSOe>ol~AX}JYX$T?b94zRn6Ag-ur#kQ-Dceu!n{y#; zrN~jM)@$^wOq?`m%hT$N4k4MSWvPC$y6m;od+|w{_)PP?wGu=o_4=mv2LJAQIBSu5J(V@5f*!A2K%+K~N1V+{w72>B)8W(ltU6RHJ6fSDY5}(&LF>5;T3O-#! z1eA@6>YlOqxyM?Ea-V!*h)~N(vDl$|WtVNlhYdeq*x|o z*+^MbFW`ucP85$2a4?zTyYs|u=c@2DtM_N_EaP6dz=)sVTtqAwfc3(K!! z`d7!7vxRt1Am$o)$nA4Yr4uH%>;*MB44hX7mYvQI1W0f3KnI=r1+vb_n7GnAp+17- zcKp;9GYf1APTTf6TP$;AkB_3jq`>8s;J1l)K4%+XqWIB?`r?|$ld4~jh;pyCP*}2j zme4s*tZ99|Zjq2_#QZEzBCw{v@U5B(bgh2+IPmP)atT+GaoaOMwfl_W0pFXD_aE6b z>onfpiFd!}>;Zh+GwHca0O~OqPO8qI8eLyqYB%)hO&URc6P)^D;VJuWrkrrf68eSrLTXGoEr$HjSl zXe1B+Dci=ti@MdbIO0kp7k*u>^}W|D_RfYNKvM5*Vm@t;iY{{TCc24}TS*u1e+TVBT4{t!kPsn@;aHcuXFXHa4khfZnkFIcOHxEr)q5&}r5 zV(0E&diV0N8+wsosZ-S8IHT2R+GPASDekUD7@l@ZdQz3#xK4WVtM|_|l=ehnig(oQ zRsk_!R%z=+7QLM`$#70FCCYqBGbn9zZfmzR;Ci{D44#+U)2Oic2V(S0W!B?t^koRK zCpK}zpKovnLg?Z+2#WQ<9fZ|kRtfo85u~&+#|%c&#m~6cMUxsa&ouTiiWJlcwRurBQqUn$}SO3<OKQyJUrB#P&RspHnfH}2Blg(I6SPZ z?si#9J2X8tmKZ@7Ik^ehk|4JbJj~vI&PaJ%E6cPR8!_TOoVyjpT&w9wbesN}MB-~w zWsPm_-3NUK6JVaaQ;pUQfrVnX&K(q#+3IIg6!|4vr7$}m5rZXH9y)l`&X*c=$$+`c zBHaT^&B_%`I+MEEL(>@NvGZe>msC3WYPYH`5846Nev1)++|taK?pA7J5#l}#gXi&O zX5ywEWFup4Cj4VuR|2YHEezB?96BCv$c)78x^-f|={#Nk;4vAL0d`0mIC$0;kab1` zSubtB?sL`FIY>40!rCEiM(B%95NGkxr5V===2&^}IMp#+bgx*nO16)@|LlOM>pjB) zgR?TRHgjE6Ifl#ALm6qW=27Q>!s*qC=pL6+I+3%D9Cw&(7B`5} zu{?R!-dh|{^M&!`UXqIt_kNSHt2JyrJa_7hCz!ABw!F^nkf_yc1va!-B2j&gmpLRv z6SDKT3sCA%P8m7QX(R8RcPN;ZLANI0G@W584%@{H%1XSi7!;>w#g$y>=sGL24~Py2 zT!b}P_6>H4XsS{kV9dHLxUHz_Pd@1)6j9wB$EP~1%q6E%uVm?wby9M(PiLFpv0Cfg z5PC=BdV{_J2bo?hw;i3T$?5XBXcf0G`6ov1Pc|4nW;b##x^s@*J5};XM>jqcan=iL ze<|2qHz|^AH<@2mChrB5E)s^g?Jk$bZ`PmVQ)DL};9peOs^(2K)X=+Nw*-ljRrOlf zb#^)pm=MMkzrb;D_jf)t@THWlqA` zFDANlW@v=34i~4+xQLP#UOH`d1UsBJH)w9}_in zYVwvwc@iaH;$)KUNK!fc7(-_cL+544j8wOK-#sly6AS!WO&{x?6(x}GG;DUDRc?L?;c*94oxHqX+DdC1@J9E~JH@*@bvIli;=hSInvR=N-7 z{g@K*Y)FNU#6}8Jc8d<47Od{(CYgUBFDlzS>9h)#9NxI|)UhS}Rj&&Ic4TNJvaW(@ zqOFNOVse2dzPIp56K?J9zIt4oLXL3YnCL2pXDB~Nnb5H!=7P2prxi_bZ8oi7qXkQgG;irj*;d}~Ss zJ4EZ&wiV*Z99o+ORyK6|6h$}dwC>a`wjwrc?yDs<KUs_9S=*(TJvd}Cg1HenHu0#pRcAkdA`Y&-kjJ?u{Aw&%DBc+;c5$hJGY)LLQI?_ z5TU`=kXT=|&Rcyr>BqNiy?(GKcjlBLd0uhBr*K&IC9jNG8mnFjwlImL%A0MZOx-Fh zJKom1>=@ZMFo-82-t7r%eT#QQcwxWYu=}_;JqMi4R90qc)Vox@tIchFHFIT`(NkA| zV|*#VF1pJrk1a`ENeL9ja-W6bf~!cK(RQ%uWpn9_iYsRY@yg2L6MpRLsNTLF&UZ*# z=*NW@MPIU0@}p@L3mGz*M_uV$9JZO=ULD<~zJ~p@x`*Jp-sA!^MoLhJ4duyd%hB!Y zyd66-`O-H@+lbj1iO4!9*cr;j7Kv{^^>#nkq<-&zpLObD)wQR*D^b+M-S)woIQOEn z5%|Ruz9Pk|HFkadQ)^rlv6oc}OClSwHA}TP%)51`^!9~uQjVw2TYAl!_Eb6-H5{(D zq+N;6oimgbBX@`KMmC5>H>mWB59Ui~&~qTgtaFr}1@c-hhpz8iC;)3}i81yrfq9Fa z=ip6F(biU1K5kKs+3duNL+8D4$;Th9qx`Fj(`#4MWbMKAx<@nPX-(@>4OPmO!*@@D zTypr`_av>0*AhFKs;5=J_336Ad;q2Zowyq_#{mJG;o=S*spE$IY$%Pk8a3uQJ=XSH zzPH!-H!FD|u8X6&9nZ81to8%kis1rv2`sU@y1?6lR@@H-^W9Db)tgRlQ|1*l)CiSN zxVLziQvOfGU$Ln--t!Z7O#0s!VMO-Typx4RFaopnn}PePJ_Q%y2u?XI;Nt^ioSr3Z7m=Hv#pb8Qg7T|3`(PLFe}z)oire#n#{dk*-dwwHK+ zMB9uuHulnZBX3r_G;{A$j_gF;!PD5eiBVna{Pw!nU%bsnO)N!+t(40-DhdNSmPzo91s138iGWMCkYoeTt|MmqbMo$OmaFr{DU z$z;CKlUcx!{AB-$mkbE_!AZu>1>*djlMKl<@&G2hraF~sqH5~9*>N~j^G7Le% z-}6wjf93l6T2)OB4v6*-=~u$E-vEH>*&2Q2Spz^t#r}phP29@B+7M=C0#JiliCEdf zetedI!ENnCP4(cv6Se&j3iY={(SQefzbUXI@%%>2CIJR0BlPXQ2Co7~7=5e7kE$R` zKyt&`Qh((fLuQ%&5$jJ}azDrVGlV~a`o9U1{c9^w`Xfpt-`w{gA^$~?-*Ejo%HPS~ zkeq0L!}0YEEF|9=@VA6-)DR%DG-^)B_is``-%Q!g@{jayrc?3C+6v>sH_n((@q1h< z9V!?IF>gQ2^Ti02dgkj0oF!$sMRrH>rTertAOa&LYD0EW(0Iw7$sj-FimvdZmy+*p zymP@Yx=QujP*S)g;D&(c%e%F=ZcU$JDRm5iBOXKVCO<$$Nr8IKr1;-{1JxG8K=o~j z4lTyJaVwe0I5O}NZc12|dYW-Q?L(BiMVx3kP-=XVV+yRmi7T=xcEb5gtT)!A@mrh+ zP>U1oMDm#|#fHNLY1fAOcUb}vxS>9GtGI8`9U|bL7tP%&pRbWQ4B=FhsfqUJ-=LyM zVAM)=V#SEhP+Le9SG>Vj`5~@90ngwxZ??7U)P5T0eOK0Lyd=!Z&cw2mBDSv9w9<#B%YMW< zWV5%HPqoL2Mu>Pqi&8~uc#CV=*7neTH*LIJTW5-k<2AV!BrZj0Kx=cXHoxokIDA}) z*?K6LFA92CN=0dPdeNA$AJ?2n5idV=+qe|rh@iPo@1>NYl+Bb3)hjtQmNUDXlaS8w z^`%m;^vFkrDOX+$Ez<8kfi&}5EXR#z^SY6fmJ8%E%1XCOZP$m=U+^&KfY~KCoTHnEJYWK6Um=MTTzp=nryfnlltUJcgmT~mk zC2P2Q$|cd0D^IsgXGifj|1vW4Q<4?c|K?^bGav^!{k>{6da4dIsi3cGUVtCNL`j z+O66KT56b~0IeEW4k%|MYGewNa)uizJIkvWIGY>r7}5#}V(~ljI$GLTBE3;NT3T4y z@;VC8>KR(=8}TBqzls60)ZbL>%mrv4%RQtPwT2r}gW14rKw3d8YHDhJxS=txl9~u6=Y@0_AO>M18YkF@&z+SnRS{X>Wx_Q3pKEBlARA1Lu7E6OX1q*6fs zq^Ve2Tl`nP{%rGi?u^9r?2H6CfE*xJAUi7uNQE853*_YG1Tq7`$TL6Shm-G`fAS%R z{1r5I`fq&vr1`54IXPZ2YXihr0HwtQ5eS$eFFO>1>?7O|RxutCPF4_yIE0l43W2h+ zi->V>ia{jAMZx0VBKy_$FMg%1Z0+={42=F?{QhM7lV3vvUW4!7!neNiqX~cOG|EO# zf0cf10bg6a1x!#x&(;)1{ZP-!&`FOU@SE@t$6qzSNq_ah5BO_=-}Qd#Sl@f?H)~|K zMUDV~A49-j!ub*K|K`On)%f3Z{Ijor3;7w1f4u$|u78B+XN7;^`WcOXy#5!ie}w2~ zg@57t8I6Cu{ui!)gy?65{{$D-ABzYi8J7U919FM*cZ;2$h`B@%cBa7V!U7Hi$LV24m$|Q`E9Dm#0g~jO$%xJV@~@&&2#Sokki5c?CbYg^MB#& zkJXkV+{hRg3rXV+MxK8h)DSS36HNW}&ewwj%*Bq}m-u>6Tm3FW?mQqVwtkUu0zsTe zTz-*(IXJ<{U7|n9z&wA|L#D3(vmPfqGKxRha&fT##g+@qiQJ$1r3?s=>n~++1KGiU zj+q11+4BCy<^LlL?BIGZ3nMr#7IGg`8Rm@KF98Fj#WeZ3ArK&hogFH|DaIoX0dag? zrT)A~737x?1Br-&!9XzyFo;6}#0~{PxW(C_Vm$2PKn@^;OHdm*dSM}#sc^gRgBLqH P1Q&~eL0mxs7wi83N$vW2 literal 0 HcmV?d00001 diff --git a/examples/pipeline/kg_builder_with_schema.py b/examples/pipeline/kg_builder_from_pdf.py similarity index 60% rename from examples/pipeline/kg_builder_with_schema.py rename to examples/pipeline/kg_builder_from_pdf.py index 17ee1a9e..b5e02977 100644 --- a/examples/pipeline/kg_builder_with_schema.py +++ b/examples/pipeline/kg_builder_from_pdf.py @@ -18,12 +18,24 @@ import logging from typing import Any +import neo4j +from langchain_text_splitters import CharacterTextSplitter +from neo4j_genai.experimental.components.entity_relation_extractor import ( + LLMEntityRelationExtractor, + OnError, +) +from neo4j_genai.experimental.components.kg_writer import Neo4jWriter +from neo4j_genai.experimental.components.pdf_loader import PdfLoader from neo4j_genai.experimental.components.schema import ( SchemaBuilder, SchemaEntity, SchemaRelation, ) +from neo4j_genai.experimental.components.text_splitters.langchain import ( + LangChainTextSplitterAdapter, +) from neo4j_genai.experimental.pipeline import Component, DataModel +from neo4j_genai.llm import OpenAILLM from pydantic import BaseModel, validate_call logging.basicConfig(level=logging.DEBUG) @@ -86,7 +98,7 @@ async def run(self, graph: Neo4jGraph) -> WriterModel: ) -if __name__ == "__main__": +async def main(neo4j_driver: neo4j.Driver) -> dict[str, Any]: from neo4j_genai.experimental.pipeline import Pipeline # Instantiate Entity and Relation objects @@ -96,34 +108,62 @@ async def run(self, graph: Neo4jGraph) -> WriterModel: label="ORGANIZATION", description="A structured group of people with a common purpose.", ), + SchemaEntity(label="LOCATION", description="A location or place."), SchemaEntity( - label="AGE", + label="HORCRUX", + description="A magical item in the Harry Potter universe.", ), ] relations = [ SchemaRelation( - label="EMPLOYED_BY", description="Indicates employment relationship." + label="SITUATED_AT", description="Indicates the location of a person." ), SchemaRelation( - label="ORGANIZED_BY", - description="Indicates organization responsible for an event.", + label="LED_BY", + description="Indicates the leader of an organization.", ), SchemaRelation( - label="ATTENDED_BY", description="Indicates attendance at an event." + label="OWNS", + description="Indicates the ownership of an item such as a Horcrux.", + ), + SchemaRelation( + label="INTERACTS", description="The interaction between two people." ), ] potential_schema = [ - ("PERSON", "EMPLOYED_BY", "ORGANIZATION"), - ("ORGANIZATION", "ATTENDED_BY", "PERSON"), + ("PERSON", "SITUATED_AT", "LOCATION"), + ("PERSON", "INTERACTS", "PERSON"), + ("PERSON", "OWNS", "HORCRUX"), + ("ORGANIZATION", "LED_BY", "PERSON"), ] # Set up the pipeline pipe = Pipeline() - pipe.add_component("chunker", DocumentChunker()) + pipe.add_component("pdf_loader", PdfLoader()) + pipe.add_component( + "splitter", + LangChainTextSplitterAdapter( + # chunk_size=50 for the sake of this demo + CharacterTextSplitter(chunk_size=50, chunk_overlap=10, separator=".") + ), + ) pipe.add_component("schema", SchemaBuilder()) - pipe.add_component("extractor", ERExtractor()) - pipe.add_component("writer", Writer()) - pipe.connect("chunker", "extractor", input_config={"chunks": "chunker.chunks"}) + pipe.add_component( + "extractor", + LLMEntityRelationExtractor( + llm=OpenAILLM( + model_name="gpt-4o", + model_params={ + "max_tokens": 1000, + "response_format": {"type": "json_object"}, + }, + ), + on_error=OnError.RAISE, + ), + ) + pipe.add_component("writer", Neo4jWriter(neo4j_driver)) + pipe.connect("pdf_loader", "splitter", input_config={"text": "pdf_loader.text"}) + pipe.connect("splitter", "extractor", input_config={"chunks": "splitter"}) pipe.connect("schema", "extractor", input_config={"schema": "schema"}) pipe.connect( "extractor", @@ -132,10 +172,8 @@ async def run(self, graph: Neo4jGraph) -> WriterModel: ) pipe_inputs = { - "chunker": { - "text": """Graphs are everywhere. - GraphRAG is the future of Artificial Intelligence. - Robots are already running the world.""" + "pdf_loader": { + "filepath": "examples/pipeline/Harry Potter and the Death Hallows Summary.pdf" }, "schema": { "entities": entities, @@ -143,4 +181,11 @@ async def run(self, graph: Neo4jGraph) -> WriterModel: "potential_schema": potential_schema, }, } - print(asyncio.run(pipe.run(pipe_inputs))) + return await pipe.run(pipe_inputs) + + +if __name__ == "__main__": + with neo4j.GraphDatabase.driver( + "bolt://localhost:7687", auth=("neo4j", "password") + ) as driver: + print(asyncio.run(main(driver))) diff --git a/examples/pipeline/kg_builder.py b/examples/pipeline/kg_builder_from_text.py similarity index 100% rename from examples/pipeline/kg_builder.py rename to examples/pipeline/kg_builder_from_text.py diff --git a/poetry.lock b/poetry.lock index c3a9be62..781156b8 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. [[package]] name = "aiohappyeyeballs" @@ -4609,4 +4609,4 @@ external-clients = ["pinecone-client", "weaviate-client"] [metadata] lock-version = "2.0" python-versions = "^3.8.1" -content-hash = "25af85c6c6dc90b893ef6e77c29d1a3497e1b6be80fbe8afee9014da5e290e05" +content-hash = "f49763e3e7eede0e2e028e352310e7527836b4a0c038003a054ec56783435c24" diff --git a/pyproject.toml b/pyproject.toml index b135912e..8408143d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,6 +36,7 @@ weaviate-client = {version = "^4.6.1", optional = true} pinecone-client = {version = "^4.1.0", optional = true} types-mock = "^5.1.0.20240425" eval-type-backport = "^0.2.0" +pypdf = "^4.3.1" [tool.poetry.group.dev.dependencies] pylint = "^3.1.0" diff --git a/src/neo4j_genai/exceptions.py b/src/neo4j_genai/exceptions.py index 0788b4e4..92354b84 100644 --- a/src/neo4j_genai/exceptions.py +++ b/src/neo4j_genai/exceptions.py @@ -106,7 +106,13 @@ class SchemaFetchError(Neo4jGenAiError): pass -class SchemaValidationError(Exception): +class SchemaValidationError(Neo4jGenAiError): """Custom exception for errors in schema configuration.""" pass + + +class PdfLoaderError(Neo4jGenAiError): + """Custom exception for errors in PDF loader.""" + + pass diff --git a/src/neo4j_genai/experimental/components/pdf_loader.py b/src/neo4j_genai/experimental/components/pdf_loader.py new file mode 100644 index 00000000..b6b77408 --- /dev/null +++ b/src/neo4j_genai/experimental/components/pdf_loader.py @@ -0,0 +1,78 @@ +# Copyright (c) "Neo4j" +# Neo4j Sweden AB [https://neo4j.com] +# # +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# # +# https://www.apache.org/licenses/LICENSE-2.0 +# # +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import io +from abc import abstractmethod +from pathlib import Path +from typing import Optional, Union + +import fsspec +import pypdf +from fsspec import AbstractFileSystem +from fsspec.implementations.local import LocalFileSystem + +from neo4j_genai.exceptions import PdfLoaderError +from neo4j_genai.experimental.pipeline import Component, DataModel + + +class PdfDocument(DataModel): + text: str + + +class DataLoader(Component): + """ + Interface for loading data of various input types. + """ + + @abstractmethod + async def run(self, filepath: Path) -> PdfDocument: + pass + + +def is_default_fs(fs: fsspec.AbstractFileSystem) -> bool: + return isinstance(fs, LocalFileSystem) and not fs.auto_mkdir + + +class PdfLoader(DataLoader): + @staticmethod + def load_file( + file: Union[Path, str], + fs: Optional[AbstractFileSystem] = None, + ) -> str: + """Parse PDF file and return text.""" + if not isinstance(file, Path): + file = Path(file) + + fs = fs or LocalFileSystem() + + try: + with fs.open(file, "rb") as fp: + stream = fp if is_default_fs(fs) else io.BytesIO(fp.read()) + pdf = pypdf.PdfReader(stream) + num_pages = len(pdf.pages) + text_parts = ( + pdf.pages[page].extract_text() for page in range(num_pages) + ) + full_text = "\n".join(text_parts) + + return full_text + except Exception as e: + raise PdfLoaderError(e) + + async def run( + self, + filepath: Path, + fs: Optional[AbstractFileSystem] = None, + ) -> PdfDocument: + return PdfDocument(text=self.load_file(filepath, fs)) diff --git a/src/neo4j_genai/experimental/components/schema.py b/src/neo4j_genai/experimental/components/schema.py index e05e7506..83ecf0ba 100644 --- a/src/neo4j_genai/experimental/components/schema.py +++ b/src/neo4j_genai/experimental/components/schema.py @@ -92,7 +92,7 @@ def check_schema(cls, data: Dict[str, Any]) -> Dict[str, Any]: ) if entity2 not in entities: raise SchemaValidationError( - f"Entity '{entity1}' is not defined in the provided entities." + f"Entity '{entity2}' is not defined in the provided entities." ) return data diff --git a/tests/unit/experimental/components/sample_data/lorem_ipsum.pdf b/tests/unit/experimental/components/sample_data/lorem_ipsum.pdf new file mode 100644 index 0000000000000000000000000000000000000000..02bcd5e6b98ebef599152695d1e8cd569a26bda3 GIT binary patch literal 13891 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 literal 0 HcmV?d00001 diff --git a/tests/unit/experimental/components/test_pdf_loader.py b/tests/unit/experimental/components/test_pdf_loader.py new file mode 100644 index 00000000..44d80f21 --- /dev/null +++ b/tests/unit/experimental/components/test_pdf_loader.py @@ -0,0 +1,48 @@ +# Copyright (c) "Neo4j" +# Neo4j Sweden AB [https://neo4j.com] +# # +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# # +# https://www.apache.org/licenses/LICENSE-2.0 +# # +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from pathlib import Path +from unittest.mock import patch + +import pytest +from neo4j_genai.exceptions import PdfLoaderError +from neo4j_genai.experimental.components.pdf_loader import PdfLoader + +BASE_DIR = Path(__file__).parent + + +@pytest.fixture +def pdf_loader() -> PdfLoader: + return PdfLoader() + + +@pytest.fixture +def dummy_pdf_path() -> Path: + return BASE_DIR / "sample_data/lorem_ipsum.pdf" + + +def test_pdf_loading(pdf_loader: PdfLoader, dummy_pdf_path: Path) -> None: + expected_content = "Lorem ipsum dolor sit amet." + actual_content = pdf_loader.load_file(dummy_pdf_path) + assert actual_content == expected_content + + +def test_pdf_processing_error(pdf_loader: PdfLoader, dummy_pdf_path: Path) -> None: + with patch( + "fsspec.implementations.local.LocalFileSystem.open", + side_effect=Exception("Failed to open"), + ): + with pytest.raises(PdfLoaderError): + pdf_loader.load_file(dummy_pdf_path)