From 5f8aabbe14669720a900ec7fca645e09324e0036 Mon Sep 17 00:00:00 2001 From: Jakob Gahde Date: Tue, 8 Aug 2023 02:18:25 +0200 Subject: [PATCH 01/15] Add Windows installer --- .../actions/create-package/create-package.sh | 41 +- .../install-dependencies.sh | 4 +- app/data/pencil2d.rc | 55 ++- core_lib/src/external/win32/win32.cpp | 10 + util/common.pri | 5 +- util/installer/cog-hover.png | Bin 0 -> 254 bytes util/installer/cog-hover@2x.png | Bin 0 -> 509 bytes util/installer/cog.png | Bin 0 -> 302 bytes util/installer/cog@2x.png | Bin 0 -> 582 bytes util/installer/pencil2d.bundle.wxs | 68 ++++ util/installer/pencil2d.cpp | 363 ++++++++++++++++++ util/installer/pencil2d.def | 3 + util/installer/pencil2d.ico | Bin 0 -> 285478 bytes util/installer/pencil2d.png | Bin 0 -> 32006 bytes util/installer/pencil2d.pro | 21 + util/installer/pencil2d.thm | 104 +++++ util/installer/pencil2d.wxl | 60 +++ util/installer/pencil2d.wxs | 268 +++++++++++++ util/installer/pencil2d@2x.png | Bin 0 -> 70773 bytes util/installer/win_pcl_icon.ico | Bin 0 -> 313398 bytes util/installer/win_pcl_icon.xcf | Bin 0 -> 123138 bytes util/installer/win_pclx_icon.ico | Bin 0 -> 313398 bytes 22 files changed, 990 insertions(+), 12 deletions(-) create mode 100644 util/installer/cog-hover.png create mode 100644 util/installer/cog-hover@2x.png create mode 100644 util/installer/cog.png create mode 100644 util/installer/cog@2x.png create mode 100644 util/installer/pencil2d.bundle.wxs create mode 100644 util/installer/pencil2d.cpp create mode 100644 util/installer/pencil2d.def create mode 100644 util/installer/pencil2d.ico create mode 100644 util/installer/pencil2d.png create mode 100644 util/installer/pencil2d.pro create mode 100644 util/installer/pencil2d.thm create mode 100644 util/installer/pencil2d.wxl create mode 100644 util/installer/pencil2d.wxs create mode 100644 util/installer/pencil2d@2x.png create mode 100644 util/installer/win_pcl_icon.ico create mode 100644 util/installer/win_pcl_icon.xcf create mode 100644 util/installer/win_pclx_icon.ico diff --git a/.github/actions/create-package/create-package.sh b/.github/actions/create-package/create-package.sh index 71a5ddf9f8..51554c857b 100755 --- a/.github/actions/create-package/create-package.sh +++ b/.github/actions/create-package/create-package.sh @@ -40,7 +40,7 @@ wayland-decoration-client,wayland-graphics-integration-client,wayland-shell-inte ${update_info} \ -appimage local qtsuffix="-qt${INPUT_QT}" - local output_name="pencil2d${qtsuffix/-qt5/}-linux-$1-$(date +%F)" + local output_name="pencil2d${qtsuffix/-qt5/}-linux-$3" mv Pencil2D*.AppImage "$output_name.AppImage" mv Pencil2D*.AppImage.zsync "$output_name.AppImage.zsync" \ && sed -i '1,/^$/s/^\(Filename\|URL\): .*$/\1: '"$output_name.AppImage/" "$output_name.AppImage.zsync" \ @@ -84,8 +84,8 @@ create_package_macos() { popd >/dev/null echo "Create ZIP" local qtsuffix="-qt${INPUT_QT}" - bsdtar caf "pencil2d${qtsuffix/-qt5/}-mac-$1-$(date +%F).zip" Pencil2D - echo "output-basename=pencil2d${qtsuffix/-qt5/}-mac-$1-$(date +%F)" > "${GITHUB_OUTPUT}" + bsdtar caf "pencil2d${qtsuffix/-qt5/}-mac-$3.zip" Pencil2D + echo "output-basename=pencil2d${qtsuffix/-qt5/}-mac-$3" > "${GITHUB_OUTPUT}" } create_package_windows() { @@ -110,13 +110,38 @@ create_package_windows() { echo "Copy OpenSSL DLLs" curl -fsSLO https://download.firedaemon.com/FireDaemon-OpenSSL/openssl-1.1.1w.zip "${WINDIR}\\System32\\tar" xf openssl-1.1.1w.zip - local xbits="x${platform#win}" - local _xbits="-${xbits}" + local wordsize="${platform#win}" + local xbits="x${wordsize}" + local _xbits="-x${wordsize}" cp "openssl-1.1\\${xbits/32/86}\\bin\\lib"{ssl,crypto}"-1_1${_xbits/-x32/}.dll" Pencil2D/ + echo "Create Installer" + env -C ../util/installer qmake CONFIG-=debug_and_release CONFIG+=release + env -C ../util/installer "PATH=${PATH/\/usr\/bin:/}" nmake + local versiondefines="-d Edition=Nightly -d NightlyBuildNumber=$1 -d NightlyBuildTimestamp=$(date +%F)" + if [ "$IS_RELEASE" = "true" ]; then + versiondefines="-d Edition=Release -d Version=$2" + fi + wix build -arch "x${wordsize/32/86}" -dcl high -b ../util/installer -b Pencil2D \ + -d "ProductCode=$(python -c "import uuid; print(str(uuid.uuid5(uuid.NAMESPACE_URL, '-Nhttps://github.com/${GITHUB_REPOSITORY}/commit/${GITHUB_SHA}')).upper())")" \ + $versiondefines \ + -out "pencil2d-${platform}-$3.msi" \ + ../util/installer/pencil2d.wxs + wix build -arch "x${wordsize/32/86}" -dcl high -sw1133 -b ../util/installer -b Pencil2D \ + -ext WixToolset.Util.wixext -ext WixToolset.Bal.wixext \ + -d "ProductCode=$(python -c "import uuid; print(str(uuid.uuid5(uuid.NAMESPACE_URL, '-Nhttps://github.com/${GITHUB_REPOSITORY}/commit/${GITHUB_SHA}')).upper())")" \ + $versiondefines \ + -out "pencil2d-${platform}-$3.exe" \ + ../util/installer/pencil2d.bundle.wxs echo "Create ZIP" local qtsuffix="-qt${INPUT_QT}" - "${WINDIR}\\System32\\tar" caf "pencil2d${qtsuffix/-qt5/}-${platform}-$1-$(date +%F).zip" Pencil2D - echo "output-basename=pencil2d${qtsuffix/-qt5/}-${platform}-$1-$(date +%F)" > "${GITHUB_OUTPUT}" + "${WINDIR}\\System32\\tar" caf "pencil2d${qtsuffix/-qt5/}-${platform}-$3.zip" Pencil2D + echo "output-basename=pencil2d${qtsuffix/-qt5/}-${platform}-$3" > "${GITHUB_OUTPUT}" } -"create_package_$(echo $RUNNER_OS | tr '[A-Z]' '[a-z]')" "${GITHUB_RUN_NUMBER}" +eval "$(grep '^VERSION =' ../util/common.pri | tr -d '[:blank:]')" +buildversion="${GITHUB_RUN_NUMBER}-$(date +%F)" +if [ "$IS_RELEASE" = "true" ]; then + buildversion="${VERSION}" +fi + +"create_package_$(echo $RUNNER_OS | tr '[A-Z]' '[a-z]')" "${GITHUB_RUN_NUMBER}" "${VERSION}" "${buildversion}" diff --git a/.github/actions/install-dependencies/install-dependencies.sh b/.github/actions/install-dependencies/install-dependencies.sh index d078452584..5d5f3bdf42 100755 --- a/.github/actions/install-dependencies/install-dependencies.sh +++ b/.github/actions/install-dependencies/install-dependencies.sh @@ -51,7 +51,9 @@ setup_macos() { } setup_windows() { - : # Nothing to do here + dotnet tool install -g wix + wix extension add -g WixToolset.Util.wixext WixToolset.Bal.wixext + nuget install -x -OutputDirectory util/installer WixToolset.BalUtil } "setup_$(echo "${RUNNER_OS}" | tr '[A-Z]' '[a-z]')" diff --git a/app/data/pencil2d.rc b/app/data/pencil2d.rc index 1a9c57b9b6..ac10920b40 100644 --- a/app/data/pencil2d.rc +++ b/app/data/pencil2d.rc @@ -1 +1,54 @@ -IDI_ICON1 ICON DISCARDABLE "pencil2d.ico" +#include + +#if defined(PENCIL2D_RELEASE_BUILD) +#define BUILD_FILEFLAG 0 +#elif defined(PENCIL2D_NIGHTLY_BUILD) +#define BUILD_FILEFLAG VS_FF_PRERELEASE +#else +#define BUILD_FILEFLAG VS_FF_PRIVATEBUILD +#endif + +#if defined(QT_NO_DEBUG) +#define DEBUG_FILEFLAG 0 +#else +#define DEBUG_FILEFLAG VS_FF_DEBUG +#endif + +IDI_ICON1 ICON "pencil2d.ico" + +VS_VERSION_INFO VERSIONINFO +FILEVERSION APP_VERSION_RC +PRODUCTVERSION APP_VERSION_RC +FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +FILEFLAGS DEBUG_FILEFLAG|BUILD_FILEFLAG +FILEOS VOS_NT_WINDOWS32 +FILETYPE VFT_APP +{ + BLOCK "StringFileInfo" + { + BLOCK "040904B0" + { + VALUE "ProductName", "Pencil2D" + VALUE "ProductVersion", APP_VERSION + VALUE "CompanyName", "The Pencil2D Team" + VALUE "LegalCopyright", "\xA9 The Pencil2D Team" + VALUE "FileDescription", "Pencil2D" + VALUE "FileVersion", APP_VERSION + VALUE "InternalName", "pencil2d" + VALUE "OriginalFilename", "pencil2d.exe" + VALUE "PrivateBuild", "Private Build" + } + } + + BLOCK "VarFileInfo" + { + VALUE "Translation", 0x0409 0x04B0 + } +} + +STRINGTABLE +LANGUAGE LANG_ENGLISH, SUBLANG_NEUTRAL +{ + 0 "Pencil2D Animation" + 1 "Pencil2D Animation (Old Format)" +} diff --git a/core_lib/src/external/win32/win32.cpp b/core_lib/src/external/win32/win32.cpp index eef2c17377..0c3bda1a1a 100644 --- a/core_lib/src/external/win32/win32.cpp +++ b/core_lib/src/external/win32/win32.cpp @@ -21,6 +21,8 @@ GNU General Public License for more details. #include #include +#include + #include "pencildef.h" namespace PlatformHandler @@ -29,6 +31,14 @@ namespace PlatformHandler bool isDarkMode() { return false; }; void initialise() { +#if defined(PENCIL2D_RELEASE_BUILD) + SetCurrentProcessExplicitAppUserModelID(L"Pencil2D.Pencil2D.Release"); +#elif defined(PENCIL2D_NIGHTLY_BUILD) + SetCurrentProcessExplicitAppUserModelID(L"Pencil2D.Pencil2D.Nightly"); +#else + SetCurrentProcessExplicitAppUserModelID(L"Pencil2D.Pencil2D"); +#endif + #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) // Temporary solution for high DPI displays // EnableHighDpiScaling is a just in case mechanism in the event that we diff --git a/util/common.pri b/util/common.pri index f23947401b..e4d4ddec83 100644 --- a/util/common.pri +++ b/util/common.pri @@ -1,5 +1,6 @@ VERSION = 0.6.6 DEFINES += APP_VERSION=\\\"$$VERSION\\\" +DEFINES += APP_VERSION_RC=$$replace(VERSION, "\.", ",") PENCIL2D_NIGHTLY { DEFINES += PENCIL2D_NIGHTLY_BUILD @@ -17,9 +18,9 @@ win32-g++ { } win32-msvc* { - QMAKE_CXXFLAGS += /MP /utf-8 + QMAKE_CXXFLAGS += /MP /utf-8 CONFIG(release,debug|release) { - QMAKE_CXXFLAGS += /Gy /GL + QMAKE_CXXFLAGS += /Gy /GL CONFIG += ltcg CONFIG += force_debug_info } diff --git a/util/installer/cog-hover.png b/util/installer/cog-hover.png new file mode 100644 index 0000000000000000000000000000000000000000..1b3d11aba9b0d15519d0f6022832164b99525f3f GIT binary patch literal 254 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6j(WN{hG>Yg9<MEsj*k*7*=Ue&fzwm2l4LIG&SAo;F@>=F@pRjr@g{Pg0qr zqVD;~XA+OzUhks$D)UqhZeOipE|=aH^_kQwW*cIX0W&rR}%KPSYSx25d( xr0Kockdg0005RNkl&aLTs762Mk7BR~I0icjR zimlbE%qHzB?he)KOREkvo52S4MU5r`Q=v|-G8zrmO=SJRjg z;QfC&jvGBE%z%W!xM}p&7(l6XLlv^|%Qq(8Gr zUFJjzQ)6khoGGeD&%_q(AfKEt&pct`n%1rZ7Hk!hPkoW{iP!>sB*UBp4BLKCCS|~y zZNQEUaB-XF`7}SZH_3AQ3!;;21cD3t$-~Wqa_?>&^sq-9!4*a3#^R;PTFpp+<&+Qg z85@h1x@A(KH)PXXx2)-DcHOxO|8IkDP4D#$M<%C2*E{1A00000NkvXXu0mjfn)Kul literal 0 HcmV?d00001 diff --git a/util/installer/cog.png b/util/installer/cog.png new file mode 100644 index 0000000000000000000000000000000000000000..90daf5ba8826286d142fabc95c020098ffdd3d9c GIT binary patch literal 302 zcmV+}0nz@6P)NklQ#)X+N?WRkdg0006FNklQ0bq%&AGmz%(-T{pOFp7eVcFEz?Ku0dmPNWkSmI2K!#ZE zB_!n^Q8dHg7bNzTd~p;5a@S(jf(PbJM=>C$o>T*JV$i+tog@R^r*WYLV(vncJkW;` z3wc%;%6{eT%Iycj-MPOpR;}T zY&(eKtbyt98;az%1{P%PX{^AwLYDuOJ2_t+Z$ir5m!}FZMAUK)qJ>f#MoI*hH0U1r zox3-0Lf(YjeYt-yg4qhgfZT~B<;I0*1{8AUz9q?kpRiztg+M&11xjumYKb(HWCK>C z7?3ZXdl^UZiM^=31j}xSKokWQ)*z{)xseTQz+(L!TD+TuGH3hbZUV(f&iP^ytQAXc zd4T~uU38)tFb!c*UIf;P1sxVjBWLs+T{0@yyrpmh4v + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/util/installer/pencil2d.cpp b/util/installer/pencil2d.cpp new file mode 100644 index 0000000000..bf5460fc84 --- /dev/null +++ b/util/installer/pencil2d.cpp @@ -0,0 +1,363 @@ +#include +#include + +#include +#include + +#include "dutil.h" +#include "dictutil.h" +#include "locutil.h" +#include "pathutil.h" +#include "strutil.h" +#include "thmutil.h" +#include "xmlutil.h" + +#include "BootstrapperEngine.h" +#include "BootstrapperApplication.h" +#include "BAFunctions.h" + +#include "IBootstrapperEngine.h" +#include "IBootstrapperApplication.h" +#include "IBAFunctions.h" + +#include "BalBaseBAFunctions.h" +#include "BalBaseBAFunctionsProc.h" + +#include "balutil.h" + +enum PENCIL2DBAFUNCTIONS_CONTROL +{ + PENCIL2DBAFUNCTIONS_PROGRESS_ACTION_TEXT = THEME_FIRST_ASSIGN_CONTROL_ID, + + LAST_PENCIL2DBAFUNCTIONS_CONTROL, +}; + +class Pencil2DBAFunctions : public CBalBaseBAFunctions +{ +public: + Pencil2DBAFunctions( + __in HMODULE hModule, + __in IBootstrapperEngine* pEngine, + __in const BA_FUNCTIONS_CREATE_ARGS* pArgs, + __in WIX_LOCALIZATION* pWixLoc + ) : CBalBaseBAFunctions(hModule, pEngine, pArgs), m_pWixLoc(pWixLoc) + { + } + + ~Pencil2DBAFunctions() + { + LocFree(m_pWixLoc); + } + + virtual STDMETHODIMP OnThemeControlLoading( + __in LPCWSTR wzName, + __inout BOOL* pfProcessed, + __inout WORD* pwId, + __inout DWORD* pdwAutomaticBehaviorType + ) + { + if (::CompareStringW(LOCALE_NEUTRAL, 0, wzName, -1, L"ProgressActionText", -1) == CSTR_EQUAL) + { + *pfProcessed = TRUE; + *pwId = PENCIL2DBAFUNCTIONS_PROGRESS_ACTION_TEXT; + *pdwAutomaticBehaviorType = THEME_CONTROL_AUTOMATIC_BEHAVIOR_EXCLUDE_ENABLED | THEME_CONTROL_AUTOMATIC_BEHAVIOR_EXCLUDE_VISIBLE | THEME_CONTROL_AUTOMATIC_BEHAVIOR_EXCLUDE_ACTION | THEME_CONTROL_AUTOMATIC_BEHAVIOR_EXCLUDE_VALUE; + return S_OK; + } + + return __super::OnThemeControlLoading(wzName, pfProcessed, pwId, pdwAutomaticBehaviorType); + } + + virtual STDMETHODIMP OnThemeControlLoaded( + __in LPCWSTR wzName, + __in WORD wId, + __in HWND hWnd, + __inout BOOL* pfProcessed + ) + { + HRESULT hr = S_OK; + + WCHAR szClass[countof(PROGRESS_CLASSW)] = L""; + if (!::GetClassNameW(hWnd, szClass, countof(szClass))) + { + BalExitOnLastError(hr, "Failed to get window class."); + } + + if (::CompareStringW(LOCALE_NEUTRAL, 0, szClass, -1, PROGRESS_CLASSW, -1) == CSTR_EQUAL && + ::GetWindowLongPtrW(hWnd, GWL_STYLE) & PBS_MARQUEE) + { + ::SendMessageW(hWnd, PBM_SETMARQUEE, TRUE, 0); + } + + if (wId == PENCIL2DBAFUNCTIONS_PROGRESS_ACTION_TEXT) + { + if (m_hwndControlProgressActionText) + { + BalLog(BOOTSTRAPPER_LOG_LEVEL_ERROR, "Duplicate control name: %ls", wzName); + } + else + { + m_hwndControlProgressActionText = hWnd; + } + + *pfProcessed = TRUE; + ExitFunction(); + } + + hr = __super::OnThemeControlLoaded(wzName, wId, hWnd, pfProcessed); + + LExit: + return hr; + } + + virtual STDMETHODIMP OnDetectRelatedBundle( + __in_z LPCWSTR wzBundleId, + __in BOOTSTRAPPER_RELATION_TYPE relationType, + __in_z LPCWSTR wzBundleTag, + __in BOOL fPerMachine, + __in_z LPCWSTR wzVersion, + __in BOOL fMissingFromCache, + __inout BOOL* pfCancel + ) + { + LPWSTR wzValue = NULL; + LONGLONG llValue = 0; + + BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Trying to recover installation options from related bundle %ls.", wzBundleId); + if (SUCCEEDED(BalGetRelatedBundleVariable(wzBundleId, L"InstallFolder", &wzValue)) && wzValue) + { + BalSetStringVariable(L"InstallFolder", wzValue, TRUE); + BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Recovered install folder: %ls.", wzValue); + } + + if (SUCCEEDED(BalGetRelatedBundleVariable(wzBundleId, L"DesktopShortcut", &wzValue)) && wzValue) + { + if (SUCCEEDED(StrStringToInt64(wzValue, 0, &llValue))) + { + BalSetNumericVariable(L"DesktopShortcut", llValue); + BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Recovered desktop shortcut option: %lld.", llValue); + } + else + { + BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Failed to convert desktop shortcut option '%ls' from related bundle to number, ignoring.", wzValue); + } + } + + return __super::OnDetectRelatedBundle(wzBundleId, relationType, wzBundleTag, fPerMachine, wzVersion, fMissingFromCache, pfCancel); + } + + virtual STDMETHODIMP OnPauseAutomaticUpdatesBegin() + { + if (m_hwndControlProgressActionText) { + LOC_STRING* pLocString = NULL; + LocGetString(m_pWixLoc, L"#(loc.PauseAutomaticUpdatesMessage)", &pLocString); + LPWSTR sczFormattedString = NULL; + if (pLocString) + { + BalFormatString(pLocString->wzText, &sczFormattedString); + } + ::SetWindowTextW(m_hwndControlProgressActionText, sczFormattedString ? sczFormattedString : L"Pausing Windows automatic updates"); + } + + return __super::OnPauseAutomaticUpdatesBegin(); + } + + virtual STDMETHODIMP OnSystemRestorePointBegin() + { + if (m_hwndControlProgressActionText) { + LOC_STRING* pLocString = NULL; + LocGetString(m_pWixLoc, L"#(loc.SystemRestorePointMessage)", &pLocString); + LPWSTR sczFormattedString = NULL; + if (pLocString) + { + BalFormatString(pLocString->wzText, &sczFormattedString); + } + ::SetWindowTextW(m_hwndControlProgressActionText, sczFormattedString ? sczFormattedString : L"Creating system restore point"); + } + + return __super::OnSystemRestorePointBegin(); + } + + virtual STDMETHODIMP OnCacheBegin( + __inout BOOL* pfCancel + ) + { + if (m_hwndControlProgressActionText) { + LOC_STRING* pLocString = NULL; + LocGetString(m_pWixLoc, L"#(loc.CacheMessage)", &pLocString); + LPWSTR sczFormattedString = NULL; + if (pLocString) + { + BalFormatString(pLocString->wzText, &sczFormattedString); + } + ::SetWindowTextW(m_hwndControlProgressActionText, sczFormattedString ? sczFormattedString : L"Preparing files"); + } + + return __super::OnCacheBegin(pfCancel); + } + + virtual STDMETHODIMP OnExecutePackageBegin( + __in_z LPCWSTR wzPackageId, + __in BOOL fExecute, + __in BOOTSTRAPPER_ACTION_STATE action, + __in INSTALLUILEVEL uiLevel, + __in BOOL fDisableExternalUiHandler, + __inout BOOL* pfCancel + ) + { + if (m_hwndControlProgressActionText) { + LOC_STRING* pLocString = NULL; + switch (action) { + case BOOTSTRAPPER_ACTION_STATE_UNINSTALL: + LocGetString(m_pWixLoc, L"#(loc.ExecuteUninstallPackagesMessage)", &pLocString); + break; + case BOOTSTRAPPER_ACTION_STATE_INSTALL: + LocGetString(m_pWixLoc, L"#(loc.ExecuteInstallPackagesMessage)", &pLocString); + break; + case BOOTSTRAPPER_ACTION_STATE_MODIFY: + LocGetString(m_pWixLoc, L"#(loc.ExecuteModifyPackagesMessage)", &pLocString); + break; + case BOOTSTRAPPER_ACTION_STATE_REPAIR: + LocGetString(m_pWixLoc, L"#(loc.ExecuteRepairPackagesMessage)", &pLocString); + break; + case BOOTSTRAPPER_ACTION_STATE_MINOR_UPGRADE: + LocGetString(m_pWixLoc, L"#(loc.ExecuteUpgradePackagesMessage)", &pLocString); + break; + } + + LPWSTR sczFormattedString = NULL; + if (pLocString) + { + BalFormatString(pLocString->wzText, &sczFormattedString); + } + + ::SetWindowTextW(m_hwndControlProgressActionText, sczFormattedString ? sczFormattedString : L"Processing packages"); + } + else + { + BalLog(BOOTSTRAPPER_LOG_LEVEL_ERROR, "Don't have progress control!"); + } + + return __super::OnExecutePackageBegin(wzPackageId, fExecute, action, uiLevel, fDisableExternalUiHandler, pfCancel); + } + + virtual STDMETHODIMP OnExecuteMsiMessage( + __in_z LPCWSTR wzPackageId, + __in INSTALLMESSAGE messageType, + __in DWORD dwUIHint, + __in_z LPCWSTR wzMessage, + __in DWORD cData, + __in_ecount_z_opt(cData) LPCWSTR* rgwzData, + __in int nRecommendation, + __inout int* pResult + ) + { + if (messageType == INSTALLMESSAGE_ACTIONSTART && cData >= 3) + { + if (m_hwndControlProgressActionText) + { + // Second field contains human-readable action description + ::SetWindowTextW(m_hwndControlProgressActionText, rgwzData[1]); + } + } + + return __super::OnExecuteMsiMessage(wzPackageId, messageType, dwUIHint, wzMessage, cData, rgwzData, nRecommendation, pResult); + } + + virtual STDMETHODIMP OnExecuteComplete( + __in HRESULT hrStatus + ) + { + if (m_hwndControlProgressActionText) + { + ::SetWindowTextW(m_hwndControlProgressActionText, L""); + } + + return __super::OnExecuteComplete(hrStatus); + } + +private: + WIX_LOCALIZATION *m_pWixLoc = NULL; + HWND m_hwndControlProgressActionText = NULL; +}; + +static HINSTANCE vhInstance = NULL; + +extern "C" BOOL WINAPI DllMain( + IN HINSTANCE hInstance, + IN DWORD dwReason, + IN LPVOID /*pvReserved*/ + ) +{ + switch (dwReason) + { + case DLL_PROCESS_ATTACH: + ::DisableThreadLibraryCalls(hInstance); + vhInstance = hInstance; + break; + + case DLL_PROCESS_DETACH: + vhInstance = NULL; + break; + } + + return TRUE; +} + +extern "C" HRESULT WINAPI BAFunctionsCreate( + __in const BA_FUNCTIONS_CREATE_ARGS* pArgs, + __inout BA_FUNCTIONS_CREATE_RESULTS* pResults + ) +{ + HRESULT hr = S_OK; + + IBootstrapperEngine* pEngine = NULL; + LPWSTR sczModulePath = NULL; + WCHAR sczLanguage[6] = L""; + SIZE_T cch = countof(sczLanguage); + LPWSTR sczLocPath = NULL; + WIX_LOCALIZATION *pWixLoc = NULL; + Pencil2DBAFunctions* pBAFunctions = NULL; + + hr = BalInitializeFromCreateArgs(pArgs->pBootstrapperCreateArgs, &pEngine); + ExitOnFailure(hr, "Failed to initialize Bal."); + + hr = XmlInitialize(); + BalExitOnFailure(hr, "Failed to initialize XML util."); + + hr = PathRelativeToModule(&sczModulePath, NULL, vhInstance); + BalExitOnFailure(hr, "Failed to get module path."); + + // Language Identifiers are 16 bit, hence max. 5 digits + terminating null character + hr = pEngine->GetVariableString(L"WixStdBALanguageId", sczLanguage, &cch); + BalExitOnFailure(hr, "Failed to get language id."); + + hr = LocProbeForFile(sczModulePath, L"thm.wxl", sczLanguage, &sczLocPath); + BalExitOnFailure(hr, "Failed to probe for loc file: %ls in path: %ls", L"thm.wxl", sczModulePath); + + hr = LocLoadFromFile(sczLocPath, &pWixLoc); + BalExitOnFailure(hr, "Failed to load loc file from path: %ls", sczLocPath); + + pBAFunctions = new Pencil2DBAFunctions(vhInstance, pEngine, pArgs, pWixLoc); + BalExitOnNull(pBAFunctions, hr, E_OUTOFMEMORY, "Failed to create new Pencil2DBAFunctions object."); + + pResults->pfnBAFunctionsProc = BalBaseBAFunctionsProc; + pResults->pvBAFunctionsProcContext = pBAFunctions; + pBAFunctions = NULL; + +LExit: + ReleaseObject(pBAFunctions); + ReleaseStr(sczLocPath); + ReleaseStr(sczModulePath); + ReleaseObject(pEngine); + + return hr; +} + +extern "C" void WINAPI BAFunctionsDestroy( + __in const BA_FUNCTIONS_DESTROY_ARGS* /*pArgs*/, + __inout BA_FUNCTIONS_DESTROY_RESULTS* /*pResults*/ + ) +{ + XmlUninitialize(); + BalUninitialize(); +} diff --git a/util/installer/pencil2d.def b/util/installer/pencil2d.def new file mode 100644 index 0000000000..c010853777 --- /dev/null +++ b/util/installer/pencil2d.def @@ -0,0 +1,3 @@ +EXPORTS + BAFunctionsCreate + BAFunctionsDestroy diff --git a/util/installer/pencil2d.ico b/util/installer/pencil2d.ico new file mode 100644 index 0000000000000000000000000000000000000000..306a16bbde76bb0e07a5f2e695c7f3217ba89b5a GIT binary patch literal 285478 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

{`a_Pr{(tKu@F7Nk?cpFVr8?R7YYFeae*&1d z#sz%st4TMgruzsV;!f26&)6J+L*7bOn)?ROJ%8sD#=JEyxE<`J^d}!EOKkoo`v0Ym zKunK7sHakZ?EC42`9E~rM;Nd8i+v%ojf%ze@1lRdJ_0d00wJDCRl@sjYX9lDj}Z4- zyMV{+haexNa!me4`giLi5Zxm{+SYf}4(OP781q^VP+!wn9$_wx?%zrOK79nDa|CFv zDodE(r{g|)aIYOlHK)K!`8qm(GyS__WCS>_lbc#zY8j|~MlIex4pOc>-K+Dd{ZD(( z>aU}n3)nAMf6!CO6>o2-xN~7e=u}%%n@{a5wO7>srAFZ#i|rk~|AN|GYUijOrM92i z25QTx@%N0Q7D%lhwYJoJsJT+BLG3$grKmBlWTy5(0i-H*TMIFELmTl58_ zasG{Rp#%9hp!-07#O?^xqW|s`HETGJ?e~ACb9qYb7PT|ff~f7FwuTyW%0y~`)cR0k zPVu1DkXkirrKuI9=1k4*+%&rP>X1%-U%DS7x?lCb$4srlUHT1b(r>3fVrK*b>A#6> ze8=|x_X}O)b85G#F`ooeV?J4(ETOWrYA)qM%P*DxI+a$?yPSf+iV7xHQ!uNxg2nX} ztZt%UdvgW*J!5@N{FFIneQ*oa*QB3Gf5gxTG@|dd8;c2?oRBa<0whk92uTtrMzSPH zkd%6DOG1B7oG_t!Yyvvoi9YAZ|MM{)n>e9@)JYXMr&N$Xt%Bm26qI#VP$idwh6NNf zFQUM&xPtayDd<&J!BFCoaa9#euc=@`Jp-3)aaFLlg?(Id$Vb5`e+3s?DY(&I!MzSn zc-+Ye&$~F`bvGxx>EVQ*dOG2qrty3HH$H}sebm`W{p^i)hVME_-^t(ok=r{jDTj!C zMg0*oBM?eoYZ04_^At&w;`7fwLx$9;kvVNzWKEYYN-Yb0N9HtXkck?9XL@SsQl&!L zlquE!Csm3RNSQ2|`u{SwFvkcUiBB9N#yo+Of>cQqWFaoelSVmm43OgFcfjeR?=kv-SPf{+5OQU*?aDpMS1$ zhlw|mCr63$)lskONK_5zgK|v+@MTRG6e?E**$aP(&ogI>vo=Up;)WFso$y}_a)6d! z{v=L#MRvn&vNuk){7CqKv>B?gDE~>LHF_^Tfxx`n^W3b(Uk<`<-Yi*AAX_#R$&mwJ z{3(R|KPxXw9_X0wl?*{maIHscVQ zP7g)XX~AeZ^&px}KM4032jMY&KfGq_h4=Iy;5~T@ye4jd=eX5yAF&wC2F^f(?qgB6 z(@@lG-47L-x5HO;nxROAn#ljvx5$#WFcKwBV$o)j$1%E}S0KCKd_c_E0a^}_U;p06 z2~Ws}xY$|&)%JWypW$!v2fEYP>W}CdfgkB>O!smk^4VqV^BiA@uo+!=kIeTlM-(L9 zVg6xzg3n1lNBOzyfN5}@cM7g^Pr!9H@xUzNftiPmJP<-W5Tx>e%ar|anY<4!6ZfFW zgk5Md{s%M}w*!sGZb#!WTkUGD6L-L43h~GEUDS5MXX-ZiOx_5eiEH6KZY4ZMEFvzM zhKAinp-zWEsL`?~$~Ox@$(oIkzw~#=Ua%N4IOjwH8guzKu=Sk%1)pMyIycMsjLqkN z_jAHC;(`mr1s_m5ShLqBe&?V>54>vdj$`k}H^B*9rgY|6%L_!8hzDu&#K5 zw8Rg<1(&%FE5bWmKfu-q43+WE&smofc*;%qifJrI_4^AG7l`xCK{kT>{1e0h=ioN~ z4A}yL2iPZI9w47!Ciw)+1FBCD1eYny17r&j4>Xy$+h`B$MB{O63&b7|XgR`n?jdCG z*ol;-+gr5{N@r1U-1ozB0CNFr6R$}_JRcD2Jn&YpC$a_a2>ylM*=cz}HZwg-&bz)YbHuq|NF2EurNd;;cyNcaR= z3`ga46Y@hU3<^RzxAn;AxgUu$m$1kKv=E=_6TIm9;dy|$fa8!?+r%ml{7E^RUJ>5u z`T^EPfb)D!_ZIsA+E^dk*sRI1KF1p1$HoV2rwGn!)_XjfFS(57i!Z@#(FGF^s6K&F z8<2ehgGOkNHW2%^fX}Q0NbkN5>6>pt)_{jd*JKS6BuQ!dt>oYBbIM7WTEhwdkbf@h z^AFkoN}6FT@&MNm477HG>+jnf0Z;ip;^!$To+j{Qt!HhX;{qJ_%V*?;=!^|GVlOZ+ ziSw-O(Hbq5UV+E=!~rS~kS(C{0Qm&04VZiap$)K4aM<7z2yH<12@KkR>=PI?!r0}3 zx?>KL4X_TGyiX%*%cscF>Jd^`8D)_J__r&XLBT=KkAnl4f8JC60>=$vLm!~nz$_XV zGKutu10%p|yK`Qw>7KG=0|ufl8D6_p3v zWgbv{0-+7aK7phSNb$ljpFn5>6ek!@+JG7-h#emAnYEwhf3^X(AWO?9DhH@M(DE9R z<*#S@&E(&YpEsZ!qPvtU_#tfo`Tu@Pe!;2O$R+Sm7J$}Tr!mkU_K!dZI@Ii5;@m%h zsi^kspEDnD9Ir?;_@+%B%^~Li~C0Oax6gLOZ0_v`0ytAIm;NA>slV z!%=z8nuIv7GT&B2z^ZHTUwO^M18fTj9x&Gij6MO!3t1b`#0xEI17`6;kv9;twt(*( z1O79#*cT4}Di5@Jf^-d*!YOfbi#))!3dj`@SMfmrYfHt72nIYI$SeSv$? za~+SsmFO#$Duu6|!9IUh z#{bvfRzjOK*U@VAHMBJHfG^ntvQJ=98!(F(TG9qMP9Wli;k5xZUP!V0sA&GyKI=l? z`$flHNY{Klvid!+%mJ!4@Bk^x_O!?W{F|1^s^Eyv$Kw+`r_UWK?n3Y zWflLzC&=u78A)u+3tbe?J(V@w~Ub(-zJ{Xh95d2KIV z^T%}Wa6J&$?Fpw{L6f>Xw)dQb#sf*E@0g-GWo_Fe-P(a%hd-R*WW+~;(&H* zZ>Y9F>($p)pP;4W6L?ELfzSrzcwt!HfKeL=mrE@21|)4DlDWi|@UDH&YsNkm{~6qO zMu>mG0~y@+AwjCFrr%QjT~j1hFsy(>4s)&=f$j6n|2V}p(m8?Vo0cF)N1 zz>!_MI*fmr3nusNi+U9*AREp30<&g4=>x14I^q+so*=%%wbMX!*?1G3H{4WtfNg7NO1HvbWNE^Q~CGh=T-Bkz{M^Z zfWb*Ws6D{7hNojDPWTt^OJ?8g|H&VflSY8o%rf0CydDQ*jPrq)j~^c`9Kc+_T4Gb; z6iYD#wh_2C*rqK&xyf=3P}ilQ=(Y7WdThC6;(^X&4|Lijki*-R-)T~=Yi=MGbgFX^?zc5wjbP#uyvKxl#4Dc^pHCI%>Q9F>0S?Ahqy z=ZD z1F|+?Gne=S)EU?qHvwe94j#ascNN z%6>z~Nh>g9*If+y;V$vO9rPz2=u7qh^8otvBvHjuB)S)|EU()3%K{qD5(kXxBdcrgCkFdmp!4j7v) zR(OExn+dbg$pe2M@>IUj5gy?PB%&jD&3w~+A@TwXlJ>T0;=~x^0JaA@wP<0+0h}wO z;-CI+x$eJ-e{cMX2TzL>< z4?Mt_{SQw#j z0d9@n`Cr2q+1flpzJ^mRasb~4+0rJ(eBVO&-$K#_gkQk=z>wrI$^%bn?ZIf}03T(s z4sW|gfcNn;-4DF4hsX=;*QQO3bAW5DT4o#|>w{J5G{U6dhnNub5aSL$PdMw@|c7 zE7R{T-vj)-bgoo5)UQ++2P~kN0mlmlCX6v2h;B`g)(z127>SqylF}j9$$hpLp)*zE}iLI|eR%f&^2H<}`Mr{DWCC(Ht{G#JUWGnEERUT+i zB0cVoB|Sjc0vtCCOdVq!5Y4f{*N0jv86$?kCx67ZGy?yVIY871e_OmbHqV?HqZ}}R z>I>z0pPyH6*bFldKgRS!k1;Luk;(&X3os9imv|t&HW20$Sc(^lya8+4Kr3TSfwjB= zb8SG%CALs!EU!zf<`VPzZeMZ6LKp9!QcX z0lHStj-O{%H1GiX1`~3{NW75q1EMoWi1vS7`pKi)z5$pkKdc?Uo&~K zndX;0V-!KcY#qGm|h$hlsMXL0nQVQ&RpS8FNOEP z)*rS15orT*ywFnKK$tdQJ(oBp>WqEo9aHh2DH?Nt1g0JCNgMdGGvy-X z{K9lU$oB?6ukl4%Tp95Vu#mLDQJJFM4&b`M=!yxD4KT>|t*`&pI0CEqw-rs)2l2ez zv__3+#s5mmF({fhuW9agCOc#JlFe9t<~f$0evT!lo|$-nZ2{&1_6YU(2_R5^@Spr*pWJ8^LU}-b;e@PBHslkjQBtILFa#&E1X+DLDlX-NSZ8#>7Eex z2KR{*I-zYPXS|wH-k3Aw6s${Vm2FN{bV zkaLMGxcXo;-!48quj0$*d_4Ky~qh*yhbHA za3f*AX1Q`E-1GMpFHsUJj@-ni%dfEU(kraL_!4W4Jg`dTf#)WlK=6R94ah!$-~l;r zK-LE2c%h}d0a+X1x*|*Q!kDTv_FH_;i2utUjs0(ie_<0450veG7WwiOGtCk5y~59H z6-t3CZKBT?;59{~Lkl1sU=N+2{)l)4*jIW_&GZ{*FxCe#W(QHs-qE?A*9Q8!Xi+ol z7cNi;-yb}W?blvo>($rTa^;oE0~;hBV4r|_K~t90XdgAB5gpf zGnR9S#rouS*BNVaiM0Id~L zDdO8-KY~V}yNrK1C!l}>H9}nf&pAGMrTsjZLm2yu_MXJ9n?K@*8$V*l^&hd#$OD^A zJn$0hjP`(58~FaTJ=%cncp=*Z!YAO`B3to7N9v6IjB62E*9OAZ88@F}z<(A$2i5@; zbMgo5b9Z=vrmd%#<_Y_dDnSR^U z#+(4guS>OR5!wJ#2Mh>T^Ut3x`BfRLI&=a1Z@+F8UsW4}iICfIf9A%gGygrK``ap2Bd>@)JfZsGy91(*leCou4U z!6&e!4X{rj;)M}u19H63Qr>{94H)W-!{-u*twCm48<5u?5;X<(cwaC9c@x6r8i=w#oxlb166<5IG*;c)&^jsIM15YYyzR@AlV^q7fKH&GdW9 zIRTs(#CwM@-gz&8s%6R`hqP}u<6X4unKGke|3DnR{{}}M{)|Hpen#m1pHv<=XyO5~ z1;`!{JitDI&<13mKxl;4v;jF@DDnoZX#;XDv8B8LSsRe+jOAS7ZqmBM5#pAKZyzUV#Ho$*Deo9d~7yS|O2!yK< zOsm;HNMPJrU%5tYtPMJeQ%`=uiO277{LwocB@Q@D9B_y@AcR^F*#pc2`&E0uzysE_ zfsN!BY`A352G&rlz`8a-IfPbniKjb|OB|6l5I$aLzCO9U2AQQ?VqS}gbAL0o2#FW? z7j{HB|DEX4thrSl_$-q9l|;urgH#)|DB@dRKf*WyteO5tP5mw9oB(T>=l9E${SH%> zuEY7~zu?^S_c;6P7o2|j3r;?Hr}Drti3ivg2$6gOp$)JtV6Qe{h!JTXCUx_J4?mW&O~tmJ6zVRoW^KZBQQ_kpL;ncK<0p4&e_n+Cjbk!?jy|qf{QPI#pPGOs{Mr*?^PZ+ zBk{m-vIm$4v_3(YHt&kC99(yaX_y+UKkh99qu)2o9-p~zT)S+mubIp3fR`SrV(C^1{)y6 zQ>kj_y{{i;7=cav`-nDi<6i6{4%l;#@JSqS@Bz)+!~vni0f*VPXJ4P@_){tmko`}% zzeqg5K7rr?YuW(&1gsI-qYZ?`3&VJT;{<{SWNm=!3oXS9MNNS zOKg45qHa`osA_*+$KsvsFLObK`qR*&NCmVlTMwNpH^m^A))?&C7Sp=)!x#DTneHcX zUx_|jDh2cFI^lm5`_uBkFVUj|tfv1LCg_g7dIbIl%HW1l5V|neN zurvB)eru3l!MzS)w!rIXSSKXdNAaNV)*tqd0Ba@(sF^rm+ODJ6LfRbjz)s?UUBm;j zHV`bdfybl`Fs7frGx`MfYXg?!g|@T-kwX~f6GWs9a9vSk>Wt-F;t{rTiMNN<8FRgH zR_~3-*e2M3ea63Nedsym)5$h;Tz{U|_k!vJv@TN{ohrFtP}4SsX2ieXf$^=np?VqX z>k=nVWY7lQ^>hNS8G775$~l2s?7#K(BaI_afO^wDg6Xn2W8Kvk*i0O-^%mvr5eMuf zpMbRi*(VU%fb0`k(gxT!5b;7wc>}UGU@ezew z84n{LAtU+y8QX>0#=hVH?pYg%<32&QR`=Ch0QLd8Rdd5&fqPBguc5z+|4tQ~U?BMi zqy4+WrE)c^9Kd|=Z8in#Tq4Z_%XCEBKLQ9;5>PGXt9f+|^&C9@+_L2>h!vM#V9nK6 zSVugtLE?e!T5W)^dO#B|v_~6|1?W(|k&1t79KhITJE30#Ka*BCmb8Il zdGlN4fn=l&_?J+yuZ6=r@QUwg`w{SIA4$2Bl8SBi^%?)7nKVIqk7ERkfA$50HpuZda zV;peETlwnKMz#G{Pc_uT1pfDUC~zh%M*If6PQaWaH?ZvTOX7i7SWP@2e1eVS6R8JUz}mo)26pqnK>HE!X&*`0KPd3e z{lscv_-7s{@YUB?a*@{Zr#ju`!~-iO9*}(kId4FY7YdEgESK1rH()E5_zdS7TB|eG z*Cj|`)DA?u} zArI{Sv{7x})vtF`5)$U$%lPN#HS?HrK-cNtW6^~d!~-u(Jg|y*z^XQ2j2Ch)@jeT= z#Hx5{tY6TYDCbIq=XB^Xqmd>T|!A7nldSQ)~J0 zx8`M=s=0uy0S+PjbF;()T?yZ8129jR@XuPIkpueF^HKlaxv~oaYBxpd&r(|Dfz-4X zVdpXmg1oHqz&pOT?L)z*dldUgTI}=d?ZmHXlZA0W!bFKN>-ZfkAP!hW9PmBa0>USV zNE^`R5_8^wHkX+521I>fm`@OvHxOPM2%k$FQ+392F0t6Nh}Rn^KlBjI{oA5%?$>ev zzm5aiK;4>s)I5MLR0|;RFM62=dQ+_s<6o^A(8LIYPtcM413rfRg@H|5!=-$6oAE+k zi*R}^%N%gXS1Ix7BHO+zr+pNi9V{^{FLvPx~tIrkj%&p*dP;(^5)9si8WbiX&4xZoqrC9cqH z9=wZJQGI)Xdu`7=(BBvbY)>@`Ss94{1k1M(VV)^dr>>x{#% zOFUqQA=fu^Z!5XJ_F_4*$FVlh?c?ErFMNX47y#pz_5Pv60o(-cglJLP8=|cYytKO=8;ceT^lgu5X!m4oHr1)I%D&AVNBH-%j*(zo$(TC z&fc4lAz)wZ*!{LRg0+G6AD##Dw>%3EV+@e(dVzn@%lH=>AosF1AoBpn0hmivAAtBk zwGX5?0dqmaFKVD*x{@>}Ihp1rzBlDoE}Qbd%*m9zpE}O1T|et15n-SI&Khe$O>Xdj zHTyB;)Kg3&9+)BVfF*4}ju#qg3c}|S$CWx`x0$rJ2j}?@x%c7mFSy|Y=Mv{>N&BHN z{%Jjs0kjr?z`eF-9_VSz17bTs@PdqeelB#vP8AxP#|fAVj6Be(sxKPlaYfCXjo_Rr zw;Aqb4sdc(ey7)g)RIusAJPa=-jA0(_~&C5*H@4zK^VWLN|zoJk3GO7T6@dD1J8^; zfw?vy#|s4yXmg2e))^bu93>7Tf17XW+QdKeK_99U;<=r50G|I%9KbO{!Z$arCFEncnbj3C{*7%w6N(MwZ%!QG zrt(0g9CeW@X!t_Vi+?`O3u!8c3x>P17OkUw zO!Ktfj`V)CuSay{`pDRguIGWo0kNzNQ~uAypeNpRf3SHMU=<=RI*h=^7!j|3e(XKOZ}_rUH()im^=x6JfPJEwDCgDAJXO$+paSf>k=E*8?cy5OlyrZn8Mj~uZnwC>JQTM9MnF^2jTglqxk3JYv&EaKMfpQdXK>H zBablh=wpl_9uPi(&<4VMf-r4B8!u#Sz-lhBScA-FF0t)3$Rb;3yz2Z*WN=@H46P5w zJ?zUo&@<-Z1o^#A81z4y{~6yV{7XDw!a4cx0{p9mMM`JE=six~q`9JLU2R84Za)2csU>plv_o6x=fq88&`w4x?PLOQ_nFl&mZHXrN zJ%|IiNjzZW0IfDqCzlKId~UVAa4DhxlZX=@@Kw?aEJvolM|(PH{Q%EVvoVl3U@&pO zFtP=NPaw1bjuU9Lf#}U8wxJEsnj_ZsEYj8)^V(xBQ%;cGzX3(YU4yeNEXC!&^&=h# zh`K#cuHjrm{x8M!RO~bUB@U2zV5pt=XFEdX2^s&gEzrAeD~bcQAP(SW-~mgvfH@Di zqEhxcNS^pJOSZtSPk{qy&7bU%!M*s*ri3dWw-|a zh&nr7qtLYHao_&8#8sS2+#_lnP_^a=co(Y-*6Pggui*jK1+@6L7AIhPK-3Cw9-tQg z;`JbxHgGA>LgfGh4+vYpBSN2`UY@4Nk}`+s{uTEz^_!{1>)PQ^Po;psa%B4FT@Cv- zOsZy{e_7z`^5`3UAN_(Kn0UbC6G+;?c#0KhwSifbM;LJ~@vCs_5?jk9cC^m;%(M6K zoO4Fi`oErhM#VnkU$n~WULn`GXYrE&AU@&^i8;((>Z0r6H3 zIO?Mmiwy3?XLzp`-ox#meoiQzCCmn(F@yiq73g*FKKcYbK!4(afguK;U?}+nfohx} zyf&bX7h0<`7CD4+-hlbK#9*z@w&^zcp*#pD_k{-yb>I<zG%*CpP}^H7ie<8IuF#``WpGC#8aQZjymIFZaYn}|ACaZFXMl#PdCi% z6^J#Xr();qh1kDjIkrrlfr)L~V|=T&SUYhlw$ECCwPUAZLBEk0>(|}P9x&mbbOlTJ z7w@$#-;%KJZERW|uwNUfpW6kglcd&izzYI@*7!yMhdh;U1ePPyztimH{#$P+aHvAaxu2?#F z9QH3-hI2c2;@l5EnA%x-y<_%lOzYfPZTpuj!I>R9aGKlp?P?2NwFaw4Pr;K!J5jeTPZ`XjaGv%}gA?TtK#fnLQxc0yg4>HFDOc^~MruIe=pV@#+!ct9%<7 z+>6ife(l;l+=D!w%yNU1r%r=j`)`{#pc`?4$^#mofa8U%4VcFZ4S56Fcp`v3}fioY}qu7k2N)gXh{CQ&;qo5gI%vtd~Q6|23X%T?q{6c?>0P&R7B^h4Y6+AcwF4G2NwzZ+yn<` zd0<&!pb7scw`>911l$A%$UHE&PapNz$?ZB}a@#(pngSX7{Jd-R)^IKCt2WgRF!F$X zJ^|$oXtV*24P;IcZk@5mg#VQBg#)77{uj0Y#|1Ldel0Xkrq*%gL6Z$2IDmV>1AWLI z5I%w6fk@{PUo_SkYxXQ+ZD3^3LuB^aNU{C($T;F8;hxs+ll*;0o@ZP06yI!k0geY~ z@h@K2-0}+fCdE^2fO3h8w+=$Piq$ZoO&jcAycm}l|Dp*F(AWa=`u0^ZJ*QVM)h`hE z561yy6U^-1T|IVwzkWEmbt~44nTkO74&iv9drii_pNRvQ3moSGkvCw77uF;{Ac0f3 zeM%?97yL)J{wMIy{qlz9IRU9NWkt^ecPw&%$tN(z3z-Mhc%eoc7)`N)vBx9MCFV8A zv~|Yw&%MC6Lxa^hKYgnmWbe~HeUZey_H((&C#Xc)fWW-AZyNL(71q2$&av^22dZ>g zgYNa}VLJKqXUJZ^w0Ez{0VW=hZ2@|Ijxar~OBWT>-wzpL(gj!}(DDHL0OHuig9fSE z0Q&^{NJAXs+s(uQ>=$&a*#@pf82{!R;HugI>=Q&z8z`K%sA&!}&S!s6?;IaEAUflJ zGWNyuTAKYsYPIic5&yy-=tgmZ9v0$-j^q++wEMlh)|;UV0fB zJl3gsycxP5M3yCYqixQYaW6l2CY$2RHP6v#pLL(0-Vd))WMu2?mCbhtP{=$dsVJD@A$ z{|f{DO+2950_OIB%memn10^zirL_TmrF%I;T(E$aE~n49xUFW4v(R;$@@J66Uq)@W+E2Xajth2k zfXV|>4&i`Msw*NL-*4@86zj=(dt~ENOYgNA83!JT6+1s7+-v_{n0$hI6cf~HgW`3g zy{}Pf0qrXw`PLtEZ9&QY$Iyjr|A}qeV%OZcxOU(Gu1Orge4yolW9!$O@XY?aMU9a1 z1%ywqX6#tg@duX~a)|^7a4&e^*v3uhP^kmli?%}ZqJjgsH}Zf{7hu1@pbuL23BqXu zYE6+Rs^_eu#Xr9;AD3+a+WR9)>wnyAr`Uym<^yeRaPE@dsIfoBwynmwLVXTCK({^j z;Jx-5%8xmMj4ddBXT&_O!=IrC&GnqS7el(97R!-+oozkk60ajYl5{|Udu`8k#s#N- z{Mvx0dw2A0(gZWQc2)6uo$)W4%mYSEfVp6sG@oyqF~g(_SmOcK{6(JNv5gx|u>vy= zF!I1qzXfPjbt(cXPe98`v<6=YrW_=DT{j`Bec@(IdsByB*dE7tNrmGv)?d;G^4FU&XW23YqS?eC8b6DHvL z!Gne-@New3KEc8P159{6x^A7S56IepoHxK2pHAGu_@6=XLiPu^ne;(=F7v?9fDP!_ zXe~N4T!Z!vR#RJrcJ)`HUA+}(TW>j9)m#9-@}pHga3j0GpbD|eXZ@m*4dj_d- zyUbH*uf65>;~d_t@k2h+2y1M!t_`?+q;P|W3Xd-ui_Nf%J#1X8Skc_4J=0p6P2 zVCDdB$xAju#z8cvPrHIFb8nIlPkU>viJ3UPH9UT(_tiS%-PU~q&NKd4>Wp&--c#rP zVV<5?Lb$w1*ykoVz#0$ilxlu9Pni-<8_>oIw$GYn!vChplTC2~p$*79aCrSrbavT@ z&P|vD)}y1~0kQ=;G&I-(?b#NnZ?Fa0)?E&j2Wl;XPq|^LW?+vt;8M^NDHEsEa=@Ut zjDJV>|Il*9Uw!S<02%w-I5+s~tYLY<0{^1_tXBJvQooC7ZcyutSsSobXUw_8lRvCa zP_O+QbfdX{N~cZ;S-u>%f`f6BTLe6?c;G-2o{v!6PxTEXZ9t6~O7X(wQk-!A_uq%r z6KLZEq!;d(zXM&GZblcEO)3v`vcUtYPhjGKWyAwZ(X#q1czoGe;}clc2n(k#ro}(+ z9}s6Bj_&`Z#s3@48UO<4w)+23OmJBPCuB=yg$EKRLz>pJk#*IlG5^cl!nwru)EVde z0CmP$4aPI$p7C#y10U)BY}#R-TLE)u3^QG8JN3+y|n+JGjPSl9w9 zC+tAiW?RseIiRV515{g}$$Eo5(8%Z)SkVSlTcGw5c#&Rc${n(jOI$u%H7))*A2?}T zB>+eE|I}iiUq7-V2f!K^uqHUJK}MuZYH>YwB+8Hz8HVmAU7up((UhwnSH7nJX#@7v z8ONSI;L>V5dQh(aRGRw_Q{C?EkPx-qqTUt{tfM?%fn|;XSd0@$@xtI0D@@08-A_1; zP{RW=`|m_I*KO$5Y-<<~7;S+t9+0&GqfcPe2xV=+_q!2hu>x)0K%KlzwD{-O#p5de zgS?e5E#cbU_pUh*1GLBkW1R71;&<@*HVbHq(!SD^URB%90xF06{od_8d7e6 zHa;L;*QcC>Wl{m>_m6B9n`j)@qp|T*wO~HK7lXA2{?B^ z*aEUP!0U-5N)T?oa*M0@zv`wWA*}ypFW$Aso%DBH12p4-A<2M+Re?oSacXdBe3$QY ziyT1Xi&TwzA?q^QgXa^o1+vrie&{-5FOMGRS--wP^WU%mcM1E9f6;_3pydIs3lLad zO*#Cm51KSW;s7~TAbf#2J$sry!*+(XTw?YKj%?V2p6)-8{?9Q00|#_xTfkMa1%x)x zWFt)4fHj}Ms15j#FQ9UOSxtc`uI8FMaij?vNU z6O`^3s?PmmTDHW>kt1>U&>>S3_z!0bkUemN@XfJ4f&Zgx))?Xhk~W~V1&+`$;&|2y zcQkKO3$u`3)8s6K%i4`{Uk_6e+L0~90h{HkYI4xz*YdD4c< z1zr)C@lP7yN=NXnJyxs(Za3bw{4go63IEIi+Ao|Dwq} zAo&9~$YID&WWv5w{eTC@{pe{Gcmm^Kh;9dyp1`T6={5yks>&VRu8H*$b29^jfF zF^?~zykFJ?wc3DL&H(uYdx&4eXXeqme?0e#Sb?wughs%2z=7ra(a-xJ`g$KA4j>-z zlz703PY_-k*ks5Xu&NELqMYGw!~s-WWUMc&lBd2F{}1Cd{;Md72-EMixOU|AAAO>z z0gTUS6aUNsLL11P!Ll}xAVq4V>%Q`n)CSZ#V;i}|yhh=-E9|c`&NlopS~qO2*7!^( z{r()q;2#`4YG{H3tk?pq@6DDqJetSN^g$_BV6p}1GwdS>{PWr%T5W*2K<0tPqYk3K zZxH(V7&xG>H`@YXJkX2%0xLXVpEf}C1XNSds@gQQw$M;t*a}tiHrC?*=eUf2KKBqG zCCCxHYma@_C5reToRs1KRU+g7=7HblRKoDadGMK)yn)2dg^+RN!B5U7P_+Ttv#6ep zTw<;>wkMakajOaFN^5&eYS#`ss8;Xcv152h_~)kb0Ab%`3ut&?r?kcouL~w(g_blz z5i?|MP+*_qg_kI9Xo?dMH^^}U_6aWU+mGSxf(id2)PjivBpzT6u;>#wt_>J+iPylh zR9DghTB$rxBVV{2fd3JM;`Ukq-b$br(~i7$q!!Sk{m+` z7udJ1KVv7pG*M^VipDrfus$D;{oywIIbY@&+&g-8X?;O!L*+A0KZUbA!=g|u%8DgUTCHbaJ-QA zsj;99ha>xw!wTm_HfZHWWgpmxFLTKvC{)8MC*U+<rALw9_Vxy1R22WruLFLDO8y{I$J zG4c^wH*iOv#*I}xo}%@4pPoLACnrzh@re@#4j?WNJfO7&f~ZbM;F#C#ze0Js7UKk( zc;WKl!%d%KJ3#mZCT)Q81wkECp=}#Qc2Gt8R)8hYCT*p73KjC?e7SoQrzUaVuAmQeIkrOa3N2Kx3 z9Ps;`${5!yA5tZ=oHvlVz}Lt<{an1U^&PPhic@`|wOnG(8F23~Uajq$)V@9TEL?~e z7cSuWxpR1S_G}mrSh5AkFJL=C*8C38+MQ~gK%)(4^9GJmEui2G?oSivgo_i9e<0ff z>!*fdP{0ukYRQc`K;i+_7BJcak@5+w=MuNBGD)=oD&=da#ebaE{{?rE4e#p+-Yp#) zq@OpHu zT^r+Dx5fs_yLoZt3SM5mj29O#;yLlaGvj#1`rpr+b4me62KuzUJnj&v;m^TC5oQH%qy9S}tuKeWxZqDx8>l{FE7ZC^()u?}n}$Dr{uyuY-o=~SxAEi6n|OWw zI$jYEyks7@bjjco2p%A9fUz#t>En5va|9!d6Oe6ii~RZd#(e7a_?gp()u`Yz;Ocy*uw*6K7sXkVINZtp-~&KkW1`SrZ);?DyhZ)92rA#`FW_9 z;%6_`tsNK9zCc!ef0-{vXO6NDAmg8(|23~Nrg;=V>g3_}b5eiLY_!jOfd$dGFQ7g4 z_=h~E(lA;tgKBz*`}klL+1~&D^%wY|a=^WNczfp#-rTws#sgQc8hirc0rm+V6aM9# zozHi6ekcq!M>%3F|^G|%K1G(9KbC+52!wY zQ5!JmgIaAMYVkt<^26xV|NMhL-oC{z zPoLta`}gr9*#mFL9$>rR-J?hN{l^~>ENOQ3tHz+MF_QfIU1Q^g$~=fg{?0s4w&-{1aZZ%~i%wTz^hF;6{6J zZtIv|dPai|Ff;|_1XhlAJ3#P)Ep5OlaZ-FcW+$BETb(hjrBu7u0(2pNeuG(B ze~k0Kz`i~G4Z^q3?bzqPOtC&woPe|e5iiv80BeBqy8g?C4psF4QBxqa0q%uA!2RyU zM=`AJX=7s!2;%|S7KoHKAmW9-LK`>`uBJf53!9ehrNutK{xYs(UOxXIAEmY}Y}@m< zYi*;+2AG&9#_%tAfVF|V8IxQ3U6CPIA(WYUI$mf4&MTjwS=&H0ub21i+(|LM|NZ-~ zJ#aTW<|+9E0{h$_B0J!P&;}xi7w(xi&-7X5jSI9Mknjnt#S3o*AHswlXAs!V&nB)YuZ4$?lX~nMcmQ`N=-hD4t46GpNosSZubMiYGfYoUcCZqbppTJ z3BRlh{Ky)ih!+YT;Jg8j6OcXdlz4z^facPAKH{@n7sUA1Y6IHZqRV@ZVoc|A7~X+e zdv44DVLTxF1QGH;fFWjRmOErc8?cm1%r!-+lBd(+f0V#XeCm&QD9(iQDCGh$PrRo! ze(loxh303iAD=76{Q#K<&JFz=lwbs zQm)PWpMHuA^zrk{myp-x3!%E6-|4$p8#Id-5)W{^P|X`)pMZGaDRIE6kzw^cvxq~k z(b_$aB#ls;ODuR`(TKAc(eVOCbU3dz0|(gVfiP{rJWdc*ZNR(sR8Wzh7XS6*6Yk|} zAs=A5y>q>_<1V*}CLLfP@yPVzvC09=2OB#Sv#Jf`{i-5LE}%UKKe8M`UK^?AX|WK zgQHZ>Bj$bXx!y;uDIol7^+A~j4z4(fk)1ALWXFp}4v2^cB%i=eZ9t9}s=36nJ)qGB z%9rrfV*ek)OIjH-@##6`0u(1)|7Q)`_P!sPJwhzn41*F=ebBeD&H;bVucGD+d~PLg zpmys)$WQ+D$G`)*NuzLUH5gqemv?B37T~#-ef@tao)?+NQ^K?Cvmc~7eHHuCm;L+q z-}v+0JN!oe!LMW|aQpqu8~pS8?|A+2p;@eN7wLaCbBT?0#q z04)!g`2?~yAjJtH^a+glL*a9Y4S54{ePP!0g|ztJAD{4U=~_s~J76!)tsQsDKN@lZ zgMzTL3`vi7q17SXamHeRya*4aRZ>Iez5@_+?!4hWT(|cqC)Ut+aN8W!N zg?)m;*#e_75(n6~R*)9M(ee7)$g-$YESwIc-W#bhWI~nMC*T}Qdza=}bQ^WM&sK5Y zyHO*IZPf}(h7H3-($?NnF7K~AFaPq3$^n1;_8b18xjG^Y^WRSp)@AHpC0pH*$DhPG z3#C2(w$PeDoKwX9fVEs=QD+>q;tWQ2xk~Ly7zY@6K(z&oK0!DhQ1!vcX#;9KfsI_^ zDqpqLVxQOiagI+|w{|Ur^Fxkc-O{m#Xs_TX*9Hn3fctUTW8DwXatG%Pk>P!dV*4uj>6Ngw_(0-(gfoO_w#74tfLf9e@piFJF>rj;ru<)=-v|t{7M|~ z+xzz>9{BsuKf!i8YXbixUtYAgFJ9n#X$=qdAD&S?fFlpiC0s&zJ%T@0(f(ijfAQmQ zvO|~yUWqt?F_&1x3$F)X#P}XpF{bM^s`FzGu)zZseS-7GIDy~+kvAY|15)mgt-OIS zZQwA{rp~U#{}F3=iEr-*c`4N`VcOC6qGgRRnFC@WH%NHR2c0~~WKL7HBp&XY;cudS}hJ;cL9U7wF}A4(eAOVa7y5cc1aAO6$p*Z7&Vxp#sC zjJAN52iPz8i}3mv@xeJ-TVs}Fudg0IUj3UR*#C>ZZ<(}r?^5CtOS#3Y6>!`@@BqgT ze}3`|Yi8cX*lyPe|J;ZJtnol6gI^F{8!*NRWS>CN1{{hP8ts7=wWnyY&#$}0H=NtL z9>RLCqjH(HN#psOo*A0FO=b0yX6oS?kh=ai5Cit_YdKYNBBpFhVNn#0)!cuO4c6LG-L zWD96{K=lcX_5gpDwE{6;bAOoD`;Ev?(DK3`^nHt@dVcmpm=A0{WmBLuB^rXZ-kY2tNUBx0kQ$gTf(!W?;Y_aKOm~>1Pbh{ zJ*^owrQk=w0n7ue4b&|ju0Bk?f3oDvi&kS+qHez>s6KENst#GJ;=2~TZa{fO%}KX! zLoqwn@VIp&4Zk1R_QOcWA4ltQOe4(mT)$)SVqBvf`)3q)V}0)h;r|8A{Vypu&%^`7 z0a{x?%LD8ioT50qyl&52T6h1cgZ4h-`&as|c~U(u+W^{m-xd!%xcY|d{#%59Za2+& zAR=49f;M2#2P29Xp3&44kT$5PE9&976A2Q8s~4ST2_y0SJ;M41NAYgy`14dB809qr z%s7B-iV3+s8V+C{*wV?mHsD6M9!`5|^dY^j58=B%>Giz7*5KyNG2F`wWBmP9yI!4- zyL3_Yyd9LQf0k;ACc;OOH=`oCsMegl7xBQ-@oK7Ehzz3&kIZyPv3@c)qXvquz{XC8P$ zJn&TJ0ZX=k(I;Sg;4ZD>v60sEm;cZCwC~0lTECBVLe>a5Mquyb9<323*Ya+s^*+PX(FRODfgCFcrw!PM7uwJU`uQD1vLvarwtq-e zFcjB6OE@3xDAuhVA8mO-vMr#-1}lG5wg9g;;9uVIT7*dwCd3lb#}86|-dW0#zea0q z-k{j{Okq1-` zu#*S6T(cS{u$eayLA;xdnZL!6#tf;56-(vu4sHGn}%Gv77eed`vckDNbNXBQ)xRYK(y51Ai0dxm}}m|72f( zTGy^{w5I6K-~Pt@QI9aG_kB#{MjW8!f$_uz23z1Z##z(`9P|ks$R+OUcK}I~q}1a7 zB4H;%RPYlYJ{#(z)N=&qwvIg$px}S~W55^ST;XZOJ}Nta`9thsm@B>IJq(*SY>30# zx8oZ5=huk?w6=gn9uOR0^a%khZ(2V2?z=M8Y~(Er=J z61Xa=?>|q?tY3jL2%cyGD{72z}z=n0XN(*1=BQ_R7}7v zO*2K&78ex3UEB}_<@-Np-kW*zh8Z5qLon|9e9q_1%$d2%_ug~n+;h*pqmLWlIR&;M zv}1=E^li^eG{=yeUs`GgrVl@X@qLeBT;BxJ0ZiHH0nM18zI7aR841@-f?0jBvo=wr17#`2gz z9v9?cOh9o1s&9bi3)MM8)i+=sOWd>Va$5g=mtOvhO}tM|^h0!8=>d}AGg>*$&+*@% zxoDlBG6vB8^Zo(1VGohK=z_$tufXT!hbgu^%eqpOFIyH%Nyhfj-g(NHfbD^JdcXfp zcKtdUfB!)H=4yTKihS~WndNg2$*t@o%*HpM)dNcGkPxZLvcc+4u?++u*{PbOaAc#st3;M2VQ7=z#Bz*=+&Y9(%Y@#c^9iWwa?J@5uKBi8Qv;|mi#Pod*&(_Q` z-jw@c!v+noGAsgB7_9?$Za6w5RR{+KcN?+AmM>4X~|$+`u=W#0~I#p&B=! znJ-KrKjRACtBd9zl{_ZXIG@KA9Al)7CDz6evL4`AV)g^7zQ9ai_vWhz>Ys$5eoQR? zHXV=?J&-HkfIW67SM!B7J@8@E03+F7Q=H^FH+3an;6l9|=jS}h)$xH^9l*zfX;0At z+E+L)?|ZUAGwr<60S-r!&I6Y`iK zi;qy}8(>?&FmAvWJH+Y8^8_U8irn*m1nm>bK0alhK<^viwMB{^;I#!jhse4h?OFy_ zF1Ub+{ZA4l%VgC7S@nQ+OyJx%khl3l!!-rAF+u;%o5<$MvggZnl81V^k%{7TZh;CRg4O}72ZqtNhKt}F0qcX5$*;q&SuK<)W$YUmK=0&T6bt0cH*kb}1J2?G zl4)GP^8~xd*T6Eaec!X(b1Y9h`TON@K@MVxWj$aU6P!4jin$ZcV$y(9Hewy%L=SwI zXyO}i922fr$f5^gwRL1O~nV?R=qWEU_Fv zlyzN^Z}VUy*^eW6xGOI*QQV#(Ss##Bc{h9Rge&(9Fp_`e+JI7|2WUNUKE6G!wc}lV z9QEz9c&ggnM*R~{)vb#)6gR*=K}8QJIzS&caERgvc2b-l&;4uH=PI(#bNW1oz+(Vj zQy|9@^SHoCEU|W-adN^XESY{DQwE>IltE`@nmouv4>+?0%zOh*=L_|51KGzC4l2P8p762puv}1xe+Oy*~y0&KCJbA6)6pHs#WL^26Mlk_PDb{!g%_ne7 zaTecz);~ykfPH^PYYNVvxq!{Tq#$JI1xy`s9#aR~bbzV{NC(Jz;I!2q$jz95^nlhk zFwQh?KsR5QgIHp={p(bJK`;A!J}IxVP+Xte(n-3PlDuEcugvS8-%l|@1rjHymwTgg|9gOOj{w0% zM;9Cz{51ZruJJdEIBuXXecxvW?Z35P#0V^-efpzljIf=)vB~iRhB1WNSYnPNG@B>T z*aQ1_p26ba6a)ucBD!cLMF;rP-hYZ7AX{LntOIf|CeY}Cpnl2fd|^;-d;?DA3l-l0 zkNGW9mTy2_q5d!Y{rOM=(e0!rB)|Foc7R?7aICOv_YN?4?;FX#_S)dGz=&!wa2~;w7w0*mD$QY18Ej>WY-K^s3Rz=^sQFOk!3Qyl*5RwZ0o}SHQ$3(r zU#Qmu$qC13F8>rFLoXt9=oN$nUbYeI0J|P=v<2*Af}H6A6aS#r7SN6fwDChZ^bLID zyUHlOpKSrpd~|*Bs0{&<-Hv+sb;bEs+CQW~)(vW9JU7R@&R}RIYn<_fy1cA3-WJhCZMDt%+c|1}9^OBw5d2G2Z$#pDCf`UVsqp}f9Oi6zcv zo$--_N3mtiDJ+`;WlT_DzJaW<#D1MNqQX5{{C#4~ z?_%vmdk25-3YpiZ!QU3-{R0YQ%|JGCmYob5@_2rc=N1N*2H2k<6TQ0!G1<l<)3PoNnSa14`v3mudB{?(>_AiT=9+3e9B#Z<<`~DN42%!iOR-$ zpj^3f_@Y}k{Hci>(5^Gyx8pBtTAhgHVJQe3eFHN`*l755%p{sIoOOVK9*}JTt3BX! zOyCmVfIXHtr@n!JFLt9!Wp^XlXMf*)#adVksPZ-)Fw<2suTO{f6TB_4LU)*sNcXc~ z;@cM7TiRF;)Tmxv_6^LMIveYkB+2r=aN>2$9(B`7BQxlo&y>kJfq#-+voN@A^y| z-J<=7ZkgzT9NGe!F@b}R&~QvZbB6Lff#Mr5pD&c-2z7A-QwE)+SjDs07I_H^$DeUr zTV$Ir?B8`09;j5?NcPWC_pB>~wBQlg)lIsKJ*Qb)G=+4cKA^v}1xC z_y$4)X)lt{3;2E673^Md1rekJjC=!M`>en{tLZpJ&jRV0tqPDwi|X19z9J1g{no$>zUdw*^L<*#eGZ0_VPg zY~~5HV*;%n(8Ude1e`;}qzm|U{$>36^Hu!0@+x*Mzk-G1&Oy7TK=BWDXf*?Ol``CC zDS`T=yV5Vk|LsFS_6K-Nlgwn-mDhP+p{q1Erk8`_etw>GW6u{Plr-3Lgn9xVe(-Vh z>bMGX#^hv7;HU>=-++OCFh{-tb)LXJCI}muf~8Y0VPp6elJ{%avocks-BRr2E?# z-aFo5Okm_22pgS_@Ci4_Pe}d&XY&M_F@fGU5E^(1^T%AKz0a>;!-A{WxjYSfSEpf* zOeFiO6iUU0d6y~P=xmnth5ft6qWVKm8IAS%+E${<`u-@+3kQK{AE^V$Yr2uly80T& z3>@et;c{wPSTM#EtBL-vNT^iScuY{LWNEzX(FegpFB*>t$Tz_A1V2nn z$EJvz*zr>aq8DW#YJNIa&rZirp*LuK(RG<3r=;P>X=(T=I1S4~uVMA9G;ElkhS)`E z*s<(7_O7`>#Q!!Txo7!TXwT|vbYChK1*K$JU&wn4wR~#`xV+Sxjc7Vu7xVjtBkHEP z+P*F7^7R7Q>5n}WH^BaZA|F5GLVpC;_3Sqm@VA$Yuvzu7gpcZ(j|td^=G9^n%?o50 z>jBw6n1RTt8Q8Y;CibnH)3%^RZP2 znCStw1GYq@VaXKo9R_BN8|c?926gLX`8KB_^ZcJi)V$C;xF~>A1bFRmLF^xplRnR5 zgS`|#aFXWAGhF&@(!v>Qa2=9q54F7}@A{lzGNK8sAG+II4>W4!Zv59i5uY9p&s5#Q16i@S~)j5 zj-gI>kJFAPZYVMcP$ODsKhgfwKV7z$SWf!7_8#7QjAMy-AJRK1o`}oJu|9D$=fV0+ zTc^Apul-a)hx!ukDru|-O5aru|9ia`f(9jJJ0?(K2$i^jStG7v-q`C{7-Xdd=5zdmo;0Dc~>+S2pI=?~h_%l={-W!GE9b8#weOe1zNN8NmSO-w+%5&^& z5A7X3G1dPZ{Cn=i7wwjy)jNTxU++D$m^~x; zPp8fvLL_|qcf8bRtpN3N{>I3;!szcg&2ux28TcK{K7_wXK9ADcWR64TeazWzU_Ej1 zTMI7fh_5k^@8Ns-8GiOJN`up4+k<18b6SquaUadsAn*+dWlY8d)PhDbit-d&Sh

    lf&FGErF~@%s-Wu+3AtpZa!@vjuL4ycN|v zHj|~sI{BGyHHxCj;5`9HflSupo0$C6sTc8HLgXU9z z&dg_@{x8XA!PUh_T1j)Gb+R->&M&ZD;OCj%Ao3u3iRd9B@e>H-2?6p)y-M;QEp$ME z`3ZlG@s(cAQ{#w-1Om4SfoNapHK7Mwr~|yEZM-()HZ`BfMj+r41ZZ9H|7ctgCG3Gb z=>i^0ts`Cfwo4jABq9(fBm_43O7*EP^PFLt&;?F)!41MFlJw?_h16UkTY*4W~RL@P-S*!C^Bd9$LC_D!nq7Mj27#&y3X)J8}Lhei=`#TFL1Ox)N1%U)fDw9n{*ICWFncon=e2Xbxemt85V)$`MDru5H zrj;#8{>C@hk~hsDMtR;O1BER~hUwq5^F54ixM=5BG~&nD`3?mLuvIv~&es;enynku z+VgGx_6#)H+7obd!q*fq!Tyx}NK-&VzNU>0`I-tC^F7o88uRTHFsz?suYfV%-iwX- z_6n-KMsoP6