From bfad5b33526d75211c950b8c09deb08790f3fc81 Mon Sep 17 00:00:00 2001 From: Eric Myllyoja Date: Thu, 20 Jan 2022 17:47:42 -0500 Subject: [PATCH] Properly implemented Polymod for mod loading. --- Project.xml | 31 +++- README.md | 21 ++- example_mods/.gitignore | 2 + example_mods/modList.txt | 1 - example_mods/readme.txt | 2 - example_mods/testing123/_polymod_icon.png | Bin 0 -> 66718 bytes example_mods/testing123/_polymod_meta.json | 8 + source/Main.hx | 33 +--- source/TitleState.hx | 2 +- source/modding/IHook.hx | 13 ++ source/modding/PolymodHandler.hx | 201 +++++++++++++++++++++ 11 files changed, 271 insertions(+), 43 deletions(-) create mode 100644 example_mods/.gitignore delete mode 100644 example_mods/modList.txt delete mode 100644 example_mods/readme.txt create mode 100644 example_mods/testing123/_polymod_icon.png create mode 100644 example_mods/testing123/_polymod_meta.json create mode 100644 source/modding/IHook.hx create mode 100644 source/modding/PolymodHandler.hx diff --git a/Project.xml b/Project.xml index 8c133047d..8208dc649 100644 --- a/Project.xml +++ b/Project.xml @@ -29,9 +29,6 @@ - - - @@ -40,12 +37,9 @@ - - - @@ -102,9 +96,8 @@ - + - @@ -223,6 +216,28 @@ + +
+ + + + + + + + + + + + + + + + + + +
+
diff --git a/README.md b/README.md index 4d209a9b5..d868c6574 100644 --- a/README.md +++ b/README.md @@ -2,19 +2,26 @@ This is the repository for Friday Night Funkin, a game originally made for Ludum Dare 47 "Stuck In a Loop". -Play the Ludum Dare prototype here: https://ninja-muffin24.itch.io/friday-night-funkin -Play the Newgrounds one here: https://www.newgrounds.com/portal/view/770371 -Support the project on the itch.io page: https://ninja-muffin24.itch.io/funkin +Play free in your browser on Newgrounds: https://www.newgrounds.com/portal/view/770371 +Download the game for desktop on Itch.io: https://ninja-muffin24.itch.io/funkin + +# Credits + +- [ninjamuffin99](https://twitter.com/ninja_muffin99) - Programmer +- [PhantomArcade3K](https://twitter.com/phantomarcade3k) and [Evilsk8r](https://twitter.com/evilsk8r) - Art +- [Kawaisprite](https://twitter.com/kawaisprite) - Musician + +This game was made with love to Newgrounds and it's community. Extra love to Tom Fulp. + + IF YOU MAKE A MOD AND DISTRIBUTE A MODIFIED / RECOMIPLED VERSION, YOU MUST OPEN SOURCE YOUR MOD AS WELL ## Credits / shoutouts -- [ninjamuffin99 (me!)](https://twitter.com/ninja_muffin99) - Programmer -- [PhantomArcade3K](https://twitter.com/phantomarcade3k) and [Evilsk8r](https://twitter.com/evilsk8r) - Art -- [Kawaisprite](https://twitter.com/kawaisprite) - Musician -This game was made with love to Newgrounds and it's community. Extra love to Tom Fulp. + + ## Build instructions diff --git a/example_mods/.gitignore b/example_mods/.gitignore new file mode 100644 index 000000000..cd193dac6 --- /dev/null +++ b/example_mods/.gitignore @@ -0,0 +1,2 @@ +./tricky +./enaSkin \ No newline at end of file diff --git a/example_mods/modList.txt b/example_mods/modList.txt deleted file mode 100644 index 3e2492595..000000000 --- a/example_mods/modList.txt +++ /dev/null @@ -1 +0,0 @@ -introMod \ No newline at end of file diff --git a/example_mods/readme.txt b/example_mods/readme.txt deleted file mode 100644 index f8d8f6e7e..000000000 --- a/example_mods/readme.txt +++ /dev/null @@ -1,2 +0,0 @@ -THIS MOD FOLDER DOES NOT ENTIRELY WORK JUST YET!!! -DONT EXPECT MUCH OUT OF IT RIGHT NOW!!! \ No newline at end of file diff --git a/example_mods/testing123/_polymod_icon.png b/example_mods/testing123/_polymod_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..2828bd554185ad530273cd9859e6c41210ac7736 GIT binary patch literal 66718 zcmeFaWmuib(k{Gkx8SZJxO;%$7Th6_;O_2OxVr^Q@Zf>q7F+_sA-IR&?iRj>nb|Y5 z*|YP#=bZOv)`hI@>ZT=+^p?@)*ul7GdDYZ zLrY^PG6Q2%a~lDQ{l*pwGIJvV3Jp#<7CAdnV>5Fp4+mov4|!EX4@*N{BZ_B&i2QDR zfB@UECnq~TW@cAcS0-0>CR+znW>#KaUS<|HW;QlPpar9&yN#2+8>5XQD z$z$j2VD;P3j0~BLt&FXWZJZndKGuKavoo`GvUN1G{V!eqN&c@L18X8D_h;Y#I9_Y( zf9%@PN!$g1;15Xuk<(Gt-OiX<+1Sz6*}>3Q+y$5lhTJJ~v@+S*zP{;p+;|ALTARP;BkBBRkTw=uGHb)@BI ze#r9IdjBQOSWMr^Sdfi{jfD|VMs`+J77jiRUOsj%M&Jz#%io0j-tvJAIa?!h6Ze0~ zU*wyZLMq_fMFR6vhy?lQ}sV`sT#XE$?CfsJ2?Jrb$~Vc&0^KW zWNvQ6XT+j!%*keK!f3$G!_LTJ%)!HGV92J=$irgHYQ$s2YRJW9_?!CuJNsW_{X?{v zt)cV1pZP=0CcUGIsGuZa|G9wwGnD^>{lE9&YG!QnGgtJxsNY)scOj0pCQh#U z4#vW!fKL2}mt+I>u)n*=-$njA&qLY&Yz_Y_tKg{b^8dC5|1%@{zgUC+=F0yU*5Ds@ zs{hF{+ynl5J3}*l8&hK=LFRvH@4qVkXDj#ndj7jv{mUEtry26!@8W!b2?Oe+|C{Ns z@-zQO-CsTb-d^+Gy<0i|)}Eb{<^BZ(d%)`t-oMiy@@oD6@cy0tkoPZEH5+p$LAF1- zdrMK{xi~r5Ir*6%RzKuWG|)A zwf@G*31IRU=iexQaQ?nre~V#%^M=3I0ueG0oHPF!o&SfU{L_v7Z@&3!O8=WuAISRE z$pb)sUi<~u&+&Oc{RP(pKz?5Q1=r8MFGPLA%SH;*dXY^d^X#h zr^^ADsdiAUu&uU~l=6hEoDlG4o~~2Yv!6l35HvHNG^&XG7tRPPBYS7=7Uyarb9dc# z?{Fc^tY-7eI_ygzhH5-f%%8p%nQeYt?M*s)W()m!bq%Txb%_E@39`|?^l88{lMkN> zWkTfwPjSVqLBT_#L$|g>CN#~~9BvBr`M5aju5c;Cfm6A{tFw0Zlei3QYmL(QV!W>R z)8(Pia6un-1usEOpo<#sb(>{RS~xqrR&vl?&3rVbe6~w=ct>TVkw;amtx(#;`mBVA zlJ#ue)3m-lGPoFoC4TT2XcRPOlV;DeOl9$es235{y3$Q_R*D--$RLfAXv&0`Z^U^R zkqoN!G3fn_R8#LX10b}$W=VJxF4Bf_<$#L<)!gwpPv}%A2dD=`1am-|U_-fI0h(_8H_g-O*)0p1BPzp1ua5NLFGMLkRF%k5q`A8Wm)G+NZTWfPm8`sW%z^v znip&ZdQ}yBo>69F{WNq2;p2e~7G+_{|HMLiJH;CK7>ZXUQyWEod!55m~>YOR&~ zN%ptZM#jKFhFDRqQqj!g0BdTN}>3|~cMs$7Td`|t%<2{~E- zd-_1=p6JQ|Xb+MmfUT_ny-$o7BVjsmO;O_Q6rWP?GSyZY8cD(k7OkR$W@q*7v)*YA zc^-XqIqSP5PywtWOeS7m*OzqEJN4?=<|kl}uyr@$R#@vGr`g~&S@M0pOwknIWcbWy z2}quWirqv&cdG%I5?S6sDZ^*1Vq1?T(nXWI%ZM;Lg;0@7IyT#yKU zk{m>4o2fuGz^m{cwLWTpw$viOQo7Xtt+g0`d1QiTM@qG6tyv<(Bii9PNcdFW{042I zuVD>WI2>HnexGwisa1q15=E)vMCjDO^6!PS$XX3X$dl9K7t)v>fKv$PovC*HAb+O4rHfA5A&>jI|{VtTpa+RbaKH?9YDt8*YdE-1pu`Y01p zL_i+)oM42;Sv<9XS(~c0lme0y$BIDW$q0)%8S!fTW(bnY*%NlK-J|MD#K1Vso+>71(i(N9Z*)cctba?K~lI0pC=K%#Sanh15{MVl$x; z9~B@uYpq>Ky*?rF3-Fkk$CC3%O()K|ThU-a-`v(6oY+BxcY)FdK=HzGpsK3AR&#c1 zV+R+^6x_~zi zTC7w^oz<5P!go|VGc!&o58RsZi2XZUxi$T_$*BS=br1lS_W3uRu_URmB6u%H#VA`; zx;xap-j&k1{f*qA8}p=MFcqb+T!g!j&b8n>wY9An^~kC zkZz%Yr3!hOD5G3f@FYe>BD0{cPg>jR<+(SW*YOpTj0JqcIQqr)jR3s>*P9^ULnnTo zm>>k&lRc?9F99(|sNpRti``tJXip{F-LD_Vl({IiA3Mwq6ieDmQ#u@P+uxeN$n>S! zU1;t#M?PAIxggcU6+F9b<@RoG5M~2T%EMRXtfS!a)jzwrBM$LE9&#dJg&1)eK! z33Ox$SP7gN6RWFx(M`=ux812ZinHy_Gjg`m{Na`*zmC#jva=mQqPYzlsiB~#p& z@=;kRM7{;yStUXlqbB&Z8aRi+?B<TDrRWeq zUm6N*Va9#?mMJ9c06Ih7|6O!imrZq{*2>veaaRfwn zzWlLd_hutw3F%WKl1Jwy8C5TF7WtmUi}e7%5Vr1Y!AXfIUd5oGZ$etTU{qtqk2748 zB3xit_9`_jFdPIwLgu@8^+?I$gx1q4wtMZrDy7qDQVvR=;~OO&VInVqFvP!9?%zKTV#EkF9JNB75^fPuq+xXC+m_Y6>6peRt zz7WXx6pAll<@AKBJy}?5D`?^SrvoSD5)AeZYO-c<>jV+xx-ET-N)fVU`!2iC?tGbJ z4kOB$J@K4P()EswXlzuUQ?PYS@nnB&l9F_2fvyf7EN?lxQssc#z*}vpDcTVO=p*_> z^U?K6tU5KRdy(^O#MAC0h7iISWcw5th%0>8b*R+uubp_PXI;b?OP~WLQ0Kka@T(t% zTj6x*h1i*9yO_++qC3DSDnsdfQC~9P@_i8qjruB2QzL#CH2@9fNWmpiq9PexK%QGU z(;2OLzMh_)=+or}mMBDuY{zu6e0B{vEv_0AFa)XoCkL;BMh&=-{NU*3Nh2ReEh;L< zW@x6Af%>sy!Ww ztz{)_pEY&Z8oBFIPa}#S`Izgu>DM=f4_3Q)wCcWJ_sov zsHY!oV7Io*Y<9_3&pvY=Wx#%(A|y;m`>I(fsuEWwCP^vu`**HlvOS2_mgrq379(`U zMEz&6nBDC!aj>T6$;5`#DKsPVgdAZSSUsS4VwG_3ku?|fggr?Yo`gqRgvRXSMP2}bp^R#;6OWwzA%`vw6_MM&`+3~@I9j;tc z_0_FNhul1k<&{L`^cJJeb{#{61iC;jtboH^1l2hZL0AS(^=I4X+~tN=u{ug2l+wHntlz8293UUnF}^z zE+b54BFXO2o9;eUiiPdXo1f=8$rTybok7shrEfp2k^zQNs9a*ZSWzzWLig=%XeueB zTMx(?wMdQJQfccMi>|foxGulPg!&bU+NN$1{${sy(UlVU7Sr;TSz_<~E&{+HDy$C$ z82G{dXRlcuS(OxT4w(y|e=vat3 z6iqjU=+&a)-W(h?6i?sdm@+2;dtXS^2^}!5So&ilMh*>7oXM;P!ZIw#2SI3pv1jKt z&IHhTjdx{)8A}*8w~k3VI}QV8-wd(|v9oI$jd$}+5W-{#ViR@!Z$uzIezde(w;@Ih zC)^2-LD53_5n9s{wFJ?Z3n^Ju^kS!TE8BHs%eiLw99`|{8AUB>xt7EPBl+%?oqr;I zPL<3zbdIX~%^27jRMiobR7b(-a~`T{NcZy=%VuI3sKSlKFMGDMILkWmS$nrL`@5S{ zhn%vvG({v#aDrMB1K-z4P;#2g-+{US0kF0TH_hV{j?vbHxg#YgAeqD=ET4Y zax#Q9Tr)%C8Mx3Foljp9&h-1mmr^P)z*t_tFJ^0q!ur6~C?ca}7%Uf9AVAylth=WA zHO25T`5K*vE4Vibu{sFFrRglbdaB3SNxWVK*A={K-i7%{=yM*^Z9`+d@>};nWpazY zk-bO?%+8=D18~6Rynjh?<<7cx9YoET6U&Sk2HpGq8raB%)2saC#MPVaZCDXcBZCb^ePt2ho-;dP)x}&Rk`&2GkYWwX_eTWo3HKwzE zBL26h0u*3D$A%hXM$3wKntGsv-DS5iH%}=J@(`wO5OQmOnAkkUMjW~OS859xRzAR~ zjp^k_^&>$(GI6r*pD7D4H52L;>alp1MNF0IR9%4PgV$w;v!$(EGLp`;@7 zPUX#P-2pt@qjd<`fKoj~mRyP}C?$Pjpj?Z@R?_SDNe$(V!ys#$Xs(?hghg zrrG&a60>HZ4lX*cGbc;RXlbW4tw@m!h)X+!;EvR0MZZaEIC{HvY3}PdyY5Q9m=g@0 zi9}ZN^fNFq&?*h&EA?a<_T*~aGBEIQC{#Whe~bR+8_(g+*+JY`<1k-X+6QNB2>OQL zSt!ulT*TIsJ)@ABcUwx9jF$@skiMPuHMs0-+&k9fU4b7Mn3m9?GKi_9dc}0#GkZwB z*w;~xy~U@+35Z4XATbI_b(m9LahS55FRaG&L)S|stTrc zwy6cCRoauWm)f}L$o%BL!}aywL1rc5s88|d8Sj1-4-4ljwZPOtTiNsWacoQVU}iiO zQgN@P*!rrTlkJZMOelOyslQaqF<}78V`!5gsahbZ^C;9YLMrXM%lIdoi-BG}erRAy-w9V&s#VuB)tS+`+)er9k^Fq2f8O#Z!Weh)V`Dy| z$FO6v2j!EX%~E4!n+bcX3G33{AZ%I}XmK7!hY4wqAJ@&(zSW4}tGzl6JQfybX4%V# z?tJy}uc7vP1_%U%FP_TgS(gaWSUTHT&V*Hr9jRZB)m9`Co2S!Y(uSwTIlT05rZPM9 z15bqt4MOxF6?~AYe3lIhj)4%`V?AXZNemQhz8NkKW?nI9!ocbsD^Jyug@s2yIA3cY zh=hsiZyuzJr++8+Je=rJC{gJnd;)?O6AWg289^IT3SyETMV}gN&3M#5y?!Lt*ey|v zf{WScH`UB}J2tO5m@vdm=O-f)R6q+utAVgnpmy^p;jq;Gj_>PO$xx-jd9W)(j4P27 zf$vL!TNWcl__%mTH8px3CfSRty0)Q76v2hEgQdpS`FWV`jp6aH;juo&1mcfTVm@=g z&46ArW#{n6rfIykr8Z#CcCiyCPbzjs@xS7C(x~%H4KX;2*;0A=>0Bbm%i8M4w+GVi8))okN?cM{JqXY`tX| z(Cdga9e+x}AvT^M*TCn=!9*cRi;F`{t6NPyRu$P-m(R?0=EJ+eDOQU0#) z@T-In#S}x1h2@qG*!&s6X-Kq%=lEJ4ggqKfH9ZlGpNNpfGw94z+WLd#Zs)FEeGGMS zbL*tD4GfIT5i@wCW&i$Nz2{SXw86{mu-$Ub7jJM`aj#qQC1)Uup3yI+^noO(1P{bRi>3v|BlvCYarT5>L!oA=Y*CE zZJ3y;(u?{enY@D1QgJys6pxb)2%P7elIk>AW)>EHQdE9AOmM>JdKH>_EO_@{mD5WO z^}tlL8Mim2m@h6HmIvo+@JwEazv?CC;TW1pU7cqk#IRyQXM-o=YUPY7utdh-G!~{- zD$YozT7iL3%He4LvhzsJ7+l`R zOA$Ur78WNwaA`?TRYN1EtPJ(^^fYs9)6Cr5H#iuMhX@rC3Tkzm89rTU zTAa}{k%)jATu6dyhB*nhTqmee_N*19eBm-zL`XBzCiq~vFHmgt`6u9%nakf&>KqU= z+WJGLy1LKly5(yTGTD|-+A9gk9CeL4T~R~&C=!9N=eP>1ouQa@-q&0KBFoL1rbU=! zxVUwVjfQ;*v~PIqDdy()>v=U9VDXUi-p%Bfp-ES+A}+poVO3mMavfWRM0&7a%25)@ ztZK^=mHN>vXd>}ALVQPTO;t;8U9fWIsf+M<9BOxwrU+=*Xq&R9Oz(CE&F=EZIOlUc zrS^*#BQrB$si_1U+}y<&oc>w-Eve%3| zOuToS6YRP?n)lq~nX9-sj1k*ud`&czmuoU=lAtfiGDpOwq@)8f3K5s0Cd^4FG^$R1 zR?{G)L_n|b`=hrQUvZhYZLUa2^errbzctBG`7S%7fOgwU^($u7Sd0}(42xWSo!QXX zWS>(SW_2C5A`OU-c=$BHvgkR3!(LGl9Sv5PyjW>d*xZdr1Q7`YNphqU&31e{cA_#v;-4Bt(@kAYCz6jBTuVAA(uLje*)ZTb)m zh_ui1l0qBM!@CH2Oe*o=k(91Vv}E}_Iz4hEOU}yg3P1#!$dCxj9J%XhDFwUJ*7-<+ zhhIrg8plK^`qehm_MktdDV3o$3t#ObFz?Oh+pm(8?^D!I0C_+QZd8mlj9qYO%eq0+ibU$HS#l8l1HORaFzS!J-m zz|YSAmQ&_pR4o~Vg#HXab9R#|yYP#Ny0jNOiXd!|RiFq2Y==X;AR{AV#-QW^TNI+= z6&&1oZkj7gEIhHo{@eu8Qn2P-Qw@`#6=NM7#1HSPA6Q$Ks*9Mh_TGw~I8iUTq6k5q zQE+=iUYrNyItNWB{OV&6EGu(1wEKJHs3KJRv4Gk?^S9HBgEJapWIy6Eas>z+>3!yli zFsP!9gVUEtfeFQ%!mO8pLUB@d=?f#|A}OotkA4V7%oj9lT***u(vwfNmatmoYB4Fk z3>D-c_SOl~;pqqz60HHCl zIN}itbeJ8SXOeS;1o_%?%)JwnbYMVXpeC~pN5o%93(7Tvg7VE#b2)?`3lS?vRdV$& z=jXO1^9opyb0f;pA%$ea;moTq5t)k)+G z=qU_e->cJ40s;c8daaQiPn)Q3SmREC`)XEVH06(EW`Y zMX==Zbkho;u4%g#kR#(sB(%mOO==5XG^7&JmA8DPN@`Y7)b=94r(ijkQ1au>yI zSN$@iF*x&h-X1kDU68GifJS|)K0xLJ9^irn{JCO=*0B#h;9{c|er|q#d3!s2#bAJL zjFy&Gk1b`Y(iAN|(LINX@N^Tt6yKnMv5QKYnh_4fsXLBktCNP@ua zg-FTp0(E303gAO5+U2j%m(gUU@>eHS_;g+c%vC_ASYbRxp~3u&<=`Y;)yOZ^KE`97 z=)oo?hrpwBj?qTyW}(^?>QE5?{8GxA=6w5p~iyRcB2 zQMqGMqn_YxN=oS5oDK*S+~HeXOwZ5HPxdHuX=TOl$L%#GIXOgDR@TAsv8bLN85SbJ zH^dHT&ue)`$c}0S;SVpH5wjFSvP6U9-YL36ba;%|Z-n7|ObR2GTo_lc7z5uHtEBp6 z{s2qz6w2{h5$HsOzr=o%QD8~XumN=#0ZAbN3cQ;h;!J#1OQ-Z|h?5^);VnPDoSdB7 z*|h1%_;|qg?j|?3f8zxi?68NjcAzcPiRF43> zMJQr3H9owwb9L>BB;*DFE`NRJgN2JrNkaqgB}j_Ke~=lZklJOCSyh5C&0Br3GE2|n z#(@jm*`)JngsqcCPS(}D!OMe>6%igl{O$l2jCC@?a+(>6J zS!sW;B{{S8uDd!V(Q1S+{8J)7H3Q^N3pq^C%t2B6{Ay4PDKTVv$J!|XQPAjbGUayk|Ah- zPej3o$>4IqibV4Xu{L-Qk(t%&vw-bLVFllclv@>^d^oz8a^;gtxcVc;d4$v7^Sc`O zhB!B@F)pD|IdHX|4_sQni;jk#0{#>0s9-9%oh^XlD z{(f{p0ZjxE@1tio2mVLmnGk5mnH>{(V|vRpNBN%wtX%i5n#y`0Nc4rK6#E)sJhUXr zBM`u%x5g5al2UZTidLlLo`}4PE`diJUo@L8Gl-NRIAmp&TpHBztC(WOCngGU&>-@z zGJr5L`u%(f4YNk~iR+K%<~nOrbkJZrvxK`idurN*_n?SAy>=eh^F3MY!GT?(DqY$@ z_k5#k+p--x78dlgXV31H-SPVuVId*VeR#a)%*@U?6&%zHA}h|RRa^m0>mnyv-;PB- z*4>^rZJ^0%jSvFAS8BvhuVIBy9LyolK^S?Aeh#v8E>`}s__d%UHT4~x0Xu>el`^Fq=we@o6)_CD&P`lJj)h_lib=aYaN3INrTZE- z5sw{+oSb~B!VvC_EVYiV?(*&~ih_c|@a9aiv0qc-XGASx%UP+^otAeqBCgt;t7bbM z*gdOHpqRQpQ(btxdBytyh(JFi!M|uYFffoTuanU~n9HeY!Kue8kWyiC(MIT+fd0Xg z)7lj4q{>Y*NzGs1hh;sixpe3T9Cmo@SD+mn9S?_|-H`$IC*XP3Nod=Yh1j)f$Fl@{ z9bdwupmYIR!fHNBWejJ;hCxgm+331YK|>=Yo{bV&+RKb3#E`W74S!(xL!&Dlna$&+ zy`smCN_6*!tfHbK7K?EjG0FJjefCWuCo+`xv*BOqjlf?ZN*=wSSu3<^D=9l2ygp|& z7ohnvSul@mfrV$R#2q&5jXs4|P+#igKShwpT`DsUI@puvrGNqlun=HDqwu2&JxRd# z=U`DKcNG*A42g=80D1#-fYtIVLseB(W=#!_NESL^u<*#p(C>zV!^5vigeYQ#7;tjx z>+zKfu^j4&>MtXKOzu+fJDco6>39ZgMBuU=@xs&Ms)L@6PF0Ci^|97O!jSgX?yKO` zRr6WCG~Lg;%Ui}({W-)o-3V;><3YxdnM4Dx)Mw=wwp=>pL8C5HFWZ%L(8lLsno4nl z9>+dIG_@jTK<6&~R|YQg2F5XQp-AOe*h>J)@(_-@bp( zu2Bcs`k=qnokN3*`nEh=p(90gjw5;X1ZHdeb{FqZ>D8-fz!pX)SH@VI`Y@=TLRoF3 zC53^5nBq1>Od*?1Qfy)f*I8LLX>&ctWjLlS4k1Ngp#ohL@oKk{)IzmS<@o^N#sdfd~6E9gbH$-DVaPSL8`6AGA zAnyr7wL-QJe4uSJVryGJwqNZ=88+kS?CQ#DY9azwoD9pr>yr;;QIU9E?90#w4_29C zZPv{9)SIv{Fm1E5g!T3HQ}vEdY!;dd9RdS_gAI?r54_>BPSp<&DR-<5Hl=E<(XSsX zi{m1Rfroya27H)AdpuW%RK7Sh{SvZMPMNxWYQ|Q}!8cASf_BNl%*`7XN(VItOT6;p z5-`%ZxHutnXaWKP;K&gRgbc&OW&zOkl)yFQ?KLb-yk3~|D}|>R%(@L&d3kxgpFg*) z^(Wh39O!d!m~~6g!-L5{q&~rhGoH84o)I!p$OP(A`pg6>(2DDjPBElP)X_|Hry?sk zE<^JkKqiK}cdc7_5_8rjX7nQ#d31P=Ep1D6=z?F041Q>jyagGW8~TfP)ctT822n|jmUxCE!pO+T43Ccby}rA} z#lXNw&6wP#xcJ}Beh6^PN@F@1dI`Wz2br7>IbFHPboOLcaL~JRE zS7Lf`yH{_^5zXivcU-3^iQr{e_bFLF-B|DfhrXH0^zi5#^fe1lz$j8o>+ehM`wYBhOIXUlhX z-G2z}AZ2WI7Ms^6#PTMW`|s3;`SAtV{m zyH5}y(Weq3Xs=3Mdcv+VYq4N-a<{p7%af}Ft?|;CIc2Vk_LUeqdMZOkIC#fs!|Ow4 z;Dv@|PIHIelQNVy$0yc(gU_a)}BYqb&^SUt1@tg)EeJQ_Vy z5}r6Lb|G`DAW+C*UenD^2l?t8r8V``^zgLCGNvE<`xAmY!J2Kyi4-n{;`1{X@#o>l z6tNhiMQxvPUKp}Du*N2sab)ZS6+t8lxyBl?A-^L5@(tD>vTjl@O@pimV9#^O-}p6E zDAIHSXM~`cnHi=-vrX!f3|N?h^3Bylo+?k0_Kq(*bLSDzQ(Va7A7eQMtR2v>7CaEd zI%LMbw*)n`=keT3ddcEFU%p)p24PS#0yo>#jWKlg3UFP$Xt48}SHpI`!`66VFW;HE z1lImw<$!iqD!z4DZifMa?IMxwhNo|k3A&@g#J=a5mVc`k)?*u}+OX`OGS|E3W-9+!^R*C0iU8m#~ySn8Fg7b<2L^nbs~dx}uij&=1yezWKc8$t4XN>oiLZ6~G+r>+H{Hk!2CM zVsEX9p6a?x$apuvnh8X`|6WaYJD2l@yEu7aAoYq9A@zvQRvuE~qG;1P(>_HmL3cwiM477l*OglhJ@T4`^I zUJd^6zJ0Ps>P63NP{o*Xma=Jg92o)VQ2qp-H^lIIv7P(XYY-`^1FNlV6C1Rlg!m>) zf4ndF6OL^*Xtk&@W<`Y$BxBCY(Fy||zua;b*?|t1FFq0ZYEdIwvD|DHf~G{b78|I; z)N{H$iGhthVNK%diH%Q}IR+L#eiZ9?>&|~S4(b?lMxoxYY$U94@=IiZv--@fdDe%e zQ|}KiGF;144gt$Cwd#{`uh7TZ07myL&|24 z)Amo^*AZzHo^?y%rPr%<^tfL%=T05>HrhIJu*d@_Sk2g$@xjy(K9B>jv zGS%4F*!oA`K5tBZAQim3am>xjyWg#Vf5K8wSSVp*Q`X>0*$%be#F`D&$eQ3|PTv|S z>i^E37CM)oVAlmRaYw8yzQCExqUz&9DkE7Lx4XC?1vqG&#OZ)WCd9~yX7zN@eVzE` zYWqX)(9k~H2r2kuz|=ysCxBugu)zS%lCaM6oGD*6#qaWXy*TVlSsd^Kbq*G+fPQmyXt+OG(!!)7Dwfa#1~gtPdOpfip_aaz}9NyLZti zCr(BtCI-_VjYC35A}-w4E``r2tSKZR_uACWDPFA}H%U#fT0XHDRd=>5)(QIB&7@8> zAgkxVK=8wG>RY4D=$^C^#|fth`To&bKafc`v$5%Jaz92VCPsPv`t`})JmKc%ChDCg zunMv9@%~@c2YSa}`CP(yU!QexFM2`Mr#Eo1hfDVmen4*9r61Ct(jz`RKu$t2e2)-+ zomjRi|Bg&-W^L$j#_~hq?a{Y*g_X}w-USGefimPLLxxE$mRVH#KQ6gvA7s3fzNeAx< zJmmSjE9s}p?}S!!br?WCr30A3aLeo0-`3XjH-@w7d~O>=pDE+w;x@Af0O?)+<1g&@ z2dTjfc6lvUx^^g2ROZg^=x*~XErIq@<#EmRCEM>iv!K_wJ2PCM#@E-1ITXY7j_c*X z3QQ~lSsK;Ks?SS@Fwz^mHmPc9pQYSY`fxa_twamogrB_g{f@|!1yg~U@PqY5=E+B; z#=r|up@4Y;rhpg)Mx73mpT9o_0YTWyW)JEcq;At)az zmaW#IJ^RI=GX%qJGcQ@n`UA=b!DsNv@(k)|Yn6GNx(*{Hl3qqGXh!L;B6utJE~B2y z?B&hg-JUO6%qqNL@jc?jb0S#qOt+m#Vrx4UE{afms-!aHXl)J2<^tiY>k09hrtT6_ z_}1ESZ-&Si1}_ZnYg*KX(AF3?aBl(V)@mCZY3I&#Wrf|c$d`0p%p8fx_Do@a7SlnZ zrh|4Q%?2mhqvK=Zvsfg?$;-2PfBQ7`Ioe$q8f8GdkfviM=UG zaRZHw)G3U!sdumRoH**gJ<9tkt_GXF5m2rV4v*}kQaYg>HRIst0mGuP=dz7#I=Q*I zk@4{n_`{;KC(x=K0FqaFNMAcm9SEezO1QU`7Zo8Y2%KWUBIALdCl^S5D}UqURqjBA zy6@gO6~R45W(yNG1jL!o-x3C#I4Ugr+MmOwA00VF;IqTpHlHSGb6M)n3sC-k%`$RP z5Ls)Y`Qbpcymk#bh3`@I;q#LK$X?z8*#^7pj*xCx3hRVIjYQPm-Y4lnSCCMvjHcee z09*U}`}IllM6y`;!qxzH04QR}$X?80hnKxE5|ZJS7OzCh1rZr`n#4=ty*j%ad#fuq zqPjWHO@iyQUD3r)-u7GLv}@4gyKe)BD>B}BpJ~MpK06j9X}>LH?}fonK9Rb5Z2kHw z|7n_IG>tKLMjhNDiAgD$@B%@cvJ5>bx}<1b%d!2Ym3;kN=JtKQY)J5$0TzWIcZ_%x z$hGY(G^ZV1Lh<`{6sKqk&dO|)l%h~edUze2(R|Bq29KkDa;eve;$CorLK8Sax3I8q zLJb3dM2s$sgO;U+x=A`#H)jJb1fU={w~%(l4e`Ip%SE_MVPpm zOFt}2AO<(tby?sfPk;bi`ZkCUHZ?UJd|@BbTWa-nTM2#As%Q3OJTC6hz4AG(4~m=9 zR&Nl&5?_3?hyCG|2BYvcu(b0gzR$r{f?{`0#m#e?g%f2TxI>8`ACOC6IKgOA8~@P(j9IP(Z2^2*IMJ?ydX@()*|&!G+qTZHXg}g19{GC3m~X(90m}(clHS%EV~s6 zn7sN#hFFkdokcMeJ$njtpU8!XS`Hwd?3M}&JXcWY0qnI0PPv6luuFo07${QunF+*V*o}PeMpW`;g)J=TeoO0GYL3W|q3bO)xxeAG z#4)~ejYeM@rN+re<2(mF2f;jvoH<^6{atU-*0I&3@YNWQVTfq+hofX>R#^W;F(UA^ zV*b_c=BD)K4UimjTT9d!F4kZMk|9eAXb!B3uHA?@)k;uL%#$mXa5$4K_2?96z>UEP z+MnfVPK&H#E2cDy#?im}BhWh8O$|!sPVSi7e6@IdeCbu9+lUhy8hW3n-CtSR+?i@S3kd+L@8vly4P&FIbNhB8?Vb(HLotM0?v{%T_3j?x8LWFnRg?y#d5{a2CqYaf+Mn< zL}2HpEuFLM8v||8TKi#_&BaYmUCM!5kKuF$NoFUlCfiS!)FPr2fpI{#Vq{#5k)b3z z8xnxEEexBUrueAT>rGUPI;)(tzK!RrJfUTCna0j;H_?}OIQ#+=NS0qGCk=rR;VjV#AcK2kV$A70v|VF88(<7o`+6b>pidnWd-H5S#3RIsqH6jW4VtJnLVt_O1+Uw!hzhk`|Jjir>N*~P^M z>0Bg)21^oPv_B~V29`WEOPZ{}^!36AaAtUdUOYC7`T3Cxtg0X8TRsfwestY`$$$AR zo^KLm=04ARpVXya)Cn`RWS9(Zj)-p0vQkp%<29+Ijhc%yS^COkT%+PDxuItqR?n%F zQdYeyP!C!z0T=p4K?CZbs8h1}Y4w=1i&$G*n?@_{D#UU$SNc9fOtZV*2kYbQ@5?yE z+Ge6e7VQ_G+i~c|&-LSJm7;(se(PYyQ&z|CvejQi=*r%?R7rYraBbmu&sLeo>$?Wj z)@sXoiqx$c4BrYwE+je`;;&t?6e+$hkT=(&H=0j_F>@+bORwWDHlHX`+wFkcO2;Jj zA2w0K#lkX+83h7Y;8x|!ajy|u)A8WbH|(ZSgTq3)Zsv%@!5ZwJ<<5(3Y3B{8><@5P+8yG}=S+PmKjU^qfqID-1H;1^WXNr@7rI!+l|Lj*l~rRgA# zqT&U=#|UTP32J&Do=m=a-Q_qWV9N4Ql(es}PjxTfr4Yg!K|(T`q|5R{a}e;siRPhl z!;r@yevVEyv0cL^hnLuD*-Y;pPBKAn4_zk!cLBS(7eZt{Z^4pHkeLPF+-`oc2nqW( zLrfC5^40$Yn#VuO8uR;_yyI~6O*);=8BsEdsI7LbdAMQxsI{+ z-+E)G%Jrd+j*bq1NGiv4=&km=B9LseSj_9x&d<3%DqYX1Y1$UGE{lixM!daX)#?IA zA)#rj6LQcwDm|dd7w;RuqNnqk&m#b2MV&sp;$kLgX<6Kjv={|!LM!nKf^ARUdHIpP zz8T4$q(X;h0Tit1dap4dS7p>hlHf0t<%RU zZGDOK5Fi1M6GiX$*3@GdOiWB}I~6@Kv9Z3^vo+?LQyDqV*^rE)ORCYHy=FNMf9G5am_|l+}!I|LIZEhEiUb-x>#6QBz#jkHsFr~F&nxS&zgS# zmu{!sT#NONaISlEtkXqQ;eeizvYQU(5*5!sWdbGF)~yUkyUt=UqbUlWw>&`_pECk{ zxk=-PGjUDe%rGIssO5_0-`2X)6>h&iNZfSy2F8WnniR4eintjI>DZHVAp?%F%`Fyi)Kzb3 zX{ki$-HS&+ev3OUKAv_m$Eb4pVk7WnU3mlivY>L``tHpF91ILO%WzW=tbdy#F*|*D zDl$xRe^-%Ou^liR{-a(>g77rt25HtIKK_UoGb1 zGDdJXH-#8&6*RK6_BqZ&z8+NA_z$as4L#6S9H!rJH*zn$JU^g^TGjKR zHom1$JoYK>APfj~_GV0)vbvy9dV|iMZ~QDE?;5K7kJD^o;x^nxH?9vYyP0+?iNj>Oh*{7IHs3PA%Frdhdy~L)Z%kX zWBy{J{cLxZ)ohro4~GW04?45OA!E{UO_-{?&awY~AadbmUiOBQlXH1R{HV*;ouB0D zbo>4Bd4FBmG?#7+`woUUY5wV zCH1e-(9?_h_y{5*BF1E7MDFZZr9XR3Vr-m?1TGM{SnxWQYdZbYJW>WF{mz11I&Tqigd2TM1>>Cyc(IDjez)O<>hs66t zX=kop#qhdVNc>s!s5+n4fZ)(!105WuLF7|8&hD`^<{)bZXh)!`;FqzDvg9namrJ1&h zis&XoZzGvMT|ffK2Vk{201p%m>_*$CD2sLWP(T)?W3Jv&ntm*jfD;i@q8?Nle7J*2 zd$AY(nSjb0*conaj)#g`0!7F#yaY+yzhMyZyP>P8sa>2-zG8j-!z+UdMaWZvd>#b| z-_>s2fhBv^`*1{_z%MIe)zUqv-E@Bx~GiTOl+T#G&~ zLA+EkKeLvZ43*GjNWpq5JA20b3q!J=h|&gyVQ6aA6b-u!<= zeFaceYa8ySQ@TSM6_FAU5$Ohz?vfHoMM?yuLFrQI?yf_(fS{msw@67#Na%gnfA7pa zrcT1)W}wnM%j#oj%NCLM~K^`X>5s~`i^1H2Qy!T)r+(T9u}}b05XIC zWLp>FKIbu<>q8g;JhggFNdngIimy(7O7ww;d#?28{Y@*$ z38&1)me*Anvy5R4>lMGoM~O@HBD*4PJ>>IoAtu~l`r-OgAMadyj_{jU-P8SQeeN(> z)>5N-B4{cf#a;=#=P`L#(RPjxMJn)ltm?m8zQH)?7o9@P_%EN{TFqu+U<${x%obwjOsizn2n`NK@ETD(1GCuK zjt)tLPh(@lxH#SGgPY?34qT4&VjJj-KAjz`R@senDUbdI=yP?Z&R)OWw{>ErGDX<2 z3wq-CZV_w~gM))~vnqL-+@>uwFb-6O5cFvu+!9WSOrY3_HGvbEv2_kVw?K3ee#qdV zm=XKWy23{!Rsy0?GcG!&s=>0jx&Ne?r=R-|R~DqY}i2^x(7jUf>}UWk0NIEuMzrmE=<`jXS+2LfWM8^#^Y!~ywEK%;i3=rVJ20oxBc!+Pev9X@%IeF=s$;H8a`GwHe}sNv@lV~EhwX|R3+F6eF6*W7Ek_v4e z^scaY&8WYwS9!|Yi#@u3uu52(tk4&cC3x2G;O)qJ^_vuS$Copms|WiNM$VmmeK^3n zeH45aH-RN!68@I4Y!OsRS~a-V0!RrOEqJV8VUaD>8MdFP(w7Eb8@kKr|F|o0y z-9XDbw;W)@xl$0N%d`9)%K!Z3%kCH!ncBzcMuyrJT93sJFhT8PB|r-e=>Y`=#S$EQ zWF6*rniDy@xUd9W&Q!~*yHSh}^4}j;+%audHeV3$x)+6gs{&^v@}XZ!N@V^jKCSxm z;x92$-Z!shh!1wm^bkfUWhYg?`xTTlJTj6!u26OdFXX!>$H#ub%c!7`kYw+)0<|=0 z7Z(9juT73Lj;jBh7t4PhIVwm=p~**Ij|BW*b7V~1V>h*b@@mR5dh>E8#kmbFbF9F$ z+6oV~^yc3MQ+9SXpXa`LseTnYl!;M#meKp0`AUSi$%FP9FC$-@-I~0!tvVKLa2Y}QQKqL&y zXSCoj_ievT#~$c^-BLg2U@Sw-Ljto z)9r8C`;$IEvGM#ptl;*y4ZaaI5b+g@fC`1Ov$sDu{KCt2_bxfQKZ-RLx2LB^w^pzss-960AsaX>ZZ|NkmNxyq zHfd{T&2F~7u#U9h4>`#g6D~bA-<12m6;O}r3%-vkV9LzV6B)cEWw*Xz%#zCnhbv@j z%kIbedP;(|t*T81%i+cE(Z@QUCIBx(Z+745I{GG2aW^@*dwHpD(zF|Hw(+o}ek+Tv zAiUzR2!MT!+q?}5GLpF8-!Te-Ins1Hvl?oOm9;f6_h^80@c5oBpk)AYu_2V!h1t*ne zpFY6_DVCSqGn2{nnPZhjiIAv0GfRs>R_t?G5v3VYbH#PGJ9i%OD#agY#7~EC!?+v@ z`^GB=#vgANTm$&RBMcI7)n00arGl$ioP+wo)Y7e#9 z*q;mdD(a>TJ`NE>;rU)iO{^kHw~g-TNGN751f)cY^x%ieihlrEK2v`IthnaCyOjDO2-*}DX5E$BcBOvjr;uX`z$ zrT<8O_*%Q1MQhjMcx#-?L+&Yzu*H|FjENU0Yr{(@dW2?XW;&m9)l#BRLyHqH67xRz zZ7*s~1n3P(M$p;bvR`-KRmwg3=F>X=Yj3c)vCLsV*&)RYKT^Is22=FE)~-+gsQA9$ z{;K31h3%O2N?Wow)Sf5XcR854W38BXfBnY~bHIoYVn%3A1k|LS7d!PD>gs-$eNnOa z0u4oOKa z*u|^tFOTkTxvm8)k7?7LsokDod1B{AEgy=Pk${9cKT#R?%|!Zfj~`VF7`V zV?d09fkR|IQ~OLl;|s{L;T(43*thkXwTls%-EERI1HoNc)dFgN-eVEKO%f+3r!!ap z#(gahy7oKnzF8jllk-tT@?qhU3z7c~;eOIK#hK+!Dz3>o+5GMAw6s_9(-O0PxO0!e zyu;9;>fnee;H#tihlt5$1@n=Fv5D5rj7o&xhg?jf5BS1QHT{~~0CW-W?LU&v!&ByzxQHpOwhULtQqYceG z%^nm|RPICoC30(?L|s?<)q0x8KBz=lLEME|1>T7%L3X)z}9A z;EW4ZZ&jt_}EM1pndMquI>K|8;I|2ZbO& zHuwd08n$Sf&B;4FDjBV$5lXUqr2A2KXP@AF8ay?jv#~r5r=b&c0y;Vkbf5?oh zXU*RF>}YRR|6_iI=X*rmgILTHfk z>l}4cq$!70OhaQclcUS(c@iQE((yF&c}E zj7-46aCUYUJDqze>|F4x+3oDlDdFWyW}Kw@5|-FG6|{^i05BHsE3w`EzR{_LcKJ%) zpZE0kbJ4Wy7dJ~Wxkk9Hjz=Tv3U3)TsA_$6iOSKtPCAM4OalEO6S`Q}vD1LfaOGbm zY}4cwZS}1I+sRa*(Kr>XXjr#^(HrRVhFbf3!lITvR{-mTsV$uNUTV);NfWgcG4)Bu z7qc%1JxBR}FiPnBDu{1Zu6|@_T$3*krp&0(f2|+?PjF~#jJ?R+oZ?tB=ihg{o*r#=6n@T*r544VD1){@UQol7yMX;d7PNH6_XQmvbZtXWR7mW zx}!budY#v4eJpM_t-RN)Fm2GodO)=|F5K`9(SG)QrKXfj6B$Eps`z&^-*IF#*wVVc z5k9Wlq%*ueA#LIl{v__FCpsyc_8Z^E$5CzHR1W$Kx~*<&q28D=^KDSldWms#-oshT zj}vzStOt6DM|NnkCM(Fmqp!nH()PXS|K*w@W#dJ9TZzbib8A z{M#9I8@6$-Ti)V}=8WPTx?<(kN%h$f$T9l`kkiB#e|Gll(MB{PC+uh*z@2M2? zLb^@BPvdr8ef*~o4zYE(A&7N(KF}wAviRl8rRgaAoeJ$OO3&jzJ*8{@d(ofEE=W>t zb9;F<9W0wBFa`B`n{w*?h@DURV(m6qUn@%Rd7?#>J)oBvZ)<*a#F-a>GkxDHcgv*JuW;Dirbc)w?MIbT zp!7QL;UQM8ea~#mKsblSOQR&GE!p}YeeQ`8g;vG^UtOFkWQfmDXH7fIm)NGg zjpx4p`WJuT`!<-!LF-iIwyn#pUx|VtycjqB{M_pjhS!gLPtc2!qqumb1Ji?tr*KeB zjI@p`qRdy+;TgR_r49pH1lK0}UOr}z=Q)^P^Bzmnc&*U*nda0lzOjimSF=bh{2W;= z7JN=kP?EB;LGsI!?)#o%X?^$p6LBy#y)GX?;}0H-F4!HRmB_*V1yge@$QeOknUI+H zOg6Qam`;%H+W7c54WBtGZ%aV*h(j71{gUM3)pID>H+cxGSnP>{9d&(+74ZL6U{UcMlY(o2O_wCGRcd&LsL%Z2&Y{cpcqSw5 zm@n-F92x6SE! z_J#hK)qvH`LaR{${pv)S5ea@UUG~+Y&nY9wiZ8FOz$`@o7T+p;!eHsFk$=oNEecpW z7^?R6w?l}T%9AOzb#>_oXTRLuu+n%b=Jz?)oiADU_SJCNBa=3XtwR~T_=gaIrcQ3P zS#0ZI7fe2n0}dk5vgMv|YRj#$qR+tAhBEmU9?`(Ygt&xW-i05yf=tbll72&lBp|=2 zt`-1J2tW=Dz;#7@FM&dBD;rI-z%4IVzLy7Q8R%Y}#R@p^@tluFnw<^hZ!8x!D9M+o zC0|>c^y~VEYW!sLA(O9-ugX9+36&Z43vI>HCnnZle9dgGR~|2Q<2p3W8yXlL2=EHK zPx@GuT84Neu+1#DZxaA82e1*Jn3gpk3E0*EeAdCDmTcTOg}=FS`R54q0jOsyKac)! zg(r8K7jE5tpO9bY9MIB9U+v@N=07hAWR1RK?pPGU0n}4rq19x{%gT@d$2Vf8-J_S!2bcJQu?Y1w< zO~HpW`|xA31Ba3k%kL<{4Z-a@oLj7RBj@4%Xe~|$hq@0S)_~CfLKzYi_ots`JOM2Z zpkcD!-eO%{T}$ihp}=kG#0Eqmj`Rah(C38~6x;y2*V5{04yohH+FCHctQJ7u17P&| z>(@`PaaV!p$++FugtCr|lr(FmVBW0FvXAKU&w2(_oPdRG39sx&%h5xXCgT33Sf3wS zyolvcs4Y}l|Ih37izYdl`#xjy1m|%&5nB?Gk&v3FU9!<-&Ie=E^7?wgIlRMekl4dk zZg=aat0<$XsVThPpo|PAV4<{q*H0ENes2Z>l8cC1AX>D3fG%)Es()R+ZBHPO7Q*798p8MrV;KGmxffHY|hq*t;t8MEKS`3MdYV3 z$;t0Nn0n#ebDC4PzMyT6DIfr-2(c~#h*6|S0sq9QIUD=P^DLj;ts-@m4{7gFx-!kFl2*S+_pE`dwHB_{3zwAU@&>?Vb@`T@@OCH%2I)PgR4e~smB!$CGn zZ~Vq-?=dn|B&sEqs*Vg+{M3!Z{lmj9pfC76c8$Sh;tkqGSiq5#0SA|dz;E8<;gNsw zf}h8@A@h6zF#0D?p6nkSNIidEIZzE|CCrpTc{jH@<)^vep8@61QwE_AU*w)WyM-)$ z$PH-mmnF5xmxLCJN|{?jF)`Toj`r&JD9NP4XFsH)1v}2U>&Opp`upEj2VO=bH{;)tCtn?sjLu^cp`9~E>%ET-xvy@2 z#&L{?0V^Amo?f29w;}lTmm85^QkdaHwsv95acDP8Lcar8=Tjdf#NL{n-Q2O(upN|ks8-%HHKp>@iA1YlQ^fA%( zOUN1Y`OV%|m3T7fxYSFm9IT835_b)3hP4=0AI*FdzocJ& zJ}2VVvl4)igPgiLN;t-V8Nn%ldjnWJs6*xD2L!iAvFRt1k8!bq;Q%uGnwl?kvam_)d>_@rPr|?yw2nV-LO{pl+gkD>jt(I0EW!> z6fZ&B$NW#C<2EJkN2gES%CRB&#AxCznc4l(Arrx@oTOuxIk3#Kvf@k;9J z(*XK|13os`b)>V@J4Q#z0q=mXlHg(@*rmC7rfHWAAB`uRQ3SgM^V15THD@ptF}|)WL#$_7mLpe-3TdM$sO!xT zBF1+LOgs4 zYWS>!BNW&gqep^D)SQpgOW#=w-{87^JNEti5HL&6wfP`AZkR0u>@k%!HRBc**<@O) z-0=2$9kAa!#xL(3F;2Kplu3?1$=tY?$&aD#nn}^b+p&*9GmK)JdvZ|~D}`;U?eSe< zEYFIVjC6N+?X9Rt}90uKv zOtp!|W&d`lYWoDf3V03aNe;cX4ycEIfT#eNM1G^!!FE-3zy z>D0KzlN7`_J#auGC+efZ!`bRh_$r@Lk}H&xdpZru{V-X;PWX%dIat&ia%r1)WIS-D zWKiy0DC*FyQMY4xJlUji`1mXEul-!zIzHriBrq@MJuqkcI2wVw5$6|F4=XFH%+gZT zl4e#O9wNX@1rZ(uPDvS;%M9P^6Ngl>S7bnhFH^bx3X|z!3GbeP1tzh4}{c!sJ<9W?RqqhaLP5JPz?AFo)0B;1F8y`SXf2IoteVJ$l4g?PB=+QkDGV`d9wEfOq5OcQ6udI_f8-ZNgIi{kVR4cu~gl zNQ9~7A-*#&J@ySk8Lq_a!a`hRg7iM)gE$1lz*mL|W&o31 zKmvI@JsYM=a$?dgE%Hi-viyh()0bu*>)5`Outu1^QjG@EBev_!K1(fmib#_WhfY^thPDFuob1S8M@J}3*P z)HI{57sYGaIl*{u|Ia-=b!~_CgYoUjh@KH@ty`mbejZ(utR`#@t66=StuYX5C1O{k!W;o$6#%fX*>ypJNn*xskRr1R30(0<@1 zLvk75kVI}zR>*Mcp3c4yVffVBn++mjq{eA#Y9izK_wVW><=3hax*qyq-ezkfzsnEB zOQ@l_VRzuz0DA+tD{Py{hYWHRY$Ap*_#UAzi9HtnU)H+j=S@oFj0_FmAym%;_g{Qd zHXv;29DOVisc`+(rwxPXTW3E*w>@q8(VDmZ@k%_vO_88gaI0rTQ6#1i);pV}KJZY>sdRiwNW+JMt0gr1%E!lt-|M&SoX4UMvJ`_u zRws}pWiSM!DxiB7!e<+soLpUe^REZ!)fazTd}-goTWtAzzKy{8WolC??QIcy3nCWx z_BxLqU+bXWzM(!3Nkz&@(jj495B!2dh^mk33B}IG7EMBe(hX80^wODv(qD+H$?paM zF7Ru%o*3Xvez z(^uk@&Ml&t{`0ckL8Y&eb@ptlq~d?-#=JZ%*bLxUE2^r>f^Z9AK4ldY;JwVSX4z_& z4g9;>dxNZ_pmRH>Dz0M(!JS*2>#JAy5qVSiH?NuQ-zaO<-+&v$CMV-Vf`p!)UY*>4 zyIw!cWqeL^t()HPV=K)&(V=2VWvNTDld(K}$OskZ`nMa0;sSgzF zP=-YG#Dp$%Ij~6-#`z)lCyPu-CLC|sK_HWudz*Uepzv=0Ubl;P$eg0{q=mMVhA%gYPt9*9Z{DF|KN-K5vAJAFU3BSzi< zV&zFm`v=WNQAuf7ROaCDuv$5hMg|$A!KkOr(G0VXhPHN4LoIelnRz|OdPoR1G+=X} z-Oqp7GBTDg?uC6p&gPI+3%;adNk76itsjH3Oh4+2{9<<^zJs4#zRzAH2GhX?G zK!ppcw~FjBUdm>54qpBEIg!98mA zjTsjmW_1`OKYE*+u6}ESdm>C zS^93?x^Y9H#5y%DE&$jA+txN1v@F5l#`R@1ozG#4?|-Bf=nv`W>BqO^;~0O($H$LL z6D6r~Qt_HbfQrQA4u{E2iWN8weXuK*ABzs9-p@HT{-S#oer&`uRom+AGpC+*%4I!^ z>vtoOk?=khRxa;UcqE+{Z%2h*iqa?{?rk(F7Ur8M**f=emhNt`7@y<&&y5+P!&LpH zvm^n%{Lf)J08oCItyh6FLvlZ0d{w#SIGe7nt&JJ07&JAd&zGc%AQXLl3UZY@x29o* zfj=}1w?d?n@rk&Aj#^P1MG#9{k^ zusR#sv55OG8fj^1Fu$V{g|-L=Ln5E=<$(flveH79Fo~W0OmRj=QyA>D*N9eJ8viE- ze7+>v^50z0KQvq+$rP25}RuOdJn8>_kZOs9u1tfR} zOj$;5Ujd6_D$y+)vD;~GY@8NzjUj{qE%5Bj^9%x|CMQ44JP@|0`g^HW^WM(bm_Znl zaq!4F3kN57Oqzm#+{}U57AEDLow6f_x?_tod8gV}5AfcZh2mtmW z$9_9A8RISju04*M5-8?pns%eYdZ-oAwf3?{$}e6JSPVYMIhYv9ntzuGL)`NppGmc~ zwV7F2(UHwdRh4jMb@i5k%E>!8nrr|TVoCwe$r6X1$!g7INWpcH6S)*07e_)(9g370 zz`vem>A#g-A%T$}6f%fR^7-!EeZ=AmX;Zngwmt7C4d03a&q_eW-GNkJ5SA2D<>6eT z3qlV6=15*K)>ly376;?m=_geZtCUnJSrBT3Vl>zT@-Bu7?EghD(SIY|o#sgN3O-0&QY$@h!}&U85F5NCVpfPg96G1k-!fSWwjZXHf{%i+LnTzq_K7_PwV zsdUW`1{^)|^er(F9-tPPy!ZW+r8A_nIsoyl0%$8YH`jc9C`~jvBZXJep`F)ZL7bL4 zLuxO*P1|D|&Chj$DCypbFm3k9T|M;V@X$k&DqwjpTiV8Yb4{GCFo9#Q_3lxMvX;`b=d2_mJg78F8 zTY|LhJ~9B3P|JDgDsO4Yrdw|O7Gymuuw-lb?5(a^e(#ABW&ZSYN7M9Kf+ib>CTlll zu5!I+^Q<1OoFDbIO|$Cn_eKt+AEaWIy+!VY`}b*$>Yaodc3`f~jQufU`t?0wr#@L! zbxh&QWHbFR*RNxWeg}smW~O{%3C>5t{M7^DOdM*=RgY+sF#a6w z6x`(q8hyTVmuf|ZVI8YdM~6(I1IFD*kd#?HeHuU02AdtUQmqV=s%bzEtDd>%-4S5F z;}65lh$sil^I5LHPQEHuL-1_%tJi{{b9FxwzNZmSC%V&f{KAZt@##bj$*&!nw6=#z z(kVZzJVJq00Ev`N-M_-6rOrTi4+*O>bp@2cwVg5TL+fHsvGmU3^)yn8FU2ZO;*!5G z1^>|LWJi<9#J)XePE6`rom%MO^I*qVZ0|+&p|Rhx5=bh3DVmixIzGM(C$GmJqn9$b zQo-yww9qvl0MTI9WJy#;*7D{?>gt-56IDHdCQbnL^Sv2$?}!eX-|nAgBixU|m`i*T z>?WOKoS1-K(NE^~5Y_sU(2U+_tU~RnIdHn6pM^oNTKP7!EoTW}wvVE2TyWST#N`bQ zljr9@l&cGwghfa9fl8N@f+DE2lp6uyr~1xPI-x-M4u!MKP}6jm1w zoiJtrfw)7V6qAC`ezcD~10+xM9{a6g?W3dVIa`mUQzeYixN$0TJ+}%oM6>=8YMT9X zM*X($nlZL6Z|$2wqNG$*Akht_?M{G2_+i-;6#S_B%8;2Pv#w63EKCZ@K17_6Qc+<8 zQ~-d1hsPJSv;Hpdd?TZW*iMRE%lU_rbA>a)nUcU?FsMsN=3I@nx!Ngv%+Jkr0LwQug$v8dK=SR|w?~_p0H=ojU}0&Aq#-~;l90zl zS1^H2KQApUZSJfEj3Rc)i?Hi7xNeexxbRV9FKc|iETs0ueE3jM}o)^ok{Jv!@a4~S_=R$uSR{mn?gfFLkEEGFpI5= zGv+wMm=B=e?{pa$oO6K8zFs;BRQey&Fv9 z79dUuH=qN`J0EDmK)AgE>m_#d{Ipl@u&wS3H)JV>g;>PpM_4k?-9(3efCkHg`qty$ z^k4T}LTfqbr3W}kGf{Pv(j>P`A~-0Bh9OrmDa!XpM4wiHS}a}dZzEZ5j{7%;Fyb;W zrE!cBa&>$no9+$#!sGSR+)BXIFq*Vu$8|Ll(X691Y4H9d0Jv-MsPqq)Mr7axoiVy( z(k0CH8X6k@pkSsK^IZ?43t+xUns)#B&Wupv+T-BDZy6F5%jf`~vvP!tIr&!@HDadDN$%bZXpB4^f1kx_@{j#)`k) zFGvue)i5k%RT<06l~=o65sPPp(!Ez#$jG>}a+sGl)2s_k8eHsx`GY&hbp5%U9tcie z;=&x=*9|q{;0tfNIRKW1_4nO>edJ2m0cs>)a1@y(1&w8`YVV?uuY!#kBT`;QTbn|k z`~5;sI}-MXiC(uyc+Kv7f=o0(IjRFxSrIr)-X!$G4jqtcOiE2%P!nAkBSNg`rTt9l zt|J?@hNbZzm62;Q|4qi>ODU=W9vgw+=%;<=w`*rllz@81-r z`(Jt;kt-{DW_k2HJ*r5ZxtdC-XyJ+DWN3i8Z|ZYGK+8csrO2yPVNlbX`EME+1y#<` z%rKwzqGn?ry>T@`oCf1^yMx$4oBt(D04rMQd*zjwk^=#sIzsvLK2lTwC?kT!(C$u% z@z@8IodvM1xhJh)-Gmf8DH6<27W@bb21~Epo_Ly@FkxOxd|KMaWVe#rnmy_2cE)*9 zBfcUvhGP@%KJetR)J}>he+U6oO&2q8{?r9c{I~A!4aFEgUx`-XH+<7YqMIK=`^T7l zVdeqv3k72IM(nC9D;BVm0R<$(84paDM)`-SnHlB#2Km4U0aSPsN>n85-{8!qH%eF2t^AZPBK+CH62=Afh2PJV%I<7GF_~aU`=On5mpY0`0@TUw%rMj< z_K`B9dJ+J3Ay73w+UIyn2U)MzYv+L>{lH_wYO>__H6T+s+o|F$Jln8ozWA3hrZ9l% zh|Uw*QW)&ba5(|YHLNRc2C<6)o=J(0zTrENyIXYlp%s>v3W|utxUnTE*G8$w7Irr1 z+tpkY8lfoA!@lpGS30dSoM+l6Bvc!$+u3#?M;?4jMUP&$!bT5KRtRLqnXy{Y{gVcW#?ZgS2&sj_>Ht#P`yGQV~Ovt zZ8Dv55Qcbk09zoNQ5%bGCWi}RQNbSoR}$DVEiH1~fJ(&>3!p$Y$9$@t*tyE1VUkHm zNGLp}R$$(Wqssw-fY5Ydtz;TY_DNNCwAWu->?yT$VLDhEfkzg#d?F(w^C*4BX{Htr z%tFOOi}jAPA+Rna9HKL&4C?A&PhvS%HUIptu%C<)`Ve$5*uX%~fnijmfboJv zHK9xmI}oi(KLYMzgrLgJ#f0nwps*EWWH5kH(a_SusM2?c{o8HMrx;2fm$=UeQ);@` z)-A<6O(Z9>FPcf=<;$8L%f&(eL(v>}Hk0;n{Bc^>4@O_I)!yY>cE=Ajh-s-C8<*aD z0tT^xjo^BaSBV{uX?YRE1Cp+*b0eAy>=UxAv8E&ARIT4l#X5|c=@sVG96-1$0{(^M ziEvo8Ra6K*SyT;Z+6W~5|3LgIeXf$~tNJ0^`mQ|9qGCr7umV#R2x@i;O3Gyf`cYAl z(a<0T5*wGCj8xP#o+T!dX!+<5K-poDk#YzOXgxsTeKdHFhy~5TN?v&L89QaR@J7K; z1D2o{GwPykZxZny^Dxkz2ib5(!d>+><=!{eNkINWUmg8i1{l{6%)&N=V7_qT+a4s* z@QC`e69I@>+50qc4?LY1j?Ab}3kEUaY6ab({RM4rLidy?Q$d>K>^D#@gl=ruMmqLb z@WTr%E-BH_*AIgp1p;uS>muyiqeqdQ!3tb8cdB{lAkc@9QB*te{Q^KmfH!RK+%9w1 z%&*H{D4bUek5XsZk`B}j44ym@_ey=cR3Ldg9m=)oW1y{5Ch3tg`JYtmh} z5Z5cv@dAAMpTXxx;5~ZuYB$V%yxCn)NGMiC&K(`7X%Mf0)IFa*m-3fe8yYNjnm=(D z2V1C)vu>+pb3U*JM)m>1FGBiGM6GTmPkkT6!2EVP0))#F)^Ni&kP5I@`Rd3K15VDy$CLe^%u2Kfk% z|N0`H&@N@fC+o1Wun8NW&fg=UAT1MIjn91-o=cQE5me)?i5ZR8vypXGiOY{`9Xf&*dJl ziHoiRR*o>BNQT#dw8YH!W)Ej17Xdlw3p;=)W*=Vwa7O`HFjeb1WIe#gXS65GCLi&g zIROmZHNEOub%o7zN*G&DJhZ6@k7*gTXN$f^aohQSFSKV_JV0iH zII}#|Eo!Fe@V&vqUYs2AUv*(Kt0=zevzo#pkX#t#a7BxUalq3>kHiC~%;~%ozN_mJ z7`LiON=Yd+Hp~=iVW*@OmSD1%5)$lhF5BaW7799D`vI;KI7x`KB623<%i0Ru{=G1x z@!Nc*$%)D;F?4lu;sJ=?A7VI+tg_00dWGpgVB=&%|5Zzx>}ULI_n-WzZEu?SVF|hw z<-CzYuCEFsqoE^JE<6~ws!nl#d0qF{_+srShep_~$Rt!0%)s^QM#(clZx%GupHH{6 zHsJxO^A~b4itJ|>d+mrzAV<*)hFhc#sl&Jq4u9H5BPc|RmDb)0*TxpsYDIc*_t7Nm zq#`_khqbk}Xbs0B|F%v=o)2um^uS&R0;|0^pXyfTa#hZ|;oD^415k^a&$$fQp%r$@HJFE-;_0w-pf&vUAo*UmlzxqN(6~k?`pI} z6mYg01Lff$r+K~C8VX{GRFN0x;Z%3B1?w;q4*Jr{@<`d_&F7okn#`Cn!hL!(+uE+f zXEj1^(Pt%41#Hxy|KG7&H5UaBi~<-l=3)HW2SjNZ&<)t96NID~A`4YiR0dt5VW)+M zto%3eZe!-TP@kuo;@cd{e;3>g27{lzW6t-k70TL$6p$vGD$4n&v)G{}jXi(K%UPVy z(g=?Puog(_m3{{iieTRb5+(|y4N1SN5HF=nDA6)x%OF#|YZDh?BW-Uq6ETSK0T5r^ zEXdG3I%-3BN|4Cc?p}anHKo-D78Jtw8+7-aQbT$bpy3cPi91w1#g@!tyc6G#Ah4+q zUsHkXuEV+gDg>ygBpt)?^zS_XSyi5KV`cMzvIZ!LVCZnPt_3vRcrs)gQx_6c;9gOwbZt(anU1lvVJ(;E9(s#quw;Ku=7o2{oig zGax{rXWm5qu{+`n(MDzneo^@9cre72{FG!7Wp3kM!Q&c#4dB3p| zyhUj*`vOr3AOo^J!3X&kkYnghu%eq!lo~*i_fFi^e?F)YJ-!cH9j9P?>VVl9oQBwM z&ll-`lzPIms*<{GJ$(fNtAka?_e-;OkJ;7|3fOhk4OPZy1jdtGm)^o-c==8LobElP z_*henU)XpJ7vJxvvSgNAO3VY}BQy(O?I}NA?uNmRfV}G10Z4Tk00;NH&0qPMFVy~7JuV$FG$CrE=$;+eS^RZc%lFU zL{-q#*4t}n#2VnV1Fi>Q@R}71U&~m#-{1b07=m>=dT_3aZGm1k$~i#tP&p9o)>D3t z>~eebwE=SjJ!iDZzx*v((%4~ki5c#EQ+|&bmdJ_k^OF3_fAwS_vz$KPQ~ zy^avHQ`cW%LU*3zigD(K(Jrcf!AoV^`JVH_Cs2?9Y~YNz`2MdkTh#Cr_CKMcj zs+ojkl+mWK97dQ~^V&WT{0VN6PE1U!z@kw%b;Jd7NAN@sE#_or3u;a`lg+Fa-l@_T z1vaa-ovBHBgJa_qE{N%(?^>h z0p$3f(>#6v^K($&B}Qwe9RGtdlbq1IFuaBs`CBJkVJzMU%kVSrH}F?#*ez%XWU^1A zh(PcGll8zk_~xHXz*{2gbtgV;T2@I7FL)0?@(rHh>kw;TE9@byfQ-IH1?jAmbZ!8U zK$n1cbckmoM)86Cp)AWTM05CBYzJT|RiG;bv+H&`nLyInN;t1z+lPKDq{ukTP=n4; z)s(l=Bl|yD?!8(F2G21>oh#u7DVcp{5n+E*nv2=j0$v zGYXbZj7s?UkQo#l9UwI+?x~FiI`#lk{$fl?SaGE(<%ZKEdzYUh?LN{Gd6on0(>dka z(Dx7w@ML$s#G|<&!`HARVr#iO^u_kXos?r7y2udtACG6jtuSG<1{U6$sBLq9kfK!B z!~ME>^tsJLg4XWAJt~e>f<0U|d|E!qF04nJJ4}g+1=_4KQYfK1)*9it>F}P9g5ne9 zq7DWIwC=yA{M-MYt8{+=Di$$;Xg(W9GT=2hIyEZ&OnlkOx+H$;=}9 z5ZKM_96tbwJ)G~;_3c~qm{(v9AdQ(IhJ==BBXI)LGfZGyCTU`3snQBT?bf?@D_VAp ztEnVMFiG%Hf_^<%Q^^91J>&Ahq@fs}@6u~LrkBofrF1*CP|S0IxA%55*j;W6$RE&W zg$>b|!Nbddc?CIRV97tYe2@Z9^UzCBgds{T{JngR6hs69Feu`>K>}Mb&_4*%VFArQ zcboC&`no-bs0=WuF#RdOBNMhBnB=;GASF^C)l+-?7zf1Dpa(!~(ODi@*N{2Y zM6Kv9tQO-#AcVw zA$RxY|8!IhnBsA<^53#Tm;M$4HQX@a$wbWpvh2U*n?&G0XuF@Eh|#CnW^g z+6TC}wcd%{37nG_NmG+q6i0)HvIi#kO6{*`h$nUmx)f8@(I-Y48Q!s+zO1`9yDM5Q zerFy05+A)Ufoxt$^H>;G8rczf`IC^H>}{t5zsbr!D=;OjQMH3X!T2&vYee1ubmv0JFPP*W{k3oSyGVZaYFm)o zho2H0OxlmF-NR>iw*2?z68)Llk}dQY^~_uYir(G=QA)JLUy-6u0kAa!x|Z3{pucXR z3l)&Ztj(c1xZ=y=*X8Gk`x#IjVt|2do-IQ8rTcgK=3l{aJxET>hqL9}N2zNYt()k| z&Dxzt{=#I2Xk`%`4I(a~UD2sF%pBI81l1SY9g){*=d0Hg=H#?gK6hg6g-4HP1%BNn zzE^nKnX7po!i=jdBlogqj5SS`M=!H9o3_*c#Ig=hhsW#A*RSVO#?8S_nD=oBxS7o~ zFQ)r0pMG3e^U+}6?qa`j1E?5;GMa+?iQ#pxtK&(xfnw8U_d)ZfDj`s?TE3@EcnBUs z{K;~YyPGsHb@#whhq$=`W3zzU)GH^kxHzS1`|%E*bAoq2du*)1wOGY|vx?S_@1hr* znYi&p z=L5NiV_VbDzAC!!3O2R^=vjpJ8E`Im8cQ$ixPbdBOsCcQT)3yPrvYRHWp*YpVk4Zl zZ7MI`c&6-`43CIR;3Xmoe06Ar2m?UeV@N>e@#&w>8<}k?qZ*$g~&ue zS`g-LYt9^CxwIgM~rX_qC5U2w*MM&DwO$z*Q z{ipd>1$PWSHa1U-|SJcw0%yWyGC#VXKmL#8}LvdgJ8V zI=y@JD>&};5Gq(l8AX?%KPEqR8%+$0xod(kr&O>Yvc=y&FeK}rU%z?NiGraQ$B^mG z-f!(s)mZ`JwEJIftx~DUwJ5IN90oMxXh%S;IQ#|eGRH-~DYJTM2 zl^Tq!N!8X3ju^eo^OO>ykW9>K^ZopT>HK=+k$4O0~eM4*2T(}`}$QQ(Ul#t4+Ae{&#F zeE+k)BqziIM|KmTcRR%49o-9nJ+eCGY{RB(zp3#&Y}%G#JDB%)?3+WGcJtO#PeSu3 zA~*_0iD7SU{@>1?Lb;$VZwh#-AEB`TWfzPQHKC=y^I@iv)Ck_wAvE87Wg3o-`I^U5 zo+v37L#C~OeuReaMeN3-SATRSs938)kK`cI|A_Ivy2yvPrepU^Uu@m(oZy>}5VG#t!FMniKNt*^@e z-njEv%CnTbiaA`zQOG)<8GZ3WeA;_Xz1eKkuH!j^N-Iv7(omEy6>REcb(B7D8$R~g zhti-x_O7{K&->06F-P&Z?1Pedc$M`7ZYu73W^m9u!r52mko@Yj9tajj^d=eQvt4-) zyJw+uB^Ng&8A zVexTT7#)do)8xNrL?jS=T&FQ}0He$JqGJjXQhn?B$HVpiPSbN{C9~#fJiRN}2+gm~ zH}$38C8{jG=KDW?&i}R|F4M(b+3_7#LcY?yJUju!t#}uOhaM}O6d~>|`>~FRj9!24 zIy#mkg%@$xHl4+-ig#NFcyR!9*@sbVeCo^|#TrD*nf@|G91Io$Ce>ciAiv74amCBJ z@)g;(a^jK8d7>fua2Kitln494wG*N>Ei*H4e3En=ef?5Lju>A_kUD%=ucpR7jcTO1 z;N0D~(0{5`)hii&voCX%?FzE|s!cKRy>YSJBV7-8Q39w)*>uy2*P@I%R{u%aTQ1L! zEkTd0@~FABRm;}!k%{PI#sF^wScY)Q^^dQ5I6IRVPXfkPf1=?$7V8r78)fS!R%jSz zZ1-|?JxH(^u>NtvN%pivEKS1vk$LIk>#JjGigspG#oxh0G7vHWgqi86%pZ(EIAWAx_ice86U!Nxa!M}?hI3)CB&MBHJLRmq zrJ3$E^p;&>9`sxN4|e%}Q?BP;i@6^>lI4AmU`)4fX$~(hIAA2QiA-}4dJ!w{S$|c$ zAuW@OzkcZ%y~bY+!z2bw>_mlMgV3xceXw_#n(4Grw$$6W{koe>Zz zsKaTBbz&zSg_j*B09c9(Y;ySbcexjQPtJsug~eX-t;MtY8yYraJ~(2KZ+KF6;5-+4 zBXUv@n~rqBmA5t}h!oWSk@MhQ#tc0ddTe|M!D2RPM;2lNF)HqA^H0*|zhxqNTX7%d z|IDWj&R4HK+~9Pz#&=-DZHn;_c_-t}{jmRK85cdcbEl0}zLQpPKg}yU(@+opYqQmV zR92TDUYbMM9m#xXrl1t)(e4h9A&I^vGgM!${XNBfK8U{Z#BbKWL^X4e0(vxrOo7XV zT79=fd8F-&G_%tqU!7!tX%Y=gk|tWAb8EExnFlK%@>umykmlRg6ai{^=$BM|gA8}h z`VYm2Hy(dXE0-kD3IrU19rExu!#tSkBZ`i&CE@TWK22KH6$H!| z2s=o@=15jOViIf;ilq-7f`sBUuX(?`(rT=ltO55^2bFB8&7ZVO9_n|w7Vsb zVZ4L2fox}p{&BM?*B8kL@Is{bsdQnBhiaSjD}u`6Q9ik!f#mze%DUP-dp--Q!~(ix zIIs-vIXStzHz1@d6fie?=C#YhP?8~dm_Uu#J+$}mVP;5fAo#|=MC{+O z%Nw`iX$C-eCph>uur#dXxeux`u3?c--5(EXlf*Gubx>w;$oMa%xTOIKf zPl3J>U)`qLb*XO2;EQ$v3;&RkC3*uzxXTsoZJC{Jc=ZrI)q!!h%0YSLXL6^NmUfQx z=o%WTApFoDEuiF4t}4WzAVW)T!p{62U)B4hqs*uxN-)<#?WwG*2;(NCYa~J$QV9eZ zQUgM}^stlxg!64ARFK3sk&~|zJ?EPa;5=h05t)~@I1lB2S&goV3DGL00u3OCYbd82 zez^b6PIc%4X7U7{NQPwHPdic2kYwC0upvvEKSXp|8}B?($)f42Xc#<8f%nl9^b{$p zfas_}e6N_ae_Pan5O(c^VUx<(Gywe*dJlp|-Y`i~)R_iM_l( zzN0uV!Hr1ZVaR#%tZkNkeF(3eF@}1E_+Uw{9}Mo$!Kb*rMEgefN2I{n1>9D;Qip~E;QE?7#rw@9&+n2+V}Z2B*)X^{MZYsV9%iW6gGqN`AMOHc{c-Q zJ++$&dq>)qlA6biGp|%We@+K2o`I=4W@S7mwm*L%?exVhWGnX$!V$0kNlZc_9IfDS zl_oLmlbFYgteY5KH#7vk^9||zmd>Zt`Sa(`dPKk$bUVAcy55D`?8vsb*N~L@8&-Kr z{KV_I3qPvEjQtN7SvARm+#>;WdPeCe%HFfM06Nfy6$x! z08eLkxT7RfJv;nnh~@?nasm0vDJj^=aU`RB4PHNye||Vk87_6_?`7DvtLbwcUpmt+ z_!sU$L10**Y<8OKH|o*If;l^$&iyD$oALeY;||)Am=qFngQjQh_wVv1DGg+%6Z87o z0G48tJs-e?b$(q_+s^=OiW}Y$!ZHA@SukjykO}l5o3aS|96#D9dL#+EA8;xVH$HHv z2hi%3{nuZzg9~v^j-OR(?kGVXg);SSF+4W*4sc$F>LBO@P%O8=r%l#<;*&@{NgsHu zMt7@eVi}bdll&W^Eru8im@%o$*cHbwBBFHiRL zL4lEp$#_i`gc<{)aNIetsB0gTQ>wG(MnHhbArZA`RGAMfHkNSK zC}L9XcaK~~aTf|Fh6YO#l7Pyn*pR` zyw&XVpAZq?KzRk#<{4jCpuX=p8t4>JHtNT~z_2w{+pf#j^V@sYvP%dydfxsfx3KU4 z_?eR^Z10AuQMMAu7G`YY&HWRLaEp4NYIpIxMMUJ?eE%J9AdlbL;<>WgVh-GAhfnZ6 zMY$byTet{G_6VfUDAc!Vr&NJZkPH{nkSgMxnz(6)5uB|@9NF+?|KY^H166?~f!;oy zDb@u4!!$hVlKu8t3*{PgZfNH-OEF5}z% zZS72=OnYwYES@=s@2yQu63x!8E-rU)?%5l<_uDX#*v)S12#_T4Nr`1fh;7naT=#fs zXWOv?hc18kN6_bYFx5RGvsVqD4ol{|tUSq5??o z0pb4cpeTM$!!};~QeWGMFL2us=|e&E?S2s#bvpM|UpF)UO(&}Gy>6NOTc7sz zHqjsZ{cj^rn*TmJ27hLKsw;QiwpXPHcy;Dm4c1A{u^0`$JP>NkYHar4^!>jn&Sy^P z>76>Hr@ui-gmIotfPQ$>9Ueh$|5r|t!)t4Mz5P~?l>AASyV3A#xr!^+_vMqdnoDw1 zMqcoBSj9@?hAKa^pZ=ikJ0)fudPGoAtz0X9grPbz7M_1zjDsdkl)B6Y$vv;yaMh>_{lx;J}gKLC+2ipY$rHI;vb3gxyWbP zg=moM`igmhGZRyHyN?-wP_h&eSPk-DPC=MVr0h892@3|;wyJA-;!pt!UP@^xV}Wtm z$P#~!!+<4(WLtayQHR(sWW?eTB1}b^Pdo9|BR88ob||SNuF4bK6XD1V9~2zHQEU?w z>V>fE=hxS3YPXyrr!EGXhc}blaP z1$Cj#56t`bI3yVtNcX+K)`rL~tI)f5CGyVg;^fpsY*oB>XZ~*}7ub9}!3SCc*|$be zdPER)<-Bgtl1q4UvZlhRQ=4zkchbdva78!G zi?bP6f4I#SQ&<{|Eih zThtxds23=XAIe4k%f8QgNlg!J)#G-WGK0J^Z)t@yY?Cmx7%3Z{5$iV;JGZ^}m`YJg zuS#lFRU#PBNPMkCep8Ev&-oG?jer_D^cfP9-he=aRL`8zKlawx$f${ZVGrV7_TCD^ zXe(rCDA0DC`kP~D%QDT@try?92J1xccD(fh6g|Pt?wBuH@$n5wN*qa?I~> z?|sE}7#b<9SXZ3&o@^?&U}obuq!=21nHqZRYqQIk_Svh?%}h--%Ri}8rddQy+rOF- zJ?*Qutnya%;KPv)`yXeI7aXg>Vw{MmC`F)K*ZwXQWmr@o#SdJ#HBeA%*jy6_^VKr< z{h9r8CF&s$5Qc}N&2R2#Z%5#zL4k2Npka1D7;UuLQx`CHFj|byEqY=*O;g1q$LnQu zY#rKqjb3<%6MgYleasKhwIUW6{)DTK$nCfoorBA$r_&Ub$H{Eok2^=t7P6>-|LczoVa5=H?yYH`a#mWG7W6NK@irc)oXZGXc&?b`|(qF$CJPln&IDaj~ zbDInMh)D~h4K{8Z%z9H_|5lK;cuOokZK18p)c~l+wb$i=#x6e@X+sM4d z)SfAz;Oa8lZ=ls=a(ju>V9q8@Sy3_8_xi8-d6|<2dPB}lpEtMpkFJD`xQHK~P!wPe z>>Ujo=?))V{U_vH@p5HSsDyI_Ixeb*#?+6FV0MrQdEeT4fIvw5|Cg-LPO<0FaRbl` zFJg+s4jeeJ;Y3vaIFvt1$6q{n@SylXXlp?QwjT~&TwXX<|6G3Q^F1G*ORlWOINaz> z!~_KHo;$DtzTalx3yw^6kJ+L{-6dU61OEQ|X^t*+xJJK*CQ4CENV>})`22T(_Dt@3 zpBB0k?Gtue4C8)~DFzjT5I(P7z2ckL5O??r=OMQH(~EF|$mYBN0FXDn`WH=0I_@%Q zJYkrid|NoAc~k9DR(e)eqh*g1x~Hnvzr`1uNd$BH#qN%eA2)w5x_CjOg6r0a=u^8& z3b0o=@~Rgy;@dC1Jr{TSa#=F;3mYja-6s4|eUSy#uH86|!HTI=0AF~6u2$wFoVo-8 zZ?1Vcy|4t!K;#tC`yxj4l&>A$HI^1DS8=FnYp;2Dc#w20B7Puz zCfYv^Hm4&|$q1ERN@ABr_U7;X!Xj&6wi_U&8a3rB>EB_<`w zek?NCfbVrmFo+yLuD3wii(?VbNzQ_RFU7{>&VDH z&-c^$$`p!uT@erkxInpvCP4+RbR5)-cY}lX;d}AH=~>m27$FDf(8_5^V0{^iqB9-8 zdvj*#n(UeNBsDU1lb)r$QgArm0!}{HES^{deA0 zRJ^EuAGW@gK@5+EONtZ5j|ZH$1kz9Qa?8T}1nsucgq!2#gGbNC|EszW^LtqD@aSlr zP@Eu@+wgu0Ys__3$Lvttb!yHhX}TGWoPgnzrJi`sWcZlRe{$9x>Q`doQbxB{he6G;=QI=$o+j2>gDMnUNu0 zu5|8V#wSUKTf;*`+>=$yUdx@n^p+3q$bG}DPSQJSb8QIx)4mt=43-2#4FF(>< z`KVd4bAdUl$aJISN1Uy!~s6O z#t|Q<)Zd_p?)^~Jok4S+Cg7!;qvdm`93d0)m#<*{O&ptWpF!%4D#Z2apQ95Qz2)0^ zq~%%}nd4~7FE=6eKxnm(6+GnlYEw@$V}yI=>b;L09U*G1YOHY`(M#hO-;c|C7kP2Q zf?MC-9{!77Du(JwyPXPhP}&`kY5dYJ#;Z{C?P$Fr1#r8t(kg-S8&NYx@iQ1>*h_;E z!upW_J%_hj-7@RCO_M4tBL8hO2ZHjdKAQXdRBC^-I5&LC2OuXw#E|ma5;qIGF^;`n z{)?qZJsJO8aWFu~8D5R1o@{^$iQjL2kR-$@_u~E8rQS0%oJ=>l5jP(IX~GDiUK>a{ zu8GO}*w!cSt%7Ylply4fESGRq{_JuV6c_{{g&aK;T*i?3`U*25hMl3IL&>FQyH90Y zz=W(qsF%MEPzB-|vc(=ym@UegKDS*{Qxh29g){IzHj*`SweHYY+yrz3h;$<+xfrhk zWvMvMGREu0EI~nx=K?Y>YK*N&Mo*d^whrx&r78}4u-&{}U%L0-`8&d4=Yc{Koc2N1 zmg?oz)g3EM6LB_CFJpdqOm$@5%U^x{=Fko5n}=#vg_vMDs2>;@*jE${roegsv9aup zG11Wy%3P2qj0m6Fd~jxZn)>5-JZDs>A$9VxYp<_$@7c3Qu_Cq9SmYXe}b zKVRJ+oW}&41li*Yl)arAIf#wHXsc zbDY*r{>H{e7v&4ON99pI6Z=CkZAGmWS?00j>I>3(2Yz7M@8i{}82a^rR0~o$1YiZR*#{|oE5HLfNy9xgkrqP zPL?6pagFBm>C+`@SBr#3+$K9!`QI8f+h!M}r>85a3-tH(!G~|6BX;e=1#Zkc2Lue= zft59MG+qant*p+@yuEyG7?2L400XP5zC4uH|}B3x`4nS1XQe9Iyp1C8{a#=e{|eD z;@f7^1RH2+2%3h$g~!3v;|99Ho!HDv2;;UKy#u9}2iV9S>};KMwj?|9D|PF5@*)R; zRa>Uo-Hw_?uj*R&y=D1E$g;To%TaBpMxr)GX>13rE~S#-koxiC zvW#jq^}?>FnemN4b;qAv+r`4+;@wF>j_!7Iqy`+}1}GFRb`kvoP}T!p*Kh*Tnb0c$ ztvlj2&h6k0LWXIUhWI}_U0_Y4y6Gc9mivPF=G`&ysjtrhYc83Nn(O5TIiBPM`P}!; z-Vq$ct@KSmAWVTaze~}zyL73U?g4W;l`3;LFhOOAG*6jKqNR=qT}0se2&rdG)&Ias z(!6sdttLvfnAZThI)o{`pZnCULSCm8wJRN7bW9`>s*xK3} z<*~C?`MJ543zZGqh1+Yd%4xK#XrvRRCM@4yKeP2*U99P$E|XX`=Nx^(4&X_un=kZzs)9_OXE+z&bOZ|x z-ppP38??Mik=g@OLB^$e+RJxa|_9a!|Y14w*DK&*4i2@5fmg9cMK+5dr?IPKi$Px}tE<{Kk93dyRo`i8Jzo0

