From b4a83d4fcab39bee5a8cd6e8e6eec06314864e5b Mon Sep 17 00:00:00 2001 From: hgn Date: Mon, 24 Apr 2023 12:47:32 +0100 Subject: [PATCH] chaos caused by async --- blender_export.py | 2 + font.h | 24 +-- maps_src/mp_mtzero.mdl | Bin 17083520 -> 17083520 bytes maps_src/mp_spawn.mdl | Bin 7373024 -> 7372712 bytes menu.h | 20 +- model.h | 123 ++++++++--- player_ragdoll.c | 6 +- player_render.c | 42 +--- player_skate.c | 14 +- render.h | 37 ++-- rigidbody.h | 8 +- scene.h | 257 +++++++++++------------ skaterift.c | 31 ++- skeleton.h | 6 +- world.h | 25 +-- world_gate.h | 8 +- world_gen.h | 462 +++++++++++++++++++---------------------- world_render.h | 113 +++++----- world_routes.h | 37 ++-- world_sfd.h | 40 ++-- world_water.h | 20 +- 21 files changed, 638 insertions(+), 637 deletions(-) diff --git a/blender_export.py b/blender_export.py index 6211204..861d692 100644 --- a/blender_export.py +++ b/blender_export.py @@ -1321,6 +1321,8 @@ def sr_compile( collection ): # entity ignore mesh list # if ent_type == 'ent_traffic': continue + if ent_type == 'ent_font': continue + if ent_type == 'ent_font_variant': continue #-------------------------- print( F'[SR] {i: 3}/{mesh_count} {obj.name:<40}', end='\r' ) diff --git a/font.h b/font.h index eaba149..9b5a13b 100644 --- a/font.h +++ b/font.h @@ -31,32 +31,18 @@ VG_STATIC void font3d_load( font3d *font, const char *mdl_path, void *alloc ) mdl_load_array( &font->mdl, &font->glyphs, "ent_glyph", alloc ); vg_linear_clear( vg_mem.scratch ); - mdl_load_mesh_block( &font->mdl, vg_mem.scratch ); if( !mdl_arrcount( &font->mdl.textures ) ) - vg_fatal_exit_loop( "No texture in font file" ); + vg_fatal_error( "No texture in font file" ); mdl_texture *tex0 = mdl_arritm( &font->mdl.textures, 0 ); void *data = vg_linear_alloc( vg_mem.scratch, tex0->file.pack_size ); mdl_fread_pack_file( &font->mdl, &tex0->file, data ); - vg_acquire_thread_sync(); - { - /* upload mesh */ - mesh_upload( &font->mesh, - font->mdl.verts.data, font->mdl.verts.count, - font->mdl.indices.data, font->mdl.indices.count ); - - /* upload first texture */ - font->texture = vg_tex2d_new(); - - vg_tex2d_set_error(); - vg_tex2d_qoi( data, tex0->file.pack_size, - mdl_pstr( &font->mdl, tex0->file.pstr_path )); - vg_tex2d_nearest(); - vg_tex2d_repeat(); - } - vg_release_thread_sync(); + mdl_async_load_glmesh( &font->mdl, &font->mesh ); + vg_tex2d_load_qoi_async( data, tex0->file.pack_size, + VG_TEX2D_NEAREST|VG_TEX2D_REPEAT|VG_TEX2D_NOMIP, + &font->texture ); mdl_close( &font->mdl ); } diff --git a/maps_src/mp_mtzero.mdl b/maps_src/mp_mtzero.mdl index f5de1f762a27ca73bc31b7880c92786b092c7cbc..0fb6064d7c7b40fe1aaea8378cd649ba03a23401 100644 GIT binary patch delta 135287 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 UNu z-U^@iy>&%s1*x;4ct3nyQE>YcNRVs!h_itNuyS*pow%1W2mTvad{*2rnFI0Yyx!-2 zfH(SrSvui8Uor>E=h1-`hMA_bky)8IS4&NVk=reQ3R>+F zUK4VXgI%5Cp5%Sy2BCfJ#M?KDdEn}>aFbV;D*-4rK@`=+%>#?yK6T4$ozf1)oI%1# zYwCRPo4Bx=!R$v%G%p-}CX7fGE9S%Cb!?lr;3;PT1g+k9Uco-j0W}I$5m$Z5LcAx^ z@X;34t0)ijd}K%Xi80tA(}yj_Lw5(6H#clrPtc=&*0V!jYcM8rFGg;D5NEq`*RZlr=!`;nhJj7mVxV)c9vWL zYzIExwAo7#BY7-`WNf+(P_=+hrN20H%|Kds`Esa>(e3SwA$pz0&%|I(h z_7YrkR)8OmP7}o~Ynzo2(X1QR#;De@$obns!Bfdf@U(YKyzrm*9f~$|(6DlF8@-<*~osZ(OHFPcf_x`Im=I5-1h~7=8Pe2d=FLFBHR-gv5q z&qC1$JBY=e3Nf{P+fn$hJQafWZ@MtQdxKfXZ;XrJ8kz=vIxY1Q{!?rKKR3Tm$@?^H zCdxY1jkxOLHgte13RB*y1y89Pp+3%a9qCo|Klo_&RySw}_#7f^6EuXZs7YRKps3K) zv^R}FFTj=0T`P@Baaybg|^joOW{5)vxejQh&5*bauvd*+}) z@$ccP4!L`|72-IoPc$ro`CelS^RZ4SZ6_q}w_<|Pa4r^I8{tY4+8z2=2NT(2-qEoAcm{ z_?yLPV9Bly-lj`U^GR#ayYKF>X@RBj&KYBK|43Bw(vn<|(^qtGcxfV^w0;FQcFSb6 z;YSN00hyD-AQ?)njjSH`fzPDj1z5W!4zPh*!`W~lwGoOb^an*W{t1*NOB^gMOTxFg%vm; zZcv2aDsyy`kz<*tR#TcQhp zfnWxUhuS$gTAJ_nXq&%E=i%ho+4MuMD7#5=a zCMF85ijIzQ%j}r!yietGkf*&Uy!7knXeB!dp|ih@5D$>zJ31;YUybUPFN5H_Ll+9c zOFBA6TW)BY=eY)6gxB`37F;8o9pTq5udNo!AlHw%Rg2Dx|d(1y9w>jiu*T0K|DEwR;y-k~5 z6Rpp1f#_|oi58XM5U+9~lcbcyDO%n6a1wu4@XyrK) zLiF|!Qx3(hf!2i{7s1SBv105=T_CL)$7YLJ=>nD30E+#rHe7Hi?c%t}GAZ|bUOjMK z{z$CK3|A;6$FY&(jlWy2kk#V%eBMzw%h~$XLp0G1>JT5=gmmg$Al%pSaC59@_U?2L z{EH8>BHf@$<1F?mLm~2VZI}?Q$PEl#+o-Pc7ldt>s1RJs!Bsx-9w;e(z%MTy_$lmK z*mng(+ApjIhLEAMD;TnG)AYQV;Az~qT0+pIt`HOjZ}9vC=1u+81*A%NDxBNZv7Twr zYcbVQ@MM|g*gStF?6~ZV2^4}V+@X=|*%_>S1VNu{=_t6yxkIW;))o&7h%ztIPvR*cT$Zn&~OHxO;%Vh6U-KcylJor@i1B zfnApsSbA`f6Eok2f@>r`dO+VC`D#jjAlRPUG7x$UzHwOr z&X%q>JUs70dR_9n3USzbLL8rF*?T&J=lP$)MCDtUCwMN4PRSn!4fEi{1i^C>c(yEj z>zV%}bL;7{=;kgD(S{c<>aCP?rLtpv4%4-g;%O-=NG5Di0k#H^6 zGT+Kdc?hCVZ5S?iE&|V%Kf;}f>$z6L1lMvLh0lg;&mbs)Plvlh&Eunwj zbj@NbA%RdeB-_1qZZ2-nj_t%l>?G`ZXYbWKJ!Gc(=DC939PIk2`6$l?xUJeseP0b# zS1l=6@T2JF=xw(00}RJx;E(SH?Ird42Bj}VAB(htr;Kh8faIw_Sc6W@j z?Emtr=OieNgD369y!HV5Q%}6}%mvro&Flo%q#jVjrZzQ|C19duv}j^!59ooTA@`p% zri(fAhIdGK|802%;BWDP-eOj~;XN4krlT?&T`@BWtjOL&j;YCT@P`5 zNb&)jXO+~;Zwf_rbe*>lVJQSPZPH3?Pzqlt*2m9Y<^2FZg_mIzAm1j^_`=}YXzgIJ z0ONh3T;QXw~a&cgZ#Lk257Ukhx=W}J@;%gRMEnQu{dX9$#ZLE+Ga}mUBnR|Gd zM+y|9dY{`q3N2L9?68lyuVGc|U}h9nzHwT}jq$QaPL(Q&=&+4l4w+?TXdU<4%I{a}&0VWA z0L5<*zI3CHi*mg4NdD@-Ee6xe-?-eWLxt;Fae+?X<@ztq+`&3C(Ux(dge^75$=j^m z*&f20x;)6qOWu3*7v*c{hxQSzgjINGA14sqytmF1#)&0;oa&jq-YWc{nl7i06Wqed z^H$<-hqZXHLU@gp;vmoCr;7{szTjtd(X9OL;K#YbRY^XTuj%Uqx`8fhJaAUqs!xhp z#eP*0hm=;}I;zev4>IG<=nL_6`tAq&|M>Hvw{XyNJ1^uX!exmkUErH%lH8Brxzp~=VyOi~>bcJr3;$){pr6mUDmQ_jOFybBb?H+*q11w%kn9aOeGl1? zM~c;b00iq=M?eBVQ#TT#2>W?br6(!O=o8`(43=Y8 z2gQz@6A)7F(^&{<9|9rIxafqR($j^7faSiSw>@*f)9Jm<1W!rWQ={j_g5^2*zfKcZ z3I$&p0?l!R>WJrg2=TMFr4Yg|6cUS1n3MYwTyNL7Dr6-NyH2;&<}U}=2ygMDHW}D8 z=3Z1j0@rSI=!klW$-hzjkAKDAn zMT9|Y?g0z)^1!uOXeS|9YM7IiEE-(mD#W9wBJA=BT;8Yn=Lut3MHr+wyfj+55S(Y1 zY!xE39|#dfb^V#M4qOkVuK*n3*E#fR5A!6eA8={(jNRwsMAi!s{3FFS#_CBem?ZOv)>B@*NDN8-Lv5D znXH9aB-me@n@%2Qz;$GSn3E#x5C8sV(Bupur{&mRvko=#aW~P;ttq(L4{?e$3k+@` z#FaAy>>5+jJCBr2=@1C9BK&w>I)tb_$WQR27z(cSE+qG3=VGuyZK zm<7R(RG%lf+7E}wqH>3jJ7d=tbrD=cv1?iPW1bJd@5Muh1=EwT>#vl{xp*A9a1;ry zIoNec?i2U-;ELMr6SIk3XY76E@fW!6S~)<7S1|%y_xg4rhnO$YAHsk{K1DIYNh!Y& z+%F%WZ5|mnB3D?O>=^+qB&p6EB`LU)5m1bAtyX)I|70T}rZw_4${fh!!Sq!^{O;J* z+Tk1d5cbyUnSw15BOzq{ot=evQn4Syuic*SAhBEjeHF^9Xe5+QLUa`+9smxG`Y5Dg zKMMRl{A5mkT{SYT09qv;K*L5st6aW(OI|5>o;O$Q3rVBkO%#>ACQq2sJ|E@O!|d`q zqhN#IXeYVl!-tJMzeA8q+O@ilsUD4V@uMN4vZ4t}T)}5=+!g$0fM5BJCpYr2Ei-P4 z!&nJ+Ets=3AAjC@+34eW!mSL8F;GbBJ6sU5;XVec{Rnti=pP_NmO2J9Khm#>kf9>{ z-`+Ej(4kJS9Km5n9kmb&&psRy2vqhZAL}m5yCsAV4Tli+b-e^XN!ZVzE`61|AdLpW zPIWesQE*MG3hz)-IUW&^ z=*HHf!4VNqDYm_pVx^po07LgU49~;E;_R<$#Mf~}gj1A!=_GIEW^m@q?n1l73yLL? z;Cr-7?|j@>ujFhK(#?s4QQ#7|gr8}w6e{6)B)pjL@RsE>*ORnQzj03Ri!W~ya~^_g z9mnsUq`+^Dg9z`{nxe#GeB#wjLZ!)~AbWE*dMmep>xma7LJaOvP+a|A+A4+45E%tQ z&ouMSGlHjYcFszYOe*#?{`%Hj@?R1DuVilA_QDS5M4h{t{+gnHv~jZ6Xbp%b0f`IwbX5x)ZEcw!Y;nO9^#EEj~4gz^-i1QtGtp_dic8fxgHBt zLQtC=cnx2Alz>jhEfPHXQR`uldm?6{C>K(=SDKlB3U;E+9|novO0CF+0!TaHBSdDO2cFif2sixF!YCi_ z0~b!Q+$$^(VvJWFFq|q#K$lQ|!E+M!Jah7ML-GCDNO@zjcsn&0dp_t=&$#5kEEKm^ zyysJz2S)!0(Zi?X>cM7$O+I*Pbl%T6Avhit)O#+(=$8+ku0N zNwH{c)e(Yg3HH+{K|Jx66@Z`W57fr>6c9n}UbIdpt zJS$g-rwF_D^Jr~++-)2h${EC~rxgWIjYU((q0a7w!o|dP1{gJJF4|!jZ5)SAwkX2E zVP0c^4CK44Fs$Lnp_vY6g-A;c5NUk##)g$O#vzYYmjqXZ5k`qO1Kt~#&gzG%uiOL& zxOk6qj}hL7Hyc&wU)uIUW3}QLjf{sVtR7nMHzWO#e75)j40j%Kw4#Za>j>Z_geTb<2VG3oHvmRP!2(XHjf3@66~60f5tf6fKcKA@rQn7 zCm`gyho7e9&c{3JByqB!x) zN^uI}woo?W4IS;!-Im`(tFY^n{tCV{vkiLRMZCojcM7T~@r@Z@b%h5qyY@`*D?9CE zRlR(8FZ9mkqwq0&kJC_mD>9B5QtuB#uJu0({vu98$={E8D1NLs4Ln&ED|e|L)ro?i zOFJW|{LkW`^=BPWO??%MjxJm&1T8-e<_sCsgS%=s1AUw*{%DH*87TcHgYR&S+KoU- z7eFdV){{%lKolb#E4ZzTL(!W2VMg&p?F_Wp#hXHq{mJe|GJclg@MpZMp&6Y9paWCH z<4?c8p_Xr^^+Q{?!ZjE?HHiNk3T$mFk!So3p|+G1a*wV>p^JE*FuBc4^v>Hxtk?74`m1e4 zz8a43>h%)uvb%$;W!(nuDi8Rky4`Y7cNBsB%KS2oDPKa6&&Ml50jFZu%=}x%H+glC z+O7+T%38R=p5b{gYv#=&@PqmN4O8*$2Y5?N_k?* z3lo|p7o7f)wTN$tBJZojosf$V>|=6E;lGTFkYaYLZ(QEMrpUTwGr_e4yO#DT=adc| zkWp(TxXLa;|M~j5zj&DHaS3Xf{HyMaKPh?%O8VqWB^n&#fO4ma@=RU%B_}KMx~pGu z7P^}MIJK1*2ew5wt=-Wm<0QBp6$||^>>sCzvbPt8qt*FOgaNzsAIQtferLIDn3fq~XC98SGph)t9#;%jsp^LcK}+y|N56GdieIj{3`S)Z?B!;J!WH-> zZo+&e^)h77>+mM-)3GV&`iFUfYtdy$_0EY=-0PHh)c!@d;A(#by70I`e=C>4TA@o5 z7va}|a<4$%YkbcV<_x7*Aif{|jS6gFPZy{t%ttXzsUW?`` z1iiSVst|qLRi~KB%#%wsi)GiG;OPjDGd!K(ae=3^UUscZz$f{x4o_7#O#;y74`MTj zJL~FgR=r1tC8p8P($!VeZ3ma7`Ug@uN1QUuqy&#v{&8h_knB)j+eJ)d3I znwi~n`vCWmu%I&Rn`>>^U~U}xHFQ263mWN`esirMe|z(xL3Ls_I^wie=;t}#Ao74+ zUfeUAsmMKLln{9-cHMKcAvdsj4Ek^=U9e5@-F3N{{QlI{#;7$t(U_feNNY?fa;tAP zXr*vYo>J~6w`_fFRe{Pa0R_H)BYbV>Cw!Riz{TjJN%j^CMRE~nF)w)cg3 zdr4C_Z?kLr#qA;YW{~dMdcMj6u;!oRhx18hiki8_nswQ^POu`hIi$D1G|_W0#IyfM zjNqEo-0hm#VEq`fyQ+(`b@P(%cRHWHAL8lhCGNzQ*g~O9fKX2wcYV%_4LNKbf_ z@OZ(af`@|#!J~$!8$8|N=>d;7JU!v@(dR_^4wlPr?TR$^ojx5cdHLEvb_4Vt(|qCT zTc@x+LLnwi_q`ymHM%~UzO*NDue*pN#Ss_hE0-VISqCL2_@KQZ%LUhrINw;aYw{Gh zl#tN~zLgU1>tEHPU%DSZZ0$=fK)+(9Z`Z080dw2(181nwQ2oW(zLr%@?DV(h_#QGb z@8y$aFx9V^>$}^;+`1Or$ur(@0aLK#spnXHI0|NGWJ;U+boLe8u(?xDGl6t2m4k+?@oYMed^j74qNi>)3y}qMM)~Xo6i#~$W zz^5tOxr17r1j#{~3-S$M<&>Et(EqH=P;0)+*L&p}fAxq)hMU!ly5u>UCb|pVG@GhJ zn&?ZNrn=?_G>vpix@(m3b1JoQ#*J8%-gu0d%hK+eShEAa>WTlx_0Y)WiS|ACZB{K% z>@EwzS)b8E14^T`bnEP-#@?bq_C29|`rqDWJQQ=1TOK-8H%tTN6X2s!n-uF-_-KZi zb=bNVelEcX#be>C*=YH;d7Lo_Od2tvy-=1Hd^PTtHXptju&dQ(7vidS@YB39seTcD zQ@T&s9Nioj2=1)jXtfPW?xnL=U=}#Pe-ovzga_g zUCcmmj~t+BURCCN$T@qlRDk-7P>sBrJXZF}7{aaNO1tzIO)D9yQOoMfx_5c~>zA06 z`!H<6s5;k;KBYC$$A#{qX-UI1>r70KcK;!k(@0IU<+H?7T-`y@sL$0Uf@{%8O^ht% zNmggSria984jrXQm)&U90<{mUAv9H;VzlO(S(~4&;8nX38jyU9MlK6mHv+wg-2-Ph~_slcoC%Q-0TZhJ4Gp}I#v+%3T=cUz?BR34#`TPC$i zF9?Beb|s?W#4f#kq{g;t^#R}%(*CeuYD5&&=%sr1l&v8A^7?;^;X|V#e3ep=| z;RN;!Ejn7Gw5*aM%RBdK4hrx&Bg9%7ttm5+jh~a)C2K`1=$%_MP4wR~bfu2>fE8R4V?On0*&l66sYOVjh~*goJiN==fPMn4GjfX#6t$x*`-5kT`5H^h23(L~SWztBX6str))1&}kNKL~)iWU0CDK?EJzrA} zm!G~F`oQ2SjUT$@3pB-MyTEM0+_;4>b_{-E!$nt{$&a%$5uIg=U<6)Qk|dh#j{kim zjV$_zMH;nfbrslJnyu9R>J0l^V%&1dR!jY2V7EZ4wv$Hqh_S`fNI<7HB)OIe}mDDO3QE{Wvxk_KWV&sS(_ z%N*ja8`dTa77I(U66(XE?sZND)pr4p0YQ^+ax1~-VyNg*89hXw87slCoXxMe)lgjR zr3!`LC(t~uYSy%#SXcU@HJbf0xq3o-z8BtDg3UZo47+&uZkW1 zUrj-E`SqG7U9i_G@JC2b_DEA;VtM+4A7}S$27h?sFR>>-*4(cuv+4WX4Sb3@D}4ro zO9Z@dGU3IebAF>y=rT%S%wQrV&Z*Be@T=K!_+=jQZ|DnX20CMR{?*zRs9_kq*obrK z3+N?^(Y26W-*xb*afnZ^c&Ul0CVRCCex~TaVZqz(jCas^Pd^GrRvWvDA&cHai)r4= zUHDgD{$As3^1mUKMDF(yhArLHV52P99~CI->N>uG`ilDquczvBYYYEne1!fouw|mL z{6jD*SA7*@kNBkVvOMG3!Jt08j!Vmr6+9Px(iF?CcY4RQPo58IJDmHR&tQhnG#zNz z@V}*>p>y_|U3cO zn%3bSeC_a#7Pd3WVJ7F?b&QwpzNtTqYZcIqT>|~Mg*8E%`fUjO$m%%o6;`3yDF3=; z9p~{i7M<@jp|fC&;w!w!Rt|i}4cN2EMJU|3uXt7yJ!6ejir+Nq>Q?{ya{X`25b|jM zU1L@KN52~?yVL~1CG78enI)@AN53^#Waf4S`QPgQr-ZZFN5*=4%*BW|4pi@jWs*{Y@Yb9!W5!^SrLnVrmy2Jd|L|6I3A6u zcBB0C=^|CXQweDEm?vUU%gnUj#Pgx{lynLA8d{jfcJ{1=KHu(-dYzac zM6b)S1e1r44HPTaPp*YNfXmKUc;$$YQff^tY{fvb01bm?m# zM-??8M|<9$yXD?6q_15F`VYuQXrjZbjtiU(67r)Ynf;Q>eI@CK$0NwHeBsVw!)JI?WAL$RNi zPS;*g$f;Qe6rHWVjs8}$c9==^_GbRvu56(t>qFOQ1I*>rv_&lCBApgS$1=lLV>?}M zZeXi0(xCNmY1-x0Et_9OyzgFru1%Jm;B3E5n^;vQ&XUA7TC_v!ZFjf6)pgv*?Mj%R z;u3kjR|~5+J4m?aqY5#rsr$8~;dcQy!4R6<7)r%YCWr%V#33z=1!m1>ir#WE zwV<1enQZ)2cPjjBP&?6CaTuJZb>40$htMBej}kk4++l5u%*`wq-M_zG@Tr#_!OeI6 zqai$k!s!3{k{Cm17FhUfR4wFfye2v&WkICTuRj@85X0MVD@5l~>>Sgr1OEoz5?%Sz zqO)JN*2`i>hdstC+oMs4Zbi0smD$B;7<%rTL2f;cLb+r4(*_x<4kp zTg$cZJqql3_>6sqZ;+eJsyT{22TUIrzZXP4Vr!UXZ z4z6J-(*^N?7q6(^)|6f+Ct;kZ`^%fZ114X(vqUW1jFZ}EJNYtkp!j6`2%WD#9tEFh zJDSLFH(pri;i^k+1dU?JQ|&iXxpRNs*xDo_@8P2bFuN4H z^h+4G{o?d#tI=$tGO;+iHPxQWez+&%Y5Gj>f85ip&O$@Zw`NafA*F4`Y z)9_;MEOa5aw&Y$C6DYUXyz`)8Lh>w-bia-X>|jwNZ59g3t|@tOpA>k(;?s4Fam2|f zC_qf;2(ky9!Ns!af$#*u(+8fu@brVHKRm(k41gyD zo=|wg;28+dAb1ADGX$QY@C<`zI6NcZ841rQct*oB2A*(u#=;W;PbBfBow4Izc)#)O_jkOz?f5Yr0_x6=NB2W{Sr{SjVIvn98=vG558ah zOjNaME~4rBo>7e(@Uf`}(PQ6(4AGG^PnR#^A2_6;)@ysRu@3JEu{yWTb${G#GuoIH zqAs8L)Yw};lFN%70^fJXX|`&W>wZPH8wE@m@PAO>A-fEdrtLsqUHY@M49868W?Ew# zV@mRHR6iA@+ax!%RSYFoMQ=*xkB6^AL+|^k8A_~byKET$&%hLP=0pHXGkqZ4p7jRs zQ)i^0)jqvgYK3z&`)e(}=_egJy{gY|)EB7hip4zt{wa5$ZdOU!6;S41eZsD z{*>n)w6R4{Awvs$M%h>|P3BuP+lJPU?8QPWEiSy1Xa7R=W8Sl|lHBZgKa9V;_AfLr zETFK((_Mys@Y(QS`A~x{Mhj_ftv`W3WVs*B8gIf<(u}lqbKJL0J&F^*A|UYVSPK8lx>bwC~o&j z16K57>HRI^Y^?9--ItpBp@HfFEVSJULFr_p8y0#M zf9k|ndDB%)Hi8PvP!jgeQ@wlmR2!sw>sRk31OdsI8w}JrV~R)d z@Xu{gUec}q59<4=6g&)>-2+BXT zEni25w(vIn`RmQTqSDqno}u^qLfE>S$M8S1-lJJlQ&>uhHu3Cm-m1YDlzmcbWWuWZ zVS`W1|AK=0G-DA7xOc-q{>bHWRMys(H7T70lu(nA4fv+*JkbN|T$p7LBo!Tv*7wJ$ zEo%4yO^#F{n!vgRBV)i9^ml>^%_~1?c)T|R?aYVYyBXde@>gqDjyq@j1AS~8z|v$) z<=b-Hi%(QlhwEKfT8JrKu1w6NT-Jwa;gOxTzKI8CV$G_D)YFaB|l^D*lSZ(W>~wNa6L;kGx(Vcj$%LyJkk z7h|%~rg`HTv_1q!iDx@qGJF`KbFM^qBE-ZuoFHlX#Gqt?PA_|lva{|P7{oSI1`+d{ zjSb@OoqUZhJUzi*33_Pc8wDUm>=n4u6bhO1o7$7_as4@3{^A@PRqvub1u#|*NkJIs&;<}^NQ?)Er?}xCjAISOa zQ5*{2)?dBTGRhFOtvkB-S8M2pm~Lv5>u&$T3k4;GvNRp2b*Wvhd-|?GWP7MDO?Cfl zj~Ay(Q@Z-T_L^#} zaeALI%qtS`4Z8JlO%{0CH=B{BuyKTmIV)g)B{9>DilMksF%6QT zq%`QJet66*e!rrfF=qL7FQJ_2MJGeatk5kyjenqXMvWG9S2HvQ&+6%}?eV!WUpmQ; zpT4mQ-0;D(LOLu%Nmx2vhLUvY8oUt~&A&4)Hy%k%f;;gzzjTfmN?Hz`E<;JWbgN@1 z2}=(e{ZS{rgP9vzy%SDYNhhOiW+<_lwu+%7X1c64J*&mXm;~@!=fd@2QdYE84E-ZV z48=LJ4v1S|+?aR-)yy}bNxeE6V^+^Z?pCXHhXP^2NAJH-P^Ba96MFB4q2x{Vu_(vA zyxuXC=+Dy;iwk{v@_l$sZKLL`8)`JAqd57dC(sNfG1FEtlvwrdh#7Czb}RbwDp1W( z5|&=Zq}>bQnqRc!o30EL7gzMs>rYBApBPG(PxKOqp`?oFbPKLMRULpIys4JtAf`(% zju}c8$Mi~*p=6~=+sshXtOmn!@zd1x=yqCg;oL!|4GE(!a1I)7T2VS5qhq=wBt%uMfYa>%?W<|`dk=q_BBZ7-(MY$3f&8M8tRg7108)ZfRA4~ z2~}-iWa<6FNSJlbtzwTh!VH)Vh@3v3q zW=b(jyO0dMFHvc4l%ZDn5Hr0p-VvLpTzACM=(=GxeCiM92wUa;VmEiV`&Goy7#tSo z*X{qJ=|HV9jrB7_*|6rO!s_Pa!K{j|y^Wj=*Ue-$pWfnKfl$nm4b%C#-AAF=*B|&l zX#_;f8KNu`jsoI%rnms2y_t$fdOV^HCs zdTNG}28C-c4jR;=k+oQAYk;trN;SZQB{e{2XI}D3)xTSv_ywV!VwcM?h>Xy4fYuG7csBNK0r3zpuQ~@XCv0|tL>x}R(6rsElu zejEbgYW?3pk;pF{db;!MZ3DXK$Us3iaU8aiRt_>!_h4vc_mG+sLrHU@hfRjs;%-R~ zBMc=)K@UL;#Y2!{L-<6#S+f_Y`jEB!glZA|x}XxSZNf=VYM;bKv8(qPWPT)%ML`4= zyJexQ+Sx2hBuLuJU?R*UNZJ8m(0zh#*MEmb2b&@1*<<-;8*X#skK`$JR;RET(vAg# z)C5WU91MyfNIG0%P&z@<<|2cN36jj%YB_+P|HKlt+0{d(OPqptVx&+E$|OkIjbqS# zf}}k>2Eq28Lb00KhdMuE2ESlHFn2xFB44MDrT4EGM5dbbHYY>VNkHj*j6ubf2yZ4a z2sV=xis@a~@yj3YMQ7{o=2ca~{Nc9!WKGaBk( zcbFaT7+N+Jmw~jGxzwXR-_5rp;&x+oC{yGN3YvyPNjuIAN+f9M!aVeHyACmkOb+Qn z?YC_Zf3Zpx^yJz**s8{R$MgXqLrK{1ishAwGE_aC*dy+^6_)qn3#%y5&<$<8bTI@; z&5c3n1W65tLB#|~8_EnKme5C)%f6c$$G07cRC}Lt!UUK;eg2cu2bl~Nc0Q?7`W^8} zhOJo%NEWz31*h~11-Oc8cd=LB8k$`GW3r^_>k8#zCG=V}yCt&f_anRB2p=;Kd@l7ghIVkohh9>EKG zNAb>Mia4wGUEq#OB5vZ+c@Tq0lcH;Yp`-@r+G8lmEIr` z?f(=C_r&oCMb|t{NzKzH(@7OWGES%=o9f~ z{2bnVL=)9}t90*N?up=FVRU`PXeLrvma%;ns_zsjGbqvfv(iZ61G((3kz*&(dzYK!oKZSxmdyeRqYB9bjelC#+hD963ZKoj-e)SWy-gBD_wqyu4%;e>H@R3N$> z^cX&9{`;XWLo-Q0X>!7#`vggIHU^PWr?+ry2lXoGSu%&Wm7Bx-`uA-ZhLY9QI+I*? z&8WNFrmVJVh6=k`)b&G#29>}nhdyLxXl8p@=TmpzScrqt%cl>#rohcTfxmDbz9CPR zPqtTb-0}X-A=v$4Xv|bt=TjCluyO-IT1zsN3ihP`vm^dxLkvdY$3!n%yE}C7#K>z(&_$5X`2~JY^Kv~T_;dE++`MD z<7!7Zx5ir+^tJ~>$+ic5jfbIDcOWdi@6J#XGreceP_k=CUzcJi$uC_Re^Pp_aj@45 zqv>sbq+E6mrg?a(LBDWly51iKue$RqZ`0CDn3z7^Hk1Fi06tXMeFtKw)p9&iNDC(h zkx`Exytej!Y*;cP7X63>H2@jB=mChKB<#nIIqp3+en!)pT;dr@t`*Ri4*sO{m7Lor zoATFMbwm9;#~Ov~&{i>&SVhOoP?9cvC4r&DX8I0Rif6c?$KF6*U$p_!kvmxQ1csrc zdS+!+;Wxcsg|@8-QZqDYB~;#)7P;;}Yph0Jn)GLBBBpfA8Dk?1%;iXb&Z({apnx(xjz-Js5nhVJW;A#FB%8#M6&bTB$BLo+d@kN+7;cFgDt3(w>i z4CBWPH5fx-x6|q&gr&=wp=wO&(qJgDicXiIBwhN7c8$HGjGp>M28U|#kS?C-)7QHh zO0IWb?>U^$?zaM=DFJGhu75j`n3S* zf~29&8B@CQ8A=)sy~6l!-9Y1u>@9}#fw-9Qoie%-Sc)rw&JaUMhI$@q&KH-jKzE5p$A z@qucFs#Ac{waZXayL8K7C}|n(&oAc-_|a(k6JK?-b)n&O+7L9M_#2%5~Pgu(L*G8aj$v!M4b9cImbba@6W)`jn_pdR~s(x>;3?(_D zFN`s?Y(3aaU;1LGt?sw7S}*TwtT_FW^R>p35u7ev&I~2xOkYK#DcJ+1jiRBB7)4j_ z=IttD@A%q$tzEsv7Ybb%EX79A8Dc2O5PbuVq3Nl=W$1^Q2fu%DH^YVb&hRBU+;C{C z7)oAqbj&QpG1G-XQ&JcozK`HX)>)3eZ_uizbe?9cF?@}ow0Jsn-j{G-ckxIPpU`YM zYJ1F=rn=@^;ZT%rHcU`*;e>8-3{8iK74-1>tL{ESc)J+hy7qq9PR0Z1j84mVZqy3& z(^;ctD0$`6M*T_Y3^9~kE1+Y(aIPDQJ@Clz&-GT&sBkBuyBI@B7o+pbP|{6ks~AdR zrn{&7>2&_6*HFWxsqt`=5a*XJ4Th4^pmW4hELx$e}2n&UqqU7aDZ{jeNloee^e^R=v z7)r{D&e5t)3C8+Q_8M}npgEHq(J?cWq)S`%C#6e+r7-MU)3<6JuND~_Oz(uQoo%F> z7z7tX==&%X6z-!icS&6XW=@5VUxYIi#8g zs}IK<_l0W_r_< zp=8sPZrBVZ4V$)#p~NcsdgbD=#Rm6PV~}Fm9eCRXLb~)FNrsY|k2sm*ez2JVCGnZ) zPfG6-(De5m2AT=)I{Ng5rsVX6zQLSz>!PX$NR#JRN|R}MF+<59+iR*NlBCHDCE1DH zD@SgkteK&tuU1WhA3hYN$&b%3Qe}ZO*{xEVyyE8~^q(j(W@!3u=ypgFlro4U+G3Ii zk~GaUC3&ThlG_ps^UU<8Fiz&~Qc2ol29g1bzWd5hlB(v-uhwa(m+Ag z%uw=XKCovEdMK)ky|aVS5Kt!jV`VaF7#T%XGegyw4js4w zjS#iRG$jWprN=j*>7s0zhQiU=<$kM?KZui)L7eR2ITDTD_Lkc;?{UhpfxS|!w@G*ni)zin$yWHZCF@P0=ne#*OD%| z?#3`QPSh4Nlw6LdH`*EcyBwN<#3;J@?p3?XZ3kKMuu55SyV3KIBrRqrkrvM@pN^V~ zvSfymJNb0gGn7<)IgDwOL|O9sQvqlO$dcPs%981H8A|l8w9O19^NE2l9!eKA8A|2^ zI$u*H$&#z=tid^M%r@MvlqJ)zEQXRHf!-2lDA_A;u&jzCNi##qs_xL|WaI|2WJi!C zFT5Fn+Jh{4!PaB&D`r`E9P$x`#SAJYXtbzEW)L~5#&OO8HSVG@y9OfZn3kdUNx(+izn~ZP z*9;6IwRz^+a1`133%awYq47^jN85U215_V$$&auuIp!F)M>_pw5L>nkD*P8uc{qem zqECV}xv>1C>H$cTGeDZWUQg$cCW2&}KKf=TIr^q0%?u@yW_n^#rRfT8JjjwwDrL#^ zq=cblQbNxt8A@i9^lX%&q;UJS-hiZ=C|U4XAbU_I7oI(@*CpoQ%u3CjK|*s^fGBx0 zNHQ37pM<&$YUa(LW@eC8E{@Q9K{hJv>0wmV4M)kKNUn+%$!dZc6}~|MA>CONLy%Pc zOsI4rl-O<Awc{cbdpRK*NUG=;YjHylZVWCoJ1d_J)!lElmmCBwkd{k_mD zQIP!fU^K^#oM7l&DM;?(5{QP0qGE;$qGFd;ND?G7ln9dR2De0#n3=QIGukKOa;F z^vFXh^~jM4I&@xC95a*%9;f`X0ZD3Qh7zmhzLujbQIDKv8Ks&HdgPo+J@UPJmZ*=7 zAS$LQR`*)dr+XAkLE{=(Q#xh}!O{v#FzGZyTHA6tphiYmjZ7q`bZ!_*azmE{Ly5@p zfyrQWLlg}&l!%7i{re$FaLiC5IPN>KHj>233?*V^x+G{ybk20ex9UBWOFy;GIJQ!a zOlOFpBtvvzFq9Mq-Dnv4N2B@JJ4V$L)X2t4H8LHRp(HG=8D=Qa4Ac7n3?)itI_4*D z?y3?PH8PzehLRl7YGj6zra@c9P+}F`l=qIAh346`GmfiNBmam>L-$0zF+;J^RY9*b z8A_&m^qa=zb7NEnYUIY1YGgVrLrGXVU51i$>DoUX7md96<;Dw@YGk_QFqCvoI%bBF znCa4BC<#k<6i?I%`G6YPzEX`$hh-=UOXruNf0WhrXSI+&sF8#gY=44*Msi7l;fc3q*Rc%uuperuT(s4mzz$0wwa~N+mL_CT3{y zZkU%+D`^Ij{R(;&&QQGZ%dE4jq%<e7;1(0GU#m^hLXd^ zOYsqC%h+RR%vkfn)UpezAG0`Au4pHo`_M5{R5#MQH|44nJ8dpD7hu~W&Kw4 z6LiStphLFbKF&}Lbja~ohkW0599Z;96cRIt+|hXriCzE^vK~ap3@vPe14^q(1|?3y zNZM+|BH^(hKYm;(KYj;s{-2cG=EPLmh-AVF%0OzHlA)RSRxG`gJv|{WKOf}BT_pLj zHO`A9A*QIVdDC%C8X$Z%^#EK=r3f7EH^W)^KM}b;N|*Wu&c>();c;T6@R+VKhLRe4 z2IhE)!eg4QZ;sPU6a~vP5#-GDPVMN3kzQDL+@?}@Ocx(RN%6gfG^dKXV}=r8<C}~6Oo1|A-wK937;g+O3F6$O;(~!yx1qJCa&Z)GQLP2PKSYb-vTu_1_hli-G`Z=EwDjS*JlV8@Y01)CmJ2)Kym!MQgKWdAVWz3Vv0Axu;Q4Z z;&MaIxV6}CtkQ9$mBHWl4DJi2B?wyu~odub?Q5K&LlMZi+5fW{PGeYO*H!T*bv zTr#GuWx^6`>6|jOGN)3PVJNv1Pd5fk9dr{qR~t1vTSpo<-7y$SItDu?QDK9c;!=`E z0489f5+i9uVUR5eB@LV`!UGi^iloNL(B#%QPJ9fl2fgqClL+)LK_I>XQ)g z-v>zupC(&?(3qhhG=|U1PM(OcLfH}&$_%w_gQJ!9Fc=g>khJr`phSYCy$Ic;v1tF< z+nh4xx>A=(khFopp!)<#T1^I7wZ&#gJBkbf4Yfi+Z~ZYeh6I%2+-^Al%?7#giN6H7 zF??Bq+P-6G&<*^?l{P9Flt_?d41@5@(3;+*^cXP%*^UV2x*oRB@qTb#LGMgaFkfeN z6DKI`F)>I@5Y`P}1l=%$VhF-pJ9z(wLFs_%|L>fPGGrAtgdVDTyc&((*grAWtG!3L zzJ#7?&_w4pbeCP9QT5!7^hI?bukaormzv_h%p(W+0hL zclh|DL1BH-3%?fhs$4@k}`-KbkO$J-yVT_ zg4Wn^l%zGLqy3Z8CNY%g`RKedl;oA3Bw9Tji&}uz_~v0rYrMY7X7m9B#daVlW~ejC zjx=Ln&~So|i(2E<4biAhmWn(14z$L}1WB_;29ZjmCmIYbBLO8#(D8|A*t9Hethb;t zRw(FPFqA|~PYxNH_#dtm$y5fB-c2{%unDkV3M%7NNo7p8KN<>GH0Vnh3@yfMzru(V zG7Mv-@Q&BB(N9nr*TpJhatns;PYflwp?76iitmuq`z{Q{m-Cp56f`9*n>M+}^)~3< zxYlTErOKGjE<=e?^qC_=$*mIl&dL8jMb3}7x4mqQS1MJ;bj*KJ`b3hU)h_ zDwG*YuCCLSaHe+@G69wGhjyScCY3c7u9D(`{{lJxk-tfeCzaW$}pJfoy2-6c`hLY^lXUGgC&4)fi9@{Ndh4sbyN_{ac z(PJnHOCPc_wD1`=SUP`Z5ZN-CL!Ih^7MNQj>5FYkaX@L##UPRwdN#t)L=sR+kwGLy zS|j{uU@tFk&==cbeKA=9)9WFIl06#wDj7{->%zvGx`akET_%KI1wCMqZ5EaXU%>L<`z^6O($bqjWa&-c zhe@v+n2+_n7Fgd)G`jRg0Yiztmrj(SWZ6!ua2ZO9m%do^C#Cnv8A{Z@^d37yGdY}D z=_cUnUN5*hAnvun;$HSPAA?9QrPmBB#jp3Z)G~&pcv>;>z)W;oRQ~=+>9J#d@5icT zAn&cHl=sr7@C+qFT3QhBC#A<7hLRl7Bii+oP0>w|_x7!n_tNM4e^S~ih7zmj95IyK z1*h*a?e+{;sX^XbP$}=FrK1c@#1h?_d=<1&l=m`}2x;kA2SdrMgQg3@BUEoe-g~D~ z-b=^KP!e;gi5xW)<-H6gYDs!N!%#Axp=s3PE5`1OyqAudp(N%-mUWOM{$(hUf6_K@ zba7O*0(q~lQr=6SYcrH=X42_0l!$-n3jmMh7gR4m-pg0Yd+C@NN@Aw1VknXK()G(w zA`On{GaO}!65V%uMsXf`QQk|GK=eIlmf~M;qVGsE)C%{((rv-WD9UUZN+gdHbNivc zMTss$1z{p}yMUoY#7W;wU?@>d-KjPdofKuo3?*tUx_*unZ0{+<}QE#-}B6uSAWjgGv}O{-8p+^ulWre?@h5D@5Me6D31;71%dMOy}0H9 zQ+^s28{>4$0IArtHt!HS-m9GdM8)O;<%YzY29dIz3=VdI@~MD_D^MQJ7qh=4>d|14 zvLzPN(Ay!>%f$oon#1v4<*NW#vPjv%VQdUcxiN6<2!=BEE{+U=^2j){u_mc*IT|cb ze!}xPj^9?)W2a_c0@!r#umylkTBf0|R$(#GdLx_63SD@UGII0B7qYArs ze(%lZdu3bY1z3;w;u0!>@)NDN{7RtwBrUdvK)E$A9pT(t@`GbpZLG(8v1EaA$+$QR z)7W0%KWt_Um4mc6GDfa9NbTWxZ&mB@-rJ}qOr-1}EjETgxiPRI1w_SNFt;c)u%|@X7W`lE30_6`tc)SATpu%ckGo~4P54dpry>?GAeIHl%EXN;Rj~{vLh?FxCBAv?5`d_&D)o^lS1Hl z?_zemmp@hGXKoGE;i6hZmGiwF(a~T8;pdj^LtsOszFxXoZVIX0B0;)YcsN%M;z&)+ z2#6;Ua85^{yn-7a+!1II7poqA5)cm-KSPXFp8)TnWOMl06XRn?9H;vKPR z136vk;#q@sa0qLcj7I52oycbIrD3^>QRG>UUamG@hJY$KE=q8UUFtFpj z71{A#9xu3HQA=^HqdSxM9@;4fJoe5w&mc(?a0TK_2HWz z16ayK%>@dGzdpxFM1h757%Tp2oj{YBSnJmf1ysP%|NDyAv_ePt;JBD85opjrc186o zX#(OM@v&(w#mi%ji1gfuSM5mZ$FE>%$>bG)9%gG!f_ju>5A|7lb5>r8Ym3()x>F} z(XsQncOOK+H+ThQ1;lNDl@(}FC76gbVA&3`-uZt-K%&fg6?bP}ffGh)YyN1f*cDq& zOR)vC6zijRNU;d^&zUnf4*V++ugL0BQa-C46uY z*g`!H9|Vb9;L3#7vfoYCH=d;ts>j1Wey9VrTRSgc*B$tDkf^7CM3D$7Ur@rTAZRNx z+cUttA-^r1nBD+>=thV*0Wqtcff8LRowD0ZGD2*`hL0EvBYZL~i)1%lMB2D7H+LU6DIogLRAq!^ z7aHmDBWCh_pAul&>TR^*OiJRGF3|QQGq+Rk278I)2rblObvACiYM3x>E_s!~0Am$Sft4{=^QAR^`*aAQ8yq&kNcdxu2&U59k5m0Gum5K<=?lCL~()Jli*(tvf zgp{dx`?nZ+zS?&3hs$CNA!F#tX3p(^H1hADd1U;jFmf{VWKM*KcaGvnc}Wa)mA8}a zuS%j=tk9RK<6%`tK%&*wJ}WesJ$oCrR-bFRA>+W(Qml_a#eoP&bjI)5p7f_VUFpxw zi}Gw-C?HXwfW*-WNbxS3s^hEHAiGX~OCst$Hz+2>-qljUq?*2X_}aesgUdCp52r1M z-Zp0(8Piq{4T0w%{HzZ0eYUN>ek|8ZOVi!7MNjsvmyqVMX}4cKEh&HU}0 z8L*)a6@PyUL;m|y>}$&EFE(NL-!C??cd_i}kp#-$#p2J$pPxNAV6$_1^VSXOFQwt% zQPWW2x6lw(itX9gu+^W9Ly*W`tne7y@Oj~A8n^z8ncP{`R{5n+{H<((dhJk5tp4h` z0Qq?){IfO!4V(ZoiNBO)pV8J|A5J=hS4U*3Ud08hm~!9XQdA7(0xng3E00lZD862m zI(2i2{WLQHhsGLI!Yb1-ku&(4bG52pK>P>6u#y7J=T}o}4$sUUocjPAxy9;8Rsx`w zfeVy*LpYIwsNzU`m<2)j;4eR4qmKP<;b?LKym;lQ>P2icf%3V4#R}AQ5;Kol%^)Ct zDDdR@IJ)#jYtm-uH8S^Hg}h&a`kJ>knF)_PUTg_2I5JA|t$0#Ip}uf{d|4N|rF}ms za`-6`7OjB!HLfcy^`Zr7wePwJeFj0#v^ctFavRd;r;DW1xe5mVpuW=fCNrs0qT=e> zl{T8(iu`E0R05sQybJ9|evym=j)@e$HV@j)I5biE!SSewY!yoBTpTd5+YEA{?Q}_d zO@Z2~D?nZZfz9`M>a{zJJ`K&ytrgukPqq~-KyfSr5}ooHl-Q*>cTBe#^e6x6@HKG3 zI0E8>z*ZHgt)o8+L(hhhpW-`aJ1%##lpA5W8mhydMpS;XVr*3$K!{o7p0&j6^#*10 zlOblmg_wm1viw$J?+dZ?D1>d{NtY7nV@uq&s$UXa0fAfmyal;Fqf7~XJuQ)YVyjdB zyz>YOrK2#Us*E?4!@qd7YI&9?1fkUl&W(Qo+ue zzS#TPzL-veX#TQy$Lu%1tI>=lYbo}EhU%~f5tY3Mg;doYk!fuH2GTjNp|r#>i>{p4 zQTqAMLGWuUEO8*elIaI&16drLnX9GEtHjf0VQa{}khBu$rouRyU2iR^J+n~>l5yV^ z(`M0O*NF7sUL2ePYQ*-Yr3WUEgVSC75t5f*f-ex)S`bfbnG;CJ0A~q7f4RsHP7I<; zBB=E2Un`EbJhGmc`_H7m!$?=dNH_kij`VVmIGWIDJ@IR{ssx%iA)c07w3?JDUlOg* zHlC(8Swk8%DoHZ#n*t*}c7;gyPO_2CVcU~wLGi?=#!8A1*H?GqYCK(aAfBwb5Uz#z zlD0kduQNu_89^B&eC;;UaznO3nl+IAkzr?9DIBtf)5^nE!J1|)xxA=2bU@OELsXj*;hPBQOq25ENdPxH}~?&R-q_&pmwaXwubKtFBV zO=i5wEP+-i>`&uPWsx^qw~Dl&>P%1FH25*K^?OL^HJe4q1>^AyjIxuSxVw-k^?rbJ z(>7fN$h+dJYAH5_mKJ{V6W!l+H>td32l3hWGVjZ314;KIr7X9B7fn~2Jwvm|>}|Ov z(8=8s%|+MtlDzM-MVhf39$)tLrJnEhkY`u7iIA&|J+Nejoq3D93yrDwgXOZ=$O5(X zj{vz~95kP&hfasm@e^m6^~)!iWm~}lwDo`hHO|x0v{`ZH$Vny=^gfF$aGwq*Qd&v@ z2Rd0I3R_W2u?MuY$)I@i&eD5`*Uvd6NM7dIhpzY9MW*)NO2Vt#OLyK6pqqa$Wtl)& zD=o#6wRG{CKD6t^OtQ)gCXq%mrew;)ydNTp&1DM*TAYg|YbhSDmf~m?sBOeGp8D1h z{Y5F#X!=0QaIu-S6dOZJu_3h-Prr9gJ;~)^H>898_M2r}r3A?11`F0wJae@aPoYB( z%8=#Nqs;N0yIZV`eW0b-j#`SRpO#{+%%Q_btH_IHkNoDA2MatREyY@CDISrQVy)uq ze2{8owjoQ&E6XgxBNC{s69mYefc>YXf4`_e8|*ic3;BD=rBf4W`l1xGQEp**ejC%c z0?1NIc1aD{y8Pk{ADSI3#RZIK$fh2S{$p&JyUKt&5F>F5FcD#aiwB z;9`zkP>S4-7+{%2__|t(b=FdB$7;QEyWJh z(iQFNlJ*^T5+C0TawvH&+41i}gRcV=QfVwHP+KPmkaxWg#h1gk?jV29$}B;!Z{caf zmH8&JqjwhZ3wfNkaZYa1rqwG_{y%Ke&?D<6-T7hbPwF*A08mSRh4DPHKb6l>*FGmuoP z_tD&aS)t|G3Xe!ju~u4&N2H}#tFHUJNyk~WiDAud%d-_8k(OdFXesufmfm`OLfW6O zhg7hK9c16hG+95!{3y7e<+{^GotD}c?IK1u*nMi~p>wCCb&X7<Tf+{na6?Vv8!=CT6hm&F=uDYoP1X*bVq z=BOUsscU^#%Phi@wG^}|F4ICX$STR}(6r*{6j4;=j&Wq9Hif)jfyc|dJp`z>n zRFokGF6a(#hzP4g>jiaa0xDR|-a4@YHeV=U6A;U4>K=M05Va2N--eR35bDq}Ep=%6 zR_Vzk8mh^jLNytJ@UC+mlgg^lCP5XNfZ+TCd{5^IRIfdT>NSLvLIXU$w@{qb;>7vf z!>k64=UDsXCJ=+AnoLWvt^$Q}8&7PU&%!l!yW3ucQZzejDH@h5P&O71>sSONn*1~9 zH5A`KLyiB+J90tLj!e|7*Q!k_}}BvhaYRCMEKP~MAOtk8~{C#tn)Sf-X@i)$(N zmWJvwvXV(9OS#pg4-rz8UCjd8S&Go~eXj2!te9*q6q6yS#E!c)b`Vkm1jihL@G(2V z87B{QAT6K-Z3insW8wIpNQ9IMC#;GFV)J|!Ui1u*#z7fcdU^w`SPjIs(LikU&%)7R z8_Xew#yR0?IT{wLf!K5!h=be~>Q}!@C2C390VohV-*HlII4eoxQRz@4m8g|vTAJ#+ zm9VO`BDft2wC6@Pd(J{R+hHhY!zlI#c&|a!iZl<8<T zG6ccTKeB$VmU=XV6o;HxVkBxMn=RDiL0nF`nl~Ei(MqMN^=P=ONa2zm)=P?ry%oZv z|NqcFlSv~eM$2TyXlx`%tbmwUY=X;}ibnkmdbR1QVJuXlEi^(Un&L)eR!o^UV3o7f z2V$c1!@;4UI&8V3UAGO9{d(nn1GQ-EH!^iwBV&kKR;Gc!#>J3yC`c;}1!))-_YSH4 zUvyx?e|NJ%Vhlm`X!Kh5lQ|yA%`Ek3SSXa0*-)&HKnsj4R#_q2W~GqLrX#jN-J-(0 zN$$N3Io6Uitdc-Qu>#V}EKEh0EXnpH{h%VP3ad!t{qQKY6sx19cqm$mr%6cF8gwg^ zrUli9(ll`>0^%xR(`qS>5`nsgz+0ZHafDUAw1Uc){bwr}+6q+!Re$YD?4X3DIh3$y z>Ewhi@EaxlqzI^f5vWfccqX_OOO9CTW(3F|#IA0OBdq+T7nHxuJzpWOD-;oIvlbEb z-yTb*Kov_5sAAF5_W@mqTK=M?YpQi6YUzxY;sM?Lwm5f^Py!Q=jG?7iXD!9o)lw|E z=I$`E8ERlY#IPC|8&e68n+h94OR-V{wH4eLN+wt>%us6y0d}93Vk>JYR!U2;WO&g} zpDpf~ty`v+5MUo@DYm1QVy(1v75MLW2xe9ivlxo1STI9WS@sQ;Ey2vnTC{Wm1T!n; zVkI$J>Sl>%R!*a#x{DCayCIrcNz6=$=AlYSjJ&+o%&Izw_eu{<7P+0$AOgKeRuSYs{4*VR%ixf;asr3tyYL*vwf7;Gt# z)`B9I%YRpp~f=y zftF%BYAIGqOD`Ogi3|lXeozpz%rJ`#g)$L4YnjN{J8^^+wYWo33#PHV+0(c;6vOlz zmzIl&e8LC?Wgle1%4ps|84Y6ote1ziSKPE&tkW|Q#tR6(oW?wRYcFn++)!qEJOplZz%1t9&qr-J0sc(l?q_qu{z1UFe2Sw7w zejg;)$+d;9a@1|m*KIJ};Qd}2YzxC#S6Y7%ogFfk^bRN!IMmHCz<2x%5?yw>#IM@o z!BYC9Xe@ECfpQ`1y87)>`anOJjA-C4bd_DRfiCSdh)$0gM0VIvF8I-n!L%Q}WjI>a zBXG#Oa=Do==F$NlP4HVFtm~1(k+k5(Jwv!HO=c8(UFgfauEP<7s64?m)>EImY%o1| zW`Q*K{Z-;s$1P{n^hk3|IXEvFJ_#PV)DVJNd1r^ogcXds))$TJx7q2K@>@YO;8haLTh+pgxye8jPjA&-3>o~?+=q!{iZ zXqqFYh#fXPnr`3Jj11pVEifq2m)@-Nz0~++Q+R8d587^yrsH3}mx_G86k!I1f#Nkl z=*k_AH4-RaKfdb~O{X92MaINb4s7_iCB0Non)r2ouPg#sCk*9qc3CV~pj)fql?SOH2Okv;u{v6cC2J{O`vuC^{*;js^mOTW(w=7Sfjd5i(GTOD0t)6O zWyKzb$hpuZf?heGBmLS}7NG3I=pEk(I!xD?q!X7CXh_otdi;2E5;V6=2{gD>1RYbO z5!sknOz>sp{KL#Kw<=d5N1whFQ4vS?s=bn&W1or0>j>*rDlT6-GX9l_xT=%mBj}5w zc&T#RQlc{9M_?e2k|SvKc}t~1?`>4&^xwD$dhb@E^kB2iFbi4Vg!v%(?E&dbxQ&Ti z|Fkh+`9mXVT*95aS*6b@w`^>B4CPSP^-r|=3zV<^c##$;U!<{T)_ISj*N3k*>tYj> z%VMW$AeM`vviRdQ8dJV{VTUgW8AUs^IAebP{#+i1SR-4g!(tJXD^`FXKSygcVqB^Y zN73-$Q8cycDf9P5FXdwP@Q3w5(4blR1t>1j0*YD=&vsoStiidk$taq+HP*buKUukj zVRbOHS@$vG#=-Xs4CVY|e3i09{FVHX)a~cPc{Q9aK*fNKG8k%vV#uC-VXmmR3jsy( z>#5Vo{hN_={vms5&C|1zjVb~X1q#UPI2(YvJY&Rl#M3hP(g@n3)<&u4f&@tp=lxVg zFyj66H=?aVZK1A3xftsLji5{qLQvqTUVhZibgTCVsosU&26jcg9_u5}&=YJN>as5& zxC80+czqTqU)%8tk^&bEbA2xj-5Hq|TL4|LMi?p@VZj2`+%&WlFHMnGN6-~x)=De8 zC&NvXT^B2bDOU>LjWAU1MtHBGrFdEE(Pbok(&LWdUDXS4q>wFZSSf*WrLbgy7E^Oz^)M}&sAWz3N+|7L@3%w2Tym(x#uw5JSh~u zX3ICy*m(lw&ck*TXhuEQsi1_<^rpUM*Hfp=#yi6;w!oGWXwf@SCjoMu!ixt}uNgF8 zhWQ*F+Qcb$3?$szZ-9hb_<6SCg_kJ^aHlqid#BH-NE*09XIMG+nb?s(>pH#}OkKxT zG`yN4Qa%~~Z8VrJyK_P^MwHE;67J-m2HCdJkZt4eNN^;b_M||1WdmiNcd6+UNpl)_ zk%w*$LRV$)FYg>gJ8%4wthJ$B@Wt(e=pL^+q)G!LT~^J_e?Fw!qSSO7X%OmU5qNX*-BcJ>HMZFkYZZl^p|GK(fuK zCfkh9m(shv`;*FPB2oPuF@I z=2gm}&p#>2wg(^7WLvwFk+kRSuMO2J+t7?l*yBP+=5ZYk6-1Rx+m>~M>FDMiq+=^f z=dUjBma`KwZIH}__cklxp(!)g&ehoK35=nZ8bgWr|j*q(-1VvL8&m5`_Xj4 z^$_Xpr7g4*q}fc6W?N)Uvtio`lrJp*t^vQ)=_O73Dpl;uXCj_59@P%!6nFHarFL1; zYAiu^o3rHP|xMi?N4CT;& z*f7*ZNFw27KJf@LN8O{TstICz1FFLdAA-v4!(oLW z%)T2;m-;U}NtL#C`3}!vc#u|m)6<^DCbH3~s$im72L#9i6$iOMc{aI`DVk=iJt;l= z)*-(kB-SQCV(lE1ht}POBZ9RCd?GJ!RAq-!&2=-=7IY(dBJq z1bsGejnq5yaS8O{`UrY(%sA=QmRlm_d9)Gf5!8KYZ|Rpt=S!l{H>1}?sq>$Iij-&B zD#3N{V+8l#E^LA0wz5 zl`9~*mITSQp=xpsYa>8m^%n?xA2@GbwDqQeA=49u`f13meKGiO-VcylK45|tVwib|JTgnn_qCU1rSoj6VrQ+ooQ$7?tEvG`3Eda7?9+oVdUXK;R zly}8)G2|JAD(H@Zppt0Av%L)DyeK5vo}5<`ZCE8O#jCzR3)xl}t2#mm$0kZIcrnYKmNOdHk-Q=VztiS9)hDmRt; zXuF}McxmennYOdv-!ZsXQ!{N?DS`4#8)?(l1xn?eK+t<6*Kg z8od2sM(PC@EhZL-ciF6G6pUsyz%c7)~GY~x;lyeod@5h#D=!L(08e$Hq}v&CA|Y}hdZ<&MEl6)4{;W7;ju zDF^Dc%;T+jHk^|YX!0u-+Nuc!)N>Pix>He66JN6vq}Vd8DK=~*Eyel>lxzFp^;i;^ zTP9%J%k%VWOFrf*%g02$27O34`P;v;EecFwg@lFCrvhqr&c(gt6Yy?Jx6Uq@1lGP8 zu*U}S7hg9Dg2|)i1(G~*9qs#to4*X1u1Lsq$vxk&vc2*RPe>m^1tbs20-<%@#gM5v zHOY>j({Mj|IfLuJ4I%f)m!$g;0j?UtUeSe+X$PtizwHkB!zMcU?}U8b2unUs*Xd0R zu_x8Y!)*eTzho6nt8-&W`Ra$I*LBMYJ>{Nb;Im*ygUPeHN2Ct*1Sp5Gp2u@T$i_!M zl5N*7QZLB-uo^3~rN&CP*LM|ZG3G~7MTC5VsWa4FMIJ_WB*!Pc#69JT*&z08VhH)U z@;7AUWC1Gs)@j9KiC6aefF`@2(dS~!*#^qt@5ffF zY<0A?pFB8gY&AU&4=Ykdep(Yk)_8nNiprR&2V^Y0A!B*ilCjkFsJDtVT+xaAC_?$m zTrdDOI_{~YGqJxgW#iCYJe@%LRqiHr8D^J1#oSohy1NoJR{UP>!90x(iy-C6dfmxB z!KA^qmeS~EkPt>)E9OC0JWFoK`8mU30fOw7V!XOPfx|5G3qzJt^Q?j_i=aFt2gG8Z zAgGAN^Q3XLgZ`zy@gpC0D!DCTh9Ssjm>ydfLHNpRZMdNzzhKDY07vbOxP1R0$l|Sq zES{Xd7xuF#-UY}?vV`f0s4_k8qKS6>p!dj3WF_}A9t*GWytgVIn!Rs_L- zH4-2*eHCPS1o=`UEK(TqQqK*;6UnA8{E2h3eRTJ%*5qToW@J>3rBV(nq=9%EVyH|* z9Ag3vwP!yr{m)$;sr+IaU9WFVb{sB6CiS({1Y&(`p|C6h}Q>vOyfF%3#F99gDwCdt zRUruVAgU@D@zG(S7|MZ;te?7M2`H4K@HV3jlG_E^Zgq2VtKe(;{Sqi2;}3C26#*6q zA~A|B!!D*inqVS_yE5c@b&g^6(jvM&u{r79+K&d;P;+*tHYX5O6@f+xG6lr%gm|SF zXc2UDC;2`9lzjI+XW1dr86LLVJxZ2~|9~mzQW!-N1{6!vMidFq`!Kj+=*uW_#^grU z=G?*1PYy53hS7FRHL_^HMG<8Hawi2l+{xqfe`6#wk-Fz_y)Hl7k(HGT< zROlxcfKU$-_uT-=>n2a~Sy8MLyWF{>(bCL&JjbUJx#FK75!>vWE+dKQ`#X95)u65@ z{3hJ}4n$e4ji5Y%^~6g%f|AU)8h8;FD6dPy&iLQe5#-RAwdSPmmg*_2k_KYA7%Fc} zcA)zLru@F}%f~3In|H4rLAIZ}XpZ-LrKFs&MhF`C;$8)bMNsJ}tiu0^HON8E%qME} ztX?yMw0V5l9J9-ks>AANAQq~DcoEh>9F(&zjUeCE+GsvKKLOsG2N1QGw+o(+5lu#s)mvkw#r{w{mCXC8nqb8Hg`b7599wQP7%EkV zXdxCLf1QD6`Se*qr2LBK(%0i7p%#PHreTG&6yI$GnqQF(Q(cb*#1>uM09bd_^`qkK zAmX3#LP{F`gIs*VX5B#$ijw&~K$R*W@%A7fAIk2u>Y4-vq~yx*)sj~%6#Nx(fvO?` za;?Nhpx$o;#BUpT_aM+v-ch}6R5&z}G)TB(m|psvBqsy|+fxhQ%W z-XATDU7IC`9)?GJv>C>b2PEDhF|qe2I0Zm@EK8|L!h2eQ@+=JA05IAKuG;J!ytQJP z^=Py|$55$7!+S5LQ`ZoufbzZ9D_!v>3Chi=$0VnKkQl{A!X6y%^>i>?bn`>YMe%N# zU33VPtB+{H>;ScB!p>rBqAz(-=X-O_mreOb(gVBA3gxYIY&Bs6YDJcQLNMHY)RI&= zS(;Ak3}+9-NEeXic}Ac-JBFWj&ec1Z^A_qo9H8DqDMG`35h(MEu%0SR_}e6)#VJaWr?{9X{Zt6)40#Lb;!`t2J-CK-#3FvsqxRH{pV{1wkz-EzZkM(U>?4E*R?qkL#mBAI(Uk|WC-9ZWiYHB;((@QTot=g9C}8JC!!GZb=U zYgm$=zX3tBOn{Ih(+kE$R7sLyw;-s@2RvDtKmk}8NRqvQBpJVG6*SEdRHhj=FM`mM z9lXPy!Ia;xaP0oDCf|P;WXV>uEEzuvh@xJAUSG0FsLoG>loT1B*$6_q>H+MdIwg|f zlfEL})BhnskRqdyBD-rzk?D6=N+dps52PsrFJnmMLViVc+T(sKL8imY1%^D6RexL} zvAffikKX&A={@B6|cWvY-!5Wdet!^`($T2x?~$ zg38Mryz*hlUIXc0UP~aILzYY4i>n2)td=A7HQ$9q88e^%rv1DppH?wwY&-CMbL z;)Pg%ELGMpD}i{GcacV$D+d-qs%$x=%F41-8Q&IReK6(AB9@DwvIgOY1O$mvHT%u( z1hRBdDe3W|GJyt2ncanyS?>r)nFTI{M{1;!0GUd{(+8sb-JEbULr{5e(YG=skkL;Z zrSO;+0EZ? zIwgZP|9%wd`&}iHlJi10VLB3Aer`? znoPqgVW_zg2$0Lg_Yh3^0*d{;5wc!)AemOL%_|7*-(b?9ND-jzy+D9$(XN6PZ3LA} z8xEsLNT{P;)Q9kPii~*&2wWb2_Bc>OnfK&H~E`TC9);VzC;CmuwBh zL0=X!Y9}G1wqMPtVTCjhi`789WMim&8~{(I;;V152y1Ek4#r3(>s^Lq#rL zwK3&$0#DM#kX%~@$+blPWI60O+zqfs2r3$3u^Nc)BN!_85j^>4LVB$Wj#RD>I4I#r8u4dSl8Z2G3d7M*#lw(O3;eDJ2#zH2b?AK4FU%ixL|3Xi^m0&$v zLKZ4vt&+de;hh?Sa?&YC(dHj~rxH2i z>tMaU=lzx0CDKAh8v#AHz83M_*h}o|>IbyHx6xc84P^9n`UZ1C7dNtga?gBr-9f`5 z&Fd<_;lNNv<6CbuU$rxkW0QUmX);hLEh)^mwds)Q9*VG@H+_id0=vGzUOcK!tVCRdmyZ)akoyKj`PSk%RkKu-^5 z;VnNum%6m<9>_-8y+*V&Qr`MC_?nrhT-!S2e9xW;8T0(o3qwJGv;wb!Ks_5D zM!n%$!+qgP*xagYfLNxLGOG&y+6CVpUi;IboK=7Pn=NyHVO6yhk5QmJig1i+scnq) z0)3h3WgcU;gB7Xmc&(I=*Vfx2wT<4j5cLz-!Ua3;MgKWG#!AIAakF5Sx zudAURY^Hz6cPGV7dgMR<-mT@zVUbdTJPsmRA9};&r$H5wU zGRhp}!Ip^jwp3oj#Im`nie>tohAXaM9l5q_vZ`VQ%6*5|C9nfcy?Q98c+AbViiPo5 zv=pl(P;OzorfI3|nidcGE{8QniAHP+rn5+GM`WdZM0jx$`f4c5O_BxUH4lRETB&L) zEyZ>gD7Q0SF|`z1BVqJEzFT0tIyPRbtyJe~DYk|{`OL+Z)KaV!v&L1p=j6|3=|!%SkEDqB#E77Yy*%){D;F4L`Qcw7+0Z`B2%ZVudH>$kjp0zw{DS{^y!}{GOr<%&Ryu6kdQ2uck>DuWh{~-BkQL0Yvw>CAv<%|6ZhIj44$c%q02L#DGlHu>O z)}}hU-0ZX^VCvH_vf*q}w&m~dvA?(bSq{j40Y_V03)H{YC#5<&O*y?N!0mMyNtBx= zrQUT}(y2&tDmRq;&}B=W<#K+>sU01=@2U-d?lsJ)m*bOD-R$h;t;wn0j@_D8GbsPe z^d>pAy1m_a*<(ZM5T|)9ySHSc_)ea)A+^4f)O7^^<7Cs;4XIxTyQE+GJFj;A^V0L% zBk2%jP~|Ebot=sPd|qDnZIZd=1o*&WQL5hLSJ8N;vg62+Tg=M8Gc~AfT>7(%L&!Pv zintMEbY3MDTnIN#Y2z>gw$a^jeR!aS%W>Iofs{von^RLplA`)P%0Dw5 z$uZbRnV;wF^xkr;!FS32dOtR2%75N74k;Tt|AFDMeP8*+J)@`G`M%NFvDP>pT_pFvZ}fIt@AKMF(G+># z7+lV7jQsYgk=hM0?R{n}wzoSk?|o@pZkK85^2#`*wB05-?X9tKg~)5(^x�Qh3wW za#F+e>ZbQ^jV`5~8sDl*E*@x4hswRSrs?H|AB`34QcSHr8i~DgJ;RFZYggt}jFNGjrvs$(<-=h_-ko)+W3{y?C+;q{J*MS+G-aE zQibj_eM>eR9}ITlF|D^tbGDP^dUk2vF7a!-(Yo!*5c_~wvn4iX*rkOy-<;Z=ZvL?h z`PgNJS-EyO`!sjQ#pZFAe`fNtPb+dL$L-+P5ndT|F?yQ1lua9G=Yobx)amln=vr>f z)f!Uiy}m^DS(xT2$GTK>7ILFKeuI~VSkqWZ@qtHc-*d=`uF<# zMpq|`U)5`lc29FCJ7i7`$y07652=z?)fAym`?9;;dO2+bjAowfI5KUBqw#r*HZM(M zMy5TCb+JzG>+7?(%R79GI$5(EWXLC*!QZpx!^ygQ$ax>rezJRM^7xc?y_qu?8FNXB z4I4$}o`0u#nmn7PU$%Fdx3+DYryX`ke>MuG7W3(S(gW?*oBI2t&+1_JQa(F5-P`U9 z*>Os`42#B^De$Lmza5*B4sA2EEzq_?+Xihrva%;(DI;}p;2i0(Dp&w5A6W7gU}8^`vclxXh)#^3GFXve?vP8?HIJ<&`v-rfOZnv zDQKsmoq={1+Bs5!xkam!VyOb`{z+XxE_?Li@*bY|4#+uRM$3iQp-;XO{La z{P!_y@>A18ohhUF%|WiULhVYGnq9h7sX3PREBtqsr7_xl*Naq2;sx z%I#J@sN;AD{^vn?-<6AQ^3oX(ySbc%Kc9id{#zjD!9Q_12LJOCH1^-4^2Zqu>$qHl z|5*r){r9T;=;6aza^Q%Yb$@eCx(V$TwA;|`K)Va=9<=+=9zc5t?O$k*pgo561X>Za zr_i23dk*adw3pCcL3<7D4Yaq=-a&g0?E|!r&^|#c{@pprZaFme|LocSD{V)elN{`( Gxcncgc}r&i delta 75027 zcmYgYc{o(>7Y`GIYbj$E+Epl2BqQb?MMayWM2HfNNQ;&sOQl5nKD3t>+BXd`_qI^9 z@6o0wZuO|{4>HoA^sWTpNU5F+;mkt>RQ`bjBK(BCNvmo)$@LuN{g$gUxt)J z)C4-@V;tU5dLydL$TT}>ogySC6XthqrT#nCOs1)_pdyTnUk_ZTcx#;j z=^AGVrJ<;H_Ya>6t4M)<>!WG)yeuD?#<(-}K;LxfU2E^kkD0KTKA`?Iv5k$!*q-t- zq@*tlJa7HY1Wyl1*@kd4>0+fbg@0!FXO4ds8l|&k`7FJKnl1&FW5jxin)Fi39zFH$ zEk0OpsX18R3Vifrnh%bx-`E=eNFT+jsH^l`^`il;yXzg$7!PcnCDR+LSsvBeR@UmgIuf3~s^Mt_(=sY9mnsHPC(-JPJ32IrVD@?@*!0N4QYYj*dS5mG6y1hMx!T ziCg9qMp9#urBU?heTt-|)72IZ?QGNm#v)T{&HN;=waB7R>Mta8Dx?#t)YGw;J9aWU*vNbhmx;-qB)zeP9Z3wZl z6N)kDizP%w-l9A1>O;`HPAG=+_ZPHDS^%T|Txf$f>LjudUapkDwv5DbwNI0;Ox@H; zPWbiC4e?_ zW)QTFLuaH!z`=BpqOwwt2qNt)@}?SsBcVgnA=;~;oY1N|BkkU(7_fU^PcsMnbsDM* zIojk2yi*ei?UD8Tug`>`y#g$dO@IdRuRO(3z4|~0dV5%B1S#0r?*TU z<|W!hB}a~d--1>2%;@)oQ0gu66MPJO#i*kn*~`=^-WVqlg5FTj%^a==y+?CJ~|o_Y`zWK3Fz(io0ww;ZQ+ymC024l*e$nlcP>9AZez z5)OT^=srF8{Y1Fi#)Qz;(devD&zJO;Ipd-DwH-nI0r|DvRz#jufC@z1=nS%}eL-hh zO%aIR=~4GLG|)LWTw!jkkjPQe58FNWvm!m#aZkqdN)iCl{>Y_yaXd5~KTm%5?~lJL zM<-%rn<-?Pl>VaT*3|HOC+Yr?BjIQ?y5h927>zZWbH#Eu*t@|}7dh&x(Wpv^Pq|`= zeG)j_EM|0SH*)CUSBL56@#CP)+LHuz2tjw-AHAqmTLyc{)VU$ZY{q}1pjY@cqFqS{ zHtYW430*2454EZN7?O+XLqxs;ui=|$F5RgE#-Ova+HRy%uS(%k3{BKkjX~qB9sG!9 zS4TmM&T)*6wss80$>kBl35_rm*&m+xo@Ne@f{E?7={nWOLq#3*g&%Icq4y55&=G1> zV?|F*h2^!?^bHe7o$MM_oCv3!n`g3Vug2LhIr&r>84LMSaKHz{Z+hy~aj^E+HZtHF zr=T=?D~#aB_#il{iX-ZUCSm_-ufy~U`4k9%_Bzh$91iWUe=!}Ipa)OfMiN;|ICO$t zHeK5?2`J@4B5Pfe=(C>iLb@lk-2Z?;jnhPJMAW_)XX)DeQBa|`k#LnSLKiQmM!~iP zr*wpB(;lc0?p z+GCx;<_S{bG$X zJo(U#v@P5qN;Iuq^oKs$e+W1@9am?r?_{I#REtavsa3Nt(R02=!Nq6GiAu^XIMuX$ zIvpaHiwIJ+1qG^z8OL00?+mxydh=p(Xy-ByMe4+O_|@iyP6D;VRzzJ-?A9vU1;R%| zYeE~k6&KCR#+x|Cfm1g!H}(#Jfs6TcHSM6S#2=jgEYOmHTY3`5nxdsQR2%Ko^`WUdDLQQ>3<^F;Px)O) zli92KqUf*CaG5vk4dyd+-6domc=0_y{$-a@0#Rx{U3hy2bUJdKPac<%XozbEBE0G{ z3UB4Hw_JQ^E)?7MC2|#VG{#>WX)^X}IY#EPHMHRwB@Bj5^mnp+mVFxS6jcXw@t1$!hL6`f8tZIPqakscw3OvU~bG zqMd&B=ZzTl8q?V$;UHZbP04Ffnmz@4E#dttKiIowBTbYJtH;!}@ahLbl~XTDw5Aph zuTv~4n+p9KiWr@0(!V$)N)?$fXVYqh`t!s#IEntnb{}_lB@z|>ML8=Ro#BhWH>{q~ zUO}X){fpsHb@(_Pk^5T5X}!>zq5`)$gV8V%IL&)Q=7IH|)~1xj9W%(7IRK`_Y)1u7 z$z{dy))ofBss7!d=xPNKFVDa_O+>vC#nEG041lRdGJc-+lp=%g@jDfTMuBj)w>5Ey zQfe&{*e+Q|;w4XtUB44e(*9bL30JH8lMGtL(I{u~1EP_mDHI>0Z%vp4xot90JWf|f znYFKA?7$xkF7iqx_II`3Ol9_URGfUK1m)^m1QoiWh{2o3 zVfErB!6J24%E^#yE45Y^wTLcMuuboi>F72ZpOHg1v0i#zU+vgnwRmK$YQIEh&UN zIjAyYG`!fJLV8dRLA}=e=R~h`oC{%N&k${^hM-<2{6&h8+A%PAlreEc;}F!~x8ws~ z*EtSFQBADR67@odBBRh%ibz6awsx^@%u-CY=HsMU!B6iGe6nDjEO#QaZ)xWJFe6y z8fFc`F{;jBQ4q=x9OL1rtZ2SFm=`_cAnoxG1*i9afymovmr>XEMaHB4Zph^xsVR}xn@Lo8Kecpn& zE-xOv^RUrM!4xOM<$_IwUnA0*{$Zag`h;Y_sQaq%pW@0 zT4W#%t0pu#98E#V8T#3eMEKwm-&dDkN;oua@cFUyF2!bG&n z$0z|%7U8t6S9zlKG@;2@eJEZ3n)g+8B8FzyfFES~&@?4l_Ye#B+;0IPgJqc0IH3Zv zFgiw#E~EuEWSy*5Wuf%X$|k|7b7$!pfBGRWOke7vEEF?+bPU8psBqgF4p z_M#lRbOn=T{o(x2RwQy97NO5ZtTLeQD$^mjd^T=oaDwM9LZZnTn9`bFiO{{egrt`I#VEto0~C|lD+b1RJtMSL9ETn zPoB}HKhVFrDPERqZDBNO)iwImgde)mrw+)qPN1w4+re>%HsBohnw1NFb z9lh+2k$iMN7)?fddkCgiDC{eJ< z71}@bwu00nvK^>@Naa+JyB5)}mV8u@#bE#k+uxc2hinq*w}ZwJAyhk1h<05Pz$|t( z-S5^izNRVKfoww;-B--3yuwS1gr+a%>%p^Q5zyfGi3~O2PPEv0p%0;v??hu<$`6LJ zOB4A4zZ2O{U)T23uck~mSRLt2=9m1P$R5z$XHpvYn5f=~qvDaAUtTnF?MA*jT>j{7 zChYGx4%^ZFZPeWgtXm8G-z0kJ3>aE~oxiZQCSB!lPjfPdk>5%RkU`yw(DDfExbMXS z1g+y}BChjmd+9Eu+4$=yv*5TAa^@v4ISoO$7e&-Cw}ZY>_K#zyA5;?9t!#M9lgoUOV}RH`wi& zEoNE=7b$d}aX5o?7mxI$XCBB!LAl+)urtU$)~r<(NE78bYyy8qz}~Gl3G2Lb$ohQlDf;`OvG9Ex z!`rX=9L7iBDL$V$RG?IGZN0!d!5R$3{02l$1vZ7|hqV5=ad12(nXhn4D=;s6TuY^Y zbeshBbti}|rIkp0cjhE|RquiDV6=n?>|crY{#(Zq8Wl(L+sO`&chiSE?jq1xx3Cgr z_VjNHb^D@;k!mVYoZ2mUw1IInB-@`OsQf(A)j#b9*)FdLqCAhKhWFuUk`k)8-#vf( zz?5$rFq=5E!-d0nYg5y`EhxzPH2~Jx?;=ZM#|ze`Qc60;9Xi{)!iRJJ@hL6r2`cvC z$!wVTD4cE))sA#h@&wr`!H!<}b0-Ohx+kcH^|=5@IU|M2JR3qMeTrzY_f+_^WgdNA zJfEQcPtgG0#yiN9ihCOF_MAKwK1FZFEQnC7*X$>V@EP`1{iRH?@h28oWFhzIf>%>;$M+S_u9j;zzJDgzZ(c@BFMNrFzo!S%9hFIN&u9~Au6&7=qQP#B z;&H1aIJe>?jy$gVZF*^4Ac*t##7#UIsr4KEt%_cf1_xR{(hi~RxBY_D&bm|+g+!7 zyC3D_U2#cj+Je-K?7eM9S;@{&m0~l&JH}5oJ0vtNtK)K*~!#8jJp*EiG^0 zk~VJ`l&=NCrREPBVD!KgSUM_2*7z5B zC)$MQp4K~vErq8oC&N?U^}6=!L&X%et=LU_)N?MF?FBN>*XN3@3_|ly>jusGQgH(1 zwyz%@pOy+elKI5wuP64VDzatJVT>QGcrg%nQ@LWSNKb4^NrT@h^805%=mj-S8k|3B z^~6>JRi7$i9icvUdhDK-?)BRr%3J*5W5rWn3_{m=9bqQbo_H!xUwmCE+#{O=$9%Jh z!*gu0?XI#a#kh(LFe$yv7uvR{SD)O0;5ylow?e(G*h0AGfhp{jcoJ^XHsVCew1P5V zvxn6yb~c8oSzob@rpQ5TMG0PRl>@)G(i`=SbK9u+V3-NUk#5A!N_XtHpYRRczuP^! z<&pqiKzDJ2oES%7AQ6~y|w!> zeKc7gj9bxa_E`@+CkjMgKH)O4G+pB16gU9D7No8BRAy z-Bq3ISr&Ib11RHvlPX7(cfK95mP5SwfGJgn+Z%V<1b|((9htA2W{SP24zI=R73d6O zhc@$xCTtc8!KhsLITj;%gS{G;)UuE6?Vpnb(N0V zcoT}&@T`|2X>lgZ8tP2Ol6(`2_BYy-NjVt}<>D7aH037oW{SEr`aGlAVGVW*`9nB| zLbTZU3=3v~q!YwG=})B7looPgm<*E8c|+#H{vA5~< zBWcX5d)^>@-hmIiVsSIo=D&39)uIlt`T*tv-8onMNfh{)U^V^OLm%SpMi5w&e^Shv z2n$Ewpr^cXXG#7$gTvS0_j@{WKu4C$MMY=OVySmmGY!2=!CW?&7uEQzxWG`bzHtkm zN2{yEzJe7lp_uo%8O*U-yveloF2$S+8wH!!nh^QwtHl;Zy(YGS@}+|bBD*N|GL^nB z(H?($lpgmniJ&PLaab+&D^sky>joDO^(JW1MT|p5Cp;wAby3STwfXDB46Lw%so6ty zL>kXaVgo$`!JVoQZ(ic9Rba&wHqiNY6w2`tL#de)=?C$^3h0;DH}s(ZA9| zh$X7-p*t;Vl(d<(F)Wjh(4m^fd*W3BqxnHoz-z!d5)DNUG0@)kY~i&yCIhxaztR$$ zdp<&&FJB;6*#C-$+NoE0q2nKkH&HP@wv2C8cWAhT^Py9b=u{Pa!6Y5LIR=Y35MwB&28!8hYGl1XHV2Nekv|Aq4vC7 zqd2-t0pEW93;+7JsQ&PFo>1BRmp-N6KoX!P;GNjkoZ96qWCyr}!0^*8b-}C7X%hPh zsxBYaEx>TMqzM~`w2skw%!-8a0VLI`{eOyQ3U)GGcyWHB*}_#KHkdW0Hys{EP+>DN za?QBVmygG041>VpZ}f22V4_=oGn%FJVHGpgMhL$gd`PpRrq@Hbl4S=#TP}T5(#dL ztn0&+`-&iG7k}6!l}apy-!{LXi?<9ULitN2lV{?Q8C@bcJpx#C@*PLpVU&nlij)Hl${JJp55rwMBd(FIU7X<^y4J3CP zN*yJplqdC((W?&!pZIV_ms#r^C3sSF_i{9>tJ$T4)OAi0KLeL#tge|Rz*&-PD9G;e z4#$_SzHmb&tWp%v=4Mwd8K<7TQQg_c8<{i4N9f2hJ|yybqp{eX6^a$|45DpSZ`5{3 z^%cfrn;fF2TN1R9L;rmE?bW>^6T~7Xl58E^5k2)OPwV(911_E%&vzB(F0nB3FBu9M zy(nVqTz6D!r*|5&%KR(6CNPvREpeCpqJ~A>_CC~I49Dex1g+^K@exj|e?Xs)?x;gF zat}#^nV>_3f~f940DEm6(#(j0!tf>nzxS!)&~3ARF>TL;LG#bPgtl-1>es(25~}A7 zV8}9}c7Vi6aAxQ*LLeN71huMh5Z`VnLF61VN)!P*NAfhvfs)JAfZtmg({WSbhHnqv z$YFydSj#&m!H0UjB+VHl5ee>W7)ThE43bzHx%y8AZG^8nirYJ>AH;dL>L?T3A^|1` z`4Kv)za)_wDs0chu9yY(b<+u2=#RW2^drbqjXy@qkmUk4e!?&am*(+1_yH(^bD;>% zM(DG;nL{3cR@mC{BeP?!D=7Dx>QId`K(b6gy(_R`PyZeQp6>$45?MMNyQuwgmQ-~9 z!_n>s_8Wl5Jqa%YhfsQ!AUw=3VugW-blYSFnl~SCRmL5=#|L6uP0!NP8Xe1kCsq~w z*sKneSQ$(^&S&SQKvX8(I zKfevX@=FQA=Dt=XOwt_%JkoE)*DOUGd^OpSeK_w8ePKBkth#EjHV7U3Y`QIZ)EJMH zBvXQG<1XVp0q#6Ce;l?tQ}WkabR`oQab>w~%TQB2PBKKFT0NzXnSMPA=C|reY#<+x zHaeQf4_f7TH1F6}pPA7$V_|M)457*6&?vM2n617M(Bjk}hE$E!j87LVmvf_^XCJ}aRN&8BK9Hkam@r6GSQt7hfYB2__tBQG;jWVI%k69wqU!B z8~I%ogTL1gh=<)nN9fX~x+q4nO_)4C9!{>@LTHo|vBQnEZp>H7ObD$>C1~D6Y`J__ zI*e*{lK8%gql>(8i*e}|0>_?eh+vwgiISxPs?hL(R#}?{6PbE`d$TAWeZKbGSf=sU zSisXE-c81n(eS+wtl=xM$@Z*e)lh^wBA!WE7-g6Fq}^V4l^0%j@q;24O0zl_#} zZ(RaPcB0*Px=&*(GWMm361)IVTl|HIv{Zn#>Kh>pO+vyb_6R-q0$Isva*`zPO(?^M zM%t{>3|P2?KbOl(LBff7h}hlM>8hzpk-XFwWHfv7s;8mqT~Z#G`@YG9@11jWyOf&7 zG|5nXD)jGlrrZ2DXl`x8+cOiR;aG_+Z^uk*YTWZ9b5|G+yOWf-py$?n)tM4s!J>>5 zKHoUb!!S6oegdqS5yMl2%|nN0CsZ)i*WlmwA;$Wcuke0!SBhi?1=6mVJF1I$t7L@ar6F?5UW{??zjU6x=>LI zbI^X*fBoV2|8h`(?Jf0~_iJas*0CFS6*%;H%wNX;Lj;7n?c!q~2QzTUXFpcF_BP#W zM(4D}61Mzw}X(i_%Yj{gh5h__w2yD@nAV zx=%c-ojx=TR+m_i&QdQ(^Tr%ux~`iHiOxX;m2+rU|9yI3Pjv?CB%7KFnpZG%BCqtM)BtdgHG=|#8^xB^YkGAkLWXV?anAOot ze($S(D`t$B*Vd3G(rwrztV1z#<#{ypoWWN*{@YNx?1zgPYmdpW=JX~)TgahvtsR-E zCUao-7R-RUtDM^r{ncR2PD+u(+7DVCs!?v2Jk+NoK{s2)k&MU$o4z`s) zC1}nrY#!J%yZrp>ba-E3N|Q~#`dw(tG~odz_R}=5TW3w;SGpUmG3;+TY3jclo7#JI zXC36NAo>@d=?ZtFy%#xrq8$hIAaP#9A(uZ`f!mBux;+{jwaFfd3H5g1H|A)57Z~wM zLUN~kkK~BH&?xjiegE;lC5~|s3KA?&W@6(VK>VW*pNc&>xIV1~6ZXd!inBWsSQB3) zd1pd(ekNsyo@)VaU)$>}r%|1d;1PJ!V7w@~EEV)8@#o}HsVPNuTrO11DbIk*Q&}x{ z3rFL4Qc|Wz$?v8!gI6U(w4N8Sv#IGx{<0}b_%nW;l>?I%jP6V>FUDs zPdSB6hOm6PEj)#TcAV{Q=Eda%SQ#5dO1|1t7&j{)#Y5M3DE1U zn$g`=iZ4T6W#9J`h4RX<&RQQc0bE^=5Tuc7rElWFtdq@x-*$ZJb|^>mTkk^c*0Q-U z*0$@v`K25ce^QvwJp8K!+dgY}6>~W_Gef|>a1Df!9aa#|CFNYie!0RNDvXEiyVsD+ zB-KjF^{Bd>R_ux2K`^Uk9!}%jZgmqQNua((A7MrhxJ0+B3S-sNzPsR|Gm93IShr`- z#`c3>yGIe$bu7lWY*K4}w98Io>Re|T4_iN35d#0y*f)iD$hPiEhK~2tv~FY-o<^+- zmtE1im&U?N!-qOlQ*&C9Xh69H3)r=VLt+0ZegjWgfw{Yn$cdT%cmTxiXhX(GV+BUd zt92f5?m1bZYaA*i^Gtr8+*m0!dYln2O+`-ol4)3v=zHo%RfS@UPFLBbN+U|5`Zq=)RKEoHJ z!jEX%$lhxhkLA-q)!;+Ct%?6AS*k}}-1tuWY~O4!37bRumwrZfR}AIr2>;J0&AAGn z^6*EIa5eHTsa`cHpSkd7nzERpgc&d=+mGP~{1-Ivt)n9etCBC+@qU97O#cIM@Z-;X zJ|<*ek?3vK7IOVh9q<)3Q!cMyzW0~_yCZT*Th&)=TQ35{PGP9$i1+Enh zJDfhH8*7???-JXV)ZKeWv`PA%;r0k$&|P@dNw6E!e+pMnSym9&d6$TWu)y6&S@`!&NGGUh8NiH8t(9SC92-;SUdQo+1-b zn32>%IO0bF1ZQpHb4;$0)C&cB{b9YnIQ^0N(moV^`!6P_&_bF>^_z5s5g!VLLxIQn z;gWA51>xvGJOXIVdXw8fO%~Eydi^z5ETzr*!o-iq=+=7tc2}Jha%Lu(vtd(T(Utc6 zS&dXAwKOtHk-+prrewb=K!ncF@BSATwwyDHL@4}_q9fYUk8>cc|5RQ~5iGL;ECqAbTAoY$W3 z9tyHY_+ks^QH^Iu=_frQbvqgomv7fet?{>$9?++{x6(4b#!P})hU17b(ykbzH52$6 z$-gVITR2|GzU&hOXUxVE8dX(Ctqn6$7Bl-%?n88?(edSnj+4~v!r$?1+Q3vZjS{`aim&M+H-mUNeTQ=j{G zWG+?Bh8xOoT9@;sPST;KR7<1B%$mt#Kr7h&Z%ldMKv2AlWoG-$fWXEn|E6;eZg5+z z=-HNrvQ*s7*A1HhIgX;oq4~O*Os$e*|GRIW*A6mDhl4@kt`-q`PsyPnLJq&cwf(7$y{wKuxt0PVrtn>`!et_mc?jowl}!N@~= zwHd0wrrXu+*&}7fkVCg3A(g|Swt=6R9p?RE*6TXbvP6M~+`TH3sdzO9b~S{N1A8fr zv|To>Eq^~S9lBrpcX}8=W9M&L{Oxv009+qD`;k zsRK6_N`1IEH&ip*O^hJ6fo$$;>U^X#DS>&9`$QVmFznYpW(t!UI~B$_@-s>yhgMv& zWJ`-hc6S#!V$=Eb-Dq2xMB=EN$$+| z&Y|A!#_TPFF(B4Ij9ca0M!j(mYB}n-fKA8ONc3)EeWoj4JcDq^pJKoB8|wK%7-5Dr z{K~p2Na`bOF~l3LTjONO*~)Pwa=Gxbg?8QcG;mwciJ)O4rPqWFu5%%3FTZ{1AB=8K zy1}ob3WHIkMPXaC%WP6$!FoOs)C8mI?Oc-JP)RyU!`1x8qmX@{{UY|!*iI0(|KC>g zD2xP2+*ihQRTv~R@O5$CC}ir}xI??KXD0m2H^4(HtWGu6qok~!@aoXx^x+j=WJnf< zAmx?aCm4-g2XL`-DIbqo^yH{YMB`7s*wh8yrsYKoEC>Qmp&o3N?wy+Q9ge_k$+Lu;%wB%_EtNjpz}UHoXlu?^o6*5elX;uAmg8NCNLiyCV^;Y zIZ?PI1?8F|=>Q(9$r4Fj$I;PyCNnVD2R5a*(+wq!G*ya4>8ScO3c9=&PEljw{DIFpu9~V0j#|r7Y^3u6x=`y&bd%1*&Q7MDrTfVT6U2WWcGhwA zLG8giz2NGje>)Z_^U&9w>1>6Y=Wr-EEe72(L{l_RYG*D00bfegt-zw;!;^ZZ%Wk~? zy|}MVQnhL&cG7uvE9miu+yu}Ru9V_idnfXeA)?h>qITVC?03P|C)#30=WSdEMD@nYTWfG+F29Y-4&4EA${I{#Kko?Og2@jO7n-6qQr!L+c_c?`QacR- zJMANUa@HaDhA~GOgGupFX+MFWCF_v8et?{pU>%C7U+e-|mQS&S&gv#p%hsdT8Li$k zc?Ue<^izH)`maYqXXBZ4{po0|#grhCc=aXu1LUvqN3D;qLl%<{jwopE*J1{Be)mzWQGM>S@u z1q*uVB-Z4prSJ8q$+z0Dek*LDeViV-L!`;imxh~BsU`u889N5T0{OQN@WpY860g&G z8;(tYHa68nZGR43x#yr(ni>xaXI&wvibKcL=PS%wj)f5y1$=Q@v=<#PV%JoDiBY>3 zWe(mJteCYy1@U)rCrGy??^%dcBfmuBYcAYcHNFt3R(F1?9WcQent()wrmB#O$Zhh6 z+MTnG7Bo=m+1z!#(2LpP+uswPJu@|EqMtKN;gwsZMrEU zwq(F_qjL&f_{$GT6D>@K7C+WTZW;&6cYaqxV^wH6)Op|dfQFew<`(G&^HMlB9Y z{mF~HHXO`=;=|WSNfFAR>V1~IQtUO(fHOTt6EufIg?HyOKU;pH2RsiY97-7Ea5;K@ z`L5VO&|_W)cEjObc%aU5>396H0dVA`4d2yiY`(g5IsNIB59mLU64c=gHuqR#O!ptC z1izn`7+v$+GtzK9YX5X2?+*>(aQT})nWBx)p&99JPKxzsy2Ivd1(5PP{v4|2^YRK~ zFh3Ul#N!5=?oNLGIrKsP`)&MVHTO6wd;|a3bWYk#UB4CM-KR??3_Zth%u6dV*zVXx z@qtl^BHLa(%j}Gp3@z*pb*M&FiEA5bc5S`(Rme1WICc*q4!wZHe)7B8YgI#l+QRFX za{(D1-^!46V+r?E;!TFOrtX5&$3VERAVzWJU=FP-=KU{8cL_TA@h_|jFC%%sC`R|2 zMt)g3)SMdSsb-9B#=yF-NBJC3bRX3}e*13u@nM6JjqJV`pLgelK&WM=u^|f$f$OBf?OPruV&f^XMsE~oPWhD>f-rR zX8AKN(XZ$@iJe@VPJg_AoXDN`63dlIwav6e>LG$OzQk_ahJL2Q47!8P&JM3I?6yU? zus>pF(<_X65j5u&YS2CR7Gv}}6skV#Bdtp~^rF*!#<(^PN(tti)s0!x%3-0|F40iw_6S*L&pCbHouyGgSj!HJ6u0QCPTIA8~wm~pfZbcY7{6NMjdy<&0 z=LbQ`G7&*TIka-_G3IhlC0I61=e7EQwTxsNe`Bcb2MQ_sI|dfgEr=it991~XEGtUzbf6ZlH)R(m>-rJof!c~3Tw<5c<7BW+6;cyXsrD8H@-1&Df zLM>!ILSMW)wP4&IzMv@O2)*<#GONDEzz2UkQ|3NJqpr7*SqP7rOow5%GjuswEweDESiECD$#I32D1Ga0Z?s495`npNikP>?QnuMF?9@cI zW$9JLgH}(OaJ62znM9q}N|s2OFHkaHm^i4pSfF;GL1vwmx&Px#hlhM z+z&Y15AHYPRTi9Q)TOOuRt5uF%~1b6)C;e>w3cn6PEHxZD$Gow_B!sVaWq9%GAn_| zkAJGQLdE!KxskrI?kG)W@O+WXSFo@8Eg@(W z$wUIv*w)0?4%RZfdaE#C`)_iGEjxb@njCBNmq)3bZG3#4j&rl%<3fxr9~J*cXjEeC zsM>5A^fkr^(-mB`Vl;Esu@>6@UeAWDBeQjc8lgn?(3~odZ^0h(8U&5;XBgeM5_Uyf zZ`kI}`YkD<8~TycGPRsTuP1e2J5_w3{oKfutd8$0yF_{3`;Yk`1DM?KiEs$DN7@Yh zR*4u3;#;mfnq!X|jUQI56~vE+A4wkxZ5>BzJG~>lWB)V|mh!6zsRL?sk*?I?DV6f7SfR5ABA0BE#-6yDv`y!BQn@mD3G{8)2DNwyP`!WDes= z%Q}v>qo9GY91{({X0BA|_({7X+H$6)Hhe`Y2tEuawEi6WyP{rOKRyi}+cXneRd+O3 z@7w&V#)aKwGh05|Tk~%?$er+4QNSBwHl-8Fa3#MDn>)b=LVu^>7P;=*Mouyi`ZbII z=fk8VQ9C%}D0;B66>DgNXJ=0@Xw^P0&Nw=paXid_6s8rMWy0s=B}6lo3kKb-QK>M{ zOsSJeQ{y7Tbof#6n>N1Q17D}&78;H{ah&|hyF{BU&*h=8p0Z}s0q%jU`=}SRXLSYn zuuMuXnT633$rpMa6cD7S7Y?}Shq>gdR_a=gz$;-FeMtS#^wD-{9I3pudJDJ>^YcqiWY*hXcKW(o*xF4gDbz=*yx9n zED0C0!aid7e8OB;7ONcxU>0dm8S|FO9UwC`?Q-rtWAkYOoHEHLbyUd!Y?|G1AbaL+ z2T-{Dd-G`kM)70ApR~se3!;{EAc|h{;uT*$1PsKe*z13jzL|InuT61*QZ!IDRhTz! zCEdDNLfXg&p^%$*wBz+y^8Rh(C(6fn7zPcUi-$8xVk$(!WYpICd+2 zsnc>EPT}Bd_e0o|KZM}W{=7oRKvNVTTd5~(zrKOaLoT{;7CHnaTrk55f(P#+NDhZ= z``H!BjCT{HghP@{g|KuSzQV}e(Wo1OqsY|Pgt-`&4pH9+;{D!BGF(Xy#cuD^*fFlY zc;`O(9*HZ}P&EEyQ7ywP2!cy_=Lw6#p|aZo;{zvjPnx`8G9P@Af3Fh0?c>v4V+2}q zV}L88>(L<+t<>*l6MbZ}3rmJmZX|j>Ifo*Kt&2pF>;#?I`OiMmpPl*r4F7R5Jd>;$ z_LFeQi$YNbZ;oK=ca+edj-4cERTS!Hul-18(~TtKHAZ1?tHnp?8MHtrpgJ@fX|B8} zqgC_BqEMX^jeZZ^@h^*UzyDC5px;$?ph+1a8!x*i{Ihu}z48L24vfh&l2qe+hrF-SbDlMUN_;!t>a<31_HLSxV>+wz_e zhB+LKQ|)wi$?_d^d^Ud*u!KW*#MrSVj4ycDYKR-^xRxceyOJmAMA=NiglbpPSK&l# z@%e-u`|=PCgMaoXXw5{l!ne==(WBG!2_lb0x<~bK?2TCu=_212gqJcFO&@-u3AX@7I#uCUs66()sL< z2K($pys~gfW}`k8Cu=R(mD7tftBXT1N^;w?gZlJ_S=0C>iF6X8Gd6{?hg5s%MYHY^ zT7M25HGTy9e85Kf?f`r-OE;EMCSfiPRfN;${_r0yDx8G=>>l-wG!rVZ*|^6Z?A(r> zpedK1*W?`Pc2mMezx9F{aYZ^>jZ!JwY(aVT?8ErBn+w)*ej;*EA@TXvI~iveCG-tg z!H@x`Lgjv5F^0M2{Nf`=g^sD-i67L_Nmi=DR6lm_R$U}&>QpjZ8D}2}VNVs~@~hi4 z!lfz|x!4+1(v$w31UIH)Z*?PQu)_SEv>-Va&mg(P>Npp3MvvabGz{obYA>r zy0h6`Z&DzY&c$&X<2iwKYVnv}yP`KSLET(*f15YI=xxgf62w0ZoAyo>z&-Eo1W|EF zpoKAv7<-HAC`#HveOkX_4m@r-j-c{+sJ!dY6fjQYM~reFO0!gw1{>eI5SpraShDVF z>&D)iu!}a2wd1Sq`KWkdz-OX($$aEa?R(Gsjh+A&L5qoebsTD?ap?JlgP0$|Ghy#KJ_{8t zKp}r;45Y7J=Fi)NS%@5TZx1;~h7hrpS=jQcb07BVU}sP*^wFW3yeyfMCDoL5ow=Co z0rm}+M4P&`NF4DkoC%-aA3iv>C8%^AqNi9(rng}_z8)P*wDMnvc}Kkg4?Va&t=e_6 z?s}%hh9RuwPzu^UyQc;hXB)NS1`OKo+pJ+|LM(nMhMQV)H=x=N7xiJMin>GoxPNzb zHeeqgOG4O@__B-Rz0bVmHel(NYTbd|gSQcuUmr-5&43g&w@itpVXFtxM_s7K<|hxn zWfEq_KgT7daag$NrCUknIs)uy0;NOL-O&FDVtKRCIt#;Uq zPb1o^bx)em&9Y^d)PnFyOi9~0Fu5IHB?}KCQSfzRBBT5uN^^Wy2lnn#V~Fn0hli3w z9fJ3Ghg+vZ%Tg)d{XxtKNr{9gf-}I3;L?dWL;8oSmtB& zlF|on`3({xo<~qa#e{J7l6x|}*!eBb^a$!?JFx>KnDWOojYqKatkw3+ujW+PvXWmW zIUGg0V8=}GQs*di*2p<3^D_{=IzZ~hI(!mjA38+r=6_6PY1ICCJ8<=>BfqN<5k`A- zg6g}ANza8GlD0$$JE>xw#nd&&xcb1Nh>t$c;~2n#Hp`fZHTAT-G88vjxivxjaajT- zFS*8CpzNXft{sqAZQ`g^2V`u+;7*|3(?pnP98bvJSyH3a__krQ6SPagGYj1c*RvAI zSC2c#T>aD!D%SC9du1ic^i>~MC6962M>o0TSEAVl>@lSsHl@Sc+J&U3Xskq09qt|^ zs)U}$X1RJJ>D7k!36jGhAqflV(Q~>HPnU3raF{QBYvdn7Q+FN>T{(RS>r%Xg?rF~7 z8<1W=&abC!B{ZrFNK@ByJL9u$I{aQ*%g<3o7f`6SyT-D+59@>NoXf-`!YT}q39ehU zS3T1~R?J@)S5~3tx^GE_sK-5No#(2mkm-cZm5h6bL^u`3*CdTqm}kspJoDBK>D+4U z!S9tLlV+%bssY~kaXW4?S6_{08$9?Y?H>~fr(eA#9ZN6DE>o-87Hf@@Gr(%wA_XBf zzJy~|)OR+tczIDlrXtTvvSdN{9zIN}E}P^KGH>s~oK&E@jwH&2UPh%S-(1kw>s~u>KIe~TFC33jj`+LL0_L{M zVEFLKoQLZ<*zwB}?c*487-~FV+1yr?f3u7Y6ghy%u%1}IqJn0j_!w_E#Y9rh$CLB z>qdiS2VcnLJj0yi`a%zM;ZgDoIR>q|qqS|70j~xvB-+$H!ztp#0Z)a%Ar;g)qe$Ho2-VVw?7jfUeadB1_db4Aocf3jS>ge8&|mlYh+1 z^=l>!*s+P^yWH=%@34E*tI|;X+|LO0YA-UL1Abs&?{hg@w!a_~8k)!O`M>A~N-S7^ zlDRN55!M{BAnMipK*N}w_9jFc<3<@Cso&Zj%RbU3(8J_s_#6@N6KCITM?NVoty@nT z7XC!wt+Tbf8TFg%b%Lohy+jW-4Z|yS+%Su8 z#)+&r2d`3bkDB~u*^5>JGraw(Ym{eZgI9}2_h(gW+Cr<3p#-hs(9c$bS^XeWuu0?B z%8h0=B0oiq3j?HqTRAp(?|+gJ%Usj^A4 zI&)<0d7}+`s9$f0e5}!-8mWa%gn*JtjX}^g6gFwskoq#u$_7^jlkh-+3}!1E{9v7V zI~eiHAC7(rAfezOLXPu9dXVrS9M&h45;Rm~GflX&csHFtX9ceGxN%%B!sc_gOk`io zJy`D2%|}8Oot2nU-we;w$uzb>!_}O^(FI zyES!ujxn2j)E}4yd~s3di1zgkq#=~a=VL?G&Bj9LIkq2!G5}XEx?sS7@>93U9g69yTC+e)=TceB?7f7s`6t_zKqL zuO?1V^+X+p>-B)2UCsHKxTvR1vfzHg2|^(6g(20{`HJpIqwHma`vw2aSVYWP;)@ zQ&T=wDSV4(z~Yx1iJFCdY%aH^My_wgI=34PABQIDV0B&q3NtZqpH|(ozdIg81fXf7 zZWR+dHgZ267*;~~It)g|PD}d1-&S1`%RexK1>mSX8w|fU* z6m#WaDPE})rY;Hxf$>KoyL31zI%k^`t9bj3-mkVGv%G3Ja{O)moc>{2Lj)`wj>F;T zC9Gq0=WE7+7`PV)Ww4ggaf*!48@y;EYs$F{5`aJ*i8jB$nI z*5d3lsbh_<@sa}ixJ@Ne6s$!p7KJ+)IIS^e?K&E2RJ@@W1Wo|w`+Y9 zCS&b7h79rb_`h}Ed9=rFu*v4V-!a_qzJC^@i)v5y1;!0F(>igsMe9pVSv>b+b+6bh zHPlHRA^L7h!bq_nRd%gEL4{#cLJhT!828&moBI}-k>--;V+Vh*@+vc=tkjfORhw^f zq7!G3#|_eRD)d;u^16A3g1Yz2sV}w!t<|&r(CYX3^Wr+8Mfjo&Y5?e-T>#X_Rks!E}?fD$mn4_zY4revt0=#{_5? z-Jd9-F2@=@+NGDFay$c%Thjxz=UJOP&eWPMM0D;sn+QI)Wkw0p{P!TjJL3@!`#l|s znd|lzCPY>Hh+P3L&Wko&^;^%FS$-mfo=>nRhYi`p9QQd*x1>){*gd(ShF_LvnI#{n zov46C53XEfm}zs0>9L*Kii}TieC_WRW%wAdi?Q7nL3oOuBJJM4F$VpO^-P4n8A0VN zI^~|iFz;e0&oW)j@U^7=V%lEJ8J z2ZM`O6FTl6toNQ6@@DVq9t4s9!JOy+H-PbX-%gMW7CGA25zfRsA<|Z`xh{wHg@lo% z1abU}$Q15i5X?VJHTsLW{`{{c}>R~m%-We+ zOjYo*Ga4kaGwjMXBb97Vh{jZVsjoZZ^Ls=xedbeXN?&&#WX93m2o{rKE#G!-q0@3dea%H5Y; z?;#$#?7FGpRNRl9r*SzW109HZs<pG)z*wXlnjd&ozx`RkgVQx8|0fbs{Uwv^MV;B@5;v z8E4BFxsf05hpm#-;Y z*g}xYIr?@SnV{t@1=&3F$8TM4AW@G6cgUb|Y$f3FmdzJv&LAq;e1a>GvHrwENomDr&*2g&%XWssoPGF#j|+6 zRGf_PjHwrf(eBwEsdKeP7a_uv6 zqBZR=>*ILGZLGxAayVoLS_@ znCe35-5quR!i$F;`LpnW4jY7|w7Z}k=V@XlnFgx6V@-PmeU)4fh=(~psdgZxJ|7+EbDMYhFtU3nNSHXyzcj{2&(kwoM`^x2GVKm;PkA zG=iH5*In?~LL8rZ3aoflwlUU;Nt@ETK zhb6%DQgTL7I`%^1PU|;F6Lul7eMiDV#-iSX7fRuG0{pLyGh_0}OY4Qoio~r6jT&jJ zZ0i?D&t)XSq596`O24KTmh!Y>jdVOO33e{9BD8!*l>bbx3DQHcNif8YIu;hN=wIF> zsp@1Beq*PB2JCPV3R+nd{7!=Qo4+Y19(Ax$1`Cntf(wJC%WIOL2$Zz9FcLMfZK!DR~!@40B#SB510U z0B@D$$uKYEDM8duSVDDLjAU49GMu<)Bq-k*(YFz1l5_arbkyow1XVaA&j}W<%Lb~G zp>PAW2Nob|6>=-p^)8}={H_pv?mMGC%6?q!C5)XI{pKR!!0nA3N@tzYjJ%AruJme3 z#G+A^5!zcwW+uiiMR@o0n%eX`ZxE{(T`5pVCDt_4u z^m_DO{xMcc%@f}JaZo?(rqJ_yD4=OCAt6@x$HM*&Pu73C9t-*X==Xp41CYh1*YSFr zh*&t%GmFrA4nQ$myVHAc#Q;GbXRNrGEa9So_+RIrdkLj{Am$H`5b2A`6F~SXkI-Zc z#Flq13O+yHB83 zSgC`M&M-F_x?0wd64WfRy*dg0Hb=h(lfz!kAXIzOhg4mcj>+J{ze!aYj0HDd-=PcX zh_S2JI7-RgOWa_r%$DL5@a2u7AIP{r80U{m!qz(1=E=Z``AQWWB8cE-4NQTIr<;fa zg|co4woh<}yV}>~Nf<0X!}QY+2`Ul^+MBmGcO(phMS|O$Yt^+>G8fEo z`q5?G?IVe>;BON;3AtdsKDiPH0Rud6mgd@{R4yoo@l=iOLDxhmai`b#d{@j~zPDa? z=yU=MFC>0GN`)&{g0}vfZfv_a;2s%6m=?Gq(`-Wm1SU2oh|yJ0#nJzBF{lt@E|2Q{ zy3gklp;kucxLOts8oXV%OBW9Z^z^pQQGx@t;o%mYTUjC$n6;&1OOSSM@*3Ul%6J%W zM;d6|m{>IgUr{NGO{DH$M5rB9r0-PTyxYfcxLRF-CxPEJK+X`BKi zIwl<7@9j$^Xf>cr_u9#VT6gMZRp5p>SEK~%j+IBlvOe3;##V=) zl)LYSqOPxxf;ampp=dY~j^8>$A|D?GtsM3cW^xw2{&Afo|40jqUz%9@w*6 z?r1M@{um4PwaJ8o(E~YLIOm|xHzzgGZofS}R)@ znK2HS0l3j1FBVwX5bUXOSR4mO2L}-z6(f-Ibf61zE+hQaBXOHe(5@$v40e_YeSpY(GzK>2~X-Wu1AB@aoQR(Pvq;>`>5`X zC<JWB%E9D7}WgPtvS*(2mssOZwPS)OFTRv zNXqFD1a&!2u)5h5wQ>wrW!U8xgs655%F}P#O6gHq5EOoRL{QmSoL6Gc2f>7fhXhF- zi_Dy#CrRt?FMw%=y98B_#oU?gVx_GP1Vh$)j2&uH+j<^Tlu zaLcwzJKBfB$a&=iRg6Oxr|lm~Gfss;?txhof4P@Ibl#0N>T14EIo2) z7+Aerjt=*1hya&KSbF07NQg{KBpow&5;Dv^7|(pZ837@Qw0mVtLWVa-4`3=QVqnpG zf4V4CVs@_bPBgl)&?P%PjQ&Q zMRBlmrG!*n>SP>7?FQ1*zj`w6o2r(@!>6HL$p8E)C`FTRKcqZmJUmIFbe>Z%m-Q<; zy(?In@+1F~#{8E6?SG&H9(nRV1q*a}(u8RnkO2GL>1Nx=62A=pBo+83fCJB(6vLg0 z=ve+AY185ad}3)y+m%Iwe}9sO=OjR~p$$RhQ?YPa09_6S=;J^EDmXl9;%0 z)3Iu&oTPj3g6UY+ymrl*6T(F3Jf7~hxifGjS$VG&Q-se}AAjVMGBai%_fD&L%p0#n zXqa*ZHxXAf$*!Z$YmBR#Sl&o4ih(=C{b zH%hvcc_8(0O@?7HW9YHQ8;S3T^RqI9e6iSy(vhr z?FCAKkATOuTbTkL$NQ3eo`~?aze$yX9Nk(H#}icHgGx_TrogcE&&4z%hYvRFx`O|S zO!g%1Y%FeX^I})}QK8u=_W;Kyl2;he@V4(=YLl3aa>tb9O5T4>0b%+yf>z8Hgj%`s z)=19a6VJ3|&50FM=8JveRe`STC7#X8uJ0oDi)vq#uB`n&&FDWVAb<0l*o63V5VaF@ z*B)(1fiHiT6IxFeUFIOtCfBFHl(N}`Rxt#ClAneLr&vb$Dkd9-ScMpAyq>2w}f%6A2NP6Po=qyR*ef5R$@~PIQk>{AhL;O z7YeKi6p`X&ELyIxD`P)uH1feiqH?M~Rz%wJEU_)3->RCMIH;=q1;>VS$X(oo~}djtFL*2MsAD?+SCSmkk;kr<0M$y0E#-Is%jxqtLl@LL1-eFkC1~vdlvG)|O#f#&es3y9r!(>57ow!LE_?O2 zTSY>@t=|Z$C`8*-Z{9c^-or_04+vLQ=PMTGU}wt)Du9q(nzB6?$eB zQLC0sDK(4!Z6%IkBVSE8!Vt-eP{y8qq54O^W#Dk&J3}sg?-vR7phx;xQ24hd7hxI4 zP@GRAcj-kfN5W}0@}@^sdrZJF;~0j$r`$@ATer9G_3EN=(9P{UL5(HY7xx@INm8QY zNK@9@SDzN-3qh@`30iv`*?Y9xEuFsAAL25;5>$2q(H(DINUx0WgRXzR5me2hPE$OX zdFOnf#Tkn7Pa@hT&|lgtX(s$ivLs?FPGZ@`3Jhaw^3}V45|tm8(gZz5*kCg*r_kp1 zvbvpNkn<2I9(aSwatb*$ap++9+c*S1sL0kzB~uAbn{k`;0GQn63LzAgBJ<1(gg}{5 zid|#O_TTzGK~rGFD0&H~E<_WYT29$UPz8%FIlP+TXN5yzaX3MZEZVH^1jfuc8cu`;5L9G98Eo6Of$8~naJsR% zft5ieJ1v;hlsnc>M7_?TZT7!8VgFnQ&I{_T zHXeJ8AyNF{c$6~18M|s1FW$jFes`>)U_~EsY;L+zJW2ypq z1@Co)>Ytc>>Pf6ZG8A5aA|kSB$zU_68pQ|n90;@-|G^#@y;J7 z^*_=^LX4G#frJmRyv&*xN(RBYDfAXyei`fIXg`1HiXn0sr@Djr*%-!^mr>m5T?0w= zI9|af=l^jgsnjc&WoXqo#<*nxjfS}}zn}v_ z`L_`rR(*!aI2HoqPn{txsJM+1YTW4coRLjU$=^&SaZ!~Z+v7YNqqSFmr@*Y5>86EAskn;+ z?X@^evlf>tSxK<6=`jc9-(MH9WpTNOOpORR*{(6Im#U0=f)4|% z4mKN!@h3aOtc{~d;}lrhN_h1F0q|4umhl;iQCduu%584z#_cx$E;Hz}1+8a!bKCZu z?zuf^G6R!lf0Rd>+s@=oP#T%MFY}??qBs55(aIK0-cGNWVzoDX>#&KyDw&n-D=uf! zV|vLgYmbGu+jznCCQ6#~{R3J0)a`Avd2@YRmHkF^g^LGS?-dfTn~xq zb%X#5b4KVFe;@9xSfBAa0c!SGxmPVlcvN@d zPupBh(yw8JAHNso96iL69tawUM1&hkkCX1IoOMur+DQaZVty+WYRr5snRy&9u z_gx%q#a1mB^c1VRCqm1X1E`S!QQp_NBC*G?L>Lv&j}%wyh%82U4R+0$mXF-+R4^~);Hm6S3RL&Tc33t!Oj0@)eSALlCa9thqLoX1 zCDVNq;XsfxK}CJBv|&fwB|pOxVb(PvW12}b``Xr9eaJSKM5W=`S2 zk(~Vgn6vk^CE~;BiC}rKCoKh0tIwZzxrE@M^>;iZ|f7cM0AGk^>71yC%A8)JxGqe!!7%t{s5oxec76$qq||y3=JrD;Ne_RfTQ5goZ9?z1!r8g@{3D76^t(6}=RCT+JO+4&M= zc6Az;7AV022Xty8DSVIwajmK4#mJ(4>R*Vh%#&fYjM`d6QbdK#9*KuKB}00^cWMpE zl;X^|YeF(ytba$Qn_8C8#chW83SM7MyiW};G6oBty6zdh^ebghUj5=&&ANnS=)H=X zKoo#k9f$1ISg%Tk!ABnAg%ca8=ssXO)ppF%tih|#<0TJFwh25dyV=(AQm&e5m*d^% z>`Z$1DI1PFF3gS6j4MutkK3-9-an%KVYuxc?ov%MY#n=f$=(5`LWQ zA-&=>x?}c*cXx`PJx+$*aGK~O@<8cjQ?ztK^+1|y)n;f$NQSzj)QhOr1J^?NF@H(* zs1(@eLajCYk+wP9o5{EYOpGSEjUzGl@5XHsZgvU`I5C};FbbPWeJlk|*@$T=EMhE0 zLq(t?L26lKUPTJ5-@zw{Y_zS!Y>F~{wCw^;GnH0_BaqGi{0BxUr(;uPGrlGC** z;L?PixJ6!wK3aKLd=QtgCP_xJgk`X(yZc`86I|*-l(_Jkj6ii>*!5X6NWZ;f$v%ZY z7JFf~OQZTCqM!CUi-}eE{#b0){>35<>&B5jVh-gx4!L%&^w&fo`m`tU3sTmysNCnU zrURmJD_^;oRwdbZME_epSo;HQCXc5cC)*u0i;k#Xp!LO%=pKK6wv4{yn}8$j@bmGm z#CDQ6!B)f@>hG=nhEyN4_%z8h72ThJ?R?zTNjnucnvP@X?ng9{6)JRV*-tEf__?8E z7nLy)+quf>0ZG-eH0kpiT^f+a?2f^Ns$`RFPs}hc%S}{1ZQaF2B|KoeqJmQxlci@B zP*sH6P3z6sw7!ZC*K9ip??kaX^X2m#IM;!msWYyWUDZ2ScEC6_%1s!FLmE}spW5P5Pdf%$LH!@c4$LfR3gn-&!kec2TONV21pNhjfc6T`P5**qP;76>qcLj1W!)2BWUd&yHH;HKCShm zs;0vO{Aw&YIHu)b=^|M#y`9h>geR)W6@#iK#|~X_@Bo9mTlN~navzdy@AyQza9}J% z{D>sl%lDz45yJ6|olh+IRO7sB8qdO9B;NHhfO&8w7LN9$^G0eeiq&hLFLT>J4lWn2 zmXeKJO|G2>XOhEj(wjZ=km%yqjnXqdDe&Z+l%NH9b|W}ZGa5?Cs}{@sc3?3GogD6N z??+A{^8I$WPaSv^y#*rR?RPGX0dnOWav6RiujiZ3+-|_9b)J~tGbYtf47;TnSLg;9ZEMzo(B|VE{yg}|bgL^DxGQ6RUEa;;f87#fKPfyy$MMzLXo`2212GtLXhertm8$6^GV9{ z80Oe!Jr|DurKSvSF;;Oz;Wd5aotdEiNX;IOC7A2`M2#tzDz(H8{r-7@3-!7xIgC17 zOqk)vZty<*>oL~@Z{^T+RTV+yEP82wxJ2g=2;yO{2wK6St+T&rx4ia;lrG;1W5<(h zzn`(Dnh<%OLZZ4JHu?^K=fnN7hXgHP(P5KtW z>IL|^!eo#NR$;AHtu1GQszySW9!)XS9(%WzrbcRUAqR3t3*KK-R-*D)eG>tJa_B3FFHGTLm z6pR78!MD)K`myad>B-%h zBSmYOvXC%1JUouDcRXWB3;ycxG^*JQA z8XC)}4Y8oOOTO-)qj50p?ohRr>KKm#t@VQr}&;GRHeAg5;;~-H|LBi*hcf0ebU){ zO@dDuUdWt%H|>4ZZV&fU4%X|femc|Ty!AD#*3?#;bt``)L)*3VwYKpZmf=~GqrCL*7rMnnCdg&e(g|%e%T;*e0WsRm_zq7zozAl!z?5jUpd(COx{X~Rwan*bq>)T_-i)qVsgX5l{{x>S3KRd90)JzPtKnV!d# zPiyQk&{3Lw7EiYFrY<8r3HDqllalL;N)|pgs76wL1>Jx~jAcv>l)BbFn|D#RT`F%A z2M*5pudaXm^If3rX%$XPzxVn&)rd31)^2j)N$5I9+qr+v89@x|T^= zv;;PWX7BO6HX@6OGYc8c)(EIn7E^DuLKc2qT)@;Fhyb(S$N#-Q-h^~WyHm_YaT)tiy%?gk#ScN5wGy(bqCq(F({d7a47XO0Si5nZAQ%FVzMuhpmNJy(Um&7v&?6=k5%(k9#W zHv8tm&6Q;Yt<69=zUpt2lq?fdTWr6e_cH5^P?~9fnHN8LwJvJlJYWJpnut^dJMD3a zAAV?xepaWs@cAcQdmXb;mfLUq^mC8;L0LF`tencC$9jk8t(MGzr@_xiIn~*y$*W<$ z5bpAvAfCHWx*hiG_0kU*RAN3wxx4M%ESi^iL&kx}%9IQJ(KmNDw(#2bIr;&)GAJJP zh%V)oEPP4osUNz2Hr#vrnJ{(SgG~2U&tMccr-9ahak5z_b7jpQ`#l!N?#_U$k|w5a zfh!Ah>~lG;Ma{_SB;RY_z`Hqjgnm&!A8^?FgU;${`>>2rt48Z5G?T%h-;Gq2efD{r z&8O)-MnNvB%U$?Z`ow-JEO|`gQmD9j_T8Iu%mQo38m{unx1Vpud6RpWOq>-5FjL0B zLlOsW95k64N`)`LI`a2SfR$7J?bul4FuHFin0+U6OLYMjetK#<^d4cuL>3mJgu>Fz z(rspFIhaHDl-z?zls=5QWK|qQCe7c(gWF{@YR(WI!fcw~MLIDqw3WMX0yoV7X)N4( ze{cQmMG4UO`5@`I)rahPRvjLHkVcD=VP>=AWCGwH#*Wj$?ShsXQxDs>!!T2ANS1=b zsNY)A5$Sx-c-U+<(xjh?dxRZ--=3YI>K;W7Pp;9Cq+T^F*-;Jim=U>-MFkf5P^{i?A?h7@?%JQc(+<7s!WE&q7FK8 z@~Av!pJg@YzqMM&$0-n1^ol5xT8zYRy5&fp8I$4Da*QaOGujrrO|g9=_r%6zaGTec zaOECHLYFPwv{tyN{0wPN9U+2`;}q7#VYJjV-Bqwe&63r)B}{>y*LG3Y4dDr#EMB?a zmOe%E*|KDF?8xk@?{yL@edP5u;V z+2EixWhh{7dRuAbj3m(Jv?ML;sX-xr?v5v^0u3@A+x(SexwQgr-k>N~i)hWJJ<{@& zcyLVgAhdE8_0KxMbm|rg*7qk9v_gwLdD+D=VB@@#AdWgLq4@ZDl1kOt=Wy5Lh+(B2 z?LVG+$!9KW7syX#EO7peIgEj%13jGnGCA$=_Gss@Y zU93sLUBSlL`DEi!a0ZEtbG8sm3AY?mvuCz*HT5HTIToGLBTQS0Rvw%1nPgK^QI74b z6TKxgsb?|Oc8Q&aT=aOI!$R_oHW#nMLMHoD0qd9C7N;1Bl@gl3!^$126OlQyQe;H-%E+tEaD)_uTKEz78(^v2B z6b>GfbLbAa^n!f|Z>ZTEeGg+eoDN%WVyp7JXy3b|<^Ns0s*)btk2U+hi%?eGHPuh- zRn52}B3!H4H}YhN)eg-Z0R%ivv{QKP*{GIhH{{}OKG-960s`FO8gl!(CSy`p{B=`hOzO^y;_dwKN>?*-Ap}glVB)Z*;%s+S#n~R?y7J_8 zmzaUIU7?9gNR|ZAn;utqE!~C8wI&Q$jOa=DJHG8v^^Frb_CI1GQCUCi>F3BTne~uy zIP?>b?xtH~^Iju3KYl)>cZ9X(y&fg;`qb>xFWKh;Z>I|kB;Z5cvR=97W^GlwR`u!^ z#5vaSB5{RR)x7V8A<5$#8l(-)5+K)HK$Mk#>~+|NXY-URU2`@G-1j%7Rl;>VZO^r7 zeTq4_K};m)J35B)y6kRlaKDzp931RLBrkAu+-$*ZJYB^2r7b3+DP{c~+jHK0E~Qu1 zsr?;CaD37akff@*zhi@fH*ddEEI$+r{nsobC2|isUU|ry*~UiSZ1pJcsUu;MRJE&w zU2M4)c)mLC{(~NIa)mszrOJ`H!cDyB56)tN5uf)ZQHxA1{>jshjxYOj8)s6Bj?|G& zm?y;ZRfeN>s38SXo25We(?f)|fJL>3j%Wo<@Y-^D5kZYCDrLrLk8*L^tDz`2 zAJMx#D>YVa(f(UQcY~sQA%4sk-%s3Hdzj>wvvfU{*=bg^Pl37fDP0DO3cjRk*78!I zsogPZwyw-a@lU)O=A);nQg9Mqg1VjNty>6#>ic<`X*EL8NOQa#VL!69Ij97Z5a+ zMY}KCs5}2L0_^<@394q%$2x!AH^)dYi>GKci*9mu(p?LWgcYwS2mT>Moq6?Ihhvd2 zu{A|KS#(y>L2c<%oVw;6Abb^vP;XV+^BRZNi(%Hze7tU9H;MNTVI|oK&y>CIxfs?8 z5H>AsmWQ!&L-+0{c}0g&^UE%afqRf5^21oh%`3&?FGz8aZ=p2J`(nK zpe0uv#*$-~*|?tYjfA~92kFU6cmzw{c4&~M)!PWTBszjH>o4Wa!vBr5)JFSZt?-Z0 zx;i4v=B@K=rBfXag)Y;|3F>(i%iHm`r*6g65GY8jpx(uCN0EhYz%bq4hrwXe>^d#5 z@TjmAmm`(K)Q)#ae&bObVFP)JKd{VAFQo45@Gt!3$ce!v*>kN*&AZmI$a16^lTSaNq$AmYy4(O6~B%~Rb=7fS`VQUM?VHsG=`^=&KK`U}6yznS?>9{gLX%N~670U+AdWGc4o&`0w4wy% z4_r7M5`A0HFR<5@U=ho2yGp)?%z(yQRwTRQam=3bd$#1ujhQebA49vFV!3!9M`G2S zg_4LMZ}`&1;-BrGg?owoB$x41>uoP`2oLpf6lj^?-%S9^ao#Xr$;Oql;lBnNwTXWM zn|_6*gT%hV2fFLYQAy#qT8Pcc! zOM*qZo61&+gV3o!iyT+lZQv-hYl<^zxcipE^$bui)F6XeM@b-N*romxk(fSfc zu^iF#tT_bbo9Npn z>~uowc>&R`=}Yx7i(|o}?-YU>F9@@(HuXNQJAXbIPP=a)XTXe$$k);Oon+996!6cs zC0f<8s9l=_QfPs(S06l)n0!*aD}){#=MNtUjk*G9c4g*E@fIJdGG3$q9ebT+U5P4w zR&ACRj!1#-z38R3q7sSwTThcpwx+;I*=-XGm9bKI&Wt13%b_N|(#tsUBqqf{dEI|f zQ`PXVV7^=7tMm`s#)9w43R1L!MT26u>G$-EfkW4O(?-35-Dhfj2!8d zB)y4I?N!V&{#&E|WAy~6pSFjfvTKMw`f6r4EFKTW%)JCvUlZnV7v7lyvu;oWhT^(V zVwIZ1GYC7n!9!0i`To)U>sTKP9afWEq8m6Xta-hU)OPI+VFRy_+upEw;v{%c9ZA)> zh2=TD=NYDiPK6UgeiKx23n%-jt+)p3;_(nVHH|SzEV_;ShE8}uQnj~HxwLG$-pZC3RQ&(ZH@g438UF982)4qy-M~HTqYg_17B}8|H4OW_`_WCJ>zOcmm z8@WmHz9+2b>DN_BdM=&@oT8Rw#ZVZrK+$Eo#u$yr`gx-VME(6m#k-FpY;FBpKRb(o zX^qtc&0x`>hZY8xa50R?dVsDvtcPyhee4wRIn51EoFs7b-3>x4dw|4OW?CBF&0^re zH0u1VX3=IBxrVKQ08_qHnrK!0hiq55eCZ6yTKkACCxEa2_In8g_nku-KE{FMabW@| z{}P+Kvih+wn)B-<@wQefo?t~=`o5CN+W5kj%k_Fv(NB?=I{UG7hO<9xul*lEGgvh1 z<#lO6hxzbO$%d+9ts!+!QImAgNH3-a!iK8Hgjn_r8K=)4$H)~S@buSVg7TlU%k{7R z&$2vPn36S z(xucdQKCy*>h%MAdV}?XF<7_k(;Vwp!Yp1=k3{D0sc<;YTS~GUUm@|n(ZiUu{4n^> zg7$3DYn145X)e>#Z6Vw+B$#Mb6|aS8^zCPr#rRyG1pyE55f+|rQK>d_%9)eP@XH4d z=(lYe;Fi@WZgP_o%%8vGp#RufdUqLIjbm4qjiLTS=|yQpHTE{anL|vgF;k$(;R6{o zH8q(1zt`T3P#OSn$FI<`-l4eP&rf5nq=mpf%Yy_hc!v{m?)vqN06&e{!8?$kMwV6` z`GUEd9stf+he_>--Xj`b&>aq8Fa6dq4E;Fq-d~ydUKqmruKmUA?c)bUr?YkRN$Urc z;{MD@%+(<=P<3G9KQk~3KNz@yxpqAqig(W@1y+AR*4w+UmbywK;ebVfp5CH-MB*`X z-{{BGxPpB?)w1evpv$j%1gA!tC1;)0r^Gg-~m~iJ%pquzfe2!}+UCFM>FJ zM#N=x4D9)W2XmA3X`iuDlk)NX+6pc01fOvo{D&x8Prxo|{Xe1DOsky!Kj9{;h8te` zj%ycy&G9qDOPc!y3op7{#H23@2Vd?ndg7OVVVnGDx`YwzPJk9i4wEUg`YR6lfzLC^ zyyW=}^A47+U>ZE5AU<|5V;U|6-%!C-1zo^umw_Pi??{)up+5}aTEk+vNzjV#sLrg$ zKCo*iJ-ImkK)SY(?Z8*>4mra!30>+B>}G!lKWAPW=YxFx4?O9zSAAYTv0ESAXw77` zPJ+D!)JvWF3t3Dv_K|)&hiCFvyQwF7@Gm3|9+IGak2{1h)BK1wjIGO@;_CM2-Yh$k& zPEnl98zrO_jWe9E6AG|Y zTzc3}Z)$^znNICF3(7~5R4tnd;wI5cQlZSrgTwsXO#V!jp*(^GE1AM&3*k#`wh2{L z%bf5o@_>~sW8#-F3yIXTY^8eiu&i~ZjxDvbP{WF%FS_)17}33veL=|vzZ3c(fBWF( zXvJdBu4z6f_{NVj^oy?sL%6zx6sz{ZytguQr2HAjnalqRGnmS$X3_uTH*}L#0%)T5 zG!W~%^=wqKZg{4C?fPK2+KG;kg4sy?EG1pvqAV27c8DjU8fQCUq?gzI_1P!l;bieW z(pBZYPOUAppW@-|g;R86?46jT)N`()<70Z-px9hqfn=3+rR*Y=V&8ypMm1isa8j8S{Ih6AT$F^RP*#CjGmpnuj8P z3Dhy2^2flDrge0_vYd}a+7!CMn*EuCi+sM*2+pUHXuK3+9|=^>cWUJ7euhD0_$Dmf z6tFeG$;v8kUZFl@O(ZODmQU)IABg$dD(O2CMIZ|P*XgbFk#{n@>)u^UE*J{~QSgNB zRnlZ#5-eL%NPB)D3SRlL2@!xBgjpj}l+qs9!|u3R5mXd}^1H;J*G9BT1|K~R1=F2X zW)LzgSoB4=^hE+p^|d6#6)cP4;_iCRfjF4iQ}EAIfF-ux^-1U8mk6te(YJq&3y?T9 z*GAXaB?YFp+CgNJv1rbnHPXHD$?(~5jG(CtP{~Wll_XWo((J3{=^r&Fz{eNQs7%&! z?77|*2P7ADDNysI8^WfKt;@0W{f$97`Sujp)eWn}bg;fJck(bFP)a|_BMNrP<~6+d zBY7o9|I$gZ_+4!Ftyf(zw&jmU=8UPKWec&pC+r`{e3+B~MI)%AK=nebq3z$NFwwGj z2+OCJ@17x8x5eM@(@k;+N}PW(j+xg@0Y2iUQWL)d7PYqA#^mav@s2f`pvDlKj~pB1 z&^K#1HCsKM1qP?tih(g7m*rtT!hlq27Dwb8Jqg)w1T8k7onDu6Uv$NA0gm+GzVp1H(ShJx_e>*b0gEbI zd|{psoeK}j))3SfhNUkJrYUYX(mXNVW~L>`VRf4oghs@opHCcQtg9nHlCqGX@^I8i zJD1jRML5b`7_(8#KA;(3ZB6cWWD%It;pER!*75YNYYVd2q_Sw6a)E|@GPJM2qLd8X z(g+-tR_HD}WX>jX(Zi3##)!Z(?b-`guEdqaD-t!Ha&eHh1;YKd?j;Vcib(7Q{yY9? zxOiR-Z1J0*Miw<#Y$;>I^9gE$$bFH@WwBHJ4xWpxt=QZ*3W}cWrv1y(Ih*%-`*_zS z*-`LAwu_+r=FaG2`s#&iPF)mKwWSlIqPephHz_$9PM0guyvV+6zTezg%v;%Izu3HQ z4776JhK3=w54%_)JmJ_0aa!9Y(6sjk!ZpJR%lcb0tSALrV{Y5ESYUnNo;K# z?5LPcP&E(BS~DR5F1>a)Au4_gXWX)Md7C4#Ux1;mjL%4eWVFQW)BA6dsP-nq%-|aY zt!;@#4Y#ThKfZ%^!s%#cXWj19t&p}nV1?^Y^mw}MXCNrQHPXh#57hp6gHLpNXlX2} z`>j!jm|kRBzuYL(#F|?yeT7)JVSO^JTXhcCNY=H* zyDh@g+Mdw$&q#vaYwyyM+F?n#J=*FUvl2k#{F$J}b|}?~qTc%MIG9Dh8we_D?>vI@ z!Lb>wIyTiLxFt!|wnsj7ZIN; zi{jzj7wWfA%Mwvx`03IGD`vNXj*W~inC;H*d|mFoDEP2J zNwU>;!EA$P;4|R<+X*6bK*@%+*h*4r2W%X}vRS(NkJ0c$PEkcyfFBK0K2jw_-4NaU+)B4&P84*1N|nf9(N$kQYA>u?41D`sjQq`hMxd@6 z)_jYzkzi${_ETAR6yR6MNv+N7NOB3FT z&a_CFwuhp|9;o8$qDT;3E}%XqEzm>}1=GzkZno+nMHO4QpKpH{!j4uZ&c zj|ri=4;E$7-c5S(c@S`(;2p8)>M5=-R&BQdbELVQ7C`T`2b61HL8!J7gH5(S8w|t#(wj5IV5I#z+KVxq z4}+E0X&V^_W7pXGv=vT9-G%Pwwb5XiHE)F7J;0$C6c4<8f$H9<} z@t_(;H|~mINcjBl1?km{c-S^TM6w%Mw4AvlU0|L7Zjb0|LXiknjGT8*+6QOxw}U!U zaYRUaMgLT~|5^exx!RVB<$^-yf1=)6Y8RxLy#9aE`<)VD-g0w>JeqdJ2Ap}PmdyJK zSF9Ab85lXy^8LRDR4l6TI_Gd3 z(QB-FogG0k7*uATk2y)zvZ<-(@Ed9-=U8vRI-Qc10`vV3knNuuu%662I7%(?to}N1 zB;A&}p?+KMrNHtiA^o=1eK(Y*w(O0>{8b8ALL+^S-P`*pgg;V z*A7Rq5^!ttSu=wmYIiIr*VR`WjUK&=E~R32)({=%fwflo@&qMoqB;x?=jPH@H>mrxTDNRd*yLi+mFHl3Tecp!zU{AdZt!(Y0@uYj0EdkOC9m(4(1rDvIafMsMjVrlK5r3|D#f`W0H@G|Y8+OtS732B4Kbeo4^kX;^7f z!~W`IM*M=}b`G^N6i#=}<%CYNGEF8b`3!a+^W<`_>Ia(pH{t~YcI zfz6vG1TBy`H}EcSZG$}M`#^q;k5g)exEjaTRhA^ zI>{6hOO-Z@T}j@xy)XHDAp!UtQZ-|*Z91^56Oa>8UjW6crJ)aI{C%fuRBieHg=AIVNpidg?1A%q6G{{Ne z9BkN)i|X`6u|ALx??i~Xen|YL)XY%lCWD_$e}c;Wu=*aGw>3E49}nA(;Bx_!SEtY) ztIz#M3qn-wk6AzTbuf&H9|5CY|J0Gv=OTJ~UU!3Um^=LGafhGPc|u_H(I8;ZzoV|Kx%GPEH`m)87!Z znnhoXc&*=FHXnSyQ`dXXg;-kFibnmi*x7JVhM`;>k*J`k}qv zG&N*?@PW0jfkt2p#ZK_q@jpXO)+|WmE66mK8tR;55%zN?ygu=q*d;s{IbY%ZIeuMV zGh+eFiQ?%^f{MaWq>Gaa^;dQ+1VeTZ+J@M3MP?W-pc22;%*PLru=?z1Q}`T}cepcN z%S6xULGl(vVBYAAX#M55P*^oFlc3y4XY{z!w}Sq`o{;Eour|LeBp`Y?9T8sM#uIhiGRdr*E%!)KRY@ z+8IB?Dxc1@{T&C%pXO2XeQh*56Es6}d+OTJ(C0C=ZW@;$=QRawLGo-2luBoi1{cL* zuZ`vY2YWK6!k!pkg4V_&?Vq)OnH$4q!ox}*g31)Q1=#REIZ5&3us=lvD@aPgrW%^9 zBq?JY=I?l`11vEg0nHAi5>yn=?p}<;!2L=ZK{DczZcCef==s+dI_Iw;Xf2CYUmF5t zXC0yH|CROKaZO$C|AwK#1owzq>#k7*6cGb~T*N^VRID>Nt5ywydjS|GXhhIut(QMsAq~{tlhJOu8GvWyE*1*N~G{`L?}KnhAU+Dq-8X9w~=?z z4V&IoXgj=tz)yT{q@$ne*3HyiE9#98H%Si%Su@b+^A8m83YorwJNq8a)MXA$6=Y+| z)@ffMNa+{*>c%I|5N3Vakn38OgT2^Fp)0`Uzn2Y2&$JT7RQzLd!GoV>3adx-;H+aMbfVf#kSfq?jY{MHG^^pm0>6r`XHS!a!m(AQ!d9ar3JdxPDJQn_PGtHT1#bN;(52bf zTZnW8>X;jjuaUd+qTig!`-Mn`qzHa*`2#a6Q1$3{L+ z{^Zk+CKGzXznz`a_stYa=4ME<+qz85T4$A+&bxT@(Re(D7gd}Ix2wIBmaV2W`1ky+ zH0L|kz);cnl9=eW_$pPp^n8|TE!Y*a@g`KS1mTa9Qgd0>qGw*&)InH;N9Op2<;W}) z7`k35SX+b&@AkivE}*Q-!Yte6QK-;2<}b;IEHrgg&sA6~(k{`t-v;gQy;Q-?Yhw{n zT*bt0F)NnO5#G%6la8V{L>Ld>_%tf^i`l}seL+&#t+1s2H0 zH%Cwpuf_}VY@)GZpBhwnF$YgNr4`{(9ro&1F5n?$|UD&xW zS;za?cKCFl+d$|3?+lk^0E5|zvewiv<8{UBxlx_Mh zNG87@-%L2r_oU=!+Ag?$W8nKs!QCf47Mx&b4(QfUDUe1JtHu9!>7vmN6zKGe?3o_e0f;`d(zC% zCb+ZjA^#P;huhi&M=LTT`)F%msd%fGnX~fX;E9!f!uvA2_HN{iH8>dWJdWz1UGi+6 zAczN~o46&x!3yP;gY9zHVtdQjv)|!`8G3oBRYp#q)${we;epJ~X(R{3ql- zQaW6^fs_^+tW`W7*(qO+?7K`$cy>={aH?Wc!@Q`qI1pa_{u|Dk+Xmxnmsh^waah+j zSfLmebt`W?c1aEGA>D#8UcXKH>p$`l0;@jwovJ4*k| z?SpsvejT4K)gc@?YTv0AH3B($MoJ}{i0xVT$H;SVbNN)sdU`m@ntgPRRF!ZvS{;Pl zZ5+)RZ+P%V#nRj}c{RbVxGOcKtplPIGA3Di;_pTWRQ1;)`b<66_HQF47bDPyN?dUm z(5`&}e_kgtBDkjCvy;8>mu_YyN1#ck2kgl?I(8duKoGU1YtxIh3;&4NCng z6SZRZj&n39wep8ic?GCOoe#sgl1BrBi{y#g9bo?%G?cUQNJLl<*@T-azBNxGAOKoU+g#?iLp8SpDFotwaC#d z5hI44xGVv!2)`B?^*hRo$nVH)sH0%x*=%)GD3lkxN|N4uONxSWQEFEHSai&N6XtT| zbSNua|3>A%#^@|rmcm&_6r%D$4AWjlSE{{D8u2PE*t*Hf^QOYWvkHs3u0@LuwtYb+ z|7X*}-pM~w9d!|u{;$Vz)mF!DI+UEop4`f{PpafqMOh0cq0{kO@Y@4lR8M`h%j7I0k$v41xj8MPQL{@b{0?8l<%{L=ez z9aX2`E`BRtU^-?Ke_AK>7xC(PZ9L3R5sX~P)(Ke-R+YM%rxU{eyld4wHR7@ILpLe> z0dep%q2EmDYwmG~`oO!ZSTAkauA>z7b#bV6$Xt2e0=U#@^=K*Tr{jWC6ulo`j+%gI ze1AeM)wMJHUw8a@lpSpLr%gDU-WehGsTZjAz(qx>Js$aiXa3ynB6r5Z+POC@3eUG%{thFl) z_G!C78wB6$Y>--9-3_zGpm*qm2;e8;;BLWkg~|U`)L&3)*;$$&(!0UuIi8yN4H2@V zYrAlRUS#!c&|Ko5&E4$+g~^!BPOz;t|&xQ`SZGht}k! zD3-tf6OVR_ja!-*i(>btkL3l(^)R{St7ck195QZXtdu%*q#ljXe|KnpFlg^5E2N1f zndl)+mgdn_=QGbnONUvoitw{y?&U6EECI)_5&J?$_X~!+>shypObVxXOq|N=tf~`vj}n)_zXD z^0gRIn@blX9Th6f7jo(~aj>&2n=$zN#>zh`_S9Xe-d{*t&v&}9TT+5=-BmvRb9153 z#Zq0a&rtrjmL)Odozn59t!`iSS;FSA(kpD%ULjrlTAuFA*VM(mLZX$uzI>y7f^n!e zH|MKx)8`?0>87Y|9-k*NJ`bts_jC*Ypql9TJVdGdDzA%{_WW%6*GhgE^HLUX+6-yo z-WxiZ?%DZq&xJY!Ez1@r+utLO5lJ;>YN(v`cf=>v<`GO9+=6CCsB z-QX6@ePHqR{55!TgKY=W2bD@YCq1>{ro@L`#&gwT`d4wS3-zZ5Sz7f)DgC}{n?DZr zc18B)H8%By((QM(_`meNDD&WfSnUtcsdKJTp0vv$WgQ&3FSii%V2!jdyqA>kT^^A? z4eZ35f!u_uAK2e+9?QE2wxIXwC~m^g4<@?DX5_vE-7b5R6t#XRz2Lzz{?A5PU!Cfp z-2k0)?<;A=t<$0qwSFOjoPu3CV0|77tENA)b*OIOC7Syq+p0sBJbI`_9#)03R?<1N z`tJyq!%aH(Ds+u1g-+^m=>vns#I{!La2yA#=+>U+R1ZMTpTop_>0D+2Jnw4yEy@9< zQ@cOqO6jE3;Nb=Cxr6=%O<2VP?;U{d_(ja2s58j%zN&)f(3?=$+`02|AA`MF`7*DH zg;+~tWBv-TW4cJ2+SrJl@JC9%0JhWWp85Q7wi_n6GCyxr8TnJx1L*8t zV8Ukz==r|ff#|Snn*YrWc?Tj=JzoZDe}+6hS(sKdajeyg*<~`@NtjTS~YaWRd2GA;__6^s&6H$We8Wp6jTFf~|h;VQvkubvNzhte#l^=SQL} zV6RV@!C4EjO>2+Kr`Lrhgw)QL?yn6E+2N-wij-!DVIi^dQE>ImjMF@udl&*Tvvuo8 zx?Opw(n8Lvzko4w?hx%TuostxbJj#`QQXm}zrdc|e~`PLPOR^@7jtRooc}@Ktb^Fa zx%V|iU^}D_t<6B65sVt9yFd9Gide7d*! z!`R`ud~K3596jW#>hrWLaGv1^y$LuH?8Q1@O%j4x9f#}Rht)Qg|VDHG6ycG3F=>GM}pM70* z%(?>fN}52EMxs})T(LRN3*|)%q_L1b5=Wx3M>6yHDec3NA)WosKX-B;^k0T36%Xz- zi28smmyBz~P-|p;G3`qjdf^_=-aPx|+V5P~23_U0``7Z0K{xHXG>v(P&7b#Gz6tE| zFOTK%r!oRYAxIm7&hlz#MxohhTkORN-MKOAC{+Fn{U^LaZu+<96bjnk4$BeB`{fS- zJb3ESD4>_NcYY@FKg+wp^P5H^N6Q+~Tqm7$hJ^Rl?t)I8ej$1M)HioD>X97OOG~XS z{~U7$yB_s$H0%rSMV?nR2A0}2k~*G#3@llDEsHEhmPd!@@X{>A_N}~LTN~`X;D$V> zjo6?6GDkfEJLK45uIm|tCOfw~Kkq2mbv`(Tvc`!tqtNv&B!|srG)l9cTB%V^o8jp0 zHecjDMV@(YGo{0Ei8&-ixqMO=?IzH!XTPIg(t;u*8QP=5dgjwuz2w-&%XK7U7B~lH z^r;3~-UttqabTj(aJbuoDAqsqV?$Dvo~QF2cfi&Neiy|8eq$^Q{$6E@mge~RmpAf8 zlc%71b2oI+ZU%e&k%wE*q##`V9yiwV!H}GStS3M1lIMg{X_K~ER*aRD#$Vl%%l^6P z-}T*}@u(G(*@dtF%DaIatIuRd@eNg4rNYqmBH#R$pl=_vazmz6RB9)fvw!r)%aU}t zB!d)Z9rM$k1>JPNi@W7Wg;l}lQq*~{Z5KV|tT&a~b}n9qWS9NwjYHO_Z<^%Mt&Nds zE2Nl=Lt7m4N#wP*jYF0Q)okvpXB^BHe)msq0dmyZ(UG(A@$iafo65`RLVSI_TR^&*>f8Asdv&{qtjHe}co`55xFXe6<~R zlZ#WOYx?$(jmlNg=`nWfuKr8s#W6f)I-ZXwaS1?9Ox*i8AJ}juPf0PE7Mz z{GT}&!Fw|ShtogD^Nk(W<)T?GoK1@!`7I{R`%)#`xhUaJ?}7Z2xDs9QPA_S%)RJ5p zM|-<*W9mF8tz9{~@S_nI8`JQuPWHN2QXVYM)b1_(sbH?~E3WLbMoK5;w8;+(f4x0N z&|aG?J)N3M%KO7=Iy3O4OUoMRIUjExoPIaJj;-Tr;$lL*d??jBqj!$)mnIa{e8?^8 z^PzO@ubS-gu4u_e?SDJm-MMzsRAG(JaL#&2r@>t5j<>u3I`Y3_ooCLc3Z943BX{Nk z=)@YO$LFjC@UzkCFz10$V}*XRbGaQiv3(<3IPY~DD-6>WN{^nF6rdS@o;Fr!ulbQb znAoZivxai%j>3`7vBHU_Zpx1HnnF|{FKlIDrfaM)tIcU{)LRInmPQQXjY%+ ztjdX5;z|D^=U21)2$fcC#0^}!#+l>9@z7JhlIwBf9>Qp&bdN^vf{E&P0$kUU69nZP zX#)(63pHBtiBxMd>D1h+az%!A7PcOfuGw2jr`F8{QvFD$+km>R3Uj*%iHGM%m+DJg z@VoavwOr?##|uAnpTd>ZKhk9Pwx7_kr}X5f=|=?ir*;E${+gjeNzcEzp5sRttv$4v zF8k#W;pPFnSi<&0efT44veEQ!%=89Bg{srvaAo~5OaxsQKH>jt$B@;$aDpyDJ48sV zcaO6kV%MurIfoSr!h*fhhkoS8ku&R#FE$jW`yk23LrRr5ZdY?n@NFi1R!!QWA^il# z|G}C~g(^$^r7aO2o=*4x8`h*~eXp7|sq z|JTGj(q_f$prp8{-4%1MdWz6~+A02)|7prvWA@&dDgWTv+$GZUrNt-V&fr0vb(fpW z6kbd?CXK^Wi2l97w{-Pe4HweS;#EPmp3FD}6QhDlbX%91gths@oYEb&Q|PlxHVzP4 zorrU?q3NakKX<7p%xu?R*gHkK{i**Mt?XHc8}eK57z~{nr2UM5Wj2@6Z9gN|CeM$$ zyH`?#^Gkm&WVYmPcsOLyr@C9|_(H;#A)M8?F$>Oi)ff6-Gz#BOm);F8Cf%Y%g}N+f=JAqGg4P?zeV^usBG_@Uto3x=BPzOrO(cJet|>P z@0J!${%n@;yh}Z)UC)5^SC{0+;uc=b9@4Yy8nB95wKXx3*i-$J71Dc0X40*sKj8fK z%>be6%S$}KR$}+(-*7(7t1fhE5{{S3nnvK7;Tdx4y4$&Ge#p_m`Q@roqZuwx7qS&gdvK%f#nCCk%NFme?LA__arM#X#Hq3 zXVsT5gp&vTtX+<^Lc}Lw{Odrumr!^4yTkmP!FvhzN)zfA)WwCPv==)&upX|u4EBB6 z!TjgQIiTghATdV6TAYj|w|4o-PE|naR7E z`IipW&%I8!pa z3Zr&bXT34Y9Z}0~@G5?vJgYcDsc3m+b%78uSLj{zl7ND>_`Ik1S;5=8SaOTEIqPl^aaL)PP1cTwg-3PYvQyY>$0rdo z`Cu@+8sFyU?Vg4aUHmS8FI^tee2Q{2YsPB};LZ7C2lH8F+@D5F_3N;6E%(CI2<0vH zogcLfcJ>{b$l3Hp5m)?%+efjhtD>cGM6_~G$eH{-u+uqOx)SSYjG)lPp1&Kk!&S$} zG4;jDO(MoB_s0clOVIbH&w9g+S)0HqkC4X3$Fkxk5s;1$4J6WD+$3seyx)P5Rhf6o z9LZ4-EhHKe1JOYQNGzliBo5LU(go5L(#`HjjvtJT0Cy!jd(D_3WITRS$gT$1Bd5pX z(YN+VIXsBzGvd!G1HY^#O#iB@(6Po+9SeuW5|8VXJF5%d%uFy(E54&oK*EBSuB4f z#kZ7AxA$8X-`Pj@gSajuewe>+r}nOf_V*d_H|t@Gy&F5?wLSsEjt2`{FAmjZ*&FVP z|2M$zXoDmdKWeu+5U)_YDO|1l@XKgnQ$`|dWq(rwq<w&(82g?6cf**(N_52L0W%9DU-T76^)BXnRxQyzvCRA56q$-PUAPHQ8HnU4UVbth4wk z!0_*XoO)8(FaR;^sxS=mt@NP6`*7TM5cgCuBn7PKv)K9Oi*dpvdtg<=m}UWmvU4$x zeb^SqJ}1l|`1lQc5!fCFH3P0ThZ_)>@spjCW({}Ue0dR1`Ggs;TYd+_JH_3QJB1@w zbag#3H5ONQGc*+2L>M&6D>0`Ev(x*!>U@QL_-~Jbjf@CGigHNrtucSw=DMCOTZ%3Y z8+KJk1D^glGV}-CkUin9pQ|^-p`L78HHKP#-OJV78pC{l`Oy{I!w;{X$W`oSodH`@ z25IoNI?Lh^3}=<=;N_HA!-fBOX^SoQ&89ouub~0?NG-yw_ zP+YyC*l4ezzL*hb&??Ww#5!kQn<{K=FiNVWH_kBCZ{Nq7(qBtw19loycXn;B)>N3f zD}d8>TW15_G-~v&&XM#6T_lIpT@jytzio5wpLjyI$~06QW7Q0r7?nisy|i&R%e7#Q4@cmS^J)8byN_rG=k^t-2|UvGz84!#}c0XZ>dh zpC`=|=Y=7=#)ux&v(-aq5)_~OTUqkJZA3^Owm#*w!P)JbgUTY6V5sFgQ`1arv>Ww) zn1I%ud;Ehl8%oR0*Oio1-O>Fvf7&8^&Jkt!$B*+kZMSqc{3w%;3dn6Y_>%_{utBR^G4OjeHd}xkC?FMupXC3m< z3X!7>m;DZI%9eamk48HwpM(@dw|I=lcz$n<_iCtbYs|3SoTzQd5>;$AC>2YaZ!PGL zJ-g-zUogMy>SRM>pGpHj4QPFkyJ}8Bi(aVthnDiMto5^$-;|2{vf1){Qf^UroRra{ zQw>^$EK8nu=AU^&k8Y>9Rd1@{nM^+1y&(MX%H|lIn+>1X-;GE3f&(#Z}E5f;Zh1;UV zXVcNNIa3V7Wb*n`HtK|N2{Gcc`v_I5X@&{%P3sPIpxdC#c(!AjK_;JvhAwU2T8f}& zx?#4z^5Mnp&Y_rM?#cpD&`#t|n~lljC-pw(n;BONyT?wD%9qbUmwj+zk8@N^yz|!U z6p1#^!H_MgU+PqWHqF2>hfgtc4AtcJQ_q}jdz5u7HyQZo{KnbC8|Z3HGs};MP=Qu+ z4cII~z3Ct4mWd~vpFip@S+LB5dd`neo#QYsjv9@#Rvx8!m@&4LPax*`=r>h-&q=AK z1qf1TQgi1N*c#xUjPI1t1W<1wMxnD^YiEDmTIWBBlcXZ_3k|hoYH`Ry!)ibK^{!6w zLSHBcEHWq*b#%Q7hqm zVGdYf!0C=kCQ2TdRvMz=P1Z_7sIupR1AKpVXAv%I?lI zd@olD<6FCWpkAYB5~CKjTQ?ZG`v+7-2kDNI)`=JljqJ*82Ahv^ux*rc1X|_8kyuID zv%@gIgM7-dEeFf{y4`ZautKJIv1N*D*AE+Y`+Y7;1OBF=ppx=h;E6C&tw4urR-XK> zp+Khi>8xJYb)i~_gRgVo5 zE6Sg)9xfc&dyuPT+n!_a{(N_|P<=y3DW|&#J*IIF4gYH|E;6*0{clQT#`P~TZGAhf zpHtp1K`2nw5JR7$y(}+rc#z_C@RkvmGm3F0*RJEJXz{jh z0_L?64C8i*dfno{Swg4MA^6DZSZF1c7&a(NH?P%2y`3tYX*a$-cSiLV2eQ=zpX>VP zYz*VUwY;UXnv|KDWl=0O#8#?)GhWyC+Du+Y^*ckgO7Hqyi)n0~%Nf%;_S>d|*1w5zYBjS^Lx2y1KOjDs!(Hw3tOJ%(9pTi-AS}rrkCO zLR&xw@j?>JM#_v@Wi8MbK_}}+go|yPfLu&eTjX2G4 z^jdltXGDB}vLT_VY{Y47SX33^^>2NJ9>>RX^P)ommj{hWlp0sBG-3?=fJ(Z4ymW|{ zWDPV{ldpbyLRTR)T=LZ&XvA|Gmv4oMTQgCkl0ekR_U{Q@r$wnkE&KOj;@3UVT)9<@ zK{fyH=>_ve-qd(o{=f4J&IK9YHTb{h4UAXE8~+LXzlZFJB?feben!Qo%Kywyc<9On zSCXd~Kl;&xBer>p(}wh^##mqZx~I=|!7uAb#LcvhwS&shgT*Epe`{l?eEVX{iC z{1SA#j_{srH)R^T`z!x*+9E~SEgCU978SmAwi0{l1~yM(9olYLXIxQ9@#$s36~8+{ z_u1hloK|l$&i9c^XGu~Yb?-2C@jcVHucWclh;vrsmMooTIgaVi;^9ufE@J~9<;dU= z=iYC7>Z(7Pj^i-7X|Ne*`6%yAY3QnTd9Ci{b}i0NDIyPd8?lOOgo5MmmPl2#esBCz z=GSH;rqHh&AUgH-85PQ3H>J2%!(`-wJ<<@???Vf(oOvx~PK$j`@%9C1rtLH0e)H+| zl7?*`dfT#nVqwYIxx&}0=1LQ-dA|{Jfp4Q(lA7ay5tpndPIkVkF%6#$Y9-OCgP>=$ z-(FaZ+%H>1XD~}jg`~8}V zspqyIY8&|j;?i6_-}xGT4=cq|iaMY8|DE)1DK=t13Q`_6b5G%0)Mmd=H>o!6A27eP zZP!6)cGHTpAaq81?oneiAHRzJ6S+NmvBNmHvZA8c%awTUQp~@BWrvd!m?x@#?Be1<5}gSoGOK{i)IQAoLx#o`Z4CM-j}~Ba&D^SGyk}yfGGNQjeTCz{o-GU$ zpG-^)3Q(+@EhHWZEK|`;N<16z=BmLt;=~l8ml!xXaX?^(_jBi+>yw4ux2HSPMcI-> zl|5r};$vBWZbimnI+s$4bEYN^^Dp_O!(qvT;;D(sz^%=O(%M!S5EK{AdAoXABF4z9 zJnIq4x9fPF2yxU7sqCB8wNybr9yCD`%PYm_9388rH zfhxF6J|hv*3-URnH>3}wFQgx&KV$&J1WAGngbacVh75rWg$#py0T~V%0T~JT5;6)h z8ZriAh9u*YWn-V66)joG^~D-pQtF5{LUDvVgeDV`e+#sokcQADLS{lfT~q3b8@^4h z%k|vEjp&NhVnQshS_HadNU19(iOKcEB1%msj#+UKVmZ8oSPqpH=ukK4=?T@K(ku+c z1K9}05%Lh4Oh~>CXgeVdp-Y6!gnabm-#YjgM(7No5rj$!W$K})UJt$F#0^?sR*!Vz zm@kfU`RKo}>dp49=@vu}Q^yC{UmBo+HCF0D4SY9h3=DnK` zi+yosg!F{&5V8gAq^pB+Dypjb8uEdVT9b}sF+aZ=cszn4pjX(p+SU-2rVbn zv^P*bAy%$;2XY|f@NXv&3x}T2o!;Oqgjl&YLUDbN_vTLIB~G<_{XpT+#bV)Ei^i_? z&ngIgS`HC9o!o{;Tl=Ims9m1aX+&*7)+$Q4Sr-e$3rG@EzJm#$zA(0dP#B>zghup5 zp~c^!s7ylYT|mbPnFulG(h0Gi=3t0g(o2Z7l`0$PP(Rp9$c8=E!!5)yWFy4-jfc?W z{?Jp{s9bq!T`|&zF>#5w6ykga0Bs-?M(7OFBUDN#lTc6&5DUs6LM%|}Ik4Q+1g{)~ zSh-$8tVvb7fqW8D>e>yvlhXotfAAbGQ};Onl*^_AknDF{e|lL*5hLJ5TK0R68Yh>HHg*Y_1d%&yMZleJF@7PKc}BW^0x zZ<0ETmHZUA?ZjzMfxAQ~g%DZ+ot{#|rUAJLjUZG^hz$w#&p_z@@R(51G~`|WGx9Q* z@(J~x4(>6bg@hWofig#8Ml`q)QZ^7QZscW+U?UVa19~?}Z!#gpX`t;u|Et)c;vT}4 z3MygJ`pxSxIfP82gHW6ZNoAFCo+d7D2GlrKCv!^;k zIcU7<3EfEpvJk2<6Uau0%?TbtEQkDT8PX79In0Du4r_U;yBrl0%AAGD2AxAajuRS0 zh&539IixbL9E55dM(`eu&6H(A}c0BY?P#zBL^Yofw!DfT?BV%9&+dju|a7e#PZq*#mz@O zZeBz^YUHAB0hdrWe!#s%IjA&qIkJ``Hz5|?VnWPQ^<|*r3n+e<%i@ww9P6YGLaepC zgjjp1t^l!PgPx&<$UEx_`LYOT4#H=z-W zky=WrnCLLXuYqGTy@?Q?UYHO!j)e4 zuqs-D?mz1~)X62g?RxS+e`)Ib9XXjN`f_9;RAU9z?04>QUGc{6h&S^|{zq934IwtE zn#++@O06rN{-Z2Mae1oxPs%$3?U(c?wIB7WbjA^K5bC`O$V+G;A=PclL8*E|tdCd- z)mRPAMu_F`l&8x70=Jz~HH1jdZvHEItc=g3-a8=Kxs&QHp>N1Ep*w^uglc4xX+m*? zJcK3_lHUW`PDsNL6=Ejjvj)gYD2$Ms5Oc7YAv%Fj-zSa@3PQ|EIzz1L43RxAAy!S* z-$2Z=o)D{&g(1peBNUefRGrCPyh2r(;W#!-!| z<*9B$%yRLgrMeUP9~~T2)k* zswZ@3D+c&`ll&vZ&im!B%W`N4 z#Zju65Sy~Cg!t-#5X(_ah#fA~Z-AHwrgD^CjvVF4ONbpLRmDK8J@kZFt6B&#D>gzr zeuOSjB;_TfmyH-`OArI5XC{u>vl3#Qn-GgjaXF`cTb61f#QJkOA!gY@h#e%o3{h#S zQgD2ANQl+kLTED0LpDNjY)M0i9T4U3fLPDb5MoOZGa;Wn)V}YieF>c*G=fkmA?CCC zJ@lAYCPGD&y8L}vs)M-R--CNx&Z$0tV-eC5Vpc2+(fO^dobwQ32S52opc+&+4Ix$| zGa=TNRzl2*n-H^H{83s7W;w`~i6zRH8B{X!=Uv?hrSNI95#?aSVAFI*L?`})t5n_#yPKX8E!BUxjgcdr;zsh8fVvs=S z4so*x;S3Jv7KGvm-6S-bkU{~posgCg^WLn0J)b;q8;A=dbcWCfLZytOMTlAnz2jSO zSV&T$Wmw*H;#f=_gs8rDuX5~6X^Cg4L&@Z{tsHp>-RTE20d--9HM*v5nVy*t3!Al! zv%Bk#EnDJQ>Xj+l7^1fE5aP?e`emsahA7ocs0O)UCB&C~gxJ(yT%M|K0FJediBQq$ zlzR5%4aU}GOFSH(TY~I;4FP%F5}{d0sDT=Y`KniwLF!NzLN%@(F@jJjp-e(SZOdX{Y74z0;+7M~78VZTYHWa~58J}ig?}QoK|7@K z_HBn$R$mK4xRN2}w1eIyijar6?S$lEq?d=($S{flO*UrY*xYYrsZ?_}<0wZlA?Cfh zJrElWrgD^CjvVF4ONd!kg#+Txr?tmg6#;8&V8 z&c z6W7!WE}u9)K8RaLT!Sb{&#sReyWWonfoIxV&=hmAO9*;B43?*xujL_>(3*qaHlwV9O=TYb3+F<*+ykvgs{)kKIb zhtdhLF5xIg-ttscXQa|H$FA=@7V9;3=Iri5S?F4KF`*h1Uv*bfq_u^K5L>mR6Jl#0 z2O)NL?j^*|_Ep`0*a}Kdh&f{+#MWyzLTshwVR~d)9#48ynuZ}d@Rsd`^AcjwP$dGfn(GO%XjmAc^_q<# zTDN=3_2j*v$68-Qh|h6^_#8rr^(Hq%l((4av3~VA%qJDch&~wTBM6leVyWuBNM$Ep zCPGD&y1Z}Mgy0~qw=cNI<(#S?I99Hn5FhgW$|7zfj#>5)n(T+XivF;-osgE$B|<5L z_?6!Nq(>KUPWOiuwl*s!j-BAB2LQ3@!c>mZ39(cMA$G>@CB#-~DpMKK6Jn_rLadfH zLTrZi5MnJOPbxziLTn~C6Y`P6(+x@RlwXWbl4_Y%!AB_EPyP8EP^bCEP*VAEQ6#&G9X_;mP1xR zRzg-mRztpqd;`gZtbweBWI?`#h!87e9b`RZ17ss)6J#@F3uG%~8)Q3Vhuu=NGxfgg zg#G^Y@9O&ar9Z<5D`^7u<8q6Yh+wUf5gwX7_h>?Zt{+D*^-R zuWwc`{@;1RbNkAAyDBx7U9@LK?n?9vh>h}sjJmy{S&g1^UWFNzeu z?!F5T9q4w|lqK7H=yuKM9$0QA@VjWqy!WeJv9)DU_EuYWwg1#FS+*~q`6J48yYTYk zf6bAbq9+D)d7*QE!29mxy~nxhU5x;2g6I5d;}%_C`|lTb-CXNGuYP}B6|r!1cBo(6 z)kb)-r1(2LaWW>mk-z-ygf}tW{u~c(H?r$fvkPPab((f!&jxO_2aeCa?ib*0KD-^> zRrZQcCT9-_xH)gqA^I!YdrZj|n+14RR$>1qich}HUKS7)8_8~Qx3$j^v+WfFU;a@T zUHK`#x7Tfe_6za(v+TN}X>)dTVAbR6W8QX}Cs_We5&eaDa4UGn=4@r)y>8z}Pk)Y$ z<*shYlXx%j6^4q@dDvQTUbPElylP9fGGN-}rO~ypN7W`VcuV$!z!lw|=>p`#g+7Mw z3#H;TTeG|PcR$h;|34pTQ;F-gX4jPYiF>zZhx#W3H;CbC_TsJCpZLheiM4lR4+~h_ zzDIkiWOs4Sj_j5Jf^ii4JK4T>M|Q`Q!0g}76gFvjT~~B}v}+izl)S19Euy+!=HZN2KuC4bADqTC5$PoUY6jQZ<`wFH*sEn zyd#R7qB+l2%YWPaSSek!=AnS^o}6)J?;0%>wQS4P?Cv~Uw6C(O{{?5n)X~D(iH)V~ zYNt&Z===7fGppTbAuH&UvSLh5TX!F2_#Tt%$A3LKU+s62zWYbpM&*)u16>(|Z|M3T z#T+?M+E!j+Q z++|zK!2FrrwUJ2Gt(>OaFSZM{)wMe=+iusA?H1R0Z9)ErdOvj@5l?$6p^-YT`CslcGS`XLWz7>TJhHvo54wWtU$*JX^;T$Ka*)={n z&-~;p4jSzIe8FJDqhXbD2FU{dQ&l{t&x-Uuw^fsye{ZPs%?%gCwo7vGG-HXaYQWAX zN?mV5q@ySheB zfh>?U+3iO$19pE=RvfifAZxACCoxYubuZ&p4{g-~q;@SU(_AaZuhJKD8tUqa9mHXE za_ZYNR5^`$$hL_&qfnbgqW|ceVg5NU!Xn?;lSk(~{x-0Dc>lRQZ@+l3t*x&3|4j!6 z#ET)|Y5E8#pFYIG_c;S(FYUEIQ%siiw{KOVWp`lrYM#OBm|p?h&GXpElxFR zB>}%^ZR!u4oYc}89P>Gj0;7%jm{G?{XSBgbY9r<&&0a>|bGb`vD$t$zob&sg^ZlLk z``vTT&UUP5_uJUj=2ssd?eG%>CJ4fkrPZ#=vL&#(ABRp5QX8^uy3-axNNOmsMXwDP z1QRC5f`ug&g$s+9mR7rpE4V(np~23o8n*D}8+&?{y?fC_OqEtHEnHGn{8}Z~;b~Uq z4#DPgWmra;KvPc9%+AUwo!O&noPsbAW7uBNRWEvVX=!2Qq7ta{X)$#9w1(Mr`SF6F zp)JfdaMyuc;k_e%f))`xL04soYreYn)!TG|Rc|ZO9Mw>=ZW&$H4W{EdD>?KMne|qh ztCvJQ;xwRy*63x?pn7l9H+q>FsZAe37Jo@JtK*+iw!bU}s@_Ig4v*)`SNMu{`^#(q zZS@anG)UqAb@(c!7-XZ@yCYDgA+={xpiKrIv(6AgH+_P_DOQwwRPj^*&#Eq%OdpFf zvr>Z?LLH*iGd_`mjj|X96+haU^qh}ZM5~Q53!@dr5ISy@M4PIrA!d?AoUu~DD#eRb zy}jIHQMA|;LaioATTE=)74L z<5Vw^q61_xR`o{HoB)|}1FX~>AoXZ+>4cAFE(HY2J*$<|vw<>Y1zM>-Q0iHymfCzY z@6&yF-W}IcdXUUwDJ3X`YJ>jGtA(}({j1tb*WuyIQgS{-LoKp6NcB3X6y9Lf>!fuS z**HY?e$&tomQ<^xx>{T=??Y1X_HE*T$$mpe;?*5aKiMuhK5l*gOiTNv@%o(Q8xCaC zQ_VU4klTWokd-Y6pV9Kr1a^fsp|#PsXg?tqmcS-Z650(k2ki&+4%!IXiuMMbLwk@! z8y^{g)*PY4Monm2sSWKex*i^< z{Q?hJB5txOVv!lzqezWzMJ7_KRZCTo2170C(DA|Z!Euxu8O%PU?U5O5JwzF-gOcnS z+EcgeCe$U(*@;r~nJz8Q+&F&1xTnCdj5v~uYUHud2Zzu74~t) z&Del{L>P9f1E?xCP#XrmFYpjh_3o5nJ>7WR(4kTi`ll;FSiLoEibS3ar(xiNs9jOq|YCxpWfvS=KY~bC)@Z2$9Dgb z)t?QP<=OJv0ERvzeyMwjNUJnV@ zdUoxwM6F!E!vccA01yJKAQXfF8wdvxAQIRCkBJ5YK@4z!Sl|S4ARY_?gTW9WfuUd+ zNC1f-2@D5MfMk#YQh^N8zz8rBi~^%UIv4{oz*sO2JP9&E7RUxUU_5vVJPn=!6Tn39 zESLl)gDK!SFcnM#xnMeY9?aOee#gwy6UTjz7xW$I0Nm#Nd9VlU1{YMD_ZPuQ@GZE+ zZO^){nHiziVRnKmfZM#k?1>GWHLWQtFENyVEWd)^0k?TCG`aF(0&c^&3;ghx;BHe> zUQDP6%K&a*l-s=j*|Sy5lRX{h3Zgv8EU$i!6BC2LaJ7E|eKHsbVpW^>DIf+!f@sy| zy#vI7Fc6{IypQ*sFy`4kMTe)?uRN>C1GB(vkPqg77r={PE+_!=Kp`js#o#3{AC!Pn c@G>X^<-i4A0SiC{SO_Y?qMc_oRoXZI0Y+`U^#A|> delta 3065 zcmaKt4NMeA6vub&IJmtJSUm9VI6ycN7db7mpdeZWYl|PPSb>UPKm~;sK@d~4+F+_x zqc)yTvzRn3nixN-sRj+v5UE5{ZH<-2Ha5|Q7;S9TR;#vZwe~;99v|h>&HdiYd;d3Y zW@l&j_P;o-?^@fT-<>+-^DF#7MyxDex94-i>ybJ6xl2Z`O z5XXb1WmUyXOY6()Dod+){(i65#cp{Ib93I6dCS#Z)B~x!y1sb%veNgec^)oDbhma6 zeXcD*8J_^tMKR39x+s&mV(z&GAr>)7%d4wdQD0tMT~mhaOH_-zOSF}_43`oFA(##` zd+fcldBWyz^g<9u@C8;@msKv(YR5gK>#R#I)x+X)1fdZKjrdLM zMG(ps{B(-PKWvKS13Z&?``f)z0YJsns^*})1E>1eQxHU`Tg z-zpyegiavKs(JhA5xg+XJ4T~J6c$dqLu}L#B8xUHet`~zC_Uaox*4LF{F=bXZA@i0 z@)~VaVeB2`pk2n^K?(GIA1{T%MTJGuTG2*xL|Kf~Cd#EvqSE8#(^+_SX#Dm{h?x{- zr&^PZa!qniyn$Al6w#q&t)u(!a5Q{3yMueoMWtpNJ;Rt7Eq<9Q&5Afg8`DL5&59{b z^Nc#WZce24R4sX%FA>OUZUpRA*ZB>!!_?Q6-bIn*1RA+ZI@CVNt!F+o%CM^anTj&xB-E2 zgQ(N#ZrK=~r%xJ(NAz{(cO7!vt}nOzc%~uN``#D{MB@zcGvlvQ;eL$tK=V_}iasoDtZVpb?u^Jj=AEDFN z(#!S{a4PM|Yy|CuolU1<@6%n_401Y>*%_Jw+eWpHq15EK$5zuOXO`g#R>dehD%slS z_Jl3OqOw>sO^C|U9bt6eHHua{ErvU|Jw5I=mTH_%d=c(P&5U1%0?ofb;I9>~8=(0% z6SiggTzoxBU1P1$sLnTyCndD(b=@{#o!`kD;x?MXzH+tmb(j;?PY+6omR^5)yDDWdha-LR z%#JkU4BsOPtgg}?;Qy<|ozwBH5`^79M+K-nP<llrBHw4Yi39PQfyaCl#;~~it zWVt7-@y$4YO!O%=?+YoRf5dlpp_@B9_yPQFpE0{%evg`oH3U|@4HrAoq293Zy?>wT-Zx&^KQ^%HpLd|jE5DCb1+Lt0XPRdE=6!r2Qrp$Ot11qt`YR7qdF7s6 z9Wa)wCDHpP`u1E?pY)rz5h`D^zjCkIcQ*>Py(-!6->bfB4y^hs4^(;OX3Wc<(Lj}- z-Ug`r1G7*&fqQyRVBb6HuO7i^(XsCHvpo&xXTW&~tom2dPsQ1bR@+)6qq$F5{kBDt zMFs!X?RYC1eG{k+$E2|T#&QG19Q|V@BstXs$0W0bzhV7LW*nC+0m4Rvjs9%4?U*DF zOxjR!Tms=>5U_y=5D5kYJ8%FehypGU4Prnn7y{xzJaB`dAOQ>miC{R8K@u1Nl7R<| z1f#%9AO(yDsXzf~ARUYWV?hSU1mi#!7!M|Zm%&6Z31ovDFd4i8rhr$$Yaka)1=GNE zFax{}-T*T}9+(B*1hZQ!j^|&^RSy*{w5Za#c^2zQY~TsNzv(B{wg2R2sdp@e4z+p5 z>>%r}2;K$1^H%M=ILoF=)+?1N3mesh ){ vg_info( "info: %s\n", btn->name ); - vg_fatal_exit_loop( "Menu programming error" ); + vg_fatal_error( "Menu programming error" ); } } @@ -794,7 +792,9 @@ VG_STATIC void menu_render_fg( camera *cam ) shader_model_menu_use(); shader_model_menu_uColour( (v4f){ 1.0f,1.0f,1.0f,1.0f} ); shader_model_menu_uTexMain( 1 ); - vg_tex2d_bind( &tex_menu, 1 ); + + glActiveTexture( GL_TEXTURE1 ); + glBindTexture( GL_TEXTURE_2D, tex_menu ); shader_model_menu_uPv( cam->mtx.pv ); shader_model_menu_uPvmPrev( cam->mtx_prev.pv ); diff --git a/model.h b/model.h index 8124198..8f90d12 100644 --- a/model.h +++ b/model.h @@ -233,7 +233,7 @@ VG_STATIC void mdl_load_fatal_corrupt( mdl_context *mdl ) { fclose( mdl->file ); vg_file_print_invalid( mdl->file ); - vg_fatal_exit_loop( "Corrupt model" ); + vg_fatal_error( "Corrupt model" ); } /* @@ -256,7 +256,7 @@ void mdl_fread_pack_file( mdl_context *mdl, mdl_file *info, void *dst ) { if( !info->pack_size ){ vg_warn( "path: %s\n", mdl_pstr( mdl, info->pstr_path ) ); - vg_fatal_exit_loop( "Packed file is only a header; it is not packed" ); + vg_fatal_error( "Packed file is only a header; it is not packed" ); } fseek( mdl->file, mdl->pack_base_offset+info->pack_offset, SEEK_SET ); @@ -266,19 +266,28 @@ void mdl_fread_pack_file( mdl_context *mdl, mdl_file *info, void *dst ) mdl_load_fatal_corrupt( mdl ); } -VG_STATIC void mdl_load_array_file( mdl_context *mdl, mdl_array_ptr *ptr, - mdl_array *arr, void *lin_alloc ) +/* TODO: Rename these */ +VG_STATIC +void mdl_load_array_file_buffer( mdl_context *mdl, mdl_array *arr, + void *buffer ) { if( arr->item_count ){ - u32 size = arr->item_size*arr->item_count; - ptr->data = vg_linear_alloc( lin_alloc, vg_align8(size) ); - fseek( mdl->file, arr->file_offset, SEEK_SET ); - u64 l = fread( ptr->data, arr->item_size*arr->item_count, 1, mdl->file ); + u64 l = fread( buffer, arr->item_size*arr->item_count, 1, mdl->file ); if( l != 1 ) mdl_load_fatal_corrupt( mdl ); } +} + +VG_STATIC void mdl_load_array_file( mdl_context *mdl, mdl_array_ptr *ptr, + mdl_array *arr, void *lin_alloc ) +{ + if( arr->item_count ){ + u32 size = arr->item_size*arr->item_count; + ptr->data = vg_linear_alloc( lin_alloc, vg_align8(size) ); + mdl_load_array_file_buffer( mdl, arr, ptr->data ); + } else ptr->data = NULL; @@ -367,7 +376,7 @@ VG_STATIC void mdl_open( mdl_context *mdl, const char *path, void *lin_alloc ) if( !mdl->file ){ vg_error( "mdl_open('%s'): %s\n", path, strerror(errno) ); - vg_fatal_exit_loop( "see above for details" ); + vg_fatal_error( "see above for details" ); } u64 l = fread( &mdl->info, sizeof(mdl_header), 1, mdl->file ); @@ -379,7 +388,7 @@ VG_STATIC void mdl_open( mdl_context *mdl, const char *path, void *lin_alloc ) vg_warn( " version: %u (current: %u)\n", mdl->info.version, MDL_VERSION_NR ); - vg_fatal_exit_loop( "Legacy model version incompatable" ); + vg_fatal_error( "Legacy model version incompatable" ); } mdl_load_array_file( mdl, &mdl->index, &mdl->info.index, lin_alloc ); @@ -514,38 +523,90 @@ VG_STATIC void mdl_draw_submesh( mdl_submesh *sm ) mesh_drawn( sm->indice_start, sm->indice_count ); } -/* WARNING: Destructive! Only use this once and then discard the context. */ -VG_STATIC void mdl_unpack_glmesh( mdl_context *mdl, glmesh *mesh ) +VG_STATIC mdl_mesh *mdl_find_mesh( mdl_context *mdl, const char *name ) { - if( !mdl->submeshs.count ) - vg_fatal_exit_loop( "Tried to unpack empty model file" ); + for( u32 i=0; imeshs ); i++ ){ + mdl_mesh *mesh = mdl_arritm( &mdl->meshs, i ); + if( !strcmp( name, mdl_pstr( mdl, mesh->pstr_name ))){ + return mesh; + } + } + return NULL; +} - mdl_submesh *sm = mdl_arritm( &mdl->submeshs, 0 ); - u32 offset = sm->vertex_count; +struct payload_glmesh_load{ + mdl_vert *verts; + u32 *indices; - for( u32 i=1; isubmeshs ); i++ ){ - mdl_submesh *sm = mdl_arritm( &mdl->submeshs, i ); - u32 *indices = mdl_arritm( &mdl->indices, sm->indice_start ); + u32 vertex_count, + indice_count; - for( u32 j=0; jindice_count; j++ ) - indices[j] += offset; + glmesh *mesh; +}; - offset += sm->vertex_count; - } +VG_STATIC void async_mdl_load_glmesh( void *payload, u32 size ) +{ + struct payload_glmesh_load *job = payload; - mesh_upload( mesh, mdl->verts.data, mdl->verts.count, - mdl->indices.data, mdl->indices.count ); + mesh_upload( job->mesh, job->verts, job->vertex_count, + job->indices, job->indice_count ); } -VG_STATIC mdl_mesh *mdl_find_mesh( mdl_context *mdl, const char *name ) +VG_STATIC void mdl_async_load_glmesh( mdl_context *mdl, glmesh *mesh ) { - for( u32 i=0; imeshs ); i++ ){ - mdl_mesh *mesh = mdl_arritm( &mdl->meshs, i ); - if( !strcmp( name, mdl_pstr( mdl, mesh->pstr_name ))){ - return mesh; + mdl_array *arr_vertices = mdl_find_array( mdl, "mdl_vert" ); + mdl_array *arr_indices = mdl_find_array( mdl, "mdl_indice" ); + + if( arr_vertices && arr_indices ){ + u32 size_verts = vg_align8(mdl_query_array_size( arr_vertices )), + size_indices = vg_align8(mdl_query_array_size( arr_indices )), + size_hdr = vg_align8(sizeof(struct payload_glmesh_load)), + total = size_hdr + size_verts + size_indices; + + vg_async_item *call = vg_async_alloc( total ); + struct payload_glmesh_load *job = call->payload; + + u8 *payload = call->payload; + + job->mesh = mesh; + job->verts = (void*)(payload + size_hdr); + job->indices = (void*)(payload + size_hdr + size_verts); + job->vertex_count = arr_vertices->item_count; + job->indice_count = arr_indices->item_count; + + mdl_load_array_file_buffer( mdl, arr_vertices, job->verts ); + mdl_load_array_file_buffer( mdl, arr_indices, job->indices ); + + /* + * Unpack the indices (if there are meshes) + * --------------------------------------------------------- + */ + + if( mdl_arrcount( &mdl->submeshs ) ){ + mdl_submesh *sm = mdl_arritm( &mdl->submeshs, 0 ); + u32 offset = sm->vertex_count; + + for( u32 i=1; isubmeshs ); i++ ){ + mdl_submesh *sm = mdl_arritm( &mdl->submeshs, i ); + u32 *indices = job->indices + sm->indice_start; + + for( u32 j=0; jindice_count; j++ ) + indices[j] += offset; + + offset += sm->vertex_count; + } } + + /* + * Dispatch + * ------------------------- + */ + + vg_async_dispatch( call, async_mdl_load_glmesh ); + } + else{ + vg_fatal_error( "no vertex/indice data\n" ); } - return NULL; } #endif diff --git a/player_ragdoll.c b/player_ragdoll.c index a7e3e75..a1733b7 100644 --- a/player_ragdoll.c +++ b/player_ragdoll.c @@ -66,7 +66,7 @@ VG_STATIC void player_init_ragdoll_bone_collider( struct skeleton_bone *bone, } else{ vg_warn( "type: %u\n", bone->collider ); - vg_fatal_exit_loop( "Invalid bone collider type" ); + vg_fatal_error( "Invalid bone collider type" ); } m4x3_invert_affine( rp->collider_mtx, rp->inv_collider_mtx ); @@ -89,7 +89,7 @@ VG_STATIC u32 ragdoll_bone_parent( struct player_ragdoll *rd, if( rd->parts[ j ].bone_id == bone_id ) return j; - vg_fatal_exit_loop( "Referenced parent bone does not have a rigidbody" ); + vg_fatal_error( "Referenced parent bone does not have a rigidbody" ); return 0; } @@ -117,7 +117,7 @@ VG_STATIC void player_setup_ragdoll_from_avatar( struct player_ragdoll *rd, continue; if( rd->part_count > vg_list_size(rd->parts) ) - vg_fatal_exit_loop( "Playermodel has too many colliders" ); + vg_fatal_error( "Playermodel has too many colliders" ); struct ragdoll_part *rp = &rd->parts[ rd->part_count ++ ]; rp->bone_id = i; diff --git a/player_render.c b/player_render.c index ab89422..df0dd6b 100644 --- a/player_render.c +++ b/player_render.c @@ -43,30 +43,19 @@ VG_STATIC void player_model_load( struct player_model *mdl, const char *path ) mdl_context ctx; mdl_open( &ctx, path, vg_mem.scratch ); mdl_load_metadata_block( &ctx, vg_mem.scratch ); - mdl_load_mesh_block( &ctx, vg_mem.scratch ); if( !mdl_arrcount( &ctx.textures ) ) - vg_fatal_exit_loop( "No texture in player model" ); + vg_fatal_error( "No texture in player model" ); mdl_texture *tex0 = mdl_arritm( &ctx.textures, 0 ); void *data = vg_linear_alloc( vg_mem.scratch, tex0->file.pack_size ); mdl_fread_pack_file( &ctx, &tex0->file, data ); - vg_acquire_thread_sync(); - { - mdl_unpack_glmesh( &ctx, &mdl->mesh ); - - /* upload first texture */ - mdl->texture = vg_tex2d_new(); - - vg_tex2d_set_error(); - vg_tex2d_qoi( data, tex0->file.pack_size, - mdl_pstr( &ctx, tex0->file.pstr_path )); - vg_tex2d_nearest(); - vg_tex2d_clamp(); - } - vg_release_thread_sync(); + vg_tex2d_load_qoi_async( data, tex0->file.pack_size, + VG_TEX2D_NEAREST|VG_TEX2D_CLAMP, + &mdl->texture ); + mdl_async_load_glmesh( &ctx, &mdl->mesh ); mdl_close( &ctx ); } @@ -77,33 +66,22 @@ VG_STATIC void player_board_load( struct player_board *mdl, const char *path ) mdl_context ctx; mdl_open( &ctx, path, vg_mem.scratch ); mdl_load_metadata_block( &ctx, vg_mem.scratch ); - mdl_load_mesh_block( &ctx, vg_mem.scratch ); mdl_array_ptr markers; mdl_load_array( &ctx, &markers, "ent_marker", vg_mem.scratch ); if( !mdl_arrcount( &ctx.textures ) ) - vg_fatal_exit_loop( "No texture in board model" ); + vg_fatal_error( "No texture in board model" ); mdl_texture *tex0 = mdl_arritm( &ctx.textures, 0 ); void *data = vg_linear_alloc( vg_mem.scratch, tex0->file.pack_size ); mdl_fread_pack_file( &ctx, &tex0->file, data ); - vg_acquire_thread_sync(); - { - mdl_unpack_glmesh( &ctx, &mdl->mesh ); - - /* upload first texture */ - mdl->texture = vg_tex2d_new(); - - vg_tex2d_set_error(); - vg_tex2d_qoi( data, tex0->file.pack_size, - mdl_pstr( &ctx, tex0->file.pstr_path )); - vg_tex2d_nearest(); - vg_tex2d_clamp(); - } - vg_release_thread_sync(); + vg_tex2d_load_qoi_async( data, tex0->file.pack_size, + VG_TEX2D_CLAMP|VG_TEX2D_NEAREST, + &mdl->texture ); + mdl_async_load_glmesh( &ctx, &mdl->mesh ); mdl_close( &ctx ); for( int i=0; i<4; i++ ) diff --git a/player_skate.c b/player_skate.c index 7da514f..7029edc 100644 --- a/player_skate.c +++ b/player_skate.c @@ -124,7 +124,7 @@ VG_STATIC int skate_grind_scansq( player_instance *player, v3_normalize( support_axis ); while( bh_next( world->geo_bh, &it, box, &idx ) ){ - u32 *ptri = &world->scene_geo->arrindices[ idx*3 ]; + u32 *ptri = &world->scene_geo.arrindices[ idx*3 ]; v3f tri[3]; struct world_surface *surf = world_tri_index_surface(world,ptri[0]); @@ -132,7 +132,7 @@ VG_STATIC int skate_grind_scansq( player_instance *player, continue; for( int j=0; j<3; j++ ) - v3_copy( world->scene_geo->arrvertices[ptri[j]].co, tri[j] ); + v3_copy( world->scene_geo.arrvertices[ptri[j]].co, tri[j] ); for( int j=0; j<3; j++ ){ int i0 = j, @@ -519,7 +519,7 @@ void player__approximate_best_trajectory( player_instance *player ) v3_copy( co, inf->log[ inf->log_length ++ ] ); v3_copy( n, inf->n ); - u32 *tri = &trace_world->scene_geo->arrindices[ idx*3 ]; + u32 *tri = &trace_world->scene_geo.arrindices[ idx*3 ]; struct world_surface *surf = world_tri_index_surface( trace_world, tri[0] ); @@ -1163,7 +1163,7 @@ VG_STATIC void player__skate_post_update( player_instance *player ) jump_info *jump = &s->possible_jumps[i]; if( jump->log_length == 0 ){ - vg_fatal_exit_loop( "assert: jump->log_length == 0\n" ); + vg_fatal_error( "assert: jump->log_length == 0\n" ); } for( int j=0; jlog_length - 1; j ++ ){ @@ -1404,11 +1404,11 @@ int skate_compute_surface_alignment( player_instance *player, if( idx != -1 ) { - u32 *tri = &world->scene_geo->arrindices[ idx * 3 ]; + u32 *tri = &world->scene_geo.arrindices[ idx * 3 ]; v3f verts[3]; for( int j=0; j<3; j++ ) - v3_copy( world->scene_geo->arrvertices[ tri[j] ].co, verts[j] ); + v3_copy( world->scene_geo.arrvertices[ tri[j] ].co, verts[j] ); v3f vert0, vert1, n; v3_sub( verts[1], verts[0], vert0 ); @@ -1951,7 +1951,7 @@ VG_STATIC enum skate_activity skate_availible_grind( player_instance *player ) struct player_skate *s = &player->_skate; if( s->grind_cooldown > 100 ){ - vg_fatal_exit_loop( "wth!\n" ); + vg_fatal_error( "wth!\n" ); } /* debounces this state manager a little bit */ diff --git a/render.h b/render.h index a4005dd..440af47 100644 --- a/render.h +++ b/render.h @@ -244,7 +244,7 @@ VG_STATIC void render_fb_bind_texture( framebuffer *fb, if( (at->purpose != k_framebuffer_attachment_type_texture) && (at->purpose != k_framebuffer_attachment_type_texture_depth) ) { - vg_fatal_exit_loop( "illegal operation: bind non-texture framebuffer" + vg_fatal_error( "illegal operation: bind non-texture framebuffer" " attachment to texture slot" ); } @@ -480,7 +480,7 @@ VG_STATIC void render_fb_allocate( struct framebuffer *fb ) vg_error( " status: Generic Error" ); vg_info( "}\n" ); - vg_fatal_exit_loop( "Incomplete framebuffer (see logs)" ); + vg_fatal_error( "Incomplete framebuffer (see logs)" ); } } @@ -503,9 +503,16 @@ VG_STATIC void render_fb_resize(void) VG_STATIC int render_framebuffer_control( int argc, char const *argv[] ); VG_STATIC void render_framebuffer_poll( int argc, char const *argv[] ); -VG_STATIC void render_init_fs_quad(void) + +VG_STATIC void async_render_init( void *payload, u32 size ) { - vg_info( "[render] Allocate quad\n" ); + /* + * Complete Framebuffers + */ + for( int i=0; iv[1] ) || !vg_validf( rb->v[2] ) ) { - vg_fatal_exit_loop( "NaN velocity" ); + vg_fatal_error( "NaN velocity" ); } v3f gravity = { 0.0f, -9.8f, 0.0f }; @@ -1231,7 +1231,7 @@ VG_STATIC int rb_sphere__triangle( m4x3f mtxA, rb_sphere *b, VG_STATIC int rb_sphere__scene( m4x3f mtxA, rb_sphere *b, m4x3f mtxB, rb_scene *s, rb_ct *buf ) { - scene *sc = s->bh_scene->user; + scene_context *sc = s->bh_scene->user; bh_iter it; bh_iter_init( 0, &it ); @@ -1273,7 +1273,7 @@ VG_STATIC int rb_box__scene( m4x3f mtxA, boxf bbx, m4x3f mtxB, rb_scene *s, rb_ct *buf ) { #if 1 - scene *sc = s->bh_scene->user; + scene_context *sc = s->bh_scene->user; v3f tri[3]; v3f extent, center; @@ -1526,7 +1526,7 @@ VG_STATIC int rb_capsule__scene( m4x3f mtxA, rb_capsule *c, v3_sub( mtxA[3], (v3f){ c->height, c->height, c->height }, bbx[0] ); v3_add( mtxA[3], (v3f){ c->height, c->height, c->height }, bbx[1] ); - scene *sc = s->bh_scene->user; + scene_context *sc = s->bh_scene->user; while( bh_next( s->bh_scene, &it, bbx, &idx ) ){ u32 *ptri = &sc->arrindices[ idx*3 ]; diff --git a/scene.h b/scene.h index aeecd4e..027f4bd 100644 --- a/scene.h +++ b/scene.h @@ -5,7 +5,7 @@ #include "model.h" #include "bvh.h" -typedef struct scene scene; +typedef struct scene_context scene_context; typedef struct scene_vert scene_vert; #pragma pack(push,1) @@ -22,10 +22,15 @@ struct scene_vert #pragma pack(pop) -struct scene +/* + * 1. this should probably be a CONTEXT based approach unlike this mess. + * take a bit of the mdl_context ideas and redo this header. its messed up + * pretty bad right now. + */ + +struct scene_context { scene_vert *arrvertices; - u32 *arrindices; u32 vertex_count, indice_count, @@ -35,29 +40,36 @@ struct scene mdl_submesh submesh; }; -/* Initialize a scene description with bounded buffers */ -VG_STATIC scene *scene_init( void *lin_alloc, u32 max_verts, u32 max_indices ) +VG_STATIC u32 scene_mem_required( scene_context *ctx ) { - u32 vertex_length = max_verts * sizeof(scene_vert), - index_length = max_indices * sizeof(u32), - tot_size = sizeof(scene) + vertex_length + index_length; + u32 vertex_length = vg_align8(ctx->max_vertices * sizeof(scene_vert)), + index_length = vg_align8(ctx->max_indices * sizeof(u32)); - scene *pscene = vg_linear_alloc( lin_alloc, tot_size ); + return vertex_length + index_length; +} - pscene->arrvertices = (scene_vert *)(pscene+1); - pscene->arrindices = (u32 *)( pscene->arrvertices + max_verts ); +VG_STATIC +void scene_init( scene_context *ctx, u32 max_vertices, u32 max_indices ) +{ + ctx->vertex_count = 0; + ctx->indice_count = 0; + ctx->max_vertices = max_vertices; + ctx->max_indices = max_indices; + ctx->arrindices = NULL; /* must be filled out by user */ + ctx->arrvertices = NULL; - pscene->vertex_count = 0; - pscene->indice_count = 0; - pscene->max_vertices = max_verts; - pscene->max_indices = max_indices; + memset( &ctx->submesh, 0, sizeof(mdl_submesh) ); - memset( &pscene->submesh, 0, sizeof(mdl_submesh) ); + v3_fill( ctx->bbx[0], 999999.9f ); + v3_fill( ctx->bbx[1], -999999.9f ); +} - v3_fill( pscene->bbx[0], 999999.9f ); - v3_fill( pscene->bbx[1], -999999.9f ); +void scene_supply_buffer( scene_context *ctx, void *buffer ) +{ + u32 vertex_length = vg_align8( ctx->max_vertices * sizeof(scene_vert) ); - return pscene; + ctx->arrvertices = buffer; + ctx->arrindices = (u32*)(((u8*)buffer) + vertex_length); } VG_STATIC void scene_vert_pack_norm( scene_vert *vert, v3f norm ) @@ -75,38 +87,32 @@ VG_STATIC void scene_vert_pack_norm( scene_vert *vert, v3f norm ) /* * Append a model into the scene with a given transform */ -VG_STATIC void scene_add_mdl_submesh( scene *pscene, mdl_context *mdl, +VG_STATIC void scene_add_mdl_submesh( scene_context *ctx, mdl_context *mdl, mdl_submesh *sm, m4x3f transform ) { - if( pscene->vertex_count + sm->vertex_count > pscene->max_vertices ){ - vg_error( "%u(current) + %u > %u\n", pscene->vertex_count, - sm->vertex_count, - pscene->max_vertices ); - - vg_warn( "%p ... %p\n", pscene, sm ); - vg_fatal_exit_loop( "Scene vertex buffer overflow" ); + if( ctx->vertex_count + sm->vertex_count > ctx->max_vertices ){ + vg_fatal_error( "Scene vertex buffer overflow (%u exceeds %u)\n", + ctx->vertex_count + sm->vertex_count, + ctx->max_vertices ); } - if( pscene->indice_count + sm->indice_count > pscene->max_indices ){ - vg_error( "%u(current) + %u > %u\n", pscene->indice_count, - sm->indice_count, - pscene->max_indices ); - vg_warn( "%p ... %p\n", pscene, sm ); - - vg_fatal_exit_loop( "Scene index buffer overflow" ); + if( ctx->indice_count + sm->indice_count > ctx->max_indices ){ + vg_fatal_error( "Scene index buffer overflow (%u exceeds %u)\n", + ctx->indice_count + sm->indice_count, + ctx->max_indices ); } mdl_vert *src_verts = mdl_arritm( &mdl->verts, sm->vertex_start ); - scene_vert *dst_verts = &pscene->arrvertices[ pscene->vertex_count ]; + scene_vert *dst_verts = &ctx->arrvertices[ ctx->vertex_count ]; u32 *src_indices = mdl_arritm( &mdl->indices, sm->indice_start ), - *dst_indices = &pscene->arrindices[ pscene->indice_count ]; + *dst_indices = &ctx->arrindices[ ctx->indice_count ]; /* Transform and place vertices */ boxf bbxnew; box_copy( sm->bbx, bbxnew ); m4x3_transform_aabb( transform, bbxnew ); - box_concat( pscene->bbx, bbxnew ); + box_concat( ctx->bbx, bbxnew ); m3x3f normal_matrix; m3x3_copy( transform, normal_matrix ); @@ -128,103 +134,67 @@ VG_STATIC void scene_add_mdl_submesh( scene *pscene, mdl_context *mdl, } for( u32 i=0; iindice_count; i++ ) - dst_indices[i] = src_indices[i] + pscene->vertex_count; + dst_indices[i] = src_indices[i] + ctx->vertex_count; - pscene->vertex_count += sm->vertex_count; - pscene->indice_count += sm->indice_count; + ctx->vertex_count += sm->vertex_count; + ctx->indice_count += sm->indice_count; } /* * One by one adders for simplified access (mostly procedural stuff) */ -VG_STATIC void scene_push_tri( scene *pscene, u32 tri[3] ) +VG_STATIC void scene_push_tri( scene_context *ctx, u32 tri[3] ) { - if( pscene->indice_count + 3 > pscene->max_indices ) - vg_fatal_exit_loop( "Scene vertex buffer overflow" ); + if( ctx->indice_count + 3 > ctx->max_indices ) + vg_fatal_error( "Scene indice buffer overflow (%u exceeds %u)\n", + ctx->indice_count+3, ctx->max_indices ); - u32 *dst = &pscene->arrindices[ pscene->indice_count ]; + u32 *dst = &ctx->arrindices[ ctx->indice_count ]; dst[0] = tri[0]; dst[1] = tri[1]; dst[2] = tri[2]; - pscene->indice_count += 3; + ctx->indice_count += 3; } -VG_STATIC void scene_push_vert( scene *pscene, scene_vert *v ) +VG_STATIC void scene_push_vert( scene_context *ctx, scene_vert *v ) { - if( pscene->vertex_count + 1 > pscene->max_vertices ) - vg_fatal_exit_loop( "Scene vertex buffer overflow" ); + if( ctx->vertex_count + 1 > ctx->max_vertices ) + vg_fatal_error( "Scene vertex buffer overflow (%u exceeds %u)\n", + ctx->vertex_count+1, ctx->max_vertices ); - scene_vert *dst = &pscene->arrvertices[ pscene->vertex_count ]; + scene_vert *dst = &ctx->arrvertices[ ctx->vertex_count ]; *dst = *v; - pscene->vertex_count ++; + ctx->vertex_count ++; } -VG_STATIC void scene_copy_slice( scene *pscene, mdl_submesh *sm ) +VG_STATIC void scene_copy_slice( scene_context *ctx, mdl_submesh *sm ) { - sm->indice_start = pscene->submesh.indice_start; - sm->indice_count = pscene->indice_count - sm->indice_start; + sm->indice_start = ctx->submesh.indice_start; + sm->indice_count = ctx->indice_count - sm->indice_start; - sm->vertex_start = pscene->submesh.vertex_start; - sm->vertex_count = pscene->vertex_count - sm->vertex_start; + sm->vertex_start = ctx->submesh.vertex_start; + sm->vertex_count = ctx->vertex_count - sm->vertex_start; - pscene->submesh.indice_start = pscene->indice_count; - pscene->submesh.vertex_start = pscene->vertex_count; + ctx->submesh.indice_start = ctx->indice_count; + ctx->submesh.vertex_start = ctx->vertex_count; } -/* finalization: tightly pack data */ -__attribute__((warn_unused_result)) -VG_STATIC scene *scene_fix( void *lin_alloc, scene *pscene ) -{ - /* FIXME: Why is this disabled? */ - - u32 vertex_count = pscene->vertex_count, - indice_count = pscene->indice_count, - vertex_length = vertex_count * sizeof(scene_vert), - index_length = indice_count * sizeof(u32), - tot_size = vg_align8(sizeof(scene) + vertex_length + index_length); - - /* copy down index data */ - void *dst_indices = pscene->arrvertices + vertex_count; - memmove( dst_indices, pscene->arrindices, index_length ); - - /* realloc */ - pscene = vg_linear_resize( lin_alloc, pscene, tot_size ); - - pscene->arrvertices = (scene_vert *)(pscene+1); - pscene->arrindices = (u32 *)(pscene->arrvertices+vertex_count); - pscene->max_vertices = vertex_count; - pscene->max_indices = indice_count; - - return pscene; -} +struct scene_upload_info{ + scene_context *ctx; + glmesh *mesh; +}; -#if 0 -/* finalization: delete any offline buffers and reduce size */ -__attribute__((warn_unused_result)) -VG_STATIC scene *scene_free_offline_buffers( void *lin_alloc, scene *pscene ) +VG_STATIC void async_scene_upload( void *payload, u32 size ) { - u32 tot_size = sizeof(scene); - - scene *src_scene = pscene; - mdl_vert *src_verts = pscene->arrvertices; - u32 *src_indices = pscene->arrindices; - - scene *dst_scene = vg_linear_resize( lin_alloc, pscene, tot_size ); - memcpy( dst_scene, src_scene, sizeof(scene) ); - - dst_scene->arrindices = NULL; - dst_scene->arrvertices = NULL; + struct scene_upload_info *info = payload; - return dst_scene; -} -#endif - -VG_STATIC void scene_upload( scene *pscene, glmesh *mesh ) -{ //assert( mesh->loaded == 0 ); + + glmesh *mesh = info->mesh; + scene_context *ctx = info->ctx; glGenVertexArrays( 1, &mesh->vao ); glGenBuffers( 1, &mesh->vbo ); @@ -234,13 +204,13 @@ VG_STATIC void scene_upload( scene *pscene, glmesh *mesh ) size_t stride = sizeof(scene_vert); glBindBuffer( GL_ARRAY_BUFFER, mesh->vbo ); - glBufferData( GL_ARRAY_BUFFER, pscene->vertex_count*stride, - pscene->arrvertices, GL_STATIC_DRAW ); + glBufferData( GL_ARRAY_BUFFER, ctx->vertex_count*stride, + ctx->arrvertices, GL_STATIC_DRAW ); glBindVertexArray( mesh->vao ); glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, mesh->ebo ); - glBufferData( GL_ELEMENT_ARRAY_BUFFER, pscene->indice_count*sizeof(u32), - pscene->arrindices, GL_STATIC_DRAW ); + glBufferData( GL_ELEMENT_ARRAY_BUFFER, ctx->indice_count*sizeof(u32), + ctx->arrindices, GL_STATIC_DRAW ); /* 0: coordinates */ glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, stride, (void*)0 ); @@ -256,30 +226,56 @@ VG_STATIC void scene_upload( scene *pscene, glmesh *mesh ) stride, (void *)offsetof(scene_vert, uv) ); glEnableVertexAttribArray( 2 ); -#if 0 - /* 3: light cluster */ - glVertexAttribIPointer( 3, 4, GL_UNSIGNED_SHORT, - stride, (void *)offsetof(scene_vert, lights) ); - glEnableVertexAttribArray( 3 ); -#endif - VG_CHECK_GL_ERR(); - mesh->indice_count = pscene->indice_count; + mesh->indice_count = ctx->indice_count; mesh->loaded = 1; vg_info( "Scene upload ( XYZ_f32 UV_f32 XYZW_i8 )[ u32 ]\n" ); - vg_info( " indices:%u\n", pscene->indice_count ); - vg_info( " verts:%u\n", pscene->vertex_count ); + vg_info( " indices:%u\n", ctx->indice_count ); + vg_info( " verts:%u\n", ctx->vertex_count ); } +VG_STATIC void scene_upload_async( scene_context *ctx, glmesh *mesh ) +{ + vg_async_item *call = vg_async_alloc( sizeof(struct scene_upload_info) ); + + struct scene_upload_info *info = call->payload; + info->mesh = mesh; + info->ctx = ctx; + + vg_async_dispatch( call, async_scene_upload ); +} + +VG_STATIC +vg_async_item *scene_alloc_async( scene_context *scene, glmesh *mesh, + u32 max_vertices, u32 max_indices ) +{ + scene_init( scene, max_vertices, max_indices ); + u32 buf_size = scene_mem_required( scene ); + + u32 hdr_size = vg_align8(sizeof(struct scene_upload_info)); + vg_async_item *call = vg_async_alloc( hdr_size + buf_size ); + + struct scene_upload_info *info = call->payload; + + info->mesh = mesh; + info->ctx = scene; + + void *buffer = ((u8*)call->payload)+hdr_size; + scene_supply_buffer( scene, buffer ); + + return call; +} + + /* * BVH implementation */ VG_STATIC void scene_bh_expand_bound( void *user, boxf bound, u32 item_index ) { - scene *s = user; + scene_context *s = user; scene_vert *pa = &s->arrvertices[ s->arrindices[item_index*3+0] ], *pb = &s->arrvertices[ s->arrindices[item_index*3+1] ], *pc = &s->arrvertices[ s->arrindices[item_index*3+2] ]; @@ -291,7 +287,7 @@ VG_STATIC void scene_bh_expand_bound( void *user, boxf bound, u32 item_index ) VG_STATIC float scene_bh_centroid( void *user, u32 item_index, int axis ) { - scene *s = user; + scene_context *s = user; scene_vert *pa = &s->arrvertices[ s->arrindices[item_index*3+0] ], *pb = &s->arrvertices[ s->arrindices[item_index*3+1] ], *pc = &s->arrvertices[ s->arrindices[item_index*3+2] ]; @@ -314,7 +310,7 @@ VG_STATIC float scene_bh_centroid( void *user, u32 item_index, int axis ) VG_STATIC void scene_bh_swap( void *user, u32 ia, u32 ib ) { - scene *s = user; + scene_context *s = user; u32 *ti = &s->arrindices[ia*3]; u32 *tj = &s->arrindices[ib*3]; @@ -335,7 +331,7 @@ VG_STATIC void scene_bh_swap( void *user, u32 ia, u32 ib ) VG_STATIC void scene_bh_debug( void *user, u32 item_index ) { - scene *s = user; + scene_context *s = user; u32 idx = item_index*3; scene_vert *pa = &s->arrvertices[ s->arrindices[ idx+0 ] ], *pb = &s->arrvertices[ s->arrindices[ idx+1 ] ], @@ -349,7 +345,7 @@ VG_STATIC void scene_bh_debug( void *user, u32 item_index ) VG_STATIC int scene_bh_ray( void *user, u32 index, v3f co, v3f dir, ray_hit *hit ) { - scene *s = user; + scene_context *s = user; v3f positions[3]; u32 *tri = &s->arrindices[ index*3 ]; @@ -358,10 +354,8 @@ VG_STATIC int scene_bh_ray( void *user, u32 index, v3f co, v3_copy( s->arrvertices[tri[i]].co, positions[i] ); float t; - if(ray_tri( positions, co, dir, &t )) - { - if( t < hit->dist ) - { + if(ray_tri( positions, co, dir, &t )){ + if( t < hit->dist ){ hit->dist = t; hit->tri = tri; return 1; @@ -373,7 +367,7 @@ VG_STATIC int scene_bh_ray( void *user, u32 index, v3f co, VG_STATIC void scene_bh_closest( void *user, u32 index, v3f point, v3f closest ) { - scene *s = user; + scene_context *s = user; v3f positions[3]; u32 *tri = &s->arrindices[ index*3 ]; @@ -396,13 +390,12 @@ VG_STATIC bh_system bh_system_scene = /* * An extra step is added onto the end to calculate the hit normal */ -VG_STATIC int scene_raycast( scene *s, bh_tree *bh, +VG_STATIC int scene_raycast( scene_context *s, bh_tree *bh, v3f co, v3f dir, ray_hit *hit ) { int count = bh_ray( bh, co, dir, hit ); - if( count ) - { + if( count ){ v3f v0, v1; float *pa = s->arrvertices[hit->tri[0]].co, @@ -419,7 +412,7 @@ VG_STATIC int scene_raycast( scene *s, bh_tree *bh, return count; } -VG_STATIC bh_tree *scene_bh_create( void *lin_alloc, scene *s ) +VG_STATIC bh_tree *scene_bh_create( void *lin_alloc, scene_context *s ) { u32 triangle_count = s->indice_count / 3; return bh_create( lin_alloc, &bh_system_scene, s, triangle_count, 2 ); diff --git a/skaterift.c b/skaterift.c index d943c2d..54e5feb 100644 --- a/skaterift.c +++ b/skaterift.c @@ -25,6 +25,7 @@ VG_STATIC struct player_avatar localplayer_avatar; VG_STATIC struct player_model localplayer_models[3]; VG_STATIC struct player_board localplayer_boards[1]; +VG_STATIC int skaterift_status = 0; #include "network.h" #include "menu.h" @@ -103,6 +104,14 @@ void temp_update_playermodel(void){ player__use_model( &localplayer, &localplayer_models[cl_playermdl_id] ); } +VG_STATIC void async_skaterift_complete( void *payload, u32 size ) +{ + skaterift_status = 1; + + localplayer.viewable_world = get_active_world(); + localplayer_cmd_respawn( 1, (const char *[]){ "start" } ); +} + VG_STATIC void vg_load(void) { vg_loader_step( render_init, NULL ); @@ -150,12 +159,9 @@ VG_STATIC void vg_load(void) #endif vg_console_load_autos(); -} -VG_STATIC void vg_start(void) -{ - localplayer.viewable_world = get_active_world(); - localplayer_cmd_respawn( 1, (const char *[]){ "start" } ); + vg_async_item *call = vg_async_alloc(0); + vg_async_dispatch( call, async_skaterift_complete ); } VG_STATIC void draw_origin_axis(void) @@ -169,7 +175,7 @@ VG_STATIC void vg_update(void) { steam_update(); - if( vg.is_loaded ){ + if( skaterift_status == 1 ){ draw_origin_axis(); network_update(); @@ -182,7 +188,7 @@ VG_STATIC void vg_update(void) VG_STATIC void vg_update_fixed(void) { - if( vg.is_loaded ){ + if( skaterift_status == 1 ){ world_routes_fixedupdate( get_active_world() ); player__update( &localplayer ); @@ -215,7 +221,7 @@ VG_STATIC void vg_update_fixed(void) VG_STATIC void vg_update_post(void) { - if( vg.is_loaded ){ + if( skaterift_status == 1 ){ player__post_update( &localplayer ); float dist; @@ -428,6 +434,11 @@ VG_STATIC void render_main_game(void) VG_STATIC void vg_render(void) { + if( skaterift_status == 0 ){ + _vg_loader_render(); + return; + } + glBindFramebuffer( GL_FRAMEBUFFER, 0 ); glViewport( 0,0, vg.window_x, vg.window_y ); @@ -449,6 +460,10 @@ VG_STATIC void vg_render(void) VG_STATIC void vg_ui(void) { + if( skaterift_status == 0 ){ + return; + } + #if 0 player__im_gui( &localplayer ); #endif diff --git a/skeleton.h b/skeleton.h index 2595cda..79e8017 100644 --- a/skeleton.h +++ b/skeleton.h @@ -61,7 +61,7 @@ VG_STATIC u32 skeleton_bone_id( struct skeleton *skele, const char *name ) } vg_error( "skeleton_bone_id( *, \"%s\" );\n", name ); - vg_fatal_exit_loop( "Bone does not exist\n" ); + vg_fatal_error( "Bone does not exist\n" ); return 0; } @@ -403,7 +403,7 @@ VG_STATIC struct skeleton_anim *skeleton_get_anim( struct skeleton *skele, } vg_error( "skeleton_get_anim( *, \"%s\" )\n", name ); - vg_fatal_exit_loop( "Invalid animation name\n" ); + vg_fatal_error( "Invalid animation name\n" ); return NULL; } @@ -441,7 +441,7 @@ VG_STATIC void skeleton_alloc_from( struct skeleton *skele, VG_STATIC void skeleton_fatal_err(void) { - vg_fatal_exit_loop( "Skeleton setup failed" ); + vg_fatal_error( "Skeleton setup failed" ); } /* Setup an animated skeleton from model. mdl's metadata should stick around */ diff --git a/world.h b/world.h index 5318f8e..7084ff1 100644 --- a/world.h +++ b/world.h @@ -174,9 +174,9 @@ struct world_instance { */ /* world geometry */ - scene *scene_geo, - *scene_no_collide, - *scene_lines; + scene_context scene_geo, + scene_no_collide, + scene_lines; /* spacial mappings */ bh_tree *audio_bh, @@ -221,6 +221,7 @@ struct world_global{ glmesh mesh_base, mesh_display; mdl_submesh sm_base; u32 active_route_board; + scene_context scene; u32 w, h; float *buffer; @@ -386,15 +387,9 @@ VG_STATIC void world_init(void) mdl_context msky; mdl_open( &msky, "models/rs_skydome.mdl", vg_mem.scratch ); mdl_load_metadata_block( &msky, vg_mem.scratch ); - mdl_load_mesh_block( &msky, vg_mem.scratch ); + mdl_async_load_glmesh( &msky, &world_global.skydome ); mdl_close( &msky ); - vg_acquire_thread_sync(); - { - mdl_unpack_glmesh( &msky, &world_global.skydome ); - } - vg_release_thread_sync(); - /* Other systems */ vg_info( "Loading other world systems\n" ); @@ -456,7 +451,7 @@ VG_STATIC void ent_audio_call( world_instance *world, ent_call *call ) v3_copy( audio->transform.co, sound_co ); } else - vg_fatal_exit_loop( "ent_audio_call (invalid function id)" ); + vg_fatal_error( "ent_audio_call (invalid function id)" ); float chance = vg_randf()*100.0f, bar = 0.0f; @@ -749,13 +744,13 @@ VG_STATIC void ray_world_get_tri( world_instance *world, ray_hit *hit, v3f tri[3] ) { for( int i=0; i<3; i++ ) - v3_copy( world->scene_geo->arrvertices[ hit->tri[i] ].co, tri[i] ); + v3_copy( world->scene_geo.arrvertices[ hit->tri[i] ].co, tri[i] ); } VG_STATIC int ray_world( world_instance *world, v3f pos, v3f dir, ray_hit *hit ) { - return scene_raycast( world->scene_geo, world->geo_bh, pos, dir, hit ); + return scene_raycast( &world->scene_geo, world->geo_bh, pos, dir, hit ); } /* @@ -788,14 +783,14 @@ VG_STATIC int spherecast_world( world_instance *world, int idx; while( bh_next( world->geo_bh, &it, region, &idx ) ){ - u32 *ptri = &world->scene_geo->arrindices[ idx*3 ]; + u32 *ptri = &world->scene_geo.arrindices[ idx*3 ]; v3f tri[3]; boxf box; box_init_inf( box ); for( int j=0; j<3; j++ ){ - v3_copy( world->scene_geo->arrvertices[ptri[j]].co, tri[j] ); + v3_copy( world->scene_geo.arrvertices[ptri[j]].co, tri[j] ); box_addpt( box, tri[j] ); } diff --git a/world_gate.h b/world_gate.h index 989e918..469f736 100644 --- a/world_gate.h +++ b/world_gate.h @@ -42,7 +42,6 @@ VG_STATIC void world_gates_init(void) mdl_context mgate; mdl_open( &mgate, "models/rs_gate.mdl", vg_mem.scratch ); mdl_load_metadata_block( &mgate, vg_mem.scratch ); - mdl_load_mesh_block( &mgate, vg_mem.scratch ); mdl_mesh *surface = mdl_find_mesh( &mgate, "rs_gate" ); mdl_submesh *sm = mdl_arritm(&mgate.submeshs,surface->submesh_start); @@ -57,13 +56,8 @@ VG_STATIC void world_gates_init(void) world_global.sm_gate_marker[i] = *sm; } + mdl_async_load_glmesh( &mgate, &world_global.mesh_gate ); mdl_close( &mgate ); - - vg_acquire_thread_sync(); - { - mdl_unpack_glmesh( &mgate, &world_global.mesh_gate ); - } - vg_release_thread_sync(); } VG_STATIC int render_gate( world_instance *world_inside, diff --git a/world_gen.h b/world_gen.h index e8e9293..3e7cdb9 100644 --- a/world_gen.h +++ b/world_gen.h @@ -9,7 +9,7 @@ VG_STATIC void world_load( u32 index, const char *path ); -VG_STATIC void world_add_all_if_material( m4x3f transform, scene *pscene, +VG_STATIC void world_add_all_if_material( m4x3f transform, scene_context *scene, mdl_context *mdl, u32 id ) { for( u32 i=0; imeshs); i++ ){ @@ -22,14 +22,14 @@ VG_STATIC void world_add_all_if_material( m4x3f transform, scene *pscene, mdl_transform_m4x3( &mesh->transform, transform2 ); m4x3_mul( transform, transform2, transform2 ); - scene_add_mdl_submesh( pscene, mdl, sm, transform2 ); + scene_add_mdl_submesh( scene, mdl, sm, transform2 ); } } } } VG_STATIC void world_add_blob( world_instance *world, - scene *pscene, ray_hit *hit ) + scene_context *scene, ray_hit *hit ) { m4x3f transform; v4f qsurface, qrandom; @@ -56,16 +56,16 @@ VG_STATIC void world_add_blob( world_instance *world, const u32 indices[] = { 0,1,3, 0,3,2, 2,3,5, 2,5,4 }; - if( pscene->vertex_count + vg_list_size(verts) > pscene->max_vertices ) - vg_fatal_exit_loop( "Scene vertex buffer overflow" ); + if( scene->vertex_count + vg_list_size(verts) > scene->max_vertices ) + vg_fatal_error( "Scene vertex buffer overflow" ); - if( pscene->indice_count + vg_list_size(indices) > pscene->max_indices ) - vg_fatal_exit_loop( "Scene index buffer overflow" ); + if( scene->indice_count + vg_list_size(indices) > scene->max_indices ) + vg_fatal_error( "Scene index buffer overflow" ); - scene_vert *dst_verts = &pscene->arrvertices[ pscene->vertex_count ]; - u32 *dst_indices = &pscene->arrindices [ pscene->indice_count ]; + scene_vert *dst_verts = &scene->arrvertices[ scene->vertex_count ]; + u32 *dst_indices = &scene->arrindices [ scene->indice_count ]; - scene_vert *ref = &world->scene_geo->arrvertices[ hit->tri[0] ]; + scene_vert *ref = &world->scene_geo.arrvertices[ hit->tri[0] ]; for( u32 i=0; ivertex_count; + dst_indices[i] = indices[i] + scene->vertex_count; - pscene->vertex_count += vg_list_size(verts); - pscene->indice_count += vg_list_size(indices); + scene->vertex_count += vg_list_size(verts); + scene->indice_count += vg_list_size(indices); } /* Sprinkle foliage models over the map on terrain material */ VG_STATIC void world_apply_procedural_foliage( world_instance *world, + scene_context *scene, struct world_surface *mat ) { if( vg.quality_profile == k_quality_profile_low ) @@ -95,7 +96,7 @@ VG_STATIC void world_apply_procedural_foliage( world_instance *world, vg_info( "Applying foliage (%u)\n", mat->info.pstr_name ); v3f volume; - v3_sub( world->scene_geo->bbx[1], world->scene_geo->bbx[0], volume ); + v3_sub( world->scene_geo.bbx[1], world->scene_geo.bbx[0], volume ); volume[1] = 1.0f; int count = 0; @@ -109,7 +110,7 @@ VG_STATIC void world_apply_procedural_foliage( world_instance *world, v3f pos; v3_mul( volume, (v3f){ vg_randf(), 1000.0f, vg_randf() }, pos ); pos[1] = 1000.0f; - v3_add( pos, world->scene_geo->bbx[0], pos ); + v3_add( pos, world->scene_geo.bbx[0], pos ); ray_hit hit; hit.dist = INFINITY; @@ -117,7 +118,7 @@ VG_STATIC void world_apply_procedural_foliage( world_instance *world, if( ray_world( world, pos, (v3f){0.0f,-1.0f,0.0f}, &hit )){ struct world_surface *m1 = ray_hit_surface( world, &hit ); if((hit.normal[1] > 0.8f) && (m1 == mat) && (hit.pos[1] > 0.0f+10.0f)){ - world_add_blob( world, world->scene_no_collide, &hit ); + world_add_blob( world, scene, &hit ); count ++; } } @@ -131,7 +132,10 @@ VG_STATIC void world_generate( world_instance *world ) /* * Compile meshes into the world scenes */ - world->scene_geo = scene_init( world->heap, 320000, 1200000 ); + scene_init( &world->scene_geo, 320000, 1200000 ); + u32 buf_size = scene_mem_required( &world->scene_geo ); + u8 *buffer = vg_linear_alloc( world->heap, buf_size ); + scene_supply_buffer( &world->scene_geo, buffer ); m4x3f midentity; m4x3_identity( midentity ); @@ -147,23 +151,39 @@ VG_STATIC void world_generate( world_instance *world ) struct world_surface *surf = &world->surfaces[ i ]; if( surf->info.flags & k_material_flag_collision ) - world_add_all_if_material( midentity, world->scene_geo, + world_add_all_if_material( midentity, &world->scene_geo, &world->meta, i ); - scene_copy_slice( world->scene_geo, &surf->sm_geo ); + scene_copy_slice( &world->scene_geo, &surf->sm_geo ); } /* compress that bad boy */ - world->scene_geo = scene_fix( world->heap, world->scene_geo ); + u32 new_vert_max = world->scene_geo.vertex_count, + new_vert_size = vg_align8(new_vert_max*sizeof(scene_vert)), + new_indice_len = world->scene_geo.indice_count*sizeof(u32); - vg_acquire_thread_sync(); - { - scene_upload( world->scene_geo, &world->mesh_geo ); - } - vg_release_thread_sync(); + u32 *src_indices = world->scene_geo.arrindices, + *dst_indices = (u32 *)(buffer + new_vert_size); + + memmove( dst_indices, src_indices, new_indice_len ); + + world->scene_geo.max_indices = world->scene_geo.indice_count; + world->scene_geo.max_vertices = world->scene_geo.vertex_count; + buf_size = scene_mem_required( &world->scene_geo ); + + buffer = vg_linear_resize( world->heap, buffer, buf_size ); + + world->scene_geo.arrvertices = (scene_vert *)(buffer); + world->scene_geo.arrindices = (u32 *)(buffer + new_vert_size); + + scene_upload_async( &world->scene_geo, &world->mesh_geo ); + + /* need send off the memory to the gpu before we can create the bvh. */ + vg_async_stall(); + vg_info( "creating bvh\n" ); /* setup spacial mapping and rigidbody */ - world->geo_bh = scene_bh_create( world->heap, world->scene_geo ); + world->geo_bh = scene_bh_create( world->heap, &world->scene_geo ); v3_zero( world->rb_geo.rb.co ); v3_zero( world->rb_geo.rb.v ); @@ -180,38 +200,25 @@ VG_STATIC void world_generate( world_instance *world ) */ vg_info( "Generating non-collidable geometry\n" ); - world->scene_no_collide = scene_init( world->heap, 200000, 500000 ); + vg_async_item *call = scene_alloc_async( &world->scene_no_collide, + &world->mesh_no_collide, + 200000, 500000 ); for( u32 i=0; isurface_count; i++ ){ - struct world_surface *mat = &world->surfaces[ i ]; + struct world_surface *surf = &world->surfaces[ i ]; - if( !(mat->info.flags & k_material_flag_collision) ){ - world_add_all_if_material( midentity, world->scene_no_collide, - &world->meta, i ); + if( !(surf->info.flags & k_material_flag_collision) ){ + world_add_all_if_material( midentity, + &world->scene_no_collide, &world->meta, i ); } - if( mat->info.flags & k_material_flag_grow_grass ) - world_apply_procedural_foliage( world, mat ); + if( surf->info.flags & k_material_flag_grow_grass ) + world_apply_procedural_foliage( world, + &world->scene_no_collide, surf ); - scene_copy_slice( world->scene_no_collide, &mat->sm_no_collide ); + scene_copy_slice( &world->scene_no_collide, &surf->sm_no_collide ); } - /* this FIXME TODO IMPORTANT is going here because need to write down. - * - * acuire_thread_sync; replace this with a buffer that you fill up with - * opengl loader commands in a seperate memory area. the operation blocks - * if the buffer is full, then those instructions get ran on the sync line. - * (start of the frame) - * - * also blocks if the other thread is executing the instructions, obviously. - * - * this prevents rapid context swaps between threads. - * - * guessing a 50mb loader buffer approx. - * - * TODO also: fadeout loading screen! - */ - for( u32 i=0; ient_traffic ); i++ ){ ent_traffic *vehc = mdl_arritm( &world->ent_traffic, i ); @@ -225,23 +232,15 @@ VG_STATIC void world_generate( world_instance *world ) m4x3f identity; m4x3_identity( identity ); - scene_add_mdl_submesh( world->scene_no_collide, &world->meta, - sm, identity ); + scene_add_mdl_submesh( &world->scene_no_collide, + &world->meta, sm, identity ); - scene_copy_slice( world->scene_no_collide, sm ); + scene_copy_slice( &world->scene_no_collide, sm ); sm->flags |= k_submesh_flag_consumed; } } - /* upload and free that */ - vg_acquire_thread_sync(); - { - scene_upload( world->scene_no_collide, &world->mesh_no_collide ); - } - vg_release_thread_sync(); - - vg_linear_del( world->heap, world->scene_no_collide ); - world->scene_no_collide = NULL; + vg_async_dispatch( call, async_scene_upload ); } float fsd_cone_infinite( v3f p, v2f c ) @@ -257,12 +256,32 @@ float fsd_cone_infinite( v3f p, v2f c ) return d * ((q[0]*c[1]-q[1]*c[0]<0.0f)?-1.0f:1.0f); } +struct light_indices_upload_info{ + world_instance *world; + v3i count; + + void *data; +}; + +VG_STATIC void async_upload_light_indices( void *payload, u32 size ) +{ + struct light_indices_upload_info *info = payload; + + glGenTextures( 1, &info->world->tex_light_cubes ); + glBindTexture( GL_TEXTURE_3D, info->world->tex_light_cubes ); + glTexImage3D( GL_TEXTURE_3D, 0, GL_RG32UI, + info->count[0], info->count[1], info->count[2], + 0, GL_RG_INTEGER, GL_UNSIGNED_INT, info->data ); + glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); + glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); +} + VG_STATIC void world_compute_light_indices( world_instance *world ) { /* light cubes */ v3f cubes_min, cubes_max; - v3_muls( world->scene_geo->bbx[0], 1.0f/k_light_cube_size, cubes_min ); - v3_muls( world->scene_geo->bbx[1], 1.0f/k_light_cube_size, cubes_max ); + v3_muls( world->scene_geo.bbx[0], 1.0f/k_light_cube_size, cubes_min ); + v3_muls( world->scene_geo.bbx[1], 1.0f/k_light_cube_size, cubes_max ); v3_sub( cubes_min, (v3f){ 0.5f, 0.5f, 0.5f }, cubes_min ); v3_add( cubes_max, (v3f){ 0.5f, 0.5f, 0.5f }, cubes_max ); @@ -305,8 +324,17 @@ VG_STATIC void world_compute_light_indices( world_instance *world ) int total_cubes = icubes_count[0]*icubes_count[1]*icubes_count[2]; - u32 *cubes_index = vg_linear_alloc( world->heap, - vg_align8(total_cubes*sizeof(u32)*2) ); + u32 data_size = vg_align8(total_cubes*sizeof(u32)*2), + hdr_size = vg_align8(sizeof(struct light_indices_upload_info)); + + vg_async_item *call = vg_async_alloc( data_size + hdr_size ); + struct light_indices_upload_info *info = call->payload; + info->data = ((u8*)call->payload) + hdr_size; + info->world = world; + u32 *cubes_index = info->data; + + for( int i=0; i<3; i++ ) + info->count[i] = icubes_count[i]; vg_info( "Computing light cubes (%d) [%f %f %f] -> [%f %f %f]\n", total_cubes, cubes_min[0], -cubes_min[2], cubes_min[1], @@ -401,160 +429,129 @@ VG_STATIC void world_compute_light_indices( world_instance *world ) } } - vg_acquire_thread_sync(); + vg_async_dispatch( call, async_upload_light_indices ); +} - glGenTextures( 1, &world->tex_light_cubes ); - glBindTexture( GL_TEXTURE_3D, world->tex_light_cubes ); - glTexImage3D( GL_TEXTURE_3D, 0, GL_RG32UI, - icubes_count[0], icubes_count[1], icubes_count[2], - 0, GL_RG_INTEGER, GL_UNSIGNED_INT, cubes_index ); - glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); - glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); +VG_STATIC void async_world_postprocess_render( void *payload, u32 _size ) +{ + /* create scene lighting buffer */ + world_instance *world = payload; - vg_linear_del( world->heap, cubes_index ); + u32 size = VG_MAX(mdl_arrcount(&world->ent_light),1) * sizeof(float)*12; + vg_info( "Upload %ubytes (lighting)\n", size ); - vg_release_thread_sync(); -} + glGenBuffers( 1, &world->tbo_light_entities ); + glBindBuffer( GL_TEXTURE_BUFFER, world->tbo_light_entities ); + glBufferData( GL_TEXTURE_BUFFER, size, NULL, GL_DYNAMIC_DRAW ); + + /* buffer layout + * + * colour position direction (spots) + * | . . . . | . . . . | . . . . | + * | Re Ge Be Night | Xco Yco Zco Range | Dx Dy Dz Da | + * + */ -VG_STATIC int reset_player( int argc, char const *argv[] ); -VG_STATIC void world_post_process( world_instance *world ) -{ - /* initialize audio if need be */ -#if 0 - audio_lock(); - for( int i=0; iaudio_things_count; i++ ) - { - struct world_audio_thing *thingy = &world->audio_things[ i ]; + v4f *light_dst = glMapBuffer( GL_TEXTURE_BUFFER, GL_WRITE_ONLY ); + for( u32 i=0; ient_light); i++ ){ + ent_light *light = mdl_arritm( &world->ent_light, i ); - if( thingy->flags & AUDIO_FLAG_AUTO_START ) - { - audio_channel *ch = - audio_request_channel( &thingy->temp_embedded_clip, thingy->flags ); + /* colour + night */ + v3_muls( light->colour, light->colour[3] * 2.0f, light_dst[i*3+0] ); + light_dst[i*3+0][3] = 2.0f; - audio_channel_edit_volume( ch, thingy->volume, 1 ); - audio_channel_set_spacial( ch, thingy->pos, thingy->range ); + if( !light->daytime ){ + u32 hash = (i * 29986577u) & 0xffu; + float switch_on = hash; + switch_on *= (1.0f/255.0f); - if( !(ch->flags & AUDIO_FLAG_LOOP) ) - ch = audio_relinquish_channel( ch ); + light_dst[i*3+0][3] = 0.44f + switch_on * 0.015f; } + + /* position + 1/range^2 */ + v3_copy( light->transform.co, light_dst[i*3+1] ); + light_dst[i*3+1][3] = 1.0f/(light->range*light->range); + + /* direction + angle */ + q_mulv( light->transform.q, (v3f){0.0f,-1.0f,0.0f}, light_dst[i*3+2]); + light_dst[i*3+2][3] = cosf( light->angle ); } - audio_unlock(); -#endif - world_compute_light_indices( world ); + glUnmapBuffer( GL_TEXTURE_BUFFER ); - vg_acquire_thread_sync(); - { - /* create scene lighting buffer */ + glGenTextures( 1, &world->tex_light_entities ); + glBindTexture( GL_TEXTURE_BUFFER, world->tex_light_entities ); + glTexBuffer( GL_TEXTURE_BUFFER, GL_RGBA32F, world->tbo_light_entities ); - u32 size = VG_MAX(mdl_arrcount(&world->ent_light),1) * sizeof(float)*12; - vg_info( "Upload %ubytes (lighting)\n", size ); + /* Upload lighting uniform buffer */ + if( world->water.enabled ) + v4_copy( world->water.plane, world->ub_lighting.g_water_plane ); - glGenBuffers( 1, &world->tbo_light_entities ); - glBindBuffer( GL_TEXTURE_BUFFER, world->tbo_light_entities ); - glBufferData( GL_TEXTURE_BUFFER, size, NULL, GL_DYNAMIC_DRAW ); - - /* buffer layout - * - * colour position direction (spots) - * | . . . . | . . . . | . . . . | - * | Re Ge Be Night | Xco Yco Zco Range | Dx Dy Dz Da | - * - */ - - v4f *light_dst = glMapBuffer( GL_TEXTURE_BUFFER, GL_WRITE_ONLY ); - for( u32 i=0; ient_light); i++ ){ - ent_light *light = mdl_arritm( &world->ent_light, i ); - - /* colour + night */ - v3_muls( light->colour, light->colour[3] * 2.0f, light_dst[i*3+0] ); - light_dst[i*3+0][3] = 2.0f; - - if( !light->daytime ){ - u32 hash = (i * 29986577u) & 0xffu; - float switch_on = hash; - switch_on *= (1.0f/255.0f); - - light_dst[i*3+0][3] = 0.44f + switch_on * 0.015f; - } - - /* position + 1/range^2 */ - v3_copy( light->transform.co, light_dst[i*3+1] ); - light_dst[i*3+1][3] = 1.0f/(light->range*light->range); - - /* direction + angle */ - q_mulv( light->transform.q, (v3f){0.0f,-1.0f,0.0f}, light_dst[i*3+2]); - light_dst[i*3+2][3] = cosf( light->angle ); - } + v4f info_vec; + v3f *bounds = world->scene_geo.bbx; - glUnmapBuffer( GL_TEXTURE_BUFFER ); - - glGenTextures( 1, &world->tex_light_entities ); - glBindTexture( GL_TEXTURE_BUFFER, world->tex_light_entities ); - glTexBuffer( GL_TEXTURE_BUFFER, GL_RGBA32F, world->tbo_light_entities ); - - /* Upload lighting uniform buffer */ - if( world->water.enabled ) - v4_copy( world->water.plane, world->ub_lighting.g_water_plane ); - - v4f info_vec; - v3f *bounds = world->scene_geo->bbx; - - info_vec[0] = bounds[0][0]; - info_vec[1] = bounds[0][2]; - info_vec[2] = 1.0f/ (bounds[1][0]-bounds[0][0]); - info_vec[3] = 1.0f/ (bounds[1][2]-bounds[0][2]); - v4_copy( info_vec, world->ub_lighting.g_depth_bounds ); - - /* - * Rendering the depth map - */ - camera ortho; - - v3f extent; - v3_sub( world->scene_geo->bbx[1], world->scene_geo->bbx[0], extent ); - - float fl = world->scene_geo->bbx[0][0], - fr = world->scene_geo->bbx[1][0], - fb = world->scene_geo->bbx[0][2], - ft = world->scene_geo->bbx[1][2], - rl = 1.0f / (fr-fl), - tb = 1.0f / (ft-fb); - - m4x4_zero( ortho.mtx.p ); - ortho.mtx.p[0][0] = 2.0f * rl; - ortho.mtx.p[2][1] = 2.0f * tb; - ortho.mtx.p[3][0] = (fr + fl) * -rl; - ortho.mtx.p[3][1] = (ft + fb) * -tb; - ortho.mtx.p[3][3] = 1.0f; - m4x3_identity( ortho.transform ); - camera_update_view( &ortho ); - camera_finalize( &ortho ); - - glDisable(GL_DEPTH_TEST); - glDisable(GL_BLEND); - glDisable(GL_CULL_FACE); - render_fb_bind( &world->heightmap, 0 ); - shader_blitcolour_use(); - shader_blitcolour_uColour( (v4f){-9999.0f,-9999.0f,-9999.0f,-9999.0f} ); - render_fsquad(); - - glEnable(GL_BLEND); - glBlendFunc(GL_ONE, GL_ONE); - glBlendEquation(GL_MAX); - - render_world_position( world, &ortho ); - glDisable(GL_BLEND); - glEnable(GL_DEPTH_TEST); - glBindFramebuffer( GL_FRAMEBUFFER, 0 ); - - /* upload full buffer */ - glBindBuffer( GL_UNIFORM_BUFFER, world->ubo_lighting ); - glBufferSubData( GL_UNIFORM_BUFFER, 0, - sizeof(struct ub_world_lighting), &world->ub_lighting ); - } + info_vec[0] = bounds[0][0]; + info_vec[1] = bounds[0][2]; + info_vec[2] = 1.0f/ (bounds[1][0]-bounds[0][0]); + info_vec[3] = 1.0f/ (bounds[1][2]-bounds[0][2]); + v4_copy( info_vec, world->ub_lighting.g_depth_bounds ); - vg_release_thread_sync(); + /* + * Rendering the depth map + */ + camera ortho; + + v3f extent; + v3_sub( world->scene_geo.bbx[1], world->scene_geo.bbx[0], extent ); + + float fl = world->scene_geo.bbx[0][0], + fr = world->scene_geo.bbx[1][0], + fb = world->scene_geo.bbx[0][2], + ft = world->scene_geo.bbx[1][2], + rl = 1.0f / (fr-fl), + tb = 1.0f / (ft-fb); + + m4x4_zero( ortho.mtx.p ); + ortho.mtx.p[0][0] = 2.0f * rl; + ortho.mtx.p[2][1] = 2.0f * tb; + ortho.mtx.p[3][0] = (fr + fl) * -rl; + ortho.mtx.p[3][1] = (ft + fb) * -tb; + ortho.mtx.p[3][3] = 1.0f; + m4x3_identity( ortho.transform ); + camera_update_view( &ortho ); + camera_finalize( &ortho ); + + glDisable(GL_DEPTH_TEST); + glDisable(GL_BLEND); + glDisable(GL_CULL_FACE); + render_fb_bind( &world->heightmap, 0 ); + shader_blitcolour_use(); + shader_blitcolour_uColour( (v4f){-9999.0f,-9999.0f,-9999.0f,-9999.0f} ); + render_fsquad(); + + glEnable(GL_BLEND); + glBlendFunc(GL_ONE, GL_ONE); + glBlendEquation(GL_MAX); + + render_world_position( world, &ortho ); + glDisable(GL_BLEND); + glEnable(GL_DEPTH_TEST); + glBindFramebuffer( GL_FRAMEBUFFER, 0 ); + + /* upload full buffer */ + glBindBuffer( GL_UNIFORM_BUFFER, world->ubo_lighting ); + glBufferSubData( GL_UNIFORM_BUFFER, 0, + sizeof(struct ub_world_lighting), &world->ub_lighting ); +} + +VG_STATIC int reset_player( int argc, char const *argv[] ); +VG_STATIC void world_post_process( world_instance *world ) +{ + world_compute_light_indices( world ); + + vg_async_item *call = vg_async_alloc(0); + call->payload = world; + vg_async_dispatch( call, async_world_postprocess_render ); } VG_STATIC void world_process_resources( world_instance *world ) @@ -567,43 +564,24 @@ VG_STATIC void world_process_resources( world_instance *world ) world->textures = vg_linear_alloc( world->heap, vg_align8(sizeof(GLuint)*world->texture_count) ); - /* TODO FIXME IMPORTANT - * - * this is another area that would benefit from our load thread buffer idea. - * could get a stall if lots of textures, since its freading, we're locking - * the frame up from drawing based on that disk read!!! terrible! - */ + vg_tex2d_replace_with_error( &world->textures[0] ); - vg_acquire_thread_sync(); - { - /* error texture */ - world->textures[0] = vg_tex2d_new(); - vg_tex2d_set_error(); - vg_tex2d_nearest(); - vg_tex2d_repeat(); - - for( u32 i=0; imeta.textures); i++ ){ - mdl_texture *tex = mdl_arritm( &world->meta.textures, i ); - - if( !tex->file.pack_size ){ - vg_release_thread_sync(); - vg_fatal_exit_loop( "World models must have packed textures!" ); - } + for( u32 i=0; imeta.textures); i++ ){ + mdl_texture *tex = mdl_arritm( &world->meta.textures, i ); - vg_linear_clear( vg_mem.scratch ); - void *src_data = vg_linear_alloc( vg_mem.scratch, - tex->file.pack_size ); - mdl_fread_pack_file( &world->meta, &tex->file, src_data ); - - world->textures[i+1] = vg_tex2d_new(); - vg_tex2d_set_error(); - vg_tex2d_qoi( src_data, tex->file.pack_size, - mdl_pstr( &world->meta, tex->file.pstr_path )); - vg_tex2d_nearest(); - vg_tex2d_repeat(); + if( !tex->file.pack_size ){ + vg_fatal_error( "World models must have packed textures!" ); } + + vg_linear_clear( vg_mem.scratch ); + void *src_data = vg_linear_alloc( vg_mem.scratch, + tex->file.pack_size ); + mdl_fread_pack_file( &world->meta, &tex->file, src_data ); + + vg_tex2d_load_qoi_async( src_data, tex->file.pack_size, + VG_TEX2D_NEAREST|VG_TEX2D_REPEAT, + &world->textures[i+1] ); } - vg_release_thread_sync(); vg_info( "Loading materials\n" ); @@ -621,6 +599,7 @@ VG_STATIC void world_process_resources( world_instance *world ) } } +#if 0 VG_STATIC void world_free( world_instance *world ) { vg_acquire_thread_sync(); @@ -644,6 +623,7 @@ VG_STATIC void world_free( world_instance *world ) world->status = k_world_status_unloaded; } +#endif VG_STATIC void world_init_blank( world_instance *world ) { @@ -653,10 +633,6 @@ VG_STATIC void world_init_blank( world_instance *world ) world->texture_count = 0; world->surfaces = NULL; world->surface_count = 0; - - world->scene_geo = NULL; - world->scene_no_collide = NULL; - world->scene_lines = NULL; world->geo_bh = NULL; world->volume_bh = NULL; @@ -831,7 +807,7 @@ VG_STATIC void world_load( u32 index, const char *path ) u32 min_overhead = sizeof(vg_linear_allocator); if( heap_availible < (min_overhead+1024) ){ - vg_fatal_exit_loop( "out of memory" ); + vg_fatal_error( "out of memory" ); } u32 size = heap_availible - min_overhead; diff --git a/world_render.h b/world_render.h index f61974e..7fb47b0 100644 --- a/world_render.h +++ b/world_render.h @@ -8,62 +8,60 @@ #include "camera.h" #include "world.h" -/* FIXME */ -VG_STATIC vg_tex2d tex_terrain_noise = { .path = "textures/garbage.qoi", - .flags = VG_TEXTURE_NEAREST }; +VG_STATIC GLuint tex_terrain_noise; -VG_STATIC void world_render_init(void) +VG_STATIC void async_world_render_init( void *payload, u32 size ) { - vg_info( "Loading default world textures\n" ); - - vg_acquire_thread_sync(); - { - vg_tex2d_init( (vg_tex2d *[]){ &tex_terrain_noise }, 1 ); - - - vg_info( "Allocate uniform buffers\n" ); - for( int i=0; i<4; i++ ) - { - world_instance *world = &world_global.worlds[i]; - world->ubo_bind_point = i; + vg_info( "Allocate uniform buffers\n" ); + for( int i=0; i<4; i++ ){ + world_instance *world = &world_global.worlds[i]; + world->ubo_bind_point = i; + + glGenBuffers( 1, &world->ubo_lighting ); + glBindBuffer( GL_UNIFORM_BUFFER, world->ubo_lighting ); + glBufferData( GL_UNIFORM_BUFFER, sizeof(struct ub_world_lighting), + NULL, GL_DYNAMIC_DRAW ); + + glBindBufferBase( GL_UNIFORM_BUFFER, i, world->ubo_lighting ); + VG_CHECK_GL_ERR(); + } - glGenBuffers( 1, &world->ubo_lighting ); - glBindBuffer( GL_UNIFORM_BUFFER, world->ubo_lighting ); - glBufferData( GL_UNIFORM_BUFFER, sizeof(struct ub_world_lighting), - NULL, GL_DYNAMIC_DRAW ); + vg_info( "Allocate frame buffers\n" ); + for( int i=0; i<4; i++ ){ + world_instance *world = &world_global.worlds[i]; + struct framebuffer *fb = &world->heightmap; + + fb->display_name = NULL; + fb->link = NULL; + fb->fixed_w = 1024; + fb->fixed_h = 1024; + fb->resolution_div = 0; + + fb->attachments[0].display_name = NULL; + fb->attachments[0].purpose = k_framebuffer_attachment_type_texture; + fb->attachments[0].internalformat = GL_RG16F; + fb->attachments[0].format = GL_RG; + fb->attachments[0].type = GL_FLOAT; + fb->attachments[0].attachment = GL_COLOR_ATTACHMENT0; + + fb->attachments[1].purpose = k_framebuffer_attachment_type_none; + fb->attachments[2].purpose = k_framebuffer_attachment_type_none; + fb->attachments[3].purpose = k_framebuffer_attachment_type_none; + fb->attachments[4].purpose = k_framebuffer_attachment_type_none; + + render_fb_allocate( fb ); + } +} - glBindBufferBase( GL_UNIFORM_BUFFER, i, world->ubo_lighting ); - VG_CHECK_GL_ERR(); - } +VG_STATIC void world_render_init(void) +{ + vg_info( "Loading default world textures\n" ); - vg_info( "Allocate frame buffers\n" ); - for( int i=0; i<4; i++ ) - { - world_instance *world = &world_global.worlds[i]; - struct framebuffer *fb = &world->heightmap; - - fb->display_name = NULL; - fb->link = NULL; - fb->fixed_w = 1024; - fb->fixed_h = 1024; - fb->resolution_div = 0; - - fb->attachments[0].display_name = NULL; - fb->attachments[0].purpose = k_framebuffer_attachment_type_texture; - fb->attachments[0].internalformat = GL_RG16F; - fb->attachments[0].format = GL_RG; - fb->attachments[0].type = GL_FLOAT; - fb->attachments[0].attachment = GL_COLOR_ATTACHMENT0; - - fb->attachments[1].purpose = k_framebuffer_attachment_type_none; - fb->attachments[2].purpose = k_framebuffer_attachment_type_none; - fb->attachments[3].purpose = k_framebuffer_attachment_type_none; - fb->attachments[4].purpose = k_framebuffer_attachment_type_none; - - render_fb_allocate( fb ); - } - } - vg_release_thread_sync(); + vg_tex2d_load_qoi_async_file( "textures/garbage.qoi", + VG_TEX2D_NEAREST|VG_TEX2D_REPEAT, + &tex_terrain_noise ); + vg_async_item *call = vg_async_alloc(0); + vg_async_dispatch( call, async_world_render_init ); } VG_STATIC void world_link_lighting_ub( world_instance *world, GLuint shader ) @@ -106,7 +104,8 @@ VG_STATIC void render_world_depth( world_instance *world, camera *cam ); VG_STATIC void bind_terrain_noise(void) { - vg_tex2d_bind( &tex_terrain_noise, 0 ); + glActiveTexture( GL_TEXTURE0 ); + glBindTexture( GL_TEXTURE_2D, tex_terrain_noise ); } struct world_pass{ @@ -203,7 +202,8 @@ VG_STATIC void render_world_vb( world_instance *world, camera *cam ) world_bind_light_index( world, _shader_scene_vertex_blend.id, _uniform_scene_vertex_blend_uLightsIndex, 4 ); - vg_tex2d_bind( &tex_terrain_noise, 0 ); + glActiveTexture( GL_TEXTURE0 ); + glBindTexture( GL_TEXTURE_2D, tex_terrain_noise ); shader_scene_vertex_blend_uPv( cam->mtx.pv ); shader_scene_vertex_blend_uCamera( cam->transform[3] ); @@ -308,7 +308,8 @@ VG_STATIC void render_terrain( world_instance *world, camera *cam ) world_bind_light_index( world, _shader_scene_terrain.id, _uniform_scene_terrain_uLightsIndex, 4 ); - vg_tex2d_bind( &tex_terrain_noise, 0 ); + glActiveTexture( GL_TEXTURE0 ); + glBindTexture( GL_TEXTURE_2D, tex_terrain_noise ); shader_scene_terrain_uPv( cam->mtx.pv ); shader_scene_terrain_uCamera( cam->transform[3] ); @@ -360,7 +361,8 @@ VG_STATIC void render_sky( world_instance *world, camera *cam ) shader_model_sky_uTexGarbage(0); world_link_lighting_ub( world, _shader_model_sky.id ); - vg_tex2d_bind( &tex_terrain_noise, 0 ); + glActiveTexture( GL_TEXTURE0 ); + glBindTexture( GL_TEXTURE_2D, tex_terrain_noise ); glDepthMask( GL_FALSE ); glDisable( GL_DEPTH_TEST ); @@ -376,7 +378,6 @@ VG_STATIC void render_world_gates( world_instance *world, camera *cam, int layer_depth ) { float closest = INFINITY; - struct ent_gate *gate = NULL; for( u32 i=0; ient_gate); i++ ){ diff --git a/world_routes.h b/world_routes.h index 820501a..99edf26 100644 --- a/world_routes.h +++ b/world_routes.h @@ -228,8 +228,9 @@ VG_STATIC void world_routes_debug( world_instance *world ) } } -VG_STATIC void world_routes_place_curve( world_instance *world, - v4f h[3], v3f n0, v3f n2 ) +VG_STATIC +void world_routes_place_curve( world_instance *world, + v4f h[3], v3f n0, v3f n2, scene_context *scene ) { float t; v3f p, pd; @@ -313,18 +314,18 @@ VG_STATIC void world_routes_place_curve( world_instance *world, vb.uv[0] = t1; vb.uv[1] = 1.0f; - scene_push_vert( world->scene_lines, &va ); - scene_push_vert( world->scene_lines, &vb ); + scene_push_vert( scene, &va ); + scene_push_vert( scene, &vb ); if( last_valid ){ /* Connect them with triangles */ - scene_push_tri( world->scene_lines, (u32[3]){ + scene_push_tri( scene, (u32[3]){ last_valid+0-2, last_valid+1-2, last_valid+2-2} ); - scene_push_tri( world->scene_lines, (u32[3]){ + scene_push_tri( scene, (u32[3]){ last_valid+1-2, last_valid+3-2, last_valid+2-2} ); } - last_valid = world->scene_lines->vertex_count; + last_valid = scene->vertex_count; } else last_valid = 0; @@ -343,7 +344,9 @@ VG_STATIC void world_routes_place_curve( world_instance *world, } } -VG_STATIC void world_routes_create_mesh( world_instance *world, u32 route_id ) +VG_STATIC +void world_routes_create_mesh( world_instance *world, u32 route_id, + scene_context *sc ) { ent_route *route = mdl_arritm( &world->ent_route, route_id ); u32 last_valid = 0; @@ -448,14 +451,14 @@ VG_STATIC void world_routes_create_mesh( world_instance *world, u32 route_id ) v3_normalize( n0 ); v3_normalize( n2 ); - world_routes_place_curve( world, p, n0, n2 ); + world_routes_place_curve( world, p, n0, n2, sc ); /* --- */ v4_copy( p[2], p[0] ); } } - scene_copy_slice( world->scene_lines, &route->sm ); + scene_copy_slice( sc, &route->sm ); } /* @@ -464,7 +467,9 @@ VG_STATIC void world_routes_create_mesh( world_instance *world, u32 route_id ) VG_STATIC void world_routes_generate( world_instance *world ) { vg_info( "Generating route meshes\n" ); - world->scene_lines = scene_init( world->heap, 200000, 300000 ); + vg_async_item *call = scene_alloc_async( &world->scene_lines, + &world->mesh_route_lines, + 200000, 300000 ); for( u32 i=0; ient_gate); i++ ){ ent_gate *gate = mdl_arritm( &world->ent_gate, i ); @@ -506,15 +511,9 @@ VG_STATIC void world_routes_generate( world_instance *world ) } for( u32 i=0; ient_route); i++ ) - world_routes_create_mesh( world, i ); - - vg_acquire_thread_sync(); - { - scene_upload( world->scene_lines, &world->mesh_route_lines ); - } - vg_release_thread_sync(); - vg_linear_del( world->heap, world->scene_lines ); + world_routes_create_mesh( world, i, &world->scene_lines ); + vg_async_dispatch( call, async_scene_upload ); world_routes_clear( world ); } diff --git a/world_sfd.h b/world_sfd.h index 98d34b2..18789c7 100644 --- a/world_sfd.h +++ b/world_sfd.h @@ -9,9 +9,7 @@ #include "shaders/scene_scoretext.h" #include "shaders/scene_vertex_blend.h" -vg_tex2d tex_scoretext = { .path = "textures/scoretext.qoi", - .flags = VG_TEXTURE_CLAMP|VG_TEXTURE_NEAREST }; - +GLuint tex_scoretex; float sfd_encode_glyph( char c ) { int value = 0; @@ -101,7 +99,9 @@ VG_STATIC void sfd_render( world_instance *world, camera *cam, m4x3f transform ) _uniform_scene_scoretext_uLightsIndex, 4 ); bind_terrain_noise(); - vg_tex2d_bind( &tex_scoretext, 1 ); + + glActiveTexture( GL_TEXTURE1 ); + glBindTexture( GL_TEXTURE_2D, tex_scoretex ); m4x4f pvm_prev; m4x3_expand( transform, pvm_prev ); @@ -131,7 +131,8 @@ VG_STATIC void sfd_render( world_instance *world, camera *cam, m4x3f transform ) world_bind_light_index( world, _shader_scene_vertex_blend.id, _uniform_scene_vertex_blend_uLightsIndex, 4 ); bind_terrain_noise(); - vg_tex2d_bind( &tex_scoretext, 1 ); + glActiveTexture( GL_TEXTURE1 ); + glBindTexture( GL_TEXTURE_2D, tex_scoretex ); shader_scene_vertex_blend_uPv( cam->mtx.pv ); shader_scene_vertex_blend_uPvmPrev( pvm_prev ); @@ -163,9 +164,15 @@ VG_STATIC void world_sfd_init(void) mdl_context mscoreboard; mdl_open( &mscoreboard, "models/rs_scoretext.mdl", vg_mem.scratch ); mdl_load_metadata_block( &mscoreboard, vg_mem.scratch ); + mdl_async_load_glmesh( &mscoreboard, &world_global.sfd.mesh_base ); + mdl_load_mesh_block( &mscoreboard, vg_mem.scratch ); - scene *sc = scene_init( vg_mem.scratch, 3000, 8000 ); + scene_context *scene = &world_global.sfd.scene; + vg_async_item *call = scene_alloc_async( scene, + &world_global.sfd.mesh_display, + 3000, 8000 ); + mdl_mesh *m_backer = mdl_find_mesh( &mscoreboard, "backer" ), *m_card = mdl_find_mesh( &mscoreboard, "score_card" ); @@ -175,17 +182,15 @@ VG_STATIC void world_sfd_init(void) *sm_card = mdl_arritm( &mscoreboard.submeshs, m_card->submesh_start ); world_global.sfd.sm_base = *sm_backer; - mdl_close( &mscoreboard ); - m4x3f identity; m4x3_identity( identity ); for( int i=0;i<4;i++ ){ - u32 vert_start = sc->vertex_count; - scene_add_mdl_submesh( sc, &mscoreboard, sm_card, identity ); + u32 vert_start = scene->vertex_count; + scene_add_mdl_submesh( scene, &mscoreboard, sm_card, identity ); for( int j=0; jvertex_count; j++ ){ - scene_vert *vert = &sc->arrvertices[ vert_start+j ]; + scene_vert *vert = &scene->arrvertices[ vert_start+j ]; float const k_glyph_uvw = 1.0f/64.0f; vert->uv[0] -= k_glyph_uvw * (float)(i-1); @@ -193,13 +198,12 @@ VG_STATIC void world_sfd_init(void) } } - vg_acquire_thread_sync(); - { - scene_upload( sc, &world_global.sfd.mesh_display ); - mdl_unpack_glmesh( &mscoreboard, &world_global.sfd.mesh_base ); - vg_tex2d_init( (vg_tex2d *[]){ &tex_scoretext }, 1 ); - } - vg_release_thread_sync(); + vg_async_dispatch( call, async_scene_upload ); + vg_tex2d_load_qoi_async_file( "textures/scoretext.qoi", + VG_TEX2D_CLAMP|VG_TEX2D_NEAREST, + &tex_scoretex ); + + mdl_close( &mscoreboard ); int w = 27, h = 13; diff --git a/world_water.h b/world_water.h index 84558a2..14e3cd7 100644 --- a/world_water.h +++ b/world_water.h @@ -11,7 +11,7 @@ #include "shaders/scene_water_fast.h" #include "scene.h" -vg_tex2d tex_water_surf = { .path = "textures/water_surf.qoi" }; +VG_STATIC GLuint tex_water_surf; VG_STATIC void world_water_init(void) { @@ -19,11 +19,9 @@ VG_STATIC void world_water_init(void) shader_scene_water_register(); shader_scene_water_fast_register(); - vg_acquire_thread_sync(); - { - vg_tex2d_init( (vg_tex2d *[]){&tex_water_surf}, 1 ); - } - vg_release_thread_sync(); + vg_tex2d_load_qoi_async_file( "textures/water_surf.qoi", + VG_TEX2D_LINEAR|VG_TEX2D_REPEAT, + &tex_water_surf ); vg_success( "done\n" ); } @@ -135,9 +133,11 @@ VG_STATIC void render_water_surface( world_instance *world, camera *cam ) render_fb_bind_texture( gpipeline.fb_water_reflection, 0, 0 ); shader_scene_water_uTexMain( 0 ); - - vg_tex2d_bind( &tex_water_surf, 1 ); + + glActiveTexture( GL_TEXTURE1 ); + glBindTexture( GL_TEXTURE_2D, tex_water_surf ); shader_scene_water_uTexDudv( 1 ); + shader_scene_water_uInvRes( (v2f){ 1.0f / (float)vg.window_x, 1.0f / (float)vg.window_y }); @@ -185,8 +185,10 @@ VG_STATIC void render_water_surface( world_instance *world, camera *cam ) else if( vg.quality_profile == k_quality_profile_low ){ shader_scene_water_fast_use(); - vg_tex2d_bind( &tex_water_surf, 1 ); + glActiveTexture( GL_TEXTURE1 ); + glBindTexture( GL_TEXTURE_2D, tex_water_surf ); shader_scene_water_fast_uTexDudv( 1 ); + shader_scene_water_fast_uTime( world_global.time ); shader_scene_water_fast_uCamera( cam->transform[3] ); shader_scene_water_fast_uSurfaceY( world->water.height ); -- 2.25.1