Z6)eRdIC$8RbVgGu5v}9
zT-eKvJ;*GT>Jz*+O;c)Kj2t$$i5g#&X=^qFv0+G?T-oxXZLW0dbN@GY4q{iMS=M!+
z_e~>las~a+vvv91UB@>c-B{;0nP_-~R0fSVlVc-8-9kkeInlJsldpUB)`88RU1_u&vN
z?pgmGd?qHkKgCs;3zK8^aJn2Ixe;Fg|NAQW75GSO4coQc9%?MUXS`@ECyLncnesl1r5o0`p1k6%PT
zd>htF*zsnOs#)98AztYi7^+j%?u-s!#_T?NtVAKT+hqWfrbTie9Wv)t2^yLgkc
z+k88!)v+wXspSRON6nUY>JVfL_!{%_U+m9ZyVD#;v|icu;Ey*`upa#T;WXPi@WVmT
zDqHKo&wK&=@0SxJ%wWB@oFo^7+IuydIZA9{q&kU1%%9p;=+Kf!ASNvXTDSmi_8WY;xW%Z-)s>ZhN>r)yec!-xF+oT_+v4-_4{e$_SSc^_Xkx?w{T5~V9<
zh)F+s5uu!VaL0y`ezh-F)#TRUTiYzv?y7p0I!2n(%yxV9q`Km+?X%CO>Cy5J+3V&K
zvkY4AP-xa49@By}IkL~U#Q#yAMbklJzy1)Ik$AQdj8*;hw;u|tG=T0Dh`!@$r#@a_
zo>RLt$LVD1rmL>29h*dFuY)be9h2`U5a+=6O>bkoNN3(Q
zu8#}vQ5G(6AJ@B&&1=nFc-Sg=Sh)j=ocy`{Bs={1`0JziszcwT8xJCw@#~H2NjNvz
zyWRvFH-2?-U0le$9Ny)F;H!CgAK$O+lk+z0@RBCTuo=>~v1MW&e(#n8i!yBWZpz(d
z{$YAj-4Ug{0U6s%lK`@}s&zImjneC(shAjfjG@|gIacIVRWBT;(|KJTwF(xdn
z@Xl2u=;t`{I}z@j^u1C0((v2a|FK9((_~o-?!zG+-(!B-~J
zrT*w>@k`qp4a0~z&bZl$%`kc$I7hJ=M(W%gw>xN
zNBt~Pov+>d$UT=ci}R06d*xmaLEY?uit0mmL9abwR07>YDhc}iR3Ryq_IP`6d^yz5
zyPK#bQ*UkRT-Qqbw>jYWI!O{S46CWW7G0&hR5?;K^u09YKQ-wh`$}F+dF9xC@;dTG
zS0}#A)c6qoQ{A`}8#_$C$d=1`O-s+?&mmt^(;Gwz!Yg8Zu<1v*pS{=>!^Ry!Y
z%Qe~?^UEKjzjnTgHXL^7uUCi+`(m7_7#R&+MwFnM><8;(VZZ3dyZ!|2#4AU#*{4da
z?}J61`D5-iU)$GmKMyuju`?W2f=`gKS&kWA4tBGI{EWPv;h62E>>xce(|R+%>QRm-
zH}uVzB9)I?iZ3@DGj&+U>{IEou){I)4R)niuc4T63s72rYTW3(c
z>N^&1!HGm;e0(5S+XWe(JZtFF&?K
z_%*N4%#7W~-fWx8-{0ykYWmr#a0dpe$Ix`$FupK989f};cAzubR0U#ndr9MsYd;p@
zpK6KD_!6x}pne-ziO`8&g9pLe16!t^uIg;$`>dEq53EbYn>~j}1S!G1&Fb
zgcUngs7^3rpFeiHjd$cS2<+k(d_X2(AG$KM8qR~{N3ta#XYR?{%h$+K85?5!Wd3Vc
zvPytimBTo6=5ihvc(k)3PtAKIqH2}6c$}`hKA!G}+~yjlw6n#&nqU-!{m`41w|
zwg#btQ+*hC9}&5w4|29c2=b^lrXOk^mEH)ifZYhc$aoMupu$$W)#~tHzaPR
z!Pkpe`k;MhQ0f9F*)ZQ0jfIEb$%wH(jm!?aJ(;uCSM$!yYty6p8S-d(L#5|7ag@+pFA{MONyeFQ@7yx_z(BaRM9l
zS4mS%0VhpGPV1f25u9^(<-e0};F{7q`5xJ6;RM%BOGjv5_7reBFguF}iXFpa_{IM8
zTfo_Nc~&?3bz|!fRS{3kYEq{m@2`9UTUk%+EBF&^yT>|fS0Y#`>%f)WYx_CHX<*`*
zdIxl@Xy-n-{*=6soGX@xIPSI1MNed#7{-iPw}~P71SD}vuXt^e`pM#&e9Jq_q=b}+kV<(NwKbMLnnik#5AmjCFyY*%@TyD-tHM2fS@j-?sqrw8k2G|y
zK`M%gmdoyzR`pF{K@QBy(1Rh1(;c}{U;AJ`acn5)y2QRCX3?O{!YoPM#~
zO)(X$;cRx2o!eVeQ@ym$nmmq0idNm*29GbtTm6Ag4{v(guu^4U&Tcn6u1n)xZP)A8
zXQ!t3nEm{8=RKDPy4-bcKjpT?-%j3A8FF_&OmzjY3{0u9f4r47
zq^>KQPbQyU0_~*q_f*8%oPKpJ1b19Na`#}jUoZr__RlPOyB4Z-g$OE;T&Q+j@ZpHc6q~6pCZ6_L{Z`mWVr^{xE%r)+i!v37HkaekLE
zHDk6H!tUX45ZZjWdGGTvqr5gP33?v=HRtJ&2O*W14@rbse5;Yc0U
z{gO=P>n7>q{>X;tC)*(JelH=i<}KI9kWOIUuZ)b)P#k5AxbNq>SGy0Sg-WnGLtb(b
zOVv`#u&uwC=KPrI4}CEy6`2!z!{$BVl5FT^7;0*L+fmB;bE!kB#G7HLtqoJgP&38N
zeJc@sfE$xHwmW>f&F3VF=-SMcR!T{KUkEg#wEVeSY2E=H`z93H(i
zcx7zG$)9-*ELRG!2#QA(HSe0m82_!v?GqKNC-=(k!R*fdxbU@qw~Z?N1Q8Y!lT9xa
z>EcCV+4cM5MTR3@rfxfU$(x=QACf1JvDvL@&+h+TOx3GA8Daw@UBsr%!#cWalYh8NdRC0~)UzW0AG_L`Mzm;3dh
z?!Zh@!pPgn_l=d2zCSOjOBK63Ma=xVSBd)LpB7g#&!0OG$v=`^)x240{zgAO`zfj{
zAD`D&gXMk7l%($WDOu}vW277FQ+lIUDQb+5(LXGHdYfjvs5@QH{(bg+%E=twMO4%S
zeXmS(oqcnspUImkKi}5Xsukrb?sy#;U4B9ne$A&hb7L8k*Y+kQ=(P3lkzR{zbB5wW
zg+M-c=Cqhu+2I&zx+K0v8;TLpLm8gIIv6R2oeJ0SMquyh=vsq68;`iAJ4V-_!C#)f#+qe}7>n82Y1#g4h=d>I#OO2|z%
zH3VI$Hz_+lk4e0#lvO@ZA1>aF7roXr?Kupb{Srz&5d8}qg*>j
zHw%MER%aay=sHsEvQ!MvQ|Q}R7Nz?QuB@|o-Xdxne5_jkaOl|BOUJPiM`YHoB1W-Z0Hh2r!{B1%jGo3MwjZMybTi!#D3IM=;UQ?Lz$8s1tJ^tNyh4TI=;I!fUMJL
zti8tCC#3BU83!hIg+nAicwHQHeIr($zKw%!J&{A8Q(u!pxwhrkL$Z%Do+rN^-1xms
zJyZtVx_!K@$%pUkRk=Ji?3!z{r@5cjUHayA()!B(J=UfGHj0zE(5AiJv|&7d&gMF5
z=~)WLD{brQe6Uo-wBZHVIi@PM}_UqEFjIr13;;zd6CP{6qNNXN?
z#ae86Vn1Z|?q3@1(K*eV_v2oX845Ykq2ltrEz9V3`KFKZ_z&7E%4||3zW-`GPt3s7
zHe0lOs+(OVbfvOAl`4Z`cYY@G6WazfpNS2K;-S7b30{s<#sDpZ=GWeYk}#kX2#wX$
zO;kdakIR|g@#5ei@6e5f;!DNGdXw?6Al}qYvJ;~?I(0Y2pzJ5h+qtyIhr(0?A2`E-aIzG{q^iuv-|0!VG#QsjdCE?R7_kNvmb-Iu+YEF
z9omutq{ZzIG=uc%5
za|U#pn0j|FUP&xmd83b}DR(WWcV-`vu_lU8&X3)Q>U_<854@S;w@7}7Zew&~g5Fmr
zmM$WC6i2QM+Z}5!-e#DnZ+r@vDCU>~Ci}PAEvlTL)A5+-Q*2%&@BX?=4UwVz-i+6H
z9wRZgJVsq~MU$~3fLQ8J_UF5#zsN$l{c$|Vj%c3}b{x`9nft}k34C^r$SD{UFKt;R>$
zqMV%=-?zrfFbPA9?%A*J=f3v6MHBd#^wm9U@SE;<>?N*?k~;z)dhM_;=Vp1dbCE1B
zo4T}%@zTDVV;(S5A7?blSsxQ#NFC6zEa)bf#PkI=!Ne!#%YTzM#$WL)%qDN*n^{VF
zlRVLvEu>x~nvGokB8zyimr0xz%d=b`kBB?ASJ}j__fYmidCyX8`yw8yo6hIP#*B^E
zzA^t%T@SJSEbj;)JE3au{8#>)WzDH!sIZ#UvS0(hb4#Vq?`Tn_$r_X{
zaZNWh-);OV*|u=gu4!3`u{(RWg%h20%v40^J=qRUWIm9uDe@qh0y6C-y%&>IXSe=W
z&I@=2NBi@lZ=9GeT~zQ
zmg$E>^ElKSM_;VJ?Q_FY8|1)w8l2pZ?dw}kR?c$j*s_NK9*$L^eJD<*vZFlN)4&&B
zHRArzhk9RK5QU$$k$>va3%>5(J_X&(gp=a0Seb!`;%D%cNA*rtsdw3Y@;Z<
zYhNEfv)P20o*-sU(NGREHR4#C{hJVSmGnBYd^QAErvj;dJjLRID6K8|E)&XLKowKAtA@+7(5nd%F?$eY6Rl{!a#{
zc4o)}rw3&5>r9w|4YoAz$Dy8t)nC`Ax}SalI`l*Cp3-OBCj~}*mbIX7DwP(D;h!wS
z0nEDT4d<)Ml{Mvf-OHQeppO4o-SW$Dp?l$Gj;oX*-G2Q2P?CYy{&4|^*U93>(x?3|
zahReGCVJZvPF)+FstjM0+-*M|Y~?;PT-sP@2SJSb^}4W=ZzRqCc0xsb=YMCx&Lfh?8u@wF1}Jz
zzIoJ6y?*_9pC^#o|TE^K60%kq`N^SdrQ$nBaX&^X4wK61fY_t9Vq~5#rnMJ~^T1
zMf*ca#{^GAHR4kIs=ha&66%{S%a9YzHnjaiwg#bjOL>iM9Oz#MhcaUEE*#imjGw4V
zOngn%je}n(%JLA=W7k!y_C7G}I*cA`bV06NQ}`X3`(sj_ZM(;FUOD^@+_9=p{azFM
z?fbEawRK{BEabbE;)}C6{cw(-@RYPSF6S~M`>tI$P`N50^U)3aezIew_^Dkuyfz+!
z{xK$x`lYxVcJHvwHn=qYhl7yeQX=WDcOcsoaTmvW+(eCwO+@9y2ig?Y_os
z=VJ5g>{yc#h*uwcCbsL>pc26COR4Tc#lWUSb<&`t$5oJGPb{{OaUGa|hmhtvK
zJWzNO~$VrPHvhb46^VTo4}H@3eYmh_IJccN!7?uRAw0P*rPbg8o=0BgV&
z=lmHL+3020E#zafDqrvH1>M&V(d~afO-hHB>R7vG_kKzpLiE@+I}qg=DkCm=q6W*Q
z`vb#}j(`4*E5rNvQ7d3g*x8=JeaQSZx6^0?Z42}ml^z6LXQK=1hdT=V55q!l_Lv(t
z+`HiB488_9Xg?slrR#otuf63bV}~Xnr_-Fi9xo%+o&urMOn2FuU+1DBx7rrJ_PxCe
z^CKBMuUGop{my!1*~{_4XvI#|$9yR|FFzZE`CaBO)nak>lE#W+cQVZW5naY)WASpo
z+))}CpYO{=N-m7jZ;1O~XewR&Yj!e5>=EQ%4p6h-hprXwon0GEb%%y{
zLERIXopGTRgh|8SvICI9n=1bzYX39nUYv>Z5K}P8l5S=
zsfj$gZfNAoMtR2rofPW5%WpNN1zF^^jE^!7cwXFt*4>Pz&Gfedr+8J$OS^9wn2aN{3xZ}Z0ZuK8Vm9egrL5|Ns48Pl$}p+s(0
z<3PR|uY`)=_&C5T$b{;wyNP%5=T3Jt7m^;U<}?g;DwoPCM#^3ch27^XvxXf%S2zrI
z`qLDHmq&N3fbJ*7>Q)&>dG*kuV@iacnxsz_MXHW{Nw$h?J`=@EN})N4z1!b8u&*-(
zmUX9Y*u}aP-G+G`Y~;%}vpVBzq)o9Q=9Z3%q+d71=9T$I%IHMWxSM06KAmZB8rvJt
zX4B9DU;~d$<85Rw$-%{n&^MJF^#fr4$K9q(Eca6*CUT3oXL?HAU%40Z@ok7hN7m-6
z#ht{?%{o1uA>(%=41rR##Ey*>-LHbuH}sAxUqhf&WIm=hFa*l+vxyGnk$JniOY722
zjz*R)f^=)b&Z~StN+!@@rQ--%zDi!;*wQl$R>ekR!+M&cp>xaFWopt>z{|(5I_%=$
zTAIH#`$NdMjhn-AxtWKK4d!?ts^X0Oy41vv>=%^{r=L$SXxDm72(?dq+zs3Q!u=f`
zFO3hS!N-i#hQNuZ7DZy3Q#IT;p;qwOcvO9sR1)4=UZ$yy)HM@>#$=6@IT{8#9!LyL
zwJzOdpUQ-tdHp!P)kov-PZmRcHg5l5oSkuuIldu!Gy1DD
zC8NA0amv^}EZr&WIdl(uFJiNJ9$U9EzV7=TC_
zYDVD0uD8~XeAf@Ti#(KJM(X;
z-{i*p$7_?dL;LeT>_6tRsjO4OJe>WTeT6wfzD||!qsb(F6>M*0P8Ip&vfYnnHLmXJ
zh&!{t&Av4n5Ys)gzsrQ)j{R#)@G&L58dAmlbUz|PV@r7-MTx7Wiy~O=RZz02H8L%w
z(X|76$2gB}s4=;-Yo?qo_Bg(8H-wrQk5Mt~hETPb7!abjn4CE=Ekz8$q~!e9bb08|
zzUP|WtMTJbF}WV4PnfPP^zl`KU(=uT`C$2TWX?tebd_pi(yNc3Ihcp{ox$CV+k7gC
z=q)OYiqV@J2IJ9jKgGY}Y@zJq&GuW9uf)P@T3>ISr>5Vg%_v_VbX&(TIOU0um5EGE
zpk#LrP-c%L9$(@&5p%?bk~kAuM(0hesVaEUc=OEi!tAzDsfq+$B0bVg;`t9WNGJZLrj>_Xi!*}-=g>~
zZMyf}aMT8U`e@>D_Ye%2iBsJq5|0mq+^dZ_Yc#%e4uf1h58XC$EEydJx%weuX_q08
zQzyc^D-UvfedWs{S^Xh2=RS~p!K@v}m(U}N_KEIu>`V_N5XQ3eU2v+36CF5
z*_1_k5=YDS@p}|sX%SB9plE<*H+DohVqTONS09V$8OPV}qO0m+rNB$IQ8p~LTw!T7
zRT?wX%l6*IyVJ^3MY6F>>NU3@i>9%nqVL`iD+R4JG(CBM&{dtZ))d?38g
z)V6W7*gBXXeY`>}e_=fgkU%0mFB;9I9cU=Kksd$;0ZaAr7XkTWOXt4`Uzm<_a
zu<`j*edaf*56=5Rprj;e%=}Q^c*WM#JSFQ;5_8Q*-;Z$-!)xqA;G6eX9}~V~>jFA4
z|JwV2KHYT!sn4^ik35r^bw3+k$i*@BMCSYIQEF-@#)p~?+BMjjfS}qsKMR4^Nu=G>
z^y5VWzF`W8+2=$z>5cW%lFj^*DCiuEmji{P!Oe~_<|G_WvIJ;U_0W%nI6cJLQO?Kfnr(?DEBgSTpw$AT@mW^jbcg?N1
zkKYBn8csGj;X5lLkw%ROCv*DfsA%v1-ZrbKXMwB~`HAK%6@Ij0{8*8mPrK5;p7)#5
zVWB?zXnJ-TyyA*j_KWKEsZo}=ii{f>GtZ|)x^I#7!!n4qQzk~2NE>2J1?rZi)0b?Z
zGQrrlI6k5#7RjM5!ixqjg}(HQs$U_V%ysbt-L0xzl>smN_9Dg(ef*1dz{bVs{%Gn4
z^<{A>@YwXQ>~pSjP%lz%e~f)AO~~2pO&^qMGgxW#MuwgE7mp$y%~wH=^@F>KJY#9+
zRgja#k!6XoTRrm&+=1_TU=^o)@gUp7n6WbzNTALBC-SIRgx}*>ZuR~kjciZAej|-e
zUwVBM^T+b>S3`{)Qag!6>uaMicU*}<^Nw!mYAPpqc5ygE_wBiyj(y3qDrA8o`W)8=
zB@xMSvMpTYdVj~qXf-$@njg9fW_;0jFtc|>_d}X?8ykY%Q*T-%KJJDWd5aiJ;A~gWl2f#=7vU4j+eKhQiMz9Q4;jOeFX(O+MN7*5(#$VRP?IgjyZh
zqpuC$pA4P!bgn6mnXy%t3vZMx7n|_#>T;|?P7$hRXd_Vdvsps#zss=Fg{!Iv6pq8M
zebBy1RE@FMG{+;|(8~77D~jcF{$f1Krf>N7#5(rc^IWnW(drJXU{;1M7M<}o@t8lR
zEzDnSo14>`DX-@Dh_JF$Du1V`5Xt12`mPP>a4g8#U<*sfgWd-DggKuY>piZM1v*Xk
zU9s7P-3&P}uDeXU=aD;68rnYYiwwntnXhTQ34Jrzh$wFY&ye-u4urb7cM~7Azvdi;
zw~ObXoj2p_sxIgq58ZNYUei(CAqwn*kKTFR)7drOQdG}aIo*|;ZF`wx>ZC>3(MFdu
z_84coMs$jWj#h1_@8)NtI(Z^C#vZ1Ru+N&w&s5i4zjEQ%3?b_h=tz3bo`1L(eP(b`pJ-lIrTT`|ik2N{!~ZU2n9xB#CH>>vkIkh{f$kwz
z9Dl2K-wX6(@andbUoHlITdiCS_ES_)E*Fv6A+Cv!0aYdWaAf|PyTgeD(4ol3m1&D&J(gPop6Dzh=J
zH}+YfKIpkcr`~zRf4gR%;$=Ykp;yOM?5Lv;dN>AeJz6*HFutcR2%agE_Grv9c!zC0
zp8fl1K7cm(G<^YWK8sTCndhF>@Ke=A4r2Q6WPew`z<$CYwns^aBHNU5)G9w%zmH#Q
zYjcjeqVRj!x^-oK@XzKuoTmzq`;}BWvAr?l?jabIQNdaV6UE|D^9Y|zm%cTgQ4RXW
zxQc!|W+>P%*6f$pMbv2XL2Vhy*kBosOiz)Q&ABx)%j6egYSs+Bf8=uQGfqAQ5TBd!
zzHPg9N?!&-6iS<*iHEzY}~2!
zDZ31yd6XkmWFJQc9BTdPQv>9v@+6wqc4OR}$Wiey*gYnW)p0!pb~+1HON^CQcGy)r
z(Kgh~Em7yo*-h*G&78w-@)F38;5qmP*lcf!D%DXQZJvs`f};dKe;$~oAr??oeZdi`k@v+U
z&Lr6VF!5gJ?Y_x(#uIpASJuJ%x7oL*KlE$IxaG#aMjnBT!>;}L&N_g1O@bFWOa1v$tAKV_b#;85413CQ{#H-3nM&uRUkU_um(P!fq^1iu-=+}+n(taogF?NJ>
zaSz#=clN7EckP?kmh^~x)3w+4V9xe8GiOKwd4mXfo31z53?J==p2GWRsx?MlXB+P$
zd}8!ob>Y+A*sRHwvzFc^MsIE%A1_ba4L|iDG!_x>;tpqRf_!b3Z~Q$mUGQ^zj5$y!
z4;J+AYomU)eMonlYRjfraI+@1?j77+$
zqPZy8^ht<0m3tm9CSC<2d;*M$k0V;Tt-GRWif+;!`A>PN~3
z=A1vdg4jMVns5g%%zP||JI2MM;rva01OARNL$*HL<FkPH#lN3@r35O*S?d1X6aWz6|9
z_B1K)6t#wcRN`h&7BSHt3A{o!
zgRvc&4%xn)PUtS>z5bmteu)`42A(OK13cc_M*q=v
zEO!?k?~{JJNl}SwG^PRR1eRtV!-5Zm6wZPFV{9lH$~#>&hhvBUwQ(h4J!A1ru#3bC
z&CI0pkS?)oEB4-AC)gqu^IB;)>8EDb0J#LXY~0OrL%EB6GFiuVV>A8+w{2lVwLyMl
z)V_!z95>H{Sbg25!5g4klz!gNW;b2Fh+N`U_q%ZZYF@LZXP9_rh913fWPOZp8<}3e
z;8adjaBa{J!A$W^JRQQNV>$!ah=IpRjMKaWiARHH7I!*p6$aWuf|k%exro*^c#&Q3md
zO-wEt??9b}5nqHUcREnn*Tc3vI7)FQ9jaGmU)ozcxzdvVhU2NMUfhVf33DHo?y0^t
ztApp-#G!cU$2>OKC*@U?`{Zlv4t1WQ
z_asgw?%F)$cXM?KvbJ!>N5kRRERQnl^Ap_UZQ}R`_roJjWYC8P{^o~UZIw9*`p4MT
zvku(a@DwE$TMu%V-53_FTXws61!)E5m$w@m7?
zx-}&E0XA*qs7{>(Oie_!r1LQ2FRJ@8u8&UNC|*m>#ISQ!9prI6#V)87RVWgbr!__%
zugk;gg4Vlx&>``mRmQpu+5%;qUhO{ZHZOJTkpSxEm4mqaOOFv=M=2bktvcmEi@hiX
zTAu?fL6gyWpbmsmpe;wrn8HvJW(mw(G`4LS>M?3e1N>P4i|{hQfu
z?WfL+!*;Brgm{F{KBm7x#Z{e4#DmVQ-Z>#_auCWKt9erI?SyG!Dj
zUT5zclR^jS&)oY+=Y~hfuW!9xQC#(PsK~8&HukZ@>@jG(IR?5k!OQ?WQz8bwS*=_Q
z$XEdVIIp1H*(YXa@^zA?b)jbwO|9IUpawSlmB0LO@A|uadM~ev0K_qp`GF5b6OXK+Ts)qLVAjs
z$K`qjUdgH1M}JpcSR?XMZDo6O9nN(>8e~`2+w>QM>+i`MIJMt(nT-B=-5CJ(bMp`W
z%f5p@E^Gfo;*^sHr@S&uh%;`Iu4Rn7Pjef1C`(p89uabqtKQ>l
znw_Sy!aOeiclJD(Bq5I#(Q5yvWjC1m?uLBdJnX2D|HXVHY_zgB&6xo5!(`aKlaYx5
ze)4x_+25LP_(%JU{vhI`hpdb(=b3)^r9sPuU)=5$j$M<7vgohQpgiH2;s3$x#ZAf?
zVma^+wI3}a7imjX7Z?37`!Xj7G2vIVS*jE(BU~>1rTM$ykEBJhwI?QvSN5m2F-q6u
z>G5obxf?;W5ZNPI4PL$y39GR{8q@*6ip;|Ida$bQ47a?cko4kd%`s4@8W`3Rh+3Ln$8!=XQrhtD-*R=_yayT9E3-iKp)g;QBPsG8Xq3o#k7dwn6J})S
ze=*vBGLVWH>{Cr6XWh=UT%#X`kxGTyaCtdes?0W53me&`Gj#Lb`|WAwfX-v
z4MQi|hr}~o9jkG>hlx$`c`wa=(z~~tqSfYCB*)55>E~P~RGrv%tOO;gCn$Q@v5eTa
zNoPMZk8sDn$DAKkhNA@Sa%o-gHY0s-l*T;a_L}OceW=H1b8FT#jwnu@yVB
zIOG-CSgyU&%-LoRRmCZ846!+GKHEJ-+~|CnE>G$LLg`wiTjKCcwO?zBd`ZR`A8M*^
z=Ue}#_;&1|nl5M3iOs7`lQYR;Mz4QvZpqn=HeGwSXD>J1x1)|aUAY6d=<|x3%N=#&
z=#|&|V5e)G)3gXoB~aO#CU#`l$FF|rHwH9lks$@H?xO>;>{
z_OT|4@xrxDcdR=1=J2bh4^LaO1CcRczeKLB0lE5>#;vXmp?w>2EQ8{1rW?lVHdqZg
zwOFp2@+Xsbu2qSv$!KYkTRii4+dS?Aw>C-$`f}iA2Lqm+cBsUa(LR15BE*jzBJ+7S{KPQo$ck=F*|x*H2+`TK
zc{I7Qi*6?h+cpMFaI?Lb$O)b$2E4GU{E2
Date: Mon, 12 Aug 2024 07:42:09 -0400
Subject: [PATCH 4/9] try swapping order of EmitPushValue and
CreateFilteredBaseTypesListEnumerator
---
DMCompiler/DM/Builders/DMProcBuilder.cs | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/DMCompiler/DM/Builders/DMProcBuilder.cs b/DMCompiler/DM/Builders/DMProcBuilder.cs
index 640ab45802..52ca056594 100644
--- a/DMCompiler/DM/Builders/DMProcBuilder.cs
+++ b/DMCompiler/DM/Builders/DMProcBuilder.cs
@@ -602,6 +602,7 @@ public void ProcessStatementForList(DMExpression list, DMExpression outputVar, D
lValue = null;
}
+
// Depending on the var's type and possibly a given "as [types]", an implicit istype() check is performed
DreamPath? implicitTypeCheck = null;
if (dmTypes == null) {
@@ -610,12 +611,6 @@ public void ProcessStatementForList(DMExpression list, DMExpression outputVar, D
} else if (dmTypes.Value.TypePath != null) {
// "as /datum" will perform a check for /datum
implicitTypeCheck = dmTypes.Value.TypePath;
- } else if (!dmTypes.Value.IsAnything) {
- // "as anything" performs no check. Other values are unimplemented.
- byte typeId = (byte) dmTypes.Value.Type;
- proc.CreateFilteredBaseTypesListEnumerator(typeId, dmTypes.Value.Type);
- // DMCompiler.UnimplementedWarning(outputVar.Location,
- // $"As type {dmTypes} in for loops is unimplemented. No type check will be performed.");
}
list.EmitPushValue(dmObject, proc);
@@ -628,6 +623,9 @@ public void ProcessStatementForList(DMExpression list, DMExpression outputVar, D
$"Cannot filter enumeration by type {implicitTypeCheck.Value}, it does not exist");
proc.CreateListEnumerator();
}
+ } else if (dmTypes != null && !dmTypes.Value.IsAnything) {
+ byte typeId = (byte) dmTypes.Value.Type;
+ proc.CreateFilteredBaseTypesListEnumerator(typeId, dmTypes.Value.Type);
} else {
proc.CreateListEnumerator();
}
From 1657d6d225db807a5f4e1506d81a2b2b161c045d Mon Sep 17 00:00:00 2001
From: Romayne <27376947+MeggalBozale@users.noreply.github.com>
Date: Mon, 12 Aug 2024 09:21:21 -0400
Subject: [PATCH 5/9] Reorder things to be inline with the current code.
Requires an unnecessary second bytecase and a unnecessary null check, though.
Also add annotated bytecode case
---
DMCompiler/DM/Builders/DMProcBuilder.cs | 31 +++++++++++--------
.../Optimizer/AnnotatedBytecodeSerializer.cs | 3 ++
2 files changed, 21 insertions(+), 13 deletions(-)
diff --git a/DMCompiler/DM/Builders/DMProcBuilder.cs b/DMCompiler/DM/Builders/DMProcBuilder.cs
index 52ca056594..dcb63adc2a 100644
--- a/DMCompiler/DM/Builders/DMProcBuilder.cs
+++ b/DMCompiler/DM/Builders/DMProcBuilder.cs
@@ -602,32 +602,37 @@ public void ProcessStatementForList(DMExpression list, DMExpression outputVar, D
lValue = null;
}
-
+ list.EmitPushValue(dmObject, proc);
// Depending on the var's type and possibly a given "as [types]", an implicit istype() check is performed
DreamPath? implicitTypeCheck = null;
+ bool alreadyCreatedEnumerator = false; // Keep track of if we did CreateFilteredBaseTypesListEnumerator already
if (dmTypes == null) {
// No "as" means the var's type will be used
implicitTypeCheck = lValue?.Path;
} else if (dmTypes.Value.TypePath != null) {
// "as /datum" will perform a check for /datum
implicitTypeCheck = dmTypes.Value.TypePath;
+ } else if (!dmTypes.Value.IsAnything) {
+ // "as anything" performs no check. Other than that, all that's left are type assignments like `as mob|obj|area`.
+
+ proc.CreateFilteredBaseTypesListEnumerator((byte) dmTypes.Value.Type, dmTypes.Value.Type);
+ alreadyCreatedEnumerator = true;
+ DMCompiler.VerbosePrint($"Created CreateFilteredBaseTypesListEnumerator");
}
- list.EmitPushValue(dmObject, proc);
- if (implicitTypeCheck != null) {
- if (DMObjectTree.TryGetTypeId(implicitTypeCheck.Value, out var filterTypeId)) {
- // Create an enumerator that will do the implicit istype() for us
- proc.CreateFilteredListEnumerator(filterTypeId, implicitTypeCheck.Value);
+ if (!alreadyCreatedEnumerator) {
+ if (implicitTypeCheck != null) {
+ if (DMObjectTree.TryGetTypeId(implicitTypeCheck.Value, out var filterTypeId)) {
+ // Create an enumerator that will do the implicit istype() for us
+ proc.CreateFilteredListEnumerator(filterTypeId, implicitTypeCheck.Value);
+ } else {
+ DMCompiler.Emit(WarningCode.ItemDoesntExist, outputVar.Location,
+ $"Cannot filter enumeration by type {implicitTypeCheck.Value}, it does not exist");
+ proc.CreateListEnumerator();
+ }
} else {
- DMCompiler.Emit(WarningCode.ItemDoesntExist, outputVar.Location,
- $"Cannot filter enumeration by type {implicitTypeCheck.Value}, it does not exist");
proc.CreateListEnumerator();
}
- } else if (dmTypes != null && !dmTypes.Value.IsAnything) {
- byte typeId = (byte) dmTypes.Value.Type;
- proc.CreateFilteredBaseTypesListEnumerator(typeId, dmTypes.Value.Type);
- } else {
- proc.CreateListEnumerator();
}
proc.StartScope();
diff --git a/DMCompiler/Optimizer/AnnotatedBytecodeSerializer.cs b/DMCompiler/Optimizer/AnnotatedBytecodeSerializer.cs
index 9d92355fae..cb1dda3412 100644
--- a/DMCompiler/Optimizer/AnnotatedBytecodeSerializer.cs
+++ b/DMCompiler/Optimizer/AnnotatedBytecodeSerializer.cs
@@ -140,6 +140,9 @@ private void SerializeInstruction(AnnotatedBytecodeInstruction instruction) {
case AnnotatedBytecodeTypeId annotatedBytecodeTypeId:
_bytecodeWriter.Write(annotatedBytecodeTypeId.TypeId);
break;
+ case AnnotatedBytecodeTypeFilter annotatedBytecodeTypeFilter:
+ _bytecodeWriter.Write(annotatedBytecodeTypeFilter.FilterTypeId);
+ break;
default:
throw new ArgumentOutOfRangeException();
}
From 13aef79f0f394cee6fcbca94462ca4b5d3eb0185 Mon Sep 17 00:00:00 2001
From: Romayne <27376947+MeggalBozale@users.noreply.github.com>
Date: Mon, 12 Aug 2024 09:32:19 -0400
Subject: [PATCH 6/9] remove excess whitespace
---
DMCompiler/DM/Builders/DMProcBuilder.cs | 1 -
1 file changed, 1 deletion(-)
diff --git a/DMCompiler/DM/Builders/DMProcBuilder.cs b/DMCompiler/DM/Builders/DMProcBuilder.cs
index dcb63adc2a..2ed16a4199 100644
--- a/DMCompiler/DM/Builders/DMProcBuilder.cs
+++ b/DMCompiler/DM/Builders/DMProcBuilder.cs
@@ -614,7 +614,6 @@ public void ProcessStatementForList(DMExpression list, DMExpression outputVar, D
implicitTypeCheck = dmTypes.Value.TypePath;
} else if (!dmTypes.Value.IsAnything) {
// "as anything" performs no check. Other than that, all that's left are type assignments like `as mob|obj|area`.
-
proc.CreateFilteredBaseTypesListEnumerator((byte) dmTypes.Value.Type, dmTypes.Value.Type);
alreadyCreatedEnumerator = true;
DMCompiler.VerbosePrint($"Created CreateFilteredBaseTypesListEnumerator");
From 62b73f597aa41e0dc656ed1471a4c95108fcd8e2 Mon Sep 17 00:00:00 2001
From: Romayne <27376947+MeggalBozale@users.noreply.github.com>
Date: Mon, 12 Aug 2024 09:37:48 -0400
Subject: [PATCH 7/9] few comment changes
---
DMCompiler/Optimizer/AnnotatedByteCodeWriter.cs | 7 ++++---
OpenDreamRuntime/Procs/DMOpcodeHandlers.cs | 4 ++--
OpenDreamRuntime/Procs/ProcDecoder.cs | 2 +-
3 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/DMCompiler/Optimizer/AnnotatedByteCodeWriter.cs b/DMCompiler/Optimizer/AnnotatedByteCodeWriter.cs
index d3ca5f9645..903b8aa67f 100644
--- a/DMCompiler/Optimizer/AnnotatedByteCodeWriter.cs
+++ b/DMCompiler/Optimizer/AnnotatedByteCodeWriter.cs
@@ -156,10 +156,11 @@ public void WriteFilterId(int filterTypeId, DreamPath filterPath, Location locat
/// Write a filter. Filters are stored as reference IDs in the raw bytecode, which refer
/// to a string in the string table containing the datum path of the filter.
///
- /// The datum paths of the filter
+ /// The type ID of the filter
+ /// /// The base types of the filter
/// The location of the filter in the source code
///
- public void WriteFilterTypeId(byte filterTypeId, DMValueType filterPaths, Location location) {
+ public void WriteFilterTypeId(byte filterTypeId, DMValueType filterTypes, Location location) {
_location = location;
if (_requiredArgs.Count == 0 || _requiredArgs.Peek() != OpcodeArgType.FilterId) {
@@ -168,7 +169,7 @@ public void WriteFilterTypeId(byte filterTypeId, DMValueType filterPaths, Locati
_requiredArgs.Pop();
- _annotatedBytecode[^1].AddArg(new AnnotatedBytecodeTypeFilter(filterTypeId, filterPaths, location));
+ _annotatedBytecode[^1].AddArg(new AnnotatedBytecodeTypeFilter(filterTypeId, filterTypes, location));
}
///
diff --git a/OpenDreamRuntime/Procs/DMOpcodeHandlers.cs b/OpenDreamRuntime/Procs/DMOpcodeHandlers.cs
index af85f7e4dc..8be0d3425b 100644
--- a/OpenDreamRuntime/Procs/DMOpcodeHandlers.cs
+++ b/OpenDreamRuntime/Procs/DMOpcodeHandlers.cs
@@ -125,10 +125,10 @@ public static ProcStatus CreateFilteredListEnumerator(DMProcState state) {
return ProcStatus.Continue;
}
- public static ProcStatus CreateFilteredBaseTypesListEnumerator(DMProcState state) { // this is also plagarized from the above. make sure thats ok? and remove this comment
+ public static ProcStatus CreateFilteredBaseTypesListEnumerator(DMProcState state) {
var enumeratorId = state.ReadInt();
var filterTypeId = state.ReadInt();
- var filterType = state.Proc.ObjectTree.GetTreeEntry(filterTypeId); // this REALLY probably has to change. seems to be a path rn
+ var filterType = state.Proc.ObjectTree.GetTreeEntry(filterTypeId);
var enumerator = GetContentsEnumerator(state.Proc.ObjectTree, state.Proc.AtomManager, state.Pop(), filterType);
state.Enumerators[enumeratorId] = enumerator;
diff --git a/OpenDreamRuntime/Procs/ProcDecoder.cs b/OpenDreamRuntime/Procs/ProcDecoder.cs
index f9142b3905..dc1eaf3a6d 100644
--- a/OpenDreamRuntime/Procs/ProcDecoder.cs
+++ b/OpenDreamRuntime/Procs/ProcDecoder.cs
@@ -293,7 +293,7 @@ or DreamProcOpcode.JumpIfTrueReference
case (DreamProcOpcode.CreateFilteredBaseTypesListEnumerator, int enumeratorId, int type):
text.Append(enumeratorId);
text.Append(' ');
- text.Append(getTypePath(type)); // TODO: maybe make sure this works / leave as thing for reviewer to talk abt
+ text.Append(getTypePath(type));
break;
case (DreamProcOpcode.CreateListNRefs
From 2e6068e9232e35e4a627c238ec5a186e5c2ee43a Mon Sep 17 00:00:00 2001
From: Romayne <27376947+MeggalBozale@users.noreply.github.com>
Date: Mon, 12 Aug 2024 09:38:57 -0400
Subject: [PATCH 8/9] change filter type id from int to byte as it should be
---
OpenDreamRuntime/Procs/DMOpcodeHandlers.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/OpenDreamRuntime/Procs/DMOpcodeHandlers.cs b/OpenDreamRuntime/Procs/DMOpcodeHandlers.cs
index 8be0d3425b..cb95777daf 100644
--- a/OpenDreamRuntime/Procs/DMOpcodeHandlers.cs
+++ b/OpenDreamRuntime/Procs/DMOpcodeHandlers.cs
@@ -127,7 +127,7 @@ public static ProcStatus CreateFilteredListEnumerator(DMProcState state) {
public static ProcStatus CreateFilteredBaseTypesListEnumerator(DMProcState state) {
var enumeratorId = state.ReadInt();
- var filterTypeId = state.ReadInt();
+ var filterTypeId = state.ReadByte();
var filterType = state.Proc.ObjectTree.GetTreeEntry(filterTypeId);
var enumerator = GetContentsEnumerator(state.Proc.ObjectTree, state.Proc.AtomManager, state.Pop(), filterType);
From a906dc339206e18d94fbff61d770bd879d6e2ff8 Mon Sep 17 00:00:00 2001
From: Romayne <27376947+MeggalBozale@users.noreply.github.com>
Date: Mon, 12 Aug 2024 13:02:08 -0400
Subject: [PATCH 9/9] put this up for now as I work on something else (this is
a bit much rn)
---
DMCompiler/DM/DMObject.cs | 4 +++
OpenDreamRuntime/Objects/DreamObject.cs | 4 +++
.../Objects/DreamObjectDefinition.cs | 5 +++
OpenDreamRuntime/Objects/DreamObjectTree.cs | 5 +++
OpenDreamRuntime/Procs/DMOpcodeHandlers.cs | 32 ++++++++++++++++-
OpenDreamRuntime/Procs/DreamEnumerators.cs | 35 ++++++++++++++++++-
6 files changed, 83 insertions(+), 2 deletions(-)
diff --git a/DMCompiler/DM/DMObject.cs b/DMCompiler/DM/DMObject.cs
index ea65433a88..52172642b8 100644
--- a/DMCompiler/DM/DMObject.cs
+++ b/DMCompiler/DM/DMObject.cs
@@ -230,4 +230,8 @@ public DMValueType GetDMValueType() {
return DMValueType.Anything;
}
+
+ public DreamPath[] GetDMAncestors() {
+
+ }
}
diff --git a/OpenDreamRuntime/Objects/DreamObject.cs b/OpenDreamRuntime/Objects/DreamObject.cs
index 912ba49781..7c81f8d930 100644
--- a/OpenDreamRuntime/Objects/DreamObject.cs
+++ b/OpenDreamRuntime/Objects/DreamObject.cs
@@ -120,6 +120,10 @@ public bool IsSubtypeOf(TreeEntry ancestor) {
return ObjectDefinition.IsSubtypeOf(ancestor);
}
+ public bool IsSubtypeOf(byte ancestors) {
+ return ObjectDefinition.IsSubtypeOf(ancestors);
+ }
+
#region Variables
public virtual bool IsSaved(string name) {
return ObjectDefinition.Variables.ContainsKey(name)
diff --git a/OpenDreamRuntime/Objects/DreamObjectDefinition.cs b/OpenDreamRuntime/Objects/DreamObjectDefinition.cs
index 670299e238..eebd3a104c 100644
--- a/OpenDreamRuntime/Objects/DreamObjectDefinition.cs
+++ b/OpenDreamRuntime/Objects/DreamObjectDefinition.cs
@@ -197,4 +197,9 @@ public bool TryGetVariable(string varName, out DreamValue value) {
public bool IsSubtypeOf(TreeEntry ancestor) {
return TreeEntry.IsSubtypeOf(ancestor);
}
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public bool IsSubtypeOf(byte ancestors) {
+ return TreeEntry.IsSubtypeOf(ancestors);
+ }
}
diff --git a/OpenDreamRuntime/Objects/DreamObjectTree.cs b/OpenDreamRuntime/Objects/DreamObjectTree.cs
index ce86bb4c33..bf351c0ac6 100644
--- a/OpenDreamRuntime/Objects/DreamObjectTree.cs
+++ b/OpenDreamRuntime/Objects/DreamObjectTree.cs
@@ -516,6 +516,11 @@ public bool IsSubtypeOf(TreeEntry ancestor) {
return (TreeIndex - ancestor.TreeIndex) <= ancestor.ChildCount;
}
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public bool IsSubtypeOf(byte ancestors) {
+ return true;
+ }
+
public override string ToString() {
return Path;
}
diff --git a/OpenDreamRuntime/Procs/DMOpcodeHandlers.cs b/OpenDreamRuntime/Procs/DMOpcodeHandlers.cs
index cb95777daf..c143fdfe25 100644
--- a/OpenDreamRuntime/Procs/DMOpcodeHandlers.cs
+++ b/OpenDreamRuntime/Procs/DMOpcodeHandlers.cs
@@ -107,6 +107,36 @@ private static IDreamValueEnumerator GetContentsEnumerator(DreamObjectTree objec
return new DreamValueArrayEnumerator(Array.Empty());
}
+ private static IDreamValueEnumerator GetContentsEnumeratorAeiou(DreamObjectTree objectTree, AtomManager atomManager, DreamValue value, byte? filterType) {
+ if (!value.TryGetValueAsDreamList(out var list)) {
+ if (value.TryGetValueAsDreamObject(out var dreamObject)) {
+ if (dreamObject == null)
+ return new DreamValueArrayEnumerator(Array.Empty());
+
+ if (dreamObject is DreamObjectAtom) {
+ list = dreamObject.GetVariable("contents").MustGetValueAsDreamList();
+ } else if (dreamObject is DreamObjectWorld) {
+ return new WorldContentsEnumerator(atomManager, filterType);
+ }
+ }
+ }
+
+ if (list != null) {
+ // world.contents has its own special enumerator to prevent the huge copy
+ if (list is WorldContentsList)
+ return new WorldContentsEnumerator(atomManager, filterType);
+
+ var values = list.GetValues().ToArray();
+
+ return filterType == null
+ ? new DreamValueArrayEnumerator(values)
+ : new FilteredDreamValueArrayEnumeratorAeiou(values, (byte) filterType);
+ }
+
+ // BYOND ignores all floats, strings, types, etc. here and just doesn't run the loop.
+ return new DreamValueArrayEnumerator(Array.Empty());
+ }
+
public static ProcStatus CreateListEnumerator(DMProcState state) {
var enumeratorId = state.ReadInt();
var enumerator = GetContentsEnumerator(state.Proc.ObjectTree, state.Proc.AtomManager, state.Pop(), null);
@@ -129,7 +159,7 @@ public static ProcStatus CreateFilteredBaseTypesListEnumerator(DMProcState state
var enumeratorId = state.ReadInt();
var filterTypeId = state.ReadByte();
var filterType = state.Proc.ObjectTree.GetTreeEntry(filterTypeId);
- var enumerator = GetContentsEnumerator(state.Proc.ObjectTree, state.Proc.AtomManager, state.Pop(), filterType);
+ var enumerator = GetContentsEnumeratorAeiou(state.Proc.ObjectTree, state.Proc.AtomManager, state.Pop(), filterType);
state.Enumerators[enumeratorId] = enumerator;
return ProcStatus.Continue;
diff --git a/OpenDreamRuntime/Procs/DreamEnumerators.cs b/OpenDreamRuntime/Procs/DreamEnumerators.cs
index b954ea507b..c47d4ec9dd 100644
--- a/OpenDreamRuntime/Procs/DreamEnumerators.cs
+++ b/OpenDreamRuntime/Procs/DreamEnumerators.cs
@@ -84,7 +84,7 @@ public bool Enumerate(DMProcState state, DreamReference? reference) {
///
/// Enumerates over an array of DreamValues, filtering for a certain type
-/// for (var/obj/item/I in contents)
+/// for (var/I as obj|mob in contents)
///
internal sealed class FilteredDreamValueArrayEnumerator : IDreamValueEnumerator {
private readonly DreamValue[] _dreamValueArray;
@@ -115,6 +115,39 @@ public bool Enumerate(DMProcState state, DreamReference? reference) {
}
}
+///
+/// Enumerates over an array of DreamValues, filtering for a certain type
+/// for (var/I as obj|mob in contents)
+///
+internal sealed class FilteredDreamValueArrayEnumeratorAeiou : IDreamValueEnumerator {
+ private readonly DreamValue[] _dreamValueArray;
+ private readonly byte _filterType;
+ private int _current = -1;
+
+ public FilteredDreamValueArrayEnumeratorAeiou(DreamValue[] dreamValueArray, byte filterType) {
+ _dreamValueArray = dreamValueArray;
+ _filterType = filterType;
+ }
+
+ public bool Enumerate(DMProcState state, DreamReference? reference) {
+ do {
+ _current++;
+ if (_current >= _dreamValueArray.Length) {
+ if (reference != null)
+ state.AssignReference(reference.Value, DreamValue.Null);
+ return false;
+ }
+
+ DreamValue value = _dreamValueArray[_current];
+ if (value.TryGetValueAsDreamObject(out var dreamObject) && (dreamObject?.IsSubtypeOf(_filterType) ?? false)) {
+ if (reference != null)
+ state.AssignReference(reference.Value, value);
+ return true;
+ }
+ } while (true);
+ }
+}
+
///
/// Enumerates over all atoms in the world, possibly filtering for a certain type
/// for (var/obj/item/I in world)