From 64d2b9e02b612c36d96096b9acf71d6dfdf25c8d Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Sat, 24 Jun 2023 19:09:46 +0200 Subject: [PATCH] lego: implement SetControlMax and related partials (MxVideoManager, MxPalette, MxUnknown100dc6b0) (#42) * lego: implement LegoNavController::SetControlMax and related * use MxResult * fix name --- LEGO1/legonavcontroller.cpp | 24 ++++++------- LEGO1/legonavcontroller.h | 2 +- LEGO1/legovideomanager.h | 29 ++------------- LEGO1/mxpalette.cpp | 8 +++++ LEGO1/mxpalette.h | 14 +++++++- LEGO1/mxunknown100dc6b0.cpp | 15 ++++++++ LEGO1/mxunknown100dc6b0.h | 23 ++++++++++++ LEGO1/mxvideomanager.cpp | 36 +++++++++++++++++++ LEGO1/mxvideomanager.h | 19 +++++++++- LEGO1/mxvideoparam.h | 6 ++++ LEGO1/mxvideoparamflags.h | 17 +++++++++ isle.mak | 70 ++++++++++++++++++++++++++++++++++++ isle.mdp | Bin 51200 -> 50176 bytes 13 files changed, 219 insertions(+), 44 deletions(-) create mode 100755 LEGO1/mxpalette.cpp create mode 100755 LEGO1/mxunknown100dc6b0.cpp create mode 100755 LEGO1/mxunknown100dc6b0.h create mode 100755 LEGO1/mxvideomanager.cpp diff --git a/LEGO1/legonavcontroller.cpp b/LEGO1/legonavcontroller.cpp index 6f032701..e9110d7b 100644 --- a/LEGO1/legonavcontroller.cpp +++ b/LEGO1/legonavcontroller.cpp @@ -100,22 +100,18 @@ LegoNavController::LegoNavController() // inputManager->UnRegister(this); // } -// TODO: VideoManager() // OFFSET: LEGO1 0x10054ca0 -// void LegoNavController::SetControlMax(int p_hMax, int p_vMax) -// { -// LegoVideoManager* videoManager = VideoManager(); +void LegoNavController::SetControlMax(int p_hMax, int p_vMax) +{ + this->m_hMax = p_hMax; + this->m_vMax = p_vMax; -// this->m_hMax = p_hMax; -// this->m_vMax = p_vMax; - -// Probably checks for MxVideoParamFlags: FULL_SCREEN -// if ((videoManager->m_unk44 & 0x01) != 0) -// { -// this->m_hMax = 640; -// this->m_vMax = 480; -// } -// } + if (VideoManager()->GetVideoParam().flags().GetFullScreen()) + { + this->m_hMax = 640; + this->m_vMax = 480; + } +} // OFFSET: LEGO1 0x10054cd0 void LegoNavController::ResetToDefault() diff --git a/LEGO1/legonavcontroller.h b/LEGO1/legonavcontroller.h index de762dfd..3220d794 100644 --- a/LEGO1/legonavcontroller.h +++ b/LEGO1/legonavcontroller.h @@ -20,7 +20,7 @@ class LegoNavController : public MxCore LegoNavController(); // virtual ~LegoNavController(); - // void SetControlMax(int p_hMax, int p_vMax); + void SetControlMax(int p_hMax, int p_vMax); void ResetToDefault(); void SetTargets(int p_hPos, int p_vPos, MxBool p_accel); float CalculateNewTargetSpeed(int p_pos, int p_center, float p_maxSpeed); diff --git a/LEGO1/legovideomanager.h b/LEGO1/legovideomanager.h index a221504f..d96fac87 100644 --- a/LEGO1/legovideomanager.h +++ b/LEGO1/legovideomanager.h @@ -1,10 +1,10 @@ #ifndef LEGOVIDEOMANAGER_H #define LEGOVIDEOMANAGER_H +#include "mxvideomanager.h" #include "lego3dmanager.h" -// class LegoVideoManager : public MxVideoManager -class LegoVideoManager +class LegoVideoManager : public MxVideoManager { public: __declspec(dllexport) int EnableRMDevice(); @@ -14,31 +14,6 @@ class LegoVideoManager inline Lego3DManager *Get3DManager() { return this->m_3dManager; } - int m_unk00; - int m_unk04; - int m_unk08; - int m_unk0c; - int m_unk10; - int m_unk14; - int m_unk18; - int m_unk1c; - int m_unk20; - int m_unk24; - int m_unk28; - int m_unk2c; - int m_unk30; - int m_unk34; - int m_unk38; - int m_unk3c; - int m_unk40; - int m_unk44; - int m_unk48; - int m_unk4c; - int m_unk50; - int m_unk54; - int m_unk58; - int m_unk5c; - int m_unk60; int m_unk64; Lego3DManager *m_3dManager; int m_unk6c; diff --git a/LEGO1/mxpalette.cpp b/LEGO1/mxpalette.cpp new file mode 100755 index 00000000..dd245538 --- /dev/null +++ b/LEGO1/mxpalette.cpp @@ -0,0 +1,8 @@ +#include "mxpalette.h" + +// OFFSET: LEGO1 0x100bf150 +MxResult MxPalette::GetEntries(LPPALETTEENTRY p_entries) +{ + memcpy(p_entries, this->m_entries, sizeof(this->m_entries)); + return SUCCESS; +} \ No newline at end of file diff --git a/LEGO1/mxpalette.h b/LEGO1/mxpalette.h index fff36897..ab52b412 100644 --- a/LEGO1/mxpalette.h +++ b/LEGO1/mxpalette.h @@ -1,11 +1,23 @@ #ifndef MXPALETTE_H #define MXPALETTE_H -class MxPalette +#include + +#include "mxcore.h" +#include "mxresult.h" + +class MxPalette : public MxCore { public: __declspec(dllexport) unsigned char operator==(MxPalette &); __declspec(dllexport) void Detach(); + + MxResult GetEntries(LPPALETTEENTRY p_entries); + +private: + LPDIRECTDRAWPALETTE m_pDirectDrawPalette; + PALETTEENTRY m_entries[256]; + // there's a bit more here }; #endif // MXPALETTE_H diff --git a/LEGO1/mxunknown100dc6b0.cpp b/LEGO1/mxunknown100dc6b0.cpp new file mode 100755 index 00000000..e3125cef --- /dev/null +++ b/LEGO1/mxunknown100dc6b0.cpp @@ -0,0 +1,15 @@ +#include "mxunknown100dc6b0.h" + +// OFFSET: LEGO1 0x100b84c0 +MxUnknown100dc6b0::MxUnknown100dc6b0() +{ + Init(); +} + +// OFFSET: LEGO1 0x100b85d0 +MxResult MxUnknown100dc6b0::Init() +{ + this->m_unk08 = 0; + this->m_unk0c = 0; + return SUCCESS; +} \ No newline at end of file diff --git a/LEGO1/mxunknown100dc6b0.h b/LEGO1/mxunknown100dc6b0.h new file mode 100755 index 00000000..87779eaf --- /dev/null +++ b/LEGO1/mxunknown100dc6b0.h @@ -0,0 +1,23 @@ +#ifndef MXUNKNOWN100DC6B0_H +#define MXUNKNOWN100DC6B0_H + +#include "mxcore.h" +#include "mxresult.h" +#include "mxcriticalsection.h" + +class MxUnknown100dc6b0 : public MxCore +{ +public: + MxUnknown100dc6b0(); + + MxResult Init(); + +private: + int m_unk08; + int m_unk0c; + +protected: + MxCriticalSection m_criticalSection; +}; + +#endif // MXUNKNOWN100DC6B0_H diff --git a/LEGO1/mxvideomanager.cpp b/LEGO1/mxvideomanager.cpp new file mode 100755 index 00000000..c7a41c99 --- /dev/null +++ b/LEGO1/mxvideomanager.cpp @@ -0,0 +1,36 @@ +#include "mxvideomanager.h" + +// OFFSET: LEGO1 0x100be1f0 +MxVideoManager::MxVideoManager() +{ + Init(); +} + +// OFFSET: LEGO1 0x100be320 +int MxVideoManager::Init() +{ + this->m_unk50 = 0; + this->m_unk54 = NULL; + this->m_unk58 = NULL; + this->m_unk5c = 0; + this->m_videoParam.SetPalette(NULL); + this->m_unk60 = MX_FALSE; + return 0; +} + +// OFFSET: LEGO1 0x100bebe0 +long MxVideoManager::RealizePalette(MxPalette *p_palette) +{ + PALETTEENTRY paletteEntries[256]; + + this->m_criticalSection.Enter(); + + if (p_palette && this->m_videoParam.GetPalette()) + { + p_palette->GetEntries(paletteEntries); + // TODO + } + + this->m_criticalSection.Leave(); + return 0; +} \ No newline at end of file diff --git a/LEGO1/mxvideomanager.h b/LEGO1/mxvideomanager.h index f2805b15..eba332f3 100644 --- a/LEGO1/mxvideomanager.h +++ b/LEGO1/mxvideomanager.h @@ -1,11 +1,28 @@ #ifndef MXVIDEOMANAGER_H #define MXVIDEOMANAGER_H -class MxVideoManager +#include "mxunknown100dc6b0.h" +#include "mxvideoparam.h" + +class MxVideoManager : public MxUnknown100dc6b0 { public: __declspec(dllexport) void InvalidateRect(MxRect32 &); __declspec(dllexport) virtual long RealizePalette(MxPalette *); + + MxVideoManager(); + + int Init(); + + inline MxVideoParam& GetVideoParam() { return this->m_videoParam; } + +private: + MxVideoParam m_videoParam; + int m_unk50; + LPDIRECTDRAWSURFACE m_unk54; + void* m_unk58; + int m_unk5c; + MxBool m_unk60; }; #endif // MXVIDEOMANAGER_H diff --git a/LEGO1/mxvideoparam.h b/LEGO1/mxvideoparam.h index aeb50554..70569978 100644 --- a/LEGO1/mxvideoparam.h +++ b/LEGO1/mxvideoparam.h @@ -1,7 +1,10 @@ #ifndef MXVIDEOPARAM_H #define MXVIDEOPARAM_H +#include + #include "mxpalette.h" +#include "mxbool.h" #include "mxrect32.h" #include "mxvariabletable.h" #include "mxvideoparamflags.h" @@ -19,6 +22,9 @@ class MxVideoParam inline MxVideoParamFlags &flags() { return m_flags; } + inline void SetPalette(MxPalette *p_palette) { this->m_palette = p_palette; } + inline MxPalette *GetPalette() { return this->m_palette; } + private: MxRect32 m_rect; MxPalette *m_palette; diff --git a/LEGO1/mxvideoparamflags.h b/LEGO1/mxvideoparamflags.h index 3897c788..4e030499 100644 --- a/LEGO1/mxvideoparamflags.h +++ b/LEGO1/mxvideoparamflags.h @@ -40,6 +40,23 @@ class MxVideoParamFlags inline void Set_f2bit6(BOOL e) { m_flags2.bit6 = e; } inline void Set_f2bit7(BOOL e) { m_flags2.bit7 = e; } + inline BYTE GetFullScreen() { return m_flags1.bit0; } + inline BYTE GetFlipSurfaces() { return m_flags1.bit1; } + inline BYTE GetBackBuffers() { return m_flags1.bit2; } + inline BYTE Get_f1bit3() { return m_flags1.bit3; } + inline BYTE Get_f1bit4() { return m_flags1.bit4; } + inline BYTE Get16Bit() { return m_flags1.bit5; } + inline BYTE GetWideViewAngle() { return m_flags1.bit6; } + inline BYTE Get_f1bit7() { return m_flags1.bit7; } + inline BYTE Get_f2bit0() { return m_flags2.bit0; } + inline BYTE Get_f2bit1() { return m_flags2.bit1; } + inline BYTE Get_f2bit2() { return m_flags2.bit2; } + inline BYTE Get_f2bit3() { return m_flags2.bit3; } + inline BYTE Get_f2bit4() { return m_flags2.bit4; } + inline BYTE Get_f2bit5() { return m_flags2.bit5; } + inline BYTE Get_f2bit6() { return m_flags2.bit6; } + inline BYTE Get_f2bit7() { return m_flags2.bit7; } + private: flag_bitfield m_flags1; flag_bitfield m_flags2; diff --git a/isle.mak b/isle.mak index 78b41308..59570097 100644 --- a/isle.mak +++ b/isle.mak @@ -66,8 +66,11 @@ CLEAN : -@erase "$(INTDIR)\mxomnicreateflags.obj" -@erase "$(INTDIR)\mxomnicreateparam.obj" -@erase "$(INTDIR)\mxomnicreateparambase.obj" + -@erase "$(INTDIR)\mxpalette.obj" -@erase "$(INTDIR)\mxstring.obj" -@erase "$(INTDIR)\mxtimer.obj" + -@erase "$(INTDIR)\mxunknown100dc6b0.obj" + -@erase "$(INTDIR)\mxvideomanager.obj" -@erase "$(INTDIR)\mxvideoparam.obj" -@erase "$(INTDIR)\mxvideoparamflags.obj" -@erase "$(INTDIR)\vc40.pdb" @@ -140,8 +143,11 @@ LINK32_OBJS= \ "$(INTDIR)\mxomnicreateflags.obj" \ "$(INTDIR)\mxomnicreateparam.obj" \ "$(INTDIR)\mxomnicreateparambase.obj" \ + "$(INTDIR)\mxpalette.obj" \ "$(INTDIR)\mxstring.obj" \ "$(INTDIR)\mxtimer.obj" \ + "$(INTDIR)\mxunknown100dc6b0.obj" \ + "$(INTDIR)\mxvideomanager.obj" \ "$(INTDIR)\mxvideoparam.obj" \ "$(INTDIR)\mxvideoparamflags.obj" @@ -180,8 +186,11 @@ CLEAN : -@erase "$(INTDIR)\mxomnicreateflags.obj" -@erase "$(INTDIR)\mxomnicreateparam.obj" -@erase "$(INTDIR)\mxomnicreateparambase.obj" + -@erase "$(INTDIR)\mxpalette.obj" -@erase "$(INTDIR)\mxstring.obj" -@erase "$(INTDIR)\mxtimer.obj" + -@erase "$(INTDIR)\mxunknown100dc6b0.obj" + -@erase "$(INTDIR)\mxvideomanager.obj" -@erase "$(INTDIR)\mxvideoparam.obj" -@erase "$(INTDIR)\mxvideoparamflags.obj" -@erase "$(INTDIR)\vc40.idb" @@ -256,8 +265,11 @@ LINK32_OBJS= \ "$(INTDIR)\mxomnicreateflags.obj" \ "$(INTDIR)\mxomnicreateparam.obj" \ "$(INTDIR)\mxomnicreateparambase.obj" \ + "$(INTDIR)\mxpalette.obj" \ "$(INTDIR)\mxstring.obj" \ "$(INTDIR)\mxtimer.obj" \ + "$(INTDIR)\mxunknown100dc6b0.obj" \ + "$(INTDIR)\mxvideomanager.obj" \ "$(INTDIR)\mxvideoparam.obj" \ "$(INTDIR)\mxvideoparamflags.obj" @@ -530,6 +542,7 @@ DEP_CPP_LEGOO=\ ".\LEGO1\mxticklemanager.h"\ ".\LEGO1\mxtimer.h"\ ".\LEGO1\mxtransitionmanager.h"\ + ".\LEGO1\mxunknown100dc6b0.h"\ ".\LEGO1\mxvariabletable.h"\ ".\LEGO1\mxvideomanager.h"\ ".\LEGO1\mxvideoparam.h"\ @@ -614,6 +627,7 @@ DEP_CPP_MXOMN=\ ".\LEGO1\mxstring.h"\ ".\LEGO1\mxticklemanager.h"\ ".\LEGO1\mxtimer.h"\ + ".\LEGO1\mxunknown100dc6b0.h"\ ".\LEGO1\mxvariabletable.h"\ ".\LEGO1\mxvideomanager.h"\ ".\LEGO1\mxvideoparam.h"\ @@ -777,6 +791,7 @@ DEP_CPP_LEGON=\ ".\LEGO1\mxticklemanager.h"\ ".\LEGO1\mxtimer.h"\ ".\LEGO1\mxtransitionmanager.h"\ + ".\LEGO1\mxunknown100dc6b0.h"\ ".\LEGO1\mxvariabletable.h"\ ".\LEGO1\mxvideomanager.h"\ ".\LEGO1\mxvideoparam.h"\ @@ -817,6 +832,59 @@ DEP_CPP_MXATO=\ $(CPP) $(CPP_PROJ) $(SOURCE) +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\LEGO1\mxunknown100dc6b0.cpp +DEP_CPP_MXUNK=\ + ".\LEGO1\legoinc.h"\ + ".\LEGO1\mxbool.h"\ + ".\LEGO1\mxcore.h"\ + ".\LEGO1\mxcriticalsection.h"\ + ".\LEGO1\mxunknown100dc6b0.h"\ + + +"$(INTDIR)\mxunknown100dc6b0.obj" : $(SOURCE) $(DEP_CPP_MXUNK) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\LEGO1\mxvideomanager.cpp +DEP_CPP_MXVIDEO=\ + ".\LEGO1\legoinc.h"\ + ".\LEGO1\mxbool.h"\ + ".\LEGO1\mxcore.h"\ + ".\LEGO1\mxcriticalsection.h"\ + ".\LEGO1\mxpalette.h"\ + ".\LEGO1\mxrect32.h"\ + ".\LEGO1\mxunknown100dc6b0.h"\ + ".\LEGO1\mxvariabletable.h"\ + ".\LEGO1\mxvideomanager.h"\ + ".\LEGO1\mxvideoparam.h"\ + ".\LEGO1\mxvideoparamflags.h"\ + + +"$(INTDIR)\mxvideomanager.obj" : $(SOURCE) $(DEP_CPP_MXVIDEO) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\LEGO1\mxpalette.cpp +DEP_CPP_MXPAL=\ + ".\LEGO1\mxpalette.h"\ + + +"$(INTDIR)\mxpalette.obj" : $(SOURCE) $(DEP_CPP_MXPAL) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + # End Source File # End Target ################################################################################ @@ -894,6 +962,7 @@ DEP_CPP_ISLE_=\ ".\LEGO1\mxticklemanager.h"\ ".\LEGO1\mxtimer.h"\ ".\LEGO1\mxtransitionmanager.h"\ + ".\LEGO1\mxunknown100dc6b0.h"\ ".\LEGO1\mxvariabletable.h"\ ".\LEGO1\mxvideomanager.h"\ ".\LEGO1\mxvideoparam.h"\ @@ -949,6 +1018,7 @@ DEP_CPP_MAIN_=\ ".\LEGO1\mxticklemanager.h"\ ".\LEGO1\mxtimer.h"\ ".\LEGO1\mxtransitionmanager.h"\ + ".\LEGO1\mxunknown100dc6b0.h"\ ".\LEGO1\mxvariabletable.h"\ ".\LEGO1\mxvideomanager.h"\ ".\LEGO1\mxvideoparam.h"\ diff --git a/isle.mdp b/isle.mdp index 375126de1fb0e167099a3ea158190f92cebdac37..390064aa600f2bb5cc48156405e1040876938d6d 100644 GIT binary patch literal 50176 zcmeHQOLN@D5$+{LhNNWcK~l11OOchg6R-J@Wm|qE)>2la(6J-hk&~VkBZg~GWIck%p zV+2mYH$)Sl*MtBeKnM^5ga9Ex2oM5<03kpK5CVh%Auz!RT$zTefBJk1{tkbJ(HD=W zK0O7{xz+t>;KqY)rx$yJ#IwTgM)WB3Bg+|dy@Bs`H}Bkif3+Ko`j+n|iQBgO{p$?r@<%tbO0}%p*03kpK5CVh%AwUQa0)zk|KnM^5gupQ)K>5Fung9D1d>g(4 z--YkN_u&WdBK+`}?U06lk_e>vKX%z~>E71noog>$d+3GhYu6sQzH1HK8EEA{s|SCo zpNZ%??v5AoP5`ae%bGl_mjHYG^f>~{3sa6Y%`sv(?OD){?N;mUgPGFS2EMx+S)mtL zi5G=gqk`UBChXfo&v)>H{yF!nCfvJL;0_Y(QPA$)GU4;W{xHdheA9$Ah#c4NBVKNp zU|WWs2Eqkctf@k~_lC)M*g_!@hSM;#Vz@ZM(Tsp8wVdb~0rMz|eMgw7HZZ|x+@SE0x~s`tT*5z302Rht&2u!6@+p zHa+c406AhS9C)QI#9*fTR_s~Z*kFhKGJ4dCPpBBUGe81T5wM~g_-TYzZgBh%r9ph5jmOsFUg*hC~|C+vKS;HjqBYO{x z#7xi3v^bXmq=l9Svn&=louvUl1#8~;sMRvyFFa=I^|-$8=mT8g-^P<_s)M#|L_mGe;%+!7~98ju#3rDja#fM8cJ?PJU)N zScO8oo(l3Th-5Ms3l$tO?;#--<}LUU3E{Nk;*u;uXT$Bgq2q@3XB|vbV>!`{#|A%# zg%e%{X~9{Mjv0JGlGZ)cB=by7FSOe|HO*N@v+iX1kp{{$DdoQBV%0<~kdtBA&PzUP zBIDx&ET1EPjx>N=C~9$PiI>&Y zH#O5@-A^?rc7_$FvWk{kC{8!4VX29@tZ`njVaRjA$lXWd&_D@EgWcKftT6|Lz;YtlyjaXx)mbg!^ROZx@(W;7CoSF=0IsPJp27PhKEA=+D z!1-)LZjiT(H1(RAS|*NPsiLWA5m8-d^0ZhhYjU_~b=8f&LA$4zo7Y%S99}r*GzjFb zc9?ir*;nh0bF60j8>naImNxD`q}>$H&9s~1cZxKa3hkz}oALmYc2nGZ+0_xX6QoLQo#xe z(gv%U;f|$+-Nv&bNRfmcCsuU=%JC;ma7wE5>@44N8VD9}Gl_<=jn`?_QjR=3dr`GD zsq|P@Y)mTpBTxV8B(aTB#7j)0`tGJu=qt!5bCI=uP&I)g&p&ej>N}une2fROkB+Df z^-ux!(NsC`C|)hjH9S$6uo6H0q1K49<90&Xar~f)+C(TjuH618JI<~%d{y~uI)11& zD>{B0T+pWDM|#$6|Mc-+|H<>f-OfS%+Nl5QB=mp%7=8u6hTlLJK7rrD@8HwPHF46c IhQK`h4@5i>LI3~& literal 51200 zcmeHQS#ul55pIa0LQ1lAkdkcqlAZWSVk4I5_&!BaGHJ@9MLWs?$6D?#iH-I^?Jj7z zT;*3ksqgQREnm;rWX2@D|7A{teqP(V-b^fx`z(_han*0-*| zIs-?+0XPEmnmPpjN3W?y;NMeiJsJNeco}SX4ju!B#iRT$p)x%P$N}%a(_=PSnj>%& zej&R6y(a_+0YZQfAOr{jLVyq;1PB2_fDj-A2!TV4z!9we{BUOm{t4eh=lgq93p&JO zEt@tA$B+S4gB_J z(JSi2gFztU|JY%_#kH-C)l08jy6uHaS1#Rheb-9dS!k5650>9TZ}altvyk0eKXJUbDSs-j|LQr&3o& zo&usPafCe?1KvH)aidAV`*jrij%1S|yg|=Oqrh{T?M*XygWk4f-`$O)Zs=HD#}mdG z_h{Qg2kbQ4?;H0hiu^H}+fj^jXvOsEju*Rj>crO9&GuDeC5dITMaFpE1U)C&@o>pC zhjFZF7xY+jJ9cqF+VQR3#CQVBns6dpL9_jlDXbmKcT=`P8apQ&+odaGDM-40+H4yx ztwAqI5!Aqr!ZeP2pDnG%UY4mEV|C`e!T8l|UpF0+)U)sUZn-2HuFXL&^@1^iF}9Db zF!A~VyRl7sR_s~Z=xXfG7)uF{7P-$GhQFXEl;rae7I-`>H;F6mc6V3aA{tK)zH;(C zqTvj6d|&MI4BeV-()iNFJ7Tyw3wm~p&R|=9f)k!C#9Z4oQ!lr=Y2-)tU3AfL@G0D! z>o6WBfsU~~!l^QQjA0gvGVdI3&_vA1W)0VN({#`Vv~6Q1m04@(ndNFZDI>>+j7^r% z+LNLQ@0F8m}oJud?|#>{>rSI zLQXQjWY!d7(zV43p~FftO$dv*p-?Zi5VJ|JV2T#c3NQv*luVbRRXI9+Y?eY$*`eV~ zP_t5sYn&G*I5P935S98Zu}ccU8OKHUU4-Qox8sJ68`|G2W3dH~AGmSu@N-2<)__y8 z9CLUflGPFQBJ<2lFSMI&z04^lv*eTswqEjNCb{RiSa;k<3`_D}`c0h}zpiwmK(Fv@ zW`%reKrg(&g!}o%n!X-q(tJwQ2yqm7Szdox-p78XLN9z=)Wr2d7xi^-eWQiyI#pxX zNtW>zRbahR>~2x%)eCW5IWt>x$$gy@B!7e=YKgVmJ2@|wQ8 zXRzkWY2+QWKZh~W_~=Ia?z0}A_?SgW4OMcc zSvgOyNI_5KQk)FZuqlO1d0tAP2bl?e*g-z~t`K{=$f8-kRXq-%;&RI5o;9hQVpp}e zAYY^}v#c^j7iHQ06X`0|Ps-whWqMVElChB!%xX8DkoBU6%4f(`YH@HgLX)Y@Q_`x| zKH~=WkyY_N;|7c5s$P`F$$4y5?{h_G>oVDDGf8`KPFvN9(~@>xyxvEs;7Y0&lqnwR zWVK44MDfU(b5*Bggvgz%Vv-R>idhvZokUIq%OrD1`EvQI%1bPylr~o7B%4IyxQ|$o zI#$I>uPahK>4X@DvT6efdpRep3QGMHSz%S|ap6Ffys#==&O9kItV)%OmL@l>wvc*J z$quX1lB@`NGn`2mBXB0l`k@jN>qQS$-Q=&1U2nk2y60$1#{h z-Pp!+&H63P#A(a(y3nNKU(aa*lTMz~r<3GGhhcX|;!YQtMb+r0Gw420tz2a#4(d8E zablJOP>q1P>*Kb%xVK5~s786}Waxj~(GH$5ubENEL@PhGPHPEo~^Wb2YS~z(W?&;R%dAREMTIbpKt> z`XEeo==@0}dWa6V4xMc%f53j=;@Fu(kZ^JwAF1!ct!w2vod<0iv8CGBwuEBNq7}j7NK7kFm z0iVK6*o4pE7Hq-i@CEz