ze5Uqy;>F6N7uvFHe z;9{p^__)~&25K6w{%NyZ!^9)*@7mb?pgiO?O-Fc8v!5m<5veBX)Fbqd9zou?okIUO zAqA)Rsvew65OWUZeE6=V<>JEJ*uwASAAuF~&;IK#Jqd1^r6?QtA12t{nE9=qk5PUe zozYQWeB9yfZ@I|Z=}?wG_$X@diq&#IdqT5F<{!;FW4xCdq@&f8h@jk#cO0nksePxd zt@qzWLM?urLjv(Uo20LJ^%Y;-b4_2s#8i6Y4F_OPY2G$b{7mL?!g?1TUsF$I{x&wY zO>jUXPO@R2oP&p!8jKL=P77D zzR{F*ea1mjZxbMI*5 zb-Gl0j}jZDgzt)*QFM^|5srV0h1aD7&IPcj2v9b12EPl`Klec2cekGS0e+TUyVA#t zfZw+Hh+8V#01zz#GfxQixn<#(<65jyJN3;bSFzA$C z>Y;TgV+L@A9CrC z!#;ebXKE2y+X2eywV-y$z9Z-ztiTT86Ejz@p-)uEwCu7{mL ze^!UyF}sT53P;XmoO`?l$ANP1~-o9N)1aiCMM za;eC)UY244K*9R*tl(~vK;V{yv26%zY-{mzk?@nRU#+2pO9&Z9z*~{G5D9F>ZpfA} zAt~O3qtFqg{|d}7To#A;y5xyD>=M?YLA`Ra9z_;<7fRe9!@|C+( ze}I|lgCsggMf3~$g1bkL1)A{sKup#Eev$Pf2!875mcX#6sQnW@kowfdl>_Juc-E3J z74U$##f{6<3@VFFP)^DJMucA$J{Le2rN+Kq;%_Rk%C)|<1wnJoQ`-$|d}NPY{Xvc9 z4CJi^S;LIPa-_giUY(^aGycyl+ZRz;56nt%JVT=Wp-qey>nUK0Z7aU0j&_X`6|D}v zKeZRiSp2y!2`(p9?uL@(%|wJ$m|AqGxAa6gWt4+B2*5U|Dlv-(N%(>ltNO9ABITUT zRY=ixh*iCMVS;7=b_~|$<33B;o$`3^>VICkrdv9-QCRxUp2_4r9=AX1>Rt~lb>@Hn*G{-+OTr-FH)*qAjz?5d znV=Wu)>gzU)=uxvPumk_i8O3crU@$>QLsa?o`44QM>T`Gfjg==0`8XO>;i! zuflY5?av>mN)vp|py?=f;EBgx$&@`7zOr7s#M8woR^yyec6{<9A|hmZM1c>4k7hN$ zURhb07mbXGY4lzPpmb(_;acvEU0b$nQSDTc?F*gORQHvAu9xQ9si5Nvfc|}=>@MJ} zHZK&R8hVPLdt@NL$``K4`s!de&2T}tR4;099kDHh8Bh1KIx>1g0S&S2N8(@lPzsAF zCq7zGqlfbxQRq`IO39K!-Bu<{uO)u?mj-q35mwzp3KS_ApF+M6&+K9|%ym{6853<4 zwrP)*XFuP_MZykoWu3CFW5uVk=`n2V8*;ydRYltcr35JfMUuu!Vg_MeRq~TeE*?b9 zLq}(fR0KQ+;>g%^n;jh3e-0BoJL<|CM1=9)rDLr#m-sJnCsaETG3Qp&&mxwC2&Yi9 zU|QNfE9oY|z1^pkI^i`LQkCOpaGVnbMdV3+uzDn)mh3SH@~>lTyd56_JYNdZ*~WW| z(r>DN&OIvxB9O!iETKlseQnwm^vDHxMX;HeM_9AJ)SpfF_ay!1qXHXJ#npwXKmdO|i_*BsLMJ!)fMP&w502tEdFVq( zau(A|F0_cYo5ZHRs2)|KmRij_b=$bWM)9Kn!Deh?`<_NAB<(rG_wan~w*W)GO8u=r zZv~#nxf{3LxM<`3#&0Fw_jTPIp{Syxr>_<7jG`@zxNx0c!~U8O- z?WSCs0MrZ`8ZEzkZeE-he)iI<|M_R`tjtn*D1|OYMdr8L$q2kflf_rjh!N)CWL+{A z8C%wzk~ja3#<%df-{u!XPZHgnaxg|(PnSG>sy#1FwUg5^YD;0ylqw`3*MyeeE-so^ zxCH8Kd$R|~U9GMirvKt6cTF6>)Fc(H;~ws+HZ#8v6Iv_xw)H32M;c+vzJ;o+?u_Sb^&Mk4=Two1C*0TGIO3Am<)HfRRt&$cqu}NQ1&9#% zH$F#&Yjkl_GeARNyAH_z+=3AvsCuT?Qh^|-ouc}*%|lZ5zWR59f=;klP#}|igAxmF z(3@uOhsI9j&!6``tqBbc&2R_dx@q^0J`K&iCKW@YI-tJ7880S;ZM^ys=oYJ0Fupcd4uZsk zQar+S+QmWi-C|4e+Q^3wABr6en3$O((FQqrzHzK6HY+>;P0(i>cV&To4^y$Zc&`5LFKw$B=J$gf`TX2DAR{Y_jcx5J`ZiS!4PL;c z`*E~jNYd5Uuis{4U|`@9^cLuMJNvv}M8i4k!*HqrO_u0$bagef$#(L3QqN-U&^$v2w;9xT z03Z}}B|+F0D|xE{&T$F%N&QCoWbYrcPy?_5Q$Y4mkwvBEVbRG~i;;|d=E?|d>eHh>@8oyCuDMHE?+CLf0Yn^=GZ5R^1Tfj%-2GNRUH>vAF5>%$uIQ=jj^#YoIo5z>w+9FoJ?ky zizG-Y+tTWn^#|Ag{d$ymjh2=cd*io~)pXd<4S!lKRHg`+JG8PlACCe?9!`0mJE#C; z4>ys&y?u*}^y0nSl(r#moItd|{cIV1pO%!=VN&s|_(@J_;7Xp6$q>l|VY(#db;6nJ zNY!DUPS;3~j)*=0(vLNI5G?XNJPB0Sf^u_n=b$ICMAt~|C%@T4f%%3Rh2Q$er}Es~ z`*uTgg0}7A!}XDXFnNztt`&rM+$=g#+mYo_xQBy7Nlg7N!I$Z6ZNJ<8sK}T+)!|!$ z+8pgBiXpSUw)Q4IECY_-k;zFlVD@(d0s`7o{Z2_suLjIK{?7jUd}YOp7p^Q~K+hEm zdm=H)yP$J$0e+3Lt%N=2TFA>&LH3BHhlp0SnHJn^YS2DxG8M;`i=i?0zxFs=kHF#*qObXIx|PvXD^oWd%6k`ty{Mi%m!x?bFU$Q# zK3uoJ!S7ssK`UCrD|TBCt71VJMuHDV#e{^K^Q{A;q8L%1xTU0a18fTE{DJW76bxW2 z$2^~A++vbOkj#4_Lo3ng>FKs7rbl}}eM(0UMkc{Aq0-`FvIri0tp)jYY#Rf;D}0`iM5N)copp}`#^YQx=xg_Z1)>4oLK&w=mz#J1!a&ch!8_AxKi0uJw8|%IQ{E)h1 zKTzTN#yXSff0zpH)V84<7w+B1y6q07P2VUe5P=3K@cR1dm&WZ%Zj`TbD#QMrbGjZo z#YgYLZW!PEpD3!=ZZS=YU6rq6K-EoRtQ~;JCp|g z3~ph2PI{HZ);~4Q_%Wi@atzPo7AtO)!2$L{c8J3DGuL=%{U
}k3= zchKe{*dosZxiL!6HkCo5nf>I8vUl?L(3a?|sQKR;J@v$wE(`0_K|o2veWSZ7UZc49 zq#AGP#|biU8W`|NI`dqxSu0CZx_h#|B`sDYX;*c{O zp*lHftR1#AZX1;kD~QaMZg4kUGne0}pi!9n(yVi_UFxNK>sQygofPX^hN4$?rn;SK zv3hO_r!pPFo?j~3Ym6N~h&`G_MFP`Z+dhF=jOY;U7b$tSGolTc{R@}UQOeJShZ#3h z1W$66o?cWgXKk?yQV6roHsa6A&o6!HG`xY-QY2qt3BrIiE8p?s$FcNs4}Ns`;E!Ws zdHkGz)x1F?0`&s!MUpc}W0^9gvoVG1#+eg7lRgLI+d~>9IuB2p8-DZr)6Qe^!sC9) z)AV$nf4`r-tbO+`Si%>c$SSWb*Olr9GS!(ECcBzbB2O$<0f7blOL1&W=y2V zWywS7tTa1aO}K<8{`S1x$5@uT>BQa}w-?u$yVlLkj<4yg%{ox*%+JrCr_86M>-O=E zr>>!*6Q0|1$UF((dKY!1;D n&mH=y+T)m=fQwYS&Q5V_`)P;cl(uCQ_(xSqQ}Kzy1^@p8wcQ9> literal 0 HcmV?d00001 diff --git a/example_mods/testing123/_polymod_meta.json b/example_mods/testing123/_polymod_meta.json new file mode 100644 index 000000000..e74efc4f3 --- /dev/null +++ b/example_mods/testing123/_polymod_meta.json @@ -0,0 +1,8 @@ +{ + "title": "Testing123", + "description": "Newgrounds? More like OLDGROUNDS lol.", + "author": "MasterEric", + "api_version": "0.1.0", + "mod_version": "1.0.0", + "license": "Apache-2.0" +} diff --git a/source/Main.hx b/source/Main.hx index 7b4429484..0c219844c 100644 --- a/source/Main.hx +++ b/source/Main.hx @@ -1,5 +1,6 @@ package; +import modding.PolymodHandler; import flixel.FlxGame; import flixel.FlxState; import flixel.util.FlxColor; @@ -41,30 +42,14 @@ class Main extends Sprite { super(); - #if polymod - polymod.Polymod.init({ - modRoot: "mods", - dirs: ['testing123'], - frameworkParams: { - assetLibraryPaths: [ - "songs" => "songs", "shared" => "shared", "tutorial" => "tutorial", "week1" => "week1", "week2" => "week2", "week3" => "week3", - "week4" => "week4", "week5" => "week5", "week6" => "week6", "week7" => "week7", "week8" => "week8" - ] - }, - framework: OPENFL, - errorCallback: function(error:polymod.Polymod.PolymodError) - { - trace("POLYMOD ERROR! code = " - + error.code - + " severity = " - + error.severity - + " origin = " - + error.origin - + " message = " - + error.message); - } - }); - #end + // TODO: Ideally this should change to utilize a user interface. + // 1. Call PolymodHandler.getAllMods(). This gives you an array of ModMetadata items, + // each of which contains information about the mod including an icon. + // 2. Provide an interface to enable, disable, and reorder enabled mods. + // A design similar to that of Minecraft resource packs would be intuitive. + // 3. The interface should save (to the save file) and output an ordered array of mod IDs. + // 4. Replace the call to PolymodHandler.loadAllMods() with a call to PolymodHandler.loadModsById(ids:Array). + PolymodHandler.loadAllMods(); if (stage != null) { diff --git a/source/TitleState.hx b/source/TitleState.hx index 084f7e3c5..e5271ed6a 100644 --- a/source/TitleState.hx +++ b/source/TitleState.hx @@ -278,7 +278,7 @@ class TitleState extends MusicBeatState override function update(elapsed:Float) { - trace(FlxG.renderBlit); + // trace(FlxG.renderBlit); #if HAS_PITCH if (FlxG.keys.pressed.UP) diff --git a/source/modding/IHook.hx b/source/modding/IHook.hx new file mode 100644 index 000000000..a1a75d08d --- /dev/null +++ b/source/modding/IHook.hx @@ -0,0 +1,13 @@ +package modding; + +import polymod.hscript.HScriptable; + +/** + * Add this interface to a class to make it a scriptable object. + * Functions annotated with @:hscript will call the relevant script. + */ +@:hscript({ + // ALL of these values are added to ALL scripts in the child classes. + context: [FlxG, FlxSprite, Math, Paths, Std] +}) +interface IHook extends HScriptable {} diff --git a/source/modding/PolymodHandler.hx b/source/modding/PolymodHandler.hx new file mode 100644 index 000000000..3d3c9bace --- /dev/null +++ b/source/modding/PolymodHandler.hx @@ -0,0 +1,201 @@ +package modding; + +#if cpp +import polymod.Polymod; +import polymod.backends.OpenFLBackend; +import polymod.backends.PolymodAssets.PolymodAssetType; +import polymod.format.ParseRules.LinesParseFormat; +import polymod.format.ParseRules.TextFileFormat; +#end + +class PolymodHandler +{ + /** + * The API version that mods should comply with. + * Format this with Semantic Versioning; ... + * Bug fixes increment the patch version, new features increment the minor version. + * Changes that break old mods increment the major version. + */ + static final API_VERSION = "0.1.0"; + + /** + * Where relative to the executable that mods are located. + */ + static final MOD_FOLDER = "mods"; + + /** + * Loads the game with ALL mods enabled with Polymod. + */ + public static function loadAllMods() + { + #if cpp + trace("Initializing Polymod (using all mods)..."); + loadModsById(getAllModIds()); + #else + trace("Polymod not initialized; not supported on this platform."); + #end + } + + /** + * Loads the game without any mods enabled with Polymod. + */ + public static function loadNoMods() + { + // We still need to configure the debug print calls etc. + #if cpp + trace("Initializing Polymod (using no mods)..."); + loadModsById([]); + #else + trace("Polymod not initialized; not supported on this platform."); + #end + } + + public static function loadModsById(ids:Array) + { + #if cpp + if (ids.length == 0) + { + trace('You attempted to load zero mods.'); + } + else + { + trace('Attempting to load ${ids.length} mods...'); + } + var loadedModList = polymod.Polymod.init({ + // Root directory for all mods. + modRoot: MOD_FOLDER, + // The directories for one or more mods to load. + dirs: ids, + // Framework being used to load assets. + framework: OPENFL, + // The current version of our API. + apiVersion: API_VERSION, + // Call this function any time an error occurs. + errorCallback: onPolymodError, + // Enforce semantic version patterns for each mod. + // modVersions: null, + // A map telling Polymod what the asset type is for unfamiliar file extensions. + // extensionMap: [], + + frameworkParams: buildFrameworkParams(), + + // List of filenames to ignore in mods. Use the default list to ignore the metadata file, etc. + ignoredFiles: Polymod.getDefaultIgnoreList(), + + // Parsing rules for various data formats. + parseRules: buildParseRules(), + }); + + if (loadedModList == null) + { + trace('[POLYMOD] An error occurred! Failed when loading mods!'); + } + else + { + if (loadedModList.length == 0) + { + trace('[POLYMOD] Mod loading complete. We loaded no mods / ${ids.length} mods.'); + } + else + { + trace('[POLYMOD] Mod loading complete. We loaded ${loadedModList.length} / ${ids.length} mods.'); + } + } + + for (mod in loadedModList) + trace(' * ${mod.title} v${mod.modVersion} [${mod.id}]'); + + #if debug + var fileList = Polymod.listModFiles("IMAGE"); + trace('[POLYMOD] Installed mods have replaced ${fileList.length} images.'); + for (item in fileList) + trace(' * $item'); + + fileList = Polymod.listModFiles("TEXT"); + trace('[POLYMOD] Installed mods have replaced ${fileList.length} text files.'); + for (item in fileList) + trace(' * $item'); + + fileList = Polymod.listModFiles("MUSIC"); + trace('[POLYMOD] Installed mods have replaced ${fileList.length} music files.'); + for (item in fileList) + trace(' * $item'); + + fileList = Polymod.listModFiles("SOUND"); + trace('[POLYMOD] Installed mods have replaced ${fileList.length} sound files.'); + for (item in fileList) + trace(' * $item'); + #end + #else + trace("[POLYMOD] Mods are not supported on this platform."); + #end + } + + #if cpp + static function buildParseRules():polymod.format.ParseRules + { + var output = polymod.format.ParseRules.getDefault(); + // Ensure TXT files have merge support. + output.addType("txt", TextFileFormat.LINES); + // Ensure script files have merge support. + output.addType("hscript", TextFileFormat.PLAINTEXT); + + // You can specify the format of a specific file, with file extension. + // output.addFile("data/introText.txt", TextFileFormat.LINES) + return output; + } + + static inline function buildFrameworkParams():polymod.Polymod.FrameworkParams + { + return { + assetLibraryPaths: [ + "songs" => "./songs", "shared" => "./", "tutorial" => "./tutorial", "scripts" => "./scripts", "week1" => "./week1", "week2" => "./week2", + "week3" => "./week3", "week4" => "./week4", "week5" => "./week5", "week6" => "./week6", "week7" => "./week7", "week8" => "./week8", + ] + } + } + + static function onPolymodError(error:PolymodError):Void + { + // Perform an action based on the error code. + switch (error.code) + { + case MOD_LOAD_PREPARE: + trace('[POLYMOD] ${error.message}'); + case MOD_LOAD_DONE: + trace('[POLYMOD] ${error.message}'); + case MISSING_ICON: + trace('[POLYMOD] A mod is missing an icon. Please add one.'); + default: + // Log the message based on its severity. + switch (error.severity) + { + case NOTICE: + trace('[POLYMOD] ${error.message}'); + case WARNING: + trace('[POLYMOD] ${error.message}'); + case ERROR: + trace('[POLYMOD] ${error.message}'); + } + } + } + #end + + public static function getAllMods():Array + { + #if cpp + trace('Scanning the mods folder...'); + var modMetadata = Polymod.scan(MOD_FOLDER); + trace('Found ${modMetadata.length} mods when scanning.'); + return modMetadata; + #else + return []; + #end + } + + public static function getAllModIds():Array + { + var modIds = [for (i in getAllMods()) i.id]; + return modIds; + } +}