diff --git a/.gitattributes b/.gitattributes index 1ff0c42..87813be 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,63 +1,63 @@ -############################################################################### -# Set default behavior to automatically normalize line endings. -############################################################################### -* text=auto - -############################################################################### -# Set default behavior for command prompt diff. -# -# This is need for earlier builds of msysgit that does not have it on by -# default for csharp files. -# Note: This is only used by command line -############################################################################### -#*.cs diff=csharp - -############################################################################### -# Set the merge driver for project and solution files -# -# Merging from the command prompt will add diff markers to the files if there -# are conflicts (Merging from VS is not affected by the settings below, in VS -# the diff markers are never inserted). Diff markers may cause the following -# file extensions to fail to load in VS. An alternative would be to treat -# these files as binary and thus will always conflict and require user -# intervention with every merge. To do so, just uncomment the entries below -############################################################################### -#*.sln merge=binary -#*.csproj merge=binary -#*.vbproj merge=binary -#*.vcxproj merge=binary -#*.vcproj merge=binary -#*.dbproj merge=binary -#*.fsproj merge=binary -#*.lsproj merge=binary -#*.wixproj merge=binary -#*.modelproj merge=binary -#*.sqlproj merge=binary -#*.wwaproj merge=binary - -############################################################################### -# behavior for image files -# -# image files are treated as binary by default. -############################################################################### -#*.jpg binary -#*.png binary -#*.gif binary - -############################################################################### -# diff behavior for common document formats -# -# Convert binary document formats to text before diffing them. This feature -# is only available from the command line. Turn it on by uncommenting the -# entries below. -############################################################################### -#*.doc diff=astextplain -#*.DOC diff=astextplain -#*.docx diff=astextplain -#*.DOCX diff=astextplain -#*.dot diff=astextplain -#*.DOT diff=astextplain -#*.pdf diff=astextplain -#*.PDF diff=astextplain -#*.rtf diff=astextplain -#*.RTF diff=astextplain +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* binary + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/source-code/data/plugins/config_template.bin b/source-code/data/plugins/config_template.bin index 123c39e..1b3b29c 100644 --- a/source-code/data/plugins/config_template.bin +++ b/source-code/data/plugins/config_template.bin @@ -1,156 +1,156 @@ - ######################################### -# /!\ WARNING: DO NOT EDIT WITH NOTEPAD!# -######################################### - -[Global] -# Load plugins including below options -Enable=1 - -[GPU] -# Force GPU model -- -1=auto, 0=Kepler, 1=Maxwell, 2=Turing, 3=Ampere -Model=-1 - -[Launcher] -# Forces the launcher to be skipped, you can use the --launch parameter instead of this. -Skip=0 -# Disables unsupported GPU warning dialogs. -No_GPU_Dialog=0 -# Sets the dark colour scheme in the launcher. -Dark_Launcher=0 -# Enables acrylic blur in the launcher on Windows 10 20H2 or later. -Acrylic_Blur=0 -#Ignores some OpenGL-related errors. Don't use both patches at the same time unless you're know what you're doing -OpenGL_Patch_A=0 -#Ignores some OpenGL-related errors. Don't use both patches at the same time unless you're know what you're doing -OpenGL_Patch_B=0 -# Command line arguments -Command_Line= -# Launches divahook.bat/start.bat intead of diva.exe. -Use_divahook_bat=0 - -[Patches] -#Disable movies (enable this if the game hangs when loading certain PVs) -No_Movies=0 -#Enable custom MP4 adv movies (experimental) -MP4_Movies=1 -#Enable or disable mouse cursor -Cursor=1 -#Use 2 channels instead of 4 (when not using DivaSound) -Stereo=1 -#Skip one or more menus -- 0=disabled, 1=guest, 2=guest+normal -Quick_Start=1 -#Disable the scrolling sound effect -No_Scrolling_SFX=0 -#Enhanced Stage Manager (sets a custom number of stages; "stage_manager" should be disabled in "components.ini") -#Number of stages (0 = disabled) -Enhanced_Stage_Manager=0 -#Use encore stages or not -Enhanced_Stage_Manager_Encore=1 -#Change the mouth animations -- 0=default, 1=force PDA, 2=force FT -Force_Mouth=0 -#Change the expressions -- 0=default, 1=force PDA, 2=force FT -Force_Expressions=0 -#Change the look animations -- 0=default, 1=force PDA, 2=force FT -Force_Look=0 -#Disable hand scaling -No_Hand_Scaling=0 -#Default hand size -- 0-10000=default, 12200=PDA -Default_Hand_Size=0 -#Sing missed notes -Sing_Missed=0 -#Hide the volume and SE control buttons -Hide_Volume=0 -#Remove the photo controls during PV playback -No_PV_UI=0 -#Hide the watermark that's usually shown in PV viewing mode -Hide_PV_Watermark=0 -#Set the card reader and network status icons -- 0=default, 1=hidden, 2=error, 3=OK, 4=partial OK -Status_Icons=0 -#Disable showing lyrics -No_Lyrics=0 -#Disable the error banner -No_Error=1 -#Hide "CREDIT(S)"/"FREE PLAY" -Hide_Freeplay=0 -#Show "FREE PLAY" instead of "CREDIT(S)" and don't require credits -Freeplay=1 -#Show "PD Loader" instead of "FREE PLAY" -PDLoaderText=1 -#Freeze the timer -No_Timer=1 -#Disable the timer sprite -No_Timer_Sprite=1 -#Unlock PSEUDO modules (incomplete, will default to Miku) -Unlock_Pseudo=0 -#Enable the card menu (incomplete, it doesn't bypass the card prompt) -Card=0 -#Allow using a real arcade slider attached to COM11 (or PS4 official FT controller) -Hardware_Slider=0 -#Enable custom patches -Custom_Patches=1 -#Prevent data deletion -Prevent_Data_Deletion=0 - -[Graphics] -# Lag Compensation -Lag_Compensation = 0 -# Set to -1 to unlock the frame rate. -FPS.Limit=60 -# Reduces FPS Limiter CPU usage -# (may have less consistent performance) -FPS.Limit.LightMode=1 -# Enable debug warnings for lightweight limiter -FPS.Limit.Verbose=0 -# Temporal Anti-Aliasing -TAA=1 -# Morphological Anti-Aliasing -MLAA=1 -# MAG Filter -- 0=default (bilinear), 1=nearest-neighbour, 2=sharpen, 3=cone (smooth) -MAG=0 -# Depth of Field -DOF=1 -# Reflections -Reflections=1 -# Gamma -- 0 or 100=default, 125=console-like -Gamma=100 -# Shadows -Shadows=1 -# Transparent Meshes -Punchthrough=1 -# Glare -Glare=1 -# Shader -Shader=1 -# Toon shader (press F9 to toggle) -- 0=default, 1=force on, 2=force off -NPR1=0 -# Disable all 3D passes. WARNING: The extended data will be deleted unless Prevent Data Deletion is enabled. -2D=0 -# FrameRateManager motion rate (fps) -FRM.Motion.Rate=400 - -[Resolution] -# 0 = Windowed, 1 = Fast, 2 = Exclusive, 3 = Safe -# For same as screen res: -1x-1 -Display=1 -Width=-1 -Height=-1 -# Fullscreen only options -BitDepth=32 -RefreshRate=60 - -# Set a custom internal render resolution -# Same as window: -1x-1 -# HD : 1280x720 -# FHD : 1920x1080 -# WQHD : 2560x1440 -# 4K UHD: 3840x2160 -# 5K UHD: 5120x2880 -# 8K UHD: 7680x4320 -r.Enable=0 -r.Width=1920 -r.Height=1080 - -[plugins] -DivaWig.dva=0 -DSCRemote.dva=0 -custom_freeplay_text_example.p=0 + ######################################### +# /!\ WARNING: DO NOT EDIT WITH NOTEPAD!# +######################################### + +[Global] +# Load plugins including below options +Enable=1 + +[GPU] +# Force GPU model -- -1=auto, 0=Kepler, 1=Maxwell/Pascal, 2=Turing, 3=Ampere +Model=-1 + +[Launcher] +# Forces the launcher to be skipped, you can use the --launch parameter instead of this. +Skip=0 +# Disables unsupported GPU warning dialogs. +No_GPU_Dialog=0 +# Sets the dark colour scheme in the launcher. +Dark_Launcher=0 +# Enables acrylic blur in the launcher on Windows 10 20H2 or later. +Acrylic_Blur=0 +#Ignores some OpenGL-related errors. Don't use both patches at the same time unless you're know what you're doing +OpenGL_Patch_A=0 +#Ignores some OpenGL-related errors. Don't use both patches at the same time unless you're know what you're doing +OpenGL_Patch_B=0 +# Command line arguments +Command_Line= +# Launches divahook.bat/start.bat intead of diva.exe. +Use_divahook_bat=0 + +[Patches] +#Disable movies (enable this if the game hangs when loading certain PVs) +No_Movies=0 +#Enable custom MP4 adv movies (experimental) +MP4_Movies=1 +#Enable or disable mouse cursor +Cursor=1 +#Use 2 channels instead of 4 (when not using DivaSound) +Stereo=1 +#Skip one or more menus -- 0=disabled, 1=guest, 2=guest+normal +Quick_Start=1 +#Disable the scrolling sound effect +No_Scrolling_SFX=0 +#Enhanced Stage Manager (sets a custom number of stages; "stage_manager" should be disabled in "components.ini") +#Number of stages (0 = disabled) +Enhanced_Stage_Manager=0 +#Use encore stages or not +Enhanced_Stage_Manager_Encore=1 +#Change the mouth animations -- 0=default, 1=force PDA, 2=force FT +Force_Mouth=0 +#Change the expressions -- 0=default, 1=force PDA, 2=force FT +Force_Expressions=0 +#Change the look animations -- 0=default, 1=force PDA, 2=force FT +Force_Look=0 +#Disable hand scaling +No_Hand_Scaling=0 +#Default hand size -- 0-10000=default, 12200=PDA +Default_Hand_Size_uint=0 +#Sing missed notes +Sing_Missed=0 +#Hide the volume and SE control buttons +Hide_Volume=0 +#Remove the photo controls during PV playback +No_PV_UI=0 +#Hide the watermark that's usually shown in PV viewing mode +Hide_PV_Watermark=0 +#Set the card reader and network status icons -- 0=default, 1=hidden, 2=error, 3=OK, 4=partial OK +Status_Icons=0 +#Disable showing lyrics +No_Lyrics=0 +#Disable the error banner +No_Error=1 +#Hide "CREDIT(S)"/"FREE PLAY" +Hide_Freeplay=0 +#Show "FREE PLAY" instead of "CREDIT(S)" and don't require credits +Freeplay=1 +#Show "PD Loader" instead of "FREE PLAY" +PDLoaderText=1 +#Freeze the timer +No_Timer=1 +#Disable the timer sprite +No_Timer_Sprite=1 +#Unlock PSEUDO modules (incomplete, will default to Miku) +Unlock_Pseudo=0 +#Enable the card menu (incomplete, it doesn't bypass the card prompt) +Card=0 +#Allow using a real arcade slider attached to COM11 (or PS4 official FT controller) +Hardware_Slider=0 +#Enable custom patches +Custom_Patches=1 +#Prevent data deletion +Prevent_Data_Deletion=0 + +[Graphics] +# Lag Compensation +Lag_Compensation = 0 +# Set to -1 to unlock the frame rate. +FPS.Limit=60 +# Reduces FPS Limiter CPU usage +# (may have less consistent performance) +FPS.Limit.LightMode=1 +# Enable debug warnings for lightweight limiter +FPS.Limit.Verbose=0 +# Temporal Anti-Aliasing +TAA=1 +# Morphological Anti-Aliasing +MLAA=1 +# MAG Filter -- 0=default (bilinear), 1=nearest-neighbour, 2=sharpen, 3=cone (smooth) +MAG=0 +# Depth of Field +DOF=1 +# Reflections +Reflections=1 +# Gamma -- 0 or 100=default, 125=console-like +Gamma=100 +# Shadows +Shadows=1 +# Transparent Meshes +Punchthrough=1 +# Glare +Glare=1 +# Shader +Shader=1 +# Toon shader (press F9 to toggle) -- 0=default, 1=force on, 2=force off +NPR1=0 +# Disable all 3D passes. WARNING: The extended data will be deleted unless Prevent Data Deletion is enabled. +2D=0 +# FrameRateManager motion rate (fps) +FRM.Motion.Rate=400 + +[Resolution] +# 0 = Windowed, 1 = Fast, 2 = Exclusive, 3 = Safe +# For same as screen res: -1x-1 +Display=1 +Width=-1 +Height=-1 +# Fullscreen only options +BitDepth=32 +RefreshRate=60 + +# Set a custom internal render resolution +# Same as window: -1x-1 +# HD : 1280x720 +# FHD : 1920x1080 +# WQHD : 2560x1440 +# 4K UHD: 3840x2160 +# 5K UHD: 5120x2880 +# 8K UHD: 7680x4320 +r.Enable=0 +r.Width=1920 +r.Height=1080 + +[plugins] +DivaWig.dva=0 +DSCRemote.dva=0 +custom_freeplay_text_example.p=0 diff --git a/source-code/source/plugins/Launcher/ConfigOption.h b/source-code/source/plugins/Launcher/ConfigOption.h index b764a38..243560e 100644 --- a/source-code/source/plugins/Launcher/ConfigOption.h +++ b/source-code/source/plugins/Launcher/ConfigOption.h @@ -1,1238 +1,1239 @@ -#pragma once -#pragma warning(push) -#pragma warning(disable: 4947) - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -// Windows Header Files -#include -#include -#include -#include - -#include - -#include "PluginConfigApi.h" -#include "IniReader.h" - -using namespace System; -using namespace System::Windows::Forms; - -float BaseScaleSize = 96; -int Col1Width = 110; -int Col2Left = 140; -int Col2Width = 90; -int ConfigBtnLeft = 120; -int ControlSpacing = 6; - - - -// declare this early (actual definitions below) -class ConfigOptionBase; -Panel^ MakePanel(int width, int height, std::vector &cfg, ToolTip^ tooltip, bool* hasChanged); - - -#define RESOPT_MATCH_WINDOW_TEXT "Match Window" -#define RESOPT_MATCH_SCREEN_TEXT "Match Screen" - -ref class ComboboxValidation -{ -public: - ComboBox^ cb; - - ComboboxValidation(ComboBox^ combobox) - { - cb = combobox; - } - - System::Void CheckNumberLeave(System::Object^ sender, System::EventArgs^ e) - { - System::String^ text = cb->Text; - - cli::array^ digitsarray = gcnew cli::array{ L'0', L'1', L'2', L'3', L'4', L'5', L'6', L'7', L'8', L'9' }; - System::Collections::Generic::List^ digitslist = gcnew System::Collections::Generic::List(digitsarray); - - if (text->Length <= 0) - return; - - while (text->Length > 0 && text[0] != L'-' && !digitslist->Contains(text[0])) - { - text = text->Remove(0, 1); - } - - if (text->Length <= 1) // can discard up to 1 now because first digit is known good - { - cb->Text = text; - return; - } - - for (int i = 1; i < text->Length; i++) - { - if (!digitslist->Contains(text[i])) - { - text = text->Remove(i, 1); - i--; // negate the upcoming ++ - } - } - - cb->Text = text; - } - - System::Void CheckResolutionLeave(System::Object^ sender, System::EventArgs^ e) - { - System::String^ text = cb->Text; - - if (text == RESOPT_MATCH_WINDOW_TEXT || text == RESOPT_MATCH_SCREEN_TEXT) - return; - - cli::array^ digitsarray = gcnew cli::array{ L'0', L'1', L'2', L'3', L'4', L'5', L'6', L'7', L'8', L'9' }; - System::Collections::Generic::List^ digitslist = gcnew System::Collections::Generic::List(digitsarray); - - int numX = 0; - - while (text->Length > 0 && text[0] != L'x' && !digitslist->Contains(text[0])) - { - text = text->Remove(0, 1); - } - - if (text->Length <= 0) - { - cb->Text = "x"; - return; - } - - if (text[0] == L'x') - { - numX++; - } - - if (text->Length <= 1) // can discard up to 1 now because first digit is known good - { - if (numX == 0) // if that digit wasn't an x though, add one - { - text += "x"; - } - cb->Text = text; - return; - } - - for (int i = 1; i < text->Length; i++) - { - if (!digitslist->Contains(text[i]) && !(numX == 0 && text[i] == L'x' && ++numX)) - { - text = text->Remove(i, 1); - i--; // negate the upcoming ++ - } - } - - if (numX == 0) - { - text += "x"; - } - - cb->Text = text; - } - -}; - -ref class PluginConfigHandler -{ -public: - Form^ form; - - PluginConfigHandler(Panel^ optspanel, String^ title, float btnScaleSize) - { - form = gcnew Form(); - - form->Text = title; - - form->FormBorderStyle = FormBorderStyle::FixedDialog; - form->StartPosition = FormStartPosition::CenterScreen; - form->MaximizeBox = false; - form->MinimizeBox = false; - form->ShowInTaskbar = false; - form->ShowIcon = false; - //form->TopMost = true; - - form->BackColor = Drawing::Color::FromArgb(64, 64, 64); - form->ForeColor = Drawing::Color::White; - - form->Font = optspanel->Font; - - optspanel->Left = 0; - optspanel->Top = 0; - - Button^ OkBtn = gcnew Button(); - OkBtn->Scale(btnScaleSize); - OkBtn->Text = L"OK"; - OkBtn->Left = 4; - OkBtn->Top = optspanel->Bottom + 4; - OkBtn->AutoSize = true; - OkBtn->FlatStyle = System::Windows::Forms::FlatStyle::Flat; - - form->ClientSize = Drawing::Size(optspanel->Width, OkBtn->Bottom + 4); - - form->Controls->Add(optspanel); - form->Controls->Add(OkBtn); - form->AcceptButton = OkBtn; - - form->FormClosing += gcnew System::Windows::Forms::FormClosingEventHandler(this, &PluginConfigHandler::FormClosing); - OkBtn->Click += gcnew EventHandler(this, &PluginConfigHandler::OkClick); - } - - System::Void OpenForm(System::Object^ sender, System::EventArgs^ e) - { - // ShowDialog seems to prevent disposal by copying the panel... - // which would be fine if I didn't rely on using the control handles - // MessageBox::Show(form->Controls[0]->Handle.ToString()); - - //Application::OpenForms[0]->Enabled = false; - form->Owner = Application::OpenForms[0]; - if (form->Visible) - form->Hide(); - form->Show(); - } - - System::Void FormClosing(System::Object^ sender, FormClosingEventArgs^ e) - { - if (e->CloseReason == CloseReason::UserClosing) - { - form->Hide(); - //Application::OpenForms[0]->Enabled = true; - e->Cancel = true; - } - } - - System::Void OkClick(System::Object^ sender, System::EventArgs^ e) - { - form->Close(); - } -}; - -ref class ChangeHandler -{ -public: - bool* changebool; - - ChangeHandler(bool* onchangebool) - { - changebool = onchangebool; - } - - System::Void SetChanged(System::Object^ sender, System::EventArgs^ e) - { - *changebool = true; - } -}; - -ref class CustomFuncHandler -{ -public: - void(*_func)(); - - CustomFuncHandler(void(*func)()) - { - _func = func; - } - - System::Void RunFunc(System::Object^ sender, System::EventArgs^ e) - { - _func(); - } -}; - - -class ConfigOptionBase -{ -public: - LPCWSTR _iniVarName; - LPCWSTR _iniSectionName; - LPCWSTR _iniFilePath; - - LPCWSTR _friendlyName; - LPCWSTR _description; - - System::IntPtr mainControlHandle; - bool* hasChanged; - - virtual int AddToPanel(Panel^ panel, unsigned int left, unsigned int top, ToolTip^ tooltip) - { - return 0; - } - - virtual void SaveOption() - { - return; - } -}; - - -class OptionMetaGroupStart : public ConfigOptionBase -{ -public: - int _height; - - OptionMetaGroupStart(LPCWSTR friendlyName, int height) - { - _friendlyName = friendlyName; - _height = height; - } -}; -class OptionMetaGroupEnd : public ConfigOptionBase -{ -public: - OptionMetaGroupEnd() - { - } -}; - -class OptionMetaSectionLabel : public ConfigOptionBase -{ -public: - OptionMetaSectionLabel(LPCWSTR friendlyName) - { - _friendlyName = friendlyName; - } - - virtual int AddToPanel(Panel^ panel, unsigned int left, unsigned int top, ToolTip^ tooltip) - { - Label^ lab = gcnew Label(); - - lab->Text = gcnew String(_friendlyName); - lab->Left = left + 2; - lab->Top = top; - lab->Font = gcnew System::Drawing::Font(lab->Font->Name, 12.0f, System::Drawing::FontStyle::Bold); - lab->AutoSize = true; - - Form^ RootForm = panel->FindForm(); - float ScaleWidth = 1.0f; - float ScaleHeight = 1.0f; - if (RootForm) - { - Drawing::SizeF CurrentScaleSize = RootForm->CurrentAutoScaleDimensions; - ScaleWidth = CurrentScaleSize.Width / BaseScaleSize; - ScaleHeight = CurrentScaleSize.Height / BaseScaleSize; - } - lab->Scale(ScaleWidth, ScaleHeight); - - panel->Controls->Add(lab); - mainControlHandle = lab->Handle; - - int ControlHeight = lab->Font->Height / ScaleHeight; - return ControlHeight + ControlSpacing; - } -}; - -class OptionMetaSpacer : public ConfigOptionBase -{ -public: - int _height; - - OptionMetaSpacer(int height) - { - _height = height; - } - - virtual int AddToPanel(Panel^ panel, unsigned int left, unsigned int top, ToolTip^ tooltip) - { - return _height; - } -}; - -class OptionMetaSeparator : public ConfigOptionBase -{ -public: - OptionMetaSeparator() - { - } - - virtual int AddToPanel(Panel^ panel, unsigned int left, unsigned int top, ToolTip^ tooltip) - { - Label^ lab = gcnew Label(); - - lab->Text = "_____________________________________"; - lab->Left = left + 2; - lab->Top = top; - lab->AutoSize = true; - - Form^ RootForm = panel->FindForm(); - float ScaleWidth = 1.0f; - float ScaleHeight = 1.0f; - if (RootForm) - { - Drawing::SizeF CurrentScaleSize = RootForm->CurrentAutoScaleDimensions; - ScaleWidth = CurrentScaleSize.Width / BaseScaleSize; - ScaleHeight = CurrentScaleSize.Height / BaseScaleSize; - } - lab->Scale(ScaleWidth, ScaleHeight); - - panel->Controls->Add(lab); - mainControlHandle = lab->Handle; - - int ControlHeight = lab->Font->Height / ScaleHeight; - return ControlHeight + ControlSpacing; - } -}; - - -class BooleanOption : public ConfigOptionBase -{ -public: - bool _defaultVal; - bool _saveAsString; - - BooleanOption(LPCWSTR iniVarName, LPCWSTR iniSectionName, LPCWSTR iniFilePath, LPCWSTR friendlyName, LPCWSTR description, bool defaultVal, bool saveAsString) - { - _iniVarName = iniVarName; - _iniSectionName = iniSectionName; - _iniFilePath = iniFilePath; - _friendlyName = friendlyName; - _description = description; - _defaultVal = defaultVal; - _saveAsString = saveAsString; - } - - virtual int AddToPanel(Panel^ panel, unsigned int left, unsigned int top, ToolTip^ tooltip) - { - CheckBox^ cb = gcnew CheckBox(); - - cb->Text = gcnew String(_friendlyName); - cb->Checked = GetIniBool(_iniSectionName, _iniVarName, _defaultVal, _iniFilePath); - cb->Left = left + 2; - cb->Top = top; - cb->AutoSize = true; - cb->FlatStyle = System::Windows::Forms::FlatStyle::Flat; - - // hack to ensure high contrast - cb->BackColor = System::Drawing::Color::FromArgb(0, 127, 127, 127); - - Form^ RootForm = panel->FindForm(); - float ScaleWidth = 1.0f; - float ScaleHeight = 1.0f; - if (RootForm) - { - Drawing::SizeF CurrentScaleSize = RootForm->CurrentAutoScaleDimensions; - ScaleWidth = CurrentScaleSize.Width / BaseScaleSize; - ScaleHeight = CurrentScaleSize.Height / BaseScaleSize; - } - cb->Scale(ScaleWidth, ScaleHeight); - - tooltip->SetToolTip(cb, gcnew String(_description)); - - if (hasChanged == nullptr) - hasChanged = new bool(false); - ChangeHandler^ changehandler = gcnew ChangeHandler(hasChanged); - cb->CheckedChanged += gcnew System::EventHandler(changehandler, &ChangeHandler::SetChanged); - - panel->Controls->Add(cb); - mainControlHandle = cb->Handle; - - int ControlHeight = cb->Font->Height / ScaleHeight; - return ControlHeight + ControlSpacing; - } - - virtual void SaveOption() - { - SetIniBool(_iniSectionName, _iniVarName, ((CheckBox^)CheckBox::FromHandle(mainControlHandle))->Checked, _iniFilePath, _saveAsString); - } -}; - - -class NumericOption : public ConfigOptionBase -{ -public: - int _defaultVal; - int _minVal; - int _maxVal; - - NumericOption(LPCWSTR iniVarName, LPCWSTR iniSectionName, LPCWSTR iniFilePath, LPCWSTR friendlyName, LPCWSTR description, int defaultVal, int minVal, int maxVal) - { - _iniVarName = iniVarName; - _iniSectionName = iniSectionName; - _iniFilePath = iniFilePath; - _friendlyName = friendlyName; - _description = description; - _defaultVal = defaultVal; - _minVal = minVal; - _maxVal = maxVal; - } - - virtual int AddToPanel(Panel^ panel, unsigned int left, unsigned int top, ToolTip^ tooltip) - { - Label^ label = gcnew Label(); - NumericUpDown^ numberbox = gcnew NumericUpDown(); - - label->Text = gcnew String(_friendlyName); - label->Left = left; - label->Top = top + 3; - label->Width = Col1Width; - label->AutoSize = true; - label->FlatStyle = System::Windows::Forms::FlatStyle::Flat; - - numberbox->Minimum = _minVal; - numberbox->Maximum = _maxVal; - - numberbox->Value = GetIniInt(_iniSectionName, _iniVarName, _defaultVal, _iniFilePath); - - numberbox->Left = left + Col2Left; - numberbox->Top = top; - numberbox->Width = Col2Width; - numberbox->AutoSize = true; - - Form^ RootForm = panel->FindForm(); - float ScaleWidth = 1.0f; - float ScaleHeight = 1.0f; - if (RootForm) - { - Drawing::SizeF CurrentScaleSize = RootForm->CurrentAutoScaleDimensions; - ScaleWidth = CurrentScaleSize.Width / BaseScaleSize; - ScaleHeight = CurrentScaleSize.Height / BaseScaleSize; - } - label->Scale(ScaleWidth, ScaleHeight); - numberbox->Scale(ScaleWidth, ScaleHeight); - - tooltip->SetToolTip(label, gcnew String(_description)); - tooltip->SetToolTip(numberbox, gcnew String(_description)); - - if (hasChanged == nullptr) - hasChanged = new bool(false); - ChangeHandler^ changehandler = gcnew ChangeHandler(hasChanged); - numberbox->ValueChanged += gcnew System::EventHandler(changehandler, &ChangeHandler::SetChanged); - - panel->Controls->Add(label); - panel->Controls->Add(numberbox); - mainControlHandle = numberbox->Handle; - - int ControlHeight = numberbox->Height / ScaleHeight; - return ControlHeight + ControlSpacing; - } - - virtual void SaveOption() - { - SetIniInt(_iniSectionName, _iniVarName, Convert::ToInt32(((NumericUpDown^)NumericUpDown::FromHandle(mainControlHandle))->Value), _iniFilePath); - } -}; - - -class StringOption : public ConfigOptionBase -{ -public: - LPCWSTR _defaultVal; - bool _useUtf8; - - StringOption(LPCWSTR iniVarName, LPCWSTR iniSectionName, LPCWSTR iniFilePath, LPCWSTR friendlyName, LPCWSTR description, LPCWSTR defaultVal, bool useUtf8) - { - _iniVarName = iniVarName; - _iniSectionName = iniSectionName; - _iniFilePath = iniFilePath; - _friendlyName = friendlyName; - _description = description; - _defaultVal = defaultVal; - _useUtf8 = useUtf8; - } - - virtual int AddToPanel(Panel^ panel, unsigned int left, unsigned int top, ToolTip^ tooltip) - { - Label^ label = gcnew Label(); - TextBox^ textbox = gcnew TextBox(); - - const wchar_t* stringBuf; - - label->Text = gcnew String(_friendlyName); - label->Left = left; - label->Top = top + 3; - label->Width = Col1Width; - label->AutoSize = true; - label->FlatStyle = System::Windows::Forms::FlatStyle::Flat; - - stringBuf = GetIniString(_iniSectionName, _iniVarName, _defaultVal, _iniFilePath, _useUtf8); - - textbox->Text = gcnew String(stringBuf); - textbox->Left = left + Col2Left; - textbox->Top = top; - textbox->Width = Col2Width; - textbox->AutoSize = true; - - Form^ RootForm = panel->FindForm(); - float ScaleWidth = 1.0f; - float ScaleHeight = 1.0f; - if (RootForm) - { - Drawing::SizeF CurrentScaleSize = RootForm->CurrentAutoScaleDimensions; - ScaleWidth = CurrentScaleSize.Width / BaseScaleSize; - ScaleHeight = CurrentScaleSize.Height / BaseScaleSize; - } - label->Scale(ScaleWidth, ScaleHeight); - textbox->Scale(ScaleWidth, ScaleHeight); - - // disable editing for utf8 mode because the ANSI hack used may not work correctly - //if (_useUtf8) { - // textbox->Enabled = false; - //} - - tooltip->SetToolTip(label, gcnew String(_description)); - tooltip->SetToolTip(textbox, gcnew String(_description)); - - if (hasChanged == nullptr) - hasChanged = new bool(false); - ChangeHandler^ changehandler = gcnew ChangeHandler(hasChanged); - textbox->TextChanged += gcnew System::EventHandler(changehandler, &ChangeHandler::SetChanged); - - panel->Controls->Add(label); - panel->Controls->Add(textbox); - mainControlHandle = textbox->Handle; - - int ControlHeight = textbox->Height / ScaleHeight; - return ControlHeight + ControlSpacing; - } - - virtual void SaveOption() - { - // disable saving for utf8 mode because the ANSI hack used may not work correctly - //if (_useUtf8) - // return; - - System::String^ tempSysStr; - std::wstring tempWStr; - - tempSysStr = ((TextBox^)TextBox::FromHandle(mainControlHandle))->Text; - tempWStr = msclr::interop::marshal_as(tempSysStr); - - SetIniString(_iniSectionName, _iniVarName, tempWStr.c_str(), _iniFilePath, _useUtf8); - } -}; - - -class DropdownOption : public ConfigOptionBase -{ -public: - int _defaultVal; - int _indexOffset; - std::vector _valueStrings; - - DropdownOption(LPCWSTR iniVarName, LPCWSTR iniSectionName, LPCWSTR iniFilePath, LPCWSTR friendlyName, LPCWSTR description, int defaultVal, std::vector valueStrings, int indexOffset=0) - { - _iniVarName = iniVarName; - _iniSectionName = iniSectionName; - _iniFilePath = iniFilePath; - _friendlyName = friendlyName; - _description = description; - _defaultVal = defaultVal; - _valueStrings = valueStrings; - _indexOffset = indexOffset; - } - - virtual int AddToPanel(Panel^ panel, unsigned int left, unsigned int top, ToolTip^ tooltip) - { - Label^ label = gcnew Label(); - ComboBox^ combobox = gcnew ComboBox(); - - label->Text = gcnew String(_friendlyName); - label->Left = left; - label->Top = top + 3; - label->Width = Col1Width; - label->AutoSize = true; - label->FlatStyle = System::Windows::Forms::FlatStyle::Flat; - - for (LPCWSTR& choice : _valueStrings) { - combobox->Items->Add(msclr::interop::marshal_as(choice)); - } - combobox->SelectedIndex = GetIniInt(_iniSectionName, _iniVarName, _defaultVal, _iniFilePath)-_indexOffset; - combobox->Left = left + Col2Left; - combobox->Top = top; - combobox->Width = Col2Width; - combobox->AutoSize = true; - combobox->FlatStyle = System::Windows::Forms::FlatStyle::System; - combobox->DropDownStyle = ComboBoxStyle::DropDownList; - - Form^ RootForm = panel->FindForm(); - float ScaleWidth = 1.0f; - float ScaleHeight = 1.0f; - if (RootForm) - { - Drawing::SizeF CurrentScaleSize = RootForm->CurrentAutoScaleDimensions; - ScaleWidth = CurrentScaleSize.Width / BaseScaleSize; - ScaleHeight = CurrentScaleSize.Height / BaseScaleSize; - } - label->Scale(ScaleWidth, ScaleHeight); - combobox->Scale(ScaleWidth, ScaleHeight); - - tooltip->SetToolTip(label, gcnew String(_description)); - tooltip->SetToolTip(combobox, gcnew String(_description)); - - if (hasChanged == nullptr) - hasChanged = new bool(false); - ChangeHandler^ changehandler = gcnew ChangeHandler(hasChanged); - combobox->SelectedIndexChanged += gcnew System::EventHandler(changehandler, &ChangeHandler::SetChanged); - - panel->Controls->Add(label); - panel->Controls->Add(combobox); - mainControlHandle = combobox->Handle; - - int ControlHeight = combobox->Height / ScaleHeight; - return ControlHeight + ControlSpacing; - } - - virtual void SaveOption() - { - SetIniInt(_iniSectionName, _iniVarName, Convert::ToInt32(((ComboBox^)ComboBox::FromHandle(mainControlHandle))->SelectedIndex+_indexOffset), _iniFilePath); - } -}; - - -class DropdownTextOption : public ConfigOptionBase -{ -public: - LPCWSTR _defaultVal; - std::vector _valueStrings; - bool _editable; - bool _useUtf8; - - DropdownTextOption(LPCWSTR iniVarName, LPCWSTR iniSectionName, LPCWSTR iniFilePath, LPCWSTR friendlyName, LPCWSTR description, LPCWSTR defaultVal, std::vector valueStrings, bool editable, bool useUtf8) - { - _iniVarName = iniVarName; - _iniSectionName = iniSectionName; - _iniFilePath = iniFilePath; - _friendlyName = friendlyName; - _description = description; - _defaultVal = defaultVal; - _valueStrings = valueStrings; - _editable = editable; - _useUtf8 = useUtf8; - } - - virtual int AddToPanel(Panel^ panel, unsigned int left, unsigned int top, ToolTip^ tooltip) - { - Label^ label = gcnew Label(); - ComboBox^ combobox = gcnew ComboBox(); - - const wchar_t* stringBuf; - - label->Text = gcnew String(_friendlyName); - label->Left = left; - label->Top = top + 3; - label->Width = Col1Width; - label->AutoSize = true; - label->FlatStyle = System::Windows::Forms::FlatStyle::Flat; - - for (LPCWSTR& choice : _valueStrings) { - combobox->Items->Add(msclr::interop::marshal_as(choice)); - } - - stringBuf = GetIniString(_iniSectionName, _iniVarName, _defaultVal, _iniFilePath, _useUtf8); - - combobox->Text = gcnew String(stringBuf); - combobox->Left = left + Col2Left; - combobox->Top = top; - combobox->Width = Col2Width; - combobox->AutoSize = true; - combobox->FlatStyle = System::Windows::Forms::FlatStyle::System; - - if (_editable) - combobox->DropDownStyle = ComboBoxStyle::DropDown; - else - combobox->DropDownStyle = ComboBoxStyle::DropDownList; - - Form^ RootForm = panel->FindForm(); - float ScaleWidth = 1.0f; - float ScaleHeight = 1.0f; - if (RootForm) - { - Drawing::SizeF CurrentScaleSize = RootForm->CurrentAutoScaleDimensions; - ScaleWidth = CurrentScaleSize.Width / BaseScaleSize; - ScaleHeight = CurrentScaleSize.Height / BaseScaleSize; - } - label->Scale(ScaleWidth, ScaleHeight); - combobox->Scale(ScaleWidth, ScaleHeight); - - // disable editing for utf8 mode because the ANSI hack used may not work correctly - //if (_useUtf8) { - // label->Enabled = false; - // combobox->Enabled = false; - //} - - tooltip->SetToolTip(label, gcnew String(_description)); - tooltip->SetToolTip(combobox, gcnew String(_description)); - - if (hasChanged == nullptr) - hasChanged = new bool(false); - ChangeHandler^ changehandler = gcnew ChangeHandler(hasChanged); - if (_editable) - combobox->TextChanged += gcnew System::EventHandler(changehandler, &ChangeHandler::SetChanged); - else - combobox->SelectedIndexChanged += gcnew System::EventHandler(changehandler, &ChangeHandler::SetChanged); - - panel->Controls->Add(label); - panel->Controls->Add(combobox); - mainControlHandle = combobox->Handle; - - int ControlHeight = combobox->Height / ScaleHeight; - return ControlHeight + ControlSpacing; - } - - virtual void SaveOption() - { - // disable saving for utf8 mode because the ANSI hack used may not work correctly - //if (_useUtf8) - // return; - - System::String^ tempSysStr; - std::wstring tempWStr; - - tempSysStr = ((ComboBox^)ComboBox::FromHandle(mainControlHandle))->Text; - tempWStr = msclr::interop::marshal_as(tempSysStr); - - SetIniString(_iniSectionName, _iniVarName, tempWStr.c_str(), _iniFilePath, _useUtf8); - } -}; - - -class DropdownNumberOption : public ConfigOptionBase -{ -public: - int _defaultVal; - std::vector _valueInts; - bool _editable; - - DropdownNumberOption(LPCWSTR iniVarName, LPCWSTR iniSectionName, LPCWSTR iniFilePath, LPCWSTR friendlyName, LPCWSTR description, int defaultVal, std::vector valueInts, bool editable) - { - _iniVarName = iniVarName; - _iniSectionName = iniSectionName; - _iniFilePath = iniFilePath; - _friendlyName = friendlyName; - _description = description; - _defaultVal = defaultVal; - _valueInts = valueInts; - _editable = editable; - } - - virtual int AddToPanel(Panel^ panel, unsigned int left, unsigned int top, ToolTip^ tooltip) - { - Label^ label = gcnew Label(); - ComboBox^ combobox = gcnew ComboBox(); - - System::String^ tempSysStr; - - label->Text = gcnew String(_friendlyName); - label->Left = left; - label->Top = top + 3; - label->Width = Col1Width; - label->AutoSize = true; - label->FlatStyle = System::Windows::Forms::FlatStyle::Flat; - - for (int& choice : _valueInts) { - combobox->Items->Add(Convert::ToInt32(choice).ToString()); - } - - tempSysStr = Convert::ToInt32(GetIniInt(_iniSectionName, _iniVarName, _defaultVal, _iniFilePath)).ToString(); - - combobox->Text = gcnew String(tempSysStr); - combobox->Left = left + Col2Left; - combobox->Top = top; - combobox->Width = Col2Width; - combobox->AutoSize = true; - combobox->FlatStyle = System::Windows::Forms::FlatStyle::System; - - if (_editable) - combobox->DropDownStyle = ComboBoxStyle::DropDown; - else - combobox->DropDownStyle = ComboBoxStyle::DropDownList; - - Form^ RootForm = panel->FindForm(); - float ScaleWidth = 1.0f; - float ScaleHeight = 1.0f; - if (RootForm) - { - Drawing::SizeF CurrentScaleSize = RootForm->CurrentAutoScaleDimensions; - ScaleWidth = CurrentScaleSize.Width / BaseScaleSize; - ScaleHeight = CurrentScaleSize.Height / BaseScaleSize; - } - label->Scale(ScaleWidth, ScaleHeight); - combobox->Scale(ScaleWidth, ScaleHeight); - - tooltip->SetToolTip(label, gcnew String(_description)); - tooltip->SetToolTip(combobox, gcnew String(_description)); - - ComboboxValidation^ validation = gcnew ComboboxValidation(combobox); - combobox->Leave += gcnew System::EventHandler(validation, &ComboboxValidation::CheckNumberLeave); - - if (hasChanged == nullptr) - hasChanged = new bool(false); - ChangeHandler^ changehandler = gcnew ChangeHandler(hasChanged); - if (_editable) - combobox->TextChanged += gcnew System::EventHandler(changehandler, &ChangeHandler::SetChanged); - else - combobox->SelectedIndexChanged += gcnew System::EventHandler(changehandler, &ChangeHandler::SetChanged); - - panel->Controls->Add(label); - panel->Controls->Add(combobox); - mainControlHandle = combobox->Handle; - - int ControlHeight = combobox->Height / ScaleHeight; - return ControlHeight + ControlSpacing; - } - - virtual void SaveOption() - { - System::String^ tempSysStr; - std::wstring tempWStr; - - tempSysStr = ((ComboBox^)ComboBox::FromHandle(mainControlHandle))->Text; - tempWStr = msclr::interop::marshal_as(tempSysStr); - - SetIniString(_iniSectionName, _iniVarName, tempWStr.c_str(), _iniFilePath, false); - } -}; - - -enum ResolutionOptionOpts -{ - RESOPT_INCLUDE_MATCH_WINDOW = 1, - RESOPT_INCLUDE_MATCH_SCREEN = 2 -}; - -class ResolutionOption : public ConfigOptionBase -{ -public: - LPCWSTR _iniVarName2; - resolution _defaultVal; - std::vector _valueResolutions; - bool _editable; - ResolutionOptionOpts _opts; - - ResolutionOption(LPCWSTR iniVarName, LPCWSTR iniVarName2, LPCWSTR iniSectionName, LPCWSTR iniFilePath, LPCWSTR friendlyName, LPCWSTR description, resolution defaultVal, std::vector valueResolutions, bool editable, ResolutionOptionOpts opts) - { - _iniVarName = iniVarName; - _iniVarName2 = iniVarName2; - _iniSectionName = iniSectionName; - _iniFilePath = iniFilePath; - _friendlyName = friendlyName; - _description = description; - _defaultVal = defaultVal; - _valueResolutions = valueResolutions; - _editable = editable; - _opts = opts; - } - - virtual int AddToPanel(Panel^ panel, unsigned int left, unsigned int top, ToolTip^ tooltip) - { - Label^ label = gcnew Label(); - ComboBox^ combobox = gcnew ComboBox(); - - System::String^ tempSysStr; - - label->Text = gcnew String(_friendlyName); - label->Left = left; - label->Top = top + 3; - label->Width = Col1Width; - label->AutoSize = true; - label->FlatStyle = System::Windows::Forms::FlatStyle::Flat; - - if (_opts & RESOPT_INCLUDE_MATCH_WINDOW) - combobox->Items->Add(RESOPT_MATCH_WINDOW_TEXT); - else if (_opts & RESOPT_INCLUDE_MATCH_SCREEN) - combobox->Items->Add(RESOPT_MATCH_SCREEN_TEXT); - - for (resolution& choice : _valueResolutions) { - tempSysStr = Convert::ToInt32(choice.width).ToString() + L"x" + Convert::ToInt32(choice.height).ToString(); - combobox->Items->Add(tempSysStr); - } - - int width = GetIniInt(_iniSectionName, _iniVarName, -39, _iniFilePath); - int height = GetIniInt(_iniSectionName, _iniVarName2, -39, _iniFilePath); - if (width == -39 || height == -39) { - if (_defaultVal.width == -1 || _defaultVal.height == -1) - width = -1; - else - { - tempSysStr = Convert::ToInt32(_defaultVal.width).ToString() + L"x" + Convert::ToInt32(_defaultVal.height).ToString(); - combobox->Text = tempSysStr; - } - } - if (width == -1 || height == -1) { // -1 -> Match window/screen - if (_opts & RESOPT_INCLUDE_MATCH_WINDOW) - combobox->Text = RESOPT_MATCH_WINDOW_TEXT; - else if (_opts & RESOPT_INCLUDE_MATCH_SCREEN) - combobox->Text = RESOPT_MATCH_SCREEN_TEXT; - } - else { - tempSysStr = Convert::ToInt32(width).ToString() + L"x" + Convert::ToInt32(height).ToString(); - combobox->Text = tempSysStr; - } - - combobox->Left = left + Col2Left; - combobox->Top = top; - combobox->Width = Col2Width; - combobox->AutoSize = true; - combobox->FlatStyle = System::Windows::Forms::FlatStyle::System; - - if (_editable) - combobox->DropDownStyle = ComboBoxStyle::DropDown; - else - combobox->DropDownStyle = ComboBoxStyle::DropDownList; - - Form^ RootForm = panel->FindForm(); - float ScaleWidth = 1.0f; - float ScaleHeight = 1.0f; - if (RootForm) - { - Drawing::SizeF CurrentScaleSize = RootForm->CurrentAutoScaleDimensions; - ScaleWidth = CurrentScaleSize.Width / BaseScaleSize; - ScaleHeight = CurrentScaleSize.Height / BaseScaleSize; - } - label->Scale(ScaleWidth, ScaleHeight); - combobox->Scale(ScaleWidth, ScaleHeight); - - tooltip->SetToolTip(label, gcnew String(_description)); - tooltip->SetToolTip(combobox, gcnew String(_description)); - - if (hasChanged == nullptr) - hasChanged = new bool(false); - ChangeHandler^ changehandler = gcnew ChangeHandler(hasChanged); - if (_editable) - combobox->TextChanged += gcnew System::EventHandler(changehandler, &ChangeHandler::SetChanged); - else - combobox->SelectedIndexChanged += gcnew System::EventHandler(changehandler, &ChangeHandler::SetChanged); - - ComboboxValidation^ validation = gcnew ComboboxValidation(combobox); - combobox->Leave += gcnew System::EventHandler(validation, &ComboboxValidation::CheckResolutionLeave); - - panel->Controls->Add(label); - panel->Controls->Add(combobox); - mainControlHandle = combobox->Handle; - - int ControlHeight = combobox->Height / ScaleHeight; - return ControlHeight + ControlSpacing; - } - - virtual void SaveOption() - { - System::String^ tempSysStr; - std::wstring tempWStr; - cli::array^ resolutionArray; - - tempSysStr = ((ComboBox^)ComboBox::FromHandle(mainControlHandle))->Text; - - // Match window/screen -> -1x-1 - if (tempSysStr == RESOPT_MATCH_WINDOW_TEXT || tempSysStr == RESOPT_MATCH_SCREEN_TEXT) - tempSysStr = "-1x-1"; - - resolutionArray = tempSysStr->Split('x'); - - tempSysStr = resolutionArray[0]; - tempWStr = msclr::interop::marshal_as(tempSysStr); - SetIniString(_iniSectionName, _iniVarName, tempWStr.c_str(), _iniFilePath, false); - - tempSysStr = resolutionArray[1]; - tempWStr = msclr::interop::marshal_as(tempSysStr); - SetIniString(_iniSectionName, _iniVarName2, tempWStr.c_str(), _iniFilePath, false); - - } -}; - - -class ButtonOption : public ConfigOptionBase -{ -public: - void(*_func)(); - - ButtonOption(LPCWSTR friendlyName, LPCWSTR description, void(*func)()) - { - _friendlyName = friendlyName; - _description = description; - _func = func; - } - - virtual int AddToPanel(Panel^ panel, unsigned int left, unsigned int top, ToolTip^ tooltip) - { - Button^ button = gcnew Button(); - - button->Text = gcnew String(_friendlyName); - button->Left = left; - button->Top = top; - button->AutoSize = true; - button->FlatStyle = System::Windows::Forms::FlatStyle::Flat; - - Form^ RootForm = panel->FindForm(); - float ScaleWidth = 1.0f; - float ScaleHeight = 1.0f; - if (RootForm) - { - Drawing::SizeF CurrentScaleSize = RootForm->CurrentAutoScaleDimensions; - ScaleWidth = CurrentScaleSize.Width / BaseScaleSize; - ScaleHeight = CurrentScaleSize.Height / BaseScaleSize; - } - button->Scale(ScaleWidth, ScaleHeight); - - tooltip->SetToolTip(button, gcnew String(_description)); - - CustomFuncHandler^ funchandler = gcnew CustomFuncHandler(_func); - button->Click += gcnew System::EventHandler(funchandler, &CustomFuncHandler::RunFunc); - - panel->Controls->Add(button); - - int ControlHeight = button->Height / ScaleHeight; - return ControlHeight + ControlSpacing; - } -}; - - -class PluginOption : public ConfigOptionBase -{ -public: - bool _defaultVal; - std::vector _configopts; - - PluginOption(LPCWSTR iniVarName, LPCWSTR iniSectionName, LPCWSTR iniFilePath, LPCWSTR friendlyName, LPCWSTR description, bool defaultVal, std::vector configopts) - { - _iniVarName = iniVarName; - _iniSectionName = iniSectionName; - _iniFilePath = iniFilePath; - _friendlyName = friendlyName; - _description = description; - _defaultVal = defaultVal; - _configopts = configopts; - } - - virtual int AddToPanel(Panel^ panel, unsigned int left, unsigned int top, ToolTip^ tooltip) - { - CheckBox^ cb = gcnew CheckBox(); - Button^ button = gcnew Button(); - - cb->Text = gcnew String(_friendlyName); - cb->Checked = GetIniBool(_iniSectionName, _iniVarName, _defaultVal, _iniFilePath); - cb->Left = left + 2; - cb->Top = top + 3; - cb->AutoSize = true; - cb->FlatStyle = System::Windows::Forms::FlatStyle::Flat; - - // hack to ensure high contrast - cb->BackColor = System::Drawing::Color::FromArgb(0, 127, 127, 127); - - button->Text = L"Config"; - button->Left = left + ConfigBtnLeft; - button->Top = top; - button->AutoSize = true; - button->FlatStyle = System::Windows::Forms::FlatStyle::Flat; - - Form^ RootForm = panel->FindForm(); - float ScaleWidth = 1.0f; - float ScaleHeight = 1.0f; - if (RootForm) - { - Drawing::SizeF CurrentScaleSize = RootForm->CurrentAutoScaleDimensions; - ScaleWidth = CurrentScaleSize.Width / BaseScaleSize; - ScaleHeight = CurrentScaleSize.Height / BaseScaleSize; - } - cb->Scale(ScaleWidth, ScaleHeight); - button->Scale(ScaleWidth, ScaleHeight); - - tooltip->SetToolTip(cb, gcnew String(_description)); - - if (hasChanged == nullptr) - hasChanged = new bool(false); - ChangeHandler^ changehandler = gcnew ChangeHandler(hasChanged); - cb->CheckedChanged += gcnew System::EventHandler(changehandler, &ChangeHandler::SetChanged); - - panel->Controls->Add(cb); - mainControlHandle = cb->Handle; - - if (_configopts.size() > 0) - { - ToolTip^ paneltooltip = gcnew ToolTip(); - Panel^ configPanel = MakePanel((Col2Left + Col2Width + 76), 250, _configopts, paneltooltip, hasChanged); - configPanel->Scale(ScaleWidth, ScaleHeight); - if (RootForm) - configPanel->Font = RootForm->Font; - PluginConfigHandler^ confighandler = gcnew PluginConfigHandler(configPanel, gcnew String(_friendlyName) + " Options", ScaleHeight); - button->Click += gcnew System::EventHandler(confighandler, &PluginConfigHandler::OpenForm); - - panel->Controls->Add(button); - } - - int ControlHeight = button->Height / ScaleHeight; - return ControlHeight + ControlSpacing; - } - - virtual void SaveOption() - { - SetIniBool(_iniSectionName, _iniVarName, ((CheckBox^)CheckBox::FromHandle(mainControlHandle))->Checked, _iniFilePath, false); - - for (ConfigOptionBase* opt : _configopts) - { - opt->SaveOption(); - } - } -}; - - -Panel^ MakePanel(int width, int height, std::vector &cfg, ToolTip^ tooltip, bool* hasChanged) -{ - Panel^ outpanel = gcnew Panel(); - outpanel->Width = width; - outpanel->Height = height; - outpanel->AutoScroll = true; - - Form^ RootForm = outpanel->FindForm(); - float ScaleWidth = 1.0f; - float ScaleHeight = 1.0f; - if (RootForm) - { - Drawing::SizeF CurrentScaleSize = RootForm->CurrentAutoScaleDimensions; - ScaleWidth = CurrentScaleSize.Width / BaseScaleSize; - ScaleHeight = CurrentScaleSize.Height / BaseScaleSize; - } - - int curX = 12; - int curY = 3; - - for (int i = 0; i < cfg.size(); i++) - { - if (typeid(*cfg[i]).hash_code() == typeid(OptionMetaGroupEnd).hash_code()) - continue; - - if (typeid(*cfg[i]).hash_code() == typeid(OptionMetaGroupStart).hash_code()) - { - OptionMetaGroupStart* groupData = (OptionMetaGroupStart*)(cfg[i]); - GroupBox^ groupbox = gcnew GroupBox(); - groupbox->Width = width - (ScaleWidth * 28); - groupbox->Height = ScaleHeight * (groupData->_height); - groupbox->Left = ScaleWidth * 4; - groupbox->Top = ScaleHeight * curY; - groupbox->Text = gcnew String(groupData->_friendlyName); - groupbox->ForeColor = Drawing::Color::White; - - // find the end of this group by simple iteration keeping track of indent level - int level = 1; - int endidx; - for (endidx = i + 1; endidx < cfg.size(); endidx++) - { - if (typeid(*cfg[endidx]).hash_code() == typeid(OptionMetaGroupStart).hash_code()) - level++; - if (typeid(*cfg[endidx]).hash_code() == typeid(OptionMetaGroupEnd).hash_code()) - level--; - - if (level == 0) - break; - } - - Panel^ groupPanel = MakePanel(groupbox->Width - (ScaleWidth * 12), groupbox->Height - (ScaleHeight * 20), std::vector(&(cfg[i + 1]), &(cfg[endidx])), tooltip, hasChanged); - groupPanel->Left = ScaleWidth * 2; - groupPanel->Top = ScaleHeight * 14; - - groupbox->Controls->Add(groupPanel); - outpanel->Controls->Add(groupbox); - - i = endidx; - curY += groupData->_height; - } - else - { - cfg[i]->hasChanged = hasChanged; - curY += cfg[i]->AddToPanel(outpanel, curX, curY, tooltip); - } - } - - return outpanel; -} - +#pragma once +#pragma warning(push) +#pragma warning(disable: 4947) + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +// Windows Header Files +#include +#include +#include +#include + +#include + +#include "PluginConfigApi.h" +#include "IniReader.h" + +using namespace System; +using namespace System::Windows::Forms; + +float BaseScaleSize = 96; +int Col1Width = 110; +int Col2Left = 140; +int Col2Width = 90; +int ConfigBtnLeft = 120; +int ControlSpacing = 6; + + + +// declare this early (actual definitions below) +class ConfigOptionBase; +Panel^ MakePanel(int width, int height, std::vector &cfg, ToolTip^ tooltip, bool* hasChanged); + + +#define RESOPT_MATCH_WINDOW_TEXT "Match Window" +#define RESOPT_MATCH_SCREEN_TEXT "Match Screen" + +ref class ComboboxValidation +{ +public: + ComboBox^ cb; + + ComboboxValidation(ComboBox^ combobox) + { + cb = combobox; + } + + System::Void CheckNumberLeave(System::Object^ sender, System::EventArgs^ e) + { + System::String^ text = cb->Text; + + cli::array^ digitsarray = gcnew cli::array{ L'0', L'1', L'2', L'3', L'4', L'5', L'6', L'7', L'8', L'9' }; + System::Collections::Generic::List^ digitslist = gcnew System::Collections::Generic::List(digitsarray); + + if (text->Length <= 0) + return; + + while (text->Length > 0 && text[0] != L'-' && !digitslist->Contains(text[0])) + { + text = text->Remove(0, 1); + } + + if (text->Length <= 1) // can discard up to 1 now because first digit is known good + { + cb->Text = text; + return; + } + + for (int i = 1; i < text->Length; i++) + { + if (!digitslist->Contains(text[i])) + { + text = text->Remove(i, 1); + i--; // negate the upcoming ++ + } + } + + cb->Text = text; + } + + System::Void CheckResolutionLeave(System::Object^ sender, System::EventArgs^ e) + { + System::String^ text = cb->Text; + + if (text == RESOPT_MATCH_WINDOW_TEXT || text == RESOPT_MATCH_SCREEN_TEXT) + return; + + cli::array^ digitsarray = gcnew cli::array{ L'0', L'1', L'2', L'3', L'4', L'5', L'6', L'7', L'8', L'9' }; + System::Collections::Generic::List^ digitslist = gcnew System::Collections::Generic::List(digitsarray); + + int numX = 0; + + while (text->Length > 0 && text[0] != L'x' && !digitslist->Contains(text[0])) + { + text = text->Remove(0, 1); + } + + if (text->Length <= 0) + { + cb->Text = "x"; + return; + } + + if (text[0] == L'x') + { + numX++; + } + + if (text->Length <= 1) // can discard up to 1 now because first digit is known good + { + if (numX == 0) // if that digit wasn't an x though, add one + { + text += "x"; + } + cb->Text = text; + return; + } + + for (int i = 1; i < text->Length; i++) + { + if (!digitslist->Contains(text[i]) && !(numX == 0 && text[i] == L'x' && ++numX)) + { + text = text->Remove(i, 1); + i--; // negate the upcoming ++ + } + } + + if (numX == 0) + { + text += "x"; + } + + cb->Text = text; + } + +}; + +ref class PluginConfigHandler +{ +public: + Form^ form; + + PluginConfigHandler(Panel^ optspanel, String^ title, float btnScaleSize) + { + form = gcnew Form(); + + form->Text = title; + + form->FormBorderStyle = FormBorderStyle::FixedDialog; + form->StartPosition = FormStartPosition::CenterScreen; + form->MaximizeBox = false; + form->MinimizeBox = false; + form->ShowInTaskbar = false; + form->ShowIcon = false; + //form->TopMost = true; + + form->BackColor = Drawing::Color::FromArgb(64, 64, 64); + form->ForeColor = Drawing::Color::White; + + form->Font = optspanel->Font; + + optspanel->Left = 0; + optspanel->Top = 0; + + Button^ OkBtn = gcnew Button(); + OkBtn->Scale(btnScaleSize); + OkBtn->Text = L"OK"; + OkBtn->Left = 4; + OkBtn->Top = optspanel->Bottom + 4; + OkBtn->AutoSize = true; + OkBtn->FlatStyle = System::Windows::Forms::FlatStyle::Flat; + + form->ClientSize = Drawing::Size(optspanel->Width, OkBtn->Bottom + 4); + + form->Controls->Add(optspanel); + form->Controls->Add(OkBtn); + form->AcceptButton = OkBtn; + + form->FormClosing += gcnew System::Windows::Forms::FormClosingEventHandler(this, &PluginConfigHandler::FormClosing); + OkBtn->Click += gcnew EventHandler(this, &PluginConfigHandler::OkClick); + } + + System::Void OpenForm(System::Object^ sender, System::EventArgs^ e) + { + // ShowDialog seems to prevent disposal by copying the panel... + // which would be fine if I didn't rely on using the control handles + // MessageBox::Show(form->Controls[0]->Handle.ToString()); + + //Application::OpenForms[0]->Enabled = false; + form->Owner = Application::OpenForms[0]; + if (form->Visible) + form->Hide(); + form->Show(); + } + + System::Void FormClosing(System::Object^ sender, FormClosingEventArgs^ e) + { + if (e->CloseReason == CloseReason::UserClosing) + { + form->Hide(); + //Application::OpenForms[0]->Enabled = true; + e->Cancel = true; + } + } + + System::Void OkClick(System::Object^ sender, System::EventArgs^ e) + { + form->Close(); + } +}; + +ref class ChangeHandler +{ +public: + bool* changebool; + + ChangeHandler(bool* onchangebool) + { + changebool = onchangebool; + } + + System::Void SetChanged(System::Object^ sender, System::EventArgs^ e) + { + *changebool = true; + } +}; + +ref class CustomFuncHandler +{ +public: + void(*_func)(); + + CustomFuncHandler(void(*func)()) + { + _func = func; + } + + System::Void RunFunc(System::Object^ sender, System::EventArgs^ e) + { + _func(); + } +}; + + +class ConfigOptionBase +{ +public: + LPCWSTR _iniVarName; + LPCWSTR _iniSectionName; + LPCWSTR _iniFilePath; + + LPCWSTR _friendlyName; + LPCWSTR _description; + + System::IntPtr mainControlHandle; + bool* hasChanged; + + virtual int AddToPanel(Panel^ panel, unsigned int left, unsigned int top, ToolTip^ tooltip) + { + return 0; + } + + virtual void SaveOption() + { + return; + } +}; + + +class OptionMetaGroupStart : public ConfigOptionBase +{ +public: + int _height; + + OptionMetaGroupStart(LPCWSTR friendlyName, int height) + { + _friendlyName = friendlyName; + _height = height; + } +}; +class OptionMetaGroupEnd : public ConfigOptionBase +{ +public: + OptionMetaGroupEnd() + { + } +}; + +class OptionMetaSectionLabel : public ConfigOptionBase +{ +public: + OptionMetaSectionLabel(LPCWSTR friendlyName) + { + _friendlyName = friendlyName; + } + + virtual int AddToPanel(Panel^ panel, unsigned int left, unsigned int top, ToolTip^ tooltip) + { + Label^ lab = gcnew Label(); + + lab->Text = gcnew String(_friendlyName); + lab->Left = left + 2; + lab->Top = top; + lab->Font = gcnew System::Drawing::Font(lab->Font->Name, 12.0f, System::Drawing::FontStyle::Bold); + lab->AutoSize = true; + + Form^ RootForm = panel->FindForm(); + float ScaleWidth = 1.0f; + float ScaleHeight = 1.0f; + if (RootForm) + { + Drawing::SizeF CurrentScaleSize = RootForm->CurrentAutoScaleDimensions; + ScaleWidth = CurrentScaleSize.Width / BaseScaleSize; + ScaleHeight = CurrentScaleSize.Height / BaseScaleSize; + } + lab->Scale(ScaleWidth, ScaleHeight); + + panel->Controls->Add(lab); + mainControlHandle = lab->Handle; + + int ControlHeight = lab->Font->Height / ScaleHeight; + return ControlHeight + ControlSpacing; + } +}; + +class OptionMetaSpacer : public ConfigOptionBase +{ +public: + int _height; + + OptionMetaSpacer(int height) + { + _height = height; + } + + virtual int AddToPanel(Panel^ panel, unsigned int left, unsigned int top, ToolTip^ tooltip) + { + return _height; + } +}; + +class OptionMetaSeparator : public ConfigOptionBase +{ +public: + OptionMetaSeparator() + { + } + + virtual int AddToPanel(Panel^ panel, unsigned int left, unsigned int top, ToolTip^ tooltip) + { + Label^ lab = gcnew Label(); + + lab->Text = "_____________________________________"; + lab->Left = left + 2; + lab->Top = top; + lab->AutoSize = true; + + Form^ RootForm = panel->FindForm(); + float ScaleWidth = 1.0f; + float ScaleHeight = 1.0f; + if (RootForm) + { + Drawing::SizeF CurrentScaleSize = RootForm->CurrentAutoScaleDimensions; + ScaleWidth = CurrentScaleSize.Width / BaseScaleSize; + ScaleHeight = CurrentScaleSize.Height / BaseScaleSize; + } + lab->Scale(ScaleWidth, ScaleHeight); + + panel->Controls->Add(lab); + mainControlHandle = lab->Handle; + + int ControlHeight = lab->Font->Height / ScaleHeight; + return ControlHeight + ControlSpacing; + } +}; + + +class BooleanOption : public ConfigOptionBase +{ +public: + bool _defaultVal; + bool _saveAsString; + + BooleanOption(LPCWSTR iniVarName, LPCWSTR iniSectionName, LPCWSTR iniFilePath, LPCWSTR friendlyName, LPCWSTR description, bool defaultVal, bool saveAsString) + { + _iniVarName = iniVarName; + _iniSectionName = iniSectionName; + _iniFilePath = iniFilePath; + _friendlyName = friendlyName; + _description = description; + _defaultVal = defaultVal; + _saveAsString = saveAsString; + } + + virtual int AddToPanel(Panel^ panel, unsigned int left, unsigned int top, ToolTip^ tooltip) + { + CheckBox^ cb = gcnew CheckBox(); + + cb->Text = gcnew String(_friendlyName); + cb->Checked = GetIniBool(_iniSectionName, _iniVarName, _defaultVal, _iniFilePath); + cb->Left = left + 2; + cb->Top = top; + cb->AutoSize = true; + cb->FlatStyle = System::Windows::Forms::FlatStyle::Flat; + + // hack to ensure high contrast + cb->BackColor = System::Drawing::Color::FromArgb(0, 127, 127, 127); + + Form^ RootForm = panel->FindForm(); + float ScaleWidth = 1.0f; + float ScaleHeight = 1.0f; + if (RootForm) + { + Drawing::SizeF CurrentScaleSize = RootForm->CurrentAutoScaleDimensions; + ScaleWidth = CurrentScaleSize.Width / BaseScaleSize; + ScaleHeight = CurrentScaleSize.Height / BaseScaleSize; + } + cb->Scale(ScaleWidth, ScaleHeight); + + tooltip->SetToolTip(cb, gcnew String(_description)); + + if (hasChanged == nullptr) + hasChanged = new bool(false); + ChangeHandler^ changehandler = gcnew ChangeHandler(hasChanged); + cb->CheckedChanged += gcnew System::EventHandler(changehandler, &ChangeHandler::SetChanged); + + panel->Controls->Add(cb); + mainControlHandle = cb->Handle; + + int ControlHeight = cb->Font->Height / ScaleHeight; + return ControlHeight + ControlSpacing; + } + + virtual void SaveOption() + { + SetIniBool(_iniSectionName, _iniVarName, ((CheckBox^)CheckBox::FromHandle(mainControlHandle))->Checked, _iniFilePath, _saveAsString); + } +}; + + +class NumericOption : public ConfigOptionBase +{ +public: + int _defaultVal; + int _minVal; + int _maxVal; + + NumericOption(LPCWSTR iniVarName, LPCWSTR iniSectionName, LPCWSTR iniFilePath, LPCWSTR friendlyName, LPCWSTR description, int defaultVal, int minVal, int maxVal) + { + _iniVarName = iniVarName; + _iniSectionName = iniSectionName; + _iniFilePath = iniFilePath; + _friendlyName = friendlyName; + _description = description; + _defaultVal = defaultVal; + _minVal = minVal; + _maxVal = maxVal; + } + + virtual int AddToPanel(Panel^ panel, unsigned int left, unsigned int top, ToolTip^ tooltip) + { + Label^ label = gcnew Label(); + NumericUpDown^ numberbox = gcnew NumericUpDown(); + + label->Text = gcnew String(_friendlyName); + label->Left = left; + label->Top = top + 3; + label->Width = Col1Width; + label->AutoSize = true; + label->FlatStyle = System::Windows::Forms::FlatStyle::Flat; + + numberbox->Minimum = _minVal; + numberbox->Maximum = _maxVal; + + numberbox->Value = GetIniInt(_iniSectionName, _iniVarName, _defaultVal, _iniFilePath); + + numberbox->Left = left + Col2Left; + numberbox->Top = top; + numberbox->Width = Col2Width; + numberbox->AutoSize = true; + + Form^ RootForm = panel->FindForm(); + float ScaleWidth = 1.0f; + float ScaleHeight = 1.0f; + if (RootForm) + { + Drawing::SizeF CurrentScaleSize = RootForm->CurrentAutoScaleDimensions; + ScaleWidth = CurrentScaleSize.Width / BaseScaleSize; + ScaleHeight = CurrentScaleSize.Height / BaseScaleSize; + } + label->Scale(ScaleWidth, ScaleHeight); + numberbox->Scale(ScaleWidth, ScaleHeight); + + tooltip->SetToolTip(label, gcnew String(_description)); + tooltip->SetToolTip(numberbox, gcnew String(_description)); + + if (hasChanged == nullptr) + hasChanged = new bool(false); + ChangeHandler^ changehandler = gcnew ChangeHandler(hasChanged); + numberbox->ValueChanged += gcnew System::EventHandler(changehandler, &ChangeHandler::SetChanged); + + panel->Controls->Add(label); + panel->Controls->Add(numberbox); + mainControlHandle = numberbox->Handle; + + int ControlHeight = numberbox->Height / ScaleHeight; + return ControlHeight + ControlSpacing; + } + + virtual void SaveOption() + { + SetIniInt(_iniSectionName, _iniVarName, Convert::ToInt32(((NumericUpDown^)NumericUpDown::FromHandle(mainControlHandle))->Value), _iniFilePath); + } +}; + + +class StringOption : public ConfigOptionBase +{ +public: + LPCWSTR _defaultVal; + bool _useUtf8; + + StringOption(LPCWSTR iniVarName, LPCWSTR iniSectionName, LPCWSTR iniFilePath, LPCWSTR friendlyName, LPCWSTR description, LPCWSTR defaultVal, bool useUtf8) + { + _iniVarName = iniVarName; + _iniSectionName = iniSectionName; + _iniFilePath = iniFilePath; + _friendlyName = friendlyName; + _description = description; + _defaultVal = defaultVal; + _useUtf8 = useUtf8; + } + + virtual int AddToPanel(Panel^ panel, unsigned int left, unsigned int top, ToolTip^ tooltip) + { + Label^ label = gcnew Label(); + TextBox^ textbox = gcnew TextBox(); + + const wchar_t* stringBuf; + + label->Text = gcnew String(_friendlyName); + label->Left = left; + label->Top = top + 3; + label->Width = Col1Width; + label->AutoSize = true; + label->FlatStyle = System::Windows::Forms::FlatStyle::Flat; + + stringBuf = GetIniString(_iniSectionName, _iniVarName, _defaultVal, _iniFilePath, _useUtf8); + + textbox->Text = gcnew String(stringBuf); + textbox->Left = left + Col2Left; + textbox->Top = top; + textbox->Width = Col2Width; + textbox->AutoSize = true; + + Form^ RootForm = panel->FindForm(); + float ScaleWidth = 1.0f; + float ScaleHeight = 1.0f; + if (RootForm) + { + Drawing::SizeF CurrentScaleSize = RootForm->CurrentAutoScaleDimensions; + ScaleWidth = CurrentScaleSize.Width / BaseScaleSize; + ScaleHeight = CurrentScaleSize.Height / BaseScaleSize; + } + label->Scale(ScaleWidth, ScaleHeight); + textbox->Scale(ScaleWidth, ScaleHeight); + + // disable editing for utf8 mode because the ANSI hack used may not work correctly + //if (_useUtf8) { + // textbox->Enabled = false; + //} + + tooltip->SetToolTip(label, gcnew String(_description)); + tooltip->SetToolTip(textbox, gcnew String(_description)); + + if (hasChanged == nullptr) + hasChanged = new bool(false); + ChangeHandler^ changehandler = gcnew ChangeHandler(hasChanged); + textbox->TextChanged += gcnew System::EventHandler(changehandler, &ChangeHandler::SetChanged); + + panel->Controls->Add(label); + panel->Controls->Add(textbox); + mainControlHandle = textbox->Handle; + + int ControlHeight = textbox->Height / ScaleHeight; + return ControlHeight + ControlSpacing; + } + + virtual void SaveOption() + { + // disable saving for utf8 mode because the ANSI hack used may not work correctly + //if (_useUtf8) + // return; + + System::String^ tempSysStr; + std::wstring tempWStr; + + tempSysStr = ((TextBox^)TextBox::FromHandle(mainControlHandle))->Text; + tempWStr = msclr::interop::marshal_as(tempSysStr); + + SetIniString(_iniSectionName, _iniVarName, tempWStr.c_str(), _iniFilePath, _useUtf8); + } +}; + + +class DropdownOption : public ConfigOptionBase +{ +public: + int _defaultVal; + int _indexOffset; + std::vector _valueStrings; + + DropdownOption(LPCWSTR iniVarName, LPCWSTR iniSectionName, LPCWSTR iniFilePath, LPCWSTR friendlyName, LPCWSTR description, int defaultVal, std::vector valueStrings, int indexOffset=0) + { + _iniVarName = iniVarName; + _iniSectionName = iniSectionName; + _iniFilePath = iniFilePath; + _friendlyName = friendlyName; + _description = description; + _defaultVal = defaultVal; + _valueStrings = valueStrings; + _indexOffset = indexOffset; + } + + virtual int AddToPanel(Panel^ panel, unsigned int left, unsigned int top, ToolTip^ tooltip) + { + Label^ label = gcnew Label(); + ComboBox^ combobox = gcnew ComboBox(); + + label->Text = gcnew String(_friendlyName); + label->Left = left; + label->Top = top + 3; + label->Width = Col1Width; + label->AutoSize = true; + label->FlatStyle = System::Windows::Forms::FlatStyle::Flat; + + for (LPCWSTR& choice : _valueStrings) { + combobox->Items->Add(msclr::interop::marshal_as(choice)); + } + combobox->SelectedIndex = GetIniInt(_iniSectionName, _iniVarName, _defaultVal, _iniFilePath)-_indexOffset; + combobox->Left = left + Col2Left; + combobox->Top = top; + combobox->Width = Col2Width; + combobox->AutoSize = true; + combobox->FlatStyle = System::Windows::Forms::FlatStyle::System; + combobox->DropDownStyle = ComboBoxStyle::DropDownList; + + Form^ RootForm = panel->FindForm(); + float ScaleWidth = 1.0f; + float ScaleHeight = 1.0f; + if (RootForm) + { + Drawing::SizeF CurrentScaleSize = RootForm->CurrentAutoScaleDimensions; + ScaleWidth = CurrentScaleSize.Width / BaseScaleSize; + ScaleHeight = CurrentScaleSize.Height / BaseScaleSize; + } + label->Scale(ScaleWidth, ScaleHeight); + combobox->Scale(ScaleWidth, ScaleHeight); + + tooltip->SetToolTip(label, gcnew String(_description)); + tooltip->SetToolTip(combobox, gcnew String(_description)); + + if (hasChanged == nullptr) + hasChanged = new bool(false); + ChangeHandler^ changehandler = gcnew ChangeHandler(hasChanged); + combobox->SelectedIndexChanged += gcnew System::EventHandler(changehandler, &ChangeHandler::SetChanged); + + panel->Controls->Add(label); + panel->Controls->Add(combobox); + mainControlHandle = combobox->Handle; + + int ControlHeight = combobox->Height / ScaleHeight; + return ControlHeight + ControlSpacing; + } + + virtual void SaveOption() + { + SetIniInt(_iniSectionName, _iniVarName, Convert::ToInt32(((ComboBox^)ComboBox::FromHandle(mainControlHandle))->SelectedIndex+_indexOffset), _iniFilePath); + } +}; + + +class DropdownTextOption : public ConfigOptionBase +{ +public: + LPCWSTR _defaultVal; + std::vector _valueStrings; + bool _editable; + bool _useUtf8; + + DropdownTextOption(LPCWSTR iniVarName, LPCWSTR iniSectionName, LPCWSTR iniFilePath, LPCWSTR friendlyName, LPCWSTR description, LPCWSTR defaultVal, std::vector valueStrings, bool editable, bool useUtf8) + { + _iniVarName = iniVarName; + _iniSectionName = iniSectionName; + _iniFilePath = iniFilePath; + _friendlyName = friendlyName; + _description = description; + _defaultVal = defaultVal; + _valueStrings = valueStrings; + _editable = editable; + _useUtf8 = useUtf8; + } + + virtual int AddToPanel(Panel^ panel, unsigned int left, unsigned int top, ToolTip^ tooltip) + { + Label^ label = gcnew Label(); + ComboBox^ combobox = gcnew ComboBox(); + + const wchar_t* stringBuf; + + label->Text = gcnew String(_friendlyName); + label->Left = left; + label->Top = top + 3; + label->Width = Col1Width; + label->AutoSize = true; + label->FlatStyle = System::Windows::Forms::FlatStyle::Flat; + + for (LPCWSTR& choice : _valueStrings) { + combobox->Items->Add(msclr::interop::marshal_as(choice)); + } + + stringBuf = GetIniString(_iniSectionName, _iniVarName, _defaultVal, _iniFilePath, _useUtf8); + + combobox->Text = gcnew String(stringBuf); + combobox->Left = left + Col2Left; + combobox->Top = top; + combobox->Width = Col2Width; + combobox->AutoSize = true; + combobox->FlatStyle = System::Windows::Forms::FlatStyle::System; + + if (_editable) + combobox->DropDownStyle = ComboBoxStyle::DropDown; + else + combobox->DropDownStyle = ComboBoxStyle::DropDownList; + + Form^ RootForm = panel->FindForm(); + float ScaleWidth = 1.0f; + float ScaleHeight = 1.0f; + if (RootForm) + { + Drawing::SizeF CurrentScaleSize = RootForm->CurrentAutoScaleDimensions; + ScaleWidth = CurrentScaleSize.Width / BaseScaleSize; + ScaleHeight = CurrentScaleSize.Height / BaseScaleSize; + } + label->Scale(ScaleWidth, ScaleHeight); + combobox->Scale(ScaleWidth, ScaleHeight); + + // disable editing for utf8 mode because the ANSI hack used may not work correctly + //if (_useUtf8) { + // label->Enabled = false; + // combobox->Enabled = false; + //} + + tooltip->SetToolTip(label, gcnew String(_description)); + tooltip->SetToolTip(combobox, gcnew String(_description)); + + if (hasChanged == nullptr) + hasChanged = new bool(false); + ChangeHandler^ changehandler = gcnew ChangeHandler(hasChanged); + if (_editable) + combobox->TextChanged += gcnew System::EventHandler(changehandler, &ChangeHandler::SetChanged); + else + combobox->SelectedIndexChanged += gcnew System::EventHandler(changehandler, &ChangeHandler::SetChanged); + + panel->Controls->Add(label); + panel->Controls->Add(combobox); + mainControlHandle = combobox->Handle; + + int ControlHeight = combobox->Height / ScaleHeight; + return ControlHeight + ControlSpacing; + } + + virtual void SaveOption() + { + // disable saving for utf8 mode because the ANSI hack used may not work correctly + //if (_useUtf8) + // return; + + System::String^ tempSysStr; + std::wstring tempWStr; + + tempSysStr = ((ComboBox^)ComboBox::FromHandle(mainControlHandle))->Text; + tempWStr = msclr::interop::marshal_as(tempSysStr); + + SetIniString(_iniSectionName, _iniVarName, tempWStr.c_str(), _iniFilePath, _useUtf8); + } +}; + + +class DropdownNumberOption : public ConfigOptionBase +{ +public: + int _defaultVal; + std::vector _valueInts; + bool _editable; + + DropdownNumberOption(LPCWSTR iniVarName, LPCWSTR iniSectionName, LPCWSTR iniFilePath, LPCWSTR friendlyName, LPCWSTR description, int defaultVal, std::vector valueInts, bool editable) + { + _iniVarName = iniVarName; + _iniSectionName = iniSectionName; + _iniFilePath = iniFilePath; + _friendlyName = friendlyName; + _description = description; + _defaultVal = defaultVal; + _valueInts = valueInts; + _editable = editable; + } + + virtual int AddToPanel(Panel^ panel, unsigned int left, unsigned int top, ToolTip^ tooltip) + { + Label^ label = gcnew Label(); + ComboBox^ combobox = gcnew ComboBox(); + + System::String^ tempSysStr; + + label->Text = gcnew String(_friendlyName); + label->Left = left; + label->Top = top + 3; + label->Width = Col1Width; + label->AutoSize = true; + label->FlatStyle = System::Windows::Forms::FlatStyle::Flat; + + for (int& choice : _valueInts) { + combobox->Items->Add(Convert::ToInt32(choice).ToString()); + } + + tempSysStr = Convert::ToInt32(GetIniInt(_iniSectionName, _iniVarName, _defaultVal, _iniFilePath)).ToString(); + + combobox->Text = gcnew String(tempSysStr); + combobox->Left = left + Col2Left; + combobox->Top = top; + combobox->Width = Col2Width; + combobox->AutoSize = true; + combobox->FlatStyle = System::Windows::Forms::FlatStyle::System; + + if (_editable) + combobox->DropDownStyle = ComboBoxStyle::DropDown; + else + combobox->DropDownStyle = ComboBoxStyle::DropDownList; + + Form^ RootForm = panel->FindForm(); + float ScaleWidth = 1.0f; + float ScaleHeight = 1.0f; + if (RootForm) + { + Drawing::SizeF CurrentScaleSize = RootForm->CurrentAutoScaleDimensions; + ScaleWidth = CurrentScaleSize.Width / BaseScaleSize; + ScaleHeight = CurrentScaleSize.Height / BaseScaleSize; + } + label->Scale(ScaleWidth, ScaleHeight); + combobox->Scale(ScaleWidth, ScaleHeight); + + tooltip->SetToolTip(label, gcnew String(_description)); + tooltip->SetToolTip(combobox, gcnew String(_description)); + + ComboboxValidation^ validation = gcnew ComboboxValidation(combobox); + combobox->Leave += gcnew System::EventHandler(validation, &ComboboxValidation::CheckNumberLeave); + + if (hasChanged == nullptr) + hasChanged = new bool(false); + ChangeHandler^ changehandler = gcnew ChangeHandler(hasChanged); + if (_editable) + combobox->TextChanged += gcnew System::EventHandler(changehandler, &ChangeHandler::SetChanged); + else + combobox->SelectedIndexChanged += gcnew System::EventHandler(changehandler, &ChangeHandler::SetChanged); + + panel->Controls->Add(label); + panel->Controls->Add(combobox); + mainControlHandle = combobox->Handle; + + int ControlHeight = combobox->Height / ScaleHeight; + return ControlHeight + ControlSpacing; + } + + virtual void SaveOption() + { + System::String^ tempSysStr; + std::wstring tempWStr; + + tempSysStr = ((ComboBox^)ComboBox::FromHandle(mainControlHandle))->Text; + tempWStr = msclr::interop::marshal_as(tempSysStr); + + SetIniString(_iniSectionName, _iniVarName, tempWStr.c_str(), _iniFilePath, false); + } +}; + + +enum ResolutionOptionOpts +{ + RESOPT_NONE, + RESOPT_INCLUDE_MATCH_WINDOW, + RESOPT_INCLUDE_MATCH_SCREEN +}; + +class ResolutionOption : public ConfigOptionBase +{ +public: + LPCWSTR _iniVarName2; + resolution _defaultVal; + std::vector _valueResolutions; + bool _editable; + ResolutionOptionOpts _opts; + + ResolutionOption(LPCWSTR iniVarName, LPCWSTR iniVarName2, LPCWSTR iniSectionName, LPCWSTR iniFilePath, LPCWSTR friendlyName, LPCWSTR description, resolution defaultVal, std::vector valueResolutions, bool editable, ResolutionOptionOpts opts) + { + _iniVarName = iniVarName; + _iniVarName2 = iniVarName2; + _iniSectionName = iniSectionName; + _iniFilePath = iniFilePath; + _friendlyName = friendlyName; + _description = description; + _defaultVal = defaultVal; + _valueResolutions = valueResolutions; + _editable = editable; + _opts = opts; + } + + virtual int AddToPanel(Panel^ panel, unsigned int left, unsigned int top, ToolTip^ tooltip) + { + Label^ label = gcnew Label(); + ComboBox^ combobox = gcnew ComboBox(); + + System::String^ tempSysStr; + + label->Text = gcnew String(_friendlyName); + label->Left = left; + label->Top = top + 3; + label->Width = Col1Width; + label->AutoSize = true; + label->FlatStyle = System::Windows::Forms::FlatStyle::Flat; + + if (_opts & RESOPT_INCLUDE_MATCH_WINDOW) + combobox->Items->Add(RESOPT_MATCH_WINDOW_TEXT); + else if (_opts & RESOPT_INCLUDE_MATCH_SCREEN) + combobox->Items->Add(RESOPT_MATCH_SCREEN_TEXT); + + for (resolution& choice : _valueResolutions) { + tempSysStr = Convert::ToInt32(choice.width).ToString() + L"x" + Convert::ToInt32(choice.height).ToString(); + combobox->Items->Add(tempSysStr); + } + + int width = GetIniInt(_iniSectionName, _iniVarName, -39, _iniFilePath); + int height = GetIniInt(_iniSectionName, _iniVarName2, -39, _iniFilePath); + if (width == -39 || height == -39) { + if (_defaultVal.width == -1 || _defaultVal.height == -1) + width = -1; + else + { + tempSysStr = Convert::ToInt32(_defaultVal.width).ToString() + L"x" + Convert::ToInt32(_defaultVal.height).ToString(); + combobox->Text = tempSysStr; + } + } + if (width == -1 || height == -1) { // -1 -> Match window/screen + if (_opts & RESOPT_INCLUDE_MATCH_WINDOW) + combobox->Text = RESOPT_MATCH_WINDOW_TEXT; + else if (_opts & RESOPT_INCLUDE_MATCH_SCREEN) + combobox->Text = RESOPT_MATCH_SCREEN_TEXT; + } + else { + tempSysStr = Convert::ToInt32(width).ToString() + L"x" + Convert::ToInt32(height).ToString(); + combobox->Text = tempSysStr; + } + + combobox->Left = left + Col2Left; + combobox->Top = top; + combobox->Width = Col2Width; + combobox->AutoSize = true; + combobox->FlatStyle = System::Windows::Forms::FlatStyle::System; + + if (_editable) + combobox->DropDownStyle = ComboBoxStyle::DropDown; + else + combobox->DropDownStyle = ComboBoxStyle::DropDownList; + + Form^ RootForm = panel->FindForm(); + float ScaleWidth = 1.0f; + float ScaleHeight = 1.0f; + if (RootForm) + { + Drawing::SizeF CurrentScaleSize = RootForm->CurrentAutoScaleDimensions; + ScaleWidth = CurrentScaleSize.Width / BaseScaleSize; + ScaleHeight = CurrentScaleSize.Height / BaseScaleSize; + } + label->Scale(ScaleWidth, ScaleHeight); + combobox->Scale(ScaleWidth, ScaleHeight); + + tooltip->SetToolTip(label, gcnew String(_description)); + tooltip->SetToolTip(combobox, gcnew String(_description)); + + if (hasChanged == nullptr) + hasChanged = new bool(false); + ChangeHandler^ changehandler = gcnew ChangeHandler(hasChanged); + if (_editable) + combobox->TextChanged += gcnew System::EventHandler(changehandler, &ChangeHandler::SetChanged); + else + combobox->SelectedIndexChanged += gcnew System::EventHandler(changehandler, &ChangeHandler::SetChanged); + + ComboboxValidation^ validation = gcnew ComboboxValidation(combobox); + combobox->Leave += gcnew System::EventHandler(validation, &ComboboxValidation::CheckResolutionLeave); + + panel->Controls->Add(label); + panel->Controls->Add(combobox); + mainControlHandle = combobox->Handle; + + int ControlHeight = combobox->Height / ScaleHeight; + return ControlHeight + ControlSpacing; + } + + virtual void SaveOption() + { + System::String^ tempSysStr; + std::wstring tempWStr; + cli::array^ resolutionArray; + + tempSysStr = ((ComboBox^)ComboBox::FromHandle(mainControlHandle))->Text; + + // Match window/screen -> -1x-1 + if (tempSysStr == RESOPT_MATCH_WINDOW_TEXT || tempSysStr == RESOPT_MATCH_SCREEN_TEXT) + tempSysStr = "-1x-1"; + + resolutionArray = tempSysStr->Split('x'); + + tempSysStr = resolutionArray[0]; + tempWStr = msclr::interop::marshal_as(tempSysStr); + SetIniString(_iniSectionName, _iniVarName, tempWStr.c_str(), _iniFilePath, false); + + tempSysStr = resolutionArray[1]; + tempWStr = msclr::interop::marshal_as(tempSysStr); + SetIniString(_iniSectionName, _iniVarName2, tempWStr.c_str(), _iniFilePath, false); + + } +}; + + +class ButtonOption : public ConfigOptionBase +{ +public: + void(*_func)(); + + ButtonOption(LPCWSTR friendlyName, LPCWSTR description, void(*func)()) + { + _friendlyName = friendlyName; + _description = description; + _func = func; + } + + virtual int AddToPanel(Panel^ panel, unsigned int left, unsigned int top, ToolTip^ tooltip) + { + Button^ button = gcnew Button(); + + button->Text = gcnew String(_friendlyName); + button->Left = left; + button->Top = top; + button->AutoSize = true; + button->FlatStyle = System::Windows::Forms::FlatStyle::Flat; + + Form^ RootForm = panel->FindForm(); + float ScaleWidth = 1.0f; + float ScaleHeight = 1.0f; + if (RootForm) + { + Drawing::SizeF CurrentScaleSize = RootForm->CurrentAutoScaleDimensions; + ScaleWidth = CurrentScaleSize.Width / BaseScaleSize; + ScaleHeight = CurrentScaleSize.Height / BaseScaleSize; + } + button->Scale(ScaleWidth, ScaleHeight); + + tooltip->SetToolTip(button, gcnew String(_description)); + + CustomFuncHandler^ funchandler = gcnew CustomFuncHandler(_func); + button->Click += gcnew System::EventHandler(funchandler, &CustomFuncHandler::RunFunc); + + panel->Controls->Add(button); + + int ControlHeight = button->Height / ScaleHeight; + return ControlHeight + ControlSpacing; + } +}; + + +class PluginOption : public ConfigOptionBase +{ +public: + bool _defaultVal; + std::vector _configopts; + + PluginOption(LPCWSTR iniVarName, LPCWSTR iniSectionName, LPCWSTR iniFilePath, LPCWSTR friendlyName, LPCWSTR description, bool defaultVal, std::vector configopts) + { + _iniVarName = iniVarName; + _iniSectionName = iniSectionName; + _iniFilePath = iniFilePath; + _friendlyName = friendlyName; + _description = description; + _defaultVal = defaultVal; + _configopts = configopts; + } + + virtual int AddToPanel(Panel^ panel, unsigned int left, unsigned int top, ToolTip^ tooltip) + { + CheckBox^ cb = gcnew CheckBox(); + Button^ button = gcnew Button(); + + cb->Text = gcnew String(_friendlyName); + cb->Checked = GetIniBool(_iniSectionName, _iniVarName, _defaultVal, _iniFilePath); + cb->Left = left + 2; + cb->Top = top + 3; + cb->AutoSize = true; + cb->FlatStyle = System::Windows::Forms::FlatStyle::Flat; + + // hack to ensure high contrast + cb->BackColor = System::Drawing::Color::FromArgb(0, 127, 127, 127); + + button->Text = L"Config"; + button->Left = left + ConfigBtnLeft; + button->Top = top; + button->AutoSize = true; + button->FlatStyle = System::Windows::Forms::FlatStyle::Flat; + + Form^ RootForm = panel->FindForm(); + float ScaleWidth = 1.0f; + float ScaleHeight = 1.0f; + if (RootForm) + { + Drawing::SizeF CurrentScaleSize = RootForm->CurrentAutoScaleDimensions; + ScaleWidth = CurrentScaleSize.Width / BaseScaleSize; + ScaleHeight = CurrentScaleSize.Height / BaseScaleSize; + } + cb->Scale(ScaleWidth, ScaleHeight); + button->Scale(ScaleWidth, ScaleHeight); + + tooltip->SetToolTip(cb, gcnew String(_description)); + + if (hasChanged == nullptr) + hasChanged = new bool(false); + ChangeHandler^ changehandler = gcnew ChangeHandler(hasChanged); + cb->CheckedChanged += gcnew System::EventHandler(changehandler, &ChangeHandler::SetChanged); + + panel->Controls->Add(cb); + mainControlHandle = cb->Handle; + + if (_configopts.size() > 0) + { + ToolTip^ paneltooltip = gcnew ToolTip(); + Panel^ configPanel = MakePanel((Col2Left + Col2Width + 76), 250, _configopts, paneltooltip, hasChanged); + configPanel->Scale(ScaleWidth, ScaleHeight); + if (RootForm) + configPanel->Font = RootForm->Font; + PluginConfigHandler^ confighandler = gcnew PluginConfigHandler(configPanel, gcnew String(_friendlyName) + " Options", ScaleHeight); + button->Click += gcnew System::EventHandler(confighandler, &PluginConfigHandler::OpenForm); + + panel->Controls->Add(button); + } + + int ControlHeight = button->Height / ScaleHeight; + return ControlHeight + ControlSpacing; + } + + virtual void SaveOption() + { + SetIniBool(_iniSectionName, _iniVarName, ((CheckBox^)CheckBox::FromHandle(mainControlHandle))->Checked, _iniFilePath, false); + + for (ConfigOptionBase* opt : _configopts) + { + opt->SaveOption(); + } + } +}; + + +Panel^ MakePanel(int width, int height, std::vector &cfg, ToolTip^ tooltip, bool* hasChanged) +{ + Panel^ outpanel = gcnew Panel(); + outpanel->Width = width; + outpanel->Height = height; + outpanel->AutoScroll = true; + + Form^ RootForm = outpanel->FindForm(); + float ScaleWidth = 1.0f; + float ScaleHeight = 1.0f; + if (RootForm) + { + Drawing::SizeF CurrentScaleSize = RootForm->CurrentAutoScaleDimensions; + ScaleWidth = CurrentScaleSize.Width / BaseScaleSize; + ScaleHeight = CurrentScaleSize.Height / BaseScaleSize; + } + + int curX = 12; + int curY = 3; + + for (int i = 0; i < cfg.size(); i++) + { + if (typeid(*cfg[i]).hash_code() == typeid(OptionMetaGroupEnd).hash_code()) + continue; + + if (typeid(*cfg[i]).hash_code() == typeid(OptionMetaGroupStart).hash_code()) + { + OptionMetaGroupStart* groupData = (OptionMetaGroupStart*)(cfg[i]); + GroupBox^ groupbox = gcnew GroupBox(); + groupbox->Width = width - (ScaleWidth * 28); + groupbox->Height = ScaleHeight * (groupData->_height); + groupbox->Left = ScaleWidth * 4; + groupbox->Top = ScaleHeight * curY; + groupbox->Text = gcnew String(groupData->_friendlyName); + groupbox->ForeColor = Drawing::Color::White; + + // find the end of this group by simple iteration keeping track of indent level + int level = 1; + int endidx; + for (endidx = i + 1; endidx < cfg.size(); endidx++) + { + if (typeid(*cfg[endidx]).hash_code() == typeid(OptionMetaGroupStart).hash_code()) + level++; + if (typeid(*cfg[endidx]).hash_code() == typeid(OptionMetaGroupEnd).hash_code()) + level--; + + if (level == 0) + break; + } + + Panel^ groupPanel = MakePanel(groupbox->Width - (ScaleWidth * 12), groupbox->Height - (ScaleHeight * 20), std::vector(&(cfg[i + 1]), &(cfg[endidx])), tooltip, hasChanged); + groupPanel->Left = ScaleWidth * 2; + groupPanel->Top = ScaleHeight * 14; + + groupbox->Controls->Add(groupPanel); + outpanel->Controls->Add(groupbox); + + i = endidx; + curY += groupData->_height; + } + else + { + cfg[i]->hasChanged = hasChanged; + curY += cfg[i]->AddToPanel(outpanel, curX, curY, tooltip); + } + } + + return outpanel; +} + #pragma warning(pop) \ No newline at end of file diff --git a/source-code/source/plugins/Launcher/framework.h b/source-code/source/plugins/Launcher/framework.h index e17ea32..f70f112 100644 --- a/source-code/source/plugins/Launcher/framework.h +++ b/source-code/source/plugins/Launcher/framework.h @@ -1,549 +1,556 @@ -#pragma once - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -// Windows Header Files -#include -#include -#include -#include -#include - -#include "ConfigOption.h" -#include "PluginConfig.h" -#include - -int (__cdecl* divaMain)(int argc, const char** argv, const char** envp) = (int(__cdecl*)(int argc, const char** argv, const char** envp))0x140194D90; - -using namespace std; - -string arg; - -wstring ExePath() { - WCHAR buffer[MAX_PATH]; - GetModuleFileNameW(NULL, buffer, MAX_PATH); - return wstring(buffer); -} - -wstring DirPath() { - wstring exepath = ExePath(); - wstring::size_type pos = exepath.find_last_of(L"\\/"); - return exepath.substr(0, pos); -} - -wstring DIVA_EXECUTABLE_STRING = ExePath(); -LPCWSTR DIVA_EXECUTABLE = DIVA_EXECUTABLE_STRING.c_str(); - -wstring DIVA_DIRPATH_STRING = DirPath(); -LPCWSTR DIVA_DIRPATH = DIVA_DIRPATH_STRING.c_str(); - -wstring DIVA_EXECUTABLE_LAUNCH_STRING = DIVA_EXECUTABLE_STRING + L" --launch"; -LPWSTR DIVA_EXECUTABLE_LAUNCH = const_cast(DIVA_EXECUTABLE_LAUNCH_STRING.c_str()); - -wstring PLUGINS_DIR = DirPath() + L"\\plugins"; -wstring PATCHES_DIR = DirPath() + L"\\patches"; - -wstring CONFIG_FILE_STRING = PLUGINS_DIR + L"\\config.ini"; -LPCWSTR CONFIG_FILE = CONFIG_FILE_STRING.c_str(); - -wstring COMPONENTS_FILE_STRING = PLUGINS_DIR + L"\\components.ini"; -LPCWSTR COMPONENTS_FILE = COMPONENTS_FILE_STRING.c_str(); - -wstring PLAYERDATA_FILE_STRING = PLUGINS_DIR + L"\\playerdata.ini"; -LPCWSTR PLAYERDATA_FILE = PLAYERDATA_FILE_STRING.c_str(); - -wstring KEYCONFIG_FILE_STRING = PLUGINS_DIR + L"\\keyconfig.ini"; -LPCWSTR KEYCONFIG_FILE = KEYCONFIG_FILE_STRING.c_str(); - -LPCWSTR PATCHES_SECTION = L"patches"; -LPCWSTR GRAPHICS_SECTION = L"graphics"; -LPCWSTR RESOLUTION_SECTION = L"resolution"; -LPCWSTR LAUNCHER_SECTION = L"launcher"; -LPCWSTR COMPONENTS_SECTION = L"components"; -LPCWSTR PLAYERDATA_SECTION = L"playerdata"; -LPCWSTR KEYCONFIG_SECTION = L"keyconfig"; - -int nSkipLauncher = GetPrivateProfileIntW(LAUNCHER_SECTION, L"skip", FALSE, CONFIG_FILE); -int nNoGPUDialog = GetPrivateProfileIntW(LAUNCHER_SECTION, L"no_gpu_dialog", FALSE, CONFIG_FILE); - - -resolution getCurrentScreenResolution() { - return resolution(GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN)); -} - -std::vector getScreenModes() { - static std::vector outVec = std::vector(); - - DEVMODEW dm = { 0 }; - dm.dmSize = sizeof(dm); - for (int iModeNum = 0; EnumDisplaySettingsW(NULL, iModeNum, &dm) != 0; iModeNum++) - { - outVec.push_back(dm); - } - - return outVec; -} - -std::vector getScreenResolutionsVec(std::vector &screenModes) { - static std::vector outVec = std::vector(); - - for (DEVMODEW &dm : screenModes) - { - resolution res = resolution(dm.dmPelsWidth, dm.dmPelsHeight); - - if (std::find(outVec.begin(), outVec.end(), res) == outVec.end()) { - outVec.push_back(res); - } - } - - std::sort(outVec.begin(), outVec.end()); - - return outVec; -} - -static std::vector getScreenDepthsVec(std::vector &screenModes) { - static std::vector outVec = std::vector(); - - for (DEVMODEW &dm : screenModes) - { - int depth = dm.dmBitsPerPel; - - if (depth < 24) - continue; - - if (std::find(outVec.begin(), outVec.end(), depth) == outVec.end()) { - outVec.push_back(depth); - } - } - - std::sort(outVec.begin(), outVec.end()); - - return outVec; -} - -static std::vector getScreenRatesVec(std::vector &screenModes) { - static std::vector outVec = std::vector(); - - for (DEVMODEW &dm : screenModes) - { - int rate = dm.dmDisplayFrequency; - - if (std::find(outVec.begin(), outVec.end(), rate) == outVec.end()) { - outVec.push_back(rate); - } - } - - std::sort(outVec.begin(), outVec.end()); - - return outVec; -} - -std::vector screenModes = getScreenModes(); - - -DropdownOption* DisplayModeDropdown = new DropdownOption(L"display", RESOLUTION_SECTION, CONFIG_FILE, L"Display:", L"Sets the window/screen mode.", 1, std::vector({ L"Windowed", L"Fast", L"Exclusive", L"Safe" })); -ResolutionOption* DisplayResolutionOption = new ResolutionOption(L"width", L"height", RESOLUTION_SECTION, CONFIG_FILE, L"Resolution:", L"Sets the display resolution.", resolution(-1, -1), getScreenResolutionsVec(screenModes), true, RESOPT_INCLUDE_MATCH_SCREEN); - -ConfigOptionBase* screenResolutionArray[] = { - DisplayModeDropdown, - DisplayResolutionOption, - //new DropdownNumberOption(L"bitdepth", RESOLUTION_SECTION, CONFIG_FILE, L"Bit Depth:", L"Sets the display bit depth.", 32, getScreenDepthsVec(screenModes), true), - new DropdownNumberOption(L"refreshrate", RESOLUTION_SECTION, CONFIG_FILE, L"Refresh Rate:", L"Sets the display refresh rate.", 60, getScreenRatesVec(screenModes), true), -}; - -BooleanOption* InternalResolutionCheckbox = new BooleanOption(L"r.enable", RESOLUTION_SECTION, CONFIG_FILE, L"Enable", L"Enable or disable custom internal resolution.", false, false); -ResolutionOption* InternalResolutionOption = new ResolutionOption(L"r.width", L"r.height", RESOLUTION_SECTION, CONFIG_FILE, L"Resolution:", L"Sets the internal resolution (instead of 1280x720).", resolution(1920, 1080), std::vector({ resolution(1,1), resolution(320,240), resolution(426,240), resolution(640,480), resolution(854,480), resolution(960,540), resolution(1280,720), resolution(1366,768), resolution(1600,900), resolution(1920,1080), resolution(2560,1440), resolution(3200,1800), resolution(3840,2160), resolution(5120,2880), resolution(7680,4320) }), true, RESOPT_INCLUDE_MATCH_WINDOW); - -ConfigOptionBase* internalResolutionArray[] = { - InternalResolutionCheckbox, - InternalResolutionOption -}; - -ConfigOptionBase* graphicsArray[] = { - new DropdownOption(L"model", L"GPU", CONFIG_FILE, L"NVIDIA GPU:", L"Select your NVIDIA GPU's architecture to apply the necessary workarounds.\n\nNOTE: Automatic detection does not currently work on GNU/Linux.", -1, std::vector({ L"Automatic", L"Kepler", L"Maxwell", L"Turing", L"Ampere" }), -1), - new BooleanOption(L"TAA", GRAPHICS_SECTION, CONFIG_FILE, L"TAA", L"Temporal Anti-Aliasing", true, false), - new BooleanOption(L"MLAA", GRAPHICS_SECTION, CONFIG_FILE, L"MLAA", L"Morphological Anti-Aliasing", true, false), - new DropdownOption(L"MAG", GRAPHICS_SECTION, CONFIG_FILE, L"Filter:", L"Image filter.\n\nBilinear: default filter\nNearest-neighbour: sharpest, but blocky\nSharpen: sharp filter\nCone: smooth filter", 0, std::vector({ L"Bilinear", L"Nearest-neighbour", L"Sharpen", L"Cone" })), - new BooleanOption(L"DOF", GRAPHICS_SECTION, CONFIG_FILE, L"Depth of Field", L"Blurs the background. Disable for better performance.", true, false), - new BooleanOption(L"reflections", GRAPHICS_SECTION, CONFIG_FILE, L"Reflections", L"Enable or disable reflections.", true, false), - new ResolutionOption(L"reflect_res_width", L"reflect_res_height", GRAPHICS_SECTION, CONFIG_FILE, L"Reflection Res:", L"Sets the reflection buffer resolution (instead of 512x256).", resolution(512, 256), std::vector({resolution(256,256), resolution(512,256), resolution(512,512), resolution(1024,1024), resolution(2048,2048), resolution(4096,4096)}), true, (ResolutionOptionOpts)0), - new ResolutionOption(L"refract_res_width", L"refract_res_height", GRAPHICS_SECTION, CONFIG_FILE, L"Refraction Res:", L"Sets the refraction buffer resolution (instead of 512x256).", resolution(512, 256), std::vector({resolution(256,256), resolution(512,256), resolution(512,512), resolution(1024,1024), resolution(2048,2048), resolution(4096,4096)}), true, (ResolutionOptionOpts)0), - new NumericOption(L"gamma", GRAPHICS_SECTION, CONFIG_FILE, L"Gamma:", L"Increase to darken shadows.\nSet to 125 for a console-like experience.\n\nDefault: 0 or 100", 100, 0, 200), - new BooleanOption(L"shadows", GRAPHICS_SECTION, CONFIG_FILE, L"Shadows", L"Enable or disable shadows.", true, false), - new BooleanOption(L"punchthrough", GRAPHICS_SECTION, CONFIG_FILE, L"Transparent Meshes", L"Show transparent meshes.", true, false), - new BooleanOption(L"glare", GRAPHICS_SECTION, CONFIG_FILE, L"Glare", L"Enable or disable glare.", true, false), - new BooleanOption(L"shader", GRAPHICS_SECTION, CONFIG_FILE, L"Shader", L"Enable or disable high-quality shaders.", true, false), - new DropdownOption(L"NPR1", GRAPHICS_SECTION, CONFIG_FILE, L"Toon (F9):", L"NPR1 shader\n\nPress F9 to toggle.", 0, std::vector({ L"Default", L"Force on", L"Force off" })), - new BooleanOption(L"2D", GRAPHICS_SECTION, CONFIG_FILE, L"Disable 3D rendering", L"Disable all 3D passes.\n\nWARNING: The extended data will be deleted unless Prevent Data Deletion is enabled.", false, false), - -}; - -ConfigOptionBase* optionsArray[] = { - new OptionMetaSectionLabel(L"Compatibility"), - new BooleanOption(L"no_movies", PATCHES_SECTION, CONFIG_FILE, L"Disable Movies", L"Disable movies (enable this if the game hangs when loading certain PVs).", false, false), - new BooleanOption(L"mp4_movies", PATCHES_SECTION, CONFIG_FILE, L"Custom MP4 Adv Movies", L"Enable MP4 (instead of WMV) advertise/attract movies.", false, false), - new BooleanOption(L"cursor", PATCHES_SECTION, CONFIG_FILE, L"Cursor", L"Enable or disable the mouse cursor.", true, false), - new BooleanOption(L"stereo", PATCHES_SECTION, CONFIG_FILE, L"Stereo", L"Use 2 channels instead of 4 (when not using DivaSound).", true, false), - new OptionMetaSeparator(), - new OptionMetaSpacer(8), - - new OptionMetaSectionLabel(L"Controller Options"), - new BooleanOption(L"rumble", KEYCONFIG_SECTION, KEYCONFIG_FILE, L"XInput Rumble", L"Enables rumble during chainslides.", true, true), - new NumericOption(L"xinput_rumble_intensity_left", KEYCONFIG_SECTION, KEYCONFIG_FILE, L"Left motor:", L"Left rumble motor intensity (XInput).\n\nDefault: 8000", 8000, 0, USHRT_MAX), - new NumericOption(L"xinput_rumble_intensity_right", KEYCONFIG_SECTION, KEYCONFIG_FILE, L"Right motor:", L"Right rumble motor intensity (XInput).\n\nDefault: 4000", 4000, 0, USHRT_MAX), - new NumericOption(L"xinput_preferred", KEYCONFIG_SECTION, KEYCONFIG_FILE, L"XInput Controller Num:", L"Sets the preferred XInput controller.\nIf unavailable, the next connected controller is used.", 0, 0, 3), - new BooleanOption(L"hardware_slider", PATCHES_SECTION, CONFIG_FILE, L"Use Hardware Slider", L"Enable this if using a real arcade slider.\n(set the slider to port COM11)", false, false), - new OptionMetaSeparator(), - new OptionMetaSpacer(8), - - new OptionMetaSectionLabel(L"PV Selector"), - new DropdownOption(L"quick_start", PATCHES_SECTION, CONFIG_FILE, L"Quick Start:", L"Skip one or more menus.", 1, std::vector({ L"Disabled", L"Guest", L"Guest + Normal" })), - new BooleanOption(L"no_scrolling_sfx", PATCHES_SECTION, CONFIG_FILE, L"Disable Scrolling SFX", L"Disable the scrolling sound effect.", false, false), - new BooleanOption(L"unlock_pseudo", PATCHES_SECTION, CONFIG_FILE, L"Unlock PSEUDO modules (incomplete)", L"Lets you play any PV with any performer.\n(incomplete, recommended modules will default to Miku)", false, false), - new BooleanOption(L"card", PATCHES_SECTION, CONFIG_FILE, L"Unlock card menu (incomplete)", L"Enables the card menu.\n(incomplete, it doesn't bypass the card prompt)", false, false), - new OptionMetaSeparator(), - new OptionMetaSpacer(8), - - new OptionMetaSectionLabel(L"Stages/Songs"), - new NumericOption(L"Enhanced_Stage_Manager", PATCHES_SECTION, CONFIG_FILE, L"Number of Stages:", L"Set the number of stages (0 = default).", 0, 0, INT_MAX), - new BooleanOption(L"Enhanced_Stage_Manager_Encore", PATCHES_SECTION, CONFIG_FILE, L"Encore", L"Enable encore stages.", true, false), - new BooleanOption(L"sing_missed", PATCHES_SECTION, CONFIG_FILE, L"Sing Missed", L"Sing missed notes.", false, false), - new BooleanOption(L"autopause", KEYCONFIG_SECTION, KEYCONFIG_FILE, L"Pause Automatically", L"Pause when focus is lost.", true, true), - new OptionMetaSeparator(), - new OptionMetaSpacer(8), - - new OptionMetaSectionLabel(L"PV Customization"), - new DropdownOption(L"force_mouth", PATCHES_SECTION, CONFIG_FILE, L"Mouth Type:", L"Change the mouth animations.", 0, std::vector({ L"Default", L"Force PDA", L"Force FT" })), - new DropdownOption(L"force_expressions", PATCHES_SECTION, CONFIG_FILE, L"Expression Type:", L"Change the expressions.", 0, std::vector({ L"Default", L"Force PDA", L"Force FT" })), - new DropdownOption(L"force_look", PATCHES_SECTION, CONFIG_FILE, L"Look Type:", L"Change the look animations.", 0, std::vector({ L"Default", L"Force PDA", L"Force FT" })), - new BooleanOption(L"no_hand_scaling", PATCHES_SECTION, CONFIG_FILE, L"No Hand Scaling", L"Disable hand scaling.", false, false), - new NumericOption(L"default_hand_size", PATCHES_SECTION, CONFIG_FILE, L"Default Hand Size:", L"0-10000: default\n12200: PDA", 0, 0, INT_MAX), - new OptionMetaSeparator(), - new OptionMetaSpacer(8), - - new OptionMetaSectionLabel(L"UI Elements"), - new BooleanOption(L"hide_volume", PATCHES_SECTION, CONFIG_FILE, L"Hide Volume Buttons", L"Hide the volume and SE control buttons.", false, false), - new BooleanOption(L"no_pv_ui", PATCHES_SECTION, CONFIG_FILE, L"Disable PV UI", L"Remove the photo controls during PV playback.", false, false), - new BooleanOption(L"hide_pv_watermark", PATCHES_SECTION, CONFIG_FILE, L"Hide PV Watermark", L"Hide the watermark that's usually shown in PV viewing mode.", false, false), - new DropdownOption(L"status_icons", PATCHES_SECTION, CONFIG_FILE, L"Top-Right Corner Icons:", L"Set the state of card reader and network status icons.", 3, std::vector({ L"Default", L"Hidden", L"Error", L"OK", L"Partial OK" })), - new BooleanOption(L"no_lyrics", PATCHES_SECTION, CONFIG_FILE, L"Disable Lyrics", L"Disable showing lyrics.", false, false), - new BooleanOption(L"no_error", PATCHES_SECTION, CONFIG_FILE, L"Disable Error Banner", L"Disable the error banner on the attract screen.", true, false), - new BooleanOption(L"hide_freeplay", PATCHES_SECTION, CONFIG_FILE, L"Hide \"FREE PLAY\"/\"CREDIT(S)\"", L"Hide the \"FREE PLAY\"/\"CREDIT(S)\" text.", false, false), - new BooleanOption(L"freeplay", PATCHES_SECTION, CONFIG_FILE, L"FREE PLAY", L"Show \"FREE PLAY\" instead of \"CREDIT(S)\" and don't require credits.", true, false), - new BooleanOption(L"pdloadertext", PATCHES_SECTION, CONFIG_FILE, L"PD Loader FREE PLAY", L"Show \"PD Loader\" instead of \"FREE PLAY\".", true, false), - new BooleanOption(L"no_timer", PATCHES_SECTION, CONFIG_FILE, L"Freeze Timer", L"Disable the timer.", true, false), - new BooleanOption(L"no_timer_sprite", PATCHES_SECTION, CONFIG_FILE, L"Disable Timer Sprite", L"Disable the timer sprite.", true, false), - new OptionMetaSeparator(), - new OptionMetaSpacer(8), - - new OptionMetaSectionLabel(L"Framerate"), - new BooleanOption(L"FPS.Limit.LightMode", GRAPHICS_SECTION, CONFIG_FILE, L"Use Lightweight Limiter", L"Makes the FPS limiter use less CPU.\nMay have less consistent performance.", true, false), - new NumericOption(L"FPS.Limit", GRAPHICS_SECTION, CONFIG_FILE, L"FPS Limit:", L"Allows you to set a frame rate cap. Set to -1 to unlock the frame rate.", 60, -1, INT_MAX), - new NumericOption(L"frm.motion.rate", GRAPHICS_SECTION, CONFIG_FILE, L"FRM Motion Rate:", L"Sets the motion rate (fps) for the Frame Rate Manager component.\nLarger values should be smoother, but more CPU intensive and possibly buggier.", 300, 1, INT_MAX), - new OptionMetaSeparator(), - new OptionMetaSpacer(8), - - new OptionMetaSectionLabel(L"Advanced Compatibility"), - new BooleanOption(L"opengl_patch_a", LAUNCHER_SECTION, CONFIG_FILE, L"OpenGL Patch A", L"Ignores some OpenGL-related errors. Don't use both patches at the same time unless you're know what you're doing.", false, false), - new BooleanOption(L"opengl_patch_b", LAUNCHER_SECTION, CONFIG_FILE, L"OpenGL Patch B", L"Ignores some OpenGL-related errors. Don't use both patches at the same time unless you're know what you're doing.", false, false), - new OptionMetaSeparator(), - new OptionMetaSpacer(8), - - new OptionMetaSectionLabel(L"Loader"), - new BooleanOption(L"custom_patches", PATCHES_SECTION, CONFIG_FILE, L"Enable Custom Patches", L"Enables all custom patches.", true, false), - new BooleanOption(L"prevent_data_deletion", PATCHES_SECTION, CONFIG_FILE, L"Prevent Data Deletion", L"Prevents the game from deleting files.", false, false), - new OptionMetaSeparator(), - new OptionMetaSpacer(8), - - new OptionMetaSectionLabel(L"Launcher"), - new BooleanOption(L"dark_launcher", LAUNCHER_SECTION, CONFIG_FILE, L"Dark Launcher", L"Sets the dark colour scheme in the launcher.", false, false), - new BooleanOption(L"acrylic_blur", LAUNCHER_SECTION, CONFIG_FILE, L"Acrylic Blur", L"Enables acrylic blur in the launcher on Windows 10 20H2 or later.", false, false), - new BooleanOption(L"no_gpu_dialog", LAUNCHER_SECTION, CONFIG_FILE, L"Disable GPU Warning", L"Disables the warning dialog for unsupported GPUs.", false, false), - //new BooleanOption(L"ignore_exe_checksum", PATCHES_SECTION, CONFIG_FILE, L"Ignore exe checksum", L"Use at your own risk.", false, false), - new StringOption(L"command_line", LAUNCHER_SECTION, CONFIG_FILE, L"Command Line:", L"Allows setting command line parameters for the game when using the launcher.\nDisabling the launcher will bypass this.", L"", false), - new BooleanOption(L"use_divahook_bat", LAUNCHER_SECTION, CONFIG_FILE, L"Use divahook.bat/start.bat", L"Launches divahook.bat/start.bat intead of diva.exe.", false, false), -}; - -ConfigOptionBase* playerdataArray[] = { - new StringOption(L"player_name", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Player Name:", L"Player name shown in game.", L"NO-NAME", true), - new StringOption(L"level_name", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Level Name:", L"Level (plate) name shown in game.", L"忘れないでね私の声を", true), - - new NumericOption(L"level_plate_id", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Level Plate:", L"Sets the level background image (plate).", 0, 0, INT_MAX), - new NumericOption(L"level_plate_effect", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Level Plate Effect:", L"Sets the effect on the level background image (plate).", -1, -1, 2), - new NumericOption(L"skin_equip ", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Skin:", L"Sets the gameplay UI skin.", 0, 0, INT_MAX), - - new NumericOption(L"btn_se_equip", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Button Sound:", L"Sets the sound effect for buttons.\n-1 = song default", -1, -1, INT_MAX), - new NumericOption(L"slide_se_equip", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Slide Sound:", L"Sets the sound effect for slides.\n-1 = song default", -1, -1, INT_MAX), - new NumericOption(L"chainslide_se_equip", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Chainslide Sound:", L"Sets the sound effect for chain slides.\n-1 = song default", -1, -1, INT_MAX), - new NumericOption(L"slidertouch_se_equip", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Slider Touch Sound:", L"Sets the sound effect for touching the slider with no note.\n-1 = song default", -1, -1, INT_MAX), - new BooleanOption(L"act_toggle", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Button SE", L"Enables button/slider sounds.", true, true), - - new BooleanOption(L"border_great", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Clear Border (Great)", L"Shows the clear border for a great rating on the progress bar.", true, true), - new BooleanOption(L"border_excellent", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Clear Border (Excellent)", L"Shows the clear border for an excellent rating on the progress bar.", true, true), - new BooleanOption(L"border_rival", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Clear Border (Rival)", L"Shows the clear border for beating your rival on the progress bar.", false, true), - - new BooleanOption(L"use_card", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Use Card", L"Enables IC card. This allows module selection.", false, true), - new BooleanOption(L"module_card_workaround", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Module Selection Workaround", L"Allows module selection without card and tries to improve menu performance.\n(BETA)", true, true), - new BooleanOption(L"use_pv_module_equip ", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Song Specific Modules", L"Allows song-specific module selection.", false, true), - new BooleanOption(L"use_pv_skin_equip ", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Song Specific Skins", L"Allows song-specific skin settings.\nValues stored in skins.ini", false, true), - new BooleanOption(L"use_pv_sfx_equip ", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Song Specific Sound Effects", L"Allows song-specific sound effect settings.\nValues stored in sfx.ini", false, true), - - new BooleanOption(L"gamemode_options", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Game Modifiers", L"Allows use of game mode modifiers (hi-speed, hidden, and sudden).", true, true), -}; - - -ConfigOptionBase* componentsArray[] = { - new BooleanOption(L"input_emulator", COMPONENTS_SECTION, COMPONENTS_FILE, L"Input Emulator", L"Emulates input through keyboard and/or mouse.", false, true), - new BooleanOption(L"touch_slider_emulator", COMPONENTS_SECTION, COMPONENTS_FILE, L"Slider Emulator", L"Emulates slider through keyboard and/or mouse.", false, true), - new BooleanOption(L"touch_panel_emulator", COMPONENTS_SECTION, COMPONENTS_FILE, L"Touch Panel Emulator", L"Emulates touch panel through mouse.", false, true), - - new BooleanOption(L"player_data_manager", COMPONENTS_SECTION, COMPONENTS_FILE, L"Player Data Manager", L"Loads user-defined values into the PlayerData struct.\nRequired for modules and game mode modifiers.", false, true), - - new BooleanOption(L"frame_rate_manager", COMPONENTS_SECTION, COMPONENTS_FILE, L"Frame Rate Manager", L"Adjusts animations to the correct speed at different frame rates.\nOnly needed when FPS isn't locked at 60.", false, true), - - new BooleanOption(L"fast_loader", COMPONENTS_SECTION, COMPONENTS_FILE, L"Fast Loader", L"Skip or speed up unnecessary loading steps.", false, true), - - new NumericOption(L"fast_loader_speed", COMPONENTS_SECTION, COMPONENTS_FILE, L"Fast Loader Speed", L"Set this to 4 or less when playing online.\nDefault: 39", 39, 2, 1024), - - new BooleanOption(L"camera_controller", COMPONENTS_SECTION, COMPONENTS_FILE, L"Camera Controller", L"Enables freecam (toggled using F3).\nWASD to move, SPACE/CTRL for up/down, Q/R to rotate, R/F for zoom.\nHolding SHIFT/ALT changes control speed.", false, true), - - new BooleanOption(L"scale_component", COMPONENTS_SECTION, COMPONENTS_FILE, L"Scale Component", L"Scales the graphics output framebuffer to fill the screen/window.", false, true), - - new BooleanOption(L"debug_component", COMPONENTS_SECTION, COMPONENTS_FILE, L"Debug Component", L"Allows for changing game state (F4-F8 keys), using dev GUI and tests, and speeding up 2d animations/menus (hold SHIFT+TAB).", false, true), - - new BooleanOption(L"target_inspector", COMPONENTS_SECTION, COMPONENTS_FILE, L"Target Inspector", L"Enables hold transfers.", false, true), - - new BooleanOption(L"score_saver", COMPONENTS_SECTION, COMPONENTS_FILE, L"Score Saver", L"Saves high scores to plugins/scores.ini.", false, true), - - new BooleanOption(L"pause", COMPONENTS_SECTION, COMPONENTS_FILE, L"Pause", L"Adds a pause menu.", false, true), -}; - -bool IsLineInFile(LPCSTR searchLine, LPCWSTR fileName) -{ - bool result = false; - - std::ifstream fileStream(fileName); - - if (!fileStream.is_open()) - return false; - - std::string line; - - // check for BOM - std::getline(fileStream, line); - if (line.size() >= 3 && line.rfind("\xEF\xBB\xBF", 0) == 0) - fileStream.seekg(3); - else - fileStream.seekg(0); - - while (std::getline(fileStream, line)) - { - if (line.compare(searchLine) == 0) - { - result = true; - break; - } - } - - fileStream.close(); - return result; -} - -void PrependFile(LPCSTR newStr, LPCWSTR fileName) -{ - std::fstream fileStream(fileName); - - if (!fileStream.is_open()) - return; - - - std::string origStr; - - // this is apparently more efficient than just going straight into the string - fileStream.seekg(0, std::ios::end); - origStr.reserve(fileStream.tellg()); - fileStream.seekg(0, std::ios::beg); - - // check for BOM - std::string BOMcheckLine; - std::getline(fileStream, BOMcheckLine); - if (BOMcheckLine.size() >= 3 && BOMcheckLine.rfind("\xEF\xBB\xBF", 0) == 0) - fileStream.seekg(3); - else - fileStream.seekg(0); - - origStr.assign((std::istreambuf_iterator(fileStream)), std::istreambuf_iterator()); - - - std::string outStr = newStr; - outStr += origStr; - - fileStream.seekg(0, std::ios::beg); - fileStream << outStr; - fileStream.close(); -} - - -struct PluginInfo { - HMODULE handle; - std::wstring filename; - std::wstring name; - std::wstring description; - std::wstring builddate; - std::vector configopts; -}; -std::vector LoadPlugins() -{ - std::vector outvec; - - HANDLE hFind; - WIN32_FIND_DATAW ffd; - - hFind = FindFirstFileW((PLUGINS_DIR + L"\\*.dva").c_str(), &ffd); - if (hFind != INVALID_HANDLE_VALUE) { - do { - if (!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) - { - auto pos = wcslen(ffd.cFileName); - - if (ffd.cFileName[pos - 4] == '.' && - (ffd.cFileName[pos - 3] == 'd' || ffd.cFileName[pos - 3] == 'D') && - (ffd.cFileName[pos - 2] == 'v' || ffd.cFileName[pos - 2] == 'V') && - (ffd.cFileName[pos - 1] == 'a' || ffd.cFileName[pos - 1] == 'A')) - { - PluginInfo thisplugin; - thisplugin.handle = LoadLibraryW((PLUGINS_DIR + L"\\" + ffd.cFileName).c_str()); - thisplugin.filename = ffd.cFileName; - - if (thisplugin.handle == NULL) - continue; - - auto nameFunc = (LPCWSTR(*)())GetProcAddress(thisplugin.handle, "GetPluginName"); - auto descFunc = (LPCWSTR(*)())GetProcAddress(thisplugin.handle, "GetPluginDescription"); - auto dateFunc = (LPCWSTR(*)())GetProcAddress(thisplugin.handle, "GetBuildDate"); - auto optsFunc = (PluginConfig::PluginConfigArray(*)())GetProcAddress(thisplugin.handle, "GetPluginOptions"); - - if (nameFunc != NULL) - thisplugin.name = nameFunc(); - else - thisplugin.name = thisplugin.filename; - - if (descFunc != NULL) - thisplugin.description = descFunc(); - else - thisplugin.description = (thisplugin.filename + L" Plugin").c_str(); - - if (dateFunc != NULL) - thisplugin.builddate = dateFunc(); - else - thisplugin.builddate = L"Unknown"; - - thisplugin.description += L"\n\nVersion: " + thisplugin.builddate; - - if (optsFunc != NULL) - thisplugin.configopts = PluginConfig::GetConfigOptionVec(optsFunc()); - - // sometimes this might screw with custom button config, so let's just not free stuff - // FreeLibrary(thisplugin.handle); - - outvec.push_back(thisplugin); - } - } - } while (FindNextFileW(hFind, &ffd)); - FindClose(hFind); - } - - return outvec; -} -// don't load until actually needed to avoid loading disabled plugins -std::vector AllPlugins; // = LoadPlugins(); - -std::vector GetPluginOptions(std::vector* plugins) -{ - std::vector outvec; - - for (PluginInfo &pi : *plugins) - { - PluginOption* opt = new PluginOption(pi.filename.c_str(), L"plugins", CONFIG_FILE, pi.name.c_str(), pi.description.c_str(), true, pi.configopts); - outvec.push_back(opt); - } - - return outvec; -} -// don't load until actually needed to avoid loading disabled plugins -std::vector AllPluginOpts; // = GetPluginOptions(&AllPlugins); - -std::vector LoadCustom() -{ - std::vector outvec; - - HANDLE hFind; - WIN32_FIND_DATAW ffd; - - hFind = FindFirstFileW((PATCHES_DIR + L"\\*.p?").c_str(), &ffd); - if (hFind != INVALID_HANDLE_VALUE) { - do { - if (!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) - { - auto pos = wcslen(ffd.cFileName); - - if ((ffd.cFileName[pos - 2] == '.' && (ffd.cFileName[pos - 1] == 'p' || ffd.cFileName[pos - 1] == 'P')) || - (ffd.cFileName[pos - 3] == '.' && (ffd.cFileName[pos - 2] == 'p' || ffd.cFileName[pos - 2] == 'P') && (ffd.cFileName[pos - 1] == '2'))) - { - PluginInfo thisplugin; - thisplugin.filename = ffd.cFileName; - - thisplugin.name = thisplugin.filename; - if (thisplugin.filename[pos - 1] == '2') - thisplugin.name.resize(thisplugin.name.size() - 3); - else - thisplugin.name.resize(thisplugin.name.size() - 2); - - thisplugin.description = L"Custom patch"; - - outvec.push_back(thisplugin); - } - } - } while (FindNextFileW(hFind, &ffd)); - FindClose(hFind); - } - - return outvec; -} -std::vector AllCustomPatches; // = LoadCustom(); - -std::vector GetCustomOptions(std::vector* patches) -{ - std::vector outvec; - - for (PluginInfo& pi : *patches) - { - PluginOption* opt = new PluginOption(pi.filename.c_str(), L"plugins", CONFIG_FILE, pi.name.c_str(), pi.description.c_str(), true, pi.configopts); - outvec.push_back(opt); - } - - return outvec; -} -// don't load until actually needed to avoid loading disabled plugins -std::vector AllCustomOpts; // = GetCustomOptions(&AllCustomPatches); - -// used to trick Optimus into switching to the NVIDIA GPU -HMODULE nvcudaModule = LoadLibraryW(L"nvcuda.dll"); -// cuInit actually returns a CUresult, but we don't really care about it -void(WINAPI * cuInit)(unsigned int flags) = (void(WINAPI*)(unsigned int flags))GetProcAddress(nvcudaModule, "cuInit"); - -// needed to close the OpenGL window (freeglut only) -HMODULE glutModule = LoadLibraryW(L"glut32.dll"); -void(__stdcall * glutMainLoopEventDynamic)() = (void(__stdcall*)())GetProcAddress(glutModule, "glutMainLoopEvent"); - - -using namespace PluginConfig; - -extern "C" __declspec(dllexport) LPCWSTR GetPluginName(void) -{ - return L"Launcher"; -} - -extern "C" __declspec(dllexport) LPCWSTR GetPluginDescription(void) -{ - return L"PD Launcher is the window you currently have open.\nYou can disable it if you want, but you'll need to edit config.ini if you ever want to re-enable it."; +#pragma once + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +// Windows Header Files +#include +#include +#include +#include +#include + +#include "ConfigOption.h" +#include "PluginConfig.h" +#include + +int (__cdecl* divaMain)(int argc, const char** argv, const char** envp) = (int(__cdecl*)(int argc, const char** argv, const char** envp))0x140194D90; + +using namespace std; + +string arg; + +wstring ExePath() { + WCHAR buffer[MAX_PATH]; + GetModuleFileNameW(NULL, buffer, MAX_PATH); + return wstring(buffer); +} + +wstring DirPath() { + wstring exepath = ExePath(); + wstring::size_type pos = exepath.find_last_of(L"\\/"); + return exepath.substr(0, pos); +} + +wstring DIVA_EXECUTABLE_STRING = ExePath(); +LPCWSTR DIVA_EXECUTABLE = DIVA_EXECUTABLE_STRING.c_str(); + +wstring DIVA_DIRPATH_STRING = DirPath(); +LPCWSTR DIVA_DIRPATH = DIVA_DIRPATH_STRING.c_str(); + +wstring DIVA_EXECUTABLE_LAUNCH_STRING = DIVA_EXECUTABLE_STRING + L" --launch"; +LPWSTR DIVA_EXECUTABLE_LAUNCH = const_cast(DIVA_EXECUTABLE_LAUNCH_STRING.c_str()); + +wstring PLUGINS_DIR = DirPath() + L"\\plugins"; +wstring PATCHES_DIR = DirPath() + L"\\patches"; + +wstring CONFIG_FILE_STRING = PLUGINS_DIR + L"\\config.ini"; +LPCWSTR CONFIG_FILE = CONFIG_FILE_STRING.c_str(); + +wstring COMPONENTS_FILE_STRING = PLUGINS_DIR + L"\\components.ini"; +LPCWSTR COMPONENTS_FILE = COMPONENTS_FILE_STRING.c_str(); + +wstring PLAYERDATA_FILE_STRING = PLUGINS_DIR + L"\\playerdata.ini"; +LPCWSTR PLAYERDATA_FILE = PLAYERDATA_FILE_STRING.c_str(); + +wstring KEYCONFIG_FILE_STRING = PLUGINS_DIR + L"\\keyconfig.ini"; +LPCWSTR KEYCONFIG_FILE = KEYCONFIG_FILE_STRING.c_str(); + +LPCWSTR PATCHES_SECTION = L"patches"; +LPCWSTR GRAPHICS_SECTION = L"graphics"; +LPCWSTR RESOLUTION_SECTION = L"resolution"; +LPCWSTR LAUNCHER_SECTION = L"launcher"; +LPCWSTR COMPONENTS_SECTION = L"components"; +LPCWSTR PLAYERDATA_SECTION = L"playerdata"; +LPCWSTR KEYCONFIG_SECTION = L"keyconfig"; + +int nSkipLauncher = GetPrivateProfileIntW(LAUNCHER_SECTION, L"skip", FALSE, CONFIG_FILE); +int nNoGPUDialog = GetPrivateProfileIntW(LAUNCHER_SECTION, L"no_gpu_dialog", FALSE, CONFIG_FILE); + + +resolution getCurrentScreenResolution() { + return resolution(GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN)); +} + +std::vector getScreenModes() { + static std::vector outVec = std::vector(); + + DEVMODEW dm = { 0 }; + dm.dmSize = sizeof(dm); + for (int iModeNum = 0; EnumDisplaySettingsW(NULL, iModeNum, &dm) != 0; iModeNum++) + { + outVec.push_back(dm); + } + + return outVec; +} + +std::vector getScreenResolutionsVec(std::vector &screenModes) { + static std::vector outVec = std::vector(); + + for (DEVMODEW &dm : screenModes) + { + resolution res = resolution(dm.dmPelsWidth, dm.dmPelsHeight); + + if (std::find(outVec.begin(), outVec.end(), res) == outVec.end()) { + outVec.push_back(res); + } + } + + const resolution defaultres(1280, 720); + if (std::find(outVec.begin(), outVec.end(), defaultres) == outVec.end()) { + outVec.push_back(defaultres); + } + + std::sort(outVec.begin(), outVec.end()); + + return outVec; +} + +static std::vector getScreenDepthsVec(std::vector &screenModes) { + static std::vector outVec = std::vector(); + + for (DEVMODEW &dm : screenModes) + { + int depth = dm.dmBitsPerPel; + + if (depth < 24) + continue; + + if (std::find(outVec.begin(), outVec.end(), depth) == outVec.end()) { + outVec.push_back(depth); + } + } + + std::sort(outVec.begin(), outVec.end()); + + return outVec; +} + +static std::vector getScreenRatesVec(std::vector &screenModes) { + static std::vector outVec = std::vector(); + + for (DEVMODEW &dm : screenModes) + { + int rate = dm.dmDisplayFrequency; + + if (std::find(outVec.begin(), outVec.end(), rate) == outVec.end()) { + outVec.push_back(rate); + } + } + + std::sort(outVec.begin(), outVec.end()); + + return outVec; +} + +std::vector screenModes = getScreenModes(); + +const std::vector internalResOptions = { resolution(320,240), resolution(426,240), resolution(640,480), resolution(854,480), resolution(960,540), resolution(1280,720), resolution(1366,768), resolution(1600,900), resolution(1920,1080), resolution(2560,1440), resolution(3200,1800), resolution(3840,2160), resolution(5120,2880), resolution(7680,4320) }; + +DropdownOption* DisplayModeDropdown = new DropdownOption(L"display", RESOLUTION_SECTION, CONFIG_FILE, L"Display:", L"Sets the window/screen mode.", 1, std::vector({ L"Windowed", L"Fast", L"Exclusive", L"Safe" })); +ResolutionOption* DisplayResolutionOption = new ResolutionOption(L"width", L"height", RESOLUTION_SECTION, CONFIG_FILE, L"Resolution:", L"Sets the display resolution.", resolution(-1, -1), getScreenResolutionsVec(screenModes), false, RESOPT_INCLUDE_MATCH_SCREEN); +DropdownNumberOption* RefreshRateOption = new DropdownNumberOption(L"refreshrate", RESOLUTION_SECTION, CONFIG_FILE, L"Refresh Rate:", L"Sets the display refresh rate.", 60, getScreenRatesVec(screenModes), true); + +ConfigOptionBase* screenResolutionArray[] = { + DisplayModeDropdown, + DisplayResolutionOption, + //new DropdownNumberOption(L"bitdepth", RESOLUTION_SECTION, CONFIG_FILE, L"Bit Depth:", L"Sets the display bit depth.", 32, getScreenDepthsVec(screenModes), true), + RefreshRateOption, +}; + +BooleanOption* InternalResolutionCheckbox = new BooleanOption(L"r.enable", RESOLUTION_SECTION, CONFIG_FILE, L"Enable", L"Enable or disable custom internal resolution.", false, false); +ResolutionOption* InternalResolutionOption = new ResolutionOption(L"r.width", L"r.height", RESOLUTION_SECTION, CONFIG_FILE, L"Resolution:", L"Sets the internal resolution (instead of 1280x720).", resolution(1920, 1080), internalResOptions, true, RESOPT_INCLUDE_MATCH_WINDOW); + +ConfigOptionBase* internalResolutionArray[] = { + InternalResolutionCheckbox, + InternalResolutionOption +}; + +ConfigOptionBase* graphicsArray[] = { + new DropdownOption(L"model", L"GPU", CONFIG_FILE, L"NVIDIA GPU:", L"Select your NVIDIA GPU's architecture to apply the necessary workarounds.\n\nNOTE: Automatic detection does not currently work on GNU/Linux.", -1, std::vector({ L"Automatic", L"Kepler", L"Maxwell/Pascal", L"Turing", L"Ampere" }), -1), + new BooleanOption(L"TAA", GRAPHICS_SECTION, CONFIG_FILE, L"TAA", L"Temporal Anti-Aliasing", true, false), + new BooleanOption(L"MLAA", GRAPHICS_SECTION, CONFIG_FILE, L"MLAA", L"Morphological Anti-Aliasing", true, false), + new DropdownOption(L"MAG", GRAPHICS_SECTION, CONFIG_FILE, L"Filter:", L"Image filter.\n\nBilinear: default filter\nNearest-neighbour: sharpest, but blocky\nSharpen: sharp filter\nCone: smooth filter", 0, std::vector({ L"Bilinear", L"Nearest-neighbour", L"Sharpen", L"Cone" })), + new BooleanOption(L"DOF", GRAPHICS_SECTION, CONFIG_FILE, L"Depth of Field", L"Blurs the background. Disable for better performance.", true, false), + new BooleanOption(L"reflections", GRAPHICS_SECTION, CONFIG_FILE, L"Reflections", L"Enable or disable reflections.", true, false), + new ResolutionOption(L"reflect_res_width", L"reflect_res_height", GRAPHICS_SECTION, CONFIG_FILE, L"Reflection Res:", L"Sets the reflection buffer resolution (instead of 512x256).", resolution(512, 256), std::vector({resolution(256,256), resolution(512,256), resolution(512,512), resolution(1024,1024), resolution(2048,2048), resolution(4096,4096)}), true, (ResolutionOptionOpts)0), + new ResolutionOption(L"refract_res_width", L"refract_res_height", GRAPHICS_SECTION, CONFIG_FILE, L"Refraction Res:", L"Sets the refraction buffer resolution (instead of 512x256).", resolution(512, 256), std::vector({resolution(256,256), resolution(512,256), resolution(512,512), resolution(1024,1024), resolution(2048,2048), resolution(4096,4096)}), true, (ResolutionOptionOpts)0), + new NumericOption(L"gamma", GRAPHICS_SECTION, CONFIG_FILE, L"Gamma:", L"Increase to darken shadows.\nSet to 125 for a console-like experience.\n\nDefault: 0 or 100", 100, 0, 200), + new BooleanOption(L"shadows", GRAPHICS_SECTION, CONFIG_FILE, L"Shadows", L"Enable or disable shadows.", true, false), + new BooleanOption(L"punchthrough", GRAPHICS_SECTION, CONFIG_FILE, L"Transparent Meshes", L"Show transparent meshes.", true, false), + new BooleanOption(L"glare", GRAPHICS_SECTION, CONFIG_FILE, L"Glare", L"Enable or disable glare.", true, false), + new BooleanOption(L"shader", GRAPHICS_SECTION, CONFIG_FILE, L"Shader", L"Enable or disable high-quality shaders.", true, false), + new DropdownOption(L"NPR1", GRAPHICS_SECTION, CONFIG_FILE, L"Toon (F9):", L"NPR1 shader\n\nPress F9 to toggle.", 0, std::vector({ L"Default", L"Force on", L"Force off" })), + new BooleanOption(L"2D", GRAPHICS_SECTION, CONFIG_FILE, L"Disable 3D rendering", L"Disable all 3D passes.\n\nWARNING: The extended data will be deleted unless Prevent Data Deletion is enabled.", false, false), + +}; + +ConfigOptionBase* optionsArray[] = { + new OptionMetaSectionLabel(L"Compatibility"), + new BooleanOption(L"no_movies", PATCHES_SECTION, CONFIG_FILE, L"Disable Movies", L"Disable movies (enable this if the game hangs when loading certain PVs).", false, false), + new BooleanOption(L"mp4_movies", PATCHES_SECTION, CONFIG_FILE, L"Custom MP4 Adv Movies", L"Enable MP4 (instead of WMV) advertise/attract movies.", false, false), + new BooleanOption(L"cursor", PATCHES_SECTION, CONFIG_FILE, L"Cursor", L"Enable or disable the mouse cursor.", true, false), + new BooleanOption(L"stereo", PATCHES_SECTION, CONFIG_FILE, L"Stereo", L"Use 2 channels instead of 4 (when not using DivaSound).", true, false), + new OptionMetaSeparator(), + new OptionMetaSpacer(8), + + new OptionMetaSectionLabel(L"Controller Options"), + new BooleanOption(L"rumble", KEYCONFIG_SECTION, KEYCONFIG_FILE, L"XInput Rumble", L"Enables rumble during chainslides.", true, true), + new NumericOption(L"xinput_rumble_intensity_left", KEYCONFIG_SECTION, KEYCONFIG_FILE, L"Left motor:", L"Left rumble motor intensity (XInput).\n\nDefault: 8000", 8000, 0, USHRT_MAX), + new NumericOption(L"xinput_rumble_intensity_right", KEYCONFIG_SECTION, KEYCONFIG_FILE, L"Right motor:", L"Right rumble motor intensity (XInput).\n\nDefault: 4000", 4000, 0, USHRT_MAX), + new NumericOption(L"xinput_preferred", KEYCONFIG_SECTION, KEYCONFIG_FILE, L"XInput Controller Num:", L"Sets the preferred XInput controller.\nIf unavailable, the next connected controller is used.", 0, 0, 3), + new BooleanOption(L"hardware_slider", PATCHES_SECTION, CONFIG_FILE, L"Use Hardware Slider", L"Enable this if using a real arcade slider.\n(set the slider to port COM11)", false, false), + new OptionMetaSeparator(), + new OptionMetaSpacer(8), + + new OptionMetaSectionLabel(L"PV Selector"), + new DropdownOption(L"quick_start", PATCHES_SECTION, CONFIG_FILE, L"Quick Start:", L"Skip one or more menus.", 1, std::vector({ L"Disabled", L"Guest", L"Guest + Normal" })), + new BooleanOption(L"no_scrolling_sfx", PATCHES_SECTION, CONFIG_FILE, L"Disable Scrolling SFX", L"Disable the scrolling sound effect.", false, false), + new BooleanOption(L"unlock_pseudo", PATCHES_SECTION, CONFIG_FILE, L"Unlock PSEUDO modules (incomplete)", L"Lets you play any PV with any performer.\n(incomplete, recommended modules will default to Miku)", false, false), + new BooleanOption(L"card", PATCHES_SECTION, CONFIG_FILE, L"Unlock card menu (incomplete)", L"Enables the card menu.\n(incomplete, it doesn't bypass the card prompt)", false, false), + new OptionMetaSeparator(), + new OptionMetaSpacer(8), + + new OptionMetaSectionLabel(L"Stages/Songs"), + new NumericOption(L"Enhanced_Stage_Manager", PATCHES_SECTION, CONFIG_FILE, L"Number of Stages:", L"Set the number of stages (0 = default).", 0, 0, INT_MAX), + new BooleanOption(L"Enhanced_Stage_Manager_Encore", PATCHES_SECTION, CONFIG_FILE, L"Encore", L"Enable encore stages.", true, false), + new BooleanOption(L"sing_missed", PATCHES_SECTION, CONFIG_FILE, L"Sing Missed", L"Sing missed notes.", false, false), + new BooleanOption(L"autopause", KEYCONFIG_SECTION, KEYCONFIG_FILE, L"Pause Automatically", L"Pause when focus is lost.", true, true), + new OptionMetaSeparator(), + new OptionMetaSpacer(8), + + new OptionMetaSectionLabel(L"PV Customization"), + new DropdownOption(L"force_mouth", PATCHES_SECTION, CONFIG_FILE, L"Mouth Type:", L"Change the mouth animations.", 0, std::vector({ L"Default", L"Force PDA", L"Force FT" })), + new DropdownOption(L"force_expressions", PATCHES_SECTION, CONFIG_FILE, L"Expression Type:", L"Change the expressions.", 0, std::vector({ L"Default", L"Force PDA", L"Force FT" })), + new DropdownOption(L"force_look", PATCHES_SECTION, CONFIG_FILE, L"Look Type:", L"Change the look animations.", 0, std::vector({ L"Default", L"Force PDA", L"Force FT" })), + new BooleanOption(L"no_hand_scaling", PATCHES_SECTION, CONFIG_FILE, L"No Hand Scaling", L"Disable hand scaling.", false, false), + new NumericOption(L"default_hand_size_uint", PATCHES_SECTION, CONFIG_FILE, L"Default Hand Size:", L"0-10000: default\n12200: PDA", 0, 0, INT_MAX), + new OptionMetaSeparator(), + new OptionMetaSpacer(8), + + new OptionMetaSectionLabel(L"UI Elements"), + new BooleanOption(L"hide_volume", PATCHES_SECTION, CONFIG_FILE, L"Hide Volume Buttons", L"Hide the volume and SE control buttons.", false, false), + new BooleanOption(L"no_pv_ui", PATCHES_SECTION, CONFIG_FILE, L"Disable PV UI", L"Remove the photo controls during PV playback.", false, false), + new BooleanOption(L"hide_pv_watermark", PATCHES_SECTION, CONFIG_FILE, L"Hide PV Watermark", L"Hide the watermark that's usually shown in PV viewing mode.", false, false), + new DropdownOption(L"status_icons", PATCHES_SECTION, CONFIG_FILE, L"Top-Right Corner Icons:", L"Set the state of card reader and network status icons.", 3, std::vector({ L"Default", L"Hidden", L"Error", L"OK", L"Partial OK" })), + new BooleanOption(L"no_lyrics", PATCHES_SECTION, CONFIG_FILE, L"Disable Lyrics", L"Disable showing lyrics.", false, false), + new BooleanOption(L"no_error", PATCHES_SECTION, CONFIG_FILE, L"Disable Error Banner", L"Disable the error banner on the attract screen.", true, false), + new BooleanOption(L"hide_freeplay", PATCHES_SECTION, CONFIG_FILE, L"Hide \"FREE PLAY\"/\"CREDIT(S)\"", L"Hide the \"FREE PLAY\"/\"CREDIT(S)\" text.", false, false), + new BooleanOption(L"freeplay", PATCHES_SECTION, CONFIG_FILE, L"FREE PLAY", L"Show \"FREE PLAY\" instead of \"CREDIT(S)\" and don't require credits.", true, false), + new BooleanOption(L"pdloadertext", PATCHES_SECTION, CONFIG_FILE, L"PD Loader FREE PLAY", L"Show \"PD Loader\" instead of \"FREE PLAY\".", true, false), + new BooleanOption(L"no_timer", PATCHES_SECTION, CONFIG_FILE, L"Freeze Timer", L"Disable the timer.", true, false), + new BooleanOption(L"no_timer_sprite", PATCHES_SECTION, CONFIG_FILE, L"Disable Timer Sprite", L"Disable the timer sprite.", true, false), + new OptionMetaSeparator(), + new OptionMetaSpacer(8), + + new OptionMetaSectionLabel(L"Framerate"), + new BooleanOption(L"FPS.Limit.LightMode", GRAPHICS_SECTION, CONFIG_FILE, L"Use Lightweight Limiter", L"Makes the FPS limiter use less CPU.\nMay have less consistent performance.", true, false), + new NumericOption(L"FPS.Limit", GRAPHICS_SECTION, CONFIG_FILE, L"FPS Limit:", L"Allows you to set a frame rate cap. Set to -1 to unlock the frame rate.", 60, -1, INT_MAX), + new NumericOption(L"frm.motion.rate", GRAPHICS_SECTION, CONFIG_FILE, L"FRM Motion Rate:", L"Sets the motion rate (fps) for the Frame Rate Manager component.\nLarger values should be smoother, but more CPU intensive and possibly buggier.", 300, 1, INT_MAX), + new OptionMetaSeparator(), + new OptionMetaSpacer(8), + + new OptionMetaSectionLabel(L"Advanced Compatibility"), + new BooleanOption(L"opengl_patch_a", LAUNCHER_SECTION, CONFIG_FILE, L"OpenGL Patch A", L"Ignores some OpenGL-related errors. Don't use both patches at the same time unless you're know what you're doing.", false, false), + new BooleanOption(L"opengl_patch_b", LAUNCHER_SECTION, CONFIG_FILE, L"OpenGL Patch B", L"Ignores some OpenGL-related errors. Don't use both patches at the same time unless you're know what you're doing.", false, false), + new OptionMetaSeparator(), + new OptionMetaSpacer(8), + + new OptionMetaSectionLabel(L"Loader"), + new BooleanOption(L"custom_patches", PATCHES_SECTION, CONFIG_FILE, L"Enable Custom Patches", L"Enables all custom patches.", true, false), + new BooleanOption(L"prevent_data_deletion", PATCHES_SECTION, CONFIG_FILE, L"Prevent Data Deletion", L"Prevents the game from deleting files.", false, false), + new OptionMetaSeparator(), + new OptionMetaSpacer(8), + + new OptionMetaSectionLabel(L"Launcher"), + new BooleanOption(L"dark_launcher", LAUNCHER_SECTION, CONFIG_FILE, L"Dark Launcher", L"Sets the dark colour scheme in the launcher.", false, false), + new BooleanOption(L"acrylic_blur", LAUNCHER_SECTION, CONFIG_FILE, L"Acrylic Blur", L"Enables acrylic blur in the launcher on Windows 10 20H2 or later.", false, false), + new BooleanOption(L"no_gpu_dialog", LAUNCHER_SECTION, CONFIG_FILE, L"Disable GPU Warning", L"Disables the warning dialog for unsupported GPUs.", false, false), + //new BooleanOption(L"ignore_exe_checksum", PATCHES_SECTION, CONFIG_FILE, L"Ignore exe checksum", L"Use at your own risk.", false, false), + new StringOption(L"command_line", LAUNCHER_SECTION, CONFIG_FILE, L"Command Line:", L"Allows setting command line parameters for the game when using the launcher.\nDisabling the launcher will bypass this.", L"", false), + new BooleanOption(L"use_divahook_bat", LAUNCHER_SECTION, CONFIG_FILE, L"Use divahook.bat/start.bat", L"Launches divahook.bat/start.bat intead of diva.exe.", false, false), +}; + +ConfigOptionBase* playerdataArray[] = { + new StringOption(L"player_name", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Player Name:", L"Player name shown in game.", L"NO-NAME", true), + new StringOption(L"level_name", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Level Name:", L"Level (plate) name shown in game.", L"忘れないでね私の声を", true), + + new NumericOption(L"level_plate_id", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Level Plate:", L"Sets the level background image (plate).", 0, 0, INT_MAX), + new NumericOption(L"level_plate_effect", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Level Plate Effect:", L"Sets the effect on the level background image (plate).", -1, -1, 2), + new NumericOption(L"skin_equip ", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Skin:", L"Sets the gameplay UI skin.", 0, 0, INT_MAX), + + new NumericOption(L"btn_se_equip", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Button Sound:", L"Sets the sound effect for buttons.\n-1 = song default", -1, -1, INT_MAX), + new NumericOption(L"slide_se_equip", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Slide Sound:", L"Sets the sound effect for slides.\n-1 = song default", -1, -1, INT_MAX), + new NumericOption(L"chainslide_se_equip", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Chainslide Sound:", L"Sets the sound effect for chain slides.\n-1 = song default", -1, -1, INT_MAX), + new NumericOption(L"slidertouch_se_equip", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Slider Touch Sound:", L"Sets the sound effect for touching the slider with no note.\n-1 = song default", -1, -1, INT_MAX), + new BooleanOption(L"act_toggle", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Button SE", L"Enables button/slider sounds.", true, true), + + new BooleanOption(L"border_great", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Clear Border (Great)", L"Shows the clear border for a great rating on the progress bar.", true, true), + new BooleanOption(L"border_excellent", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Clear Border (Excellent)", L"Shows the clear border for an excellent rating on the progress bar.", true, true), + new BooleanOption(L"border_rival", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Clear Border (Rival)", L"Shows the clear border for beating your rival on the progress bar.", false, true), + + new BooleanOption(L"use_card", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Use Card", L"Enables IC card. This allows module selection.", false, true), + new BooleanOption(L"module_card_workaround", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Module Selection Workaround", L"Allows module selection without card and tries to improve menu performance.\n(BETA)", true, true), + new BooleanOption(L"use_pv_module_equip ", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Song Specific Modules", L"Allows song-specific module selection.", false, true), + new BooleanOption(L"use_pv_skin_equip ", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Song Specific Skins", L"Allows song-specific skin settings.\nValues stored in skins.ini", false, true), + new BooleanOption(L"use_pv_sfx_equip ", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Song Specific Sound Effects", L"Allows song-specific sound effect settings.\nValues stored in sfx.ini", false, true), + + new BooleanOption(L"gamemode_options", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Game Modifiers", L"Allows use of game mode modifiers (hi-speed, hidden, and sudden).", true, true), +}; + + +ConfigOptionBase* componentsArray[] = { + new BooleanOption(L"input_emulator", COMPONENTS_SECTION, COMPONENTS_FILE, L"Input Emulator", L"Emulates input through keyboard and/or mouse.", false, true), + new BooleanOption(L"touch_slider_emulator", COMPONENTS_SECTION, COMPONENTS_FILE, L"Slider Emulator", L"Emulates slider through keyboard and/or mouse.", false, true), + new BooleanOption(L"touch_panel_emulator", COMPONENTS_SECTION, COMPONENTS_FILE, L"Touch Panel Emulator", L"Emulates touch panel through mouse.", false, true), + + new BooleanOption(L"player_data_manager", COMPONENTS_SECTION, COMPONENTS_FILE, L"Player Data Manager", L"Loads user-defined values into the PlayerData struct.\nRequired for modules and game mode modifiers.", false, true), + + new BooleanOption(L"frame_rate_manager", COMPONENTS_SECTION, COMPONENTS_FILE, L"Frame Rate Manager", L"Adjusts animations to the correct speed at different frame rates.\nOnly needed when FPS isn't locked at 60.", false, true), + + new BooleanOption(L"fast_loader", COMPONENTS_SECTION, COMPONENTS_FILE, L"Fast Loader", L"Skip or speed up unnecessary loading steps.", false, true), + + new NumericOption(L"fast_loader_speed", COMPONENTS_SECTION, COMPONENTS_FILE, L"Fast Loader Speed", L"Set this to 4 or less when playing online.\nDefault: 39", 39, 2, 1024), + + new BooleanOption(L"camera_controller", COMPONENTS_SECTION, COMPONENTS_FILE, L"Camera Controller", L"Enables freecam (toggled using F3).\nWASD to move, SPACE/CTRL for up/down, Q/R to rotate, R/F for zoom.\nHolding SHIFT/ALT changes control speed.", false, true), + + new BooleanOption(L"scale_component", COMPONENTS_SECTION, COMPONENTS_FILE, L"Scale Component", L"Scales the graphics output framebuffer to fill the screen/window.", false, true), + + new BooleanOption(L"debug_component", COMPONENTS_SECTION, COMPONENTS_FILE, L"Debug Component", L"Allows for changing game state (F4-F8 keys), using dev GUI and tests, and speeding up 2d animations/menus (hold SHIFT+TAB).", false, true), + + new BooleanOption(L"target_inspector", COMPONENTS_SECTION, COMPONENTS_FILE, L"Target Inspector", L"Enables hold transfers.", false, true), + + new BooleanOption(L"score_saver", COMPONENTS_SECTION, COMPONENTS_FILE, L"Score Saver", L"Saves high scores to plugins/scores.ini.", false, true), + + new BooleanOption(L"pause", COMPONENTS_SECTION, COMPONENTS_FILE, L"Pause", L"Adds a pause menu.", false, true), +}; + +bool IsLineInFile(LPCSTR searchLine, LPCWSTR fileName) +{ + bool result = false; + + std::ifstream fileStream(fileName); + + if (!fileStream.is_open()) + return false; + + std::string line; + + // check for BOM + std::getline(fileStream, line); + if (line.size() >= 3 && line.rfind("\xEF\xBB\xBF", 0) == 0) + fileStream.seekg(3); + else + fileStream.seekg(0); + + while (std::getline(fileStream, line)) + { + if (line.compare(searchLine) == 0) + { + result = true; + break; + } + } + + fileStream.close(); + return result; +} + +void PrependFile(LPCSTR newStr, LPCWSTR fileName) +{ + std::fstream fileStream(fileName); + + if (!fileStream.is_open()) + return; + + + std::string origStr; + + // this is apparently more efficient than just going straight into the string + fileStream.seekg(0, std::ios::end); + origStr.reserve(fileStream.tellg()); + fileStream.seekg(0, std::ios::beg); + + // check for BOM + std::string BOMcheckLine; + std::getline(fileStream, BOMcheckLine); + if (BOMcheckLine.size() >= 3 && BOMcheckLine.rfind("\xEF\xBB\xBF", 0) == 0) + fileStream.seekg(3); + else + fileStream.seekg(0); + + origStr.assign((std::istreambuf_iterator(fileStream)), std::istreambuf_iterator()); + + + std::string outStr = newStr; + outStr += origStr; + + fileStream.seekg(0, std::ios::beg); + fileStream << outStr; + fileStream.close(); +} + + +struct PluginInfo { + HMODULE handle; + std::wstring filename; + std::wstring name; + std::wstring description; + std::wstring builddate; + std::vector configopts; +}; +std::vector LoadPlugins() +{ + std::vector outvec; + + HANDLE hFind; + WIN32_FIND_DATAW ffd; + + hFind = FindFirstFileW((PLUGINS_DIR + L"\\*.dva").c_str(), &ffd); + if (hFind != INVALID_HANDLE_VALUE) { + do { + if (!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) + { + auto pos = wcslen(ffd.cFileName); + + if (ffd.cFileName[pos - 4] == '.' && + (ffd.cFileName[pos - 3] == 'd' || ffd.cFileName[pos - 3] == 'D') && + (ffd.cFileName[pos - 2] == 'v' || ffd.cFileName[pos - 2] == 'V') && + (ffd.cFileName[pos - 1] == 'a' || ffd.cFileName[pos - 1] == 'A')) + { + PluginInfo thisplugin; + thisplugin.handle = LoadLibraryW((PLUGINS_DIR + L"\\" + ffd.cFileName).c_str()); + thisplugin.filename = ffd.cFileName; + + if (thisplugin.handle == NULL) + continue; + + auto nameFunc = (LPCWSTR(*)())GetProcAddress(thisplugin.handle, "GetPluginName"); + auto descFunc = (LPCWSTR(*)())GetProcAddress(thisplugin.handle, "GetPluginDescription"); + auto dateFunc = (LPCWSTR(*)())GetProcAddress(thisplugin.handle, "GetBuildDate"); + auto optsFunc = (PluginConfig::PluginConfigArray(*)())GetProcAddress(thisplugin.handle, "GetPluginOptions"); + + if (nameFunc != NULL) + thisplugin.name = nameFunc(); + else + thisplugin.name = thisplugin.filename; + + if (descFunc != NULL) + thisplugin.description = descFunc(); + else + thisplugin.description = (thisplugin.filename + L" Plugin").c_str(); + + if (dateFunc != NULL) + thisplugin.builddate = dateFunc(); + else + thisplugin.builddate = L"Unknown"; + + thisplugin.description += L"\n\nVersion: " + thisplugin.builddate; + + if (optsFunc != NULL) + thisplugin.configopts = PluginConfig::GetConfigOptionVec(optsFunc()); + + // sometimes this might screw with custom button config, so let's just not free stuff + // FreeLibrary(thisplugin.handle); + + outvec.push_back(thisplugin); + } + } + } while (FindNextFileW(hFind, &ffd)); + FindClose(hFind); + } + + return outvec; +} +// don't load until actually needed to avoid loading disabled plugins +std::vector AllPlugins; // = LoadPlugins(); + +std::vector GetPluginOptions(std::vector* plugins) +{ + std::vector outvec; + + for (PluginInfo &pi : *plugins) + { + PluginOption* opt = new PluginOption(pi.filename.c_str(), L"plugins", CONFIG_FILE, pi.name.c_str(), pi.description.c_str(), true, pi.configopts); + outvec.push_back(opt); + } + + return outvec; +} +// don't load until actually needed to avoid loading disabled plugins +std::vector AllPluginOpts; // = GetPluginOptions(&AllPlugins); + +std::vector LoadCustom() +{ + std::vector outvec; + + HANDLE hFind; + WIN32_FIND_DATAW ffd; + + hFind = FindFirstFileW((PATCHES_DIR + L"\\*.p?").c_str(), &ffd); + if (hFind != INVALID_HANDLE_VALUE) { + do { + if (!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) + { + auto pos = wcslen(ffd.cFileName); + + if ((ffd.cFileName[pos - 2] == '.' && (ffd.cFileName[pos - 1] == 'p' || ffd.cFileName[pos - 1] == 'P')) || + (ffd.cFileName[pos - 3] == '.' && (ffd.cFileName[pos - 2] == 'p' || ffd.cFileName[pos - 2] == 'P') && (ffd.cFileName[pos - 1] == '2'))) + { + PluginInfo thisplugin; + thisplugin.filename = ffd.cFileName; + + thisplugin.name = thisplugin.filename; + if (thisplugin.filename[pos - 1] == '2') + thisplugin.name.resize(thisplugin.name.size() - 3); + else + thisplugin.name.resize(thisplugin.name.size() - 2); + + thisplugin.description = L"Custom patch"; + + outvec.push_back(thisplugin); + } + } + } while (FindNextFileW(hFind, &ffd)); + FindClose(hFind); + } + + return outvec; +} +std::vector AllCustomPatches; // = LoadCustom(); + +std::vector GetCustomOptions(std::vector* patches) +{ + std::vector outvec; + + for (PluginInfo& pi : *patches) + { + PluginOption* opt = new PluginOption(pi.filename.c_str(), L"plugins", CONFIG_FILE, pi.name.c_str(), pi.description.c_str(), true, pi.configopts); + outvec.push_back(opt); + } + + return outvec; +} +// don't load until actually needed to avoid loading disabled plugins +std::vector AllCustomOpts; // = GetCustomOptions(&AllCustomPatches); + +// used to trick Optimus into switching to the NVIDIA GPU +HMODULE nvcudaModule = LoadLibraryW(L"nvcuda.dll"); +// cuInit actually returns a CUresult, but we don't really care about it +void(WINAPI * cuInit)(unsigned int flags) = (void(WINAPI*)(unsigned int flags))GetProcAddress(nvcudaModule, "cuInit"); + +// needed to close the OpenGL window (freeglut only) +HMODULE glutModule = LoadLibraryW(L"glut32.dll"); +void(__stdcall * glutMainLoopEventDynamic)() = (void(__stdcall*)())GetProcAddress(glutModule, "glutMainLoopEvent"); + + +using namespace PluginConfig; + +extern "C" __declspec(dllexport) LPCWSTR GetPluginName(void) +{ + return L"Launcher"; +} + +extern "C" __declspec(dllexport) LPCWSTR GetPluginDescription(void) +{ + return L"PD Launcher is the window you currently have open.\nYou can disable it if you want, but you'll need to edit config.ini if you ever want to re-enable it."; } \ No newline at end of file diff --git a/source-code/source/plugins/Launcher/ui.h b/source-code/source/plugins/Launcher/ui.h index 1a402de..c563804 100644 --- a/source-code/source/plugins/Launcher/ui.h +++ b/source-code/source/plugins/Launcher/ui.h @@ -1,1219 +1,1220 @@ -#pragma once -#include "framework.h" -#include -#include -#include "TabPadding.h" -#include -#include -#include "SkinnedMessageBox.h" -#include "PluginConfig.h" -#include "GPUModel.h" -#include "WineVer.h" -#include "composition.h" -#include - -namespace Launcher { - - using namespace System; - using namespace System::ComponentModel; - using namespace System::Collections; - using namespace System::Windows::Forms; - using namespace System::Data; - using namespace System::Drawing; - using namespace msclr::interop; - - HWND hWnd; - - /// - /// Summary for ui - /// - public ref class ui : public System::Windows::Forms::Form - { - public: - ui(void) - { - InitializeComponent(); - - hWnd = (HWND)Control::Handle.ToPointer(); - - this->ClientSize = Drawing::Size(444, 323); - TabPadding^ tabpad = gcnew TabPadding(tabControl); - - // if components.ini has no section name, add one - if (!IsLineInFile("[components]", COMPONENTS_FILE)) - { - PrependFile("[components]\n", COMPONENTS_FILE); - } - - // if playerdata.ini has no section name, add one - if (!IsLineInFile("[playerdata]", PLAYERDATA_FILE)) - { - PrependFile("[playerdata]\n", PLAYERDATA_FILE); - } - - // if keyconfig.ini has no section name, add one - if (!IsLineInFile("[keyconfig]", KEYCONFIG_FILE)) - { - PrependFile("[keyconfig]\n", KEYCONFIG_FILE); - } - - - this->panel_ScreenRes->SuspendLayout(); - - // populate options (patches) from array in framework - // (easier than manually setting everything up) - int screenresY = 3; - for (ConfigOptionBase* option : screenResolutionArray) - { - option->hasChanged = ResolutionConfigChanged; - screenresY += option->AddToPanel(panel_ScreenRes, 12, screenresY, toolTip1); - } - ((ComboBox^)ComboBox::FromHandle(DisplayModeDropdown->mainControlHandle))->SelectedIndexChanged += gcnew System::EventHandler(this, &ui::DisplayTypeChangedHandler); - DisplayTypeChangedHandler(this, gcnew EventArgs); // run handler now - this->panel_ScreenRes->ResumeLayout(false); - this->panel_ScreenRes->PerformLayout(); - - - this->panel_IntRes->SuspendLayout(); - - // populate options (patches) from array in framework - // (easier than manually setting everything up) - int intresY = 3; - for (ConfigOptionBase* option : internalResolutionArray) - { - option->hasChanged = ResolutionConfigChanged; - intresY += option->AddToPanel(panel_IntRes, 12, intresY, toolTip1); - } - ((CheckBox^)CheckBox::FromHandle(InternalResolutionCheckbox->mainControlHandle))->CheckedChanged += gcnew System::EventHandler(this, &ui::InternalResEnabledChangedHandler); - InternalResEnabledChangedHandler(this, gcnew EventArgs); // run handler now - this->panel_IntRes->ResumeLayout(false); - this->panel_IntRes->PerformLayout(); - - - this->panel_Details->SuspendLayout(); - - // populate details (patches) from array in framework - // (easier than manually setting everything up) - int detailsY = 3; - for (ConfigOptionBase* option : graphicsArray) - { - option->hasChanged = OptionsConfigChanged; - detailsY += option->AddToPanel(panel_Details, 12, detailsY, toolTip1); - } - trackBar_LagCompensation->Value = GetIniInt(GRAPHICS_SECTION, L"lag_compensation", 0, CONFIG_FILE); - this->panel_Details->ResumeLayout(false); - this->panel_Details->PerformLayout(); - - - this->panel_Patches->SuspendLayout(); - - // populate options (patches) from array in framework - // (easier than manually setting everything up) - int optionsY = 3; - for (ConfigOptionBase* option : optionsArray) - { - option->hasChanged = OptionsConfigChanged; - optionsY += option->AddToPanel(panel_Patches, 12, optionsY, toolTip1); - } - this->panel_Patches->ResumeLayout(false); - this->panel_Patches->PerformLayout(); - - - - this->panel_Playerdata->SuspendLayout(); - - // populate playerdata options from array in framework - // (easier than manually setting everything up) - int playerdataY = 3; - for (ConfigOptionBase* option : playerdataArray) - { - option->hasChanged = PlayerdataConfigChanged; - playerdataY += option->AddToPanel(panel_Playerdata, 12, playerdataY, toolTip1); - } - this->panel_Playerdata->ResumeLayout(false); - this->panel_Playerdata->PerformLayout(); - - - this->panel_Components->SuspendLayout(); - - // populate components from array in framework - // (easier than manually setting everything up) - int componentsY = 3; - for (ConfigOptionBase* component : componentsArray) - { - component->hasChanged = ComponentsConfigChanged; - componentsY += component->AddToPanel(panel_Components, 12, componentsY, toolTip1); - } - this->panel_Components->ResumeLayout(false); - this->panel_Components->PerformLayout(); - - - AllPlugins = LoadPlugins(); - AllPluginOpts = GetPluginOptions(&AllPlugins); - - this->panel_Plugins->SuspendLayout(); - - int pluginsY = 3; - for (ConfigOptionBase* option : AllPluginOpts) - { - option->hasChanged = new bool(false); - pluginsY += option->AddToPanel(panel_Plugins, 12, pluginsY, toolTip1); - } - this->panel_Plugins->ResumeLayout(false); - this->panel_Plugins->PerformLayout(); - - - AllCustomPatches = LoadCustom(); - AllCustomOpts = GetPluginOptions(&AllCustomPatches); - - this->panel_Custom->SuspendLayout(); - - int customY = 3; - for (ConfigOptionBase* custom : AllCustomOpts) - { - custom->hasChanged = new bool(false); - customY += custom->AddToPanel(panel_Custom, 12, customY, toolTip1); - } - - this->panel_Custom->ResumeLayout(false); - this->panel_Custom->PerformLayout(); - - - // trick Optimus into switching to the NVIDIA GPU - if (cuInit != NULL) cuInit(0); - - int argc = 1; - char* argv[1] = { (char*)"" }; - - - updateLagCompMsec(); - - updateStyle(); - - - glutInit(&argc, argv); - int window = glutCreateWindow("glut"); // a context must be created to use glGetString - glutHideWindow(); - - String^ vendor = gcnew String((char*)glGetString(GL_VENDOR)); - vendor = vendor->Replace(" Corporation", ""); // this is useless.. remove it to help ensure the GPU type line fits - String^ renderer = gcnew String((char*)glGetString(GL_RENDERER)); - String^ version = gcnew String((char*)glGetString(GL_VERSION)); - version = version->Replace(" Profile Context", ""); // we don't need this, either - - String^ gpuModel = gcnew String(GPUModel::getGpuName().c_str()); - - String^ wineVersion = gcnew String(WineVer::getWineVer().c_str()); - - int driver_version_major = 1; - int driver_version_minor = 0; - auto version_split = version->Split(' '); - if (version_split->Length > 1) // make sure we don't use the OpenGL version instead of the driver version - { - String^ driver_version = gcnew String(version_split[version_split->Length - 1]); - auto driver_version_split_major_minor = driver_version->Split('.'); - if (driver_version_split_major_minor->Length >= 2) - { - driver_version_major = int::Parse(driver_version_split_major_minor[0]); - driver_version_minor = int::Parse(driver_version_split_major_minor[1]); - } - } - - glutDestroyWindow(window); // destroy the window so it doesn't remain on screen - if (glutMainLoopEventDynamic != NULL) glutMainLoopEventDynamic(); // freeglut needs this - - if (wineVersion != "") - { - this->labelGPU->Text = "Wine " + wineVersion + " (at least 4.12.1 is required)\n"; - } - else this->labelGPU->Text = "GPU Info:\n"; - this->labelGPU->Text += vendor + " " + renderer + "\n"; - this->labelGPU->Text += "OpenGL: " + version + "\n"; - - int linkStart = this->labelGPU->Text->Length; - bool showGpuDialog = false; - if (vendor->Contains("AMD") || vendor->Contains("ATI")) // check OpenGL to get actual GPU being used for vendor check (to get accurate results for iGPU) - { - bool hasNovidia = false; - for (PluginInfo i : AllPlugins) - { - if (i.name == L"Novidia") - hasNovidia = true; - } - - if (hasNovidia) - { - if (wineVersion == "" && (driver_version_major < 21 || (driver_version_major == 21 && driver_version_minor < 6))) - { - this->labelGPU->Text += L"Driver has known issues."; - GPUIssueText = L"The graphics driver you're using has known issues. Please install the latest driver from your GPU vendor's website."; - this->labelGPU->LinkColor = System::Drawing::Color::Orange; - showGpuDialog = true; - } - else - { - this->labelGPU->Text += "Issues: AMD GPU support is unofficial."; - GPUIssueText = "AMD GPUs are not supported without mods.\nThe PD Loader AMDPack seems to be installed, but please keep in mind that it may have issues."; - this->labelGPU->LinkColor = System::Drawing::Color::Yellow; - } - } - else - { - this->labelGPU->Text += "Issues: Mods needed for AMD compatibility!"; - GPUIssueText = "AMD GPUs are not supported without mods.\nThe PD Loader AMDPack can be used to make 3D rendering work. Please download it and follow the included instructions.\n\nIf you have a laptop with an NVIDIA GPU and wish to use it instead of the detected GPU, you may need to set diva.exe to use it in Windows settings or NVIDIA Control Panel."; - this->labelGPU->LinkColor = System::Drawing::Color::Red; - showGpuDialog = true; - } - } - else if (vendor->Contains("NVIDIA")) - { - if (wineVersion == "" && (driver_version_major > 446 && driver_version_major < 460)) - { - this->labelGPU->Text += L"Driver has known issues."; - GPUIssueText = L"The graphics driver you're using has known issues. Please install the latest driver from your GPU vendor's website."; - this->labelGPU->LinkColor = System::Drawing::Color::Orange; - showGpuDialog = true; - } - else if (gpuModel->StartsWith("GA")) // unconfirmed?? - { - this->labelGPU->Text += L"Issues: Ampere GPU detected! Possible noise.\n(Click for more information)"; - GPUIssueText = L"On Ampere GPUs (RTX 30xx), some important character shaders have issues resulting in lines/noise.\nPlease make sure the ShaderPatch plugin is enabled."; - this->labelGPU->LinkColor = System::Drawing::Color::Yellow; - } - else if (gpuModel->StartsWith("TU") || gpuModel->StartsWith("GV")) // let's assume Volta is like Turing for now - { - this->labelGPU->Text += L"Issues: Ampere GPU detected! Possible noise.\n(Click for more information)"; - GPUIssueText = L"On Turing GPUs (GTX 16xx/RTX 20xx), some important character shaders have issues resulting in lines/noise.\nPlease make sure the ShaderPatch plugin is enabled."; - this->labelGPU->LinkColor = System::Drawing::Color::Yellow; - } - else if (gpuModel->StartsWith("GM") || gpuModel->StartsWith("GP")) - { - this->labelGPU->Text += L"Issues: May have minor noise on some stages.\n(Click for more information)"; - GPUIssueText = L"On Maxwell GPUs (~GTX 900) and newer, some minor stage shaders create noise.\nPlease make sure the ShaderPatch plugin is enabled."; - this->labelGPU->LinkColor = System::Drawing::Color::Teal; - } - else if (gpuModel->StartsWith("GK")) - { - this->labelGPU->Text += L"Issues: None."; - GPUIssueText = L"Your GPU should have no issues running the game."; - this->labelGPU->LinkColor = System::Drawing::Color::LightBlue; - } - else if (gpuModel->StartsWith("GF")) - { - if (version[0] < '4') - { - this->labelGPU->Text += L"Issues: Driver too old."; - GPUIssueText = L"Your GPU should be able to run the game, but it looks like your OpenGL version is too old.\nA driver update should fix this."; - this->labelGPU->LinkColor = System::Drawing::Color::Orange; - showGpuDialog = true; - } - else - { - this->labelGPU->Text += L"Issues: No known issues."; - GPUIssueText = L"Your GPU should have no issues running the game, but it is older than the GPU the game was originally designed for (GTX 650 Ti).\nThere may be some issues with graphics.\nPlease report any issues so that they can be analysed and potentially fixed."; - this->labelGPU->LinkColor = System::Drawing::Color::Teal; - } - } - else if (gpuModel->StartsWith("G") || gpuModel->StartsWith("NV") || gpuModel->StartsWith("NB") || gpuModel->StartsWith("N10") || gpuModel->StartsWith("MCP")) - { - this->labelGPU->Text += L"Issues: GPU too old! 3D rendering might be broken.\n(Click for more information)"; - GPUIssueText = L"Your GPU is very old and does not support rendering techniques used by the game.\nYou may be able to play, but graphics will likely have major issues.\nPlease upgrade to a GTX 600 series or later GPU."; - this->labelGPU->LinkColor = System::Drawing::Color::Orange; - showGpuDialog = true; - } - else if (version[0] >= '4' && gpuModel->Length > 0 && !gpuModel->StartsWith("Unk") && !gpuModel->StartsWith("Oth")) - { - this->labelGPU->Text += L"Issues: GPU may be too new.\n(Click for more information)"; - GPUIssueText = L"It looks like your GPU may be too new. Only up to Ampere (RTX 30xx) is currently supported.\nGood news: the game should be capable of running, but shader patches (probably needed) may not support it yet.\nYou will likely see lines/noise on important character shaders and some minor stage shaders.\nPlease report any issues so that ShaderPatch can be updated.\nYou can also try forcing a specific GPU workaround type."; - this->labelGPU->LinkColor = System::Drawing::Color::Orange; - } - else - { - this->labelGPU->Text += L"Issues: Unable to detect GPU architecture.\n(Click for more information)"; - GPUIssueText = L"It looks like you have an NVIDIA GPU, but something went wrong while trying to determine your GPU's architecture (type).\nThis may be a caused by a bug, but it probably indicates potential issues.\nPlease make sure you have a GTX 600 series or later GPU. (GTX 400 series or later should also work)"; - this->labelGPU->LinkColor = System::Drawing::Color::Orange; - showGpuDialog = true; - } - } - else //if (gpuModel->Length == 0 || gpuModel->StartsWith("Unk") || gpuModel->StartsWith("Oth")) - { - this->labelGPU->Text += L"Issues: UNSUPPORTED GPU!"; - GPUIssueText = L"Your graphics card is not supported. Only NVIDIA GPUs are recommended (though AMD ones can be used with mods).\nPlease use a GTX 600 series or later NVIDIA GPU.\n\nIf you have a laptop with an NVIDIA GPU and wish to use it instead of the detected GPU, you may need to set diva.exe to use it in Windows settings or NVIDIA Control Panel.\n\nOwners of other GPUs may be able to run the game using plugins or mods, but 3D graphics will probably not work."; - this->labelGPU->LinkColor = System::Drawing::Color::Red; - showGpuDialog = true; - } - int linkEnd = this->labelGPU->Text->Length - linkStart; - - this->labelGPU->LinkClicked += gcnew System::Windows::Forms::LinkLabelLinkClickedEventHandler(this, &ui::LinkLabelLinkClickedGPUIssueHandler); - this->labelGPU->LinkArea = System::Windows::Forms::LinkArea(linkStart, linkEnd); - - if (showGpuDialog && !nNoGPUDialog) - SkinnedMessageBox::Show(this, GPUIssueText + "\n\nYou can disable this message from the options tab.", "PD Launcher", MessageBoxButtons::OK, MessageBoxIcon::Warning); - } - - protected: - /// - /// Clean up any resources being used. - /// - ~ui() - { - if (components) - { - delete components; - } - } - - void OnPaintBackground(PaintEventArgs e) override - { - } - - /*property System::Windows::Forms::CreateParams^ CreateParams - { - virtual System::Windows::Forms::CreateParams^ get() override - { - System::Windows::Forms::CreateParams^ params = Form::CreateParams; - params->ExStyle |= 0x00200000L; - - return params; - } - }*/ - - void updateLagCompMsec() - { - this->groupBox_Lag->Text = "Lag Compensation (" + this->trackBar_LagCompensation->Value + " msec)"; - } - - void updateStyle() - { - int nDarkLauncher = GetPrivateProfileIntW(LAUNCHER_SECTION, L"dark_launcher", FALSE, CONFIG_FILE); - int nAcrylicLauncher = GetPrivateProfileIntW(LAUNCHER_SECTION, L"acrylic_blur", FALSE, CONFIG_FILE); - - bool useAcrylic = nAcrylicLauncher && setBlur(hWnd, AccentState::ACCENT_ENABLE_ACRYLICBLURBEHIND); - - Color colourBg, colourBg2, colourFg; - - if (nDarkLauncher) - { - setDarkTheme(hWnd); - colourFg = Color::White; - colourBg = Color::FromArgb(32, 32, 32); // tabControl - colourBg2 = Color::FromArgb(25, 25, 25); - } - else - { - setDarkTheme(hWnd, false); - colourFg = Color::FromArgb(64, 64, 64); - colourBg = Color::White; // tabControl - colourBg2 = Color::FromArgb(242, 242, 242); - } - - if (useAcrylic) - { - this->button_Discord->BackColor = colourBg2; - this->button_github->BackColor = colourBg2; - this->button_Wiki->BackColor = colourBg2; - - colourBg2 = Color::FromArgb(255, 0, 255); - } - else - { - setBlur(hWnd, AccentState::ACCENT_DISABLED); - - this->button_Discord->BackColor = Color::Transparent; - this->button_github->BackColor = Color::Transparent; - this->button_Wiki->BackColor = Color::Transparent; - } - - this->tabPage_Resolution->BackColor = colourBg; - this->tabPage_Resolution->ForeColor = colourFg; - this->tabPage_Patches->BackColor = colourBg; - this->tabPage_Patches->ForeColor = colourFg; - this->tabPage_Playerdata->BackColor = colourBg; - this->tabPage_Playerdata->ForeColor = colourFg; - this->tabPage_Plugins->BackColor = colourBg; - this->tabPage_Plugins->ForeColor = colourFg; - this->tabPage_Components->BackColor = colourBg; - this->tabPage_Components->ForeColor = colourFg; - this->creditsTextBox->BackColor = colourBg; - this->creditsTextBox->ForeColor = colourFg; - - this->tabControl->BackColor = colourBg; - this->tabControl->ForeColor = colourFg; - - this->BackColor = colourBg2; - - this->button_Launch->BackColor = colourBg; - this->button_Launch->ForeColor = colourFg; - this->button_Apply->BackColor = colourBg; - this->button_Apply->ForeColor = colourFg; - - this->labelGPU->ForeColor = colourFg; - - this->groupBox_Details->ForeColor = colourFg; - this->groupBox_InternalRes->ForeColor = colourFg; - this->groupBox_Lag->ForeColor = colourFg; - this->groupBox_ScreenRes->ForeColor = colourFg; - } - - private: - - - private: System::Windows::Forms::Button^ button_Launch; - - private: System::Windows::Forms::GroupBox^ groupBox_ScreenRes; - private: System::Windows::Forms::TabControl^ tabControl; - private: System::Windows::Forms::TabPage^ tabPage_Resolution; - private: System::Windows::Forms::GroupBox^ groupBox_InternalRes; - private: System::Windows::Forms::TabPage^ tabPage_Components; - private: System::Windows::Forms::Panel^ panel_Components; - private: System::Windows::Forms::TabPage^ tabPage_Patches; - private: System::Windows::Forms::Panel^ panel_Patches; - private: System::Windows::Forms::TabPage^ tabPage_Plugins; - private: System::Windows::Forms::Panel^ panel_Plugins; - private: System::Windows::Forms::Button^ button_Discord; - private: System::Windows::Forms::Button^ button_github; - private: System::Windows::Forms::TabPage^ tabPage_Playerdata; - private: System::Windows::Forms::Panel^ panel_Playerdata; - private: System::Windows::Forms::ToolTip^ toolTip1; - private: System::Windows::Forms::Panel^ panel_ScreenRes; - private: System::Windows::Forms::Panel^ panel_IntRes; - private: System::Windows::Forms::LinkLabel^ labelGPU; - - - -private: System::Windows::Forms::TabPage^ tabPage_Credits; -private: System::Windows::Forms::TextBox^ creditsTextBox; -private: System::Windows::Forms::GroupBox^ groupBox_Details; -private: System::Windows::Forms::Panel^ panel_Details; -private: System::Windows::Forms::Panel^ panel_Custom; -private: System::Windows::Forms::Button^ button_Apply; -private: System::Windows::Forms::GroupBox^ groupBox_Lag; -private: System::Windows::Forms::TrackBar^ trackBar_LagCompensation; -private: System::Windows::Forms::Button^ button_Wiki; - - - - - - - - - - - - - - - - - - - - - private: System::ComponentModel::IContainer^ components; - - private: - /// - /// Required designer variable. - /// - - -#pragma region Windows Form Designer generated code - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - void InitializeComponent(void) - { - this->components = (gcnew System::ComponentModel::Container()); - System::ComponentModel::ComponentResourceManager^ resources = (gcnew System::ComponentModel::ComponentResourceManager(ui::typeid)); - this->button_Launch = (gcnew System::Windows::Forms::Button()); - this->groupBox_ScreenRes = (gcnew System::Windows::Forms::GroupBox()); - this->panel_ScreenRes = (gcnew System::Windows::Forms::Panel()); - this->tabControl = (gcnew System::Windows::Forms::TabControl()); - this->tabPage_Resolution = (gcnew System::Windows::Forms::TabPage()); - this->groupBox_Lag = (gcnew System::Windows::Forms::GroupBox()); - this->trackBar_LagCompensation = (gcnew System::Windows::Forms::TrackBar()); - this->groupBox_Details = (gcnew System::Windows::Forms::GroupBox()); - this->panel_Details = (gcnew System::Windows::Forms::Panel()); - this->labelGPU = (gcnew System::Windows::Forms::LinkLabel()); - this->groupBox_InternalRes = (gcnew System::Windows::Forms::GroupBox()); - this->panel_IntRes = (gcnew System::Windows::Forms::Panel()); - this->tabPage_Patches = (gcnew System::Windows::Forms::TabPage()); - this->panel_Patches = (gcnew System::Windows::Forms::Panel()); - this->tabPage_Playerdata = (gcnew System::Windows::Forms::TabPage()); - this->panel_Playerdata = (gcnew System::Windows::Forms::Panel()); - this->tabPage_Components = (gcnew System::Windows::Forms::TabPage()); - this->panel_Components = (gcnew System::Windows::Forms::Panel()); - this->tabPage_Plugins = (gcnew System::Windows::Forms::TabPage()); - this->panel_Custom = (gcnew System::Windows::Forms::Panel()); - this->panel_Plugins = (gcnew System::Windows::Forms::Panel()); - this->tabPage_Credits = (gcnew System::Windows::Forms::TabPage()); - this->creditsTextBox = (gcnew System::Windows::Forms::TextBox()); - this->button_Discord = (gcnew System::Windows::Forms::Button()); - this->button_github = (gcnew System::Windows::Forms::Button()); - this->toolTip1 = (gcnew System::Windows::Forms::ToolTip(this->components)); - this->button_Apply = (gcnew System::Windows::Forms::Button()); - this->button_Wiki = (gcnew System::Windows::Forms::Button()); - this->groupBox_ScreenRes->SuspendLayout(); - this->tabControl->SuspendLayout(); - this->tabPage_Resolution->SuspendLayout(); - this->groupBox_Lag->SuspendLayout(); - (cli::safe_cast(this->trackBar_LagCompensation))->BeginInit(); - this->groupBox_Details->SuspendLayout(); - this->groupBox_InternalRes->SuspendLayout(); - this->tabPage_Patches->SuspendLayout(); - this->tabPage_Playerdata->SuspendLayout(); - this->tabPage_Components->SuspendLayout(); - this->tabPage_Plugins->SuspendLayout(); - this->tabPage_Credits->SuspendLayout(); - this->SuspendLayout(); - // - // button_Launch - // - this->button_Launch->BackColor = System::Drawing::Color::White; - this->button_Launch->FlatAppearance->BorderColor = System::Drawing::SystemColors::Control; - this->button_Launch->FlatStyle = System::Windows::Forms::FlatStyle::Flat; - this->button_Launch->Location = System::Drawing::Point(344, 778); - this->button_Launch->Margin = System::Windows::Forms::Padding(6); - this->button_Launch->Name = L"button_Launch"; - this->button_Launch->Size = System::Drawing::Size(434, 46); - this->button_Launch->TabIndex = 20; - this->button_Launch->Text = L"Launch"; - this->button_Launch->UseVisualStyleBackColor = false; - this->button_Launch->Click += gcnew System::EventHandler(this, &ui::Button_Launch_Click); - // - // groupBox_ScreenRes - // - this->groupBox_ScreenRes->Controls->Add(this->panel_ScreenRes); - this->groupBox_ScreenRes->FlatStyle = System::Windows::Forms::FlatStyle::Flat; - this->groupBox_ScreenRes->Location = System::Drawing::Point(10, 12); - this->groupBox_ScreenRes->Margin = System::Windows::Forms::Padding(6); - this->groupBox_ScreenRes->Name = L"groupBox_ScreenRes"; - this->groupBox_ScreenRes->Padding = System::Windows::Forms::Padding(6); - this->groupBox_ScreenRes->Size = System::Drawing::Size(526, 226); - this->groupBox_ScreenRes->TabIndex = 10; - this->groupBox_ScreenRes->TabStop = false; - this->groupBox_ScreenRes->Text = L"Screen Resolution"; - // - // panel_ScreenRes - // - this->panel_ScreenRes->AutoScroll = true; - this->panel_ScreenRes->Location = System::Drawing::Point(10, 38); - this->panel_ScreenRes->Margin = System::Windows::Forms::Padding(6); - this->panel_ScreenRes->Name = L"panel_ScreenRes"; - this->panel_ScreenRes->Size = System::Drawing::Size(506, 178); - this->panel_ScreenRes->TabIndex = 0; - // - // tabControl - // - this->tabControl->Controls->Add(this->tabPage_Resolution); - this->tabControl->Controls->Add(this->tabPage_Patches); - this->tabControl->Controls->Add(this->tabPage_Playerdata); - this->tabControl->Controls->Add(this->tabPage_Components); - this->tabControl->Controls->Add(this->tabPage_Plugins); - this->tabControl->Controls->Add(this->tabPage_Credits); - this->tabControl->Location = System::Drawing::Point(0, 0); - this->tabControl->Margin = System::Windows::Forms::Padding(6); - this->tabControl->Name = L"tabControl"; - this->tabControl->SelectedIndex = 0; - this->tabControl->Size = System::Drawing::Size(1120, 768); - this->tabControl->TabIndex = 10; - // - // tabPage_Resolution - // - this->tabPage_Resolution->BackColor = System::Drawing::Color::White; - this->tabPage_Resolution->BackgroundImageLayout = System::Windows::Forms::ImageLayout::Stretch; - this->tabPage_Resolution->Controls->Add(this->groupBox_Lag); - this->tabPage_Resolution->Controls->Add(this->groupBox_Details); - this->tabPage_Resolution->Controls->Add(this->labelGPU); - this->tabPage_Resolution->Controls->Add(this->groupBox_InternalRes); - this->tabPage_Resolution->Controls->Add(this->groupBox_ScreenRes); - this->tabPage_Resolution->ForeColor = System::Drawing::Color::FromArgb(static_cast(static_cast(64)), - static_cast(static_cast(64)), static_cast(static_cast(64))); - this->tabPage_Resolution->Location = System::Drawing::Point(8, 39); - this->tabPage_Resolution->Margin = System::Windows::Forms::Padding(6); - this->tabPage_Resolution->Name = L"tabPage_Resolution"; - this->tabPage_Resolution->Padding = System::Windows::Forms::Padding(6); - this->tabPage_Resolution->Size = System::Drawing::Size(1104, 721); - this->tabPage_Resolution->TabIndex = 0; - this->tabPage_Resolution->Text = L"Graphics"; - // - // groupBox_Lag - // - this->groupBox_Lag->Controls->Add(this->trackBar_LagCompensation); - this->groupBox_Lag->FlatStyle = System::Windows::Forms::FlatStyle::Flat; - this->groupBox_Lag->Location = System::Drawing::Point(10, 564); - this->groupBox_Lag->Margin = System::Windows::Forms::Padding(6); - this->groupBox_Lag->Name = L"groupBox_Lag"; - this->groupBox_Lag->Padding = System::Windows::Forms::Padding(6); - this->groupBox_Lag->Size = System::Drawing::Size(526, 140); - this->groupBox_Lag->TabIndex = 21; - this->groupBox_Lag->TabStop = false; - this->groupBox_Lag->Text = L"Lag Compensation"; - // - // trackBar_LagCompensation - // - this->trackBar_LagCompensation->LargeChange = 1; - this->trackBar_LagCompensation->Location = System::Drawing::Point(14, 40); - this->trackBar_LagCompensation->Margin = System::Windows::Forms::Padding(6); - this->trackBar_LagCompensation->Maximum = 500; - this->trackBar_LagCompensation->Name = L"trackBar_LagCompensation"; - this->trackBar_LagCompensation->Size = System::Drawing::Size(500, 90); - this->trackBar_LagCompensation->TabIndex = 0; - this->trackBar_LagCompensation->ValueChanged += gcnew System::EventHandler(this, &ui::trackBar_LagCompensation_ValueChanged); - // - // groupBox_Details - // - this->groupBox_Details->Controls->Add(this->panel_Details); - this->groupBox_Details->FlatStyle = System::Windows::Forms::FlatStyle::Flat; - this->groupBox_Details->Location = System::Drawing::Point(548, 12); - this->groupBox_Details->Margin = System::Windows::Forms::Padding(6); - this->groupBox_Details->Name = L"groupBox_Details"; - this->groupBox_Details->Padding = System::Windows::Forms::Padding(6); - this->groupBox_Details->Size = System::Drawing::Size(544, 692); - this->groupBox_Details->TabIndex = 11; - this->groupBox_Details->TabStop = false; - this->groupBox_Details->Text = L"Details"; - // - // panel_Details - // - this->panel_Details->AutoScroll = true; - this->panel_Details->Location = System::Drawing::Point(10, 38); - this->panel_Details->Margin = System::Windows::Forms::Padding(6); - this->panel_Details->Name = L"panel_Details"; - this->panel_Details->Size = System::Drawing::Size(522, 642); - this->panel_Details->TabIndex = 0; - // - // labelGPU - // - this->labelGPU->AutoSize = true; - this->labelGPU->BackColor = System::Drawing::Color::Transparent; - this->labelGPU->ForeColor = System::Drawing::Color::Black; - this->labelGPU->Location = System::Drawing::Point(10, 418); - this->labelGPU->Margin = System::Windows::Forms::Padding(4, 0, 4, 0); - this->labelGPU->MinimumSize = System::Drawing::Size(526, 26); - this->labelGPU->Name = L"labelGPU"; - this->labelGPU->Size = System::Drawing::Size(526, 26); - this->labelGPU->TabIndex = 21; - this->labelGPU->TextAlign = System::Drawing::ContentAlignment::MiddleLeft; - // - // groupBox_InternalRes - // - this->groupBox_InternalRes->Controls->Add(this->panel_IntRes); - this->groupBox_InternalRes->FlatStyle = System::Windows::Forms::FlatStyle::Flat; - this->groupBox_InternalRes->Location = System::Drawing::Point(10, 248); - this->groupBox_InternalRes->Margin = System::Windows::Forms::Padding(6); - this->groupBox_InternalRes->Name = L"groupBox_InternalRes"; - this->groupBox_InternalRes->Padding = System::Windows::Forms::Padding(6); - this->groupBox_InternalRes->Size = System::Drawing::Size(526, 166); - this->groupBox_InternalRes->TabIndex = 20; - this->groupBox_InternalRes->TabStop = false; - this->groupBox_InternalRes->Text = L"Internal Resolution (Quality)"; - // - // panel_IntRes - // - this->panel_IntRes->AutoScroll = true; - this->panel_IntRes->Location = System::Drawing::Point(10, 38); - this->panel_IntRes->Margin = System::Windows::Forms::Padding(6); - this->panel_IntRes->Name = L"panel_IntRes"; - this->panel_IntRes->Size = System::Drawing::Size(506, 118); - this->panel_IntRes->TabIndex = 1; - // - // tabPage_Patches - // - this->tabPage_Patches->BackColor = System::Drawing::Color::White; - this->tabPage_Patches->Controls->Add(this->panel_Patches); - this->tabPage_Patches->ForeColor = System::Drawing::Color::FromArgb(static_cast(static_cast(64)), static_cast(static_cast(64)), - static_cast(static_cast(64))); - this->tabPage_Patches->Location = System::Drawing::Point(8, 39); - this->tabPage_Patches->Margin = System::Windows::Forms::Padding(6); - this->tabPage_Patches->Name = L"tabPage_Patches"; - this->tabPage_Patches->Size = System::Drawing::Size(1104, 721); - this->tabPage_Patches->TabIndex = 1; - this->tabPage_Patches->Text = L"Options"; - // - // panel_Patches - // - this->panel_Patches->AutoScroll = true; - this->panel_Patches->Location = System::Drawing::Point(0, 0); - this->panel_Patches->Margin = System::Windows::Forms::Padding(6); - this->panel_Patches->Name = L"panel_Patches"; - this->panel_Patches->Size = System::Drawing::Size(1104, 716); - this->panel_Patches->TabIndex = 9; - // - // tabPage_Playerdata - // - this->tabPage_Playerdata->BackColor = System::Drawing::Color::White; - this->tabPage_Playerdata->Controls->Add(this->panel_Playerdata); - this->tabPage_Playerdata->ForeColor = System::Drawing::Color::FromArgb(static_cast(static_cast(64)), - static_cast(static_cast(64)), static_cast(static_cast(64))); - this->tabPage_Playerdata->Location = System::Drawing::Point(8, 39); - this->tabPage_Playerdata->Margin = System::Windows::Forms::Padding(6); - this->tabPage_Playerdata->Name = L"tabPage_Playerdata"; - this->tabPage_Playerdata->Size = System::Drawing::Size(1104, 721); - this->tabPage_Playerdata->TabIndex = 3; - this->tabPage_Playerdata->Text = L"Player"; - // - // panel_Playerdata - // - this->panel_Playerdata->AutoScroll = true; - this->panel_Playerdata->Location = System::Drawing::Point(0, 0); - this->panel_Playerdata->Margin = System::Windows::Forms::Padding(6); - this->panel_Playerdata->Name = L"panel_Playerdata"; - this->panel_Playerdata->Size = System::Drawing::Size(1104, 716); - this->panel_Playerdata->TabIndex = 1; - // - // tabPage_Components - // - this->tabPage_Components->BackColor = System::Drawing::Color::White; - this->tabPage_Components->Controls->Add(this->panel_Components); - this->tabPage_Components->ForeColor = System::Drawing::Color::FromArgb(static_cast(static_cast(64)), - static_cast(static_cast(64)), static_cast(static_cast(64))); - this->tabPage_Components->Location = System::Drawing::Point(8, 39); - this->tabPage_Components->Margin = System::Windows::Forms::Padding(6); - this->tabPage_Components->Name = L"tabPage_Components"; - this->tabPage_Components->Padding = System::Windows::Forms::Padding(6); - this->tabPage_Components->Size = System::Drawing::Size(1104, 721); - this->tabPage_Components->TabIndex = 2; - this->tabPage_Components->Text = L"Components"; - // - // panel_Components - // - this->panel_Components->AutoScroll = true; - this->panel_Components->Location = System::Drawing::Point(0, 0); - this->panel_Components->Margin = System::Windows::Forms::Padding(6); - this->panel_Components->Name = L"panel_Components"; - this->panel_Components->Size = System::Drawing::Size(1104, 716); - this->panel_Components->TabIndex = 0; - // - // tabPage_Plugins - // - this->tabPage_Plugins->BackColor = System::Drawing::Color::White; - this->tabPage_Plugins->Controls->Add(this->panel_Custom); - this->tabPage_Plugins->Controls->Add(this->panel_Plugins); - this->tabPage_Plugins->ForeColor = System::Drawing::Color::FromArgb(static_cast(static_cast(64)), static_cast(static_cast(64)), - static_cast(static_cast(64))); - this->tabPage_Plugins->Location = System::Drawing::Point(8, 39); - this->tabPage_Plugins->Margin = System::Windows::Forms::Padding(6); - this->tabPage_Plugins->Name = L"tabPage_Plugins"; - this->tabPage_Plugins->Padding = System::Windows::Forms::Padding(6); - this->tabPage_Plugins->Size = System::Drawing::Size(1104, 721); - this->tabPage_Plugins->TabIndex = 3; - this->tabPage_Plugins->Text = L"Plugins and Patches"; - // - // panel_Custom - // - this->panel_Custom->AutoScroll = true; - this->panel_Custom->Location = System::Drawing::Point(552, 0); - this->panel_Custom->Margin = System::Windows::Forms::Padding(6); - this->panel_Custom->Name = L"panel_Custom"; - this->panel_Custom->Size = System::Drawing::Size(552, 716); - this->panel_Custom->TabIndex = 3; - // - // panel_Plugins - // - this->panel_Plugins->AutoScroll = true; - this->panel_Plugins->Location = System::Drawing::Point(0, 0); - this->panel_Plugins->Margin = System::Windows::Forms::Padding(6); - this->panel_Plugins->Name = L"panel_Plugins"; - this->panel_Plugins->Size = System::Drawing::Size(552, 716); - this->panel_Plugins->TabIndex = 0; - // - // tabPage_Credits - // - this->tabPage_Credits->Controls->Add(this->creditsTextBox); - this->tabPage_Credits->Location = System::Drawing::Point(8, 39); - this->tabPage_Credits->Margin = System::Windows::Forms::Padding(4); - this->tabPage_Credits->Name = L"tabPage_Credits"; - this->tabPage_Credits->Padding = System::Windows::Forms::Padding(4); - this->tabPage_Credits->Size = System::Drawing::Size(1104, 721); - this->tabPage_Credits->TabIndex = 5; - this->tabPage_Credits->Text = L"Credits"; - this->tabPage_Credits->UseVisualStyleBackColor = true; - // - // creditsTextBox - // - this->creditsTextBox->BackColor = System::Drawing::Color::White; - this->creditsTextBox->ForeColor = System::Drawing::Color::FromArgb(static_cast(static_cast(64)), static_cast(static_cast(64)), - static_cast(static_cast(64))); - this->creditsTextBox->Location = System::Drawing::Point(0, 0); - this->creditsTextBox->Margin = System::Windows::Forms::Padding(4); - this->creditsTextBox->Multiline = true; - this->creditsTextBox->Name = L"creditsTextBox"; - this->creditsTextBox->ReadOnly = true; - this->creditsTextBox->ScrollBars = System::Windows::Forms::ScrollBars::Both; - this->creditsTextBox->Size = System::Drawing::Size(1100, 712); - this->creditsTextBox->TabIndex = 0; - this->creditsTextBox->Text = resources->GetString(L"creditsTextBox.Text"); - // - // button_Discord - // - this->button_Discord->BackColor = System::Drawing::Color::FromArgb(static_cast(static_cast(242)), static_cast(static_cast(242)), - static_cast(static_cast(242))); - this->button_Discord->Cursor = System::Windows::Forms::Cursors::Hand; - this->button_Discord->FlatAppearance->BorderSize = 0; - this->button_Discord->FlatStyle = System::Windows::Forms::FlatStyle::Flat; - this->button_Discord->Image = (cli::safe_cast(resources->GetObject(L"button_Discord.Image"))); - this->button_Discord->Location = System::Drawing::Point(992, 768); - this->button_Discord->Margin = System::Windows::Forms::Padding(6); - this->button_Discord->Name = L"button_Discord"; - this->button_Discord->Size = System::Drawing::Size(64, 64); - this->button_Discord->TabIndex = 31; - this->button_Discord->UseVisualStyleBackColor = false; - this->button_Discord->Click += gcnew System::EventHandler(this, &ui::button_Discord_Click); - // - // button_github - // - this->button_github->BackColor = System::Drawing::Color::FromArgb(static_cast(static_cast(242)), static_cast(static_cast(242)), - static_cast(static_cast(242))); - this->button_github->Cursor = System::Windows::Forms::Cursors::Hand; - this->button_github->FlatAppearance->BorderSize = 0; - this->button_github->FlatStyle = System::Windows::Forms::FlatStyle::Flat; - this->button_github->Image = (cli::safe_cast(resources->GetObject(L"button_github.Image"))); - this->button_github->Location = System::Drawing::Point(1056, 768); - this->button_github->Margin = System::Windows::Forms::Padding(6); - this->button_github->Name = L"button_github"; - this->button_github->Size = System::Drawing::Size(64, 64); - this->button_github->TabIndex = 32; - this->button_github->UseVisualStyleBackColor = false; - this->button_github->Click += gcnew System::EventHandler(this, &ui::button_github_Click); - // - // button_Apply - // - this->button_Apply->BackColor = System::Drawing::Color::White; - this->button_Apply->FlatAppearance->BorderColor = System::Drawing::SystemColors::Control; - this->button_Apply->FlatStyle = System::Windows::Forms::FlatStyle::Flat; - this->button_Apply->Location = System::Drawing::Point(8, 778); - this->button_Apply->Margin = System::Windows::Forms::Padding(6); - this->button_Apply->Name = L"button_Apply"; - this->button_Apply->Size = System::Drawing::Size(138, 46); - this->button_Apply->TabIndex = 33; - this->button_Apply->Text = L"Apply"; - this->button_Apply->UseVisualStyleBackColor = false; - this->button_Apply->Click += gcnew System::EventHandler(this, &ui::button_Apply_Click); - // - // button_Wiki - // - this->button_Wiki->BackColor = System::Drawing::Color::FromArgb(static_cast(static_cast(242)), static_cast(static_cast(242)), - static_cast(static_cast(242))); - this->button_Wiki->BackgroundImage = (cli::safe_cast(resources->GetObject(L"button_Wiki.BackgroundImage"))); - this->button_Wiki->BackgroundImageLayout = System::Windows::Forms::ImageLayout::Stretch; - this->button_Wiki->Cursor = System::Windows::Forms::Cursors::Hand; - this->button_Wiki->FlatAppearance->BorderSize = 0; - this->button_Wiki->FlatStyle = System::Windows::Forms::FlatStyle::Flat; - this->button_Wiki->Location = System::Drawing::Point(928, 768); - this->button_Wiki->Margin = System::Windows::Forms::Padding(6); - this->button_Wiki->Name = L"button_Wiki"; - this->button_Wiki->Size = System::Drawing::Size(64, 64); - this->button_Wiki->TabIndex = 34; - this->button_Wiki->UseVisualStyleBackColor = false; - this->button_Wiki->Click += gcnew System::EventHandler(this, &ui::button_Wiki_Click); - // - // ui - // - this->AcceptButton = this->button_Launch; - this->AutoScaleDimensions = System::Drawing::SizeF(192, 192); - this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Dpi; - this->AutoSize = true; - this->AutoSizeMode = System::Windows::Forms::AutoSizeMode::GrowAndShrink; - this->BackColor = System::Drawing::Color::Magenta; - this->BackgroundImageLayout = System::Windows::Forms::ImageLayout::Stretch; - this->ClientSize = System::Drawing::Size(1120, 834); - this->Controls->Add(this->button_Wiki); - this->Controls->Add(this->button_Apply); - this->Controls->Add(this->tabControl); - this->Controls->Add(this->button_Launch); - this->Controls->Add(this->button_github); - this->Controls->Add(this->button_Discord); - this->DoubleBuffered = true; - this->ForeColor = System::Drawing::Color::FromArgb(static_cast(static_cast(64)), static_cast(static_cast(64)), - static_cast(static_cast(64))); - this->FormBorderStyle = System::Windows::Forms::FormBorderStyle::Fixed3D; - this->HelpButton = true; - this->Icon = (cli::safe_cast(resources->GetObject(L"$this.Icon"))); - this->KeyPreview = true; - this->Margin = System::Windows::Forms::Padding(6); - this->MaximizeBox = false; - this->Name = L"ui"; - this->StartPosition = System::Windows::Forms::FormStartPosition::CenterScreen; - this->Text = L"PD Launcher (2.6)"; - this->TransparencyKey = System::Drawing::Color::Magenta; - this->FormClosing += gcnew System::Windows::Forms::FormClosingEventHandler(this, &ui::Ui_FormClosing); - this->FormClosed += gcnew System::Windows::Forms::FormClosedEventHandler(this, &ui::Ui_FormClosed); - this->groupBox_ScreenRes->ResumeLayout(false); - this->tabControl->ResumeLayout(false); - this->tabPage_Resolution->ResumeLayout(false); - this->tabPage_Resolution->PerformLayout(); - this->groupBox_Lag->ResumeLayout(false); - this->groupBox_Lag->PerformLayout(); - (cli::safe_cast(this->trackBar_LagCompensation))->EndInit(); - this->groupBox_Details->ResumeLayout(false); - this->groupBox_InternalRes->ResumeLayout(false); - this->tabPage_Patches->ResumeLayout(false); - this->tabPage_Playerdata->ResumeLayout(false); - this->tabPage_Components->ResumeLayout(false); - this->tabPage_Plugins->ResumeLayout(false); - this->tabPage_Credits->ResumeLayout(false); - this->tabPage_Credits->PerformLayout(); - this->ResumeLayout(false); - - } -#pragma endregion -private: System::Void SaveSettings() { - if (*ResolutionConfigChanged) - { - for (ConfigOptionBase* option : screenResolutionArray) - { - option->SaveOption(); - } - - for (ConfigOptionBase* option : internalResolutionArray) - { - option->SaveOption(); - } - - *ResolutionConfigChanged = false; - } - - if (*OptionsConfigChanged) - { - for (ConfigOptionBase* option : optionsArray) - { - option->SaveOption(); - } - - for (ConfigOptionBase* option : graphicsArray) - { - option->SaveOption(); - } - - *OptionsConfigChanged = false; - } - - if (*PlayerdataConfigChanged) - { - for (ConfigOptionBase* option : playerdataArray) - { - option->SaveOption(); - } - - *PlayerdataConfigChanged = false; - } - - if (*ComponentsConfigChanged) - { - for (ConfigOptionBase* component : componentsArray) - { - component->SaveOption(); - } - - *ComponentsConfigChanged = false; - } - - if (*LagCompensationConfigChanged) - { - SetIniInt(GRAPHICS_SECTION, L"lag_compensation", trackBar_LagCompensation->Value, CONFIG_FILE); - *LagCompensationConfigChanged = false; - } - - for (ConfigOptionBase* option : AllPluginOpts) - { - if (*(option->hasChanged)) - { - option->SaveOption(); - } - - *(option->hasChanged) = false; - } - - for (ConfigOptionBase* option : AllCustomOpts) - { - if (*(option->hasChanged)) - { - option->SaveOption(); - } - - *(option->hasChanged) = false; - } -} -private: System::Void Button_Help_Click(System::Object^ sender, System::EventArgs^ e) { - System::Diagnostics::Process::Start("https://notabug.org/PDModdingCommunity/PD-Loader/wiki"); -} -private: System::Void Button_Launch_Click(System::Object^ sender, System::EventArgs^ e) { - - //SkinnedMessageBox::Show(this, "It looks like the executable has been tampered with, or the version of the game is not 7.10.\n\nPlease use the \"patches\" folder instead of modifying the executable directly (or disable verification).", "PD Launcher", MessageBoxButtons::OK, MessageBoxIcon::Error); - - SaveSettings(); - - if (GetPrivateProfileIntW(LAUNCHER_SECTION, L"use_divahook_bat", FALSE, CONFIG_FILE)) - { - if (GetPrivateProfileIntW(L"patches", L"quick_start", 1, CONFIG_FILE) > 0) - { - SkinnedMessageBox::Show(this, L"\"Quick Start\" and \"Use divahook.bat / start.bat\" cannot be enabled at the same time.", "PD Launcher", MessageBoxButtons::OK, MessageBoxIcon::Error); - return; - } - - DIVA_EXECUTABLE = NULL; - wstring DIVA_EXECUTABLE_LAUNCH_STRING_cmd = L"cmd.exe /C \""; - const wstring DIVA_EXECUTABLE_LAUNCH_STRING_path = DIVA_DIRPATH; - - wstring DIVAHOOK_BAT_PATH = DIVA_EXECUTABLE_LAUNCH_STRING_path; - DIVAHOOK_BAT_PATH.append(L"\\divahook.bat"); - if (std::filesystem::exists(DIVAHOOK_BAT_PATH)) - { - DIVA_EXECUTABLE_LAUNCH_STRING_cmd.append(DIVAHOOK_BAT_PATH); - DIVA_EXECUTABLE_LAUNCH_STRING_cmd.append(L"\""); - DIVA_EXECUTABLE_LAUNCH = const_cast(DIVA_EXECUTABLE_LAUNCH_STRING_cmd.c_str()); - } - else - { - wstring START_BAT_PATH = DIVA_EXECUTABLE_LAUNCH_STRING_path; - START_BAT_PATH.append(L"\\start.bat"); - if (std::filesystem::exists(START_BAT_PATH)) - { - DIVA_EXECUTABLE_LAUNCH_STRING_cmd.append(START_BAT_PATH); - DIVA_EXECUTABLE_LAUNCH_STRING_cmd.append(L"\""); - DIVA_EXECUTABLE_LAUNCH = const_cast(DIVA_EXECUTABLE_LAUNCH_STRING_cmd.c_str()); - } - else if (SkinnedMessageBox::Show(this, L"divahook.bat/start.bat not found.\nThe game will start normally/offline.\n\nNOTE: Disable \"Use divahook.bat / start.bat\" to avoid this warning.", "PD Launcher", MessageBoxButtons::OKCancel, MessageBoxIcon::Warning) != System::Windows::Forms::DialogResult::OK) return; - } - } - else - { - // read the command line here so it'll be up to date even if the user changed it - WCHAR stringBuf[256]; - GetPrivateProfileStringW(LAUNCHER_SECTION, L"command_line", L"", stringBuf, 256, CONFIG_FILE); - - DIVA_EXECUTABLE_LAUNCH_STRING += L" " + wstring(stringBuf); - DIVA_EXECUTABLE_LAUNCH = const_cast(DIVA_EXECUTABLE_LAUNCH_STRING.c_str()); - } - - STARTUPINFOW si; - PROCESS_INFORMATION pi; - - ZeroMemory(&si, sizeof(si)); - si.cb = sizeof(si); - ZeroMemory(&pi, sizeof(pi)); - CreateProcessW(DIVA_EXECUTABLE, DIVA_EXECUTABLE_LAUNCH, NULL, NULL, false, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi); - - // this->Close won't work in here since it will prompt the user to save the settings - TerminateProcess(GetCurrentProcess(), EXIT_SUCCESS); -} -private: System::Void InternalResEnabledChangedHandler(System::Object^ sender, System::EventArgs^ e) { - if (((CheckBox^)CheckBox::FromHandle(InternalResolutionCheckbox->mainControlHandle))->Checked) - { - ((Control^)Control::FromHandle(InternalResolutionOption->mainControlHandle))->Enabled = true; - } - else - { - ((Control^)Control::FromHandle(InternalResolutionOption->mainControlHandle))->Enabled = false; - } -} -private: System::Void DisplayTypeChangedHandler(System::Object^ sender, System::EventArgs^ e) { - int idx = ((ComboBox^)ComboBox::FromHandle(DisplayModeDropdown->mainControlHandle))->SelectedIndex; - - if (idx == 2) // fullscreen - { - for (ConfigOptionBase* option : screenResolutionArray) - { - if (option != DisplayModeDropdown && option != DisplayResolutionOption) - { - ((Control^)Control::FromHandle(option->mainControlHandle))->Enabled = true; - } - } - } - else - { - for (ConfigOptionBase* option : screenResolutionArray) - { - if (option != DisplayModeDropdown && option != DisplayResolutionOption) - { - ((Control^)Control::FromHandle(option->mainControlHandle))->Enabled = false; - } - } - } -} -private: System::Void Ui_FormClosing(System::Object^ sender, System::Windows::Forms::FormClosingEventArgs^ e) { - if (!AnyConfigChanged()) - return; - - switch (SkinnedMessageBox::Show(this, "Do you want to save your settings?", "PD Launcher", MessageBoxButtons::YesNoCancel, MessageBoxIcon::Question)) - { - case System::Windows::Forms::DialogResult::Yes: - SaveSettings(); - break; - - case System::Windows::Forms::DialogResult::No: - break; - - case System::Windows::Forms::DialogResult::Cancel: - e->Cancel = true; - break; - } -} -private: System::Void Ui_FormClosed(System::Object^ sender, System::Windows::Forms::FormClosedEventArgs^ e) { - // Prevents abnormal termination messages, remember that the game is still technically running and must be killed! - TerminateProcess(GetCurrentProcess(), EXIT_SUCCESS); -} -private: System::Void button_Discord_Click(System::Object^ sender, System::EventArgs^ e) { - switch (SkinnedMessageBox::Show(this, "Would you like to read the user guide for troubleshooting?", "PD Launcher", MessageBoxButtons::YesNoCancel, MessageBoxIcon::Information)) - { - case System::Windows::Forms::DialogResult::Yes: - System::Diagnostics::Process::Start("https://notabug.org/PDModdingCommunity/PD-Loader/wiki"); - break; - - case System::Windows::Forms::DialogResult::No: - System::Diagnostics::Process::Start("https://discord.gg/cvBVGDZ"); - break; - } -} -private: System::Void button_github_Click(System::Object^ sender, System::EventArgs^ e) { - System::Diagnostics::Process::Start("https://notabug.org/PDModdingCommunity/PD-Loader"); -} -private: System::Void button_Apply_Click(System::Object^ sender, System::EventArgs^ e) { - SaveSettings(); - updateStyle(); - ShowWindow(hWnd, SW_HIDE); - ShowWindow(hWnd, SW_SHOW); -} -private: System::Void Ui_KeyDown(System::Object^ sender, System::Windows::Forms::KeyEventArgs^ e) { - if (e->KeyCode == Keys::Escape) this->Close(); -} - -private: bool* ResolutionConfigChanged = new bool(false); - bool* OptionsConfigChanged = new bool(false); - bool* PlayerdataConfigChanged = new bool(false); - bool* ComponentsConfigChanged = new bool(false); - bool* LagCompensationConfigChanged = new bool(false); - -private: bool AnyConfigChanged() { - if (*ResolutionConfigChanged || *OptionsConfigChanged || *PlayerdataConfigChanged || *ComponentsConfigChanged || *LagCompensationConfigChanged) - return true; // fast case - - for (ConfigOptionBase* option : AllPluginOpts) - { - if (*(option->hasChanged)) return true; // slow case for iterating over individual plugins - } - - return false; -} - -private: String^ GPUIssueText; -private: System::Void LinkLabelLinkClickedGPUIssueHandler(System::Object^ sender, System::Windows::Forms::LinkLabelLinkClickedEventArgs^ e) { - SkinnedMessageBox::Show(this, GPUIssueText, "PD Launcher", MessageBoxButtons::OK, MessageBoxIcon::Warning); -} -private: System::Void trackBar_LagCompensation_ValueChanged(System::Object^ sender, System::EventArgs^ e) { - *LagCompensationConfigChanged = true; - - updateLagCompMsec(); -} -private: System::Void tabPage_Resolution_Click(System::Object^ sender, System::EventArgs^ e) { -} -private: System::Void button_Wiki_Click(System::Object^ sender, System::EventArgs^ e) { - System::Diagnostics::Process::Start("https://notabug.org/PDModdingCommunity/PD-Loader/wiki"); -} -private: System::Void trackBar_LagCompensation_Scroll(System::Object^ sender, System::EventArgs^ e) { -} -}; -} +#pragma once +#include "framework.h" +#include +#include +#include "TabPadding.h" +#include +#include +#include "SkinnedMessageBox.h" +#include "PluginConfig.h" +#include "GPUModel.h" +#include "WineVer.h" +#include "composition.h" +#include + +namespace Launcher { + + using namespace System; + using namespace System::ComponentModel; + using namespace System::Collections; + using namespace System::Windows::Forms; + using namespace System::Data; + using namespace System::Drawing; + using namespace msclr::interop; + + HWND hWnd; + + /// + /// Summary for ui + /// + public ref class ui : public System::Windows::Forms::Form + { + public: + ui(void) + { + InitializeComponent(); + + hWnd = (HWND)Control::Handle.ToPointer(); + + this->ClientSize = Drawing::Size(444, 323); + TabPadding^ tabpad = gcnew TabPadding(tabControl); + + // if components.ini has no section name, add one + if (!IsLineInFile("[components]", COMPONENTS_FILE)) + { + PrependFile("[components]\n", COMPONENTS_FILE); + } + + // if playerdata.ini has no section name, add one + if (!IsLineInFile("[playerdata]", PLAYERDATA_FILE)) + { + PrependFile("[playerdata]\n", PLAYERDATA_FILE); + } + + // if keyconfig.ini has no section name, add one + if (!IsLineInFile("[keyconfig]", KEYCONFIG_FILE)) + { + PrependFile("[keyconfig]\n", KEYCONFIG_FILE); + } + + + this->panel_ScreenRes->SuspendLayout(); + + // populate options (patches) from array in framework + // (easier than manually setting everything up) + int screenresY = 3; + for (ConfigOptionBase* option : screenResolutionArray) + { + option->hasChanged = ResolutionConfigChanged; + screenresY += option->AddToPanel(panel_ScreenRes, 12, screenresY, toolTip1); + } + ((ComboBox^)ComboBox::FromHandle(DisplayModeDropdown->mainControlHandle))->SelectedIndexChanged += gcnew System::EventHandler(this, &ui::DisplayTypeChangedHandler); + DisplayTypeChangedHandler(this, gcnew EventArgs); // run handler now + this->panel_ScreenRes->ResumeLayout(false); + this->panel_ScreenRes->PerformLayout(); + + + this->panel_IntRes->SuspendLayout(); + + // populate options (patches) from array in framework + // (easier than manually setting everything up) + int intresY = 3; + for (ConfigOptionBase* option : internalResolutionArray) + { + option->hasChanged = ResolutionConfigChanged; + intresY += option->AddToPanel(panel_IntRes, 12, intresY, toolTip1); + } + ((CheckBox^)CheckBox::FromHandle(InternalResolutionCheckbox->mainControlHandle))->CheckedChanged += gcnew System::EventHandler(this, &ui::InternalResEnabledChangedHandler); + InternalResEnabledChangedHandler(this, gcnew EventArgs); // run handler now + this->panel_IntRes->ResumeLayout(false); + this->panel_IntRes->PerformLayout(); + + + this->panel_Details->SuspendLayout(); + + // populate details (patches) from array in framework + // (easier than manually setting everything up) + int detailsY = 3; + for (ConfigOptionBase* option : graphicsArray) + { + option->hasChanged = OptionsConfigChanged; + detailsY += option->AddToPanel(panel_Details, 12, detailsY, toolTip1); + } + trackBar_LagCompensation->Value = GetIniInt(GRAPHICS_SECTION, L"lag_compensation", 0, CONFIG_FILE); + this->panel_Details->ResumeLayout(false); + this->panel_Details->PerformLayout(); + + + this->panel_Patches->SuspendLayout(); + + // populate options (patches) from array in framework + // (easier than manually setting everything up) + int optionsY = 3; + for (ConfigOptionBase* option : optionsArray) + { + option->hasChanged = OptionsConfigChanged; + optionsY += option->AddToPanel(panel_Patches, 12, optionsY, toolTip1); + } + this->panel_Patches->ResumeLayout(false); + this->panel_Patches->PerformLayout(); + + + + this->panel_Playerdata->SuspendLayout(); + + // populate playerdata options from array in framework + // (easier than manually setting everything up) + int playerdataY = 3; + for (ConfigOptionBase* option : playerdataArray) + { + option->hasChanged = PlayerdataConfigChanged; + playerdataY += option->AddToPanel(panel_Playerdata, 12, playerdataY, toolTip1); + } + this->panel_Playerdata->ResumeLayout(false); + this->panel_Playerdata->PerformLayout(); + + + this->panel_Components->SuspendLayout(); + + // populate components from array in framework + // (easier than manually setting everything up) + int componentsY = 3; + for (ConfigOptionBase* component : componentsArray) + { + component->hasChanged = ComponentsConfigChanged; + componentsY += component->AddToPanel(panel_Components, 12, componentsY, toolTip1); + } + this->panel_Components->ResumeLayout(false); + this->panel_Components->PerformLayout(); + + + AllPlugins = LoadPlugins(); + AllPluginOpts = GetPluginOptions(&AllPlugins); + + this->panel_Plugins->SuspendLayout(); + + int pluginsY = 3; + for (ConfigOptionBase* option : AllPluginOpts) + { + option->hasChanged = new bool(false); + pluginsY += option->AddToPanel(panel_Plugins, 12, pluginsY, toolTip1); + } + this->panel_Plugins->ResumeLayout(false); + this->panel_Plugins->PerformLayout(); + + + AllCustomPatches = LoadCustom(); + AllCustomOpts = GetPluginOptions(&AllCustomPatches); + + this->panel_Custom->SuspendLayout(); + + int customY = 3; + for (ConfigOptionBase* custom : AllCustomOpts) + { + custom->hasChanged = new bool(false); + customY += custom->AddToPanel(panel_Custom, 12, customY, toolTip1); + } + + this->panel_Custom->ResumeLayout(false); + this->panel_Custom->PerformLayout(); + + + // trick Optimus into switching to the NVIDIA GPU + if (cuInit != NULL) cuInit(0); + + int argc = 1; + char* argv[1] = { (char*)"" }; + + + updateLagCompMsec(); + + updateStyle(); + + + glutInit(&argc, argv); + int window = glutCreateWindow("glut"); // a context must be created to use glGetString + glutHideWindow(); + + String^ vendor = gcnew String((char*)glGetString(GL_VENDOR)); + vendor = vendor->Replace(" Corporation", ""); // this is useless.. remove it to help ensure the GPU type line fits + String^ renderer = gcnew String((char*)glGetString(GL_RENDERER)); + String^ version = gcnew String((char*)glGetString(GL_VERSION)); + version = version->Replace(" Profile Context", ""); // we don't need this, either + + String^ gpuModel = gcnew String(GPUModel::getGpuName().c_str()); + + String^ wineVersion = gcnew String(WineVer::getWineVer().c_str()); + + int driver_version_major = 1; + int driver_version_minor = 0; + auto version_split = version->Split(' '); + if (version_split->Length > 1) // make sure we don't use the OpenGL version instead of the driver version + { + String^ driver_version = gcnew String(version_split[version_split->Length - 1]); + auto driver_version_split_major_minor = driver_version->Split('.'); + if (driver_version_split_major_minor->Length >= 2) + { + driver_version_major = int::Parse(driver_version_split_major_minor[0]); + driver_version_minor = int::Parse(driver_version_split_major_minor[1]); + } + } + + glutDestroyWindow(window); // destroy the window so it doesn't remain on screen + if (glutMainLoopEventDynamic != NULL) glutMainLoopEventDynamic(); // freeglut needs this + + if (wineVersion != "") + { + this->labelGPU->Text = "Wine " + wineVersion + " (at least 4.12.1 is required)\n"; + } + else this->labelGPU->Text = "GPU Info:\n"; + this->labelGPU->Text += vendor + " " + renderer + "\n"; + this->labelGPU->Text += "OpenGL: " + version + "\n"; + + int linkStart = this->labelGPU->Text->Length; + bool showGpuDialog = false; + if (vendor->Contains("AMD") || vendor->Contains("ATI")) // check OpenGL to get actual GPU being used for vendor check (to get accurate results for iGPU) + { + bool hasNovidia = false; + for (PluginInfo i : AllPlugins) + { + if (i.name == L"Novidia") + hasNovidia = true; + } + + if (hasNovidia) + { + if (wineVersion == "" && (driver_version_major < 21 || (driver_version_major == 21 && driver_version_minor < 6))) + { + this->labelGPU->Text += L"Driver has known issues."; + GPUIssueText = L"The graphics driver you're using has known issues. Please install the latest driver from your GPU vendor's website."; + this->labelGPU->LinkColor = System::Drawing::Color::Orange; + showGpuDialog = true; + } + else + { + this->labelGPU->Text += "Issues: AMD GPU support is unofficial."; + GPUIssueText = "AMD GPUs are not supported without mods.\nThe PD Loader AMDPack seems to be installed, but please keep in mind that it may have issues."; + this->labelGPU->LinkColor = System::Drawing::Color::Yellow; + } + } + else + { + this->labelGPU->Text += "Issues: Mods needed for AMD compatibility!"; + GPUIssueText = "AMD GPUs are not supported without mods.\nThe PD Loader AMDPack can be used to make 3D rendering work. Please download it and follow the included instructions.\n\nIf you have a laptop with an NVIDIA GPU and wish to use it instead of the detected GPU, you may need to set diva.exe to use it in Windows settings or NVIDIA Control Panel."; + this->labelGPU->LinkColor = System::Drawing::Color::Red; + showGpuDialog = true; + } + } + else if (vendor->Contains("NVIDIA")) + { + if (wineVersion == "" && (driver_version_major < 391 || (driver_version_major > 446 && driver_version_major < 460))) + { + this->labelGPU->Text += L"Driver has known issues."; + GPUIssueText = L"The graphics driver you're using has known issues. Please install the latest driver from your GPU vendor's website."; + this->labelGPU->LinkColor = System::Drawing::Color::Orange; + showGpuDialog = true; + } + else if (gpuModel->StartsWith("GA")) // unconfirmed?? + { + this->labelGPU->Text += L"Issues: Ampere GPU detected! Possible noise.\n(Click for more information)"; + GPUIssueText = L"On Ampere GPUs (RTX 30xx), some important character shaders have issues resulting in lines/noise.\nPlease make sure the ShaderPatch plugin is enabled."; + this->labelGPU->LinkColor = System::Drawing::Color::Yellow; + } + else if (gpuModel->StartsWith("TU") || gpuModel->StartsWith("GV")) // let's assume Volta is like Turing for now + { + this->labelGPU->Text += L"Issues: Ampere GPU detected! Possible noise.\n(Click for more information)"; + GPUIssueText = L"On Turing GPUs (GTX 16xx/RTX 20xx), some important character shaders have issues resulting in lines/noise.\nPlease make sure the ShaderPatch plugin is enabled."; + this->labelGPU->LinkColor = System::Drawing::Color::Yellow; + } + else if (gpuModel->StartsWith("GM") || gpuModel->StartsWith("GP")) + { + this->labelGPU->Text += L"Issues: May have minor noise on some stages.\n(Click for more information)"; + GPUIssueText = L"On Maxwell GPUs (~GTX 900) and newer, some minor stage shaders create noise.\nPlease make sure the ShaderPatch plugin is enabled."; + this->labelGPU->LinkColor = System::Drawing::Color::Teal; + } + else if (gpuModel->StartsWith("GK")) + { + this->labelGPU->Text += L"Issues: None."; + GPUIssueText = L"Your GPU should have no issues running the game."; + this->labelGPU->LinkColor = System::Drawing::Color::LightBlue; + } + else if (gpuModel->StartsWith("GF")) + { + if (version[0] < '4') + { + this->labelGPU->Text += L"Issues: Driver too old."; + GPUIssueText = L"Your GPU should be able to run the game, but it looks like your OpenGL version is too old.\nA driver update should fix this."; + this->labelGPU->LinkColor = System::Drawing::Color::Orange; + showGpuDialog = true; + } + else + { + this->labelGPU->Text += L"Issues: No known issues."; + GPUIssueText = L"Your GPU should have no issues running the game, but it is older than the GPU the game was originally designed for (GTX 650 Ti).\nThere may be some issues with graphics.\nPlease report any issues so that they can be analysed and potentially fixed."; + this->labelGPU->LinkColor = System::Drawing::Color::Teal; + } + } + else if (gpuModel->StartsWith("G") || gpuModel->StartsWith("NV") || gpuModel->StartsWith("NB") || gpuModel->StartsWith("N10") || gpuModel->StartsWith("MCP")) + { + this->labelGPU->Text += L"Issues: GPU too old! 3D rendering might be broken.\n(Click for more information)"; + GPUIssueText = L"Your GPU is very old and does not support rendering techniques used by the game.\nYou may be able to play, but graphics will likely have major issues.\nPlease upgrade to a GTX 600 series or later GPU."; + this->labelGPU->LinkColor = System::Drawing::Color::Orange; + showGpuDialog = true; + } + else if (version[0] >= '4' && gpuModel->Length > 0 && !gpuModel->StartsWith("Unk") && !gpuModel->StartsWith("Oth")) + { + this->labelGPU->Text += L"Issues: GPU may be too new.\n(Click for more information)"; + GPUIssueText = L"It looks like your GPU may be too new. Only up to Ampere (RTX 30xx) is currently supported.\nGood news: the game should be capable of running, but shader patches (probably needed) may not support it yet.\nYou will likely see lines/noise on important character shaders and some minor stage shaders.\nPlease report any issues so that ShaderPatch can be updated.\nYou can also try forcing a specific GPU workaround type."; + this->labelGPU->LinkColor = System::Drawing::Color::Orange; + } + else + { + this->labelGPU->Text += L"Issues: Unable to detect GPU architecture.\n(Click for more information)"; + GPUIssueText = L"It looks like you have an NVIDIA GPU, but something went wrong while trying to determine your GPU's architecture (type).\nThis may be a caused by a bug, but it probably indicates potential issues.\nPlease make sure you have a GTX 600 series or later GPU. (GTX 400 series or later should also work)"; + this->labelGPU->LinkColor = System::Drawing::Color::Orange; + showGpuDialog = true; + } + } + else //if (gpuModel->Length == 0 || gpuModel->StartsWith("Unk") || gpuModel->StartsWith("Oth")) + { + this->labelGPU->Text += L"Issues: UNSUPPORTED GPU!"; + GPUIssueText = L"Your graphics card is not supported. Only NVIDIA GPUs are recommended (though AMD ones can be used with mods).\nPlease use a GTX 600 series or later NVIDIA GPU.\n\nIf you have a laptop with an NVIDIA GPU and wish to use it instead of the detected GPU, you may need to set diva.exe to use it in Windows settings or NVIDIA Control Panel.\n\nOwners of other GPUs may be able to run the game using plugins or mods, but 3D graphics will probably not work."; + this->labelGPU->LinkColor = System::Drawing::Color::Red; + showGpuDialog = true; + } + int linkEnd = this->labelGPU->Text->Length - linkStart; + + this->labelGPU->LinkClicked += gcnew System::Windows::Forms::LinkLabelLinkClickedEventHandler(this, &ui::LinkLabelLinkClickedGPUIssueHandler); + this->labelGPU->LinkArea = System::Windows::Forms::LinkArea(linkStart, linkEnd); + + if (showGpuDialog && !nNoGPUDialog) + SkinnedMessageBox::Show(this, GPUIssueText + "\n\nYou can disable this message from the options tab.", "PD Launcher", MessageBoxButtons::OK, MessageBoxIcon::Warning); + } + + protected: + /// + /// Clean up any resources being used. + /// + ~ui() + { + if (components) + { + delete components; + } + } + + void OnPaintBackground(PaintEventArgs e) override + { + } + + /*property System::Windows::Forms::CreateParams^ CreateParams + { + virtual System::Windows::Forms::CreateParams^ get() override + { + System::Windows::Forms::CreateParams^ params = Form::CreateParams; + params->ExStyle |= 0x00200000L; + + return params; + } + }*/ + + void updateLagCompMsec() + { + this->groupBox_Lag->Text = "Lag Compensation (" + this->trackBar_LagCompensation->Value + " msec)"; + } + + void updateStyle() + { + int nDarkLauncher = GetPrivateProfileIntW(LAUNCHER_SECTION, L"dark_launcher", FALSE, CONFIG_FILE); + int nAcrylicLauncher = GetPrivateProfileIntW(LAUNCHER_SECTION, L"acrylic_blur", FALSE, CONFIG_FILE); + + bool useAcrylic = nAcrylicLauncher && setBlur(hWnd, AccentState::ACCENT_ENABLE_ACRYLICBLURBEHIND); + + Color colourBg, colourBg2, colourFg; + + if (nDarkLauncher) + { + setDarkTheme(hWnd); + colourFg = Color::White; + colourBg = Color::FromArgb(32, 32, 32); // tabControl + colourBg2 = Color::FromArgb(25, 25, 25); + } + else + { + setDarkTheme(hWnd, false); + colourFg = Color::FromArgb(64, 64, 64); + colourBg = Color::White; // tabControl + colourBg2 = Color::FromArgb(242, 242, 242); + } + + if (useAcrylic) + { + this->button_Discord->BackColor = colourBg2; + this->button_github->BackColor = colourBg2; + this->button_Wiki->BackColor = colourBg2; + + colourBg2 = Color::FromArgb(255, 0, 255); + } + else + { + setBlur(hWnd, AccentState::ACCENT_DISABLED); + + this->button_Discord->BackColor = Color::Transparent; + this->button_github->BackColor = Color::Transparent; + this->button_Wiki->BackColor = Color::Transparent; + } + + this->tabPage_Resolution->BackColor = colourBg; + this->tabPage_Resolution->ForeColor = colourFg; + this->tabPage_Patches->BackColor = colourBg; + this->tabPage_Patches->ForeColor = colourFg; + this->tabPage_Playerdata->BackColor = colourBg; + this->tabPage_Playerdata->ForeColor = colourFg; + this->tabPage_Plugins->BackColor = colourBg; + this->tabPage_Plugins->ForeColor = colourFg; + this->tabPage_Components->BackColor = colourBg; + this->tabPage_Components->ForeColor = colourFg; + this->creditsTextBox->BackColor = colourBg; + this->creditsTextBox->ForeColor = colourFg; + + this->tabControl->BackColor = colourBg; + this->tabControl->ForeColor = colourFg; + + this->BackColor = colourBg2; + + this->button_Launch->BackColor = colourBg; + this->button_Launch->ForeColor = colourFg; + this->button_Apply->BackColor = colourBg; + this->button_Apply->ForeColor = colourFg; + + this->labelGPU->ForeColor = colourFg; + + this->groupBox_Details->ForeColor = colourFg; + this->groupBox_InternalRes->ForeColor = colourFg; + this->groupBox_Lag->ForeColor = colourFg; + this->groupBox_ScreenRes->ForeColor = colourFg; + } + + private: + + + private: System::Windows::Forms::Button^ button_Launch; + + private: System::Windows::Forms::GroupBox^ groupBox_ScreenRes; + private: System::Windows::Forms::TabControl^ tabControl; + private: System::Windows::Forms::TabPage^ tabPage_Resolution; + private: System::Windows::Forms::GroupBox^ groupBox_InternalRes; + private: System::Windows::Forms::TabPage^ tabPage_Components; + private: System::Windows::Forms::Panel^ panel_Components; + private: System::Windows::Forms::TabPage^ tabPage_Patches; + private: System::Windows::Forms::Panel^ panel_Patches; + private: System::Windows::Forms::TabPage^ tabPage_Plugins; + private: System::Windows::Forms::Panel^ panel_Plugins; + private: System::Windows::Forms::Button^ button_Discord; + private: System::Windows::Forms::Button^ button_github; + private: System::Windows::Forms::TabPage^ tabPage_Playerdata; + private: System::Windows::Forms::Panel^ panel_Playerdata; + private: System::Windows::Forms::ToolTip^ toolTip1; + private: System::Windows::Forms::Panel^ panel_ScreenRes; + private: System::Windows::Forms::Panel^ panel_IntRes; + private: System::Windows::Forms::LinkLabel^ labelGPU; + + + +private: System::Windows::Forms::TabPage^ tabPage_Credits; +private: System::Windows::Forms::TextBox^ creditsTextBox; +private: System::Windows::Forms::GroupBox^ groupBox_Details; +private: System::Windows::Forms::Panel^ panel_Details; +private: System::Windows::Forms::Panel^ panel_Custom; +private: System::Windows::Forms::Button^ button_Apply; +private: System::Windows::Forms::GroupBox^ groupBox_Lag; +private: System::Windows::Forms::TrackBar^ trackBar_LagCompensation; +private: System::Windows::Forms::Button^ button_Wiki; + + + + + + + + + + + + + + + + + + + + + private: System::ComponentModel::IContainer^ components; + + private: + /// + /// Required designer variable. + /// + + +#pragma region Windows Form Designer generated code + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + void InitializeComponent(void) + { + this->components = (gcnew System::ComponentModel::Container()); + System::ComponentModel::ComponentResourceManager^ resources = (gcnew System::ComponentModel::ComponentResourceManager(ui::typeid)); + this->button_Launch = (gcnew System::Windows::Forms::Button()); + this->groupBox_ScreenRes = (gcnew System::Windows::Forms::GroupBox()); + this->panel_ScreenRes = (gcnew System::Windows::Forms::Panel()); + this->tabControl = (gcnew System::Windows::Forms::TabControl()); + this->tabPage_Resolution = (gcnew System::Windows::Forms::TabPage()); + this->groupBox_Lag = (gcnew System::Windows::Forms::GroupBox()); + this->trackBar_LagCompensation = (gcnew System::Windows::Forms::TrackBar()); + this->groupBox_Details = (gcnew System::Windows::Forms::GroupBox()); + this->panel_Details = (gcnew System::Windows::Forms::Panel()); + this->labelGPU = (gcnew System::Windows::Forms::LinkLabel()); + this->groupBox_InternalRes = (gcnew System::Windows::Forms::GroupBox()); + this->panel_IntRes = (gcnew System::Windows::Forms::Panel()); + this->tabPage_Patches = (gcnew System::Windows::Forms::TabPage()); + this->panel_Patches = (gcnew System::Windows::Forms::Panel()); + this->tabPage_Playerdata = (gcnew System::Windows::Forms::TabPage()); + this->panel_Playerdata = (gcnew System::Windows::Forms::Panel()); + this->tabPage_Components = (gcnew System::Windows::Forms::TabPage()); + this->panel_Components = (gcnew System::Windows::Forms::Panel()); + this->tabPage_Plugins = (gcnew System::Windows::Forms::TabPage()); + this->panel_Custom = (gcnew System::Windows::Forms::Panel()); + this->panel_Plugins = (gcnew System::Windows::Forms::Panel()); + this->tabPage_Credits = (gcnew System::Windows::Forms::TabPage()); + this->creditsTextBox = (gcnew System::Windows::Forms::TextBox()); + this->button_Discord = (gcnew System::Windows::Forms::Button()); + this->button_github = (gcnew System::Windows::Forms::Button()); + this->toolTip1 = (gcnew System::Windows::Forms::ToolTip(this->components)); + this->button_Apply = (gcnew System::Windows::Forms::Button()); + this->button_Wiki = (gcnew System::Windows::Forms::Button()); + this->groupBox_ScreenRes->SuspendLayout(); + this->tabControl->SuspendLayout(); + this->tabPage_Resolution->SuspendLayout(); + this->groupBox_Lag->SuspendLayout(); + (cli::safe_cast(this->trackBar_LagCompensation))->BeginInit(); + this->groupBox_Details->SuspendLayout(); + this->groupBox_InternalRes->SuspendLayout(); + this->tabPage_Patches->SuspendLayout(); + this->tabPage_Playerdata->SuspendLayout(); + this->tabPage_Components->SuspendLayout(); + this->tabPage_Plugins->SuspendLayout(); + this->tabPage_Credits->SuspendLayout(); + this->SuspendLayout(); + // + // button_Launch + // + this->button_Launch->BackColor = System::Drawing::Color::White; + this->button_Launch->FlatAppearance->BorderColor = System::Drawing::SystemColors::Control; + this->button_Launch->FlatStyle = System::Windows::Forms::FlatStyle::Flat; + this->button_Launch->Location = System::Drawing::Point(344, 778); + this->button_Launch->Margin = System::Windows::Forms::Padding(6); + this->button_Launch->Name = L"button_Launch"; + this->button_Launch->Size = System::Drawing::Size(434, 46); + this->button_Launch->TabIndex = 20; + this->button_Launch->Text = L"Launch"; + this->button_Launch->UseVisualStyleBackColor = false; + this->button_Launch->Click += gcnew System::EventHandler(this, &ui::Button_Launch_Click); + // + // groupBox_ScreenRes + // + this->groupBox_ScreenRes->Controls->Add(this->panel_ScreenRes); + this->groupBox_ScreenRes->FlatStyle = System::Windows::Forms::FlatStyle::Flat; + this->groupBox_ScreenRes->Location = System::Drawing::Point(10, 12); + this->groupBox_ScreenRes->Margin = System::Windows::Forms::Padding(6); + this->groupBox_ScreenRes->Name = L"groupBox_ScreenRes"; + this->groupBox_ScreenRes->Padding = System::Windows::Forms::Padding(6); + this->groupBox_ScreenRes->Size = System::Drawing::Size(526, 226); + this->groupBox_ScreenRes->TabIndex = 10; + this->groupBox_ScreenRes->TabStop = false; + this->groupBox_ScreenRes->Text = L"Screen Resolution"; + // + // panel_ScreenRes + // + this->panel_ScreenRes->AutoScroll = true; + this->panel_ScreenRes->Location = System::Drawing::Point(10, 38); + this->panel_ScreenRes->Margin = System::Windows::Forms::Padding(6); + this->panel_ScreenRes->Name = L"panel_ScreenRes"; + this->panel_ScreenRes->Size = System::Drawing::Size(506, 178); + this->panel_ScreenRes->TabIndex = 0; + // + // tabControl + // + this->tabControl->Controls->Add(this->tabPage_Resolution); + this->tabControl->Controls->Add(this->tabPage_Patches); + this->tabControl->Controls->Add(this->tabPage_Playerdata); + this->tabControl->Controls->Add(this->tabPage_Components); + this->tabControl->Controls->Add(this->tabPage_Plugins); + this->tabControl->Controls->Add(this->tabPage_Credits); + this->tabControl->Location = System::Drawing::Point(0, 0); + this->tabControl->Margin = System::Windows::Forms::Padding(6); + this->tabControl->Name = L"tabControl"; + this->tabControl->SelectedIndex = 0; + this->tabControl->Size = System::Drawing::Size(1120, 768); + this->tabControl->TabIndex = 10; + // + // tabPage_Resolution + // + this->tabPage_Resolution->BackColor = System::Drawing::Color::White; + this->tabPage_Resolution->BackgroundImageLayout = System::Windows::Forms::ImageLayout::Stretch; + this->tabPage_Resolution->Controls->Add(this->groupBox_Lag); + this->tabPage_Resolution->Controls->Add(this->groupBox_Details); + this->tabPage_Resolution->Controls->Add(this->labelGPU); + this->tabPage_Resolution->Controls->Add(this->groupBox_InternalRes); + this->tabPage_Resolution->Controls->Add(this->groupBox_ScreenRes); + this->tabPage_Resolution->ForeColor = System::Drawing::Color::FromArgb(static_cast(static_cast(64)), + static_cast(static_cast(64)), static_cast(static_cast(64))); + this->tabPage_Resolution->Location = System::Drawing::Point(8, 39); + this->tabPage_Resolution->Margin = System::Windows::Forms::Padding(6); + this->tabPage_Resolution->Name = L"tabPage_Resolution"; + this->tabPage_Resolution->Padding = System::Windows::Forms::Padding(6); + this->tabPage_Resolution->Size = System::Drawing::Size(1104, 721); + this->tabPage_Resolution->TabIndex = 0; + this->tabPage_Resolution->Text = L"Graphics"; + // + // groupBox_Lag + // + this->groupBox_Lag->Controls->Add(this->trackBar_LagCompensation); + this->groupBox_Lag->FlatStyle = System::Windows::Forms::FlatStyle::Flat; + this->groupBox_Lag->Location = System::Drawing::Point(10, 564); + this->groupBox_Lag->Margin = System::Windows::Forms::Padding(6); + this->groupBox_Lag->Name = L"groupBox_Lag"; + this->groupBox_Lag->Padding = System::Windows::Forms::Padding(6); + this->groupBox_Lag->Size = System::Drawing::Size(526, 146); + this->groupBox_Lag->TabIndex = 21; + this->groupBox_Lag->TabStop = false; + this->groupBox_Lag->Text = L"Lag Compensation"; + // + // trackBar_LagCompensation + // + this->trackBar_LagCompensation->LargeChange = 1; + this->trackBar_LagCompensation->Location = System::Drawing::Point(14, 40); + this->trackBar_LagCompensation->Margin = System::Windows::Forms::Padding(6); + this->trackBar_LagCompensation->Maximum = 500; + this->trackBar_LagCompensation->Name = L"trackBar_LagCompensation"; + this->trackBar_LagCompensation->Size = System::Drawing::Size(500, 93); + this->trackBar_LagCompensation->TabIndex = 0; + this->trackBar_LagCompensation->TickStyle = System::Windows::Forms::TickStyle::None; + this->trackBar_LagCompensation->ValueChanged += gcnew System::EventHandler(this, &ui::trackBar_LagCompensation_ValueChanged); + // + // groupBox_Details + // + this->groupBox_Details->Controls->Add(this->panel_Details); + this->groupBox_Details->FlatStyle = System::Windows::Forms::FlatStyle::Flat; + this->groupBox_Details->Location = System::Drawing::Point(548, 12); + this->groupBox_Details->Margin = System::Windows::Forms::Padding(6); + this->groupBox_Details->Name = L"groupBox_Details"; + this->groupBox_Details->Padding = System::Windows::Forms::Padding(6); + this->groupBox_Details->Size = System::Drawing::Size(544, 698); + this->groupBox_Details->TabIndex = 11; + this->groupBox_Details->TabStop = false; + this->groupBox_Details->Text = L"Details"; + // + // panel_Details + // + this->panel_Details->AutoScroll = true; + this->panel_Details->Location = System::Drawing::Point(10, 23); + this->panel_Details->Margin = System::Windows::Forms::Padding(6); + this->panel_Details->Name = L"panel_Details"; + this->panel_Details->Size = System::Drawing::Size(522, 667); + this->panel_Details->TabIndex = 0; + // + // labelGPU + // + this->labelGPU->AutoSize = true; + this->labelGPU->BackColor = System::Drawing::Color::Transparent; + this->labelGPU->ForeColor = System::Drawing::Color::Black; + this->labelGPU->Location = System::Drawing::Point(10, 418); + this->labelGPU->Margin = System::Windows::Forms::Padding(4, 0, 4, 0); + this->labelGPU->MinimumSize = System::Drawing::Size(526, 26); + this->labelGPU->Name = L"labelGPU"; + this->labelGPU->Size = System::Drawing::Size(526, 26); + this->labelGPU->TabIndex = 21; + this->labelGPU->TextAlign = System::Drawing::ContentAlignment::MiddleLeft; + // + // groupBox_InternalRes + // + this->groupBox_InternalRes->Controls->Add(this->panel_IntRes); + this->groupBox_InternalRes->FlatStyle = System::Windows::Forms::FlatStyle::Flat; + this->groupBox_InternalRes->Location = System::Drawing::Point(10, 248); + this->groupBox_InternalRes->Margin = System::Windows::Forms::Padding(6); + this->groupBox_InternalRes->Name = L"groupBox_InternalRes"; + this->groupBox_InternalRes->Padding = System::Windows::Forms::Padding(6); + this->groupBox_InternalRes->Size = System::Drawing::Size(526, 166); + this->groupBox_InternalRes->TabIndex = 20; + this->groupBox_InternalRes->TabStop = false; + this->groupBox_InternalRes->Text = L"Internal Resolution (Quality)"; + // + // panel_IntRes + // + this->panel_IntRes->AutoScroll = true; + this->panel_IntRes->Location = System::Drawing::Point(10, 38); + this->panel_IntRes->Margin = System::Windows::Forms::Padding(6); + this->panel_IntRes->Name = L"panel_IntRes"; + this->panel_IntRes->Size = System::Drawing::Size(506, 118); + this->panel_IntRes->TabIndex = 1; + // + // tabPage_Patches + // + this->tabPage_Patches->BackColor = System::Drawing::Color::White; + this->tabPage_Patches->Controls->Add(this->panel_Patches); + this->tabPage_Patches->ForeColor = System::Drawing::Color::FromArgb(static_cast(static_cast(64)), static_cast(static_cast(64)), + static_cast(static_cast(64))); + this->tabPage_Patches->Location = System::Drawing::Point(8, 39); + this->tabPage_Patches->Margin = System::Windows::Forms::Padding(6); + this->tabPage_Patches->Name = L"tabPage_Patches"; + this->tabPage_Patches->Size = System::Drawing::Size(1104, 721); + this->tabPage_Patches->TabIndex = 1; + this->tabPage_Patches->Text = L"Options"; + // + // panel_Patches + // + this->panel_Patches->AutoScroll = true; + this->panel_Patches->Location = System::Drawing::Point(0, 0); + this->panel_Patches->Margin = System::Windows::Forms::Padding(6); + this->panel_Patches->Name = L"panel_Patches"; + this->panel_Patches->Size = System::Drawing::Size(1104, 716); + this->panel_Patches->TabIndex = 9; + // + // tabPage_Playerdata + // + this->tabPage_Playerdata->BackColor = System::Drawing::Color::White; + this->tabPage_Playerdata->Controls->Add(this->panel_Playerdata); + this->tabPage_Playerdata->ForeColor = System::Drawing::Color::FromArgb(static_cast(static_cast(64)), + static_cast(static_cast(64)), static_cast(static_cast(64))); + this->tabPage_Playerdata->Location = System::Drawing::Point(8, 39); + this->tabPage_Playerdata->Margin = System::Windows::Forms::Padding(6); + this->tabPage_Playerdata->Name = L"tabPage_Playerdata"; + this->tabPage_Playerdata->Size = System::Drawing::Size(1104, 721); + this->tabPage_Playerdata->TabIndex = 3; + this->tabPage_Playerdata->Text = L"Player"; + // + // panel_Playerdata + // + this->panel_Playerdata->AutoScroll = true; + this->panel_Playerdata->Location = System::Drawing::Point(0, 0); + this->panel_Playerdata->Margin = System::Windows::Forms::Padding(6); + this->panel_Playerdata->Name = L"panel_Playerdata"; + this->panel_Playerdata->Size = System::Drawing::Size(1104, 716); + this->panel_Playerdata->TabIndex = 1; + // + // tabPage_Components + // + this->tabPage_Components->BackColor = System::Drawing::Color::White; + this->tabPage_Components->Controls->Add(this->panel_Components); + this->tabPage_Components->ForeColor = System::Drawing::Color::FromArgb(static_cast(static_cast(64)), + static_cast(static_cast(64)), static_cast(static_cast(64))); + this->tabPage_Components->Location = System::Drawing::Point(8, 39); + this->tabPage_Components->Margin = System::Windows::Forms::Padding(6); + this->tabPage_Components->Name = L"tabPage_Components"; + this->tabPage_Components->Padding = System::Windows::Forms::Padding(6); + this->tabPage_Components->Size = System::Drawing::Size(1104, 721); + this->tabPage_Components->TabIndex = 2; + this->tabPage_Components->Text = L"Components"; + // + // panel_Components + // + this->panel_Components->AutoScroll = true; + this->panel_Components->Location = System::Drawing::Point(0, 0); + this->panel_Components->Margin = System::Windows::Forms::Padding(6); + this->panel_Components->Name = L"panel_Components"; + this->panel_Components->Size = System::Drawing::Size(1104, 716); + this->panel_Components->TabIndex = 0; + // + // tabPage_Plugins + // + this->tabPage_Plugins->BackColor = System::Drawing::Color::White; + this->tabPage_Plugins->Controls->Add(this->panel_Custom); + this->tabPage_Plugins->Controls->Add(this->panel_Plugins); + this->tabPage_Plugins->ForeColor = System::Drawing::Color::FromArgb(static_cast(static_cast(64)), static_cast(static_cast(64)), + static_cast(static_cast(64))); + this->tabPage_Plugins->Location = System::Drawing::Point(8, 39); + this->tabPage_Plugins->Margin = System::Windows::Forms::Padding(6); + this->tabPage_Plugins->Name = L"tabPage_Plugins"; + this->tabPage_Plugins->Padding = System::Windows::Forms::Padding(6); + this->tabPage_Plugins->Size = System::Drawing::Size(1104, 721); + this->tabPage_Plugins->TabIndex = 3; + this->tabPage_Plugins->Text = L"Plugins and Patches"; + // + // panel_Custom + // + this->panel_Custom->AutoScroll = true; + this->panel_Custom->Location = System::Drawing::Point(552, 0); + this->panel_Custom->Margin = System::Windows::Forms::Padding(6); + this->panel_Custom->Name = L"panel_Custom"; + this->panel_Custom->Size = System::Drawing::Size(552, 716); + this->panel_Custom->TabIndex = 3; + // + // panel_Plugins + // + this->panel_Plugins->AutoScroll = true; + this->panel_Plugins->Location = System::Drawing::Point(0, 0); + this->panel_Plugins->Margin = System::Windows::Forms::Padding(6); + this->panel_Plugins->Name = L"panel_Plugins"; + this->panel_Plugins->Size = System::Drawing::Size(552, 716); + this->panel_Plugins->TabIndex = 0; + // + // tabPage_Credits + // + this->tabPage_Credits->Controls->Add(this->creditsTextBox); + this->tabPage_Credits->Location = System::Drawing::Point(8, 39); + this->tabPage_Credits->Margin = System::Windows::Forms::Padding(4); + this->tabPage_Credits->Name = L"tabPage_Credits"; + this->tabPage_Credits->Padding = System::Windows::Forms::Padding(4); + this->tabPage_Credits->Size = System::Drawing::Size(1104, 721); + this->tabPage_Credits->TabIndex = 5; + this->tabPage_Credits->Text = L"Credits"; + this->tabPage_Credits->UseVisualStyleBackColor = true; + // + // creditsTextBox + // + this->creditsTextBox->BackColor = System::Drawing::Color::White; + this->creditsTextBox->ForeColor = System::Drawing::Color::FromArgb(static_cast(static_cast(64)), static_cast(static_cast(64)), + static_cast(static_cast(64))); + this->creditsTextBox->Location = System::Drawing::Point(0, 0); + this->creditsTextBox->Margin = System::Windows::Forms::Padding(4); + this->creditsTextBox->Multiline = true; + this->creditsTextBox->Name = L"creditsTextBox"; + this->creditsTextBox->ReadOnly = true; + this->creditsTextBox->ScrollBars = System::Windows::Forms::ScrollBars::Both; + this->creditsTextBox->Size = System::Drawing::Size(1100, 712); + this->creditsTextBox->TabIndex = 0; + this->creditsTextBox->Text = resources->GetString(L"creditsTextBox.Text"); + // + // button_Discord + // + this->button_Discord->BackColor = System::Drawing::Color::FromArgb(static_cast(static_cast(242)), static_cast(static_cast(242)), + static_cast(static_cast(242))); + this->button_Discord->Cursor = System::Windows::Forms::Cursors::Hand; + this->button_Discord->FlatAppearance->BorderSize = 0; + this->button_Discord->FlatStyle = System::Windows::Forms::FlatStyle::Flat; + this->button_Discord->Image = (cli::safe_cast(resources->GetObject(L"button_Discord.Image"))); + this->button_Discord->Location = System::Drawing::Point(992, 768); + this->button_Discord->Margin = System::Windows::Forms::Padding(6); + this->button_Discord->Name = L"button_Discord"; + this->button_Discord->Size = System::Drawing::Size(64, 64); + this->button_Discord->TabIndex = 31; + this->button_Discord->UseVisualStyleBackColor = false; + this->button_Discord->Click += gcnew System::EventHandler(this, &ui::button_Discord_Click); + // + // button_github + // + this->button_github->BackColor = System::Drawing::Color::FromArgb(static_cast(static_cast(242)), static_cast(static_cast(242)), + static_cast(static_cast(242))); + this->button_github->Cursor = System::Windows::Forms::Cursors::Hand; + this->button_github->FlatAppearance->BorderSize = 0; + this->button_github->FlatStyle = System::Windows::Forms::FlatStyle::Flat; + this->button_github->Image = (cli::safe_cast(resources->GetObject(L"button_github.Image"))); + this->button_github->Location = System::Drawing::Point(1056, 768); + this->button_github->Margin = System::Windows::Forms::Padding(6); + this->button_github->Name = L"button_github"; + this->button_github->Size = System::Drawing::Size(64, 64); + this->button_github->TabIndex = 32; + this->button_github->UseVisualStyleBackColor = false; + this->button_github->Click += gcnew System::EventHandler(this, &ui::button_github_Click); + // + // button_Apply + // + this->button_Apply->BackColor = System::Drawing::Color::White; + this->button_Apply->FlatAppearance->BorderColor = System::Drawing::SystemColors::Control; + this->button_Apply->FlatStyle = System::Windows::Forms::FlatStyle::Flat; + this->button_Apply->Location = System::Drawing::Point(8, 778); + this->button_Apply->Margin = System::Windows::Forms::Padding(6); + this->button_Apply->Name = L"button_Apply"; + this->button_Apply->Size = System::Drawing::Size(138, 46); + this->button_Apply->TabIndex = 33; + this->button_Apply->Text = L"Apply"; + this->button_Apply->UseVisualStyleBackColor = false; + this->button_Apply->Click += gcnew System::EventHandler(this, &ui::button_Apply_Click); + // + // button_Wiki + // + this->button_Wiki->BackColor = System::Drawing::Color::FromArgb(static_cast(static_cast(242)), static_cast(static_cast(242)), + static_cast(static_cast(242))); + this->button_Wiki->BackgroundImage = (cli::safe_cast(resources->GetObject(L"button_Wiki.BackgroundImage"))); + this->button_Wiki->BackgroundImageLayout = System::Windows::Forms::ImageLayout::Stretch; + this->button_Wiki->Cursor = System::Windows::Forms::Cursors::Hand; + this->button_Wiki->FlatAppearance->BorderSize = 0; + this->button_Wiki->FlatStyle = System::Windows::Forms::FlatStyle::Flat; + this->button_Wiki->Location = System::Drawing::Point(928, 768); + this->button_Wiki->Margin = System::Windows::Forms::Padding(6); + this->button_Wiki->Name = L"button_Wiki"; + this->button_Wiki->Size = System::Drawing::Size(64, 64); + this->button_Wiki->TabIndex = 34; + this->button_Wiki->UseVisualStyleBackColor = false; + this->button_Wiki->Click += gcnew System::EventHandler(this, &ui::button_Wiki_Click); + // + // ui + // + this->AcceptButton = this->button_Launch; + this->AutoScaleDimensions = System::Drawing::SizeF(192, 192); + this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Dpi; + this->AutoSize = true; + this->AutoSizeMode = System::Windows::Forms::AutoSizeMode::GrowAndShrink; + this->BackColor = System::Drawing::Color::Magenta; + this->BackgroundImageLayout = System::Windows::Forms::ImageLayout::Stretch; + this->ClientSize = System::Drawing::Size(1120, 834); + this->Controls->Add(this->button_Wiki); + this->Controls->Add(this->button_Apply); + this->Controls->Add(this->tabControl); + this->Controls->Add(this->button_Launch); + this->Controls->Add(this->button_github); + this->Controls->Add(this->button_Discord); + this->DoubleBuffered = true; + this->ForeColor = System::Drawing::Color::FromArgb(static_cast(static_cast(64)), static_cast(static_cast(64)), + static_cast(static_cast(64))); + this->FormBorderStyle = System::Windows::Forms::FormBorderStyle::Fixed3D; + this->HelpButton = true; + this->Icon = (cli::safe_cast(resources->GetObject(L"$this.Icon"))); + this->KeyPreview = true; + this->Margin = System::Windows::Forms::Padding(6); + this->MaximizeBox = false; + this->Name = L"ui"; + this->StartPosition = System::Windows::Forms::FormStartPosition::CenterScreen; + this->Text = L"PD Launcher (2.6a)"; + this->TransparencyKey = System::Drawing::Color::Magenta; + this->FormClosing += gcnew System::Windows::Forms::FormClosingEventHandler(this, &ui::Ui_FormClosing); + this->FormClosed += gcnew System::Windows::Forms::FormClosedEventHandler(this, &ui::Ui_FormClosed); + this->groupBox_ScreenRes->ResumeLayout(false); + this->tabControl->ResumeLayout(false); + this->tabPage_Resolution->ResumeLayout(false); + this->tabPage_Resolution->PerformLayout(); + this->groupBox_Lag->ResumeLayout(false); + this->groupBox_Lag->PerformLayout(); + (cli::safe_cast(this->trackBar_LagCompensation))->EndInit(); + this->groupBox_Details->ResumeLayout(false); + this->groupBox_InternalRes->ResumeLayout(false); + this->tabPage_Patches->ResumeLayout(false); + this->tabPage_Playerdata->ResumeLayout(false); + this->tabPage_Components->ResumeLayout(false); + this->tabPage_Plugins->ResumeLayout(false); + this->tabPage_Credits->ResumeLayout(false); + this->tabPage_Credits->PerformLayout(); + this->ResumeLayout(false); + + } +#pragma endregion +private: System::Void SaveSettings() { + if (*ResolutionConfigChanged) + { + for (ConfigOptionBase* option : screenResolutionArray) + { + option->SaveOption(); + } + + for (ConfigOptionBase* option : internalResolutionArray) + { + option->SaveOption(); + } + + *ResolutionConfigChanged = false; + } + + if (*OptionsConfigChanged) + { + for (ConfigOptionBase* option : optionsArray) + { + option->SaveOption(); + } + + for (ConfigOptionBase* option : graphicsArray) + { + option->SaveOption(); + } + + *OptionsConfigChanged = false; + } + + if (*PlayerdataConfigChanged) + { + for (ConfigOptionBase* option : playerdataArray) + { + option->SaveOption(); + } + + *PlayerdataConfigChanged = false; + } + + if (*ComponentsConfigChanged) + { + for (ConfigOptionBase* component : componentsArray) + { + component->SaveOption(); + } + + *ComponentsConfigChanged = false; + } + + if (*LagCompensationConfigChanged) + { + SetIniInt(GRAPHICS_SECTION, L"lag_compensation", trackBar_LagCompensation->Value, CONFIG_FILE); + *LagCompensationConfigChanged = false; + } + + for (ConfigOptionBase* option : AllPluginOpts) + { + if (*(option->hasChanged)) + { + option->SaveOption(); + } + + *(option->hasChanged) = false; + } + + for (ConfigOptionBase* option : AllCustomOpts) + { + if (*(option->hasChanged)) + { + option->SaveOption(); + } + + *(option->hasChanged) = false; + } +} +private: System::Void Button_Help_Click(System::Object^ sender, System::EventArgs^ e) { + System::Diagnostics::Process::Start("https://notabug.org/PDModdingCommunity/PD-Loader/wiki"); +} +private: System::Void Button_Launch_Click(System::Object^ sender, System::EventArgs^ e) { + + //SkinnedMessageBox::Show(this, "It looks like the executable has been tampered with, or the version of the game is not 7.10.\n\nPlease use the \"patches\" folder instead of modifying the executable directly (or disable verification).", "PD Launcher", MessageBoxButtons::OK, MessageBoxIcon::Error); + + SaveSettings(); + + if (GetPrivateProfileIntW(LAUNCHER_SECTION, L"use_divahook_bat", FALSE, CONFIG_FILE)) + { + if (GetPrivateProfileIntW(L"patches", L"quick_start", 1, CONFIG_FILE) > 0) + { + SkinnedMessageBox::Show(this, L"\"Quick Start\" and \"Use divahook.bat / start.bat\" cannot be enabled at the same time.", "PD Launcher", MessageBoxButtons::OK, MessageBoxIcon::Error); + return; + } + + DIVA_EXECUTABLE = NULL; + wstring DIVA_EXECUTABLE_LAUNCH_STRING_cmd = L"cmd.exe /C \""; + const wstring DIVA_EXECUTABLE_LAUNCH_STRING_path = DIVA_DIRPATH; + + wstring DIVAHOOK_BAT_PATH = DIVA_EXECUTABLE_LAUNCH_STRING_path; + DIVAHOOK_BAT_PATH.append(L"\\divahook.bat"); + if (std::filesystem::exists(DIVAHOOK_BAT_PATH)) + { + DIVA_EXECUTABLE_LAUNCH_STRING_cmd.append(DIVAHOOK_BAT_PATH); + DIVA_EXECUTABLE_LAUNCH_STRING_cmd.append(L"\""); + DIVA_EXECUTABLE_LAUNCH = const_cast(DIVA_EXECUTABLE_LAUNCH_STRING_cmd.c_str()); + } + else + { + wstring START_BAT_PATH = DIVA_EXECUTABLE_LAUNCH_STRING_path; + START_BAT_PATH.append(L"\\start.bat"); + if (std::filesystem::exists(START_BAT_PATH)) + { + DIVA_EXECUTABLE_LAUNCH_STRING_cmd.append(START_BAT_PATH); + DIVA_EXECUTABLE_LAUNCH_STRING_cmd.append(L"\""); + DIVA_EXECUTABLE_LAUNCH = const_cast(DIVA_EXECUTABLE_LAUNCH_STRING_cmd.c_str()); + } + else if (SkinnedMessageBox::Show(this, L"divahook.bat/start.bat not found.\nThe game will start normally/offline.\n\nNOTE: Disable \"Use divahook.bat / start.bat\" to avoid this warning.", "PD Launcher", MessageBoxButtons::OKCancel, MessageBoxIcon::Warning) != System::Windows::Forms::DialogResult::OK) return; + } + } + else + { + // read the command line here so it'll be up to date even if the user changed it + WCHAR stringBuf[256]; + GetPrivateProfileStringW(LAUNCHER_SECTION, L"command_line", L"", stringBuf, 256, CONFIG_FILE); + + DIVA_EXECUTABLE_LAUNCH_STRING += L" " + wstring(stringBuf); + DIVA_EXECUTABLE_LAUNCH = const_cast(DIVA_EXECUTABLE_LAUNCH_STRING.c_str()); + } + + STARTUPINFOW si; + PROCESS_INFORMATION pi; + + ZeroMemory(&si, sizeof(si)); + si.cb = sizeof(si); + ZeroMemory(&pi, sizeof(pi)); + CreateProcessW(DIVA_EXECUTABLE, DIVA_EXECUTABLE_LAUNCH, NULL, NULL, false, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi); + + // this->Close won't work in here since it will prompt the user to save the settings + TerminateProcess(GetCurrentProcess(), EXIT_SUCCESS); +} +private: System::Void InternalResEnabledChangedHandler(System::Object^ sender, System::EventArgs^ e) { + if (((CheckBox^)CheckBox::FromHandle(InternalResolutionCheckbox->mainControlHandle))->Checked) + { + ((Control^)Control::FromHandle(InternalResolutionOption->mainControlHandle))->Enabled = true; + } + else + { + ((Control^)Control::FromHandle(InternalResolutionOption->mainControlHandle))->Enabled = false; + } +} +private: System::Void DisplayTypeChangedHandler(System::Object^ sender, System::EventArgs^ e) { + int idx = ((ComboBox^)ComboBox::FromHandle(DisplayModeDropdown->mainControlHandle))->SelectedIndex; + + if (idx == 2) // fullscreen + { + for (ConfigOptionBase* option : screenResolutionArray) + { + if (option == RefreshRateOption) + { + ((Control^)Control::FromHandle(option->mainControlHandle))->Enabled = true; + } + } + } + else + { + for (ConfigOptionBase* option : screenResolutionArray) + { + if (option == RefreshRateOption) + { + ((Control^)Control::FromHandle(option->mainControlHandle))->Enabled = false; + } + } + } +} +private: System::Void Ui_FormClosing(System::Object^ sender, System::Windows::Forms::FormClosingEventArgs^ e) { + if (!AnyConfigChanged()) + return; + + switch (SkinnedMessageBox::Show(this, "Do you want to save your settings?", "PD Launcher", MessageBoxButtons::YesNoCancel, MessageBoxIcon::Question)) + { + case System::Windows::Forms::DialogResult::Yes: + SaveSettings(); + break; + + case System::Windows::Forms::DialogResult::No: + break; + + case System::Windows::Forms::DialogResult::Cancel: + e->Cancel = true; + break; + } +} +private: System::Void Ui_FormClosed(System::Object^ sender, System::Windows::Forms::FormClosedEventArgs^ e) { + // Prevents abnormal termination messages, remember that the game is still technically running and must be killed! + TerminateProcess(GetCurrentProcess(), EXIT_SUCCESS); +} +private: System::Void button_Discord_Click(System::Object^ sender, System::EventArgs^ e) { + switch (SkinnedMessageBox::Show(this, "Would you like to read the user guide for troubleshooting?", "PD Launcher", MessageBoxButtons::YesNoCancel, MessageBoxIcon::Information)) + { + case System::Windows::Forms::DialogResult::Yes: + System::Diagnostics::Process::Start("https://notabug.org/PDModdingCommunity/PD-Loader/wiki"); + break; + + case System::Windows::Forms::DialogResult::No: + System::Diagnostics::Process::Start("https://discord.gg/cvBVGDZ"); + break; + } +} +private: System::Void button_github_Click(System::Object^ sender, System::EventArgs^ e) { + System::Diagnostics::Process::Start("https://notabug.org/PDModdingCommunity/PD-Loader"); +} +private: System::Void button_Apply_Click(System::Object^ sender, System::EventArgs^ e) { + SaveSettings(); + updateStyle(); + ShowWindow(hWnd, SW_HIDE); + ShowWindow(hWnd, SW_SHOW); +} +private: System::Void Ui_KeyDown(System::Object^ sender, System::Windows::Forms::KeyEventArgs^ e) { + if (e->KeyCode == Keys::Escape) this->Close(); +} + +private: bool* ResolutionConfigChanged = new bool(false); + bool* OptionsConfigChanged = new bool(false); + bool* PlayerdataConfigChanged = new bool(false); + bool* ComponentsConfigChanged = new bool(false); + bool* LagCompensationConfigChanged = new bool(false); + +private: bool AnyConfigChanged() { + if (*ResolutionConfigChanged || *OptionsConfigChanged || *PlayerdataConfigChanged || *ComponentsConfigChanged || *LagCompensationConfigChanged) + return true; // fast case + + for (ConfigOptionBase* option : AllPluginOpts) + { + if (*(option->hasChanged)) return true; // slow case for iterating over individual plugins + } + + return false; +} + +private: String^ GPUIssueText; +private: System::Void LinkLabelLinkClickedGPUIssueHandler(System::Object^ sender, System::Windows::Forms::LinkLabelLinkClickedEventArgs^ e) { + SkinnedMessageBox::Show(this, GPUIssueText, "PD Launcher", MessageBoxButtons::OK, MessageBoxIcon::Warning); +} +private: System::Void trackBar_LagCompensation_ValueChanged(System::Object^ sender, System::EventArgs^ e) { + *LagCompensationConfigChanged = true; + + updateLagCompMsec(); +} +private: System::Void tabPage_Resolution_Click(System::Object^ sender, System::EventArgs^ e) { +} +private: System::Void button_Wiki_Click(System::Object^ sender, System::EventArgs^ e) { + System::Diagnostics::Process::Start("https://notabug.org/PDModdingCommunity/PD-Loader/wiki"); +} +private: System::Void trackBar_LagCompensation_Scroll(System::Object^ sender, System::EventArgs^ e) { +} +}; +} diff --git a/source-code/source/plugins/Launcher/ui.resx b/source-code/source/plugins/Launcher/ui.resx index c29e9fe..0a3b9ec 100644 --- a/source-code/source/plugins/Launcher/ui.resx +++ b/source-code/source/plugins/Launcher/ui.resx @@ -1,1749 +1,1749 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - PD Loader is intended for educational purposes only; not for piracy. -Users should possess a legally-obtained dump of the game to use this software. -Please check your local laws/regulataions to verify the legality of tampering -with and dumping data from protected arcade machine hardware. - -Project Contributors: -***REMOVED***, Brolijah, crash5b, ona, korenkonder, Kyberal, lybxlpsv, nastys, -Nezarn, samyuu, Skyth, somewhatlurker, Stewie1.0, SwigS-27, zsccat - - -PD Loader and the included plugins are distributed under MIT License: - - Copyright (c) Project DIVA Modding 2nd Community - Copyright (c) samyuu (nop) (original TLAC code) - Copyright (c) ThirteenAG (original Ultimate ASI Loader code) - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - -Microsoft Detours, utilized by many plugins, is licensed under MIT License: - - # Copyright (c) Microsoft Corporation - - All rights reserved. - - # MIT License - - Permission is hereby granted, free of charge, to any person obtaining a copy of - this software and associated documentation files (the "Software"), to deal in - the Software without restriction, including without limitation the rights to - use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies - of the Software, and to permit persons to whom the Software is furnished to do - so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - -Launcher, Patches, Render and TLAC plugins utilize files from FreeGLUT: - - Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies or substantial portions of the Software. - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of Pawel W. Olszta shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Pawel W. Olszta. - - -Launcher uses SimpleIni, licensed under MIT License: - - The MIT License (MIT) - - Copyright (c) 2006-2013 Brodie Thiesfield - - Permission is hereby granted, free of charge, to any person obtaining a copy of - this software and associated documentation files (the "Software"), to deal in - the Software without restriction, including without limitation the rights to - use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - the Software, and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - -DivaSound uses miniaudio (public domain or MIT-0) and BASSASIO (free for -non-commercial use only) - - -AMD compatibilty pack dependencies have additional licenses, detailed in the AMD - - - - - iVBORw0KGgoAAAANSUhEUgAAACoAAAApCAYAAABDV7v1AAAABGdBTUEAALGPC/xhBQAAA7hJREFUWEft - mEtME0EYgIshUY/GqwcPevbsjYMXb95MPHnTKAUWEVADNQLdFnlUUHkEA4IKmMhD8BEf1IiCUQERIt3t - g7ZIodBCS+mDbbu/MyUtLaVAYbYa7CSTbbrT///+50xHJEqOpAeiPXBeMnkgvZg5S0nZIopmS4WYmVKG - zqA1YrFEfWRHMaCoqYOUjOnIlrOQiEnJWO1FyeTRuGEzSibECNCfCMigjiwZMywWq/fHBYvC7EgkZEiX - jDmxbdC0NGXqX4FEaZYlVZ9MgpL0/v/t0bxyNZQ36qGiSQ/5Fatt7EopCzm3Vz/nlrGgaNZDTasRbt7T - bKvNEfdo9SMDDI3boLlrGrrem+HT0AL80i6DweQG44w78Bz+ZYd3AxZo6zXBGLsEfV+scL1SvSkwUdCW - bhPMWz0wxtiB4/yw1fD5eFDpsBEuZIwjcaAagxM8K1sDrjfA7+eB53moQtGIVYDEPFpcq93KgVu+ty1x - gVzeCJYY6CgK924H5/WDvGFSONBrqBDWhxyH0uH0wtKyF3Bow4fT7QW7wwsYDK8LDvy558OccKCKZgN4 - kdJwhaMqOxTX6qCwWgMfvy+E3lltHJQ1TsINhRraXs1G/A4v6kddQrDQ9yrnozwjrVsLYf3T3yHQps7p - EIjkrhYW7FyEt3EXEAz0zWdLhDIcQtyqggofPFsDHRxZDH1/674OnC5vxG9XOJ9woP1hocVaMSjOv+6+ - OXjyYgZWVnwRaTEwssg3dU3zZos7IhLBRXnl0ZVPpOoHR20hEA+CMpndUQUUqyO4PL5Aw8fNPzgKqqK3 - VSKgr/vXctSPvPmTtUPLcxNoDMsxgXGXGPyxCK1oG11a5kKetSxycBWdBdbnKRHQXBQq5dcFsDlWFeJp - tnhA8VAPhahgatunoP3lDHS8nYXHPSa402KEfHRwwbntcq+mhdfnB+2UE6paNt6diIAGrS+p00E3OohM - oH37GzqY4FPUZmfSyiYDaI1OwAVW02YMtCzBt1CSh2TB2pPQkFg+0dALCbw3QUUiyT50c+Em7TlKzvJI - rgM/iRQT/l9NSZkK0qCBHKRV9ehGpDMWbFyhx6Dn8g2H0N3T+GbW78QQSqZqTZMoU7Notm0j2XGDYtgL - RZrjSGBBtoxtREKbiUwZ04BlX5ZOHM6kVTVIJhdu8I5Aw65WUkQiIDhDklOyaEYWfhm3W9BtXwfFu/A0 - ur1DOZuDiswadx+NVxmJ9elS5gwlZ1z/rEfDjRTTzKlL9PgxEoYnZewZD/wB4r+Nvne+oTwAAAAASUVO - RK5CYII= - - - - - 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 - - - - 17, 17 - - - - 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 - xP/nnr//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAD38vAB7e3u5uzs7P/s6+v/6+nq/+ro6f/p5+j/6efo/+nn6P/p5ef/6OHl/+jf5P/o4OT/6LTO/+eT - vf/mgbH/5YGw/+SMtv/lk7r/5aHB/+awyOznwNJy5ObqI+Hq7Gff6ey73ens79vp7P/Y6e3/1ujt/9Tp - 7f/U6e7/1ent/9Tp7f/U6O3/0uju/9Lo7f/R6O3/z+jt/8/o7v/P6O7/z+jt/9Lo7f/Q5+3/0Ojt/9Po - 7f/T6O3/1Ojt/9Pp7f/S6O3/1unt/9bo7P/X5+v/1+fr/9nn6//b5+vj3ufqmeDo6jPr6ekBAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAADRrr8A57rPEOe0y8Pno8L/55u9/+aWu/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu7u7L7Ozs/+zq6//r6uv/6ujp/+rn - 6P/p5uj/6ebn/+nj5f/o2OD/6MjY/+jT3f/nosb/6IW0/+dxpv/lbqX/5XGm/+V+r//mlLr/5b7Q/+Le - 5P/d6ez52Ons/9fp7P/V6O3/0enu/9Dp7v/O6O7/zOju/83o7v/L6O7/zeju/8/o7f/H5+7/yuft/8jn - 7v/G6O//xefv/8Xo7//M6O7/zuft/8nn7v/K5+7/yefu/9Do7f/Q6O3/z+ju/83o7v/U6O3/0ejt/9Ho - 7f/T6Oz/1efr/9bn6//Y5+v/2ufq+d3n6svf5+lh4+bqCQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASj5EAOW+0Qnmtsy+5qTC/+Wa - vf/mkLj/5o23/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAO/v73bt7Oz/7Orr/+vp6v/r6On/6ujp/+rm5//p5ef/6eHl/+nZ4f/ovdT/57HN/+ma - v//qeab/5Wad/+N1qP/ldaT/5bXJ/+Di6P/c6u3/2Onu/9Tp7v/Q6O3/zejt/83o7v/N6O7/y+ju/8rn - 7v/G5+7/x+fu/8zm7f/F5u7/yebt/8Lm7v/E5u3/v+bu/8Tn7//E5+7/wefu/8Hn7v/B5+//x+fv/8vo - 7v/C5u7/xObu/8rn7f/N5+3/yOfu/8/o7f/M6O3/zujt/8zo7f/Q6O3/0Ofs/9Pn6//U5uv/1ubr/9nn - 6v/c5urc3+fqW+Lo6gcAAAAAKy0tAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAABMPEQDksc8B5q/ImeWfwP/lmbz/5Y21/+aFsf/lirT/AAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7+/vEu7t7u3s6+v/7Orq/+vo - 6f/r5+n/6ubo/+nk5//q4uX/6t7k/+vF2P/pk7//6m2i/+htof/jdKf/4ajB/9/h5v/Z6u3/1+ru/9Tp - 7v/Q6O3/zOju/8bn7v/H5+7/xufu/8fn7v/F5+7/xebu/8jm7f/G5u3/w+bu/8Lm7v+/5u7/u+bu/8Ll - 7f+55e7/uObv/73m7v/A5e3/uuXu/7/m7v+85+//w+fu/77m7v++5u7/w+bt/8Pm7f+55u//xefu/8Pn - 7v/I5+7/xufu/8rn7f/N5+z/zufs/8/m7P/S5uv/0ubq/9Xm6v/Y5+r/3Obq19/m6Vfi6OsIAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOa0ylHlosD+5ZW6/+ST - uv/ljLb/5oWw/+WBrv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAA7+ztlu3r7P/s6er/6+jp/+vo6f/r5Of/6uXn/+rg5f/r2eH/7sbW/+uE - sv/paJz/53ml/+HO2f/b6e3/1unu/9Hp7v/Q6O7/yufu/8jn7v/F5+7/x+fu/8Xn7v/E5u7/x+bu/8Hm - 7//D5+//zObt/8bm7v/G5u7/xOXt/7zk7f+55O7/vOPt/7fk7v+65O7/tuTu/73k7f+65O3/uuXu/7nm - 7/+45e//vOXt/7rl7v+05O7/vuXu/7bl7//C5u7/webu/7zm7v/B5u7/x+bt/8bm7f/M5+3/xebt/83n - 7P/O5+z/zufs/9Hm6//V5uv/2ebq/tzm6szf5+lZ4uXrApmdnwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAADnus1A5qjD8+WNtf/kibP/5JC3/+V2qP/mfav/5Yey/wAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAuLwDu3+Yh7uXp+O3o - 6v/s5un/7Obp/+zk5//s4eb/7c7b/+2tyf/tiq//6n2r/+aeuv/f4OX/2ent/9Tp7v/Q6O7/0ejt/8rn - 7v/C5+//vOfw/8Hm7v+/5u//v+bu/8Dl7v/B5e7/vOXu/7fk7v+x4u3/rOHt/63h7f+s4O3/r+Ht/7Dh - 7v+w4u7/sePu/7Lj7f+y4u3/seLt/6/i7v+24u3/suPt/7bk7f+w4+7/tOTu/7Xj7v+34+7/s+Tu/7vl - 7v+85e3/veXt/7bl7v+95u7/wubu/8fm7P/G5u3/yebt/83n7P/N5+z/zufs/9Hm6//T5ur/1ubq/9jm - 6v7c5um43+XpHgAAAAAqKioAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5a3GQeajwfXkl7v/44mz/+WE - sf/liLP/5nqp/+eCrv/lbaH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAO3D1APtwtXV7dfh/+7g5v/u2OL/7svb/++zzP/ujrj/6nWn/+ho - m//norr/3ujr/9bp7v/R6e7/z+ju/83o7v/J5+7/yObu/77m7v/A5u7/wOTt/7Tk7/+34+3/suHt/6Le - 6/+c3Ov/jNjp/4DT5v+B0uf/idbp/4HT5/+O2On/rt7s/6bd7f+j3ez/ptzt/6Td7f+k3u3/qd7t/6Pe - 7v+o3+7/q+Dt/6ng7f+s4e3/sOLt/7bh7P+14+3/t+Pt/7Xk7v+85e3/v+Tt/73k7f/B5e3/wObt/73m - 7v/J5u3/y+bs/8fm7f/J5u3/z+fs/9Hm6//R5uv/0+br/9bl6v/a5unw3eXpgeDl5wkAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAOawyCvloL/t5JK4/+OPtv/kgK//5Xur/+WDsP/mfq3/5Yez/+Znmf8AAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOmr - xqzqmr3/6pq//+yQuP/shbL/6n2r/+pyo//pap3/5qW9/9/n6//V6e7/zuju/8zn7v/K5+7/yefu/8Lm - 7//B5e7/uOXv/7fj7f+14u3/suHt/7Pi7v+u4O3/g9Po/3HB4f9eo9b/QHrL/zJfx/82Ycj/NmDH/zBc - yv9CYsr/P2HK/z5fyf8/ZMn/Q2vK/0x4zf9dkNL/cqTZ/4K94v+Tzun/oNns/6He7f+l3u3/pt/t/6rg - 7f+t4u7/tePt/7Xj7f++5Oz/seTu/8Ll7f++5e3/t+Xu/7/l7f/E5u3/wubu/8Tm7v/F5u3/zefs/8vn - 7P/R5uv/0ebr/9Tl6v/W5er/2uTo0d3j5zkAAAAArK6xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKZ0iADlrsYO5aLB1OSUuf/kj7b/5Iay/+V8 - q//meKj/5oSx/+dclP/lga//5XGi/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA56vDf+acvf/mh7H/6YCu/+hvof/nb6L/6Xan/+mM - rf/f5+v/1urv/8/o7v/K5+7/xufu/8Lm7v+/5u7/t+Xv/7Pj7v+y4u7/rODt/6Te7f+Tzuj/eq/c/2KJ - 0P8rSsT/CwC//wwAv/8IBL7/BAG4/wIBrP8BAa//AAC3/wYEwP8MBsT/EgfF/xMIxf8SBsb/DwTG/w8F - x/8NAcX/BADE/w0axf8yUsr/UobT/3Kl2/+Jx+b/ndnr/6Xc7P+k3u3/p9/t/7Dh7f+04u3/vOPt/7nk - 7P+25O3/u+Tt/7nk7v++5e3/wuXt/8Xm7v/E5u3/x+bt/8/m7P/P5uz/0ebs/9Hm6v/U5er/2OTp+Nzj - 54/f4uQMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AABmVVwA477NBeWiwKnjlLn/44iy/+OLtP/kirT/5H+t/+V7qv/kg7D/5mSZ/+SArf/kdqf/AAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AADoqcNk557A/+WFr//ngq7/54q1/+d3p//peKT/4dzi/9Xp7v/K6O//yOfv/8Xm7v+75e//tuTv/7bk - 7v+t4e7/rODt/5jV6v9up9j/PWbH/xMev/8HAL//BAG9/wEAtv8AAKX/AACg/wwEsf8zIcb/UDvb/2NN - 5P9yW+f/fGPo/4Fo6f+Daun/hWno/4Bk5/94XOf/cVTn/2VL5v9cQuX/Ujvj/0Uw4f82It7/IxDZ/xYY - 0/86Ydf/aZ3d/5DO6P+g3Oz/p97t/6vg7f+w4e3/suPt/7Tj7f+54+z/u+Ps/7rl7f+95e3/wOXt/77m - 7v/A5u7/yObt/83m7P/O5uz/zebs/9Dm6//T5er/1+To/9vj59Dd4+Y3AAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAXFBUAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOS0yRLkqcSw45e6/+OKs//khrD/4oey/+KF - sf/jeKn/43+t/+OCsP/lYpn/5Hmo/+Vwo/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOipxE3ooMD/55K3/+Z8qv/mibL/6IWy/+XF - 0f/W6e7/0eju/8Ln7/+75u//uePu/7bi7f+v4u7/rN/t/5jU6v9mnNT/GzW8/woEvf8DAb3/AQC2/wAA - p/8DAZj/Ixaz/0851P92XOb/kXfp/6GJ6/+okuz/rpnr/7Kd6/+0n+v/tJ/r/7Oe6/+znev/sp3s/7Ca - 6/+sluv/po/r/56G6v+Xfen/knbo/4tw5/9+Y+b/Zkzk/0sz4f81IN7/Kifa/1uK3/+Nyej/oNzs/6be - 7P+p3+3/rOHt/7ri6/+34+z/t+Tt/7Xk7v+55e3/vuXt/7fl7v/B5u3/x+bs/8vm7P/H5uz/zebs/8/m - 6//Q5er/1OXp/9jj6PTg2+G75sbUvebD0sHmxdTE58XTxObE08PmxNO+5sXTuebG1LLmxdOu5sbUrObG - 1Kvmx9Wp5sfVp+bH1J/mx9SW5snVjObI1YDmyNV05snVZ+bK1lbmy9ZH58vXNebN2CPmzdgU583YCubN - 2AXjsMdE46PA3uSZu//ij7b/44aw/+KCrv/hhLD/4oCu/+KDr//jcaT/5Hen/+Vyof/keKf/42ab/wAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAwKCoA6KnEQ+mdv//ojLX/5oi0/+d8qv/mo7//3Ont/87p7//J5+7/t+Xu/63j7/+t4e7/p97t/5zZ - 7P9wqtn/IEC+/wgBu/8DAbz/AACz/wAAn/8MBJr/RjPE/3Vd5P+UfOr/qZLr/7Oe7P+5pez/vqzs/8Gw - 7P/Dsu3/xLTt/8W17f/Gt+3/x7ju/8i47v/Iue3/x7ft/8W17f/Csuz/v67s/7uo6/+0oOv/r5nq/6uU - 6f+ljuj/ln7n/4Np5f9oTeX/UDbi/zss3v9ah+D/jMnp/6Lc7P+n3+z/seDr/6zi7f+y5O7/tuTt/7bk - 7f+95O3/tuTt/73l7f/A5e3/x+bt/8nm7P/M5uz/yObs/87l6//R5er/0+Xq/9fk6P/e2OD/5L7P/+S4 - zP/ktsv/5bbL/+W1y//lt8z/5bbL/+S1yv/ltsv/5LfM/+S3zP/kuMz/5LrN/+W6zf/lu83/5bvN/+W9 - z//lvs//5b/P/+XA0P/lwtH/5cPR/+XF0vzlwtHw5LLI3+Ogv/3jlbn/4ouz/+GIsv/if6z/4X+s/+F9 - q//ifaz/4n2r/+N+rP/lZ5r/5WOY/+Rzo//jdaT/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADoqMI1556+/+eOtv/mfq3/5Yax/+HY - 4P/V6e7/yOjv/73m7/+t4+//o9/t/57d7f+Iy+j/QHHG/wUAuP8DAbr/AAC1/wAApv8DAJb/Uj7C/4lw - 5f+pkuv/uabs/8Gw7f/Gtu3/yLnu/8m77v/LvO7/zL3u/82+7v/OwO7/zsHu/8/C7v/Pwu7/zsHu/83A - 7v/Mvu7/y73u/8q77f/Iue3/x7ft/8S07P/BsOz/vavr/7uo6v+2oun/rJfp/6CI5/+Ocub/eVzl/2NH - 4v9EOd//YI/h/5PQ6v+k3Oz/pt/t/67i7f+x4+3/tOPt/7nj7P+25O3/uuTt/7Pk7v/D5e3/xeXs/8vl - 6//K5uz/yebs/8nl6//R5er/0uXr/9bk6f/b3eP/48TS/+W7zf/luc3/5LbL/+Syyf/ksMj/5LDI/+Sv - x//krMb/5KzG/+Sux//kq8X/5KnE/+Ssxv/krcb/463H/+Stxv/jrcb/5K7H/+Oqxf/kq8X/5KfE/+Oi - wP/jmLv/45G3/+KLs//hhrD/4YKu/+F3p//hfqz/4Xin/+Jzpf/icqP/43mq/+Ztn//mZZf/5HWl/+N5 - qP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAOmrxSvnocD/5pK4/+aRuP/kuMz/2Ont/87o7v/D5u//s+Lu/6Pf7v+b2+z/esLj/yA+ - u/8GAbj/AgC2/wAAr/8AAJv/PCyt/4hx4f+slev/vavs/8W17f/KvO7/zb/u/87B7v/Qw+//0cXv/9HG - 7//Sxu//0sfv/9PI7//TyO//08jv/9LH7//QxO//z8Lu/83A7v/Mvu7/y73u/8q87f/Ju+3/ybrt/8e4 - 7f/Ftez/w7Ps/8Cv6/+9q+v/uabq/7Gd6P+ji+j/lHnn/4Fm5f9gRuL/QEff/32s5P+a2ev/o93s/6jg - 7P+s4e3/tOLs/7Pj7P+34+z/tuTt/7rk7f/D5e3/xeXt/8bm7P/F5ez/yubs/87l6//O5ev/0eXr/9Xk - 6f/Z3+X/4cHS/+SxyP/ktMr/5LbL/+S3y//ktcr/5LDI/+Stxv/kq8X/5KjE/+Omw//jpsP/46PB/+Sg - wP/kocD/45y+/+Ofv//jnb7/45m9/+OXu//jlLn/45O5/+KOtv/iibL/4YSu/+GFsP/hgKz/4Xqo/+B6 - qP/hd6f/4m+h/+N2pv/jc6P/5WCT/+Rmmv/kaJz/5Gmd/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6KrGH+egwPvokbj/55W6/93j - 6P/R6O7/xOfv/7vk7v+o4O7/oN3t/4XF5f8bO7f/BgK0/wEAtf8AAKv/BgOZ/2dUyf+nkOr/uqbs/8S0 - 7f/Juu7/zL7u/87A7v/Pwu//0sXv/9PJ7//Vyu//1czv/9bM7//Wze//1s3v/9bM7//Vy+//08fv/9HE - 7//Pwu7/zsDu/82/7v/Mvu3/y73t/8q87f/Ju+3/ybrt/8e47P/Gt+z/xbbs/8Oz7P/Bsev/vq3q/7im - 6v+vm+n/ppDn/5mA5f98YeT/UDfh/1yF4f+S0ur/n9zs/6He7P+s4Ov/s+Hr/7Ti7P+v4+3/t+Pt/7nk - 7f+85e3/weXt/8Hl7f/H5ez/yubs/83l6//O5ev/0OXr/9Pk6v/X4eb/38nW/+Slwv/kp8P/5KrE/+St - xv/kr8f/5K3G/+Sux//krcb/46rF/+Skwv/koMD/5Jy+/+Sdvv/knL7/5Ja7/+SXvP/jlbv/45G4/+OP - t//ijLX/4ou0/+GGsP/ghbD/4H2s/+CCrv/gfav/33im/+Brnv/ib5//4myd/+Nvov/kZJf/42+e/+Vn - mv/lZ5n/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAADpqsMV6aHA9emSuf/lxNT/1unt/8vm7f+95e7/tuLt/6nf7f+O0On/KFC7/wUC - tf8BALX/AACq/w4Hmf98Z9j/tJ7r/7+u7P/Ht+3/yrzu/8y+7v/NwO7/z8Hu/9HD7//Tx+//1cvv/9fN - 7//Yz+//2M/v/9jQ7//Yz+//187v/9XL7//Tx+//0cTu/8/B7v/Nv+7/zL7t/8u97f/LvO3/yrzt/8q7 - 7f/Ju+3/ybrs/8i57P/HuOz/xrfs/8W17P/Ds+v/wLDr/72s6v+3pen/sJzo/6SN5/+MceX/ZUnj/1Ri - 3/+Kx+j/mtrs/6Hc6/+s3uv/r+Hs/7Ti7P+54uz/tOPt/7vk7f+85e3/veXt/7/l7f/G5ez/xuXs/8vm - 7P/M5ez/0OXr/9Hk6f/V4uf/3srX/+Oiwf/jnL//45+//+Ojwf/jn7//46bD/+Olwv/jp8P/46TB/+Oi - wf/jnr//45i7/+SUuv/jlLr/45C4/+OTuf/jj7f/44y2/+KHs//ijLX/4YSw/+B9q//gean/4H6s/998 - q//fd6b/4Gqb/+BnmP/gcaD/4GaY/+Fyov/ic6L/42KW/+Rjl/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOiuxhHppMPy6Jq8/97l - 6v/Q5+3/w+Ts/7rj7v+r4O3/mtns/0R4xf8EALP/AQC0/wAAqv8MBZv/g23a/7ei6//Csez/yLnt/8u8 - 7v/Mvu7/zb/u/87A7v/Pwe7/0cTv/9PH7//Vy+//187v/9nQ7//Y0O//2NDv/9jQ7//Xzu//1cvv/9PG - 7//Qwu7/zcDu/8u97f/LvO3/yrzt/8q77f/Ku+z/yrvs/8m67P/Juuz/yLns/8i57P/HuOz/xrfs/8W1 - 7P/Ds+v/wrLr/7+v6/+8qur/taPp/6uV6P+VfOb/b1Tk/1JT4f9/uOb/mtnr/57b6/+k3uz/quHs/7Hi - 7P+14+z/uePs/7rk7f+15O3/v+Xt/8bl7P/H5uz/yuXs/8nl7P/L5ez/0OXr/9Lk6f/V4uj/3NDb/+Kc - vv/jmLv/4pW7/+Obvf/jm73/45y+/+Ocvv/jmrz/45+//+Obvf/jmr3/45e7/+OSuf/jjrf/45C4/+KM - tv/ijrf/4omz/+KEsf/hfqz/4Xuq/+Bil//feaj/3nGh/99voP/geKb/33Kh/99mmP/fdKP/33in/+Fh - lf/jYpT/422d/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAA6K3FDemjwu3lwNH/1+nt/8vn7v++5O3/r+Ht/6Dc7f9pqNj/AQCw/wEA - s/8AAKv/AACc/3xm0/+4pOv/w7Ps/8e47f/LvO7/zL7u/8y+7v/Mvu7/zb/u/87A7v/Pwu7/0sbv/9XL - 7//Xzu//2M/v/9jP7//Xzu//187v/9bM7//UyO//0cTu/83A7f/Lve3/yrvt/8m77P/Juuz/ybvs/8q7 - 7P/Ku+z/ybrs/8m67P/Iuez/yLjs/8e37P/Gt+z/xrbs/8W17P/EtOv/wrPr/8Cw6/++rer/uKfq/6+b - 6P+Zgef/e2Lk/1pI4f9tquP/kNXq/53b6v+h3uz/qeHt/7Hi7f+24+z/tuPt/7Xk7v+/5Oz/veTt/8Pl - 7P/H5ez/x+Xs/8jl7P/L5ev/0eTq/9Lk6f/V4uj/3NLc/+KZvP/ilLr/4pS6/+KVu//jl7v/45W6/+OV - uv/jmbz/45a7/+OTuf/jlrv/45O5/+OPt//jibT/4oq0/+KGsv/ifq3/4n+u/+KBr//hean/4GaX/99w - oP/fbJz/3VWH/952pP/eapr/3mqa/952pf/eaJr/4GaY/+Jkl//iZ5r/AAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADjucoF6aHA4+Hd - 5P/Q6O3/w+bu/7jj7v+q3uz/iM/o/xo9tP8CALL/AACu/wAAof9iUcH/taHq/8Sz7P/Juu3/yrzt/8y9 - 7f/Mvu3/zL7t/8y97f/Mve3/zL7t/87A7v/Qw+7/08fv/9TJ7//Vyu//1Mrv/9TJ7//TyO//0sbu/9DE - 7v/OwO3/y73t/8q77P/Juuz/yLns/8i57P/Juuz/ybrs/8m67P/Iuez/yLjs/8e37P/Gt+z/xrfs/8a3 - 7P/Gt+z/xbbs/8W16//Etev/w7Pr/8Gx6/+/r+r/u6rq/7Gf6P+Yg+X/e2Hg/0w42v9knN7/kdTp/5na - 6/+l3uv/reDs/7Di7P+y4+3/tuPt/7nk7f/A5e3/veXt/8Tl7P/F5ez/yOXs/8rl7P/M5ev/0OTr/9Hk - 6f/U4uf/29Db/+Gbvf/ikbj/4pC4/+OUuv/ikrn/4pS5/+OTuf/jlLn/45O5/+OTuf/jjrb/44+3/+OH - s//jiLP/44Cv/+OCsP/jgrD/4nmr/+J9rP/gaZz/33Cg/99unf/ebZv/3WOV/95ik//ea5r/3m2e/95u - nf/gZ5j/4GmY/99Qhf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADotszE2ujs/87n7f++5O7/seHt/6Db7P9bmdH/AgCv/wAA - sf8AAKj/LySn/6qW6P/Csez/x7nt/8q87f/LvO3/y73t/8u97f/LvO3/yrzt/8q87f/LvO3/zL7t/87A - 7v/Pwu7/0MPu/9DD7v/Pwu7/z8Hu/87A7v/NwO3/zL7t/8q77P/Juuz/yLns/8e47P/HuOz/x7js/8i5 - 7P/Iuev/yLnr/8e47P/Gt+z/xrfs/8a37P/Gt+z/xrfs/8a36//Gt+v/xbbr/8S16//DtOv/w7Pr/8Ky - 6/+/sOr/uKjo/6iU5f+LdN//bFPZ/0Mx0/9cmNz/ktXp/5ra6v+j3er/reDr/7Th6/+64uz/tePt/7rk - 7f+55O3/vOTt/8Pl7P/A5ez/x+Xs/8jl7P/K5ez/zeXr/8/k6//V4ej/2tHc/+GXu//ijLb/4om0/+KQ - uP/ikrn/45C4/+ONtv/jj7f/4462/+OMtf/jjLX/44m0/+OHs//jgq//4nys/+OBr//hX5P/4n2r/+Bz - pf/fbaD/3mWY/95sm//dRnn/3VmM/91dkP/dW47/3miX/99De//gapv/31iK/wAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOTY - 4KLU6O7/x+bt/7fj7v+o3u3/kdXr/x5Etf8BALH/AACt/wAAnP+GdNT/vqzs/8a37f/Ju+3/yrzt/8u9 - 7f/Lve3/y73t/8q87f/Ku+3/ybvt/8q77P/Ku+z/yrzs/8u97f/Lve3/y7zt/8q87f/Ku+z/ybvs/8m6 - 7P/Iuez/xrjs/8a36//Ftev/xbXr/8W26//Gt+v/xrfr/8a26//Gtuv/xbXr/8W16//Ftev/xbbr/8W2 - 6//Ftuv/xrbr/8a26//Ftuv/xLXr/8S06//Ds+v/wLDq/7ur6f+zoef/qZTk/5mD4P+EbNz/aU/Y/0Is - 0v9hnN3/jtTp/5ja6v+l3Or/rN/r/7Th6/+t4u3/tePt/7Xk7f+65O3/weXs/8Hl7P/C5Oz/yeXs/8fl - 7P/M5ev/zOXr/9Dk6v/U4uj/2tPd/+CXu//ijLb/4ou1/+KGsv/ijrf/4oez/+OIs//jirT/44q0/+OF - sv/jibP/4oey/+KFsf/ifqz/4n2s/+Jxo//icKP/4nin/+BtoP/gcqP/3muc/95Pgv/dUYL/3F2O/95w - oP/cWYv/3WOS/95nmP/eXY//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3urtp83n7f/A5O3/reDt/6Ld7P9zt9//AACp/wAA - rv8AAKf/Niqn/7Wi6v/Etez/ybrt/8q87f/KvO3/yrzt/8u87f/KvOz/yrvs/8m67P/Iuez/yLns/8i5 - 7P/Iuev/x7ns/8e47P/Ht+z/xrfs/8a36//Gtuv/xbXr/8S16//Ds+r/w7Pq/8Oz6v/Ds+r/w7Pq/8S0 - 6v/EtOr/w7Pr/8Oy6//Csuv/wrLr/8Oz6//DtOv/xLXr/8S16//Etev/xLXr/8W16//Ftev/xLXr/8Gy - 6v+7q+n/s6Hm/6yX5P+mkeL/oYzh/5eC3/+Gbt3/Z07Y/0Au0f9qpN3/lNbo/5vY6P+g3Or/pd/s/6zi - 7P+v4u3/rePt/7Xj7f+55O3/vuTs/7/l7f++5Oz/vuTs/8vl7P/N5ev/zOTr/9Dj6v/U4ej/2tPe/+CP - t//hhrP/4oez/+KMtv/ih7P/44Wy/+ONtv/ji7X/44Wx/+OKtP/ih7L/4oGv/+F/rf/hfKv/4Xmp/+F8 - q//gcKL/4W2g/+Btof/fZpr/3maW/9xcj//ccqH/3Guc/9tglP/ecKH/3WaX/95jlP8AAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHx4eAODq - 7g7Y6e7pyebt/7jj7f+s3+3/l9ns/1CNyv8AAKb/AACo/wAAmP+BcMv/wbDs/8e57f/KvO3/yr3t/8q8 - 7f/KvOz/yrvs/8m67P/Iuez/yLns/8e47P/Gtuv/xbXr/8W16//EtOv/xLTr/8S06//Ds+v/w7Pq/8Oy - 6v/Csur/wbHq/8Cw6v/AsOr/wbDq/8Gx6v/Bser/wbHq/8Gx6v/AsOr/wK/q/7+v6v/AsOr/wbHq/8Gx - 6v/Bsur/wbLq/8Gx6v/Bser/wLDq/7+v6f+9rOn/uafo/7Sh5v+tmeT/qZTj/6eS4v+lkOL/oYzg/5iD - 3/+FbNv/ZErX/z8z0f9wseD/j9bp/5nZ6f+e3On/pt/s/6rh7P+t4uz/tOLr/7rj7P+55O3/uuTt/7vk - 7f+/5ez/yeXs/8nl7P/E5ez/zuTr/9Hj6v/U4ej/2dDc/+B/sv/hdKz/4oi0/+KGs//ihLD/44m0/+OJ - s//ihLD/4oiy/+KJs//ihrH/4Xur/+F/rf/hdaf/4Xao/+Fvov/hc6X/4Gug/+Bmm//dU4n/3mud/9tt - nf/aXZD/3FyN/9xunv/bVob/3FKF/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3ursQ9Lo7v/D5u7/tOLt/6Ld7P+P0+r/Klu0/wAA - n/8AAJn/AACN/66c5f/Ftu3/ybvt/8q87P/KvOz/yrvs/8m67P/Iuez/x7js/8a37P/Gtuv/xbXr/8S0 - 6//Ds+r/wrLq/8Gx6v/BsOr/wbDq/8Cw6v/AsOr/wK/p/7+u6f++ren/va3p/72t6f++ren/v67p/76u - 6f++run/vq7p/72s6f+9rOn/vKzp/76t6f++run/vq7q/76u6v+/r+r/va3p/7uq6P+5puf/taPm/7Gd - 5f+smOT/qpbj/6mV4/+plOP/p5Pj/6aS4v+jj+H/n4vg/5eB3v+Badr/XkbV/0JC0f94uuH/jdTo/5TZ - 6f+e3er/ouDs/6nh7P+s4ez/t+Lr/7bi7P+65Oz/ueTt/77k7P/H5ev/xeXs/8Tl7P/N5ev/zuTr/9Lj - 6f/V4uf/2s3a/+CGs//hgLH/4oi0/+KIs//ji7X/43+u/+KEsP/ihrL/4oWx/+GCr//hdKX/4Xmq/+Fw - pP/hdaf/4XKl/+Fwpf/gX5j/4Wee/95Xjf/eZZn/21+T/9xpmf/dYpT/20l8/9xgjf/cXYz/AAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AADc6e2byuft/7zk7f+p4O3/ltnr/3rK6P8SK6H/AACb/wAAj/9SRKj/va3r/8e57P/Ju+3/yrzs/8m7 - 7P/Iuuz/x7js/8a36//Ftuv/xLTr/8Oz6//Csuv/wrHq/8Gx6v+/r+r/vq3p/76t6f++ren/va3p/72t - 6f+9rOj/vKzo/7uq6f+7qen/u6rp/7yr6P+8q+j/u6vo/7ur6P+6quj/uajo/7qp6P+7quj/vKvo/7ur - 6P+6quj/uqno/7in5/+0o+b/sZ7l/62Z5P+qlOP/ppDi/6WP4f+lkOH/ppHi/6aR4v+lkOL/pJDi/6OP - 4f+ijuH/n4rg/5V/3f96Ytr/XETU/0NO0P97xOT/i9bp/5XZ6f+e3uz/pODs/7Hg6v+t4ez/seLs/7Pj - 7P+24+z/u+Ts/73k7P/A5ez/xuXs/8jl6//K5ev/zuTq/87j6v/T4ef/28jX/+CDs//hh7P/4Xet/+KH - s//jhrL/44ey/+N/rf/if67/4oiz/+J7qv/hf63/4Xeo/+F2qP/hc6b/4Wqg/+Flnf/gZJr/4Gmf/99k - mv/eZ5z/3V2T/9xTh//eZZb/21WG/91tnP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4OnrCdno7OjC5e3/sOLt/6He7P+K1ur/bb3j/wIW - m/8AAJj/AACI/3Zkxf+6qur/xrns/8m87f/Ju+z/yLrs/8e46//Ftuv/xLXq/8Kz6v/Bser/wLDq/7+v - 6v+/r+n/v67p/76u6f+8rOn/u6ro/7uq6P+7quj/uqro/7qp6P+5qOf/uKfo/7im6P+5p+j/uajo/7mo - 6P+5p+j/uKfn/7al5/+1o+f/taPo/7Wj5/+0ouf/sqDm/7Cd5f+tmeP/qJTj/6SP4v+hjOH/oYvg/6GL - 4P+hi+D/oYvg/6KM4P+ijOD/oY3g/6GN4P+ijuH/oY7h/6GN4P+gjOD/nIjf/4553f91Xdn/W0TV/0Je - 0v9/y+X/i9bp/5fZ6f+e3ev/o+Ds/6fg7P+z4ev/ruLt/6ri7f+34+z/uuPs/7vk7f/B5ez/xeXs/8fk - 6//K5Ov/zeTr/9Lj6f/V4Of/3MHT/+B6rv/hg7L/4Xqt/+KIs//jirT/436t/+N/rv/jhLD/4n6t/+J/ - rf/hbKH/4Xip/+Fypv/haJ//4XCj/+Fnn//gXZX/4Guf/+Bck//gYJT/3UV5/91hk//cVIX/3F+R/wAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AADg6ewx1unt/8Dk7f+p4Oz/ndzr/4XT6v9UodD/AACX/wAAk/8AAIj/j3nY/7Oi5//Bs+r/xbjr/8W3 - 6//Ftuv/xLXr/8O06v/Csur/wLHq/76u6f+9rOn/vKvp/7yr6f+8q+n/u6vo/7qq6P+5qOj/uKfo/7im - 5/+4puf/t6bn/7el5/+2pOf/tqTn/7el5/+4puf/t6bn/7al5/+1o+b/tKHn/7Gf5v+wneb/rprl/6qW - 4/+mkuH/oovh/52F4P+YgN7/lX7d/5Z+3v+Ygd7/mYLe/5qE3/+bhd//nIXf/52G3/+dh9//nojg/56K - 4P+eiuD/n4vf/5+L4P+eit//mITe/4p12/92X9n/VD7S/0Vz0/+Azeb/jNbp/5ba6v+e3+z/pt7r/6zg - 6v+v4ev/rOLs/7Hj7P+44+z/uuTt/7zl7f/E5ez/weTs/8Pl7P/J5Ov/zuTq/9Hj6f/W3+b/3rPM/+F6 - r//hWqP/4Xuv/+KBr//jhrL/44Sx/+OCsP/jf67/43Wo/+Bhlv/heKj/4Xeo/+Fuov/ha6H/4F6X/+Bi - mP/gcaT/4WGX/948c//eUof/3nCg/95pmv/eMGb/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASEpLAN3p7GvQ5+3/vuPs/6ff6/+Z2+v/hNLp/zt7 - vP8AAJf/AACP/ycdkf+eiOL/sJ/m/7en5/+7quj/va3p/7+w6f/Asen/v7Dp/72u6f+8rej/u6vo/7mp - 6P+4p+j/uKfo/7mo6P+5qOf/uajn/7mo5/+4p+f/t6Xn/7al5v+2peb/taTm/7Wj5v+1o+b/taPm/7Si - 5v+yoOb/sJ3l/66Z5P+qleP/ppLi/6SP4f+hi+D/nYfe/5mC3v+Wft3/lHvd/5N52/+Tetz/lHzd/5V9 - 3f+Vfd3/lX3d/5R93v+Vfd3/ln/d/5iB3v+Zg97/mYTf/5qF3/+aht7/m4bf/5uH3/+bh9//lIDd/4Rw - 2f9rVNP/OibG/1SP0P+H0+f/j9jo/5Xb6v+c3Or/pd7r/6zh6/+o4uz/r+Ls/7Di7P+25O3/t+Xt/77l - 7P/A5ez/vuTt/8fk6//M5Ov/zuTq/9Ph6P/W3eT/3qfG/+Juq//hdq3/4YKx/+KFsv/jfq7/5ISy/+SF - sf/jZ57/4nKj/+J+rP/geKj/4Han/+Fypv/hcqX/4Xao/99soP/gY5r/30J4/+Bqnf/dW5H/3m6f/940 - Z/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAA3Ortpcvn7f+64+z/o97r/5na6v96zef/HUqm/wAAlv8AAI3/STqm/6aS5P+wnuX/sJ7k/7Cd - 5P+yoOX/s6Ll/7Oi5f+zoeb/s6Lm/7Sj5v+0o+b/taPm/7Wj5v+1o+X/taPm/7Wj5/+1pOb/taTl/7Oh - 5f+xnuX/rpvl/6yZ5P+qluP/qZbj/6iU4/+nk+L/ppHh/6KM4f+eh+D/moLf/5iA3v+Xf93/ln3c/5N6 - 2/+Qdtz/jnTb/4102/+OdNr/kHba/5B32/+QeNv/kHfb/5B32/+Pdtz/jnbc/4933P+ReNz/knvc/5R9 - 3f+Uft3/lH/d/5WA3f+Xgt7/l4Tf/5eF3/+Ugd3/iXXY/3Zi0f9OOcj/Ixy5/2Wv2P+F0+b/ktjo/5Pb - 6v+d3er/oOHs/6bi7f+n4ez/ruLs/7Hj7f+x5O7/vOXt/7/k7P/B5Oz/w+Ts/8nl6//L5ev/0OPp/9Li - 6P/X2uL/3qHD/+B5r//ghrP/4YSy/+N6r//khLD/43ur/+R/rP/jdKX/44Ow/+F/rP/hd6j/4Guh/+Fx - pf/gcaP/4HKk/+Bqnf/gVYv/4GOZ/95hk//eZJj/3VSG/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOfy+QDZ6e3Yw+bu/7Hi7f+k3ev/mtrq/3bE - 4/8BHpj/AACR/wAAiv9oVrn/p5Tk/66d5f+uneT/rJnj/6mW4/+mk+H/oo/g/6KO4P+jkOH/pZLh/6eT - 4f+oleL/qJTi/6eS4v+mkeL/ppHi/6aR4v+lj+H/oo3g/6CL3/+dh9//m4Pf/5iB3v+Wf93/lX7d/5N7 - 3P+Qd9z/jXPb/4xy2v+Kcdr/inDZ/4tx2P+Lcdj/inDZ/4hv2f+Ib9n/iW/Z/4pw2f+Kcdn/inHa/4px - 2f+Jcdn/iG/Z/4hv2f+Hb9r/iXDa/4px2v+Lc9r/jHTa/4x12v+Nd9v/j3nb/5B73P+Oetz/jHfb/4dz - 2P9/a9X/dmLR/2VRyP86KsH/KD63/3LB4P+G0+b/i9nq/5Xc6v+g3uv/ouHs/6Xh7P+n4ez/quLt/7Dk - 7f+25O3/uuPs/7/k7P/B5Oz/xuXs/8nl6//L5ev/zuTq/9Th6P/X1uD/3pe9/+B5rf/hh7P/43Ks/+SG - sv/kgK7/5Iax/+SCr//jg7D/4n2r/+J8q//heKj/4Xeo/+Bpnf/gb6L/4W+i/+Bdkv/fY5f/3lmO/91l - mP/eZ5n/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAA4OrtEtbp7vnD5O3/suHr/57c6v+P1+n/bbba/wAAkP8AAJH/AACF/3tpyf+mleP/q5rk/6ya - 4/+oleL/pJHh/6GN4P+eid//m4Xe/5mF3v+ZhN7/mYTd/5mD3P+YgN3/ln3d/5J83f+Qetz/kXnb/5B4 - 2v+Qdtr/j3Xb/4502v+Mctr/i3Ha/4tx2v+Kcdn/inDZ/4lv2f+Jbtj/iG3Z/4ht2f+Ibdj/h27Y/4Zt - 2P+FbNf/hGvX/4Rq2P+Eatj/hGrY/4Rr2P+Ea9f/g2vX/4Jq1/+BaNf/gWjX/4Fo1/+Cadj/hGrX/4Rq - 2P+Fa9j/hW3Z/4Rt2f+Ebdj/g23X/39o1/94YtT/cFzR/21b0f9tWc//aVfK/1E/w/8sHrn/OWy9/3zO - 5P+I1ef/j9np/5nc6v+a3uv/n9/r/6Lg7P+l4e3/quPt/7Hj7f+34+z/v+Tr/77k7P++5Oz/xOXs/8rl - 6//I5ev/0ePp/9Ph6P/X097/3oi1/+CCsv/iZ6n/43us/+R3qf/kfaz/44ez/+N+rf/jf6z/44Kv/+Fy - pP/ieKn/4Xao/+FlnP/gbqL/4GSa/99vov/eZ5n/32yf/9xWjP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKeqrQDe6u1F0+jt/8Hk7P+u4Oz/mtvq/4zW - 6f9eocv/AACI/wAAjP8AAH3/iXbT/6aV4v+pmOL/qJbh/6OR4P+fjOD/nYrf/5uH3v+Yg93/lH/c/5J8 - 2/+Qedr/j3jZ/4922f+Mc9r/i3La/4px2v+JcNn/iXDZ/4lw2f+Ib9n/h27Z/4du2P+Gbdj/hm3Y/4Zt - 1/+FbNf/hWvX/4Vq1/+Eadf/g2jX/4Jn1/+BZ9b/gGbW/4Bm1f9/ZdX/fmPW/35j1v9/ZNX/f2XV/35k - 1f98Y9T/e2LU/3ph1P97YdX/fGLV/3xj1f99Y9X/fWTV/31k1f99ZNX/emHU/3Ve0v9xWdH/bVXP/2dQ - zP9kTc3/Y03N/2NOyv9iT8n/WknG/zwuvf8kGbL/SY7J/3fN5P+J1uf/jNrq/5Tc6v+b3ev/nN/r/57g - 7P+m4ez/quLs/7fi6/+34+z/tuTt/7Xk7v/A5O3/x+Xs/8fl7P/L5Ov/zeTq/9Ph5//aydn/4IKz/+F0 - rf/iea//44Sy/+ODsP/jg7D/436t/+OBr//jgK7/43ao/+J4qf/ib6P/4nSm/+FzpP/hcKP/32me/95z - pP/eaJv/3VqN/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAANrp7YjQ6O3/vOPs/6be6/+U2uv/g9To/0uOuv8AAID/AACB/w0Hd/+Sftz/pZTi/6aW - 4f+kkuD/nozf/5mG3v+Wgt3/lH/c/5J92/+Qetr/jXfa/4t02v+Kctn/iXDZ/4hv2f+Ib9j/h27Y/4Zs - 2P+Fa9j/hGrY/4Np2P+Cadf/gGjW/4Bn1v9/Ztb/f2XW/35k1f9+ZNX/fmTV/35k1P98Y9X/fGPU/3xi - 0/97YtP/emHT/3le0/93XNT/d13U/3hf0/93XdP/dlzT/3Vb0v90WtH/dFrS/3Ra0v91W9P/dFrS/3JZ - 0v9wV9H/bVTP/2pRzv9mTM7/YkjM/2BGyv9eRMr/XEPJ/1tDyf9aRMj/WkTI/1lFyP9VRcX/RDi9/zEl - tP8bGqn/V6bQ/33Q5f+F1+n/i9nq/5ba6f+Y3Or/n93q/6Lf6/+i4e3/qeHt/7ni6/+x4+3/uOXt/73l - 7P/E5ev/yOXs/8jk6//P5Or/0OPq/9Xf5f/buM//4Hux/+F9sP/hea3/4oWy/+OFsv/jgq//44Kv/+OE - sP/kf63/432t/+N1p//idaf/4myi/+Fuof/gaZ7/33Sk/91ilf/fcqH/AAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA2ejtzsnm7v+z4+3/pN7r/5ba - 6v+A0uf/OXSp/wAAef8AAHj/GRJ7/5eD3/+klOH/o5Pg/5+O3/+Yht3/k4Dc/5B82/+Nd9r/i3TZ/4ly - 2f+IcNj/hm3Y/4Rq1/+CaNf/gmjW/4Jp1f+BZtb/gGbW/39l1v9/Zdb/fmTW/3xj1P97YtT/emDV/3pg - 1f96X9T/eV7T/3he0/94XtP/eF3T/3dc0/92XNL/dlzR/3Zb0f90WtD/c1jQ/3JY0f9yWdL/clnR/3JY - 0P9xV8//h3fT/56U1v94ZM//cVfR/25V0f9pUc//ZEzN/2FHyv9dQ8b/Vz7D/1U7w/9UOsT/VTvF/1Q5 - xv9SOsb/UTrF/1E8w/9TPMX/Uz3E/088v/9GN7r/Ny22/yEaqv8WNKf/Ybfc/3/Q5v+C1ej/jtfp/5ba - 6f+X2+r/oNzq/6He6/+l4Oz/rOHs/7Ti7P+z4+3/tOTt/7/l7P/F5ez/yOTr/83k6v/P4+j/0uLo/9bc - 5P/cscz/4IOz/+Fuq//ifa//43Or/+SDsv/keqr/436t/+SEsf/kfq3/5Hmq/+R5qf/jbqP/43io/+N2 - p//hdKb/322g/950pf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAOHp7BvV6O32x+bt/7Di7f+b3Ov/jtjp/3/P5/8pX5j/AAB3/wAAdP8bEnv/jnnc/56N - 3/+cjd//l4bc/5GA2/+Oetr/iXTZ/4Vw1/+CbdX/gmvV/4Fp1f+AZtX/fmXV/3xh1f97YdT/e2LT/3xg - 0/97YNT/el/U/3hf1P94XtP/d13R/3Zb0v91WtP/dVrT/3Ra0v9zWdH/cljS/3BX0v9wVtL/cFbQ/3BW - 0P9wVc//b1TP/21Tzv9sU83/bFPO/21Vzv9uVc3/bVPN/4R10f/m5en/6+vr/9zb5v9/b83/YEbI/1lA - x/9UO8X/UDfD/0w1wP9LM77/TTW//042wP9ONsH/TDXA/0s0wP9IMr//SDK//0kzwP9HMsD/RTG8/0Av - t/85LbP/LSmt/xgZnv8sXaf/a8Ph/3XS6P+F1un/h9jr/5Ha6v+g2+n/n93r/6Pf7P+i4O3/p+Hs/7Di - 7f+w4+3/vuTs/7/k7P/F5ev/yOXr/8zk6v/N4+n/0+Lp/9fX4f/dnsP/34Cx/+JwrP/kUqD/5H+w/+Vs - p//kdaj/5H+t/+V1qP/laqD/5Xip/+RwpP/kd6j/42Sc/+FroP/hcqT/4G6h/wAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3OnsSdLo7f/F5Oz/ruHs/5/c - 6v+O1+j/d8vk/xlGjP8AAHP/AABv/xgQev96Ztb/jHvZ/5GB2f+Pftr/infa/4Vx2P+CbNb/f2jV/3pi - 1P95YtP/emLT/3pg0/95X9L/eF7S/3Zc0f91XND/dVvQ/3RZ0f90WdH/cljR/3BX0P9xV87/cVbP/3BV - 0P9wVNH/b1TQ/25Uz/9tU8//alHP/2lPzv9qUM3/a1HM/2pRzf9rUcz/aVDL/2hPzP9oUMz/aE/L/2VL - y/9hRsr/w7/d/+vr7P/r6+v/6urq/9XU4/9XRcD/SDC8/0Qtvf9ELbv/RC25/0QtuP9EK7r/RzC8/0w8 - vf9aWMH/ZmzE/3WAxf+Hms7/iZrO/5+z1/+ku9r/qsDc/67H3/+0zN3/sMrd/7LO3/+32OT/ttro/7Lc - 6f+w3On/qtzq/6jc6v+r3Or/oN7s/5zf7f+o4Oz/quDs/7Hi7P/B4+v/uuTt/8Pl7P/F5ez/xeXs/8fk - 6//O4+n/1OHn/9nN2//elb7/4XKt/+NvrP/lda7/5nSs/+V+rv/lhbH/5Hyr/+V7q//ke6v/43ip/+R4 - qf/keKr/43Wm/+Jxov/hYJT/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAADc6OxtzOft/8Lj6/+v4Ov/m93q/4nV5/9zx+L/Aih+/wAAcP8AAGv/EQps/2xX - z/94ZtT/fGvU/3po1P93ZNP/eGPR/3hh0f94YNL/dl/S/3Rd0f9xWtD/clnQ/3JZ0P9yWdD/cVjP/3BW - zv9vVc3/bVPO/21Tzv9rUc7/alHO/2xSzP9rUc3/a1DO/2tQzv9pT83/aFDN/2lQzf9oT83/Z07M/2ZN - y/9mTcn/ZkzJ/2ZMyf9kScn/YkfI/2BHx/9dRMX/Vj3E/19Nxf/l5un/6+vr/+vr6//q6ur/6urq/66t - 0v87ILX/RTW2/1xcvf9+h8f/iJjN/5ir1P+xyOD/utHj/7/Y5v/E3ej/xuDp/8jh6v/I4er/y+Pq/8zj - 6v/M5Ov/yuTr/83k6//M5ev/zuXr/8vk6//O5ev/zOTr/83k6v/P5On/zePp/8ri6f/C4er/uuHr/67f - 6/+y3+v/teHr/7zj7P++4+z/vOPs/8Tk6//E5Oz/xuTr/8vk6v/Q4+n/1N7m/9q70v/firr/4nOv/+Rv - rf/laqr/5Xet/+Ryp//jirT/5IOw/+R6qv/jean/43eo/+Rjmf/jeKn/43Wm/+JmmP8AAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANjo7Z/I5u7/vuHq/6zf - 6v+b2+n/h9Tn/23D3/8AAGv/AABq/wAAZ/8CAV7/XErE/2tbzv9oV83/ZVPL/2BLy/9gSMv/ZEzK/2dQ - y/9qUs3/alHN/2dOzf9mTc3/Z07M/2hOzP9oTs3/alDN/2pQzf9oT8z/Zk3M/2VMzP9lS8z/ZUzL/2VM - zP9lTMz/ZEvK/2JJyf9gSMj/YEfI/19HyP9eRcj/W0LG/1lAxf9WPcT/VDrC/1A3v/9LNL7/STG9/0Yv - u/9ELLj/kIvH/+vs7P/r6+v/6+vr/+rq6v/q6ur/5OXo/7PF3P+0zuH/wNnm/8fg6f/I4Or/y+Lq/8vj - 6v/M5Or/zOTr/8vl6//M5ev/y+Xr/8zl6//N5uz/zebs/8zm7P/M5u3/zObs/8zm7P/J5u3/yuft/8zn - 7f/N5+z/zubs/87m6//O5ev/0OXq/87l6//Q5er/zuTq/8rj6v/M4+r/zOTq/8Pj7P/B4+v/v+Ps/8Hj - 7P/C5Oz/xOTr/8nk6//R4un/1dfi/9ysy//ggLP/5Eyi/+Vip//la6j/5YGx/+R+rf/kgK7/43+t/+J/ - rf/jean/5Wub/+R6qf/jcaP/43en/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAA1ufszsDk7f+64uv/qd7r/5Ha6v9+0+j/ZLzc/wAAZP8AAGf/AABj/wAA - V/9GNq7/YFHK/1tKyf9aRMb/WEDE/1Q8w/9ROsL/UjrA/1M7wP9VPMH/VjzD/1c9wv9XPsL/Vz/D/1lB - xP9bQ8X/XUTG/1xDxP9aQsP/WUDE/1c/xP9YPsT/Wj/F/1lBxv9YP8X/Vz/E/1U9xP9SO8L/UDnA/043 - v/9LNL7/RzG8/0Ywuf9DLbb/Pym1/zwmtP85I7P/Oiiy/1BLtP++v9f/6uvs/+vr6//q6+v/6urq/+jp - 6v/m6er/1uXq/8jj7P/J5ez/y+Xs/8rl7P/K5ev/y+Xr/8vm6//N5uz/xubt/8Tm7f/K5uz/yubs/8jm - 7f/F5u3/xubt/8jm7P/C5u3/yObt/8jm7f/F5u3/yubt/8bm7f/A5u3/yebs/8nm7f/F5ez/yuXr/87m - 6//N5ev/z+Xr/8/l6v/Q5Or/z+Tq/8zk6v/F4+v/w+Pr/7/j6//B5Ov/yOPq/9Hk6f/R4ej/2cfY/96e - w//hfLD/5HGu/+RxrP/kfq//5Xys/+V4qP/jfKv/4oGu/+N9rP/ke6r/5HKl/+V4qf/kbaH/AAAAAAAA - AAAAAAAAAAAAAAAAAADAwMAA7+/vF+vr66TX2985AAAAAAAAAAAAAAAAAAAAAODq7BPU5+3yvuLr/7Dh - 7P+i3ev/jdnq/33R6P9cs9b/AABc/wAAZP8AAF3/AABS/ysgjP9UQ8T/Tz7D/047wv9NOMD/Tja+/0ky - vf9EL7z/Qi66/0Mtuf9GLrj/Ry+5/0Uuu/9ELbz/RS26/0Ytuv9GLbv/RS26/0Msuf9DLLn/RC25/0Uu - uf9HLrn/Ri67/0Qsu/9DK7r/QSu5/0Apuf8/Kbn/PSi2/zwmtP87JLX/OSKz/zorsv9KRbT/bXTC/5el - 0P+xxN3/ydzn/9rm6//j6ez/5+rr/+bq6//k6er/4Ojq/9nn6//R5uz/x+bt/8fm7f/K5+3/wObt/8Tm - 7f/E5uz/w+Xt/8nm7P/D5ez/wuXt/8Xl7P/B5e3/wOXt/8Xl7P/A5ez/w+Xt/8Xl7P/E5ez/xuXs/8Hl - 7P/H5ez/w+bt/77l7f/I5ez/x+bt/8bl7P/H5ez/zObs/8jl7P/L5uz/zeXr/87l6v/O5Or/zeTq/8/k - 6v/O5Or/y+Tq/8Dk7P/C5Ov/yuTq/9Di6f/U1uL/3LfR/9+Ouv/igLL/5G+r/+N5rf/keKv/5X6s/+SA - rv/ifKv/436t/+OArv/jeKj/43yr/+Vypf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu7u6n6urr/9PY - 26wAAAAAAAAAAAAAAAAAAAAA3unsPtPn7f++4en/sN7p/5zb6/+H1+r/eM7m/0+o0f8AAFv/AABg/wAA - WP8AAE7/Dglf/0Mxtf9GM7r/RDC6/0QvuP9CLbj/QSu5/z8puP89KLb/Pii0/z4ntP87JrX/OiW2/zkj - tf86I7T/OSOz/zgjs/83IrP/NyKz/zgjs/85I7L/OSSx/zgksf83I7H/NyKw/zcgr/82IK//NCCw/zIe - r/8zH67/V1e2/3uEw/+Uoc7/ucvf/77U4//M4ur/zeTr/87l7P/O5u3/0Ofu/9Ho7v/U6O3/0+jt/9Pn - 7P/Q6O3/xObu/8Lm7f/D5u3/yebs/8Lm7f++5e7/v+Xt/77l7f+/5ez/x+Xr/8Pk6//C5Oz/wuTs/73k - 7P+95Oz/weXs/73k7P/C5ez/v+Ts/7/k7P/A5Oz/wOTs/8Ll7P/B5e3/u+Xt/8Xl7P/I5ez/yOXs/8Pm - 7f/F5u3/x+bs/8nm7P/I5ez/y+bs/8zm6//L5ev/zeXr/9Dk6v/R5On/z+Tq/8jk6//F5Oz/zOPq/9Lh - 6P/Xz97/3ajK/+GFtf/kbav/5HGs/+R/sP/kiLP/5Iax/+R/rf/jfq3/4n6s/+N8q//jgK3/43Kk/wAA - AAAAAAAAAAAAAAAAAAAAAAAA7+/vLO3t7frq6+v/1trd7srV3Rfa5ekb2eTpIdjk6Bra6Ox+yuXs/7nh - 6/+m3+z/mdrr/33W7P92zuj/TaDO/wAAWv8AAF7/AABU/wAATP8AAET/KxyV/zgmsf84JbL/NyWw/zck - sP82I7D/NiOw/zYir/81Ia7/NCCt/zQgq/8zIKz/MiCu/zMgrv8yH63/MR6t/zEdrf8xHa3/MR6t/zIe - rP8xHav/MB2r/zAcrP8uG6z/Lhyo/zguqv9xe73/k6PP/63C2//H2+f/zeLq/87k6//P5ez/zubs/87n - 7f/M5+3/xubt/8nn7v/L5+3/wefu/8Tn7v+/5u//xubu/8Pm7f/G5u3/v+Xt/8Hl7P/A5ez/uuTs/7/k - 7P/F5ez/vuXs/7nl7f/A5Oz/xOTr/8Hk6/+/5Ov/wOTr/8Lk6/+75Oz/vePs/8Hl6/+55Oz/vuTs/8Tl - 7P+95Oz/vOTs/8Hk7P/C5Ov/xuXr/8bl7P/B5e3/xebt/7/l7f/F5u3/xubt/8jl7P/I5uz/yeXs/8nl - 7P/K5ev/y+Xr/87l6//Q5Or/0uTp/9Lj6f/P4+r/0ePo/9Ld5f/Zwtb/3pe+/+Jyr//jfrP/5G+q/+R6 - rf/kfq3/5H2s/+R6qf/jfqz/43Cj/+N8q//kc6T/AAAAAAAAAAAAAAAAAAAAAAAAAADu7u6V7Ozt/+rr - 6//c3+L/ztzi+tDg5/7M3+f+yd7m/Mre5vzG3uf/wN7o/7De6/+c2+v/f9fs/3HO6f9NoM7/AABY/wAA - W/8AAFH/AABK/wAAQ/8GA1T/JBed/yobpf8rG6f/Kxum/yoapf8qGqX/Khql/ysapf8rGqT/Khqk/yoZ - pf8qGaf/Khmn/ykZpv8qGaX/Khmk/yoYo/8rGKX/KRWn/yscp/82L6j/YWm1/4ybyP+nudf/vdLh/8vh - 6v/P5Ov/zOXt/8/m7P/O5uz/zeft/83n7f/N5+3/yeft/8Tm7f/F5u3/x+bs/8Tm7f/B5u3/wOXt/8Xm - 7P+95e7/wOXt/77l7f+/5Oz/weTs/7vk7f+65O3/wuTs/77k6//A5Oz/uuTt/7Xk7f/B5Ov/uOPs/7/k - 6/+74+v/weTr/8Lk6//B5Ov/w+Xr/7rl7f+95ez/v+Ts/7nk7P/C5Ov/v+Ts/8Lk6//H5ev/weXs/8Tl - 7P/E5ez/xeXs/8fm7P++5e3/wuXt/8Tl7P/I5ez/yuXs/8fl7P/H5ez/y+Xr/87l6//R5ev/0uXq/9Pj - 6f/U4uj/0uHo/9XX4v/dsc7/4Hey/+J9sf/jfrH/5H2v/+WBsP/lh7L/5IKu/+OGsf/jgKz/5Hen/+Vx - o/8AAAAAAAAAAAAAAAAAAAAA5OrsLO3t7u3s7e3/6evs/+Pm6f/J1t//v9bh/77Y5P+/2eT/udfk/7fZ - 5v+x2Ob/sdnn/7Da6P+Q2ez/e9Lq/1Cdyv8AAF//AABX/wAAT/8AAEr/AABD/wAAQf8GA1n/GxCU/yAS - mv8hE5v/IhSZ/yETmv8iFJz/IxSf/yQVoP8kFZ//IxSg/yITof8jE6H/IAyd/yQTnf85OaL/VVuu/3KA - vf+brtD/qb3X/7zR4f/N4en/z+Tr/8/l7P/O5uz/z+ft/83n7P/J5u3/zebs/8zm7P/L5uz/yebs/8bm - 7P/H5uz/x+Xs/8Hl7f/F5uz/vuXt/8Dl7f+55O3/wuXs/7zl7f+95e3/wuXs/7rj7P/A5Oz/veTs/7vk - 7P+95Ov/uuPr/73j6//A5Ov/vOTs/8Hk6//C5Ov/vOPr/8Lk6/+64+z/v+Pr/8Dk6//B5Ov/vOTs/7Xk - 7f/B5Oz/weTr/8Lk6//B5ez/teTt/8Ll7P/A5ez/v+Xs/8Dl7P/F5ez/xOXs/8Dl7f++5e3/xeXs/77l - 7f/J5ev/xuXr/8fl7P/K5ev/zOXr/8jl7P/O5ev/0eXq/9Xj6f/T4uj/1N3l/9y/1v/dl7//4X6w/+J0 - rP/igrH/5Xau/+WBr//kfqz/5Iax/+R8qv/keqn/5YGu/wAAAAAAAAAAwMjLAOLq7SDi6u3o6uzt/+Pq - 7P/c5+z/1eTr/83g6f/E2eX/vNbj/7XU4/+t0eL/kcnj/2ehzv9Igb7/SHm3/1iax/9gsNb/RYGz/wAA - aP8AAFn/AABS/wAATf8AAEf/AABC/wAAN/8FAlT/EwqF/xcNjf8YDo7/GQ+Q/xsQkv8cEJL/Gw2V/xgA - lv8tKJz/YGmt/3+Ovf+arc7/rsTZ/77T4v/I3uj/zOLq/8/l7P/P5ez/z+bs/8/n7f/P5+3/zOft/8bo - 7//N6O7/yOft/8bm7f/H5u3/xubs/8fm7f/C5u3/weXt/77l7f/D5ez/veXt/8Pm7f+95e3/weXs/7zl - 7f+75e3/vOXt/7nk7f/D5Oz/uuTs/8Hk7P+35O3/vuTs/7zk7P/A4+v/uuLr/8Hj6v+/4+v/v+Tr/7fk - 7P+64+z/wOTr/7/k7P++5Oz/wuTr/8Dk7P+45Oz/vuTs/77k7P/A5Oz/vePr/7/k7P/A5Oz/u+Ts/8Pl - 7P+95e3/weXs/8Hl7P/C5ez/weXt/8Tl7P/F5ez/xOXs/8Xl6//E5ez/yOXr/8fl6//F5ez/xOXs/8nm - 7P/O5uz/0eXq/9Pj6f/V4ef/2NLf/92syv/gf7L/4nit/+KJtf/lea3/5n6v/+aDsP/leKn/5IKv/+R9 - q//lga7/AAAAAAAAAAAAAAAA4ertseDq7f/d6u3/2Ojt/9Xn7P/T5uz/0uXr/87j6v/I3uj/xtzm/7vW - 5P+Hp87/SFyt/yU4oP8AAI3/AACC/wAAef8AAG7/AABr/wAAXP8AAFT/AABQ/wAATP8AAEf/AAA+/wAA - Nf8AAEn/CwZ//yw0jf9XZaP/bnyw/4mZwP+YqMj/tsnb/7/U4f/N4en/zePr/87k6//P5ez/zebt/8/m - 7P/P5+z/zefs/83n7f/K5+3/xefu/8zo7f/I6O7/wufu/8Tn7v/H5+3/w+bt/8bm7f/D5e3/vuXu/73l - 7v/A5u3/vOXt/8Hl7f+95e3/uuTt/77l7P+95Oz/weTr/7/l7P+25e3/t+Tt/7rk7f+85ez/tuTt/7/l - 7P+45Oz/u+Ts/73j7P++4+r/v+Pq/77k6/+25Oz/u+Ts/7rj7P+74+v/u+Ts/7rk7P+45O3/vOTs/77k - 7P/A5Oz/tOTt/8Dk6/+74+z/weTr/7/k6/+95Oz/xOXr/7/l7f+95e3/t+Xt/8Hl7P/D5ez/w+Xs/8Ll - 7P/G5ez/weXs/7/l7P/E5ez/vOXt/8fl7P/G5ez/yuXs/9Dm6//R5uv/0+Xr/9Tj6f/V3+b/273V/9+R - vP/heK3/4oa0/+VopP/ncaf/53mp/+d5pv/lf6z/5YGt/+R8q/8AAAAAAAAAAOHq7UPf6u793Oru/9np - 7f/W6O3/1ujs/9Xn7P/T5uz/0ubs/9Hk6//P5Ov/zuLq/87h6f/J3uf/wdnl/7bO3v+uxNj/m7HN/5ux - yP+YrcT/k6a9/5Kmvf+Oo7r/lqq//4qft/+QpLb/nbLD/6nA0f+70+D/wtnl/8nf6P/N4ur/zuTq/9Dl - 6//Q5uz/0Obt/87n7v/O5+3/zuft/87n7f/K5+7/zuft/8vn7f/G5+7/xufu/8fn7v/D5+//wufu/73n - 7//F5+7/xebt/8Ll7P/F5ez/uuXt/77m7f+55e7/u+Xt/7nk7f+95e3/wOXt/7nk7f+95Oz/u+Ts/7bj - 7P/C5Ov/vuTs/7bk7f+z5O3/wOXs/7fk7f+25O3/vOXs/7nk7f+z4+3/veTs/8Dk6/+75Oz/ueTs/77k - 6/+75Oz/vuTs/8Pk6/+55Oz/vuTs/7jk7P+75Oz/vuTs/73k7P+24+3/veTs/7/k6//B5Ov/xeTr/8Xk - 6//B5ez/wOXs/73l7f+/5e3/vOXt/8Hl7P/H5Ov/vuTs/8bl7P/B5ez/xOXs/8bl7P/C5e3/yObs/8Tm - 7f/J5ez/y+bt/8/n7f/T5uz/1eXq/9Tj6P/Z1+L/3aHE/+FrrP/hgrD/5Het/+Z2rf/lgq7/54Ct/+Vy - o//lgq7/5Xqp/wAAAAAAAAAA3+rttNzq7f/b6u7/2enu/9bp7f/X6O3/1ejt/9Tn7P/T5+z/0ubs/9Hm - 7P/S5uz/0ebs/9Dm7P/O5Ov/zeTr/83k6//N5Oz/zuTr/9Dk6//P5Ov/zuTr/83k6//P5Ov/zuTr/87k - 6//O5ez/z+bs/83m7f/Q5+3/0Oft/8/n7f/Q5+3/zOft/8fn7v/O6O3/zOfu/8vn7v/J5+3/y+fu/8nn - 7v/K5+3/yeft/8jn7f/C5u3/x+ft/7nm7/+95u7/wObu/8Lm7f/D5u3/u+Xt/8Hl7f+65e3/ueXt/7fl - 7f+75e3/uuTt/73l7f+35O3/tOTt/7nk7f+/5ez/wOTr/8Dl7P+25O3/s+Tt/73l7P++5Oz/tuTt/8Dj - 6//B5Ov/tOTt/7nj7P+95Oz/veTr/7Xk7f+34+z/wuTs/73k7f+15O3/vOTs/7zk7P+45Oz/ueTs/8Dk - 6/+64+z/uOPs/8Dk7P++5ez/u+Ts/7/k6/+94+v/weXs/7Tl7v+95e3/wObt/7zm7f/B5u3/wOXs/7rl - 7P/A5Oz/vuXt/7vl7f/C5ez/xeXs/8Lm7f/G5uz/x+ft/8rn7f/O5+3/z+ju/9Po7f/V5uz/1OXp/9jf - 5v/cutL/4Xqz/+F1rf/ih7T/5YKx/+aGsv/ng67/5n6r/+WIsv/lfav/LDAwAODq7Rne6u302+ru/9nq - 7v/W6e7/1+nu/9Xp7f/U6e3/0+nu/9Po7f/S6O3/0ujt/9Lo7f/R5+z/0ufs/9Dn7P/P5+z/z+ft/9Dn - 7f/R5+z/0ebs/8/m7P/P5+z/z+fs/8/n7f/O5+3/z+ft/8/n7f/O5+3/zuju/8zo7v/M6O7/yOfu/83o - 7f/I5+7/w+jv/8vo7v/M5+3/y+ft/8nn7f/F5+7/yeju/8Ln7v/D5+7/yOft/8Hm7f/H5u3/weXu/73l - 7v/C5u3/u+Xt/77l7f+/5ez/veXs/7vl7P+75ez/vOTs/73k7P+55Oz/vOTs/7zk7f+15O3/uOTt/7zl - 7P+75Oz/uuXt/7Lk7f+95O3/uuTt/7Xk7f+24+z/vuTs/7jk7P+75Oz/uOTs/7Xk7f+25O3/s+Tt/7vk - 7P++5Oz/tuXt/7bl7v+45O3/v+Ts/7fk7f+45O3/vuPr/77j6/+65Oz/vuTs/7jl7f+65O3/vuTs/7fk - 7f/C5Oz/uOXt/7zl7f/B5u3/veXu/7fl7v/A5e3/uOTt/73k7P/B5e3/uuXu/8Hm7v/C5u3/webu/8Dm - 7v/K5+7/zOju/8Xn7v/O6O//yefu/9Ln7P/V5+z/1+Lp/97C1//fi7v/4X2v/+KCs//kgLL/5oCu/+eA - rP/mf6z/5omz/+Zzo/8AAAAA4evuVd3q7v/b6u7/1+ru/9Xp7v/V6e7/0+nu/9Pp7v/T6e7/zunv/9Pp - 7f/S6O3/zOju/8/o7v/O6O7/zujt/9Do7f/O5+3/0Ofs/9Hn7P/P5+z/zufs/9Dn7P/M5+3/zuft/83o - 7v/M6O7/zuju/8ro7v/N6O7/yuju/8vo7v/E6O//xujv/8fo7v/E5+7/yefu/8Pm7v/F5u7/yeft/8Dm - 7v/I6O7/v+fu/8Hm7v/F5uz/vuXt/7vl7f/D5u3/wOXt/7zl7f/A5e3/uOXt/8Dl7f+05O3/uuTt/7nk - 7f++5Oz/u+Ps/73k7P+95Oz/veTs/7jk7f+/5Oz/uuXt/7jk7f+45e7/ueXt/77l7f+45O3/tuTt/7fj - 7P+85Oz/tuTt/7nk7P+44+z/uuTs/7nk7P+55Oz/ueTt/77l7f+05e3/ueXu/7rk7f/B5Oz/v+Xt/7Pj - 7f+94+z/vOTs/7zk7f+55e3/vOXt/7nl7f/A5e3/veXt/8Hl7f+65O3/wubt/8Hm7v/C5u7/ueXu/8Dk - 7f/D5ez/yebs/8Xm7f/B5u7/wufu/8Ln7v++5u7/xufu/8Xn7v/E5+//y+nv/8ro7//P6O7/1Ojt/9Tn - 7P/V5er/2s3d/96ix//jcq7/43yx/+J+sP/khLH/5nyq/+aBrf/mdaX/5nal/wAAAADg6+6n3ert/9nq - 7v/V6u7/1enu/9Pp7v/S6e7/0+nv/9Lp7v/R6e7/0enu/8zo7v/N6e7/zeju/8ro7v/O6O7/zejt/8vo - 7v/O5+3/zufs/83n7f/N5+3/zOft/83o7v/L6O7/zeju/8vo7v/O6O7/xujv/8To7//G6O7/y+ft/8Lm - 7f/H6O7/x+fu/8Tn7v/C5+//wufu/8Tn7v/D5+3/wefu/7jm7/+95u7/xObt/8Lm7f+85e3/vebu/7zl - 7v++5e3/veXt/7Tl7v+45e3/vOTs/7nk7f+75O3/vuTs/7/j6/+94+v/uuTs/7Tk7P+45Oz/u+Pr/77k - 7P+15O3/uOXu/7bl7v+15O3/t+Tt/7Xk7P+34+z/v+Xs/7jk7P+05O3/t+Tt/7vk7P+95Oz/t+Ps/7vk - 7f+55e3/uuXt/7nl7f+05O7/vuXt/8Hl7f+55e3/uOXt/7zk7P+14+3/uuTs/7zl7f+35O3/u+Xt/7vm - 7v/C5u7/ueXt/8nn7f/H5+3/xOfu/8Dn7/+95u7/xefu/8nn7f/K6O7/xuju/8zp7//C5+//xOfu/8nn - 7v/N5+7/v+fu/8ro7//P6e//zejv/9Pp7v/T6O3/1Ofs/9Xj6//b0d//36XI/+N0r//jda7/5Iq2/+SN - t//mirT/5oix/+WBrf/kibL/4OvtCd/r7ujc6u7/2Oru/9Xq7v/W6e7/0+rv/9Lq7//S6u//0enu/83p - 7v/O6e7/y+ju/87o7v/O6O7/y+ju/8zo7v/L6O7/zOjt/8ro7v/L5+3/yefu/8Tn7v/L6O7/xOfv/8Xo - 7//J6O7/x+jv/8jo7v/J6O7/x+jv/8Pn7v/J5+3/yOft/8bn7f/G5+7/wObu/8Pn7//B5+7/wOfu/8Dm - 7v/B5u3/weXt/7/l7f/A5ez/u+Xt/7nl7v+45e7/vuXt/7vl7f+25e7/s+Xu/7rl7f+85O3/uOTs/8Dl - 7P+24+z/v+Tr/7/k6/+y4+3/uOPs/7jj7P+74+v/t+Ps/7Hk7f+15e3/suTu/7Xj7f+54+z/uePs/7nk - 7P+z5O3/tuTt/7Tk7f+55e3/ueTt/7jk7f+/5Oz/vuXs/7jl7f+05O7/uOXt/7/l7f/A5u7/t+Xt/7fl - 7v+45e3/ueXt/7fk7f/C5Oz/v+bt/7zl7f/C5u7/w+fv/77m7v/I6O//xOjv/8fn7v/H6O//vOfv/8jn - 7v/B5+//v+fv/8Lo7//E6O//vOfv/8jo7//G6O//yujv/8zo7f/M6O7/0unu/9Dq7//R6e//0Oju/9Ho - 7v/W5+z/1uPq/93F2P/fosb/44K0/+Vtrf/ka6v/5Iq1/+aBrv/mdqX/5IKv/+SMtP/h6+4r3uvu/9vq - 7v/Y6u//1+ru/9Lp7//S6u//zerw/9Dp7//O6e7/zeju/83o7v/K6O7/yuju/8no7v/N6O7/y+ju/83o - 7v/G5+7/yeju/8rn7v/L5+3/xOfu/8no7v/G6O7/x+ju/8bo7v/G5+7/xufu/8Po7//F5+7/w+fu/8Hn - 7v/E5u3/xObu/77m7v/F5+7/wObu/8Tn7v/A5u7/wubt/8Lm7f/C5ez/veTs/8Hl7f+65e3/u+bu/73m - 7v/A5u3/veXt/7rl7v+z5e7/v+Xs/7rk7f+05O7/teTt/7bk7f+35Oz/vuTs/7Xj7P+54+v/vOPq/7ri - 6/+44+z/teTt/7Pk7f+25O3/uuPs/7rj6/+54+z/sePt/7Xk7f+55O3/tOTt/7fk7f+65e3/uOXt/7zl - 7f+35e3/tuXt/77m7f+85e3/weXt/7vm7v+z5e7/v+bu/7nl7v/A5u7/wObu/8Lm7v+85u7/xefu/8bn - 7v/C5+//x+nv/8Xo7//C6PD/yOnv/8To8P/J6O//yunv/8bp8P/D6PD/xujw/8vp7//B6O//yOjv/8rp - 8P/N6fD/zOju/87p7v/Q6e7/z+nv/9Pq7//R6e//0uju/9Tn7f/V4Oj/3r3U/96Zwv/lg7T/5YO1/+Ry - rP/khbP/53ur/+eErv/kga3/5Iqz/9/r7lbd6+7/2uvu/9nq7//W6u//1Orv/9Lq7//L6fD/z+nv/87o - 7v/M6O7/zOjt/8vo7v/G6O//yejv/83n7f/E5+//yuju/8ro7v/K5+3/x+ft/8vn7f/K5+3/w+fu/8jn - 7v/D5+//xufu/8fn7f/C5+7/xOfu/8Pn7v/B5+7/wufu/8Tn7v/D5u3/wObu/8Pn7f/B5u7/vubu/73m - 7f/A5u7/vebu/8Pl7P/E5ez/wOXs/77m7f+35e7/v+bt/7bk7v+85e3/uOXt/7bl7f+55O3/u+Xt/7rl - 7f+25e3/suTt/7Xk7f+y5O3/t+Ps/7rj6/+44+v/u+Pr/7rj7P+05O3/uuTt/7nk7P+44+z/u+Lr/7rj - 6/+54+z/uOTt/7nk7f+/5ez/vuXt/8Hm7f+45e3/v+bt/7/l7f/A5e3/webu/7jl7v++5e3/uObu/7Tl - 7v+/5u7/vubv/7vm7//E5+7/webv/8Ln7//D6O//z+nv/8Lo7//H6fD/yunw/8np8P/K6fD/xunw/73n - 7//E6PD/xOjw/8fp8P/L6vD/x+nx/8Xp8P/N6vD/yenw/8rp7//Q6e//0Oju/9Lo7v/T6e//z+nv/9Do - 7v/R6O7/1OXr/9rX4v/dwNX/34S6/+N5r//le7H/436z/+WPuv/ng7H/5oGs/+WBrf/kjLT/4Ovucdzr - 7//b6u7/2Orv/9Xq7//T6u//0env/8np8P/Q6e//zuju/8vo7v/O6O3/y+ju/8vo7v/H6O//zeju/8Xo - 7//H6O//yuju/8jn7f/G5+3/yuft/8fn7v/G5+7/x+ju/8Tn7//J5+3/xeft/8Ln7v/D5+7/v+fv/8Hn - 7v/G5+7/wObu/8Xm7f+75u7/xObt/8Hm7f++5u7/vebu/7rm7v/B5u3/wObt/7zl7f/D5u3/uuXu/7zm - 7v+55e7/vubu/7nl7f+95e3/u+Tt/7zk7f+x5O7/t+Xu/7bk7f+85Oz/tuTt/7Xk7f+04+z/tuPs/7jj - 7P+35Oz/t+Tt/7Xk7f+z5e3/tOTt/8Hk7P+34+v/vePr/7zk6/+95Oz/uuTt/73l7f++5e3/teXt/7/l - 7f/B5u3/t+Xu/8Lm7f/C5+7/uubv/8Tm7f/B5u7/t+bu/8Pn7/+95u//wOfu/8fo7//L6O7/yejv/8jp - 8P/D6O//z+nv/8fp7//T6/D/yOnv/83p8P/D6PD/zOnv/83q8P/Q6/H/yenw/8np8P/D6fD/zurw/83q - 8P/N6vD/z+nv/8/p7//S6O3/0eju/8/p7//S6e7/0unu/8/o7v/T4ej/283c/9vE1f/ib7L/5G6v/+Rt - qv/ld6//5YCz/+eCsP/mcaL/5Y62/+WTuf/e6++D3Ovv/9vq7v/Y6u7/1erv/9Tq7//R6u//0unv/9Dp - 7v/M6O//y+ju/8zo7v/N6O3/y+ju/8Xo7//L6O7/xOjv/8jo7//K6O7/x+fu/8Ho7//I5+7/xOfu/8Xo - 7//C6O//xOjv/8Tn7v/I5+3/vefv/8Pn7v/E5+7/webu/7/n7v+/5u7/w+bt/8Dm7f/A5u3/w+bt/7rm - 7v+65u7/vubu/7rm7v+75u7/vubt/73l7f+45e7/v+bt/73m7f++5u3/uOXt/7fl7f+25O3/v+Ts/7fk - 7f+05e7/uuXt/7jk7f+35O3/sOTt/7zl7f+45O3/u+Ts/7Xk7f+35e3/teXu/7nl7f+y5O3/u+Xt/7jk - 7P+/5ev/w+Xs/7Hj7f/C5u7/v+bu/7zm7v+55u7/xebt/8Tn7v+65u//xuju/7vm7v+65u//wefv/8Dn - 7//B6O//zOrw/8To7//Q6u//yejv/8vo7//S6vD/z+rw/8zp8P/Q6u//y+nv/8zq8P/K6vD/0Ovx/8zq - 8P/Q6vD/0Ovx/8np8P/N6vD/zerw/8rp8P/N6/D/x+rx/8jq8f/Q6u//zuju/9Ho7f/P6O//z+ju/8/o - 7v/O6O7/z+bt/9Xc5P/bzNr/3bDO/+Nmsv/kaqn/5W6w/+Z4r//miLT/6Imz/+iKtP/njrf/5oWx/9/r - 7ojb6+//2uru/9jq7v/W6u//0unv/87q8P/Q6e//zunv/87o7v/I6O//yuju/87o7f/I6O7/v+jw/8jp - 7//I6e//yOjv/8ro7v/H6O7/w+fv/8nn7f/G5+7/xOjv/8Lo7//C5+//wejv/8Xn7v/B5+7/xuft/77m - 7v/E5+7/webu/8Tm7f++5e3/vebu/8Xm7f/B5u3/uObu/77m7v+65u7/uubu/7zm7v+65e3/v+Xt/7nk - 7f+15e7/seXu/7Hl7/+z5e7/uOTt/7rk7P+65Oz/teXt/7Xl7f+y5O3/tuTt/7Tk7f+25e3/u+bt/7jk - 7f+35e3/teXu/7Pl7v+55e7/s+Xu/7Xl7v+25e3/t+Xu/7bl7f+95e3/wObt/7/m7v+35u7/uObv/7rm - 7/++5e7/xOfv/8np7/+55u7/zOnv/8Ho8P/B6O//yujv/8rp7//C6PD/vejv/8Ho8P/T6/D/0evw/8jq - 8f/J6fD/xenw/8zp7//R6vD/0urw/8vq8f/J6vH/xunw/8/q8P/J6vH/yOrx/87p8P/P6vD/zOrx/8jq - 8P/N6fD/zenw/8vp7//M5+3/yufu/8zn7v/O5+3/zebs/9Dj6f/R3uf/2drh/9nK2f/gi77/5Fuv/+Vf - qv/kdK//522p/+h2qv/ohbH/6Iix/+eGsf/ogKz/3uvue9vr7//a6+//2Oru/9Xq7//S6u//z+rv/8/q - 7//Q6e7/z+nu/83o7//K6e//yejv/8fp7//H6fD/x+jv/8jo7//H6O//yeju/8ro7v/I5+7/xefu/8Dn - 7//C5+//xeju/8Hn7v/F5+7/wufv/77n7//C5+7/xOfu/7vm7//E5+7/xuXs/8Hl7f/A5u7/u+bu/7rm - 7v+/5+7/vebu/7zm7v+85e7/vOXt/7Xl7v/C5Oz/v+Ts/7nk7f+05O7/uuXt/7vk7f+25O3/uuTt/7nk - 7P+z5O3/s+Tt/7Pk7v+35O3/tOTt/7bk7f+25e7/seTu/7rl7v+z5e7/tOXu/7fl7v+35e7/seXu/7Xl - 7v+y5O3/veXu/7rl7f/A5+7/v+bu/8Po7/+65u//wOfu/83o7f/G6O//w+jv/8Do7//B5+//x+nw/7/n - 7//K6e//yOjv/8fp8P/J6PD/zenv/8Xp8P/K6vD/yOnw/8Xo8P/P6vD/zurw/8rq8f/H6fD/zOvx/8Xp - 8P/O6vD/y+nw/83p8P/J6fD/zenv/83p8P/M6O//zOjv/8bo8P/B5+//yebt/8vl7f/J5e3/y+Pr/8rf - 6f/N3ub/0tvk/9XT3v/Zz9v/36rN/+Rgrv/kRKv/5UKj/+WCs//mea//53mq/+eOtv/pfan/6H+r/+mA - rP/d6+5p3Ovv/9rr7//Z6+//1+vv/9Pq7//R6e//z+rv/8zp7//Q6e7/zuju/87p7//L6O//yOnv/8np - 7//N6O7/yuju/8fo7v/E6O7/xOjv/8fn7v/G5+7/wefv/8Pn7//A5+//vOfv/8Pn7//F5+7/wOfu/8bm - 7f+75u7/wOfv/8Hn7//G5uz/w+Xs/8Dm7v+75u7/u+bu/7vm7v+65u7/tubu/7rl7v+75e3/uuXt/7jk - 7f+85e3/vOXt/7jk7f+35O3/ueTt/7rk7P+35O3/tOTt/7Hk7v+55O3/vOTt/7vk7f+65e3/ueTt/7Pk - 7f+y5O7/uOXu/7bl7v+45u//uOXu/7zm7v+25e7/wObu/8Tm7f/C5e3/wObt/7jl7v/E6O7/uubv/8Dn - 7v/F6O//xeju/8fp7/+95u7/seXv/8Po7//C6fD/yOnw/8jp7//M6e//wejw/8rp8P/G6fD/yenw/8bp - 8P/K6vD/zOnv/9Hp8P/H6fD/yurw/9Pq8P/J6fD/zuju/83o7//N6e7/yejv/8zo7//K6O//y+bt/83n - 7f/F5+//xuXt/8fl7f/K5ez/yuPq/83d5v/R1eH/ztjj/9LY4P/Xzdv/2bjS/9+Iwv/kLKb/5C+o/+RL - rf/lX6z/5HGt/+aCtP/mhLP/54+2/+l9qf/pkLj/6YWv/97r70bc6+//2+vv/9fr8P/V6/D/1evv/9Lq - 7//N6e//zenv/8/p7v/P6O7/yeju/8vp7//K6e//y+nv/8/o7v/L6e7/zeju/8Xo7v/K6O7/yOfu/8bn - 7v/F5+7/xefu/8bn7v+85+//vufv/8bn7v/A5u7/x+ft/7/m7v++5+//wOfu/7/m7f/D5u3/w+bu/8Hm - 7v+35u//u+bu/7zm7v/B5u7/uOXt/7zl7P+35e3/ueXt/7Ll7v+65e3/r+Tt/7Pk7v+15O3/uOTs/7Hj - 7f+85O3/ueXt/7Pk7v+75e3/s+Xu/7jl7v+55e7/teTu/7vl7f+55e7/v+bu/7nm7v+45e7/xefu/7vm - 7v++5u7/uuXu/8jn7v/A5u7/yOju/8bp7//C5+7/z+ju/8Po7//C6O//v+bu/8fn7v/M5+7/y+ju/8Po - 7//D6PD/zenv/8Hn7//C5+7/yejv/8fo7//O6e//yujv/8To8P/I5+//zeft/8To7//E6O//zefu/8fn - 7v/Q5ez/zuft/87n7v/N5+7/xufu/8rl7f/M5Oz/yubt/8fk7P/J4+v/xuLq/8jc6P/J2uT/ztPg/9TI - 2f/Tz9v/1sjW/9yZx//fSqz/4k+w/+Q2of/kMKj/5Ge0/+RwsP/lhbf/5nyz/+iGs//nibH/6Iqz/+iP - t//pi7P/3+zvHNvr7/7b7PD/1+zx/9fr8P/W6/D/0erv/8/q7//P6e//0Orv/8/p7//N6e//yenv/83p - 7//L6e//zOrw/8np8P/O6e//x+jv/8jo7v/J5+3/xOfu/8fn7v/J5+7/y+bs/8Hn7v/D5+7/w+fv/8Ln - 7//I5+7/wOfu/8Po7v/B5+7/w+bt/77m7v+45u//vebu/7rm7v+95u7/vebu/73l7f/A5e3/vuXt/7rl - 7f+25e7/tuXu/7nk7f+45O3/t+Tt/7fk7f+w5O3/sOPt/7Tk7f+05O3/tOTu/6/k7v++5u7/uOXu/7vm - 7/++5u7/uuXt/73l7f+45e3/uebv/8Ho7v+/5+//xunv/8Po7//E5+7/xuju/8Tn7v/E6O//wufv/8no - 7//S6u//yejv/8Dn7//L6O7/x+fu/8ro7v/D5+7/y+jv/8Dn7v/G5u3/zujt/8nm7f/C5+7/y+fu/8Tm - 7v/I5u3/xebt/73k7f/H5ev/x+Xs/7zl7v/I5e3/xOTs/8bj6//I5Oz/xOXt/8Xk7P/G5Oz/xOPr/8fi - 6//G4er/xuDp/8fa5P/L1eL/zNDd/8/J2f/Wv9T/177R/9Ctzv/daLX/4CWg/+NIpP/jR6r/5kuh/+U4 - ov/lb7X/5GKy/+aKt//nbqz/6H+w/+eIsv/pg67/6HOj/+qPt//d6/AG3ezv4dvs8P/Z7PD/1+vw/9Xr - 8P/T6u//0erv/9Dp7//P6vD/0Orw/9Dq7//L6e//y+nv/8bp7//H6fD/y+rw/8zq8P/H6e//yeju/8zo - 7v/G6O7/xujv/8To7//F5u3/v+fu/8Xn7v+/5+//xefv/8Dn7//M6O7/0Oju/8Tn7f/C5u3/wOfu/7/m - 7v++5u7/vebu/7zm7v+65u7/webu/7/m7f+75e7/v+bu/7bl7v+25e3/tuTt/73k7P+55Oz/tePt/7rk - 7P+64+z/uOTs/7Tj7f+55O3/t+Tu/7zm7v+z5u//u+bu/7vm7//A5+//vObu/73l7f/N6e//wunw/7rn - 7//B5+//x+jv/8no7v/J6O7/z+nv/8vp7//R6u//xejv/8jo7v/C5+//x+fv/8jn7v+65u//xubt/8Tm - 7f/L5u3/wOXt/8bl7f/B5O3/weTs/8Pj6/+94+z/w+Lq/7/h6f+/4Or/vd/p/8Lf6f+84Or/v9/p/8Lg - 6P/B3+n/xd/o/8Lh6v/C4er/xeDp/8Hg6f/C3+j/xdzl/8nV4v/MzNv/0MHX/9S80//SutH/zpXH/9WH - uf/ecrL/3kil/+E+nv/hJ6D/4leo/+Rbrf/mQKT/5zSl/+Zosv/kcLX/52un/+diqv/mY6T/6JO5/+mC - rv/qhrD/6omz/wAAAADd7PCo2uzw/9ns8f/X7PD/1evw/9Xr8P/V6+//0+rv/9Lq8P/P6vD/z+rw/9Dq - 7//Q6u//yunv/83p7//S6vD/0Orv/8vp7//H6O//yOnv/8jp7//D6O//xejw/83p7v/A6O//vejv/73o - 8P/F6O//vufv/8Hm7f+65e3/w+bt/8bn7v/H5+7/xebu/8Lm7v/D5+7/t+Xu/73m7v+65u7/uObu/7zm - 7v+95u7/vOXu/73l7f+95Oz/ruPt/7bk7f+z4+3/t+Tt/73k7P+25O3/u+Tt/7fk7v+95u7/u+bu/7bm - 7/+65u//vufu/7vn8P/O6e//yefu/8Hn7/+25u//wujw/8np8P/K6fD/yunv/8vq7//D6e//x+nw/8jo - 7//K6O//x+fv/8Hn7//L5+7/wubt/8fn7v/F5u3/weTt/8Ll7P/A5Oz/vuLr/7ri6//D4On/wN7n/7ve - 6P+73ef/u9zn/7fc5/+32+f/udrl/7Ha5v+32eT/udjj/7rY5P+62eX/vNrl/7zb5P/B2uP/wdTf/8fN - 3P+/0N//z8LX/8nE1//Oqcn/0pfA/9Vxtv/bT6H/33Ws/+J3sv/hQZn/4TGi/+NKp//jXqv/5GOm/+ZS - rv/nTaf/6DOf/+Zfsf/oW6L/53ax/+d9rf/ojbX/6n+r/+p4pv/rfa3/AAAAANzs717b7PD/2ezx/9fr - 8f/X6/D/z+vx/9Xr8P/U6/D/0uvw/9Dr8P/Q6vD/0Orv/9Dp7//T6u//z+nu/8To7v/H6O//yOjv/8fn - 7//D6e//xunv/8Tp8P/F6fD/xenw/8To7//B6O//x+jv/8Ho7/+35e7/kd/q/4bc6P+v4uv/yebt/8jm - 7f/F5u3/vebu/77n7v+75u7/vuXt/7vl7v+25e7/vObu/7zn7v++5u7/v+bt/8Tm7f+15O3/wOXs/7jl - 7f+95u7/vObu/7fm7v+75u7/ueXu/8Xo7/+65u//uebv/8Hn7v/B5+//wOfv/7zn7//J6e//yOjv/8rp - 7//O6vD/wefw/8vq8P/F6O//v+jv/7/n7//K6O7/x+jv/8/o7v/N6O7/wObu/8Tl7f/J5uz/webt/8Pl - 7P+94uz/teHr/77g6P+74On/td7q/7bd5/+42+b/r9rm/7PY4/+41uH/sdPi/7rP3v+0ytv/ssPY/7S8 - 1f+7vtX/uL7V/7i61P+7vdP/usXW/7280f/OocL/zp3D/8yexv/TjMH/0Ya9/9h1rv/bUJn/31id/+NM - m//hR5f/4V2m/+BVo//iVKH/5Eig/+RPqP/kXav/5kOm/+dcof/naa3/53+u/+d5qf/nirT/54av/+eR - t//qhK3/6mea/+uTuf9CR0cA2+zxEdzs8Ova7PD/2Ovw/9bs8f/S7PH/0ezx/9Lr8f/T6/D/0+vw/9Lq - 8P/R6vD/0uvw/9br8P+75u3/h97p/63i6//J6e//z+nv/8rp8P/M6vD/xenw/8Lp8f/E6fH/yOrx/8fp - 8P/E6O//v+fv/63j7f9By+D/Ksrf/0XM4P+P3un/uuXt/9Ho7f/H5u3/wOfu/8nn7v/I5+7/w+fu/8Hm - 7v++5+7/vOfv/8Po7//F6O//xefu/7/l7f/F5u3/v+fu/8Dn7v+85u7/wufv/7vn7v+75u//vefv/7rm - 7//J6O//zurv/83q8P/W6+//yOrw/8jp8P/L6e//yenw/8nq8P/L6fD/vejw/8fp7//I5+7/yefu/8ro - 7//G5+7/x+fu/77m7v/G5u3/y+Xr/8Lj6/+34+z/wOHp/7jd6P+83Ob/s93o/7Tc5v+x2eb/s9Lh/7jI - 2v+zxtn/wLjR/8Cnzv+/mcn/zY69/9WTuv/Ng7D/0oey/9eNtv/ShrH/03up/9CBsP/Ph7X/zGqj/8tw - pv/Obqn/1FGa/9k8jf/dX5f/202S/99poP/jSZX/5SB8/+Q1jf/iPpH/4kOg/+VAmv/oM5L/5mCm/+Vg - rP/mXqv/51Cl/+ZjrP/mi7T/5YS0/+eLsf/oiLD/6Iy1/+l5pP/ph7H/6oew/wAAAAAAAAAA2+3wh9rs - 8P/Z7PD/1uzx/9bs8f/T7PH/0+vx/9Ps8P/P7PL/0+vw/9Pr8P/U6/H/v+jw/2/c5/8tz+H/hNjl/7rm - 7v/P6/D/zurw/73p8P/G6fH/yOnw/8Tp8P/J6vH/wunw/8zp7//K6e//tuTt/0jL3/8Zv9j/GL3W/ybB - 2P9k1eT/nODr/7nk7f+95u7/w+bu/7rm7//C5+//wObu/73n7//B6O//uubv/7/o7//E6O//xufu/8Pm - 7f+35e7/t+Xu/8jo7v/H6fD/vujw/87q8P/A6O//xefv/87p7//M6/D/wenw/87r8P+96PD/yunw/8rq - 8P/K6vD/xunv/8Xo7//C5/D/zOnv/8bn7v/J5+3/xefu/8Pn7v+85e7/vOXt/8Ll7P+84uv/wODq/7bd - 6P+43Ob/uNrl/7fY4/+20+D/scfc/7utz/+8kcD/yoS2/9OMt//Ve63/3YCv/9x2p//cXpf/3XCi/9t0 - pf/be6r/3ISv/9x0pP/chbH/3Hmo/9xpn//aZZz/2GGW/9NQjf/YM4P/2lCR/9xUj//caqD/3mif/+Nh - nv/mM4X/5UGR/+Jop//jc6z/5j+Z/+dsov/nXaT/51Cg/+d7q//mX6T/53Op/+WMtP/ljbP/54Ss/+eE - rv/oha//6X+q/+mIsf/qgq7/AAAAACgqKwDa7fEY2u3x8dns8P/Y7PH/1+3y/9bs8f/V7PH/0ezy/9Ps - 8f/S6/D/1evw/8zq7/+I4Or/ONDh/zLN3/9y1OP/uOXu/8zq8P/N6vD/yOnw/8Xp8P/I6vD/x+rw/8Xp - 8P/G6fD/zenv/8jp8P/J6O7/c9Pj/zLG2/8kwdn/FbbT/y7H2/87zuD/idnm/7nj7P/S5+3/uObv/7zn - 7/+75u//vebu/7bm7/+/6O//vOfv/7rn7//G6O//zejt/8Xm7v/L6O//xufv/8Xp7//B6PD/y+rx/8vq - 8P/T6vD/zunv/8fq8P/A6PD/yurx/7rn7//P6fD/x+rw/8Tp8P/B6O//zunv/8vo7/+95u//yufu/8Xm - 7v+95+//u+Xt/8Hj7P+64+z/uuHr/7rf6f+y3ef/t9rl/7LY5P+1zd7/sbjU/8WWvf/Leqn/2IGw/9hy - o//ZfKr/23Ok/95kmP/gbKD/4WSc/+Frnv/hZZj/4HOk/958qv/ee6r/332r/995qf/eeqn/3nSl/+B3 - qP/dXpX/2mCX/9dTj//YU4//3W+k/91Tkv/gb6H/41SW/+ZHjP/lUJH/4m6o/+R6qf/mdKf/5nyo/+dy - p//pYJb/6HKi/+eDrv/nha3/5pC1/+SHrv/lhKz/5oaw/+iLs//og67/6Iuz/+iGsP8AAAAAAAAAAAAA - AADb7fGN2+3w/9rt8f/W7fL/1e3y/9fs8f/U7fL/0ezy/9Ts8f/W6/H/mOHr/znQ4f8wzN7/Nsrd/2HQ - 4f/I5+7/0+vw/9Dr8f/N6vD/yenv/8fp8P/I6vH/x+nw/8Tp8P/I6fD/yurw/8zp7/+04ev/U8nd/y/G - 2/8mwdj/Ib7W/x691v84yNz/jdfl/8nm7f+55u//wOfv/7nm7v+85u7/tObv/8Dn7/+45u//vufv/7/m - 7//E5u7/yejv/8Xo7//X7PD/wunw/87r8P/L6vH/xOrw/8rp7//T6u//0uvw/8jq8P/J6vH/zenw/9Dq - 8P/B6PD/w+jv/8jo7v/O5+3/x+ju/8Dn7//H5u3/ueTt/77i6/++4ev/uuHr/7vh6v+23uj/sNrl/7rV - 3/+8x9j/v6TI/82Quv/TdKX/2m2e/9xZjf/fdaX/3l+V/957q//ffKv/4nOl/+Nkmf/jYpb/4YKv/+Jr - n//hdKX/4Hyr/9+Arf/ffav/34iy/96Brv/egq7/32ad/992p//fZ53/21+X/9hIh//cWJT/4DZ//+F1 - pv/jXpn/5VaX/+VVlv/kfK3/6FyP/+Z0ov/kha//5Yav/+d+qf/nfqn/5YWu/+d2ov/mf6r/5YGs/+aI - r//lgar/53+q/+eGsP/niLH/5421/wAAAAAAAAAAdYCHANzs8BHb7fHl2u3x/9nu8v/X7fL/1+3y/9Lt - 8v/S7fL/1Ozx/9Pr8f913Of/M83f/z7N3/8+xNv/ndzn/8jn7//U6vD/yuvx/9Lr8P/R6e//xujv/8rp - 8P/L6fD/xOnv/8zp7//G6fD/zurw/83o7/+14Or/iNTj/27L3v9kzd7/T8nc/1DH2/9Vzd//tuHr/73m - 7v+/5+//yuju/77l7f+/5+//xOnw/8Po7//G6O//yunw/8/p7//J6O//x+nw/8bp8P/F6PD/vujw/8vq - 8P/F6vD/wujv/9jr7//C6PD/yOrw/8Ho8P/R6vD/y+nv/8fo7//J5+7/yOfu/8fo7v/B5+//veXu/8jk - 6//H4un/x+Hp/8Xh6f+33un/tdjl/7bT3/+6uc//zJq6/9J/rf/YVo7/2mac/911o//ec6L/4Gud/+Ji - mv/iXJP/4nuq/+F4qP/idab/42Wa/+JvoP/hcKT/4Xmp/+Fuof/geqr/4IWw/+CCr//eeaj/34ax/957 - qf/fe6n/4Huq/+B4qf/gZp3/3GKZ/9tfmP/gWJP/4leO/+JvoP/kc6b/5W+i/+R/rv/oVZH/5Xej/+WD - rf/kh7D/6HSi/+d6p//mga3/53qm/+d9qf/ngaz/5n6p/+WNtP/mjbP/5oOt/+WIsP/nkrj/AAAAAAAA - AAAAAAAAAAAAANnt8Vfa7fL/2u7y/9fu8//X7fL/1u3y/9Xt8v/W7fL/x+rw/3Hc6P9Rz+D/eNXj/6Lc - 5/++5Oz/1Orw/9br7//B6fD/y+rw/8zq8P/L6e//xOnw/8rq8P/L6vD/zOrw/8fp8P/O6vD/yuju/9Ho - 7v/J5uz/t+Ps/8Lk6/+44ur/tOHq/5jZ5f+74+v/w+fu/83p7//F5+7/zOjv/8jo7//G6fD/xunw/7zo - 8P/I6vD/zevw/8jp8P/I6fD/v+jv/8To7//L6fD/xejw/8Hn7/+65u//yenv/8bo7//A6O//vefv/87p - 7/+85+//zejv/8/o7v/G5u7/w+bt/7zk7f+84uv/v+Hp/8Dg6f+13un/t9zm/7bV4f+7ttP/vJS//8xo - nP/YaZz/3V2R/+BWjf/gWo//33Kj/992pv/jb6L/42+i/+Rdkf/jY5r/4mGY/+NnnP/ja5//4n+s/+J0 - pP/ifKv/4nGi/+F3p//hfqz/4H+s/+CCrv/ghrH/4IKv/99/rf/ghbD/4HWm/+F3qP/hbKH/3mmd/91f - l//hXpX/42GX/+Vwov/lapz/5X6r/+Zyov/mcqD/5Hyn/+WGsP/nfqn/53Cg/+d3pP/na5z/53uo/+Zt - m//mgq3/5YSu/+aKsP/ngaz/55S5/+eHrv8AAAAAAAAAAAAAAAAAAAAA2/DyAtnt8qvZ7fL/2e3y/9nt - 8v/W7fL/1u3y/9Xt8v/R6/H/oeHq/6/h6v/G5uz/0enu/9fr8P/W6/H/0+vw/87q8P/P6/H/0ezx/9Lr - 8P/K6e//zOrw/8zr8f/K6vH/wujw/8bq8P/O6u//zunv/9Pp7v/Q6vD/1evw/8vq8P/M6fD/1Ovv/83p - 7//O6e//yunv/8vq8P/I6vD/1uzx/8Po8P/B6fD/yurx/8Tp8P+65/D/uufv/9Pq7//F6PD/yunv/8Dm - 7v/J6fD/yerw/8rp8P/J6e//zunv/8vo7//L6e//zenv/8To7//L6O7/x+bu/8fm7f/D5Oz/w+Lq/8Th - 6f+/3+j/wt7m/7TT4v+0vdb/xpS+/9Bqn//XdKX/23Oj/955qP/hZ5r/40uC/+NlmP/iR4L/4nKk/+Rp - nf/kYZf/5Wia/+Vjmv/lZ5n/5XKi/+Nrnv/jZJv/4n2s/+JonP/hcaT/4oGv/+Nnnf/ic6X/4YOw/+F1 - pf/hgKz/4Xqp/9+Crv/hgK7/4nWm/+Jnn//ibqL/3Web/+E5ef/jaZz/5W2d/+Vvnv/kfKf/52SU/+dr - nf/mfqr/5Xin/+hQhf/mb6D/5nil/+dfkv/ngqz/52GS/+Z7p//lfqr/5nai/+eCrf/mfaj/54mx/wAA - AAAAAAAAAAAAAAAAAACAi4QA2ezxGNrt8uTa7vL/2u7y/9ju8v/V7fL/2O7y/9ft8f/P6/H/0+vw/9fs - 8f/X7PH/2Ozx/9bs8f/S7PH/y+rw/9Hr8P/Q7PH/zuvx/87r8f/L6/H/v+rx/8bq8f/M6fD/w+nw/8jp - 8P/L6e//zurv/8/p7//J6e//xunw/8vq8P/Q6/D/wejw/9Hr8f/U7PD/0uzx/8Tp8P/O6/H/zOrx/83r - 8f/F6vH/yerw/8fq8f/T7PH/z+rw/8Tp8P/N6vD/1Ovw/9Ps8P/B6vH/zurx/8Xp8P/M6vD/zunv/8Pp - 8P/N6e//v+fv/8bn7f/J5u3/wuTt/7/j7P/A4er/t9zo/7jU4v+6utP/uZfA/8x6p//Wc6P/21+S/9xp - m//dapz/3m6i/+B0pP/jXpP/5F6T/+RpnP/kbqH/5EiC/+Rzo//kdKX/5WGV/+RjmP/jeKj/5GCV/+Nr - nf/ieKj/4lWM/+GBrv/ifaz/5IGt/+Non//kfKv/43mp/+N+rf/jga7/44Wx/+OArP/jeqj/5HWm/+R6 - qv/id6f/32CT/+Nzo//kWZD/5Xim/+R4pP/ldJ//5Xej/+RmmP/lfKf/52GU/+V/rP/mcqH/5naj/+Z9 - qf/lfqr/5n6o/+RrnP/kibH/54mx/+eLs//okbj/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA39/oi9vu - 8v/Z7vL/2e7z/9nt8v/Z7fL/1e7y/9ju8v/U7PL/1Ozy/9Ts8f/T6/D/0u3x/9Pt8v/S6/H/0evw/8rr - 8f/L6/H/zOvx/87r8f/M7PL/0Ovx/9Tr8P/N6/H/zevx/9Hr8P/S6/D/zOnv/8zp8P/H6fD/xOnw/9Ts - 8P/J6vD/zuvx/9Dr8f/S7PH/y+vx/9ru8v/Y7fH/2O3y/9Xt8f/K6vD/y+rw/9Ps8f/U7fL/0+zx/9Hr - 8P/O6/D/zuzx/8Pr8f/P7PH/yurw/8Ln7//G6O//wejw/8ro7//D5u3/veXt/8Dj6//F4+v/wuHp/7fa - 5f+2xtn/xJS7/8ltpP/UWY7/2XKg/9t0pf/eX5T/3mue/957qv/eZ5z/4HWn/+Nrnv/jW5D/42+h/+Rr - n//lUIf/5GOY/+Rnm//kW5D/5E+H/+N8q//jc6L/4nqp/+J7qf/kaZz/43ys/+N1pv/lYpv/5X6t/+Z+ - rf/lfqz/5Xao/+WDsf/kgrD/5Xip/+WBrv/kear/5Xao/+V7qv/hdqX/41SJ/+Nxn//keqf/436q/+KB - rf/jeaX/43Si/+VunP/mcKH/5nai/+Vbjv/kgq3/5mqc/+Vtn//kgKv/5HOg/+SErv/ne6j/54aw/+aT - uP8AAAAAAAAAAAAAAAAAAAAAAAAAAOW9zgbots7Z4N3n/9ru8//Z7vP/1+7z/9vu8v/Y7fL/1+7y/9bu - 8//T7fL/1Ozy/9Ts8f/T7PH/y+zy/9Xt8v/U7fL/0+zy/9bt8f/N6/H/1O3y/8br8f/c7vH/0evx/83r - 8f/P7PL/yOvx/9bs8f/O6e//zenv/8zp8P/S6/D/2O3x/8Pp8f/P6/H/1+3x/9bt8v/Y7fL/1+7y/9Ht - 8v/N6/H/0ezx/9ru8v/X7fH/2O3x/8vs8v/S7fL/2O3x/9nt8v/L6/H/wenx/8vr8P/N6vD/y+nv/8fo - 7//I6O//vuXu/7zk7f/J5Ov/wOHq/8Th6f/A1+L/xa7J/9CFsP/Td6b/2nuo/9tunv/baJv/3Gqc/95o - mv/fa57/32md/+Fzpf/iap3/5FSM/+VrnP/jYpf/5FeO/+Rllv/kX5X/43em/+R1pP/kd6b/42ic/+Jl - mf/jdKb/436s/+Vjmf/lbaL/5nKm/+drn//meqz/52ig/+dwpP/od6n/6Ye3/+iHtP/oeqr/6Y25/+eI - tf/mg7H/53qp/+N5qP/gY5P/4XCf/+GBrP/igaz/4n+r/+N8qf/igKz/43+q/+Ztnf/mZJf/5HGe/+WA - q//me6n/5YCq/+Vtnv/keKX/5IGr/+dunv/ngaz/5YGt/wAAAAAAAAAAAAAAAAAAAAAAAAAA6LHLQuiv - yv/nrMn/3+Lq/9vv8//Z7vP/2u7z/9nt8v/Y7fL/1e7z/9fu8//a7fH/2O3x/9jt8f/V7fL/1+3y/9Tt - 8v/a7vP/1uzx/9Xs8v/Y7vL/0ezy/9ju8v/S7PL/2e3x/87s8v/P7PL/zuzx/9Lr8P/Q6/D/1ezx/9nt - 8f/Q6/H/1ezx/9ft8f/O6/H/1O3y/9ft8v/O7PL/1O3y/9jt8v/d7vL/zezy/8zr8f/b7vL/zezy/8Pq - 8f/X7PD/zurx/8Lp8f/L6vH/w+nw/8fp8P/L6e//xefv/77n7v/F5Ov/xuLq/8Pg6v/G3uf/xsHV/8SB - qv/SVoz/2nup/9t3p//cXJH/3m6f/954p//fga7/4HOk/+Fsnf/jbKD/43ip/+VonP/mW5D/5VeP/+Rh - lP/kcaP/5Hmp/+Rpm//kcqL/5Gue/+R5qf/kfa3/5XOk/+RXj//ngrH/52yh/+d0p//peKr/6ou3/+qI - tv/qjbj/65vC/+yYv//rkbr/65e8/+uYvv/roMT/6pG5/+mVvP/ojbf/5n+s/+Bxnv/hc6H/4YGs/+J1 - of/jfar/4num/+J8qv/ifKr/5Wyb/+Z3pP/kc6D/5XOi/+Vyov/leqb/5XSi/+Rsm//je6f/5oCq/+Z9 - qv/mlrv/AAAAAAAAAAAAAAAAAAAAAAAAAADossuf6KrH/+eewf/mpsb/3uTr/9vu8v/a7/P/2u7y/9nu - 8v/a7vL/1u7z/9ru8//Y7fL/2+7y/9nt8f/X7vL/2O7z/9bu8//c7vP/2O7y/9Lt8//Y7vP/2u7z/9Xt - 8//i7/P/3O/z/9Xu8//W7vP/1e7y/9Ds8f/V7PL/0+zx/9bt8v/U7fL/0+zx/93u8v/V7PH/yerx/9zv - 8v/J6/L/1u3y/9fu8v/X7fL/2e7y/9Hs8v/O7PL/0+zy/9Ls8f/Y7fH/0Ovw/9Dq7//L6e//w+jv/87p - 7v/J5+7/w+Xt/8fk7P/E4Or/wMvc/8KuyP/Rf63/2mya/95ejf/dcqT/32qf/+Fzov/gYJj/4GOZ/+Fn - nv/jb6P/5GKY/+U4eP/lT4r/52SZ/+dSjP/nYZb/5nmp/+VXj//lear/5V6W/+dqnf/ndaX/54Kx/+dy - pv/ofq3/6G+h/+qMuf/qear/6nut/+yZwP/sibX/65O5/+yavf/slbn/7J2+/+uPr//pjKr/6Zi2/+eU - sf/leqP/54eu/+mOtf/nh7H/44Cs/99tnP/hf6n/43yp/+OCr//kZ5j/42ma/+Jzov/lb6H/5GmZ/+J5 - pv/ke6f/5XCd/+R5pv/kfaj/43ej/+N4pf/lcKD/5oOs/+WKsv8AAAAAAAAAAAAAAAAAAAAA6LLLC+iu - yenprMj/6aPF/+ecwP/lo8P/3ePr/9vu8v/Z7vP/2e7y/9fu8//Y7vP/2O7z/9ju8//X7vP/2O/0/9rv - 9P/c7/T/3e/z/93w8//c7/P/2O/z/9ru8//Z7vP/2u/0/93v8//c7/P/1u7z/9zw8//M7PL/4vDz/9ju - 8//c7/P/3vDz/9fu8//b7/P/2e/y/9ju8v/U7fL/2O7y/8vs8v/W7vL/z+3z/9Ht8v/X7vP/1e3y/8br - 8v/T7PH/z+rx/8rq8f/H6fD/xenw/8To7//B6O//xufu/8bl7f+74uz/wd3o/8rC2f/RhrX/1F6R/9tq - m//ecaD/4X2s/+N0pf/jaJ7/5HWo/+V1p//lUYz/5m2i/+Vrn//nfq3/6E6G/+hsnf/pYpj/6XCj/+hS - jP/odKb/6IGt/+iFsv/pkLn/6nel/+psnf/qfKn/6nup/+uSt//rhbD/7JG4/+uBqf/rhqv/66C5/+mc - tf/pr77/6cHM/+jHzv/o0tb/5tTZ/+XV2f/j09j/3snP/9Orvf+/WYr/wzxk/+V4o//khLD/4Haj/+J1 - ov/jbZ3/5Xel/+VjlP/japr/4nOj/+Rtn//kZpf/43up/+R0of/kdaL/5Gmc/+Rwnv/jhK//43Oj/+R9 - qf/lh6//5Y20/wAAAAAAAAAAAAAAAAAAAADpsMtH6q/K/+msyf/pn8H/5p/B/+aSuv/mmbz/3uLr/9vu - 8v/a7vP/2u7y/9vu8v/b7/P/2+/z/9rv8//Y7/P/2O/0/9jv8//c8PT/1+/z/9jv8//T7vP/1+7z/9zv - 9P/c8PT/3e/0/9zw9P/W7/P/2/D0/9vw9P/e8PT/3vD0/9nv8//f8PT/2u/z/9zv9P/W7vP/z+3z/87t - 8//Y7/P/0+7y/9Pu8//J7PL/1+3z/9Tt8v/T7fL/zOzx/9Ts8f/Q6/H/0ezw/8vq8P/J6fD/zuju/8bn - 7v/I5e3/xuXs/8rf6f/Rwtj/3Im3/+GLuP/ib6D/42SX/+R7qf/ka6H/526f/+dXkf/piLT/52+j/+mA - rf/nbaH/6H6r/+p+q//pa5z/6pe+/+qBrf/rfKn/6maW/+tzn//rdqP/6m6b/+uHrP/qe5//6YGg/+mW - q//pq7v/6LbE/+jBy//oztX/6Nbb/+ja3f/p3d//6d/h/+rh4//q4uT/6uPk/+rk5P/q5OT/6uPk/+nh - 4v/m29z/3crP/8OCn/+lGUL/22qT/+SKs//hhK7/4lyL/+VtnP/mZpf/5Wmb/+N1o//ieaf/5meY/+Vt - nf/jeab/5Guc/+RyoP/mfan/5G6d/+OCrf/jdKT/5Xej/+WErv/llbj/AAAAAAAAAAAAAAAAAAAAAOy6 - 0ZfrrMn/6qPE/+mgwv/mnMH/55vA/+iSu//mmL7/4Nvl/9vu8v/c7/L/2u7y/9vv8//a7/P/2+/z/93v - 8//d7/P/2O/z/9vv8//U7vT/1+/0/9bu8//Y7/T/2e7z/9bv8//a8PT/2/D0/9Tu8//V7vP/1O70/9vw - 9P/g8PX/2+/z/9zw9P/X7vP/4PD0/9ju8//d8PP/1u7z/9bv9P/W7vP/0O3z/8/t8//T7PH/0+3y/87s - 8f/M6/H/z+rw/87q8P/Q6e//wujv/8fn7v/I5u3/xuXt/8nk7P/K4er/17nU/+B+qf/ljrX/6JK7/+eK - sv/pirP/54Sv/+l4pP/pcaL/6mKU/+p7pf/qbJ7/64Kr/+lynf/peZ7/6YOh/+mOq//opb7/6KvA/+ev - v//nt8L/5r/K/+bJ0P/n1Nr/5trf/+fd4f/o3+L/6eHk/+ni5P/p4+T/6uTl/+rk5f/r5eb/6+bm/+vn - 5//s6Oj/7Ojo/+zo6f/s6On/7Ojo/+zo6P/s6Oj/6+bm/+nh4P/h09T/y5m3/6sxYv/hhKr/5Y20/+N/ - q//hbpv/5Wyb/+Vgkv/maZr/42CU/+V2pf/mYJP/5G6d/+R2pf/kc6H/5XOi/+ZjmP/lXpL/5HCg/+R8 - qP/ld6X/5YSs/+aFr/8AAAAAAAAAAAAAAAAAAAAA7a/MzO2ryv/tp8f/66jI/+igxf/nmcD/6pS//+uT - vv/pmcD/5cfb/93r8P/a7/P/2+/z/93v8//b7/P/2u/0/93v8//d7/P/2+/z/97v8//b7/P/3vD0/9rw - 9P/b8PT/3fD0/9jw9P/c8PX/2/D0/+Lw9P/h8PP/2e/z/9vv9P/c8PT/3/H1/97x9P/j8fT/1+/0/9Lu - 9P/Z7/T/0+7z/9nv8//V7vP/0u7z/9ft8v/S7PH/y+zx/87r8f/R6/D/zenv/8vo7v+/5u7/xOXt/73j - 7P/H5e3/yOHq/9XG2P/ggKb/31SG/95zl//bYIn/1mWI/9Bpif/IXX3/vE5t/7FEZP+pOlb/nzdO/4sp - P/96Kz3/u5qx/97P0v/j2t7/5t3g/+ff4f/o4eP/6ePk/+nl5v/q5eb/6ubn/+rn6P/r6Oj/6+jo/+vo - 6P/s6en/7Onp/+zp6f/s6er/7Orq/+zq6v/t6ur/7erq/+3r6v/t6+v/7evr/+3r6//t6+r/7erq/+zp - 6f/r5+f/6eHi/+HQ1f/Lm7r/zYWr/+aStP/mi7P/44Ks/+Jtm//kXo//5Wub/+VhlP/kYJL/5lKJ/+Vu - nv/jcqH/5Gqb/+ZrnP/nbJ3/52OW/+Vwn//lapv/5Xum/+Z1pP/ncqD/54Ss/wAAAAAAAAAAAAAAAAAA - AADusMqL7q/L/+6tyv/trsz/7K3M/+ykx//tl7//7Z/E/+yZvv/rncP/6KXE/+DZ5P/a7/P/2u/z/9vv - 8//b7/P/2+/z/9zv8//a7/P/2u/z/9/w9P/c8PT/3vH1/97w9P/h8fX/3/H1/+Dx9f/g8fX/5fL1/+Px - 9P/c7/T/4PH0/9nw9f/U7/X/3fH1/9zw9P/Z7/T/1u/0/9vv8//e7/P/2O70/9rv8//P7vP/1e3y/8vr - 8f/P6vD/xunw/8To7//K5+3/xOXs/8Xm7f/I5ez/v+Lr/8Pi6//I4On/qb3H/1FIVP9BKC//NyYr/ykm - J/8dJiX/HCcm/yAoKP8mKir/Kisr/ywrK/8rKir/Kigo/yYiIv9fU2X/2dLZ/+fj4//p5ub/6+fn/+vo - 6f/r6er/7Orq/+zr6//s6+v/7evr/+3r6//t6+v/7evr/+3r6//t7Oz/7ezs/+3s7P/t7Oz/7ezs/+3s - 7P/t7Oz/7ezs/+3s7P/t7Oz/7ezs/+3r6//t6ur/7Ojp/+vl5v/n3N//3cXP/9anv//mqcT/53+q/+aM - tf/kgKv/4HOg/+N4pP/lZpX/5Wib/+R+q//mWo3/5Wyd/+Rsnf/lZpj/5lqP/+Zkl//lbJz/5XSj/+ZY - jv/lcqD/5nqn/+hqmf/ndKH/AAAAAAAAAAAAAAAAIR0eAO6yxgbvscdB77zPnOq+zv/hm7H/4omm/+N8 - oP/kjqn/436g/+KCov/cdJb/0nGT/8KaqP/G3OL/2u7y/9vv8//c7/P/3O/z/93v8//b7/P/3/Dz/9zv - 8//c8PX/3/H0/9/w9P/g8fX/5fL1/9jw9f/e8fX/5vL1/+fy9f/i8vX/3/H1/9/x9f/c8fX/2vH0/9Pu - 9P/Z7vT/3u/z/8/t8//O7vP/0O7z/8ns8v/K7PL/0ezx/8nr8P/O6u//y+bu/83n7f/K5e3/yOTr/8Tj - 7P/B4ev/sNHd/3iPnP8uOUP/LDU8/y81OP8xNTf/MTM0/zI0Nf8yNDX/MjM0/zIzM/8yMjP/MjIz/zEy - Mv8xMTH/MTAw/ysnJ/+tqbP/6Obn/+vq6v/s6+v/7ezs/+3s7P/t7Oz/7ezs/+3t7f/t7e3/7u3t/+7t - 7f/u7e3/7u3t/+7t7f/u7e3/7u3t/+7t7f/u7e3/7u3t/+7t7f/u7Oz/7ezs/+3s7P/t6+z/7evr/+3p - 6f/s5uf/6eDh/+PS2f/gvND/5KvF/+ibvf/ojrX/5oiy/+SEr//gcKD/5G+d/+ZelP/lapv/42OY/+R2 - pP/kbJ3/5F2S/+N5pv/mbJ3/5VqO/+Nsnf/kcaD/5HCf/+N5pf/lfKf/52qX/+Z/q/8AAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAADz8vFJyMXG/1tbW/9LS0v/Q0RE/z09Pf84OTj/MzU0/zAxMf8tLS7/LCst/y80 - OP+DmqL/xt7k/9ju8v/b7/P/3vD0/93v8//e7/P/3+/0/97w9P/g8fX/3fH1/+Hx9P/c8PT/1u70/9Xv - 9P/X7/T/1+/0/9jv9P/c8PX/3PH1/9fw9P/X7/T/1e7z/9Ds8v/P7PL/0uvx/83s8v/N7PL/y+rw/83p - 8P/G6O//x+fu/9Hn7f/P5u3/zeXs/8jk7P/F4uz/wuHr/63I0f9Za3f/LTg9/zE5Pv80OT3/NDk8/zU5 - O/81ODv/NTg5/zU3OP80Njf/NDY2/zQ1Nf80NDT/NDQ0/zMzM/8yMjL/MjEx/2Fgaf/i4eX/7Ovq/+3s - 7P/t7e3/7u3t/+7u7f/u7u3/7u7t/+7t7f/u7u3/7u7t/+7u7f/u7e7/7u3t/+7t7f/u7e3/7u3t/+7t - 7f/u7e3/7u3t/+7t7P/u7Oz/7evs/+3r6//t6en/7Ofn/+rg4v/m1dr/5sPT/+u50v/qlLj/54+0/+eC - r//nh7H/5ISu/+Num//kapr/5l+P/+VRh//kcaH/5Gaa/+Zklv/jX5L/5WCR/+Zhlv/lYpT/5HWk/+Ns - nP/jcaD/42yb/+RyoP/jeKL/5oWt/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPX09V+ioqH/XFxc/1JS - Uv9LS0v/R0dH/0RERP9CQkL/Pz8//z09Pv88PD3/Ozs9/zg6PP8sQEj/ip6m/9Hk7v/Z7vP/2+/z/93v - 8//e7/T/3/D0/9/w9P/c7/T/3vD0/9vv9P/k8PT/3u/z/93v8//a7/P/2+/0/9vv9P/U7/P/1e7z/83u - 9P/R7PH/0+zx/9Dr8f/Q7fL/0e3y/9Ls8v/U6/D/1erv/9Hn7v/K5+7/z+fs/87l7P/F4uz/yeHr/7/c - 6v+NscL/N0hZ/zE9RP81PEL/OD1A/zg7Pv84Oz3/Nzo8/zc5O/83OTr/Njg4/zY3OP82Nzf/NjY3/zY2 - Nv81NTb/NDQ1/zMzM/8yMjL/Li0s/8PCy//r6+v/7e3t/+7u7f/u7u7/7u7u/+7u7v/u7u7/7u7u/+7u - 7v/u7u7/7u7u/+7u7v/u7u7/7u3u/+7t7f/u7e3/7u3t/+7t7f/u7Oz/7uzs/+3r7P/t6uv/7Onp/+zm - 5//q4OL/5tXb/+bD0//rtM3/66XE/+mDrv/ohK//6IOx/+iMtv/kfKj/4WqZ/+Jtnf/kZ5j/5HOk/+R6 - p//mYZT/5z96/+RwoP/lTYL/5Gyf/+Rsnf/jYpf/422d/+Nvn//hdaH/4nel/+F/qP/lcZ7/AAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAA8fDxdHx8fP9aWlv/UVFR/0xMTP9ISEj/RUVF/0NDQ/9BQUH/Pz9A/z0+ - P/88PTz/Ojs8/zU6Pf8lMDr/mqfE/93m7P/g7PH/3u7z/9zu8//d7/P/3vD0/9/w9P/f8PT/3/D0/9/w - 9P/d7/P/3e/0/9rv9P/b7/T/3e7z/9ru8//T7fL/0uzy/8/s8v/O7PL/0+zx/9Dr8f/P6/H/z+rw/9Hq - 7//V6O7/0uft/8/l7f/R5Ov/0OTs/8ri6//I3en/y9nm/2Fzhv84Q0n/OkJF/zs/Q/87P0L/Oz5A/zs9 - Pv86PD3/Ojs8/zk6O/85OTr/OTk6/zg5Ov84ODn/Nzc3/zY2Nv81NTX/MzQz/zMzM/8yMjL/lZWh/+rp - 6//t7e3/7u7u/+7u7v/u7u7/7u7u/+7u7v/u7u7/7u7u/+7u7v/u7u7/7u7u/+7t7v/u7e7/7u3t/+7t - 7f/u7e3/7uzs/+3s7P/t6+v/7erq/+zo6P/r5OX/6d7h/+fS2v/mwdL/7LPO/+yev//plrn/6I2z/+iT - uv/piLL/54Gu/+SFr//fcJ7/4XOh/+Rsm//kbZ7/5V+T/+Zek//mVon/42+g/+Nllv/jZ5n/5GGU/+Nm - mP/ja5v/4W6f/+B4pf/hcqD/4XWh/+R8p/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADf3t9/cHBw/1pa - Wv9SUlL/TU1N/0lJSf9GRkb/RERE/0JCQv9AQUH/Pz8//z0+Pv87PDz/ODs7/y01O/9meJT/2+Hq/+jr - 7//s7/H/6e/y/+Tv8//h7/P/3+/z/9/v8//g7/P/3u/z/9rv9P/b7vT/2u7z/93u8//c7vP/3u/z/9rv - 8//a7vP/0e3z/9Dt8v/T7fH/0e3y/9Hs8v/R6/H/z+ju/9Pl7P/T3uj/z9zp/8/W5P/Q1eP/1NXk/9vb - 5v/r6+7/bHB3/0BGTP8/REb/QENF/z9BQv8+QEH/PkBB/z0+P/88PT3/PDw9/zs8Pf86Ozz/OTo7/zk5 - Of83ODj/NjY2/zU2Nv80NDT/MzMz/zIyMv9qa3j/5+fq/+3t7f/u7u7/7u7u/+7u7v/u7u7/7u7u/+7u - 7v/u7u7/7u7u/+7u7v/u7e3/7u3t/+7t7f/u7e3/7uzt/+3s7P/t6+v/7erq/+zo6f/s5uj/6uHj/+fZ - 3v/qzdr/68HU/+yyzP/tpMT/6o60/+mEr//pm7//6Iiz/+iJs//njLX/5IOu/990ov/gdKL/42aX/+VZ - kP/mUon/5HSl/+NekP/idKP/4WiZ/+JxoP/iV43/42SX/+FrnP/gb6H/4WeX/99sm//gc5//4YGo/wAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAM7Oznxra2v/WVlZ/1JSUv9NTk7/SkpK/0dHR/9FRUX/Q0ND/0FC - Qv9AQED/Pj8//zw9Pf85Ozv/NDc5/ztLYP/O2Ob/6ezu/+3w8f/t8PL/7fDy/+3v8v/s7/L/6O/y/+Xv - 8v/k7vL/4u7y/+Dt8v/e7fL/3ezy/9vs8v/Z7PL/1+3y/9Xt8v/V6/H/1Ovx/9Lp7//T5u7/0uPs/9Td - 6f/U1OP/1cXb/9S41f/QstL/16fM/96fx//ft9f/7ufs//Dw8f9zbXT/RklN/0VISf9DRUb/QkNF/0FD - RP9AQkP/P0BA/z4/P/8+Pz//PT4//zw9Pf86Ozv/Ojo6/zg5Of83Nzf/NTY2/zU1Nf8zMzP/MjIy/zs7 - RP/h4ef/7ezs/+7u7v/u7u7/7u7u/+7u7v/u7u7/7u7u/+7u7v/u7u7/7u3t/+7t7f/u7e3/7uzs/+7s - 7P/t7Oz/7err/+zo6f/r5uf/6uLk/+jc4f/m09v/6cfX/+y0zv/rnb//7Iux/+qavf/rnr//6Zq7/+iX - vP/pl7z/6Yy0/+aGsP/jfKr/33ak/+B6pv/jc6P/5mKU/+ZXjv/kcqD/4meY/+Ftnv/fb57/4HGh/+Ji - lP/hXpH/4GCU/99gk//iVov/32WX/95wnP/feaP/AAAAAAAAAAAAAAAAAAAAAEY9QADq2+AC1MvOpmtr - a/9aWlr/U1NT/05OTv9LS0v/SEhI/0ZGRv9ERET/Q0ND/0FBQf8/QED/Pj4+/zs7PP82ODr/KC42/7vE - 1v/q7O7/7/Hy/+7w8v/u8PL/7vDy/+3w8v/t7/L/7e/y/+zu8v/r7vH/6+3x/+ns7//k4Or/4Mjf/+PR - 4f/h2eb/4trm/+PT4v/lxtz/57PT/+Wly//jkMD/4Ia8/9iFuP/dbav/3Vaj/9dNm//XS5j/3WCm/+iw - 0v/x7/D/8PDy/4N7gf9NTVD/SUtM/0hJSv9FRkj/REVH/0NERf9CQ0T/QUJC/0BAQP8/Pz//PT4+/zw8 - PP86Ozv/OTk5/zg4OP82Njb/NTU1/zQ0NP8zMjL/MzEy/9ra4f/t7Oz/7u3t/+7u7f/u7u7/7u7u/+7u - 7v/u7e3/7u3t/+7t7f/u7e3/7uzs/+3s7P/t6+v/7erq/+zp6v/s5+j/6+Tl/+ne4f/n1tz/6MnX/+u/ - 0//sq8f/65S5/+yLtP/rjLL/65S6/+uMtf/pi7L/6Yu1/+iGsP/oirP/5Ymz/+R7qf/edKL/4W6c/+J2 - pf/lZ5f/5Uh//+Nxof/hc6D/4WKU/+Bqm//fZ5j/33Gh/99wof/fX5L/3GCT/99aj//dV4//3GOS/99z - nv8AAAAAAAAAAAAAAAAAAAAAAAAAAOvM3FThx9L+b25u/1tbW/9UVFT/T09P/0xMTP9JSUn/R0dI/0VG - Rv9ERET/Q0ND/0FCQv9AQUL/PT4+/zg5O/8wMzL/qLHG/+nr7f/v8fH/7/Hy/+/x8v/u8PL/7vDx/+3v - 8f/t7/H/7e7x/+zu8P/s7e//7Ovu/+zp7P/oqcz/5Gep/+d2sv/pgLj/64S7/+pnqv/rV6L/6lWf/+hY - nv/nN47/5TSH/+Mcc//jDGr/3zKB/9wreP/fIXX/67DN//Hv8P/x8fL/nZaa/1JPUf9MTk//SktM/0pL - S/9ISUn/RkdH/0VGR/9ERUX/QkJC/0BBQf8/Pz//PT09/zs8PP86Ojr/ODg5/zc3N/81NTX/NDQ0/zMy - Mv8xMDD/2Nfe/+zs7P/u7e3/7u3t/+7t7f/u7e3/7u3t/+7t7f/u7O3/7ezs/+3r7P/t6+v/7erq/+zo - 6f/r5uj/6uTm/+nf4//n193/6czY/+zD1v/rrcf/6oy0/+uXu//pj7P/65a9/+uMtP/spcX/7Iiy/+ye - wf/rocP/6Za8/+ePuP/libP/4nWl/99unf/iapr/4nup/+Rtnf/kZ5j/426f/+Jhk//hapv/32qc/95l - lv/ca53/21+U/9thlv/aV4z/2VSK/9pckP/ZZJP/23Kb/wAAAAAAAAAAAAAAAAAAAADt0NsK7dHe1uOo - vv92dXX/XV1d/1VVVf9QUFD/TU1N/0pKSv9JSUn/R0dH/0ZGRv9ERUX/Q0RE/0NDQ/9AQUH/Ozs8/zM0 - Nf+dobT/6Ort//Dx8f/w8fL/8PHy/+/x8f/v8PH/7e/w/+3u8P/s7e//7Ozu/+zs7v/s6+3/7Onr/+vk - 5//lhbv/41GZ/+Vjpf/pbKz/7Fqh/+1MoP/sa63/6jiN/+lKmf/mHXf/4yeA/+MSav/kFGz/4Btz/+Ad - dv/qpcb/8u/w//Lw8f++tbn/WlJW/1NSU/9RUVH/T09P/0xNTv9LS0z/SUlJ/0dHR/9FRUX/Q0ND/0FB - Qf8+Pj7/PT09/zs7O/85OTn/Nzc3/zY2Nv80NDT/MzIy/zIuL//a2eD/7Ovr/+3s7P/u7ez/7ezs/+3s - 7P/t7Oz/7ezs/+3r6//t6ur/7Ojp/+zn6P/r5eb/6uLk/+je4P/m1dz/6sXW/+mtxf/smLz/7aHA/+yQ - tf/tqsf/6oux/+ufwv/urcv/7rPO/+6pyP/umb//7Z7B/+qQt//qnL7/55C4/+aJsf/je6j/4HCg/+Nx - n//kbp//43Sj/+Vil//jX5P/4WaY/99xof/daZr/3GaY/9xQhP/aW5D/2FKK/9hOhv/YVI3/2FGJ/9pZ - j//db57/AAAAAAAAAAAAAAAAAAAAAO3R3T/svNH/4HSK/4eCgv9gYGD/V1dX/1FRUf9OTk7/TExM/0pK - Sv9JSUn/SEhI/0hHR/9HR0f/RUZG/0RERf8/P0D/NTU2/5SYrf/p6u3/8PHw//Dw8f/v7/D/7u/w/+7v - 8P/t7u//7e3v/+zs7v/s7O3/7Ovt/+zq7P/s6er/6+fo/+vW4v/jSKX/3jmS/+Zjpv/sV5//7WOl/+5k - p//pNIX/6l+j/+c/hv/mQ4z/4y57/+IleP/iF3L/4QVm/+eYuv/y7+//8vDw/9zX2f9gVFj/WVdY/1VV - Vf9UU1T/UlJT/09QUP9MTE3/SkpK/0hISP9FRUb/Q0JD/0BAQf8+Pj7/PDs8/zk5Of84Nzf/NjU2/zQ0 - NP8yMTH/PDQ7/+Lg5f/r6ur/7evr/+3r6//t6+v/7erq/+3q6v/s6en/7Ojo/+vm5//q4+X/6N7i/+jY - 3v/m0tv/57vM/+qpwf/slrn/7HSh/+yDrP/rhKz/7JO3/+uAqv/smLv/656//+2qyP/so8T/7qHC/++Q - uv/vnML/7JK6/+qYvf/olrz/5Xyo/+J0o//gZpf/5Gua/+Vhk//lapv/42SV/+J5qP/fbJv/3m6f/9xk - lv/ZXpH/2EiA/9ZUjf/YUoz/2VGM/91cl//eYJr/32Kc/+Fon/8AAAAAAAAAAAAAAAAAAAAA7c3cZ+mc - vP/XL1j/qJmc/2NjY/9ZWVn/U1NT/1BPUP9NTU3/TEtM/0tKS/9KSkr/SkpK/0pKSv9LS0v/SUlJ/0ND - Q/83Njf/mJqt/+np7P/t7u//7e7v/+3t7//t7e7/7e3u/+3t7v/t7O3/7Ozt/+zr7P/s6uv/6+jq/+vm - 6f/q5Ob/6eDj/+J6q//ZCWj/4EuV/+txs//wg7z/72Gp/+19t//qa6T/6nWu/+hjn//lVJb/5T+K/+Ih - dP/aD13/3GST/+3m6f/x7e7/7+zt/4Fxd/9gXF3/YF5f/11cXP9ZWVn/V1ZX/1NSU/9PT0//TExM/0lI - Sf9GRUX/QkJC/z8/P/89PDz/OTg5/zc2N/80MzT/MzIy/zAuLv9pYnH/5uPl/+vo6P/r6Oj/6+jo/+vn - 6P/r5uf/6uTm/+ni5f/p3+P/59vg/+fS2//ox9b/6rLK/+qux//tosL/7Ymx/+2HsP/thqv/7JC0/+uK - sP/urMn/7p2//+2XvP/ur8v/7KXF/+6tzP/vncH/8aPE/+6LuP/tlLv/6pe8/+iTuv/lf6v/4nGh/+Jm - mP/kdKP/42KT/+Run//ieKf/4HOk/95tnf/dYZP/2VyP/9dPiP/YUY3/2leS/91cmP/fYZv/32Cb/+Fm - n//iYZz/42Ke/wAAAAAAAAAAAAAAAAAAAADt0+Bi6Jm4/9AQQ//AlqL/amho/1xbW/9WVVX/UlFR/09P - T/9OTU3/TU1N/01NTf9OTk7/UVBR/1FRUf9RUFD/SUhI/zY1NP+gn7H/5+bp/+zr7P/t7O3/7ezt/+zr - 7P/s6+z/7Ovs/+zq6//r6ev/6+fq/+rl6P/p4+b/5+Dj/+Ta3v/i0tz/4KnE/9w8eP/kRof/52Cw/+5X - qf/wc7f/8JDB//CEuv/vjLv/75jC/+2Svv/pSpT/52ig/9AsY//JG1v/373P/+rh5//s5ur/vbG3/2hg - Yv9nY2T/ZGJj/2FgYf9eXV3/WFhY/1FPT/9PTk//S0lK/0dFRv8+PDz/NzY2/zQyM/8zMDH/Mi8x/zEu - L/8xLi7/KSIk/5iNnP/m4eP/6ePk/+ji4//o4eP/6N/i/+fc4P/m1dv/5tDZ/+bAzv/orsL/6qC+/+x6 - n//rfqr/7J7A/+2iwv/sg6r/7Ze5/+yHq//rlrr/7aLB/+yRt//vq8j/7Zm7/+6ryf/tpsb/7arJ//Cr - yP/viLL/753C/+6awP/rj7j/6Ja7/+SGsP/ha53/4m2d/+J5p//jcJ//5GeY/+Jyo//fc6T/3WiY/9ld - j//WVoz/2ViS/91alf/fX5n/4GKc/+FhnP/hX5v/4mWf/+NgnP/jZqD/AAAAAAAAAAAAAAAAAAAAAO3P - 3zPqpMH/zBdE/8uEkf9/cXf/YF1e/1hVVv9VUlP/UlBQ/1FOT/9QTk//UE9P/1JQUf9VVFT/WVhZ/1xa - W/9OS0z/LiUk/66owP/n5ef/6ujp/+vp6v/r6Or/6ujp/+rn6f/q5uj/6eXo/+jj5//n4OT/5dvh/+PU - 3f/iyNf/46/G/+aTs//rc6D/6mWW/+uHrf/phbD/7obC//Cfx//xZLv/8JXF//CMt//xnsP/74W1/+1d - oP/rga//6pS5/8plg//Fc6X/38XY/+XX3v/h19z/fWhw/2JYXf9iXF//WVRX/05JSv9LRkj/OjM2/z02 - OP83MjT/NjAy/zErLf8vKSv/LSYo/y0lKP8tJCf/Jx8i/yYfIf8mCAf/wq28/+HV2v/j0dn/49HY/+XL - 1//lydT/6LzN/+qvyf/pp8T/6Xyj/+qAqP/rjbT/7X2m/+2CrP/qj7T/7qvI/+yHrf/tl7r/7aLC/+6y - zP/sj7H/76PD/+2Xuf/upMH/7pm9/++xzf/uoML/76TE/++Xvf/unMD/7ZO7/+yXvP/nkbf/5Hup/+Bu - nv/jW4z/4nin/+Nbjf/kV4v/4HOk/9xnmf/XU4b/0lCE/9dQiv/cTYr/4FeU/+Bim//hZZ3/40iI/+Nd - mP/iW5j/4mig/+Foof8AAAAAAAAAAAAAAAAAAAAA7snXBu7I2d3XaYj/tjRL/66Fl/9nUFj/W0tQ/1JG - Sv9TSUz/SUJE/01GSP9LRkf/RkBB/1dTVP9QTE3/Qjw+/0o+Qf8pDxz/w7bK/+Td4f/n4eP/6OHk/+fg - 4//n3+P/59zh/+bb4f/l2OD/6NHd/+jB1P/nq8L/6p6//+yKsP/sbpz/7Za6/+yKsf/sgqr/7Ji7/+qH - rv/sjrz/8XvE//GOvv/xqMr/8Z/D//CcwP/wp8f/7Yu7/+2Crf/snsD/6rnR/+Kvyf/Zn8X/2rrQ/9zI - 1P+1nqn/QyYu/0ArMv9HLjf/NSUr/zkoLf82JSv/OCUr/0AnL/9KKTX/QSYw/2g9Tv9yR1f/VDA9/5Bb - cP9XLDj/US05/4BMZf/Uo7v/37DF/+ewyP/mnbr/54uw/+mau//rkLP/65a7/+ugwf/sp8P/7KDA/+2h - v//tmLn/7Y2y/+yZu//spsP/7arG/+2YuP/ti7P/7Zm7/++vy//vqsj/7qTE/+60zv/thq//8KjJ//Cv - y//wscv/76bF/+2fwf/tpMX/65e8/+d/q//ibqD/4GiZ/+Nrnf/jZJf/41+T/+Fjlv/dZpn/2mCV/9RH - e//TPXT/3VuU/+BalP/gWZT/4V+Z/+Jonv/kTYn/5FiU/+RKif/jWZb/4l+a/wAAAAAAAAAAAAAAAAAA - AAAAAAAA7sLVi+q/0v/Pl6n/xoKi/3BEV/8+Iyv/PSMs/zwpLv8/LjP/Oikt/zgoLP8zJCn/UDtC/z0v - M/9QND7/cVNg/5Nrgv/Wtc7/4svX/+nL2//lzNj/58rY/+fG1v/qvtX/6rrR/+ugvf/tfqn/7ZK5/+yJ - rv/thq3/7X6p/+2Aqf/wttH/7Z29/+2Zu//upML/7aXC/+uWuv/yo8r/86DI//Kpy//yqcr/8Z3B//CZ - v//vm7//7Xio/+ybv//ro8P/7KfH/+quyP/mqsf/353A/9qkv/+/dpX/u2mK/851lP+9c5L/pl15/6tr - hf/Ie5z/x36c/9R+of/Of6L/1Yqo/9J8oP/TfqD/5Zi6/+KRsv/ic5f/6oqt/+qGrP/qgKj/7qnJ/+yX - uf/roMH/6qPC/+p7o//qdaD/7KHA/+qIq//tqcb/63eh/+t8o//rnLv/6nmk/+6mxf/so8H/77LM/++r - yf/vscz/7rLM/++rxv/unL3/77jR//Czzf/wqcj/8aXH//Cvy//uq8f/7qvJ/+2Vuv/qlbr/53yn/+Fo - nP/hZZf/42eZ/+Raj//ia5//32GU/98+cP/UP2//10uD/91Hgv/fSYj/4FiU/+BgmP/hWJL/4VyX/+JQ - jv/jXZf/5VqS/+Nemf/jZ5//AAAAAAAAAAAAAAAAAAAAAAAAAADuuc407rTM/um1y//mtMr/4avC/794 - lP/AgZn/yYOh/7Jog//IhqL/oVx4/6ZWb//Vm7X/s11//9abtP/XmrP/5aTB/+q10f/rqMn/77LP/+2a - uv/vpcf/7pS5/++gxP/wrc3/7oav/+6Msv/vn8D/8KzK//Cmxv/ukbP/75O4/+2Wuf/uqMX/7qnH/+t5 - pP/urcn/7J29//Kvz//zqsz/86rL//Kpy//ylLr/8KXG//CVu//up8n/652//+yoxf/snL7/7Jy//+yb - wP/pncD/6Ja8/+mVu//nh7H/6VGQ/+l3pf/pg7D/6Y22/+d9qv/pj7j/6F+X/+mLtP/ne6v/6p/D/+mQ - uP/qga7/7JO8/+p4ov/tjLD/7Zy8/+2VuP/sia7/7p+9/+2qxv/us8z/7Jq6/+uVtf/spMH/7JO0/+6n - xv/qiq7/7KbF/+62zv/to8L/76HE/+6uyv/vts7/7qTD/++zzP/usMj/76PC//Coxf/uqcb/8LbQ//C2 - zv/wss3/76rI/+6uyv/up8f/7aDB/+qPtv/kb5//4Wye/+Jmlv/kVoz/41qL/+FdkP/eXpL/2leH/9dO - hv/dT4r/31WO/+BEgf/gTov/4F6W/+BYkv/hYpr/4XSl/+Jdlv/jVJD/42CZ/+Jrov8AAAAAAAAAAAAA - AAAAAAAAAAAAAOvK2gHuscvE7rLM/+yzzP/tr8v/7KjG/+2YvP/tmsD/65i+/+uoyP/rnsL/7JC5/+yC - sP/ri7T/7Jm9/+ycwf/tjLX/76fI/++oyv/wqMv/76DD//CoyP/vnL//8J/A//Ciw//vpsT/74+0//Go - x//vmLv/75q8/+6RtP/um7z/7Z68/+6qx//wtc//76zJ//Czzv/tmLz/8ajK//Oz0v/zqMr/8qzN//Gs - y//wrMv/8J/D//Cmyf/vj7r/7ajG/+yiwv/rocL/65rA/+yhw//rlb3/7ZO8/+yTvP/ri7X/7JC5/+x9 - rf/unML/7XWp/+xypP/sgrD/7Yuz/+6myP/uo8b/7Z7D//G20//vn8H/76nI//C00P/sjK//7Ze3/+6Z - uf/sgaX/64Gn/+2iwv/to8L/6ZCw/+yiwf/tnb7/7Zm7/+yrx//wttD/7aC+/+6qxf/vocH/7rPO//C3 - z//slLb/767J/+6mxf/wtM3/8bPO/+6hwf/wsMz/8LbP//Cyy//uq8f/77rR//Ctyv/tnsH/6Yiy/+Fv - oP/hbp//4maX/+Nmm//hUof/3luN/9hWh//ZVIv/20+J/95Ri//fVZD/4V+V/+Fil//gX5b/4W6g/99n - nP/fa57/4GGV/+Fpnf/haqD/42We/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO24zUvvssr97q3I/+6w - y//vsM3/76zL//Cixv/wpMj/75/F/++jx//ve6//76fK/++nyf/uqMn/76vL//G00//xrs//8rHS//Gp - y//yr8//8bfW/++Wu//yrcz/8aTF//Cgwv/xm77/8Ju8//Cpxv/vp8b/77HM//CxzP/wu9T/8LLN/++d - vf/wr8v/8KnH//Clw//xn8X/87bU//Kjx//zpcf/8rDO//Knx//xrs7/8aHG//CXv//un8H/7a3I/+yo - xv/tn8H/7KLB/+yqx//uq8r/763N/+2lyP/tqMr/7pzD/+6Jtf/vnMH/8Ji+//CszP/uh7L/7oKt//Gx - 0P/yttP/873Y//K81v/xsMz/8LPO/++uyf/uoL7/76jG/+2Xt//tn73/6568/+ysxv/rqMT/767K/++n - w//ui6//7q/K/++nw//qdJ7/767K/++lxP/vq8f/77XM/+yCrP/vsMr/77vT//C1zv/xtc//8bvT//Cm - xv/xtM3/8LTO//C60f/xrsr/76XD/+yYu//ld6X/4W2f/+Jdkf/jZZn/4mab/+Bfkv/ZWoz/1ViI/9tP - h//cU43/3k2H/+FYkv/iaJ7/4nan/+FnnP/gZ53/32Sb/9xjmP/dZpf/32SY/+Nqnv/kX5b/AAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAA78DiAe62zLnvrsn/77HK/++syP/vtM//8K3N//CXv//wqsv/8KPG//Gj - yP/xnsT/8abJ//Gwz//xq8z/8rLS//Ox0f/yoMT/87LR//Kdw//yqsv/8a/P//GpyP/whLD/8Y20//CV - uv/wkbT/8K/L//Crx//wnLz/8afG//GqyP/yudP/8KHA//G+1v/wocH/8Z/A//CXvv/zo8j/86fJ//Ol - yP/zpcf/8pvA//Kqy//yp8n/8Z7F//Ccwv/urcn/7anG/+6cwP/uoML/7avI/+2qyf/wrMr/8KrK/++w - zf/vtdD/8LDO//Gtzv/xqcr/8afJ//K31P/yt9X/88Hb//Gqy//zuNP/8qvL//Kzz//wrsr/77fQ/+6u - yP/xu9T/76rH/+2zzP/tsMv/7K7H/+++1f/tgqX/752//+6lwf/uqcb/8KvG/+6jwP/wu9P/7Yyw//Cl - wv/vq8f/8LjR//G60v/wvNP/8K3J//G1z//yqcn/8rnS//Gmxv/ysc7/8rvT//CbwP/up8T/6o2y/+Fs - nf/iYZT/5FiO/+NUi//iY5X/4F2Q/9lhk//cV47/3FmQ/99pnP/hZpj/5GOX/+NNif/ja6H/4mWc/+JZ - k//hWpL/3muf/9xom//eW47/4FKF/+REgP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADHnLYA7rnNJu61 - zPTvssv/76nG//G1z//wuND/8LHM//G61P/xtdH/8rXR//Kuzf/yr9D/8rTR//K31P/yn8X/8qTH//Ku - zf/xrMz/8rTS//Gtzv/xtNL/8aHE//GGsP/yrcv/8JC2//Gpx//yttH/8bLN//GgwP/xpsX/8abF//Kn - xv/zss7/8rXQ//LC2f/xlLr/75u9//KYv//zqMr/9KjK//Otzf/yq8v/8qrK//Okx//ynsP/8J7D/+6j - xP/urcj/7qbG/+6dv//uosP/7arH/+6oxv/vmb3/8bPQ//G40//xvdf/8LLQ//Gz0P/woMH/8bHO//Kx - 0P/xvNb/8bbS//Gnx//xpsf/8afG/+6MsP/wu9P/77HK/+6nwv/tosD/77vT/+640P/vtM3/77rR/+2i - v//upsT/7rLL/+6vyf/umrr/7Yuw//C1zf/tmbr/8LTN/+2Yu//xuNH/8KzI//G+1P/yudP/8rvS//Gl - xf/xuNH/8q/M//OoyP/yqsn/8LTO/+2iwf/mfKb/4Wmc/+VhlP/mWpH/5FyP/+JDdf/YRHT/3l6U/+Bc - lP/hYpb/4G2e/+Nxov/lbKD/5mqd/+ZTjf/lXZT/5Ham/+JlnP/gap7/32+h/95hlP/fOmv/5XGh/wAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7rvPeO+5z//wqMb/8K3K//Gkxf/ws87/8cDX//Gs - y//ysc3/8qLH//KtzP/yr87/8rTS//Cnx//yq83/8a3N//Gy0f/ysND/8Ju///Gav//xp8j/8Yy1//Kp - yP/xrMr/75K1//K71f/whq//8rPO//K71P/yss//863M//OLtP/we6n/87jT//O0z//ukLf/8ajJ//Kh - xP/zq8z/86/O//Ovzv/yqsv/8qzM//KexP/xncP/8aDG//Clxf/ursr/7qfF/+6kxP/up8f/7bDM/++a - v//wqcn/76XF/++pyP/xutb/8bTR/++cwf/wlr3/8bHO//G10f/xsM3/8a7N//CUuf/ysc3/8KHB//C+ - 1f/vsMz/7qjF//C81f/vudH/7qnF/+6xyv/uoLz/8LfQ//Cxy//vt9D/8L3U//Cvyf/vqcb/8LTO/++s - yP/vtM3/8cHW//K10P/xnsH/8a3M//K60//ypcf/8KvI//HC1//xts7/8rDL//GryP/vssv/65S3/+Rd - jv/mTof/51GI/+Y/dv/iZpf/22OQ/9dIef/kX5b/5mWZ/+V2o//jb6D/5HCh/+Zuof/nYZb/51SJ/+dz - pf/ld6f/5GSZ/+JckP/fOnX/32GS/99XiP/kaZv/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AADqtM2K7rTM//Cuyv/xqMf/8a3L//Gxzf/wsMz/8qjJ//KpyP/yr8//8qbI//K31P/yttP/8rjV//G0 - 0//ytdL/87fV//Klx//yqcz/8Z7D//O20v/yscz/8H6p//Kvzf/yvNb/8qfF//GNtf/yocL/87TQ//Gi - wf/yttD/86zK//Oxz//0vNb/9LPP/+6Zvv/vkbj/8Ze9//GszP/ynsT/8qvL//K00f/yqcv/8qrL//Gm - yv/xmMD/8ZnB/++pyP/wp8f/77HM/+6iw//uq8n/7q7L/++ewf/xr83/7qbG//G00f/xuNP/8KfG//G9 - 1v/xstD/8KjJ//Ktzv/xpcf/8r/Y//Kxzv/yrcv/8KXC//G50v/vrcf/8LzU/++1zv/uqsX/8MDX/+6g - vP/xpMT/8KjF//G2z//uqcX/8LbQ//CyzP/xutL/8bTP//G90//uosD/8bjR//K1z//zvtT/867L//Ko - x//wv9P/8b/V//K50f/yp8j/8KvI/+2oxP/mh67/4mOV/+ZakP/nUIf/5UuB/9xMev/SVX7/4FSF/+l1 - pf/ndaX/43il/+V2o//maZr/5nmo/+hBfv/obJ//5n2r/+V2pv/ldaX/43Oj/+FMf//eXo//3lmL/+Nk - lv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6cHTBeqxzOTrpcb/8LfP//CzzP/wtM//8arI//Gz - z//xp8j/8bLO//Gkx//yn8T/86nL//Kjx//yrs7/8qPH//K00v/yp8n/8qLI//COuP/ylbv/87LP//Kn - x//ypMX/8Ymy//O20v/xmLz/8qXF//Kty//0vtf/8r7W//TG3P/0sc7/9bXS//W81//1vNX/7qTF/+52 - pv/vnMD/76rJ//Cxzv/xrs3/8qjJ//Oqyv/zpMf/8qPI//Gdw//ylsD/8pnC//Cxzf/wrsv/8KbH/++s - yf/vsc7/7qTF/++kx//vr8z/8LHO//Cqyv/xpsf/8afK//Cyz//xtdL/8rvX/++ox//yu9X/8rnT//Kt - y//xq8n/8LDK/++1z//wwNb/8LjR//C20P/xvdX/8b/W//Clwf/vscv/8LXO//C60//ytM//8aTE//Gr - yP/wm7//8LLN//K/1f/xsM3/8rfQ//Osy//zosT/8qrK//HD1v/ysM3/8rTN//K5z//vqMX/6pe4/+Jt - nf/ibJz/5V+R/+k1cP/jSnz/1Tli/9hUfv/obaD/7H6s/+iKtP/mhq7/54ez/+R3o//lhK7/52CR/+dw - n//me6j/5m+e/+Z9qf/lgK3/4mSU/9o9bv/fbpj/4VaK/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF9Q - VwDqt84+6qnH/+qjxP/rn8H/8LTN//Gyzf/wttD/8bPO//Kwz//xs8//8bLQ//O21P/yrc3/8rDP//Ky - 0f/yq8z/8rTS//Gawf/yp8n/8Z7D//Opyf/ztdH/8q3L//O41P/zsc//87TR//KtzP/zvtf/8p/B//Ou - zf/ztM7/9cne//S20v/1yd7/9sHb//a+2P/wo8X/8KfJ/+6ewf/vn8L/8KbH//Chw//xoMP/8qbH//OV - vf/zlsD/8qDF//Gawv/xmMH/8afK//GvzP/wrMn/763L//G81v/vsc3/76/M//Cvzf/xstL/8LHP//Cp - yf/xp8f/8rjT//G51P/zwNr/873Y//Kxz//zxNz/88DY//O91v/xq8j/8bvU//G+1f/vscr/8LfQ//Gx - zP/ytND/8K7I//HB1v/xwtj/8cLY//Kqx//xqcj/8bvT//C3zv/xs87/8a/K//G60v/yudH/8qXG//G0 - zf/xu9H/8rjS//K60//yuM//8LzQ/+2nxP/kd6L/4XCf/+JyoP/nUob/50h+/+Fgjv/YYIr/3kx9/+tc - k//sdab/6oix/+Zomv/leqf/5IKu/+N5pv/mgaz/5omy/+R6pv/mcJ3/5meX/+RbkP/keaX/3WWR/91o - kv/gTH//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOquyn3rqcj/66TF/+mRuf/rqcX/8LnQ//Gr - yf/xtM7/8bDP//Kry//xtdH/8K3N//Gcw//ypsj/8rPR//Krzf/yt9X/8rTS//KjyP/yqcz/8qvK//Kv - zf/zvdb/86XG//Knxv/yqMn/87rU//CRt//zv9j/87jT//O00P/0x93/9MXc//XI3v/2yd//9sXd//Kt - zP/yuNT/8KXH//CuzP/vlLn/75u+//CnyP/yqMn/8p3C//GYwP/xn8T/8Z/F//Glyf/ymsH/8qTJ//Gl - xP/xr8z/8a/M//Gx0P/xutT/8brV//Cxz//xrs7/8bHR//CnyP/xocb/8rDO//S/2v/yttH/87DO//TK - 3//0x93/88Ta//Gsyv/ysc7/8r/W//HA1//xxdr/8bbP//GlwP/vkrj/8LnS//HB1//zt9D/87PN//Gt - yf/xutL/8rvU//HA1//xxtr/8rrS//Kwzf/xwNX/8cHV//LA1f/zttD/87XO//G0zf/vtMv/6YGn/+Vt - m//lZZb/5G2b/+dPgv/mXo//4WyZ/9VMdP/iN2v/7GSZ/+18qv/rfqv/6IGq/+aCrf/khrH/5HOh/+Zy - o//mZpj/5YOt/+R6pv/leqX/5mCR/+Nbi//db5v/3GGQ/+Fjkv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAA7LHMpOutyv/rnsL/6ZC3/+uixP/upMT/8bfP//Gsyv/xuNL/8bfS//Guzf/xutX/8rzW//K3 - 0//ys9L/8qjK//Oz0//yttP/87PQ//Kpyf/ystD/88HZ//O+1//yp8f/9MHa//K00f/yttL/877X//Sz - 0P/0qMj/9KfI//S20f/1yN7/9cPa//fP4//3yd//8rnT//Gfw//xo8T/8avL//Gmxv/vss//7pu+//CK - tP/xiLP/8Z/D//Gcw//yn8T/8aXJ//Klx//znMP/85zC//GpyP/wr8z/8bTQ//Gxzv/yttL/8q3L//Cv - zv/ys9H/8q3O//K41f/zp8r/87bT//OmyP/0r83/867L//XH3f/0x9z/87rU//Ovy//yqMf/8r/X//O9 - 1//yr8z/8KTC//LC2v/wv9b/8cLY//Kuyv/xr8v/8bLO//K50//yxNn/87jR//Oty//zvdX/8rXP//G/ - 1P/xu9H/8cPV//HE1v/xv9L/77bN/+qQtP/oc6H/6G+e/+hqmv/oZZj/52WX/+dnmf/gU4T/2laD/+E1 - a//sTYj/7nyr/+x+rP/oirL/5oSu/+aCrv/ng63/52mZ/+d3o//kha//44iw/+N+qf/jQnb/3jlo/9tf - iv/cZI7/4W6c/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADssMvA7KjH/+uav//og63/54qw/+2b - v//upsX/8bzT//K50v/xtdD/8azM//G10f/ytdL/8rTR//Orzf/zsM//87LR//O72P/zqcz/85nB//XD - 2//0ttL/9LjT//Oew//ztdL/863N//K61P/yuNP/8qLE//S/2P/zosX/863N//S81v/0sM7/9bzV//XG - 3P/xttD/8bHN//Ggw//xt9L/8KHE//Ckxf/wnb//8rPR//Cix//wocb/8JW9//Gcwv/ypsn/8qPH//Kg - xf/zlb3/8qHF//Gtyv/wp8j/8KbI//Gy0P/xss//8Za+//K10//yu9X/87HQ//OrzP/zrM3/9LzX//Oq - yf/znMH/9Mfd//PA1//zyd7/8r/X//K91f/yvtf/8qvJ//Osy//ywdj/88je//LA1//xwtj/8cHW//LB - 1//yt9D/877V//O10P/zjbn/86DE//Oyzv/zvNP/87jQ//LB1v/ywtX/8sDU//G80P/ujrP/63Wl/+t0 - pf/rbJ7/6nSl/+p0pv/rap3/6GSX/+FXhv/dZJH/4TRq/+tGhP/uhbH/7Xyq/+iRtv/mfqr/53Oh/+d6 - p//oeqj/53Ke/+V6pv/ihK3/44Ot/+J+p//ea5T/2WKH/99znf/keKb/AAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAOyxy9HtqMf/7KDD/+d7qP/njrP/64Ww/+2Xvf/unMD/8rbP//K0z//xudP/8rLP//O5 - 1f/zt9P/87fU//Smyf/0qcr/867P//Oqzf/0qcr/9KXH//W81v/0p8j/9LTR//O+2P/yncL/86zM//O4 - 0//yttL/8r7X//Gryv/yt9P/8rHP//Oz0P/yr83/8rTQ//CdwP/wq8n/8a7M//Czz//xqcn/8bHN//Gk - xf/yqcr/8arL//Gcwf/vncL/8ZK9//KVvv/ynMT/86XL//Kkx//znML/85fA/++kxf/wocT/8KLE//Gp - yf/xrMz/8rDO//K41f/xp8r/86jK//Kjx//yu9b/87DP//S81v/1yN7/9cTa//S/2P/0w9r/87/Y//O3 - 0v/yvtb/8sDY//LC2f/zvdX/87LP//O+1v/yvNT/87vU//Gty//ywNb/87LP//Oxz//ztND/87zT//K1 - z//zuND/87nP//LF1v/xuc//8I22/+6Otv/shrH/7Hyq/+1wo//uZZn/7WKY/+xJhv/oUon/4E18/91i - jf/fQHD/6kJ//+5onf/ub6H/6Iy0/+iUuv/ogqv/532q/+d5pf/mi7P/5G2d/+N3o//heqT/3GmU/9hZ - hP/bcZn/44ew/+Rqnv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7LPM1O2qyP/sk7z/6I63/+aQ - tv/rpsX/65u//+2cwP/tnb//8bHM//K50v/yutT/87XS//O41P/zsdD/86/R//OozP/ztdL/87jU//Su - zf/1xdv/9b3X//Sxz//0psj/9LzX//Onyv/0o8b/8p7C//O41P/yt9P/8rfT//K30//zrMz/87PR//Kn - yv/xss//8KXG//GuzP/xocT/8bXQ//CvzP/xt9L/8rXQ//O30//xr83/8bTR//Cewv/wo8b/8Y24//Gd - w//xm8L/8p/F//Kcw//zkbz/8pS+//Ctyv/wqMn/8LHO//CvzP/xqcr/8a7N//GrzP/ypsj/8qzM//K4 - 0//yrs3/86zM//Snyf/1vNb/9cTa//S61P/0yt//9KrK//O+1//ywtn/88jd//LA1//zwtj/88LZ//PC - 2P/zwtn/87zU//O71P/zss7/8sXZ//Szz//zudH/9LjQ//O+0//yvdL/87HN//Kew//wmL3/74y2/+6D - sP/uap3/7mie/+5roP/uXJf/7VWR/+pglv/jOmv/1zpi/9grVP/kLWb/7EqJ/+uCrf/ni7L/6IKs/+iB - rP/pdKL/6W+d/+V2ov/ic57/4nmk/91jkP/bbJn/1Ex1/9lUgf/kd6b/5lWK/wAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAADttM7Q7ajI/+2Vvf/oi7b/5oyz/+eVuv/qocL/7Jq9/+2cwf/ukrv/76HC//K0 - z//yu9T/8rfS//O30//zsM7/87fU//O41f/0stH/9LHO//a71v/1stD/9bjU//Sixv/zttL/87LQ//Oy - z//zutX/873X//K30//yutX/8qfJ//Opy//zrMz/8qrK//K00f/yrc7/86nL//K41P/xrcz/8bHP//C4 - 0v/xoML/8qXF//Kuzf/yxtz/8rzW//Gy0P/xoMP/8rfU//Cawf/wnsT/8azN//Kjyf/ynsX/8qDH//Kq - yv/xrsv/8avL//Gpyf/wss7/8KvM//Gqyv/xrMv/8anK//Kszf/zrs7/9LDO//Sz0f/1udX/9cTb//W8 - 1f/1uNT/88DZ//PF3P/0xdv/9L7X//PC2P/0wNf/873W//PE2v/zvNT/87/X//O40v/zxNn/9LjR//PA - 1f/zvtP/873U//Sqy//0oMT/86HF//Kfwv/wkrr/73Ok/+9zpf/vbKH/72Kb/+9dl//uXZf/7FaR/+U7 - cv/cP2z/1Ddc/90/bP/oRHz/6ZS3/+eDrP/odaL/52yf/+dOg//nX5D/4mmY/+Ftm//fX4//2U+B/9tm - l//aYY//3lqM/+Rgkv/mXZL/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO20zbvuqsj/7p7C/+qM - t//leaX/4Xij/+eUuP/rkbT/7Yax/+6Otv/tjLP/7Ju//+6lxf/ysMz/87HO//Kxz//yqsz/86zM//Ot - zf/0qMv/9K7O//Wdxv/1udT/9L7Y//S81f/zwNn/873X//O30v/zvdf/8rvV//O40//ywdn/87fR//O+ - 1//0vtf/87/X//Suz//0psr/9LjU//Opy//ytdL/8bnT//Gxzf/ys8//8bfR//PG3P/zxdr/8bzV//K6 - 1P/ypsf/8rLP//O51f/xo8f/8aHI//GdxP/yncT/8p/F//Gbwf/xq8r/8bLO//Cyzv/wsM3/8K3M//Gr - yv/xrcv/8bbS//Kxzv/zqsv/87LQ//Oxzv/1vdb/9cfd//TH3f/0x9z/9cjd//TB2P/0xtv/9MTb//W9 - 1//0vNX/88PZ//TD2f/0wNf/9MTZ//TD2P/1wNf/9bPN//Soyf/0qsr/9KjJ//Sdxf/zpcf/85/E//KP - uv/xgK//8HSm//Bwo//waJ//8FiW/+9Skf/uS4r/6kmF/+I0aP/dVoL/10Rr/+R4oP/mZJL/5maV/+ZI - fP/kdqT/5HCf/+M1bP/haJn/3mqe/9tWjP/YTIL/21GI/91XiP/kW5L/5VaQ/+dAff8AAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAA7bTNle2kxf/uocT/7J3B/+eArP/ljLX/4n+q/+aGrf/pd6T/7Iuy/+qP - tP/ogKr/5Ymu/+J7oP/spcP/8rDO//Kvzf/zrc3/863N//Onyv/zq8z/9K7N//S51f/1wtr/9bPR//TE - 2v/zxtz/8sHY//LF2//zwtr/8sXb//TH3P/1v9f/9cPa//W61f/0sdD/9KbJ//Soy//0qsz/9K3O//O8 - 1//ztdH/8qrK//CqyP/xrMn/88fd//TG2//zudP/9c3h//PC2P/ztdH/87jT//S81f/zsM3/8qXJ//Gj - yP/wpMn/8KjL//KZwv/xosf/8rrU//K91f/wt9H/8b3W//G30f/xuNL/8bXR//Oryv/0qsv/87jS//S0 - 0P/1wtn/9cLa//XN4P/1zuD/9cbb//TO4P/1yN3/9cTa//XF2v/1wNf/9cXa//XC2P/0vNX/9LvU//Oo - x//0pMX/867L//Gcvv/ys8//8qXG//Gtyv/xo8T/8Jm9//GKtf/yf63/8Xmo//Fnn//wX5r/8FWU/+9R - kf/tVJD/6VWL/+Rik//ZWIL/22WO/9k9Z//eV4X/31iK/91EeP/fZ5n/3EV6/9lRhv/WQ3b/0jpp/9dE - dv/eU4b/4T53/+ZXj//mWZL/5lqO/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADtuM9l767K/+6n - xv/toMP/6pK5/+iPuP/jdKL/4nOd/99bi//eWob/4W+Y/+SLsv/jgqz/4X2o/99nlP/pjLT/75y///Gs - yf/ytdD/867O//Oqy//0rMz/9KzM//Sy0P/1s9D/9rvV//a91//2xdv/9s3f//fJ3v/3zN//98fd//e+ - 1//1uNT/9LDP//OtzP/0osf/9KnL//SkyP/0psn/9LHQ//Sy0P/0uNT/8rjT//LH3P/0zeH/87rT//S/ - 1//1xNv/9LzW//TJ3v/0yN3/9Mbb//Oxzf/zsc7/86vM//Goy//zuNT/9LDQ//Ohxf/zr83/9crf//S9 - 1f/0xdr/88DX//LA1v/yutP/87jS//Syzv/1ttD/9bvU//bH3P/20eH/9tXl//bR4v/11OT/9dXk//TO - 3//1zN7/9cXa//S81f/0ttL/86vK//O60//zutL/8pS7//Omxv/xocH/8LHN/++Zvf/wpMX/8LHN/++n - xv/uoML/7pu+//KMtf/yd6n/8XGl//Fsov/wXZn/712a/+9Zlf/tW5X/6G6g/+Flkf/bV4T/2kh7/9My - ZP/XRXv/10h9/9dCe//WQXn/2EuD/9tNhP/ZP3P/4FeN/+NOiP/mWY7/50V+/+Zqnf/laZ3/AAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAO2xyiburcn+7qnI/+6jxf/sncD/7Ju//+d1o//mf6j/5o20/99n - k//kfaf/5YSt/+eLs//niLH/6Y61/+uLtf/tkLn/73qq//CEsP/xe6n/8pS6//OgxP/zrs3/9LDN//Sr - y//1rs3/9qrL//asy//0tM//9K3L//Sexf/1lsP/9ZPB//WrzP/zuNP/87TR//Okxv/0qcn/9LDO//Sx - z//0rMz/87HP//O10f/xsc//76nI//K/1//zw9j/9Mjc//O40f/0utT/9Mjd//TF2//0yN3/9Mfb//XO - 4f/0yt7/9Mbb//S+1f/0u9T/9bfU//S40//1xNr/9LnT//Svzf/0ttH/8pi8//TE2v/yscz/9Mba//XO - 4P/0wtf/9cfb//TK3f/1yt7/9Mjc//TF2f/0xNr/9L/X//TC2v/0wdj/87LO//OvzP/znMD/8pe9//Kk - xP/ynsL/8aDE//Ckxf/vq8r/8KPF//Gwzf/ym8L/8a7M//Kjxf/xnMH/8Ze9//J6rP/yd6n/8XCk//Fm - n//waKD/8Gig/+91qf/sY5n/6GGT/+Rck//bOXP/3EaC/9xRi//TKl//0CVV/9c7cf/dWY//30+H/94n - Yf/mTo3/5zZ0/+dnmf/nXJL/5UuD/+h6pf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA88HSAe+0 - ztPupMX/757C/+6ewv/ulLz/7Yq4/+uJsv/qjbX/6Ymx/+mIsP/pf6n/7Ji9/+yKtf/ui7f/7X6u/++C - sP/wear/8Ia0//CJuP/zcqn/832y//SEtf/0jLn/9JrE//WUwf/1jrz/9pTC//alyf/0rMv/8qTH//Oe - xf/1psn/9aHI//WgyP/zr87/86zK//Glx//yqcr/8abH//Gwzf/ylbz/8Z3A/++Yvv/xttH/9MLZ//TG - 2//zw9n/9Mve//TH3P/1zeD/9c3g//XM3v/1yt//9Mve//S+1v/0wdj/9MLZ//XL4P/0wNj/86XG//XJ - 3v/0xdv/9MLZ//S71P/0xdr/9MXb//O+1//zy97/88fc//PF2//0xNv/8p7A//Oty//zwdn/8rHN//O+ - 1v/zrsz/9LLQ//OuzP/0w9r/8pzB//Oewf/zrc7/8q7N//Kryf/xn8P/8a3M//Kxz//yqsv/86TI//KZ - wP/zq8r/86bH//Ouy//zn8P/8n2w//J/rv/ydaf/8W2j//FooP/xc6n/8Im1/+1onf/rZZv/52KY/+M1 - cv/gQ3z/4EmE/946cP/gUIb/4VaO/+A3cv/kTIj/5jd3/+g4ef/oPXz/52md/+d6qP/ndKP/6X2p/wAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7rXNe++uy//wnMD/76TG//Cgxf/wkLv/74q1/+2F - sf/tp8f/7Iy1/+6WvP/ujLf/7oay/++Otf/umr7/8XGk//CFs//ylr7/8pjB//N+sf/0frP/9H2y//SL - uv/1jbz/9ZbC//aiyP/3qcv/963O//evzv/2ss748a3K4/Kixv/0qsv/9avM//Sexv/zosX/8rjR//K2 - 0f/ys9D/8Z3C//KTvP/zoMT/8rPQ//PA1//0xdr/9MTa//TF2//0z+H/9dDj//TJ3v/0wNf/9czf//XP - 4v/1y9//9cXb//bR4//1xNv/9c/h//XN4P/1xNr/9c3h//XI3P/0vtb/9L/X//XI3v/0rcz/9MDY//TD - 2//ytc//8rPO//S71v/0sM3/87rT//Kvy//yxdr/9MLa//S81v/zosX/87DO//Ggw//yrMz/86zM//Kc - wf/xqMn/8anI//Gtzf/ypsj/8qPG//Ory//yqMn/87TR//Opyv/0rcz/9KjK//Swzf/yoMP/8oCv//J6 - rP/xd6j/8Xmq//F/rv/umb//63yp/+tkmv/qWJH/6F6V/+Vblf/lUIr/5jdy/+Zkm//ma6L/5VGK/+Zu - of/nVo3/6F6T/+lyov/nZ5n/6FKJ/+mGrf/pbZz/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AADtw9Ua7rPM9fClxf/wocP/8Jm///Cdwv/vk7z/75zA/+6mxv/unsL/75G5/++awP/vlbr/75m9/++S - uv/xlLv/8Z7D//KqzP/0kLv/9JTC//WDtv/1grb/9ZC///WPvv/2nsX/96TI//eszP/3rc3/967M/vay - z2vww9UN8bPOfvKuzfP0qcv/9avM//Sfxv/zuNL/877W//O40//yvNX/8rHO//O20f/zwtn/88PZ//S8 - 1f/0wtf/9cvf//TD2f/1z+H/9MTa//S30f/1xNv/9cve//XM4P/2z+L/9cXb//XD2f/1xNr/9s7h//XG - 3P/1yd7/87PP//O50//0rsz/9LvV//Okxv/zqcn/87TQ//O50//zutX/87bS//Oewv/ysM3/8bDN//Gu - zf/xqsn/87HQ//Oawf/yr87/8qPG//Kgxf/ylL3/8abI//Gz0P/xt9P/8bTQ//Gsyv/yss//8rLP//Ou - zf/zsc7/9KrK//Ozzv/zs8//867N//Oxzv/ylLv/8oiz//KCr//xhLL/8Za9/+yQt//oeqf/6VSL/+pj - l//naJ3/5Wug/+dXkP/oTIn/5mWZ/+ZWjv/nTYb/6IKw/+dwoP/nXJD/6Gmb/+hsm//peKb/52WV/+mE - rP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADtvNGT7rbP/++ox//wn8L/8J3B//Gf - wv/woMT/76DD/++nx//vmr//76LD/++avv/wmsD/8anJ//KLtf/ypMn/9KvO//Wiyf/1jLv/9Yu7//WI - u//1jL//9pTA//aiyP/3qcv/963N//eszf/3utKe7NnNAAAAAAAAAAAA8b/UG/K20Jjzp8n19KnL//Sj - yP/zvNT/87vU//O91v/zuNP/87nS//O91f/zvtb/87rU//O50v/0xtr/9dDi//XP4f/0udP/9c/h//XC - 2f/0vtX/9tXl//XK3v/2zuH/9szf//bL3//2zuD/9cre//XI3f/zvdX/9MHZ//O20//zrs3/8qLF//Kj - xf/ypcf/8qTG//Knx//yo8b/8abH//CUuv/wn8P/8bXT//Gpy//yqMn/8GGZ//GNuf/xoMT/8ZnA//KW - vv/zpMj/8a7N//Kry//zrs3/9ZnD//SqzP/zs9D/9KbI//Wfx//0q8z/86/M//O30f/0rcz/87DN//On - x//yjbf/8oy2//KOuP/wlrz/6o+3/+iFr//pcJ//6W6f/+lsnv/ncaP/50eC/+l5qf/neqr/50+F/+hT - if/pbqD/6WWX/+h+q//odqP/65e8/+qKr//tp8b/65G1/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAoIWQAO7E1Rntuc/r76/L/++wzP/woML/8Z/C//Cdwf/xnMH/8KfH//Ccv//ypMb/8KfJ//Gm - yP/zosf/86DF//Ov0P/0rdD/9bLT//Wky//2j7//9Ym7//aTwf/2msT/96jK//etzf/3rs7/97fRwfe0 - 0Ql9aXEAAAAAAAAAAACOe4MAAAAAAPG60iDzss6O86bI8fSqzP/0xNr/9MDX//S91f/zuNH/88bb//PD - 2f/zutP/9MXa//XK3v/1yd3/9cnd//XP4P/1zd//9dLi//XL3f/1z+D/9dDh//XO4f/2z+L/9cLZ//bV - 5f/21eX/9MLY//KwzP/zutX/8Zu///KszP/wiLb/8aLG//Guzf/wiLX/8ZC7//GLuf/xmcH/8rDP//Kf - wv/yr8//8qTH//GQu//xqsv/8aHH//GfxP/xrcz/8qDE//KuzP/xss//8bTP//Osy//zqsv/86fI//Oq - yf/zss7/863N//Oty//ztdD/87LO//Owzf/zss//8rLP//Kjw//ylLv/8Za///CNtP/qjLP/6YGt/+p/ - rP/paJv/6VyT/+mGsv/pgK3/6G+i/+hZj//pgq7/53un/+yYvf/qbJr/6X+r/+ykxP/qhK3/7Ja3/+2l - w//tob//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO++0l/wr8v+77LN//Ct - yv/xp8n/8K3N//Ggwv/xsM7/86DF//OZwf/yr9D/87DR//Wfxf/0qMr/9a/R//Wx0v/2sNL/9qbN//WV - wv/2lsP/9pjD//ekyf/3qMv/96vN//exz8z2uNEUrIuVAAAAAAAAAAAAAAAAAAAAAAAAAAAAqpCZAAAA - AADxuc8b8rDLg/Kwy+3zw9j/9MTZ//TC2P/0xdv/88fb//PD2v/0xNr/9cre//XG2v/1ydz/9tXl//bP - 4P/21+b/9tXl//XM3//2z+L/9tLi//bY5//20+P/9dDi//S51P/zpcj/87PR//KexP/xmcH/8ZrB//Gc - wv/xoMT/75O6/++ewv/wpMf/75G6/+6av//vfq7/8JK8//CBsv/wiLT/8Z/E//CUvP/wncL/8ajI//Cq - yf/xn8P/8azK//Gzzv/xudP/8rvU//Kyzf/zvNT/8rHN//O20P/zttD/87HP//Szz//zsc7/9K3N//Wr - zP/0t9H/9LjQ//OcwP/ymcD/75/B/+yZvf/rirP/6n6r/+mMtf/pfqr/64+4/+pglf/rgq3/6m+f/+uK - s//pjrb/7Zu+/+tjlP/tn8H/7Ju8/+yMsv/wt9H/75q8//CvzP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAArIiYA7qu3AfG60Y7xt9D/8LnT//Koyv/yrc3/8rDP//Oszf/0msL/9afJ//Wy - 0f/0ttX/9bLS//Wx0v/2u9f/9rPS//a01P/2pMv/9pjE//aex//3osj/96XK//epy//3ttHL9r3VFgAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8bXNHvC1zajyudL988TZ//TG - 2v/0xdn/9MXa//TH2//0yNv/9MXZ//XI3P/20OH/9tbm//bU4//21+b/9tXk//bR4v/21uX/9tPj//bV - 5f/1wdj/9MDZ//KWvf/xnML/8JS9//GPvP/wdKn/8KXI/++Uvf/wqcr/8LTR/++kx//wsM//8LDO//Gm - x//ym77/8ZzC//Gz0P/wqsr/8KzL//Gxzv/xpMb/8LXQ//G50v/0psn/9K/O//K+1v/zudL/87rT//O2 - 0f/yutL/87bQ//Oxzv/zs87/87PP//O40f/0uNL/9LXQ//O00P/0r87/867N//Khxf/wrMr/7aLC/+6X - u//tnL//65zA/+yZvf/tocT/7G6d/+2Gs//tmr7/7JC3/++nyP/vqcb/7pu8/+2hwf/uq8j/8bHO//Gt - yP/yt9D/877U/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA88fWA/K6 - 0pnzutT/87jU//Sszf/0tNL/9bHR//Wny//1stL/9a/Q//W21f/2u9j/9q/R//a10v/2s9P/9q7Q//am - y//2nMb/96LK//eky//3qMz997LQnvfJ2g28macAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAABKJjgAAAAAAPC1zzHwt9Cm8bXQ9PG50v/yuNH/9MXa//TI2//0yt7/9Mjb//TG - 2v/1zd//9c/h//bV5P/21OT/9tLi//bX5f/20+P/9s/h//TH3P/zvtf/8rfT//K31P/xqcr/8KnM//Ck - x//wmsD/76LH/++pyv/vm7//8LTR//Cwzf/wqsn/8K/N//GQuv/xu9T/8a3M//Kryv/yqsr/8rTQ//Og - xf/zn8X/85zE//OuzP/zs9D/9LfS//Suzv/0ss//87bQ//O00P/zrsz/87nS//O+1f/0vtb/9KbJ//Sh - x//0rM3/9JzF//OWwP/zpsr/86HF//Gxzf/wttD/7qDB/++qyf/vrMr/7aDC/+2LtP/ue6b/8KXH/++j - xP/wpcX/8bbR/++LsP/wjbX/8KDC//O/2f/zwtj/873V//S91f/ztM//AAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9crZAvS60370ttH59bLQ//W41P/1stH/9rLS//as - zP/1qcz/9rTT//a61//2uNX/97TS//e21P/3rc7/96rN//eoy//3qMz/96jM4Pez0FXyw8EBw5yrAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE049AAAA - AADwuM8a8LnRbfG10MXxttD38rfS//K20v/zsM//9LvU//S/1f/0w9j/9cvd//XL3v/2z+D/9c3f//bU - 5f/1zeD/9MTa//Soy//ystD/8LDO//CmyP/wnML/8ajJ//Cnyv/vqcr/8LbS/++pyv/umb3/8LrU//C1 - z//xrsv/8LLO//Gxzv/xqcj/8bDN//KoyP/xpcf/8pK+//Sfxv/0n8f/9KnL//OlyP/zr83/863N//O3 - 0f/zttD/9L/V//TJ3f/1tdL/9cPb//Sszf/0stH/9IK1//OPvf/zibj/8oWz//Kpy//zmsP/863M//HA - 1v/yutT/8bzU/++fwf/vqsn/8K7N//Gxzf/xr83/8rnU//Kxzv/ysc//8aDB//XF3f/0yN3/9Mje//S9 - 1f/1y9//9cfc//XH3P8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAB6Zm8AAAAAAPS2zz30vdTO9bjT//a10v/2udX/9rDP//a41f/3vtn/97HR//e+2f/3vNf/97nV//e0 - 0//3s9L/97HP5ve00Hr2s8wOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFZHSwAAAAAAAAAAAPG40B3yutJh8bnRqfG6 - 0uXyt9H/87fR//O40v/0t9H/9LjS//S50v/0vtX/9b/X//TA2P/zrM7/85zF//Kgxv/xr83/76XG//Ce - xP/ylsD/8JG8//CexP/vpsj/8LLP//CnyP/vqMr/8KrK//GdxP/wrMv/8aXH//Gfw//woMT/8JS///OT - wP/zncT/85nC//Kkx//zqMn/86zL//Ozz//zudP/9MXa//XN4P/0xNv/9c3i//Omyf/0p8r/9LvX//Sx - 0f/0rc3/8p/F//S61v/zoMX/87bT//Ogxv/zrsz/87bR//TG2v/0xNn/9MXa//O/1//0y9//8rPQ//TE - 2//0x93/9Mfc//O/1v/1y+D/9b3X//XF2v/20OL/9c7h//bK3f/1wNb/9tXl/wAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPS90gb1yNtQ9cLYrva/ - 1/T2vdb/9sDZ//e61f/3rs//97vW//fC2v/3wNj298Taufa/1mT1wNYPAAAAAFkAIgAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAASDtBAAAAAAAAAAAA8cTXCPHB1ibyvdNd8rrTkPK807/zvNPn8rfR/PO9 - 1P/zv9X/9LzV//S91//0w9r/8qXJ//Gyz//wrsv/77HN/++dwP/xqMn/8a/M//Cryf/wq8r/8afI//Cp - yf/xqMj/8pO+//Ghxv/wnsT/8J3E//Ghxf/yosX/86HG//Okx//0qcr/9bfT//Wy0P/1xNv/9cDZ//XF - 3P/0v9j/87jU//TI3v/0wtv/9L7Y//S81//0psn/9JvE//Sfxf/0uNX/9LbU//SmyP/0wNn/8rnT//PC - 2v/0uNT/9LnU//TD2v/1y93/9Mre//bO4P/1zuH/9tDi//TL3//1y9//9cne//bN4P/1xNv/99fn//bM - 4P/32uj/9s3f//fU5P/32Ob///4AAH/AAAA/////////+P/+AAAeAAAAB/////////D//AAAAAAAAAD/ - ///////g//4AAAAAAAAAP///////wP/+AAAAAAAAAA///////4D//gAAAAAAAAAD//////+A//8AAAAA - AAAAAP//////AP//AAAAAAAAAAB//////gD//wAAAAAAAAAAH/////wA//+AAAAAAAAAAA/////4AP// - gAAAAAAAAAAD////8AD//4AAAAAAAAAAAf///+AA//+AAAAAAAAAAAAAAAAAAP//gAAAAAAAAAAAAAAA - AAD//4AAAAAAAAAAAAAAAAAA//+AAAAAAAAAAAAAAAAAAP//gAAAAAAAAAAAAAAAAAD//4AAAAAAAAAA - AAAAAAAA//+AAAAAAAAAAAAAAAAAAP//gAAAAAAAAAAAAAAAAAD//4AAAAAAAAAAAAAAAAAA///AAAAA - AAAAAAAAAAAAAP//wAAAAAAAAAAAAAAAAAD//8AAAAAAAAAAAAAAAAAA//+AAAAAAAAAAAAAAAAAAP// - gAAAAAAAAAAAAAAAAAD//4AAAAAAAAAAAAAAAAAA//8AAAAAAAAAAAAAAAAAAP//AAAAAAAAAAAAAAAA - AAD//wAAAAAAAAAAAAAAAAAA//8AAAAAAAAAAAAAAAAAAP//AAAAAAAAAAAAAAAAAAD//gAAAAAAAAAA - AAAAAAAA//4AAAAAAAAAAAAAAAAAAP/+AAAAAAAAAAAAAAAAAAD//gAAAAAAAAAAAAAAAAAA//wAAAAA - AAAAAAAAAAAAAP/8AAAAAAAAAAAAAAAAAAD//AAAAAAAAAAAAAAAAAAA//wAAAAAAAAAAAAAAAAAAP/8 - AAAAAAAAAAAAAAAAAAD8eAAAAAAAAAAAAAAAAAAA/HgAAAAAAAAAAAAAAAAAAPgAAAAAAAAAAAAAAAAA - AAD4AAAAAAAAAAAAAAAAAAAA8AAAAAAAAAAAAAAAAAAAAOAAAAAAAAAAAAAAAAAAAADgAAAAAAAAAAAA - AAAAAAAAwAAAAAAAAAAAAAAAAAAAAMAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAA - AAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAA - AAAAAAAAAAAAAMAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAA4AAAAAAAAAAAAAAAAAAAAOAA - AAAAAAAAAAAAAAAAAADwAAAAAAAAAAAAAAAAAAAA8AAAAAAAAAAAAAAAAAAAAPgAAAAAAAAAAAAAAAAA - AAD8AAAAAAAAAAAAAAAAAAAA+AAAAAAAAAAAAAAAAAAAAPgAAAAAAAAAAAAAAAAAAAD4AAAAAAAAAAAA - AAAAAAAA8AAAAAAAAAAAAAAAAAAAAPAAAAAAAAAAAAAAAAAAAADwAAAAAAAAAAAAAAAAAAAA8AAAAAAA - AAAAAAAAAAAAAPAAAAAAAAAAAAAAAAAAAADwAAAAAAAAAAAAAAAAAAAA/AAAAAAAAAAAAAAAAAAAAPwA - AAAAAAAAAAAAAAAAAAD8AAAAAAAAAAAAAAAAAAAA/AAAAAAAAAAAAAAAAAAAAPwAAAAAAAAAAAAAAAAA - AAD4AAAAAAAAAAAAAAAAAAAA+AAAAAAAAAAAAAAAAAAAAPAAAAAAAAAAAAAAAAAAAADwAAAAAAAAAAAA - AAAAAAAA8AAAAAAAAAAAAAAAAAAAAPAAAAAAAAAAAAAAAAAAAADwAAAAAAAAAAAAAAAAAAAA8AAAAAAA - AAAAAAAAAAAAAPgAAAAAAAAAAAAAAAAAAAD4AAAAAAAAAAAAAAAAAAAA+AAAAAAAAAAAAAAAAAAAAPwA - AAAAAAAAAAAAAAAAAAD8AAAAAAAAAAAAAAAAAAAA/gAAAAAAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAA - AAD/AAAAAAAAAAAAAAAAAAAA/gAAAAAAAAAAAAAAAAAAAP4AAAAAAAAAAAAAAAAAAAD+AAAAAAAAAAAA - AAAAAAAA/gAAAAAAAAAAAAAAAAAAAP4AAAAAAAAAAAAAAAAAAAD+AAAAAAAAAAAAAAAAAAAA/gAAAAAA - AAAAAAAAAAAAAP4AAAAAAAAAAAAAAAAAAAD+AAAAAAAAAAAAAAAAAAAA/gAAAAAAAAAAAAAAAAAAAP4A - AAAAAAAAAAAAAAAAAAD+AAAAAAAAAAAAAAAAAAAA/gAAAAAAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAA - AAD/AAAAAAAAAAAAAAAAAAAA/4AAAAcAAAAAAAAAAAAAAP+AAAAHwAAAAAAAAAAAAAD/wAAAD/AAAAAA - AAAAAAAA/8AAAB/8AAAAAAAAAAAAAP/gAAA//wAAAAAAAAAAAAD/8AAAf//AAAAAAAAAAAAA//wAAf// - +AAAAAAAAAAAAP/+AAf///8AAAAAAAAAAAA= - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + PD Loader is intended for educational purposes only; not for piracy. +Users should possess a legally-obtained dump of the game to use this software. +Please check your local laws/regulataions to verify the legality of tampering +with and dumping data from protected arcade machine hardware. + +Project Contributors: +***REMOVED***, Brolijah, crash5b, ona, korenkonder, Kyberal, lybxlpsv, nastys, +Nezarn, samyuu, Skyth, somewhatlurker, Stewie1.0, SwigS-27, zsccat + + +PD Loader and the included plugins are distributed under MIT License: + + Copyright (c) Project DIVA Modding 2nd Community + Copyright (c) samyuu (nop) (original TLAC code) + Copyright (c) ThirteenAG (original Ultimate ASI Loader code) + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + +Microsoft Detours, utilized by many plugins, is licensed under MIT License: + + # Copyright (c) Microsoft Corporation + + All rights reserved. + + # MIT License + + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is furnished to do + so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + +Launcher, Patches, Render and TLAC plugins utilize files from FreeGLUT: + + Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies or substantial portions of the Software. + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Pawel W. Olszta shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Pawel W. Olszta. + + +Launcher uses SimpleIni, licensed under MIT License: + + The MIT License (MIT) + + Copyright (c) 2006-2013 Brodie Thiesfield + + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + the Software, and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +DivaSound uses miniaudio (public domain or MIT-0) and BASSASIO (free for +non-commercial use only) + + +AMD compatibilty pack dependencies have additional licenses, detailed in the AMD + + + + + iVBORw0KGgoAAAANSUhEUgAAACoAAAApCAYAAABDV7v1AAAABGdBTUEAALGPC/xhBQAAA7hJREFUWEft + mEtME0EYgIshUY/GqwcPevbsjYMXb95MPHnTKAUWEVADNQLdFnlUUHkEA4IKmMhD8BEf1IiCUQERIt3t + g7ZIodBCS+mDbbu/MyUtLaVAYbYa7CSTbbrT///+50xHJEqOpAeiPXBeMnkgvZg5S0nZIopmS4WYmVKG + zqA1YrFEfWRHMaCoqYOUjOnIlrOQiEnJWO1FyeTRuGEzSibECNCfCMigjiwZMywWq/fHBYvC7EgkZEiX + jDmxbdC0NGXqX4FEaZYlVZ9MgpL0/v/t0bxyNZQ36qGiSQ/5Fatt7EopCzm3Vz/nlrGgaNZDTasRbt7T + bKvNEfdo9SMDDI3boLlrGrrem+HT0AL80i6DweQG44w78Bz+ZYd3AxZo6zXBGLsEfV+scL1SvSkwUdCW + bhPMWz0wxtiB4/yw1fD5eFDpsBEuZIwjcaAagxM8K1sDrjfA7+eB53moQtGIVYDEPFpcq93KgVu+ty1x + gVzeCJYY6CgK924H5/WDvGFSONBrqBDWhxyH0uH0wtKyF3Bow4fT7QW7wwsYDK8LDvy558OccKCKZgN4 + kdJwhaMqOxTX6qCwWgMfvy+E3lltHJQ1TsINhRraXs1G/A4v6kddQrDQ9yrnozwjrVsLYf3T3yHQps7p + EIjkrhYW7FyEt3EXEAz0zWdLhDIcQtyqggofPFsDHRxZDH1/674OnC5vxG9XOJ9woP1hocVaMSjOv+6+ + OXjyYgZWVnwRaTEwssg3dU3zZos7IhLBRXnl0ZVPpOoHR20hEA+CMpndUQUUqyO4PL5Aw8fNPzgKqqK3 + VSKgr/vXctSPvPmTtUPLcxNoDMsxgXGXGPyxCK1oG11a5kKetSxycBWdBdbnKRHQXBQq5dcFsDlWFeJp + tnhA8VAPhahgatunoP3lDHS8nYXHPSa402KEfHRwwbntcq+mhdfnB+2UE6paNt6diIAGrS+p00E3OohM + oH37GzqY4FPUZmfSyiYDaI1OwAVW02YMtCzBt1CSh2TB2pPQkFg+0dALCbw3QUUiyT50c+Em7TlKzvJI + rgM/iRQT/l9NSZkK0qCBHKRV9ehGpDMWbFyhx6Dn8g2H0N3T+GbW78QQSqZqTZMoU7Notm0j2XGDYtgL + RZrjSGBBtoxtREKbiUwZ04BlX5ZOHM6kVTVIJhdu8I5Aw65WUkQiIDhDklOyaEYWfhm3W9BtXwfFu/A0 + ur1DOZuDiswadx+NVxmJ9elS5gwlZ1z/rEfDjRTTzKlL9PgxEoYnZewZD/wB4r+Nvne+oTwAAAAASUVO + RK5CYII= + + + + + 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 + + + + 17, 17 + + + + iVBORw0KGgoAAAANSUhEUgAAAikAAAIrCAYAAAAqWwkVAAABgWlDQ1BJQ0MgcHJvZmlsZQAAKM+VkUso + RFEcxn8uIo0sjDyyuAusTAnJUkOkqGmMMli4944Zau413TuysVS2ysJj47WwsWZrYauU8ijZ2VkRG+n6 + n5mpmdQop07n13fO93XOd0A7TFu2V9UDtpN1o2NhfSY+q9e8oNFKE800G5aXmZwajVF2fN5RodbbkMri + f6M+sehZUKELD1kZNyu8IDywls0o3hUOWktGQvhMuNuVCwo/KN3M86viVI41lRl0Y9Fh4aCwniphs4St + JdcW7hfuSNiO5GszeU4oXldsp1etwj3VCwOLzvSU0mW2M8Y4k0TQMVllmTRZQrI6onhEZT9cxt+W80fE + ZYprGUscI6xgY+T8qD/43a2X7OvNJwXCUP3s+++dULMN31u+/3Xk+9/HUPkEl07Rv3IIgx+ibxW1jgNo + 2IDzq6Jm7sDFJrQ8ZgzXyEmVMrVkEt5O5Zvi0HgDdXP53gr7nNxDTLqauIa9fehKSfZ8mXfXlvb255lC + fz93xXKpDPMGbQAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB+UCGRUXHaHk4jAAAEcySURBVHhe + 7Z3vz2XXddct8Q/MC14ghOEFvAAJCfGCViABL1CFLKqiItWVkJAAVQipiFd2RYWgAygSwq6nbUjj0E4z + LmoDFlarUbFo62baOh7/mPGPmdhOHDlKMk3Gjh0nntjzw3bsy7Nmeh7fuc+99+xzzlp7r7XXZ6QrN33O + 3Weftb5rrc9de59z7litVnfwwQZoAA1YaeDGlWvH5PMnT371729+5P9vdV7GRdNoIL4GABQgDQ2gAVUN + CHicOX76hHx+/s57V6UfOV4gBnCJX1iAA3yopQHV5KQ1KcZB4GgglgYGMCkFkrHjBmBBB7F0gL/wl7YG + gBR+RaMBNDBbA9pwsg1epLuinfgYj2KKBmJoYHZywsExHIyf8JOFBmrAySawACto2ULLjOlbV0AKv6LR + ABqYpAGBhbHlGqu/s2fFd0Gh4OMfbQ1MSk7aJ2c8BI0GYmmgJaCsgw9dlVi6Ic7x11wNACn8ikYDaKBI + A1Pv1rHqpgArFLy5BY/vxdNOUXLCsfEci8/wmaYGPALKACvcCYTWNbXOWL70BKTwKxoNoIG9GvAMKHRV + fBUUCjz+0NYABYoChQbQwE4NRAEUYIXiqF0cGc+HpihQFCg0gAa2asDLJtk5e1tYAvJRYCj0+GGpBihQ + FCg0gAaOaCAyoNBVoTAuLYx834+GKFAUKDSABm7TQC+AAqz4KTQUfXwxVwMUKAoUGkADhxroEVCAFQrk + 3ALJ99prhwJFgUIDaOCmBnoHlAFWeBBc+8JD8ccHpRqgQFGg0AAaSAModFUojqXFkeN8aIUCRYFCA8k1 + kKWDsusuITorPooRUIAftmmAApW8QJEYcieG7IDCElBu/ZP//PsfSAFS0EBSDQAo9642uyt0VfwXLcAi + l48oUEkLFIGeK9A3/Q2gHAUU9qvkjglyok//AylAChpIpgEAZT+gsATks1gBETn9QoFKVqAI9JyBPvgd + QCkDFLoqueOEPOnH/0AKkIIGkmjgxpVrx+a8B4fv3AIb9qv4KVxARB5fUKCSFCiCOk9Qb/M1gDK9g7IN + zgCV3HFEHq3vfyAFSEEDnWsAQNEBFJaA6hcooACbU6A6L1AEee4gB1D0AQVYyR1T5NS6/gdSgBQ00KkG + ABRbQFm/C0hsTfGqW7ywdw57U6A6LVAEcI4A3udnNrzWgRRuWSbWyLd2GgBSgBQ00KEGzhw/fQJIqQsp + wIpdoQIC8tqWAtVhgSKg8wa0+B5AaQMnm3tVWALKHYfkYR3/AylAChroSAMASntAYWOtTnGiyGNH0QAF + qqMCRVDnDmoAxRegACu545F8rON/IAVIQQMdaABA8QsoA6yIj3gYnE7hAgDy2JEC1UGBImDzBOw2XwMo + /gGFrkruGCVHz/c/kAKkoIHAGuCFgbEABViZX6wo9DltR4EKXKAI2pxByxuN44LJ5m3hLAHljmFy+Lj/ + gRQgBQ0E1AAdlH5AhTcsjxcqinleG1GgAhYoAjZvwIrvAZS+AIUloNzxTD7f738gBUhBA4E0AKD0CyjA + CrACsBzVAAUqUIFCwLmTGICSA1B4vH7uOCfP3+5/IAVIQQMBNACg5AIUuiqACrBySwMUqAAFCrHmTlgA + Sl5AAVZyxz65H0gB0oA01xoAUAAUQAVQyQwrrhN0Zsdw7SQmAAVA2XyuCvtVyAvZagOQQicBDTjUAIAC + oOwCFDorgEomUKFAOSxQmQTItR5NuAAKgFICKHRVgJUM+RNIAVLQgCMN3Lhy7diUAsWxAA2wAqz0DCsU + KEcFqmehcW3jiRRAATg0oFM6ccTbeLxhoxg2AlKAFDTgQAMACoCiASh0VWIUXgCp3E8UKAcFCsGWC7ZH + WwEoAIomoLCxNnc+6S1HAilAChpoqAEABUCxAhRgBVjpAVgoUA0LVA8C4hqWJcIaBYpzAEKiAdmrIlBM + zC6LWexX135ACpCCBhpp4Mzx0ycACACitgbYWFu3yAI1y+xNgWpUoBDuMuFGtx+AApzUhpPN8wEruXNQ + lBwKpAApaKCyBgAUAKU1oKzfBcQSELDiGVgoUJULlGcxMDf7ZAWgACheAIWNtfbxTk5dbmMgBUhBA5U0 + AKAAKB4BBVhZXkiBETsbUqAqFShEbCfiCLblfTwAindAGeYnMM1+ldz5ylNOBVKAFDRgrAEABUCJAih0 + VYATT4Aic6FAGRcobw5nPnWTEIACoEQEFGClbp4gL++2N5ACpKABIw0AKABKdEBhCQhYaQ1QFCijAtXa + sZy/bXIBUACUXgCFrkrbXJI9lwMpQAoaUNYAgAKg9AgowAqw0gKYKFDKBaqFEzmnn+QBoAAovQMKsOIn + 32TI/UAKkIIGlDQAoAAomQBl/am1GYol19gGzihQSgUKAbcRsBe7AygASkZAoauSO+/VyL9ACpCCBhZq + AEABULIDCrACrFgBCwVqYYGycgzjxgh6AAVAAVCOaoAn1sbIXxHqDJACpKCBmRoAUAAUAGW/BoAVYGUp + CFGgZhaopYbn+7GDV15vT4ECUtBAmQaAldj5rmW9AlKAFDQwUQMASllhooBjJ/aqACdLAYcCNbFALTU4 + 348dtAAKhRf4WqYBuiqxc2DtGgakAClooFADAMqy4kRxx350VgCUqZBDgSosUFMNy/F9BSOAQoEFsvQ1 + QFelrzxpUfeAFCAFDRRogAKlX6CwKTblqbVAyhjYUKAKCtSYEfl734F25vjpExRUCioasNcAnZW+c+mc + WgmkACloYI8GABT7wkTxx8abe1VkeXVOQeM7/UEOBQpIQQM7NACgUDwBqHYaoKvSH3DMgUgKFJCCBrZo + AEBpV5wAA2zPXUAAygA0FCggBQ1saABAoUgCSr40IF0VloByggsFCkhBA2sa4H08vooTsIA/6KrkhBM6 + KcAJcLKhAQCFgggUxdAA+1XygAuFClhBAwcaAFBiFCcgAj8NGpBlWWClf1ihQAEp6TUAoFD4gJ+4GgBU + +gaV9AVqzi1RfKefoABQ4hYnwALfsV+ln1y8q64CKXRS0moAQPFd5B6++8FV6Qdg8e3LWv5hCag/aElb + oOiG9CfmKT4FUNoWtQE+zj7we6tLZ189/Bz4cPG/YTwZWz5yrlpFkvO01RXvAuovrwMpdFLSaQBAqVtI + BBIGGFlMIAsHEIAZ4AWgqKuDFvZmv0p8aElXoKb82ubY+ALf9CGAYl+YBEqGbsZCpqjydaDFXhMtAIX9 + Kn3kbyCFTkoaDQAoNsVoWLoRMIn+b+i0tC6qnF9fq3RVYkJLmgJFVySmQLX8BqDoJ/2hYxIdTHbNH2DR + 14wH+AJWYtUCIIVOSvcaAFD0ik3vYAKw6GnFA5DsmwOwEgNWui9QWr/EGSeGoDf9JC8l854sI8wvK5xs + gxb2sPQDMoCK/7wOpNBJ6VYDAMryYgKc7F7MYjloub68ADqw4hdWui1QdD78iq6GbwCUZQUEOJm200a6 + K14KLvOYr31gxV/dAFLopHSnAQBlfpIGTqbByebRwMp87XmBK0DFF6h0V6Bq/ErnHL5EvO4PAGVekQBO + lsEJsDJPd17AZNs8gBUfeR5IoZPSjQYAlHmFQn7988/GAnRW5mnSE7wAK21hpZsCRXejrZA82F9eLuYp + uXmfC90TGzDZdUeQdz0wv91ABai0qy9ACp2ULjQAoEz7xUr3pB6grJ+Jzso0nXoDJ2ClPqx0UaA8/Ipn + DvXFO9gcQClP/HRP2sAJoFKuUW9gwn6VdrldcjyQQicltAYAlPLkT/ekPaAAK+V69Q4r0lWRfXD8QLWF + mNAFCnHYisO7fQGU8oTfw8v/fCGG3mxYAirXsUdwYQnItg4BKXRSQmoAQClL7LK8wz//FgBUyvTsEVKG + OQErNrASskB5/4XP/GzEOtiVFwaWJXSWd/zDCc9XKdOyZzhZnxtLQPq5H0ihkxJKAwBKWVIHUOIByjBj + uiplGvcMLnRV9GAlVIGiQ6Hn+Ii2BFDKkjeAEhdQ2FhbpnHPgLLZWYmYaz3NGUihkxJCAwBKWfJmg2wf + gEJXpUzvEWBF9s/RWZn/AztEgfJEdcxlvtjm2g5AKUvYAEpfgDJcjfg1QjFmjvvjFFCZVzuAFDoprjUA + oAAofaLH9Ktir0pZLHiHJWBlGqy4LlBzf3nzvWki8GovAKUsKdNBmV7wo34DUCmLCe+gwhJQeY0CUuik + uNQAgFKWjAGUqLgxf96ASllseAcVmR9dlXFYcVmgvP6yZ17jgtKwEYBSloQBlPmFPvo32adSFiMRQAVY + 2V9XgBQ6Ka40AKCUJV9uM46OGTrzlycKRynEzHM8tumsHAUWVwVK41c4Y9TpdljYGUAZT2KS6AEUnQLf + yygs/5TFTRRIAlRur2FACp0UFxoAUMoSLYDSC1roXgegUhY/UUCFJaCPQcVFgbL4Vc6YcToq8rrzSMmj + 1VwBFN3C3ttogEp/oAKsrO4AUuikNNUAgFKeWHsrqlyPvgUAlfJ4avVjY855My8BNS1QdDvidDssfAWg + lCdU7uTRL+i9jgiolMfVHGBo+Z2MsAKk0ElpogEApTyRsszTK07YXRegUh5fLaFj7rkzwUqTAmXxq5wx + 43RlAJTyBAqg2BXy3kcGVMrjbC4stPxeFlABUuikVNdAy8COdu7eCynXZ2sBQKVvUMmwsbZ6gaLjEafj + YeEreWdFNFBoNd/MXRTZgyMfsYE8sGz47PLF8Hc5fviwj+cWAAEq/YNKz7ACpNBJqaYBAKU8WWYDFAGK + MRCZC4sy7gAutn0Lv6PzZNry2JurMw/f63EJqFqBsvhVzphxujIAyrQkmaELMIBJ7eQ+QItfpLCZGaAy + LQZr61LzfD3BCpBCJ8VcAwDK9ORoU6baj9oKTPYtE2XpWvFSwulxqAkOLcbqAVbMCxTdjjjdDgtfASjT + E6P84u3tnzc42VYwMiwJASrT47EFXGieU0BF7qi0yO81xgRS6KSYaYD38cxLiD1BSgQ42SwIvS8HsZF2 + XlxqgkOLsaJ2VcwKVA3C4hx+uzQAyvxE2AOkRISTXd2V3rpacj3sT5kfny0AQ/Oc0WAFSKGToq4BAGV5 + AoxcGHv8pd7jvhVAZXmcasJDzbEiLQGpFyi6G367GzV8A6DoJL6Id/f00j3ZVSx627PC/hSdWK0JF9rn + itBVAVLopKhpAEDRS3rRlnx67J7sg5XIna71uWfym3aB72k8z7CiVqBq/ErnHH67NACKHqAMyS9CN6X3 + 7sm+QtTLEhDLPvqxGxFg5E5Mj7ACpNBJWawBAMUuyXn+xc6v8HtvPsk2+j+WfeziNyKseAOVxQWK7obf + 7kYN3wAotglOfuV67KgAKLf7PTqs4E/bOAZW5tdJIIVOymwNACj1EpunIsjywHa/e/LRnO4Ofq0Xz1Gg + xcMS0OwCVeNXOueYT5/WtgNQ2iS01oWQQjbud4+drxJoYdln3LdR4EJ7ni2XgIAUOimTNQCgtE1mLUAl + 8wbZOQm/hY9KQGTsGJZ92sb2HK3V/E4LWJlcoKx/oTO+3+6J+AZA8ZPEahVCfmHP83kt/4yBx9S/0y2b + 5++asND6XDVhBUihk1KsAXlJVevg4PxHE6hlMQRQlhWsaM+7EaDB58t8niVH1QKV4gJFh8N3h8PaPwCK + 78RlASoUKx2fRwQVuik6vs8ALNawAqTQSRnVAIASJ2FpwkqGBFvzGiNtqAVQ48R8TQ3vO5cVrIwWKOtf + 6Izvu0MDoMRMVkthhV/SNn6PBCpowEYDXqDCYh4WoAKk0EnZqQEAJXaSmgMq3MVj7/MooEI3xV4LFqDg + YUxNWAFSgJSdGvAgduawPFGWwgq3ny63daleo4AK3ZR6mijVTqTjNGAFSAFStmpAnjQYKRiY63gyFQiR + jxTI4SP/m0I0bjttfUXZTEs3pb42tLXWeryloAKkAClHNACgkJhaJ7YM548CKkAs+UAjHufCCpACpNym + AQCFhKSRkBijTEelS3FTH8imeTzdlDJfovkyO02FFSAFSDnUAIBSFmQkI+ykqYEIoEI3Bc1ran4KqAAp + QMpNDQAoJCHNJMRY0/TkfSMt3ZRp/kT/4/YqBRUgBUjhfTx3jgcUSQcbWWtAc4nGYizr62f8fDEmP47H + npUGpCSHFF4YmC8xUAx8+tz7RlqWfHzqJno8j4EKkJIYUgAUkk70BNfb/D0v+7DkQ76wird9Sz9ASlJI + AVBIOFYJh3GXactiqUZrTLopy3xLbOy23y5QAVISQgqAQqIhWfrVgOdlHyDFr256iGl5FcvmHhUgJRmk + ACgkmR6SWe/X4HXZhyUf8odl7G3bnwKkJIIUAIUEY5lgGFtPX3RT9GyJLmPZcnPZB0hJAikASqxAJbHi + L6/dFJZ80KZ1flpf8gFSEkAKgEJSsU4qjK+vMa/dFJZ89H1N/Nxu0/VuCpDSOaQAKCQUEmBcDXjtpqCp + uJqK4Lv1vSlASseQAqCQSCIkJOa4W6deuyks+ZBbrON2uNMHSOkUUgAUkoh1EmH8Ohrz2E1hyaeO7zPH + 2NBNAVI6hBQh0Mzi5tpJoD1pwGM3BUghxmrEmGygBVI6gxQAheRRI3lwjro689hNQQN1NZDR3lLPgJSO + IAVAIWlkTGQZrtljN4V9KeQb69gDUgCUlbXIGJ9EhgaWawBIWW5DdBjPhrIvhU5KB6BCByVe8JEw8dlU + DXhb8mFfChqequGpxwMpAAqdlDtJNFMTB8e30Yy3bgqQ0kYHmeIPSOkAUsSJmUTLtZIYs2rAG6Qc3HnB + jxx+5JhrgOWewKACoFCwsxbsrNctYODpX1Y/cN31ci+QEhRSAJR6QUJCwtZeNOBtXwp3+BAb1rEBpASE + FACFxGCdGBjfp8bOPvB7nhopKyDFp056iV/2pAAo5uuJvQQL10Ey9qABb/tSBJo82IU59BmfQEowSKGD + 0mcgkmDxa6kGgBS0UqqVHo6Td9Cx3BMEVHhhIMmph6TDNSzTMZCyzH7oL5b9gBQAhVYttxCigWAa8LQp + hWelxCr60SCNx+IHgBQ6KCSBaImF+dpqFkixtS/69WNf3oLsHFIAFD/BQuLCF140AKSgRS9atJyH7MEE + UhxDCoBCIrJMAIwdV19ASlzfEXflvpMaCKQ4hRQApVzIBD22yqYBIAXNZ9C8AAqQ4hBSABQSUIYExDXO + 1zmQMt926C6G7YYuCpDiDFIAlBgBRKLDTy01AKSgv5b6q3HuoYsCpDiCFACFxFMj+DlHbJ15e04KtyDH + 1pPHfLDeRQFSnEAKgEKge0wWzMmfLr29uwdI8aeR6HG73kUBUhxACoBCkEdPKsy/noaBlHq2Rtf1bb3Z + RQFSGkMKgFI/CEg82DyyBqRz4ekfLxgknrTiaRugACkNIUUe96vlXMYhUaCBHBrwBCgyFyAlh+5q5JfN + ZR5uQQZQeGdLsHe21EgUnMNv0fG2aRZI8auVaHEsP9qBlIZQsm58OigEdrQEwnx9aNbbfhQgxYcuosfn + PkBhuacyuAAoBHX0hML822nY21KPzEe6O2iinSai237XPhSek1IZTsTgAAqBHD2hMP92Gva41COQgiba + aSK67f/g/tOP71riAVIaQEp0QTF/khEaaKcBj0s9QEo7PUSPxf9zz6nVpUuXTgApDWBkm9HlldPRRcX8 + SUhooJ0GPC718CC3dnqIHIsCKOfPnwdSSgitxjEACoEcOaEw9/b69dpF4fbj9tqIFp8DoAApdFBYK+b2 + YjTQiQY8dlG4swdAmQpI64ACpDiAFDooBPHUIOZ4NLOpAa9dFO7sQatT8tUmoAApjSEFQCGApwQwx6KX + XRrw2kVh0yyaLc1b2wAFSGkIKbyPh+AtDV6OQyv7NOC5i8KmWbRbkr92AQqQ0ghSABQCtyRwOQadlGjA + cxeFTbNoeEzD+wAFSGkAKQAKQTsWtPwdjZRqwHMXhf0o6HhMx2OAAqRUhhQAhaAdC1r+jkZKNeAdUNiP + gpb3abkEUICUipACoBCwpcWH49BKiQY8L/Nw6zEa3qfhk3fdd/NBbSUfnjhbAVQAFAK2pOhwDDop1YBs + SPX+j/0o6HmbnqcACp0UAIUHeXXyIK/S4sZx8QtHhGUelnri68wiV0wFFCDFGFLooBCoFoHOmHl1FQVQ + 6KLk1eiu/DQHUIAUQ0gBUAhSYAINaGrg4bsf9L7Cczg/IAXtr2t/LqAAKUaQAqAQoJrFibHQUyRAYakH + vWoBCpBiACkACgEKVKABTQ1EAxS6KOh/Xf8ld/DsO4a7exRBBUAhODWLE2Ohp2iAQhcFza7nrcdOPVp0 + mzGQoggiB0F4x7bPjSvXjlFUCFA0gAa0NBARUOiioP9B/xqAwnKPErwAKASmVmFiHLQkGohyF8/mTl70 + i35FA1qAAqQoQAqAQlCSmNGApgaiAgpdFOJAG1CAlIWQAqAQlJrFibFy60mWdyI8SXbXfdDoN7d+LQAF + SFkAKQAKAUlSRgNaGojaPRmAhS4KsVD6wsCpd/twd89MUNFKToxDcKOBvBqIuDl2WycFDefVsPjeClDo + pMwElDPHT58gKHMHJf7H/0s0EH1pZx1U6KLkjgVLQAFSZkAKgJI7IJcUJr6bWzsCJtGXdeii5NbwZg6z + BhQgZSKkACgEKKCBBqZqoKeuySak0EXJGw81AAVImQApAEreYJxalDgerQxgEvlunbG3Gcq1ofWcWq8F + KEBKIaQAKDkDkQSM36doIAOYsBeFmKgJKEBKAaTwPh6Cckqh4thceskGJtxynEvfLfagbN6izC3Ie0AF + QMkdkAAH/t/UgEBJz3tMxpZ4hr8TG/lio3YHZYAVIGUHpAAo+YKQxIvPt2kga7dkF7CwWTZfnLQCFJZ7 + ABQ2vh08iAg4wQaDBtY7JT1vei3tmHA3D7HRElCAlC2QQgeFoARa8mgAKCnHFe7myRMXQw5sDShAygak + ACj5ghAgyeNzgKQcSLYdKfYjXvLEy8m77ltNfc+OxfHsSflTUAFQ8gQfiTaHr9lLsgxKuN04R5xsy4de + AIVOCoDCLyP2pHShAbokekDCPpS8cCLA4glQgJQDSKGDkjsg6arE9D+3AttBCR2UmDGhkcu8AUp6SAFQ + 8gajRkAzRj39ACV1oGT9LGyUradvD7nEI6CkhhQAJVcAekgCzGGa5thTUh9MhjMCKNO02kNsW2x61Rgz + 5cZZACVfAPaQRHq/BoESeVAYzydpByfDmbmTJ1eOfOzUoy7u5NkGNekg5caVa8d6T/ZcX64EE9nfPGK+ + PZBszgBAyZU/PANKuuUeACVX8EUu3j3PHTDxByZ0UHLmRu+AkgpSAJScQdhzsY90bYCJXzCRmckSGx2U + XDkyAqCkgRQAJVfwRSrevc8VOPENJwOg9K5Dru/2GhAFUFJACoACoJCg6mtANsDyz78FeKNx/dhonY8i + AUr3kAKg5AvA1gkg+/mBE/9gMswQQMmXHz28MHDqbclP/c7jX5dafqDbO/Z99v5x7Mut/p69YHD9+ZJQ + K58DJ3HgRGbK/pN8uSEioAjQSOdH8toYqISDlDPHT59olbA5b74EkNXn7DmJBSc8pC1nbooKKOuQIjm2 + m04KgJIzELOCQovrBk5iwYnMluWdnHkxMqBsQorU9l2gEqaTAqDkDMQWhTrrOVnaiQUo3F6cNydGB5RN + SJGcK0+M3wYqISAFQMkbjFmBoeZ10z2JBSfsPcmdD3sAlG2Qsmt/intIAVByB2TNYp3xXHRPYgEKSzu5 + 82EvgLILUrbtT3ENKbwwMHdAZoSGWtdM9yQWnLC0Qy7sCVD2Qcrmso9bSAFQCMpaBTvbeeiexAEU4IQ8 + KPmpN0DZBymbyz4uIQVAITCzgUOt6wVQYgAKcEIOHHJCj4AyBinrd/u4gxQAheCsVbCznUcKH/98WwA4 + If+t56VeAWUMUtb3priCFACFAM0GDrWuF0ABTmppjfPo5PGeAaUEUoYn0bqBFABFR9gkCOy4qQEAxSeg + 0DUhVnfl65N33bea+i6caMcPj8XfZYNhyccFpAAoBCtwpa8B7uDxByeAib7Oe8sdGQBFgOqRex+6+e6e + fR95uFtzSAFQCNoxofL3eRqhg9IeUsQHgMk8/WaM+yyAIpAi1zrmY1nyaQopAArBOyZS/j5PIwBKG0BZ + hxLeSDxPu1ljPhOglHRRRAfCCM0gBUAhgLMmI+vrBlDqAQpQQh7TiGcAZbuOZF9KE0gBUAhsjcBmjKM6 + 4jkotoAClJC7LPJOtE2vc+db2kEZbNwEUgAUgtwiyBnz3hWAogsoAAm5qkZekbtc5hb9SN+bCihi++qQ + Iptgajidc5BcsmkAQFkGKAAJOaNFzgBQxnVXbbkHQBl3Rosg4Zx9+GVZic71bYCkD81Hz10ASpkOq0AK + gFLmjOhBx/zb+JmNsvshS+wjnSbutmmjT/LCUbsDKOVaNIcUAKXcGQQztpqqAZZ5jgLK8FwSoIR4mhpP + NY4HUMp1ab4nBUApd0aN4OAcffkDQLkFKEBJX7ruOU/1/j6eYSPvnE2y2/xuDik9i41rIzG21kCunSQf + Xy1PcSX2WsfenPNnAZSxd/JMsZ3pw9yEgKZMhmNJPGigXAPZuiiASbk2iCN/tgJQ5vnEDFIAlHkOIblg + txINZAEUwIR4KIkH78cAKPN1bPLuHgBlvkO8Bxvz8+Hb3u/m4YV8PnRGvC/3A4CyzIbqb0EGUJY5hKSA + /cY00GsXBTBB+2Paj/Z3AGWZpmWpRxVSAJRlDokWgMy3jb972ywLnLTREfFra/csgCJ388jLES30pAop + vI/HVvAWAmDMeD7rqYsCnMTTHzmjzGcASpmdxvQkXRSVTgqAouOQMYfxd+zcQxcFOEHHPecyAEVH30MX + ZTGkACg6Duk5aLk2HY1E76IAJzo6IJ782hFA0fPN0EVZBCkAip5DSDzYcp8GogOKzB+No/GeNQCg6Ol7 + vYsyG1IAFD2H9By4XJuOTiJDCu/P0dEAseTXjpkARetx9/v0vN5FmQUpAIrfYCGR9eebqIAiyzvosT89 + 4tPbfSp3tgzvq+n9vzUAZbOLMhlSABSSDkmqrgYibpZleaeuRojJNvYGUHTtvg1QJkEKgKLrEBIL9hzT + QMQuCoCCrsd03cPfARRdnctz1jaXeSbdggyg6DqkhyDlGuw1Ea2LAqDYa4K4a29jAEXXB/sApaiTAqDo + OoQkgz1LNBCtiwKgoOsSXUc/BkDR1fkYoIxCCoCi65DoAcr86+kh0ksEAZR6uiAG29kaQNG3vbzleNcy + z+hyj3yZgNB3CjbFpiUaiLLUA6Cg5xI993DMY6ceTXEnT427eEQPJYCyt5PSg6i4BhJoVA1EgZSo9mXe + 5IYpGgBQdPVSCig7IYVlHl2HTAkGjsX2ooEI/3hQG1rNkK+yAIpcZw1/TgGUrZACoJB4agiVc+zXmXdI + YZmHPJEhhgEUXZ1PBZStkJJBeFyjrvCwp749PW+cBVD0/U0M+bMpgKLrkzmAcgRS6KLoOoXEgz3nasAz + pMy9Jr5HPETRAICiq9VdT5Mdu7PnCKREERDz1BUQ9vRnT9nv4fEfXRR/WiF+dX2S6YWBNbSzBFBugxS6 + KLpCr+F8ztG3z7x1UwCUvvVGPrl3lQlQ5Lkv1j5fCii3QYo8+c16woxPkkMD5Rrw1k3Bd+W+w1bxbAWg + 6PpMA1Bug5T1oLr/4BbIn7/znh2Udc/q1t/5YAM0YK0BL4/Hp4uC1q213nJ8AEVX31qAcggpLPXoOqhl + sHHu/nzpAVTQVX+6wqe3fAqg6GpbE1CAFLpBdMSCaKAlqNBF0U3iwIEfe2YClBqPu9cGlENIIWj8BA2+ + wBf7NFAbVgAU9NhrTgJQdLVtAShASpBf0b0mCa5rXpIQcKh15w+Pvp/nI7Tt224Aiq5/rADlJqTwtmNd + Z5GcsGctDVh3VeiioOVaWq55HgBFV9eWgPIxpPyFhZNe+n06GuwNQQOzNWAFKzULB+damIOJn6L4AVB0 + dWYNKHRSCOyiwKaA6Aa2hT21l4Doovj3uYWOeh4TQNHVdA1AAVKAFCClMw1odFUAFN1k3nPhj3JtAIqu + puXhryXv3dE4hj0pnRWpKEmDeeomjU17zoUVAMXWL+i+vn3l8e/nz59P8alxm3FNQKGTAqDQSelYAwIc + pbAidwtxJ0/9Agq02NocQNG1b21AAVI6LlAkP93gjGzPfbACnKCTyNreN3cARVfbLQCF56QAKXRS0AAa + QAPdaSAToDx26lFz/7UCFCCF5GQu7l5/pXFdur/SsCf21NIAgKKvJY0NsHPHuEO++Jkf+sQlLYEwjr5A + sCk2RQNoAA2UaSDLJtkaHRTRnDzwdS5gaHzvJqT89k899FsEQFkAYCfshAbQABrwqQEp3BkgJQugHC73 + ACk+A45EiF/QABpAA2UayAIoAmE1NNG6gzJ0YW52Un7/Zx/5dI2L5hxlwYadsBMaQANooFwDmQBF9txY + a8MLoBx2UoCU8mCwFgfj4ws0gAbQQLkGAJRyW5XoyhOgACnc3WNO5CVBwTG6SQZ7Ys8sGgBQdLVe6308 + UzbUstwDqAAqaAANoIFwGsj0Pp4aSzweAYVOCokpXGLy+gtRHikvT2+Vz+a/4YmvXufOvHR/jWJPe3tm + ApQa7+PxCihACpACpCzUwAAnR8hky/9DYIX349gXMCChbxsDKLr+9QwoQMrCAkUy1A2WaPYsfXnfts5K + tGtlvrm17sX/AIquDr0DCpACpNBJmamBuYCyDiwyhpfkzzx0kz/21LcngKJr0wiAAqTMLFAkIN1giWZP + DUAZYEX2sAArufUUTf8t5gug6MZIFEABUoAUfsnP0EDJ/pOpxwAqukm4RSHlnDY+BFB07RoJUICUGQWK + RKQbMNHsqdlF2QYywEpufUWLB+v5Aii68RANUIAUIIVOykQNTO2QzDmeJSDdxGxdSBnfxl8Aiq5dIwIK + kDKxQJGMdIMmmj2tuyjcBZRbX9HiwXK+AIpuLEQFFCAFSKGTUqiB2oDCXUC6SdqyoDK2rq8AFF17RgYU + IKWwQJGEdIMmoj1bQsoALOxXQYcRY2fKnDMBirx3aIpt5hx75vjpE1Pek+PxWN7dA6iYB8qc4PL0HQ+A + AqgAKJ5iwmIu8n6a8+fPp/gAKKub7FHyAVKAFCBlRANzNr9af4euCtBiAQqtxgRQdPXcQwdlABgVSPnc + j3+KB1IBO13CjqcuCrcs6ybyVgWZ897uRwBFV9c9AYranhSBFNrRukIjkfmwp3VHRGN8uio+tELMTvdD + JkCRpSxrjfQGKCaQIkmXpDk9WK3Fy/jTfeK9i8IdQNN9Shz4sVk2QJHrtdRfj4BiBil0VfwkAsug6H1s + jS5HzTEevvtB0yTYu7+5vnp5C0DRt3XJJtSIx6jtSdmXjOms6AuShGpr00hdlCH25Em16MJWF9hXx75Z + 7uKR67TuoIgmb1y5diwigJTMuQqksASkE9gkyDp2jAgoA6jQTamjEWJxvp3l9tsskAKglN1mvA9WqkEK + S0Dzg5qEWNd2kSGFbkpdrRCb0+ydCVAeufch885mzx0U9VuQp669swQ0LbhJhnXsFRlQJAaBlDo6IR6n + 2xlAmW6zfTrLACjmG2fHwAVQ0RUtiXO5Pcc0G+Hv6GC5DrChrg0BFF17ZgGU5pDCEpCucEmsy+wZvYsy + xBM6WKYD7KdrPwBF157RXxhYsll2/Zjqe1K4C0hXsCRUPXtG6JKUzBFN6GkCWy6zZaYXBtbYg5INUNx0 + UjYfSsUdCssSA4l1uv166aJILOH/6f7HZvo2A1B0bZoRUFxCCktAusIm+ZbZs6RDEeEYNs6W+Zu4sLUT + gKJr36yA4hpSgBVdkZOUd9uzpy4Km9GJm9axDqDoajAzoISAlOFBcCwB6Qq/dSLzdP4IHZLSOXqyK3PJ + F7MAiq7PswNKGEihq6IrfIrHx/aki4K2iAcdDWQCFLljyVo3AMqtp9W6urun9NciLW2dpGIdZBHG7wlS + ItibOfYZuwCKrl8BlI8fpx8SUoYnawIruoGRsYDIRtMe/hELxEKr+AVQdLUHoNz+vp+wkMISkG5gtEpw + rc/bC6S0tiPnzxmPAIqu3wGUoy8kDA8pwIpukGQrNj1ACl0UYqBF3AIouroDULa/MbkbSGEJSDdgWiS9 + FueMDik8FwXdt4ibTIBy/vz51cm77jPdKAugbAeUsBtnx/YQ8MuSxF2auOXW9sj/0DpaL9W61nEAiq7m + zhw/fUKKMZ8EnZTNYkMC1w0mrSTnaZzIkIK+0XftWJKOgnQWsnysOygAyjicdbXcs+sXMcmcZL4vmUdd + 8qldoDhf7jgCUHT9D6CMA0q3yz3bYAVQ0Q2wngpWxG4KekbPNWMQQNHVG4BSBiipIIW7gHSDrGaCrHGu + aA91q2ETzkHMiAayAcoj9z5kukkWQCkHlJSQAqyQeHcV3yigQhcFDdcCSABFX2tskAVSim/WINnrB2Ct + 5Gl1ngigYnXtjEs8bGogywZZuU7rDorY9saVa8eAFCClGFLoqpCUtxVm2aPiFVYAazRbCyblJXpZIAVA + mQYONUErxd09pdRCAaAArBcAb6CCPtEngKJ/+zOA4hdQUu9J4XZlEn5pwvcCK0AKmi3V7JLj6KDo6owl + nmUQRCdlB61QEHQDdUnS9PDd1ktA6BE91ogDAEVXZwDKMkChk1KwDkRx0A3aGonW8hytuiqW18TYaFw0 + AKDo6gBAWQ4oQEoBpMghgIpu8PZQFGvCCvpDf9YxA6DoaowXBuoACpBSCCncBaQbwNYJt+b4NWCl5vVw + rnxaz/TCQIExa40DKHqAAqRMhBRgJV8CL0lolqBCFwXNlWhw7jEAiq6+ABRdQAFSZkLKsAQkmynnJge+ + p5scPNhTG1bkxYceros59KdV8SmAoutXAEUfUICUBZBCV0U3wHsqhFqwAgSjMau4AFB0tQWg2AAKkKIA + KcCKbrBbJeXa4y4FFQAFXVlpNhOgyBNzrew4jAug2AEKkKIIKSwBUVS2JcOpsCJLPAAKWrIqrNkARV6Q + aGVLGRdAsQUUIEUZUuiqUFx2JcQxWAFO0I5lMc22B0U6KACKPUDUeIcPT5w1AhWer0LR2VZ0hifXCrTI + R/43nRO0AqDovpMHQOkDUOikGALKMLT8QuY2UoqQdRFifDS2SwMs8ehqgyWeugBEJ6UCqNBV0U0SFGTs + iQbKNJANUKzfaAyg1AUUOimVAGX9NHRVypIrRQg7oYFlGgBQltlvU38ASn1AAVIaQIqckiUg3eRBMcOe + aOB2DQAoujFx5vjpEzU2iXKOoyDEck8jUGEJSDeJUKSwJxq4pQHZNCp3t2T5WC/xAChtOigDsAEpDSGF + W5YprBRWNKCpAQBFV08ASltAYbnHAaBwF5BuUtFM+IyFbyJpAEDR1SuA0h5QgBRHkEJXRTfBRCouzBXf + L9UAgKKrIQDFB6AAKQ4hBVjRTTZLkz/fxx/eNQCg6GuUDaxAimM88DU1blnWT0Deiw7zw+dTNJBlg6xc + p/UmWbH7jSvXjgEpQIovEnA+G0CFojWlaHFsHr08dupR7uI5AAstzQMofuCEu3ucg8m26QEreslIK6kx + Dj5ppYFMgCLXam1nAMUfoBzuSfntn3rot5YI4HM//qmAJT/ulIEVCuOSeOW78fUDoOj6EEDxCSiHkPKb + P/bJJ5ckLiClPvAAKrpJaon++S6+qKkBAEVXbwCKX0A5hJTP/NAnLi0JMiClPqRwF5Buolqif76LL2pp + AEDR1Rrv4/ENKIeQsjTAgJR2kAKs6CatpbHA9/GHlQayvY/Hyo7DuACKf0AJCymXLl1avfHGG+3JwNkM + WAKiQFondsZvo7FsgCLPfrHUGoASA1BuQoqsxy0VQ81Oyte+9rXVCy+8cPO2u+eff3715ptvOkOF9tMB + VtoUkqVxxPfx2zYNACi6ugBQ4gBKOEj5xje+cQgowwOMBFguXLiw+s53vtOeDpzNAFjRTW5ABPasrQEA + RVdzAEosQAkFKbLEI52TbU9XfPbZZ1df/OIXb8LKd7/7XWeo0HY6gIpukqtdpDhfXv8BKLq+B1DiAUoY + SPnmN7+5E1A2oeXixYsr+Xzve99rSwfOzg6s6CY84AF7WmogG6BYP+4eQIkJKCEg5Vvf+taRJZ6Sd1UI + qEh35e2333aGC22nA6xQXC2LK2Mv1xeAstyG6zoEUOICintIuXz5cnEHZRe4yBLQV77yldX3v//9tnTg + 6OwCKg/f/aDp7nmKlW6ixZ457Amg6PoZQIkNKGqQIglUCp/mv9dee20xoAzgcu7cuZvdmFdffXX1zjvv + aE4z9Fh0VXQTIiCBPZdoAEDR1Q+AEh9Q1J6TMgSmFqh8+9vfXj333HMmb/eUzbdf/epXV1evXg0NGJqT + B1Z0k+OSQsV3c/oCQNH1O4DSB6AcQsrSx+JvJtYlsCIPaRueg1Ky92TOMdJZEQiSZ65cu3ZNs96HHYsl + IN0kCWxgz1INACi6WgFQ+gGUQ0j5Hz+87N09u4JxKqzIg9kEHuSW4jnwMec7cj55/sr169fDAobmxOmq + 6CbM0kLFcTntDqDo+v3M8dMnpLDx6ccGN535h//59ANWSbIUVORhbLuegzIHPuZ8R57F8t5772nW/LBj + ASu6ydMqvhg3rp/k0e9z8lTU71jfZgyg9AMm65B5E1Je+Z0LP2Gd7PbByltvvWW2B2VKQMsykBwvz2V5 + //33wwKG1sQvnX315oZoa20wftxCi+/m+Q5AmWe3XXoDUPoElMPlno8+/OjP1Eg220BFHrpWc3lnDFoG + UJHj5BktH3zwgVbNDzsOoKKbUGvEGufw6zMARdc3AEq/gHIIKfJ/PPfZJ/7NrMT2F39m8i/tAVbkQWtj + 0ND677JnRZ7X8tFHH4WFDK2JAyu6yXVWvB3c7s/34togG6A8dupRU70CKH0Dym2QIv/j/okJcOrx68n1 + 1/7R/TcBZb1z0RpI9p1fYOX111/Xqvdhx2EJKG6BBG7a+g5A0bU/gNI/oByBlK//0Ss/UiOR/eo//G+r + c0/f2v8R7SN3IPFvxV6ViUBfI644h24R1LQngKLvmxtXrh3jLp7+QeXIrVoSmPffec/eFt3Y3/cF96/8 + g/+6eubs0672oZSC0ssvvwyfbFiAJSD95KtZHBnLh39k2aM0z0Q/znqJRzQNoPQPJwOAHoEUcb5VYnvw + 731i9fQXngoXrLIkBaDs5zNgxUcxtIpdxp3v30yAIoBlrRUAJQ+gHFnuGchF1vq0hfbpv/1fVk/98ZPh + AEWCTgDlww8/pIsyYgFAZX4h0443xvPhi2yAIstaltoDUHIByk5IkT9oCu2X/9Z/Wj35h2dDAspLL720 + +sEPfgCgTLAAsOKjQGrGMGNN9ymAMt1m+3QGoOQDlL2QorXs89//5s+tnvz8EyEB5cUXXwRQJsDJ5qHA + im6SBhTi2BNA0fUVgJITUPZCivxRXtS0JDF+8q//h9XZ3/9CSEC5ePEiD3JbACjDVwEV3WS9JB75bh1f + ACi6duaFgXkBZRRSloDKL/7Vf7964nf/OCSgXLhwgcfiKwDK+hDAim7iBjh82pMXBur6BUDJDShFkDIH + VH7hr/zs6guP/lFYQOElg8qEsjYcsKKbxIEVP/YEUHR9AaAAKMWQIgcW71H5Sz+z+sL/jQco8v4g6aAA + KHaAwhKQbhIHUPzYE0DR9QWAAqDsfE7K8Idd/x3bp/L53/jdkB2U559/fnXjxg37Cs0ZDi1AV0U3sQMt + bewJoOjaHUABUNb548jD3MYgZd/yzx/8+v8LCyjXr18HHxpZAFjRTfLASj17Aii6tgZQAJRNBpkFKcMg + 612Vxz4b87HP8uLAa9euNSrPnJYlIN0kD6DUsyeAomtrAAVA2dYkWQQpw4AvPP7c56O9b0IedS9LPACK + L1Ciq6Kb+IEWG3sCKLp2BVAAlF2rOIsh5fLly/8xGqDIfKWDcvXqVV8VmtmwX4W3K5s+Vl0D2gAUAKVk + WwTH6IDXIkh57bXX/l1EQJE7ed555x2QwLkFpKvy8N0Pui9aGoWPMXQLn5U9ARRdP9FB0SnkPQPRIkg5 + 6EZcjQYpAIpzMtkyPZaAdAuDVQHvfdxsgCJPzrX0KYACoJTA1SJIiQYo58+dX7361JfjVWlmfNMCwAqw + Ylk0940NoOhqD0ABUEoARY7JAykHgPJrP3r/zV8GUuz4F9MCLAHpFotWRT/SeQEUXc2dOX76RGmB4jhg + Jg2kfPYfP3CkdQmsxAQVuiq6RSMSMNSe68m77gv57Ke5XW7rJR4ABeiYCp5dQ4rsPzn3zLnVqX/yCzvX + VgGVuKACrAArltACoOjqC0ABUKYCSvfLPeeePrd66Cd+sWjzF7ASF1YunX2V/SrculwU56VQkw1QpPMi + 11xqn6nHASgAyhxA6RpSzj31zOrXf/KXJgWdgIoUPP7FtAAba3V/+U4tRL0cD6Do6ghAAVDmAkq/kHKw + xPM//+knJwHKeoKlqxITUoZZAyu6RaYX+Ci5DgBFXztLChTfBXC62pMij7p/5qCD8hv/7FOzAQVYiQ0o + w+xZAtIvNiVFPvoxczecRv2e5RKPaOHGlWvHAA1AY4kGuoKUm4Dyz39ZBVCGZEtXJTa00FUBVkrBSe5s + iQobc+YNoAAPS+Ch1ne7gZRnnnxm9Zv/8tOqgEJXJTagrM8eWAFW9sFKNkB55N6HzHIlHRTgRxNguoCU + p88+vfrcv/qMadAND4FjY21ccGEJCFDZBioAiq4uWOIBUoCUg9vlhvbm0088tfpf//pXzAGFrkpcONmc + OV0V3aJUupzi8TgARVcLAAqAogko4e/uEUD53z/9q1UBBVgBVjwWW+Y0vdgCKNNttk9nvI8HQNEGlNCQ + 8vQXnlo9/G9PNgMUNtYCK4CBbpGrac9s7+Ox3oMCoAAoFoASFlLkVuN3333370hg1Exs+87FXUCxoYUl + oLjAMTUHACi6vgZQABQrQAkLKbIfZd0oXmCFJ9bGBhWZPbCiW8CmAoT18QCKrn8BFADFElC6gRS5EC+g + MtwFFL9c574CYEW3mFnDR8n4AIquTwEUAMUaULqClMFYwEpuuNC8ekBFt6iVgITVMQCKri8BFAClBqB0 + CSneYIW9KprY0GYsYEW3wFmByK5xswGK3LVkaWMABUCpBShdQwpLQG0Kes9nBVbiwQqAouszAAVAqQko + 3UOKx64KT6yNjTGAim7Rs/zFD6Do+gpAAVBqA0oaSPEIK7FLNbMHVnQLoDasACi6/gFQAJQWgJIOUlgC + Ai60LQCs6BZDDVjJBijySAYNu+0aA0ABUFoBSkpIoauiXaYZD1DxAyoZAeXkXfeZQQqAAqC0BJTUkAKs + ABfaFgBW2sIKgKJr/zPHT59oXaA4P5B0xxIRDG8ibvHfJfPe/K6XZ6vwxFptbGgzHrCiWyxLljKkm9Ai + D7U8p2UHBUABDjRr7JKxgJSDp9XSVWlTzHs+q4DKw3c/aNaGLyncWY4BUHShEEABUJZAhfZ3gZQ1SAFW + esaGNtdGV0W3gG6CV0ZAsXyjMYACoGhDxtLxgJQtkCJGlSUgCdjWv0Z5Ym0buNA+K7CiDysAiq5NARQA + ZSlQWHwfSNkBKXRVtMs047EEpFdUARQ9W8oPMQAFQLEADI0xF0HKl7/85cfnbhw7+O4Tzz777OzNbhoX + P2UMD5tr2VjbB+jQVVlWYAGUZfbb1h2ekgs5FqCpqYFFkLJkoh988MGfPQCcD8+dOzcLVJace+53WQLq + AxK8XAWwMq/Yzv1hFPV7lntQBFhuXLl2bG5O5HsAi7UGmkGKXNj777//5w66KdfnJA9rw+wb30NXRZIL + +1W84Mb8eci7nICVcliRN/zOyRdRvwOgAAEta52HczeFFDHAe++9d+cLL7zwvalJxIPxPMAKoDIfEDx9 + E1AZBxUAZdxGUzb600EBgDzU0bE5NIcUmeCNGzf+8oULF16fAipjF1br7xLowIqnch97LsDK9kIMoAAo + tXI65/EFby4gRURx/fr1v3bx4sWvl4KKNyF5ARVZPuBfbAuwBHR7QQZQABRv+Z751AMZN5AiTr969erf + ePHFF18pARWvIvECK7HLNLMXC9BVuXcFoOgCCi8MrFdcvdaoaPNyBSlivHffffeHX3rppQtjoOLZ0CwB + ARmaFsgKK9leGChANmVPydRjARQAxXPd3DU3d5AiE33nnXf+7ssvv3zAKed37uSPYGy6KpqlmrEywQqA + QgclQo5njvbg5xJSxPFXrlz5kS996UtP7AKVSOIAVgAMLQtkABUABUCJlN+Zqy2ouIUUcfzbb7/9Y6+8 + 8srntz3wLaIwWsMKT6zVQoX24/QKKwAKgBIxtzNnO1BxDSni+Lfeeusnt22mjSqK1qDCQ+DaA4bmDHqC + lWyAIl3iqftKphzPHhS7whm1/kSct3tIEaO++eab/+IAVF5aX/qJaOz1OQMrmqU691g9gEpGQJF3EE2B + jinHAigASvQaOcw/BKTIZN94442fXr/rpxcHtIYVnljbD+BEhRUAhSWeXvI516EPh2EgRZz/+uuv33Ow + mfY56aj0JIbWoMISUD+gIlcSCVYAFAClp1zOtSSHFBHA5cuXf643SBmE3RpW2FjbD6xEABUABUChqOsX + 9d5sGqqTMhj/4O3Jf743R3jar8ISELAyZf/DnGMzAorlG43Zg0Kx77UmhoSUXp3hCVRYAuoHVLwtAQEo + dFAy5HCuUQccgZSDJSTPYvKwBNRXuc57NR6WgLK9i0eWpi07KGeOnz7hOX8xN9/1JYJ/XBfoCAasNUdg + JS9caF95C1iR223H3sfV498BFIp0rRrR63mAFOedFE9LQA/f/eDq0tlXtWsm4zWyQA1YETjJ2D2hgwKc + 9AoNta8LSAkEKYM46Ko0quqdntYCVjLDCYACoNQu5D2fD0gJCCnASqe00PiyBFaWAMsAJlk7J8NyFUs8 + QErP0FD72oCUwJAiYpGuimyem3MbqMZ3uF25MVkYnV6W9QZoOfWjD6wEQLZ95E6d7FCyvpfGElAkXmsX + CM4HcLXWAJASHFLoqhhVaYY9tMDBm8hTbnqdupHXGlBuXLl2rHXB4PxAS20NACmdQIoHWGFjbZ9kA6Sc + H4U0AIXiXbt4ZzkfkNIZpLAE1CcotLwqIGU/pMhyl8bS6a4x6KAAQFmAZNt1AikdQoqHrgpPrG2JFbrn + BlJ2QwqAAkBkBoga1w6kdAwpHmCFjbW6wNBiNCBlO6QAKABKjSKd/RxASgJIYQmoRWnv55xAylFIAVAA + lOzwUOv6gZQkkOKhq8LG2pjgAqQchRTLPSi80RgAqgUAEc4DpCSDFA+wwhJQLFgBUm6HFHlejBWkACgA + SgRwqDlHICUppIjI5K6Blo/YB1ZiwAqQ8jGkAChARM0CzblWdwApiSGFrkoMSGg9SyDlFqQAKAAK0FBf + A0AKkHKoAboqrXHA5/mBFACF4ly/OGPzWzYHUoCU2zTQcgmIjbVAytRH0dc43vJpsuxBofgDI/s1AKQA + KVs1QFfFJzC0mFXmTgqAAkQAEW01AKQAKXs1AKy0wAJf58wKKQBK2+IEHGB/lnsAlGJIbQUr3AHUHlgy + QgqAQoEEknxooLhI4TAfDmvph1agwnuA2oJKNkgBUMh1LfMs575df0AK3ZTJGmgFK2ysbQMrmSAFQAFQ + gARfGphcoHCgLwe29EcrWGEJqC6sZIEUAIXc1jKfcu7t+gNS6KQs0kArUGEJqB6oZIAUS0A5c/z0CQoQ + AIQG5mlgUYHC6POM3qPdWsEKXRV7WOkdUgAU8liPObmXawJS6KSoagBYsYeG2mfoGVIAFACll2Le63Wo + FqhejcR1TUtkrUCFjbU2+NIrpDx26lGztxmzxDMtZ5BjsdcuDQApdFLMNNAKVlgC0oWVHiEFQKEoAkYx + NGBWoBBADAHU8BOwogsNtUfrDVIsAUU2dNeIKc5Bfs2iASCFTkoVDQAqtdFC73w9QYo1oMgLOrMUD64T + UKqhgSoFqsaFcI4YAQOs6MFDrZF6gpSTd91ntg8FQImRg6gVsfwEpNBJaaKBFrDCxtp5WNMLpAAosYoT + MIG/RANNChTiQ3yiAQEVuQtC1vFrfthYOw1WeoAUAIWcQ92JqQEghU5Kcw206KrwxNpyUIkOKQBKzOIE + VOA3OikASnNAWU9ELWCFrso4rESGFEtAEb1SSCmkaMBWA66KFM62dXYE+7IENA4NtY+ICimWT5MFUMhV + EfJpD3MEUuimuNRAi64KG2u3409ESAFQgIgeCjTXwMZZlwUaYX6cYFvACktAt8NKNEgBUAAUcmg/GqBI + 00lxrwF5/gSwUnuR5+PzRYIUAKWf4gRo4Es2zgIo7gGFjbXt4GQ4cxRIAVAoaoBNfxoIVaQQYH8CnONT + uip1wSUCpAAo5IY5uYTv+NcNkEI3JaQGWiwBZd1Y6x1SABT/hQYYwEdzNRCyQM29WL7XX6DQVbHvqniG + FAClv5gmT+PTdQ0AKXRSutAAsGIHK14hBUChmAE0/WugiwKFUPsXaqmPa8NKhtuVPULKY6ceNXvfEw9q + I5+U5huOs9cKkEInpTsN1AaV3t8D5A1SABT7wkDxxcZeNNBdgfJiWObRPshrw0qvG2s9QYoloMgbuYnb + 9nGLD/ABe1LonqSC09qw0tsSkBdIAVAoXgBMPg2kKlYIPJ/AB5/XBpWeloA8QAqAkjd2ydu5fQ+k0FVJ + pYHasNJDV8UDpJy86z6TjbIs8eQugACQf/+nKlAI0r8ga/kIWCm/Zbk1pAAoxG2tvMB5/GkNSKGTklYD + tUEl6sbalpACoPgrGhRyfFJTA2kLVE0jcy7fQV0bVqItAbWCFCtAkf1C8loF4tJ3XOIf/CMaAFLopKCB + P9UAsLJ9CagFpFg+TRZAofgBQHE0QIECUtDAmgYAlaOgUhtSAJQ4BYRij6+sNUCBAlLQwBYNACsfw0pN + SAFQKHrWRY/xY2mMAgWkoIE9GqgJK1431taCFAAlVvGg2OOvGhqgQAEpaGBEAwIq8jwN2XBZ4+NtY20N + SAFQKHg1Ch7niKczChSQggYKNVCzq+LpibXWkGIJKLzROF5RAiTwGe/uKSxKBAvBsk0DNWHFQ1fFElIA + FGKMPIsG9mmAX9EACxqYoYFMS0BWkAKgUJwAFDQwpgEK1IwCNWZU/p4n8Gp2VWRjbYvOigWkACh5YoR8 + iK+XaABIAVLQgIIGasJKbVDRhhQAhaK1pGjx3Vz6oUApFCiCJlfQ7PJ3r0tAmpDy2KlHze6QYpMscUgu + 7k8DQAqQggaUNdBbV0ULUgCU/goIUIBPrTVAgVIuUNYOY/w4SaEXWNGAFAAljm7JMfjKkwaAFCAFDRhq + QF5mVwtWrDbWLoUUAIWi56noMZdYeqRAGRYogiFWMFj6qxaoWDwEbimkWD2llz0oxJdlzDK2D30BKUAK + GqiogYiwsgRSTt51n8lGWQDFRwGhkOMHaw1QoCoWKGtnMn6MhFFzCUjjduW5kAKgxNAjeQM/edYAkAKk + oIFGGojSVZkDKVaAIi969JxQmRsFHw3oaoAC1ahAIWRdIUe2Zy1YmbuxdiqkAChoO3I8Mndf+gVSgBQ0 + 4EQDtWBl6hLQFEixeposHRRfhYNCjj9qaYAC5aRA1XI45/GdXGqBypS7gEohBUDxrS1iH/9E1ACQAqSg + AYcaqAUrJV2VEkgBUCiAEQsgc/avWwqUwwJF4PgPnFo+8gArY5BiBSjS7allZ85DzKEBnxoAUoAUNOBc + A7VAZdfG2n2QYgkocqs2hcNn4cAv+KWWBihQzgtULSFwHv9JpxasbC4B7YIUAMW/ZohrfBRdA0AKkIIG + gmmgNqxsgxQAheIXvfgx/xgapkAFK1AEVozAsvZTTVC5fPny6vz584efpx953ORR97IHhSUe9G0dO4wf + S2NACpCCBgJroBasCJhcPPfCCkCJleApyPgrugYoUIELVHTxMX+9BFoLVnijsZ7P0D+2RAPjGgBSgBQ0 + 0IkGooIKbzQeT9QUM2yUVQMUqE4KVFYBc91Hk3ckWAFQKL7EMBrYpwEgBUhBA51qwDusACgUJwAFDYxp + gALVaYEaczx/z5EcBATk5XxWe0nmjgug5NAfeQY/L9UAkAKkoIEEGvDUVeE2YwrX0sLF9/NoiAKVoEAR + 0HkCeszXLWFFOjoACloc0yh/RyPrGgBSgBQ0kEwDLZaAWN6h8AAfaGCOBihQyQrUHJHwnT6TS42uinRP + 0E+f+sGv+LWGBoAUIAUNJNeAwIomsAiYyHgs7VDEahQxztG3zihQyQsUAd53gE/179ylIAET9pygpal6 + 43g0M6YBIAVIQQNoYKsGpBMin6HTsvnf4e9jSYa/U4jQABqYq4H/Dx9K5BQhRG+7AAAAAElFTkSuQmCC + + + + + AAABAAEAgIAAAAEAIAAoCAEAFgAAACgAAACAAAAAAAEAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADt7e0m6+zrw+rq6vXq6ur86unp9+rp6e/q6Ojj6uDk/enX3/7p0tz/6cnY/em/1f/pss396KzK/ui3 + zubowNKq6MXVVejI1hQAAAAAn4qSAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADl6+0B5OrtDeTr + 7Szi6uxR4ertbuHq7ZDg6uyt3+rt197q7eze6ezs3ens993p7Pjd6ez73Ojr+d3o7Prd6Ov03ejr597o + 69rf6eu53+nrneDp7Hji6es84+nrFOTn6gIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAOe2zSTnrcjt56HC/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO3t7q7s7Oz/6+vr/+rq6v/q6en/6ejp/+no + 6f/p6Oj/6ejo/+no6f/q4eX/6tDd/+m60v/oocX/55i+/+aVvf/mpMT/5a3I9Oe80JToydcYAAAAAAAA + AAAAAAAAAAAAAOTq7RTi6uw94ersiN/q7L7e6ezv3Ons/9vp7f/a6e3/2unt/9np7P/Y6ez/2Ons/9bp + 7f/X6e3/1ejs/9bo7P/W6Oz/1ufr/9fo7P/X6Oz/1+js/9jo7P/Y6Oz/2Ojr/9ro7P/b6Ovz3ejrxt7n + 6oHh5+k14+nqCgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKmVngDowtIR57DJyeem + xP/nnr//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAD38vAB7e3u5uzs7P/s6+v/6+nq/+ro6f/p5+j/6efo/+nn6P/p5ef/6OHl/+jf5P/o4OT/6LTO/+eT + vf/mgbH/5YGw/+SMtv/lk7r/5aHB/+awyOznwNJy5ObqI+Hq7Gff6ey73ens79vp7P/Y6e3/1ujt/9Tp + 7f/U6e7/1ent/9Tp7f/U6O3/0uju/9Lo7f/R6O3/z+jt/8/o7v/P6O7/z+jt/9Lo7f/Q5+3/0Ojt/9Po + 7f/T6O3/1Ojt/9Pp7f/S6O3/1unt/9bo7P/X5+v/1+fr/9nn6//b5+vj3ufqmeDo6jPr6ekBAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAADRrr8A57rPEOe0y8Pno8L/55u9/+aWu/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu7u7L7Ozs/+zq6//r6uv/6ujp/+rn + 6P/p5uj/6ebn/+nj5f/o2OD/6MjY/+jT3f/nosb/6IW0/+dxpv/lbqX/5XGm/+V+r//mlLr/5b7Q/+Le + 5P/d6ez52Ons/9fp7P/V6O3/0enu/9Dp7v/O6O7/zOju/83o7v/L6O7/zeju/8/o7f/H5+7/yuft/8jn + 7v/G6O//xefv/8Xo7//M6O7/zuft/8nn7v/K5+7/yefu/9Do7f/Q6O3/z+ju/83o7v/U6O3/0ejt/9Ho + 7f/T6Oz/1efr/9bn6//Y5+v/2ufq+d3n6svf5+lh4+bqCQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASj5EAOW+0Qnmtsy+5qTC/+Wa + vf/mkLj/5o23/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAO/v73bt7Oz/7Orr/+vp6v/r6On/6ujp/+rm5//p5ef/6eHl/+nZ4f/ovdT/57HN/+ma + v//qeab/5Wad/+N1qP/ldaT/5bXJ/+Di6P/c6u3/2Onu/9Tp7v/Q6O3/zejt/83o7v/N6O7/y+ju/8rn + 7v/G5+7/x+fu/8zm7f/F5u7/yebt/8Lm7v/E5u3/v+bu/8Tn7//E5+7/wefu/8Hn7v/B5+//x+fv/8vo + 7v/C5u7/xObu/8rn7f/N5+3/yOfu/8/o7f/M6O3/zujt/8zo7f/Q6O3/0Ofs/9Pn6//U5uv/1ubr/9nn + 6v/c5urc3+fqW+Lo6gcAAAAAKy0tAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAABMPEQDksc8B5q/ImeWfwP/lmbz/5Y21/+aFsf/lirT/AAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7+/vEu7t7u3s6+v/7Orq/+vo + 6f/r5+n/6ubo/+nk5//q4uX/6t7k/+vF2P/pk7//6m2i/+htof/jdKf/4ajB/9/h5v/Z6u3/1+ru/9Tp + 7v/Q6O3/zOju/8bn7v/H5+7/xufu/8fn7v/F5+7/xebu/8jm7f/G5u3/w+bu/8Lm7v+/5u7/u+bu/8Ll + 7f+55e7/uObv/73m7v/A5e3/uuXu/7/m7v+85+//w+fu/77m7v++5u7/w+bt/8Pm7f+55u//xefu/8Pn + 7v/I5+7/xufu/8rn7f/N5+z/zufs/8/m7P/S5uv/0ubq/9Xm6v/Y5+r/3Obq19/m6Vfi6OsIAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOa0ylHlosD+5ZW6/+ST + uv/ljLb/5oWw/+WBrv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA7+ztlu3r7P/s6er/6+jp/+vo6f/r5Of/6uXn/+rg5f/r2eH/7sbW/+uE + sv/paJz/53ml/+HO2f/b6e3/1unu/9Hp7v/Q6O7/yufu/8jn7v/F5+7/x+fu/8Xn7v/E5u7/x+bu/8Hm + 7//D5+//zObt/8bm7v/G5u7/xOXt/7zk7f+55O7/vOPt/7fk7v+65O7/tuTu/73k7f+65O3/uuXu/7nm + 7/+45e//vOXt/7rl7v+05O7/vuXu/7bl7//C5u7/webu/7zm7v/B5u7/x+bt/8bm7f/M5+3/xebt/83n + 7P/O5+z/zufs/9Hm6//V5uv/2ebq/tzm6szf5+lZ4uXrApmdnwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAADnus1A5qjD8+WNtf/kibP/5JC3/+V2qP/mfav/5Yey/wAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAuLwDu3+Yh7uXp+O3o + 6v/s5un/7Obp/+zk5//s4eb/7c7b/+2tyf/tiq//6n2r/+aeuv/f4OX/2ent/9Tp7v/Q6O7/0ejt/8rn + 7v/C5+//vOfw/8Hm7v+/5u//v+bu/8Dl7v/B5e7/vOXu/7fk7v+x4u3/rOHt/63h7f+s4O3/r+Ht/7Dh + 7v+w4u7/sePu/7Lj7f+y4u3/seLt/6/i7v+24u3/suPt/7bk7f+w4+7/tOTu/7Xj7v+34+7/s+Tu/7vl + 7v+85e3/veXt/7bl7v+95u7/wubu/8fm7P/G5u3/yebt/83n7P/N5+z/zufs/9Hm6//T5ur/1ubq/9jm + 6v7c5um43+XpHgAAAAAqKioAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5a3GQeajwfXkl7v/44mz/+WE + sf/liLP/5nqp/+eCrv/lbaH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAO3D1APtwtXV7dfh/+7g5v/u2OL/7svb/++zzP/ujrj/6nWn/+ho + m//norr/3ujr/9bp7v/R6e7/z+ju/83o7v/J5+7/yObu/77m7v/A5u7/wOTt/7Tk7/+34+3/suHt/6Le + 6/+c3Ov/jNjp/4DT5v+B0uf/idbp/4HT5/+O2On/rt7s/6bd7f+j3ez/ptzt/6Td7f+k3u3/qd7t/6Pe + 7v+o3+7/q+Dt/6ng7f+s4e3/sOLt/7bh7P+14+3/t+Pt/7Xk7v+85e3/v+Tt/73k7f/B5e3/wObt/73m + 7v/J5u3/y+bs/8fm7f/J5u3/z+fs/9Hm6//R5uv/0+br/9bl6v/a5unw3eXpgeDl5wkAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAOawyCvloL/t5JK4/+OPtv/kgK//5Xur/+WDsP/mfq3/5Yez/+Znmf8AAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOmr + xqzqmr3/6pq//+yQuP/shbL/6n2r/+pyo//pap3/5qW9/9/n6//V6e7/zuju/8zn7v/K5+7/yefu/8Lm + 7//B5e7/uOXv/7fj7f+14u3/suHt/7Pi7v+u4O3/g9Po/3HB4f9eo9b/QHrL/zJfx/82Ycj/NmDH/zBc + yv9CYsr/P2HK/z5fyf8/ZMn/Q2vK/0x4zf9dkNL/cqTZ/4K94v+Tzun/oNns/6He7f+l3u3/pt/t/6rg + 7f+t4u7/tePt/7Xj7f++5Oz/seTu/8Ll7f++5e3/t+Xu/7/l7f/E5u3/wubu/8Tm7v/F5u3/zefs/8vn + 7P/R5uv/0ebr/9Tl6v/W5er/2uTo0d3j5zkAAAAArK6xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKZ0iADlrsYO5aLB1OSUuf/kj7b/5Iay/+V8 + q//meKj/5oSx/+dclP/lga//5XGi/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA56vDf+acvf/mh7H/6YCu/+hvof/nb6L/6Xan/+mM + rf/f5+v/1urv/8/o7v/K5+7/xufu/8Lm7v+/5u7/t+Xv/7Pj7v+y4u7/rODt/6Te7f+Tzuj/eq/c/2KJ + 0P8rSsT/CwC//wwAv/8IBL7/BAG4/wIBrP8BAa//AAC3/wYEwP8MBsT/EgfF/xMIxf8SBsb/DwTG/w8F + x/8NAcX/BADE/w0axf8yUsr/UobT/3Kl2/+Jx+b/ndnr/6Xc7P+k3u3/p9/t/7Dh7f+04u3/vOPt/7nk + 7P+25O3/u+Tt/7nk7v++5e3/wuXt/8Xm7v/E5u3/x+bt/8/m7P/P5uz/0ebs/9Hm6v/U5er/2OTp+Nzj + 54/f4uQMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABmVVwA477NBeWiwKnjlLn/44iy/+OLtP/kirT/5H+t/+V7qv/kg7D/5mSZ/+SArf/kdqf/AAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADoqcNk557A/+WFr//ngq7/54q1/+d3p//peKT/4dzi/9Xp7v/K6O//yOfv/8Xm7v+75e//tuTv/7bk + 7v+t4e7/rODt/5jV6v9up9j/PWbH/xMev/8HAL//BAG9/wEAtv8AAKX/AACg/wwEsf8zIcb/UDvb/2NN + 5P9yW+f/fGPo/4Fo6f+Daun/hWno/4Bk5/94XOf/cVTn/2VL5v9cQuX/Ujvj/0Uw4f82It7/IxDZ/xYY + 0/86Ydf/aZ3d/5DO6P+g3Oz/p97t/6vg7f+w4e3/suPt/7Tj7f+54+z/u+Ps/7rl7f+95e3/wOXt/77m + 7v/A5u7/yObt/83m7P/O5uz/zebs/9Dm6//T5er/1+To/9vj59Dd4+Y3AAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAXFBUAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOS0yRLkqcSw45e6/+OKs//khrD/4oey/+KF + sf/jeKn/43+t/+OCsP/lYpn/5Hmo/+Vwo/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOipxE3ooMD/55K3/+Z8qv/mibL/6IWy/+XF + 0f/W6e7/0eju/8Ln7/+75u//uePu/7bi7f+v4u7/rN/t/5jU6v9mnNT/GzW8/woEvf8DAb3/AQC2/wAA + p/8DAZj/Ixaz/0851P92XOb/kXfp/6GJ6/+okuz/rpnr/7Kd6/+0n+v/tJ/r/7Oe6/+znev/sp3s/7Ca + 6/+sluv/po/r/56G6v+Xfen/knbo/4tw5/9+Y+b/Zkzk/0sz4f81IN7/Kifa/1uK3/+Nyej/oNzs/6be + 7P+p3+3/rOHt/7ri6/+34+z/t+Tt/7Xk7v+55e3/vuXt/7fl7v/B5u3/x+bs/8vm7P/H5uz/zebs/8/m + 6//Q5er/1OXp/9jj6PTg2+G75sbUvebD0sHmxdTE58XTxObE08PmxNO+5sXTuebG1LLmxdOu5sbUrObG + 1Kvmx9Wp5sfVp+bH1J/mx9SW5snVjObI1YDmyNV05snVZ+bK1lbmy9ZH58vXNebN2CPmzdgU583YCubN + 2AXjsMdE46PA3uSZu//ij7b/44aw/+KCrv/hhLD/4oCu/+KDr//jcaT/5Hen/+Vyof/keKf/42ab/wAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAwKCoA6KnEQ+mdv//ojLX/5oi0/+d8qv/mo7//3Ont/87p7//J5+7/t+Xu/63j7/+t4e7/p97t/5zZ + 7P9wqtn/IEC+/wgBu/8DAbz/AACz/wAAn/8MBJr/RjPE/3Vd5P+UfOr/qZLr/7Oe7P+5pez/vqzs/8Gw + 7P/Dsu3/xLTt/8W17f/Gt+3/x7ju/8i47v/Iue3/x7ft/8W17f/Csuz/v67s/7uo6/+0oOv/r5nq/6uU + 6f+ljuj/ln7n/4Np5f9oTeX/UDbi/zss3v9ah+D/jMnp/6Lc7P+n3+z/seDr/6zi7f+y5O7/tuTt/7bk + 7f+95O3/tuTt/73l7f/A5e3/x+bt/8nm7P/M5uz/yObs/87l6//R5er/0+Xq/9fk6P/e2OD/5L7P/+S4 + zP/ktsv/5bbL/+W1y//lt8z/5bbL/+S1yv/ltsv/5LfM/+S3zP/kuMz/5LrN/+W6zf/lu83/5bvN/+W9 + z//lvs//5b/P/+XA0P/lwtH/5cPR/+XF0vzlwtHw5LLI3+Ogv/3jlbn/4ouz/+GIsv/if6z/4X+s/+F9 + q//ifaz/4n2r/+N+rP/lZ5r/5WOY/+Rzo//jdaT/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADoqMI1556+/+eOtv/mfq3/5Yax/+HY + 4P/V6e7/yOjv/73m7/+t4+//o9/t/57d7f+Iy+j/QHHG/wUAuP8DAbr/AAC1/wAApv8DAJb/Uj7C/4lw + 5f+pkuv/uabs/8Gw7f/Gtu3/yLnu/8m77v/LvO7/zL3u/82+7v/OwO7/zsHu/8/C7v/Pwu7/zsHu/83A + 7v/Mvu7/y73u/8q77f/Iue3/x7ft/8S07P/BsOz/vavr/7uo6v+2oun/rJfp/6CI5/+Ocub/eVzl/2NH + 4v9EOd//YI/h/5PQ6v+k3Oz/pt/t/67i7f+x4+3/tOPt/7nj7P+25O3/uuTt/7Pk7v/D5e3/xeXs/8vl + 6//K5uz/yebs/8nl6//R5er/0uXr/9bk6f/b3eP/48TS/+W7zf/luc3/5LbL/+Syyf/ksMj/5LDI/+Sv + x//krMb/5KzG/+Sux//kq8X/5KnE/+Ssxv/krcb/463H/+Stxv/jrcb/5K7H/+Oqxf/kq8X/5KfE/+Oi + wP/jmLv/45G3/+KLs//hhrD/4YKu/+F3p//hfqz/4Xin/+Jzpf/icqP/43mq/+Ztn//mZZf/5HWl/+N5 + qP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAOmrxSvnocD/5pK4/+aRuP/kuMz/2Ont/87o7v/D5u//s+Lu/6Pf7v+b2+z/esLj/yA+ + u/8GAbj/AgC2/wAAr/8AAJv/PCyt/4hx4f+slev/vavs/8W17f/KvO7/zb/u/87B7v/Qw+//0cXv/9HG + 7//Sxu//0sfv/9PI7//TyO//08jv/9LH7//QxO//z8Lu/83A7v/Mvu7/y73u/8q87f/Ju+3/ybrt/8e4 + 7f/Ftez/w7Ps/8Cv6/+9q+v/uabq/7Gd6P+ji+j/lHnn/4Fm5f9gRuL/QEff/32s5P+a2ev/o93s/6jg + 7P+s4e3/tOLs/7Pj7P+34+z/tuTt/7rk7f/D5e3/xeXt/8bm7P/F5ez/yubs/87l6//O5ev/0eXr/9Xk + 6f/Z3+X/4cHS/+SxyP/ktMr/5LbL/+S3y//ktcr/5LDI/+Stxv/kq8X/5KjE/+Omw//jpsP/46PB/+Sg + wP/kocD/45y+/+Ofv//jnb7/45m9/+OXu//jlLn/45O5/+KOtv/iibL/4YSu/+GFsP/hgKz/4Xqo/+B6 + qP/hd6f/4m+h/+N2pv/jc6P/5WCT/+Rmmv/kaJz/5Gmd/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6KrGH+egwPvokbj/55W6/93j + 6P/R6O7/xOfv/7vk7v+o4O7/oN3t/4XF5f8bO7f/BgK0/wEAtf8AAKv/BgOZ/2dUyf+nkOr/uqbs/8S0 + 7f/Juu7/zL7u/87A7v/Pwu//0sXv/9PJ7//Vyu//1czv/9bM7//Wze//1s3v/9bM7//Vy+//08fv/9HE + 7//Pwu7/zsDu/82/7v/Mvu3/y73t/8q87f/Ju+3/ybrt/8e47P/Gt+z/xbbs/8Oz7P/Bsev/vq3q/7im + 6v+vm+n/ppDn/5mA5f98YeT/UDfh/1yF4f+S0ur/n9zs/6He7P+s4Ov/s+Hr/7Ti7P+v4+3/t+Pt/7nk + 7f+85e3/weXt/8Hl7f/H5ez/yubs/83l6//O5ev/0OXr/9Pk6v/X4eb/38nW/+Slwv/kp8P/5KrE/+St + xv/kr8f/5K3G/+Sux//krcb/46rF/+Skwv/koMD/5Jy+/+Sdvv/knL7/5Ja7/+SXvP/jlbv/45G4/+OP + t//ijLX/4ou0/+GGsP/ghbD/4H2s/+CCrv/gfav/33im/+Brnv/ib5//4myd/+Nvov/kZJf/42+e/+Vn + mv/lZ5n/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAADpqsMV6aHA9emSuf/lxNT/1unt/8vm7f+95e7/tuLt/6nf7f+O0On/KFC7/wUC + tf8BALX/AACq/w4Hmf98Z9j/tJ7r/7+u7P/Ht+3/yrzu/8y+7v/NwO7/z8Hu/9HD7//Tx+//1cvv/9fN + 7//Yz+//2M/v/9jQ7//Yz+//187v/9XL7//Tx+//0cTu/8/B7v/Nv+7/zL7t/8u97f/LvO3/yrzt/8q7 + 7f/Ju+3/ybrs/8i57P/HuOz/xrfs/8W17P/Ds+v/wLDr/72s6v+3pen/sJzo/6SN5/+MceX/ZUnj/1Ri + 3/+Kx+j/mtrs/6Hc6/+s3uv/r+Hs/7Ti7P+54uz/tOPt/7vk7f+85e3/veXt/7/l7f/G5ez/xuXs/8vm + 7P/M5ez/0OXr/9Hk6f/V4uf/3srX/+Oiwf/jnL//45+//+Ojwf/jn7//46bD/+Olwv/jp8P/46TB/+Oi + wf/jnr//45i7/+SUuv/jlLr/45C4/+OTuf/jj7f/44y2/+KHs//ijLX/4YSw/+B9q//gean/4H6s/998 + q//fd6b/4Gqb/+BnmP/gcaD/4GaY/+Fyov/ic6L/42KW/+Rjl/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOiuxhHppMPy6Jq8/97l + 6v/Q5+3/w+Ts/7rj7v+r4O3/mtns/0R4xf8EALP/AQC0/wAAqv8MBZv/g23a/7ei6//Csez/yLnt/8u8 + 7v/Mvu7/zb/u/87A7v/Pwe7/0cTv/9PH7//Vy+//187v/9nQ7//Y0O//2NDv/9jQ7//Xzu//1cvv/9PG + 7//Qwu7/zcDu/8u97f/LvO3/yrzt/8q77f/Ku+z/yrvs/8m67P/Juuz/yLns/8i57P/HuOz/xrfs/8W1 + 7P/Ds+v/wrLr/7+v6/+8qur/taPp/6uV6P+VfOb/b1Tk/1JT4f9/uOb/mtnr/57b6/+k3uz/quHs/7Hi + 7P+14+z/uePs/7rk7f+15O3/v+Xt/8bl7P/H5uz/yuXs/8nl7P/L5ez/0OXr/9Lk6f/V4uj/3NDb/+Kc + vv/jmLv/4pW7/+Obvf/jm73/45y+/+Ocvv/jmrz/45+//+Obvf/jmr3/45e7/+OSuf/jjrf/45C4/+KM + tv/ijrf/4omz/+KEsf/hfqz/4Xuq/+Bil//feaj/3nGh/99voP/geKb/33Kh/99mmP/fdKP/33in/+Fh + lf/jYpT/422d/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA6K3FDemjwu3lwNH/1+nt/8vn7v++5O3/r+Ht/6Dc7f9pqNj/AQCw/wEA + s/8AAKv/AACc/3xm0/+4pOv/w7Ps/8e47f/LvO7/zL7u/8y+7v/Mvu7/zb/u/87A7v/Pwu7/0sbv/9XL + 7//Xzu//2M/v/9jP7//Xzu//187v/9bM7//UyO//0cTu/83A7f/Lve3/yrvt/8m77P/Juuz/ybvs/8q7 + 7P/Ku+z/ybrs/8m67P/Iuez/yLjs/8e37P/Gt+z/xrbs/8W17P/EtOv/wrPr/8Cw6/++rer/uKfq/6+b + 6P+Zgef/e2Lk/1pI4f9tquP/kNXq/53b6v+h3uz/qeHt/7Hi7f+24+z/tuPt/7Xk7v+/5Oz/veTt/8Pl + 7P/H5ez/x+Xs/8jl7P/L5ev/0eTq/9Lk6f/V4uj/3NLc/+KZvP/ilLr/4pS6/+KVu//jl7v/45W6/+OV + uv/jmbz/45a7/+OTuf/jlrv/45O5/+OPt//jibT/4oq0/+KGsv/ifq3/4n+u/+KBr//hean/4GaX/99w + oP/fbJz/3VWH/952pP/eapr/3mqa/952pf/eaJr/4GaY/+Jkl//iZ5r/AAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADjucoF6aHA4+Hd + 5P/Q6O3/w+bu/7jj7v+q3uz/iM/o/xo9tP8CALL/AACu/wAAof9iUcH/taHq/8Sz7P/Juu3/yrzt/8y9 + 7f/Mvu3/zL7t/8y97f/Mve3/zL7t/87A7v/Qw+7/08fv/9TJ7//Vyu//1Mrv/9TJ7//TyO//0sbu/9DE + 7v/OwO3/y73t/8q77P/Juuz/yLns/8i57P/Juuz/ybrs/8m67P/Iuez/yLjs/8e37P/Gt+z/xrfs/8a3 + 7P/Gt+z/xbbs/8W16//Etev/w7Pr/8Gx6/+/r+r/u6rq/7Gf6P+Yg+X/e2Hg/0w42v9knN7/kdTp/5na + 6/+l3uv/reDs/7Di7P+y4+3/tuPt/7nk7f/A5e3/veXt/8Tl7P/F5ez/yOXs/8rl7P/M5ev/0OTr/9Hk + 6f/U4uf/29Db/+Gbvf/ikbj/4pC4/+OUuv/ikrn/4pS5/+OTuf/jlLn/45O5/+OTuf/jjrb/44+3/+OH + s//jiLP/44Cv/+OCsP/jgrD/4nmr/+J9rP/gaZz/33Cg/99unf/ebZv/3WOV/95ik//ea5r/3m2e/95u + nf/gZ5j/4GmY/99Qhf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADotszE2ujs/87n7f++5O7/seHt/6Db7P9bmdH/AgCv/wAA + sf8AAKj/LySn/6qW6P/Csez/x7nt/8q87f/LvO3/y73t/8u97f/LvO3/yrzt/8q87f/LvO3/zL7t/87A + 7v/Pwu7/0MPu/9DD7v/Pwu7/z8Hu/87A7v/NwO3/zL7t/8q77P/Juuz/yLns/8e47P/HuOz/x7js/8i5 + 7P/Iuev/yLnr/8e47P/Gt+z/xrfs/8a37P/Gt+z/xrfs/8a36//Gt+v/xbbr/8S16//DtOv/w7Pr/8Ky + 6/+/sOr/uKjo/6iU5f+LdN//bFPZ/0Mx0/9cmNz/ktXp/5ra6v+j3er/reDr/7Th6/+64uz/tePt/7rk + 7f+55O3/vOTt/8Pl7P/A5ez/x+Xs/8jl7P/K5ez/zeXr/8/k6//V4ej/2tHc/+GXu//ijLb/4om0/+KQ + uP/ikrn/45C4/+ONtv/jj7f/4462/+OMtf/jjLX/44m0/+OHs//jgq//4nys/+OBr//hX5P/4n2r/+Bz + pf/fbaD/3mWY/95sm//dRnn/3VmM/91dkP/dW47/3miX/99De//gapv/31iK/wAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOTY + 4KLU6O7/x+bt/7fj7v+o3u3/kdXr/x5Etf8BALH/AACt/wAAnP+GdNT/vqzs/8a37f/Ju+3/yrzt/8u9 + 7f/Lve3/y73t/8q87f/Ku+3/ybvt/8q77P/Ku+z/yrzs/8u97f/Lve3/y7zt/8q87f/Ku+z/ybvs/8m6 + 7P/Iuez/xrjs/8a36//Ftev/xbXr/8W26//Gt+v/xrfr/8a26//Gtuv/xbXr/8W16//Ftev/xbbr/8W2 + 6//Ftuv/xrbr/8a26//Ftuv/xLXr/8S06//Ds+v/wLDq/7ur6f+zoef/qZTk/5mD4P+EbNz/aU/Y/0Is + 0v9hnN3/jtTp/5ja6v+l3Or/rN/r/7Th6/+t4u3/tePt/7Xk7f+65O3/weXs/8Hl7P/C5Oz/yeXs/8fl + 7P/M5ev/zOXr/9Dk6v/U4uj/2tPd/+CXu//ijLb/4ou1/+KGsv/ijrf/4oez/+OIs//jirT/44q0/+OF + sv/jibP/4oey/+KFsf/ifqz/4n2s/+Jxo//icKP/4nin/+BtoP/gcqP/3muc/95Pgv/dUYL/3F2O/95w + oP/cWYv/3WOS/95nmP/eXY//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3urtp83n7f/A5O3/reDt/6Ld7P9zt9//AACp/wAA + rv8AAKf/Niqn/7Wi6v/Etez/ybrt/8q87f/KvO3/yrzt/8u87f/KvOz/yrvs/8m67P/Iuez/yLns/8i5 + 7P/Iuev/x7ns/8e47P/Ht+z/xrfs/8a36//Gtuv/xbXr/8S16//Ds+r/w7Pq/8Oz6v/Ds+r/w7Pq/8S0 + 6v/EtOr/w7Pr/8Oy6//Csuv/wrLr/8Oz6//DtOv/xLXr/8S16//Etev/xLXr/8W16//Ftev/xLXr/8Gy + 6v+7q+n/s6Hm/6yX5P+mkeL/oYzh/5eC3/+Gbt3/Z07Y/0Au0f9qpN3/lNbo/5vY6P+g3Or/pd/s/6zi + 7P+v4u3/rePt/7Xj7f+55O3/vuTs/7/l7f++5Oz/vuTs/8vl7P/N5ev/zOTr/9Dj6v/U4ej/2tPe/+CP + t//hhrP/4oez/+KMtv/ih7P/44Wy/+ONtv/ji7X/44Wx/+OKtP/ih7L/4oGv/+F/rf/hfKv/4Xmp/+F8 + q//gcKL/4W2g/+Btof/fZpr/3maW/9xcj//ccqH/3Guc/9tglP/ecKH/3WaX/95jlP8AAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHx4eAODq + 7g7Y6e7pyebt/7jj7f+s3+3/l9ns/1CNyv8AAKb/AACo/wAAmP+BcMv/wbDs/8e57f/KvO3/yr3t/8q8 + 7f/KvOz/yrvs/8m67P/Iuez/yLns/8e47P/Gtuv/xbXr/8W16//EtOv/xLTr/8S06//Ds+v/w7Pq/8Oy + 6v/Csur/wbHq/8Cw6v/AsOr/wbDq/8Gx6v/Bser/wbHq/8Gx6v/AsOr/wK/q/7+v6v/AsOr/wbHq/8Gx + 6v/Bsur/wbLq/8Gx6v/Bser/wLDq/7+v6f+9rOn/uafo/7Sh5v+tmeT/qZTj/6eS4v+lkOL/oYzg/5iD + 3/+FbNv/ZErX/z8z0f9wseD/j9bp/5nZ6f+e3On/pt/s/6rh7P+t4uz/tOLr/7rj7P+55O3/uuTt/7vk + 7f+/5ez/yeXs/8nl7P/E5ez/zuTr/9Hj6v/U4ej/2dDc/+B/sv/hdKz/4oi0/+KGs//ihLD/44m0/+OJ + s//ihLD/4oiy/+KJs//ihrH/4Xur/+F/rf/hdaf/4Xao/+Fvov/hc6X/4Gug/+Bmm//dU4n/3mud/9tt + nf/aXZD/3FyN/9xunv/bVob/3FKF/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3ursQ9Lo7v/D5u7/tOLt/6Ld7P+P0+r/Klu0/wAA + n/8AAJn/AACN/66c5f/Ftu3/ybvt/8q87P/KvOz/yrvs/8m67P/Iuez/x7js/8a37P/Gtuv/xbXr/8S0 + 6//Ds+r/wrLq/8Gx6v/BsOr/wbDq/8Cw6v/AsOr/wK/p/7+u6f++ren/va3p/72t6f++ren/v67p/76u + 6f++run/vq7p/72s6f+9rOn/vKzp/76t6f++run/vq7q/76u6v+/r+r/va3p/7uq6P+5puf/taPm/7Gd + 5f+smOT/qpbj/6mV4/+plOP/p5Pj/6aS4v+jj+H/n4vg/5eB3v+Badr/XkbV/0JC0f94uuH/jdTo/5TZ + 6f+e3er/ouDs/6nh7P+s4ez/t+Lr/7bi7P+65Oz/ueTt/77k7P/H5ev/xeXs/8Tl7P/N5ev/zuTr/9Lj + 6f/V4uf/2s3a/+CGs//hgLH/4oi0/+KIs//ji7X/43+u/+KEsP/ihrL/4oWx/+GCr//hdKX/4Xmq/+Fw + pP/hdaf/4XKl/+Fwpf/gX5j/4Wee/95Xjf/eZZn/21+T/9xpmf/dYpT/20l8/9xgjf/cXYz/AAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADc6e2byuft/7zk7f+p4O3/ltnr/3rK6P8SK6H/AACb/wAAj/9SRKj/va3r/8e57P/Ju+3/yrzs/8m7 + 7P/Iuuz/x7js/8a36//Ftuv/xLTr/8Oz6//Csuv/wrHq/8Gx6v+/r+r/vq3p/76t6f++ren/va3p/72t + 6f+9rOj/vKzo/7uq6f+7qen/u6rp/7yr6P+8q+j/u6vo/7ur6P+6quj/uajo/7qp6P+7quj/vKvo/7ur + 6P+6quj/uqno/7in5/+0o+b/sZ7l/62Z5P+qlOP/ppDi/6WP4f+lkOH/ppHi/6aR4v+lkOL/pJDi/6OP + 4f+ijuH/n4rg/5V/3f96Ytr/XETU/0NO0P97xOT/i9bp/5XZ6f+e3uz/pODs/7Hg6v+t4ez/seLs/7Pj + 7P+24+z/u+Ts/73k7P/A5ez/xuXs/8jl6//K5ev/zuTq/87j6v/T4ef/28jX/+CDs//hh7P/4Xet/+KH + s//jhrL/44ey/+N/rf/if67/4oiz/+J7qv/hf63/4Xeo/+F2qP/hc6b/4Wqg/+Flnf/gZJr/4Gmf/99k + mv/eZ5z/3V2T/9xTh//eZZb/21WG/91tnP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4OnrCdno7OjC5e3/sOLt/6He7P+K1ur/bb3j/wIW + m/8AAJj/AACI/3Zkxf+6qur/xrns/8m87f/Ju+z/yLrs/8e46//Ftuv/xLXq/8Kz6v/Bser/wLDq/7+v + 6v+/r+n/v67p/76u6f+8rOn/u6ro/7uq6P+7quj/uqro/7qp6P+5qOf/uKfo/7im6P+5p+j/uajo/7mo + 6P+5p+j/uKfn/7al5/+1o+f/taPo/7Wj5/+0ouf/sqDm/7Cd5f+tmeP/qJTj/6SP4v+hjOH/oYvg/6GL + 4P+hi+D/oYvg/6KM4P+ijOD/oY3g/6GN4P+ijuH/oY7h/6GN4P+gjOD/nIjf/4553f91Xdn/W0TV/0Je + 0v9/y+X/i9bp/5fZ6f+e3ev/o+Ds/6fg7P+z4ev/ruLt/6ri7f+34+z/uuPs/7vk7f/B5ez/xeXs/8fk + 6//K5Ov/zeTr/9Lj6f/V4Of/3MHT/+B6rv/hg7L/4Xqt/+KIs//jirT/436t/+N/rv/jhLD/4n6t/+J/ + rf/hbKH/4Xip/+Fypv/haJ//4XCj/+Fnn//gXZX/4Guf/+Bck//gYJT/3UV5/91hk//cVIX/3F+R/wAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADg6ewx1unt/8Dk7f+p4Oz/ndzr/4XT6v9UodD/AACX/wAAk/8AAIj/j3nY/7Oi5//Bs+r/xbjr/8W3 + 6//Ftuv/xLXr/8O06v/Csur/wLHq/76u6f+9rOn/vKvp/7yr6f+8q+n/u6vo/7qq6P+5qOj/uKfo/7im + 5/+4puf/t6bn/7el5/+2pOf/tqTn/7el5/+4puf/t6bn/7al5/+1o+b/tKHn/7Gf5v+wneb/rprl/6qW + 4/+mkuH/oovh/52F4P+YgN7/lX7d/5Z+3v+Ygd7/mYLe/5qE3/+bhd//nIXf/52G3/+dh9//nojg/56K + 4P+eiuD/n4vf/5+L4P+eit//mITe/4p12/92X9n/VD7S/0Vz0/+Azeb/jNbp/5ba6v+e3+z/pt7r/6zg + 6v+v4ev/rOLs/7Hj7P+44+z/uuTt/7zl7f/E5ez/weTs/8Pl7P/J5Ov/zuTq/9Hj6f/W3+b/3rPM/+F6 + r//hWqP/4Xuv/+KBr//jhrL/44Sx/+OCsP/jf67/43Wo/+Bhlv/heKj/4Xeo/+Fuov/ha6H/4F6X/+Bi + mP/gcaT/4WGX/948c//eUof/3nCg/95pmv/eMGb/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASEpLAN3p7GvQ5+3/vuPs/6ff6/+Z2+v/hNLp/zt7 + vP8AAJf/AACP/ycdkf+eiOL/sJ/m/7en5/+7quj/va3p/7+w6f/Asen/v7Dp/72u6f+8rej/u6vo/7mp + 6P+4p+j/uKfo/7mo6P+5qOf/uajn/7mo5/+4p+f/t6Xn/7al5v+2peb/taTm/7Wj5v+1o+b/taPm/7Si + 5v+yoOb/sJ3l/66Z5P+qleP/ppLi/6SP4f+hi+D/nYfe/5mC3v+Wft3/lHvd/5N52/+Tetz/lHzd/5V9 + 3f+Vfd3/lX3d/5R93v+Vfd3/ln/d/5iB3v+Zg97/mYTf/5qF3/+aht7/m4bf/5uH3/+bh9//lIDd/4Rw + 2f9rVNP/OibG/1SP0P+H0+f/j9jo/5Xb6v+c3Or/pd7r/6zh6/+o4uz/r+Ls/7Di7P+25O3/t+Xt/77l + 7P/A5ez/vuTt/8fk6//M5Ov/zuTq/9Ph6P/W3eT/3qfG/+Juq//hdq3/4YKx/+KFsv/jfq7/5ISy/+SF + sf/jZ57/4nKj/+J+rP/geKj/4Han/+Fypv/hcqX/4Xao/99soP/gY5r/30J4/+Bqnf/dW5H/3m6f/940 + Z/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAA3Ortpcvn7f+64+z/o97r/5na6v96zef/HUqm/wAAlv8AAI3/STqm/6aS5P+wnuX/sJ7k/7Cd + 5P+yoOX/s6Ll/7Oi5f+zoeb/s6Lm/7Sj5v+0o+b/taPm/7Wj5v+1o+X/taPm/7Wj5/+1pOb/taTl/7Oh + 5f+xnuX/rpvl/6yZ5P+qluP/qZbj/6iU4/+nk+L/ppHh/6KM4f+eh+D/moLf/5iA3v+Xf93/ln3c/5N6 + 2/+Qdtz/jnTb/4102/+OdNr/kHba/5B32/+QeNv/kHfb/5B32/+Pdtz/jnbc/4933P+ReNz/knvc/5R9 + 3f+Uft3/lH/d/5WA3f+Xgt7/l4Tf/5eF3/+Ugd3/iXXY/3Zi0f9OOcj/Ixy5/2Wv2P+F0+b/ktjo/5Pb + 6v+d3er/oOHs/6bi7f+n4ez/ruLs/7Hj7f+x5O7/vOXt/7/k7P/B5Oz/w+Ts/8nl6//L5ev/0OPp/9Li + 6P/X2uL/3qHD/+B5r//ghrP/4YSy/+N6r//khLD/43ur/+R/rP/jdKX/44Ow/+F/rP/hd6j/4Guh/+Fx + pf/gcaP/4HKk/+Bqnf/gVYv/4GOZ/95hk//eZJj/3VSG/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOfy+QDZ6e3Yw+bu/7Hi7f+k3ev/mtrq/3bE + 4/8BHpj/AACR/wAAiv9oVrn/p5Tk/66d5f+uneT/rJnj/6mW4/+mk+H/oo/g/6KO4P+jkOH/pZLh/6eT + 4f+oleL/qJTi/6eS4v+mkeL/ppHi/6aR4v+lj+H/oo3g/6CL3/+dh9//m4Pf/5iB3v+Wf93/lX7d/5N7 + 3P+Qd9z/jXPb/4xy2v+Kcdr/inDZ/4tx2P+Lcdj/inDZ/4hv2f+Ib9n/iW/Z/4pw2f+Kcdn/inHa/4px + 2f+Jcdn/iG/Z/4hv2f+Hb9r/iXDa/4px2v+Lc9r/jHTa/4x12v+Nd9v/j3nb/5B73P+Oetz/jHfb/4dz + 2P9/a9X/dmLR/2VRyP86KsH/KD63/3LB4P+G0+b/i9nq/5Xc6v+g3uv/ouHs/6Xh7P+n4ez/quLt/7Dk + 7f+25O3/uuPs/7/k7P/B5Oz/xuXs/8nl6//L5ev/zuTq/9Th6P/X1uD/3pe9/+B5rf/hh7P/43Ks/+SG + sv/kgK7/5Iax/+SCr//jg7D/4n2r/+J8q//heKj/4Xeo/+Bpnf/gb6L/4W+i/+Bdkv/fY5f/3lmO/91l + mP/eZ5n/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAA4OrtEtbp7vnD5O3/suHr/57c6v+P1+n/bbba/wAAkP8AAJH/AACF/3tpyf+mleP/q5rk/6ya + 4/+oleL/pJHh/6GN4P+eid//m4Xe/5mF3v+ZhN7/mYTd/5mD3P+YgN3/ln3d/5J83f+Qetz/kXnb/5B4 + 2v+Qdtr/j3Xb/4502v+Mctr/i3Ha/4tx2v+Kcdn/inDZ/4lv2f+Jbtj/iG3Z/4ht2f+Ibdj/h27Y/4Zt + 2P+FbNf/hGvX/4Rq2P+Eatj/hGrY/4Rr2P+Ea9f/g2vX/4Jq1/+BaNf/gWjX/4Fo1/+Cadj/hGrX/4Rq + 2P+Fa9j/hW3Z/4Rt2f+Ebdj/g23X/39o1/94YtT/cFzR/21b0f9tWc//aVfK/1E/w/8sHrn/OWy9/3zO + 5P+I1ef/j9np/5nc6v+a3uv/n9/r/6Lg7P+l4e3/quPt/7Hj7f+34+z/v+Tr/77k7P++5Oz/xOXs/8rl + 6//I5ev/0ePp/9Ph6P/X097/3oi1/+CCsv/iZ6n/43us/+R3qf/kfaz/44ez/+N+rf/jf6z/44Kv/+Fy + pP/ieKn/4Xao/+FlnP/gbqL/4GSa/99vov/eZ5n/32yf/9xWjP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKeqrQDe6u1F0+jt/8Hk7P+u4Oz/mtvq/4zW + 6f9eocv/AACI/wAAjP8AAH3/iXbT/6aV4v+pmOL/qJbh/6OR4P+fjOD/nYrf/5uH3v+Yg93/lH/c/5J8 + 2/+Qedr/j3jZ/4922f+Mc9r/i3La/4px2v+JcNn/iXDZ/4lw2f+Ib9n/h27Z/4du2P+Gbdj/hm3Y/4Zt + 1/+FbNf/hWvX/4Vq1/+Eadf/g2jX/4Jn1/+BZ9b/gGbW/4Bm1f9/ZdX/fmPW/35j1v9/ZNX/f2XV/35k + 1f98Y9T/e2LU/3ph1P97YdX/fGLV/3xj1f99Y9X/fWTV/31k1f99ZNX/emHU/3Ve0v9xWdH/bVXP/2dQ + zP9kTc3/Y03N/2NOyv9iT8n/WknG/zwuvf8kGbL/SY7J/3fN5P+J1uf/jNrq/5Tc6v+b3ev/nN/r/57g + 7P+m4ez/quLs/7fi6/+34+z/tuTt/7Xk7v/A5O3/x+Xs/8fl7P/L5Ov/zeTq/9Ph5//aydn/4IKz/+F0 + rf/iea//44Sy/+ODsP/jg7D/436t/+OBr//jgK7/43ao/+J4qf/ib6P/4nSm/+FzpP/hcKP/32me/95z + pP/eaJv/3VqN/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAANrp7YjQ6O3/vOPs/6be6/+U2uv/g9To/0uOuv8AAID/AACB/w0Hd/+Sftz/pZTi/6aW + 4f+kkuD/nozf/5mG3v+Wgt3/lH/c/5J92/+Qetr/jXfa/4t02v+Kctn/iXDZ/4hv2f+Ib9j/h27Y/4Zs + 2P+Fa9j/hGrY/4Np2P+Cadf/gGjW/4Bn1v9/Ztb/f2XW/35k1f9+ZNX/fmTV/35k1P98Y9X/fGPU/3xi + 0/97YtP/emHT/3le0/93XNT/d13U/3hf0/93XdP/dlzT/3Vb0v90WtH/dFrS/3Ra0v91W9P/dFrS/3JZ + 0v9wV9H/bVTP/2pRzv9mTM7/YkjM/2BGyv9eRMr/XEPJ/1tDyf9aRMj/WkTI/1lFyP9VRcX/RDi9/zEl + tP8bGqn/V6bQ/33Q5f+F1+n/i9nq/5ba6f+Y3Or/n93q/6Lf6/+i4e3/qeHt/7ni6/+x4+3/uOXt/73l + 7P/E5ev/yOXs/8jk6//P5Or/0OPq/9Xf5f/buM//4Hux/+F9sP/hea3/4oWy/+OFsv/jgq//44Kv/+OE + sP/kf63/432t/+N1p//idaf/4myi/+Fuof/gaZ7/33Sk/91ilf/fcqH/AAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA2ejtzsnm7v+z4+3/pN7r/5ba + 6v+A0uf/OXSp/wAAef8AAHj/GRJ7/5eD3/+klOH/o5Pg/5+O3/+Yht3/k4Dc/5B82/+Nd9r/i3TZ/4ly + 2f+IcNj/hm3Y/4Rq1/+CaNf/gmjW/4Jp1f+BZtb/gGbW/39l1v9/Zdb/fmTW/3xj1P97YtT/emDV/3pg + 1f96X9T/eV7T/3he0/94XtP/eF3T/3dc0/92XNL/dlzR/3Zb0f90WtD/c1jQ/3JY0f9yWdL/clnR/3JY + 0P9xV8//h3fT/56U1v94ZM//cVfR/25V0f9pUc//ZEzN/2FHyv9dQ8b/Vz7D/1U7w/9UOsT/VTvF/1Q5 + xv9SOsb/UTrF/1E8w/9TPMX/Uz3E/088v/9GN7r/Ny22/yEaqv8WNKf/Ybfc/3/Q5v+C1ej/jtfp/5ba + 6f+X2+r/oNzq/6He6/+l4Oz/rOHs/7Ti7P+z4+3/tOTt/7/l7P/F5ez/yOTr/83k6v/P4+j/0uLo/9bc + 5P/cscz/4IOz/+Fuq//ifa//43Or/+SDsv/keqr/436t/+SEsf/kfq3/5Hmq/+R5qf/jbqP/43io/+N2 + p//hdKb/322g/950pf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAOHp7BvV6O32x+bt/7Di7f+b3Ov/jtjp/3/P5/8pX5j/AAB3/wAAdP8bEnv/jnnc/56N + 3/+cjd//l4bc/5GA2/+Oetr/iXTZ/4Vw1/+CbdX/gmvV/4Fp1f+AZtX/fmXV/3xh1f97YdT/e2LT/3xg + 0/97YNT/el/U/3hf1P94XtP/d13R/3Zb0v91WtP/dVrT/3Ra0v9zWdH/cljS/3BX0v9wVtL/cFbQ/3BW + 0P9wVc//b1TP/21Tzv9sU83/bFPO/21Vzv9uVc3/bVPN/4R10f/m5en/6+vr/9zb5v9/b83/YEbI/1lA + x/9UO8X/UDfD/0w1wP9LM77/TTW//042wP9ONsH/TDXA/0s0wP9IMr//SDK//0kzwP9HMsD/RTG8/0Av + t/85LbP/LSmt/xgZnv8sXaf/a8Ph/3XS6P+F1un/h9jr/5Ha6v+g2+n/n93r/6Pf7P+i4O3/p+Hs/7Di + 7f+w4+3/vuTs/7/k7P/F5ev/yOXr/8zk6v/N4+n/0+Lp/9fX4f/dnsP/34Cx/+JwrP/kUqD/5H+w/+Vs + p//kdaj/5H+t/+V1qP/laqD/5Xip/+RwpP/kd6j/42Sc/+FroP/hcqT/4G6h/wAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3OnsSdLo7f/F5Oz/ruHs/5/c + 6v+O1+j/d8vk/xlGjP8AAHP/AABv/xgQev96Ztb/jHvZ/5GB2f+Pftr/infa/4Vx2P+CbNb/f2jV/3pi + 1P95YtP/emLT/3pg0/95X9L/eF7S/3Zc0f91XND/dVvQ/3RZ0f90WdH/cljR/3BX0P9xV87/cVbP/3BV + 0P9wVNH/b1TQ/25Uz/9tU8//alHP/2lPzv9qUM3/a1HM/2pRzf9rUcz/aVDL/2hPzP9oUMz/aE/L/2VL + y/9hRsr/w7/d/+vr7P/r6+v/6urq/9XU4/9XRcD/SDC8/0Qtvf9ELbv/RC25/0QtuP9EK7r/RzC8/0w8 + vf9aWMH/ZmzE/3WAxf+Hms7/iZrO/5+z1/+ku9r/qsDc/67H3/+0zN3/sMrd/7LO3/+32OT/ttro/7Lc + 6f+w3On/qtzq/6jc6v+r3Or/oN7s/5zf7f+o4Oz/quDs/7Hi7P/B4+v/uuTt/8Pl7P/F5ez/xeXs/8fk + 6//O4+n/1OHn/9nN2//elb7/4XKt/+NvrP/lda7/5nSs/+V+rv/lhbH/5Hyr/+V7q//ke6v/43ip/+R4 + qf/keKr/43Wm/+Jxov/hYJT/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAADc6OxtzOft/8Lj6/+v4Ov/m93q/4nV5/9zx+L/Aih+/wAAcP8AAGv/EQps/2xX + z/94ZtT/fGvU/3po1P93ZNP/eGPR/3hh0f94YNL/dl/S/3Rd0f9xWtD/clnQ/3JZ0P9yWdD/cVjP/3BW + zv9vVc3/bVPO/21Tzv9rUc7/alHO/2xSzP9rUc3/a1DO/2tQzv9pT83/aFDN/2lQzf9oT83/Z07M/2ZN + y/9mTcn/ZkzJ/2ZMyf9kScn/YkfI/2BHx/9dRMX/Vj3E/19Nxf/l5un/6+vr/+vr6//q6ur/6urq/66t + 0v87ILX/RTW2/1xcvf9+h8f/iJjN/5ir1P+xyOD/utHj/7/Y5v/E3ej/xuDp/8jh6v/I4er/y+Pq/8zj + 6v/M5Ov/yuTr/83k6//M5ev/zuXr/8vk6//O5ev/zOTr/83k6v/P5On/zePp/8ri6f/C4er/uuHr/67f + 6/+y3+v/teHr/7zj7P++4+z/vOPs/8Tk6//E5Oz/xuTr/8vk6v/Q4+n/1N7m/9q70v/firr/4nOv/+Rv + rf/laqr/5Xet/+Ryp//jirT/5IOw/+R6qv/jean/43eo/+Rjmf/jeKn/43Wm/+JmmP8AAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANjo7Z/I5u7/vuHq/6zf + 6v+b2+n/h9Tn/23D3/8AAGv/AABq/wAAZ/8CAV7/XErE/2tbzv9oV83/ZVPL/2BLy/9gSMv/ZEzK/2dQ + y/9qUs3/alHN/2dOzf9mTc3/Z07M/2hOzP9oTs3/alDN/2pQzf9oT8z/Zk3M/2VMzP9lS8z/ZUzL/2VM + zP9lTMz/ZEvK/2JJyf9gSMj/YEfI/19HyP9eRcj/W0LG/1lAxf9WPcT/VDrC/1A3v/9LNL7/STG9/0Yv + u/9ELLj/kIvH/+vs7P/r6+v/6+vr/+rq6v/q6ur/5OXo/7PF3P+0zuH/wNnm/8fg6f/I4Or/y+Lq/8vj + 6v/M5Or/zOTr/8vl6//M5ev/y+Xr/8zl6//N5uz/zebs/8zm7P/M5u3/zObs/8zm7P/J5u3/yuft/8zn + 7f/N5+z/zubs/87m6//O5ev/0OXq/87l6//Q5er/zuTq/8rj6v/M4+r/zOTq/8Pj7P/B4+v/v+Ps/8Hj + 7P/C5Oz/xOTr/8nk6//R4un/1dfi/9ysy//ggLP/5Eyi/+Vip//la6j/5YGx/+R+rf/kgK7/43+t/+J/ + rf/jean/5Wub/+R6qf/jcaP/43en/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA1ufszsDk7f+64uv/qd7r/5Ha6v9+0+j/ZLzc/wAAZP8AAGf/AABj/wAA + V/9GNq7/YFHK/1tKyf9aRMb/WEDE/1Q8w/9ROsL/UjrA/1M7wP9VPMH/VjzD/1c9wv9XPsL/Vz/D/1lB + xP9bQ8X/XUTG/1xDxP9aQsP/WUDE/1c/xP9YPsT/Wj/F/1lBxv9YP8X/Vz/E/1U9xP9SO8L/UDnA/043 + v/9LNL7/RzG8/0Ywuf9DLbb/Pym1/zwmtP85I7P/Oiiy/1BLtP++v9f/6uvs/+vr6//q6+v/6urq/+jp + 6v/m6er/1uXq/8jj7P/J5ez/y+Xs/8rl7P/K5ev/y+Xr/8vm6//N5uz/xubt/8Tm7f/K5uz/yubs/8jm + 7f/F5u3/xubt/8jm7P/C5u3/yObt/8jm7f/F5u3/yubt/8bm7f/A5u3/yebs/8nm7f/F5ez/yuXr/87m + 6//N5ev/z+Xr/8/l6v/Q5Or/z+Tq/8zk6v/F4+v/w+Pr/7/j6//B5Ov/yOPq/9Hk6f/R4ej/2cfY/96e + w//hfLD/5HGu/+RxrP/kfq//5Xys/+V4qP/jfKv/4oGu/+N9rP/ke6r/5HKl/+V4qf/kbaH/AAAAAAAA + AAAAAAAAAAAAAAAAAADAwMAA7+/vF+vr66TX2985AAAAAAAAAAAAAAAAAAAAAODq7BPU5+3yvuLr/7Dh + 7P+i3ev/jdnq/33R6P9cs9b/AABc/wAAZP8AAF3/AABS/ysgjP9UQ8T/Tz7D/047wv9NOMD/Tja+/0ky + vf9EL7z/Qi66/0Mtuf9GLrj/Ry+5/0Uuu/9ELbz/RS26/0Ytuv9GLbv/RS26/0Msuf9DLLn/RC25/0Uu + uf9HLrn/Ri67/0Qsu/9DK7r/QSu5/0Apuf8/Kbn/PSi2/zwmtP87JLX/OSKz/zorsv9KRbT/bXTC/5el + 0P+xxN3/ydzn/9rm6//j6ez/5+rr/+bq6//k6er/4Ojq/9nn6//R5uz/x+bt/8fm7f/K5+3/wObt/8Tm + 7f/E5uz/w+Xt/8nm7P/D5ez/wuXt/8Xl7P/B5e3/wOXt/8Xl7P/A5ez/w+Xt/8Xl7P/E5ez/xuXs/8Hl + 7P/H5ez/w+bt/77l7f/I5ez/x+bt/8bl7P/H5ez/zObs/8jl7P/L5uz/zeXr/87l6v/O5Or/zeTq/8/k + 6v/O5Or/y+Tq/8Dk7P/C5Ov/yuTq/9Di6f/U1uL/3LfR/9+Ouv/igLL/5G+r/+N5rf/keKv/5X6s/+SA + rv/ifKv/436t/+OArv/jeKj/43yr/+Vypf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu7u6n6urr/9PY + 26wAAAAAAAAAAAAAAAAAAAAA3unsPtPn7f++4en/sN7p/5zb6/+H1+r/eM7m/0+o0f8AAFv/AABg/wAA + WP8AAE7/Dglf/0Mxtf9GM7r/RDC6/0QvuP9CLbj/QSu5/z8puP89KLb/Pii0/z4ntP87JrX/OiW2/zkj + tf86I7T/OSOz/zgjs/83IrP/NyKz/zgjs/85I7L/OSSx/zgksf83I7H/NyKw/zcgr/82IK//NCCw/zIe + r/8zH67/V1e2/3uEw/+Uoc7/ucvf/77U4//M4ur/zeTr/87l7P/O5u3/0Ofu/9Ho7v/U6O3/0+jt/9Pn + 7P/Q6O3/xObu/8Lm7f/D5u3/yebs/8Lm7f++5e7/v+Xt/77l7f+/5ez/x+Xr/8Pk6//C5Oz/wuTs/73k + 7P+95Oz/weXs/73k7P/C5ez/v+Ts/7/k7P/A5Oz/wOTs/8Ll7P/B5e3/u+Xt/8Xl7P/I5ez/yOXs/8Pm + 7f/F5u3/x+bs/8nm7P/I5ez/y+bs/8zm6//L5ev/zeXr/9Dk6v/R5On/z+Tq/8jk6//F5Oz/zOPq/9Lh + 6P/Xz97/3ajK/+GFtf/kbav/5HGs/+R/sP/kiLP/5Iax/+R/rf/jfq3/4n6s/+N8q//jgK3/43Kk/wAA + AAAAAAAAAAAAAAAAAAAAAAAA7+/vLO3t7frq6+v/1trd7srV3Rfa5ekb2eTpIdjk6Bra6Ox+yuXs/7nh + 6/+m3+z/mdrr/33W7P92zuj/TaDO/wAAWv8AAF7/AABU/wAATP8AAET/KxyV/zgmsf84JbL/NyWw/zck + sP82I7D/NiOw/zYir/81Ia7/NCCt/zQgq/8zIKz/MiCu/zMgrv8yH63/MR6t/zEdrf8xHa3/MR6t/zIe + rP8xHav/MB2r/zAcrP8uG6z/Lhyo/zguqv9xe73/k6PP/63C2//H2+f/zeLq/87k6//P5ez/zubs/87n + 7f/M5+3/xubt/8nn7v/L5+3/wefu/8Tn7v+/5u//xubu/8Pm7f/G5u3/v+Xt/8Hl7P/A5ez/uuTs/7/k + 7P/F5ez/vuXs/7nl7f/A5Oz/xOTr/8Hk6/+/5Ov/wOTr/8Lk6/+75Oz/vePs/8Hl6/+55Oz/vuTs/8Tl + 7P+95Oz/vOTs/8Hk7P/C5Ov/xuXr/8bl7P/B5e3/xebt/7/l7f/F5u3/xubt/8jl7P/I5uz/yeXs/8nl + 7P/K5ev/y+Xr/87l6//Q5Or/0uTp/9Lj6f/P4+r/0ePo/9Ld5f/Zwtb/3pe+/+Jyr//jfrP/5G+q/+R6 + rf/kfq3/5H2s/+R6qf/jfqz/43Cj/+N8q//kc6T/AAAAAAAAAAAAAAAAAAAAAAAAAADu7u6V7Ozt/+rr + 6//c3+L/ztzi+tDg5/7M3+f+yd7m/Mre5vzG3uf/wN7o/7De6/+c2+v/f9fs/3HO6f9NoM7/AABY/wAA + W/8AAFH/AABK/wAAQ/8GA1T/JBed/yobpf8rG6f/Kxum/yoapf8qGqX/Khql/ysapf8rGqT/Khqk/yoZ + pf8qGaf/Khmn/ykZpv8qGaX/Khmk/yoYo/8rGKX/KRWn/yscp/82L6j/YWm1/4ybyP+nudf/vdLh/8vh + 6v/P5Ov/zOXt/8/m7P/O5uz/zeft/83n7f/N5+3/yeft/8Tm7f/F5u3/x+bs/8Tm7f/B5u3/wOXt/8Xm + 7P+95e7/wOXt/77l7f+/5Oz/weTs/7vk7f+65O3/wuTs/77k6//A5Oz/uuTt/7Xk7f/B5Ov/uOPs/7/k + 6/+74+v/weTr/8Lk6//B5Ov/w+Xr/7rl7f+95ez/v+Ts/7nk7P/C5Ov/v+Ts/8Lk6//H5ev/weXs/8Tl + 7P/E5ez/xeXs/8fm7P++5e3/wuXt/8Tl7P/I5ez/yuXs/8fl7P/H5ez/y+Xr/87l6//R5ev/0uXq/9Pj + 6f/U4uj/0uHo/9XX4v/dsc7/4Hey/+J9sf/jfrH/5H2v/+WBsP/lh7L/5IKu/+OGsf/jgKz/5Hen/+Vx + o/8AAAAAAAAAAAAAAAAAAAAA5OrsLO3t7u3s7e3/6evs/+Pm6f/J1t//v9bh/77Y5P+/2eT/udfk/7fZ + 5v+x2Ob/sdnn/7Da6P+Q2ez/e9Lq/1Cdyv8AAF//AABX/wAAT/8AAEr/AABD/wAAQf8GA1n/GxCU/yAS + mv8hE5v/IhSZ/yETmv8iFJz/IxSf/yQVoP8kFZ//IxSg/yITof8jE6H/IAyd/yQTnf85OaL/VVuu/3KA + vf+brtD/qb3X/7zR4f/N4en/z+Tr/8/l7P/O5uz/z+ft/83n7P/J5u3/zebs/8zm7P/L5uz/yebs/8bm + 7P/H5uz/x+Xs/8Hl7f/F5uz/vuXt/8Dl7f+55O3/wuXs/7zl7f+95e3/wuXs/7rj7P/A5Oz/veTs/7vk + 7P+95Ov/uuPr/73j6//A5Ov/vOTs/8Hk6//C5Ov/vOPr/8Lk6/+64+z/v+Pr/8Dk6//B5Ov/vOTs/7Xk + 7f/B5Oz/weTr/8Lk6//B5ez/teTt/8Ll7P/A5ez/v+Xs/8Dl7P/F5ez/xOXs/8Dl7f++5e3/xeXs/77l + 7f/J5ev/xuXr/8fl7P/K5ev/zOXr/8jl7P/O5ev/0eXq/9Xj6f/T4uj/1N3l/9y/1v/dl7//4X6w/+J0 + rP/igrH/5Xau/+WBr//kfqz/5Iax/+R8qv/keqn/5YGu/wAAAAAAAAAAwMjLAOLq7SDi6u3o6uzt/+Pq + 7P/c5+z/1eTr/83g6f/E2eX/vNbj/7XU4/+t0eL/kcnj/2ehzv9Igb7/SHm3/1iax/9gsNb/RYGz/wAA + aP8AAFn/AABS/wAATf8AAEf/AABC/wAAN/8FAlT/EwqF/xcNjf8YDo7/GQ+Q/xsQkv8cEJL/Gw2V/xgA + lv8tKJz/YGmt/3+Ovf+arc7/rsTZ/77T4v/I3uj/zOLq/8/l7P/P5ez/z+bs/8/n7f/P5+3/zOft/8bo + 7//N6O7/yOft/8bm7f/H5u3/xubs/8fm7f/C5u3/weXt/77l7f/D5ez/veXt/8Pm7f+95e3/weXs/7zl + 7f+75e3/vOXt/7nk7f/D5Oz/uuTs/8Hk7P+35O3/vuTs/7zk7P/A4+v/uuLr/8Hj6v+/4+v/v+Tr/7fk + 7P+64+z/wOTr/7/k7P++5Oz/wuTr/8Dk7P+45Oz/vuTs/77k7P/A5Oz/vePr/7/k7P/A5Oz/u+Ts/8Pl + 7P+95e3/weXs/8Hl7P/C5ez/weXt/8Tl7P/F5ez/xOXs/8Xl6//E5ez/yOXr/8fl6//F5ez/xOXs/8nm + 7P/O5uz/0eXq/9Pj6f/V4ef/2NLf/92syv/gf7L/4nit/+KJtf/lea3/5n6v/+aDsP/leKn/5IKv/+R9 + q//lga7/AAAAAAAAAAAAAAAA4ertseDq7f/d6u3/2Ojt/9Xn7P/T5uz/0uXr/87j6v/I3uj/xtzm/7vW + 5P+Hp87/SFyt/yU4oP8AAI3/AACC/wAAef8AAG7/AABr/wAAXP8AAFT/AABQ/wAATP8AAEf/AAA+/wAA + Nf8AAEn/CwZ//yw0jf9XZaP/bnyw/4mZwP+YqMj/tsnb/7/U4f/N4en/zePr/87k6//P5ez/zebt/8/m + 7P/P5+z/zefs/83n7f/K5+3/xefu/8zo7f/I6O7/wufu/8Tn7v/H5+3/w+bt/8bm7f/D5e3/vuXu/73l + 7v/A5u3/vOXt/8Hl7f+95e3/uuTt/77l7P+95Oz/weTr/7/l7P+25e3/t+Tt/7rk7f+85ez/tuTt/7/l + 7P+45Oz/u+Ts/73j7P++4+r/v+Pq/77k6/+25Oz/u+Ts/7rj7P+74+v/u+Ts/7rk7P+45O3/vOTs/77k + 7P/A5Oz/tOTt/8Dk6/+74+z/weTr/7/k6/+95Oz/xOXr/7/l7f+95e3/t+Xt/8Hl7P/D5ez/w+Xs/8Ll + 7P/G5ez/weXs/7/l7P/E5ez/vOXt/8fl7P/G5ez/yuXs/9Dm6//R5uv/0+Xr/9Tj6f/V3+b/273V/9+R + vP/heK3/4oa0/+VopP/ncaf/53mp/+d5pv/lf6z/5YGt/+R8q/8AAAAAAAAAAOHq7UPf6u793Oru/9np + 7f/W6O3/1ujs/9Xn7P/T5uz/0ubs/9Hk6//P5Ov/zuLq/87h6f/J3uf/wdnl/7bO3v+uxNj/m7HN/5ux + yP+YrcT/k6a9/5Kmvf+Oo7r/lqq//4qft/+QpLb/nbLD/6nA0f+70+D/wtnl/8nf6P/N4ur/zuTq/9Dl + 6//Q5uz/0Obt/87n7v/O5+3/zuft/87n7f/K5+7/zuft/8vn7f/G5+7/xufu/8fn7v/D5+//wufu/73n + 7//F5+7/xebt/8Ll7P/F5ez/uuXt/77m7f+55e7/u+Xt/7nk7f+95e3/wOXt/7nk7f+95Oz/u+Ts/7bj + 7P/C5Ov/vuTs/7bk7f+z5O3/wOXs/7fk7f+25O3/vOXs/7nk7f+z4+3/veTs/8Dk6/+75Oz/ueTs/77k + 6/+75Oz/vuTs/8Pk6/+55Oz/vuTs/7jk7P+75Oz/vuTs/73k7P+24+3/veTs/7/k6//B5Ov/xeTr/8Xk + 6//B5ez/wOXs/73l7f+/5e3/vOXt/8Hl7P/H5Ov/vuTs/8bl7P/B5ez/xOXs/8bl7P/C5e3/yObs/8Tm + 7f/J5ez/y+bt/8/n7f/T5uz/1eXq/9Tj6P/Z1+L/3aHE/+FrrP/hgrD/5Het/+Z2rf/lgq7/54Ct/+Vy + o//lgq7/5Xqp/wAAAAAAAAAA3+rttNzq7f/b6u7/2enu/9bp7f/X6O3/1ejt/9Tn7P/T5+z/0ubs/9Hm + 7P/S5uz/0ebs/9Dm7P/O5Ov/zeTr/83k6//N5Oz/zuTr/9Dk6//P5Ov/zuTr/83k6//P5Ov/zuTr/87k + 6//O5ez/z+bs/83m7f/Q5+3/0Oft/8/n7f/Q5+3/zOft/8fn7v/O6O3/zOfu/8vn7v/J5+3/y+fu/8nn + 7v/K5+3/yeft/8jn7f/C5u3/x+ft/7nm7/+95u7/wObu/8Lm7f/D5u3/u+Xt/8Hl7f+65e3/ueXt/7fl + 7f+75e3/uuTt/73l7f+35O3/tOTt/7nk7f+/5ez/wOTr/8Dl7P+25O3/s+Tt/73l7P++5Oz/tuTt/8Dj + 6//B5Ov/tOTt/7nj7P+95Oz/veTr/7Xk7f+34+z/wuTs/73k7f+15O3/vOTs/7zk7P+45Oz/ueTs/8Dk + 6/+64+z/uOPs/8Dk7P++5ez/u+Ts/7/k6/+94+v/weXs/7Tl7v+95e3/wObt/7zm7f/B5u3/wOXs/7rl + 7P/A5Oz/vuXt/7vl7f/C5ez/xeXs/8Lm7f/G5uz/x+ft/8rn7f/O5+3/z+ju/9Po7f/V5uz/1OXp/9jf + 5v/cutL/4Xqz/+F1rf/ih7T/5YKx/+aGsv/ng67/5n6r/+WIsv/lfav/LDAwAODq7Rne6u302+ru/9nq + 7v/W6e7/1+nu/9Xp7f/U6e3/0+nu/9Po7f/S6O3/0ujt/9Lo7f/R5+z/0ufs/9Dn7P/P5+z/z+ft/9Dn + 7f/R5+z/0ebs/8/m7P/P5+z/z+fs/8/n7f/O5+3/z+ft/8/n7f/O5+3/zuju/8zo7v/M6O7/yOfu/83o + 7f/I5+7/w+jv/8vo7v/M5+3/y+ft/8nn7f/F5+7/yeju/8Ln7v/D5+7/yOft/8Hm7f/H5u3/weXu/73l + 7v/C5u3/u+Xt/77l7f+/5ez/veXs/7vl7P+75ez/vOTs/73k7P+55Oz/vOTs/7zk7f+15O3/uOTt/7zl + 7P+75Oz/uuXt/7Lk7f+95O3/uuTt/7Xk7f+24+z/vuTs/7jk7P+75Oz/uOTs/7Xk7f+25O3/s+Tt/7vk + 7P++5Oz/tuXt/7bl7v+45O3/v+Ts/7fk7f+45O3/vuPr/77j6/+65Oz/vuTs/7jl7f+65O3/vuTs/7fk + 7f/C5Oz/uOXt/7zl7f/B5u3/veXu/7fl7v/A5e3/uOTt/73k7P/B5e3/uuXu/8Hm7v/C5u3/webu/8Dm + 7v/K5+7/zOju/8Xn7v/O6O//yefu/9Ln7P/V5+z/1+Lp/97C1//fi7v/4X2v/+KCs//kgLL/5oCu/+eA + rP/mf6z/5omz/+Zzo/8AAAAA4evuVd3q7v/b6u7/1+ru/9Xp7v/V6e7/0+nu/9Pp7v/T6e7/zunv/9Pp + 7f/S6O3/zOju/8/o7v/O6O7/zujt/9Do7f/O5+3/0Ofs/9Hn7P/P5+z/zufs/9Dn7P/M5+3/zuft/83o + 7v/M6O7/zuju/8ro7v/N6O7/yuju/8vo7v/E6O//xujv/8fo7v/E5+7/yefu/8Pm7v/F5u7/yeft/8Dm + 7v/I6O7/v+fu/8Hm7v/F5uz/vuXt/7vl7f/D5u3/wOXt/7zl7f/A5e3/uOXt/8Dl7f+05O3/uuTt/7nk + 7f++5Oz/u+Ps/73k7P+95Oz/veTs/7jk7f+/5Oz/uuXt/7jk7f+45e7/ueXt/77l7f+45O3/tuTt/7fj + 7P+85Oz/tuTt/7nk7P+44+z/uuTs/7nk7P+55Oz/ueTt/77l7f+05e3/ueXu/7rk7f/B5Oz/v+Xt/7Pj + 7f+94+z/vOTs/7zk7f+55e3/vOXt/7nl7f/A5e3/veXt/8Hl7f+65O3/wubt/8Hm7v/C5u7/ueXu/8Dk + 7f/D5ez/yebs/8Xm7f/B5u7/wufu/8Ln7v++5u7/xufu/8Xn7v/E5+//y+nv/8ro7//P6O7/1Ojt/9Tn + 7P/V5er/2s3d/96ix//jcq7/43yx/+J+sP/khLH/5nyq/+aBrf/mdaX/5nal/wAAAADg6+6n3ert/9nq + 7v/V6u7/1enu/9Pp7v/S6e7/0+nv/9Lp7v/R6e7/0enu/8zo7v/N6e7/zeju/8ro7v/O6O7/zejt/8vo + 7v/O5+3/zufs/83n7f/N5+3/zOft/83o7v/L6O7/zeju/8vo7v/O6O7/xujv/8To7//G6O7/y+ft/8Lm + 7f/H6O7/x+fu/8Tn7v/C5+//wufu/8Tn7v/D5+3/wefu/7jm7/+95u7/xObt/8Lm7f+85e3/vebu/7zl + 7v++5e3/veXt/7Tl7v+45e3/vOTs/7nk7f+75O3/vuTs/7/j6/+94+v/uuTs/7Tk7P+45Oz/u+Pr/77k + 7P+15O3/uOXu/7bl7v+15O3/t+Tt/7Xk7P+34+z/v+Xs/7jk7P+05O3/t+Tt/7vk7P+95Oz/t+Ps/7vk + 7f+55e3/uuXt/7nl7f+05O7/vuXt/8Hl7f+55e3/uOXt/7zk7P+14+3/uuTs/7zl7f+35O3/u+Xt/7vm + 7v/C5u7/ueXt/8nn7f/H5+3/xOfu/8Dn7/+95u7/xefu/8nn7f/K6O7/xuju/8zp7//C5+//xOfu/8nn + 7v/N5+7/v+fu/8ro7//P6e//zejv/9Pp7v/T6O3/1Ofs/9Xj6//b0d//36XI/+N0r//jda7/5Iq2/+SN + t//mirT/5oix/+WBrf/kibL/4OvtCd/r7ujc6u7/2Oru/9Xq7v/W6e7/0+rv/9Lq7//S6u//0enu/83p + 7v/O6e7/y+ju/87o7v/O6O7/y+ju/8zo7v/L6O7/zOjt/8ro7v/L5+3/yefu/8Tn7v/L6O7/xOfv/8Xo + 7//J6O7/x+jv/8jo7v/J6O7/x+jv/8Pn7v/J5+3/yOft/8bn7f/G5+7/wObu/8Pn7//B5+7/wOfu/8Dm + 7v/B5u3/weXt/7/l7f/A5ez/u+Xt/7nl7v+45e7/vuXt/7vl7f+25e7/s+Xu/7rl7f+85O3/uOTs/8Dl + 7P+24+z/v+Tr/7/k6/+y4+3/uOPs/7jj7P+74+v/t+Ps/7Hk7f+15e3/suTu/7Xj7f+54+z/uePs/7nk + 7P+z5O3/tuTt/7Tk7f+55e3/ueTt/7jk7f+/5Oz/vuXs/7jl7f+05O7/uOXt/7/l7f/A5u7/t+Xt/7fl + 7v+45e3/ueXt/7fk7f/C5Oz/v+bt/7zl7f/C5u7/w+fv/77m7v/I6O//xOjv/8fn7v/H6O//vOfv/8jn + 7v/B5+//v+fv/8Lo7//E6O//vOfv/8jo7//G6O//yujv/8zo7f/M6O7/0unu/9Dq7//R6e//0Oju/9Ho + 7v/W5+z/1uPq/93F2P/fosb/44K0/+Vtrf/ka6v/5Iq1/+aBrv/mdqX/5IKv/+SMtP/h6+4r3uvu/9vq + 7v/Y6u//1+ru/9Lp7//S6u//zerw/9Dp7//O6e7/zeju/83o7v/K6O7/yuju/8no7v/N6O7/y+ju/83o + 7v/G5+7/yeju/8rn7v/L5+3/xOfu/8no7v/G6O7/x+ju/8bo7v/G5+7/xufu/8Po7//F5+7/w+fu/8Hn + 7v/E5u3/xObu/77m7v/F5+7/wObu/8Tn7v/A5u7/wubt/8Lm7f/C5ez/veTs/8Hl7f+65e3/u+bu/73m + 7v/A5u3/veXt/7rl7v+z5e7/v+Xs/7rk7f+05O7/teTt/7bk7f+35Oz/vuTs/7Xj7P+54+v/vOPq/7ri + 6/+44+z/teTt/7Pk7f+25O3/uuPs/7rj6/+54+z/sePt/7Xk7f+55O3/tOTt/7fk7f+65e3/uOXt/7zl + 7f+35e3/tuXt/77m7f+85e3/weXt/7vm7v+z5e7/v+bu/7nl7v/A5u7/wObu/8Lm7v+85u7/xefu/8bn + 7v/C5+//x+nv/8Xo7//C6PD/yOnv/8To8P/J6O//yunv/8bp8P/D6PD/xujw/8vp7//B6O//yOjv/8rp + 8P/N6fD/zOju/87p7v/Q6e7/z+nv/9Pq7//R6e//0uju/9Tn7f/V4Oj/3r3U/96Zwv/lg7T/5YO1/+Ry + rP/khbP/53ur/+eErv/kga3/5Iqz/9/r7lbd6+7/2uvu/9nq7//W6u//1Orv/9Lq7//L6fD/z+nv/87o + 7v/M6O7/zOjt/8vo7v/G6O//yejv/83n7f/E5+//yuju/8ro7v/K5+3/x+ft/8vn7f/K5+3/w+fu/8jn + 7v/D5+//xufu/8fn7f/C5+7/xOfu/8Pn7v/B5+7/wufu/8Tn7v/D5u3/wObu/8Pn7f/B5u7/vubu/73m + 7f/A5u7/vebu/8Pl7P/E5ez/wOXs/77m7f+35e7/v+bt/7bk7v+85e3/uOXt/7bl7f+55O3/u+Xt/7rl + 7f+25e3/suTt/7Xk7f+y5O3/t+Ps/7rj6/+44+v/u+Pr/7rj7P+05O3/uuTt/7nk7P+44+z/u+Lr/7rj + 6/+54+z/uOTt/7nk7f+/5ez/vuXt/8Hm7f+45e3/v+bt/7/l7f/A5e3/webu/7jl7v++5e3/uObu/7Tl + 7v+/5u7/vubv/7vm7//E5+7/webv/8Ln7//D6O//z+nv/8Lo7//H6fD/yunw/8np8P/K6fD/xunw/73n + 7//E6PD/xOjw/8fp8P/L6vD/x+nx/8Xp8P/N6vD/yenw/8rp7//Q6e//0Oju/9Lo7v/T6e//z+nv/9Do + 7v/R6O7/1OXr/9rX4v/dwNX/34S6/+N5r//le7H/436z/+WPuv/ng7H/5oGs/+WBrf/kjLT/4Ovucdzr + 7//b6u7/2Orv/9Xq7//T6u//0env/8np8P/Q6e//zuju/8vo7v/O6O3/y+ju/8vo7v/H6O//zeju/8Xo + 7//H6O//yuju/8jn7f/G5+3/yuft/8fn7v/G5+7/x+ju/8Tn7//J5+3/xeft/8Ln7v/D5+7/v+fv/8Hn + 7v/G5+7/wObu/8Xm7f+75u7/xObt/8Hm7f++5u7/vebu/7rm7v/B5u3/wObt/7zl7f/D5u3/uuXu/7zm + 7v+55e7/vubu/7nl7f+95e3/u+Tt/7zk7f+x5O7/t+Xu/7bk7f+85Oz/tuTt/7Xk7f+04+z/tuPs/7jj + 7P+35Oz/t+Tt/7Xk7f+z5e3/tOTt/8Hk7P+34+v/vePr/7zk6/+95Oz/uuTt/73l7f++5e3/teXt/7/l + 7f/B5u3/t+Xu/8Lm7f/C5+7/uubv/8Tm7f/B5u7/t+bu/8Pn7/+95u//wOfu/8fo7//L6O7/yejv/8jp + 8P/D6O//z+nv/8fp7//T6/D/yOnv/83p8P/D6PD/zOnv/83q8P/Q6/H/yenw/8np8P/D6fD/zurw/83q + 8P/N6vD/z+nv/8/p7//S6O3/0eju/8/p7//S6e7/0unu/8/o7v/T4ej/283c/9vE1f/ib7L/5G6v/+Rt + qv/ld6//5YCz/+eCsP/mcaL/5Y62/+WTuf/e6++D3Ovv/9vq7v/Y6u7/1erv/9Tq7//R6u//0unv/9Dp + 7v/M6O//y+ju/8zo7v/N6O3/y+ju/8Xo7//L6O7/xOjv/8jo7//K6O7/x+fu/8Ho7//I5+7/xOfu/8Xo + 7//C6O//xOjv/8Tn7v/I5+3/vefv/8Pn7v/E5+7/webu/7/n7v+/5u7/w+bt/8Dm7f/A5u3/w+bt/7rm + 7v+65u7/vubu/7rm7v+75u7/vubt/73l7f+45e7/v+bt/73m7f++5u3/uOXt/7fl7f+25O3/v+Ts/7fk + 7f+05e7/uuXt/7jk7f+35O3/sOTt/7zl7f+45O3/u+Ts/7Xk7f+35e3/teXu/7nl7f+y5O3/u+Xt/7jk + 7P+/5ev/w+Xs/7Hj7f/C5u7/v+bu/7zm7v+55u7/xebt/8Tn7v+65u//xuju/7vm7v+65u//wefv/8Dn + 7//B6O//zOrw/8To7//Q6u//yejv/8vo7//S6vD/z+rw/8zp8P/Q6u//y+nv/8zq8P/K6vD/0Ovx/8zq + 8P/Q6vD/0Ovx/8np8P/N6vD/zerw/8rp8P/N6/D/x+rx/8jq8f/Q6u//zuju/9Ho7f/P6O//z+ju/8/o + 7v/O6O7/z+bt/9Xc5P/bzNr/3bDO/+Nmsv/kaqn/5W6w/+Z4r//miLT/6Imz/+iKtP/njrf/5oWx/9/r + 7ojb6+//2uru/9jq7v/W6u//0unv/87q8P/Q6e//zunv/87o7v/I6O//yuju/87o7f/I6O7/v+jw/8jp + 7//I6e//yOjv/8ro7v/H6O7/w+fv/8nn7f/G5+7/xOjv/8Lo7//C5+//wejv/8Xn7v/B5+7/xuft/77m + 7v/E5+7/webu/8Tm7f++5e3/vebu/8Xm7f/B5u3/uObu/77m7v+65u7/uubu/7zm7v+65e3/v+Xt/7nk + 7f+15e7/seXu/7Hl7/+z5e7/uOTt/7rk7P+65Oz/teXt/7Xl7f+y5O3/tuTt/7Tk7f+25e3/u+bt/7jk + 7f+35e3/teXu/7Pl7v+55e7/s+Xu/7Xl7v+25e3/t+Xu/7bl7f+95e3/wObt/7/m7v+35u7/uObv/7rm + 7/++5e7/xOfv/8np7/+55u7/zOnv/8Ho8P/B6O//yujv/8rp7//C6PD/vejv/8Ho8P/T6/D/0evw/8jq + 8f/J6fD/xenw/8zp7//R6vD/0urw/8vq8f/J6vH/xunw/8/q8P/J6vH/yOrx/87p8P/P6vD/zOrx/8jq + 8P/N6fD/zenw/8vp7//M5+3/yufu/8zn7v/O5+3/zebs/9Dj6f/R3uf/2drh/9nK2f/gi77/5Fuv/+Vf + qv/kdK//522p/+h2qv/ohbH/6Iix/+eGsf/ogKz/3uvue9vr7//a6+//2Oru/9Xq7//S6u//z+rv/8/q + 7//Q6e7/z+nu/83o7//K6e//yejv/8fp7//H6fD/x+jv/8jo7//H6O//yeju/8ro7v/I5+7/xefu/8Dn + 7//C5+//xeju/8Hn7v/F5+7/wufv/77n7//C5+7/xOfu/7vm7//E5+7/xuXs/8Hl7f/A5u7/u+bu/7rm + 7v+/5+7/vebu/7zm7v+85e7/vOXt/7Xl7v/C5Oz/v+Ts/7nk7f+05O7/uuXt/7vk7f+25O3/uuTt/7nk + 7P+z5O3/s+Tt/7Pk7v+35O3/tOTt/7bk7f+25e7/seTu/7rl7v+z5e7/tOXu/7fl7v+35e7/seXu/7Xl + 7v+y5O3/veXu/7rl7f/A5+7/v+bu/8Po7/+65u//wOfu/83o7f/G6O//w+jv/8Do7//B5+//x+nw/7/n + 7//K6e//yOjv/8fp8P/J6PD/zenv/8Xp8P/K6vD/yOnw/8Xo8P/P6vD/zurw/8rq8f/H6fD/zOvx/8Xp + 8P/O6vD/y+nw/83p8P/J6fD/zenv/83p8P/M6O//zOjv/8bo8P/B5+//yebt/8vl7f/J5e3/y+Pr/8rf + 6f/N3ub/0tvk/9XT3v/Zz9v/36rN/+Rgrv/kRKv/5UKj/+WCs//mea//53mq/+eOtv/pfan/6H+r/+mA + rP/d6+5p3Ovv/9rr7//Z6+//1+vv/9Pq7//R6e//z+rv/8zp7//Q6e7/zuju/87p7//L6O//yOnv/8np + 7//N6O7/yuju/8fo7v/E6O7/xOjv/8fn7v/G5+7/wefv/8Pn7//A5+//vOfv/8Pn7//F5+7/wOfu/8bm + 7f+75u7/wOfv/8Hn7//G5uz/w+Xs/8Dm7v+75u7/u+bu/7vm7v+65u7/tubu/7rl7v+75e3/uuXt/7jk + 7f+85e3/vOXt/7jk7f+35O3/ueTt/7rk7P+35O3/tOTt/7Hk7v+55O3/vOTt/7vk7f+65e3/ueTt/7Pk + 7f+y5O7/uOXu/7bl7v+45u//uOXu/7zm7v+25e7/wObu/8Tm7f/C5e3/wObt/7jl7v/E6O7/uubv/8Dn + 7v/F6O//xeju/8fp7/+95u7/seXv/8Po7//C6fD/yOnw/8jp7//M6e//wejw/8rp8P/G6fD/yenw/8bp + 8P/K6vD/zOnv/9Hp8P/H6fD/yurw/9Pq8P/J6fD/zuju/83o7//N6e7/yejv/8zo7//K6O//y+bt/83n + 7f/F5+//xuXt/8fl7f/K5ez/yuPq/83d5v/R1eH/ztjj/9LY4P/Xzdv/2bjS/9+Iwv/kLKb/5C+o/+RL + rf/lX6z/5HGt/+aCtP/mhLP/54+2/+l9qf/pkLj/6YWv/97r70bc6+//2+vv/9fr8P/V6/D/1evv/9Lq + 7//N6e//zenv/8/p7v/P6O7/yeju/8vp7//K6e//y+nv/8/o7v/L6e7/zeju/8Xo7v/K6O7/yOfu/8bn + 7v/F5+7/xefu/8bn7v+85+//vufv/8bn7v/A5u7/x+ft/7/m7v++5+//wOfu/7/m7f/D5u3/w+bu/8Hm + 7v+35u//u+bu/7zm7v/B5u7/uOXt/7zl7P+35e3/ueXt/7Ll7v+65e3/r+Tt/7Pk7v+15O3/uOTs/7Hj + 7f+85O3/ueXt/7Pk7v+75e3/s+Xu/7jl7v+55e7/teTu/7vl7f+55e7/v+bu/7nm7v+45e7/xefu/7vm + 7v++5u7/uuXu/8jn7v/A5u7/yOju/8bp7//C5+7/z+ju/8Po7//C6O//v+bu/8fn7v/M5+7/y+ju/8Po + 7//D6PD/zenv/8Hn7//C5+7/yejv/8fo7//O6e//yujv/8To8P/I5+//zeft/8To7//E6O//zefu/8fn + 7v/Q5ez/zuft/87n7v/N5+7/xufu/8rl7f/M5Oz/yubt/8fk7P/J4+v/xuLq/8jc6P/J2uT/ztPg/9TI + 2f/Tz9v/1sjW/9yZx//fSqz/4k+w/+Q2of/kMKj/5Ge0/+RwsP/lhbf/5nyz/+iGs//nibH/6Iqz/+iP + t//pi7P/3+zvHNvr7/7b7PD/1+zx/9fr8P/W6/D/0erv/8/q7//P6e//0Orv/8/p7//N6e//yenv/83p + 7//L6e//zOrw/8np8P/O6e//x+jv/8jo7v/J5+3/xOfu/8fn7v/J5+7/y+bs/8Hn7v/D5+7/w+fv/8Ln + 7//I5+7/wOfu/8Po7v/B5+7/w+bt/77m7v+45u//vebu/7rm7v+95u7/vebu/73l7f/A5e3/vuXt/7rl + 7f+25e7/tuXu/7nk7f+45O3/t+Tt/7fk7f+w5O3/sOPt/7Tk7f+05O3/tOTu/6/k7v++5u7/uOXu/7vm + 7/++5u7/uuXt/73l7f+45e3/uebv/8Ho7v+/5+//xunv/8Po7//E5+7/xuju/8Tn7v/E6O//wufv/8no + 7//S6u//yejv/8Dn7//L6O7/x+fu/8ro7v/D5+7/y+jv/8Dn7v/G5u3/zujt/8nm7f/C5+7/y+fu/8Tm + 7v/I5u3/xebt/73k7f/H5ev/x+Xs/7zl7v/I5e3/xOTs/8bj6//I5Oz/xOXt/8Xk7P/G5Oz/xOPr/8fi + 6//G4er/xuDp/8fa5P/L1eL/zNDd/8/J2f/Wv9T/177R/9Ctzv/daLX/4CWg/+NIpP/jR6r/5kuh/+U4 + ov/lb7X/5GKy/+aKt//nbqz/6H+w/+eIsv/pg67/6HOj/+qPt//d6/AG3ezv4dvs8P/Z7PD/1+vw/9Xr + 8P/T6u//0erv/9Dp7//P6vD/0Orw/9Dq7//L6e//y+nv/8bp7//H6fD/y+rw/8zq8P/H6e//yeju/8zo + 7v/G6O7/xujv/8To7//F5u3/v+fu/8Xn7v+/5+//xefv/8Dn7//M6O7/0Oju/8Tn7f/C5u3/wOfu/7/m + 7v++5u7/vebu/7zm7v+65u7/webu/7/m7f+75e7/v+bu/7bl7v+25e3/tuTt/73k7P+55Oz/tePt/7rk + 7P+64+z/uOTs/7Tj7f+55O3/t+Tu/7zm7v+z5u//u+bu/7vm7//A5+//vObu/73l7f/N6e//wunw/7rn + 7//B5+//x+jv/8no7v/J6O7/z+nv/8vp7//R6u//xejv/8jo7v/C5+//x+fv/8jn7v+65u//xubt/8Tm + 7f/L5u3/wOXt/8bl7f/B5O3/weTs/8Pj6/+94+z/w+Lq/7/h6f+/4Or/vd/p/8Lf6f+84Or/v9/p/8Lg + 6P/B3+n/xd/o/8Lh6v/C4er/xeDp/8Hg6f/C3+j/xdzl/8nV4v/MzNv/0MHX/9S80//SutH/zpXH/9WH + uf/ecrL/3kil/+E+nv/hJ6D/4leo/+Rbrf/mQKT/5zSl/+Zosv/kcLX/52un/+diqv/mY6T/6JO5/+mC + rv/qhrD/6omz/wAAAADd7PCo2uzw/9ns8f/X7PD/1evw/9Xr8P/V6+//0+rv/9Lq8P/P6vD/z+rw/9Dq + 7//Q6u//yunv/83p7//S6vD/0Orv/8vp7//H6O//yOnv/8jp7//D6O//xejw/83p7v/A6O//vejv/73o + 8P/F6O//vufv/8Hm7f+65e3/w+bt/8bn7v/H5+7/xebu/8Lm7v/D5+7/t+Xu/73m7v+65u7/uObu/7zm + 7v+95u7/vOXu/73l7f+95Oz/ruPt/7bk7f+z4+3/t+Tt/73k7P+25O3/u+Tt/7fk7v+95u7/u+bu/7bm + 7/+65u//vufu/7vn8P/O6e//yefu/8Hn7/+25u//wujw/8np8P/K6fD/yunv/8vq7//D6e//x+nw/8jo + 7//K6O//x+fv/8Hn7//L5+7/wubt/8fn7v/F5u3/weTt/8Ll7P/A5Oz/vuLr/7ri6//D4On/wN7n/7ve + 6P+73ef/u9zn/7fc5/+32+f/udrl/7Ha5v+32eT/udjj/7rY5P+62eX/vNrl/7zb5P/B2uP/wdTf/8fN + 3P+/0N//z8LX/8nE1//Oqcn/0pfA/9Vxtv/bT6H/33Ws/+J3sv/hQZn/4TGi/+NKp//jXqv/5GOm/+ZS + rv/nTaf/6DOf/+Zfsf/oW6L/53ax/+d9rf/ojbX/6n+r/+p4pv/rfa3/AAAAANzs717b7PD/2ezx/9fr + 8f/X6/D/z+vx/9Xr8P/U6/D/0uvw/9Dr8P/Q6vD/0Orv/9Dp7//T6u//z+nu/8To7v/H6O//yOjv/8fn + 7//D6e//xunv/8Tp8P/F6fD/xenw/8To7//B6O//x+jv/8Ho7/+35e7/kd/q/4bc6P+v4uv/yebt/8jm + 7f/F5u3/vebu/77n7v+75u7/vuXt/7vl7v+25e7/vObu/7zn7v++5u7/v+bt/8Tm7f+15O3/wOXs/7jl + 7f+95u7/vObu/7fm7v+75u7/ueXu/8Xo7/+65u//uebv/8Hn7v/B5+//wOfv/7zn7//J6e//yOjv/8rp + 7//O6vD/wefw/8vq8P/F6O//v+jv/7/n7//K6O7/x+jv/8/o7v/N6O7/wObu/8Tl7f/J5uz/webt/8Pl + 7P+94uz/teHr/77g6P+74On/td7q/7bd5/+42+b/r9rm/7PY4/+41uH/sdPi/7rP3v+0ytv/ssPY/7S8 + 1f+7vtX/uL7V/7i61P+7vdP/usXW/7280f/OocL/zp3D/8yexv/TjMH/0Ya9/9h1rv/bUJn/31id/+NM + m//hR5f/4V2m/+BVo//iVKH/5Eig/+RPqP/kXav/5kOm/+dcof/naa3/53+u/+d5qf/nirT/54av/+eR + t//qhK3/6mea/+uTuf9CR0cA2+zxEdzs8Ova7PD/2Ovw/9bs8f/S7PH/0ezx/9Lr8f/T6/D/0+vw/9Lq + 8P/R6vD/0uvw/9br8P+75u3/h97p/63i6//J6e//z+nv/8rp8P/M6vD/xenw/8Lp8f/E6fH/yOrx/8fp + 8P/E6O//v+fv/63j7f9By+D/Ksrf/0XM4P+P3un/uuXt/9Ho7f/H5u3/wOfu/8nn7v/I5+7/w+fu/8Hm + 7v++5+7/vOfv/8Po7//F6O//xefu/7/l7f/F5u3/v+fu/8Dn7v+85u7/wufv/7vn7v+75u//vefv/7rm + 7//J6O//zurv/83q8P/W6+//yOrw/8jp8P/L6e//yenw/8nq8P/L6fD/vejw/8fp7//I5+7/yefu/8ro + 7//G5+7/x+fu/77m7v/G5u3/y+Xr/8Lj6/+34+z/wOHp/7jd6P+83Ob/s93o/7Tc5v+x2eb/s9Lh/7jI + 2v+zxtn/wLjR/8Cnzv+/mcn/zY69/9WTuv/Ng7D/0oey/9eNtv/ShrH/03up/9CBsP/Ph7X/zGqj/8tw + pv/Obqn/1FGa/9k8jf/dX5f/202S/99poP/jSZX/5SB8/+Q1jf/iPpH/4kOg/+VAmv/oM5L/5mCm/+Vg + rP/mXqv/51Cl/+ZjrP/mi7T/5YS0/+eLsf/oiLD/6Iy1/+l5pP/ph7H/6oew/wAAAAAAAAAA2+3wh9rs + 8P/Z7PD/1uzx/9bs8f/T7PH/0+vx/9Ps8P/P7PL/0+vw/9Pr8P/U6/H/v+jw/2/c5/8tz+H/hNjl/7rm + 7v/P6/D/zurw/73p8P/G6fH/yOnw/8Tp8P/J6vH/wunw/8zp7//K6e//tuTt/0jL3/8Zv9j/GL3W/ybB + 2P9k1eT/nODr/7nk7f+95u7/w+bu/7rm7//C5+//wObu/73n7//B6O//uubv/7/o7//E6O//xufu/8Pm + 7f+35e7/t+Xu/8jo7v/H6fD/vujw/87q8P/A6O//xefv/87p7//M6/D/wenw/87r8P+96PD/yunw/8rq + 8P/K6vD/xunv/8Xo7//C5/D/zOnv/8bn7v/J5+3/xefu/8Pn7v+85e7/vOXt/8Ll7P+84uv/wODq/7bd + 6P+43Ob/uNrl/7fY4/+20+D/scfc/7utz/+8kcD/yoS2/9OMt//Ve63/3YCv/9x2p//cXpf/3XCi/9t0 + pf/be6r/3ISv/9x0pP/chbH/3Hmo/9xpn//aZZz/2GGW/9NQjf/YM4P/2lCR/9xUj//caqD/3mif/+Nh + nv/mM4X/5UGR/+Jop//jc6z/5j+Z/+dsov/nXaT/51Cg/+d7q//mX6T/53Op/+WMtP/ljbP/54Ss/+eE + rv/oha//6X+q/+mIsf/qgq7/AAAAACgqKwDa7fEY2u3x8dns8P/Y7PH/1+3y/9bs8f/V7PH/0ezy/9Ps + 8f/S6/D/1evw/8zq7/+I4Or/ONDh/zLN3/9y1OP/uOXu/8zq8P/N6vD/yOnw/8Xp8P/I6vD/x+rw/8Xp + 8P/G6fD/zenv/8jp8P/J6O7/c9Pj/zLG2/8kwdn/FbbT/y7H2/87zuD/idnm/7nj7P/S5+3/uObv/7zn + 7/+75u//vebu/7bm7/+/6O//vOfv/7rn7//G6O//zejt/8Xm7v/L6O//xufv/8Xp7//B6PD/y+rx/8vq + 8P/T6vD/zunv/8fq8P/A6PD/yurx/7rn7//P6fD/x+rw/8Tp8P/B6O//zunv/8vo7/+95u//yufu/8Xm + 7v+95+//u+Xt/8Hj7P+64+z/uuHr/7rf6f+y3ef/t9rl/7LY5P+1zd7/sbjU/8WWvf/Leqn/2IGw/9hy + o//ZfKr/23Ok/95kmP/gbKD/4WSc/+Frnv/hZZj/4HOk/958qv/ee6r/332r/995qf/eeqn/3nSl/+B3 + qP/dXpX/2mCX/9dTj//YU4//3W+k/91Tkv/gb6H/41SW/+ZHjP/lUJH/4m6o/+R6qf/mdKf/5nyo/+dy + p//pYJb/6HKi/+eDrv/nha3/5pC1/+SHrv/lhKz/5oaw/+iLs//og67/6Iuz/+iGsP8AAAAAAAAAAAAA + AADb7fGN2+3w/9rt8f/W7fL/1e3y/9fs8f/U7fL/0ezy/9Ts8f/W6/H/mOHr/znQ4f8wzN7/Nsrd/2HQ + 4f/I5+7/0+vw/9Dr8f/N6vD/yenv/8fp8P/I6vH/x+nw/8Tp8P/I6fD/yurw/8zp7/+04ev/U8nd/y/G + 2/8mwdj/Ib7W/x691v84yNz/jdfl/8nm7f+55u//wOfv/7nm7v+85u7/tObv/8Dn7/+45u//vufv/7/m + 7//E5u7/yejv/8Xo7//X7PD/wunw/87r8P/L6vH/xOrw/8rp7//T6u//0uvw/8jq8P/J6vH/zenw/9Dq + 8P/B6PD/w+jv/8jo7v/O5+3/x+ju/8Dn7//H5u3/ueTt/77i6/++4ev/uuHr/7vh6v+23uj/sNrl/7rV + 3/+8x9j/v6TI/82Quv/TdKX/2m2e/9xZjf/fdaX/3l+V/957q//ffKv/4nOl/+Nkmf/jYpb/4YKv/+Jr + n//hdKX/4Hyr/9+Arf/ffav/34iy/96Brv/egq7/32ad/992p//fZ53/21+X/9hIh//cWJT/4DZ//+F1 + pv/jXpn/5VaX/+VVlv/kfK3/6FyP/+Z0ov/kha//5Yav/+d+qf/nfqn/5YWu/+d2ov/mf6r/5YGs/+aI + r//lgar/53+q/+eGsP/niLH/5421/wAAAAAAAAAAdYCHANzs8BHb7fHl2u3x/9nu8v/X7fL/1+3y/9Lt + 8v/S7fL/1Ozx/9Pr8f913Of/M83f/z7N3/8+xNv/ndzn/8jn7//U6vD/yuvx/9Lr8P/R6e//xujv/8rp + 8P/L6fD/xOnv/8zp7//G6fD/zurw/83o7/+14Or/iNTj/27L3v9kzd7/T8nc/1DH2/9Vzd//tuHr/73m + 7v+/5+//yuju/77l7f+/5+//xOnw/8Po7//G6O//yunw/8/p7//J6O//x+nw/8bp8P/F6PD/vujw/8vq + 8P/F6vD/wujv/9jr7//C6PD/yOrw/8Ho8P/R6vD/y+nv/8fo7//J5+7/yOfu/8fo7v/B5+//veXu/8jk + 6//H4un/x+Hp/8Xh6f+33un/tdjl/7bT3/+6uc//zJq6/9J/rf/YVo7/2mac/911o//ec6L/4Gud/+Ji + mv/iXJP/4nuq/+F4qP/idab/42Wa/+JvoP/hcKT/4Xmp/+Fuof/geqr/4IWw/+CCr//eeaj/34ax/957 + qf/fe6n/4Huq/+B4qf/gZp3/3GKZ/9tfmP/gWJP/4leO/+JvoP/kc6b/5W+i/+R/rv/oVZH/5Xej/+WD + rf/kh7D/6HSi/+d6p//mga3/53qm/+d9qf/ngaz/5n6p/+WNtP/mjbP/5oOt/+WIsP/nkrj/AAAAAAAA + AAAAAAAAAAAAANnt8Vfa7fL/2u7y/9fu8//X7fL/1u3y/9Xt8v/W7fL/x+rw/3Hc6P9Rz+D/eNXj/6Lc + 5/++5Oz/1Orw/9br7//B6fD/y+rw/8zq8P/L6e//xOnw/8rq8P/L6vD/zOrw/8fp8P/O6vD/yuju/9Ho + 7v/J5uz/t+Ps/8Lk6/+44ur/tOHq/5jZ5f+74+v/w+fu/83p7//F5+7/zOjv/8jo7//G6fD/xunw/7zo + 8P/I6vD/zevw/8jp8P/I6fD/v+jv/8To7//L6fD/xejw/8Hn7/+65u//yenv/8bo7//A6O//vefv/87p + 7/+85+//zejv/8/o7v/G5u7/w+bt/7zk7f+84uv/v+Hp/8Dg6f+13un/t9zm/7bV4f+7ttP/vJS//8xo + nP/YaZz/3V2R/+BWjf/gWo//33Kj/992pv/jb6L/42+i/+Rdkf/jY5r/4mGY/+NnnP/ja5//4n+s/+J0 + pP/ifKv/4nGi/+F3p//hfqz/4H+s/+CCrv/ghrH/4IKv/99/rf/ghbD/4HWm/+F3qP/hbKH/3mmd/91f + l//hXpX/42GX/+Vwov/lapz/5X6r/+Zyov/mcqD/5Hyn/+WGsP/nfqn/53Cg/+d3pP/na5z/53uo/+Zt + m//mgq3/5YSu/+aKsP/ngaz/55S5/+eHrv8AAAAAAAAAAAAAAAAAAAAA2/DyAtnt8qvZ7fL/2e3y/9nt + 8v/W7fL/1u3y/9Xt8v/R6/H/oeHq/6/h6v/G5uz/0enu/9fr8P/W6/H/0+vw/87q8P/P6/H/0ezx/9Lr + 8P/K6e//zOrw/8zr8f/K6vH/wujw/8bq8P/O6u//zunv/9Pp7v/Q6vD/1evw/8vq8P/M6fD/1Ovv/83p + 7//O6e//yunv/8vq8P/I6vD/1uzx/8Po8P/B6fD/yurx/8Tp8P+65/D/uufv/9Pq7//F6PD/yunv/8Dm + 7v/J6fD/yerw/8rp8P/J6e//zunv/8vo7//L6e//zenv/8To7//L6O7/x+bu/8fm7f/D5Oz/w+Lq/8Th + 6f+/3+j/wt7m/7TT4v+0vdb/xpS+/9Bqn//XdKX/23Oj/955qP/hZ5r/40uC/+NlmP/iR4L/4nKk/+Rp + nf/kYZf/5Wia/+Vjmv/lZ5n/5XKi/+Nrnv/jZJv/4n2s/+JonP/hcaT/4oGv/+Nnnf/ic6X/4YOw/+F1 + pf/hgKz/4Xqp/9+Crv/hgK7/4nWm/+Jnn//ibqL/3Web/+E5ef/jaZz/5W2d/+Vvnv/kfKf/52SU/+dr + nf/mfqr/5Xin/+hQhf/mb6D/5nil/+dfkv/ngqz/52GS/+Z7p//lfqr/5nai/+eCrf/mfaj/54mx/wAA + AAAAAAAAAAAAAAAAAACAi4QA2ezxGNrt8uTa7vL/2u7y/9ju8v/V7fL/2O7y/9ft8f/P6/H/0+vw/9fs + 8f/X7PH/2Ozx/9bs8f/S7PH/y+rw/9Hr8P/Q7PH/zuvx/87r8f/L6/H/v+rx/8bq8f/M6fD/w+nw/8jp + 8P/L6e//zurv/8/p7//J6e//xunw/8vq8P/Q6/D/wejw/9Hr8f/U7PD/0uzx/8Tp8P/O6/H/zOrx/83r + 8f/F6vH/yerw/8fq8f/T7PH/z+rw/8Tp8P/N6vD/1Ovw/9Ps8P/B6vH/zurx/8Xp8P/M6vD/zunv/8Pp + 8P/N6e//v+fv/8bn7f/J5u3/wuTt/7/j7P/A4er/t9zo/7jU4v+6utP/uZfA/8x6p//Wc6P/21+S/9xp + m//dapz/3m6i/+B0pP/jXpP/5F6T/+RpnP/kbqH/5EiC/+Rzo//kdKX/5WGV/+RjmP/jeKj/5GCV/+Nr + nf/ieKj/4lWM/+GBrv/ifaz/5IGt/+Non//kfKv/43mp/+N+rf/jga7/44Wx/+OArP/jeqj/5HWm/+R6 + qv/id6f/32CT/+Nzo//kWZD/5Xim/+R4pP/ldJ//5Xej/+RmmP/lfKf/52GU/+V/rP/mcqH/5naj/+Z9 + qf/lfqr/5n6o/+RrnP/kibH/54mx/+eLs//okbj/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA39/oi9vu + 8v/Z7vL/2e7z/9nt8v/Z7fL/1e7y/9ju8v/U7PL/1Ozy/9Ts8f/T6/D/0u3x/9Pt8v/S6/H/0evw/8rr + 8f/L6/H/zOvx/87r8f/M7PL/0Ovx/9Tr8P/N6/H/zevx/9Hr8P/S6/D/zOnv/8zp8P/H6fD/xOnw/9Ts + 8P/J6vD/zuvx/9Dr8f/S7PH/y+vx/9ru8v/Y7fH/2O3y/9Xt8f/K6vD/y+rw/9Ps8f/U7fL/0+zx/9Hr + 8P/O6/D/zuzx/8Pr8f/P7PH/yurw/8Ln7//G6O//wejw/8ro7//D5u3/veXt/8Dj6//F4+v/wuHp/7fa + 5f+2xtn/xJS7/8ltpP/UWY7/2XKg/9t0pf/eX5T/3mue/957qv/eZ5z/4HWn/+Nrnv/jW5D/42+h/+Rr + n//lUIf/5GOY/+Rnm//kW5D/5E+H/+N8q//jc6L/4nqp/+J7qf/kaZz/43ys/+N1pv/lYpv/5X6t/+Z+ + rf/lfqz/5Xao/+WDsf/kgrD/5Xip/+WBrv/kear/5Xao/+V7qv/hdqX/41SJ/+Nxn//keqf/436q/+KB + rf/jeaX/43Si/+VunP/mcKH/5nai/+Vbjv/kgq3/5mqc/+Vtn//kgKv/5HOg/+SErv/ne6j/54aw/+aT + uP8AAAAAAAAAAAAAAAAAAAAAAAAAAOW9zgbots7Z4N3n/9ru8//Z7vP/1+7z/9vu8v/Y7fL/1+7y/9bu + 8//T7fL/1Ozy/9Ts8f/T7PH/y+zy/9Xt8v/U7fL/0+zy/9bt8f/N6/H/1O3y/8br8f/c7vH/0evx/83r + 8f/P7PL/yOvx/9bs8f/O6e//zenv/8zp8P/S6/D/2O3x/8Pp8f/P6/H/1+3x/9bt8v/Y7fL/1+7y/9Ht + 8v/N6/H/0ezx/9ru8v/X7fH/2O3x/8vs8v/S7fL/2O3x/9nt8v/L6/H/wenx/8vr8P/N6vD/y+nv/8fo + 7//I6O//vuXu/7zk7f/J5Ov/wOHq/8Th6f/A1+L/xa7J/9CFsP/Td6b/2nuo/9tunv/baJv/3Gqc/95o + mv/fa57/32md/+Fzpf/iap3/5FSM/+VrnP/jYpf/5FeO/+Rllv/kX5X/43em/+R1pP/kd6b/42ic/+Jl + mf/jdKb/436s/+Vjmf/lbaL/5nKm/+drn//meqz/52ig/+dwpP/od6n/6Ye3/+iHtP/oeqr/6Y25/+eI + tf/mg7H/53qp/+N5qP/gY5P/4XCf/+GBrP/igaz/4n+r/+N8qf/igKz/43+q/+Ztnf/mZJf/5HGe/+WA + q//me6n/5YCq/+Vtnv/keKX/5IGr/+dunv/ngaz/5YGt/wAAAAAAAAAAAAAAAAAAAAAAAAAA6LHLQuiv + yv/nrMn/3+Lq/9vv8//Z7vP/2u7z/9nt8v/Y7fL/1e7z/9fu8//a7fH/2O3x/9jt8f/V7fL/1+3y/9Tt + 8v/a7vP/1uzx/9Xs8v/Y7vL/0ezy/9ju8v/S7PL/2e3x/87s8v/P7PL/zuzx/9Lr8P/Q6/D/1ezx/9nt + 8f/Q6/H/1ezx/9ft8f/O6/H/1O3y/9ft8v/O7PL/1O3y/9jt8v/d7vL/zezy/8zr8f/b7vL/zezy/8Pq + 8f/X7PD/zurx/8Lp8f/L6vH/w+nw/8fp8P/L6e//xefv/77n7v/F5Ov/xuLq/8Pg6v/G3uf/xsHV/8SB + qv/SVoz/2nup/9t3p//cXJH/3m6f/954p//fga7/4HOk/+Fsnf/jbKD/43ip/+VonP/mW5D/5VeP/+Rh + lP/kcaP/5Hmp/+Rpm//kcqL/5Gue/+R5qf/kfa3/5XOk/+RXj//ngrH/52yh/+d0p//peKr/6ou3/+qI + tv/qjbj/65vC/+yYv//rkbr/65e8/+uYvv/roMT/6pG5/+mVvP/ojbf/5n+s/+Bxnv/hc6H/4YGs/+J1 + of/jfar/4num/+J8qv/ifKr/5Wyb/+Z3pP/kc6D/5XOi/+Vyov/leqb/5XSi/+Rsm//je6f/5oCq/+Z9 + qv/mlrv/AAAAAAAAAAAAAAAAAAAAAAAAAADossuf6KrH/+eewf/mpsb/3uTr/9vu8v/a7/P/2u7y/9nu + 8v/a7vL/1u7z/9ru8//Y7fL/2+7y/9nt8f/X7vL/2O7z/9bu8//c7vP/2O7y/9Lt8//Y7vP/2u7z/9Xt + 8//i7/P/3O/z/9Xu8//W7vP/1e7y/9Ds8f/V7PL/0+zx/9bt8v/U7fL/0+zx/93u8v/V7PH/yerx/9zv + 8v/J6/L/1u3y/9fu8v/X7fL/2e7y/9Hs8v/O7PL/0+zy/9Ls8f/Y7fH/0Ovw/9Dq7//L6e//w+jv/87p + 7v/J5+7/w+Xt/8fk7P/E4Or/wMvc/8KuyP/Rf63/2mya/95ejf/dcqT/32qf/+Fzov/gYJj/4GOZ/+Fn + nv/jb6P/5GKY/+U4eP/lT4r/52SZ/+dSjP/nYZb/5nmp/+VXj//lear/5V6W/+dqnf/ndaX/54Kx/+dy + pv/ofq3/6G+h/+qMuf/qear/6nut/+yZwP/sibX/65O5/+yavf/slbn/7J2+/+uPr//pjKr/6Zi2/+eU + sf/leqP/54eu/+mOtf/nh7H/44Cs/99tnP/hf6n/43yp/+OCr//kZ5j/42ma/+Jzov/lb6H/5GmZ/+J5 + pv/ke6f/5XCd/+R5pv/kfaj/43ej/+N4pf/lcKD/5oOs/+WKsv8AAAAAAAAAAAAAAAAAAAAA6LLLC+iu + yenprMj/6aPF/+ecwP/lo8P/3ePr/9vu8v/Z7vP/2e7y/9fu8//Y7vP/2O7z/9ju8//X7vP/2O/0/9rv + 9P/c7/T/3e/z/93w8//c7/P/2O/z/9ru8//Z7vP/2u/0/93v8//c7/P/1u7z/9zw8//M7PL/4vDz/9ju + 8//c7/P/3vDz/9fu8//b7/P/2e/y/9ju8v/U7fL/2O7y/8vs8v/W7vL/z+3z/9Ht8v/X7vP/1e3y/8br + 8v/T7PH/z+rx/8rq8f/H6fD/xenw/8To7//B6O//xufu/8bl7f+74uz/wd3o/8rC2f/RhrX/1F6R/9tq + m//ecaD/4X2s/+N0pf/jaJ7/5HWo/+V1p//lUYz/5m2i/+Vrn//nfq3/6E6G/+hsnf/pYpj/6XCj/+hS + jP/odKb/6IGt/+iFsv/pkLn/6nel/+psnf/qfKn/6nup/+uSt//rhbD/7JG4/+uBqf/rhqv/66C5/+mc + tf/pr77/6cHM/+jHzv/o0tb/5tTZ/+XV2f/j09j/3snP/9Orvf+/WYr/wzxk/+V4o//khLD/4Haj/+J1 + ov/jbZ3/5Xel/+VjlP/japr/4nOj/+Rtn//kZpf/43up/+R0of/kdaL/5Gmc/+Rwnv/jhK//43Oj/+R9 + qf/lh6//5Y20/wAAAAAAAAAAAAAAAAAAAADpsMtH6q/K/+msyf/pn8H/5p/B/+aSuv/mmbz/3uLr/9vu + 8v/a7vP/2u7y/9vu8v/b7/P/2+/z/9rv8//Y7/P/2O/0/9jv8//c8PT/1+/z/9jv8//T7vP/1+7z/9zv + 9P/c8PT/3e/0/9zw9P/W7/P/2/D0/9vw9P/e8PT/3vD0/9nv8//f8PT/2u/z/9zv9P/W7vP/z+3z/87t + 8//Y7/P/0+7y/9Pu8//J7PL/1+3z/9Tt8v/T7fL/zOzx/9Ts8f/Q6/H/0ezw/8vq8P/J6fD/zuju/8bn + 7v/I5e3/xuXs/8rf6f/Rwtj/3Im3/+GLuP/ib6D/42SX/+R7qf/ka6H/526f/+dXkf/piLT/52+j/+mA + rf/nbaH/6H6r/+p+q//pa5z/6pe+/+qBrf/rfKn/6maW/+tzn//rdqP/6m6b/+uHrP/qe5//6YGg/+mW + q//pq7v/6LbE/+jBy//oztX/6Nbb/+ja3f/p3d//6d/h/+rh4//q4uT/6uPk/+rk5P/q5OT/6uPk/+nh + 4v/m29z/3crP/8OCn/+lGUL/22qT/+SKs//hhK7/4lyL/+VtnP/mZpf/5Wmb/+N1o//ieaf/5meY/+Vt + nf/jeab/5Guc/+RyoP/mfan/5G6d/+OCrf/jdKT/5Xej/+WErv/llbj/AAAAAAAAAAAAAAAAAAAAAOy6 + 0ZfrrMn/6qPE/+mgwv/mnMH/55vA/+iSu//mmL7/4Nvl/9vu8v/c7/L/2u7y/9vv8//a7/P/2+/z/93v + 8//d7/P/2O/z/9vv8//U7vT/1+/0/9bu8//Y7/T/2e7z/9bv8//a8PT/2/D0/9Tu8//V7vP/1O70/9vw + 9P/g8PX/2+/z/9zw9P/X7vP/4PD0/9ju8//d8PP/1u7z/9bv9P/W7vP/0O3z/8/t8//T7PH/0+3y/87s + 8f/M6/H/z+rw/87q8P/Q6e//wujv/8fn7v/I5u3/xuXt/8nk7P/K4er/17nU/+B+qf/ljrX/6JK7/+eK + sv/pirP/54Sv/+l4pP/pcaL/6mKU/+p7pf/qbJ7/64Kr/+lynf/peZ7/6YOh/+mOq//opb7/6KvA/+ev + v//nt8L/5r/K/+bJ0P/n1Nr/5trf/+fd4f/o3+L/6eHk/+ni5P/p4+T/6uTl/+rk5f/r5eb/6+bm/+vn + 5//s6Oj/7Ojo/+zo6f/s6On/7Ojo/+zo6P/s6Oj/6+bm/+nh4P/h09T/y5m3/6sxYv/hhKr/5Y20/+N/ + q//hbpv/5Wyb/+Vgkv/maZr/42CU/+V2pf/mYJP/5G6d/+R2pf/kc6H/5XOi/+ZjmP/lXpL/5HCg/+R8 + qP/ld6X/5YSs/+aFr/8AAAAAAAAAAAAAAAAAAAAA7a/MzO2ryv/tp8f/66jI/+igxf/nmcD/6pS//+uT + vv/pmcD/5cfb/93r8P/a7/P/2+/z/93v8//b7/P/2u/0/93v8//d7/P/2+/z/97v8//b7/P/3vD0/9rw + 9P/b8PT/3fD0/9jw9P/c8PX/2/D0/+Lw9P/h8PP/2e/z/9vv9P/c8PT/3/H1/97x9P/j8fT/1+/0/9Lu + 9P/Z7/T/0+7z/9nv8//V7vP/0u7z/9ft8v/S7PH/y+zx/87r8f/R6/D/zenv/8vo7v+/5u7/xOXt/73j + 7P/H5e3/yOHq/9XG2P/ggKb/31SG/95zl//bYIn/1mWI/9Bpif/IXX3/vE5t/7FEZP+pOlb/nzdO/4sp + P/96Kz3/u5qx/97P0v/j2t7/5t3g/+ff4f/o4eP/6ePk/+nl5v/q5eb/6ubn/+rn6P/r6Oj/6+jo/+vo + 6P/s6en/7Onp/+zp6f/s6er/7Orq/+zq6v/t6ur/7erq/+3r6v/t6+v/7evr/+3r6//t6+r/7erq/+zp + 6f/r5+f/6eHi/+HQ1f/Lm7r/zYWr/+aStP/mi7P/44Ks/+Jtm//kXo//5Wub/+VhlP/kYJL/5lKJ/+Vu + nv/jcqH/5Gqb/+ZrnP/nbJ3/52OW/+Vwn//lapv/5Xum/+Z1pP/ncqD/54Ss/wAAAAAAAAAAAAAAAAAA + AADusMqL7q/L/+6tyv/trsz/7K3M/+ykx//tl7//7Z/E/+yZvv/rncP/6KXE/+DZ5P/a7/P/2u/z/9vv + 8//b7/P/2+/z/9zv8//a7/P/2u/z/9/w9P/c8PT/3vH1/97w9P/h8fX/3/H1/+Dx9f/g8fX/5fL1/+Px + 9P/c7/T/4PH0/9nw9f/U7/X/3fH1/9zw9P/Z7/T/1u/0/9vv8//e7/P/2O70/9rv8//P7vP/1e3y/8vr + 8f/P6vD/xunw/8To7//K5+3/xOXs/8Xm7f/I5ez/v+Lr/8Pi6//I4On/qb3H/1FIVP9BKC//NyYr/ykm + J/8dJiX/HCcm/yAoKP8mKir/Kisr/ywrK/8rKir/Kigo/yYiIv9fU2X/2dLZ/+fj4//p5ub/6+fn/+vo + 6f/r6er/7Orq/+zr6//s6+v/7evr/+3r6//t6+v/7evr/+3r6//t7Oz/7ezs/+3s7P/t7Oz/7ezs/+3s + 7P/t7Oz/7ezs/+3s7P/t7Oz/7ezs/+3r6//t6ur/7Ojp/+vl5v/n3N//3cXP/9anv//mqcT/53+q/+aM + tf/kgKv/4HOg/+N4pP/lZpX/5Wib/+R+q//mWo3/5Wyd/+Rsnf/lZpj/5lqP/+Zkl//lbJz/5XSj/+ZY + jv/lcqD/5nqn/+hqmf/ndKH/AAAAAAAAAAAAAAAAIR0eAO6yxgbvscdB77zPnOq+zv/hm7H/4omm/+N8 + oP/kjqn/436g/+KCov/cdJb/0nGT/8KaqP/G3OL/2u7y/9vv8//c7/P/3O/z/93v8//b7/P/3/Dz/9zv + 8//c8PX/3/H0/9/w9P/g8fX/5fL1/9jw9f/e8fX/5vL1/+fy9f/i8vX/3/H1/9/x9f/c8fX/2vH0/9Pu + 9P/Z7vT/3u/z/8/t8//O7vP/0O7z/8ns8v/K7PL/0ezx/8nr8P/O6u//y+bu/83n7f/K5e3/yOTr/8Tj + 7P/B4ev/sNHd/3iPnP8uOUP/LDU8/y81OP8xNTf/MTM0/zI0Nf8yNDX/MjM0/zIzM/8yMjP/MjIz/zEy + Mv8xMTH/MTAw/ysnJ/+tqbP/6Obn/+vq6v/s6+v/7ezs/+3s7P/t7Oz/7ezs/+3t7f/t7e3/7u3t/+7t + 7f/u7e3/7u3t/+7t7f/u7e3/7u3t/+7t7f/u7e3/7u3t/+7t7f/u7Oz/7ezs/+3s7P/t6+z/7evr/+3p + 6f/s5uf/6eDh/+PS2f/gvND/5KvF/+ibvf/ojrX/5oiy/+SEr//gcKD/5G+d/+ZelP/lapv/42OY/+R2 + pP/kbJ3/5F2S/+N5pv/mbJ3/5VqO/+Nsnf/kcaD/5HCf/+N5pf/lfKf/52qX/+Z/q/8AAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAADz8vFJyMXG/1tbW/9LS0v/Q0RE/z09Pf84OTj/MzU0/zAxMf8tLS7/LCst/y80 + OP+DmqL/xt7k/9ju8v/b7/P/3vD0/93v8//e7/P/3+/0/97w9P/g8fX/3fH1/+Hx9P/c8PT/1u70/9Xv + 9P/X7/T/1+/0/9jv9P/c8PX/3PH1/9fw9P/X7/T/1e7z/9Ds8v/P7PL/0uvx/83s8v/N7PL/y+rw/83p + 8P/G6O//x+fu/9Hn7f/P5u3/zeXs/8jk7P/F4uz/wuHr/63I0f9Za3f/LTg9/zE5Pv80OT3/NDk8/zU5 + O/81ODv/NTg5/zU3OP80Njf/NDY2/zQ1Nf80NDT/NDQ0/zMzM/8yMjL/MjEx/2Fgaf/i4eX/7Ovq/+3s + 7P/t7e3/7u3t/+7u7f/u7u3/7u7t/+7t7f/u7u3/7u7t/+7u7f/u7e7/7u3t/+7t7f/u7e3/7u3t/+7t + 7f/u7e3/7u3t/+7t7P/u7Oz/7evs/+3r6//t6en/7Ofn/+rg4v/m1dr/5sPT/+u50v/qlLj/54+0/+eC + r//nh7H/5ISu/+Num//kapr/5l+P/+VRh//kcaH/5Gaa/+Zklv/jX5L/5WCR/+Zhlv/lYpT/5HWk/+Ns + nP/jcaD/42yb/+RyoP/jeKL/5oWt/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPX09V+ioqH/XFxc/1JS + Uv9LS0v/R0dH/0RERP9CQkL/Pz8//z09Pv88PD3/Ozs9/zg6PP8sQEj/ip6m/9Hk7v/Z7vP/2+/z/93v + 8//e7/T/3/D0/9/w9P/c7/T/3vD0/9vv9P/k8PT/3u/z/93v8//a7/P/2+/0/9vv9P/U7/P/1e7z/83u + 9P/R7PH/0+zx/9Dr8f/Q7fL/0e3y/9Ls8v/U6/D/1erv/9Hn7v/K5+7/z+fs/87l7P/F4uz/yeHr/7/c + 6v+NscL/N0hZ/zE9RP81PEL/OD1A/zg7Pv84Oz3/Nzo8/zc5O/83OTr/Njg4/zY3OP82Nzf/NjY3/zY2 + Nv81NTb/NDQ1/zMzM/8yMjL/Li0s/8PCy//r6+v/7e3t/+7u7f/u7u7/7u7u/+7u7v/u7u7/7u7u/+7u + 7v/u7u7/7u7u/+7u7v/u7u7/7u3u/+7t7f/u7e3/7u3t/+7t7f/u7Oz/7uzs/+3r7P/t6uv/7Onp/+zm + 5//q4OL/5tXb/+bD0//rtM3/66XE/+mDrv/ohK//6IOx/+iMtv/kfKj/4WqZ/+Jtnf/kZ5j/5HOk/+R6 + p//mYZT/5z96/+RwoP/lTYL/5Gyf/+Rsnf/jYpf/422d/+Nvn//hdaH/4nel/+F/qP/lcZ7/AAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA8fDxdHx8fP9aWlv/UVFR/0xMTP9ISEj/RUVF/0NDQ/9BQUH/Pz9A/z0+ + P/88PTz/Ojs8/zU6Pf8lMDr/mqfE/93m7P/g7PH/3u7z/9zu8//d7/P/3vD0/9/w9P/f8PT/3/D0/9/w + 9P/d7/P/3e/0/9rv9P/b7/T/3e7z/9ru8//T7fL/0uzy/8/s8v/O7PL/0+zx/9Dr8f/P6/H/z+rw/9Hq + 7//V6O7/0uft/8/l7f/R5Ov/0OTs/8ri6//I3en/y9nm/2Fzhv84Q0n/OkJF/zs/Q/87P0L/Oz5A/zs9 + Pv86PD3/Ojs8/zk6O/85OTr/OTk6/zg5Ov84ODn/Nzc3/zY2Nv81NTX/MzQz/zMzM/8yMjL/lZWh/+rp + 6//t7e3/7u7u/+7u7v/u7u7/7u7u/+7u7v/u7u7/7u7u/+7u7v/u7u7/7u7u/+7t7v/u7e7/7u3t/+7t + 7f/u7e3/7uzs/+3s7P/t6+v/7erq/+zo6P/r5OX/6d7h/+fS2v/mwdL/7LPO/+yev//plrn/6I2z/+iT + uv/piLL/54Gu/+SFr//fcJ7/4XOh/+Rsm//kbZ7/5V+T/+Zek//mVon/42+g/+Nllv/jZ5n/5GGU/+Nm + mP/ja5v/4W6f/+B4pf/hcqD/4XWh/+R8p/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADf3t9/cHBw/1pa + Wv9SUlL/TU1N/0lJSf9GRkb/RERE/0JCQv9AQUH/Pz8//z0+Pv87PDz/ODs7/y01O/9meJT/2+Hq/+jr + 7//s7/H/6e/y/+Tv8//h7/P/3+/z/9/v8//g7/P/3u/z/9rv9P/b7vT/2u7z/93u8//c7vP/3u/z/9rv + 8//a7vP/0e3z/9Dt8v/T7fH/0e3y/9Hs8v/R6/H/z+ju/9Pl7P/T3uj/z9zp/8/W5P/Q1eP/1NXk/9vb + 5v/r6+7/bHB3/0BGTP8/REb/QENF/z9BQv8+QEH/PkBB/z0+P/88PT3/PDw9/zs8Pf86Ozz/OTo7/zk5 + Of83ODj/NjY2/zU2Nv80NDT/MzMz/zIyMv9qa3j/5+fq/+3t7f/u7u7/7u7u/+7u7v/u7u7/7u7u/+7u + 7v/u7u7/7u7u/+7u7v/u7e3/7u3t/+7t7f/u7e3/7uzt/+3s7P/t6+v/7erq/+zo6f/s5uj/6uHj/+fZ + 3v/qzdr/68HU/+yyzP/tpMT/6o60/+mEr//pm7//6Iiz/+iJs//njLX/5IOu/990ov/gdKL/42aX/+VZ + kP/mUon/5HSl/+NekP/idKP/4WiZ/+JxoP/iV43/42SX/+FrnP/gb6H/4WeX/99sm//gc5//4YGo/wAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAM7Oznxra2v/WVlZ/1JSUv9NTk7/SkpK/0dHR/9FRUX/Q0ND/0FC + Qv9AQED/Pj8//zw9Pf85Ozv/NDc5/ztLYP/O2Ob/6ezu/+3w8f/t8PL/7fDy/+3v8v/s7/L/6O/y/+Xv + 8v/k7vL/4u7y/+Dt8v/e7fL/3ezy/9vs8v/Z7PL/1+3y/9Xt8v/V6/H/1Ovx/9Lp7//T5u7/0uPs/9Td + 6f/U1OP/1cXb/9S41f/QstL/16fM/96fx//ft9f/7ufs//Dw8f9zbXT/RklN/0VISf9DRUb/QkNF/0FD + RP9AQkP/P0BA/z4/P/8+Pz//PT4//zw9Pf86Ozv/Ojo6/zg5Of83Nzf/NTY2/zU1Nf8zMzP/MjIy/zs7 + RP/h4ef/7ezs/+7u7v/u7u7/7u7u/+7u7v/u7u7/7u7u/+7u7v/u7u7/7u3t/+7t7f/u7e3/7uzs/+7s + 7P/t7Oz/7err/+zo6f/r5uf/6uLk/+jc4f/m09v/6cfX/+y0zv/rnb//7Iux/+qavf/rnr//6Zq7/+iX + vP/pl7z/6Yy0/+aGsP/jfKr/33ak/+B6pv/jc6P/5mKU/+ZXjv/kcqD/4meY/+Ftnv/fb57/4HGh/+Ji + lP/hXpH/4GCU/99gk//iVov/32WX/95wnP/feaP/AAAAAAAAAAAAAAAAAAAAAEY9QADq2+AC1MvOpmtr + a/9aWlr/U1NT/05OTv9LS0v/SEhI/0ZGRv9ERET/Q0ND/0FBQf8/QED/Pj4+/zs7PP82ODr/KC42/7vE + 1v/q7O7/7/Hy/+7w8v/u8PL/7vDy/+3w8v/t7/L/7e/y/+zu8v/r7vH/6+3x/+ns7//k4Or/4Mjf/+PR + 4f/h2eb/4trm/+PT4v/lxtz/57PT/+Wly//jkMD/4Ia8/9iFuP/dbav/3Vaj/9dNm//XS5j/3WCm/+iw + 0v/x7/D/8PDy/4N7gf9NTVD/SUtM/0hJSv9FRkj/REVH/0NERf9CQ0T/QUJC/0BAQP8/Pz//PT4+/zw8 + PP86Ozv/OTk5/zg4OP82Njb/NTU1/zQ0NP8zMjL/MzEy/9ra4f/t7Oz/7u3t/+7u7f/u7u7/7u7u/+7u + 7v/u7e3/7u3t/+7t7f/u7e3/7uzs/+3s7P/t6+v/7erq/+zp6v/s5+j/6+Tl/+ne4f/n1tz/6MnX/+u/ + 0//sq8f/65S5/+yLtP/rjLL/65S6/+uMtf/pi7L/6Yu1/+iGsP/oirP/5Ymz/+R7qf/edKL/4W6c/+J2 + pf/lZ5f/5Uh//+Nxof/hc6D/4WKU/+Bqm//fZ5j/33Gh/99wof/fX5L/3GCT/99aj//dV4//3GOS/99z + nv8AAAAAAAAAAAAAAAAAAAAAAAAAAOvM3FThx9L+b25u/1tbW/9UVFT/T09P/0xMTP9JSUn/R0dI/0VG + Rv9ERET/Q0ND/0FCQv9AQUL/PT4+/zg5O/8wMzL/qLHG/+nr7f/v8fH/7/Hy/+/x8v/u8PL/7vDx/+3v + 8f/t7/H/7e7x/+zu8P/s7e//7Ovu/+zp7P/oqcz/5Gep/+d2sv/pgLj/64S7/+pnqv/rV6L/6lWf/+hY + nv/nN47/5TSH/+Mcc//jDGr/3zKB/9wreP/fIXX/67DN//Hv8P/x8fL/nZaa/1JPUf9MTk//SktM/0pL + S/9ISUn/RkdH/0VGR/9ERUX/QkJC/0BBQf8/Pz//PT09/zs8PP86Ojr/ODg5/zc3N/81NTX/NDQ0/zMy + Mv8xMDD/2Nfe/+zs7P/u7e3/7u3t/+7t7f/u7e3/7u3t/+7t7f/u7O3/7ezs/+3r7P/t6+v/7erq/+zo + 6f/r5uj/6uTm/+nf4//n193/6czY/+zD1v/rrcf/6oy0/+uXu//pj7P/65a9/+uMtP/spcX/7Iiy/+ye + wf/rocP/6Za8/+ePuP/libP/4nWl/99unf/iapr/4nup/+Rtnf/kZ5j/426f/+Jhk//hapv/32qc/95l + lv/ca53/21+U/9thlv/aV4z/2VSK/9pckP/ZZJP/23Kb/wAAAAAAAAAAAAAAAAAAAADt0NsK7dHe1uOo + vv92dXX/XV1d/1VVVf9QUFD/TU1N/0pKSv9JSUn/R0dH/0ZGRv9ERUX/Q0RE/0NDQ/9AQUH/Ozs8/zM0 + Nf+dobT/6Ort//Dx8f/w8fL/8PHy/+/x8f/v8PH/7e/w/+3u8P/s7e//7Ozu/+zs7v/s6+3/7Onr/+vk + 5//lhbv/41GZ/+Vjpf/pbKz/7Fqh/+1MoP/sa63/6jiN/+lKmf/mHXf/4yeA/+MSav/kFGz/4Btz/+Ad + dv/qpcb/8u/w//Lw8f++tbn/WlJW/1NSU/9RUVH/T09P/0xNTv9LS0z/SUlJ/0dHR/9FRUX/Q0ND/0FB + Qf8+Pj7/PT09/zs7O/85OTn/Nzc3/zY2Nv80NDT/MzIy/zIuL//a2eD/7Ovr/+3s7P/u7ez/7ezs/+3s + 7P/t7Oz/7ezs/+3r6//t6ur/7Ojp/+zn6P/r5eb/6uLk/+je4P/m1dz/6sXW/+mtxf/smLz/7aHA/+yQ + tf/tqsf/6oux/+ufwv/urcv/7rPO/+6pyP/umb//7Z7B/+qQt//qnL7/55C4/+aJsf/je6j/4HCg/+Nx + n//kbp//43Sj/+Vil//jX5P/4WaY/99xof/daZr/3GaY/9xQhP/aW5D/2FKK/9hOhv/YVI3/2FGJ/9pZ + j//db57/AAAAAAAAAAAAAAAAAAAAAO3R3T/svNH/4HSK/4eCgv9gYGD/V1dX/1FRUf9OTk7/TExM/0pK + Sv9JSUn/SEhI/0hHR/9HR0f/RUZG/0RERf8/P0D/NTU2/5SYrf/p6u3/8PHw//Dw8f/v7/D/7u/w/+7v + 8P/t7u//7e3v/+zs7v/s7O3/7Ovt/+zq7P/s6er/6+fo/+vW4v/jSKX/3jmS/+Zjpv/sV5//7WOl/+5k + p//pNIX/6l+j/+c/hv/mQ4z/4y57/+IleP/iF3L/4QVm/+eYuv/y7+//8vDw/9zX2f9gVFj/WVdY/1VV + Vf9UU1T/UlJT/09QUP9MTE3/SkpK/0hISP9FRUb/Q0JD/0BAQf8+Pj7/PDs8/zk5Of84Nzf/NjU2/zQ0 + NP8yMTH/PDQ7/+Lg5f/r6ur/7evr/+3r6//t6+v/7erq/+3q6v/s6en/7Ojo/+vm5//q4+X/6N7i/+jY + 3v/m0tv/57vM/+qpwf/slrn/7HSh/+yDrP/rhKz/7JO3/+uAqv/smLv/656//+2qyP/so8T/7qHC/++Q + uv/vnML/7JK6/+qYvf/olrz/5Xyo/+J0o//gZpf/5Gua/+Vhk//lapv/42SV/+J5qP/fbJv/3m6f/9xk + lv/ZXpH/2EiA/9ZUjf/YUoz/2VGM/91cl//eYJr/32Kc/+Fon/8AAAAAAAAAAAAAAAAAAAAA7c3cZ+mc + vP/XL1j/qJmc/2NjY/9ZWVn/U1NT/1BPUP9NTU3/TEtM/0tKS/9KSkr/SkpK/0pKSv9LS0v/SUlJ/0ND + Q/83Njf/mJqt/+np7P/t7u//7e7v/+3t7//t7e7/7e3u/+3t7v/t7O3/7Ozt/+zr7P/s6uv/6+jq/+vm + 6f/q5Ob/6eDj/+J6q//ZCWj/4EuV/+txs//wg7z/72Gp/+19t//qa6T/6nWu/+hjn//lVJb/5T+K/+Ih + dP/aD13/3GST/+3m6f/x7e7/7+zt/4Fxd/9gXF3/YF5f/11cXP9ZWVn/V1ZX/1NSU/9PT0//TExM/0lI + Sf9GRUX/QkJC/z8/P/89PDz/OTg5/zc2N/80MzT/MzIy/zAuLv9pYnH/5uPl/+vo6P/r6Oj/6+jo/+vn + 6P/r5uf/6uTm/+ni5f/p3+P/59vg/+fS2//ox9b/6rLK/+qux//tosL/7Ymx/+2HsP/thqv/7JC0/+uK + sP/urMn/7p2//+2XvP/ur8v/7KXF/+6tzP/vncH/8aPE/+6LuP/tlLv/6pe8/+iTuv/lf6v/4nGh/+Jm + mP/kdKP/42KT/+Run//ieKf/4HOk/95tnf/dYZP/2VyP/9dPiP/YUY3/2leS/91cmP/fYZv/32Cb/+Fm + n//iYZz/42Ke/wAAAAAAAAAAAAAAAAAAAADt0+Bi6Jm4/9AQQ//AlqL/amho/1xbW/9WVVX/UlFR/09P + T/9OTU3/TU1N/01NTf9OTk7/UVBR/1FRUf9RUFD/SUhI/zY1NP+gn7H/5+bp/+zr7P/t7O3/7ezt/+zr + 7P/s6+z/7Ovs/+zq6//r6ev/6+fq/+rl6P/p4+b/5+Dj/+Ta3v/i0tz/4KnE/9w8eP/kRof/52Cw/+5X + qf/wc7f/8JDB//CEuv/vjLv/75jC/+2Svv/pSpT/52ig/9AsY//JG1v/373P/+rh5//s5ur/vbG3/2hg + Yv9nY2T/ZGJj/2FgYf9eXV3/WFhY/1FPT/9PTk//S0lK/0dFRv8+PDz/NzY2/zQyM/8zMDH/Mi8x/zEu + L/8xLi7/KSIk/5iNnP/m4eP/6ePk/+ji4//o4eP/6N/i/+fc4P/m1dv/5tDZ/+bAzv/orsL/6qC+/+x6 + n//rfqr/7J7A/+2iwv/sg6r/7Ze5/+yHq//rlrr/7aLB/+yRt//vq8j/7Zm7/+6ryf/tpsb/7arJ//Cr + yP/viLL/753C/+6awP/rj7j/6Ja7/+SGsP/ha53/4m2d/+J5p//jcJ//5GeY/+Jyo//fc6T/3WiY/9ld + j//WVoz/2ViS/91alf/fX5n/4GKc/+FhnP/hX5v/4mWf/+NgnP/jZqD/AAAAAAAAAAAAAAAAAAAAAO3P + 3zPqpMH/zBdE/8uEkf9/cXf/YF1e/1hVVv9VUlP/UlBQ/1FOT/9QTk//UE9P/1JQUf9VVFT/WVhZ/1xa + W/9OS0z/LiUk/66owP/n5ef/6ujp/+vp6v/r6Or/6ujp/+rn6f/q5uj/6eXo/+jj5//n4OT/5dvh/+PU + 3f/iyNf/46/G/+aTs//rc6D/6mWW/+uHrf/phbD/7obC//Cfx//xZLv/8JXF//CMt//xnsP/74W1/+1d + oP/rga//6pS5/8plg//Fc6X/38XY/+XX3v/h19z/fWhw/2JYXf9iXF//WVRX/05JSv9LRkj/OjM2/z02 + OP83MjT/NjAy/zErLf8vKSv/LSYo/y0lKP8tJCf/Jx8i/yYfIf8mCAf/wq28/+HV2v/j0dn/49HY/+XL + 1//lydT/6LzN/+qvyf/pp8T/6Xyj/+qAqP/rjbT/7X2m/+2CrP/qj7T/7qvI/+yHrf/tl7r/7aLC/+6y + zP/sj7H/76PD/+2Xuf/upMH/7pm9/++xzf/uoML/76TE/++Xvf/unMD/7ZO7/+yXvP/nkbf/5Hup/+Bu + nv/jW4z/4nin/+Nbjf/kV4v/4HOk/9xnmf/XU4b/0lCE/9dQiv/cTYr/4FeU/+Bim//hZZ3/40iI/+Nd + mP/iW5j/4mig/+Foof8AAAAAAAAAAAAAAAAAAAAA7snXBu7I2d3XaYj/tjRL/66Fl/9nUFj/W0tQ/1JG + Sv9TSUz/SUJE/01GSP9LRkf/RkBB/1dTVP9QTE3/Qjw+/0o+Qf8pDxz/w7bK/+Td4f/n4eP/6OHk/+fg + 4//n3+P/59zh/+bb4f/l2OD/6NHd/+jB1P/nq8L/6p6//+yKsP/sbpz/7Za6/+yKsf/sgqr/7Ji7/+qH + rv/sjrz/8XvE//GOvv/xqMr/8Z/D//CcwP/wp8f/7Yu7/+2Crf/snsD/6rnR/+Kvyf/Zn8X/2rrQ/9zI + 1P+1nqn/QyYu/0ArMv9HLjf/NSUr/zkoLf82JSv/OCUr/0AnL/9KKTX/QSYw/2g9Tv9yR1f/VDA9/5Bb + cP9XLDj/US05/4BMZf/Uo7v/37DF/+ewyP/mnbr/54uw/+mau//rkLP/65a7/+ugwf/sp8P/7KDA/+2h + v//tmLn/7Y2y/+yZu//spsP/7arG/+2YuP/ti7P/7Zm7/++vy//vqsj/7qTE/+60zv/thq//8KjJ//Cv + y//wscv/76bF/+2fwf/tpMX/65e8/+d/q//ibqD/4GiZ/+Nrnf/jZJf/41+T/+Fjlv/dZpn/2mCV/9RH + e//TPXT/3VuU/+BalP/gWZT/4V+Z/+Jonv/kTYn/5FiU/+RKif/jWZb/4l+a/wAAAAAAAAAAAAAAAAAA + AAAAAAAA7sLVi+q/0v/Pl6n/xoKi/3BEV/8+Iyv/PSMs/zwpLv8/LjP/Oikt/zgoLP8zJCn/UDtC/z0v + M/9QND7/cVNg/5Nrgv/Wtc7/4svX/+nL2//lzNj/58rY/+fG1v/qvtX/6rrR/+ugvf/tfqn/7ZK5/+yJ + rv/thq3/7X6p/+2Aqf/wttH/7Z29/+2Zu//upML/7aXC/+uWuv/yo8r/86DI//Kpy//yqcr/8Z3B//CZ + v//vm7//7Xio/+ybv//ro8P/7KfH/+quyP/mqsf/353A/9qkv/+/dpX/u2mK/851lP+9c5L/pl15/6tr + hf/Ie5z/x36c/9R+of/Of6L/1Yqo/9J8oP/TfqD/5Zi6/+KRsv/ic5f/6oqt/+qGrP/qgKj/7qnJ/+yX + uf/roMH/6qPC/+p7o//qdaD/7KHA/+qIq//tqcb/63eh/+t8o//rnLv/6nmk/+6mxf/so8H/77LM/++r + yf/vscz/7rLM/++rxv/unL3/77jR//Czzf/wqcj/8aXH//Cvy//uq8f/7qvJ/+2Vuv/qlbr/53yn/+Fo + nP/hZZf/42eZ/+Raj//ia5//32GU/98+cP/UP2//10uD/91Hgv/fSYj/4FiU/+BgmP/hWJL/4VyX/+JQ + jv/jXZf/5VqS/+Nemf/jZ5//AAAAAAAAAAAAAAAAAAAAAAAAAADuuc407rTM/um1y//mtMr/4avC/794 + lP/AgZn/yYOh/7Jog//IhqL/oVx4/6ZWb//Vm7X/s11//9abtP/XmrP/5aTB/+q10f/rqMn/77LP/+2a + uv/vpcf/7pS5/++gxP/wrc3/7oav/+6Msv/vn8D/8KzK//Cmxv/ukbP/75O4/+2Wuf/uqMX/7qnH/+t5 + pP/urcn/7J29//Kvz//zqsz/86rL//Kpy//ylLr/8KXG//CVu//up8n/652//+yoxf/snL7/7Jy//+yb + wP/pncD/6Ja8/+mVu//nh7H/6VGQ/+l3pf/pg7D/6Y22/+d9qv/pj7j/6F+X/+mLtP/ne6v/6p/D/+mQ + uP/qga7/7JO8/+p4ov/tjLD/7Zy8/+2VuP/sia7/7p+9/+2qxv/us8z/7Jq6/+uVtf/spMH/7JO0/+6n + xv/qiq7/7KbF/+62zv/to8L/76HE/+6uyv/vts7/7qTD/++zzP/usMj/76PC//Coxf/uqcb/8LbQ//C2 + zv/wss3/76rI/+6uyv/up8f/7aDB/+qPtv/kb5//4Wye/+Jmlv/kVoz/41qL/+FdkP/eXpL/2leH/9dO + hv/dT4r/31WO/+BEgf/gTov/4F6W/+BYkv/hYpr/4XSl/+Jdlv/jVJD/42CZ/+Jrov8AAAAAAAAAAAAA + AAAAAAAAAAAAAOvK2gHuscvE7rLM/+yzzP/tr8v/7KjG/+2YvP/tmsD/65i+/+uoyP/rnsL/7JC5/+yC + sP/ri7T/7Jm9/+ycwf/tjLX/76fI/++oyv/wqMv/76DD//CoyP/vnL//8J/A//Ciw//vpsT/74+0//Go + x//vmLv/75q8/+6RtP/um7z/7Z68/+6qx//wtc//76zJ//Czzv/tmLz/8ajK//Oz0v/zqMr/8qzN//Gs + y//wrMv/8J/D//Cmyf/vj7r/7ajG/+yiwv/rocL/65rA/+yhw//rlb3/7ZO8/+yTvP/ri7X/7JC5/+x9 + rf/unML/7XWp/+xypP/sgrD/7Yuz/+6myP/uo8b/7Z7D//G20//vn8H/76nI//C00P/sjK//7Ze3/+6Z + uf/sgaX/64Gn/+2iwv/to8L/6ZCw/+yiwf/tnb7/7Zm7/+yrx//wttD/7aC+/+6qxf/vocH/7rPO//C3 + z//slLb/767J/+6mxf/wtM3/8bPO/+6hwf/wsMz/8LbP//Cyy//uq8f/77rR//Ctyv/tnsH/6Yiy/+Fv + oP/hbp//4maX/+Nmm//hUof/3luN/9hWh//ZVIv/20+J/95Ri//fVZD/4V+V/+Fil//gX5b/4W6g/99n + nP/fa57/4GGV/+Fpnf/haqD/42We/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO24zUvvssr97q3I/+6w + y//vsM3/76zL//Cixv/wpMj/75/F/++jx//ve6//76fK/++nyf/uqMn/76vL//G00//xrs//8rHS//Gp + y//yr8//8bfW/++Wu//yrcz/8aTF//Cgwv/xm77/8Ju8//Cpxv/vp8b/77HM//CxzP/wu9T/8LLN/++d + vf/wr8v/8KnH//Clw//xn8X/87bU//Kjx//zpcf/8rDO//Knx//xrs7/8aHG//CXv//un8H/7a3I/+yo + xv/tn8H/7KLB/+yqx//uq8r/763N/+2lyP/tqMr/7pzD/+6Jtf/vnMH/8Ji+//CszP/uh7L/7oKt//Gx + 0P/yttP/873Y//K81v/xsMz/8LPO/++uyf/uoL7/76jG/+2Xt//tn73/6568/+ysxv/rqMT/767K/++n + w//ui6//7q/K/++nw//qdJ7/767K/++lxP/vq8f/77XM/+yCrP/vsMr/77vT//C1zv/xtc//8bvT//Cm + xv/xtM3/8LTO//C60f/xrsr/76XD/+yYu//ld6X/4W2f/+Jdkf/jZZn/4mab/+Bfkv/ZWoz/1ViI/9tP + h//cU43/3k2H/+FYkv/iaJ7/4nan/+FnnP/gZ53/32Sb/9xjmP/dZpf/32SY/+Nqnv/kX5b/AAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA78DiAe62zLnvrsn/77HK/++syP/vtM//8K3N//CXv//wqsv/8KPG//Gj + yP/xnsT/8abJ//Gwz//xq8z/8rLS//Ox0f/yoMT/87LR//Kdw//yqsv/8a/P//GpyP/whLD/8Y20//CV + uv/wkbT/8K/L//Crx//wnLz/8afG//GqyP/yudP/8KHA//G+1v/wocH/8Z/A//CXvv/zo8j/86fJ//Ol + yP/zpcf/8pvA//Kqy//yp8n/8Z7F//Ccwv/urcn/7anG/+6cwP/uoML/7avI/+2qyf/wrMr/8KrK/++w + zf/vtdD/8LDO//Gtzv/xqcr/8afJ//K31P/yt9X/88Hb//Gqy//zuNP/8qvL//Kzz//wrsr/77fQ/+6u + yP/xu9T/76rH/+2zzP/tsMv/7K7H/+++1f/tgqX/752//+6lwf/uqcb/8KvG/+6jwP/wu9P/7Yyw//Cl + wv/vq8f/8LjR//G60v/wvNP/8K3J//G1z//yqcn/8rnS//Gmxv/ysc7/8rvT//CbwP/up8T/6o2y/+Fs + nf/iYZT/5FiO/+NUi//iY5X/4F2Q/9lhk//cV47/3FmQ/99pnP/hZpj/5GOX/+NNif/ja6H/4mWc/+JZ + k//hWpL/3muf/9xom//eW47/4FKF/+REgP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADHnLYA7rnNJu61 + zPTvssv/76nG//G1z//wuND/8LHM//G61P/xtdH/8rXR//Kuzf/yr9D/8rTR//K31P/yn8X/8qTH//Ku + zf/xrMz/8rTS//Gtzv/xtNL/8aHE//GGsP/yrcv/8JC2//Gpx//yttH/8bLN//GgwP/xpsX/8abF//Kn + xv/zss7/8rXQ//LC2f/xlLr/75u9//KYv//zqMr/9KjK//Otzf/yq8v/8qrK//Okx//ynsP/8J7D/+6j + xP/urcj/7qbG/+6dv//uosP/7arH/+6oxv/vmb3/8bPQ//G40//xvdf/8LLQ//Gz0P/woMH/8bHO//Kx + 0P/xvNb/8bbS//Gnx//xpsf/8afG/+6MsP/wu9P/77HK/+6nwv/tosD/77vT/+640P/vtM3/77rR/+2i + v//upsT/7rLL/+6vyf/umrr/7Yuw//C1zf/tmbr/8LTN/+2Yu//xuNH/8KzI//G+1P/yudP/8rvS//Gl + xf/xuNH/8q/M//OoyP/yqsn/8LTO/+2iwf/mfKb/4Wmc/+VhlP/mWpH/5FyP/+JDdf/YRHT/3l6U/+Bc + lP/hYpb/4G2e/+Nxov/lbKD/5mqd/+ZTjf/lXZT/5Ham/+JlnP/gap7/32+h/95hlP/fOmv/5XGh/wAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7rvPeO+5z//wqMb/8K3K//Gkxf/ws87/8cDX//Gs + y//ysc3/8qLH//KtzP/yr87/8rTS//Cnx//yq83/8a3N//Gy0f/ysND/8Ju///Gav//xp8j/8Yy1//Kp + yP/xrMr/75K1//K71f/whq//8rPO//K71P/yss//863M//OLtP/we6n/87jT//O0z//ukLf/8ajJ//Kh + xP/zq8z/86/O//Ovzv/yqsv/8qzM//KexP/xncP/8aDG//Clxf/ursr/7qfF/+6kxP/up8f/7bDM/++a + v//wqcn/76XF/++pyP/xutb/8bTR/++cwf/wlr3/8bHO//G10f/xsM3/8a7N//CUuf/ysc3/8KHB//C+ + 1f/vsMz/7qjF//C81f/vudH/7qnF/+6xyv/uoLz/8LfQ//Cxy//vt9D/8L3U//Cvyf/vqcb/8LTO/++s + yP/vtM3/8cHW//K10P/xnsH/8a3M//K60//ypcf/8KvI//HC1//xts7/8rDL//GryP/vssv/65S3/+Rd + jv/mTof/51GI/+Y/dv/iZpf/22OQ/9dIef/kX5b/5mWZ/+V2o//jb6D/5HCh/+Zuof/nYZb/51SJ/+dz + pf/ld6f/5GSZ/+JckP/fOnX/32GS/99XiP/kaZv/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADqtM2K7rTM//Cuyv/xqMf/8a3L//Gxzf/wsMz/8qjJ//KpyP/yr8//8qbI//K31P/yttP/8rjV//G0 + 0//ytdL/87fV//Klx//yqcz/8Z7D//O20v/yscz/8H6p//Kvzf/yvNb/8qfF//GNtf/yocL/87TQ//Gi + wf/yttD/86zK//Oxz//0vNb/9LPP/+6Zvv/vkbj/8Ze9//GszP/ynsT/8qvL//K00f/yqcv/8qrL//Gm + yv/xmMD/8ZnB/++pyP/wp8f/77HM/+6iw//uq8n/7q7L/++ewf/xr83/7qbG//G00f/xuNP/8KfG//G9 + 1v/xstD/8KjJ//Ktzv/xpcf/8r/Y//Kxzv/yrcv/8KXC//G50v/vrcf/8LzU/++1zv/uqsX/8MDX/+6g + vP/xpMT/8KjF//G2z//uqcX/8LbQ//CyzP/xutL/8bTP//G90//uosD/8bjR//K1z//zvtT/867L//Ko + x//wv9P/8b/V//K50f/yp8j/8KvI/+2oxP/mh67/4mOV/+ZakP/nUIf/5UuB/9xMev/SVX7/4FSF/+l1 + pf/ndaX/43il/+V2o//maZr/5nmo/+hBfv/obJ//5n2r/+V2pv/ldaX/43Oj/+FMf//eXo//3lmL/+Nk + lv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6cHTBeqxzOTrpcb/8LfP//CzzP/wtM//8arI//Gz + z//xp8j/8bLO//Gkx//yn8T/86nL//Kjx//yrs7/8qPH//K00v/yp8n/8qLI//COuP/ylbv/87LP//Kn + x//ypMX/8Ymy//O20v/xmLz/8qXF//Kty//0vtf/8r7W//TG3P/0sc7/9bXS//W81//1vNX/7qTF/+52 + pv/vnMD/76rJ//Cxzv/xrs3/8qjJ//Oqyv/zpMf/8qPI//Gdw//ylsD/8pnC//Cxzf/wrsv/8KbH/++s + yf/vsc7/7qTF/++kx//vr8z/8LHO//Cqyv/xpsf/8afK//Cyz//xtdL/8rvX/++ox//yu9X/8rnT//Kt + y//xq8n/8LDK/++1z//wwNb/8LjR//C20P/xvdX/8b/W//Clwf/vscv/8LXO//C60//ytM//8aTE//Gr + yP/wm7//8LLN//K/1f/xsM3/8rfQ//Osy//zosT/8qrK//HD1v/ysM3/8rTN//K5z//vqMX/6pe4/+Jt + nf/ibJz/5V+R/+k1cP/jSnz/1Tli/9hUfv/obaD/7H6s/+iKtP/mhq7/54ez/+R3o//lhK7/52CR/+dw + n//me6j/5m+e/+Z9qf/lgK3/4mSU/9o9bv/fbpj/4VaK/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF9Q + VwDqt84+6qnH/+qjxP/rn8H/8LTN//Gyzf/wttD/8bPO//Kwz//xs8//8bLQ//O21P/yrc3/8rDP//Ky + 0f/yq8z/8rTS//Gawf/yp8n/8Z7D//Opyf/ztdH/8q3L//O41P/zsc//87TR//KtzP/zvtf/8p/B//Ou + zf/ztM7/9cne//S20v/1yd7/9sHb//a+2P/wo8X/8KfJ/+6ewf/vn8L/8KbH//Chw//xoMP/8qbH//OV + vf/zlsD/8qDF//Gawv/xmMH/8afK//GvzP/wrMn/763L//G81v/vsc3/76/M//Cvzf/xstL/8LHP//Cp + yf/xp8f/8rjT//G51P/zwNr/873Y//Kxz//zxNz/88DY//O91v/xq8j/8bvU//G+1f/vscr/8LfQ//Gx + zP/ytND/8K7I//HB1v/xwtj/8cLY//Kqx//xqcj/8bvT//C3zv/xs87/8a/K//G60v/yudH/8qXG//G0 + zf/xu9H/8rjS//K60//yuM//8LzQ/+2nxP/kd6L/4XCf/+JyoP/nUob/50h+/+Fgjv/YYIr/3kx9/+tc + k//sdab/6oix/+Zomv/leqf/5IKu/+N5pv/mgaz/5omy/+R6pv/mcJ3/5meX/+RbkP/keaX/3WWR/91o + kv/gTH//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOquyn3rqcj/66TF/+mRuf/rqcX/8LnQ//Gr + yf/xtM7/8bDP//Kry//xtdH/8K3N//Gcw//ypsj/8rPR//Krzf/yt9X/8rTS//KjyP/yqcz/8qvK//Kv + zf/zvdb/86XG//Knxv/yqMn/87rU//CRt//zv9j/87jT//O00P/0x93/9MXc//XI3v/2yd//9sXd//Kt + zP/yuNT/8KXH//CuzP/vlLn/75u+//CnyP/yqMn/8p3C//GYwP/xn8T/8Z/F//Glyf/ymsH/8qTJ//Gl + xP/xr8z/8a/M//Gx0P/xutT/8brV//Cxz//xrs7/8bHR//CnyP/xocb/8rDO//S/2v/yttH/87DO//TK + 3//0x93/88Ta//Gsyv/ysc7/8r/W//HA1//xxdr/8bbP//GlwP/vkrj/8LnS//HB1//zt9D/87PN//Gt + yf/xutL/8rvU//HA1//xxtr/8rrS//Kwzf/xwNX/8cHV//LA1f/zttD/87XO//G0zf/vtMv/6YGn/+Vt + m//lZZb/5G2b/+dPgv/mXo//4WyZ/9VMdP/iN2v/7GSZ/+18qv/rfqv/6IGq/+aCrf/khrH/5HOh/+Zy + o//mZpj/5YOt/+R6pv/leqX/5mCR/+Nbi//db5v/3GGQ/+Fjkv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAA7LHMpOutyv/rnsL/6ZC3/+uixP/upMT/8bfP//Gsyv/xuNL/8bfS//Guzf/xutX/8rzW//K3 + 0//ys9L/8qjK//Oz0//yttP/87PQ//Kpyf/ystD/88HZ//O+1//yp8f/9MHa//K00f/yttL/877X//Sz + 0P/0qMj/9KfI//S20f/1yN7/9cPa//fP4//3yd//8rnT//Gfw//xo8T/8avL//Gmxv/vss//7pu+//CK + tP/xiLP/8Z/D//Gcw//yn8T/8aXJ//Klx//znMP/85zC//GpyP/wr8z/8bTQ//Gxzv/yttL/8q3L//Cv + zv/ys9H/8q3O//K41f/zp8r/87bT//OmyP/0r83/867L//XH3f/0x9z/87rU//Ovy//yqMf/8r/X//O9 + 1//yr8z/8KTC//LC2v/wv9b/8cLY//Kuyv/xr8v/8bLO//K50//yxNn/87jR//Oty//zvdX/8rXP//G/ + 1P/xu9H/8cPV//HE1v/xv9L/77bN/+qQtP/oc6H/6G+e/+hqmv/oZZj/52WX/+dnmf/gU4T/2laD/+E1 + a//sTYj/7nyr/+x+rP/oirL/5oSu/+aCrv/ng63/52mZ/+d3o//kha//44iw/+N+qf/jQnb/3jlo/9tf + iv/cZI7/4W6c/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADssMvA7KjH/+uav//og63/54qw/+2b + v//upsX/8bzT//K50v/xtdD/8azM//G10f/ytdL/8rTR//Orzf/zsM//87LR//O72P/zqcz/85nB//XD + 2//0ttL/9LjT//Oew//ztdL/863N//K61P/yuNP/8qLE//S/2P/zosX/863N//S81v/0sM7/9bzV//XG + 3P/xttD/8bHN//Ggw//xt9L/8KHE//Ckxf/wnb//8rPR//Cix//wocb/8JW9//Gcwv/ypsn/8qPH//Kg + xf/zlb3/8qHF//Gtyv/wp8j/8KbI//Gy0P/xss//8Za+//K10//yu9X/87HQ//OrzP/zrM3/9LzX//Oq + yf/znMH/9Mfd//PA1//zyd7/8r/X//K91f/yvtf/8qvJ//Osy//ywdj/88je//LA1//xwtj/8cHW//LB + 1//yt9D/877V//O10P/zjbn/86DE//Oyzv/zvNP/87jQ//LB1v/ywtX/8sDU//G80P/ujrP/63Wl/+t0 + pf/rbJ7/6nSl/+p0pv/rap3/6GSX/+FXhv/dZJH/4TRq/+tGhP/uhbH/7Xyq/+iRtv/mfqr/53Oh/+d6 + p//oeqj/53Ke/+V6pv/ihK3/44Ot/+J+p//ea5T/2WKH/99znf/keKb/AAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAOyxy9HtqMf/7KDD/+d7qP/njrP/64Ww/+2Xvf/unMD/8rbP//K0z//xudP/8rLP//O5 + 1f/zt9P/87fU//Smyf/0qcr/867P//Oqzf/0qcr/9KXH//W81v/0p8j/9LTR//O+2P/yncL/86zM//O4 + 0//yttL/8r7X//Gryv/yt9P/8rHP//Oz0P/yr83/8rTQ//CdwP/wq8n/8a7M//Czz//xqcn/8bHN//Gk + xf/yqcr/8arL//Gcwf/vncL/8ZK9//KVvv/ynMT/86XL//Kkx//znML/85fA/++kxf/wocT/8KLE//Gp + yf/xrMz/8rDO//K41f/xp8r/86jK//Kjx//yu9b/87DP//S81v/1yN7/9cTa//S/2P/0w9r/87/Y//O3 + 0v/yvtb/8sDY//LC2f/zvdX/87LP//O+1v/yvNT/87vU//Gty//ywNb/87LP//Oxz//ztND/87zT//K1 + z//zuND/87nP//LF1v/xuc//8I22/+6Otv/shrH/7Hyq/+1wo//uZZn/7WKY/+xJhv/oUon/4E18/91i + jf/fQHD/6kJ//+5onf/ub6H/6Iy0/+iUuv/ogqv/532q/+d5pf/mi7P/5G2d/+N3o//heqT/3GmU/9hZ + hP/bcZn/44ew/+Rqnv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7LPM1O2qyP/sk7z/6I63/+aQ + tv/rpsX/65u//+2cwP/tnb//8bHM//K50v/yutT/87XS//O41P/zsdD/86/R//OozP/ztdL/87jU//Su + zf/1xdv/9b3X//Sxz//0psj/9LzX//Onyv/0o8b/8p7C//O41P/yt9P/8rfT//K30//zrMz/87PR//Kn + yv/xss//8KXG//GuzP/xocT/8bXQ//CvzP/xt9L/8rXQ//O30//xr83/8bTR//Cewv/wo8b/8Y24//Gd + w//xm8L/8p/F//Kcw//zkbz/8pS+//Ctyv/wqMn/8LHO//CvzP/xqcr/8a7N//GrzP/ypsj/8qzM//K4 + 0//yrs3/86zM//Snyf/1vNb/9cTa//S61P/0yt//9KrK//O+1//ywtn/88jd//LA1//zwtj/88LZ//PC + 2P/zwtn/87zU//O71P/zss7/8sXZ//Szz//zudH/9LjQ//O+0//yvdL/87HN//Kew//wmL3/74y2/+6D + sP/uap3/7mie/+5roP/uXJf/7VWR/+pglv/jOmv/1zpi/9grVP/kLWb/7EqJ/+uCrf/ni7L/6IKs/+iB + rP/pdKL/6W+d/+V2ov/ic57/4nmk/91jkP/bbJn/1Ex1/9lUgf/kd6b/5lWK/wAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAADttM7Q7ajI/+2Vvf/oi7b/5oyz/+eVuv/qocL/7Jq9/+2cwf/ukrv/76HC//K0 + z//yu9T/8rfS//O30//zsM7/87fU//O41f/0stH/9LHO//a71v/1stD/9bjU//Sixv/zttL/87LQ//Oy + z//zutX/873X//K30//yutX/8qfJ//Opy//zrMz/8qrK//K00f/yrc7/86nL//K41P/xrcz/8bHP//C4 + 0v/xoML/8qXF//Kuzf/yxtz/8rzW//Gy0P/xoMP/8rfU//Cawf/wnsT/8azN//Kjyf/ynsX/8qDH//Kq + yv/xrsv/8avL//Gpyf/wss7/8KvM//Gqyv/xrMv/8anK//Kszf/zrs7/9LDO//Sz0f/1udX/9cTb//W8 + 1f/1uNT/88DZ//PF3P/0xdv/9L7X//PC2P/0wNf/873W//PE2v/zvNT/87/X//O40v/zxNn/9LjR//PA + 1f/zvtP/873U//Sqy//0oMT/86HF//Kfwv/wkrr/73Ok/+9zpf/vbKH/72Kb/+9dl//uXZf/7FaR/+U7 + cv/cP2z/1Ddc/90/bP/oRHz/6ZS3/+eDrP/odaL/52yf/+dOg//nX5D/4mmY/+Ftm//fX4//2U+B/9tm + l//aYY//3lqM/+Rgkv/mXZL/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO20zbvuqsj/7p7C/+qM + t//leaX/4Xij/+eUuP/rkbT/7Yax/+6Otv/tjLP/7Ju//+6lxf/ysMz/87HO//Kxz//yqsz/86zM//Ot + zf/0qMv/9K7O//Wdxv/1udT/9L7Y//S81f/zwNn/873X//O30v/zvdf/8rvV//O40//ywdn/87fR//O+ + 1//0vtf/87/X//Suz//0psr/9LjU//Opy//ytdL/8bnT//Gxzf/ys8//8bfR//PG3P/zxdr/8bzV//K6 + 1P/ypsf/8rLP//O51f/xo8f/8aHI//GdxP/yncT/8p/F//Gbwf/xq8r/8bLO//Cyzv/wsM3/8K3M//Gr + yv/xrcv/8bbS//Kxzv/zqsv/87LQ//Oxzv/1vdb/9cfd//TH3f/0x9z/9cjd//TB2P/0xtv/9MTb//W9 + 1//0vNX/88PZ//TD2f/0wNf/9MTZ//TD2P/1wNf/9bPN//Soyf/0qsr/9KjJ//Sdxf/zpcf/85/E//KP + uv/xgK//8HSm//Bwo//waJ//8FiW/+9Skf/uS4r/6kmF/+I0aP/dVoL/10Rr/+R4oP/mZJL/5maV/+ZI + fP/kdqT/5HCf/+M1bP/haJn/3mqe/9tWjP/YTIL/21GI/91XiP/kW5L/5VaQ/+dAff8AAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA7bTNle2kxf/uocT/7J3B/+eArP/ljLX/4n+q/+aGrf/pd6T/7Iuy/+qP + tP/ogKr/5Ymu/+J7oP/spcP/8rDO//Kvzf/zrc3/863N//Onyv/zq8z/9K7N//S51f/1wtr/9bPR//TE + 2v/zxtz/8sHY//LF2//zwtr/8sXb//TH3P/1v9f/9cPa//W61f/0sdD/9KbJ//Soy//0qsz/9K3O//O8 + 1//ztdH/8qrK//CqyP/xrMn/88fd//TG2//zudP/9c3h//PC2P/ztdH/87jT//S81f/zsM3/8qXJ//Gj + yP/wpMn/8KjL//KZwv/xosf/8rrU//K91f/wt9H/8b3W//G30f/xuNL/8bXR//Oryv/0qsv/87jS//S0 + 0P/1wtn/9cLa//XN4P/1zuD/9cbb//TO4P/1yN3/9cTa//XF2v/1wNf/9cXa//XC2P/0vNX/9LvU//Oo + x//0pMX/867L//Gcvv/ys8//8qXG//Gtyv/xo8T/8Jm9//GKtf/yf63/8Xmo//Fnn//wX5r/8FWU/+9R + kf/tVJD/6VWL/+Rik//ZWIL/22WO/9k9Z//eV4X/31iK/91EeP/fZ5n/3EV6/9lRhv/WQ3b/0jpp/9dE + dv/eU4b/4T53/+ZXj//mWZL/5lqO/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADtuM9l767K/+6n + xv/toMP/6pK5/+iPuP/jdKL/4nOd/99bi//eWob/4W+Y/+SLsv/jgqz/4X2o/99nlP/pjLT/75y///Gs + yf/ytdD/867O//Oqy//0rMz/9KzM//Sy0P/1s9D/9rvV//a91//2xdv/9s3f//fJ3v/3zN//98fd//e+ + 1//1uNT/9LDP//OtzP/0osf/9KnL//SkyP/0psn/9LHQ//Sy0P/0uNT/8rjT//LH3P/0zeH/87rT//S/ + 1//1xNv/9LzW//TJ3v/0yN3/9Mbb//Oxzf/zsc7/86vM//Goy//zuNT/9LDQ//Ohxf/zr83/9crf//S9 + 1f/0xdr/88DX//LA1v/yutP/87jS//Syzv/1ttD/9bvU//bH3P/20eH/9tXl//bR4v/11OT/9dXk//TO + 3//1zN7/9cXa//S81f/0ttL/86vK//O60//zutL/8pS7//Omxv/xocH/8LHN/++Zvf/wpMX/8LHN/++n + xv/uoML/7pu+//KMtf/yd6n/8XGl//Fsov/wXZn/712a/+9Zlf/tW5X/6G6g/+Flkf/bV4T/2kh7/9My + ZP/XRXv/10h9/9dCe//WQXn/2EuD/9tNhP/ZP3P/4FeN/+NOiP/mWY7/50V+/+Zqnf/laZ3/AAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAO2xyiburcn+7qnI/+6jxf/sncD/7Ju//+d1o//mf6j/5o20/99n + k//kfaf/5YSt/+eLs//niLH/6Y61/+uLtf/tkLn/73qq//CEsP/xe6n/8pS6//OgxP/zrs3/9LDN//Sr + y//1rs3/9qrL//asy//0tM//9K3L//Sexf/1lsP/9ZPB//WrzP/zuNP/87TR//Okxv/0qcn/9LDO//Sx + z//0rMz/87HP//O10f/xsc//76nI//K/1//zw9j/9Mjc//O40f/0utT/9Mjd//TF2//0yN3/9Mfb//XO + 4f/0yt7/9Mbb//S+1f/0u9T/9bfU//S40//1xNr/9LnT//Svzf/0ttH/8pi8//TE2v/yscz/9Mba//XO + 4P/0wtf/9cfb//TK3f/1yt7/9Mjc//TF2f/0xNr/9L/X//TC2v/0wdj/87LO//OvzP/znMD/8pe9//Kk + xP/ynsL/8aDE//Ckxf/vq8r/8KPF//Gwzf/ym8L/8a7M//Kjxf/xnMH/8Ze9//J6rP/yd6n/8XCk//Fm + n//waKD/8Gig/+91qf/sY5n/6GGT/+Rck//bOXP/3EaC/9xRi//TKl//0CVV/9c7cf/dWY//30+H/94n + Yf/mTo3/5zZ0/+dnmf/nXJL/5UuD/+h6pf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA88HSAe+0 + ztPupMX/757C/+6ewv/ulLz/7Yq4/+uJsv/qjbX/6Ymx/+mIsP/pf6n/7Ji9/+yKtf/ui7f/7X6u/++C + sP/wear/8Ia0//CJuP/zcqn/832y//SEtf/0jLn/9JrE//WUwf/1jrz/9pTC//alyf/0rMv/8qTH//Oe + xf/1psn/9aHI//WgyP/zr87/86zK//Glx//yqcr/8abH//Gwzf/ylbz/8Z3A/++Yvv/xttH/9MLZ//TG + 2//zw9n/9Mve//TH3P/1zeD/9c3g//XM3v/1yt//9Mve//S+1v/0wdj/9MLZ//XL4P/0wNj/86XG//XJ + 3v/0xdv/9MLZ//S71P/0xdr/9MXb//O+1//zy97/88fc//PF2//0xNv/8p7A//Oty//zwdn/8rHN//O+ + 1v/zrsz/9LLQ//OuzP/0w9r/8pzB//Oewf/zrc7/8q7N//Kryf/xn8P/8a3M//Kxz//yqsv/86TI//KZ + wP/zq8r/86bH//Ouy//zn8P/8n2w//J/rv/ydaf/8W2j//FooP/xc6n/8Im1/+1onf/rZZv/52KY/+M1 + cv/gQ3z/4EmE/946cP/gUIb/4VaO/+A3cv/kTIj/5jd3/+g4ef/oPXz/52md/+d6qP/ndKP/6X2p/wAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7rXNe++uy//wnMD/76TG//Cgxf/wkLv/74q1/+2F + sf/tp8f/7Iy1/+6WvP/ujLf/7oay/++Otf/umr7/8XGk//CFs//ylr7/8pjB//N+sf/0frP/9H2y//SL + uv/1jbz/9ZbC//aiyP/3qcv/963O//evzv/2ss748a3K4/Kixv/0qsv/9avM//Sexv/zosX/8rjR//K2 + 0f/ys9D/8Z3C//KTvP/zoMT/8rPQ//PA1//0xdr/9MTa//TF2//0z+H/9dDj//TJ3v/0wNf/9czf//XP + 4v/1y9//9cXb//bR4//1xNv/9c/h//XN4P/1xNr/9c3h//XI3P/0vtb/9L/X//XI3v/0rcz/9MDY//TD + 2//ytc//8rPO//S71v/0sM3/87rT//Kvy//yxdr/9MLa//S81v/zosX/87DO//Ggw//yrMz/86zM//Kc + wf/xqMn/8anI//Gtzf/ypsj/8qPG//Ory//yqMn/87TR//Opyv/0rcz/9KjK//Swzf/yoMP/8oCv//J6 + rP/xd6j/8Xmq//F/rv/umb//63yp/+tkmv/qWJH/6F6V/+Vblf/lUIr/5jdy/+Zkm//ma6L/5VGK/+Zu + of/nVo3/6F6T/+lyov/nZ5n/6FKJ/+mGrf/pbZz/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADtw9Ua7rPM9fClxf/wocP/8Jm///Cdwv/vk7z/75zA/+6mxv/unsL/75G5/++awP/vlbr/75m9/++S + uv/xlLv/8Z7D//KqzP/0kLv/9JTC//WDtv/1grb/9ZC///WPvv/2nsX/96TI//eszP/3rc3/967M/vay + z2vww9UN8bPOfvKuzfP0qcv/9avM//Sfxv/zuNL/877W//O40//yvNX/8rHO//O20f/zwtn/88PZ//S8 + 1f/0wtf/9cvf//TD2f/1z+H/9MTa//S30f/1xNv/9cve//XM4P/2z+L/9cXb//XD2f/1xNr/9s7h//XG + 3P/1yd7/87PP//O50//0rsz/9LvV//Okxv/zqcn/87TQ//O50//zutX/87bS//Oewv/ysM3/8bDN//Gu + zf/xqsn/87HQ//Oawf/yr87/8qPG//Kgxf/ylL3/8abI//Gz0P/xt9P/8bTQ//Gsyv/yss//8rLP//Ou + zf/zsc7/9KrK//Ozzv/zs8//867N//Oxzv/ylLv/8oiz//KCr//xhLL/8Za9/+yQt//oeqf/6VSL/+pj + l//naJ3/5Wug/+dXkP/oTIn/5mWZ/+ZWjv/nTYb/6IKw/+dwoP/nXJD/6Gmb/+hsm//peKb/52WV/+mE + rP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADtvNGT7rbP/++ox//wn8L/8J3B//Gf + wv/woMT/76DD/++nx//vmr//76LD/++avv/wmsD/8anJ//KLtf/ypMn/9KvO//Wiyf/1jLv/9Yu7//WI + u//1jL//9pTA//aiyP/3qcv/963N//eszf/3utKe7NnNAAAAAAAAAAAA8b/UG/K20Jjzp8n19KnL//Sj + yP/zvNT/87vU//O91v/zuNP/87nS//O91f/zvtb/87rU//O50v/0xtr/9dDi//XP4f/0udP/9c/h//XC + 2f/0vtX/9tXl//XK3v/2zuH/9szf//bL3//2zuD/9cre//XI3f/zvdX/9MHZ//O20//zrs3/8qLF//Kj + xf/ypcf/8qTG//Knx//yo8b/8abH//CUuv/wn8P/8bXT//Gpy//yqMn/8GGZ//GNuf/xoMT/8ZnA//KW + vv/zpMj/8a7N//Kry//zrs3/9ZnD//SqzP/zs9D/9KbI//Wfx//0q8z/86/M//O30f/0rcz/87DN//On + x//yjbf/8oy2//KOuP/wlrz/6o+3/+iFr//pcJ//6W6f/+lsnv/ncaP/50eC/+l5qf/neqr/50+F/+hT + if/pbqD/6WWX/+h+q//odqP/65e8/+qKr//tp8b/65G1/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAoIWQAO7E1Rntuc/r76/L/++wzP/woML/8Z/C//Cdwf/xnMH/8KfH//Ccv//ypMb/8KfJ//Gm + yP/zosf/86DF//Ov0P/0rdD/9bLT//Wky//2j7//9Ym7//aTwf/2msT/96jK//etzf/3rs7/97fRwfe0 + 0Ql9aXEAAAAAAAAAAACOe4MAAAAAAPG60iDzss6O86bI8fSqzP/0xNr/9MDX//S91f/zuNH/88bb//PD + 2f/zutP/9MXa//XK3v/1yd3/9cnd//XP4P/1zd//9dLi//XL3f/1z+D/9dDh//XO4f/2z+L/9cLZ//bV + 5f/21eX/9MLY//KwzP/zutX/8Zu///KszP/wiLb/8aLG//Guzf/wiLX/8ZC7//GLuf/xmcH/8rDP//Kf + wv/yr8//8qTH//GQu//xqsv/8aHH//GfxP/xrcz/8qDE//KuzP/xss//8bTP//Osy//zqsv/86fI//Oq + yf/zss7/863N//Oty//ztdD/87LO//Owzf/zss//8rLP//Kjw//ylLv/8Za///CNtP/qjLP/6YGt/+p/ + rP/paJv/6VyT/+mGsv/pgK3/6G+i/+hZj//pgq7/53un/+yYvf/qbJr/6X+r/+ykxP/qhK3/7Ja3/+2l + w//tob//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO++0l/wr8v+77LN//Ct + yv/xp8n/8K3N//Ggwv/xsM7/86DF//OZwf/yr9D/87DR//Wfxf/0qMr/9a/R//Wx0v/2sNL/9qbN//WV + wv/2lsP/9pjD//ekyf/3qMv/96vN//exz8z2uNEUrIuVAAAAAAAAAAAAAAAAAAAAAAAAAAAAqpCZAAAA + AADxuc8b8rDLg/Kwy+3zw9j/9MTZ//TC2P/0xdv/88fb//PD2v/0xNr/9cre//XG2v/1ydz/9tXl//bP + 4P/21+b/9tXl//XM3//2z+L/9tLi//bY5//20+P/9dDi//S51P/zpcj/87PR//KexP/xmcH/8ZrB//Gc + wv/xoMT/75O6/++ewv/wpMf/75G6/+6av//vfq7/8JK8//CBsv/wiLT/8Z/E//CUvP/wncL/8ajI//Cq + yf/xn8P/8azK//Gzzv/xudP/8rvU//Kyzf/zvNT/8rHN//O20P/zttD/87HP//Szz//zsc7/9K3N//Wr + zP/0t9H/9LjQ//OcwP/ymcD/75/B/+yZvf/rirP/6n6r/+mMtf/pfqr/64+4/+pglf/rgq3/6m+f/+uK + s//pjrb/7Zu+/+tjlP/tn8H/7Ju8/+yMsv/wt9H/75q8//CvzP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAArIiYA7qu3AfG60Y7xt9D/8LnT//Koyv/yrc3/8rDP//Oszf/0msL/9afJ//Wy + 0f/0ttX/9bLS//Wx0v/2u9f/9rPS//a01P/2pMv/9pjE//aex//3osj/96XK//epy//3ttHL9r3VFgAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8bXNHvC1zajyudL988TZ//TG + 2v/0xdn/9MXa//TH2//0yNv/9MXZ//XI3P/20OH/9tbm//bU4//21+b/9tXk//bR4v/21uX/9tPj//bV + 5f/1wdj/9MDZ//KWvf/xnML/8JS9//GPvP/wdKn/8KXI/++Uvf/wqcr/8LTR/++kx//wsM//8LDO//Gm + x//ym77/8ZzC//Gz0P/wqsr/8KzL//Gxzv/xpMb/8LXQ//G50v/0psn/9K/O//K+1v/zudL/87rT//O2 + 0f/yutL/87bQ//Oxzv/zs87/87PP//O40f/0uNL/9LXQ//O00P/0r87/867N//Khxf/wrMr/7aLC/+6X + u//tnL//65zA/+yZvf/tocT/7G6d/+2Gs//tmr7/7JC3/++nyP/vqcb/7pu8/+2hwf/uq8j/8bHO//Gt + yP/yt9D/877U/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA88fWA/K6 + 0pnzutT/87jU//Sszf/0tNL/9bHR//Wny//1stL/9a/Q//W21f/2u9j/9q/R//a10v/2s9P/9q7Q//am + y//2nMb/96LK//eky//3qMz997LQnvfJ2g28macAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABKJjgAAAAAAPC1zzHwt9Cm8bXQ9PG50v/yuNH/9MXa//TI2//0yt7/9Mjb//TG + 2v/1zd//9c/h//bV5P/21OT/9tLi//bX5f/20+P/9s/h//TH3P/zvtf/8rfT//K31P/xqcr/8KnM//Ck + x//wmsD/76LH/++pyv/vm7//8LTR//Cwzf/wqsn/8K/N//GQuv/xu9T/8a3M//Kryv/yqsr/8rTQ//Og + xf/zn8X/85zE//OuzP/zs9D/9LfS//Suzv/0ss//87bQ//O00P/zrsz/87nS//O+1f/0vtb/9KbJ//Sh + x//0rM3/9JzF//OWwP/zpsr/86HF//Gxzf/wttD/7qDB/++qyf/vrMr/7aDC/+2LtP/ue6b/8KXH/++j + xP/wpcX/8bbR/++LsP/wjbX/8KDC//O/2f/zwtj/873V//S91f/ztM//AAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9crZAvS60370ttH59bLQ//W41P/1stH/9rLS//as + zP/1qcz/9rTT//a61//2uNX/97TS//e21P/3rc7/96rN//eoy//3qMz/96jM4Pez0FXyw8EBw5yrAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE049AAAA + AADwuM8a8LnRbfG10MXxttD38rfS//K20v/zsM//9LvU//S/1f/0w9j/9cvd//XL3v/2z+D/9c3f//bU + 5f/1zeD/9MTa//Soy//ystD/8LDO//CmyP/wnML/8ajJ//Cnyv/vqcr/8LbS/++pyv/umb3/8LrU//C1 + z//xrsv/8LLO//Gxzv/xqcj/8bDN//KoyP/xpcf/8pK+//Sfxv/0n8f/9KnL//OlyP/zr83/863N//O3 + 0f/zttD/9L/V//TJ3f/1tdL/9cPb//Sszf/0stH/9IK1//OPvf/zibj/8oWz//Kpy//zmsP/863M//HA + 1v/yutT/8bzU/++fwf/vqsn/8K7N//Gxzf/xr83/8rnU//Kxzv/ysc//8aDB//XF3f/0yN3/9Mje//S9 + 1f/1y9//9cfc//XH3P8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAB6Zm8AAAAAAPS2zz30vdTO9bjT//a10v/2udX/9rDP//a41f/3vtn/97HR//e+2f/3vNf/97nV//e0 + 0//3s9L/97HP5ve00Hr2s8wOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFZHSwAAAAAAAAAAAPG40B3yutJh8bnRqfG6 + 0uXyt9H/87fR//O40v/0t9H/9LjS//S50v/0vtX/9b/X//TA2P/zrM7/85zF//Kgxv/xr83/76XG//Ce + xP/ylsD/8JG8//CexP/vpsj/8LLP//CnyP/vqMr/8KrK//GdxP/wrMv/8aXH//Gfw//woMT/8JS///OT + wP/zncT/85nC//Kkx//zqMn/86zL//Ozz//zudP/9MXa//XN4P/0xNv/9c3i//Omyf/0p8r/9LvX//Sx + 0f/0rc3/8p/F//S61v/zoMX/87bT//Ogxv/zrsz/87bR//TG2v/0xNn/9MXa//O/1//0y9//8rPQ//TE + 2//0x93/9Mfc//O/1v/1y+D/9b3X//XF2v/20OL/9c7h//bK3f/1wNb/9tXl/wAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPS90gb1yNtQ9cLYrva/ + 1/T2vdb/9sDZ//e61f/3rs//97vW//fC2v/3wNj298Taufa/1mT1wNYPAAAAAFkAIgAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAASDtBAAAAAAAAAAAA8cTXCPHB1ibyvdNd8rrTkPK807/zvNPn8rfR/PO9 + 1P/zv9X/9LzV//S91//0w9r/8qXJ//Gyz//wrsv/77HN/++dwP/xqMn/8a/M//Cryf/wq8r/8afI//Cp + yf/xqMj/8pO+//Ghxv/wnsT/8J3E//Ghxf/yosX/86HG//Okx//0qcr/9bfT//Wy0P/1xNv/9cDZ//XF + 3P/0v9j/87jU//TI3v/0wtv/9L7Y//S81//0psn/9JvE//Sfxf/0uNX/9LbU//SmyP/0wNn/8rnT//PC + 2v/0uNT/9LnU//TD2v/1y93/9Mre//bO4P/1zuH/9tDi//TL3//1y9//9cne//bN4P/1xNv/99fn//bM + 4P/32uj/9s3f//fU5P/32Ob///4AAH/AAAA/////////+P/+AAAeAAAAB/////////D//AAAAAAAAAD/ + ///////g//4AAAAAAAAAP///////wP/+AAAAAAAAAA///////4D//gAAAAAAAAAD//////+A//8AAAAA + AAAAAP//////AP//AAAAAAAAAAB//////gD//wAAAAAAAAAAH/////wA//+AAAAAAAAAAA/////4AP// + gAAAAAAAAAAD////8AD//4AAAAAAAAAAAf///+AA//+AAAAAAAAAAAAAAAAAAP//gAAAAAAAAAAAAAAA + AAD//4AAAAAAAAAAAAAAAAAA//+AAAAAAAAAAAAAAAAAAP//gAAAAAAAAAAAAAAAAAD//4AAAAAAAAAA + AAAAAAAA//+AAAAAAAAAAAAAAAAAAP//gAAAAAAAAAAAAAAAAAD//4AAAAAAAAAAAAAAAAAA///AAAAA + AAAAAAAAAAAAAP//wAAAAAAAAAAAAAAAAAD//8AAAAAAAAAAAAAAAAAA//+AAAAAAAAAAAAAAAAAAP// + gAAAAAAAAAAAAAAAAAD//4AAAAAAAAAAAAAAAAAA//8AAAAAAAAAAAAAAAAAAP//AAAAAAAAAAAAAAAA + AAD//wAAAAAAAAAAAAAAAAAA//8AAAAAAAAAAAAAAAAAAP//AAAAAAAAAAAAAAAAAAD//gAAAAAAAAAA + AAAAAAAA//4AAAAAAAAAAAAAAAAAAP/+AAAAAAAAAAAAAAAAAAD//gAAAAAAAAAAAAAAAAAA//wAAAAA + AAAAAAAAAAAAAP/8AAAAAAAAAAAAAAAAAAD//AAAAAAAAAAAAAAAAAAA//wAAAAAAAAAAAAAAAAAAP/8 + AAAAAAAAAAAAAAAAAAD8eAAAAAAAAAAAAAAAAAAA/HgAAAAAAAAAAAAAAAAAAPgAAAAAAAAAAAAAAAAA + AAD4AAAAAAAAAAAAAAAAAAAA8AAAAAAAAAAAAAAAAAAAAOAAAAAAAAAAAAAAAAAAAADgAAAAAAAAAAAA + AAAAAAAAwAAAAAAAAAAAAAAAAAAAAMAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAA + AAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAA + AAAAAAAAAAAAAMAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAA4AAAAAAAAAAAAAAAAAAAAOAA + AAAAAAAAAAAAAAAAAADwAAAAAAAAAAAAAAAAAAAA8AAAAAAAAAAAAAAAAAAAAPgAAAAAAAAAAAAAAAAA + AAD8AAAAAAAAAAAAAAAAAAAA+AAAAAAAAAAAAAAAAAAAAPgAAAAAAAAAAAAAAAAAAAD4AAAAAAAAAAAA + AAAAAAAA8AAAAAAAAAAAAAAAAAAAAPAAAAAAAAAAAAAAAAAAAADwAAAAAAAAAAAAAAAAAAAA8AAAAAAA + AAAAAAAAAAAAAPAAAAAAAAAAAAAAAAAAAADwAAAAAAAAAAAAAAAAAAAA/AAAAAAAAAAAAAAAAAAAAPwA + AAAAAAAAAAAAAAAAAAD8AAAAAAAAAAAAAAAAAAAA/AAAAAAAAAAAAAAAAAAAAPwAAAAAAAAAAAAAAAAA + AAD4AAAAAAAAAAAAAAAAAAAA+AAAAAAAAAAAAAAAAAAAAPAAAAAAAAAAAAAAAAAAAADwAAAAAAAAAAAA + AAAAAAAA8AAAAAAAAAAAAAAAAAAAAPAAAAAAAAAAAAAAAAAAAADwAAAAAAAAAAAAAAAAAAAA8AAAAAAA + AAAAAAAAAAAAAPgAAAAAAAAAAAAAAAAAAAD4AAAAAAAAAAAAAAAAAAAA+AAAAAAAAAAAAAAAAAAAAPwA + AAAAAAAAAAAAAAAAAAD8AAAAAAAAAAAAAAAAAAAA/gAAAAAAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAA + AAD/AAAAAAAAAAAAAAAAAAAA/gAAAAAAAAAAAAAAAAAAAP4AAAAAAAAAAAAAAAAAAAD+AAAAAAAAAAAA + AAAAAAAA/gAAAAAAAAAAAAAAAAAAAP4AAAAAAAAAAAAAAAAAAAD+AAAAAAAAAAAAAAAAAAAA/gAAAAAA + AAAAAAAAAAAAAP4AAAAAAAAAAAAAAAAAAAD+AAAAAAAAAAAAAAAAAAAA/gAAAAAAAAAAAAAAAAAAAP4A + AAAAAAAAAAAAAAAAAAD+AAAAAAAAAAAAAAAAAAAA/gAAAAAAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAA + AAD/AAAAAAAAAAAAAAAAAAAA/4AAAAcAAAAAAAAAAAAAAP+AAAAHwAAAAAAAAAAAAAD/wAAAD/AAAAAA + AAAAAAAA/8AAAB/8AAAAAAAAAAAAAP/gAAA//wAAAAAAAAAAAAD/8AAAf//AAAAAAAAAAAAA//wAAf// + +AAAAAAAAAAAAP/+AAf///8AAAAAAAAAAAA= + + \ No newline at end of file diff --git a/source-code/source/plugins/Patches/PatchApplier710.h b/source-code/source/plugins/Patches/PatchApplier710.h index 11a0d51..969ee8a 100644 --- a/source-code/source/plugins/Patches/PatchApplier710.h +++ b/source-code/source/plugins/Patches/PatchApplier710.h @@ -1,703 +1,703 @@ -#pragma once - -#pragma once -#include -#include "PatchApplier.h" -#include "framework.h" - -class PatchApplier710 : public PatchApplier { - virtual void ApplyPatches() { - const struct { void* Address; std::vector Data; } patches_710[] = - { - // Just completely ignore all SYSTEM_STARTUP errors - { (void*)0x00000001403F5080, { 0xC3 } }, - // Always exit TASK_MODE_APP_ERROR on the first frame - { (void*)0x00000001403F73A7, { 0x90, 0x90 } }, - { (void*)0x00000001403F73C3, { 0x89, 0xD1, 0x90 } }, - // Ignore the EngineClear variable to clear the framebuffer at all resolutions - { (void*)0x0000000140501480, { 0x90, 0x90 } }, - { (void*)0x0000000140501515, { 0x90, 0x90 } }, - // Write ram files to the current directory instead of Y : / SBZV / ram - { (void*)0x000000014066CF09, { 0xE9, 0xD8, 0x00 } }, - // Change mdata path from "C:/Mount/Option" to "mdata/" - { (void*)0x0000000140A8CA18, { 0x6D, 0x64, 0x61, 0x74, 0x61, 0x2F, 0x00 } }, - { (void*)0x000000014066CEAE, { 0x06 } }, - // Skip parts of the network check state - { (void*)0x00000001406717B1, { 0xE9, 0x22, 0x03, 0x00 } }, - // Set the initial DHCP WAIT timer value to 0 - { (void*)0x00000001406724E7, { 0x00, 0x00 } }, - // Ignore SYSTEM_STARTUP Location Server checks - { (void*)0x00000001406732A2, { 0x90, 0x90 } }, - // Toon Shader Fix by lybxlpsv - { (void*)0x000000014050214F, { 0x90 } }, - { (void*)0x0000000140502150, { 0x90 } }, - // Toon Shader Outline Fix by lybxlpsv - { (void*)0x0000000140641102, { 0x01 } }, - // Skip unnecessary checks - { (void*)0x0000000140210820, { 0xB8, 0x00, 0x00, 0x00, 0x00, 0xC3 } }, - { (void*)0x000000014066E820, { 0xB8, 0x01, 0x00, 0x00, 0x00, 0xC3 } }, - // Disables call to glutFitWindowSizeToDesktop, prevents window automatic resize - { (void*)0x0000000140194E06, { 0x90, 0x90, 0x90, 0x90, 0x90 } }, - // Allow modifier mode selection (by Team Shimapan) - { (void*)0x00000001405CB1B3, { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 } }, - { (void*)0x00000001405CA0F5, { 0x90, 0x90 } }, - // allow modifier modes to work without use_card - { (void*)0x00000001405CB14A,{ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 } }, - { (void*)0x0000000140136CFA,{ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 } }, - // enable module selector without use_card - { (void*)0x00000001405C513B,{ 0x01 } }, - // fix back button - { (void*)0x0000000140578FB8, { 0xE9, 0x73, 0xFF, 0xFF, 0xFF } }, - // Force Hide IDs - { (void*)0x00000001409A5918, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, - { (void*)0x00000001409A5928, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, - // fix TouchReaction - // get some more space by optimizing this code for size - { (void*)0x00000001406A1FE2,{ 0x7E } }, // MOVQ XMM0,qword ptr [0x168 + RSP] (change to MOVQ) - { (void*)0x00000001406A1FE9,{ 0x66, 0x0F, 0xD6, 0x44, 0x24, 0x6C } }, // MOVQ qword ptr [RSP + 0x6c],XMM0 - { (void*)0x00000001406A1FEF,{ 0xC7, 0x44, 0x24, 0x74, 0x00, 0x00, 0x00, 0x00 } }, // MOV dword ptr [RSP + 0x74],0x0 - { (void*)0x00000001406A1FF7,{ 0xEB, 0x0E } }, // JMP 0x1406a2007 (to rest of function as usual) - // add new code - { (void*)0x00000001406A1FF9,{ 0x66, 0x48, 0x0F, 0x6E, 0xC2 } }, // MOVQ XMM0,RDX (load touch pos) - { (void*)0x00000001406A1FFE,{ 0xEB, 0x5D } }, // JMP 0x1406a205d - { (void*)0x00000001406A205D,{ 0x0F, 0x2A, 0x0D, 0xB8, 0x6A, 0x31, 0x00 } }, // CVTPI2PS XMM1,qword ptr [0x1409b8b1c] (load 1280x720) - { (void*)0x00000001406A2064,{ 0x0F, 0x12, 0x51, 0x1C } }, // MOVLPS XMM2,qword ptr [RCX + 0x1c] (load actual res) - { (void*)0x00000001406A2068,{ 0xE9, 0x14, 0xFF, 0xFF, 0xFF } }, // JMP 0x1406a1f81 - { (void*)0x00000001406A1F81,{ 0x0F, 0x59, 0xC1 } }, // MULPS XMM0,XMM1 - { (void*)0x00000001406A1F84,{ 0x0F, 0x5E, 0xC2 } }, // DIVPS XMM0,XMM2 - { (void*)0x00000001406A1F87,{ 0x66, 0x0F, 0xD6, 0x44, 0x24, 0x10 } }, // MOVQ qword ptr [RSP+0x10],XMM0 - { (void*)0x00000001406A1F8D,{ 0xEB, 0x06 } }, // JMP 0x1406a1f95 (back to original function) - // jmp to new code - { (void*)0x00000001406A1F90,{ 0xEB, 0x67 } }, // JMP 0x1406a1ff9 - }; - - for (size_t i = 0; i < _countof(patches_710); i++) - InjectCode(patches_710[i].Address, patches_710[i].Data); - - - - // The old stereo patch... - // Use 2 channels instead of 4 - if (nStereo) - { - InjectCode((void*)0x0000000140A860C0, { 0x02 }); - printf("[Patches] Stereo patch enabled\n"); - } - - // Disable AA - if (!nTAA) - { - // set TAA var (shouldn't be needed but whatever) - *(byte*)0x00000001411AB67C = 0; - - // make constructor/init not set TAA - {DWORD oldProtect, bck; - VirtualProtect((BYTE*)0x00000001404AB11D, 3, PAGE_EXECUTE_READWRITE, &oldProtect); - *((byte*)0x00000001404AB11D + 0) = 0x90; - *((byte*)0x00000001404AB11D + 1) = 0x90; - *((byte*)0x00000001404AB11D + 2) = 0x90; - VirtualProtect((BYTE*)0x00000001404AB11D, 3, oldProtect, &bck); } - - // not sure, but it's somewhere in TaskPvGame init - // just make it set TAA to 0 instead of 1 to avoid possible issues - {DWORD oldProtect, bck; - VirtualProtect((BYTE*)0x00000001401063CE, 1, PAGE_EXECUTE_READWRITE, &oldProtect); - *((byte*)0x00000001401063CE + 0) = 0x00; - VirtualProtect((BYTE*)0x00000001401063CE, 1, oldProtect, &bck); } - - // prevent re-enabling after taking photos - {DWORD oldProtect, bck; - VirtualProtect((BYTE*)0x000000014048FBA9, 1, PAGE_EXECUTE_READWRITE, &oldProtect); - *((byte*)0x000000014048FBA9 + 0) = 0x00; - VirtualProtect((BYTE*)0x000000014048FBA9, 1, oldProtect, &bck); } - - printf("[Patches] TAA disabled\n"); - } - if (!nMLAA) - { - // set MLAA var (shouldn't be needed but whatever) - *(byte*)0x00000001411AB680 = 0; - - // make constructor/init not set MLAA - {DWORD oldProtect, bck; - VirtualProtect((BYTE*)0x00000001404AB11A, 3, PAGE_EXECUTE_READWRITE, &oldProtect); - *((byte*)0x00000001404AB11A + 0) = 0x90; - *((byte*)0x00000001404AB11A + 1) = 0x90; - *((byte*)0x00000001404AB11A + 2) = 0x90; - VirtualProtect((BYTE*)0x00000001404AB11A, 3, oldProtect, &bck); } - - printf("[Patches] MLAA disabled\n"); - } - - // gamma - if (nGamma != 100 && nGamma != 0) - { - float gamma_float = (float)nGamma / 100.0f; - InjectCode((void*)(0x1404a863b), { *((uint8_t*)(&gamma_float)), *((uint8_t*)(&gamma_float) + 1), *((uint8_t*)(&gamma_float) + 2), *((uint8_t*)(&gamma_float) + 3) }); - - printf("[Patches] Gamma: %f\n", gamma_float); - } - - // Replace the hardcoded videos with MP4s, if they exist - if (nMP4Movies) - { - patchMovieExt("adv_cm_01", (void*)0x00000001409A53CC); - patchMovieExt("adv_cm_02", (void*)0x00000001409A53E4); - patchMovieExt("adv_cm_03", (void*)0x00000001409A53FC); - patchMovieExt("adv_cfm_cm", (void*)0x00000001409C22CD); - patchMovieExt("adv_sega_cm", (void*)0x00000001409C22EE); - patchMovieExt("diva_adv02", (void*)0x00000001409FF455); - patchMovieExt("diva_adv", (void*)0x00000001409FF483); - } - // Hide "FREE PLAY" - if (nHideFreeplay) - { - InjectCode((void*)0x00000001403BABEF, { 0x06, 0xB6 }); - printf("[Patches] Hide FREE PLAY/CREDIT(S) enabled\n"); - } - // Enable "FREE PLAY" mode - if (nFreeplay || nHideFreeplay) - { - // Always return true for the SelCredit enter SelPv check - InjectCode((void*)0x0000000140393610, { 0xB0, 0x01, 0xC3, 0x90, 0x90, 0x90 }); - - InjectCode((void*)0x00000001403BABEA, { 0x75 }); - printf("[Patches] Show FREE PLAY instead of CREDIT(S)\n"); - - if (nPDLoaderText && !nHideFreeplay) - { - InjectCode((void*)0x00000001409F61F0, { 0x50, 0x44, 0x20, 0x4C, 0x6F, 0x61, 0x64, 0x65, 0x72, 0x20, 0x00 }); - printf("[Patches] Show PD Loader text\n"); - } - } - // Use GLUT_CURSOR_RIGHT_ARROW instead of GLUT_CURSOR_NONE - if (nCursor) - { - InjectCode((void*)0x000000014019341B, { 0x00 }); - InjectCode((void*)0x00000001403012b5, { 0xeb }); // Disable debug cursor - printf("[Patches] Cursor enabled\n"); - } - // Override status icon states to be invalid (hides them) - if (nStatusIcons > 0) - { - std::vector cardIcon = { 0xFD, 0x0A }; - std::vector networkIcon = { 0x9E, 0x1E }; - - if (nStatusIcons == 2) // 2 for error icons - { - cardIcon = { 0xFA, 0x0A }; - networkIcon = { 0x9F, 0x1E }; - printf("[Patches] Status icons set to error state\n"); - } - else if (nStatusIcons == 3) // 3 for OK icons - { - cardIcon = { 0xFC, 0x0A }; - networkIcon = { 0xA0, 0x1E }; - printf("[Patches] Status icons set to OK state\n"); - } - else if (nStatusIcons == 4) // 4 for partial OK icons - { - cardIcon = { 0xFB, 0x0A }; - networkIcon = { 0xA1, 0x1E }; - printf("[Patches] Status icons set to partial OK state\n"); - } - else // 1 or invalid for hidden - { - cardIcon = { 0xFD, 0x0A }; - networkIcon = { 0x9E, 0x1E }; - printf("[Patches] Status icons hidden\n"); - } - - // card icon - InjectCode((void*)0x00000001403B9D6E, cardIcon); // error state - InjectCode((void*)0x00000001403B9D73, cardIcon); // OK state - - // network icon - InjectCode((void*)0x00000001403BA14B, networkIcon); // error state - InjectCode((void*)0x00000001403BA155, networkIcon); // OK state - InjectCode((void*)0x00000001403BA16B, networkIcon); // partial state - - InjectCode((void*)0x00000001403BA1A5, { 0x48, 0xE9 }); // never show the error code for partial connection - - // I was going to use this with a string, but the assignment wasn't behaving well and making separate prints was easier than figuring it out - // printf("[Patches] Status icons %s\n", iconType); - } - // Removes PV watermark - if (nHidePVWatermark) - { - InjectCode((void*)0x0000000140A13A88, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }); - printf("[Patches] PV watermark hidden\n"); - } - // Disable the PV screen photo UI - if (nNoPVUi) - { - InjectCode((void*)0x000000014048FA91, { 0xEB, 0x6F }); // skip button panel image (JMP 0x14048FB02) - - // patch minimum PV UI state to 1 instead of 0 - // hook check for lyrics enabled (UI state < 2) to change UI state 0 into 1 - // dump new code in the skipped button panel condition - InjectCode((void*)0x000000014048FA93, { 0xC7, 0x83, 0x58, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00 }); // MOV dword ptr [0x158 + RBX],0x1 - InjectCode((void*)0x000000014048FA9D, { 0xC6, 0x80, 0x3A, 0xD1, 0x02, 0x00, 0x01 }); // MOV byte ptr [0x2d13a + RAX],0x1 - InjectCode((void*)0x000000014048FAA4, { 0xE9, 0x8B, 0xFB, 0xFF, 0xFF }); // JMP 0x14048F634 - - InjectCode((void*)0x000000014048F62D, { 0xE9, 0x61, 0x04, 0x00, 0x00 }); // JMP 0x14048FA93 - - printf("[Patches] PV UI disabled\n"); - } - // Don't show volume control - if (nHideVolCtrl) - { - // skip SE button - InjectCode((void*)0x00000001409A4D60, { 0xC0, 0xD3 }); - - // skip volume sliders button - InjectCode((void*)0x0000000140A85F10, { 0xE0, 0x50 }); - - printf("[Patches] Volume control hidden\n"); - } - // Skip loading (and therefore displaying) song lyrics - if (nNoLyrics) - { - InjectCode((void*)0x00000001404E7A25, { 0x00, 0x00 }); - InjectCode((void*)0x00000001404E7950, { 0x48, 0xE9 }); // ensure first iteration doesn't run - printf("[Patches] Lyrics disabled\n"); - } - // Skip loading (and therefore displaying) song movies - if (nNoMovies) - { - InjectCode((void*)0x00000001404EB584, { 0x48, 0xE9 }); - InjectCode((void*)0x00000001404EB471, { 0x48, 0xE9 }); - printf("[Patches] Movies disabled\n"); - } - // Disable error banner - if (nNoError) - { - // Disable Errors Banner - InjectCode((void*)0x00000001403B9E9B, { 0x90, 0x90 }); - printf("[Patches] Errors Banner disabled\n"); - } - // Disable timer - if (nNoTimer) - { - // Freeze mode selection timer - InjectCode((void*)0x0000000140566B9E, { 0x90, 0x90, 0x90 }); - - // Freeze PV selection timer - InjectCode((void*)0x00000001405BDFBF, { 0x90, 0x90, 0x90, 0x90 }); - } - // Disable timer sprite - if (nNoTimerSprite) - { - InjectCode((void*)0x00000001409C0758, { 0x00 }); // time_loop - InjectCode((void*)0x0000000140A3D3F0, { 0x00 }); // time_in - InjectCode((void*)0x0000000140A3D3F8, { 0x00 }); // time_out - } - // Enhanced Stage Manager - if (nEStageManager > 0) - { - // Replace the function that provides the number of stages and compact some of it - InjectCode((void*)0x000000014038AEF0, { 0x48, 0x8B, 0x88, 0x40, 0x01, 0x00, 0x00, 0x48, 0x89, 0x4C, 0x24, 0x20, 0x48, 0x8B, 0xD0, 0x48, 0x8B, 0x88, 0x48, 0x01, 0x00, 0x00, 0x48, 0x89, 0x4C, 0x24, 0x28, 0x8B, 0x88, 0x50, 0x01, 0x00, 0x00, 0x89, 0x4C, 0x24, 0x30, 0x8B, 0x88, 0x54, 0x01, 0x00, 0x00, 0x8B, 0x80, 0x58, 0x01, 0x00, 0x00, 0x89, 0x44, 0x24, 0x38, 0x8B, 0x82, 0x5C, 0x01, 0x00, 0x00, 0x89, 0x4C, 0x24, 0x34, 0x89, 0x44, 0x24, 0x3C, 0x48, 0x8B, 0x82, 0x60, 0x01, 0x00, 0x00, 0x48, 0x89, 0x44, 0x24, 0x40, 0x48, 0x8B, 0x82, 0x68, 0x01, 0x00, 0x00, 0x48, 0x89, 0x44, 0x24, 0x48, 0x48, 0x8B, 0x82, 0x70, 0x01, 0x00, 0x00, 0x48, 0x89, 0x44, 0x24, 0x50, 0x8B, 0x82, 0x78, 0x01, 0x00, 0x00, 0x89, 0x44, 0x24, 0x58, 0x84, 0xC0, 0x74, 0x2A, 0x48, 0x8B, 0x44, 0x24, 0x38, 0x48, 0xC1, 0xE8, 0x20, 0x85, 0xC0, 0x75, 0x1D, 0xE8, 0xD9, 0xD9, 0xE5, 0xFF, 0x48, 0x85, 0xC0, 0x74, 0x13, 0x48, 0x8D, 0x48, 0x10, 0xE8, 0xFB, 0xD3, 0xE5, 0xFF, 0xB9, 0x03, 0x00, 0x00, 0x00, 0x85, 0xC0, 0x0F, 0x45, 0xD9, 0x8B, 0x1D, 0x1B, 0x0C, 0x00, 0x00, 0x83, 0x3D, 0x1C, 0x0C, 0x00, 0x00, 0x00, 0x74, 0x06, 0x8B, 0x1D, 0x10, 0x0C, 0x00, 0x00, 0x8B, 0xC3, 0x48, 0x83, 0xC4, 0x60, 0x5B, 0xC3, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC }); - - // Jump to another section by addding some code to replace the values (Jump 1) - InjectCode((void*)0x000000014038AFF4, { 0xE9, 0x87, 0x0B, 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC }); - - // Jump to another section by addding some code to replace the values (Replace 1/2) while some reserving space for values - InjectCode((void*)0x000000014038BB40, { 0xFF, 0x05, 0x76, 0x00, 0x00, 0x00, 0x8B, 0x0D, 0x70, 0x00, 0x00, 0x00, 0xBA, 0x02, 0x00, 0x00, 0x00, 0x83, 0x3D, 0x60, 0x00, 0x00, 0x00, 0x00, 0x74, 0x02, 0xFF, 0xC2, 0x39, 0xD1, 0x0F, 0x4D, 0xCA, 0x89, 0x48, 0x08, 0xB9, 0x0E, 0x00, 0x00, 0x00, 0xE8, 0x92, 0x98, 0xE0, 0xFF, 0xB0, 0x01, 0x48, 0x83, 0xC4, 0x28, 0xC3, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x44, 0x89, 0x61, 0x08, 0x44, 0x88, 0x61, 0x0C, 0x4C, 0x89, 0x61, 0x10, 0x44, 0x89, 0x25, 0x29, 0x00, 0x00, 0x00, 0xE9, 0x68, 0xF4, 0xFF, 0xFF, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }); - - // Use the value from our own address instead of the original one - InjectCode((void*)0x00000001403F65AF, { 0x48, 0x8D, 0x05, 0x4A, 0x18, 0xDA, 0x00, 0x8B, 0x1D, 0x00, 0x56 }); - - // Jump to another section by addding some code to replace the values (Jump 2) - InjectCode((void*)0x00000001403F6638, { 0xE9, 0x03, 0x55, 0xF9, 0xFF, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC }); - - DWORD StageCountProtect; - VirtualProtect((int32_t*)0x14038BBB0, 0x10, PAGE_EXECUTE_READWRITE, &StageCountProtect); - - int* ESM = (int*)0x000000014038BBB0; - - if (nEStageManagerEncore) - ESM[1] = nEStageManager; - else - ESM[0] = nEStageManager; - - ESM[2] = nEStageManagerEncore; - - printf("[Patches] Enhanced Stage Manager enabled\n"); - } - // OpenGL Patches - if (nOGLPatchA) - { - // (call cs:glGetError) -> (xor eax, eax); (nop); (nop); (nop); (nop); - InjectCode((void*)0x000000014069D21D, { 0x31, 0xC0, 0x90, 0x90, 0x90, 0x90 }); - } - if (nOGLPatchB) - { - // (js loc_14069BC32) -> (nop)... - InjectCode((void*)0x000000014069BAF4, { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); - } - // Unlock PSEUDO modules (which will all default to Miku, unless we also patch them to match the first performer) - if (nUnlockPseudo) - { - InjectCode((void*)0x0000000140A21770, { 0x00 }); - InjectCode((void*)0x0000000140A21780, { 0x00 }); - InjectCode((void*)0x0000000140A21790, { 0x00 }); - InjectCode((void*)0x0000000140A217A0, { 0x00 }); - InjectCode((void*)0x0000000140A217B0, { 0x00 }); - } - // Enable card button by somewhatlurker (pretty much just eye candy for now) - if (nCard) - { - InjectCode((void*)0x0000000140565E6B, { 0x90, 0x90 }); - } - // The original slider update needs to run for hardware sliders to work -- only patch it when using emulation - if (!nHardwareSlider) - { - // Don't update the touch slider state so we can write our own - InjectCode((void*)0x000000014061579B, { 0x90, 0x90, 0x90, 0x8B, 0x42, 0xE0, 0x90, 0x90, 0x90 }); - } - // Quick start - if (!nUseDivahookBat) - { - if (nQuickStart == 1) // skip the card/guest screen - { - InjectCode((void*)0x0000000140578EA9, { 0xE9, 0x8E, 0x00, 0x00, 0x00 }); - } - else if (nQuickStart == 2) // skip everything; normal mode - { - InjectCode((void*)0x0000000140578EA9, { 0xE9, 0xF1, 0x00, 0x00, 0x00 }); - InjectCode((void*)0x0000000140578E9D, { 0xC7, 0x47, 0x68, 0x28, 0x00, 0x00, 0x00 }); // skip back button error - } - } - // Disable scrolling sound effect - if (nNoScrollingSfx) - { - InjectCode((void*)0x00000001405C84B3, { 0x90, 0x90, 0x90, 0x90, 0x90 }); - } - // Disable hand scaling - if (nNoHandScaling) - { - InjectCode((void*)0x0000000140120709, { 0xE9, 0x82, 0x0A, 0x00 }); - } - // Default hand size - if (nDefaultHandSize >= 10000) - { - printf("[Patches] Changing default hand size...\n"); - const float num = (float)nDefaultHandSize / 10000.0; - DWORD oldProtect; - float* addr1 = (float*)(0x140506B59); - float* addr2 = (float*)(0x140506B60); - /*float* addr3 = (float*)(0x140506B67); - float* addr4 = (float*)(0x140506B71);*/ - VirtualProtect(addr1, 4, PAGE_EXECUTE_READWRITE, &oldProtect); - VirtualProtect(addr2, 4, PAGE_EXECUTE_READWRITE, &oldProtect); - /*VirtualProtect(addr3, 4, PAGE_EXECUTE_READWRITE, &oldProtect); - VirtualProtect(addr4, 4, PAGE_EXECUTE_READWRITE, &oldProtect);*/ - *addr1 = *addr2 /*= *addr3 = *addr4*/ = num; - VirtualProtect(addr1, 4, oldProtect, nullptr); - VirtualProtect(addr2, 4, oldProtect, nullptr); - /*VirtualProtect(addr3, 4, oldProtect, nullptr); - VirtualProtect(addr4, 4, oldProtect, nullptr);*/ - printf("[Patches] New default hand size: %f\n", num); - } - // Sing missed notes - if (nSingMissed) - { - InjectCode((void*)0x140109044, { 0xEB }); - // Breaks border: - // InjectCode((void*)0x140109096, { 0xEB }); - } - // Force mouth animations - { - if (nForceMouth == 1) // PDA - { - printf("[Patches] Forcing PDA mouth...\n"); - int* mouth_table = (int*)(0x1409A1DC0); - DWORD oldProtect; - VirtualProtect(mouth_table, 44, PAGE_EXECUTE_READWRITE, &oldProtect); - for (int i = 0; i < 11; i++) - { - mouth_table[i]++; - } - VirtualProtect(mouth_table, 44, oldProtect, nullptr); - printf("[Patches] PDA mouth forced\n"); - } - else if (nForceMouth == 2) // FT - { - printf("[Patches] Forcing FT mouth...\n"); - int* mouth_table_oldid = (int*)(0x1409A1E1C); - DWORD oldProtect; - VirtualProtect(mouth_table_oldid, 44, PAGE_EXECUTE_READWRITE, &oldProtect); - for (int i = 0; i < 11; i++) - { - mouth_table_oldid[i]--; - } - VirtualProtect(mouth_table_oldid, 44, oldProtect, nullptr); - printf("[Patches] FT mouth forced\n"); - } - } - // Force expressions - { - if (nForceExpressions == 1) // PDA - { - printf("[Patches] Forcing PDA expressions...\n"); - int* exp_table = (int*)(0x140A21900); - DWORD oldProtect; - VirtualProtect(exp_table, 104, PAGE_EXECUTE_READWRITE, &oldProtect); - for (int i = 0; i < 26; i++) - { - exp_table[i] += 2; - } - VirtualProtect(exp_table, 104, oldProtect, nullptr); - printf("[Patches] PDA expressions forced\n"); - } - else if (nForceExpressions == 2) // FT - { - printf("[Patches] Forcing FT expressions...\n"); - int* exp_table_oldid = (int*)(0x140A219D0); - DWORD oldProtect; - VirtualProtect(exp_table_oldid, 104, PAGE_EXECUTE_READWRITE, &oldProtect); - for (int i = 0; i < 26; i++) - { - exp_table_oldid[i] -= 2; - } - VirtualProtect(exp_table_oldid, 104, oldProtect, nullptr); - printf("[Patches] FT expressions forced\n"); - } - } - // Force look animations - { - if (nForceLook == 1) // PDA - { - printf("[Patches] Forcing PDA look...\n"); - int* look_table = (int*)(0x1409A1D70); - DWORD oldProtect; - VirtualProtect(look_table, 36, PAGE_EXECUTE_READWRITE, &oldProtect); - for (int i = 0; i < 9; i++) - { - look_table[i]++; - } - VirtualProtect(look_table, 36, oldProtect, nullptr); - printf("[Patches] PDA look forced\n"); - } - else if (nForceLook == 2) // FT - { - printf("[Patches] Forcing FT look...\n"); - int* look_table_oldid = (int*)(0x1409A1D9C); - DWORD oldProtect; - VirtualProtect(look_table_oldid, 36, PAGE_EXECUTE_READWRITE, &oldProtect); - for (int i = 0; i < 9; i++) - { - look_table_oldid[i]--; - } - VirtualProtect(look_table_oldid, 36, oldProtect, nullptr); - printf("[Patches] FT look forced\n"); - } - } - // NPR1 - { - if (nNpr1 == 1) // force on - { - InjectCode((void*)0x0000000140502FC0, { 0xC7, 0x05, 0x6E }); - InjectCode((void*)0x0000000140502FC6, { 0x01, 0x00, 0x00, 0x00, 0xC3 }); - - printf("[Patches] NPR1 forced\n"); - } - else if (nNpr1 == 2) // force off - { - InjectCode((void*)0x0000000140502FC0, { 0xC7, 0x05, 0x6E }); - InjectCode((void*)0x0000000140502FC6, { 0x00, 0x00, 0x00, 0x00, 0xC3 }); - - printf("[Patches] NPR1 disabled\n"); - } - } - // Depth of Field - if (!nDoF) - { - InjectCode((void*)0x00000001409476AB, { 0x90, 0x90, 0x90, 0x90, 0x90 }); - - InjectCode((void*)0x00000001411AB650, { 0b00000001 }); - } - // MAG filter - if (nMAG > 0) - { - //InjectCode((void*)0x00000001404AB142, { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); - - unsigned char filter; - switch (nMAG) - { - case 1: // nearest - filter = 0; - InjectCode((void*)0x00000001404ACE56, { 0x90, 0x90 }); - break; - case 2: // sharpen - filter = 3; // sharpen(4tap) - break; - case 3: // cone - filter = 5; // cone(2tap) - break; - default: - filter = 1; - } - - //InjectCode((void*)0x00000001404A864F, { filter }); - //InjectCode((void*)0x00000001411AC518, { filter }); - - InjectCode((void*)0x00000001404ACE8E, { 0xB9, filter, 0x00, 0x00 }); - InjectCode((void*)0x00000001404ACE93, { 0x90 }); - } - // Reflections - if (!nReflections) - { - InjectCode((void*)0x1406477C0, { 0xE9, 0xF3, 0x00, 0x00, 0x00, 0x90 }); - InjectCode((void*)0x1411ADAFC, { 0x00 }); - } - // Shadows - if (!nShadows) - { - //InjectCode((void*)0x140502B44, { 0x90, 0x90, 0x90 }); - //InjectCode((void*)0x140502BB2, { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); - InjectCode((void*)0x140502766, { 0x00 }); - InjectCode((void*)0x1411AD438, { 0x00 }); - InjectCode((void*)0x1411AD320, { 0x00 }); - } - // Punch-through transparency - if (!nPunchthrough) - { - InjectCode((void*)0x1411AD43D, { 0x00 }); - } - // Glare - if (!nGlare) - { - InjectCode((void*)0x1404B2168, { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); - } - // Shader - if (!nShader) - { - InjectCode((void*)0x140C9C48E, { 0x00 }); - } - // 2D - if (n2D) - { - //InjectCode((void*)0x140502B44, { 0x90, 0x90, 0x90 }); - InjectCode((void*)0x140502BB2, { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); - InjectCode((void*)0x140502A3C, { 0x90, 0x90, 0x90, 0x90, 0x90 }); - /*InjectCode((void*)0x1411AD320, { 0x00 }); // shadow - InjectCode((void*)0x1411AD323, { 0x00 }); // reflect - InjectCode((void*)0x1411AD321, { 0x00 }); // SS_SSS - InjectCode((void*)0x1411AD325, { 0x00 }); // preprocess - InjectCode((void*)0x1411AD328, { 0x00 }); // 3D*/ - InjectCode((void*)0x1411AD32A, { 0x01 }); // post process - InjectCode((void*)0x1411AD32B, { 0x01 }); // sprite - - InjectCode((void*)0x140A07920, { 0x00 }); // ignore objset - } - // Prevent data deletion - if (nNoDelete) - { - InjectCode((void*)(0x1406FEF80 + 0x1DB), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); - InjectCode((void*)(0x1407113F0 + 0x13C), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); - InjectCode((void*)(0x140712270 + 0x6C), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); - InjectCode((void*)(0x140712580 + 0x4C), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); - InjectCode((void*)(0x140712580 + 0x7C), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); - InjectCode((void*)(0x140713470 + 0x104), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); - InjectCode((void*)(0x1407135B0 + 0x102), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); - InjectCode((void*)(0x1407135B0 + 0x135), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); - InjectCode((void*)(0x1407135B0 + 0x232), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); - InjectCode((void*)(0x140713810 + 0x3E8), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); - InjectCode((void*)(0x140713D00 + 0x677), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); - InjectCode((void*)(0x1407168A0 + 0x9C), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); - InjectCode((void*)(0x1407168A0 + 0x1D2), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); - InjectCode((void*)(0x1407168A0 + 0x218), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); - InjectCode((void*)(0x1407168A0 + 0x22A), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); - InjectCode((void*)(0x140720910 + 0x25C), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); - InjectCode((void*)(0x140723EE0 + 0xEC), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); - InjectCode((void*)(0x140870DE0 + 0x4), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); - InjectCode((void*)(0x1406FEF80 + 0x1DB), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); - InjectCode((void*)(0x1407113F0 + 0x13C), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); - InjectCode((void*)(0x140712270 + 0x6E), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); - InjectCode((void*)(0x140712580 + 0x4C), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); - InjectCode((void*)(0x140712580 + 0x7C), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); - InjectCode((void*)(0x140713470 + 0x104), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); - InjectCode((void*)(0x1407135B0 + 0x102), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); - InjectCode((void*)(0x1407135B0 + 0x135), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); - InjectCode((void*)(0x1407135B0 + 0x232), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); - InjectCode((void*)(0x140713810 + 0x3E8), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); - InjectCode((void*)(0x140713D00 + 0x677), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); - InjectCode((void*)(0x1407168A0 + 0x9C), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); - InjectCode((void*)(0x1407168A0 + 0x1D2), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); - InjectCode((void*)(0x1407168A0 + 0x218), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); - InjectCode((void*)(0x1407168A0 + 0x22A), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); - InjectCode((void*)(0x140720910 + 0x25C), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); - InjectCode((void*)(0x140723EE0 + 0xEC), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); - InjectCode((void*)(0x1407168A0 + 0x9C), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); - InjectCode((void*)(0x140870DE0 + 0x4), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); - InjectCode((void*)(0x14081B6A4), { 0xC3 }); - - InjectCode((void*)(0x1406E1090 + 0x43C), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); - InjectCode((void*)(0x140718250 + 0x176), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); - InjectCode((void*)(0x140718750 + 0xC9), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); - InjectCode((void*)(0x1407193E0 + 0xFC), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); - InjectCode((void*)(0x1406E1090 + 0x43C), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); - InjectCode((void*)(0x140718250 + 0x176), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); - InjectCode((void*)(0x140718750 + 0xC9), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); - InjectCode((void*)(0x1407193E0 + 0xFC), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); - InjectCode((void*)(0x14081B67A), { 0xC3 }); - } - - // patch refract and reflect buffer sizes - // no need to really check anything before injecting, because reinjecting defaults is fine - InjectCode((void*)(0x140a24424), std::vector((uint8_t*)&nRefractResWidth, (uint8_t*)((int64_t)&nRefractResWidth + 4))); - InjectCode((void*)(0x140a24428), std::vector((uint8_t*)&nRefractResHeight, (uint8_t*)((int64_t)&nRefractResHeight + 4))); - InjectCode((void*)(0x140a2443c), std::vector((uint8_t*)&nReflectResWidth, (uint8_t*)((int64_t)&nReflectResWidth + 4))); - InjectCode((void*)(0x140a24440), std::vector((uint8_t*)&nReflectResHeight, (uint8_t*)((int64_t)&nReflectResHeight + 4))); - // for large reflect resolutions, adjust blur effect amount to not lose the effect - // scaling is based on a 1024 width instead of the original 512px - // because we don't wanna make it too blurry when just being used to smooth jaggies - if (nReflectResWidth >= 2048) - { - int blurAmount = nReflectResWidth / 1024; - - // multiply blur setting - // ECX has blur amount, EDX has blur type - InjectCode((void*)(0x140503000), { 0x89, 0x15, 0x3a, 0xa3, 0xca, 0x00 }); // MOV dword ptr [0x1411ad340], EDX - InjectCode((void*)(0x140503006), { 0xb8 }); // MOV EAX, blurAmount - InjectCode((void*)(0x140503007), std::vector((uint8_t*)&blurAmount, (uint8_t*)((int64_t)&blurAmount + 4))); - InjectCode((void*)(0x14050300b), { 0xf7, 0xe1 }); // MUL (EDX:EAX,)ECX - InjectCode((void*)(0x14050300d), { 0xeb, 0x09 }); // JMP 0x140503018 - InjectCode((void*)(0x140503018), { 0x89, 0x05, 0x1e, 0xa3, 0xca, 0x00 }); // MOV dword ptr [0x1411ad33c], EAX - InjectCode((void*)(0x14050301e), { 0xc3 }); // RET - - // divide dwgui blur amount getting - // RDX gets type, RCX gets amount - InjectCode((void*)(0x140502910), { 0x48, 0x85, 0xd2 }); // TEST RDX, RDX - InjectCode((void*)(0x140502913), { 0x74, 0x08 }); // JZ 0x14050291d - InjectCode((void*)(0x140502915), { 0x8b, 0x05, 0x25, 0xaa, 0xca, 0x00 }); // MOV EAX, dword ptr [0x1411ad340] - InjectCode((void*)(0x14050291b), { 0x89, 0x02 }); // MOV dword ptr [RDX], EAX - - InjectCode((void*)(0x14050291d), { 0x48, 0x85, 0xc9 }); // TEST RCX, RCX - InjectCode((void*)(0x140502920), { 0x74, 0x2d }); // JZ 0x14050294f - InjectCode((void*)(0x140502922), { 0x8b, 0x05, 0x14, 0xaa, 0xca, 0x00 }); // MOV EAX, dword ptr [0x1411ad33c] - - InjectCode((void*)(0x140502928), { 0xeb, 0x0d }); // JMP 0x140502937 - InjectCode((void*)(0x140502937), { 0x49, 0xc7, 0xc0 }); // MOV R8, blurAmount - InjectCode((void*)(0x14050293a), std::vector((uint8_t*)&blurAmount, (uint8_t*)((int64_t)&blurAmount + 4))); - InjectCode((void*)(0x14050293e), { 0xeb, 0x08 }); // JMP 0x140502948 - InjectCode((void*)(0x140502948), { 0x31, 0xd2 }); // XOR EDX,EDX - InjectCode((void*)(0x14050294a), { 0x49, 0xf7, 0xf0 }); // DIV (EDX:EAX,)R8 - - InjectCode((void*)(0x14050294d), { 0x89, 0x01 }); // MOV dword ptr [RCX], EAX - InjectCode((void*)(0x14050294f), { 0xc3 }); // RET - } - - // lag compensation - if (nLagCompensation > 0 && nLagCompensation <= 500) - { - InjectCode((void*)(0x14011e44e), { 0xf3, 0x0f, 0x10, 0x05, 0x8a, 0xcf, 0x9c, 0x00 }); // hijack xmm0 - InjectCode((void*)(0x14011e46b), { 0xf3, 0x0f, 0x11, 0x44, 0x24, 0x20 }); // get value from xmm0 instead of xmm1 - float startPos = (float)nLagCompensation / 1000.0f; - InjectCode((void*)(0x140aeB3e0), { *((uint8_t*)(&startPos)), *((uint8_t*)(&startPos) + 1), *((uint8_t*)(&startPos) + 2), *((uint8_t*)(&startPos) + 3) }); - - printf("[Patches] Lag Compensation: %f\n", startPos); - } - } +#pragma once + +#pragma once +#include +#include "PatchApplier.h" +#include "framework.h" + +class PatchApplier710 : public PatchApplier { + virtual void ApplyPatches() { + const struct { void* Address; std::vector Data; } patches_710[] = + { + // Just completely ignore all SYSTEM_STARTUP errors + { (void*)0x00000001403F5080, { 0xC3 } }, + // Always exit TASK_MODE_APP_ERROR on the first frame + { (void*)0x00000001403F73A7, { 0x90, 0x90 } }, + { (void*)0x00000001403F73C3, { 0x89, 0xD1, 0x90 } }, + // Ignore the EngineClear variable to clear the framebuffer at all resolutions + { (void*)0x0000000140501480, { 0x90, 0x90 } }, + { (void*)0x0000000140501515, { 0x90, 0x90 } }, + // Write ram files to the current directory instead of Y : / SBZV / ram + { (void*)0x000000014066CF09, { 0xE9, 0xD8, 0x00 } }, + // Change mdata path from "C:/Mount/Option" to "mdata/" + { (void*)0x0000000140A8CA18, { 0x6D, 0x64, 0x61, 0x74, 0x61, 0x2F, 0x00 } }, + { (void*)0x000000014066CEAE, { 0x06 } }, + // Skip parts of the network check state + { (void*)0x00000001406717B1, { 0xE9, 0x22, 0x03, 0x00 } }, + // Set the initial DHCP WAIT timer value to 0 + { (void*)0x00000001406724E7, { 0x00, 0x00 } }, + // Ignore SYSTEM_STARTUP Location Server checks + { (void*)0x00000001406732A2, { 0x90, 0x90 } }, + // Toon Shader Fix by lybxlpsv + { (void*)0x000000014050214F, { 0x90 } }, + { (void*)0x0000000140502150, { 0x90 } }, + // Toon Shader Outline Fix by lybxlpsv + { (void*)0x0000000140641102, { 0x01 } }, + // Skip unnecessary checks + { (void*)0x0000000140210820, { 0xB8, 0x00, 0x00, 0x00, 0x00, 0xC3 } }, + { (void*)0x000000014066E820, { 0xB8, 0x01, 0x00, 0x00, 0x00, 0xC3 } }, + // Disables call to glutFitWindowSizeToDesktop, prevents window automatic resize + { (void*)0x0000000140194E06, { 0x90, 0x90, 0x90, 0x90, 0x90 } }, + // Allow modifier mode selection (by Team Shimapan) + { (void*)0x00000001405CB1B3, { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 } }, + { (void*)0x00000001405CA0F5, { 0x90, 0x90 } }, + // allow modifier modes to work without use_card + { (void*)0x00000001405CB14A,{ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 } }, + { (void*)0x0000000140136CFA,{ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 } }, + // enable module selector without use_card + { (void*)0x00000001405C513B,{ 0x01 } }, + // fix back button + { (void*)0x0000000140578FB8, { 0xE9, 0x73, 0xFF, 0xFF, 0xFF } }, + // Force Hide IDs + { (void*)0x00000001409A5918, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { (void*)0x00000001409A5928, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + // fix TouchReaction + // get some more space by optimizing this code for size + { (void*)0x00000001406A1FE2,{ 0x7E } }, // MOVQ XMM0,qword ptr [0x168 + RSP] (change to MOVQ) + { (void*)0x00000001406A1FE9,{ 0x66, 0x0F, 0xD6, 0x44, 0x24, 0x6C } }, // MOVQ qword ptr [RSP + 0x6c],XMM0 + { (void*)0x00000001406A1FEF,{ 0xC7, 0x44, 0x24, 0x74, 0x00, 0x00, 0x00, 0x00 } }, // MOV dword ptr [RSP + 0x74],0x0 + { (void*)0x00000001406A1FF7,{ 0xEB, 0x0E } }, // JMP 0x1406a2007 (to rest of function as usual) + // add new code + { (void*)0x00000001406A1FF9,{ 0x66, 0x48, 0x0F, 0x6E, 0xC2 } }, // MOVQ XMM0,RDX (load touch pos) + { (void*)0x00000001406A1FFE,{ 0xEB, 0x5D } }, // JMP 0x1406a205d + { (void*)0x00000001406A205D,{ 0x0F, 0x2A, 0x0D, 0xB8, 0x6A, 0x31, 0x00 } }, // CVTPI2PS XMM1,qword ptr [0x1409b8b1c] (load 1280x720) + { (void*)0x00000001406A2064,{ 0x0F, 0x12, 0x51, 0x1C } }, // MOVLPS XMM2,qword ptr [RCX + 0x1c] (load actual res) + { (void*)0x00000001406A2068,{ 0xE9, 0x14, 0xFF, 0xFF, 0xFF } }, // JMP 0x1406a1f81 + { (void*)0x00000001406A1F81,{ 0x0F, 0x59, 0xC1 } }, // MULPS XMM0,XMM1 + { (void*)0x00000001406A1F84,{ 0x0F, 0x5E, 0xC2 } }, // DIVPS XMM0,XMM2 + { (void*)0x00000001406A1F87,{ 0x66, 0x0F, 0xD6, 0x44, 0x24, 0x10 } }, // MOVQ qword ptr [RSP+0x10],XMM0 + { (void*)0x00000001406A1F8D,{ 0xEB, 0x06 } }, // JMP 0x1406a1f95 (back to original function) + // jmp to new code + { (void*)0x00000001406A1F90,{ 0xEB, 0x67 } }, // JMP 0x1406a1ff9 + }; + + for (size_t i = 0; i < _countof(patches_710); i++) + InjectCode(patches_710[i].Address, patches_710[i].Data); + + + + // The old stereo patch... + // Use 2 channels instead of 4 + if (nStereo) + { + InjectCode((void*)0x0000000140A860C0, { 0x02 }); + printf("[Patches] Stereo patch enabled\n"); + } + + // Disable AA + if (!nTAA) + { + // set TAA var (shouldn't be needed but whatever) + *(byte*)0x00000001411AB67C = 0; + + // make constructor/init not set TAA + {DWORD oldProtect, bck; + VirtualProtect((BYTE*)0x00000001404AB11D, 3, PAGE_EXECUTE_READWRITE, &oldProtect); + *((byte*)0x00000001404AB11D + 0) = 0x90; + *((byte*)0x00000001404AB11D + 1) = 0x90; + *((byte*)0x00000001404AB11D + 2) = 0x90; + VirtualProtect((BYTE*)0x00000001404AB11D, 3, oldProtect, &bck); } + + // not sure, but it's somewhere in TaskPvGame init + // just make it set TAA to 0 instead of 1 to avoid possible issues + {DWORD oldProtect, bck; + VirtualProtect((BYTE*)0x00000001401063CE, 1, PAGE_EXECUTE_READWRITE, &oldProtect); + *((byte*)0x00000001401063CE + 0) = 0x00; + VirtualProtect((BYTE*)0x00000001401063CE, 1, oldProtect, &bck); } + + // prevent re-enabling after taking photos + {DWORD oldProtect, bck; + VirtualProtect((BYTE*)0x000000014048FBA9, 1, PAGE_EXECUTE_READWRITE, &oldProtect); + *((byte*)0x000000014048FBA9 + 0) = 0x00; + VirtualProtect((BYTE*)0x000000014048FBA9, 1, oldProtect, &bck); } + + printf("[Patches] TAA disabled\n"); + } + if (!nMLAA) + { + // set MLAA var (shouldn't be needed but whatever) + *(byte*)0x00000001411AB680 = 0; + + // make constructor/init not set MLAA + {DWORD oldProtect, bck; + VirtualProtect((BYTE*)0x00000001404AB11A, 3, PAGE_EXECUTE_READWRITE, &oldProtect); + *((byte*)0x00000001404AB11A + 0) = 0x90; + *((byte*)0x00000001404AB11A + 1) = 0x90; + *((byte*)0x00000001404AB11A + 2) = 0x90; + VirtualProtect((BYTE*)0x00000001404AB11A, 3, oldProtect, &bck); } + + printf("[Patches] MLAA disabled\n"); + } + + // gamma + if (nGamma != 100 && nGamma != 0) + { + float gamma_float = (float)nGamma / 100.0f; + InjectCode((void*)(0x1404a863b), { *((uint8_t*)(&gamma_float)), *((uint8_t*)(&gamma_float) + 1), *((uint8_t*)(&gamma_float) + 2), *((uint8_t*)(&gamma_float) + 3) }); + + printf("[Patches] Gamma: %f\n", gamma_float); + } + + // Replace the hardcoded videos with MP4s, if they exist + if (nMP4Movies) + { + patchMovieExt("adv_cm_01", (void*)0x00000001409A53CC); + patchMovieExt("adv_cm_02", (void*)0x00000001409A53E4); + patchMovieExt("adv_cm_03", (void*)0x00000001409A53FC); + patchMovieExt("adv_cfm_cm", (void*)0x00000001409C22CD); + patchMovieExt("adv_sega_cm", (void*)0x00000001409C22EE); + patchMovieExt("diva_adv02", (void*)0x00000001409FF455); + patchMovieExt("diva_adv", (void*)0x00000001409FF483); + } + // Hide "FREE PLAY" + if (nHideFreeplay) + { + InjectCode((void*)0x00000001403BABEF, { 0x06, 0xB6 }); + printf("[Patches] Hide FREE PLAY/CREDIT(S) enabled\n"); + } + // Enable "FREE PLAY" mode + if (nFreeplay || nHideFreeplay) + { + // Always return true for the SelCredit enter SelPv check + InjectCode((void*)0x0000000140393610, { 0xB0, 0x01, 0xC3, 0x90, 0x90, 0x90 }); + + InjectCode((void*)0x00000001403BABEA, { 0x75 }); + printf("[Patches] Show FREE PLAY instead of CREDIT(S)\n"); + + if (nPDLoaderText && !nHideFreeplay) + { + InjectCode((void*)0x00000001409F61F0, { 0x50, 0x44, 0x20, 0x4C, 0x6F, 0x61, 0x64, 0x65, 0x72, 0x20, 0x00 }); + printf("[Patches] Show PD Loader text\n"); + } + } + // Use GLUT_CURSOR_RIGHT_ARROW instead of GLUT_CURSOR_NONE + if (nCursor) + { + InjectCode((void*)0x000000014019341B, { 0x00 }); + InjectCode((void*)0x00000001403012b5, { 0xeb }); // Disable debug cursor + printf("[Patches] Cursor enabled\n"); + } + // Override status icon states to be invalid (hides them) + if (nStatusIcons > 0) + { + std::vector cardIcon = { 0xFD, 0x0A }; + std::vector networkIcon = { 0x9E, 0x1E }; + + if (nStatusIcons == 2) // 2 for error icons + { + cardIcon = { 0xFA, 0x0A }; + networkIcon = { 0x9F, 0x1E }; + printf("[Patches] Status icons set to error state\n"); + } + else if (nStatusIcons == 3) // 3 for OK icons + { + cardIcon = { 0xFC, 0x0A }; + networkIcon = { 0xA0, 0x1E }; + printf("[Patches] Status icons set to OK state\n"); + } + else if (nStatusIcons == 4) // 4 for partial OK icons + { + cardIcon = { 0xFB, 0x0A }; + networkIcon = { 0xA1, 0x1E }; + printf("[Patches] Status icons set to partial OK state\n"); + } + else // 1 or invalid for hidden + { + cardIcon = { 0xFD, 0x0A }; + networkIcon = { 0x9E, 0x1E }; + printf("[Patches] Status icons hidden\n"); + } + + // card icon + InjectCode((void*)0x00000001403B9D6E, cardIcon); // error state + InjectCode((void*)0x00000001403B9D73, cardIcon); // OK state + + // network icon + InjectCode((void*)0x00000001403BA14B, networkIcon); // error state + InjectCode((void*)0x00000001403BA155, networkIcon); // OK state + InjectCode((void*)0x00000001403BA16B, networkIcon); // partial state + + InjectCode((void*)0x00000001403BA1A5, { 0x48, 0xE9 }); // never show the error code for partial connection + + // I was going to use this with a string, but the assignment wasn't behaving well and making separate prints was easier than figuring it out + // printf("[Patches] Status icons %s\n", iconType); + } + // Removes PV watermark + if (nHidePVWatermark) + { + InjectCode((void*)0x0000000140A13A88, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }); + printf("[Patches] PV watermark hidden\n"); + } + // Disable the PV screen photo UI + if (nNoPVUi) + { + InjectCode((void*)0x000000014048FA91, { 0xEB, 0x6F }); // skip button panel image (JMP 0x14048FB02) + + // patch minimum PV UI state to 1 instead of 0 + // hook check for lyrics enabled (UI state < 2) to change UI state 0 into 1 + // dump new code in the skipped button panel condition + InjectCode((void*)0x000000014048FA93, { 0xC7, 0x83, 0x58, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00 }); // MOV dword ptr [0x158 + RBX],0x1 + InjectCode((void*)0x000000014048FA9D, { 0xC6, 0x80, 0x3A, 0xD1, 0x02, 0x00, 0x01 }); // MOV byte ptr [0x2d13a + RAX],0x1 + InjectCode((void*)0x000000014048FAA4, { 0xE9, 0x8B, 0xFB, 0xFF, 0xFF }); // JMP 0x14048F634 + + InjectCode((void*)0x000000014048F62D, { 0xE9, 0x61, 0x04, 0x00, 0x00 }); // JMP 0x14048FA93 + + printf("[Patches] PV UI disabled\n"); + } + // Don't show volume control + if (nHideVolCtrl) + { + // skip SE button + InjectCode((void*)0x00000001409A4D60, { 0xC0, 0xD3 }); + + // skip volume sliders button + InjectCode((void*)0x0000000140A85F10, { 0xE0, 0x50 }); + + printf("[Patches] Volume control hidden\n"); + } + // Skip loading (and therefore displaying) song lyrics + if (nNoLyrics) + { + InjectCode((void*)0x00000001404E7A25, { 0x00, 0x00 }); + InjectCode((void*)0x00000001404E7950, { 0x48, 0xE9 }); // ensure first iteration doesn't run + printf("[Patches] Lyrics disabled\n"); + } + // Skip loading (and therefore displaying) song movies + if (nNoMovies) + { + InjectCode((void*)0x00000001404EB584, { 0x48, 0xE9 }); + InjectCode((void*)0x00000001404EB471, { 0x48, 0xE9 }); + printf("[Patches] Movies disabled\n"); + } + // Disable error banner + if (nNoError) + { + // Disable Errors Banner + InjectCode((void*)0x00000001403B9E9B, { 0x90, 0x90 }); + printf("[Patches] Errors Banner disabled\n"); + } + // Disable timer + if (nNoTimer) + { + // Freeze mode selection timer + InjectCode((void*)0x0000000140566B9E, { 0x90, 0x90, 0x90 }); + + // Freeze PV selection timer + InjectCode((void*)0x00000001405BDFBF, { 0x90, 0x90, 0x90, 0x90 }); + } + // Disable timer sprite + if (nNoTimerSprite) + { + InjectCode((void*)0x00000001409C0758, { 0x00 }); // time_loop + InjectCode((void*)0x0000000140A3D3F0, { 0x00 }); // time_in + InjectCode((void*)0x0000000140A3D3F8, { 0x00 }); // time_out + } + // Enhanced Stage Manager + if (nEStageManager > 0) + { + // Replace the function that provides the number of stages and compact some of it + InjectCode((void*)0x000000014038AEF0, { 0x48, 0x8B, 0x88, 0x40, 0x01, 0x00, 0x00, 0x48, 0x89, 0x4C, 0x24, 0x20, 0x48, 0x8B, 0xD0, 0x48, 0x8B, 0x88, 0x48, 0x01, 0x00, 0x00, 0x48, 0x89, 0x4C, 0x24, 0x28, 0x8B, 0x88, 0x50, 0x01, 0x00, 0x00, 0x89, 0x4C, 0x24, 0x30, 0x8B, 0x88, 0x54, 0x01, 0x00, 0x00, 0x8B, 0x80, 0x58, 0x01, 0x00, 0x00, 0x89, 0x44, 0x24, 0x38, 0x8B, 0x82, 0x5C, 0x01, 0x00, 0x00, 0x89, 0x4C, 0x24, 0x34, 0x89, 0x44, 0x24, 0x3C, 0x48, 0x8B, 0x82, 0x60, 0x01, 0x00, 0x00, 0x48, 0x89, 0x44, 0x24, 0x40, 0x48, 0x8B, 0x82, 0x68, 0x01, 0x00, 0x00, 0x48, 0x89, 0x44, 0x24, 0x48, 0x48, 0x8B, 0x82, 0x70, 0x01, 0x00, 0x00, 0x48, 0x89, 0x44, 0x24, 0x50, 0x8B, 0x82, 0x78, 0x01, 0x00, 0x00, 0x89, 0x44, 0x24, 0x58, 0x84, 0xC0, 0x74, 0x2A, 0x48, 0x8B, 0x44, 0x24, 0x38, 0x48, 0xC1, 0xE8, 0x20, 0x85, 0xC0, 0x75, 0x1D, 0xE8, 0xD9, 0xD9, 0xE5, 0xFF, 0x48, 0x85, 0xC0, 0x74, 0x13, 0x48, 0x8D, 0x48, 0x10, 0xE8, 0xFB, 0xD3, 0xE5, 0xFF, 0xB9, 0x03, 0x00, 0x00, 0x00, 0x85, 0xC0, 0x0F, 0x45, 0xD9, 0x8B, 0x1D, 0x1B, 0x0C, 0x00, 0x00, 0x83, 0x3D, 0x1C, 0x0C, 0x00, 0x00, 0x00, 0x74, 0x06, 0x8B, 0x1D, 0x10, 0x0C, 0x00, 0x00, 0x8B, 0xC3, 0x48, 0x83, 0xC4, 0x60, 0x5B, 0xC3, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC }); + + // Jump to another section by addding some code to replace the values (Jump 1) + InjectCode((void*)0x000000014038AFF4, { 0xE9, 0x87, 0x0B, 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC }); + + // Jump to another section by addding some code to replace the values (Replace 1/2) while some reserving space for values + InjectCode((void*)0x000000014038BB40, { 0xFF, 0x05, 0x76, 0x00, 0x00, 0x00, 0x8B, 0x0D, 0x70, 0x00, 0x00, 0x00, 0xBA, 0x02, 0x00, 0x00, 0x00, 0x83, 0x3D, 0x60, 0x00, 0x00, 0x00, 0x00, 0x74, 0x02, 0xFF, 0xC2, 0x39, 0xD1, 0x0F, 0x4D, 0xCA, 0x89, 0x48, 0x08, 0xB9, 0x0E, 0x00, 0x00, 0x00, 0xE8, 0x92, 0x98, 0xE0, 0xFF, 0xB0, 0x01, 0x48, 0x83, 0xC4, 0x28, 0xC3, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x44, 0x89, 0x61, 0x08, 0x44, 0x88, 0x61, 0x0C, 0x4C, 0x89, 0x61, 0x10, 0x44, 0x89, 0x25, 0x29, 0x00, 0x00, 0x00, 0xE9, 0x68, 0xF4, 0xFF, 0xFF, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }); + + // Use the value from our own address instead of the original one + InjectCode((void*)0x00000001403F65AF, { 0x48, 0x8D, 0x05, 0x4A, 0x18, 0xDA, 0x00, 0x8B, 0x1D, 0x00, 0x56 }); + + // Jump to another section by addding some code to replace the values (Jump 2) + InjectCode((void*)0x00000001403F6638, { 0xE9, 0x03, 0x55, 0xF9, 0xFF, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC }); + + DWORD StageCountProtect; + VirtualProtect((int32_t*)0x14038BBB0, 0x10, PAGE_EXECUTE_READWRITE, &StageCountProtect); + + int* ESM = (int*)0x000000014038BBB0; + + if (nEStageManagerEncore) + ESM[1] = nEStageManager; + else + ESM[0] = nEStageManager; + + ESM[2] = nEStageManagerEncore; + + printf("[Patches] Enhanced Stage Manager enabled\n"); + } + // OpenGL Patches + if (nOGLPatchA) + { + // (call cs:glGetError) -> (xor eax, eax); (nop); (nop); (nop); (nop); + InjectCode((void*)0x000000014069D21D, { 0x31, 0xC0, 0x90, 0x90, 0x90, 0x90 }); + } + if (nOGLPatchB) + { + // (js loc_14069BC32) -> (nop)... + InjectCode((void*)0x000000014069BAF4, { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); + } + // Unlock PSEUDO modules (which will all default to Miku, unless we also patch them to match the first performer) + if (nUnlockPseudo) + { + InjectCode((void*)0x0000000140A21770, { 0x00 }); + InjectCode((void*)0x0000000140A21780, { 0x00 }); + InjectCode((void*)0x0000000140A21790, { 0x00 }); + InjectCode((void*)0x0000000140A217A0, { 0x00 }); + InjectCode((void*)0x0000000140A217B0, { 0x00 }); + } + // Enable card button by somewhatlurker (pretty much just eye candy for now) + if (nCard) + { + InjectCode((void*)0x0000000140565E6B, { 0x90, 0x90 }); + } + // The original slider update needs to run for hardware sliders to work -- only patch it when using emulation + if (!nHardwareSlider) + { + // Don't update the touch slider state so we can write our own + InjectCode((void*)0x000000014061579B, { 0x90, 0x90, 0x90, 0x8B, 0x42, 0xE0, 0x90, 0x90, 0x90 }); + } + // Quick start + if (!nUseDivahookBat) + { + if (nQuickStart == 1) // skip the card/guest screen + { + InjectCode((void*)0x0000000140578EA9, { 0xE9, 0x8E, 0x00, 0x00, 0x00 }); + } + else if (nQuickStart == 2) // skip everything; normal mode + { + InjectCode((void*)0x0000000140578EA9, { 0xE9, 0xF1, 0x00, 0x00, 0x00 }); + InjectCode((void*)0x0000000140578E9D, { 0xC7, 0x47, 0x68, 0x28, 0x00, 0x00, 0x00 }); // skip back button error + } + } + // Disable scrolling sound effect + if (nNoScrollingSfx) + { + InjectCode((void*)0x00000001405C84B3, { 0x90, 0x90, 0x90, 0x90, 0x90 }); + } + // Disable hand scaling + if (nNoHandScaling) + { + InjectCode((void*)0x0000000140120709, { 0xE9, 0x82, 0x0A, 0x00 }); + } + // Default hand size + if (nDefaultHandSize >= 10000) + { + printf("[Patches] Changing default hand size...\n"); + const float num = (float)nDefaultHandSize / 10000.0; + DWORD oldProtect; + float* addr1 = (float*)(0x140506B59); + float* addr2 = (float*)(0x140506B60); + /*float* addr3 = (float*)(0x140506B67); + float* addr4 = (float*)(0x140506B71);*/ + VirtualProtect(addr1, 4, PAGE_EXECUTE_READWRITE, &oldProtect); + VirtualProtect(addr2, 4, PAGE_EXECUTE_READWRITE, &oldProtect); + /*VirtualProtect(addr3, 4, PAGE_EXECUTE_READWRITE, &oldProtect); + VirtualProtect(addr4, 4, PAGE_EXECUTE_READWRITE, &oldProtect);*/ + *addr1 = *addr2 /*= *addr3 = *addr4*/ = num; + VirtualProtect(addr1, 4, oldProtect, nullptr); + VirtualProtect(addr2, 4, oldProtect, nullptr); + /*VirtualProtect(addr3, 4, oldProtect, nullptr); + VirtualProtect(addr4, 4, oldProtect, nullptr);*/ + printf("[Patches] New default hand size: %f\n", num); + } + // Sing missed notes + if (nSingMissed) + { + InjectCode((void*)0x140109044, { 0xEB }); + // Breaks border: + // InjectCode((void*)0x140109096, { 0xEB }); + } + // Force mouth animations + { + if (nForceMouth == 1) // PDA + { + printf("[Patches] Forcing PDA mouth...\n"); + int* mouth_table = (int*)(0x1409A1DC0); + DWORD oldProtect; + VirtualProtect(mouth_table, 44, PAGE_EXECUTE_READWRITE, &oldProtect); + for (int i = 0; i < 11; i++) + { + mouth_table[i]++; + } + VirtualProtect(mouth_table, 44, oldProtect, nullptr); + printf("[Patches] PDA mouth forced\n"); + } + else if (nForceMouth == 2) // FT + { + printf("[Patches] Forcing FT mouth...\n"); + int* mouth_table_oldid = (int*)(0x1409A1E1C); + DWORD oldProtect; + VirtualProtect(mouth_table_oldid, 44, PAGE_EXECUTE_READWRITE, &oldProtect); + for (int i = 0; i < 11; i++) + { + mouth_table_oldid[i]--; + } + VirtualProtect(mouth_table_oldid, 44, oldProtect, nullptr); + printf("[Patches] FT mouth forced\n"); + } + } + // Force expressions + { + if (nForceExpressions == 1) // PDA + { + printf("[Patches] Forcing PDA expressions...\n"); + int* exp_table = (int*)(0x140A21900); + DWORD oldProtect; + VirtualProtect(exp_table, 104, PAGE_EXECUTE_READWRITE, &oldProtect); + for (int i = 0; i < 26; i++) + { + exp_table[i] += 2; + } + VirtualProtect(exp_table, 104, oldProtect, nullptr); + printf("[Patches] PDA expressions forced\n"); + } + else if (nForceExpressions == 2) // FT + { + printf("[Patches] Forcing FT expressions...\n"); + int* exp_table_oldid = (int*)(0x140A219D0); + DWORD oldProtect; + VirtualProtect(exp_table_oldid, 104, PAGE_EXECUTE_READWRITE, &oldProtect); + for (int i = 0; i < 26; i++) + { + exp_table_oldid[i] -= 2; + } + VirtualProtect(exp_table_oldid, 104, oldProtect, nullptr); + printf("[Patches] FT expressions forced\n"); + } + } + // Force look animations + { + if (nForceLook == 1) // PDA + { + printf("[Patches] Forcing PDA look...\n"); + int* look_table = (int*)(0x1409A1D70); + DWORD oldProtect; + VirtualProtect(look_table, 36, PAGE_EXECUTE_READWRITE, &oldProtect); + for (int i = 0; i < 9; i++) + { + look_table[i]++; + } + VirtualProtect(look_table, 36, oldProtect, nullptr); + printf("[Patches] PDA look forced\n"); + } + else if (nForceLook == 2) // FT + { + printf("[Patches] Forcing FT look...\n"); + int* look_table_oldid = (int*)(0x1409A1D9C); + DWORD oldProtect; + VirtualProtect(look_table_oldid, 36, PAGE_EXECUTE_READWRITE, &oldProtect); + for (int i = 0; i < 9; i++) + { + look_table_oldid[i]--; + } + VirtualProtect(look_table_oldid, 36, oldProtect, nullptr); + printf("[Patches] FT look forced\n"); + } + } + // NPR1 + { + if (nNpr1 == 1) // force on + { + InjectCode((void*)0x0000000140502FC0, { 0xC7, 0x05, 0x6E }); + InjectCode((void*)0x0000000140502FC6, { 0x01, 0x00, 0x00, 0x00, 0xC3 }); + + printf("[Patches] NPR1 forced\n"); + } + else if (nNpr1 == 2) // force off + { + InjectCode((void*)0x0000000140502FC0, { 0xC7, 0x05, 0x6E }); + InjectCode((void*)0x0000000140502FC6, { 0x00, 0x00, 0x00, 0x00, 0xC3 }); + + printf("[Patches] NPR1 disabled\n"); + } + } + // Depth of Field + if (!nDoF) + { + InjectCode((void*)0x00000001409476AB, { 0x90, 0x90, 0x90, 0x90, 0x90 }); + + InjectCode((void*)0x00000001411AB650, { 0b00000001 }); + } + // MAG filter + if (nMAG > 0) + { + //InjectCode((void*)0x00000001404AB142, { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); + + unsigned char filter; + switch (nMAG) + { + case 1: // nearest + filter = 0; + InjectCode((void*)0x00000001404ACE56, { 0x90, 0x90 }); + break; + case 2: // sharpen + filter = 3; // sharpen(4tap) + break; + case 3: // cone + filter = 5; // cone(2tap) + break; + default: + filter = 1; + } + + //InjectCode((void*)0x00000001404A864F, { filter }); + //InjectCode((void*)0x00000001411AC518, { filter }); + + InjectCode((void*)0x00000001404ACE8E, { 0xB9, filter, 0x00, 0x00 }); + InjectCode((void*)0x00000001404ACE93, { 0x90 }); + } + // Reflections + if (!nReflections) + { + InjectCode((void*)0x1406477C0, { 0xE9, 0xF3, 0x00, 0x00, 0x00, 0x90 }); + InjectCode((void*)0x1411ADAFC, { 0x00 }); + } + // Shadows + if (!nShadows) + { + //InjectCode((void*)0x140502B44, { 0x90, 0x90, 0x90 }); + //InjectCode((void*)0x140502BB2, { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); + InjectCode((void*)0x140502766, { 0x00 }); + InjectCode((void*)0x1411AD438, { 0x00 }); + InjectCode((void*)0x1411AD320, { 0x00 }); + } + // Punch-through transparency + if (!nPunchthrough) + { + InjectCode((void*)0x1411AD43D, { 0x00 }); + } + // Glare + if (!nGlare) + { + InjectCode((void*)0x1404B2168, { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); + } + // Shader + if (!nShader) + { + InjectCode((void*)0x140C9C48E, { 0x00 }); + } + // 2D + if (n2D) + { + //InjectCode((void*)0x140502B44, { 0x90, 0x90, 0x90 }); + InjectCode((void*)0x140502BB2, { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); + InjectCode((void*)0x140502A3C, { 0x90, 0x90, 0x90, 0x90, 0x90 }); + /*InjectCode((void*)0x1411AD320, { 0x00 }); // shadow + InjectCode((void*)0x1411AD323, { 0x00 }); // reflect + InjectCode((void*)0x1411AD321, { 0x00 }); // SS_SSS + InjectCode((void*)0x1411AD325, { 0x00 }); // preprocess + InjectCode((void*)0x1411AD328, { 0x00 }); // 3D*/ + InjectCode((void*)0x1411AD32A, { 0x01 }); // post process + InjectCode((void*)0x1411AD32B, { 0x01 }); // sprite + + InjectCode((void*)0x140A07920, { 0x00 }); // ignore objset + } + // Prevent data deletion + if (nNoDelete) + { + InjectCode((void*)(0x1406FEF80 + 0x1DB), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); + InjectCode((void*)(0x1407113F0 + 0x13C), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); + InjectCode((void*)(0x140712270 + 0x6C), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); + InjectCode((void*)(0x140712580 + 0x4C), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); + InjectCode((void*)(0x140712580 + 0x7C), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); + InjectCode((void*)(0x140713470 + 0x104), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); + InjectCode((void*)(0x1407135B0 + 0x102), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); + InjectCode((void*)(0x1407135B0 + 0x135), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); + InjectCode((void*)(0x1407135B0 + 0x232), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); + InjectCode((void*)(0x140713810 + 0x3E8), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); + InjectCode((void*)(0x140713D00 + 0x677), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); + InjectCode((void*)(0x1407168A0 + 0x9C), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); + InjectCode((void*)(0x1407168A0 + 0x1D2), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); + InjectCode((void*)(0x1407168A0 + 0x218), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); + InjectCode((void*)(0x1407168A0 + 0x22A), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); + InjectCode((void*)(0x140720910 + 0x25C), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); + InjectCode((void*)(0x140723EE0 + 0xEC), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); + InjectCode((void*)(0x140870DE0 + 0x4), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); + InjectCode((void*)(0x1406FEF80 + 0x1DB), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); + InjectCode((void*)(0x1407113F0 + 0x13C), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); + InjectCode((void*)(0x140712270 + 0x6E), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); + InjectCode((void*)(0x140712580 + 0x4C), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); + InjectCode((void*)(0x140712580 + 0x7C), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); + InjectCode((void*)(0x140713470 + 0x104), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); + InjectCode((void*)(0x1407135B0 + 0x102), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); + InjectCode((void*)(0x1407135B0 + 0x135), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); + InjectCode((void*)(0x1407135B0 + 0x232), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); + InjectCode((void*)(0x140713810 + 0x3E8), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); + InjectCode((void*)(0x140713D00 + 0x677), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); + InjectCode((void*)(0x1407168A0 + 0x9C), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); + InjectCode((void*)(0x1407168A0 + 0x1D2), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); + InjectCode((void*)(0x1407168A0 + 0x218), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); + InjectCode((void*)(0x1407168A0 + 0x22A), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); + InjectCode((void*)(0x140720910 + 0x25C), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); + InjectCode((void*)(0x140723EE0 + 0xEC), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); + InjectCode((void*)(0x1407168A0 + 0x9C), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); + InjectCode((void*)(0x140870DE0 + 0x4), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); + InjectCode((void*)(0x14081B6A4), { 0xC3 }); + + InjectCode((void*)(0x1406E1090 + 0x43C), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); + InjectCode((void*)(0x140718250 + 0x176), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); + InjectCode((void*)(0x140718750 + 0xC9), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); + InjectCode((void*)(0x1407193E0 + 0xFC), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); + InjectCode((void*)(0x1406E1090 + 0x43C), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); + InjectCode((void*)(0x140718250 + 0x176), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); + InjectCode((void*)(0x140718750 + 0xC9), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); + InjectCode((void*)(0x1407193E0 + 0xFC), { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); + InjectCode((void*)(0x14081B67A), { 0xC3 }); + } + + // patch refract and reflect buffer sizes + // no need to really check anything before injecting, because reinjecting defaults is fine + InjectCode((void*)(0x140a24424), std::vector((uint8_t*)&nRefractResWidth, (uint8_t*)((int64_t)&nRefractResWidth + 4))); + InjectCode((void*)(0x140a24428), std::vector((uint8_t*)&nRefractResHeight, (uint8_t*)((int64_t)&nRefractResHeight + 4))); + InjectCode((void*)(0x140a2443c), std::vector((uint8_t*)&nReflectResWidth, (uint8_t*)((int64_t)&nReflectResWidth + 4))); + InjectCode((void*)(0x140a24440), std::vector((uint8_t*)&nReflectResHeight, (uint8_t*)((int64_t)&nReflectResHeight + 4))); + // for large reflect resolutions, adjust blur effect amount to not lose the effect + // scaling is based on a 1024 width instead of the original 512px + // because we don't wanna make it too blurry when just being used to smooth jaggies + if (nReflectResWidth >= 2048) + { + int blurAmount = nReflectResWidth / 1024; + + // multiply blur setting + // ECX has blur amount, EDX has blur type + InjectCode((void*)(0x140503000), { 0x89, 0x15, 0x3a, 0xa3, 0xca, 0x00 }); // MOV dword ptr [0x1411ad340], EDX + InjectCode((void*)(0x140503006), { 0xb8 }); // MOV EAX, blurAmount + InjectCode((void*)(0x140503007), std::vector((uint8_t*)&blurAmount, (uint8_t*)((int64_t)&blurAmount + 4))); + InjectCode((void*)(0x14050300b), { 0xf7, 0xe1 }); // MUL (EDX:EAX,)ECX + InjectCode((void*)(0x14050300d), { 0xeb, 0x09 }); // JMP 0x140503018 + InjectCode((void*)(0x140503018), { 0x89, 0x05, 0x1e, 0xa3, 0xca, 0x00 }); // MOV dword ptr [0x1411ad33c], EAX + InjectCode((void*)(0x14050301e), { 0xc3 }); // RET + + // divide dwgui blur amount getting + // RDX gets type, RCX gets amount + InjectCode((void*)(0x140502910), { 0x48, 0x85, 0xd2 }); // TEST RDX, RDX + InjectCode((void*)(0x140502913), { 0x74, 0x08 }); // JZ 0x14050291d + InjectCode((void*)(0x140502915), { 0x8b, 0x05, 0x25, 0xaa, 0xca, 0x00 }); // MOV EAX, dword ptr [0x1411ad340] + InjectCode((void*)(0x14050291b), { 0x89, 0x02 }); // MOV dword ptr [RDX], EAX + + InjectCode((void*)(0x14050291d), { 0x48, 0x85, 0xc9 }); // TEST RCX, RCX + InjectCode((void*)(0x140502920), { 0x74, 0x2d }); // JZ 0x14050294f + InjectCode((void*)(0x140502922), { 0x8b, 0x05, 0x14, 0xaa, 0xca, 0x00 }); // MOV EAX, dword ptr [0x1411ad33c] + + InjectCode((void*)(0x140502928), { 0xeb, 0x0d }); // JMP 0x140502937 + InjectCode((void*)(0x140502937), { 0x49, 0xc7, 0xc0 }); // MOV R8, blurAmount + InjectCode((void*)(0x14050293a), std::vector((uint8_t*)&blurAmount, (uint8_t*)((int64_t)&blurAmount + 4))); + InjectCode((void*)(0x14050293e), { 0xeb, 0x08 }); // JMP 0x140502948 + InjectCode((void*)(0x140502948), { 0x31, 0xd2 }); // XOR EDX,EDX + InjectCode((void*)(0x14050294a), { 0x49, 0xf7, 0xf0 }); // DIV (EDX:EAX,)R8 + + InjectCode((void*)(0x14050294d), { 0x89, 0x01 }); // MOV dword ptr [RCX], EAX + InjectCode((void*)(0x14050294f), { 0xc3 }); // RET + } + + // lag compensation + if (nLagCompensation > 0 && nLagCompensation <= 500) + { + InjectCode((void*)(0x14011e44e), { 0xf3, 0x0f, 0x10, 0x05, 0x8a, 0xcf, 0x9c, 0x00 }); // hijack xmm0 + InjectCode((void*)(0x14011e46b), { 0xf3, 0x0f, 0x11, 0x44, 0x24, 0x20 }); // get value from xmm0 instead of xmm1 + float startPos = (float)nLagCompensation / 1000.0f; + InjectCode((void*)(0x140aeB3e0), { *((uint8_t*)(&startPos)), *((uint8_t*)(&startPos) + 1), *((uint8_t*)(&startPos) + 2), *((uint8_t*)(&startPos) + 3) }); + + printf("[Patches] Lag Compensation: %f\n", startPos); + } + } }; \ No newline at end of file diff --git a/source-code/source/plugins/Patches/framework.h b/source-code/source/plugins/Patches/framework.h index 783b6e0..b5a510c 100644 --- a/source-code/source/plugins/Patches/framework.h +++ b/source-code/source/plugins/Patches/framework.h @@ -1,131 +1,131 @@ -#pragma once -#include "windows.h" -#include -#include - -std::string TrimString(const std::string& str, const std::string& whitespace) -{ - const size_t strBegin = str.find_first_not_of(whitespace); - - if (strBegin == std::string::npos) - return ""; - - const size_t strEnd = str.find_last_not_of(whitespace); - const size_t strRange = strEnd - strBegin + 1; - - return str.substr(strBegin, strRange); -} - -std::vector SplitString(const std::string& str, const std::string& delim) -{ - std::vector tokens; - size_t prev = 0, pos = 0; - do - { - pos = str.find(delim, prev); - if (pos == std::string::npos) - pos = str.length(); - - std::string token = str.substr(prev, pos - prev); - - if (!token.empty()) - tokens.push_back(token); - - prev = pos + delim.length(); - } while (pos < str.length() && prev < str.length()); - - return tokens; -} - -void InjectCode(void* address, const std::vector data) -{ - const size_t byteCount = data.size() * sizeof(uint8_t); - - DWORD oldProtect; - VirtualProtect(address, byteCount, PAGE_EXECUTE_READWRITE, &oldProtect); - memcpy(address, data.data(), byteCount); - VirtualProtect(address, byteCount, oldProtect, nullptr); -} - -// patchMovieExt will modify an extension to mp4 only if the file exists on disk as an mp4 -void patchMovieExt(std::string moviefile, void* address) -{ - bool isinmdata = 0; - try { - for (std::filesystem::path p : std::filesystem::directory_iterator("../mdata")) - { - if (std::filesystem::path(p).filename().string().at(0) != 'M' || std::filesystem::path(p).filename().string().length() > 4) continue; - if (std::filesystem::exists(p.string() + "/rom/movie/" + moviefile + ".mp4")) - { - isinmdata = 1; - //std::cout << "[Patches] Movie " << moviefile << ".mp4 found in M" << ss.str() << std::endl; - break; - } - } - } - catch (const std::filesystem::filesystem_error& e) { - std::cout << "[Patches] File system error " << e.what() << " " << e.path1() << " " << e.path2() << " " << e.code() << std::endl; - } - - if (isinmdata || std::filesystem::exists("../rom/movie/" + moviefile + ".mp4")) - { - InjectCode(address, { 0x6D, 0x70, 0x34 }); - std::cout << "[Patches] Movie " << moviefile << " patched to mp4\n"; - return; - } - //std::cout << "[Patches] Movie " << moviefile << " NOT patched to mp4\n"; - return; -} - -const LPCWSTR CONFIG_FILE = L".\\config.ini"; - -auto nCursor = GetPrivateProfileIntW(L"patches", L"cursor", TRUE, CONFIG_FILE); -auto nHideFreeplay = GetPrivateProfileIntW(L"patches", L"hide_freeplay", FALSE, CONFIG_FILE); -auto nFreeplay = GetPrivateProfileIntW(L"patches", L"freeplay", TRUE, CONFIG_FILE); -auto nPDLoaderText = GetPrivateProfileIntW(L"patches", L"pdloadertext", TRUE, CONFIG_FILE); -auto nStatusIcons = GetPrivateProfileIntW(L"patches", L"status_icons", 0, CONFIG_FILE); -auto nHidePVWatermark = GetPrivateProfileIntW(L"patches", L"hide_pv_watermark", FALSE, CONFIG_FILE); -auto nNoPVUi = GetPrivateProfileIntW(L"patches", L"no_pv_ui", FALSE, CONFIG_FILE); -auto nHideVolCtrl = GetPrivateProfileIntW(L"patches", L"hide_volume", FALSE, CONFIG_FILE); -auto nNoLyrics = GetPrivateProfileIntW(L"patches", L"no_lyrics", FALSE, CONFIG_FILE); -auto nNoMovies = GetPrivateProfileIntW(L"patches", L"no_movies", FALSE, CONFIG_FILE); -auto nMP4Movies = GetPrivateProfileIntW(L"patches", L"mp4_movies", FALSE, CONFIG_FILE); -auto nNoError = GetPrivateProfileIntW(L"patches", L"no_error", FALSE, CONFIG_FILE); -auto nNoTimer = GetPrivateProfileIntW(L"patches", L"no_timer", TRUE, CONFIG_FILE); -auto nNoTimerSprite = GetPrivateProfileIntW(L"patches", L"no_timer_sprite", TRUE, CONFIG_FILE); -auto nEStageManager = GetPrivateProfileIntW(L"patches", L"enhanced_stage_manager", 0, CONFIG_FILE); -auto nEStageManagerEncore = GetPrivateProfileIntW(L"patches", L"enhanced_stage_manager_encore", TRUE, CONFIG_FILE); -auto nUnlockPseudo = GetPrivateProfileIntW(L"patches", L"unlock_pseudo", FALSE, CONFIG_FILE); -auto nCard = GetPrivateProfileIntW(L"patches", L"card", TRUE, CONFIG_FILE); -auto nHardwareSlider = GetPrivateProfileIntW(L"patches", L"hardware_slider", FALSE, CONFIG_FILE); -auto nOGLPatchA = GetPrivateProfileIntW(L"patches", L"opengl_patch_a", FALSE, CONFIG_FILE); -auto nOGLPatchB = GetPrivateProfileIntW(L"patches", L"opengl_patch_b", FALSE, CONFIG_FILE); -auto nTAA = GetPrivateProfileIntW(L"graphics", L"taa", TRUE, CONFIG_FILE); -auto nMLAA = GetPrivateProfileIntW(L"graphics", L"mlaa", TRUE, CONFIG_FILE); -auto nDoF = GetPrivateProfileIntW(L"graphics", L"dof", TRUE, CONFIG_FILE); -auto nMAG = GetPrivateProfileIntW(L"graphics", L"mag", 0, CONFIG_FILE); -auto nGamma = GetPrivateProfileIntW(L"graphics", L"gamma", 100, CONFIG_FILE); -auto nStereo = GetPrivateProfileIntW(L"patches", L"stereo", TRUE, CONFIG_FILE); -auto nCustomPatches = GetPrivateProfileIntW(L"patches", L"custom_patches", TRUE, CONFIG_FILE); -auto nQuickStart = GetPrivateProfileIntW(L"patches", L"quick_start", 1, CONFIG_FILE); -auto nNoScrollingSfx = GetPrivateProfileIntW(L"patches", L"no_scrolling_sfx", FALSE, CONFIG_FILE); -auto nNoHandScaling = GetPrivateProfileIntW(L"patches", L"no_hand_scaling", FALSE, CONFIG_FILE); -auto nDefaultHandSize = GetPrivateProfileIntW(L"patches", L"default_hand_size", 0, CONFIG_FILE); -auto nSingMissed = GetPrivateProfileIntW(L"patches", L"sing_missed", FALSE, CONFIG_FILE); -auto nForceMouth = GetPrivateProfileIntW(L"patches", L"force_mouth", 0, CONFIG_FILE); -auto nForceExpressions = GetPrivateProfileIntW(L"patches", L"force_expressions", 0, CONFIG_FILE); -auto nForceLook = GetPrivateProfileIntW(L"patches", L"force_look", 0, CONFIG_FILE); -auto nNpr1 = GetPrivateProfileIntW(L"graphics", L"npr1", 0, CONFIG_FILE); -auto nReflections = GetPrivateProfileIntW(L"graphics", L"reflections", TRUE, CONFIG_FILE); -auto nShadows = GetPrivateProfileIntW(L"graphics", L"shadows", TRUE, CONFIG_FILE); -auto nPunchthrough = GetPrivateProfileIntW(L"graphics", L"punchthrough", TRUE, CONFIG_FILE); -auto nGlare = GetPrivateProfileIntW(L"graphics", L"glare", TRUE, CONFIG_FILE); -auto nShader = GetPrivateProfileIntW(L"graphics", L"shader", TRUE, CONFIG_FILE); -auto n2D = GetPrivateProfileIntW(L"graphics", L"2D", FALSE, CONFIG_FILE); -auto nNoDelete = GetPrivateProfileIntW(L"patches", L"prevent_data_deletion", FALSE, CONFIG_FILE); -auto nReflectResWidth = GetPrivateProfileIntW(L"graphics", L"reflect_res_width", 512, CONFIG_FILE); -auto nReflectResHeight = GetPrivateProfileIntW(L"graphics", L"reflect_res_height", 256, CONFIG_FILE); -auto nRefractResWidth = GetPrivateProfileIntW(L"graphics", L"refract_res_width", 512, CONFIG_FILE); -auto nRefractResHeight = GetPrivateProfileIntW(L"graphics", L"refract_res_height", 256, CONFIG_FILE); -auto nLagCompensation = GetPrivateProfileIntW(L"graphics", L"lag_compensation", 0, CONFIG_FILE); +#pragma once +#include "windows.h" +#include +#include + +std::string TrimString(const std::string& str, const std::string& whitespace) +{ + const size_t strBegin = str.find_first_not_of(whitespace); + + if (strBegin == std::string::npos) + return ""; + + const size_t strEnd = str.find_last_not_of(whitespace); + const size_t strRange = strEnd - strBegin + 1; + + return str.substr(strBegin, strRange); +} + +std::vector SplitString(const std::string& str, const std::string& delim) +{ + std::vector tokens; + size_t prev = 0, pos = 0; + do + { + pos = str.find(delim, prev); + if (pos == std::string::npos) + pos = str.length(); + + std::string token = str.substr(prev, pos - prev); + + if (!token.empty()) + tokens.push_back(token); + + prev = pos + delim.length(); + } while (pos < str.length() && prev < str.length()); + + return tokens; +} + +void InjectCode(void* address, const std::vector data) +{ + const size_t byteCount = data.size() * sizeof(uint8_t); + + DWORD oldProtect; + VirtualProtect(address, byteCount, PAGE_EXECUTE_READWRITE, &oldProtect); + memcpy(address, data.data(), byteCount); + VirtualProtect(address, byteCount, oldProtect, nullptr); +} + +// patchMovieExt will modify an extension to mp4 only if the file exists on disk as an mp4 +void patchMovieExt(std::string moviefile, void* address) +{ + bool isinmdata = 0; + try { + for (std::filesystem::path p : std::filesystem::directory_iterator("../mdata")) + { + if (std::filesystem::path(p).filename().string().at(0) != 'M' || std::filesystem::path(p).filename().string().length() > 4) continue; + if (std::filesystem::exists(p.string() + "/rom/movie/" + moviefile + ".mp4")) + { + isinmdata = 1; + //std::cout << "[Patches] Movie " << moviefile << ".mp4 found in M" << ss.str() << std::endl; + break; + } + } + } + catch (const std::filesystem::filesystem_error& e) { + std::cout << "[Patches] File system error " << e.what() << " " << e.path1() << " " << e.path2() << " " << e.code() << std::endl; + } + + if (isinmdata || std::filesystem::exists("../rom/movie/" + moviefile + ".mp4")) + { + InjectCode(address, { 0x6D, 0x70, 0x34 }); + std::cout << "[Patches] Movie " << moviefile << " patched to mp4\n"; + return; + } + //std::cout << "[Patches] Movie " << moviefile << " NOT patched to mp4\n"; + return; +} + +const LPCWSTR CONFIG_FILE = L".\\config.ini"; + +auto nCursor = GetPrivateProfileIntW(L"patches", L"cursor", TRUE, CONFIG_FILE); +auto nHideFreeplay = GetPrivateProfileIntW(L"patches", L"hide_freeplay", FALSE, CONFIG_FILE); +auto nFreeplay = GetPrivateProfileIntW(L"patches", L"freeplay", TRUE, CONFIG_FILE); +auto nPDLoaderText = GetPrivateProfileIntW(L"patches", L"pdloadertext", TRUE, CONFIG_FILE); +auto nStatusIcons = GetPrivateProfileIntW(L"patches", L"status_icons", 0, CONFIG_FILE); +auto nHidePVWatermark = GetPrivateProfileIntW(L"patches", L"hide_pv_watermark", FALSE, CONFIG_FILE); +auto nNoPVUi = GetPrivateProfileIntW(L"patches", L"no_pv_ui", FALSE, CONFIG_FILE); +auto nHideVolCtrl = GetPrivateProfileIntW(L"patches", L"hide_volume", FALSE, CONFIG_FILE); +auto nNoLyrics = GetPrivateProfileIntW(L"patches", L"no_lyrics", FALSE, CONFIG_FILE); +auto nNoMovies = GetPrivateProfileIntW(L"patches", L"no_movies", FALSE, CONFIG_FILE); +auto nMP4Movies = GetPrivateProfileIntW(L"patches", L"mp4_movies", FALSE, CONFIG_FILE); +auto nNoError = GetPrivateProfileIntW(L"patches", L"no_error", FALSE, CONFIG_FILE); +auto nNoTimer = GetPrivateProfileIntW(L"patches", L"no_timer", TRUE, CONFIG_FILE); +auto nNoTimerSprite = GetPrivateProfileIntW(L"patches", L"no_timer_sprite", TRUE, CONFIG_FILE); +auto nEStageManager = GetPrivateProfileIntW(L"patches", L"enhanced_stage_manager", 0, CONFIG_FILE); +auto nEStageManagerEncore = GetPrivateProfileIntW(L"patches", L"enhanced_stage_manager_encore", TRUE, CONFIG_FILE); +auto nUnlockPseudo = GetPrivateProfileIntW(L"patches", L"unlock_pseudo", FALSE, CONFIG_FILE); +auto nCard = GetPrivateProfileIntW(L"patches", L"card", TRUE, CONFIG_FILE); +auto nHardwareSlider = GetPrivateProfileIntW(L"patches", L"hardware_slider", FALSE, CONFIG_FILE); +auto nOGLPatchA = GetPrivateProfileIntW(L"patches", L"opengl_patch_a", FALSE, CONFIG_FILE); +auto nOGLPatchB = GetPrivateProfileIntW(L"patches", L"opengl_patch_b", FALSE, CONFIG_FILE); +auto nTAA = GetPrivateProfileIntW(L"graphics", L"taa", TRUE, CONFIG_FILE); +auto nMLAA = GetPrivateProfileIntW(L"graphics", L"mlaa", TRUE, CONFIG_FILE); +auto nDoF = GetPrivateProfileIntW(L"graphics", L"dof", TRUE, CONFIG_FILE); +auto nMAG = GetPrivateProfileIntW(L"graphics", L"mag", 0, CONFIG_FILE); +auto nGamma = GetPrivateProfileIntW(L"graphics", L"gamma", 100, CONFIG_FILE); +auto nStereo = GetPrivateProfileIntW(L"patches", L"stereo", TRUE, CONFIG_FILE); +auto nCustomPatches = GetPrivateProfileIntW(L"patches", L"custom_patches", TRUE, CONFIG_FILE); +auto nQuickStart = GetPrivateProfileIntW(L"patches", L"quick_start", 1, CONFIG_FILE); +auto nNoScrollingSfx = GetPrivateProfileIntW(L"patches", L"no_scrolling_sfx", FALSE, CONFIG_FILE); +auto nNoHandScaling = GetPrivateProfileIntW(L"patches", L"no_hand_scaling", FALSE, CONFIG_FILE); +auto nDefaultHandSize = GetPrivateProfileIntW(L"patches", L"default_hand_size_uint", 0, CONFIG_FILE); +auto nSingMissed = GetPrivateProfileIntW(L"patches", L"sing_missed", FALSE, CONFIG_FILE); +auto nForceMouth = GetPrivateProfileIntW(L"patches", L"force_mouth", 0, CONFIG_FILE); +auto nForceExpressions = GetPrivateProfileIntW(L"patches", L"force_expressions", 0, CONFIG_FILE); +auto nForceLook = GetPrivateProfileIntW(L"patches", L"force_look", 0, CONFIG_FILE); +auto nNpr1 = GetPrivateProfileIntW(L"graphics", L"npr1", 0, CONFIG_FILE); +auto nReflections = GetPrivateProfileIntW(L"graphics", L"reflections", TRUE, CONFIG_FILE); +auto nShadows = GetPrivateProfileIntW(L"graphics", L"shadows", TRUE, CONFIG_FILE); +auto nPunchthrough = GetPrivateProfileIntW(L"graphics", L"punchthrough", TRUE, CONFIG_FILE); +auto nGlare = GetPrivateProfileIntW(L"graphics", L"glare", TRUE, CONFIG_FILE); +auto nShader = GetPrivateProfileIntW(L"graphics", L"shader", TRUE, CONFIG_FILE); +auto n2D = GetPrivateProfileIntW(L"graphics", L"2D", FALSE, CONFIG_FILE); +auto nNoDelete = GetPrivateProfileIntW(L"patches", L"prevent_data_deletion", FALSE, CONFIG_FILE); +auto nReflectResWidth = GetPrivateProfileIntW(L"graphics", L"reflect_res_width", 512, CONFIG_FILE); +auto nReflectResHeight = GetPrivateProfileIntW(L"graphics", L"reflect_res_height", 256, CONFIG_FILE); +auto nRefractResWidth = GetPrivateProfileIntW(L"graphics", L"refract_res_width", 512, CONFIG_FILE); +auto nRefractResHeight = GetPrivateProfileIntW(L"graphics", L"refract_res_height", 256, CONFIG_FILE); +auto nLagCompensation = GetPrivateProfileIntW(L"graphics", L"lag_compensation", 0, CONFIG_FILE); auto nUseDivahookBat = GetPrivateProfileIntW(L"launcher", L"use_divahook_bat", FALSE, CONFIG_FILE); \ No newline at end of file