?PJ!4RTPMhUNj-HpC?
z<8?j)>_=L0VgbtX03IddRR;z0Tc_AwZHsk}pSplfzP8GVjkry92lj7@FAweeITt!M
zG}Eo!MPR6W&?VYb#yUJIDTek6d1Asp&_R4;VKW7qy&kwIvoRJy&;eeKvUu_h#MB?m
z2amDTBL`wk%xW!(fZGX?f)LA~@F6cn^1qF19swbMFvdQ#vKg1iOeE2n92q%Kgf9p@
z@4aCy4I?8bm;sBE$yem0m3pz6u>+E!7tL^SABKS#CY&JSp@3DXdRpT^_^3Z$lArp^
zTKqyMp&tE$;Mqa$uN7pV3lxzdtKy5JhV3=*$kobLFW;BDzU7g#QptZ0HEHN9LJkKL
z^Dl>&+a?|C+}~|e+ijz&GCacpc5O%Y-+gQ9U*@654Keu|Lj>`WgcaV(+&8kRo@hii
zy_t(KvF)IST*<@as`B6rf79oBBylWiC-(Wu#vr|{Zlxz3ho6JM(qli+UczdI;L&bd
zCs(iSw$Jaoh66lu_g~(9`rh5U{o;X~M2bEIf0O-CFUzYT>AO$7fw4a!{`N9g`%J(7B6
zU*%s;F}2pp6f0F{^c&;NAJ-&o@P3jY=JKKKV0DOx5?LkP2VIUi2#u8yEFa~tsM+V|
zhr4~{6qDM>i#cKFRxlS5rsbU-!m9XuL-iHo>VQC9x+-bkL%Sd-T}Rh3!;KD1s2PY5
z?Yewq-=vM@S;nfKhcf|^HkE>$WpzUoLLJJpM~zcq237zYP_sQYc|J8*RsU}l;d0(I
z1J|KdT{&rX{*mDmZ++OOUg8(`f>VULP2%~3YOz3{dmkld`jI;iXJHdK*)}#oPE_oY
zRL)lq%PT(zjmwkd2OXk$$t)dCM|87vr$Vk?<(dq{PDO{0vJ@Wp35_XPop~X$
zB5ZS^w!gc11rVuL?=D>%1R0doww_YDapRruN?6aF@~-<_KSFn2Xc6&h=lFO8d(OQr
zSrleiwb*ivJI|B!7*Ink#m!)&e?FmBnNp%ZCUgW#qRD)#5DHp<441y!yd<&J2)*C|Z#u*z*!hh3_nM7rl5=6`eQcxWct`ZbaL`RK+7#
zCSScwZJFSrqQ@M$LU)>zqHCa5hC%i>I4&WdSlLf?dq%*SrwNn8yr8=S$gE$qf;~`~
zA{uOj{o-pNleyY|gvO0%*<6*7E9OV$a@YILsMikCd+^GnLC)hBGS-5GD2Ufnutx=vLD(Wk_d^y|qD@)}cNYlOLE7{Du
zfr#1$<1W7qztC=*B;aTK?n-Q;rHNSz$`jcW)J&H#>JKsVEO$O+YtkkT&a~3%`!z_4
znwJUonc|U)D6smn%W%lX0$*Sf6PvW6Ma7zuSS|#Su9Aih(;A+f7?QnJfxB=cG;ioat%Jcu
zn8&gg7XA(k%?;ERIkaZx8XacAj|#P5Uw;LIKcc?dCIVd51QcmR;fxQN)|$X%JS%rP
zhUFh4)QJk8^44s`792AdoHjg(tIKWmSO;(hx#dwtV
zybwwmC3}7XMR^pNQcHm1$SbC&wQKJq@P0g0FIp3`BxQLf*s`r#1cmNAD$FCQetF1*YdUOLZ&0{Q#*3LCruHUj-
zcKf;&cLp2xs65}?uuX1q&IKM{RL~vxw%_$uhIx{h_pnT)Z20QmN4q=O9ZfLQDsR@|
zY2XE5o_!QcjL_lxFaFS*?WU|BjF%bDsI|)rT|+fzO`MQo4ONv@a$l?YY5204i*CIn>_Va)CqZw%LIp=sculWP87JJl
zkKuyy{I;YC<@KrPxaEooY#3T0uZ%4Mw+Va`;fWnX;briy_THQ1Z(%_
zdRjw|Q
zJluTZfJH4)JCZ;yK36E5vb)*#9%74lx2+1eF}gxzz$z?L=)Z43J-!fek)U^7h4O!=
z8xra~PuxJG-ZDCsj$hEztH}x)U@z=ZQiLnQ95_(i_Xj^Ve{^4b%q39uP1t-HqWg^7
zkMlisc58wDj5aLJLiL^u1-TIrc~1=T*>Wy}U`i)x93Y{~V?k(f4W9$}+)+bKs$ztXi_$IArBKZ4>*){e?SXR`T4DavN_ad-}Ur
zJ4a?68C`wzg|mG0U`|}_R~t>ZvH0{V_9Olf-Up%EE59%DzkD!ZZiHYYV24qI$F2w$
z;f-fdk3=}%z6m1h>OVNfiQZaE3P&qf{4QSm%@}tO|?LOE&L`M`}eM
z4OdzisE12ZM98@Emi_`H#e}i>AvmDZtg|%G1Mj!7fUZK{yH*i)8$D;!)EHFiN
z5}wCiP~2@RoD0PGqGTU=*Wnd+;Ei=@uA#HQQta-+HCRA=u}t`#AD|v3%d$J>Xa+&;
zZY-d@wZ%YWASllBrufVLSidenjk8z8BX=_mL)5yHQrTIoqYfN_7LKyicWSW;%q^@?
z+~6GT(eZ)(<==y2=XKgD3o9~*XW14^20&%#|
zdc}=5xgp2X|0C}Bh1S6L{*;)W3$VP295%jvBiC>cq>|zx0bD}rx*Lak{{Dz-FK`o0
z;0OcsvZ2srag&ZzXW%LmuJKAT*q$RUra5~iyvr^oyx|8+HPy_D?Oo}wyDZv+pAa!Uk#72Fg+WReX
zO+rX@VYidGB%(*3pq+-VXg*e9FX!XM5Tr?#dQ&vR8ZRcpDez0I2EPuDlrR(Sz>9jS
z-J%1pglpA2jb``HR}`t9B*L3|(oMK8yh(^B=QS%8z+_~SU^7i=f0Z^sLaG)MYo)MR
z!sA+YMBx6wgM=?G&}X|O)x5_RiP_CDT^|4utoYHpMM9;b=B8!539+-!24egR#dh?P
z*upE^5XDfieA1o^4#i7tta19T7QS9w#8Gu);%2I`ZwHjyop|>hdz2a}WsR5tCt%RX
zr>8S39p??I8g(T@g?}y?iw;^?igqrI4;^FiOoi7j>D58Ei?Iizo6Yo3lHugLZP&nb
zxX+F7K+Lvlh1Faj0U$7YR+902lb+AEnvs6_GC{HW>DvddN8{P=>?!(|1WK7wr;-fW
zC%+VwQjs`Bf;UEP80MP}8$JhKNZV3s-LH0!4+iP?k(@G=@TX@1`^nhTuA
zdgl%oi8GgJJj`=CsNZ7A98gjBVFM!zaP_u}LI~gR-0snerPO`J5<0}K+v(N4177V3
zR*`4Ww9}Id-k(3o3)`98qQjvcYOu?6o;&OuK4s2;&1CLi*Qg+pdPutK-I_Gr<-~{d
zNbD*a?`<%3W!#k1&F)w+8W}84xt^N~R5x=OpFS_>p@QkSZ??{Uj^l1-kXl_*2Fe*n
z&l&v9xZ6o&rr)se?sb}HuA@G0;~rNcti<)0)p7r3;)#|P$Pl+RS8zg|2**jMnPG&c+-62>68
zo9Q+y48X4XP|Q6KBjS_phs^37qpU_A8S#pIBrj!fjQFjb{Qh#j!cjko!ai~LBAHYF
zcA=+!v5~l*jcGR*T2-i8ZNjZKHB#?y=E~J)Tz8#Mp|d}u>gl7D%w*=s1|#eZpg+GE
z?H7Rg(@Bm>R9ib>W1&lD?rR5BY}a`$6VfoS^vDpvk5tCu-H`{u3+kvEE>DWwN|$7E
zK<<3uRYjc9fUaiW2XB%&(=<<1
zM*;^9w;QXQ=@$58QS&ONnX|RxxptQ+K@>)GXcjrlI=X(j%UA7d->bYp_smW4`vroD
zu6msW>nv;Ww9ooO+Sn>q-Be>mI0JUrrVG~l2VfsP+8dNqxM73Cn)|-@*7W?jmedu)q6S6
zZy}0}RuVfF78@QE3G+`P3xSETRvaR^9aNJfETuyD`3ugDsK3*p+CLf)wBB*@alZ1s
zN>=%`PrHEb8p-l3SBUPqo=33oFm5Hq?~0<5B1v}X`~GI^k@K3`vvN$DKKeK5ZeNAN
z{{k46ftZAyL{g5RYhNm)q%=UmCwJ>L;{i*3n*et`fF`y~SoXC)
z8TaSwox}5xX-6qBuGWNEQRgiws70ISDe&<$Z8G{a?}>ncDL#qTyig;_y|a#kadeLm
zQ9g_Zh{QiS&mbR%OWTaRn^gP}vt=Z`@2SCLw`}_d={fDhE0bw+*el2-KTj1q5$n3()D|(J#n0DL
z_P2I1M0Fr(-niEb73T6>G*=ZgCS%U0j>u@Z*)7PCneUPmTC}O(N!^6&xisOA^~=I_
z$juvjWhJJSWj}Vsr3g>9$+vrs#J&`5!j&V%sWeX%xI0`{MZNr+Etkm3CCkGQ}pDxiRw=ZxFjN
zr*4&4I;wP&km#!k4F2AU5M5C7(-l1vb)Jm4AOpt##69JwY-!I$E~TQc6l`nzeU7Y@
z?WR7@k=iF-t?SR8^>K7W(WB&YRcFB63@KWUF(faRBrs`%Jlmc;caHkfCsOR
zOPXu+c3raStrQFip@
zTw3eDpR00SA)c&`jz*Vjk0wvaPFqwCc8j-rD>H6}8z%kCo3R!wc5#XSe`R6ODj_;ckFI%s$_=~$t9S=BMgbnLLniXXUyM7P=
z5j**Vg*G{!Df{lX$|>~o>T2Izn6XUg2WvyY_Q`6?1lz?O9;tI6+7I9riEd7VrvAW;PE8ZS^kssEfASL;CZXRte3Q+bQrPgS=&^%Q(IoSC3?MrSLPhaS
zxKh0XXWuAaB=c7T=o_#Mt&rlcD`HKi%lDKYCFxC3+##u?s9m`xOLS`Vtz6UHvhB_f
z=INZDd-Yb9s`4nMfwPc?_|hgtyLZ@w>Gy+e?u1`zedjZU<(r~J-?7eO;YCY?Q
zO{|!iCxCXpFH9{2v^Zoa=Es!|@
zsW0c2Tj-x@79h?df;>l%2?LHr6yb9ds28Ej*DfEf!P_eABR4oOjdc6{Y
zqtEU}I4B~#%x%yW=4l_q2`l-hJ8$9mSf$WQ^o5j>d(QIq^idI49`f_Oo*@KPdhOjd
z_~=VeSEI=zG`Y!GaYHBsC*3H5`y$yo9C
z8!c-nSFQ7nr)XVk?hiI6Mh)IJAj|r(_n?SxF%f;rRXs+}0#tBwKK=CL5}Q-4B=95c
z@QRJk@IYYDQ8P3B#B+gA5CsM0feU&bneImHyKTWuxX(REc47!Civb@Ma)I<8utQUk
zDEuIYZ!IH!F-Rjv-RJzV!X(}WT|Q8BbTd_WVQj?8R44q5e~jh45uPB!cXow^Iy|Z*
zrh@G`BKnPR5lWqA!KX%smT?->kZ6gO%AnoMQI`5wu+&eid}WY2P2%GB3Lru32VBNE
z*k)+%osZk53tw)W5?ISzyl~CJQpHB0@fWp^Yx(mrdEQzV==6R{S*1(8gsOGO~T2C7PFXRHw{
zle1JZXRC7xYnJseZAvU=N%8~HOjDL`Q`NU9cg9nGVlKW~uxe9EHm-|OAl$|2o{{1p
zWEod7%w<>yVx&Mq4J^aHwbMS#{hSU~&>KX>Otal$Y{v4$8$XEAqm~JjQx^1U#WAFk
z95kvKzSXJj5})U!sP635`+3=$wzp=I?GWJtTf?vX?Bd*w^cVrc%?CUeWGGx0j(m)y
zo4eaI1A?Q{`3r~Oym9!rH!DRgNK})Vn`TCN*XDBl0cF*3${)@OKI|Grw~Q%HiIm5O
z0Oo6kxVOXpR3WZya?iOXDr*?OCpwmcf?s(|UZW5{6>
zlbF0J`4sxbTx}=4%y45(Nj~-&%`P2*_tGTulL|Wv!UrS5LKZ*RB&dud6svP$j_yr;
zbF>HeNhJ#@25|OT73Wk7`>1C~i%V2;1G4unEh~N);Y_DA)Tb;~H%gKlmruar&IOq@
zcD`55;SE?I*jaj|4$o4a%K(
zYR;<|96LaCq*yN0{&D~(h{9r)-Nmq5p4Ef;oCGz$X2=dQ1>AOcuHXAn@rshzE%b#k
zp8V%N)+zJ}v=rO&d^{O9xlm~T=y3O#Lr-57?hzRh(^ib%vgtV56X83r4GtpbT1}AA
z^(*Ftp*-s5HV6Dy`Uc;tu#HdG^uuc3aPd^#g7L@346~&asz+`1Y2fO8SK}Vqp|uTn~e5){3<|+yAW@guoZ7Eqn*2tGm;@V_%%Z_r2u0rI2YP*4!CXP
z|6+EGSo9ZQV|2~U*9RFzXr0pMSIfR{GI##e^T~UkFZ*Wpolt?RcTgGoogiqU^eYw?
zpwJMyr;T8F=ZzqR1cMsKS*E`nv%^m|#t(%ia9B+c>--lB$jQ!Jtv4@1A!kh`Qw>9n
z4z=z^B%X?RftX;CFdQc}31YZ!>##N3SlzFTc@lI9kDM?FiO^l7N-AZfT~!ee9~Waf
zGX^L@v(rOj`HpcgTdju^M(v!<9wPj
z)7oaX6$=O^HJ>PxtA0Ax`T=BvshFJfR%pjN=1P}XSy&4F5!E4!HS=GgdJnAwI?2~<
zdw9)D{l*Jotbern0H+&<{Sy@H~e
zO?|sAKwX_j_atXh57e9&VQ>f{gfx)-Jxj2lS(V>m1tfqpcsf`NgD64l
zMQ}LQ6sR4tOtMmSUgn9!SFRt`Fs9JueG3?#DiX_Rno5b$(*gn&{SkF6eDg%;8bS9@
z6IQ@YK>*^@OA?$Ds<%q&tJXH<368+(rXfY8%J(6P!D=bsN&$w8oO58qPu+HE`fJB~
z@qGlc(!(S7cg>Kb#IP>WCB==ZvGZ-=MvA@5>)?*Sgcz*HkzOQ&`)oh&%N-#$17G{T
zwnEN>DHNotP~PVA0TCB%br=t^MbG5u0moa=2hM^p*-KDm;4FVifcOs=g>XS#uu%q{
zBsX$Q^}iH2N{9-)=l0I=8iWv0nej=}%Fp`3`bEIoG-07J&KqissT6%f5k1w4H0DK%
zS5$fa_vFOrCZu}@8Y`-d#?aoS_+o;Y#xIyfEIe4H5;;W|^t4(le&o&=mp9|>PWtmP
zv9~g>O4txo7Q1B087JRaN_PPZu}#vOa1ACA&E;v~?g~M-eivXD+acI}@!4*hPEL}{
zJVggwx{H5O*jUhUHD8XB=Obx3j{wFrodQ&vLtuq?1Q%tPTtfJ+ix^dJ@ZMs6v&B6Z`RW6f^{N+6aQprC#h*v~p(w{9P{sncS
zqO;v7a4Xa5%;2V%0OFF|W>Ixv-!AT{d^uDBM52BDFWyehtqH3vf6RIEjK5gbEIRSW
zvpm@!D{t{RHv>w-9)7rHo9HfRYz0;kJgxmfcaM}RLO!jO#d2N9&{
z4U>iK$WZl@hDwP5_pz_=?v8WYdPALL>;(n<_q7>xlWXX^mzD4%P?LU7Y^9hJfUOx)
zRZW->tw&KAk%rhkqM*-!EjS@qUY7+V8|Is4rqlG}8hIh~-9~h6|DO6)bpj(Skxdh^`^V-RN~hIE+HC
z7%JB76kBp^0uz_KG}%P3f#c*r4^mE}RW02j_m}DBZAl3mL7x4!<$VQtUNzp!YB*k<
z+oZ4h+&hm!%CFD?FrDYtC~fE+W~`Hk-S-IQ#P6xnlmyqsl*q0`Ot$y82&tcg{#-xJ
zA)Q`zT=HBE2q9#>O48`ba?{*4f4$An+t{8-aP3
zQjmzYgzzRAcUj&A1yYIOGj79ODFu&zFK;U%NM9#xt|SZlvJ00$We4iGFZ#fJFCdK<
z6+L(Q=-rj>odwpQt8K0qZVBlj>?4rgZCenXfu7~UYaJ4v;5+$$AveHB`y!KqdD`A^
zr)`43^&41f#c!PhhRapn=^8X3#!p_S1Im)W2Xxxz8)r&w30bYE23gbcT^=z3`mjd&
zftWy$8b~znDIaB-QdPOU`5utX*C(xPRjHdqjTaZK16#Bw{(7INC;~wF<$I~GAM?Uz1G?`3>X`Mm5UhA`y
zUHr=*d;@X5JDuit|K?~voP9FWSRshAb!`gqG75LgfGK%|gRGb~z%Oe#?q)T*|2@pF
zYp{c9`G(&tfqTf0)phpWd)pFdZ-Cx(XioB|>RuCWC{#eVD?Wuq$=>4iQ`W}fQ5Nke
z^Pb!8&fIw>tq=z+)a+CGVv6+n0y|wm+_$x{;+y;8L!gUHQhK8k07bJhb4-uFR@{3M
z*4Xx52X=u*201T?Bi>1zL`=zy=0&h4Rh@q1dDOy!s5PU*&whK4!qu{})6GDr4y2fx
zKl$L)caw*xyXuCp9oRFZ5nj$_L}`a$KFq&=RQhvC&tdc&BMPd;r+MW3iUWLqIte#P
z3kT0XYMNtS(MvMMJgU^h9X1khca9$VgU5(7tcXKHifrBe<*zSSZK{|;pBX)LtN@ht
zc@Os5=oz?_VIZFMD(v?+2>yxMf2VNsf5Ta*;F0^hEE%cE**5lOIf#13muysEoqq-_
z-|~(?|C+)j<|d4KeC!xNjtYe|fvTDoo_^wvUbP8iQVhElW+!si@1-h!`1mF$PS%8I
z>A+G2FvE)wR5?jp=X(JwM-gy4hVpV&
z{$DC}ma)Hzh&7jKrfJvPNaE{=%9|lERb9W0`Nq;`(|rfnTsQn4ZVWTU{3P$LB;5D{
z$|%((SARqu3cbfeQ;f0*7Avf_JAL&wy(5|LKIZ@IZFBHTI^1EC`jNy9l#7r)yXxsG
z#fkpA6)GS#PrJ$@g??Ms(5?X5OY~A#6e-&)6r4}71F`|4blT2@%vlaPDfGv^zV%2F
z5a8hN<9#4USfT?M&I`|eQVaE)m8qUR1;r-~?-xz*ypUL$Z6^pfpq28}E*lrs+;0If<2PSNV657YApeHGy(r2RM
zCsWvLF*Gi9crgg@xWE5z*JLjd6W9GoTe;E4Rut
zdUt2Dz78q#J(|@awj)9KWW`9Y)D+`c7twIP+y$}v%H~In??GB!7C{LNk-q49nfWqu
z_NSz>6n`OGs(q5(%m}#OVq4@9IB~LFOV&Zxc;u{69Vzw-)lX0Mf)^VKd6$#n#g>AT
zzm8(n@h8s}JQmYZ{^$ujLffkBGoPG-8jH=41Q}2=lAw)SXjmN=!7Oo-xBjcx#Ss1Y
zTy=yh3B;CA60vl#B-TX%4(K!NG
z_kjq!Dq`utVc*D}6nsnvHEg+45hFYyt}qd-`{fS-g*l8>q-EZQzz`Q<(-yO#4T6-W
zNk8pgS1$RA9e9^dIGR~5NgtzQ6y_Ci90H7fX?X+aAg~q?of{&R>-x)RSpl!^2>)7t
z&7e_fL5XgUS-s{5<{9cp9r4gTqx)w?xl1ExmDay-#M%eF%P(HCAy$uhTxPUEg?b9!
zr=~ET20x=Z*sKNVEbl&>{2`l<#Ken|!pQH@5G{iueEgWibX+IuI^BtirY#R#{v!|H
zj*6M_iXP+HO5n#t4w2B%unY@wW|pX`r7I-p(B;RYH|vGUTd1GHNw1vq;5_>X1Sw98
zT}`MOGcpT(?n4G-f;%WS3_gV+^D_V%l^b7
zt!=Frf+)O)-R9r=z5?0$$yKoS
zv49pX76z~)@dFGSu_*9_O{9I#6X1AHtdCRunlg+}n`Kl~g=;-^xZeO6!GV|o(5Wg>
z_cNZ%bs*b3SuLd5lcP-b_i40R9fZNHo`_Gp?=q|tQdz61pHmEm1Or#{9mcCYa!8V@
z!oP`TA9;pKV5S`J#(3nYhG7??)spX2x$0b#a<-SXKV2ocJYr2}KiuWcacc3ahbwaT
zKLvNN0CTh1hmb-i(o{y>$p#W|rv@>Ky~k#;6ev4oqukJ|C{bQd+QPck19x%~GV1(x
zuB6!Iu=3*K`-IqKR*`sKTfJo}HZ|f;BX|z$ix``spz5A>t|HxD;E_woLw=**=@otk3ZyddpU0U(OYZF+GC(n@^c7}
z>0HiIFCFr++RfZ#c&eYD_^q$ZJzI;1DEemHVh@rZjG+rHIWL~!@Ix?lA0yn^6`}}F
zxFMA3hcD~oMh6eJTt}@dom(dJyh%0;LZN4rsODpS-hBqtcb>T4wku2sr3C(*w%1I|
zRLs^26EW~nFQ?gzr-jP#mRdwa%y3Q|!@g(UipM{}m~(Ocf%#8tP>?>md)9W+GVSj3
z^MNiI!9F1?aKmv02#~IB1PES}qZcAt`5##QorjG_N-w#{^A%ZQ;FnCHaOO$3e@a
zDNrX@=-UZ3xPb$x6E6!LB5wMgfoE9lXNmb{=y@^}mA-Z;%zk^v@GCgwBe3a;E8(v;
zDJ3ImV|&NE*9r<@5RY_DY>wI>w<6B#9ekBVrTN(BSl~uLgj$o00nQ#D!sgE^m~xf{
zG-uDVkoTv)p0JtL7ZmkchqnHsIVwuPjTF0Wf@J+x#1On^p~3hvSxUn?3O@!r()2;}iN
z3_Hr0WXd%H6nGz%O5=Ym(6A<(TRqGv=scJUY|m90s=Y`}Dd_187{C$P;ZeKP9*Xjt
z>>mT>@E64B-G3At3fi}rW8UYF)P;Gql%hS2&wYy~2wKEmjFJB+8A<~|nR+RhPDQ^R
zmA!Pkmul*!1uZIa-H^-_Siej5AUv61fe3_f{-0*9{2$7-4?mhy<1`_sqrqfsp|KXS
zZ!H*0Leh+kq#^5^j%-6TCrM$*2!}{^o$N(1l*3^#A=6}E50WKgFcHmo@80*Hc%R>&
z&vSq7=Xt*O^}W8=brpg^0^vr@4Bz+3RYI#5FoC&aP33c`<4uUtNaV`H{^SEKc|uLE
zJll)2%f<2M^bRMP-n|K`evPhOFVG8afU{AS0>6gnClWX$P|1h`R}{uKfUJOdW05G~F{*c4X;cC21&PRSEq0
z?lB%&{`x1QXfy+06*>Dd>6(fy&BjzZ*y9MSi=VAeGWC5
zL>L>I%VtEQCI}tn@aCjCox!TXQKX23V|Ih3G{L+d9w~RJ(0Z-RT%Ot=9h`JbuQp~S
zRv|0}qeIZjs5dyZ-`~E6JgyD_)3!_Z7;+Y$6-2(?u5-Jg_qSNL-p#sPIx!_}l1H9b
z{2Cecjm{WQo;$g3iqO&Aw20O(hh-75zeVEUkCeL65U@pI5_>hw*EMZEEUMK!<{VF;
zIx~_tpXW(RyQD$xADIcb+WX%{CgKp@`9m0JK$Gi!1hyLFchtlED_DHz_M5M3LW9mg
z$!L3haQombbjzjUCf_Sswdpd?uVdq{S#nzcn1~CQtBX-#lo_Q*2|8F+31vdU;Il6m
zJ7%sqUB@O?wAq5=^0aKZMXG49amKyu_62AFMF|;waBuVYfKM4KNGT_cnhY9CZJ9vp
z5qKVpt9&Ose|+Q^^UalbXe)&n`74QoMJ*y~NzCB$Sz75**K|w?mj?D49&bX7cAtBh
z9_39`bRDVZbb7H0L6>F7`ZE$YkZhuWu$!Ot#no$zdd4(QYavIRA-%L`{XwdMP%#u{
z^P*@TwS2&s(+a1)AoVe=ZfS&vuPAX^7i;P3y|oq*wr$bB=ewgy_iQ=o+a-3lksOZl
zR$YdfKH1AFZ=Mw)*w+1}SXj}!o$uhJ%qfqJ?F2?eD~r))Msc$Tr!`6_r*KB5%%+Re
z<^|KB34V{yQL!{piqgnM?z~bb>M)0E^ZnF-jB!?2M%~toW3903V~kLW7r<-qVhu5}
zDMef9VWg9w)3lTB_)@tW#8Us3C>j=f3$6d_G2Ym_xV7cJXi|3__i294Zj_rub*kx2
zfeg6{HLfVJC8!j8c>>WA#_D*n^4$kWoMDSEd|mGxQMnSz_916#bJ@M!?_b!aL(l9WVf8Rs;A4NW<3
z$4JdhS*e~d{)7q+i~@X76j+|52X^POs}YmA=LQ6%WW+ikZeI48FFdt;wefApX@`fF
z_l>a$bLtJf(#98D>__kUICv-jsRi9QNI9cH)s%8He%&%s(NKHXn+GaE-S^8@>mqYG
zO!QCgzGHcXS=WUE0lMSX^jgObaq?6ymfiPO9K3yQ-b)NePCOY
zhs8Fdpj#>ok&-Ix%FHPvlJ2RJ^%7gDj_pCOzkZ1WyWzTtRj&iv;8#=(I0M02?1J$uf;N|07xq}A3ZLKE}d^4kft
z{SjWh*FVNVW~A>j0>!1f89>Z#=bbs29u-RG2m9BSI{UHIv$T}h>y4M4D=Xi_M{o!6
z<}PVc&s0sN8$4uBmJ`ZcvX$PZ5oS1@!^3$hd;LA&Q*8kIU+}y9Enif(hWLE`Nr;!|
zgQm$Idy=p9xr7Jysl
zYWrod!D)h7T*EiTzZ
z_OpHlN=`(wK^WXTb{KiV{J9NjRf(2KE;OOYF2(mtNB#k3eZyqKPZt2Nu!duL>D37)
zTO%68FKl-VmRkY%c`|ZBOYv0?`pF<{=oZds7o-*ecT9M8h=tjHPnb<;g;?#FdcYcM
z`xrSZH#ugOaHBSLw0kXEOHIDGL<7)}kO1CtyX#YZ+N|4a@s>^KdwmkyY2ogX1D;Ws
z_DK5d>~4cELs`rZ5vZ^bg6d2fjDvbX6&`mRN>${1%zy;veXc2Yg_0#GT6p9Vvv1gX
zU^a}-4;7)j0(AL7osY|u11C6lGX0i^l#TduX{g-?phY1Z!x9vzuS(tK{?QxK@1e;q
z$qfT$G5wx%*5+b%Qma6gGK11DrS{dr1SPIW!sDjLgr7bE03YPQo9p#5)1zHS6*mil{j1QM+m
zLV5)t&ZZGok7dCZr)-9A9YkfSYN*&u17`c=-J+Te5*~5fF3fyai8AWO&pkz4raUqO
z2~34;^y-45zrPH5`7|85M$=dm#Ej03734`5xyW-`eY9zfacue%b!1!7e$52e4)6Zy
zz1kwt7cMF~xR`QUwS<-{XSy3fdC>DKI7~ddQsL|$dFYvT>GOgl8!~qX8as+`pYJT-
z?qXF33(2bOHeFpd+S=y2GATw26cbg9W5o{|Q3b(xa36>R(u=%Jqb%~2?%mvy
z3q9%lAY32-Nkp)gVWSC8GYa1QGY+H_%_4S*qu?}=`?)#ju+1)@0EZ6z>~y~KK%XU4
z-_Q8x^&`)UMt4>5{>}y0MGw7xe_8{6VxJkKL0GA2=clnF**@d7y8<6!?t{Z@1~~xgS
zp5jgnV*Z9Y)Q802v1~P3LS32*-_6#?tQUSmY>*A2tNtIay05!A+wbTLyvHFw;^k~C
L9nMys_Pp~SPn9;#
literal 0
HcmV?d00001
diff --git a/src/kernel/common/kotlin/terramodulus/common/core/Core.kt b/src/kernel/common/kotlin/terramodulus/common/core/Core.kt
index 72461b51..afad88aa 100644
--- a/src/kernel/common/kotlin/terramodulus/common/core/Core.kt
+++ b/src/kernel/common/kotlin/terramodulus/common/core/Core.kt
@@ -11,6 +11,7 @@ import terramodulus.util.exception.Error
import terramodulus.util.exception.Fault
import terramodulus.util.exception.UnhandledExceptionFault
import terramodulus.util.exception.triggerGlobalCrash
+import terramodulus.util.logging.initLogging
import terramodulus.util.logging.logger
import java.io.Closeable
import java.io.File
@@ -20,7 +21,10 @@ import java.nio.channels.FileLock
import java.nio.file.Files
import java.nio.file.Path
-private val logger = logger {}
+private val logger = run {
+ initLogging()
+ logger {}
+}
/**
* This should only be used by `terramodulus.core.Main` in the beginning of `main` function.
diff --git a/src/kernel/common/kotlin/terramodulus/util/logging/Core.kt b/src/kernel/common/kotlin/terramodulus/util/logging/Core.kt
index 0b7b4fb9..0adf7b81 100644
--- a/src/kernel/common/kotlin/terramodulus/util/logging/Core.kt
+++ b/src/kernel/common/kotlin/terramodulus/util/logging/Core.kt
@@ -6,6 +6,37 @@
package terramodulus.util.logging
import io.github.oshai.kotlinlogging.KLogger
+import io.github.oshai.kotlinlogging.Level as KLevel
import io.github.oshai.kotlinlogging.KotlinLogging
+import org.apache.logging.log4j.Level
+import org.apache.logging.log4j.status.StatusData
+import org.apache.logging.log4j.status.StatusListener
+import org.apache.logging.log4j.status.StatusLogger
fun logger(func: () -> Unit): KLogger = KotlinLogging.logger(func)
+
+internal fun initLogging() {
+ System.setProperty("log4j2.debug", "true")
+ StatusLogger.getLogger().registerListener(object : StatusListener {
+ override fun close() {}
+
+ override fun log(data: StatusData) {
+ logger.at(when (data.level) {
+ Level.FATAL -> KLevel.ERROR
+ Level.ERROR -> KLevel.ERROR
+ Level.WARN -> KLevel.WARN
+ Level.INFO -> KLevel.INFO
+ Level.DEBUG -> KLevel.DEBUG
+ Level.TRACE -> KLevel.TRACE
+ else -> throw IllegalArgumentException("Unsupported log level: ${data.level}")
+ }) {
+ cause = data.throwable
+ message = data.message.formattedMessage
+ }
+ }
+
+ override fun getStatusLevel() = Level.ALL
+ })
+}
+
+private val logger = logger {}
diff --git a/src/kernel/common/resources/log4j2.xml b/src/kernel/common/resources/log4j2.xml
index 7feaefe2..8a0e4037 100644
--- a/src/kernel/common/resources/log4j2.xml
+++ b/src/kernel/common/resources/log4j2.xml
@@ -4,7 +4,7 @@
~ SPDX-License-Identifier: LGPL-3.0-only
-->
-
From bd6b90a1b95767fff34e5a2cb17ecab46e068fa6 Mon Sep 17 00:00:00 2001
From: Ben Forge <74168521+BenCheung0422@users.noreply.github.com>
Date: Tue, 17 Jun 2025 05:39:00 +0800
Subject: [PATCH 18/18] GMS: Drafting advanced features
---
ferricia | 2 +-
.../kotlin/terramodulus/engine/Drawable.kt | 6 +-
.../terramodulus/mui/gfx/ManagedRect.kt | 22 ++++
.../terramodulus/mui/gms/AbstractPanel.kt | 9 ++
.../kotlin/terramodulus/mui/gms/Component.kt | 30 ++++-
.../kotlin/terramodulus/mui/gms/Container.kt | 12 ++
.../kotlin/terramodulus/mui/gms/Layout.kt | 120 ++++++++++++++++++
.../kotlin/terramodulus/mui/gms/Menu.kt | 17 ++-
.../kotlin/terramodulus/mui/gms/Screen.kt | 14 +-
.../terramodulus/mui/gms/ScreenManager.kt | 31 +++--
.../mui/gms/event/ComponentEvent.kt | 9 ++
.../terramodulus/mui/gms/event/MenuEvent.kt | 9 ++
.../terramodulus/mui/gms/event/ScreenEvent.kt | 4 +-
.../mui/gms/impl/BlankComponent.kt | 16 +++
.../mui/gms/impl/FlexibleBoxLayout.kt | 20 +++
.../mui/gms/impl/GeomComponent.kt | 3 +-
.../mui/gms/impl/LaunchingScreen.kt | 22 ++--
.../mui/gms/impl/PositioningComponent.kt | 15 +++
.../mui/gms/impl/ResourceLoadingScreen.kt | 75 ++++++++++-
.../mui/gms/impl/SequenceLayout.kt | 83 ++++++++++++
.../mui/gms/impl/SpriteComponent.kt | 5 +-
.../terramodulus/mui/gms/impl/TitleScreen.kt | 13 ++
.../resources/{logo.png => game_logo.png} | Bin
src/kernel/client/resources/studio_logo.png | Bin 0 -> 107419 bytes
src/kernel/client/resources/test.png | Bin 6602 -> 0 bytes
25 files changed, 487 insertions(+), 50 deletions(-)
create mode 100644 src/kernel/client/kotlin/terramodulus/mui/gfx/ManagedRect.kt
create mode 100644 src/kernel/client/kotlin/terramodulus/mui/gms/AbstractPanel.kt
create mode 100644 src/kernel/client/kotlin/terramodulus/mui/gms/Container.kt
create mode 100644 src/kernel/client/kotlin/terramodulus/mui/gms/Layout.kt
create mode 100644 src/kernel/client/kotlin/terramodulus/mui/gms/event/ComponentEvent.kt
create mode 100644 src/kernel/client/kotlin/terramodulus/mui/gms/event/MenuEvent.kt
create mode 100644 src/kernel/client/kotlin/terramodulus/mui/gms/impl/BlankComponent.kt
create mode 100644 src/kernel/client/kotlin/terramodulus/mui/gms/impl/FlexibleBoxLayout.kt
create mode 100644 src/kernel/client/kotlin/terramodulus/mui/gms/impl/PositioningComponent.kt
create mode 100644 src/kernel/client/kotlin/terramodulus/mui/gms/impl/SequenceLayout.kt
create mode 100644 src/kernel/client/kotlin/terramodulus/mui/gms/impl/TitleScreen.kt
rename src/kernel/client/resources/{logo.png => game_logo.png} (100%)
create mode 100644 src/kernel/client/resources/studio_logo.png
delete mode 100644 src/kernel/client/resources/test.png
diff --git a/ferricia b/ferricia
index 29903d15..f1c9c3a1 160000
--- a/ferricia
+++ b/ferricia
@@ -1 +1 @@
-Subproject commit 29903d15ea2b046541e1af32a6673981222c399b
+Subproject commit f1c9c3a1dc12e65d25cc9f94069afd1f1d375edc
diff --git a/src/internal/client/kotlin/terramodulus/engine/Drawable.kt b/src/internal/client/kotlin/terramodulus/engine/Drawable.kt
index 157f010a..870000dd 100644
--- a/src/internal/client/kotlin/terramodulus/engine/Drawable.kt
+++ b/src/internal/client/kotlin/terramodulus/engine/Drawable.kt
@@ -11,9 +11,5 @@ import terramodulus.engine.ferricia.Mui.addModelTransform
sealed class Drawable(internal val handle: ULong) {
fun add(model: ModelTransform) = addModelTransform(handle, model.wideHandle)
- fun add(filter: ColorFilter) {
- println(this)
- println(filter)
- addColorFilter(handle, filter.wideHandle)
- }
+ fun add(filter: ColorFilter) = addColorFilter(handle, filter.wideHandle)
}
diff --git a/src/kernel/client/kotlin/terramodulus/mui/gfx/ManagedRect.kt b/src/kernel/client/kotlin/terramodulus/mui/gfx/ManagedRect.kt
new file mode 100644
index 00000000..5f251f8f
--- /dev/null
+++ b/src/kernel/client/kotlin/terramodulus/mui/gfx/ManagedRect.kt
@@ -0,0 +1,22 @@
+/*
+ * SPDX-FileCopyrightText: 2025 TerraModulus Team and Contributors
+ * SPDX-License-Identifier: LGPL-3.0-only
+ */
+
+package terramodulus.mui.gfx
+
+import kotlin.properties.Delegates.observable
+
+class ManagedRect(rect: RectangleF) {
+ var rect: RectangleF by observable(rect) { _, _, newValue -> observers.forEach { it(newValue) } }
+
+ private val observers = LinkedHashSet<(RectangleF) -> Unit>()
+
+ fun observe(observer: (RectangleF) -> Unit) {
+ observers.add(observer)
+ }
+
+ fun unobserve(observer: (RectangleF) -> Unit) {
+ observers.remove(observer)
+ }
+}
diff --git a/src/kernel/client/kotlin/terramodulus/mui/gms/AbstractPanel.kt b/src/kernel/client/kotlin/terramodulus/mui/gms/AbstractPanel.kt
new file mode 100644
index 00000000..3582d919
--- /dev/null
+++ b/src/kernel/client/kotlin/terramodulus/mui/gms/AbstractPanel.kt
@@ -0,0 +1,9 @@
+/*
+ * SPDX-FileCopyrightText: 2025 TerraModulus Team and Contributors
+ * SPDX-License-Identifier: LGPL-3.0-only
+ */
+
+package terramodulus.mui.gms
+
+abstract class AbstractPanel : Component(), Container {
+}
diff --git a/src/kernel/client/kotlin/terramodulus/mui/gms/Component.kt b/src/kernel/client/kotlin/terramodulus/mui/gms/Component.kt
index 4da3f8fc..acda77de 100644
--- a/src/kernel/client/kotlin/terramodulus/mui/gms/Component.kt
+++ b/src/kernel/client/kotlin/terramodulus/mui/gms/Component.kt
@@ -5,11 +5,37 @@
package terramodulus.mui.gms
-import terramodulus.mui.gfx.RectangleI
+import terramodulus.mui.gfx.ManagedRect
import terramodulus.mui.gfx.RenderSystem
+import terramodulus.mui.gms.event.ComponentEvent
+/**
+ * [Component] can only be contained by only one [Container].
+ *
+ * It is an undefined behavior when the `Component` is contained repeatedly
+ * or in different containers simultaneously.
+ */
abstract class Component {
- abstract var rect: RectangleI
+ private val listeners = HashMap