From 138c367ddb2ae269ad4c1d81c1b0c62f9ffc5e8e Mon Sep 17 00:00:00 2001 From: exian <2979958062@qq.com> Date: Fri, 27 Mar 2026 13:24:37 +0800 Subject: [PATCH] [feat] add dapo algorithm --- images/dapo-rl.png | Bin 0 -> 10444 bytes images/dapo.png | Bin 0 -> 79192 bytes trainer/train_dapo.py | 421 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 421 insertions(+) create mode 100644 images/dapo-rl.png create mode 100644 images/dapo.png create mode 100644 trainer/train_dapo.py diff --git a/images/dapo-rl.png b/images/dapo-rl.png new file mode 100644 index 0000000000000000000000000000000000000000..8b521e475460b245cde569478080f0508bcca60c GIT binary patch literal 10444 zcmb_?2UJr{yKaCF0clZGkSd~}A|N#&O{pSHkfH=a@4fe;^d>4LbVQm80qFz?phznnm-dkvA@caIMoxAQ`>zsSf&C0C6-ZQiJ%scZw@AEzr{!B%l@*@332n0f@@I*!( z0wENKKnM&-3Bi?da{VdrL*y)_pg~GXIx?v`0se)$$i8rSZg1w|Zs=qRd2ZqA;$rG# z{Q4Ie1abqSAoEzmV|aDcS69Pz>}+!#*FZr*k=^-;Gz=Ejo|uz3MftN@X9{6iVN{-M z3M(90Lwp{o@LH{~vxd#>!YgeRI|NElC>eERpACpMOjT3SO3)bzGLR8Li&!*Vfmoaxhd^@6oIuOg`G@I4g5M zP_&+-B)cXRmJng5_ zyu1JJYun$G(VO2ccAJQ73>{_IoZdTo5xhI)=B@Oy+6due&@?Bj%1zr<;JIl&dYr>0 zCTSk;fkz?zt~qR!>z{qLz(rhDl^b!Z6PhpYIXc_JXPulh2_6(1AB`eaZO`1zq^BBb zy!97<>0w_HLy9t8@-yTj^5f#Ju*y{0jTVZR1wm;GD%dYE?)V}OL?zJ%<${8mHi&}; zvqAf3GTI~lbPUQl8C*x(%kt5xl1F%KpqCrDtysxa6588tr2A{y0p7y-Ap3z48RX&3 zO1U?TcQtj?U(MnjTnl~i|JYMm2YUlHfbj@w%2J^q&ACQ)V9Hq6vwWp(e3$*J|Gefsgqmz9WI z7CWgCew}d-lM!?8deohclO0sOEe(+ueh{fWC`cyzY(L#FI{5naP^;vEt0X`;qJ|$%P9Uq9uosQB3*?%X#Cl3Hp+=mQecmVT7aOh0*>aQ9C?X#_l(3*8ILt zO-+TeoCZUuren^yf*kyCd8!%MLe-Ixa+VRd$p*q3m4&+)P5P^Gr(^CXiIs!alMcf4 z3@LUy$89F};w4FF0@kbW&{$n=ds|z~F{~!LFJ3->#z~|F-_wfzUW}1rd;zJOTUz&G z+Ujf_SvI|UY9@2FQ`0zjoged_|tF3u2=z|j>1gE0QL;!k&{JS`jLm>Z@M|K2|f0b4) z2*i%cw8d`id+;0{AJW{M>n0vg1aTmLqWXlI^x4tjU2%7whg*v` zR5&eT{Ds!9VOuExf(Bzg8EcGyXW2V$geb7<$oYvuY7n3I<$FS|P>47ze~W)k<>IXhiH6Q+Woi9JI4`gTVu?dSj8 z8~MGuhjyN)WDvS9CN|Z^k@4lrm-h*S{rx9O0 zaK$kadKBj7XXygyj*5{xcG!WUnli~fj4 z5AD`4Qnl2q=hkj_iUwX70OQc`kR;-TB%zcs*zDqwR;(vm}R0Hl@m28 z84@Qwiae{MDbDyEOIDfr&a_}?e0;oCe!2a4UC+ZTxoE3xJ#fLTMqH?(erJ)%9e0VD z8KJIzb5_g4!=uJ8WUr8V;%8MIanY=UaITW)udXit?YXX%z3RR`S6GQ)l9Jn|y}0So z>9F-W9$59@)7IA3`}gl9PdELIjE!fV4(oi6vS;;b+$gE2xbHn=_pSE#U-Mqa%;Tfa zFH%t4zkmO|gt+%!!H~^be29)G98pIx1`6$Td2`Ug>7(fuv^WjRrybok{0F^ zw9BHktgP(O-f9NSzHrFrDQS03WZ}n;CAo72jguZz;V;jQ>J_)Qwtix<8QyFA7o=Bm z8pF?592+q)@yTJAzu!u6OW#sJo}M1;PZjKJNjOc5 zy!^ghsh_WJFT%GA`yj8y$z#CML0d z{aPT^6}S|;>SAMgj$1zzSzrPJwHx2_rNY3T!8vz*7}m+JulF}F2w29udHX6VDyBpW zz+iBcQ0GI4DhCoPnEc2I>$|&j)pOw&jEroPmRrDnBtg(|s;ViH_F=u(v4^FHM~u*T z4|{VER47I7vxd4o!3H5!XrLDsQ+tYkT7#*p7^t=xipV&zIc|8>{PE*7r*`hA{-t7L zn&AT7=gtG>XKRp&6cfIr^|hKI-7z&)>%uQz*1EG&M%L~PRze;*EosQgW46b=+K~kR zc8}+7^8bg6gaB9g@A5C-`(Jd9V|+S3)W1}nEZ1#dUoMJVD1V4JM;7#FYG(=jz}9Mv zZ-0{ELsaKs5n@C(Z}s@(JCsR{1gr=yzJh)6@DR0o@%776inirDk2P15))QU?LD@?` ze;IHJ4&o1D2!b|m(B18ix^w}d1bTI~u-m1lXDlGQ*i*J#lf6@tTKUA&>@%wHi@5RU z@+aRCOn;shi?Ou>h^VIAp(UYkl}xbee1e71B9hI$P%3%-i)9brQ-IA``9#n>`!;<` z8Cj{1b0+k=x^)|$siMMML0cFvm{=TlJ9mo74?2j4mEG*jjNjp`-{N#nPstzxo~@Oi ztx9|UARkdgBh@-v0-!?IkS#u5lR?O)cx0J~urHQ_BRJUA`RtZ6f*;GbYDZ%X#!ts= zO}efcLJ%-AtL1b2_TYe3-NN_u(9PU}jFphEZ+rf1Nk`~?654s;*SA0t>h`v_j@I9s z2h%YgGLP9$ID=!a80YdmuS5Sb5kg^kMYLm|@|urcfH*`tepi(oJ>F=1o|+*fAn-}! z-r!Y0TXb~1UJhBJb%h+K4i*;1I(dRaLNv4oNm=O`7^J18#Woprqj;z3%mvv^6HBjn za~j9T83JSU8A4i7BP%ls&ITWuV-Og!6i zk@Mnq2Ro|_a-x%W)Clh$!#rgF7msN}UhAw=H2YgzwRl9NqTlKEksk7|3m4dLN7G1s z(n#~#U-QJf1VfEhes_Z%K7Q4NlBag#3)HA5o9y;&4*3{n)}ROUNA{!1izV*@gwEb| zm}%dOU&XBd_Wg^5WcT8-$YUI*9yPXeTvOAV9UF(4|BYPKx9_%e1(Pdqn^5BWq{B1& zQRdxUO1>ne%x6zBw6wH7_Y(-E*sc!80KCl7xTlhOhl$tdQ+@q-ru6u&TR-%xe%0E- z2Y!T4U*kdC@l|~MxEqko8n^zdSFeT!yY2@&v+GeSGM|2c-t;`UVtIoX8^?9k&#Q+CWnINQlWamkkZameiJF<{NZqUi>)l5zB%wEmj6S7E{$d9r3 zK=P^bQ{}_}@F>PXhEcrVMEve3&nX@f2Y5w#VTqnl?kF|tLg4-Q^(_WI)Oc>O~&8Vmyj?Hb9e66O}0-f9!}05m$B zlk$Q={yhD~VSlcB;5X?2ujM&4K(%z`#aGaUg@}AgrxCsKp(Txb{@{ZsVN%TMp<^?m ziOvetNcL?)AI@c=n@Coo-B=m%&>nIJd98d@*4UxFcr#fyZ)#d-!gfMmD&?|M&yG%- zO1|QojPE%-01I$147k88Ghb^f;*SYe)Q3ET4putQlrN@mU?8x^EMn;3{A}%%=4dcN zrxy^XNHB{yag35_F6gd@jZ=XKcu)!5@$XzyUV}&hQ;h^m4&`mgaHNC>PMtoU{V7Yl z1tV(E?UGd8;V-S^xmWNQ36Bq>m!plrH)@hseYMF)4Y*kkC9hdzlDe~yNm7Zj8OV;c7F;2WnqUUOqZN=~F6 z%67aeq&(SbmQk0A!<)PJn(;oRZ6@5m^?e@Yt$x218t@~lg{+Os!`VxL#@0e3`F^iT zEIJ@u2*T6KwKo158OuKWAZXtmqnQ*U-QbM2wBvfQp^ZUs1ii(YI?s2azbF6ixHO$T z)zX8dW1fDfeC2!snAmST68AqXDm3kAZ%>mBrD7KIFi=sklWTs{!r~tk8^IE5!Dt-z z;6*1q!Mxxm2GGw&fxm&~HdQDa7Z;{rrA(JQMcC2D#l?OeDJ3oaCEq#-8XX;-naP@} zrkf<7-1l)t@+oDgx>q+hwFlIF1^abqsltBTb>h*O|LHbbDs!Pf-yDJPvqiZM6v$to zX0Gx%O#bmhtur3DxtwetjTas(8QEgK0n^H}Bj+a@QoA7PpI`kM|E zRL^``-`2#&a*&XatdFHR59$%Ma+PsnvN^mJR<{HgU*nwo*MwE*=;#vT1XM^f)m@iH zYvvbwuS$je6GL)>nfP}M85ftzDDD*m{cf>R?`oav%=S+d$p!lpMIuTZuKo>EA$t)c z&*MtDIc&ZC23qSHIa)@$-n|ly#m=TPh#?Z;c`ETmdPkc$v~%3krf`}ZHaUvj{e4lF zg%kjryipE|qHr(NMIa6V6o3#Kn6x)f6(ePRVOwl68PP16s+XQX>2Z6GV`TzY zt?+015+|WE3EoEO920!Q?GA~i!?$Vpbc7}Z7dUQJPLwa+?r^a9jOyfDZRe6`V2giz z?$WQ}(j;V%7K~gpC6^T!>!xrvz1%(Ie?Z{d=yf(D&uqR{F84?J7k+gP9#X@FuH8OU zD>4NSro;0AcP>3#W;1h*2_{&_I*r6Z3 zKO0c2^H9iO2c6-;u5alX-)@Xln5&3oJ%S&`DVfqph|`FoA%y9A2QREGG7KuxTJq7F zB)N5$5bVoKvZ9Ig^VBRq?x^kWM8|S_t@22`wHRQm%=*MJKR*^5>bc*9+udcQbs z%izjeIE=`5qd{3s)B5FU(-)sog`$4YmHTwJ@5YWP1Qv|Q_nr&oV)*PWIr|j?d*diI zVb=XgKph*he4jyg=e6hr{u-KC_bw*;C@yCQASPcDxyvwjHf<|vxzV?!0rg>U>3yiA z1?hT5aw+S$O^L~i%amCybTo-<7eVO04?G(k8--?hLLY_!K(=X;8OuoDYF3xG@-DVGwAjb87t>SfNa|3YGBgr z*SSB>h2_@*f9&Y!IUUEzOw&=3KfE|t$vuU?_DgNJ{nBl5y5JCLmn-;*Hm(V?9AqCi zkN7}-pOcgSCc#`7AqWWw*3uEuN6pt8jRo&115lz2-Ppu^gk zrt&jhTzssLTM5qJTsQ)OMT6oDGD&HU(A>;b3DBY((woq!&l*yp{*{nUKyl z&)Vsc)v?MiRT53IXf*Fef;!C7Sv@j~S(l@;c89s8T45~1_i||U7-kak3{s&RYT?bi zA*6wbk=xj^*mu$%Z%4%Rn>jLU?r?Jh=B1!8y;i$@^euvz{PfG+MSUHR1 z);K%k=Z2x*GpSiIwIsgRVYm4CYd(Io0@6_D?bA~~z#xoU-c$_PSP%Hn(ezek&zK;_ z-c7eC21CoswetI~G5YY{0288=E@s&G>EPsu+7?%3I@ccRAxjA3_B;qQjw1Wd5gse< ztp!~Z#`$KiJTX_ES33!bS%JNtcJ>BI=Ps^9G2zP2ba7!B{S}1 z^?+5S{b5x*G=!^H85sp&D}(i)(%8jWbH0AObF$1OmbSI$^asBxOR4>^3AXxv==$e* zqS>k$o^#=4WjhkSA44c3NB&D#v&*in-HL{35ffX2pan1-uiya+{KPA&1Ht*BpNLoU zO#0?_qee5pH)Wf1nkTtAVQGO2dIt{(?MHO(@C7lv4^_>yOvhCZCC-yIxb|4Pc2+dr z?_In9yrRvf$I`WJ^SOoSUufb6-(JO{ei4?^>L+2cCJ^>>xo%bNJ|GjPIhEF4}*W^9utB-S9=xn`Q_-o zSaJ1;W0eLY8Crx{1K=|BV(l>6r{zfK>#^vO;6L5&5hrT+g|BCnY!)o+OjDM-o(@AcbXKhZG>$t_iRcVdr%O_ zfvJGt#2bdASeyu=0E2))4gPLkWl1pSvqt-O4Y3-+X?nVI-@Oq9i8Xuso=_>T|2Dnc z^_vuB-LYWY5WxLdWj-2~vDQjvg@GQ38&E__R#~tl*!XXog)R!g0li>ZiYt*z&lk@pq{ z`7k@Aq3u)N*r7O0Ye!VGiw+ZI1n9rYJL;ts7a(}xhP{viWrXc}B~r)I#uX_nv1Bj{ zXjkPGMaG&vC%xGD;CWJ;I-Dz-vzk50VNv^vl<@Y-h0yCA{drn;aJ?6ZzPq1#X~JWu zBAJ)0&0p0~Ko*{KCM#X!S41_bTYtve1r#f1E8HG-SFBzrOUnuFxvUq~>1x`xKBoUd zOOHKBI`f%Or9l1W!Fcs}_Zkd==Yv3OtxH(2{52RqRXY__2Rjn`g{SX@6<22uN-r6n z91IQ4i!5ZT6r%_4St-yZad^wt>NxIk;2Kb?hs)5~Md_C=O=kG+9s0)l-$Pl7`13a2 z=Qad+wrf%XXZ&$CxYKE-h+!{HZpYdH(M z4D>|>N_WBO3JoUq)qoZwWq6r~c=poR$NOjN80xaRsz257- z2dkAWTnS5W-$J9=AAqEZU8QQ0)7e~yJ_Wsi!_*INX{oZ2iq)#4HPQW*w(v-Xod%*a zQ=tqA?>*hF^h-oHqkU`kfaL30W;in)9)lR~GAJK@xRjRRMGmRejbSzG<`PdzLT3SGudWWEL&r2KPkQO<)t4GOs4^3W^~ZtU)LTPD zPwWU9xHL6QyO&*gdAq^a&~UU4Z*`W)OV)#Aq~i6(OFz`39o&V(;n_SQj8t#Zp;Dc! zkO25yLD%UzU$j)%z`%fUO9aTnnDV_;RE&h)$Z(8GC@U-9y?Z9%KSqBg+jA;hU)Ua4=$Sn_tDry}s8v3vhvQUq(3E$@ zf&4%!NPu(R5f-xe^@#Pys5|wY`}gOf2qEa%fdZ|RzF}rYMwe3`F7qpp+7#_w8lb}D z2kWNw>$JQinINuqAB=@F-xU^aHOnU_eFl>AD52kIoLv!ePWj!FZLhoW7tyKLoc*JY-obFdW5?fwftY*}$G7f9^C5E;i=t5g=P zmUo?AUE8b?H){{;QQz*#IlB+u)J}Iwb1%V&9P+8sjt68fLCTX?<$50|r40%%$t@m}gX!ua_wFRkQjpDAW_i|zJNu>N>O zMFPw~bJ+)ZL&& zAzLTYoF-7!SD;e;IqWuvYD7eYZs}ZLmVBg<@sa2Lso(KtNMd50nKN1y6E}z&5%6?U zS5g{}=N!jkMK9Cz4$|)7Q|#Y_goK>)?B(TUea~6fBL8VO*By)QB!0oPhoh6CHM;ua z54`uLSy^d0%JK`!4$LsKG}A$vn&yC!2SeRQ1wVY4NE}>W&x%o5?#&y_!NP2Zt4$Si zE7x{=RlB01SApcx*w|=Ov2L!)eP3*^%fGI7cz7w^n~Bz4TfIk^RmRiPG*2b7b9TN9 zj=X;uN-N2lnUgac$y31r(z#PdLuE`NWXE>#d@7U>b(|8mA6@QDTZc-ein>d{_Lo_u*AlL!i+gj6iyQB) zwA6Y>6q#q7WN7A(`7dPNl_CY~z@e;ef2`iT)921DnPpT>>bqj&sUMqueot8$&+n76 z9_{pYfskZ-O1-AI`0nl5#`$#kPLVt{X6`nD{n%4g4?Zv*v=*?Wa`eXOI@ybJZ> z9iJ~=BbxmgX*UkHwKrl7@)VynPRB6Q*aR-Wt+wkdK5v)6!2zlk{O)3L@yYk^)t;N- z63)4~`t=gr@d>Tiqg)V+{{AY=Bhk$!PnGu2wFhJju3T*DOw-4A7FBf3Y8e<9NK0q! z6!+`QH~GIpylPTsVrH)J-q%Ld#sGDz{$y|1d;KJQyK5C>llE6fIQjWUBKNDy$_ffr z;-oUe-mH!O{(Xn?ZAj2x>!T?neJzJzp_Dhf5u&uPt`P@ta$z zq;1V%tEXEy+!lL8Zrm_v2soXcjhEQUU(MRp8Z4});dmMh1$i3g2R8;toH^Oqz2@32 zlahvjfibQuFgu)>9WJq|swP#j+GSC|bt!v$-dZ_V3RrAv>iy0R4>*mGpKqO<%>5U! zr3v4V@BWDkNbrDlwS@BaJv-UQ9L`zW*BuV0io|fRzww!P70#Cw7Fl!DEuV)uJLTwU z+^bc!wqE`ytJpr*OBLE^a_=HF_4c`iI#8Cq>_z$+btY|+J9zHyZVcGO`u@JAR!h0| z_2P9v)LSo96D1@hWLH(eZ!~IvchakIa$7rg8Y;PpO+fvw^F=xzwkJ^+!7IC8I(sL9 zR8B}pv*g)fzx(*fMsW*sLYqm?Geh+r)yRlCanGI=HhUAQQ0VvW8uzYraW+1Fcdz-B za^2GgA{t5j9ox3|{&%iK1O<7p9QN16{e3pgy|n_IRq)YE>~NP)8x&Nm-ObRvbO}RuNcSL} z!<=Vy?|rW8`}QB_JLlSG{Xwjmwbt|8`MdA?xBM04B<|jRd>aCR+?9OyMhOD>XB`5$ zK8|}GoN<26D+GSsu!Tyh;Ns#=FUbD_{}S1~eQ&31X=La4(Z&#>{Mp{l&d|o->i`}E z@&qFJ=9P-m)b^~SwzB$C=UxO+^g|Vrn~Ei0T}M<)P(I}-&B6zTs#=JgLd|^iq`+1l zeqsLDs6bkw=9Uvl;)iBQvHYqhPozl9#GcTE%~LA|q<7(3H6t%Z#}A&-)YR~wtU4ii zjl1sLdTqX~V{9yO4J-&8OySBm|Nb@f#_GnOzn&=GA!Ecu;VJ!IIg z1PI2-h|@scW{Q0!_i7G{JmsTP%^%4r|rYg-&Hb)J9 z#t!lebKUZy;W;iUFHgs7vL~cAWo7*-9aUCU@`54$AMiL&{hkjm*6mEXyO{)ZG;3_C z_$`Ol-iV8fOG%l6pZDCwYP4Y%7IZPabd4!WED>E@Ir1Wp;43|(jkL~Vsjs~3x5m^8 zH_v;F2#7!eS?mp(?b2~+-Qxgz3W?Fkk`uOnY-o@S_@>ymS&w~f6lK!Ex+~nWn zvLoI-{vIBlHoTG1lrqE=!EHA7eJZvsibZ{_K;xn(JC3hfQgSq!*-&-^s~9mn<-ACH zsk||jW?9X6T>)yggrx8hcc}~+_cKFLJsjn3$&c}@)h{330df)+o^5GK{DA|m^Ss~D z(jo*-OdN8)C02sYzAu}6B)OCQrsvtyr(cV`a+fn+$j&Tve0cGK{N=2daik@ZWF_ij4IBaqqyI{d{Vi5XLREAdmyZUG4hjywOCW;W zgU*q>vPvJ{LYPl-xE#hdd*R3@@a(J)raMoFFYnH?9W+JlAHrJZ$BUCEO3g1;+P1$@ zXNhlXG;SlN>60{>x%H9zhB&Y-{wVANNLa|8>r(J+r!UrFN=r){Tu&1CtZmHA3nEW! z&kvE)m0Q1dgxjWF-@)|qWyfrOGaf!pmd1qRCf1W4 zF3Oj=mKN~Kw+NY;wZH`#_HwXnS~LabKyM2iybfCC_5vpP@jDC zKp&mRi=r!>4^G;x*9;5{!0tX68^?VAzTb@Vy2^5Xb9Gx+#2F z8K(lPeBDX4XLI!r3{?9HZJ5&hYYq87^cHpBWy@4yJ=z>4hI;$>tSnR>Te^mxpj?*v zQAr*-TpH6SsM%Y`jc^CYoYppKbmu53)UVTcjUd^*d`UgUS+!K9#`l*6YG| zHpg5>j7{s+Y5O|Fs{7Jq|Ki^mN`hTYUQr6(&26H>;hDnP7sxudAR$ ze32vV6l;iLFBQs- z*eoq~K~Tb{`SIh&YJU>ePPWF2Nz+4rt*z~DYl<$1+%tvBiZDurpj@Aqf1qc#e^eu@q=Ntki7J}ntax_D{(BMIcb8t9?LeI-IUFx z1`_x*;-ORtTk2EX7%My1v|0`L$bOtPb)UdPwwZ4Q(-X&SIfI=ks|;y@bJiN4G#qD6 z@*h)+xC@`J`h0LY4nDRCO}((k;du4$A{g zqPFS;wwC%5c;}luJOUrE8UH-h-hYoox5~NVvG{*5%EqVDo2dqNqd=Q9}nHt;RT#3H;N^Kn-Ui0^Q^&($i z9>wwvO5j>Awqc%CTDrSm0Uhvs<9_+Fbh^rd6v`(kn8LT$v@tAta&Sc94#Sp;rspD^H?*h@hVre<&AjPBdmr2W1w*NvE|EI_^$=suxYanEHJ|x~YOd zB=Xxe5kcSAoG3?!*{Xk>)^CfvW*CB`sCt9${}GkqK6NxT^7=VE3x4p0ve(-j*FNPG z&AjxR$sjbLN01=+K~+>fAJ>&pX~$am4GgTN+izvdsDi~7;e0U&#igkj^o_>M%Q3mF zLtV3XrV*X(?eL?~Z8D5X8q^0Vnj&I4vVL~3)=)MaZ0oBiEx1nWF~1(O$Xy$gPj9u9 zN9=C4Tg~k-jt_VH-M?G(rk$aS{5DNndao$!to_lRExD6JPGsh^YlN@s)WcAz%h4N6 zJA(ESBflR{HL2Q9xB1PZFMm+ZBt-?}us)ZpuD6~n@{2S^#PO?0Eesj7_*L~EHepf3 z6GcvA_dTR2ra-qr6IU@yX7Voi7y>q1%jZsHYm1MEiYhG*ep!4EdJ`uFb9wLx>NnTm zYAiBQq=Vz(fl>d57m6#5DDs;1CW@DKb$mPF3Rjs_!d;@s*D%toJc+MuW;sYc9;?Dr zE;^hj`9*p0ee6YL!O+K^#8=0i806ZUW%$lFjF$G%1+ww+{f6!KQpso(B@P$-@FF`~ zCC`f*Eux3J2MtZ=9Tu4`7@88qrSX;x{!*UxlR|~}X#3lq9xECRi<(nzI@|6`NQ+rg z7A~U-q7l8^R}D12C2jbKIa9Up@r%!U{|uirG1a#|q;PB0sdI><%}74z7u>~tDZs^5 zVbB>;GgDIenz%T;VMeKcx7rHXY@4b+T|G>GOeb_^Fd4rq`*2g^)jDwz_3V+Ew*fM| z!IXIs*8aX$tvHnkkA|E#w+zN2J9*e@0`vb;=fK)zuFk_&*)r`V`dMRCQz&9+qJdu@ zl_0O*vUT6~9mH)*=GBk@~0uSM+g!wReZtU$cD;?Z17pZr37ae}EU z%Uz1Pj#gvYon`HMq}IhMEg4#G+?8CSPxxUWDfDwXAzPfDrQ9yPY748L)8;^^;JE#k z8>4x^YTKs$<|=%y0-n_wY!J8JtD*OS>Ari)@BSD9YIyl4y%>MfkB`v31=jhY`IW~= zim1Zf@#%9eStkG2nOyM_4i1>fge%?3gRJ;L0q)9t{2J#nZcNThqxy!y}TEUvkT=&`E%6`8ogvumjGi!z>C+Eh5 z4&L!|{Z{C>bQazZpVKxmWS5t&rY60&@JVZa^n644P*Fm?NaWtd<&-K?MviqkN+5)M zbTsPOAJDb@=Iz@`*sM$Iw<8*wG7a@F>Y?ByJyxB}zM&#Rmpn?gtW6Mmg}ON{G|i)+L(_`H4L(e%Otwh3LuLE6TTYPE7ogb z_qK86~zos6#0(b0(-`e)BZPW=!F-gbQ(Oy#?py}cQ>k1&(mtFxtRttiox^=VFb zP0UA1X&Np>$o7$=+4khA`zO=#Zmpnv1z{60Uk_23T!BEtGm_lZo}weo>DArDB*Fdk zqw&gUZr=i}S+#?8Ix{{K+ULo9dJLllGDpl+p^F7L?DOND!qTA$;hHoRydG!!!@EIC z@vQlWnvO=!r1tAIoY`u!d{%sijfS(R*WZp)%G?j{jCOyPF8@s9y}EpPJi02%^P!yfD&nO}&n;uSJtjOMSQdo)-M@jSjI@|P@qQTw5+5JZ-{G##Ct!Q^Y(+d}S_e4?Tl3K_Y}$T)cRBWaP^lcbf{Y-uk{rDIRVjbP!K zWa_7pZf3jNX|JjxirKar4%He zzn^f_tIpSrUYn|Qe002_vMa#Ldww`avC7d8w~kpwW%t)Qd2nZ^tRVG#Qy4veu+;zR z=*1pp0486Y?0Uem65=?G*)_`S_7*9E_4kle6JPQMxOmzpG{k6&O~jH<0TJIyXMu;y6m<*cI`$gmzS)%vG@x^RWLfU8Y|dL z!D77LI6JWkkG(6w)>tg+uS0zVsLXb)pL>;?R>GY%c}H(JU%gl#y&;0O%L|*6;qA~! z2~G>LP8fu_q1Ad8df6f@?NWuu21!*kASN&73kdQI-|&JarJXjUNa%#DLXyq-~*;=y4wWnF>q zaY2?yEqp#WAW6JQLypGV>NC$mf)UVM%MSTTVV+uf@TK7r%~mpTEuT>JqbQ~3Lj3^d zU&zRc0^+fZK&6$)r<*RnlGAx%49q$+d38;bWpP?YFXIw2pJgx#;{+8O6i!_&4OeFM zjF@jJ!Yooh3+532ZCz~eIqydz5D4qa-JBf8rP=!j8$&~O_h<4&;OA{^Z7!~a{{H@? zP*&~g56xfCptwtK+5y^*ViCl_NkKZ;EV3R7*#G_#xH4t8|CsyoC&T|?WJOIRABPY)Qn)fiL%|*+K8M~=Gr*W4do#iv!NN{K-y&5&Sv#@yiS!5QptVFSwO0B zTXJEdLP8YOQRK+W!;!XiE%l-~DaPp{OZ4kH9&{MbXRC2dsViq}gnM$Y!&-^%CjbV> z6j4hH?6CvdAFZthm#5bEClQVCi?)uA$ATl^r(DX_nLjax82T_KX8-WeFF2S|)LlEI zc6wdek_z2(k@FhUo}9Effp|1xi7esQ6SBMbRi~Ilq32Wo@f`$Z|A>`L!a}@ofNb4;*jnd+CioFATIlEmRJG%p^v3->#mY){P zl@Gb{HqYiA&Wd#%DyMySd2Js+GiC_hU)cZKJ7f7skc}9n3W;C(E>u$M#84b`984NTE#=0pqq=t_r6W4G9PkaNf@- z-IB!{Kv+_Pq!JlPLgQUoc~osp^?j=0CkYb|&ls|}73eZ4DanTjpN##*T-QC>Hy?hn z0hx<%iZ>PF&NqJE4bfwtaygSJyEAp5k)ov|>U2U`Y!p1R%?4^z+l>pR6pB)~1}7Ky zW|w-(P2R^GW-jABLrhQg<}00@<8Ec7yv*@pn;Zxx zye^rZG5Xj(-qAJNniR1bNPwpKo{mgBMW1*E3L@ZkmYY*_`2<`hjdtBrI>!1kiE|{f z)e1%0H6fIOA}7C=yCZ<^^7Rs}&U~ZliZ&^QT$#Do99b`P3JbQCW(%j+-MLwMmuT6& zZ(=NaOLe4>H0kGRvLmrIN2eK4*<1L^|MV6nCLB@jY~Q!)1O10Et;rhRor_n<2mQ~V zhefUryT7_^yX3|jnjW$vLSmp^Xqb{!G^#ykb;+BSi|+T^Qw`Y`y=OyL6kq<`{ZFqu zAl7j^{_?h<2pb27xkk7d0=A1wqXv+}&d}7``jn2NCLbbfr{JwAt#^qX zjPH|b=y4yjsL*+P>qnlu|ZFP9Mx+|US^GtoC!F0Yy_ZUhJH<~V*)-0so z{vCZ*hxP~_yG`>HiPE+{7Bya|stgvvY|Sv0k74%qzsObfb+S3jUvyQos{2$CH(pif z&P?j)VO)+{CW+O5RLUE>ox%H4KaWPnQ6Ft8oxFJ$?)XzK(gn8?ix zhM!}|E5OvEmu@ibEqjdC`}glWL^GA?4LX8g1F6^a0xr!4Qk!F6rt87^WKN?w;$+xk zSfVn&Q!$9ToxaN-eL4SU7(k+T%j;GCsIc29E>4@B*V!A489)}h^;-O66{R5uO+i*Pn59$2m?2|MpGBPgyBO-4l*->@i>} z^min{IQB_H;j!3)GRX{C!pI->NeqMx_}qVmWKf z!NGCo+nuO5)S_yWR}uU7yW^u zlUk2@8rD5hc^TYEp0%a9!f9s@^6#-Ryi&O5tLTtc-r0ebeS7DJRH|a+e?@RVviR33 zXd;2R3Tn3Q1hg5;=h%%5Qv+|GS{r|`i73^Rb8X7vXws6#J$I-;R+;hlSbgG%ll)2^ zC)1I82fL8sq~#p1z|KR|#BAqtDG8HEg|qmj)v-dYP%2@LIU?w%IR|TNCON}YS+}rf z+mD^?&2;2VqUVD*7A3!5)ISDuQN|B-$RrzE{s%bWQ$M}d|omSkFa2v6Z+*SZl_ma@o9-wD@2&@Xvy+x z@+0{l<_GOr{7IC7d3RuQ^(F=eOUuhDxV!dyi|x`e?03m|3fdB1o!!2!S!sHNs@r{R ziAz&9$IgM5HXY42|A@pGwO^&4g5u^Vb0@wJb@ZrP9k=C0ZAOM1#owh^8qQBvg4=C& z@xKc7uI8z{cpd_ewum43Wj%mm6O{kT>iqnUl@LYB7VnKHN5pZxozwyv&h=YuA#ktPym{Zq@sGA3DdrSP#t zY7`fW*J|owr5#=3CD^3HND&ii@;&0EN~Ul&oL4>QoIbB}Xl1UFRmRruJ1sKVzwq~Q zDznh=vLKognJVBwUpo1_22MVKw=e-ek4HVXK;7EipRL%P zsl547ufe+Wi-E5Tlh>Ntp@#&qckJl%l2T;WTeyzi&}}rsVK(*Go|CwQR(2tJV;Kuz z6{>u*7T!d`kGUW7n7^0of$a*Wa9CE=CHxc&YF)e*%GMZ)1j{vT28K6-?gXP2Ma9*kbN z*O>G=mWw~DT6y=MT!51!)A5dc4AHKdoMW-BpA>uEjSO`?5!co%$*s-I+b znGa><8XQO1tS`deZ1lts98k^`8*GI%_CG?0jQ9 zwj9&#>NMt`ucOwtxsB&bSDwpSc(ZS=7yWxUc4Mmcfuwmv+*Ea49ogyy0Xfgl*jXX6 z=Oo_K2+I^cYiO|t$FStshd0IJ;J>FB;%jU9ow7h80M+>r^+vN11Am82RhZ22oa(2)~wMNnZH>sKTx8JYUC+~Dw+N)z?Y<>~1LAPM5H>kJJKgR=Yr%&;Bj z;f^idcp9(2XUQfMX_Oo7&NUeJM4p|krS$#W7s)JI&XVnB)u!=IPfveY+5M3zn~r|N zyX>%u0r7SbQs|&Et#1nRgCjE+d59XQ!?UoBL!Q_+tZhaJpvz zl%TJ#7=_*KD&~RN*=<-nkA>;BnZdSx#F2yhr#_fX@)R!3&!|kcH~K?OW~mz-yRk9M z79T&3uSQ5V%$9}lm)Scw^Ek=i;@=)t^Kk6)bQom|(hK!|GuvA?y|@Kcu)hI70_i4 zcS-r`#}r0`BiXRHA7`;B6bkekV%T-=Lzh3@2{u_VJ(WuaKfaYR&<|{?FKel{|?E!$~R9H!Zx4!Jms2`(Uot+u&J{I5jn`8BIWo@2 zr?SQ=>@Xuxu9gR-_DNrS^t#aCq5tLuQ|4A_JPB5Bkxw2-br!&J6E{^W34(%Th)^L= zzYJGLD!(BIjf;n|QS7@pZWI*Gq8fb6KJUioLW87Pw3^(GoAwy4;0yAKORc<-MsJT_ z1*b_a81u&E$~NEq-m|=jJ-$2hn!Wg;zzAyO7!0Coe7Vh~!F{C%utjzng<6P^8EQG(X{7AYo2anr^(V)}b8HQ z8gJd$-AtbKE;O^pv6vXVu?Cw9zP)##FO)kC&T(Y6eqzQqO0*<|3MeKi%CnZ@OUEbyz~Brq;T7-%=zwzCwS{voV5R_;7aLe%HdkWpLPa z-IM3U!|C@n1wV8HwW50RtBTDQmeWC{&GST$y0fPS-AS$N{|DdfWz_9OAlEBD$_w0a zo4ZIQ3YlGXJJBGoD`@!eGg9`O2fqUvL7vrkB3o3Jw0$3gF(A=P4jp#mNx4 zh;U+1v}8+jKD=`#;LQOHzea{WUFZ*vWc;`<2$vd*{nkZ~0Ps+TzSqO*wdo(UFXsO& z8#f>t`Y}3X;w?S#?SGsf{kc6IakH!189Cx{H5kcemN1PE&$EN1O5s3AoTFfizv$`cDrFvJ2Fo%L z+`zCLg$X9X_%X|0k&CSiJ<~J%LU=78M=ghRUt*1^Z zDk}4hXlAv7i890d8#n~GGy-<(4n^E=BdsT zL1!9V5$eTr$HxS0niaSN1X;hYJ@EyYuFh_QLtY;F%Insn{9)|R=QVIQ`pm4X+cYyX zGl0FOzI1SLxs(0LoM=DMC2-yY;$X@Fkh!m zZly=HBZShp9v9gW7_*q0n+w3y=!P9B^F*;0f*nDA^EPqw-2en0F}+%`?$TmAJ|OeV zlrBjaB$>T>%*m`qpgv?ex3 zv~Bad2Xb1S%}Rjv(zR>X0L|p3hzFpUfg>%A2AGT4xVyx{4YB^MP0)m7*QzoHJA(RM zq32oj8e3{?jS&{pSxUJ^{fSK8zxVggmqJCoi9q84Fera^y?FLahy{=z8z!M!E z4J;(U-+!{wY#i{$mKGQ3<&!TLea-=LpqD#5yFA$V_)&d!X66!&E}t(Yd*0sH*B5LL z#JMRia`p@;1{da;I8}e?t(Y~^2_(k}0>uz>lNgN;p|76MgaqU>?G*I7})wWN1(;(=^$&vbLHQ*XSG7u~UQ zbWGtew3#e36tr7^;q*I|QqY|QYn#XqFI4i?`o_i_e*bDlSV{os*KqhMTi?wU>}1ep8?xZS04uo^Y!+|rRh%==7h~ur>1_OX#Ckv;m+1p{;-J;5r{Vk zFR#}|`}?RmwCQ+J(vfO-csKz8!SV5NM_r}qsFbvHU_b!JT%mT24Z*xHGjpC?k_SQ? zET9Qk&gZ@%e;~YURYup!azdi9XSo}bb@H)f>Bp-qD&5)p=L{8(7sHn=lCJcJl zqeJ5-D4t14ND`BiuR5t|;OB>pwrg@qN<)BBpoM^0z+mhV-62%MQ^2vbra9Eq#y}(+ zG_CBoTU%TE*s`s&)A-XTtcslw4m+BWLXhRe@^V|Fw@Kf>D`m-O7`)wC8D# z@w|HV%EZK^qbQt;$}&mNQ4ZI7b0oLQV)`}>3eW*2jZ;+fSB(q}g+C9Z{tOV<@^Jwg zGkVMB-Q^;CrBqx`g50_FrR9y4m;Uzo(H8omX*^dsJ1i`0WF*p`m|@x24A7ySS|wa#J3*IhYk8Rqw0w_u1lNzwV??@M-SkW>FL{Biw|Ma|nqB96eEj#b`C9vV zJQ^SgdoZRBBzr!Zt1OYGz-6}jh=RiH{4h?fP!o@)3PcsF1zwN@f&&6%WMxgJDkN8L zkp>vMyF~TYh+p@t@2ZdHd3a}~HwLMxn4OiSQm9#}lqofur&?#Vu(&at9nXE>wpEDu z`t>VFZsC!U6BQ=JUd;p9@_M$mfgpE0V-TGyH$IW(O+MNbX0WkgO3ugHO5lAG0}vN% zY;5AWy0fLCn4!1^9!@lEsr~buI5{sH5)Hdo`QrS0?q-cd~k5Eqb`(Mw7)Q8pwy-Vfr5+;!Y81y zM0S4yoNi$2dTuY%9d@Pw5V959vQ11(#5(tifY8&6Bq-)JyV@)7Fyyy?;g z)`FxhlZ6Yv31ErFmG=>h7E{ zFn2r}A)z?|o8@;>Qc_;G?s^kBIII-u1P+*1f&w`O&Qs}*K98eurw7Xb>FsAq(-Q%K zbI|<+0?Vwp_JnW_EL+R6fg8Y!oSdABii$^^jqgi7r0vOrKm@D?k&uv3Sy`#g4oqtg zxKuFl%*51G&&oa+R^Fxo9_)fXKLXSsKmu6fnFH4>b%uh{0u7KBKr*f?tT&%GkT_ad z5kcG9+ks$bU_^{EH+dO5rVy4OtM&rth+#2~NlpeL`wnvH@y4(^eFPd1hD|GL!P>!1 zG^)(wtgE*H;ll_JhPNk5IpWMgs~Y5*JiVsof4}S^Oh-+xE}fkxt}!rVqc1#;PELw- z8#)R!^xV%@3P5fog}NQ|wFHn-PFI>4gE-)J>IWFAz^v*IUlBZoEX#u10h(ROhvw^K zWHDF?)Y$mc)z$6EvuRb`#>3-2t~Qyew*LG%XHV}M4am{7T=8ujhCSdljeNbP#uWJR zMwaaSbB(gYnqW|mjeB` z(h{)xyLfng6vZF|3?Hl^5hlapxQexQ8(6adeMJx$0Zf_)fC4xUV8y_;)#7p$)4zc> zTN1BjV}x=hKn>-su!6R+IbV*Df6NQpAC?zgaqtrR`2EqHZxa)B1OzLxWi_X# zIQ{)0BrK43vQ&94|98D17y73o1Ihs;D5iqs3^55n7(-MAUT0!I{C_dC`F}R-ApujOf0z3c@kH#I!GMy>WZwvs_KZZ} ziBBxot#3eHlrAqvdf|kIP@xCg{8K1I-NBgBp95QT?0*B3r4Ra`9#hT=Vp0~@$cwD> zdhOF08o@;T=X%|fU-Y!JUJ($8j5K{j)N@M)Z(RJq7Y{+_?#9szh*joY;DX}<)&7Bj z@^W$u&mf*(L47d~H1qlNcXM1Qc+qC_BjlG9IRsGEx7U9?H|ooPk#@25&>#(AP|1+ z>sv2gI-c-Gv!2Dlv_Fu$`?Lb$O$@>vyqZeLKq8tehyFgoZU zFG>=q6m;I738!UnIo__d&GzVvN41f_u?UCbZ3Yc>a<|y8vc>~zGMS4wifFkXV z?ArJ_0Y@poZq?OBxMvBJ&6s4o5 zk7BnlaJw9&4JK*lad1Q0=)Bp>hG89 z0R3h9hTl+hAmMe-o82q>KRvO|{I405xjDG7aDQ*<)6z~`TZZYVHYX-SC0b6(#oWRo zDmM0$S-#sw?+FUsKBhKVW9v%uCRZu5)?tUyyQHE5K(C|zq`D65Je(;iv%Ha+iAf_( z;bGkY#IxX;+50R9U8{Dw-K$B{ue@oC!0hC@vs2}J_e*30- zAF5q#l_{6>_<7^;{z^&EomS6l@E}Jpjax-x#;S9hFd;qLU@+YN*h?7P)^j{e#bpMt z4vtW>7H9jrpExv5P`azDtD#gT04(vl9#`;K#9Pi?F8z3$Z*CC<3a0x|R=q178=C;} zh-&l6Db#Gk_3Qo5=!A8v%nONH=H^gdgmY#SC369!Tgx`iU~kN-Hp?&mRQjHa@BXVT z#@oHRxJ1n-NS2WLjGbLKx8h?CiRbt$s=RY(&QPxJwbVA1jgj9F1u@my|Me}n|1X^s z5OcBiluS%)Ym7cGq!g$y9nN|?)|oAjnQCs<#RbhVH#c!b1&G4HU$+!`T`WIeGu#B; zR(yWdJvC*zzdT5C4?^b}|@q#c?4c3xx6W-yW?^TT4s*e`9Y@Tlj$kMs!E^3~8jq zMMf4VFiOQ#r44xA7bB&F>2=ICk0t+b3UB_vxQ+-D6cqe>n=oZt_pXVhedM>o?&`nPtnl!<%9p*z+$#`B4HWy5tmk+nvp^z6+CZDxNTbA< zuY|8M3CIh7Wa&iNZZ=YW(oZV^7|Im?Yh&^W|Fyh-ujUB|6#h{nDdzv*I0{bs$H~sj zOnsi>*Z|)E@)sa7BdnJk0fJ%k88={{5 z)o@oaL^U-4&+Zxt1baf^P-SqzfcI=*_1cH~uKj0*<+`fZ_JqqsgjOH>5dOQ2U4WCW zCv(`wGyJ%CCLu-hGb&yARYoRxaj~#8h_fmYu`AhdAj^E~R^|(3Qmm07_4Y2PG^ph` zgLqzql|QC^BBUU@&8TYH=OuKB=aiKDqZMq%cuK^qeQ!~U)K-U-l0BR{8v7uzL8rY= zUT%wDP*yh%j&~HQ*Tm}IM`9Gd;YejKQ8ml5TfuKYJacn?w8BFRo?l8b{yua$T{d7S+19;1pRRl@aehKp+j8hyD+53BUX&lb%xL1wmG8h^zynMg8cUtMIB&#bZ(FTn|m32{Z^ z4g!0}O*_79CwMHp9KYUj1K&kPd-bNknR#HI{!^8g3mW7PFIj`WPdW8>U-xMA9gm5v z5D+6(RA3MMPc8tTLxjA4s9~T^VdYw)$F)9BHL(MSPP37`*xyiTQmj{t;Vrm2!TXDU zE^?pP*1?Zx?O`4-c>DQ2OfeBYJ34S$P5!UAM7A)*6DK-hgbK>#Nob{>QypCBFi7$( z$N$Gl#EL|QUWi_ZaK&WXn4$7itk79u(e}N8arDzf3mke0tkk6Zpz8zS`CF?XWc5#( zwW=iabt9L2Mqj9{UE&Olr;!S~?$&$$9(E(XMq4S));IW3tn{_jK|t?4EM};uk9pZ{ z)}8%B$AOG)Q4ktK@kF8nwht)y51RW}%Hln(w{ZB=(;>goOCPa`oZLOcz-oNiQuM0 zg^F}Mu(;mR^wU2V-w&`S{CfYzXF3cz^x0LyCr{=VTk`0C(B)0c^g=0tK4(-K&wW-p zJ~xnMwcHV2!nZyrb(yR`)VmwOx}id;VnO$=~L9I-`*+DzPW$^|wQ)M+gr=27I3ntCw`%vk=`o^~sfg8gRH z&Q589o9-D`{CbuE7u^vFx13UcqySR&f}Ve7Q^J(E{~C4b?VqaXlaU8Fx>vi7rg zPyCS6{>C-)rvEyhZoOL2%V?v2{u_x}&XIPZT;n zgPe+1FdLb49OTtKF;3d^Rc189OUNS=AItR!vhWu|pmc@eJBI&V-ttT1|7qLfS*59md>F=-R7dQzd(l;&?4-FI8wKirWX9y1VDHVO|UJFYTBY-zD$hipj z&2fe@@{3}|>N#AZjoxGQzmZyQelhC$lS5-N4z9L-Fe4gL4;&;<9_tce)bsg}!cSye zlFolc`4)8HzYtp0OzSI)Tci3^V-c|IRum9}`UC>Z+KU|yi<2U-K+M(>Nw@q7UFqz_ zr9YP|vcCSP^?O&FWR?=2^7Ti^TKH)_d0Fpq}tp0#~xcMLE1nqa{IHvF>T!(Ciai|$0N3O)TXT?v+<^9wYgR=XH?YUUN$H z$5(FFHv5@##LFquiRu4zjD)b(awGdcD!`ehl-^)DwP`@;LQ9!?8& zM1OK;*IDE?U3y?6Nby{Zv>N0B7TX-)vd$C2OS{t=2_Jz14i3oell4xu1D~$FCVgjX z)6S=_QWoV_FOH3Mm!b>_mJudq{lH-MDGHV=2DLI?2jMquvJX)jas0Y|#`6z|HUfpo zds?(BW)Ht67+v7cqs?}6<7AL-Ox_=eJ5CaKG*lT z;^7-1T=8*h94TvOZmYJX&IxpSx4M#t-fZ~RtAZ@)xj5;O-KTn=DL>QqSkib3J z=Wur3T$y;;0dn%0?%XEXOcon=l7$Eqrh$Kl2NYc~ymc2XZBF`BfFnV`DBegU5p-WU3UuIi8&0$cMNW0lu2a_o zP-$%?;vuo^8t{KNu7BlEVP!b{R0(r5-ZOb!t9s4S6FvQ=p1eiywxGx1w%;v+9fvey zx;wo1Exoyv9j7hHL!UQ%Bll7OUQ&q2soJ`OLjFqz|J?a6O+#(12_fb>>O*yAx1lX8 zwL3tY5uI1k&1zRAob;%d-_Mjk+u*_>Z`A(Bt?&x2F-xu}Ny2vDBf;A{l#{!+4shUQ zN^yz;Wrmsm7foLQ6j#%9O#&o9kl^l%TX1)GcMB4n#UXft1_*A!-QC^YS=`-WA$air zKJQn56-7}LyWE}W={|k>bkA?WtKpvu3k)~m$vqk0PEEJ;!nqq7C1t_B{M%P*3o0ZH znttB#3WxZ3V3@N`7?`h8E_I7_f?56XLlfr+&?&30t>G@u5){IIiv(%6IsMyJ$mg!t zI)p3z7sSh1Q%pT7raXd~ByvPft=&-H$M(oyZ(0>MdpKrLRg0zqA{Swx+^I3uh5!GLJ{( z#!E1%e19v2JQHRrVEt)A#{=^S)(LPm*9BD&78-ZZpEJrc-b)BI5V(q^Y&p~Db6?z@ zb*PZ^s#9Ynkb(I%ql zEDqlZ2}q-8qCu=kp*Epn!>_ly+GcGNsusBzC55fD-TXv zyI$ROnC%S@NgscCCg{?t;u4a;IV9Zx#hSNe;{^;=ln_fK3eH_ z4YyQhZt~Z*;1_alF1`#uB2pV2BV|9OkE(1sXB?E;Cj9Dom`7fU7m)_q&cDr9Xirn`|KaN_RozY|&U?PEZ}M%Vx$|7_-NkJkIx! zFdVk$Z2o@ukiO*|UvvIX42WpuB$vUJ#8?rjcOOuHC@a%{*QeMLKbl{0;j~MG;X}zH z9KA9om>u7f7k#x+7~|y2=tsetz(ethUG)~bnl+lcQ@6GHP3_&JZ zneg`PjE$zj%uxsp*)AkwIoury`eTQw4_7-#NAmRo1v3xNAzqRtQ$Q%eas5<_&3|VE zE{j&NFLG$t+N#)6I3+#3vbZ?=t-Pe9vdmcYl}x&l$8gMPEgUFqjmkysmX?(*1D2tG zpo@T7Tv=(MtQ18ft);06xt=w%sAZ2^P2*vg?G*Go30@pD@_*A@gqQ&@DLW_~&X{JO z_O`VuE|RWI{%XRat*I#qm>uS2#V ziY$!1^^lNmqO7z(Ba<-TS>PL*+l*|h;Tza?B_%4Tcwd?mB29&XGWc+%X~ z+CJx~nct^>aTQo^9Z&}CZ3h%CI?oHneCt~K7Z#)!DUJy)XyjNnU|8~K@4wD!R^cO9 zEzfW=yBPL!Nt=_n^5lxy@G8*B@U`l_NN{anx?b~o#Gq^uNUEPRT?qiJMT&H#M+?oQ zXidduNo5E}F42wYQzGtA;uzkl=I2pFcpWD>%=l3EH6A*tT?0jN!nU!U-71}*!=5Of z9G176RI4xrl(Hvl0caBMPHAJ`t8opg>nB6KxakqKL-PvRtq0;xBqjXcU;_iAyKZI} z+T7Rupa02AI!$>?-%+BKwR|^s*$xj6F0-pTX2+67--ru_LobVDS;mjEmTKI`Nw$l? z9NE3>c8rgPX1v1Aq_Dc9@$oo|C@y~~>?>md^|OdmT-mMlr7XpyRKl2Qimo)d@Vp{J z%eMcq*Oz`8$;`HluC&-xU2VpUW#w`HaaQA+8mh1)z1J(|M=n^vT(4OUEE1;YFixvp z9dFzzy%cn`>5~+cr@mT#QdK5hCMGFPzF%Xs^K+iaB#J8#!!rd2N!Y*N!0_(_XEB5? ziJD5)R(?c-gzjNq+)O^UDL~rmd^RZfmrgvVoy|)032;&o%d}P?pH8!VS&%`y*Z_Kp z%YX*O?6+zHXDAH=kDeKkwiQS9LM- z&`N!X7P85sn%n3=8Ci`Z-K|9_oBGZN1Z#K1R*DK93rl}Chuz^ufueA|GcF-KFwr_g z(R?OHm=Z&ZrTArVlh5VeA!sKs=XQjm#itC`0d7F#mUwzf)uuRGu|81F|xPWIm_6rE@sCS=( zU-63T2X%NnY2g8d_SKq4u}=I5%0Ot}{o09=i#|olml`Ow(z}D&))*l3&J_=p{QCXU zcLn|BoSj<3s*R8LaT>KDfYOr;z#0lQ2Qn@f<+J6v$lX^%x_n7J5( z4VCuv=K&L3`PqMK@%QMRY*TRoPO>W}VyG(r9|K>>fR`@#o4o;aS-Sl>Z(happOEhI%F>q76>V&z4E>cHvL*o70i5{9O-5c; zdm1<2+~9~Euk%pLJql9!OQ@c*=O$19ZBE7XPh^VRmn2SU~Z~nMCjB*&CBCD zLR~&WaTqrPTEY>J`S!Tj<$Y38#2d9*Pj~Zr-!+v~QL&R+p;gCjKkXHF?F`uEUn4(n z?VyP`8Mt?f3S&}{7-+w&EQ1sWyf$;zw?(*Lf{J6yC8bPjWi4l5L*484g@3i7XpYH} zqeU`SaBMTzNTFk=KF91f$9(?nF1g3Q>ninF>b|vg9y6WuhEFMss}Gl}5%2%lJ|XHP zKAE9QAAb;sSc{7IdTZA!)5_=+v7f$2kAi5g&k-8=pVy6gZ~afjbm`Du>y$ayyIL@2 z^!E%2o*Z&~72sG_?wWNjQ@J3si&xp zWYffrrV+N}DgMjU_cam%*}2k2RFv&~Awx^ZR)bgr4>>62Ot7P&NG$hF3OJ7h(BF8Y zAYx?_53hTCW$Haodmslyjw1SsD|Ebv)WxhzjK)vS2FB0G@Fu;pGj0>*5-Crf`r5K~rIH%k*PS5$XGE<^!fb z@=jou(IxpQZFC1K1f-c+O^)ifQKN{mGrlVQLN|68@JaxjpAU}9FPi9hjYr<-dOTS< zS7lr!=LX`oy@US_O5+`G>i14K6mCGR>c0~fX#A*FpPRdL-qv-Qd5^$BSO1#9U`yvH z)*NH`1KHjS@|mn2K_f77tT*o$N`OE|_`MJLx2qW*)Vm+97IuJD);EZz<}6m68fDNtn?F16>HHD7>i>o1V;7e$Zw5& z#xS2VeR7|PqB8k?zFfsa6FL?OV2L>At8&Y9##1?paW~sDFX#;15j%swyi`G`VG^0W z+e*%amz+xlWBX33EQ8!`dJ^txT6VfMgJ-!4nEGno;0?(%;u}*U{yt-opcrHH?YT2Y zvg1t-v8!?a#)rh2a|6+x5wjIZ_t8)d>WsH+=Zwap?`-6%d3NTstag&}oKC!1O}xdX z&9TYG9GnSxYo=20VDfLPI+Kgg$E+L2Y<u!7zYt441%uwUr@7aiv)=KOWI%9jCZRZ*+3pkw zn^5u`e8D4dNaSR7(_BD159%#8sT>hG6bVsO@&U*P0mvSvXbHfP7S<6ct0iG)_6+01 znPlByt%ukQiq+6j+@yKBiqvexAvr3pO&Gaa3P+d5DRm%iahll8uOF_|6_Ed0ABcrmS5;Ps}vL zu%VO>h=YGc1-5e0pfPC!%k1&o@dgo&J>E`hnJ}yjG_k@Vh|B#+{ICb#B7A(drootj zI;DJd?rj*2Ucq}bfFM(eU!kFHYC;hGW;zsH@a`fpwWo{SZ3&((Ka0qHTEq!`?h2}yNc zdS(TxPdU~@A2|~fC6Z;ZzB|+W=Rv2i9;%qz$27x`b0gw!hxDf$^YQzhReb*3U$II0 zF2z*zFJzn^<-Qx9Tuh6=cflQ3aK=S5HC3@$XVoGiT)!XI&#{72<*#!a>)-|PMfVd~ zm=ffVhezGy!lJH9nqivhGJ88eS5&=Kzolh$9OgY@AfFbSL&G7qvXWUW=%RLb^*xFiF-`-GC4v^rG`4&MxrI139> zcBNwNxNLJf`Qm3JPYXUrT1|IFsvu0Mj z!cpEBZ9=GDjL~vwPSMFC%CC6yi2!4>m{H}o1zXLvixv6|PlaA4wKt39O;Cv#f;!>7 zY$Jl}hzmzn#vxDCm^0B3vAocQb6=z?Z#fO}tS7pY-BAv4iGm)aBV})c!f7&`^>9Bd z^*Y;dN=6R{kYQ&KVk~-YL%?p_2iwjvpNft{$gf zO4|qzatw&cJav$;-3l&~ly(^yE@Vvku4s-nzre8{1NlOLf5(`#a0f?80WWK!R=C{Q z!=LIXGio1lO`}KVy?`%&xa}1V9}JZc3Bc_eAtfc&SNHw>d%#SIV{M?ke-?Y8&|&6E z$;r(v{hBN|@Bel{Gv^XYlzsPQd}0EiPtq0$=TZM;WISDMRMC@U$srqW_~5_nRd{UV z+NhllXdkzvXC6MBE!Q1h`Cyy(Lw15AkydoTDEDN>( z{>7zIeO9pfBgnUPWVqI_s0M>-md04{!OKM))4N?lrMO~pmYrSLf15XS&cVHxfqCb^ zJffXxM$!UjsIq>XdWc&3u8EZww4mdUH*LJ z@%AnGU2yyQ+%dX{91f3tKlv^9M9E8USTEr%2!Fv2k)5N)K4~=?@MuRUH_a_%;sPmT zMwNE%_B1wrgmtbwT61)n3V*|h&h=ntiv7)^%$z?Wc*<=hh;lPve69J?@$F~XfK?U~ z5Hh|cR{-Ms&6^vAZ{G$Os@ic-{R4c?FTWEIoFp^Te2mO&Z*5K8ZN6+lywhOme97H| z;T$}qJ~@FdHXD)n+PjL~3Sy^W-ux@U#d>S}CDot8Rb;7jC@?tq4sXzwtmPr6bp3dAi!f;lp8Yf}m^BS*s8a|^YY z*`=l7Yu96WRf4YnOq>M_5lTx-fj1Z(;B0|gb#M9V0B|rA35H(4XBbY|?^5#_U%sw0 z>~{|~w>C@bc3K-|5T;RP;1#x}eqwM>1R0u(ZB^fkNF^botj>oE`#ft4mseJzHaWx+ zvGBI+oQy|BL96>J>cnq`aXj@&-saKvWp!>Tk98UlOKRq8YCDJ1d~WtFmq#3d@0@e6 zk1(w<`(tIzY-Y4h5>HG`Qua>?Ki3YAfsp^WYS&_kGUPr>KsKV@w~E!Ak9VEPED>bA zV(y;kTB2}a(ug6GNq(GyNRAGHrK7*0MPr3a#$dTasrafC$gVZfmXUJ+JEl z;l};tDz{&$-M*uM=kI&2W8ut%Bj=rpj0USt)=<)Pli8+lG=xF`&>D+8&b+{DC35-)qou7{Q)i>nl1(D0*FT-6P;8*wmQh!>fHp99p7U+~h z4lh-H;Vz>z0^pZJ6cFR0Q2g9}LS>GEs>Yf8`f`lv8P&@-s^szcz&3k2qI@U6dk+ii zgXWe4g3DA}32D+eAYYPnDzO)b#GhjgqQivyPPm^>3OhcyVUN*|YN4)PVYtx>G3tCe zR<;~0x71t=jHEL>%V-6N>K^T+BXNGvXh`7zy|jRjXlgwDdP0XtR;v&Z2A|xjqZxei zA~Mk8Wu5E+8-Muv=T$oKAbYOOIkE^~r}4ZVRCUt7&u91(MGl40L<1!ima4DWjaDao zhhhCHI|y_GTj@vY`a>>=65>Y1p?h{OR$rix)C^FylGhtia~ANM%9+|Nl~0m zVp+*7KQEd3=xlmvBrOrgHK+w0tvpOG6|Dt40kjQ1?CmXiGyyYYk$%&sWZcXlw&c6m zp9;n3E69Pxf)m`}tGtCOf-vzOO%2|Ij_W!d-T<5j>BM z;77iKPnVRflE>GMy=f?}9gDk@Bjp<5EAJ2Pz3b{=$H3r9?aYPzbR6!b_y_+7*QK(v z#+M(nwF%wzqqvQvwGQ)t+|C215+52%BoJ0-(+~ww7|)ajm^J zRwly!kLEFrCd()^G5umrIu{cU&@qv#@&4cBi3P({`7;HiHh&Jp57lR717LDzi=D@r zjH_84GHQ18E?U<`ggFw9n@9jGGLj9L#Z;A;n6wOX`0E0^X#Ci=N;DGm`pV|sOci#K z%jk%=1(TY7V^zXIp>L#sdz!MPbr5A1buP-PVSr5%EPnHeoP3G!C?{Uj%!Up%$ht`_ z5>ediN9gt-exeXC%=;2Z@~BTF_LhjLqieVd)2p^_?9PFWj7kl4%@oi)s$Ev1)&8Cu zzVGxwGEyjcB>0as=cfSxov%c}*tl2&8%BC5>CnAlS8{yG;mx&EYYv(I;%L>B>D)9~ z(to2BR#q-4EA;(FbymFmQatkD6xZMq6H&0k{^^P)1)1xdLJjx86Bt#yXg2&LN^9Gv zsJ>1=4wJ!WPcm74C`K?^;ePNbD_MK)ucSYrEL%kmo;+AV#|tgoJsdcpmSEmSYXWL) zFGR1bTw@hi=S$X)pX0;FwPx(BbdIMQ6wT(^F;HFO(-J)BF6@z-JnCS3SfGNNaSMic z(?9KBU{@daX@GQb%Xn%7@2P2O>^ic2ho^MeG}kcJ@hK?=kEq=&TF)DoKdC5h>Jcu* z+o<;^xb4I^0UOv(m&sP~u)YH$x44d9c2zEGDhG?-*?I^9ox##rXv5Yj!%wTb6wT>r z>bHGCIjnE{^x-*kw^XET>U+E1abaf_Y~bN122h>x$Az z;Y*GKP^?tmwVxe`Z(sg94H(=`GHWT9R22U2nM%HB!6z#HG2cB)s@kQWRMw|Ihfs!d z`s&`X{KgDISs)4{shlnP(cvnCa8myo1iK#KFZd+ukZt)@zbpT{oD9OKLtw+)%?Gbu z=sIK)0Sc_;)7Z9cliZU(yO$X2hDfy@yCux1rsr|LS`#eU=7;6XME&4;a? zoSUN?7(bf@J^P9EN-boI8!B?_6J*lljOEW;lNBDaXX% zJNkaPQ7HK&6M7c1+K=PZ#$nVeWTBwtkyR!K($7jhawo37I9H>WZw6;HUJ+CaJCw1HCI{Y;j9{IYpAjMH_EOQ$us~3N3JDPR4{L~rI~`~INzUf z>#37pg#y~GtizUCeCdgWz27g`pg`spIT6b(Y^b%V*im-=P$6^1_&oFX^TrsO-6>6L zl0l^^LFA757oYlYrrs@L?_xDY0wp(x zT*FWa>vl9=9-^bD;HM9bx1s%Hr>8xQtSi{d8`$I|A~*GOYT{yUOZANXn4u1P$0mEB zbCu*HEW6iNt8El}jR4WGqs&oV;r};E5HNXhu`g?#!Ozm;DCFe-t+heyZ#NkPuy#1^ zr*J}`s(IAV=ppqBg#manJM<+!cyd-e@FoTp_b)#aZ%Yv9gRVTBb;KSJl?H zveaPMEBq7ci;11BG4SP(Ej_W+)L~109XqwEaG>LmP1D#A%_Ngh#|L}ckvkQ;WlRbU z59%l5H&iWaPh1h@0zwIq*J~?bcLwB91c#H!#55C0F=5 zmj7uj1|@dPj5ACQH33J6C2KTavWv`kepoxib^SYA&QZwLHCKFH&Ea^75#V91w9SF= zMxOw9n+|2KoS11*HTi12)*}Z^eV}b2ZfT(tFpuY4&tN3RtYk};?{BMk~)lA@z1VW$_>Cp)f!2*H-){%5QG%>p+dRY5^(pP8vWP`Ybt#6XF$ZbruyVk zN1qx&PGPf=Q)6`_VAF^sgdJD$Xz~ftb~Cggr~lE(d>}iJ9<3YJ4xy(r8vS*93lJDC zb4?FDfz6-=e?_6Si_*zzNxreS{oLKN~>Vlo;;?n~uV zwzvhb5AaVqu#s&iZ}T#`B;pjnv|IyhYPh_YvrXZQAFG! z$jt4@G_q2S+)^@P4hzq*daWOBV2f&n8wVr4sC)}f+ zU922gA|<&W?WuiYZsKQg&)LXwf29U_@*igq>ErLvZ?eDKC3VDMs?0OUD==}ct7+YT zJrDXAWtI$XlhbCl4nke@)6g-x_C@M=IHZF1x6O7%`xSq#8s7; zsmdh{V}GOA8E3w}kCBmL0t=@+Cnh@*Ys7yahs~P66U08m@swcU1`wBPuVPR|A4+8f zJ&aGOYv~CpCoVSKqp~tbGL|!d^Y;AQ?98NHRl~xPsb5OQ{cOMr-n*Q3CxsL>O`coD2~BQwsYR#aXl3{Wftpwc$&(8CuI?;!o)) zsjefebGhD!5sR)`i%szL+5FRZtUCmvZoY&n$zQtt22~?EeEn!5zJBs;v3VxWXtWy1 z>LcV{?yF-3JyRtNy`c0F0=TzFD@zG0h$eg5J=chSg%+ZGbVrzwZF@5A^C=4a9OH)u zChLpjL;^LiWpUs`9emP0-$|S*xsx@%qkl^QMO1Ub3BtjVsW$K+Lm3MGhRA7YO z8QrfDf_@MruGZ!d68A&VAYA0GMGKki8^J*c{CMLO6MK z*X-n^Ne9_1#Z&GtBLwep5$k?fxZS>E0%aBKeYHt7nUYd-aAbP#>vnK`6}M=$QtAva z%J{k^5s{4!QCqlsTnKTwREe_ci9$q2T4gB5MB5@we+-5{mlto>RpRh6yp~2<_Y~!V zxUs~u5!_v~Bgb`^uAyu>v+WIz9AzUfWXr?g_K#?qScsp*CrW1D z>>>%BxG_z~rS`dGj%fUTVDkjQYJ~o69tlL08t%h;Y8MF88-1|IEEjy9S>w1e4i1X! z#~|lkpyg62KviWxFLdtvTxM~4Mk=d>X{w=TB}Q2_G@#n%!f_)wKuU1MN}louMHka& zC*)pS7=;K-#mN5uP5v z-;J|YM;MYOP~6|X&(2|e6uQ@gibx3m=7j>0noXVAtI9Q=cHkJPVEWiPfYT#U%kjd( znxGbLFdR6h8!;QZ_p63DqelL`U$qRSi^EC5THqG6SQ{Bpc`H+IYM4JX>p5&^>Y8V< zJIK5}x~R3p@_vhPIruFrHRHtpBrW;UR=cVdt3xfsE8EZ`^M_gXsGh|fsqx#@q1B+^ z>54AEoE8psZE_qe-v@P4|oH`o=?QGJ4=F zc`RnQomYw_@TL|=iWyDF_`YQP zXbS@Suvl+sDiJ}0*@DCyi7hX|^*)Ji*lCwuQCTnYPng9HZxklrRBS>WU^}V=!PWgvl~KeS%W1>A1<~F zlYkM)KrmK4k1DIzxKre^*OmI)(6F?bOivl}coM#n?2a-|9~F9XJfL>KIF)e_lA$Jg z-m)fMkV=>;MKc(Fa{#Q#oyFIJLJIN8_bVUATpA9#EVhHwY8DJV+gx~TVMN>qy~2lN z?N9F)_CZKmVXNkZ+e8!r*b7#$y=f#|1lX(^NtOB& z_yH80by*outfb3_l;+A>PP>cW#hmmj_#^tDe97>#AW`%iOG;9V03~G&ymh38fSE4E z{(9SZ`Veh*m>;>6W8b`mmR@K`k@6VMGy|c0*o4<{AqpS9{TMssZIqHxI&)vw?-Eo7 zmkuA3i&2IZ=S7A|i`8H>x)HCc6_rSA(&D6l_!cmkt8r&oiSJt(&)QZ2G^q6HtiOY) z9JPJ%u;}d6gd==of*#=63L;hIsVuexdCqk5Zrt^ zG6*3-krDnLe>zp_8B8Iw{RTfi&~aj8aqGx#Tf1cOn=#Zl>wz-fkvVir1Kk56H7Z)S z|33fzjsFShJuEAH_7flkZ_cpS2E9gm&*2`6XpDC9c1ZM(3=BykUO);(w@Dhwe^R1gL9%4kR0 z%M3J}z`$t#oRF1W`Sb%Z{nz_Ic~p|6+TPvE7~#%WiMLEk5~p*qzs;=GNp0k6A4as0 z0;a~$Hfo0Mc69N+0k18@rFMN!Ym~j3W&u=uT;F%Yo|4oqms?(54EbI5M-&;k9|8EC zrz*%6T(P$q0=o_%L$Oab^t_U)t}F+@8+ezC^D`}1yHUwujX*$$}M&U)L# z;w;XHeo$NkuGAoDmnVv!^)WPEC44kt#%Tw08?sZDs!L5yY4g;WG=GIw^h}93!AsZ@g+v?0LdA!NXp+zZ z*k&;gjKCU4gr< z#enTWbRZ=fgR;364SRc*F2;)OhNl5Zm*{Iff%*J9m;{vEE=5LO&W-d#2N?wV3?!p0 z7(SqX4Uh6_C@a$EtZp)+YYm0lCvfC54OB2|YRusx9JmX|t-sgT^w@$O{iP!AB}++| z?2G{D23l%d<0tAawt6?hPQ9QA*`$B_0>tneWfKn}auc(9_MObjfy^8qkyLD$AN(yh zhRHl$e&5%u&MbngfXvBGWBL6R@BL>RZvtsU>$M~UO3;UojklD}a9DS`A@b-jl0Ok| zS5a^lVp>#B2dR+&$*!9m%Q-jR9|nl%?K?;P($!RV&jLgNZB;qQA`@HqQ*7*T&D zYDDc=nDMJi_Bg|)eS(xtP%$OVMKIQX;*(vt=hT5 zLv}4k)54b~Tu5<(eN)!VWt#sQm0DRgS6Wl^C7EHsY|+w=Y4#>m#H+Rtf>TdW&Nh}Z zfL#b(ZE9{mVyR(n@j+S5g{gZzVHXJAhL2rlEQqWHqtpY3ZyaKq8_!PQm< zYjwru8k(>CJ^P@gS?KLH@SIjt;m^%Y!&PFXQnVyQ(C}jWGLUj{CL-X65q9B$X|$N% z*OnUoa>ru(0-5po2*=s=m8er7=95DtRO8+K0;Ey~vB>j7HptTwDeC5%jjQ7W(`7^@ z)fFc*2#%OZj>@_ubz(9Jb-TldXBv7WByo8SB#7C~J%g-(C^#HmQ1LScpTbR8f3Wm< z>2CaTpk0msJDBon4|8F@cUYgktXbK=4|lRX<=_o${4cFvZTk8Obom)BsqjE{~rX6_^MW=pP+KEJL=^-vv^)Dw%mxKf=GDU&c{Vz5RBV`m6K_=w877+U!JB zBMIb5XDcm9i2*3K?_shXuZj@j%CGlZYyTy+YRe$Qxt?)6N|#*y`0CKLd>VhMuH3$} zhVn1rs%y{RZ{~W>hkin^(dI5YX4<3xQ3$(?BAhUT!;Dtio8+t z@d8%#^#O8$mWwH8wrW53Xm*qYGT{UyL}8AXo@qdluF{T$Xb6AwXiC4%*0C0@gW#2z z+$7I5n6d#J?JfmyT!nSGr`D*KnvikN#q`r>uNPg{75-kR{_o`Y!#-$8UV)fcOa^`Z zc#^Nicb zm~k7KM-EH{XQ5SHeiSJJ!1X)+zN_}!!dJt2XW9)7oW{>Phh6^$rY@E)c_Y~kdW@qQ zU|?{oL?!8})M!7VVsWnxWTq9Wqy{p*;6TL`cwk^^7fUy6!R)x7?q%&*SNSP{MRPy( znFNu$fBliVpC!RhsX<8d(P~XW1|juJ=<q=7n1g= z&BXm){OTFoN4!v`zHY7*gDe>ZCc7WuV{3+tgI!gD$hk_N&6%gp*lurfgMW@s?)O6J@`sJX@?#-H50k1UEf2vm`JPQdAvVG8qn~MnpJ;J+7 z0Yaq!LCuc9;0!ykw~oRWR#sJGW9iq*vNA%_EVBRP_TShrJvLt=`7fSFqy3+e;e>wN zy%Qn%v3<}BUb@+_IUnKnZ85#?-TzkF+ui85I$;h2vlRl(P}W`w&eo2&<61s)rBsc+ z?LTX#as1P<>geqO5MlM~aqQxeBxA|>hbZ4VAf35N>hCY?NAdCd^^`e~9UC1$01w)* z0+5?@nhF<3EqMz%VGZOPyvKD4uz#DP^k~@v7zZ`}IjfVCHat0EZm(0sDF@Ms7UrRbzH_{{q8qyh6N9 zX2NA5-P81|zAz#Kb>xhrHe_?kOHZ-Yuo_24Vw^8dU^Kwr7l3y{QsH^ja?of+sUnq0 zFhnSud)iFfHF4F-%IZ&gI)y(_MCIb*is=I8064wel9p8(ZOqjJcM3LeI5=^oWdNf+ z-uhZq2&QRU)J%o=FD40}{w9)+t~L;q5q{~2KmgHzS2nOmTBswtEs?Yw?3=Q z9);P^Z*7Rf-^xy}mny&8RXZ;4tG$wtkPx8q+q9_^8Liy@aG-Dev?4e=%WgTD?s+@E zs9n_=M0D}LBKPv!8rj=VH{g$5nHvW3VZ9AX;j6%{Acw`7lyaozZ!@`{#_jKMwf3bl z&v?h7+JHa%{1p*~R+hwbPsH{Vo4F+=rdkz(BFaxDxg(lqsXA>Yt%BSUo9r0(G5Qx% zK#u%VdwZ&AXlDG)k5sW!b?vY`L-c{_JV~1D$Z%gmRM#}4TdW9W`M2faQ;yAPQY3lI za$2J%?&-Xwx8U21Fn6grJ_DiVa3yX4)q^)F8WHN#)p@3w_Qul0|5g>{NqGa7CA;r- z3e*`CnpwhLx!A77O{Wj{N6O;`B+hKVyc}SJMUFqZtFpQC(&Rkp)(!eEf3rPrJ>9tQ zb$F|20`K#j9~YsK^1DCJ$g}uecvp4aZ#b;GOu>@A{{6_(abp@`XeomFbro6e{U5TQ zi1ZM6PklQetot-W8#fk>g<};6CVc?}yzog-PZ$xP0S$YAh9UJZle=qRW&T!0Lsv`Q z1OV~vJr_hj?n&|2Ya>wg0mQj?nZ6qq5SIRU#Mw~=nI+oAhk_J!!h-qK*%Xcz6O_|1 zfc1vl*CI{e4_S+1gbeiQSU0TQ@Q9dQ*(IStgi5{^`m>MhU5MX@=WEWl* z#JnL;DanD%qqm2u@1xvTAa8)NyJO;u{-cseB@A%+ve88@t$6XrMVn`0AGB|pN`uR! z`6+=M7OO4x{^~Jst?wt;>&qz^2l^XmDq$k!$G8LZ?Z!SBfdjVS=F7oKLWi^5H_!oL z)GoN$WEO?nuGVrvH}j-ZOn^~j<9bCr%*6SD%=E_^ngIBRda>s%EX?T7{V_LBtt!15 zIWV}o8NSB3y+NQq&W26ijx+>mKc=2h$^p=cxllLEclvuGIw~y_7RzpQ7xa9)+xwCf zYH-<7YHaHxX=7IBS4*HI8zNu>@GOOnakc1*{3u;VxF8P_f(hdPuLanNDZRM90v1m- zjRs_oVp$FTkx9hr^*jIoo4Z^Ba=Z2>x}xhzv6L^i>$KclVN7E63}P8SK3pv2amnH^ zjB>~B*3d3-{7mC*=XOIWIDsiRa)=Oh{RbHo&mhDDe^CYImFF3~0BHzK+QdrphzjKN zCY%`JpCg2-2sMG&nft=#7a^f_Sju){WHl|{5&v1D0D%6PwOcD1tyQ~UkCk3iOm!^E zFu~Ho)S!C_3Iiu06CNGjX&`7O@-|CmH`+|5-$5>!qL3C)t46eqk_GB2H$fLE;ntk&??6AjR}OYfRn@|2 zV}`<**&dN3EC)omvs$-!9Ve_hUDb&BM-4h+2Ey}CLW z3u!iq+67v}R=qAYhmqdHhJ62xqP;*?PVb`5XaofSoz|oXvm&$Tq%c4KkX8`62O9uv+G_9a(0s$! zNLFJGLJC_;AH%{%T1&mIT$~Sp3z$~=_Cj5)EG$`EabHw6f(}Bcqjpb9Ph|DAH0IWQ zuNMJ6DAWIxr-e#(Keg-OAMP;JTAAG$dq#mzilEC>I!VxOVwCgk?r_tzN+v2jGsU{n zq4VjWDpDz`wu>U(-Nrc;c^Qym;S=z6#(4?>OQKoxWz;Toj8Mr-_7xi+VWet!euVUt z#d^K*au$u)Pv&|2I?c>Pu z(X+|N3OK_3mpPLa22urvnx@^Wj<3^>ngxRljeqCH1hi6)u zC*uAS^C!kVSt_!}(F~bY8>epu2S^gLdk!Wt(zrcrh^p;UXe={gPfl#0dT90SlHUq? zF{FeN(sK$6_0+H^SMbSEQTK*{-Yg1wK&ceRUS3>bZ&hr(?uvN7(~Io@z91J?jV}f+ zk-bUM^YOd$TOuq5ri#5)=j3D($-XAlC%mNl=@=RsYIg-Z*WB%Jp3%f*IYuN>0+DO@ zopzG})1$sM$0=1AGq2wXyt4qWKOm*zSIZ}r$*S&gtM>K(m`+zr<(c zct{S(m^shH&I|n}X~}K8TTias=c#0_3wXhPXsq-bxOoVUDiu;^!e?~90Y2u8s)c2g zIU|mcfFZ-14K+U|^!Hz*Oo#R@Rk5i2kMZmbnd&rYl`q35h4LX7fb^2XKB2v83B362 zDTY`IoR}_pX_wytsCFWzls_g^rUvxCGf71d?b8?>Kk4pk~zOfScW&UY13B+MCt*?;^e zwq*HuqFj0fr0XqSqNREc)1D%KASA{qrxyM%$rOdW$M|&L(|`>F<2{b(CJimY|k$3V>g7m!#2MbHlqDjdGXbxGF7nOPK8$ z%U7W$K5g&dPYmjX+{L|DPVbz#2nKkrgu|1q#-G)+m7Wfmk>#pBU4$3`;hK9I^+&y* zs3MMM)`ZPHPtA$rhn@qon^C^7ujP(xFF>Yq|QHpzB|n$1}l^|_nn4n{)OI4l~1Bl9z3 zdr?+>VIMSz0d{59HaG}X7XLN|Z_Zj+jNClWCeZJ{cygy%&mJK6sZrzwtM@0+K7d{n z>?4|qD|ratfP4f`6p%hf(U!V&ReVtAsKYaz!EMQ)PhHwF8EXey?poWTO8sK6RGj-h zBoS+G=5O;hAg6U9F!Z2?0`pOFL)yh>>)yV?cls^D_>EK*laLTCEwIR9*j3etCq2~a z)=16`{5UV3TVbwp>dRDzK0k~T45NOg+fn~}e_hys8y5VFC-9%^#LUhr{bw2;BV%`H z?(|^T8!A21-u8BFO}wH2{{#Nc`xPU_w9<9PU*8=tCv+S_|6!!#IgKDy))`V)QvHLE zr2fN@ee4IZyiB2QEuZ^y&U;TXrdm3Tm}%b0BMTU{v=0E<$%->;N1Rf8 z$e0}+0^)NH31mf8z7rn1SQpHtW?R@k*OV(CwQ@%buzz-^MNO9L2Kz2*(5b$Ys_TPW z4-Isv0)RhN9to<;OZ5w`A)n7w(juCgqi5}rKeqn23+?m^$u!9f;04P7)8RBo{I6H8 z&>bnwfGfVUOgqAi$QnZquH!I+q)kAkBCY(BH?L{$fC>*t6McAMDViv(nS+d>PuIZhvB53p(^$>Oq_%sX{=G|ydCnuPpOj97Kk zo~wcLc@|5~T3qa1=J}M|%^w}7`|=<~B3T$Aw#|5f?j&abpj4ehX;Z>^t;Xv!d7WZ9 z`vHQ<72J2-Wxj;e}PUMIK_|Cv0${1t^3yPaK7jua&p=l536>Wtqjh! z`s1wCaF1N4LuwLx$flfENF+Dzvlx&F&f3vD1_S4A)@lFC8rIhVw%GleelL-tJRX?r zy@&2rG%J>%tAV(CE^C@S${k6kiF1@2o}0&rTRzsNp@LV=l~pVoYqd2U7b59(7mzlv zs1^Bo)7JJtKJMA6BiP36`SHE`#tBCs{)s1qWsk;N^&Nmp!|b6ht5&Tv$FiBXMi3S| z`-$&`cv$xL z9kSsIe3uC4b2>xGvB+HeatNSC19j0v0okaZMdWl=RmpnbXGuUk&9#{qu@Fo+1_{V18Utf#86R!`xs1wioze0NPAa z7U|;x$T0w=%p%Tucv(X(yG!Q1lxtRwFe3Qff^=YF;wVaJV<1p3ok|cZupu0j!P+$ikQQ*hDIxKaZvpD!4%tHzhcWhP)yT7dPn;GnHB1koEi<+l5{ zq#O~sBKEfZuPRr6t~Uy;v?ajFjLl%wzW?SFdgKV}M_vlDW~rx`SB-h64QI};O^U4k z#R3Fq++`7+TRGwfbI3I-)f9z%^Q*%?T$x03^cmyzvE+$F5~ zF|)Y;kGijbin9CO9TOA@K}5PiNeO8fr5iy?QaYqTni-T5kPxK1MM}CsK}xzCq#LAb z;-2yQes%9!|F!O2cilK^ku&eS=RIeiy`TN;ea@a>%m-|I@HEJfv2pumNjFGNOdSdG zQ7BXZ?YD5?eeOv&Lg5O?EiimH0%Wy~KyFuNAX^nS2yVn2+JuSZY*mqter|oc%NgW+ z`2#>{nCA5qF*33ss|ulqc8^J76@sL@R)-4VyHcY?I)Lkx)qD8Ma!Hc$oU725Fmat; z@N1Fb+_dLv#NxGLp7P29ibt<7$IU%|C2O0D`0No_Oi1V#Qu2PZkXSm#)d^M^_KDqy z4aC81>`a7X;PkN0Ky{K*sfPxYhP^Fj?z)q70;h|!#Yt?p8T#*j`BHEEJYJQCRvjSz zseB!%ax(#+b$6#+g~F4@8>;fhJr9MS7!lilWNbS_*s8agQ9?&&bX{^;qJ>{uM!eI1 z(iX#gdN|e*H^t2hQ}}=vbn`#Mpr03DLc1wH1$or_74aVhJDE{e1lf9B8SvS=TFFjvw{uVP^Aau>(V$bLFCB zQ4xO9gu(L2?c0{KUvr-GbG@mB=1P}(Yol-prpg=d6g^&D-2wPNvZeN`|8#x+)poC> z_sFS10+2eCake`D!&zw@JE}s}i(~S#XR|@qm6!-=8<4nz5Qiuav}Y?@Z#X$kr50j4 zfJB?=skmWD<8`ILOd7h_CkC-JDki!u{HriOkiw{7H@BWV;#&SQfwyCw;5|z7Wy9P% ztmGdBta~r&x{TRzLe-7;9oT;;>3l^*fk_HcBu z(j?A{;M|xado!oqGdKHGxa<^?!hMtS z5Ma01SjFs}WwCW?B{9Un&#LwlZ80o$m_E>r_bpvDM&Uu3%^GuB4RL^{bq6fM-U<8h zwEXMTgwunDI4yEyvKOJy`}=t^$~ZV1Tvc%(FKs=0v9TfBGaW<-{PEi4Rz7Dbf%F;G z0QKKE`9Hp{lZ;5e-9~CJJf*N@m?~`qXH|dqZ+f{9_`?>Yvv5l7u;M`=H?;P8yHuJ! z_9uk6J2uW+E+r|7a@t>c=;{&}TjPCt$7W*XLbp=%h9o>GRgy2WIc#(V#Cxs3P^vnP zDihkx8+#gTjJyJFF44wGZJT0ORE`q+dhprVnUi3qwOdoW(C0IR{B7k&$6wPQ%$v>} zX9+UglzKV)8aM4;;yZnnHNdMNaG=za`T@E)GnAOZVI*;HgFEC+jxTCNCM zcsbYg4A5ErD9|F?n(CZ>5Gc)&!8{qJKv?}9bEe%l{Z0~CRP%u3OG6@#khaBZR}b)+ z0*~=3EK?+>mW)lg7=I8lK4!SN@-ylUJ3s!aJ!|S7&J}JZ!ZKci&KD9Pv$9V40}tpD z?{oG>;V=2zBqEsziKeXyqz>{Z%8j+Kqjm;w3Ntb=;!k zi`NsA#u8j{6;f*^#-gkQjuITQpzGLR_w2Hf&s9-P8O<6K{g2D2$I-#yA+54M`JuC5bN{ z`l?ibD{nch#e9V(zoVk0g=L5-`G#!ghfF@Z&jrDPfnsE<6zWRq8~1gtkFC9zhOFpC z90kb*{zzx&Qy#*^yB*IKF;OZ?pk#RbxTm29!r7Cda^e){{nZ8clyGiQ3WiZbTtqq#kaje1y0C= z%mhe_8=p>)P{z^*99JZ*iKNc}QF&7zu1Y*vgrlI!t#~YjvjKocE+`FFM zV`QRhbITbF%#kAzVhbdkfP4z+B_`f43l0<{c6+fSfNT6;`lhi%KVL@SEjKEeaswV# zzZ+RP4eTD4B09blbm*}{Bl|9@D~l$?E69~-_1;C zu<&;JB5I={e}D(cl)$^y`{Mk|WrGH*-OsV23k(MPWIax9);Igd5j`ZKP1oIDHKUcS zy5tLCe}@^ctVc>vlG@ewwSzG(T5_Mz(Uc%U8L$a--JWqR*i}kgJVFpDutf^SgqcVLG|_b@m;Y0nT5;_ zcs@RiS*u*nVl0|IRzHw$)qbcGY@{%lCmj|!aFPQy`GCu z-5sZBu1z=ye$wDyG|*mFuG<4cev!fvJRGtSH|OE5YiDOPM9L&B4qap>u& zhSW)X-{ZVuL64!K3@sb_^p3Qkk2Qmv?u1OB5~GRnhvoC~B66kVuU1pow&_1MB`5w+ zz+q&emGsAF(gvyAU8;XUF4^6Nef!O=t=pA6Afx3Mq3oDJ)aGd9?^D5ib0V#~n>86* z%r}oEqEH_UbrL%)w&XM^!*+ELtwX&JY(qobETSdE8ZL?+1d90Bd=D9v z!3`r|sV*H@n9Bv5=z~8!7NB)TF`$Wg{+gZJzyRtO4}!I!7d}H2WV-XD%o=-@f^UW6 z78!xo$4}AS(QlsU(x0`h#?(pu5>Re+kch6*Nu#=7>2})VJl*@y!(QC^?vuB!?%*63 zpus5wpL25)1tv8p)4PD7hx|-~l-2_hP zn$EmR!Z1nA#T~20cpb!q32mvRK!4KRiP<5LuQ$lI)QDML!?<#*Ik667lN7XdnC-8Q>U7X1cn>xjxfczN|3#)hUJy@d+{iZvN<^U~$?akONk z`GPSAYaY@DPbrgbKi~fIu0Nk}QWJgF0DMp8R1rIm%RGTRnN5M{I~>u zI`TrrnWEb2#X2Y^M2$rBB=F3mPEOl9n8BopT~4Zuj*Ng(IiR8$d}MSKd7g%T)Zv)W z^CMOCa?WE79~bwydZsL3EeR81?pj*{CplI1U=F2u-1F!D5MRWr3USSkYF8PfArJ4* z7}p5GQ3xUx3dB%cCNVKFCU$w+AOmPQCPQ3YM7p$eh_hWTE1;V{Rga$QMO|>epTQ%)z z2uEIjG6O1FaYb~rI?ha0vUe?aO-@b%8q&?x?b#Pl{JA$Cgz)~fS3#aDHh7ef<(f8! z=q|;P(IOf+KkrDISW1SWlA_|+`1r^Ejt(A*4t7I>HdJi9S6>UgdGfXaVPf07p{q7bFG99g`Dp-2-QZtz#TK;QD;HH{o!& z933ProqFg=4yw_KJb9udmK-0iS8c~GnwyaU14Y8Bs?3dzhqi2=i}ZsEV_uE8`ufx> zfZGfq9ydgDVGirk0(ECjmb+g3aFFO@J6{0hzLu%$(m<@-iGu%$py)!E&!MxkGet*l zUmvlF0?1)9>yB0JmjpcsSUlR;@1VL|0GzRgM$UZm#S%3dRL|>%T~5y%I`@vQgI@c} zy1lzfZpUZ8JJV1by;KA0wCqim+k1NEmX$5WXc^!HK^=Ez&iUtLi*>83ii(bF*I>x~ z2=qQD{9N~0jXW%B9AXA8RJr6zwh`yU=->vckSI9ansIw@&v-S z_TaBPJ(;2tCMvg3-~zBZT%4RhL9t74p5D0z{35S$&u4EG6G8@KY&$_vb2JpHVDCvg z{}|HN2KFDbvXU(CFhgq-mTIu5z0bnfof&ED#e60|F>m2Oxi`-mzp9V8E(?Q)zs zSkZv*lcbqPfHHy3+fZHIlE~!EKytoWhgPN@afq+NS*Hx&931T@6M^bae8N7ie=3%0 ze*yl9+6Gm6rj7=$VWnbUpKFF8HA)%|Ht}JYqK=1@Wqnz`aVxmJ+(dFC`~? z2f)uhzt$aHSyf`l(+t_1Au;OtDNnQ4TQPA4p8MtfD3J#0t1Y*#i~`#3Awf_YTw=9QNID27y3?ayB)9@&_Q<1XNQ3 zN~v(a8F9c$(b0H3mT!nU;9ou)H}LXXsxdw21q$y$BNiy4xd9f@&zIS)OTdm&tgR+h zBYp>=kB8I3KZG?p4@x!ld#_gg{P{DQdERp|IFHZvqSGWo^!#$3`p~nHf9}lD$y-SD z;+G#jr|# zetQif9}h>ZdAV*+80hQU?pZ0lzYuxv(rE;NNP2d?caa69!6oY?=qNMPz~}wlIBsD6 z`o*!^aEOPonoqOA4Si*qzhNHW@AfU{&tJYs#8FUsB_4-D_dtj}f47kbICK z`oc{`^q9B9F^Ml=4vjj^kN_^E)h|$v2=dK5H_sx~`=A+$KJSMu;K28nsG%S<7%X-L z;yd&U6a`Zear_-FEOwg1DTPmk*az{l3&55n|5=t0z8AW>hy3vJ#?n%wwh*1P5)W%@ zG9S>-obUfU^2PQ1U}bAe|Ky;%BopM+ezW=mFJAFbMdamM0fhl7@Ri!c)}I+uV?J2k zPtiQH*zU%8eMScAXyeYGo8`_p&nPM?0#jf_1;~we3LKA^a5}p=n=e3?R)}=!3je$qu_TI0sW0 z3T?JY@DgQA^FA2p>~uD;Z=FZ&80HR}p!cc0pr^I{g?f{+_?_mpU0rgkX)nWL0|VmH7JG9YQ8uIda~~4&!IwZ_-ao=qZjpMmr6JS zvDW-0Kfh_6ZXT@FtjTSJ6v?@~uG7vO@^?W=6D@WT~Bw|url zOI)oxr|u-)cY`W5(SEwdC{_gwtocEN)qIp=2~J9wb%QU7?%lPv{-RKp!`XBuFM>jB zj>g4yb)rtHgJ0yS!B5@bK8unE_4Ab8{a#b@^^MJ!v!yYt%jOBRhwS7fJVR2EBev|ik z-J7^Z#6dyM)KF~fX!ShI*~~0p`EaSj5Yf&LOgX|kxKfKi2ff{ImtR<@UEU7m;ZcB6 zQ>TH07rg+!V;q~?Dy~1d*n+k@&H$s(2<`Gf}WK;{UsE>BtoUaCk!$~QH|5~%?aKbp56;M=;uHsj>9Pz z1p1c1*Wr2=6!8nI@I@xu)v5J#{>4 zJB>O5a@1p9KFM~PG>_OF$sfUjy6bOL9^u0UM1?N;G_>@Up^tV>oG4Bg@Zqnv##FqI z3*d&Ts*Y#B`vLr4OK}6KXW#OmK0Mi^Ke)4b{rOA0vGQb0 zQTu?GzhtWJm}qG!L2}W3qjDEBa3Y9uN@1~P@AH-<+=!0h(c=#Ik<6YCVxKz3zzY<7 ztYl6V5P)LlyAOQQ*4CB?6($AF3mii}f8KXmK4}wNdD>21-*ny!N3HUs&z;jQ%b%~e z^3S?RSXH~hV5n}xCe{RzgkE!^U=jpMK`-~@ zsKEP#msedwBc^B}x1!A{L1BZN9HOwCdyWD}7x$T*NydkiPK~g2EPZ)lNS@j?zVQ=aUdV5=sFR9nO z9QZ&ToDIK+$n6;v3LAm@1u~3K`_$-ukl&Q50>4nftf_8CJy(z(`g*)d1bMU&1&>vz zZv;m;*Kg#KqYj~`^KZr*ffSJQMMh;#f;m-z9bAZd-3$eXLyetr*4y;zyUkuU?(H-m zj}@(yLt>J&Ih-HiX6W~EHxx<=F?c70o;tjC~ZeVf-F9BF(F*i3aD2S85KvhX0 zFq8n2@sZmB=LirYxw*MUg8*FcKL$eo<{?(wW^WA*GYt*V zKrnCee}K8KEV$Wo?dKZ6J^8x>@4|@p)tQMh8g=m{=&mT z+3HCL=acQ);XIzOFx)*)t)((Ehcy84uYzd>R@m#p#e7A+WH9XCE~>#?#KXe_3X?zA zs=nF^M$hgQsBJFE)Zf#isWJMm`CTO3;7gibTkRVe8+&yJKzt4GOHXggTg=%1@s7ac z*z(N)FaONoD#UkM8|M>4-F09nNT)P zXs7x}AQJ;w4!|q{>yJK%3V58Lj( z+-pXIn%FW+V1Y{sc%L~K8Qtx03=#9rFT+>y)dDtgv!Fx_jldZg0o{1~2ttJSS9g7R z+(BjgwSL2|&KCTMz*htnp8omLdr5!b)&qk`t%T{n?=7qrT*#*P#YP_gymxm|^_&nN zU*H&crF&?6+-*?mklJgTi=JFdqZYm&Y6wFerZw+WO=Hty;ZcAr@afeaM?IH8M05oaA>m*xfhKEL}$PF$bR z7LSC41haB-&04A#Mfkx=cL^wwUeLV)ST}yANhG28ScxIL_laTrlh-F<{IJrToB#q) z2AMe^KLJaU9<5BuuDE&y!Wot+&(giO9r5p6V< z>Sc^$s{^mB_kq&dDCFL}^QeYaZ;IFM7mWf?MO5BxXms?=PUSe)2V_|{2O9V}whcw< z@UtvxWan1n;ae;!?b1y1!Au1t3`)iF>NXIR=W8<13sqh+An;lTp;2!LhVd_34vXV`|?g-RfuRj`6*m1qQhL4zT z^0}Pz+G_-!{WcgCFVy)OHm!+?3Bb!UKVvHWBQ4T=b_)!V@@8gcFJDfcHlrI+C=Abf z4GZr>SXeKprQZI5G?auBlt@3#lnPz9Z$|Fe8@ew9-~}xS1E6`>4~6pb9$jqNgO9I| z5IHaebhN8b%IU1z9uUwsi$89OcMfLBfKoyR;<5mB0{VY$wlSK(>DRaKrKP1FhpUq| zRT>4FJG1r7{QRf+d8tjCUkU(dMCDYttm5*|{O+}f9dc&|V#xT}0Fg;jtYy-=}z$jU0^3`UaJYqOL~ywe_jIZw`KGXW~hqqs{x z2s*D0;McqDQBhHGJQ7s67@w_o17|g+2V8-?#B>#jItDV@0!B@yS1AVmt+gfH*o5WjTSayroiye%j#|*9L5UE+caAc$d z_buNpgLAzgP9V;3umZUGj36p8j{^oB0IS%#$?Y3TT{eaQ_Qwbb;R(5tu zQqouy*62+jMZoPmb$#=Oj~~7IdqD+{VuBOa44$SLRf$|5%)*Ecd-aT(HrP;q4(iwE zoL_fxc8=bI;oQER>b{8f0#o1oJAe~`I)&FPhOkQB+Bn-MlID2E-1ZER6Tl^%n5wfn z*`CA~`TdQg>9-2AN-708xo&Nlv?m!wb!+EaLKH0|_zJK}f*2{viYOL_Atog7ML+z} z-v{ei5n?A37ptrDH~qd}hrvK3?D+Kb^yFj+P9^AMibf$VH6TyN4!{bA9VX4Y)anHU z1b`@1;u$h0&Ok?1bsuaCvYk9=&W!5?%-HE3^eOc8__%EpZvCdYwY7D@p{Byc+;->Z z*qBnBUfDWOFF3QS$WxU^0t*iD1l(ZDRY*vPECVnkGRH7S7NllcBc7hu*8Cin5o=f^@6_9 z=n#WB>q!NJnp)l{> zMC!g|L7wy7>Y^PL{uu}Q7;{fAuX(RM(LtPpQs4mt@3>{*HyqIcp92bSI8UYd;3w;S z_PS-DQHZV^U7qYfFDLs^^XNtL-ydo`W{qWYwdi?a5_v+yajrlhKptflHSJ{r{@G7+8eoLn1>X`7@UJ5d!H?! zRCu&CvUZ6K}-o| z!3l2__J1uLUdpduiA~x#G1yC)NABv!>AQN^+3l9Vk*wmf%F2E1VdPjhZ-V%&LK9H@ zoIvSXKwl3DE&>^KKbb5qu3b%RX~`TdK(ACc+g45Q03~|@Rw~Jzn?SK-)`1S?6*tY9 zEF*|8lKzp0kMCr^18dvWIqIu49nyKVN4y-M-BH=}0+~4Ap{x&GdEfQz+qX%J{)=X` zmr+*~W9}Z}_d;vAc`xj+mp@sVIg!lNHV*GkiVzq(2*mNLQEMPrYTF=!Bj*1571-`L z33}1R7?=JMB6}C?>jiJ}m22Cno=3sarFIxlO;4i}pP{&6&4y1_CXazY{yxo6yx8)2FQ-j3!o$R2`4$};2{Po;YE`PFe5;a3% zh%+J;ktdHI3z)PY*?TWlwX}#|_&6U%^H{)gi+9a2&!X+$o0PV-aZUs56#2Zih9(~m z;fB{imxZ*93}?+N1N~Vg|43lvhh~umcDtW63PjeDd2rZ)j7h-$ptVl!V>% z{gd`*>bf_lYao{Q`LiWhMu)2!fVum4mX{(t-@IL>01B@gcsi=|bBK4YuUmRuhN2Pu zP(p&WCyhd$w3FDup;larHQ zmT$|1Q;0e)UMB-_Z#Bs(9R4)e#Um;J)gQ-Mx;R`MSsgh$?tf?v%34gji4|nt6R+G% z{op;JxR8)R-9q3NP=?r~5)t6y``_(2FG0AhqrDxE;{BaFcR)gdoRQIY_YN_iS2RKb z0rQRNajR=<(1Z8rS-0AL?_37xyrsFK%P(-1kgPJs4K=l?S_DdLsNc^|;&3&E z6_sD(-VTWS%*>YW-)WPI+^4HRgm9-9d^;S8{}fkk+=lBPIXF1DuyA+MP9;@DP(Z+c z^#(-oYOZ1eohOsd$sPOpqF4f_gXMJ)3^35sV`E|?rw~z7GiH7G@Bx{Scrz&(8Ox(b z_b;ujta&h9aoOm)hVjdMyVTWtX1^K@g9r2QsHKM0OfS`*FLw<#dbNVC)jKR8_~&O} z$Yb=;nC@QLwiN%Iw$HEIMoV4Hp|6K!`*JrE9t)w=$EdAAHEIa&V+42|UCH{R9 zlC`z9v_$>o6=IULtZP`1bOrvq*qA_!A``GJZ6V}iMP4F6T-wP?y8HXV{Gw2&{b$~% z0Kg!B5UGeFewWx*EdpiAS0uW;Ory#L6uAk~pg1$r8ysp5>P@bHARV@H(>H{7gC!{{ zBvkk6dw}}S{Lk?~A|k-l!FOI)Xa2dd$^tEzS25I?@2r9K&t1BYC_!g)Gx^KidFn?T zsd(qqkVssHfl=Kr3Njd}BAv>?bl8`n-sKbc`H%L$&&~bEC;l%x)ln8HFD9Fi)Ns@x zj(_Aw_8ufQuX(`bcct>0R)RpD>hg4&Vr~lOw!Zk$f zG6%nJ4Cf8@15w4J4iABoQBWjunFt|auV}thu2k8U)aq$1udd?Z;Ynrr;X@HyD3nBZ z9DD)CP&;HAEZe`DuOb6yxiUX9v&@zXa8~+K++fiJ+;6N=LpjBq-bRxH1J4z@1J4gR z<9RIjFwUUj+S)&^g+Mf0Sz5w+HNBTRRWCdo94zM=oZFzpB>iBGs;R3B2nd*#6BpQ# zhT(xneKS=-C*E0MHHD`E7%cdsXze{aU;67Ts!pdF|1ZdWvOj3Kb&HxjtbLe}kp zR>HJS!a};4|H(D|ll>MgSos|b@e*#w`yH1c=$z2rZojs&0y`Q^1sWv;mKGiTLQh1( z6C`P6fxSJvcp&AFt#4xD0p|E2(0pyclPLiZ6GF^isC()TP)r!VL0noI^f3VvxtF$o zzFY964#cfeJlr)}Cm@ZT15-yl36Iu6M+=e|M!C(Z_C;5-1;^`Vj%Ydu{LG5{c#b=-Gx2efqA+v|0n3U4;nORqp^ zB^-m_cm@ZH2`htMQ&_}os!SZGY^3D{aeQuem^`sM;ea_j#%WA#@r!1wIDJyIkPwQWdTP#hd{ZdQAFxMYyiVnjf{i9(tk1;{; zZ9Puv;MIcp6oY@{Ka+sxyI^dOBn4{ecQR%_NQy+ynt5!yA9op zA|k)~Zy6x6(8*oL!-4W<&@Yj{bln&CvEoDu<&I7rAd55-U9Jn}Yj3G&ry~AZ0Ivv% zf^Yx*+Ou%-H;A2HJx&$uyI;A%&_bf=lJ%Kw z9A3xwS${NX=hGvj>wo}Ga3vyaupmNoLm2Of}qTOB5 zZdIcuSq)q6cm`k%XudskULUG~wI9wU?o0JK0R#nb^Vj3r+5q;+^z-xMF;~o+S4;!A z=v5?)ik!Ta2*}s!yXX1C*B(>)S;;zk2Ab;p`ldVU3lYbBpyE|9v36BMFZ(hdF=6TJ z+q1nqIIn>LY|{1dqsdQBEUX}G+KzC_Eb468W)Z*}(3+Y`nw5W8TL1kRiDsy|A1O*f zDkNkz_q~D(r~;s}bB+l9rk8zhr8l%Ln~WFFR#x)g70*>lV*1JD=O-gCZ*$|u4G9UE zb$&pMGBUR1nUi>Uw6&cNrQE@#?CtK(+7$$E0Gi)a<|8a2E=~sf5u5rX+fux1&3gjw zqR*CudN`d_fgOR&y~6Q)L%*!vKYv6Rd=i}Ihp6)3f?r-$;++yCBsSi?e)mrjl)x~} z-3Iosm+>^5odMjXM};H4$rXpy3m*YYote?Q=r8X#7rU^;r(Fh4b0YxVB!&&YfHOo% zPCi||_teqR5r%qH3c|WrCC>L<4K1%n_GV|y`*q;nI>?}*b}HBKC*bIrw*By(8VC`+ zYQ~&~g7ea_zkr6Sk&joowG+jl5Uu~2aAFGHSg&T(3u{$)jC20J1ZGBGMbX~D9;!@} zRo9-M+jbmPd^Pd0I%ja{i`=oQ<);gVhoa;>SjO#+fJ#tXLj%eckSZHsrQE>b0IZaU zeDIMg36b zo}gu^UT$fq&Qa|+auhB=Q1)iZF1xU0Q`bE1pOC*n-umgW`wYfd(A>e+i$9G_3>Lbg z@q(E+TF%I+XjCQlsvK}ko3@JWL(pujtjO>9yPxbF0MfLtv-0rF4FJ;HRQE(S&GhT( z#Kh=Nq5H3NjFjH#Sw^u>lp`wo%c^BY;qj}92dJ)PY;1X%*ekK zC{5rUU$nQ^Oo_Q6H2uNr){XN>O|tLq=|CV?~njOWub*O^!9GH+GH>U-vBHXX3;64xt zYu^uW@Z>YGPZNcT3j2fc#RdLWvVOhe)%>q}5BXgyhdl0$cV7x8MmHn;IZ43<&p|$6 zeuYkps2Xsn8saORaf+E=`CtYro?@Vep{RLN29ls*|6TIjPiSi0=4srdcT!>$*SB}x zvakEyGr{{9uK6e3BV3m7=IjrsU*clBxVO|e_&s%N#cG>h-%uWY>n1Q5&5fj|z|)32 z#u>aL8<1pcOsZXY|H{2`GrA~jH`^rJ0`<>PFAaIw@sJejHleJRuYoi?h{l*f25G89 znjD7(DnC-&_MO1UVXpa|LPFd}J_~_3r(ahJXWJuruGLt6F)^GayU0`jWpD3V9@FQf zIofm`Vk$UYjb7@9!`>1&&A!maWzkWg zzF9Tbm-^dI@58uZ-HOGHHr?v6iBdwz=<&87jvR^RFBWWYw{q68UbC?8cg-N3AKW^AXQp^WivhUJCOn-PP#~ zhT$Ddn`$&NJB$VeCPd#`-iX$*dnU%9aB=N!$0E2yVQC2xAGu5ULs&;?cj$n?P7MXw zKxjM(rmVDThuUb&`W-1G9x0Ea83#u1k4MtSwr1CdNL~`Yhpn{=JI-I}bowtmkVJs5 zb%de`%1mTVCmtj`=?)*eMpInd_}HQDVU!d8q5##h`2B?U*1g(_j!y_Pk-3JsO|P99 zSODZ2DqF9By=zIo1^vD87RSxms5_s}-NyG=u6!xGuq1URXN7h~8;@g#eu`JR{cD(h zkxQwp)vduB9B?n^$oVhM0@kC0PVs7!jGaMjF+Ky>Z~J<++d{^bqdZNnL@GNuIjslj z*NaV+t#B4-l@OwNL7?;GN<1awt>bqYO9D!D7C*U5z8FP1ED{cO-j@h7J*zmp%_@VC zt%$%m+!9Wd(n?$&WVsdc#Q8#yY}r-z&1rTdKKCF*JguE6?>S zG7MRwuXIqj`&%}Tu?*xh3W(iXmYCbTsp-`(l=Uv2>}AZ;wN;wt(I49%xPs=uqkJeD z*)5buKP;HP7t8qeQZRvU6zh`(H_7S7i^+Zf8*JV{z7k>SU z?A27nzUz;IB8--*n~}%meJpqR$tfu*si;2gfc+2AvhS{`Db2rvGq8O4K%sy#5_V;4 zN}-^n(nN)%c74pq@{j!bRi#$qq5%Au(QY7M2^ip1Nfw};_C@_(|NV7SZiqf4S-|m~ zU6nH&pO`zl-gBi<%k5}4J!w!O()MY;gD2|FAVL7derC0E$2&RD6Qw5H9axTjP2W*o z=(BI^aXufZUZXRRi?<{*TLu@5Jkv>PX+)_X@$Qd>&ru##9NT9eG5@5J8+*PexV=8> zIO>rWP5CKR5ZSd)#JpeEwbNeA$Fx)RwmPSDP9up*VKma{{!U)k*J!Q^7rk%mAt?Yj zr?|c*RrF+A&%3#BQ*pw5^@E|o$4xeW0(!6K9CSBo2}pMD#?b3%M&lfMbCzU9NoM+F zKKyokpm@t!hzr7`yJNI$sm@!tG8Y3%qelAJh~w{nZ~<; zxJltulzrXZ$ltBAz};t73E!P1PX&%_0M1(T`Rd752|BNO&NI%86QlLO&I|W({rT)G zFX;XzmFE8ja7LPt?C^zBBXL8&V zYrO|&6t=w}+V2LLos&0@f`&svJ~5L9-&SclfDYN?;Zx@(4H^#W&o=J|QE7!uzZ^YY z*z)m1`V)BGTj?6$%p)e2Lwjfo6x#T|HSzPp-y@!0yS5-PdDEDF0Owvr44}ADA&nfW z-^c{`9!>+=@Cx!p&)u|LLqr!TpNm1N`|Ioh=XLV!`PpU}*XL6-N6hEvk6SeEuylWB zc1)Iw#JN#7HM7kBTg^}}Be-fpd2 z)3?oZFWD=Q<5}wLJ5(21zM>#ZJRC(J@-9%#%FA}!y3&a)iA{%qLGhpN_ZcUw6!jNB z26bBQ1VP0+wAo)aH$}Z#FvJFimp#!rE!M9;-4Xu191TaTa8h4_FE2FmMKmv0$ZcP_ zF@7@AP^6rDl5=ANcbhNgz&))51*50$YaPhetreu;RLc_2VAC5K)FyfCpfKBmnrxG( zyW#^KN_0exP(ot5L9v&&tw*(lyM7&k1zVl}=trZC>C!P}Z)fl|rbwD*_Js}R=T}Ri zCh1iQk@K)iL^q+YHD4(ea!BS!*P^z)fk&e8|%aF*3Rz)fVnX$$b+n2`XESS>+O!{<6~f<=Q9TWdAX{U1+g zZmH6C1{q(xxL!BK#6sf9g6(40H#5^(QP=RjzOXWM^t1Y^k{R$)Z=Jdgy=Nv>zq8oVphz6$$p#P|`1jjl zzIKI1? z_QTZ`$YDMq1IMF*X1i@`T$ie_y^Lvh^ut}|&H&&TfezTs%m>NKLUDNkt)g1XJTS`C zmyi>;3gkNB7CGq#n9b;2r3Ot=}E$&I{K%;?@YWAI-w5C7{g9`B(u=^rD^FmcEWw#>!XvUT?|S zAIhSUdY$ugHr^L9Bsw0;(^#)E7d$=SGR_T$wqgx0;4$KY7T`fycIGtnH8nJXe^lI| zj}}Ut{8aVyDp}BX=NGeV#k6wUR!?}-pHC4E1&`C|R}$h<4boiM;I|Ab2$Rk|vJ&$c zX6JPb0(ajMejX*Lbm}PXLbSgQ28Nj-z_Ld{+2$TkX?>u>wX!_&O@&`?MoZC>P_kxI zntfaAp{e*jf2&;neE9Q7{NT!heEjeuMKEre>XH(5?+|=sFvd|lpfyH68cZItOn;vq zTF2of9rU47eM_Y!)St&Jt%OzQoZpZ$~COD(5pfDG+XmsQ(Cyd@8MA5 zH(ZHR-_CwNjR20-ur)^v!`RY!M$C6#jC7nZrsCVCy&(GfnZ^qnxFBEZ5Cep-%86$1Cy#3AD3bfiIc+&&h@`jk)(2Jg4#Dwel)O7K1Nh; z&9Y-rF(yU$nf=`YWqWk-2v@j~{H{7q%`JvQ+w9LQ#k{5^UOW z{k5ippWPLF!Y<3va&SL(W0iH64wsQ5^21GaAr^83ahB#!nVxXqSE*Uukj@nM$FH4~ zuMa!7N|)POZlik!+}qWeTP~GyMY=f~k5b+$NHGFOtV4rd=^3Y}sJ#Ncsse>XoTlZq zvXw%2ORJ<%!w_hm82TBkpu+5(-h2GRXJV$+Tv2L;vv)`q8NJf!0-CcXb!Wd#JaEju zb3j{Pq&OD8sG?r*NYz7mD`<%5g+XZFjKo&{aDsa$nWk$?nUuK>sS>D}>gh3haJ}hi zbVbUI;PH5iefgKu^0x9uB5nYRqLL!_T&;|CE_|5%~2MKnEaj{QQ!NbQOU6$y-{SB-Y66G z8w+?jQ^iVC;Yv_#R8^9~geH613<$sAWJ<>Cm$DO1hk*|RnraLfrmo}H8r|w{jFg5IKJPpaFtF4{RF+(Bhf2#RrnP+9qLX(G>a2;<^lpj@L zPP@J*|NbP@c>}=sLX)?s&-t?TtOIi)1ZsOwu7QuaV?>}-I z7d;>D=mhV#tCAN9l2wnqeLHh4lntI;Ho3tM=8Mb0*u|V!=*4zAzkd$A^2oAf=F z)GzXMll{smYj5Z1Hy;x_Ych#JfeHg!D`&c!3Su=xu`vk*edz7?`N8cy%VM|DpJdNn zmNKUjl&5GmeDYM@2aTjhT>Yl#Y&cyy_-iD zA1%{jp~_dgKU8Rb7S?&hUL_U8kx!XkX)%RoDss`@*?6BpP;XH`BTVx0Q)7B_+iD zAb1}eIjRZaJdjjM94B4r6)i374IYM0P-_j{Pw|p0aAtbkY0Z8tlj%4fq%0Qr4u8)j zw)`2#kJ$42cf_vB=@uc&uC(=PnulCd)yrp4deH589zVw$4HJ9q&nB-d!pFySX}(&K zup!7BmR?$Q!sS8bqR~s&8T8-S`pd8?yYCAWMkGa)5Re9eO@nkJAe~a14uMUFbc+bm z-QAtijZ&NL?(UM35;*Jm{onU|I^Vc1H@BO6tu@!2V~jaw-s)h5MxpIHf}N|xD-&f2 znfhNdWKJ>n)cAj0bo&O+3JRjMXl=9+4;@IVn@X=7Y402N`-m4FgkG?Zb7 zxnGkY7*@x@Tkuvx$%*Azv)4Z!Sn3(~D#)2=F8{Q7A>L_Zl`0h4euGwuakvZ~@O`R$ zX0H*fK+yDsr##HU{xuWhmTe}3|ZtGe(cyL+>}w+VTY}Y#>wt*G+CvDnUQTC4NSM0hIeHyc!-+_`qLH# zTAn^{6wyDJY0eea9$k|!WHuLn7bd^X6n5H?e1>2My~f$I=IF7Pq_8=;d_l+MiQ88{~B68}b%u(UN9&1TNj2M<(q< z`SDXT4!&btjQkNx#{{Ja?qL|!j9xgSIL%m7GKMSh8B4a9J_@XgZ7`i7V7x=>o) zxLZ3{=y`go-@h4w5@OKJNt@lPAknh~xE86%SL8qv)b-lcz-j#U@*c1T8ykcZPZKV( zK$^Xxhn*OTh2f1%#j}7c`kcn%$1_SiTZ-UfYWsas-K1Fu#!q>CyB5B` zkRoi2HuDr4$4CFf|Hu+G@jZTwFr_+A!@>iAxME}H-l@5waD)I|5y` z-G>cvUhsf&o)NnA({_0iNWAZWN>tGblB{@CUwz|aq-LN|aYXZ_F)Sd}2_~!%_5o4r zY6~F>0fcCnx8gaCSltdn$&5`Dh6SneShxzC{u5W9ox%i`nn$B}ju=0!nzrp$Kdrn> zdi0A#Le8MLbX1SBFGL^&j5YB&Pv?RX5%=QVKI&IRBb=hs>54LUP7}+rz#kPoRlY{(p{%o zk$7FEw{2q)r}futCwD(`Hfd7#X8O_Q{80b}MgW_+2y;t7ke0vs^srK+E zQONjF%DCbYsl^P*v*!lSXWLhu^P}F56<>aQ-YK5`)2B5r8tb?)Ia}h^593Z06&Ji6@OW`tvgWkE~$CbAE%@b?^_)&TPT-ML)*>M}ncu%Ne*^#h^Xxan7yF;$b6!E8 zs$SZ&rp6GnP#wPz&LhF9`S~wFlwyfGD78FhpGYxK-_)%oTviJe$vppyvej(;y8xLrI(HX{M&NKrs0n7@KF7Fk%(2I89ac{Td_(_L*7etx<1e z40TyE$qX{w(Ct}u>gnp@(?wPI;XQTGH{)_4iP}OueLouYg`GPy(fm`9>}%p}>s9W; zi^^{fX7)7d9c$FJDV4*@Is51B+Df5Ud)l#E-KP8dkqt&uajeX~0c>f4J^a4LGkmyy z`g%~+UWnC83L|3Cg#wk5Ra%4ikCyf*%~OndXycC{2dI9!^uGUL{tK{?fcly=Ou<@o z1^mi1!~#Jc#DI%8ZTDa^gcImh7idSn)c)xARmB|;ZK_`GPSp#g8J4nUQ(kVgcDHoO zM6Lx3uY4=&)wb&8a165OsbU-_)x7_s2o)5HzYbF_B^5HoCB6UUAW&+qrq(%v#y=4m zO_M^R$QX|4-cB#V=zBx1(gMYT!k)Qk#=X^rpy zlcPwUAUZ>0nkJG?sH>|=xspp2mAqC#BFhXDZM9+}7dz0737Nz=Uwmg~f);X|xQoG= ztjSBlXInNhw4a&$$1%tiT9Bqj%=Bo}5HB;0U%pACW^z=|ZqLm)9FU7fZXBCAKcF~m zh(PcV|MgpZYPk`0vCm$hhlUNmad*;W^_wp3-+?{*Np{pMqqdBbK2FXjjj4JN>`i%9 z8h}_ne33Y|`aJOupSYbM=;rx;8pV~>LoB{ZusE`)v7||N+miGf71?l&;?LonYzQVu z00;u>SI)F1J5(Z=PgM>6ZopkOIktk@(zl2oS6cg2$$`i#=HR)~Ai9OXuQaVfrL|7M z)xpZdqV)~*LP{~}m1GxchNP2w3gVsbx^&Y`bAGyX?uE0B3mgT3p`f4&>UuM5j5nL? zxIW3|q}!xmf9b}J8Y$`_{V&8QDdgX&0W|W2dI!0AUiS1H zrMv)8djp&kVdZi4+0nsmZV>8`tx2{@HkQ_D%wjr(Q%-1){8eXq#1A%~QjfO&MghVw z&baiSYOHcckb~7mw+pY(-QRCL`<_Wh4|SwB2^Xu6E`B4y)mTsz<)#@kD2D87m-@%P zLeTmi%_7H;B0ltG8<)D;A?97sy8NH-XZlX95&DsI>SOZFYSmSSmTyyj!k4@UOhn6@ zulkqXz|hOL>ax3$gems}-zRhIb`}mw4d|n4UD;MSX;1@}*zlZm_Jw1F_&vn(7ByQ1 z_oI=cw)(zk3472ww+rzmD2TbYRZmoD7bAi|a4OZoHSW}X*W93HIa~yQ*qEu3y=gXX zc#T_ryW@*1R8Xc#V7!+k(%pIO5Xj~$1J#l*_(uKymPh5EoIy>I>oh!Hyl)|}ip}*c zgGj-7S#<>RhF$!?4>tqB&}}6G#$eJ(4HXq^2bz{(ds4Bcs)s2WCXT%>uE+BX2eX>R z0Yq23KLDCS(8TlctO@?xoV7EB>xizmnrJ3A(~W>|mUH(`XO%Ak!!@)9~OgxN5Rhu_hL z-ktTmm5Z%;Pl%CJa$55_{vb=G`Q!e{}v$s?htIV5CABFz-cY+h{mGs)FF26Sm zDK@F`K>Pd9OytI>f$@esD^L%`+gf`&C>x^RqZQpLyk#xyxjL^kGR$(UVI9jG+D;QW zU}IS_URtE-v*U^p(ca%Pfo4|5$9$-;56no#I_8OS9^voyEO~t8nD8ASe2#6u!HrX4 zGKXagA;U$E@TWZE$C;Mbf_*I<{Vma9k}%j^>iUUqco`9}q2>fLun zB#u!kwHJTa;``g(jT&9Frq#l*;w^i@WUfGIo}5QPFrnpwajvtUjY&YH)UQ$)Y{4Fl zPus#Q0!fB(M}5~=+)McdEhnEA8asF|*($A~&Y(l(7!J*|q-Mx__vF6rLduVx5!)JA!3;n2qE$vep>P^2^j!6hd&gc+U5O(W^k8`OC;)Qnem8{7REXEKrtSmmQRfU61n51?Awz z?Q`XDb_KeIsGd#MEcGzrzPE{=bUUa~JuQiMIgwSu*BT%OTe@9D71338p%okq=1i|- zrwteAc&*upLjs2Dp+Vg;{AUF6)NC9d&D{_|Ac+U1Q)cx{!7A^dR>gG~<$(0L;SbZ^ zYJayxo}0zge4d42Xz{DBMi(ltvG-%@+|D=8>@ngWSzUApRXgWw!o2_Gm?%&;C#2nW z!N4vn;v65$Gh<&dU)*Ch1;E*+8ye+8#~U&YOk?9l1>jW%Zo7RB(+0Ln>TvU{GZzdH z7xh*sB9<;?a*y$YU)a{i=yU0eym|-UHkrmeA)aA&=Iwhft!-+thQ%;=rKVU3tkq3V$U2#qVBprec0b6^cG=^v`PH z7%4q7eQ5FH^V|E||E(~qoh+fz{K&)c@X9u3v49WD67JSVbf%obJyV)BN(lpeelx+V z*k|QtD*C0qHS*=IXgv1vN5&=01N&*0yJ7W}zVb~Vj(nDVyO6qQ14Eae!W^O=46~Bi zC|21Id^9*zzl8Dt%}a?v&N9e1Oy5KD@0*O>{n~F1OiR0QRafX+!YQ|{1u^@~c_Y(O zo&-oSz-0(>J0OQN8~7hSY7r?}hezrt z`V_4ylvDI<+-l0>{nTrXkvomb&}84f%@Rtz1N|0uB^oN5&V(Ayd_qcp_?}EAxt;U# z_+4;5)kpHd5+`j(2tO@B^odH%x5o1)9ZJlQZ*3HNI~jIW7@hz?%E_s8=b$WM;kv3X zhDOPEIe2~D_Ie$XnmyPFHe|~}OTht-Qa(wQakgv&NadRb_mhOReI~Sr@>Ur!sqCR? zTVXV%B3aOdFE#PiCAHK|MSsIgPgni`U$&0-F#o9Yb3VX#M@z59DhYG&^Lun4UmP6R zzVio7lZikx>fl&droGL#o2F$U{Lx;bcSHV0#`20%w=wltLH#nkA)l=vIy1~5k1nuk z`^Y2qMM(aQJtp!k7T2J{YRxiKGVlfnbg8($)Y>*XneTK8={EKn&LD%8o^^byA)oU| zCF{7lXZ<_SeJ9R$dH4UPMw&c-{WiGA?~5^CO#io!w109ceXTX7cE#lOg5?Y+u)~Hd zkw8`01Fm+nvjOn@?M0f5NX{v`9bPG$;-uLPQ^sZMd^Lrr0L1AQOU#f}a4Jj_*#a<_ z$LBcHn}m!R^UuULxD|WF;P5@yXwKP6-dk*;Zq%|=X+qyjds6kcPq=~1JqruE&qv$B~28KzK@aD<^1hK zfr&PHv#tmlx&vj3sC@0Wx+CIgTHX4xl1&Hl;J^LNX!e-0hY|wnm}+O8aP{ElCV1%g zyoJwd$_v=U930SYH%rSKS};aGcxG@_dbqjWY=jb2XsgqH#YM9|bF-}|N?M#a|FFD# zs*nnO^XjzawEdJ!kWTPwssOk+MhxMI=QY=09cTXjgywzL>DEA4iPZJO-Bqn;hf`Bi z2uS}X?earu^u(l9vd1DFaF)dm_3EN0@z5KRzgpp>ZqP6VO5}K}c?GMs%**b^fOABs zQ#|4{#Osw5DUM8aqEWqukgg-i3TNm|4Yew|JyFThi=Be4z8#Z^Bbx)>gmG$6U&wHHo7wFCUn*>g(v}L&g^-l82JHtnS61bL#u4SVWEg8Rbxf&oMwHnIe^-wc?hc zBtK+C(SsTl(9GhaosH9l-eTnRXKxJOqki~<{5bg(?p$xdjUoJ=imDg1&yFPJi{CLY z?BIxjzEro}k!#R|41VIJr8S#jx{s!k06q2Fma<8~u>LqHEOQBJ6T>bANhzcNR&W z#?SSu{p*h|ww9lN;vzuf324gGR#T%3kW%=c5dCMFwW+L9f8&5*-kKhwJ^zfC9}|uO z{qSqpFoKe$AZ_eA-K|)NHcqw!pST^`$@YV(R3N?7u__*Q%R*kHcZ_R-{$sZ=ndn#G z&D-e4o~X0s41ywr^SqOg>R3V+KW<|hunt7_k_;DG(p9AN8dzZ@aRa#Gv#AgvkZ@3E zJ-a=ak=FZQq+KLDngTRw(zT~*+6Fzf1_jtlRjrgOfy4WTo6WP;Uoskt99Xz;e28cJ z-^wdfmrlh0S>JH@t=#^oa!R~;%56Ip#%Y*6(fxR$Mne{z(Kr zV>7QIN@~{GoSB<4t-qivMlQkY>uAObZHC(c=;ma<=>ir906Y#By1ndXl`j)hppEi! zD|D;c=OZuY|JL6+C8oCK;jSuA3gmz0XqfEw{utLFT{clP0QI+tE+D z*CVSdB&x6kNWsm1vb_jE!X~T6ZiZ#sD;3XSZ-y#U;hxe8kO(d;+adA!Wx7>H3lHhZ zVIozdpFNYf-uO=Eg-Mi4?@NZ0ynGoLb=>-w677l4)S@la3E%Bdnn+YjP%;Urh%wkE zM0+pLj&uyi&BRK6^+oqbp-DazNJo%_E}A1l*?x#dtwK1yi3i%K&Wvr8ha)p_@o_Tt zgkk?8o7PT9PJKQ%%u?#W65b%lOlhntt(aVXG;s03Z1^xmV3y6b!VgPDnXRFyXb&_n zMn|g_&!C`2#>LHngB%bLF=hwcO=M+5_IH8XScnc}6f{sNv=%)C{ynt&ax_OL&shqtJ3?N(=LyyyL*04sBnH)R{W5UNKvs))xW_>69n(ouSj657LY?*p*!{O92T z1%JVYjBF;BMJ}ONaZlhU4<(pE`ybmVVQ1~v-!3i2JxcOv%kCWQX*Ue^hvS8mCwlQZ zhx5eriTjSWArH-h#YwbQw?}V9nOsRP=;#M>%V72Fgzpf>FT(cM<6RU=hBi+1By-gV zU*>(Jv9K$!C_zlO(LTEXP_iy)CM_BF0qfTpUG)3X+GZ2}NOh{;%BRfO$_HA|P4Xm|`)l z5C+NzhfI)o0Cku42YDZA7o;DhzB1s>Nq;p7g@n0|Wb|+WlK26aqxuVMD`?jHZ%Xpy z2jh92FFkmnKtfFBv8Mr?awdTtKt709pzDO&#^Y}XDtX=FAWQ3)m8GVL|7$zhQ&p;y z4OLQbOH*UdtC5t4WB#CD{$-gIgY3AyN1K~1$DYte&_AodBk>Fjnn(&ZeR(42J58T1 z#gcq*Re%tgs`kv)KE`F6?#p$+k;S6_WSI%SMPEzY+N6Hx*o1XK%lmKglrs11eSzP- z`ZNkz$WWomWx1o^);#eE*0<=TG*sR@N{8Da9f!Cisw6+9e7QSDCE>~jT$6G~UlZzn}! z&m3Pl)irTdA0XY@T#CRQjfg072{bkaR?|#yi?y8&7gK5L1-|zV?_o@-eqN^W`iB~>3HNMdtc|SNN&A(o)*~>PT%4{^i`cGA7278V!(_YPN zmasM0shucjYl!wxJ5D#w54@=>QM96J#LIj3fG`d8nT1*4dL>tq7*3s_zu(lBdt_`m?jw#Txm30F1f3C7UC}%=Wz1M4IEVj-#4cVp-f20(3r`O>-upLQWb3codS%+)I~Xc9Kh$ zI2=XQUla}zcMx0SC8e`yBl#MGVn07*cfauPpk62>GK+h6)!}rFJDts36`*jm^iueP z*bFLHul2LKv~Ol{u76xP9oxKyB)A-Xzu-E~vB-_K&TcUHLC+J*jM({9$Cf5`07fcM z`m-60J#K6A`9006T5ZqJBK)u8bA>PL2d>CBYWtFy= zC!pCS@74dvN}558EMw6FTIK|8yOI%Jc4GjkQsLyor9BY0$JYUdNRqmJ9wnL*G0A4| zL3nmQiG1?+&&9WJI4@~gQ7bR$#Y5?AkM07Se)YhOo$=kX{y$Kjq`d>N*c6(NZKe2f zMij(Ak(e?u#ehP48(oye&ptu&q;mW_ML4?_lf(QAPbuNmX5o*8Uz z;d2C)%M7C*xJ5~CswO7;CW_$#wW!Sti0P>?DMFss<_CCn1?ZU@R***va%XvM%Uy0! zu0mvxd*D~x%Foj>)Y96qtCedxG{%wlRj7K^1Heas>e|yqp{maJG~AHqOVcD`=h4ac z0ARVSz?fDA8Tz(qsY&zOcfFz$xC>#IWt@9!h7JU?<0N}SVMzZH;!Xd_XygraOL>Tq zX)pug4<^zL`-~+f7^-2~fAC@m+YsCQmbuIlk+4=wHOP~1tZ5$flO=?|dx-|9R-Br@ zK>3Putg7%Gl!Vmo{ciw=VC#|$k84*c{GQjLf&wo`^I(FIWyU256y8TBOKQ**hS_c@ z13GS=9rPFNZV6QoQIXa)q5}9s$X}HztDnh?4gf42*xkQ8(k<(xB1<7(u2D|i-XtwU z6Mk5sLn}No)HOdFk%&^C68;srrf%FcrD?0r`jUImSg?R6Edxz_&YCW)dZ+~8F!GgR z8u#XThU9*uVK&}eX1_PLnOzr%d4Ka6Kd-HEbZ~!S9gTZmE9f$0>knW%RvTsF?~zps zK0^Yp1i1VREQw>2?01}ocJV0B2BKMT@Lm#Ju+YeubC#TNM4KB>BNOESq#3o54WVkN_d3pzTHgK*d??L~x)8-%8eBp=JiZ z1NwC3j{j-WnXVkyJ#M!gU&}oK3-6y;$BFRK=W=a7WllQYT&v7}H+2II( z&i^3SR?02mj1Vp-r^fc#Iv-v+Xv-LTRi$>FZLiN}7g&>~4i^GS@L}e+mWk#v2zl0h zhpCsdyp)dwg6!QrK>43dCg$<&i!q`sDv99>-xi)C57I(%@vqOKp5d>23t1MCvnqX* z3A{R!=3qb6(z@Z$zaVn|A!C`wl3yjKrfV2GLbT}uz166cyE7UrN?9{ygk7bkMchvK z0Br1nsbYLV36KCKf|4<(pPIz$eH>+&=#|*XLgmve3S-gDasv#Ec0`BfI1$3ag%Me> z%K6#wXWbajKCi5P*2ZSxY!?Ro<{Z`?18OgShq0|%fbJ~+C=m@E_B#KjFRpoQ$)(@bF0{fQHO19-+N?mo8U2 z=v>2ep~U}>fZcw3HihXx34$7E3x6ndg392cI06#2$5uO8px_F0A%4714edbuXy2qU zX9L@;;@kA_FITgA&94=ROMC}gErO*Lv+F};t`;on3GVkx1-z5b>a&lmkGbK)P(|66 zK|?4&CW#w8{YpX;K&B)|@SFmZV|VU3IsR*eq&FgsG85HdZSWj*7zJseM(3W!YOORb z@V{Y)mx8JvFwi)7pmURre=A~#f_wpJqvD+;p@>UCzeK1RC>kxqOqao#X8K778Q`T- z_YHu411K1XJAIav`*ISt^_GH~7RlD^l?Iptw#I-t3M=fzsZ3{JJqsYZ&Sv<*L5rU%wd#)DcZmAwGdg|n+|Oh@AM#eDRx%+uH{w;fYL@K?K> zH}>@_L$()b#Ne0i!gE9;q{`b|Cir^U>!Y-c9la^}>d-KshLU;X{r3*wzX2*I;7-Ew z5OBC%my_K1MJZ}k^2b|BhW|-f#ffEUP^ws}^IyyXkgTC*AZP$W`mXr%uKhHqclXR5 z(wJ<`@boYM09XtMy-OwA;rTTmLC7RHL1zd|VgQ*;Izg<$jF+HbI<8_if(FTSlA zkn68VJb~WPC=4(zYYqXA)Bl?hF#OV7qfC07{a}MEP9jU?d@B6IYopY;O)oTG;rvOn zl=e}#3l`vF8{7xqBLS+(tT(aBqOD{DMuLatB*{YX?DTY6m9Z%RVCR|`_18Xw+sCon}+2R80;**R0i zS*1Qf;?s|YX3;@aIKUhR=s}>lj-qKUpHFfjPRIIa|LrU{#5qvD9#8^ zD&gid8CoNHjTbo~7^)b_8kVPpPh_VF$e+R*UPh;PcFum-glO~@kP<22Wb)GZ=;d>W z1gdC}n#vf(aX0?6qE!B&?@p=6GMu~#3kW~oJVxv^HXGb5C%x4&oPD)5PI&c}cyn4!w|6Ba94ZkMV=pjOC5@e`t0w!y`EH z#d$V#yb<${vTrH%RdqTEz^u<53Nv)HAM zUbb-B0(t2~R4fNaPg<2XND>N1K`55>gPONd-pvDG-__l3%D3m{O*3G&Q6veSe5-nE z9MgZ2n(-Z8lx1UZlo^W-iNBXr9I`crhztL0H0_9ckB-48xmDw4Rm*tBVu!ZW)}gYI zSl2>z@sN_=R0YmNuJ4!U@s!KFgY#}2yuckIAX`K5LkZoFz?kV6NRf~#I|HmW%8RD?l1w+n{GWIau)O27QUN`OMevO~ zzJV_%*Wkpj`LHli<(f~4*CQ}n?mA5*DXrDn?{J)`F|2sOX z>T_A&Nf`VU#6ydx>HhlyaBZKtpG8^x+a~v^TcF>UN6|cfA*=YqGbm!)-t_G_J5Zf~ zn5MHV@;ZC+8r=1`N~0CTDESN~-LUucdTJX)XqTnPT8^B6vIG6+R2*MwrZBCD3aX`P zKqi=4&aOA+yLpkw4fsk0=Q%VBuSMxs z{ADaisQJKzuW$CJVeI8JRO#+wy7&PdIDKll_BHC4jbVA5bs*+AC6Dtl&SxH(ZI#i- zfBm?7z%OHyNB6@4b}dIGbwqETFqQ07B2l0kUPeQ^v@Ws#0Z_c|i9C5m{(v;4T(>+a z*}G5ioyuM?^U&pjw3nNQ*EVt zbvTs4O9tgDbOzGsg}zS4$>$#Ie7|8olxvCSChMza|-d~9rxqX{>Zwf=kP^mBj; zh=wjdMs;V7(HE(nEIP~ACMd`^Qf zy$u~Cm47N(=}PhFA61ihYEqP1Fs$198pliCq9;{nYA+@Y`R2sxL;A89Wg(gZHK02! zn&<7;B;b|P^`GD1{OAlY+p+@V?QBA?YO7F@8!ptaY3A9h-+o^&)yb{>n%D1CjD6(9 zWb!7V;wv}H_^Q+aN!~%*MwlZPh+J?ISl-pMV{XX;{(i--eN8%CKNA~9{dQ3+6*FV- z5)b^0&-#5_67UCZlI8iV-nVeP_lBG2g-TloRBjv44|-&5^G8HvW!`;cm5UCFqQ9Wu z-!4>Cif%(Ay!-75WK@+oFcM%!^t^{O%LN62-su0!snFTf{BAnV2_BThRbKp#3OcCB zEBTH7^AR`1mw(b876p4*md;M&q0a%-6|nwK0L3n5!b=QUH)V7-9XVrJ78sm22@xU` zg;2}TK7AoT)QTuUjZHe2^zm@%Jx6h5b^#&CnHHFns3b;c6n4q$G>D7>YZb82EYn0% zF$5A9DftT=jOiT0>F3C71Go7{)SGQRf7}#4fFOdCqV_r;I0Ge*oGg0|4(`6e!&3kz zUH{jxF|lwy7Oga4$Wcrr33lDMSELqnrms3L2{|AwSz6O4AxA#XvVrZx88tip*c{R_ zK3#Z&(0_&7?8uz#zNy*P2bScaU<=4Vt-@S;L*pP$-yfbF`MV&ZOT%*@T@e~(^P|d3 zPg?&uTwUALx!;7@Y>883kkOs|_V{@7xG4WRg{w=cd$Z(oIngg%JD*Z#O51vNcMFKG zXzws|oVKG;D$?0D(7vC3G9H4)lWd7*Dy!1gzg6ikW{i-e$jQ&^eaCs%1Y8K$yOhhB zKVS*JACF+$P>7vlJarnHO%4oFRs#qh{JMWm)N_FqUR{JvP3ws0Ue%CMkWY<`X{1vO8YFc8F@V zclS$mV)I_aHjgDyD_ou(gm}D2Y1|PloKZwgo!br~t&FB`o>CeZn2bsq;VSXrnn09) z*Qo$YS!7u6qQ^bXe|5(Mh-l`RGt^E6?yv~ypyvoTPm3)Vf9M7TeK+k21*B;AU&T1# zQlL|Q_qE(|!%{#x+7o%BsTTFSh@+@W5gMG^$Ll9>6rrW3m*A|aYa--Af`W$-Yc-9&u-)AuOb?AWGu+?Fib`dXaq6t?>wm|xe$a2I;Bsv}FsP$>G5Xy68fg~ zJK!X*K|Byw9j`i4XT9}2NtjZ(^i>@vk{c6hCv6xJvb3P3`PJ33kGlH$(FrqBkGcj1 zrw;0#%h#Eef~(C+`(|<%DME$SIVBYpijRUm3m0NRR}#citI#Ih?QJ}^^{VqytD4?>QCQJ-lYU(B0KpJ_LrY7)iN z>H2o_i@O|5ZYwW+my?aU%3|{MUk4@uMQ5m7kC!{N*-Ekot0m3qk#!5-s&#CtpXqKW z?;cMf9scY^&{c1vZvFgsE*-tueJf(Ejrnm{8-fr?84foD~Gh(b>xqI}PDL&Rv zKl>U|*m|^dC6Vg=82{v|>XVw!dpv`5JB?=Rr>7{Y`RS%Tb5n5x1p(_$MO8I{*|V@@ z0LD)Env_2#*0IoQ*_>0GsjA~HuCK4p#B(BY0;y^o5-amCZ*^~8Gj9|e-fj+kS~3cb zUknTk#Gnkw)BkmP`B+pW9ZKWk4|D5q9`wgLbhX10`@eNHuhDv-xD_5gDcMzocNe&| zo7HTYuCK4-%N>z+)ttV~Sa$PkZ@ats*VUdg8to|6^9y|?gB)V2M*vQe{cS+gKW{I9w<$C{j*%T)37m3-+gIb@LpsoOE6a?=1SR6MwVFIW!dMrA(~C@} zKTld(1I*Rm9K;U6i+{dE^Q1M157RL@=Q+L7%Bb8jQT%&%UZ1H*GMJOyJsd&0>U{~! zy1M78w5TLssv7)q+MkG_8I+S71UC6!&qD73KhRpwM0ay|wn^)cb#>)@b%hCLhTQ;n zd*g;hf2_}+1GH+$cB%ujbl>hdAS0!Zo44MdoM8~O8@+!Ek$=mWnj(hg*D-dB8Ni#` zc#c%p#WJ@*!bW{B;W|TAkahH7^7f-uE!H+?Qh~)1_sD4SVPWvx-z4iA_~LVIE5Q!O z%8-yylTuzIq%+_pF@pQ++CFvehb1F!Cel z;szlGfzP@2X1I6z$Ak?gdPZeWoI1MK6V09$d~upGQ0}9Ztq;htA7B+!TG6C&CaX~e z=g2OlxGpq1;DQCe-@p};iYYQ>$H*KyBTPHnpt@>5AT*^HA2Ozd!axROmPL!;#+jyv8Q0#$T|%z{%iCE zD1`QJ%{$PIiW-1P%;f);-)XGf8#Q%dV!Pz=pwupHB(=1(RH!B8KG87P?yvlnE@CdD z12yBbih4AJ6lc|gAn23LAz9?ybN!NfW}Y#GEYznxuRr@~O^;M1Y3TX+>&q((Nd7Tp zoOO@s8dl}=@S0s=ri`jFNA1gIWBVf#jz2F=6Pj(Sos_5g&8#fFuMk;SQ8@M? z-c__+&O~j0;jG%!$<(tykKja2A8N*Q+4MVe)Zy9$hK`d*pLoV@W@)J(DwRElEOSa*urVdiC#8U5!t0yNw>l3j zH&5p~O38<2Ty&#j>yCU9qe8Q2V6*)zL(|dM$0jDGGGJw9wz3=?PW?61*Vtjs`QHT> zA3vJ;%X}ow2aI`B(4~JyfpmE|UP*KPUA6{8Vz^aEBLV@3Y%rx>YL}=|CnsSblU;+h z%Zup4vSoic?IA7V0v`FK_m(pcDh|33@n}Zwlp{NB9cLk~bnLX5%U5vUWGK%@$FUHP z3Mby2Er0qY#1j=>^Ty1oMsXODD!C2Y^{7ysP8eHg=7VahCBPG{e@(7JYWZ&lz5HjL z=MR689p9R+c!59}uBvULE5uLh7?T;>t0W8qk7m}ZWn>j_1^=kOYynF|t|X2Wk$tn) ze^i&O-GAV^Y8pP;BBYUla}d;uPqHz{!QU$ogXeBSDibogm)&lY;1H_OuAbUF=dkt_ z{@e#x`X?t-`D0;Yujfjc2|nI@c=+4!>+bH56ilm$A?6f7Ph%cQ_yDtAG}isYLc0`z zD8lGSqu;S~F%DC8eG3AseyJP^EqU}(f|tJn?VyA}O#Hu{4EUrgIvVCz+OxJ45xc)y z-ozEy?X)avsa{{9y0(MiZ5kd6(QzvwKcRoRt4&$eBTOV%6sCC{7Ru`fd#pW%e5qv4 zmefD=%E=H>NV&OBD|O%wPC0!u3x!{Nta(!y!$|?&$dSW_`t(5|&k34w4ZMMq!^m#F zSxp0jMb%I%MAds@@@R3#MA24GiuwuxxjHrjb#~W~adCTB1>NBr@pqwF+tFtBp2hesQu02+Icv>wTs|C^j54hZh#4uPnMZxwM*zKre-{-<+y$n-qj`rCJZvHrMmGa}P^wOv)Y;-bmrDEp&SY>da?wV?gR)I>g`>9EI~2|Jmv*CiMa z5?4w55~UK4jgg^59uljI2Gz?~R}49-dt0*9-bV28>YdpEy2-63X3Su(q=bZI>M*I6 zg$SDQ@tjD-%-4#Oa399|{=rOER^5pu*?f?ZthH?~#*@QzBWhGhP3ZtFmV(W^ z8o?v9tTnqLm4(QeyGm>G0#qfs*z{4|QKMy((?im_9I>f$8`c^qqO?Vc=uaB%Ez=Nz za^9GU_$`?X3`LB{yo}M(8Vy+eq$*N!+?nG@tv&l=0ggLJldSEzD=GaSM{8Y(p3kxI zXn;fgbwnw38glyf2Ubg{fYbK7@-l{LH;K84iE3acAD#K3cfZxWKW6)4m$h1(`L&Q! z=4hQU2&q}ZK_}CUz^POe45YEt)STNJCv5Yeafm(?KlfZ|VjOyw?OSK8<9*wpW#dwM z3~n0z>(Awl7ExB@wFXd$R}0MajQf3Nyl65Rk&M0-#J`DQj1#a_hCjSa_W^x3nX!EI za)i_S*ZIE8B46vg=fs(N2KC>{P9QuHK<3x3e?cPTuRPj<<$a3uL?38n{joU8>qYp- zYair)>ez7DjWW|SV~Z7`ULVNBl+_AxttIEbfYUEmvv7wO4kuvrd*Wr|ss5fztx)+8 zEI5j)=lkc#7MBTJ?JJXKx_Wm_wDnmdX4Bt6`aYp~i*-468ZY>_vG{8SfA?COl2}I{J*_8)Lqz8`I+f z-tR^F(us-EkB1eIY8|&4QXd3_XCvk($&u!TGJ66N-!us8I!-g?uXYFocjuAft;moa z=FcZ)2yXL;7emGC@_tBX1Z)ehJ+x3YE}O+Byr6p3oUP-rO?l2Rq0G82gHmsy zdn!n<=I+cFk3U#_^9~?|jV%Fz+g-y}jMwS1r9NLBEIg;2TG#}chdTzX1t z@g21-C6%4{2FhK8YcQyWl~3aO31#el&Jpuo#IE0K8P-qWO3u3Q@Ct*qmh8W`seyN+ znmf||tZrK=Sx2q4VUSb9&FPs48W^_~`7~l3;c-;81SY3}a`rZ-2S-&~+mu_XxGUGl z$VgUh5ErL8Q1eVkzzRvY%63hA{JpI*ZkxTM-aW4Qj*0w$gVWfzIQ(JTQtSh4YiFop z27}FqWSta3llXP+cmM6R5+YYT+h5NnKzRVJ#kxCt#*5+Sdm;EtZhyzJbM4yHqY|$} z5uUn_U5H->m=Xq4yfzis#&S@7#B1-preM zdxjYTd;fp-U)K88xAtD&cx_!rW6IfExdi6Bqg|IbT;wm)`6QB`lycl-{uAicX$Ayu zZ!asu!F<4yz$Uv-HC)bb(Z|%()Xi;%w$%>GOk7;O9UW5hCd0!CuCARh_EAyVYuf7S z>XxbMG|&~xMd!c7;Y7s=u`0P9I!Qqbfogk}j))tHVK>R{jBDv|vF?_U2AspD_U)V9 zP22l+>y0aGDi_X50sFHzaaFai(NUtm#nuPp_pbOj8uX+b7&$g=L49^$#MfY3DV7p@ zDw518+U)cwwTAcAyB8u#bMn3cqM|Q{9;TySeBeQ?h0#Qfje~S`V~aQ&KeGZimb=OW zM_&^kM@2`Q7ETO4Iqt0JIT8K&=CxBrl1W$C8)Ae=`FVNglCHdcE6EV#v8eu@Rj}Lf zgXzr)-SDVS5s?W#gu_g8FoggFt#B^^KfqxGLY+?5tNaE*9i2 zJs9RBDH_WazQ9opVUj|2A>AF|$rQXM*SBW2kBc>}e`HjVI=bH=x3BPa9STqf)Bdsk z3QRJqpp?{|zETbl4a?Qf$f4bUimu)Ff5fnUyvMVc^q!IP`{_{*qS@esjR-LnTXd}< zS0r}~ElxkmgR0k=`9g={3ZHvw_U>u5laeaeLxL0c z-F*3_<`KP;GX9wBVB?clUz80=F&x*pkxbsbi6bU1@r=(D99RHVB-kusj0uz*uPguTe6?j zao1axvDXJ8sjsK|<*#gm(nKcj33z6}D&Z`??lVoZ3tBsN;n#{V^1{LMp`mIKl-h?- zo)Mn2IdSOk?sXH-)uVN7=4E#>!+^oDCmwG17->S?Jy$0k3R4bnKSZ8Cgb=+y3DFYmdV<4pVkreuxU)0MmJvpEBtR6f@ASrv3dxTs;2WT&0LUPEFeLAx3!?6VrCgI(DMAa zc-dn8xBR${{abT`pEY9mEQr$!VPU(m4JT2P{oCdOm+bB9X4WZXxhf8yN%>01F_6t(n%(4g z3zb!yM!c2(D`RSPr1zI89qpjiL4IslC}&M{aY8pEq9%{1HVdS|4lN*sgsd|0m-bUX zgQT9;T2*t9bR*T|xW?UHuar2yU#AAgHeD6QygQuRXrIORYpJT{X4dM)O+xA5sp4;p z!3U*no7fC@AgmxF9^w)COH>Wcg+Kvkg9tA+F%k5~HU~IX zz$t@Zip)`c2-ex*gLL#c8xX>tbd0@f5j!ZDseCX)%)TXk{zBb<+F))qLdFlBC= ztC1Aa3h2=4Y+1aQvtORnkS#%4gt?d|=tu~+L?tdx^_)`J=zPRY1k!ZvnWULRXMntI z)8NmaIkxF*gs)$JW7j!zWDk;t$K!)ON3DRfB9vdh`bOl`Xw$cE@njUn0YGwV>)ni% z2_!hPefnxX^mu^t+!q^(6GGjhqBuzD3{#;ZyN=$plXS{)LBY1R>mYOs(i#4s;U*M! z4Sm(h3Is#zp6?27YLmT+tLP@Je0+1`K`86R@PpmNnanPpB`T^p`r&(^Kc<#L>gz@9 zS&)K{cKcJLs6UHjaqIQ}20e48I~b7Pb1BujpkCzY7`-VcB$QK7U`ewyHs)hvJBtB0 zAZ~refPY9EaL=7P^jI|c{AfSaG-RtiipZM|s!sjZBYNABXnGU4`~ABw1_XEuRKwcr zML&6Fm%EIpGVkC0VBOSk&ov{X>^?V(Gm_cacXTN@M&!QOPLqVFh&}vD@`E3G(11mJ zwwCUUk8k;{Obds&kSL%t>M%GzUq3&u-NcAksWqnyB#^J(ny-8iZt{9vR@^ykT~tsS zQS;+aryBtld8dp74h_oiiivhoSC=9b-Y*x-AIC_4s~!z z=zowy_mYa9^!QsFhOi37NuG($E<`*Iz+rw6X8ND3Q;T6Hj0rT^IFdI%zYo_T7;;)z zZe=7z6skKuM^gsAH3Cwx!rRloS;^%~8X6`hWXrvie}PR+n0!x9&xypHE=b5?W{dHF zkch}cm+iJ0EdXrtOC$am9^b)ycmaxC2i~VmI&Yix;wywS4T)t2M#JZlqTywqy1L?a zs;*wDENqx4$bm@1Us?Fe)<(F8sq`Uh(s@wH%Eku#jHa(|C|-#6XKB1lbvt*msagsGMimK=-SOIlJN9t zd~)(R=e~!K`2tB(Hnmq4#JO$fbP^HGp&RSsM) zcz%%yBo%NsZrlI@brqEo+pB`mb3TjvzQK9|aa}DJ*Rzi}h->fllmL`|%UTw3iepnE5h{-WTBhNDX$D!*KTwSOMOq8l0V*irW$|UhxhKz@h89g3KP%`JyBN) z`LRtGb+mQ!g=Mp+UkIcf+;cefoq^ZBzM5FQ`M-4E{{=t91_hEPE$+(yHXg;(r5#|A0iIq1GKezbx7MyDzC;8{5$>wfn==_c=-i ztstO1=Tlx@9{9qrS;@W+Q#~BkKKEvA!hcbv#Ws}3%z{<2$x`W&tva3>wIt5Z`RR_m}#xT$HiG@2v|8YSP~^I_W&{Wgp5KhciE;uO81;y z>~*8zHhonKNP7Xypu8KN0Xw#}K0bVC#J6d?p+XTueVwH%6c?nodhp=5&~u%or6rsR zW_~En_i~miZBw0$B3x2e54)`eH&x)j(gy=OKJ;a}*UV#mu?wVb-wxJ3?Dxa{Sf?_D zdHGgsp!JDpSC9sYX&CmSt%X9;Y|$ltWwL9#ie;4KU2&Nu)U)^{RD%UOo#&*;dwDWT zBZh+`BlY~~+w->CiQ*XB<;kSyR(&NU>qkWU_$4wc@Q>Y$5*!+n^?}V$RP0^+dVV`0 zNlxw5uKuDq=3IBsdb|8!Db#sgZb2K7Z&mZxVrRpL+T*c|h$Hx&7nmRg4KC>=)i5KLGS3nK)icl7ry0Oe_S}?ZF#l@xesx;~; z?Z<B{%;d3kN zEJ?@CSK)&LudE5-_B?T4NAghHes?WXPs(>Y5>FW#8;5QZE$ZuvahUB30@dT~wgZEt z@Xb5sM%Ue@H`g9oKk8{wu3O@4TVns{$z7F=qPeYq{DTYv)+bLc0X+VuuSyz8MxVE( zsqMLDZf=Z1IlrwQ8#*N9L|N~M6*x#Zc-&9+r-JOC)C;Z##>V(`3&`$&ekkCty{4EX zW?59^x76L+%LL-KQ#&P+qUW{O$Q87+$8Qy}ezK7$q8tF-$$3!pk}3z_Sj)dn0oiCt zr|uI1A(h8MBuZEM!eLt~p5XU*1;}G{?p9Tmu3FL3)xP9p9i7B8AcYH0hPdCcvMOU$ z+fxOPVKt|bB!V`Nrd^r@1Bs~Zym^dL<;~P z7im4OJAU#HmcJhwNMZ6*MX)np;LlP*6<;`(|QdVyeemKJB=t&nIseO*6~yl)qCdYa^*E$~4`Y(< z^ZN9uyK{N5TTOI^CzbsaYVVXYvEWuM{ukf(<+tNuys|D=S+Ms6s@IoN=U?IjilU3PaeUTOD(=Nc^jGkr?n z7+%Kdm|nbCRr3g?xYBzcT5<<~6Q@tJJ{Zwn_xFIM05HB)8-;sm2~0CAz=%=C%~)(~ zOJIGx0@#Y7!0RBa@pB;T0P1Vm!P|N26Pe&FCEA_eUok>EX0-GlNQSE2s^POE(N>WO#1l5#;qPfN?} zV*5hWL;VuU^oti;T3TfxtY9O7SSmqNb}Mv**0E zCx|^;kj~nkFsZn5r2r-Dc^X49g81(PxUW#wjpe}p_qI2`pmMUIF2SYU3q5G=v=jxa zYi&y|PpRksWc%oOs4AO9+4TI~Xm<#1(mu|HZL6>#{?hZhJv^ z(4xRDJ$h7FSPPWQub7%X)6-jh%rY*o+k5m;4QYn2!sVwZX0>Wt@0o;j2thD36eVst z>jn@90F?iD+mQ)sd+xT!a6QXQoC6qOaKWCm%~17+H0R3uSdKG3#U&**Q?S*hT?d2S zfiQXP<0Ijwz8W!2d3gL9ka2_h81v=7*f=zi^;246CydV!EbOpNZ@Gd7ZgzIB70TfD zJl1=((H{WSW4^N--#k(pM@Z9LL`Snf^aQ=MwXZ|8UFs_?hN4Yxt?2Jvn`h_9uzd4l z_|qqX%634*{axZDOFV#pw#o+@dg+Q~9^*ad{P<;EG*7io;z>15-G-}^@5K+Z2PxgD zua2#_BE$Rj;`Rx$ttQz5Av^8I(h&lS55LqO90^n2)dF1`^ClXIh}eO!v1h|57gf{~DRRZ6^7{91^w*_oC<% Oprx*N39n{z|GxmgK*31> literal 0 HcmV?d00001 diff --git a/trainer/train_dapo.py b/trainer/train_dapo.py new file mode 100644 index 0000000..2965b05 --- /dev/null +++ b/trainer/train_dapo.py @@ -0,0 +1,421 @@ +import os +import sys + +__package__ = "trainer" +sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) + +import argparse +import re +import warnings +import torch +import torch.distributed as dist +import torch.nn.functional as F +from transformers import AutoTokenizer +from contextlib import nullcontext +from torch import optim +from torch.nn.parallel import DistributedDataParallel +from torch.utils.data import DataLoader, DistributedSampler +from torch.nn.utils import clip_grad_norm_ +from torch.optim.lr_scheduler import CosineAnnealingLR +from transformers import AutoModel +from model.model_minimind import MiniMindConfig, MiniMindForCausalLM +from dataset.lm_dataset import RLAIFDataset +from trainer.trainer_utils import Logger, is_main_process, lm_checkpoint, init_distributed_mode, setup_seed, SkipBatchSampler, init_model + +warnings.filterwarnings('ignore') + + +def calculate_rewards(prompts, responses, reward_model, reward_tokenizer, args): + """ + 计算复杂奖励,包含格式奖励、模型打分以及 DAPO 特有的长度惩罚。 + 输入的 prompts/responses 已经是展开后的(batch_size * group_size)条目。 + """ + def reasoning_model_reward(rewards): + # 1. 结构化格式奖励 + pattern = r"^\n.*?\n\n\n.*?\n$" + pattern2 = r"^\n.*?\n\n\n\n.*?\n$" + matches_pattern = [re.match(pattern, r, re.S) for r in responses] + matches_pattern2 = [re.match(pattern2, r, re.S) for r in responses] + format_rewards = [0.5 if (m1 or m2) else 0.0 + for m1, m2 in zip(matches_pattern, matches_pattern2)] + rewards += torch.tensor(format_rewards, device=args.device) + + # 2. 标签存在奖励 + def mark_num(text): + reward = 0 + for tag in ["", "", "", ""]: + if text.count(tag) == 1: + reward += 0.25 + return reward + + mark_rewards = [mark_num(r) for r in responses] + rewards += torch.tensor(mark_rewards, device=args.device) + return rewards + + rewards = torch.zeros(len(responses), device=args.device) + + if args.reasoning == 1: + rewards = reasoning_model_reward(rewards) + + # 3. 超长惩罚 (Overlong Punishment - DAPO 特性) + len_penalty = [] + for resp in responses: + curr_len = len(resp) + if curr_len > args.length_threshold: + penalty = -args.length_penalty * ((curr_len - args.length_threshold) / 100) + len_penalty.append(max(penalty, -1.0)) + else: + len_penalty.append(0.0) + rewards += torch.tensor(len_penalty, device=args.device) + + # 4. 奖励模型评分 + with torch.no_grad(): + reward_model_scores = [] + for prompt, response in zip(prompts, responses): + pattern = r"<\|im_start\|>(system|user|assistant)\s+(.*?)<\|im_end\|>" + matches = re.findall(pattern, prompt, re.DOTALL) + messages = [{"role": role, "content": content.strip()} for role, content in matches] + + tmp_chat = messages + [{"role": "assistant", "content": response}] + score = reward_model.get_score(reward_tokenizer, tmp_chat) + scale = 3.0 + score = max(min(score, scale), -scale) + + if args.reasoning == 1: + answer_match = re.search(r'(.*?)', response, re.DOTALL) + if answer_match: + answer_content = answer_match.group(1).strip() + tmp_chat = messages + [{"role": "assistant", "content": answer_content}] + answer_score = reward_model.get_score(reward_tokenizer, tmp_chat) + answer_score = max(min(answer_score, scale), -scale) + score = score * 0.4 + answer_score * 0.6 + reward_model_scores.append(score) + + reward_model_scores = torch.tensor(reward_model_scores, device=args.device) + rewards += reward_model_scores + + return rewards + + +def dapo_train_epoch(epoch, loader, iters, old_actor_model, ref_model, + actor_scheduler, reward_model, reward_tokenizer, + start_step=0, wandb=None): + actor_model.train() + + for step, batch in enumerate(loader, start=start_step + 1): + prompts = batch["prompt"] + batch_size = len(prompts) + G = args.group_size + + # 每个 prompt 重复 G 次,展开为 (batch_size * G) 条输入 + prompts_expanded = [p for p in prompts for _ in range(G)] + + enc = tokenizer( + prompts_expanded, + return_tensors="pt", + padding=True, + truncation=True, + max_length=args.max_seq_len, + padding_side="left" + ).to(args.device) + prompt_length = enc.input_ids.shape[1] + + with torch.no_grad(): + model_for_gen = actor_model.module if isinstance(actor_model, DistributedDataParallel) else actor_model + gen_out = model_for_gen.generate( + input_ids=enc.input_ids, + attention_mask=enc.attention_mask, + max_new_tokens=args.max_gen_len, + do_sample=True, + temperature=0.8, + pad_token_id=tokenizer.pad_token_id, + eos_token_id=tokenizer.eos_token_id, + ) + + # gen_out: (batch_size * G, seq_len) + responses_text = [ + tokenizer.decode(gen_out[i, prompt_length:], skip_special_tokens=True) + for i in range(len(prompts_expanded)) + ] + rewards_flat = calculate_rewards(prompts_expanded, responses_text, reward_model, reward_tokenizer, args) + # rewards_flat: (batch_size * G,) + + # ------------------------------------------------------------------ + # advantage = (r - mean_group) / std_group + # ------------------------------------------------------------------ + rewards_grouped = rewards_flat.view(batch_size, G) + mean_r = rewards_grouped.mean(dim=1, keepdim=True) + std_r = rewards_grouped.std(dim=1, keepdim=True).clamp(min=1e-8) + advantages = ((rewards_grouped - mean_r) / std_r).view(-1) # (batch_size * G,) + + # ------------------------------------------------------------------ + # Dynamic Sampling + # ------------------------------------------------------------------ + if args.use_dynamic_sampling == 1: + if (std_r < 1e-6).all().item(): + if is_main_process(): + Logger(f"Step {step}: All groups have zero reward variance, skipping...") + continue + + # ------------------------------------------------------------------ + # Actor forward + # ------------------------------------------------------------------ + full_mask = (gen_out != tokenizer.pad_token_id).long() + + with autocast_ctx: + res = actor_model(input_ids=gen_out, attention_mask=full_mask) + logits = res.logits + aux_loss = res.aux_loss if lm_config.use_moe else torch.tensor(0.0, device=args.device) + + labels = gen_out[:, 1:].clone() + logp_tokens = F.log_softmax(logits[:, :-1], dim=-1).gather(2, labels.unsqueeze(-1)).squeeze(-1) + + seq_len = gen_out.size(1) - 1 + resp_mask = torch.arange(seq_len, device=gen_out.device).unsqueeze(0) >= prompt_length - 1 + final_mask = resp_mask & (~labels.eq(tokenizer.pad_token_id)) + + # Token-level 平均 log-prob(防止长回复主导梯度) + token_count = final_mask.sum(dim=1).clamp(min=1).float() + actor_logp = (logp_tokens * final_mask).sum(dim=1) / token_count + + with torch.no_grad(): + old_logits = old_actor_model(input_ids=gen_out, attention_mask=full_mask).logits + old_logp_tokens = F.log_softmax(old_logits[:, :-1], dim=-1).gather(2, labels.unsqueeze(-1)).squeeze(-1) + old_logp = (old_logp_tokens * final_mask).sum(dim=1) / token_count + + ref_logits = ref_model(input_ids=gen_out, attention_mask=full_mask).logits + ref_logp_tokens = F.log_softmax(ref_logits[:, :-1], dim=-1).gather(2, labels.unsqueeze(-1)).squeeze(-1) + ref_logp = (ref_logp_tokens * final_mask).sum(dim=1) / token_count + + kl = (actor_logp - old_logp).mean() + kl_ref = (actor_logp - ref_logp).mean() + ratio = torch.exp(actor_logp - old_logp) + + # ------------------------------------------------------------------ + # Decoupled Clip + # Adv > 0:只限上界,允许正向大步更新prompts_expanded = [p for p in prompts for _ in range(G)] + # Adv ≤ 0:只限下界,防止负向更新反弹 + # ------------------------------------------------------------------ + surr1 = ratio * advantages + clipped_ratio = torch.where( + advantages > 0, + torch.clamp(ratio, max=1.0 + args.clip_epsilon_high), + torch.clamp(ratio, min=1.0 - args.clip_epsilon_low), + ) + surr2 = clipped_ratio * advantages + policy_loss = -torch.min(surr1, surr2).mean() + + loss = (policy_loss + args.kl_coef * kl_ref + aux_loss) / args.accumulation_steps + loss.backward() + + if (step + 1) % args.accumulation_steps == 0: + clip_grad_norm_(actor_model.parameters(), args.grad_clip) + actor_optimizer.step() + actor_scheduler.step() + actor_optimizer.zero_grad() + + if is_main_process(): + response_ids = gen_out[:, enc.input_ids.shape[1]:] + is_eos = (response_ids == tokenizer.eos_token_id) + eos_indices = torch.argmax(is_eos.int(), dim=1) + lengths = torch.where( + is_eos.any(dim=1), + eos_indices + 1, + torch.tensor(response_ids.shape[1], device=is_eos.device) + ) + avg_len = lengths.float().mean() + reward_std = rewards_flat.std().item() + + if wandb is not None: + wandb.log({ + "actor_loss": policy_loss.item(), + "reward": rewards_flat.mean().item(), + "reward_std": reward_std, + "kl": kl.item(), + "kl_ref": kl_ref.item(), + "avg_response_len": avg_len.item(), + "actor_lr": actor_optimizer.param_groups[0]['lr'], + }) + + Logger( + f"Epoch:[{epoch + 1}/{args.epochs}]({step}/{iters}), " + f"Loss: {policy_loss.item():.4f}, Reward: {rewards_flat.mean().item():.4f}, " + f"KL: {kl.item():.4f}, Len: {avg_len.item():.2f}" + ) + + if (step + 1) % args.update_old_actor_freq == 0: + raw_actor = actor_model.module if isinstance(actor_model, DistributedDataParallel) else actor_model + raw_actor = getattr(raw_actor, '_orig_mod', raw_actor) + old_actor_model.load_state_dict({k: v.detach().cpu() for k, v in raw_actor.state_dict().items()}) + old_actor_model.to(args.device) + + if (step % args.save_interval == 0 or step == iters - 1) and is_main_process(): + actor_model.eval() + moe_suffix = '_moe' if lm_config.use_moe else '' + ckp = f'{args.save_dir}/{args.save_weight}_{lm_config.hidden_size}{moe_suffix}.pth' + raw_actor = actor_model.module if isinstance(actor_model, DistributedDataParallel) else actor_model + raw_actor = getattr(raw_actor, '_orig_mod', raw_actor) + torch.save({k: v.half().cpu() for k, v in raw_actor.state_dict().items()}, ckp) + lm_checkpoint( + lm_config, weight=args.save_weight, model=actor_model, + optimizer=actor_optimizer, epoch=epoch, step=step, + wandb=wandb, save_dir='../checkpoints', scheduler=actor_scheduler, + ) + actor_model.train() + + del enc, gen_out, responses_text, rewards_flat, rewards_grouped + del advantages, full_mask, logits, labels, logp_tokens, final_mask, token_count + del actor_logp, old_logits, old_logp, ref_logits, ref_logp + del kl, kl_ref, ratio, surr1, surr2, clipped_ratio, policy_loss, loss + + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + description="MiniMind DAPO (Decoupled Clip and Dynamic Sampling Policy Optimization)" + ) + parser.add_argument("--save_dir", type=str, default="../out", help="模型保存目录") + parser.add_argument('--save_weight', type=str, default='dapo', help="保存权重的前缀名") + parser.add_argument("--epochs", type=int, default=1, help="训练轮数") + parser.add_argument("--batch_size", type=int, default=2, help="prompt 级别的 batch size(实际前向 = batch_size * group_size)") + parser.add_argument("--learning_rate", type=float, default=8e-8, help="Actor 学习率") + parser.add_argument("--device", type=str, default="cuda:0" if torch.cuda.is_available() else "cpu", help="训练设备") + parser.add_argument("--dtype", type=str, default="bfloat16", help="混合精度类型") + parser.add_argument("--num_workers", type=int, default=8, help="数据加载线程数") + parser.add_argument("--accumulation_steps", type=int, default=1, help="梯度累积步数") + parser.add_argument("--grad_clip", type=float, default=1.0, help="梯度裁剪阈值") + parser.add_argument("--log_interval", type=int, default=1, help="日志打印间隔") + parser.add_argument("--save_interval", type=int, default=10, help="模型保存间隔") + parser.add_argument('--hidden_size', type=int, default=512, help="隐藏层维度") + parser.add_argument('--num_hidden_layers', type=int, default=8, help="隐藏层数量") + parser.add_argument('--use_moe', type=int, default=0, choices=[0, 1], help="是否使用 MoE 架构(0=否,1=是)") + parser.add_argument('--max_seq_len', type=int, default=66, help="Prompt 最大长度") + parser.add_argument("--max_gen_len", type=int, default=1024, help="生成的最大长度") + parser.add_argument("--data_path", type=str, default="../dataset/rlaif-mini.jsonl", help="RLAIF 数据路径") + + # DAPO 核心参数 + parser.add_argument("--clip_epsilon_low", type=float, default=0.1, help="Decoupled Clip 下界") + parser.add_argument("--clip_epsilon_high", type=float, default=0.2, help="Decoupled Clip 上界") + parser.add_argument("--group_size", type=int, default=8, help="每个 prompt 的采样回复数") + parser.add_argument("--use_dynamic_sampling", type=int, default=1, choices=[0, 1], help="是否开启动态采样过滤") + parser.add_argument("--length_penalty", type=float, default=0.1, help="长度惩罚系数") + parser.add_argument("--length_threshold", type=int, default=1200, help="触发长度惩罚的字符阈值") + parser.add_argument("--kl_coef", type=float, default=0.02, help="KL 散度惩罚系数(相对 ref_model)") + parser.add_argument("--reasoning", type=int, default=1, choices=[0, 1], help="推理模型类型(0=普通模型,1=推理模型)") + parser.add_argument("--update_old_actor_freq", type=int, default=4, help="更新 old_actor_model 的频率(步数)") + parser.add_argument("--reward_model_path", type=str, default="../../internlm2-1_8b-reward", help="Reward 模型路径") + parser.add_argument('--from_resume', type=int, default=0, choices=[0, 1], help="是否自动检测并续训(0=否,1=是)") + parser.add_argument("--use_wandb", action="store_true", help="是否使用 wandb/swanlab") + parser.add_argument("--wandb_project", type=str, default="MiniMind-DAPO", help="wandb 项目名") + parser.add_argument("--use_compile", type=int, default=0, choices=[0, 1], help="是否使用 torch.compile 加速(0=否,1=是)") + args = parser.parse_args() + + # ========== 1. 初始化环境和随机种子 ========== + local_rank = init_distributed_mode() + if dist.is_initialized(): + args.device = f"cuda:{local_rank}" + setup_seed(42 + (dist.get_rank() if dist.is_initialized() else 0)) + + # ========== 2. 配置目录、模型参数、检查 ckp ========== + os.makedirs(args.save_dir, exist_ok=True) + lm_config = MiniMindConfig( + hidden_size=args.hidden_size, + num_hidden_layers=args.num_hidden_layers, + use_moe=bool(args.use_moe) + ) + ckp_data = lm_checkpoint(lm_config, weight=args.save_weight, save_dir='../checkpoints') \ + if args.from_resume == 1 else None + + # ========== 3. 设置混合精度 ========== + device_type = "cuda" if "cuda" in args.device else "cpu" + dtype = torch.bfloat16 if args.dtype == "bfloat16" else torch.float16 + autocast_ctx = nullcontext() if device_type == "cpu" else torch.cuda.amp.autocast(dtype=dtype) + + # ========== 4. 配 wandb (SwanLab) ========== + wandb = None + if args.use_wandb and is_main_process(): + import swanlab as wandb + wandb_id = ckp_data.get('wandb_id') if ckp_data else None + resume = 'must' if wandb_id else None + wandb.init( + project=args.wandb_project, + name=f"MiniMind-DAPO-{args.learning_rate}", + id=wandb_id, + resume=resume, + ) + + # ========== 5. 初始化模型 ========== + base_weight = "reason" if args.reasoning == 1 else "full_sft" + + actor_model, tokenizer = init_model(lm_config, base_weight, device=args.device) + if args.use_compile == 1: + actor_model = torch.compile(actor_model) + + old_actor_model, _ = init_model(lm_config, base_weight, device=args.device) + old_actor_model = old_actor_model.eval().requires_grad_(False) + + ref_model, _ = init_model(lm_config, base_weight, device=args.device) + ref_model = ref_model.eval().requires_grad_(False) + + reward_model = AutoModel.from_pretrained( + args.reward_model_path, + torch_dtype=torch.float16, + trust_remote_code=True, + ) + reward_model = reward_model.to(args.device).eval().requires_grad_(False) + reward_tokenizer = AutoTokenizer.from_pretrained(args.reward_model_path, trust_remote_code=True) + + # ========== 6. 数据、优化器、调度器 ========== + train_ds = RLAIFDataset(args.data_path, tokenizer, max_length=(args.max_seq_len + args.max_gen_len)) + train_sampler = DistributedSampler(train_ds) if dist.is_initialized() else None + actor_optimizer = optim.AdamW(actor_model.parameters(), lr=args.learning_rate) + + iters = len(DataLoader(train_ds, batch_size=args.batch_size, sampler=train_sampler)) + total_steps = (iters // args.accumulation_steps) * args.epochs + actor_scheduler = CosineAnnealingLR(actor_optimizer, T_max=total_steps, eta_min=args.learning_rate / 10) + + if ckp_data: + actor_model.load_state_dict(ckp_data['model']) + actor_optimizer.load_state_dict(ckp_data['optimizer']) + actor_scheduler.load_state_dict(ckp_data['scheduler']) + start_epoch = ckp_data['epoch'] + start_step = ckp_data.get('step', 0) + else: + start_epoch, start_step = 0, 0 + + if dist.is_initialized(): + actor_model = DistributedDataParallel(actor_model, device_ids=[local_rank]) + old_actor_model.to(args.device) + + # ========== 7. 打印配置摘要 ========== + if is_main_process(): + Logger("=" * 60) + Logger("DAPO Training Config (Critic-free):") + Logger(f" group_size = {args.group_size}") + Logger(f" clip_epsilon_low = {args.clip_epsilon_low}") + Logger(f" clip_epsilon_high = {args.clip_epsilon_high}") + Logger(f" use_dynamic_sampling = {args.use_dynamic_sampling}") + Logger(f" kl_coef = {args.kl_coef}") + Logger(f" effective_batch = {args.batch_size} prompts × {args.group_size} = {args.batch_size * args.group_size}") + Logger("=" * 60) + + # ========== 8. 开始训练 ========== + for epoch in range(start_epoch, args.epochs): + train_sampler and train_sampler.set_epoch(epoch) + setup_seed(42 + epoch) + indices = torch.randperm(len(train_ds)).tolist() + skip = start_step if (epoch == start_epoch and start_step > 0) else 0 + loader = DataLoader( + train_ds, + batch_sampler=SkipBatchSampler(train_sampler or indices, args.batch_size, skip), + num_workers=args.num_workers, + pin_memory=True, + ) + dapo_train_epoch( + epoch, loader, len(loader), + old_actor_model, ref_model, + actor_scheduler, reward_model, reward_tokenizer, + skip, wandb, + ) + + if dist.is_initialized(): + dist.destroy_process_group() \ No newline at end of file