From 12e9ca13a77341c7a6a39ac31092b2c2f74a9702 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Gon=C3=A7alves?= <73310001+KTSnowy@users.noreply.github.com> Date: Thu, 26 Oct 2023 17:47:00 -0300 Subject: [PATCH] [Update]: Merge our memory allocator (vhmalloc) implementation into main (plus refactoring). (#34) * [WIP]: Commit current allocator changes * Update allocator.c * [WIP}: Commit current allocator code * Update allocator.c * Update CASPAL.h * Update allocator.c * Update CASPAL.h * Update CASPAL.h * Update allocator.h * Update allocator.c * [Update]: Finish virtual heap allocator implementation * Update CASPAL.h * [Fix]: Remove unnecessary field initialization * [Refactor]: Simplify the allocator code further * [Update]: Add likely macro * [Update/Fix]: Fix value parameter in the likely macro (and add more braces) * [Update]: Improve likely macro, now using bool types (and casts) * [Update]: Add unlikely macro with bool types and casts * [Update]: Revert back to just likely * [WIP]: Commit unfinished refactoring (will need this later) * [Fix]: Use __attribute__((dllexport)) on Windows (visibility("default") doesn't work) * [WIP]: Commit benchmark code --- Libraries/Otterkit.Native/build/nativelib.dll | Bin 99328 -> 92672 bytes .../Otterkit.Native/build/nativelib.dylib | Bin 283416 -> 267104 bytes Libraries/Otterkit.Native/nativelib/CASPAL.h | 176 +++++---- .../Otterkit.Native/nativelib/allocator.c | 348 +++++++++++++++--- .../Otterkit.Native/nativelib/allocator.h | 92 ++++- .../Otterkit.Native/nativelib/compiling.md | 2 +- Libraries/Otterkit.Native/nativelib/memory.c | 10 +- .../Otterkit.Native/nativelib/u8casefold.c | 16 +- .../Otterkit.Native/nativelib/u8console.c | 2 +- .../Otterkit.Native/nativelib/u8convert.c | 107 ------ .../Otterkit.Runtime/Otterkit.Runtime.csproj | 2 +- src/Otterkit.cs | 37 ++ src/Otterkit.csproj | 2 +- 13 files changed, 531 insertions(+), 263 deletions(-) delete mode 100644 Libraries/Otterkit.Native/nativelib/u8convert.c diff --git a/Libraries/Otterkit.Native/build/nativelib.dll b/Libraries/Otterkit.Native/build/nativelib.dll index 92253c5c71a4502af6a64cfcc4e595c9c3fc7c1d..2d8203ad86525650a03ad341e21f6b372302fece 100644 GIT binary patch delta 46633 zcmcG1dt6ji_xG8BkwF<}PzUjXj0lP-ilT-h3JQ8qP%1BYhZNMjk$_@pgMsOIqO4tE zcdeeX%k!j97g4)_sNgM8D^V-4>mjVro)q(`dB5wNb=3I%-p~8jJ9XISyY|{^uf6u( zYp=b}nX!0No8r$bf$1}gB$FgbzPPl{4zZ zx!RfAOHu_W|I(?BE+Wj-$5baKn1&75k!+Ig1-(OxNs2T|QM$z>EwbH4s5D72ZNz1B zSdgPmk`hS^{wx}gqUOhYc74KZ9rna-P#w6a!kcR9oGwYq8nALfc0slzUGjhiLDFVi zABs`tu5&j<;5G|_+aeuzTLplLl2kb$PcN#e1@$B}OUn2ke2D{MV&>;Al%zOhOWTld zMmkqKY7QN=lM&T&+b0nf3|N`7bj5rLjYLKz@~uekdG~8`nCS_hO!u_ua>=F0;)K&P zkX5);-f&p{Sd#$ZvOVRpT=q0oBr6Gnhnu89hm$HKmn0?ap^Cg`WQ*5pl4LaSFR$#e zltYN@8M+n8Uh6|HtHvHf>|`;pdn~2MJ7mehUz1#NAksZ=Zgnnw2G~POwR#PO#)3sE z%(+dQo0_~4_y5$SJxW6pJCgsKCO0yniQDoe5=|9oVh>H0q-oRdhDltq=Tmw8byKk< z~*;;O@`lQS z;r89KZ*IJ`aH4&8Mw_M?a@jP;?N)KaEY9|p1d}>H4^SisvJ$TWzS_bn|c9a zX38E2WLX98m)&OqvoDF1?e84P^%Phg$g~oWO;uDr*DIR~{O!8~b3GZ>CVOs8BKlpf zffTZ`?5TzIU9;x7=T;9o+;sWxU63?Qw?QP?K(QR04wZ)2u5!pemMZPO+5XV$ut%z= zIdy#l^?j0kccL}d)28H5Gj8QJp5{TPa<5&^P4XmKDbMV!qkfhCeFV56!eBU8-3UR!R9<6mpQYjMrG|0nA2-7{TzkUhS%6jPvRywDPFQ~ zsKH%|{e!%=_><8Nf8+rC$+RWmuDz@{J3~O4r&+FQXp`poO|JSjAkA||uKKZ!Y`T!< zHl5Ik9nw5s$W=cC$fmE;JV(KW?BCK%=jED1e|f!L`Sc;V=X>WcsHK7hvhv6u)`y^o zsSfj{AP;!IRqLt41#2fL$ycoCvqFblQ%OaWJ(uOvm2yw>UYba0o+?bCM05d0KiNNN zuI!EYekkdfj7Dly5UX!iVt@Cn?76+d!YxLHY4&#yBhRS3uvDuY)Vc{C)4_h#@uUiSE**|QSJ%7km-?T|HU6Ga2lbQ+i998zTz~Hbn862jpPBS%u z=Pa3xOSce@yQ%?}zp7jQP?|@jZjw#SX(rV4b`{xM_WUAW`-1BGADrIoGqeP2#3CZId_M*DiUJdvQSWrZu+YP1)`BIT<-?&b+xvvyZq%!6bmYR|+yPpyUCTw2k%eC3w%a%OgWmWjx*U`KG1)UaT;y50 zx(8b%skG8wS_@mK2jR&!*KbM=PfXlxDoLoCgZXOTa1dEFmR$feeboh6OiC*YCaW9a zRn&j`;LlrF||z}cPUD4Id<$Awa`inTukET>x$(cvrW*)ZHujxmD%Bmm}@cfs=c)y%Ol88 z--2|l;jWT|H$gBL-l4t@%c%QNm%7JKl1d_;09}HT`@kD}Dsl4(wI|fQTHoz_$+sr; z4R9;fO)uMsSyH`#Tech%-7R4Q{)PJ{i|R&V|Dcj)d3CB%M`>d(bVvGzO8Zmr+kpMi zMZ)SA8B;OKB)R=!D;s}-u(C1Uk`~kI6u9FCL?Yy0+SVk8$53xHb;1&|(Im3`g3Tkn z;(ouxv8x~xtP6G4g7&aj>?xSb>s+uAHt-f$O1wUWi6ARyKvs`{U#a&%AQqdxC>gz5 z{OQ-#rzgaAwdT5mr^?DDvLmwIMhGMC8~pNx=x6#tllbbw0=Xo|fnH5_c%45`|0^jD z*^|=jb>;ynmGU6EpRM1Qr3dSH$Ux+!1fv-FW|tg```DCbIkrmP0~_E2>Ae7AUlv}g z!`+waMZaahe;|8Zj1btO14PD8=9lcF0`c2lR~ggD|=&K52#xo%p0uNnajpN^M&Cs zVi;Ba6^x}VVr8}{!pAjSFaUbQ=Gs?SQr;(9)_Q-lyDgWo!VW~2{DG7(rGP#tcgS)a zz+~vK2Q^9R7}PFCwG9i|g2{tQf=X_f3InwtR zUg{~`$~3#FPh&L^1%B#-n59i!)LwsLB-g5mcCATdHa}H#Vk<<#Tqxs(VbNX(+A5K% zH0>^6OsFdZG<_`UI@}OBTPuLdBbd~tp zmijWtOeDq2EPJM5z?DSonI?7yg!#1TXA++WxcZckaLfm;yW2+jd=X_5b8G|6mn`B@o69E*aF?w|`}I*MSe6!^=ykpZ(pR>auKO_2 z7&K3 z_U_SfAS8N11|T7y5J@h*AUpjfqneW_r`3v z+DT*vHi(7}3*6h*LWPn8GSwt|zu|fBbp}U(4zV3&C72ekqVCj()iNg8&*0Z4q&ARF zBZFsn2lXnZnKqCtSR4N~kV+31wpBx+s`?WO+#F0p^=aVOYKY$fjM|OaqE+aD;fX zQvr&EIzPeR3(f^?y9@^_IEJK)^q>tOo(@WJV}$QYK>IzG&6r?2O`35qYhd#A>9F51 zEReV_qx(wS8_gk3P1hyx*-X@(q^yKoxPvoOZrL#~nxL>D?ymsh_}F^dWPRDf)WGu5|JoD-m0;QN?{nf$wAHPaf_93Qz*Dv z4T)D=H+dAxsR{5&$KYg=$}-H2$1w6^PsJWiE*oQN`~-jmdu;z8Chn4w1>td0T3K>< zoN^Z0%=9x!v4_3RyL#Z@1S21IO$)~!**W1F?Kh_MfUQ8bDo4G}&Z_{lY;2(5jNS<$ zLu#`^7p|ODFN_pT(XJl5C`+kTP9wO02n>MvSP4kTK;#H#bd1j{AtoV5kM{i@VT@3s z<1)X3z9s9hS8GS!Aq$c-=2WBP&tSMY4$c-Q#H7Nk_6;wAU7P9~E!{wo6_aA!aJX;? zqMdyR>6O}&i=(lVye5ms`ge90fTPUT0>-8QETDxpAT!LO&Vif8-pmI9Yhg#U`{!Vd z^AHl%gq0YipLEiBBK<;>KpAT#_V$M?Psnr-p^SAL(#|6=c2z4*jBduUX`Zxj7lK() zHmRK}xSLkh3AHn9u|;X8_5y+0N-oefuUdQ-(>I|B6QXQhkSAE}i9;CWMk987k~%z` zGzr0;1{)Y(P-NvaR=86sbT@S4UC`MRl699DF(^9rPGqMk>k@TGC@WLtRON(v9_FIJ z97}hwIv17f!y1RKM@3H#5YG+@P4xmNmHcHY3{p}Oy|obd6-0R~C-67+aMNPBY-*hB zSr^3feMT?iwgEhmQ4M6GaBJv>7N~9Xe7JPYQN_=;WTOrkJ}0U3Ul+=zgp7 zjy1w0+I%CAQ)YAGEK_}wj9z97r2ALtUeW3A>Gvkkp-W_=mS^mHT(Mqxc*5snO;Ukx zY-N+Ie(Z)

&~5d94F2B`3U1eW)LHk|1=cM!{~>vKz&aY(;|ck<*vT998Ea{hPMB zTlAOXZ4XmD7PS`%f+}$OxAN}M^ZYOk^i1(-tSjhhBv6^#Dl2|e^(Cs{n@Ev2$ti}< z3=n4rk2ePl6=AW1CY&8Y)oW*J5$VbyS^1n6)iW4)v4>GoPW6mVEvd1pA&{8n^Lx`< zB&r1_rpOVrCLdY(4flWc5ii8{_iX}6B+c(E{?oU=d8tW+MU62pF^Sx$H1nxW@4go` zz|{F(4A=)8O%6r&P4mdsR0YA;xO+|FdcSZN`O_Z*Nu$JI&8K;t0pM?vRE$ncS@HA1 zfgEn|&{&nhw(c-1xuI~9D$DUF@B&q1#82C@+ zgx4A4AZ`o^@_vW{FwFA@WEw*=a1-=YBaT)tY^sXdMcY6cXuIoO~WZEVE8S*dllwo2{k7|IP zq3*GEM+dpz$yA?OyCXTUSuSaGq?V|Tt5tS7ML8^&Tx_;GkmnniWDoSmrZ=r$Wx7(E ziu3J)`|N#9O+mT2;@i+Cy874y9ri#ij>EA7PQ74yq>Zz>iGFdR?XUL6B0!@TOF&e2 zkr~&&%ZEe?1F7i%_eAV@49SRLBD+h+fJ8jRz-S2cS_TXg#a+TDT8Cl!guuXOut<52 z%4Gr1;i~mIH?{$`(b9#;`GOIPVIZyzw_;aQjB+UD(E>L(QOmDA#F??Z-LIp7thA%^ zS%*x$k04_fM9C$+a8;wIC7g=J*B92`6sq@iTA6L#Gvrs&$}D-ff!3EBFux)(@n{IQ zqbY$?h6Qs?deopz5o56zAoss z3lKE*e+qi^HbHweIXBPIT(WWwtt*891UEBR zuqN34{x&9Y-=t2$zn3FEmWo4;C5#l&1l1y9+tUGp)HgAxmDBKa%z)I22(whFQL4o#M@UasvT{AGY-rFvoB%2pQx!E$ z`Dvo^$X{DlQw-s3-%ZqyN^mz*tPC&JUXH(DFMS(zG`@^K>B@Uov(90h(!m~%qOG)0 z%=ZDWzOqmDI$to;S}?tEOj+hmFePLAS?1h!1Dd`yOq+jwb<#SJ=os)Ro!Sw506s44 z=tG+sr5<6^d1yLxFIt3oXu}~*>c-Nmq*_xCY-+s8)c8yG z4Fg~fw93>KUi>^YXacs?8gCEiNhJp(RQje1PS+FBz9cQ|?ssz3<|9}G?pG_HK9L&x$Ha{vf?3>|*w;^UJ--hk*W(WV zuh)yZ;Ck91w)a+-+-Se@G!E_PR1G$iv|~I(-#iOL8e&lmd8XF~{oOOIfMfRBs*wG6 z&osXZo~sxIR-phnF--A^;HBkrepL=<&b*bm8m8j4-0S=aoUjD~uRKV;wSkYw0>pMv z-ykCryojl$_Qx3WSpJ3W1lD}*Fv_V`&>U#EyNCNhB5TY15U`clmI2?k%u|qfYbp0S z`=DmUmI@}No{EL4DJaH47u*ag$dAQZ-jt`u2Ul@*u~mTkc+78grB;yi57zb1)+#zm`X5!_L;ci% z;nV<(bxaEFtQNbvHl%3lNXqMc>n}3f@t|AgKiu+vGym)0(zO2tEUnB>`+mi?A;>iO zcJm(sBh+~dL91^5_qCFw{wxSX17Fo@WAk4_M}mE=7UOE>w|T|(ySpvmSz&Xa5ZO0M zZLgKn>>HxkTAZ4&B#n4fU5pVy<_IA{Hv=jx%3bw`?AYdyW0pS(`go|r)&@GUmhTj53YUi84Q%rNn z?-s7a#8R)}osfah)Ww>jMbPv$u!7hCVhhy&P9t6>ifT+(q{5kmpRB+% z>o*~<*(+hwnFhMJlpY>t)fvVk8*>U_2{yd`>RcS7)3HJuVvCy8+qV*fTRcB0Ea=k? zdIz*on{C+Yfag`pf+%+uZcvv!_7sWu7=D(rbG2!4a~*|E^)aMBBHfAfDnp-?nPa5YcZ!nD~5rPxGhO zMa%eM_Ghtgj8AZ318<+4&?QDB$l;D&*R{njN>&bH0sp?AxKCbfUfNImBu_P$wTPtD zPUe9vVtQ)4`JRE|$<&c<+QxdF%P}e7mS4idC9iX_4xRsUquJ?86MjH zoEFm9<+AAx)jV8G86Go|>=`_D+VrF;c=|sriFS2~h@$7ThX%0+@aP!ZDdmd#IJx8V zN(;^pOYg>gT3Pgw4nkct$o$S#(QR>D^fS<>@f(^sWmCdkv@Og3ovdsxJ%Ikih$x#B zj8h~qsNb9v#fwWqmSHe9;mpS}n{F`nEEDMlBh@lulW^VJ+3eq648J!dusWC7ivc*xxwh2N6cz&EMlO8t~E_L%x(A2D%B z$P8`pB`Rl0B^;=!PhyysL{vpVvyvNs6?Ukx{2TW`=;Zf)gG6V^jXw)J)mWapNsa&+ zAyMa&8~>%_q2%z$8q2yU5i&o+Jo$uJF~6s|e>?HS{4~3^M~3+j<0_V?I*7*?_A(b; z79T8(?D$Yy7#IhjG33lF>Ps-6xV$jLJmRu&Eb3-Sx`@dmDsm$HL($uCpw_>{4>@7x z{^6o+Zdu$jn3hTlt;i8-H2h|b6a4k9A9jeyg#(hz=vlDZOVd#)oF%#*5rVB724~|4kn~jx&vpwiX5_NB z!;5KdufJ66hkjQq9j)TG`4Q$?%++$LHaTX2W@czroz2N65ws%4JQl~#E5=ju_=;d0 zzT*U9LAXmwi9M`E((rEYLOT@2QK9A}_*lnZtE<3I+n62itDmy&?d&Vz2wpa+U9~|N z-b8xTYGm>zh$inuIn5JtSK!?p>J0~;a>(n&(h=4<0kjXG`MaS3eVl}I#w*HMTCXi? zb|pNnHu&?BDzE{Q)X*B8l8y&nbzoQ9gCOHvKab|Wj8z4XN>fl*a(IT<`FN8!IU>ls zzDYEW7;c`{B*NqGnEBC96fY<(US}++iRote0WOLuJW76z2u@D})Ca4!9X`k{=p zk})a&3?X0ge0Vd)f2uMoGF8csNmahZ5iU+}G4y_SiTC5feSiH49_*|5z60*Z;!NF` zC@V{$8BTjLU=zH?fo;HCc$Z}5Xp(XyO{qzXb*^%WAtR&Ruft#7Ty(HIS8*h(?KV1T zdk+Z`5kdJ?(3HPUhblrT`fiC>^M{U4{oS-oIC_NE~4fzd2Mm~KMxfhXpGsJ`9 z7b(YM`zDkQr#!ZAb@&|;k(t-mpTb+}%xdvw-db~1qlmmOGNyhdh*cMTWuMw6|KXXw zbkb1ikmIWgufUJNk{#5Ku-WDbapi_6zR#Jm56?v42g?%Pq#JZp!Y;b;!_5}l$R)3a z7o%lTO6k>tcKX?2+7DVw?jREUmnFt4&fS+jD;}H}txnV6F z49*|!BMlpTQ+-m<4YmvSiCHUqnjiT~Jh(D=#Iy8z1ReU*Y2c$c#-dVP)IKCO!+{O9 zatQmov{BfsdFz_mYXm%1i63PWbt_%&?@$~LvB)DknqDE*tYwpY)F@DOt&1=y|Hs3S zORiM-*0$=8-|3xm`cKSN?i_oF);Wq@{T{j0Ik(S$8eM;OM+ZZN7f>onIU>h8FM&c` zd-{mH;S@hV2E#fqz)ff@hr5eA^SjulCD5jAm#OhE>?1~xciyoRH|jwAK~MEm#&)Vw z+wCyX^WURtG=dwrkiC7hOgf79!7~O70PHhG^|*NZ7YI|7+GKLuU#ROMg>8JSSTIiZ zC7EL9xGs1(O@I2MH8>U95;S@qxjakCU9KE5Hg+~}d1I|!Z4n$BTw+C=?J8m&NvuwZ z3@rRcH_=IopyylmcNIHRUh01l3yrKiA6^VL=#xbcPq0y`ih-N4eM4?Wzfb)ZVxF7U z#o|&dXS;|&5xv~+VcV^a$3Vsd7VJR@{o{8?8y@m9?h6O*wL+#Rp$vd_bRh<3DRDla za~2V&1-57^l$9pAY^WEr3kMAiNK(rt#lU~=-G*3LefLY!(;|Z(G28Y|m`A50vS;a` zq#B4tTs<}js$lbFtD()Q63|XvuI(W#yLAlTT@~YXZf~HL;smhdMsVRtux~}S`q+OU zza&DzJ=uZ!<@A&Ycg9z+?Aq`cQ-MW$JIC0>Q8cG^hDB*w`Xhkb2Zft_F<)KUwAS*k zk!?BuB_lsv&%gPEM!Bw@xQ%c1O+HVY`aulkl!eR#k@l~?a#sZ|(5H4@f1 zikUP6z-c!6Ve=uX)H@+rt%Dau!lUf+RMQej_DRdEA)I7m38qtqi{~0 z{9p0F^zOF8W=*iH99K8nwNksMk2Jr~R{TDFX22ROmioidcbdhl%)#dQgT-T+yUZ<> zV$6(*=8_ok*oX%ppJZ>Ln38Yh;)VFHZv}3=7NKmryl2@l~WBYu$5L-Fiu^niXnZeMyufS^2Z5 znAO{7f3qYm&KhP;iWOaE-*3L&AfB4t-#qc8sGgl|_B|td&$-j=Y!GYa^foW66Wix( zvVYr1qibrNwhsRBxrm!Pa9lR@Osb%ntNsOV)zrRt-BzgpPrpv6n~9xHVxIb3l8V>W zN_41^zEfQZIytT~7e)jv>Xx?RpL0WnW2#d$&g<^;%FmLpX7%X!1d5?icw4a;cd*Ub z|A^sPvF6CH#qzAa=5?QnXR?x>LJd~O*60lP4t;Js+*T` z=GW=NtnFu-wE4fG=X?Anisy|q?=Xpv=S6i;PU>&wYH?U2jaQMoB+Q)rrP#b=nn<4C zNhB^0>3)<=y>i{zZm3BnCz~ zMVF;B%;!#tf~EiTtv;pC6-%PmIsBwZS+?9f$49)sY_#*g-+H}GKB>x8J_&*iL+XV8 z@?P%7=@_H8M<z8*C#V!A3@1LM_Hrz5TgCH$1k}rYd~(9VfLX#(X?O zht&T>X>H0t(lfdwGfC>x>`q)ZWFYO1d;I|XofE6WxRNz zo~54p`!k5mx5@cHlXGjou0J}6gaGZte=jv3 zz24N4Pj4N&rz)l1oo-R-ig0groA4S34wKrY#(!kyw3tHYbedBx7 zsyh?=i#7Sq#11&v1WyF{lPJVQxW^9K=7Z%0i$d%vuX78F`3x&U8a$3MFZ2~bY##o! z7q+TK5;loPQk9eHrv? zTVb;esTFt_~GDA4xYWjl%m#oNrGUT*N=Nz}%>c?T?M{{|C(-E!a+M+eu`U zbuhoyC>E4O$zNzeh0+3v>N&jEAS;SW4ZzkgsARZQ7^uE?8^-}?2#yBge*QN4mM_H@ zWnu26ItlT<^hq&E>32fS)M;8!0hp>om>Vzl>h~_XhtV<7-^Fy6D8R@419)%B^7N0m z9X`Ifper5BL8%U;lub2jMcb=?oQEGOajOyqnPT;$Hgm&y@$jROjt`K5jV4NThnVMQ ziH{!*Ytt3C1+zqt$3or6h|$kq%Piw(p%T2mg#&@k%6dF$BOh&34`}8%st(cWpm>On zthF-@bsd6nxvXLflvOtEz${iQFGJf6wG@MfV)7LB*C*wZhqS2E*?`k+iUK21q8H|j zo-2?`GY#L*C=}y_{#jM9lBp zWLCdBCqCX3F8;OA+P()BxEJ~%D(!Gx9M~9c&g(0F+8E`+Mhw%>7hkGLYl-wCrVmmr zw?uUPUJTjPQzW(RC_dcaZx-K+nhkx;BP+#~4WrGXUc^2ucT72eHkH)Ka{OO~zfim4 z>cyiE4{l$H^jEJYMQk|pf@=CA&2?^ow%aL z=h!h=x}&=4chUX1-aX7OdA%vhiDVoXMIzkMwBCyWhPO7<5zQj&xnT2``^Ejwb?x=# z=U#8|x?t^ny%ecr8;z(xDW*tw$+5@PY&yW){alE+^kPr*jU&ST(gfc=kR#^2)JJ^w zT$p*)S<&)bgxMY;LZ44Czxs=q`}{a_T)24c`A~E0Z=&Y;5oYht!smrJ^WuFX;e~1D zzdx>)|bT^x?K;Q17(~Eu03-^lAFGeRd!}rl?XJM9HHnDmA@UIYE;skB# zDMV@*u~!T5F36-?^aRi~b*-fCX#~jPpDzyU`1?r=(`|5snqS;#NxCYD5v%(6Q_tuQ z>Epug?qMI%6e$aN=yy=dhCW9fKpl)hznVxG^j+lPu{24(ph5B`tRd4$RJFC~3+(VZ zpgf<6;B^_u#c_zSfMd(lk7Ow4ilUol|mwaWc+Rg3Ulb4O?htb)Nq-c2v2-U0jR`(%2@ZbVU6_mg<8w1wVb zpASC+S5Sq*Z6Ga+q z)TQ@UuwfE+Q>&3hRX=x&rS61oBW1Rz>KPmTidEL}&OuvdHLJU3=j^5szzl~O2RlExILH7EGSO?|BC znAh3-t~j?Y!FLaiQ$@E2L(E&=6(b%D3-}B}nARG_GV`cd>UNo}KZr-&SfL-BY>s_T zcpvQA<(+?H(BSb8R*gr(6FY$)TgR6X2#ECJt|HCdDWJ}22$^<76XN?lglskkzY76Q zF|gRu<;h+Di;#_2)gdG{U?)k{v>0|+JW}j3fA_8USMfIUJztBA^@HNyL1Bc{!9E4y ziSfU$JdPpTuf{VLZ@>K2I0VtL*BOBkO$Rp!b{+}OVjY7KiHi@{htOO5h}qx)+F+{k zDR2A%ZF)EPC`rK_SZilX8{eUkIECJL)TbicFYasABiPN-GbsRljnN(y=--0Wo=WV| zHuoE`huyLdi-83179JmR`UkwPP_Rs%e*-o?@dMha1hkMg=B6o163#MhILoBX!n=Cj zb@gF%2@Ne@Z!*>@#qz9CNIPXK{TGR_Z7{ft_LEwcLc%5CEf@w(8+A>(LKEogk^{7J zeO|tV7~jj>d%vg{AJP|gp|H-T?mceI(55kPw*%sB8Q;U*_C`2|%~tY7asMNs3m>@2 zr0zte+G!T{BZ{Rx>b|uv(I0r?;Z=q&X=>?y2njtgDGhgkg7>k~mF6_1k!;WvhrtC- zwWlUobEebwKk@i;K6m1Uv=<*=>vIY(nT0$t+~;YeGoBdXGXv?i?j(ZPyXm* z5?0Z}=Md7qVrH+!cshfD@_kbed#IG!@0Zm0pI0G-$Lf9@p4sb61>bApAHKW3#>klb z&l}_scIz(i^yT;@XYtV_XMu9m91R*Ew7lajCd|#dQ_e zpSXNq!p~RWT83*aE(O=KxL(8cZ(JYaI)dv9T;JgO1=k-lZcIO!GK zyoqZUt_obA;5vlsIIhodoyYYJu0~wVxUS*)3zua(4aQ5E=>4xg5(!VO54!g(Mrp}` zOnf=FvZ+yh0P_Qu6+52k5jhDHk>_N|9vW6nSrqjCi1WbwEA(AncuALf>7U}4XQsu| z6s3XFMLmT0n~UA3AmQ4ve)qJYLfv4Dr+yl6h+PJ9Owj-I5Rw2G91iRRgOkX>+xxui}U zEg0vHucNB$8zy4Jsr#{cFFB0HVOuOUCV(V+qI1q+L93*3ltoYI7SUkJL;Er)B;^P( zlAnHFe_3;vR&rKK?eV^dNWMUEbp}SB_Ea5D6+VJe^dvG8L(u95A)N?{ zvHXdXD1SUOt+8Cg9ZG{{LJr+&N15`HN=UI?N3KFH)6>ZW7&RM}outa>Y=F8qHlQ$3&;>(qE2$Xwt%4D6A2TG<+Nzf@p zpiI&!{WOYFOlFO@CF#T6BMCSw&;{BP&_*2L86eY#gDIqyDyR+WfS9+&s8`IsjSd~ zC8um+o?5GAD0N8i_;Ig}@XC}_HuZ-37C}Wx1XS%>4T? zUV2G_LZMn5Un3-c@wnKsqko`wgbvN{(m5>+U3^91wwKIBJ|bv)sriWt@%;9g=BLe~ zWxFdp*Km#M7{ng%*`eCkDz(EBDjlOf=qs9c1V`{*6mE&%EjmlfOb@jZiv%w-zrQX1 zT;0uG-v)c1i)z*T+J^b4>OkA@HZENIUXZYxtiAm}kF8Y=*jGzi2txj z)kDA$YUg*UUykDIJ<<9DA+?JNfwk(Rn(Aw`?~ipHf%!^HAfBb%{T3N=ek6MKs5%B} zQHXx)+)gu7qCB6?^p9<#@3wf6*DI>`;D_Of>(p6D;5cNsZk#oDNTQyXR3}l%OB1XA zHybq8b`Oi+dPSMv*&ss0V`i=ck>0UNgplppy)J|$%q0^0dBi>R65Op9;Ib)xrEn07 zQ%dZqw6c)hrzu`SpqVgq$-CR%D>Au%gC+FkPg~YeQw;4n4j?k41{Ohh;?1uk@`+3$ z)`GDg&|w5d%wL5As6%7$z`zG7Uh1^HUWP3%zI97)V9-Rwv!nw8s$gM3DH>(=r>eE5 z(22g}a>ddQquoc}CkMOkDVVk%1N2_6Gw?|Y&f65u!{YEy$GdN(Y(tP!5=xNP{gCy2HjTI z@h7M*^pLTN^2v}>eFZMC#D$jtkn#ypfqp_1c;wazk>!xMUNojVB76x)AA`9}+nZ(7 z(XWf~uZ481J4*eCiRv4BzG)`xyZWG5{aUZ2XF=BVl7P_PCzz=~SrV zacx4s>2=P9u1Y=fzS8o}U>0{gD9*p;GJAH3KVR!C;wA-(^di4WUt$li<$pPV+HnB3 zY<&Rbul|l_-*{E9z1jdzb^9sPhmfOGi#D%Eb-g`yr*Jga?k>Pr3=>X&D&~F=8gyYI zeul&zspi_JM8Bfl4~%|pq7Wa1xoZHg*k?yfP9v6qL(d?!m)67Yf;pmZIt6sKaxcp} z;7jXet3Z-^@?xq_RjzDbUW*bD2dTtE7hqz!O6{L(Z*q3jWHs5^Aw^VJ0Dp}tj$BEy z&j_f39w%{CAtOE=8%7+(gxn2Aq_%EaI^*0G`-~&F_JgnCiaj%=mqyRDHEGJu08Qhm zrMznzEtB}a1U?Em(ergaTQ@!Z1+_P#c84#%R^j|&idI>t{osr+_nj!--#xH*u*Nyt z;?kwnp=L;*3#pEX?z(o-L()Xsim)*aI!knmF8m}a{sz}6Ty*~via6I!pgJ-cechd+c`r^9X}z<`B5s^Wc!1tKL7I}x%NMz&m;FY`wzc2 zUdFLe?v}zHkY*bOHvC-13Mio7Lq1wIo{dp%oSr+Ca+4`H>h@=67Jp>pHF#URrCG+^ zr*b<>=TvdWo+$SX;Ddks@Y})b=c7NN`|AUvcO$izCc#}EJo)R-pd7S6{4E9tc$`hd zb7OWyJ|rS%=nbUy(ns}N+gF-|^C90;dNKbu)4_|M9X@dJ`h&Fx&z_GMh<2e&#E(?w zAsl*0_#H2`|G~y4=TH)Nxycrd6ocgHnSj5|K60QcAEO6^94h+TjH-h-93g9n_l6@n z3F(1vF250y$v4rzqFPv^L8A`V*k%Bn+*5ntn~QsnL4a+xroSWlNu&q9IUM@dtufN! zE*>KXn=(H~-X2SqEFRn&l(Ldu4BH3eA?*B&h>t1#c7{d6-_8hmalCNt z3+Z)&$W61IHI$yrKQ-iF<9TNkf$Nd`51#xZdXg-%_64gpzV!2Mx0MzB zKALE|@(XL4YmsPYGmcrpUionB8O#xTc{z~T}tZi_H^cZyU zT%1qu=|;m$doM9v-=D=*iyf5{(#~NQm)|MZKEP6syH#zk$oA-3{E4cf=#F-E_>G1F zXIau;_^prC!RnRQ$PtG@T2njqdkyp?(X>##+rBE^WGa7m!v0aFP9K6w3xB!;kFf9~ z7+&We8^rU~Z;PS>(>j0k59Ag^T&+qhaH*GXAPnqz$Wr?c@%@2;u~et}3TQa=*Tg~( z{dEdNS?XrW_;z%=YItUf%o{x*h}VzAr`(I3V^8DX zy$h5rS|+~ZZ1C&M@tI=K(U1vW}JvDOpMDUOLX6WmJ)Z z&@|JkE+?WVGg2Lt2eCCNE;LM1QfQn-&cR!78OMX7?p%Mn4%*LSsM!l{X>n@>6JH(g zwdkf&doY5?vS>zg@$DkC7oPQuGk?p7#dng4z3Ok&;&pj=G^oD@`Z{vB^SWG$|+|3W;^Oot9bb5!Fbo>x(?qklb zP43(CVX_#V!TzFn=lCG^t>*s!zoXu`{ex{-xlgibnopLgxcts2le676Q!%`@os#ttuGO zN?v3u+#eV(PU%O7q;gy<0cox9NXE2(qEC3M{ESvOxD{@0rSNAVCimY=@?9&2m{tOk z85+uFAd9gvW{Q~~Pvf+YJEj#wE&G8E%&>`Zcg9E+#$l?8TXfekFc#dsSR2xXkfxHsdxR^<~J+d03smB}j^ zTeN)4zeqNTQD7$vU=5|6T)=QlMeGNRF34d1_FQ3oD}`DZ8y2u~10sl@=6@vuBvFk?f09Ak_zt$rzk35JPOwn!JQuyqBkJzZ-@)q0+{_6xThm0rIT z!+m5-6PYdGWCaq(=%ct{w4N^Fv^hz~#hjnPxFJ!eyExs({M#63aT+seEDPYY!KjFF z1{cInKx&>cc#xiM=$yhv@01C_PoVo8$WFcuQYB-NtDKr&*lFak>+!wxky^p@l2j$raS~ z*9A4R;7Ws!6^n_{^Xmrdsnwt}e=sYU$@1zWb-qeYiwE-HNEYEN{TNv}g;+7UM!HB6< z7HEX9wVZGGX%}M~H4>j@#>UFDmCG9|T?1ow9#So1-EU(Y$FRnRCy`lTM_s;D%-Dz~ z5*ZtAvxspJ^H*>M!HnZL-|+KWIA2@YXdVSKgRydKV{9xGF^q3U8!Vs)S5U|Kp^PQQ zF2*g)-;=SG8%#?l)h})30!A<(F@v#I=W)KVR@bpWBRbi{xDQuQ$+$1$IF?6iF?}jn z9@cuTekqR&^w;yHEXL7{cQ77kU=}cpaRcK!7)Nr2af~xKe>mex#-q4?sh%qs%?vx4 zA(8PS&QD@o#CR;@OvcHKcQPKw*u@HsXS|K`Q}y;^DPx8S%%HLY6B%bQp2XO}crxQ) zE}y|Tlk=xB-o$u1<8AD@+&IqFKK1Nkau_GF>oOFa%@xqU<3XQ_QS3JiJW|I#j3asd z^<`|V!xqNsP>tU$wJ{jtbpd{iHznxUYG4+KmkqR!;S1X_wz2{NjJGnsjd3K)Z*O4D zk)e5ZCe*WMqj$yVvx#vaVd42G9J&^-NG8B zGNFhWCNN&acp~Fq#%YY>7*AqsWjvYjCdL_zRj%(Y9lNDqHt{rO2<9;`ow3XUW*Yh2 z!W_o6jF&Lp!4)iJoXPUnGp=9@)6X|+>rXvb=*uBW1y`v3uq{{?aToY=ek2QQ%eaUY z2w=RGyU4*<=JFjG@8JASglYa;S>qsP$mBuO)hNJy9KyJsM|FS3J2{+u)euxP%!Z4TU&p%VZP#GTy}eevE?+g&12$>(ja|;~ktIz&Ml3cXep(hYRKc@rFR| z5)%h~^*m^N8E0}n{YXE3YS}{mjCU}9TLT*wVQgiEy1JQA$$cEpxP>(|aTKYt3H=#o zvW40*uIKy!19N^?0~_)g%iI9BiKEPVCipWhGDbP$O`PAAaf8u^jDw9Xb7=;V>Uq%l zGgcY5HS+Zax}|u7flX)%*9FwF1^gMu845Ap$_m9ZZZXP7>g6MO%+OCo)2GGg62@_w z!svfff1P2GVFAXnF{&BYavz#vbbhPRC5$(5g>4zP7#10#^Y1VeVjM>er196*AQ&x( z(+gCvfVPaSEWk8U&o5#NwPhS<KqBKVk6m{`_+z{x9YVPccI z&YwP3uFuV5L6Z3lWu2Zc$y~v119SXuoD@iSyrOT*Moiw;1ai9N6F3)47;I zVTLWNfFI*H9#qB_Z4u{NIe#0Mf5oVPEpVLiCLR-SGp-CA6Y6=;oMxv&py z#W;(*5MO}MK07)8h=I90-YC>Q+oC!CuVO+TTi`RsJ6Pja8M_$&lW{E%+6xBe2H-tM z?bFN(H89TPF4)I-ORQTTwVyJfg)6woSmi!E&)CW){n`+~`DYnNa+e)qY@C$zVvJuN z)=s#MUG@&+(U@^GvXvEB$_0$06XU2Qm`%8d^J{q!wq=~iV<3%j2Imi8yoI|YpRwD; z4DFa8aTh$vxQI>m560WLf`2iVS)p{si`YUR82K#kL&lr9zEL`MOBLMWP0U~%jTmP+ z!Q97&r)*{c0nDGleQcbJ7-u`iSy2&}FJS&)F0Thdkh+yy_zp8fa*K?Uk*z!nY@EM^ zTR54qad;KU7{5%a_3^!ojpMdZ#xZP>Y{Jy42CkqzGZe8!c-6gmVrl36E!+i9F_xJB zPR7Q8rh{<{H|Q?L#_3ozux8ad9+fMZVJDkt5Mu|A@*>8@Vblo5acts;7|UEfkg;*t zG@9`u=Jy!uzm+w-+hAae3}&oyi`Ou&c#u8K*vbu>!q~;--Q`S3WC0x+*Ry~!qX4h}!x&ev!VfYo;_{ss zx9}{OX7F>DIT=^#UGA2qGog-KxYb}_4Ig2g#R|Q|xR?j+4#sh;KoDaGm(OIpg%#+` zSk~%;{bw-2I6@uCcn7y|1LF)Hgs(GBcY5~yI>aMJj$p34`V_- zGb~`7#T9&P6yOS~8OLz`PR1FWUt#34!bcgq7}ps2P(WM%yD}k<6`0M~$}RYoaWVJl ze#TiGBYwnq5$C_gIEM3|G0JlnbYtu=o})d>ghXz^9LB~mdo1IfoPR&#diH#YjJNTu z+058DRgYu5mAkZjO*9}-5F=G3FjIDcu+29EHQrw;|5l69^;*C zfuW2u-8|~oGGQwVa50YL#pxc#Ei9l1<1O4}S&TC|e+c6^?vfW7OWY+7Fm_jPg?*UN zz=LWrV=F7Lg7GG9kq=`B<8K((vjw*>u3!bXGtOiA|JHGoRL>@TlNnTw;l?qpWfSMU zd)e$~dL{9)#fI1Wv=w$6rMnaQn(j95-qz0)6YSPseH=ZOQ*EX^2tjLMUo!E8!li3S z?%jpU7i8lueTANmTe(=rAi9?4XkK^HidE8-MTJsQ;ljdvL=Tha7f5$!7f4BYE2Z@8 zmD1fgc_arimy;Z6LiTbuRX_}jDSm@cY2Lh??0aBK6qrvj8-z(y3UjEC76VStSs*3n z%$LUH+#}JTqRMAs_-CYp7gyF@Q>LVXo|Pg?qee+mG%oxvtxdo;t#OSSl_24NDFN5W zk?sU(ByI-cipJFsR}`+^xFT@%#D)LChzse`6$=N&ARUM+IvN+!{0#5TeUB>AmPIEcU<}_crkHi4! zV}3cOOE}HtbeW{j`X!v^Na%n1$>L1~u7I`7bj}UEC=}8cG|Ro}G7h!OF$U7iyFhc{wYy3s$Uj&0jGudv*3= zeW*y7ZYy*0!G@`-ea5a>nNqa4AYO}mz?dt=g)hTJ{P`Z@@K=H2-(W2{Pd^(hR-ca&yS|JP z6<<2V4wS6?x~B*{?@C!kR_!BYQ7wgWYsIqVi(SNU9EVECNn~@`biUKYFO!POPxgeWI2|>bw?tZ9ei7;qp9HT+j(!0Itb*`mx4Hdj zC}Tv)dOmsALU7@4`JhO$STB>KTy>cofm3*8p!Fe|?#lyvnnKF|)zj3rOA=_bUgYx{ zKx+gwyP$kMnY{&OFE7HMJMKrpXsiT_ZY~;RpM{LDmLrc`#NB8hrQ|82rR?%|dYZZf z%91RNKm(THZ$AE$%I^$^^omHdnpUZ3Fz1)wNu7oli5;or7Bw0K(TBQ^mL6JoqP4#o z8SXMqqZ^&2FHaJ@{R;3ckye%u>IIp>G!;4`f=<$mA=^t6;4z`Doz1AQ^73_&rf!%d_k#t0%NO@Cbt`|qk13!$!(|FC$LqSm9Vy6&mZnNG@iz@z1t@mj ziqTNn4lI>6Q`bAl#A9IEn+#+CwgA{QgzyVG(LJr%G&Yx)pCtY9nzf_6g6w^dma!Na zgQ)Sfp!s0kEpO^$3iYGzrL6mUBMYzXVvvQI9DY2=%I8I3(C9PLsCk97to%NjDsd2G z*QcW%Geu)SUkgPO{u_#>ZlU&0K~u{MB2692dk2_0^wUj}q&0f1Hk9;LhT@lKjMxnP zWqSDo?M)&66lc&ZSX#adnurl^ z%(Xf5xpqQ&cZM|0G09`rAO4ZlO*N@b`m^XMr}?qanwr|tQk-=u`qFFGP#5MS+a3w$y3Lp%~#GDfnVZ zf));xt4bTOY&RCND0r>gtW#Ai(&p0=nMPJd-R?kjeat|0U5e0~h;PCz;UxvvCsI{$ ztO=`}O8SJ;NI$X_U4oy+FW?TT#Wqz_7}v#LB}aPmTH-Vx(>1H3ZZq|*h`QyeMJm$` zFPqSd-Li?i$Q{FYtV`Cj*PF?C;)?7ACtUK3ArCGS@ygcjVz+GZE_VA}w^J$Y-1&}Y zvYE9POV*qxr|8SClO6m*mQ=IJGy7QSu@%wwkiN7s>Xz-Mq*39#M%B$XYfMq}vTSc< z3@^90%f4KqTkdEEfK$Vo_i@Q&Ni>9PpyiHor;bc!x}!?YLF8j5?j>A)ZAxSvGL?-- z`l03`@E3xR_1(PvTFvM3>@<@-FU)nQpfFR8IWe2tyW8&?~{8w{gg67 z%|})pc_4A!reCaArOx-K=*)F8y{u*!nvdI&T_2NE*EO-?xIS*D^x7Cqr^MyFCN+8f z66W3-I`egMMk1r#O~{m?BmXApm zm$Q@5nVTcsWhu9tkD2&!JHO{{r$9zmOJug%po*L{a;kk!W|E%mlyNCjPC?`uugKo+ zPVz<091jb@lqovdE;1{)eK(WYRVIbv=q+YulBYoPkqv^6UUrSj>wf6X+1;0&ncf|K zb4vFUr>^Ywyj9zs`(|x-$LZ|up|=)wH@vm1d;D}Z&#v1em1ahRteO7EP;=eIOawB4 ztfA-RbniIb)ZK6B8uf-wzKM&xX+?@Q48DC&-zkscF!Cx6cWb$bgtB@ap{CR z;_rA$^d*6=a^wAk<$lYT@d6~H{%kpZ=GRw7=wU*76U$*Qr45(h~F>LvY z<*zNzTTWeW63n*DwOnGk(b8{ux8+wYgO=a6{6T~q?H#uszq5SbGNHmGm~NSES!Q{Q z<>xIQwCuASwmfDzX8EpV;tJxIqs7a_;FE7zX1U4IZ+V|(k7d|$*z)I=XD$C=sc3!q zOtGA4SpXwPn`PExt!1<2-IkHN`RAX|SIp7sN9-*BguW8_qKtEQ+vb0}v-}hKO2Br8 zkJMRcf`4>h3H&{sMf$-O?=lQ-vCtv#Pz#-`-Zt z!)kWKx4pI1*W#WqJ9BFE!aW;xR$h%inu8>5B#g_BzqWXHyXt(iFUDpR!nXitMp4Y`^bz5C) zTf4u!rD5wjb<+6Mn<$-;jT|AZtkGH1D`Vvrvo5TO*itLb*$sN8b8fw!H*ITdc?*@y zvGf;xt1FtewGqDFxr4KLXQYN$ve)aG*$>B-Z{w)DslJ%%^48tvQ^Tun^`z^T+f`bETm0&+(K_KBOY7+2 z6hG1z*Qv{mTMD9FgI!-(eZ;yvG?k{^KeZ59j)FowZm3#&O}ZALpw|^nwkTkNtV{bL$RZ zKX}n~aX%Ef?(8Yov!+WtvM!}%@SbOMmizvg;ry^%XD>=tmsBNqlj5|ByNstE8*(*Y z(!7DPUpCY+JOeRybV7_u$cxE!GM4GfXC%k*%j*P{oR{F&sR=5z9_7cY)TxvGj(3^P zjV4?)m+xay0nvHqI(wGsx#j#3*Yx}pHT~gKZ<3AGO}&(_P9H&M2>vEa;}6VINhmdM zvfm98zkpR1z525AljZu;&cX_PRfc=9j_+XZK(7*ke4NAzol_bqB+uAxs6X)=f`mn; zYJ^D_mB$V9IR2x^bHq?N&o0wB&MzuBYCW+`&zz)_W26F{AFZJGx_AAIjoxYGrvG6D zn8xPtD)hI)e2(kjHQewk0kmh)h2k)eaX3Lm7X=#E!#eha^6Gb zN1T>b`pWs|_#uRU(uX(F8=N{d@@t()8J*n~dhQ|#J{C`<^T#{s^(0xHM6%db9{*qG z{Q6tzE@;yc=lxasvPkvH)B9_+N`0+PsqHk1eDo%zGLh^4udUT>^yL3;NQ;yrQ6*O;M2G609;MPBQ|j8I z&Xg)WUGBM}O3%s~!|#T#GtAfN$PXeW+|DgkIxAh`ETjxN5@)hXZcXqzC#&^5CuOzH zNYXNAP35xlPLtvpI>%K6hWJ)=l&CV1xTMCHj(Ri4(A z@#HbL$5X2W{IISu=Q%dEi29jYt@9%FP_0)+XS(-aB125C4J4%x@18S#&n-GPF^1UW z2Q^OcR(<>K+{EXTYxP@kv9PVSzZXa$KZ&TFmf>Zrf5wb_hKW`B=E=Z6h5`FI zWaAw(@h(!<_{hAPOkLgm`tjvLD8lt$PfeVpME+ z;bW9W_Ez-G@o7q(!xkp6JjSikDiQ8NW!S=#=-;q~mt^va5Nr=zfsSK);RO^pg(I64 z@&+U~RKQbc99wwl4C9{-OHc;y1Q-6RwY#9azft@T!KE{eT?WG_8-L*oNa7!X?^zoL zRL-U5g0R5a!dhz!+pXORe>#h8FOeRHp4nsyTUcRjFT9Y=oF@Krl$ykP-Hgra?^HYL z#J(H$p$spZxiH2klH3X3vGzH5!P-JkjtL{owstNoM8ibtg}hTw9meLxb1Ib|Oh}x( zj85@xy@)NWLsDD3v`+00SO;&kQ;bwX0#hwT0WQE$p=RL6~}_iPQr(Si2GC z@Yr#T#Du5OaqKfNdjZXW9T1~$Avaf26EL1GD!EI9M?cB0!0;c3S2B~7VK0D-c_i^- zm%spO#O{P6DALAoL7r(E;SwbNWpI*2mU+J6@}hjBc84L`ug9)julrsD`Jk+g9m zJbSJ2KL=BIni(Q|7kmSaVvobbPxBXk*dCaME?{TFIY?D$wGnt}``M0yiUxr~`JPL=p(XOA09jb`HE3NsZnIe`xJjU~Cco z0WR>OMRlz>xPg}~s=LI-|8Dpkk_3jKoU4kzaEZ0c;8(5P1%HL4wobv)Vw34Im{UT{ zNrqq>k}$%+5BNtSJq*9TgrP+sUhJrNsbj=nIAf`?dBLON<&KdI@iIsCthITeqk7%i zC*e?;Nm#h9+}tbg|IJxu{DtzeVAAESFBqN3OTxncL6W<1_`-5lfBZ+_vlYw<*u(IT zs1f@-yphL39vM_2{3aU04#GFkaqKZTVS6WjY#4bman4yGgdR}ts)^WrNZ~RN(yC}U{tM}mC zTTOE;fVC(vj|&|bPopyIA(*v^gt2GBIFihQSZuY}llb4av=2FyVGq zzcox&@ZmeCV(drY<6B4!I|x6qm8QX-2N$)HDeMY(I|nAa)-eA!W9(>SwUV1*QoB-z zuv1_N$qL4|eCjFm3jRazz!ywnhoIhWG86}wS-S#0Z0$$jX(RGE|_x*F+Qtt5FXA!V4%LyW&0$Hoiiq z!afOG?`K$Jx4{PY{iyqF?_hH!oH41|rhL1eLc*hp*c~q$m>>hYvkFgK#p?Y$9lnQb| zxC}{R74S>ez8fxljCGwbxzLX!qrx8}2|w}3uOnN5TOU{SX03!fP!4tnT>XTp=~_6i zmzoQ3L5w4)1bYp13m-?3=73py&CNNmcOT6`TkeI0eN;Q)g{zT-uZCCj)7vF} z_$cyY_rRnur`OmiFi^-pQkq?G&$nnZ2?XN?OlJ|M46?e(4X_@`xbJ|kq9FciKhFv% zj6DjQo-$#Y;Xbq<|1g~O4BJfXY@sKHH3H%z8sWb@3(0Rg) z!>j{T?|LGFOHd-V7dps;-2=D$I|ak`!yh1t=PJ*XBt z2>VbYwos1Y0)^ZlhMd8PEtGRLv4wJS_6oL8j=enGER^$yFt$+6wp$ z;x8<>ws4cRVIXqYA%W!3Lk=p$79O;=P|gj+UwGEq!nmWxUpUL!!fUN9l+Ci-E0o== z*usY+wtcJiRrzcmI_Sx=jfjwni;znD3lb#q;VI9&lKc6>M*TS*=*>~;2{ecvL&wo! z)Q=uT@1wWTIQj(|MI-1*v>RP@1+xUY6ir8|C?0)qxl+GJZ=>JhK84;uKSw`CFQe~W zK|LP8=tn>O1Pz8>MlYi0(GdC;>P6o`@_F?->iBxb4*D$mF8U_wLLT%KYDW!doUr#o zFPeu&aqsyI;}h*f+vKsthf#@cMDx)!bmT_<$3AobJ&7JgJJA-j9+jfYKFjijERQdhC;)k zk;2+pN&@s?C&^6FA z5F7{(3=Iqqj0_wb7#%nzV0_^GK-r*oux7A!&_B3+uw$@uuxqeqFgO?<92y*U zw(Zcx9~<3&V*l9wGyBK)pWm;ZN_@)mREG1PJ9O#Po@av3gr7O{%y}j?HAY3pI9CSr zPYOEwdiuhB!+pp4PV}AWJKvYspV2?Bzo5UYzox&je|vvte@}n7f4Kix|B3!H{pb4= z!x`au;exQU;LG}u)3#IJ7(dQTqMhe<>RAP2!SSF9c|zILNMXnut&bpeF%lZ39>%Ey zPj7Z_Zf_wqP}}S8?da|5eLk*37cl)Qrgics)uIZu%D^tz>)l(kw|4LLy&Zcy_sT_{ zBSF``6Z_8Z%jhfUtLf|P3sQ(73NYT6P4;rhU}3l{>5{uJg3!tBR_gwU}|W>cJg%|e_xRNJAaa0rou93^B%JoQ>{P4!cUh72}8 zs1Y^*`z~OjlB)cz)Cj9P+=1Ax5z>RuwtF=~H#R`i%`{mfWNYpqXcB}}?NdFXSeYhd z2rtcuR4SD^>yDpU5N7sUI(wFFmLPO{5(!OsD)D^D_G+SrG)E)21f0VFr{7ruN*9Fc zeoK_BymqLiK*c=7hG=8kZAMIs*eW(%8`XiTE1=p!2;k}uAJfKZ9HMJ#e8|0`^P>3+ z!i&){YlsuiWF@u{M7zj;RO zk=CCmX~cEawhqpfA%YE5^`4H%bDQ9Hd7^Y(`qq)wAiv*35Uf(QbV`(t-R9|eyr&?5 zZT1AJ9O|_T6&K{SAQq+LqI6h}f_N#&1uD|5?{E^ysL~YA-%9qj`7O8ee+!E43WL6_ z48A_$XYd)4*@n=#e!pP2ygK<)0K+HM;GS5Uj~W1a45(7Ux@yC-H9Q)rL6+ur-5ry4 zf>2&E1vDQ9(`w_ws7nczGxWM}7cV zWEcL3Zqwf51oTw^@^mzLUA4WBd;n=6HzR$SlKvp2QNUL;kH)Y6|z7(YZtEB()m>^huCw#gy53)1udus+U zO=xGw^OzIssvUYr2gW`dZBCt0>#KL^%8($}f&*`-*_rhU5L)|C`5S7;QY6Upf(5~u z@EGs{>Qst?(@tiuKPI~oy4o0h*7>7GJ_Bm0*8AEn&W%Q3zW)*o8(qL)kjnoH zELtjkgJ#N`|6zB9Wsf>|%jZMxWF@z)1Jct@BHd@2i@fW6Hl5QKV9##N*6$ym&(G1; z2RSc)$xeht1tfeau;0T<=9?#p(nUpLb!AgDg1BekYu~3lpNz_7)Y@&Lb50~ivmnxE zdgw3>MqZ@o$}{>*6A_cD#Q_w~R>JNAvl36Fcpk>Oz$n%q(@Oco~!j`XCE6$K-id;pgY&M19Mv?Ubpb zyflSJg5|Zq#&|E@!9bpmH2ERm6(l<@MzX2Ku$cW2C&))<=S_`0oDZ`o9TlZIpK0G= zfvq#fI(~{pmryeuoYZDS-|a8v9h&IrnGCkSVSa&!PCkIZopo-9LMiUK2+>tkmf;hf z1DV$~?4gk`qtK<$ z1<{ZafB7`pZe3O>gwmPt*DO{Z9v85_PGH-@&AqEYhdI#fGbPj^B)u%7mZJOFMsyC= zgS@nApQ#gQo5M#0e0xw}13LD789OG=jxhugP`k9zoC>oGa<< zGg!Nb0sV6juhVTob*aL+F8!+r8g~C0VQ@aBAT|K82MrZmG3zF>c@cdb_X6Xr52@3Q zMgYSixOBM)S+3TaZRyT>bDb^)Q5tKPE*YVnf)H>#w`XH+Mx#Aalyc+E@lBaccD+*{ zhSY3Vj23{@Od_d%8(;Q~GiuYShv~L2Ms1$0zP-X@2-#`T$jqj0+W!Ty5vKC=uINI+ z)*X^+L`Z(|BQDJyc2k2y>8Q_i{Q#uhdc|nrS}Q-`NWS!y92mrIn0g2ItVNcfAePv< z$)U)R&y=|j8PVyTL<|PwnZ% zdPSybi<{V#$P~?H=8Al>$DZ*RA;Y8R(HGVX-6x1G>x{t12rSoM)urCghIQ?)T|J&X z)YXP8-*^22e>X+VZhxi#q@b8u#PreYfMn5mI+TR&Kc6(V-GRL*+-(ZF#!{109}?F! z*upWhY_L|vjCz|+o^IxqgJxGc6&9AHpJRpGT=&`1s3$wfPqfFd=nH{_)sS{lK8QF{ zY!Tp;#5pyRjdxfMSC~=1v+jL6r!PR9YQn8O(PfJ_aud^;_2)RqzMYouN{qeFl<^sr za2{BxMefj^E$G|Tu?I1E2#Uf0-?h68bndZhIh_OsCM=CPBy^htT;wLK zA1>WMaB#NxYzgSd&M@yGX`8?eg?FgatptJ!#DW(rgIrJ-K+Z_gUmdG-Wte;piBA2` zh=Z0E3CM%e=V@obI17BByF_=`i+B$0W}61-!Zs+yg!^=(C$sH?;`^CF<&8nV|3TX0 zuu5I;GyS?7{ixR<8AJBHsz+Jno(Q%qB~|;&8MZYgMzi_DgDG8L>}Q-P?QoYnOq-w4 zV0hF5rC90A+97fQ{1HZ4{@ND7EI@@+FoMGK;H1)u(#oGO^KC*a$wuuNJ zv4+R?qv2MmA>Vl+Hs9$n=O;JhC!Z(?sA(m59Rw=7V8i1hkg0?f_uqyp=~Me_G_SI( z0q<+Ah3wLRT10jXbd0h}XROjmG5JJ(K)u138{RBBJ;r>eY`j`yuyqk7*xDDG4MwB| zh8w~|utF6i*A__i`8A$k+hRi>jW>doraf&4u^5c)Er#$=L%1eis)ZpC0i_fgW0tO4 z-B}Y(`F#1#FMS2lg?vf2O26exbIsQdBJDGc0UM}F9v($3 zA)0z9#QeuMpe>M?_63iBM6Fu6sISB7);B_zrZrgIx;g|u5$Au?bMv#8UpZkzbTfVFXZ@ z5TEHDWcFf(KDmQ6E=ZVs6N*{-7G?fM8k)0^5!!_bA;@=8*?cdGyrH?$L7(Xg>P^|F z>>zU5_1>X3NYC*fdvZ&1ucxnI$d1c<05A@sG!gnm>S)Wt~NdF!sO_=eQfNrY_YX_0e6`YI_f z9lZ(%L4LmUKdZwvJ3i6!1?mU$ado^oFXNUinTQ_hiLQrLj5W?4oS*SOTeP=RMUdz_ zNK1BNW_z2?;;Zu>&aN1dFa1p!25@~;=lKtyvd&o|YUHr38pFD^Bnt1vVJa8bTivEl zv5T|1V>V+2EkOTU+!igY>}ApUQcb>eLaezF$M(JyKj-5o*euUFf;z5M300(>ba#?#ss%FR@(G|HI0 z9^~Uf3Z!-g5~QP@+zHJE#wbc(i^&>zGsJ7~WXL;_k86m3O$w^Z#CW6Vvc`v~PJ%)j z?ymAPsJzk+hdhr@;(DJ4ekjboleQnE9HoolJdh5_DG*F+F}guNG?VwR8L|#{l*KJ- zu~(!Hu2;Lwd4cyDIvEqnh2y95ARXaTK!}7#_nl5icA|Ez-jglB>b%`Np ziqACqZGkoPiD!8UU8eL+gwaC7hkg<&F?frCP;@dkWq@iTfp`S#_v}qKZ5!=PF4cy%Now-;$!_c30J!1P1lVf0!q2K`c z&g`AA=3G)J4+6*G4q^MBd?`ZU{<-WR1f9hfF{i%5oD-*Gfoe zTJ_rN#ia|I49`^8ifmqYb3p7{a6EP&8Tcw{&W?3YPn?9FbFMK9woq#6Or;Ys9nn6a zbzPQ!?Zu+In;o7vsYB|eQ$Ex02!bpWWMnOTgJ`Sf6P>f;(=kPJ>kpR2dnu7O3L@S||EdMM_q3B~4Y}?djpuRH z9fd+gTik_O583FFZWWPWl`yexaWl0aWwJ-&e%2n%U~_sFv#mXHx+m%RdLcE+8xg|d z;?+U{Dn(#_V>b86dK}(x_l(Z2NO>CCC*AZ6MsLVnhl1Q46E_l@-JOBJzzTp@Wp_Uc z4gL_OuIP%{AhO5IDQWo_HLJ8HTiJAq(j*Zkn|y_&RI%tHMrx{6Xkx;z`a zfTmQrD2(0Jqo?^To{Q7FOs^p#_qc<|6vm$F(WS>73%XAnmURY8nJqA_+AGSR3`VQB z4QCe;I;9UnMKMTNDUbQQ9kAN&p(W3ydkFxYunmo&I=xE$Rd>gnVOx6@X{*~aZSMhN z-H=KVY7tdVD4<;ujLUkt7M4+316Ygsu95l9x)Aw1=&S*MdEX(9xx9zu2H?B_qI3m? zecqluHQ&UZ?%l<)2P-^jVhBsd?S}X@?R78g&U*PFD%b76ZZepfaFN(f=5@LAkbxUL zQadq2KLYCucCl}fhT`@RUyh)Zkrt(-NlKc9_FL-a?lLr(yp!;5{Ur+5a}B5G_^C?x zJn+QQV@2F^3PQp(Z$~82`hn%+GwdR{{=uq`cAujo5PPT}3rWai%{>P=mXokK_oq`0p_2lkXJJQKjN&kj9eY~c*%TT; zjfj&NJjOJ*S+E6sV-O$K@1Rq*Ysi*STc^uFi#}3X7f#`=2>Vw=q9i)G7A;bdsy{`P zVoIqXba^QGK>%;2EAX3P3Vb+IfwkAv%-qFtB(1@7{w(IVU+d~m<&fja*KDZKV7a$L zi|DI?!j#<64SgePpR? zYfh?Ed4sL9=**g(4u+7o23VOYU$9-Qu$>FGTw)|*tqg}83RBciN!`92d_^fcl4cfm zB!gbTTzYam9I@J1Q|1vuV}o}p+0n0Q8Iu-HMd9fo5>_K=+o1=JysSqJrw$0kUEClK#Nb`kJ>M4_cU#gf5>%gQ%ZpsC2lJzqqkR;ex0_s{WI4zy z(LBC`lK1?@^)>rDw^!E`sA<8jHyCw&)41n2$a|Mu0Gpg;RoUC9U<%+3JPvaC+eVgscXZSwY{RY6$04Ya=$;s#jYAqNDn3)*^UQwt zFm1=@+4j4K4!-~%X$?{f93u!3U(shejUbeYah=Z|=Dg{%1w+E)PmrE>Q-#E|BXU=X z^|+_I_QGIhxhFob6FQB}yQfdTAuk{qYi_nEEx;KIwta;dX`FglCDU)cHA1d**diUW zN_EyW(*uK9^*t#L*wm^Jz_TVD-NZ}sm^x@g*rA3RqEJaT!q%L=@KYl z$rLs6E10lwc~Wzv`rU*kVZ)YU7*H@DU<*F@4*3C2vA1NnRIG9 zsE*h~7&d{TvpU|DF27F+?wDZUNO}TAcaa$@;Bpk_f*QX=@p8rCxP#9(XuHCP>Qc+o zXSAk|b?ZL#6PQ~GNW*oNG2TAaXn%`qKbV%p0&X10fuxU9)i2sN2K~bHQwKX9P3Iky zNSbN=03PlJ(mLokt5nN(kUrDp=Xf)1C%k$&ixv}@-A3c24Y#r%p^BJ> zBs@JVOS^du8#%12WBXqaL^?_IyNX^1Q`N8-?=uZXj9f)I?xO7=%EeZ}ZOVorCGWZ6 z^IDA-P1l7R4;CMf)18J)#ecpCIRIc?$nse>Eo>ZHwUFhbp7I#G-w zG{lP6s6FKb?IhLBWLVb^Ek^_T#KTa4$Kb4Otlz8j%QH%^4#dLMKA!a*-aUd^>rDaq zg`NoPM4+)Jn?Ag&Hv193pXpufly^Y^!oJkKM7w6U>3IN|9Hvwc>^n}0bv0-c4L+Ph zz62L4wKGA>g`1BT$rMEU686p9Wz~cL_*?*xcVbEqpHLDVWVTXfC>aD z8^4QzGs-7MG`+!Su)=5vG5Q&{WE)1y?qKxW)7;S&h#cHY6^cB&us#r*U*ARk=lC|` zwxcTvnaNZ2_S59(8vY?@xTEVe1QbVC_3L2K5iI24RQA6eU58O`%AWQ#8@e!o6%94S z7Vw-N6qrFFw?8t?S0^jYfMTUxZZ+;P;EAa>cw0_Lv}d!O~l~ z2kVu9)cA~;J;|^v7mCFvt&&@r2`wqQkJzHL!3e%s5NE}&D}72Ol~ zGvt}gD2famMwo|-62ogcaN9G+o&XHSE<$PD*p7{;Q(QhhENu3yUy!`XfJrcLl$ac4+Vx97s_ z3BweX$qfw+*+UuyS48Mm4V}9kme0Va2`zaSSIBnSjs%dOfaXB$ksTV(2^7!zyL)zj z?W)h$ytX*v3m~wKbHN9RJ4B-}azx6??(5uP?L~|phFYxfnWk@GWjR9(i$(}SMph(- z-Y`BZygxgT6L0ix;L1Nqlny|k&L^?!Im@-Pli1QxlOlCU6D7DHMC`EP3Bg{u-e`%AdlHLF>ZgA26%sqp0ME8inLzkgUhz##?lI z>jD+&&Kf{AjTDwaGT2`3naMJ8;v7&})ORMiA6&QUDi;8kE&9b9AXy^8s&zL4FBm5c zxJ}x4Ss{&a&NFIOwj*j!BDz78G=@(?;DHfcS~~t9CZ10*C}eDsOpC4s@o>gCZ1HCD zD^5~9i{^akOo7y7CFi1toJmo*tYkBh?(Z*eK)uu|&O*70gRzk8oS9_jkgL(mU5(S= zY{b!OgY5_wXtX5%+Er^t)AGF*$r7=x8rsnolqan;dxI>FFX--BzH}?!@B#dV*Ti)` zL%9zF3&Giie)Vmww&lPHf=XlMT){A$WbtplJUZ-?criHM%fr>3P}KL@Uv$=&yid%i zK^I7e4LLIUsz~wqLH-ZWN%N_}%B=2~aX_j!j5!L*)73DCbN zKs)kt5BcLWP!So8wqD9bv^SL~JWOcR4q9dE<@Zqt`ldGzZtGkD2wqI1iu z9ftB(QNF@zs>%vxUzQCT!`oRYF;~T}0)95|K3y-Yk46jWU87JGyZp3q@CG-6%6faVpx4&vfkPT>+pWE=VKb z{Q*a%x0OA%ScAA(22ZCbeOn{9gNBJAXJ^uNMR7RL5zb;W)LSvGC~_T-Df#r4)!`oU956C5)y z%6|z`hO!5f!}8O=a}v^@)gvRd6Q5(>j_m8mA*@s&<2-1IJot8`NKU*RnJGu#j?9%i z+>VH{=60k|{@@2mxD5R;s8$^Gx^>N6m5vQ{t~BBRNbXBJPS++*1|t>2 zbXeYyK^@X+Ir!b7`UMfn`FoN)wwaniXSB8$Nk0*I+zMF3k%#4l)YXH*=ki5fDL%LS zO4WaF!DsS43MHoRio8-I*&DI)Uw<%7W~AdvCsfgS$R|gEAxijlcRhMTnSq_aQqrFw z3hq&}8&U9|5D_doi;?EtElS_W7l6R@?kMTs0wpMp0|5`W7Y9V9WE(R(Ir4E+ueIG1!GvlUEf3^;c)M|A1*2t+ccG*oEckjm6;%_B+w2Csc!C&PXv4;J`13 zoCV39mqP+T=hOd%ZQUK0L*NH2u3@nm!QpS;=6K9O9NEqL6OvY7wQxgr$QXEyQuGJFFQCwdfj;btX&(G=iX(X9CLA z)v9rXcyV76%Q*~2zi;ZxCjaa-PvWQ3iWTX8H~#oPJ~pyAG@xIIh7}YK(YmwPy5d#Z zyU#Jr?7mvxkF5XfS=#g!?CIHeYZsnnKhN%^?eQbir<2T!Q|2h*t%u$G-laH_T^hSSAQ%Yw88k9tGRwy};8>#Z9IKdFwQD zS=W+So#$Q{2QM&aqk4QXhqmG`#aE(U`O=ige3*gx(vQ=aB_V=Ma|B0c!?=fG0&f}?D{h#;_ZEpg z;`~T#S^KM!O2f-0?X7JIWGp7k0V-L4AdLX6M- z&Bl(6)6UkjMPuFR;pj@Kg%oUpd;zspwkSB!B8lJfjUoujA!zoD>C%IGw{((0`9JLeFrZlywP* z*tYmcepgYH{-iflbPa)QO@2@9yBFDO`H7vr{09Z#=rdI*Wj-p%&gaKy-@M5F&X0D? zI!?olC8I3M1^qABtynwWMgO9xIY2;*PbUs;{o_6Wm#&DAF1-anKIb7@NuP%>UWfUw zW*6kmClA5jgSreLl}p;Hv-K?0B-94h6BDtZo#K&OBY?xUAo9-n>%5o^7exL|6h|I- z9QUGS@+EXf+F7ZEUW=H39=EzvI&0YJyaCz?3s~^z^prK&P&8$3Ho0yH0;20Nn!R4FH>ABXH^N?*&71F^1y!e1Ca24n>%UQVN|+{x+S$31@BY42I4hz3T~XL@=bAF?0ySYu6YCGs62$|(=qJnw#O(meL} zy!W)ux$K>X%-VT#+0lmrPJfP;ktFRxEDe1JPXctPis96o@}o7XM)*DaKIkokI>l4z&EtNCXM zs=2Nj!etKSSF=etV1gwW5k+Nd*`D!zv=0jGm+`6E5`je)jv+9sFfz`izq>sS=3D(h zavVAvyl~-{6u1p!h6$#*N;=k*bZiOv=i8l_LUiK+kqo+n`Lpaz)nvx z&nhE2E2<+Jy{}VkL)>=-$nV3WsIcF#2Mr<7kxZAHF$jmmG?NevOBQ2!>JVH;I2+}g zP?z2lgdPT61L$yo!b!ghVlPkb8hG*n?1W!fWFFQYdmo5P0_p0G*asjCji4WotT?Di zJBf=VvlNLs?bXZm4XyId_M~@ZgEnR-?B7p911+_7MVJSw(jEtu=+jYtTt&G+mD-{E@hZv>k!Rzk7@PTs$sGHC(0riKoTG)8 z?HF%zw8}WH^^uG}h7qX5Dce}e>>eBdWk)*NjHO^Cq2T-JDh^Atb)ZXRXx(U(29F7O zvAtho7QBG`w4_6eA(ReXXj|RK%)!>l`R9Jt^tvf}DA#v~@ixFeN=Sb1Bt*DgZr_g?x0qr!AqU(*i5RTI z^4R_mS=fdC-9Nkk^(g%_2U>Z~+t1d%9v#=x4{N{$dF}gr(jJx*(LLBSg25`Fq&jas z+glJ7*bLtaGrt|-Xu5&<`ol=vO2qkHVD;79hr)DL6j}kk2DtCtwN-&ci;8-pAkx71&zCTDtv*(MlJKPdIPfvg_q{T61_8tZP_N zlws;H3sy{NAsk@vaZkFzJdfm<|G_|cJIOh%#B!Hf$T)Ym)9n%VmeZ_#>NnQljL|-@ zipkD6bD={cjFobm6Gd0vr#@5gRAt$=#uvKs-jYMUU`gdu^tCH#g*{auZKx}Bu&2ut zBPp9z%KN~YT$f|`#M(S!v|;aO!-SRWWcgiP(l_~hd1+_!rBkR{H1gu~vk4i8t{b5( zO<>E{rD#F<=DMNU&;<7Vy3Xwk5Pq|lj_ zR>Yt`SP`SOPG*l)#D$s1VUUxXpsC;dneB9$wfq0azIDa38x`ZV$0oCJuBfi_Ct;{z zQb6!F#Aio<9)`ptW5DMTSHG}sWBm+X`-wBCz5)j82Y-ZIP=_69wrR!$X4EbA@)#UQ1k2nh}!%ZB#m+7HR2;AMR*@ImpnV@9IK!1MwhX4r=lylOjwxk=}XbaxZJW3i((Q?C{r&~Mr&LI8Z4$@(U z@(mtG`|0!LX1}4 zanE*;~eC}!NU<4oqTeB@J>vwUFw{!e_qJ*3|-d>e5OLQ!t&;v}tBuE$vL zYM{?OK3HCg(WsQZmvobw!H$-_jONutV9V!SWS=jOO^gTHS)J|DMN>MCM{9QBQWuWt zkq;uY9$FHL=9ZWBT@kJCQves0g87oEYUr}O$P2y+mUXtH!~CGp;cnKCd# zfBJWnkR%q<%QN-AvHR^kO?z^RDO|o6e~1B!fjHvO ztVY)3(5oDKA0@``&(l^4X(wbHezb3P=0_O$8}1a+_z&8!(R~LdjVR%L47}Uoik1Ja z_W5$9F=p%pu`TF`x#AjQbl?aSC!mJMUP50=V} zb(jTAU3)ajbJWN|Xhk@JHFC&S*sgVB_`wfOXf(@>hEMQ5L^YYaCR~@Vb~c4Lt3#UG zp`H&K1=N+VmSpYGyLk|)Y?v};%XF-ABtgm+y#mXqYDye}*(P880s=EG0`DGNt)XME zC#dBaX;(#QLP#>cR)L$yFsh_cW_+yx=a0TeqH*+Xks9Q&up6ajy4Ig@Z9P65=#-5oF1y_haKE91%s04#78v)v<@t%bc!yd*d+{=5>ML22=!UQ=Af0QEYyj^7etwb7s2gIhA-{;AW zIP|{vd&;A+;iA@IIT;q0v)D*)q(D&l`G2#sIN}yD(NgFdrM8|y(solG1KGo?yO8w5 z@}Ax#lc(r=5r3o6V6!&c@W~yPpK`aACb3>lifyf=HwUw~UxvQvH_YB%n7tUU)4#A6 z+_5I_c7IFc>JPY200uLQ`p|4G-a#DqM;3YYfM-uRBKSen$~5ORo;)Iths zRRr62A(bd zt=_NRVmqFCCUVABplIfJ?nB4Y#;pj=IPoPL@Z8$Lzo()#&izIB@=UeYBL{;IChMI) zJ_zK#G~P>Z&$I$&b}ze;I|H+)VBJak@!a%#u>`%#2Z59- z)KBCLPd1VbpVi|XE!>!JR^x_Fi*fm`+~fv}^SWXA${cCK6La5S&pz{wBknap=z}K} z&rm!g@Z{mK;+cTwemt}A%*C@9&oVq~@RZ~E4$mb#f8z;#T@a%1^ujX`&j>tY@l3|^ z0G>s7R^fRJ&(nBb!P9MvkR|loA_z%%2H;7@GZN2eJOy|r;+cZy0X*~YEWxuJ&m(x& z;bHa9bx+*;dh6)3*GK_)XOam1iu0S&Kj{NM++p7G3hPicnORrFY2R#MOIAc_A9#gr zSTRUD^90+sVsy9F{V*`tFSuzBitLN)0*)Mk_Uk0y)5tci?#8lLw%3kb!K^Ez(sv){ z9+4<34iM1sxp=!xI%T2nACwQrOi`SC;DHzQ$2G4VcK$rpQ=Pp3HTKHNn852vsP`8u zW0-AKoVIg4+qf!0J2aAgu_{aZ*)eu&)o5*FUpD&TSnXS1vj-m@uI+M+z5Z~z_U<>> z`G+TKuWw<4SC7(eNoK27chfHW3RTO~j^Dz*U!7tJ`4ajao?!dTf0g^yCUgpB-X;$E;w@kRUtI-p%aH%6RQJ&okf3v4P7mIa$G~-d)H$A-@iv zOj-lJ>+(#EdWDH?s)}-adJ5TM(R21-x#|^!!|`@y)3Ox#lb30D!q89TuJ!NmYvuob z%{%dXn*O_w@i6W%>aU$4uhd}};^butAB<7K(su$kPHfGqo3urpSohb;wZFZ{w!C(~c3H=#UpKQ2FGV_X5Ainv zdb|XcC5{BKR>3$pMj}}Q@~;M7?}rp*g@Tk7Cp-%M8Oz=30E*zU*PR60%nYY`ANad1SU(toFojbEi81? zFm2@vZ1kq?Ebx_{j74KJK^ob|;q?vg-IfXea~}zA%(9{*e%UO7|gpW3^pn;I)^~oaSgoY;7)!PL{qgq_J*GyiK3FU8Buw&!hb7;pHafwDO{n1>3wf`H4l^M;!+)62H0=L#mwxN3Rq1+7j5$e z*8T0yj;5p70k!otwUdFRL$?lcOO@YDQ5;Ig;ky0T8i_TajZeuWzm7~!Gp>@iX7<_? z-_n0hzz`}_TuXCM2=hLY-A#`^z;=D0nrm!pE;;r&HgsD|r;8|*TeE>_XTA4hRr=-# zdvIG%%O}8dvl9!syp4!5YHfS5xW7zcGC{@u+_ZSxXWE-WEkfFXCQADT`>4_*?C>_T zw(E23(zY&a#oOIjqa(@D{yC-cae#`c>3JHxf%-4Yi23Rm>c8k;4hwv}>Hl(ADf z`kw0D)??A|te>&`3WDe;uQ5+Lh;w*k$xWs?fHzd|rUB)~F0`AxLLrkYZ|9uz3=-Ma zGBZ29xr^RJZ6b3&TpsZ(YuVgA=?OF!D%IdKMf63(>*be`!3#}=uL^O4oi=RfgT04X z_N#pzp2d(Y45jB@j0IqcI;M$oTqj~=i{+NR^2Hpeu~d1Lf)6%)3RB*z!|opS=04x- z3I9I-OScw#aORgU9e`J*H&g?5bOq8s`8B>E%bxbsT(={$8jh6fR%v2OqSf_GJYFoJ z@7me)CAq_*?7?N$mh?ccu55No`pvQKzByJLV&O9@8Gjj^dohi6>p_lvkKSVVG^oUq z0S`?%(0DUnTavNQW+-t5Sf$JGXlp(2Y(m2vElmL9uJ%x5s3i-~fji**=7=@mGN?Hz zMj8#89dE{Q--dWnO~l0gOne!F`O+cfiwL;tf&L|@5KgWH=VzQyFqHqzi4Nd?1-(2@ zFOl=6;^pRQ7?C}pi_qX|IJfH4McXQe;nQ-?*Xo|2MGI=}K_$7aXzz$!)U*=Vkfbk5 zTy&$<9rH^)&s~d)7WM1PBPgjNH+;D0gUxh9yZR?^t{q)5wLUW+ckd;oH!VA(K*oE@ zihg_a6vo@*B&NB;UW#{=A!LU`@H=~ZDwsOJdqAw)2P*hykD_w}`_gZm(iP}wWgw?fpjMV$M*}ND$&*!lFhCF3 znxVp4J=}X&*=L*{m8Y@Rp#|Rla15Y))c6n$wXA{Jt1|CW&`i_He(!gFdz!mNdAr=AmT+}G)*BaTYViLTL_kFJ&9DlSbRzhz=C_f zuPj4Yja~P*p0`meu5r8u=Z(PSxH2;E|m84>mkRKib4MYDs{WK>I9-m)U*5p7SRTI_B_)4{v)4qtm?r{3icI;|A05c< zq7y~=#^<1=`#~Ljru%zwWGONL+mAUqo@&h?YK_~Zztg67yn+EW?G9cV6U1d z$qtM2?^`(5{=kh*!c|wQd=LS(cWwk=3viXX=L|x*83{}4sDF+ig1vPvR0O6dsVT95 zpBqf5MFJE)eP$)w>K=sN3aiOkpL;poQeI;ye+Kz1YoSWfXIcxn*>(yiVN)*;!^($awabY(HsjZ6zQFn=Tal)AZ{;W@>rxxa7n%D*oPvd8=i8o@@KTwBk{zg zj6V!He?Y=t*+=^)GPKI5lN#ie09NTHZJna!jhr{_mgI#z7(z`MjuOZzc?2thM&5pn zGN4mXVk!#EU9Z-87uP@NrhQ{wxtCKZ01>$ipX4noUc@T2>?SM0wu(A&xMlc0+mdyc zYzr(E!M>vqr+ozh*DccZ(G?S$hv$`_wM`&g&U$NehGqC68+y`au~Zl=?o}-+vF|9+ zX54*f$l6b`J(Nw+npuUV*m zv;rq#ajq4%V z%C)m_bg5M5S%L0^PNCfH%rV~VY+NCM(BnfGex`nYVC^$K$vGOzFM&RH*tK$aY|{$6aE@oi|cF&Rva>JMIJKWPRL-)55u6$zP{XHR;)5BW!yOd9sOAS$m$(d8_ZTfce2||}v-AsZdtOHzqNZ!}lW&M8 zd;vbs_s~AnjzSuts=pxC51~FjQ&zZQ;U97rn3Bvi-J0o;@N_H&X$FSb;0Zq1`R-*G^e55)UPUwLV*%ohhpf57#ewK(a+ zhBsDd^5#EI{Xokj|FRAwD3#8TSEH6x!V0u7n_5Ws8=*h_KXM6{80aN0XI8*|_Ws+k zoqa1{K^hX}62rulS|0A7vS$VR@$ERruZaF>n3}M7C6V+Wd=1c0-Ut~6aYFtoS{Uoa zp1Nb8v-Z?C0_2~#kRMP}A{rLeBS*r|l;cqnSg}U#TVn8<(l{@#J{b@O$(HrJh(mu` z4EKfApdKgi)F5I0DlBO@35_WQA)r2k!~4Gd({SG*Jo`Y`^rxXHW)#O4=|h!t;5bb^ zrFBu#i2fYnhruVs$s2W_K0|@Oqk$fjZVbdFc~j7%ys(IUpiI!_uVA`&`}a!clv8!t z92Ol%$>2U6T#X5tyaZ#)#Fgy+cjIydrNER(r7|Z_@DF%S;-TIec1bMmSZg^nQB_eq475)na(c*nP_+f#g~3HsKjt1+4Y8!|luj&CQtgy_j#86KO8n_!hOQ5i@!E_& zLuaJWmtv@H=rZ>Bdr6LH#1Gu~<;sEUXH&knBYeGo$~S<9atq}Az==OD0dv6c*pCnn z(3nDr{^ryKM(}$7!O^HI&eW7t{Xd+;*%%$AUMRhyIdI{0!~P4`AE`fZ=4`@v&>~Ml zFy(o42MG_(1N$EEcukWi!)33&01!fQ@Nq=1Og*%}rWDcx#Iuz3%6&BlZW?2rC)%6F zlv#lLf4ICYW`!C^F(81xYU0>?IN5!OoY+;r|Az~^j(~xFHPsNAKLXtULqqI4w`C*; zsusB;_8ssReTB4Lx-vWa^8L=)6+F*WT_r(p(eVQ}ryl~3gi2n5F=eY#(&YnJiW*SH ziTyu#wj~q;Nr9AA%UJveaY@TK(bU=lXN#H+oV`!~HE#O>CVWTm$NO|V{^NZydu?pV z2QfYWAhdU?=~sd$N>2_t;5lm=OOfk|`wpDAk+R6nwtvvM!@*K67Cux>ekhQg{=i(k zQ$c-2s7xrW1J@TrFFTY^*ZGWLN0HhAvXKYynbh? zq`S6*J^WTwxA`E&Ww~53pLb(0vwbGHE5_8NtJ%SJycH1*-!9y*Z(yMD*6lyb@gnxC zlun)qw*Re^VZ})CnT~cLTM{<+Lq5|PgqPGxD@=h=Iz|>AzH=GQE`IWE zKXSO^0)Wlrw%o!Q^YTbJX(g>Vame5em1B4W3$!{+&wX0dC2Jd^wuGxS**3F$`6hOh zJr3#;w=vz${zLtjB+tmNAi??L$k1Ah1Wf!Xo|l18?ik{`D*UPdcR}$Li)AFu3A6Si z`{0;72<+LrNrRX%sc$!`Ux8$Sfq4k`w`KCNDEoJ0W*ZhyabVQjo^Rc$>h$-$40j1W zhF@bWxmJU(l51+kng*k12+!79UHY8aVlc;10p2P{z-J2SK+*c$?Ub*m@GnmU63*{K z<)37MIVgf0E{kC9l{(r75=mb&l^dV~$@WZ#ARhe)Vfua=PRj5ufo>Yb@v$cYE?sYs zD^@B#u?(I=HT`QsugJVr{Vi? zdeM&rT|AaM*+=#lBnrYqy{dd&0Aj8Tt=~25|I*AX>=4kZ5VRmws^`tRg}TW9p$tIc zuAuH`s<=DXfr!#BJ8y~ZO9C$4NYK~m67W}POKfXf`lum)eW@)yfP;0ID!L*xh%Q}= z!U~is<4!tV2%@_N*)Z2|r9PA@v8RRV;+`0Wt3=WIGev|4r|`j$mZ@G zKIne1@EcV)AHsJ~E}BK@xAg_tB-PVAcUd6Scc9I3riC5Z*;V`UNcQW_n2v{r(M~FF zi8N_0&cSBN-;H3McR9@oR+9AsbfO4$d2ss|g~&!ix{4CzKjyPtyUYm%OO!I!;vnO8 z8OVm61ikT(;!Eylnmv(2Cc^B!lLFr@lsC_$Q*@%jcf0-d=7X+eHCM15yQ2dGkd^h{ zZ5sC*EX_LzRsDl9PW&qYMlmmW&%dx`YnI@XgUUtmS086j?l#5e72&lRPFnUaQq(_H z!Oy&pD&I9|_niex1%*oLAG_F>ySsGl{;$lEzu&*u#ftX~V8-2MN614oEd(J>h3P81 zONDb)_=pOhR^huUtXAP^6*jA|!+eFWS%sM@3|p+=rz>%Xus}^HSK%`%+@iwIRCrp2 z7gZRsKrKLp{ZyE#!qF<6sKOEzu2A864q>Idq9Wc^VYLdsR^dez-cVuCLZ#r2D(tSp zekvTHLaPdkRJcHet5x^}L6k3SR1sTLxLt+&RCrp2zo}4Iq*NeEg@aT$T7~zkutbHc zRrrJoUs2)vfOBc=_o;}}D*Qo(zpL<;3W=6}E24xls)8R@f33uu+CWZ>KgM1{84Lfc zTSUYFg|Pe`1(qG=2@w&Qk1B}5dIgFDc|yECdP?d-VneX~Q$0GdxS#*jHt93H z4yDEZ8qRK$VQ!oFf;RCbY8>81{Cd!D z-`FPpQk%GAa~lR*+QhfEiND(>zP(NSqc-uKZQ`G)aka-BLiN89!u~cH>f6MRw22>A z<9?xSY7=i(<9;D+QR9ltVE%<%RAeAR9YeDk_X}038toAj-1 z((CU`r};0d2)G{k&v;3xP?Q=^RpVwgUZloj)%XfE-b;;dZj--SjT_YT<7%9SfXWw6 zs|d0*=-1RHL$ez9S1{strGkFNWLD$;AxKr@u+jN1TaEi0G*gYE2YLBInTkkIGi+7k z@oM~doAeeno~))P{_*b~6Ve0e)4T zsK&#UWFcFP`!#7>%~{xney$piR@#rVXcgfXvdwDTFJ#qfoHkkXYg<5(D%E~X*H%%r zo#uYMFucfXF-!%0aKO6py^U2>ot*8je1ST2;1CwrNy%rEKuq-V@AoWQd`yg zdQC6Wj2UxgJuuIYFI_&b#5Q9<)rk(8SVx+I6=uv>Vp}?75a7}|rM9K>ifw*!`=VJ3 z<~_J*&TNkGrzRq1UNi?jC*^0JJ!ioj+ZXh2t5$a0-^_=Dbp0X#Y^Ta zon>3Rlwv6(FzPhW$q=8E6g(8hL-QwPM3T@SkR%bjgiJ62Utt7bU%1lKb{0UBakT*40<8F8qah*GnbXvW<8LyU`}sjrr*qE4*+pzoI10& zFw?ej$(+R{L{{~1Cr$TI>Yhap@@!T64Vw6>N`t0r)l(fc=BjN5O^>RM;hJ7m72&`Q z2-hT5wWEY~Mon1NC8MTW)vMtebHJRrW=f2&TGCO|Bho(GW?nkSW?#C9^PQO|3N!DS zI5EGfM<yeP9~EXUUbtwUnJQa4@4?Cp(d8(YW;xn^G2vrLVXlbNDb6=GQ&8^Dsr0HTZURGvq zp$hTVZkeX)e6q$FI$xM0EEN{v?}Dl+$(raHRFLw&H%BihwJcbG7jp0T(Gm^(=%sV! zaI6|1GsiZ0)&jeNqXZQ{;Z8iwGHumYVVa&go|i4$d$uYuMic26wRmaXig~uerHhN_ zl$OFLm7~;`li^QgoA_trmGov6u2$3iu-i-}y-bDsS1Iu(75e!eSMm)OKAWKsw5ag- zBqbg;S%Lpsu0VeQsW!#V9_2^)IYy3B2>tQKHZ?0#<3+deA0{7K$W36Lr|_!6z&~V_ zYW%ng&DWIlG8GNUpJ;rm$*rKTUSk%)St~B`KQGRgWZV+CP_q*k(di<6lfv zRrkf8vc8%jRipcB_ErV<*YvGw>W{32$(U)8F&ZPW>t6Lqie_LByHLvIGEErBdu5KW zLa;$cEd-u4m9c7V2Td1dtczsky2$?4Q3bP>OyIg94`&QQ0FmIaF2>ZHbJwheb0#jf zj>^vkO6VvERsB0?`t(_GQ)zI83OA~7s|p_yW}&RHLSfa8UQqT$@u=a(IE~T2S_x&h z6b9ugtWe=Ldi2tduMTLK>Q1B@g z3shl<3d2-rRAGb)BUNZtVWJ8LsW4N83V*aeS4CJ=I8lW&Rk%cjD^!RNVDK%@Gb-Gu z!p$n&uEKg1`q$$|HQuB`nIQE)K9a{7wx|%kNFEPSp;3iq6{e~%TZKg`T%y7<6>e1F zW)*H#;dT}71mwHLY86qh!s9AzRAG|}WfeB7utkL-8l}Q!6{f0?3ZT|!tMNh=&Q#$N zjYiomR;Y-LD%`HZ{VF`7!bTM~t1wcl6p*UI3HC)o!Qw^2L@4ijVQ5U8YZpc@ohM9~ zWfPD#d)7*v0WVe{O`nPOs{e**Iy*qOw3Me}L0CFZ4dE4vSy)Wf*w|T%gwb;z5DI23 z6)a1Z09GHxMqTH8&J%TIo!@%$Qm)QBjYMt$}#o)?Syr*WUZtJBvg6)b>D7ZN=Trmb$}g zeL!DlkmpcY{SnDmZw0VVXjWVj_77Jy}wk|a&2-QQvp?!xMcr`?!je(l-K)tzh zA}*vY6O9Q|^ETsu)P~5mdGn%*ibY2xpLyd1V|szlx3Z>YrCfIOwp|^<^$>=t&eFwT z+1n2M%8ghtd^~u!q&DEXDK~c8F;6s__of(gOn(aILvISMXgaY1Nmd255wg{z2s;jW zF};*oJK2E3%fXw$_0V}LXlY?7VG}DQTDl+)dLQ(58g)Eb}Y^~&IjjD~TZzAxe6WM+c>m|q0zK?7_%JypxS&JQr%>WH-m(U>DevXNd zC$PXF@?b`xIfEHW$kWLfOly{!L9QgvBnQcvHL4M^mpn>dK~}Di?m~I4lFi}LyjG)fl5@!}avnL8oKJR> z*ONWu4P-C*T5@iP5gQrdBX1)6$=8u_)>}Qcg?F?wTf>^kh)f!I$g{|~Ic zi;(ll!{qg3m7!Z)Kz5QhkTc1lYZ>8T#71&1c@x=BzK&cjj+pWLoF zq>32POM@H8{p20wLGmv05IH~|As-;C>ADB1$xiYya;C)?e}lIq9vVcG?I+SWaxT;3 z$$oMIxs*JC93(r*&EzC%W`W~NJj)2fe)4}gL)d) z;{ji`O75ruMab5m4pQSWA6p|Vv=+AkJ}#tv6`G=1=PPGL8|;RKxWj7k7htO#z?jjTYB1?}UG z8p(}p!2!!*qTmbGEpA|X4deH*h0^7+%LeRFEGtkU-BhbS<}>s0vZc=rudZ8MyExY2 z-<^k_mMi5a%a{^Zg@a{-+GyUN1qZNO(%kT1m=XDDksp`DdFSHCA)!7gXw)hVj$*S( zLM4*mn`cZh|F_$iWV&UCUP-8wgaO%Cc)pr`BMSvYI_+mz&Yg+pd&;mQjnKI~VIVtb@1k z%bi$*F0hWJF$EOkKsz`e1+>U0;Evffz5!>f7)l4fb%in4jJV~bn1_R1*Lo)s7E7Ks zX^EKE!rbm1ZG*$b{Ct)%eH^;TESn2spEP73%SbgR%{LNEToLTjW@AWJ%8BQ- zPEhN>u+B~EJe1JDd?R%n4m0!IY!nxk1GdjPXQi9kP&#HRJ=548h;{5-+v&s0vl{Z~ z%b}j3FMBp=u11(1u_G31`}fIC@;P#*=8$S|r`?FsvHT z#E5qo5hf3k`^eXk2gv>82>C6t?ca|l4>SD@@+kRd6J`>h}=XzO>QA~liSFf!Lol9X2cI@&_}*Nw%yydKYxJf zElkg)GkG~V!gQ-}#Mv*ACNO=N>07vee14~gU=a;QX`mk)&_nD}K3*%wGHu^Odl%Wh zGqB%MO=P;8>08P68<9(&2YP9+p9am`;Y_lR>1Aa5wbvwa3Dfx~rxf!~W_l&lze{c+ zZ?n6|!3<6sw9uf4Y`=5KCbuzNU%c@}2zzib)5A<}B9}0ICAp93q1zeZWCaq*&CIZt zJirWhkt5{oWEbt1kcXLmgxt&W=aNTtdWa9PmtS*b(ZI1>kFkCN!y!VxkLmVXs;kIu zrq__Y*5^` z`Fh&BrlNr|{!BvkR#;3BM*~bAdixJ z$&Szp-GV+wxX3>xyU8z+OIU$)vX|+*$+nZ|7i26;Yz^V_-p}CqvDnf(1Y2af4Uh**0o5_BruON>y{TR8D z70w_#R_Y4fOm>lLEynp5WQOT9aMR#xWDj?EHQCGb+sG}{^cmz5rk4uK z`S0cqawGyu$sIPw7bW3V-B5k|DqV3>S@JW76& z>{z9{^!sENc>~!^4w{MZXI!bDZp-N6vYiU$bne+)p^loL&%jgaunSMQI?sMpXMT?F zbcofe+)Mh^Tcc7on@pZiRVRcx&SzL%*2^U_2VgBekP<;kMa44<1ibJ z)FY-LM!sqAXOvs+hjQz2eypvyS+ikp--U^HH5)!w`@r6VU1#HJR&G8w-I%&UoUPf` zu5^7gU;Z#jv+a`A&e?2u_o~c;sm9ba+htTkx1RWHrSy99kyLmH%F$WJ(CSdY@+0iA zzORxUX+|ydUddI^deiCq;eQy*wU=6<(}S1BMzig{w9A(drmW5UeI^`@krczZQM+xV z+wGF2f6D1G)m~=lFZ(uG+wb{5($T^+v=Co-nJ1=V=(XKGe4zE*G<1x{8hkT5b~m-? zw{3E)>Ez&;_DU`E_hyp8PREF&n_2iF900R$0HAR30S3n87B3|7n29bFE)Mc+xPrU&Ph;)Bn|sMt3X;<=W?%N|E@iAxz3=0TL3CN6sEZ2Or*Gk(p_QI$0DXUoxK z9~B4SOwNWJH5a3g%}UfNUR=x)S8slVvvP&F(B=5FZ^^X}*LJXr$6EU4@_{5Sbor+F zfVmAt#%X_7jX84~d{%g^4&Q1rnpIK{@bR#WJd}c^A-^fHQ z@iN~Tl2;5ezINZqs|LwnABCFj7Z3_B7_{rtJ}zz69~53rw~rusWs!~2>a zd4MJ9!P37n!PZMN%s-_W)8geFPBto1YZ`Kv;417)(;i_t?DYXqIQBbV1p8D~~Qdf3$-M+>4&A-%7|5fqY zeCij1-_(~y=eM9AoOogPxS%0_%A7pG^RfPw0R>+Xav>_JIjXsBhoPDgb|Fdbr0&E${9}*< zFt|Al&PPZO?&;1${tT&@gLStdKU$#FN06JcmAVyj8qxz<^p;XjK>8t5FCzcDN<9iW z0XYph2YL2g+|CRj@HXUEkbi~5MwFTek-u3eove2xb#B2o}_ms*+HfuxP-hWhTVPl}FF{{S9bL)j&E)wmyERP3yaXaP2ZH|s?LMd1aAB8T& zH{6Y7SyxM87z?XM7J58;_U^;o7T6&L}tPMvH=b3;VHR%dv?laUqQlWt6PH?iY9- z-K^u5N?ZhSV}>?I;vD;NBqhgO%DhY>RS<^owJp@;E6-6w^~1}tu$-U8w;Jj;_;D5n zY0z#c`M)>5R7Dg|jN zOA?22@yvlfRHsmU(iD9xOAQVqe9U5VzQZTmi|6QIn^P4@#BH($$9N(vH$*;^c(fj_mH4 z=9$&_yMX_=#>kwWF+pWiK#Iq!jGP3OvBWi!I+Q#(rQeBC%s;O;(oJW9;RqRN2`UY} zmR8|VX~l6W4Lz5(BxNWOUuUJ}OjM~wQ%0OallmtF$Cui5o{jOo1>%ZGg;3`yQEJKq z@gXnP34;V+Jb48^ zS^tUxS0H^I6y!RTBAeCa>n?YB?0TgpL1dsT zZT@<#F()eHO>>bB$ z!(UB8?6xLOiB(f_oNCIGlZM9j-znG>7Af@zE11Y5*e>Ve>y`Qs$Pds&)NHmjmJ>0S z7|$<_r4b*c;+MpjJJuM}Lw5eRcPjNM#O{Ev>c;CaNgROu-)tU7`m6sBn-rwa(KhB^ za*aE^8E@irz>J@ERh&w1yg{YsT(8oNA~hZzCTTLK8Tb@18AoR_j?QGXD7oGlGz-@n zE*XTqYmFIG?56y%0h36hQm;qMhu0cd6AL8-vltd#CNigeMB<{PtPrTa>g%}MKwl{ed6{M!eVTKS+HZMt$s zQmjhCY><=_r;?UT4(c;N&$V`*>Bn&c0=b=aO`92`CK`9E*rDjbsD2q}^FOg)Uq5W7 zJ&sR5D-7$U>R2|$$EfiY@GF z@Axm0jm~akOo^-oUMw z2y8@Kml^C!=0LM_z2U|U07x!QQ?LRZZjm3}fUCn%T+_t_S8z*w;N6fQL~fP*kRYTT zG6ZQs{C$vzA&)~kAhMGv{E=+5sx51*Ivl93DqmQE#S8Ff?D%W%ih$PjfwGF~T6If( zRbxQ^f|9J83Y1`Nepxzd=>A#h|Fi1VfA3YVHp}7gJXf{)YgfH0ir#i8P=CZ9sNY*x zk5v=)1oG<+)i&ZUH-Ea!$X@i@D6A^5{YV4;nzOj7CXm;#p{hC{AyqeSV{KJq71qW$ z8rWV~)zIj}p=vH&fj=`0t}v35?i{zVVSS+d(7t_vdOudp2-G&3(^eYOV?r@lkieX= z(nw2u-zvSatiJJ3aAWP>x*g_SUSs;AV-mf&uHsO2z*kmVQ61QUYe_-TmV&~iORRH5 zeH>lXSbcr%EmgG@1x@BnUL$Sme#umbB|i%4>t%V3JlV|{_8JA!tbCkFRrrJS?SVaw zRrr%z_2Rg~K-uBIm*dSRu7(3B(`&fL_r?_4i!hjfSz%0HbxtCz)fdhiq6(|Z>*dd7 z`=ko8enMVF1zL=2^vmN4>&hyaUeL5dnX^_HNt-goF#k|}Jvzl+Z(*M?cJ+n7jVTV) z*HmF@2-pU=Mfg&;pg?osa>JEYG7g;|EDGqAB6eA{9pj?R-z+!Mviru3`P+Q-nZ|%ETy5IHDHvN@5iIGm~SoEZ0=rW zeRuP1YUSyEjme9-JGyL*_n-Gfyltrml~XZ25Jy4RzH493yb$ z+$bYGra3o=g=CN}z)}QDC0*EGS0#r4j+p-CM)I|Hsr>4?1|DMSNOTbnU@^mUkQL@m z&|$Bsd`!f;7CW$Zt5qdC8BboH;;P^=b2nf?ljP0D?a^tk_ z#{vqtUgd;F4(o{CgIecfzgR-^FQdpQS0NvrLI1xx#O;qPw@{b6Ofm3R>xHP)LUh^- zX7g5~H0n^>Gm9&Y*Nq2rjYQmcZouVK9?j+Q`Z&XKnf(CrN5sqJHX~7oMOQe0{R|^G(dE_ z4&x(81fFEVdFWRe9)!lSg;oa9oAL17ghGSR&5$s{tkh(FN#lEk${VZ-Jhjqcbmnu7Xq`z8d-+h*T&7{o&OZZ^REluV1DQM$yM0a;&sL zr+amL26QpxJnW%EDrJRI4*{~EhafFd5cK?&x5I_2 z)}VV4zZ-f0B0CoS+FCpn-HhIXPRvCQA)E}o5OVxRd<5b_V3P%gDulj+;d`K8f)pad z0QArE;ATR22s#~)EejCFdOzw`h;%R30Fo7rtgz@;AyPT46{N6!kQEl)01^8Z(ILWd z=uU=3f5h-7(7$6?bn<#U2Vln@=jDeFG{5`(o&xYhiEgnk|(m3|TW&xII&DOA>(@IfR&^nDDsLchas1X}(Rc&X3==zAe@0JcI` zZ^f~Lor%UGQkISA-#{XW$AVI7v0s;;1N|xFcZeVMQG_EHVbRY) zTnN7iy=J@KSuXUqAyUzYB#vRx&lO{a6MJYZG^OOs5Pl*0k zh{TUTW2r4`I7I(DL>hx-w^Vwm4rf4DK*YWo`WYP#sf!3W%XC5(^rPkIF4Xim^c592 z9T9dzFW!rS5YB;qb{{4XgfBq9ydMof_#*VDczNb5!?;4n)?kbg?|^>378e}EzX+XI zhapCIJ@m!8ke-z;0-ipIogtwQ`fvmO1PkFNXejl}B~M7K9LZ4&uUmj^)hM5JYzH8Fclnx=TfeAu=4j z&>upi8;78iZ$lmwDtaemeK}@8=(`~b;ZEpOG}3`^5c)NU%;1{w_p% zr44#(n{JsOx(6byU;PM9(MR=;KY*U{m_D0ULw^Dh8_`9_kymyM{X+?(Ov^bV(F6h}k zSlBs$OEz>XMCK3C!w~DP33{X#4TH_?)wn$fc8Iwp+Q)5?T>I!AsmFh>shoO;d`Jz{(Cs55&jH%N55`Z z5W3)b+%-vF=s&!KA=_)HKfWZV!GLZt*3?$j5a|}t^M9fzlLgTCL$Z+JA?PhH>&p3| zZ}};P4Dnc?Ta7>p5f<%yMPE@xpMex3z8`uJQi`ziRoo>*DnkG-0tJH@SA>1ghapml zCg|@%tOF1_`3+1Ouo1l!BJnxU1rV`shyD$u6E@<;Tmg~z)zBtn5b?dxuR$UR%X{Zg z^jo?h(eFS$K|%!jpCOX@Gw7C!xWFJ@^uI$sLwFRr>TPr>!p+dHK^$;G4nd!N2R(o= z);m|vL;RTBu;#h?C8PvldC@H|{&H``N5B%0w|)Ri%bPq2i@r??I9?@xTfB6~b>rRw6tP;(??=oDc>11=8Mt9GHd6F61W24Unyn0>~=JV#qwm zRkLw$L#9JgA(J67kUz}A>G?Sfeg#RIgL57d1Nk!&e-9af{2KBxv8;DT8c>6hM|kuDl8!fwMD*(4PkS@1*x+ z?n&QC|H;ym%_mz^<3c(!6`G@kyN;L8roMv|XKWoXG9)ca(Nib_6?`I+{CL zI$As0I>H^j9eo}B9RnSM9g&Wqj?oUsDc7mYQ|?oqQ{Gd(r~6L#pB^|pcsg====AXE zk<+86)fvYb=NZ?T%rovYo-^Jvxo3Q5N}ecvqVkELd2o-BpES@p*cs^@>KyJI=^X7; zU5+lN`O+SvV1}pL+nw9(>-Kk-beDElb_ctgFezKF7*I#k9WXAebHm1m^h%_)bhmYf zyZgEax+C4g-J{)(9#@aM$J^uUDe0-~Y3ga|Y3m91^z{t%M0$pMMthVKQ-CsOR2XkM zq}k_D>NB_PHN3|1(#~LKb7yO3duMNFKk7Gxx~VQ_S7w)|E4RzvRoWHoYVK<7YVYdp z>hBut8tNM9Qr%AT7Xf2Uj0aZ?WnQt@m{B3$y=0=w(h((Rf@hk}sI#uKnP=T+J!idV zkr2eCOw!MI&z78RI@@-(@9gkd6?TN3VPDuEE)7?PgW;xdbGRkk8g2`>hr{8%aDR9p TJQ$9Ihr+|*k+3*<28{m#P`=Ex diff --git a/Libraries/Otterkit.Native/build/nativelib.dylib b/Libraries/Otterkit.Native/build/nativelib.dylib index c4c5c7c7630ec43d442da70ccdba4cfc53ce4e52..c5287f18e0c71fe24a5322213b96aafaceab1aea 100755 GIT binary patch delta 39970 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 KD4RGLcK;89)GZzW delta 63692 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 diff --git a/Libraries/Otterkit.Native/nativelib/CASPAL.h b/Libraries/Otterkit.Native/nativelib/CASPAL.h index 03e89932..f62a92f6 100644 --- a/Libraries/Otterkit.Native/nativelib/CASPAL.h +++ b/Libraries/Otterkit.Native/nativelib/CASPAL.h @@ -39,32 +39,45 @@ #error "Standard C99 (or later) support is required. Consider upgrading your compiler, or using GCC or Clang instead." #endif -#if defined C11OrLater +#if defined C23OrLater + // Built-in Standard C23 static assert. + #define StaticAssert(condition, error) static_assert(condition, error); +#elif defined C11OrLater // Built-in Standard C11 static assert. - #define StaticAssert(condition, error) _Static_assert(condition, #error); - + #define StaticAssert(condition, error) _Static_assert(condition, error); #else // C99 doesn't have a built-in static assert, so we have to use this neat trick. // If the condition is false, the compiler will complain that the array size is negative. - #define StaticAssert(condition, error) typedef int assert_ ## __LINE__ ## error[(condition) ? 5 : -5]; + #define StaticAssert(condition, error) typedef int Assert ## __LINE__ ## Static[(condition) ? 5 : -5]; #endif #if defined C23OrLater // Built-in Standard C23 alignas. #define aligned(x) alignas(x) - #elif defined C11OrLater // Built-in Standard C11 alignas. #define aligned(x) _Alignas(x) - -#elif defined C99OrLater && defined __GNUC__ || defined __clang__ +#elif defined C99OrLater && (defined __GNUC__ || defined __clang__) // C99 doesn't have a built-in alignas, so we use compiler-specific attributes. #define aligned(x) __attribute__((aligned(x))) - #else - #define aligned(x) // No alignas support, just ignore it. + // No alignas support, just ignore it. + #define aligned(x) +#endif +#if defined C23OrLater + // C23 already defines bool (equivalent to _Bool), true, and false as language keywords. + // There's (most likely) no need for us to do anything here. + // According to the C23 standard, when casting to a bool, the result is false if the + // value is a zero (for arithmetic types) or null (for pointers), otherwise the result is true. +#else + // C99 introducted _Bool, we'll typedef it as bool for the sake of readability. + // According to the C99 and C11 standards, when casting to a _Bool the result + // is 0 if the value compares equal to 0, otherwise the result is 1. + typedef _Bool bool; + #define true ((bool)1) + #define false ((bool)0) #endif // As defined by the C11 standard: @@ -94,10 +107,10 @@ typedef unsigned int uint32; typedef unsigned long long uint64; // ...and make sure they are actually the correct size. -StaticAssert(sizeof(uint8) == 1, InvalidUint8Size); -StaticAssert(sizeof(uint16) == 2, InvalidUint16Size); -StaticAssert(sizeof(uint32) == 4, InvalidUint32Size); -StaticAssert(sizeof(uint64) == 8, InvalidUint64Size); +StaticAssert(sizeof(uint8) == 1, "Invalid uint8 size") +StaticAssert(sizeof(uint16) == 2, "Invalid uint16 size") +StaticAssert(sizeof(uint32) == 4, "Invalid uint32 size") +StaticAssert(sizeof(uint64) == 8, "Invalid uint64 size") // Typedef signed integer types... typedef signed char int8; @@ -106,10 +119,10 @@ typedef signed int int32; typedef signed long long int64; // ...and make sure they are actually the correct size. -StaticAssert(sizeof(int8) == 1, InvalidInt8Size); -StaticAssert(sizeof(int16) == 2, InvalidInt16Size); -StaticAssert(sizeof(int32) == 4, InvalidInt32Size); -StaticAssert(sizeof(int64) == 8, InvalidInt64Size); +StaticAssert(sizeof(int8) == 1, "Invalid int8 size") +StaticAssert(sizeof(int16) == 2, "Invalid int16 size") +StaticAssert(sizeof(int32) == 4, "Invalid int32 size") +StaticAssert(sizeof(int64) == 8, "Invalid int64 size") // Sizes were already checked above. typedef uint64 uintptr; @@ -121,28 +134,30 @@ typedef int64 intptr; // Just to make things easier to read, double underscores everywhere is ugly and hard to read. typedef __m128i vec128i; - #elif defined ARM64 #include // Same as above, but for Aarch64 with NEON. typedef int8x16_t vec128i; - #endif +#define assembly __asm__ + //╭──────────────────────────────────────────────────────────────────────────────────╮ //│ Platform detection and abstractions │ //╰──────────────────────────────────────────────────────────────────────────────────╯ #if defined _WIN64 #define PlatformWindows - // We need to include this, otherwise it won't compile. + // We need to include it, otherwise it won't compile (Why though?) #include #elif defined __linux__ + // I hope we don't need to check for individual distributions, that would be a pain. #define PlatformLinux #elif defined __APPLE__ + // Darwin is the name of the kernel used by both macOS and iOS (and others). #define PlatformDarwin #else @@ -156,61 +171,65 @@ typedef int64 intptr; #if defined PlatformWindows #include - // Windows virtual memory primitives. - #define sysVirtualAlloc(addr, size, prot, flags) VirtualAlloc(addr, size, flags, prot) - #define sysVirtualDealloc(addr, size, flags) VirtualFree(addr, size, flags) + #define SYS_READWRITE PAGE_READWRITE + #define SYS_PROTECTED PAGE_NOACCESS - #define memReadWrite PAGE_READWRITE - #define memProtected PAGE_NOACCESS + // On Windows, attempting to reserve an address that's already reserved will fail. + // This is contrary to mmap's behavior, which will just overwrite the existing mapping. + #define SYS_ALLOCATE MEM_COMMIT | MEM_RESERVE + #define SYS_RESERVE MEM_RESERVE - #define memReserve MEM_RESERVE - #define memCommit MEM_COMMIT + // Wish we had these on Unix, but we don't. Would make the intent clearer. + #define SYS_COMMIT MEM_COMMIT + #define SYS_DECOMMIT MEM_DECOMMIT - #define memDecommit MEM_DECOMMIT - #define memRelease MEM_RELEASE + // Only really needed on Windows, but we define it anyway for consistency. + #define SYS_RELEASE MEM_RELEASE -#elif defined PlatformLinux || defined PlatformDarwin - #include + // Requests more virtual memory from the operating system (Windows Edition). + #define SystemAlloc(addr, size, prot, flags) VirtualAlloc(addr, size, flags, prot) - // Linux and macOS virtual memory primitives. - #define sysVirtualAlloc(addr, size, prot, flags) mmap(addr, size, prot, flags, -1, 0) - #define sysVirtualDealloc(addr, size, flags) munmap(addr, size) + // This also releases the address space, so it shouldn't be used to decommit virtual memory. + // Use both SystemCommit and SystemDecommit for that instead. + #define SystemDealloc(addr, size) VirtualFree(addr, size, SYS_RELEASE) - #define memReadWrite PROT_READ | PROT_WRITE - #define memProtected PROT_NONE + // Must be used with an address within a reserved address space (returned by SystemAlloc). + #define SystemCommit(addr, size) VirtualAlloc(addr, size, SYS_COMMIT, SYS_READWRITE) - // MAP_NORESERVE to avoid reserving swap space for reserved address space. - #define memReserve MAP_NORESERVE | MAP_PRIVATE | MAP_ANONYMOUS - #define memCommit MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS + // On Windows, we decommit (only release physical memory) by calling VirtualFree with MEM_DECOMMIT. + // (according to the documentation, this is the correct way to do it) + #define SystemDecommit(addr, size) VirtualFree(addr, size, SYS_DECOMMIT) +#elif defined PlatformLinux || defined PlatformDarwin + #include + + #define SYS_READWRITE PROT_READ | PROT_WRITE + #define SYS_PROTECTED PROT_NONE - // MAP_NORESERVE to avoid reserving swap space for decommitted pages. - #define memDecommit MAP_NORESERVE | MAP_PRIVATE | MAP_ANONYMOUS - // Not needed on Unix systems. - #define memRelease 0 + // These 2 have duplicate flags, but it's easier to maintain this way. + // This makes the intent of the code using them clearer, and more portable. + #define SYS_ALLOCATE MAP_PRIVATE | MAP_ANONYMOUS + #define SYS_RESERVE MAP_PRIVATE | MAP_ANONYMOUS -#endif + // These 2 also have duplicate flags, same reason as above. + #define SYS_COMMIT MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS + #define SYS_DECOMMIT MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS -//╭──────────────────────────────────────────────────────────────────────────────────╮ -//│ Additional virtual memory convenience wrappers │ -//╰──────────────────────────────────────────────────────────────────────────────────╯ + // Not needed on Linux and macOS, but we define it anyway for consistency. + #define SYS_RELEASE 0 -// So we don't have to remember the order of the arguments and flags. -#define sysReserveAddressSpace(size) sysVirtualAlloc(nullptr, size, memProtected, memReserve) -#define sysReleaseAddressSpace(addr, size) sysVirtualDealloc(addr, size, memRelease) + // Requests more virtual memory from the operating system (Unix Edition). + #define SystemAlloc(addr, size, prot, flags) mmap(addr, size, prot, flags, -1, 0) -// Must be used with an address within a reserved address space (returned by sysReserveAddressSpace). -#define sysCommitMemory(addr, size) sysVirtualAlloc(addr, size, memReadWrite, memCommit) + // This also releases the address space, so it shouldn't be used to decommit virtual memory. + // Use both SystemCommit and SystemDecommit for that instead. + #define SystemDealloc(addr, size) munmap(addr, size) -#if defined PlatformWindows - // On Windows, we decommit (only release physical memory) by calling VirtualFree with MEM_DECOMMIT. - // (according to the documentation, this is the correct way to do it) - #define sysDecommitMemory(addr, size) sysVirtualDealloc(addr, size, memDecommit) - -#elif defined PlatformLinux || defined PlatformDarwin + // Must be used with an address within a reserved address space (returned by SystemAlloc). + #define SystemCommit(addr, size) mmap(addr, size, SYS_READWRITE, SYS_COMMIT, -1, 0) + // On Linux and macOS, we decommit (only release physical memory) by calling mmap with PROT_NONE. // This will overwrite the existing mapping, and the pages will be physically released. - #define sysDecommitMemory(addr, size) sysVirtualAlloc(addr, size, memProtected, memDecommit) - + #define SystemDecommit(addr, size) mmap(addr, size, SYS_PROTECTED, SYS_DECOMMIT, -1, 0) #endif //╭──────────────────────────────────────────────────────────────────────────────────╮ @@ -219,16 +238,45 @@ typedef int64 intptr; // Shared library, set visibility to export all "public" symbols. // Should be used with `-fvisibility=hidden` compiler flag on GCC and Clang. -#if defined __GNUC__ || defined __clang__ +#if (defined __GNUC__ || defined __clang__) && defined PlatformWindows + // `visibility("default")` doesn't seem to work on Windows. Fortunately both compilers + // support the below attribute as well, which doesn't require the `__declspec` MSVC syntax. + #define public __attribute__((dllexport)) +#elif (defined __GNUC__ || defined __clang__) + // This should work on most Unix-like systems. It should also be used together with + // `-fvisibility=hidden` to avoid bloating the export table with unnecessary symbols. #define public __attribute__((visibility("default"))) - #else // Not supported on other compilers, just ignore it. #define public - +#endif + +// Shared library initializer and finalizer attributes. +#if defined __GNUC__ || defined __clang__ + // Library initializer attribute, function will be called when the library is loaded. + #define initializer __attribute__((constructor)) + // Library finalizer attribute, function will be called when the library is unloaded. + #define finalizer __attribute__((destructor)) +#else + // Not supported on other compilers, just ignore it. + #define initializer + #define finalizer +#endif + +// Branch prediction hints for performance optimizations. +#if defined __GNUC__ || defined __clang__ + // According to the C99, C11 and C23 standards, casting to a bool here should be safe. + #define likely(expect, condition) (__builtin_expect((bool)(condition), (bool)(expect))) +#else + // Not supported on other compilers, just ignore it. + #define likely(expect, condition) (condition) +#endif + +#if (defined __GNUC__ || defined __clang__) && !defined PlatformDarwin + #define alias(name) __attribute__((alias(#name), copy(name), visibility("default"), used)); #endif // For the sake of readability, since static is used for multiple different things. #define private static -#endif // CASPAL \ No newline at end of file +#endif // CASPAL diff --git a/Libraries/Otterkit.Native/nativelib/allocator.c b/Libraries/Otterkit.Native/nativelib/allocator.c index d6128901..9ef8c195 100644 --- a/Libraries/Otterkit.Native/nativelib/allocator.c +++ b/Libraries/Otterkit.Native/nativelib/allocator.c @@ -1,82 +1,314 @@ -#include "allocator.h" +//╭──────────────────────────────────────────────────────────────────────────────────────────────────╮ +//│ ╭─╮ Otterkit's Dynamic Memory Allocator ╭───╮ ╭───╮ │ +//│ │ │ 128 TiB Virtually Contiguous Heap ╰─╮ │ ╰─╮ │ │ +//│ ╭───────╯ │ ╭─╮ ╭─╮ ╭─────────╮ ╭─────────╮ │ │ │ │ ╭─────────╮ ╭─────────╮ │ +//│ │ ╭─────╮ │ │ │ │ │ │ ╭─────╮ │ ╰───────╮ │ │ │ │ │ │ ╭─────╮ │ │ ╭───────╯ │ +//│ │ │ │ │ │ ╰─────╯ │ │ │ │ │ ╭───────╯ │ │ │ │ │ │ │ │ │ │ │ │ +//│ │ │ │ │ ╰───────╮ │ │ │ │ │ │ ╭─────╮ │ │ │ │ │ │ │ │ │ │ │ │ +//│ │ ╰─────╯ │ ╭───────╯ │ │ │ │ │ │ ╰─────╯ │ ╭─╯ ╰─────╮ ╭─╯ ╰─────╮ │ ╰─────╯ │ │ ╰───────╮ │ +//│ ╰─────────╯ ╰─────────╯ ╰─╯ ╰─╯ ╰─────────╯ ╰─────────╯ ╰─────────╯ ╰─────────╯ ╰─────────╯ │ +//╰──────────────────────────────────────────────────────────────────────────────────────────────────╯ +#include "allocator.h" // includes CASPAL.h -// Convert terabytes to bytes. -#define TB(x) ((uint64)(x) * 1024 * 1024 * 1024 * 1024) +// The base address of the heap. +private uint8* BaseAddress; +// The total capacity of the heap, in bytes. +private uint64 Capacity; +// The cached pool lookup table (indexed by size class). +private VirtualPool* Cached[312]; +// The bit tree of available virtual pools. +private VirtualTree* BitTree; +// Whether the heap has been initialized. +private bool Initialized; -private inline void* ottrkReserveAddressSpace(const uint64 size) -{ - // Reserve virtual address space, the default size should be 2 TB when calling this function. - #if defined(PlatformWindows) - return sysVirtualAlloc(nullptr, size, memProtected, MEM_RESERVE); +void VirtualHeapInitialize(uint64 size) { + // Avoid overwriting the allocator instance if it has already been initialized. + if (Initialized) return; + + // If the size is 0, then we allocate the default 2TiB of address space. + if (size == 0) size = 2ull << 40; + + // Reserve the allocator's address space, and an additional 128KiB for alignment purposes. + void* base = SystemAlloc(nullptr, size + 131072, SYS_PROTECTED, SYS_RESERVE); + + // Align the heap to a 128KiB boundary (needed to make deallocation work properly) + uintptr aligned = ((uintptr)base + (131072 - 1)) & -131072; - #elif defined(PlatformLinux) || defined(PlatformApple) - return sysVirtualAlloc(nullptr, size, memProtected, MAP_NORESERVE); + BaseAddress = (uint8*)aligned; + Capacity = size; - #endif + // Allocate the bit tree. + BitTree = (VirtualTree*)SystemAlloc( + nullptr, sizeof(VirtualTree), SYS_READWRITE, SYS_ALLOCATE + ); + + Initialized = true; +} + +initializer void VirtualHeapDefault(void) { + VirtualHeapInitialize(0); } -// TODO: Replace this with the proper allocator. +private VirtualPool* VirtualPoolCreate(uint64 blockLength) { + VirtualTree* tree = BitTree; -// Convert megabytes to bytes. -#define MB(x) ((uint32)(x) * 1024 * 1024) + uint64* root = &tree->Root; + uint64 indexRoot = __tzcnt_u64(~(*root)); // 64 -// Convert kilobytes to bytes. -#define KB(x) ((uint32)(x) * 1024) + uint64* trunk = &tree->Trunks[indexRoot]; + uint64 indexTrunk = __tzcnt_u64(~(*trunk)); // 4096 -// Stack memory, default: 2 MB. -private uint8 Stack[MB(2)]; + uint64* branch = &tree->Branches[(indexRoot << 6) + indexTrunk]; + uint64 indexBranch = __tzcnt_u64(~(*branch)); // 131072 -// Stack pointer, points to the next available memory address. -private uint8* StackPointer = Stack; + uint64* twig = &tree->Twigs[(indexRoot << 12) + (indexTrunk << 6) + indexBranch]; + uint64 indexTwig = __tzcnt_u64(~(*twig)); // 4194304 -// Returns the amount of stack memory being used. -// Might be useful for debugging or profiling. -public int32 StackUsage() -{ - return StackPointer - Stack; + uint64* leaf = &tree->Leaves[(indexRoot << 18) + (indexTrunk << 12) + (indexBranch << 6) + indexTwig]; + uint64 indexLeaf = __tzcnt_u64(~(*leaf)); // 1073741824 + + *leaf |= (1ull << indexLeaf); + + if (*leaf == ~0ull) *twig |= (1ull << indexTwig); + + if (*twig == ~0ull) *branch |= (1ull << indexBranch); + + if (*branch == ~0ull) *trunk |= (1ull << indexTrunk); + + if (*trunk == ~0ull) *root |= (1ull << indexRoot); + + // If the root is full, then the entire heap is full (all 128TiB of it) + if likely(false, *root == ~0ull) return nullptr; + + VirtualPool* pool = (void*)( + BaseAddress + + ((indexRoot << 24) + + (indexTrunk << 18) + + (indexBranch << 12) + + (indexTwig << 6) + + indexLeaf) * 131072 + ); + + // Commit the pool's address space. + pool = SystemCommit(pool, 131072); + + // Initialize the pool. Size is always 128KiB. + pool->Capacity = 131072 / blockLength; + pool->Available = pool->Capacity; + pool->BlockLength = blockLength; + + // Pack the index for later use during deallocation + VirtualIndex index = { + .Root = (uint8)indexRoot, + .Trunk = (uint8)indexTrunk, + .Branch = (uint8)indexBranch, + .Twig = (uint8)indexTwig, + .Leaf = (uint8)indexLeaf + }; + + pool->Index = index; + + return pool; } -// Returns the amount of available stack memory. -// Might also be useful for debugging or profiling. -public int32 StackAvailable() -{ - return sizeof(Stack) - StackUsage(); +private void VirtualPoolDecommit(VirtualPool* pool) { + VirtualIndex index = pool->Index; + + // Unpack the bit index back to uint64s. + uint64 indexRoot = index.Root; + uint64 indexTrunk = index.Trunk; + uint64 indexBranch = index.Branch; + uint64 indexTwig = index.Twig; + uint64 indexLeaf = index.Leaf; + + VirtualTree* tree = BitTree; + + uint64* root = &tree->Root; + + uint64* trunk = &tree->Trunks[indexRoot]; + + uint64* branch = &tree->Branches[ + (indexRoot << 6) + indexTrunk + ]; + + uint64* twig = &tree->Twigs[ + (indexRoot << 12) + (indexTrunk << 6) + indexBranch + ]; + + uint64* leaf = &tree->Leaves[ + (indexRoot << 18) + (indexTrunk << 12) + (indexBranch << 6) + indexTwig + ]; + + *leaf &= ~(1ull << indexLeaf); + + if (*leaf == 0ull) *twig &= ~(1ull << indexTwig); + + if (*twig == 0ull) *branch &= ~(1ull << indexBranch); + + if (*branch == 0ull) *trunk &= ~(1ull << indexTrunk); + + if (*trunk == 0ull) *root &= ~(1ull << indexRoot); + + // Decommit the pool's address space. + SystemDecommit(pool, 131072); } -// Allocate memory on the stack. -// Returns: -// A pointer to the allocated memory, -// A NULL pointer if out of memory, -// The current stack pointer if length is zero. -public void* Alloc(uint32 length) -{ - // Return current stack pointer, if length is zero. - if (length == 0) return StackPointer; +// Apparently, GCC can't optimize this function properly and generates a bunch of branches. +// This is a performance-critical function that is called every time a block is allocated. +// We can't afford to have it be slow due to branch mispredictions, please compile with Clang. +private inline uint64 AlignLengthToSizeClass(uint64 length) { + // rdi = length (sysv calling convention) + uint64 aligned; + + // test rdi, rdi + // mov rcx, 1 + // cmovne rcx, rdi + if (length == 0) length = 1; + + // lea rdx, [rcx + 127] + // shr rdx, 7 + // add rdx, 56 + aligned = length + (128 - 1); + aligned = (aligned >> 7) + 56; + + // lea rax, [rcx + 15] + // shr rax, 4 + // cmp rcx, 1025 + // cmovae rax, rdx + if (length <= 1024) { + aligned = length + (16 - 1); + aligned = aligned >> 4; + } + + // dec rax + // ret + return aligned - 1; +} - // Return a null pointer, if there is not enough memory left on the stack. - if (length > sizeof(Stack) - (StackPointer - Stack)) return NULL; +private inline void* SmallAlloc(uint64 length) { + // Align the length to one of the small size classes. + uint64 class = AlignLengthToSizeClass(length); + // Fetch the heap's cached pool for the size class. + VirtualPool* pool = Cached[class]; - // Align the length to the next multiple of 16 bytes. - length = ((length + 16) & -16); + // Go to the fast path, if a cached pool is available. + if likely(true, pool != nullptr) goto FastAllocPath; - // Get a pointer to the next available memory address. - void* memory = StackPointer; + // If it's not available, allocate a new one (slow path). + pool = VirtualPoolCreate(length); + + // If we failed to allocate a new pool, most likely the heap is full. + if likely(false, pool == nullptr) return nullptr; + + // If we successfully allocated a new pool: + // Set it as the cached pool for the size class. + Cached[class] = pool; + + FastAllocPath:/* empty */; + // Allocate a block from the pool (fast path). + uint8* block = nullptr; + + // If there are any uninitialized blocks, initialize one. + if (pool->Initialized != pool->Capacity) { + // Get the index of the uninitialized block. + uint16 index = pool->Initialized++; + // Get the address of the uninitialized block. + block = (uint8*)pool + 16 + index * pool->BlockLength; + // Set the next block index to the next uninitialized block. + *(uint16*)block = index + 1; + } + + // Get the address of the next available block. + block = (uint8*)pool + 16 + pool->NextBlock * pool->BlockLength; + // Decrement the number of available blocks. + pool->Available--; + // If there are any available blocks left, set + // the next block index to the next available block. + pool->NextBlock = pool->Available ? *(uint16*)block : 0; - // Increment stack pointer. - StackPointer += length; + // If the pool is now empty, set the cached pool to null. + if likely(false, pool->Available == 0) { + Cached[class] = nullptr; + } + + return block; +} + +private inline void SmallDealloc(void* address) { + // Get the pool that the deallocated block belongs to. + VirtualPool* pool = (VirtualPool*)((uintptr)address & -131072); - return memory; + // Set the deallocated block's next block index to + // the next available block. + *(uint16*)address = pool->NextBlock; + // Get the deallocated block's absolute index. + uint16 index = (uint8*)address - (uint8*)pool - 16; + + // Set the next available block to the deallocated + // block's relative index. + pool->NextBlock = index / pool->BlockLength; + // Increment the number of available blocks. + pool->Available++; + + uint64 class = AlignLengthToSizeClass(pool->BlockLength); + + // Get the cached pool for the size class. + VirtualPool** cached = &Cached[class]; + // Set the pool as the cached pool for the size class, if there isn't one already. + if (*cached == nullptr) *cached = pool; + + // Decommit the pool if it's empty and there's already a cached pool for the size class. + if (*cached != pool && pool->Available == pool->Capacity) { + VirtualPoolDecommit(pool); + } +} + +private inline void* LargeAlloc(uint64 length) { + // Large allocations (bigger than 32 KiB) are treated differently, + // and are allocated outside the heap's fixed size virtual pools. + uint8* block = SystemAlloc(nullptr, length + 16, SYS_READWRITE, SYS_ALLOCATE); + // This is quite a bit slower than the virtual pools, but also, + // large allocations are much rarer according to recent research papers. + VirtualPool* pool = (VirtualPool*)block; + + // We initialize a pool with a capacity of one, which is needed to make + // deallocation possible later (we need to keep track of the length). + pool->BlockLength = length; + pool->Capacity = 1; + + // Skip the first 16 bytes, which we're using to store the pool header. + return block + 16; } -// Deallocate memory on the stack. -public void Dealloc(void* memory) +private inline void LargeDealloc(void* address) { - // Return if memory is null. - // Double free is not a good idea :) - if (memory == nullptr) return; - - // Reset stack pointer. - // We don't need to zero out the memory, because it will be overwritten - // when the next allocation is made. - StackPointer = memory; + // Get the single capacity virtual pool for this large block + VirtualPool* pool = (void*)((uint8*)address - 16); + // Get the length of the large allocation (+16 for the header) + uint64 allocLength = pool->BlockLength + 16; + + // Deallocate it directly, we can't cache large blocks. + SystemDealloc(pool, allocLength); +} + +public void* DynamicAlloc(uint64 length) { + // Likely false because large allocations are much more rare + // on average than smaller ones. + if likely(false, length > 32768) { + return LargeAlloc(length); + } + // This should get optimized to a tailcall, hopefully. + return SmallAlloc(length); +} + +public void DynamicDealloc(void* address) { + uint8* base = BaseAddress; + uint64 capacity = Capacity; + + if likely(false, (uint8*)address < base && (uint8*)address > (base + capacity)) { + LargeDealloc(address); + } + + SmallDealloc(address); } + diff --git a/Libraries/Otterkit.Native/nativelib/allocator.h b/Libraries/Otterkit.Native/nativelib/allocator.h index 52f2a37b..6ea7310d 100644 --- a/Libraries/Otterkit.Native/nativelib/allocator.h +++ b/Libraries/Otterkit.Native/nativelib/allocator.h @@ -1,24 +1,82 @@ -#if !defined(OTTERKIT_ALLOCATOR_H) -#define OTTERKIT_ALLOCATOR_H +#if !defined(VIRTUAL_ALLOCATOR_H) +#define VIRTUAL_ALLOCATOR_H #include "CASPAL.h" -// Returns the amount of stack memory being used. -// Might be useful for debugging or profiling. -int32 StackUsage(); +typedef struct vindex_t +{ + // 64 bits (1 bit per 2 TiB) + uint8 Root; // 0 .. 63 stored. + // 4096 bits (1 bit per 32 GiB) + uint8 Trunk; // 0 .. 63 stored. + // 131072 bits (1 bit per 1 GiB) + uint8 Branch; // 0 .. 63 stored. + // 4194304 bits (1 bit per 32 MiB) + uint8 Twig; // 0 .. 63 stored. + // 1073741824 bits (1 bit per 128 KiB) + uint8 Leaf; // 0 .. 63 stored. +} VirtualIndex; -// Returns the amount of available stack memory. -// Might be useful for debugging or profiling. -int32 StackAvailable(); +typedef struct vpool_t +{ + // The pool's total capacity, in blocks. + uint16 Capacity; + // The number of currently available blocks. + uint16 Available; + // The number of (lazily) initialized blocks. + uint16 Initialized; + // The size of each block, in bytes. + uint16 BlockLength; + // The offset of the next available block. + uint16 NextBlock; + // The bit tree index of the pool. + VirtualIndex Index; +} VirtualPool; -// Allocate memory on the stack. -// Returns: -// A pointer to the allocated memory, -// A NULL pointer if out of memory, -// The current stack pointer if length is zero. -void* Alloc(uint32 length); +// Trying to keep the pool bookkeeping header's memory usage to a minimum. +StaticAssert(sizeof(VirtualPool) == 16, "VirtualPool size must be 16 bytes or less!") -// Deallocate memory on the stack. -void Dealloc(void* memory); +// Bit tree of available virtual pools. +typedef struct vtree_t +{ + // 64 bits (1 bit per 2 TiB) + uint64 Root; + // 4096 bits (1 bit per 32 GiB) + uint64 Trunks[1 << 6]; + // 131072 bits (1 bit per 1 GiB) + uint64 Branches[1 << 12]; + // 4194304 bits (1 bit per 32 MiB) + uint64 Twigs[1 << 18]; + // 1073741824 bits (1 bit per 128 KiB) + uint64 Leaves[1 << 24]; +} VirtualTree; -#endif // OTTERKIT_ALLOCATOR_H +// Virtual heap for dynamic memory allocation +typedef struct vheap_t +{ + // The base address of the heap. + uint8* BaseAddress; + // The total capacity of the heap, in bytes. + uint64 Capacity; + // The cached pool lookup table (indexed by size class). + VirtualPool* Cached[312]; + // The bit tree of available virtual pools. + VirtualTree* BitTree; + // Whether the heap has been initialized. + bool Initialized; +} VirtualHeap; + +// Virtual stack for static memory allocation +typedef struct vstack_t +{ + // The base address of the stack + uint8* BaseAddress; + // Current stack pointer position + uint8* StackPointer; + // The total capacity of the stack, in bytes. + uint64 Capacity; + // Whether the stack has been initialized. + bool Initialized; +} VirtualStack; + +#endif // VIRTUAL_ALLOCATOR_H diff --git a/Libraries/Otterkit.Native/nativelib/compiling.md b/Libraries/Otterkit.Native/nativelib/compiling.md index bf79640e..88f46729 100644 --- a/Libraries/Otterkit.Native/nativelib/compiling.md +++ b/Libraries/Otterkit.Native/nativelib/compiling.md @@ -10,4 +10,4 @@ clang -shared -Wl,-rpath -O3 -fPIC -Wall -W -o ../build/nativelib.so *.c decNumb ## compile macos-x64: -clang -dynamiclib -O3 -Wall -W -o ../build/nativelib.dylib *.c ../decNumber/decContext.c ../decNumber/decDouble.c ../decNumber/decQuad.c ../decNumber/decNumber.c ../decNumber/decimal128.c ../decNumber/decimal64.c -march=core-avx2 +clang -dynamiclib -O3 -std=c11 -pedantic -Wall -Wextra -Werror -o ../build/nativelib.dylib *.c ../decNumber/decContext.c ../decNumber/decDouble.c ../decNumber/decQuad.c ../decNumber/decNumber.c ../decNumber/decimal128.c ../decNumber/decimal64.c -march=native diff --git a/Libraries/Otterkit.Native/nativelib/memory.c b/Libraries/Otterkit.Native/nativelib/memory.c index 2285e317..ae8b1e53 100644 --- a/Libraries/Otterkit.Native/nativelib/memory.c +++ b/Libraries/Otterkit.Native/nativelib/memory.c @@ -1,12 +1,12 @@ #include "CASPAL.h" // Thin abstraction of a contiguous block of memory. -typedef struct span_t { void* pointer; uint64 length; } MemorySpan; +typedef struct span_t { uint8* pointer; uint64 length; } MemorySpan; public void ottrkAlignedZeroFill(const MemorySpan to) { // Goto loop buffer index. - uint32 i = 0; + uint64 i = 0; // 128-bit vector of zeros. vec128i zeros = _mm_setzero_si128(); @@ -14,7 +14,7 @@ public void ottrkAlignedZeroFill(const MemorySpan to) // Loop through the remaining bytes in the destination buffer, zeroing them out. zeroLoop: // 128-bit store of zeros to destination. - _mm_store_si128((vec128i*) to.pointer + i, zeros); + _mm_store_si128((vec128i*) (to.pointer + i), zeros); i += 16; @@ -25,7 +25,7 @@ public void ottrkAlignedZeroFill(const MemorySpan to) public void ottrkAlignedFill(const uint8 with, const MemorySpan to) { // Goto loop buffer index. - uint32 i = 0; + uint64 i = 0; // 128-bit vector of the fill byte. vec128i fill = _mm_set1_epi8(with); @@ -44,7 +44,7 @@ public void ottrkAlignedFill(const uint8 with, const MemorySpan to) public void ottrkAlignedMove(const MemorySpan from, const MemorySpan to) { // Goto loop buffer index. - uint32 i = 0; + uint64 i = 0; // Loop through the source and destination buffers, copying 16 bytes at a time. copyLoop: diff --git a/Libraries/Otterkit.Native/nativelib/u8casefold.c b/Libraries/Otterkit.Native/nativelib/u8casefold.c index b09cf00f..a9fc96d6 100644 --- a/Libraries/Otterkit.Native/nativelib/u8casefold.c +++ b/Libraries/Otterkit.Native/nativelib/u8casefold.c @@ -1735,13 +1735,13 @@ private inline uint64 PopulationCount(uint64 value) private inline uint8 RuneLength(uint8 byte) { - if (byte < 0b10000000) return 1; + if (byte < 128) return 1; - if ((byte & 0b11100000) == 0b11000000) return 2; + if ((byte & 224) == 192) return 2; - if ((byte & 0b11110000) == 0b11100000) return 3; + if ((byte & 240) == 224) return 3; - if ((byte & 0b11111000) == 0b11110000) return 4; + if ((byte & 248) == 240) return 4; return 0; } @@ -1775,20 +1775,20 @@ private inline const uint8* MappingSearch(const uint8* data) { // The trie is designed to be used with non-ASCII UTF-8 data, so we only need to look at the last 6 bits. // The first two bits are always either 10xx.. or 11xx.., so we can toggle them off. - uint8 byte = *index++ & 0b00111111; + uint8 byte = *index++ & 63; // The above operation will leave us with a compressed byte with maximum value of 64. // This is a huge space optimization, we can then use a single uint64 to store the bitmap. // The bitmap is a 64-bit integer with each bit representing a possible next byte. - uint8 bitmap = node->bitmap; + uint64 bitmap = node->bitmap; // If the byte is not in the current node's bitmap, we can stop searching. // The byte sequence is not in the trie, so we return a no match error. - if (((bitmap >> byte) & 1UL) == 0) return data; + if (((bitmap >> byte) & 1ull) == 0) return data; // Count the number of bits set before the current byte. // This plus the offset of the current node's first child node is the index of the next node. - uint8 count = PopulationCount(bitmap & ((1UL << byte) - 1)); + uint8 count = PopulationCount(bitmap & ((1ull << byte) - 1)); // Fetch the next node. node = &root[node->offset + count]; diff --git a/Libraries/Otterkit.Native/nativelib/u8console.c b/Libraries/Otterkit.Native/nativelib/u8console.c index 8e5eb975..676162d1 100644 --- a/Libraries/Otterkit.Native/nativelib/u8console.c +++ b/Libraries/Otterkit.Native/nativelib/u8console.c @@ -20,5 +20,5 @@ public void WriteLn(const uint8* string) public void ReadLn(uint8* buffer, int32 length) { - fgets((const char*)buffer, length, stdin); + fgets((char*)buffer, length, stdin); } diff --git a/Libraries/Otterkit.Native/nativelib/u8convert.c b/Libraries/Otterkit.Native/nativelib/u8convert.c deleted file mode 100644 index fe69228c..00000000 --- a/Libraries/Otterkit.Native/nativelib/u8convert.c +++ /dev/null @@ -1,107 +0,0 @@ -// Adapted from: https://github.com/simdutf/simdutf/ -// License: MIT or Apache-2.0 (See NOTICE in root directory) - -#include "CASPAL.h" - -public int32 u8CharFromCodepoint(uint32 codepoint, uint8* destination) -{ - int32 length = 0; - - if ((codepoint & 0xFFFFFF80) == 0) - { - // will generate one UTF-8 bytes - destination[0] = (uint8)codepoint; - - length = 1; - } - else if ((codepoint & 0xFFFFF800) == 0) - { - // will generate two UTF-8 bytes - // we have 0b110XXXXX 0b10XXXXXX - destination[0] = (uint8)((codepoint >> 6) | 0b11000000); - destination[1] = (uint8)((codepoint & 0b111111) | 0b10000000); - - length = 2; - } - else if ((codepoint & 0xFFFF0000) == 0) - { - // will generate three UTF-8 bytes - // we have 0b1110XXXX 0b10XXXXXX 0b10XXXXXX - destination[0] = (uint8)((codepoint >> 12) | 0b11100000); - destination[1] = (uint8)(((codepoint >> 6) & 0b111111) | 0b10000000); - destination[2] = (uint8)((codepoint & 0b111111) | 0b10000000); - - length = 3; - } - else - { - // will generate four UTF-8 bytes - // we have 0b11110XXX 0b10XXXXXX 0b10XXXXXX 0b10XXXXXX - destination[0] = (uint8)((codepoint >> 18) | 0b11110000); - destination[1] = (uint8)(((codepoint >> 12) & 0b111111) | 0b10000000); - destination[2] = (uint8)(((codepoint >> 6) & 0b111111) | 0b10000000); - destination[3] = (uint8)((codepoint & 0b111111) | 0b10000000); - - length = 4; - } - - return length; -} - -public int32 u8CharToCodepoint(const uint8* source, uint32* destination) -{ - uint8 leadingByte = source[0]; - int32 length = 0; - - if (leadingByte < 0b10000000) - { - // We have a one-byte UTF-8 codepoint (ASCII) - *destination = (uint32)(leadingByte); - - length = 1; - } - else if ((leadingByte & 0b11100000) == 0b11000000) - { - // We have a two-byte UTF-8 codepoint - *destination = (uint32)( - ((leadingByte & 0b00011111) << 6) - | (source[1] & 0b00111111) - ); - - length = 2; - } - else if ((leadingByte & 0b11110000) == 0b11100000) - { - // We have a three-byte UTF-8 codepoint - uint32 codepoint = ( - ((leadingByte &0b00001111) << 12) - | ((source[1] &0b00111111) << 6) - | (source[2] &0b00111111) - ); - - *destination = (uint32)codepoint; - - length = 3; - } - else if ((leadingByte & 0b11111000) == 0b11110000) - { - // we have a 4-byte UTF-8 codepoint. - uint32 codepoint = ( - ((leadingByte & 0b00000111) << 18) - | ((source[1] &0b00111111) << 12) - | ((source[2] &0b00111111) << 6) - | (source[3] &0b00111111) - ); - - *destination = (uint32)codepoint; - - length = 4; - } - else - { - // return 0 indicating that we haven't converted anything. - return 0; - } - - return length; -} \ No newline at end of file diff --git a/Libraries/Otterkit.Runtime/Otterkit.Runtime.csproj b/Libraries/Otterkit.Runtime/Otterkit.Runtime.csproj index cbc663ec..c663ffd7 100644 --- a/Libraries/Otterkit.Runtime/Otterkit.Runtime.csproj +++ b/Libraries/Otterkit.Runtime/Otterkit.Runtime.csproj @@ -17,7 +17,7 @@ Otterkit.Runtime ./nupkg Apache-2.0 - 1.7.85 + 1.7.90 Copyright (c) Otterkit 2023 Otterkit Authors Otterkit Project diff --git a/src/Otterkit.cs b/src/Otterkit.cs index 0898a93c..b27b6409 100644 --- a/src/Otterkit.cs +++ b/src/Otterkit.cs @@ -5,12 +5,49 @@ using Otterkit.Workspaces; using Otterkit.Types; +using Otterkit.Native; +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Running; + +using System.Runtime.InteropServices; + namespace Otterkit; +[MemoryDiagnoser] +public unsafe partial class Bench { + public static void Run() { + BenchmarkRunner.Run(); + } + + [LibraryImport("nativelib", EntryPoint = "DynamicAlloc")] + public static partial void* DynamicAlloc(long length); + + [LibraryImport("nativelib", EntryPoint = "DynamicDealloc")] + public static partial void DynamicDealloc(void* length); + + [Benchmark] + public void BenchmarkDynamicAlloc() { + byte* alloc = (byte*)DynamicAlloc(32); + alloc[0] = 10; + alloc[31] = 200; + DynamicDealloc(alloc); + } + + [Benchmark] + public void BenchmarkMalloc() { + byte* alloc = (byte*)NativeMemory.Alloc(32); + alloc[0] = 10; + alloc[31] = 200; + NativeMemory.Free(alloc); + } +} + public static class Otterkit { public static void Main(string[] args) { + Bench.Run(); + if (args.Length < 1 || args[0].Equals("-h") || args[0].Equals("--help")) { DisplayHelpMessage(); diff --git a/src/Otterkit.csproj b/src/Otterkit.csproj index 68ba8a73..59c527c5 100644 --- a/src/Otterkit.csproj +++ b/src/Otterkit.csproj @@ -41,7 +41,7 @@ - +