From 5584acd189724d2bcda296cc5b42e4789a3fdff0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20B=C3=A1lint=20Misius?= Date: Sat, 30 Sep 2023 22:15:38 +0200 Subject: [PATCH 01/27] Add version info to bluescreen --- src/PowderToy.cpp | 4 +++ src/gui/game/IntroText.h | 64 ++++++++++++++++++++++------------------ 2 files changed, 39 insertions(+), 29 deletions(-) diff --git a/src/PowderToy.cpp b/src/PowderToy.cpp index 92d46b99f..515b2b38c 100644 --- a/src/PowderToy.cpp +++ b/src/PowderToy.cpp @@ -17,6 +17,7 @@ #include "gui/Style.h" #include "gui/game/GameController.h" #include "gui/game/GameView.h" +#include "gui/game/IntroText.h" #include "gui/dialogues/ConfirmPrompt.h" #include "gui/dialogues/ErrorMessage.h" #include "gui/interface/Engine.h" @@ -102,6 +103,7 @@ void BlueScreen(String detailMessage) String errorTitle = "ERROR"; String errorDetails = "Details: " + detailMessage; String errorHelp = String("An unrecoverable fault has occurred, please report the error by visiting the website below\n") + SCHEME + SERVER; + auto versionInfo = ByteString::Build("Version: ", VersionInfo(), "\nTag: ", VCS_TAG).FromUtf8(); // We use the width of errorHelp to center, but heights of the individual texts for vertical spacing auto pos = engine.g->Size() / 2 - Vec2(Graphics::TextSize(errorHelp).X / 2, 100); @@ -110,6 +112,8 @@ void BlueScreen(String detailMessage) engine.g->BlendText(pos, errorDetails, 0xFFFFFF_rgb .WithAlpha(0xFF)); pos.Y += 4 + Graphics::TextSize(errorDetails).Y; engine.g->BlendText(pos, errorHelp, 0xFFFFFF_rgb .WithAlpha(0xFF)); + pos.Y += 4 + Graphics::TextSize(errorHelp).Y; + engine.g->BlendText(pos, versionInfo, 0xFFFFFF_rgb .WithAlpha(0xFF)); //Death loop SDL_Event event; diff --git a/src/gui/game/IntroText.h b/src/gui/game/IntroText.h index 83d77c6a0..9ab482324 100644 --- a/src/gui/game/IntroText.h +++ b/src/gui/game/IntroText.h @@ -2,6 +2,40 @@ #include "Config.h" #include "common/String.h" +inline ByteString VersionInfo() +{ + ByteStringBuilder sb; + sb << SAVE_VERSION << "." << MINOR_VERSION << "." << BUILD_NUM << " " << IDENT; + if constexpr (SNAPSHOT) + { + sb << " SNAPSHOT " << SNAPSHOT_ID; + } + else if constexpr (MOD) + { + sb << " MODVER " << SNAPSHOT_ID; + } + if constexpr (LUACONSOLE) + { + sb << " LUACONSOLE"; + } +#ifdef REALISTIC + sb << " REALISTIC"; +#endif + if constexpr (NOHTTP) + { + sb << " NOHTTP"; + } + else if constexpr (ENFORCE_HTTPS) + { + sb << " HTTPS"; + } + if constexpr (DEBUG) + { + sb << " DEBUG"; + } + return sb.Build(); +} + inline ByteString IntroText() { ByteStringBuilder sb; @@ -37,34 +71,6 @@ inline ByteString IntroText() { sb << "\bgTo use online features such as saving, you need to register at: \brhttps://powdertoy.co.uk/Register.html\n"; } - sb << "\n" - << "\bt" << SAVE_VERSION << "." << MINOR_VERSION << "." << BUILD_NUM << " " << IDENT; - if constexpr (SNAPSHOT) - { - sb << " SNAPSHOT " << SNAPSHOT_ID; - } - else if constexpr (MOD) - { - sb << " MODVER " << SNAPSHOT_ID; - } - if constexpr (LUACONSOLE) - { - sb << " LUACONSOLE"; - } -#ifdef REALISTIC - sb << " REALISTIC"; -#endif - if constexpr (NOHTTP) - { - sb << " NOHTTP"; - } - else if constexpr (ENFORCE_HTTPS) - { - sb << " HTTPS"; - } - if constexpr (DEBUG) - { - sb << " DEBUG"; - } + sb << "\n\bt" << VersionInfo(); return sb.Build(); } From baf484653ac29469a0102e2ec805d39886eb69e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20B=C3=A1lint=20Misius?= Date: Tue, 3 Oct 2023 15:59:42 +0200 Subject: [PATCH 02/27] Update tpt-libs --- meson.build | 2 +- ...aarch64-android-bionic-static-debug-v20230819222922.wrap | 6 ------ ...aarch64-android-bionic-static-debug-v20231003175140.wrap | 6 ++++++ ...rch64-android-bionic-static-release-v20230819222922.wrap | 6 ------ ...rch64-android-bionic-static-release-v20231003175140.wrap | 6 ++++++ ...t-aarch64-darwin-macos-static-debug-v20230819222922.wrap | 6 ------ ...t-aarch64-darwin-macos-static-debug-v20231003175140.wrap | 6 ++++++ ...aarch64-darwin-macos-static-release-v20230819222922.wrap | 6 ------ ...aarch64-darwin-macos-static-release-v20231003175140.wrap | 6 ++++++ ...ilt-arm-android-bionic-static-debug-v20230819222922.wrap | 6 ------ ...ilt-arm-android-bionic-static-debug-v20231003175140.wrap | 6 ++++++ ...t-arm-android-bionic-static-release-v20230819222922.wrap | 6 ------ ...t-arm-android-bionic-static-release-v20231003175140.wrap | 6 ++++++ ...-emscripten-emscripten-static-debug-v20230819222922.wrap | 6 ------ ...-emscripten-emscripten-static-debug-v20231003175140.wrap | 6 ++++++ ...mscripten-emscripten-static-release-v20230819222922.wrap | 6 ------ ...mscripten-emscripten-static-release-v20231003175140.wrap | 6 ++++++ ...ilt-x86-android-bionic-static-debug-v20230819222922.wrap | 6 ------ ...ilt-x86-android-bionic-static-debug-v20231003175140.wrap | 6 ++++++ ...t-x86-android-bionic-static-release-v20230819222922.wrap | 6 ------ ...t-x86-android-bionic-static-release-v20231003175140.wrap | 6 ++++++ ...uilt-x86-windows-msvc-dynamic-debug-v20230819222922.wrap | 6 ------ ...uilt-x86-windows-msvc-dynamic-debug-v20231003175140.wrap | 6 ++++++ ...lt-x86-windows-msvc-dynamic-release-v20230819222922.wrap | 6 ------ ...lt-x86-windows-msvc-dynamic-release-v20231003175140.wrap | 6 ++++++ ...built-x86-windows-msvc-static-debug-v20230819222922.wrap | 6 ------ ...built-x86-windows-msvc-static-debug-v20231003175140.wrap | 6 ++++++ ...ilt-x86-windows-msvc-static-release-v20230819222922.wrap | 6 ------ ...ilt-x86-windows-msvc-static-release-v20231003175140.wrap | 6 ++++++ ...-x86_64-android-bionic-static-debug-v20230819222922.wrap | 6 ------ ...-x86_64-android-bionic-static-debug-v20231003175140.wrap | 6 ++++++ ...86_64-android-bionic-static-release-v20230819222922.wrap | 6 ------ ...86_64-android-bionic-static-release-v20231003175140.wrap | 6 ++++++ ...lt-x86_64-darwin-macos-static-debug-v20230819222922.wrap | 6 ------ ...lt-x86_64-darwin-macos-static-debug-v20231003175140.wrap | 6 ++++++ ...-x86_64-darwin-macos-static-release-v20230819222922.wrap | 6 ------ ...-x86_64-darwin-macos-static-release-v20231003175140.wrap | 6 ++++++ ...built-x86_64-linux-gnu-static-debug-v20230819222922.wrap | 6 ------ ...built-x86_64-linux-gnu-static-debug-v20231003175140.wrap | 6 ++++++ ...ilt-x86_64-linux-gnu-static-release-v20230819222922.wrap | 6 ------ ...ilt-x86_64-linux-gnu-static-release-v20231003175140.wrap | 6 ++++++ ...-x86_64-windows-mingw-dynamic-debug-v20230819222922.wrap | 6 ------ ...-x86_64-windows-mingw-dynamic-debug-v20231003175140.wrap | 6 ++++++ ...86_64-windows-mingw-dynamic-release-v20230819222922.wrap | 6 ------ ...86_64-windows-mingw-dynamic-release-v20231003175140.wrap | 6 ++++++ ...t-x86_64-windows-mingw-static-debug-v20230819222922.wrap | 6 ------ ...t-x86_64-windows-mingw-static-debug-v20231003175140.wrap | 6 ++++++ ...x86_64-windows-mingw-static-release-v20230819222922.wrap | 6 ------ ...x86_64-windows-mingw-static-release-v20231003175140.wrap | 6 ++++++ ...t-x86_64-windows-msvc-dynamic-debug-v20230819222922.wrap | 6 ------ ...t-x86_64-windows-msvc-dynamic-debug-v20231003175140.wrap | 6 ++++++ ...x86_64-windows-msvc-dynamic-release-v20230819222922.wrap | 6 ------ ...x86_64-windows-msvc-dynamic-release-v20231003175140.wrap | 6 ++++++ ...lt-x86_64-windows-msvc-static-debug-v20230819222922.wrap | 6 ------ ...lt-x86_64-windows-msvc-static-debug-v20231003175140.wrap | 6 ++++++ ...-x86_64-windows-msvc-static-release-v20230819222922.wrap | 6 ------ ...-x86_64-windows-msvc-static-release-v20231003175140.wrap | 6 ++++++ 57 files changed, 169 insertions(+), 169 deletions(-) delete mode 100644 subprojects/tpt-libs-prebuilt-aarch64-android-bionic-static-debug-v20230819222922.wrap create mode 100644 subprojects/tpt-libs-prebuilt-aarch64-android-bionic-static-debug-v20231003175140.wrap delete mode 100644 subprojects/tpt-libs-prebuilt-aarch64-android-bionic-static-release-v20230819222922.wrap create mode 100644 subprojects/tpt-libs-prebuilt-aarch64-android-bionic-static-release-v20231003175140.wrap delete mode 100644 subprojects/tpt-libs-prebuilt-aarch64-darwin-macos-static-debug-v20230819222922.wrap create mode 100644 subprojects/tpt-libs-prebuilt-aarch64-darwin-macos-static-debug-v20231003175140.wrap delete mode 100644 subprojects/tpt-libs-prebuilt-aarch64-darwin-macos-static-release-v20230819222922.wrap create mode 100644 subprojects/tpt-libs-prebuilt-aarch64-darwin-macos-static-release-v20231003175140.wrap delete mode 100644 subprojects/tpt-libs-prebuilt-arm-android-bionic-static-debug-v20230819222922.wrap create mode 100644 subprojects/tpt-libs-prebuilt-arm-android-bionic-static-debug-v20231003175140.wrap delete mode 100644 subprojects/tpt-libs-prebuilt-arm-android-bionic-static-release-v20230819222922.wrap create mode 100644 subprojects/tpt-libs-prebuilt-arm-android-bionic-static-release-v20231003175140.wrap delete mode 100644 subprojects/tpt-libs-prebuilt-wasm32-emscripten-emscripten-static-debug-v20230819222922.wrap create mode 100644 subprojects/tpt-libs-prebuilt-wasm32-emscripten-emscripten-static-debug-v20231003175140.wrap delete mode 100644 subprojects/tpt-libs-prebuilt-wasm32-emscripten-emscripten-static-release-v20230819222922.wrap create mode 100644 subprojects/tpt-libs-prebuilt-wasm32-emscripten-emscripten-static-release-v20231003175140.wrap delete mode 100644 subprojects/tpt-libs-prebuilt-x86-android-bionic-static-debug-v20230819222922.wrap create mode 100644 subprojects/tpt-libs-prebuilt-x86-android-bionic-static-debug-v20231003175140.wrap delete mode 100644 subprojects/tpt-libs-prebuilt-x86-android-bionic-static-release-v20230819222922.wrap create mode 100644 subprojects/tpt-libs-prebuilt-x86-android-bionic-static-release-v20231003175140.wrap delete mode 100644 subprojects/tpt-libs-prebuilt-x86-windows-msvc-dynamic-debug-v20230819222922.wrap create mode 100644 subprojects/tpt-libs-prebuilt-x86-windows-msvc-dynamic-debug-v20231003175140.wrap delete mode 100644 subprojects/tpt-libs-prebuilt-x86-windows-msvc-dynamic-release-v20230819222922.wrap create mode 100644 subprojects/tpt-libs-prebuilt-x86-windows-msvc-dynamic-release-v20231003175140.wrap delete mode 100644 subprojects/tpt-libs-prebuilt-x86-windows-msvc-static-debug-v20230819222922.wrap create mode 100644 subprojects/tpt-libs-prebuilt-x86-windows-msvc-static-debug-v20231003175140.wrap delete mode 100644 subprojects/tpt-libs-prebuilt-x86-windows-msvc-static-release-v20230819222922.wrap create mode 100644 subprojects/tpt-libs-prebuilt-x86-windows-msvc-static-release-v20231003175140.wrap delete mode 100644 subprojects/tpt-libs-prebuilt-x86_64-android-bionic-static-debug-v20230819222922.wrap create mode 100644 subprojects/tpt-libs-prebuilt-x86_64-android-bionic-static-debug-v20231003175140.wrap delete mode 100644 subprojects/tpt-libs-prebuilt-x86_64-android-bionic-static-release-v20230819222922.wrap create mode 100644 subprojects/tpt-libs-prebuilt-x86_64-android-bionic-static-release-v20231003175140.wrap delete mode 100644 subprojects/tpt-libs-prebuilt-x86_64-darwin-macos-static-debug-v20230819222922.wrap create mode 100644 subprojects/tpt-libs-prebuilt-x86_64-darwin-macos-static-debug-v20231003175140.wrap delete mode 100644 subprojects/tpt-libs-prebuilt-x86_64-darwin-macos-static-release-v20230819222922.wrap create mode 100644 subprojects/tpt-libs-prebuilt-x86_64-darwin-macos-static-release-v20231003175140.wrap delete mode 100644 subprojects/tpt-libs-prebuilt-x86_64-linux-gnu-static-debug-v20230819222922.wrap create mode 100644 subprojects/tpt-libs-prebuilt-x86_64-linux-gnu-static-debug-v20231003175140.wrap delete mode 100644 subprojects/tpt-libs-prebuilt-x86_64-linux-gnu-static-release-v20230819222922.wrap create mode 100644 subprojects/tpt-libs-prebuilt-x86_64-linux-gnu-static-release-v20231003175140.wrap delete mode 100644 subprojects/tpt-libs-prebuilt-x86_64-windows-mingw-dynamic-debug-v20230819222922.wrap create mode 100644 subprojects/tpt-libs-prebuilt-x86_64-windows-mingw-dynamic-debug-v20231003175140.wrap delete mode 100644 subprojects/tpt-libs-prebuilt-x86_64-windows-mingw-dynamic-release-v20230819222922.wrap create mode 100644 subprojects/tpt-libs-prebuilt-x86_64-windows-mingw-dynamic-release-v20231003175140.wrap delete mode 100644 subprojects/tpt-libs-prebuilt-x86_64-windows-mingw-static-debug-v20230819222922.wrap create mode 100644 subprojects/tpt-libs-prebuilt-x86_64-windows-mingw-static-debug-v20231003175140.wrap delete mode 100644 subprojects/tpt-libs-prebuilt-x86_64-windows-mingw-static-release-v20230819222922.wrap create mode 100644 subprojects/tpt-libs-prebuilt-x86_64-windows-mingw-static-release-v20231003175140.wrap delete mode 100644 subprojects/tpt-libs-prebuilt-x86_64-windows-msvc-dynamic-debug-v20230819222922.wrap create mode 100644 subprojects/tpt-libs-prebuilt-x86_64-windows-msvc-dynamic-debug-v20231003175140.wrap delete mode 100644 subprojects/tpt-libs-prebuilt-x86_64-windows-msvc-dynamic-release-v20230819222922.wrap create mode 100644 subprojects/tpt-libs-prebuilt-x86_64-windows-msvc-dynamic-release-v20231003175140.wrap delete mode 100644 subprojects/tpt-libs-prebuilt-x86_64-windows-msvc-static-debug-v20230819222922.wrap create mode 100644 subprojects/tpt-libs-prebuilt-x86_64-windows-msvc-static-debug-v20231003175140.wrap delete mode 100644 subprojects/tpt-libs-prebuilt-x86_64-windows-msvc-static-release-v20230819222922.wrap create mode 100644 subprojects/tpt-libs-prebuilt-x86_64-windows-msvc-static-release-v20231003175140.wrap diff --git a/meson.build b/meson.build index 6ea9abc4b..2d56592d9 100644 --- a/meson.build +++ b/meson.build @@ -88,7 +88,7 @@ tpt_libs_debug = is_debug ? 'debug' : 'release' tpt_libs_variant = '@0@-@1@-@2@-@3@'.format(host_arch, host_platform, host_libc, tpt_libs_static) tpt_libs_vtag = get_option('tpt_libs_vtag') if tpt_libs_vtag == '' - tpt_libs_vtag = 'v20230819222922' + tpt_libs_vtag = 'v20231003175140' endif if tpt_libs_static != 'none' if tpt_libs_variant not in [ diff --git a/subprojects/tpt-libs-prebuilt-aarch64-android-bionic-static-debug-v20230819222922.wrap b/subprojects/tpt-libs-prebuilt-aarch64-android-bionic-static-debug-v20230819222922.wrap deleted file mode 100644 index 14be8e44b..000000000 --- a/subprojects/tpt-libs-prebuilt-aarch64-android-bionic-static-debug-v20230819222922.wrap +++ /dev/null @@ -1,6 +0,0 @@ -[wrap-file] -directory = tpt-libs-prebuilt-aarch64-android-bionic-static-debug-v20230819222922 - -source_url = https://github.com/The-Powder-Toy/tpt-libs/releases/download/v20230819222922/tpt-libs-prebuilt-aarch64-android-bionic-static-debug-v20230819222922.zip -source_filename = tpt-libs-prebuilt-aarch64-android-bionic-static-debug-v20230819222922.zip -source_hash = 0541c47779ac3e0fadeb67093669af3e196faae140c2b04a744fe764cad72393 diff --git a/subprojects/tpt-libs-prebuilt-aarch64-android-bionic-static-debug-v20231003175140.wrap b/subprojects/tpt-libs-prebuilt-aarch64-android-bionic-static-debug-v20231003175140.wrap new file mode 100644 index 000000000..469d3b9b9 --- /dev/null +++ b/subprojects/tpt-libs-prebuilt-aarch64-android-bionic-static-debug-v20231003175140.wrap @@ -0,0 +1,6 @@ +[wrap-file] +directory = tpt-libs-prebuilt-aarch64-android-bionic-static-debug-v20231003175140 + +source_url = https://github.com/The-Powder-Toy/tpt-libs/releases/download/v20231003175140/tpt-libs-prebuilt-aarch64-android-bionic-static-debug-v20231003175140.zip +source_filename = tpt-libs-prebuilt-aarch64-android-bionic-static-debug-v20231003175140.zip +source_hash = 7648a1c16bcc182457207698bbc8d4a3e5c2bc97e195153caf954b69133f8ef4 diff --git a/subprojects/tpt-libs-prebuilt-aarch64-android-bionic-static-release-v20230819222922.wrap b/subprojects/tpt-libs-prebuilt-aarch64-android-bionic-static-release-v20230819222922.wrap deleted file mode 100644 index dde387dbf..000000000 --- a/subprojects/tpt-libs-prebuilt-aarch64-android-bionic-static-release-v20230819222922.wrap +++ /dev/null @@ -1,6 +0,0 @@ -[wrap-file] -directory = tpt-libs-prebuilt-aarch64-android-bionic-static-release-v20230819222922 - -source_url = https://github.com/The-Powder-Toy/tpt-libs/releases/download/v20230819222922/tpt-libs-prebuilt-aarch64-android-bionic-static-release-v20230819222922.zip -source_filename = tpt-libs-prebuilt-aarch64-android-bionic-static-release-v20230819222922.zip -source_hash = b36e77653e3855ec43762fc6024419a943b618ff91ae39d6d0e59bf53403bb78 diff --git a/subprojects/tpt-libs-prebuilt-aarch64-android-bionic-static-release-v20231003175140.wrap b/subprojects/tpt-libs-prebuilt-aarch64-android-bionic-static-release-v20231003175140.wrap new file mode 100644 index 000000000..8b78de985 --- /dev/null +++ b/subprojects/tpt-libs-prebuilt-aarch64-android-bionic-static-release-v20231003175140.wrap @@ -0,0 +1,6 @@ +[wrap-file] +directory = tpt-libs-prebuilt-aarch64-android-bionic-static-release-v20231003175140 + +source_url = https://github.com/The-Powder-Toy/tpt-libs/releases/download/v20231003175140/tpt-libs-prebuilt-aarch64-android-bionic-static-release-v20231003175140.zip +source_filename = tpt-libs-prebuilt-aarch64-android-bionic-static-release-v20231003175140.zip +source_hash = ca4aa82d29d1919c91b5d9d605b44476baa6bfbf785ffb0258667400659eaa41 diff --git a/subprojects/tpt-libs-prebuilt-aarch64-darwin-macos-static-debug-v20230819222922.wrap b/subprojects/tpt-libs-prebuilt-aarch64-darwin-macos-static-debug-v20230819222922.wrap deleted file mode 100644 index 5eac193d4..000000000 --- a/subprojects/tpt-libs-prebuilt-aarch64-darwin-macos-static-debug-v20230819222922.wrap +++ /dev/null @@ -1,6 +0,0 @@ -[wrap-file] -directory = tpt-libs-prebuilt-aarch64-darwin-macos-static-debug-v20230819222922 - -source_url = https://github.com/The-Powder-Toy/tpt-libs/releases/download/v20230819222922/tpt-libs-prebuilt-aarch64-darwin-macos-static-debug-v20230819222922.zip -source_filename = tpt-libs-prebuilt-aarch64-darwin-macos-static-debug-v20230819222922.zip -source_hash = c3bde6110671d7704a3026269f384d022771a6a1f2573c7953884e99048c20d8 diff --git a/subprojects/tpt-libs-prebuilt-aarch64-darwin-macos-static-debug-v20231003175140.wrap b/subprojects/tpt-libs-prebuilt-aarch64-darwin-macos-static-debug-v20231003175140.wrap new file mode 100644 index 000000000..a67be440d --- /dev/null +++ b/subprojects/tpt-libs-prebuilt-aarch64-darwin-macos-static-debug-v20231003175140.wrap @@ -0,0 +1,6 @@ +[wrap-file] +directory = tpt-libs-prebuilt-aarch64-darwin-macos-static-debug-v20231003175140 + +source_url = https://github.com/The-Powder-Toy/tpt-libs/releases/download/v20231003175140/tpt-libs-prebuilt-aarch64-darwin-macos-static-debug-v20231003175140.zip +source_filename = tpt-libs-prebuilt-aarch64-darwin-macos-static-debug-v20231003175140.zip +source_hash = 12901681aeebdcda7e35db9cf28a084620f448c416b235662dca7cc257a6890b diff --git a/subprojects/tpt-libs-prebuilt-aarch64-darwin-macos-static-release-v20230819222922.wrap b/subprojects/tpt-libs-prebuilt-aarch64-darwin-macos-static-release-v20230819222922.wrap deleted file mode 100644 index ebc892d23..000000000 --- a/subprojects/tpt-libs-prebuilt-aarch64-darwin-macos-static-release-v20230819222922.wrap +++ /dev/null @@ -1,6 +0,0 @@ -[wrap-file] -directory = tpt-libs-prebuilt-aarch64-darwin-macos-static-release-v20230819222922 - -source_url = https://github.com/The-Powder-Toy/tpt-libs/releases/download/v20230819222922/tpt-libs-prebuilt-aarch64-darwin-macos-static-release-v20230819222922.zip -source_filename = tpt-libs-prebuilt-aarch64-darwin-macos-static-release-v20230819222922.zip -source_hash = 9be581acae1300707505f0d4af0af81fda7de1733f31740f428154488100657e diff --git a/subprojects/tpt-libs-prebuilt-aarch64-darwin-macos-static-release-v20231003175140.wrap b/subprojects/tpt-libs-prebuilt-aarch64-darwin-macos-static-release-v20231003175140.wrap new file mode 100644 index 000000000..add0d790c --- /dev/null +++ b/subprojects/tpt-libs-prebuilt-aarch64-darwin-macos-static-release-v20231003175140.wrap @@ -0,0 +1,6 @@ +[wrap-file] +directory = tpt-libs-prebuilt-aarch64-darwin-macos-static-release-v20231003175140 + +source_url = https://github.com/The-Powder-Toy/tpt-libs/releases/download/v20231003175140/tpt-libs-prebuilt-aarch64-darwin-macos-static-release-v20231003175140.zip +source_filename = tpt-libs-prebuilt-aarch64-darwin-macos-static-release-v20231003175140.zip +source_hash = 93a190ecd1e5180bbb1864ef7bb358960ee77dfa2f071f9172f2f454af366c98 diff --git a/subprojects/tpt-libs-prebuilt-arm-android-bionic-static-debug-v20230819222922.wrap b/subprojects/tpt-libs-prebuilt-arm-android-bionic-static-debug-v20230819222922.wrap deleted file mode 100644 index 7bd913124..000000000 --- a/subprojects/tpt-libs-prebuilt-arm-android-bionic-static-debug-v20230819222922.wrap +++ /dev/null @@ -1,6 +0,0 @@ -[wrap-file] -directory = tpt-libs-prebuilt-arm-android-bionic-static-debug-v20230819222922 - -source_url = https://github.com/The-Powder-Toy/tpt-libs/releases/download/v20230819222922/tpt-libs-prebuilt-arm-android-bionic-static-debug-v20230819222922.zip -source_filename = tpt-libs-prebuilt-arm-android-bionic-static-debug-v20230819222922.zip -source_hash = 64b0b73af47a4af0eb6eda482b5fbfc4614d69d017fd92cbaea6a6500b6ccd4c diff --git a/subprojects/tpt-libs-prebuilt-arm-android-bionic-static-debug-v20231003175140.wrap b/subprojects/tpt-libs-prebuilt-arm-android-bionic-static-debug-v20231003175140.wrap new file mode 100644 index 000000000..b9b20f20f --- /dev/null +++ b/subprojects/tpt-libs-prebuilt-arm-android-bionic-static-debug-v20231003175140.wrap @@ -0,0 +1,6 @@ +[wrap-file] +directory = tpt-libs-prebuilt-arm-android-bionic-static-debug-v20231003175140 + +source_url = https://github.com/The-Powder-Toy/tpt-libs/releases/download/v20231003175140/tpt-libs-prebuilt-arm-android-bionic-static-debug-v20231003175140.zip +source_filename = tpt-libs-prebuilt-arm-android-bionic-static-debug-v20231003175140.zip +source_hash = 82ecadcafda676e9d48a819dda2eddf2faa9a1506063bcf4b069e59a4a245139 diff --git a/subprojects/tpt-libs-prebuilt-arm-android-bionic-static-release-v20230819222922.wrap b/subprojects/tpt-libs-prebuilt-arm-android-bionic-static-release-v20230819222922.wrap deleted file mode 100644 index 438e605a2..000000000 --- a/subprojects/tpt-libs-prebuilt-arm-android-bionic-static-release-v20230819222922.wrap +++ /dev/null @@ -1,6 +0,0 @@ -[wrap-file] -directory = tpt-libs-prebuilt-arm-android-bionic-static-release-v20230819222922 - -source_url = https://github.com/The-Powder-Toy/tpt-libs/releases/download/v20230819222922/tpt-libs-prebuilt-arm-android-bionic-static-release-v20230819222922.zip -source_filename = tpt-libs-prebuilt-arm-android-bionic-static-release-v20230819222922.zip -source_hash = 390aa72c827194fdd1dbfabafceb487472a3a3dcc383bd21296a8bfb508127c1 diff --git a/subprojects/tpt-libs-prebuilt-arm-android-bionic-static-release-v20231003175140.wrap b/subprojects/tpt-libs-prebuilt-arm-android-bionic-static-release-v20231003175140.wrap new file mode 100644 index 000000000..0d97aa541 --- /dev/null +++ b/subprojects/tpt-libs-prebuilt-arm-android-bionic-static-release-v20231003175140.wrap @@ -0,0 +1,6 @@ +[wrap-file] +directory = tpt-libs-prebuilt-arm-android-bionic-static-release-v20231003175140 + +source_url = https://github.com/The-Powder-Toy/tpt-libs/releases/download/v20231003175140/tpt-libs-prebuilt-arm-android-bionic-static-release-v20231003175140.zip +source_filename = tpt-libs-prebuilt-arm-android-bionic-static-release-v20231003175140.zip +source_hash = ee0fc5475d9cce7e7d375415a1edb5ab2329db0aecff05a9e10fb1a29045f117 diff --git a/subprojects/tpt-libs-prebuilt-wasm32-emscripten-emscripten-static-debug-v20230819222922.wrap b/subprojects/tpt-libs-prebuilt-wasm32-emscripten-emscripten-static-debug-v20230819222922.wrap deleted file mode 100644 index eb5f21f05..000000000 --- a/subprojects/tpt-libs-prebuilt-wasm32-emscripten-emscripten-static-debug-v20230819222922.wrap +++ /dev/null @@ -1,6 +0,0 @@ -[wrap-file] -directory = tpt-libs-prebuilt-wasm32-emscripten-emscripten-static-debug-v20230819222922 - -source_url = https://github.com/The-Powder-Toy/tpt-libs/releases/download/v20230819222922/tpt-libs-prebuilt-wasm32-emscripten-emscripten-static-debug-v20230819222922.zip -source_filename = tpt-libs-prebuilt-wasm32-emscripten-emscripten-static-debug-v20230819222922.zip -source_hash = 00a50b3863b9846f5ee3820c55f69aa612a710e1db02f59b9944be43db132ea1 diff --git a/subprojects/tpt-libs-prebuilt-wasm32-emscripten-emscripten-static-debug-v20231003175140.wrap b/subprojects/tpt-libs-prebuilt-wasm32-emscripten-emscripten-static-debug-v20231003175140.wrap new file mode 100644 index 000000000..1111c2bc6 --- /dev/null +++ b/subprojects/tpt-libs-prebuilt-wasm32-emscripten-emscripten-static-debug-v20231003175140.wrap @@ -0,0 +1,6 @@ +[wrap-file] +directory = tpt-libs-prebuilt-wasm32-emscripten-emscripten-static-debug-v20231003175140 + +source_url = https://github.com/The-Powder-Toy/tpt-libs/releases/download/v20231003175140/tpt-libs-prebuilt-wasm32-emscripten-emscripten-static-debug-v20231003175140.zip +source_filename = tpt-libs-prebuilt-wasm32-emscripten-emscripten-static-debug-v20231003175140.zip +source_hash = c75e9928c23b8dc210b2ea4ad608f59c02a672844cd7fee9e8d8507f758c8b1d diff --git a/subprojects/tpt-libs-prebuilt-wasm32-emscripten-emscripten-static-release-v20230819222922.wrap b/subprojects/tpt-libs-prebuilt-wasm32-emscripten-emscripten-static-release-v20230819222922.wrap deleted file mode 100644 index 4f1ed14b8..000000000 --- a/subprojects/tpt-libs-prebuilt-wasm32-emscripten-emscripten-static-release-v20230819222922.wrap +++ /dev/null @@ -1,6 +0,0 @@ -[wrap-file] -directory = tpt-libs-prebuilt-wasm32-emscripten-emscripten-static-release-v20230819222922 - -source_url = https://github.com/The-Powder-Toy/tpt-libs/releases/download/v20230819222922/tpt-libs-prebuilt-wasm32-emscripten-emscripten-static-release-v20230819222922.zip -source_filename = tpt-libs-prebuilt-wasm32-emscripten-emscripten-static-release-v20230819222922.zip -source_hash = 38bad42affb8de3c5550c5d1e8c196260f3762852f6025c8e2f236305e9679c2 diff --git a/subprojects/tpt-libs-prebuilt-wasm32-emscripten-emscripten-static-release-v20231003175140.wrap b/subprojects/tpt-libs-prebuilt-wasm32-emscripten-emscripten-static-release-v20231003175140.wrap new file mode 100644 index 000000000..0eaf74080 --- /dev/null +++ b/subprojects/tpt-libs-prebuilt-wasm32-emscripten-emscripten-static-release-v20231003175140.wrap @@ -0,0 +1,6 @@ +[wrap-file] +directory = tpt-libs-prebuilt-wasm32-emscripten-emscripten-static-release-v20231003175140 + +source_url = https://github.com/The-Powder-Toy/tpt-libs/releases/download/v20231003175140/tpt-libs-prebuilt-wasm32-emscripten-emscripten-static-release-v20231003175140.zip +source_filename = tpt-libs-prebuilt-wasm32-emscripten-emscripten-static-release-v20231003175140.zip +source_hash = d8b859257a8e5b87fed5316b6a6ff1415a86dce097c89a07dd25ecb74256f01d diff --git a/subprojects/tpt-libs-prebuilt-x86-android-bionic-static-debug-v20230819222922.wrap b/subprojects/tpt-libs-prebuilt-x86-android-bionic-static-debug-v20230819222922.wrap deleted file mode 100644 index e1fca0e3d..000000000 --- a/subprojects/tpt-libs-prebuilt-x86-android-bionic-static-debug-v20230819222922.wrap +++ /dev/null @@ -1,6 +0,0 @@ -[wrap-file] -directory = tpt-libs-prebuilt-x86-android-bionic-static-debug-v20230819222922 - -source_url = https://github.com/The-Powder-Toy/tpt-libs/releases/download/v20230819222922/tpt-libs-prebuilt-x86-android-bionic-static-debug-v20230819222922.zip -source_filename = tpt-libs-prebuilt-x86-android-bionic-static-debug-v20230819222922.zip -source_hash = 4ecd9e0fc21de8ccce5d47b75c9a2116098bd2c5e47a1fc743637991f4aa4d52 diff --git a/subprojects/tpt-libs-prebuilt-x86-android-bionic-static-debug-v20231003175140.wrap b/subprojects/tpt-libs-prebuilt-x86-android-bionic-static-debug-v20231003175140.wrap new file mode 100644 index 000000000..afdff6012 --- /dev/null +++ b/subprojects/tpt-libs-prebuilt-x86-android-bionic-static-debug-v20231003175140.wrap @@ -0,0 +1,6 @@ +[wrap-file] +directory = tpt-libs-prebuilt-x86-android-bionic-static-debug-v20231003175140 + +source_url = https://github.com/The-Powder-Toy/tpt-libs/releases/download/v20231003175140/tpt-libs-prebuilt-x86-android-bionic-static-debug-v20231003175140.zip +source_filename = tpt-libs-prebuilt-x86-android-bionic-static-debug-v20231003175140.zip +source_hash = 2a1142ece24e44a3c7a5e7103fa8b5d637978ab16f2455b866c3560391cb036b diff --git a/subprojects/tpt-libs-prebuilt-x86-android-bionic-static-release-v20230819222922.wrap b/subprojects/tpt-libs-prebuilt-x86-android-bionic-static-release-v20230819222922.wrap deleted file mode 100644 index c81c3f3dd..000000000 --- a/subprojects/tpt-libs-prebuilt-x86-android-bionic-static-release-v20230819222922.wrap +++ /dev/null @@ -1,6 +0,0 @@ -[wrap-file] -directory = tpt-libs-prebuilt-x86-android-bionic-static-release-v20230819222922 - -source_url = https://github.com/The-Powder-Toy/tpt-libs/releases/download/v20230819222922/tpt-libs-prebuilt-x86-android-bionic-static-release-v20230819222922.zip -source_filename = tpt-libs-prebuilt-x86-android-bionic-static-release-v20230819222922.zip -source_hash = 673ae7e89cc807a5c0f2824a7cea7324d59cb888b73ea11031aea4766c797736 diff --git a/subprojects/tpt-libs-prebuilt-x86-android-bionic-static-release-v20231003175140.wrap b/subprojects/tpt-libs-prebuilt-x86-android-bionic-static-release-v20231003175140.wrap new file mode 100644 index 000000000..16603fb36 --- /dev/null +++ b/subprojects/tpt-libs-prebuilt-x86-android-bionic-static-release-v20231003175140.wrap @@ -0,0 +1,6 @@ +[wrap-file] +directory = tpt-libs-prebuilt-x86-android-bionic-static-release-v20231003175140 + +source_url = https://github.com/The-Powder-Toy/tpt-libs/releases/download/v20231003175140/tpt-libs-prebuilt-x86-android-bionic-static-release-v20231003175140.zip +source_filename = tpt-libs-prebuilt-x86-android-bionic-static-release-v20231003175140.zip +source_hash = 1d2db7882c8b25293b516ef132fac6e0f83d169cc279d7433bbe6e62dc4ec951 diff --git a/subprojects/tpt-libs-prebuilt-x86-windows-msvc-dynamic-debug-v20230819222922.wrap b/subprojects/tpt-libs-prebuilt-x86-windows-msvc-dynamic-debug-v20230819222922.wrap deleted file mode 100644 index fc2aa0994..000000000 --- a/subprojects/tpt-libs-prebuilt-x86-windows-msvc-dynamic-debug-v20230819222922.wrap +++ /dev/null @@ -1,6 +0,0 @@ -[wrap-file] -directory = tpt-libs-prebuilt-x86-windows-msvc-dynamic-debug-v20230819222922 - -source_url = https://github.com/The-Powder-Toy/tpt-libs/releases/download/v20230819222922/tpt-libs-prebuilt-x86-windows-msvc-dynamic-debug-v20230819222922.zip -source_filename = tpt-libs-prebuilt-x86-windows-msvc-dynamic-debug-v20230819222922.zip -source_hash = ed0a65942a6200b0fd1a567c98a57b0915513edba59d0178d147d6851131fe50 diff --git a/subprojects/tpt-libs-prebuilt-x86-windows-msvc-dynamic-debug-v20231003175140.wrap b/subprojects/tpt-libs-prebuilt-x86-windows-msvc-dynamic-debug-v20231003175140.wrap new file mode 100644 index 000000000..d3f170f7d --- /dev/null +++ b/subprojects/tpt-libs-prebuilt-x86-windows-msvc-dynamic-debug-v20231003175140.wrap @@ -0,0 +1,6 @@ +[wrap-file] +directory = tpt-libs-prebuilt-x86-windows-msvc-dynamic-debug-v20231003175140 + +source_url = https://github.com/The-Powder-Toy/tpt-libs/releases/download/v20231003175140/tpt-libs-prebuilt-x86-windows-msvc-dynamic-debug-v20231003175140.zip +source_filename = tpt-libs-prebuilt-x86-windows-msvc-dynamic-debug-v20231003175140.zip +source_hash = 2c37f08082b70ee633b4d2664a93b1952c4257029f93befe6136a98e60ba022e diff --git a/subprojects/tpt-libs-prebuilt-x86-windows-msvc-dynamic-release-v20230819222922.wrap b/subprojects/tpt-libs-prebuilt-x86-windows-msvc-dynamic-release-v20230819222922.wrap deleted file mode 100644 index c830bcd9d..000000000 --- a/subprojects/tpt-libs-prebuilt-x86-windows-msvc-dynamic-release-v20230819222922.wrap +++ /dev/null @@ -1,6 +0,0 @@ -[wrap-file] -directory = tpt-libs-prebuilt-x86-windows-msvc-dynamic-release-v20230819222922 - -source_url = https://github.com/The-Powder-Toy/tpt-libs/releases/download/v20230819222922/tpt-libs-prebuilt-x86-windows-msvc-dynamic-release-v20230819222922.zip -source_filename = tpt-libs-prebuilt-x86-windows-msvc-dynamic-release-v20230819222922.zip -source_hash = 790959192dcf11a27cfb2747af80d4ccb1d63fc3ae68ff53392879d1be5c7ecc diff --git a/subprojects/tpt-libs-prebuilt-x86-windows-msvc-dynamic-release-v20231003175140.wrap b/subprojects/tpt-libs-prebuilt-x86-windows-msvc-dynamic-release-v20231003175140.wrap new file mode 100644 index 000000000..c68113b2f --- /dev/null +++ b/subprojects/tpt-libs-prebuilt-x86-windows-msvc-dynamic-release-v20231003175140.wrap @@ -0,0 +1,6 @@ +[wrap-file] +directory = tpt-libs-prebuilt-x86-windows-msvc-dynamic-release-v20231003175140 + +source_url = https://github.com/The-Powder-Toy/tpt-libs/releases/download/v20231003175140/tpt-libs-prebuilt-x86-windows-msvc-dynamic-release-v20231003175140.zip +source_filename = tpt-libs-prebuilt-x86-windows-msvc-dynamic-release-v20231003175140.zip +source_hash = e166842489534ccf53afb178e8b42e438c15ed0adccb4ebd2e7f4a3182ec6bcf diff --git a/subprojects/tpt-libs-prebuilt-x86-windows-msvc-static-debug-v20230819222922.wrap b/subprojects/tpt-libs-prebuilt-x86-windows-msvc-static-debug-v20230819222922.wrap deleted file mode 100644 index 18920cb1a..000000000 --- a/subprojects/tpt-libs-prebuilt-x86-windows-msvc-static-debug-v20230819222922.wrap +++ /dev/null @@ -1,6 +0,0 @@ -[wrap-file] -directory = tpt-libs-prebuilt-x86-windows-msvc-static-debug-v20230819222922 - -source_url = https://github.com/The-Powder-Toy/tpt-libs/releases/download/v20230819222922/tpt-libs-prebuilt-x86-windows-msvc-static-debug-v20230819222922.zip -source_filename = tpt-libs-prebuilt-x86-windows-msvc-static-debug-v20230819222922.zip -source_hash = 5aedb31d4ddf48bbb7cc9f0f9c6add4f371f61afa6d50a3be331497e92a36eee diff --git a/subprojects/tpt-libs-prebuilt-x86-windows-msvc-static-debug-v20231003175140.wrap b/subprojects/tpt-libs-prebuilt-x86-windows-msvc-static-debug-v20231003175140.wrap new file mode 100644 index 000000000..147a181ca --- /dev/null +++ b/subprojects/tpt-libs-prebuilt-x86-windows-msvc-static-debug-v20231003175140.wrap @@ -0,0 +1,6 @@ +[wrap-file] +directory = tpt-libs-prebuilt-x86-windows-msvc-static-debug-v20231003175140 + +source_url = https://github.com/The-Powder-Toy/tpt-libs/releases/download/v20231003175140/tpt-libs-prebuilt-x86-windows-msvc-static-debug-v20231003175140.zip +source_filename = tpt-libs-prebuilt-x86-windows-msvc-static-debug-v20231003175140.zip +source_hash = aa7b274ccf28dc0bf9b139165d23ab5a2acbd158f8c0dfc219d71515d39dd2e7 diff --git a/subprojects/tpt-libs-prebuilt-x86-windows-msvc-static-release-v20230819222922.wrap b/subprojects/tpt-libs-prebuilt-x86-windows-msvc-static-release-v20230819222922.wrap deleted file mode 100644 index 36664dd89..000000000 --- a/subprojects/tpt-libs-prebuilt-x86-windows-msvc-static-release-v20230819222922.wrap +++ /dev/null @@ -1,6 +0,0 @@ -[wrap-file] -directory = tpt-libs-prebuilt-x86-windows-msvc-static-release-v20230819222922 - -source_url = https://github.com/The-Powder-Toy/tpt-libs/releases/download/v20230819222922/tpt-libs-prebuilt-x86-windows-msvc-static-release-v20230819222922.zip -source_filename = tpt-libs-prebuilt-x86-windows-msvc-static-release-v20230819222922.zip -source_hash = a19ec2bfcb02c36d87a5a5783a06b6a9dfffb2a46276ffc5a6ed21fabf513b52 diff --git a/subprojects/tpt-libs-prebuilt-x86-windows-msvc-static-release-v20231003175140.wrap b/subprojects/tpt-libs-prebuilt-x86-windows-msvc-static-release-v20231003175140.wrap new file mode 100644 index 000000000..aba611679 --- /dev/null +++ b/subprojects/tpt-libs-prebuilt-x86-windows-msvc-static-release-v20231003175140.wrap @@ -0,0 +1,6 @@ +[wrap-file] +directory = tpt-libs-prebuilt-x86-windows-msvc-static-release-v20231003175140 + +source_url = https://github.com/The-Powder-Toy/tpt-libs/releases/download/v20231003175140/tpt-libs-prebuilt-x86-windows-msvc-static-release-v20231003175140.zip +source_filename = tpt-libs-prebuilt-x86-windows-msvc-static-release-v20231003175140.zip +source_hash = 373b849bc92507475b906c79767274b59b3383a2a90e2964423663171483ce3b diff --git a/subprojects/tpt-libs-prebuilt-x86_64-android-bionic-static-debug-v20230819222922.wrap b/subprojects/tpt-libs-prebuilt-x86_64-android-bionic-static-debug-v20230819222922.wrap deleted file mode 100644 index 01f607c59..000000000 --- a/subprojects/tpt-libs-prebuilt-x86_64-android-bionic-static-debug-v20230819222922.wrap +++ /dev/null @@ -1,6 +0,0 @@ -[wrap-file] -directory = tpt-libs-prebuilt-x86_64-android-bionic-static-debug-v20230819222922 - -source_url = https://github.com/The-Powder-Toy/tpt-libs/releases/download/v20230819222922/tpt-libs-prebuilt-x86_64-android-bionic-static-debug-v20230819222922.zip -source_filename = tpt-libs-prebuilt-x86_64-android-bionic-static-debug-v20230819222922.zip -source_hash = 3dc7d57a802b766ff934c3c6dba7ea5c58d59ae9bccf81d179a767e6f6929ba4 diff --git a/subprojects/tpt-libs-prebuilt-x86_64-android-bionic-static-debug-v20231003175140.wrap b/subprojects/tpt-libs-prebuilt-x86_64-android-bionic-static-debug-v20231003175140.wrap new file mode 100644 index 000000000..686fd7c1d --- /dev/null +++ b/subprojects/tpt-libs-prebuilt-x86_64-android-bionic-static-debug-v20231003175140.wrap @@ -0,0 +1,6 @@ +[wrap-file] +directory = tpt-libs-prebuilt-x86_64-android-bionic-static-debug-v20231003175140 + +source_url = https://github.com/The-Powder-Toy/tpt-libs/releases/download/v20231003175140/tpt-libs-prebuilt-x86_64-android-bionic-static-debug-v20231003175140.zip +source_filename = tpt-libs-prebuilt-x86_64-android-bionic-static-debug-v20231003175140.zip +source_hash = 5267b97efcbc5070059330af90cec0ae78c257e508975168f9c5578671984f79 diff --git a/subprojects/tpt-libs-prebuilt-x86_64-android-bionic-static-release-v20230819222922.wrap b/subprojects/tpt-libs-prebuilt-x86_64-android-bionic-static-release-v20230819222922.wrap deleted file mode 100644 index 35e1f94b5..000000000 --- a/subprojects/tpt-libs-prebuilt-x86_64-android-bionic-static-release-v20230819222922.wrap +++ /dev/null @@ -1,6 +0,0 @@ -[wrap-file] -directory = tpt-libs-prebuilt-x86_64-android-bionic-static-release-v20230819222922 - -source_url = https://github.com/The-Powder-Toy/tpt-libs/releases/download/v20230819222922/tpt-libs-prebuilt-x86_64-android-bionic-static-release-v20230819222922.zip -source_filename = tpt-libs-prebuilt-x86_64-android-bionic-static-release-v20230819222922.zip -source_hash = 310bc7fc68f3d23c24ee31f7d6ceb56ca8dd01167134e9fc66afde464a19ed36 diff --git a/subprojects/tpt-libs-prebuilt-x86_64-android-bionic-static-release-v20231003175140.wrap b/subprojects/tpt-libs-prebuilt-x86_64-android-bionic-static-release-v20231003175140.wrap new file mode 100644 index 000000000..e0422cdc3 --- /dev/null +++ b/subprojects/tpt-libs-prebuilt-x86_64-android-bionic-static-release-v20231003175140.wrap @@ -0,0 +1,6 @@ +[wrap-file] +directory = tpt-libs-prebuilt-x86_64-android-bionic-static-release-v20231003175140 + +source_url = https://github.com/The-Powder-Toy/tpt-libs/releases/download/v20231003175140/tpt-libs-prebuilt-x86_64-android-bionic-static-release-v20231003175140.zip +source_filename = tpt-libs-prebuilt-x86_64-android-bionic-static-release-v20231003175140.zip +source_hash = 1db9601b4a745c1a0c9c16133d3cbe66ae0023a99c7004e76494b4b54048bcc5 diff --git a/subprojects/tpt-libs-prebuilt-x86_64-darwin-macos-static-debug-v20230819222922.wrap b/subprojects/tpt-libs-prebuilt-x86_64-darwin-macos-static-debug-v20230819222922.wrap deleted file mode 100644 index 15d58464d..000000000 --- a/subprojects/tpt-libs-prebuilt-x86_64-darwin-macos-static-debug-v20230819222922.wrap +++ /dev/null @@ -1,6 +0,0 @@ -[wrap-file] -directory = tpt-libs-prebuilt-x86_64-darwin-macos-static-debug-v20230819222922 - -source_url = https://github.com/The-Powder-Toy/tpt-libs/releases/download/v20230819222922/tpt-libs-prebuilt-x86_64-darwin-macos-static-debug-v20230819222922.zip -source_filename = tpt-libs-prebuilt-x86_64-darwin-macos-static-debug-v20230819222922.zip -source_hash = 02dc73c4a1732ab8ac5667eca155b896a872ee362e9add53ed950333212bf99e diff --git a/subprojects/tpt-libs-prebuilt-x86_64-darwin-macos-static-debug-v20231003175140.wrap b/subprojects/tpt-libs-prebuilt-x86_64-darwin-macos-static-debug-v20231003175140.wrap new file mode 100644 index 000000000..98a9bf013 --- /dev/null +++ b/subprojects/tpt-libs-prebuilt-x86_64-darwin-macos-static-debug-v20231003175140.wrap @@ -0,0 +1,6 @@ +[wrap-file] +directory = tpt-libs-prebuilt-x86_64-darwin-macos-static-debug-v20231003175140 + +source_url = https://github.com/The-Powder-Toy/tpt-libs/releases/download/v20231003175140/tpt-libs-prebuilt-x86_64-darwin-macos-static-debug-v20231003175140.zip +source_filename = tpt-libs-prebuilt-x86_64-darwin-macos-static-debug-v20231003175140.zip +source_hash = 98e751366b6ec9eac5690a25aaf569915f6d3db26102e7640efae39f36a495cb diff --git a/subprojects/tpt-libs-prebuilt-x86_64-darwin-macos-static-release-v20230819222922.wrap b/subprojects/tpt-libs-prebuilt-x86_64-darwin-macos-static-release-v20230819222922.wrap deleted file mode 100644 index cee3e228a..000000000 --- a/subprojects/tpt-libs-prebuilt-x86_64-darwin-macos-static-release-v20230819222922.wrap +++ /dev/null @@ -1,6 +0,0 @@ -[wrap-file] -directory = tpt-libs-prebuilt-x86_64-darwin-macos-static-release-v20230819222922 - -source_url = https://github.com/The-Powder-Toy/tpt-libs/releases/download/v20230819222922/tpt-libs-prebuilt-x86_64-darwin-macos-static-release-v20230819222922.zip -source_filename = tpt-libs-prebuilt-x86_64-darwin-macos-static-release-v20230819222922.zip -source_hash = 70fe0dc9972a94154e8e3a58546e406d36c1d4049dcdeacddd60f83cbe9e62e4 diff --git a/subprojects/tpt-libs-prebuilt-x86_64-darwin-macos-static-release-v20231003175140.wrap b/subprojects/tpt-libs-prebuilt-x86_64-darwin-macos-static-release-v20231003175140.wrap new file mode 100644 index 000000000..cee363dd1 --- /dev/null +++ b/subprojects/tpt-libs-prebuilt-x86_64-darwin-macos-static-release-v20231003175140.wrap @@ -0,0 +1,6 @@ +[wrap-file] +directory = tpt-libs-prebuilt-x86_64-darwin-macos-static-release-v20231003175140 + +source_url = https://github.com/The-Powder-Toy/tpt-libs/releases/download/v20231003175140/tpt-libs-prebuilt-x86_64-darwin-macos-static-release-v20231003175140.zip +source_filename = tpt-libs-prebuilt-x86_64-darwin-macos-static-release-v20231003175140.zip +source_hash = 84df15f52d979bd0b703c709145a2731e01e2ccb4ba13966168dace6efea354f diff --git a/subprojects/tpt-libs-prebuilt-x86_64-linux-gnu-static-debug-v20230819222922.wrap b/subprojects/tpt-libs-prebuilt-x86_64-linux-gnu-static-debug-v20230819222922.wrap deleted file mode 100644 index cf183c36e..000000000 --- a/subprojects/tpt-libs-prebuilt-x86_64-linux-gnu-static-debug-v20230819222922.wrap +++ /dev/null @@ -1,6 +0,0 @@ -[wrap-file] -directory = tpt-libs-prebuilt-x86_64-linux-gnu-static-debug-v20230819222922 - -source_url = https://github.com/The-Powder-Toy/tpt-libs/releases/download/v20230819222922/tpt-libs-prebuilt-x86_64-linux-gnu-static-debug-v20230819222922.zip -source_filename = tpt-libs-prebuilt-x86_64-linux-gnu-static-debug-v20230819222922.zip -source_hash = 5addd00589d97fe47d1d425f58a6e6e66759fbf742fd7e3e0ce704c2a7bb47d5 diff --git a/subprojects/tpt-libs-prebuilt-x86_64-linux-gnu-static-debug-v20231003175140.wrap b/subprojects/tpt-libs-prebuilt-x86_64-linux-gnu-static-debug-v20231003175140.wrap new file mode 100644 index 000000000..3a9566ecc --- /dev/null +++ b/subprojects/tpt-libs-prebuilt-x86_64-linux-gnu-static-debug-v20231003175140.wrap @@ -0,0 +1,6 @@ +[wrap-file] +directory = tpt-libs-prebuilt-x86_64-linux-gnu-static-debug-v20231003175140 + +source_url = https://github.com/The-Powder-Toy/tpt-libs/releases/download/v20231003175140/tpt-libs-prebuilt-x86_64-linux-gnu-static-debug-v20231003175140.zip +source_filename = tpt-libs-prebuilt-x86_64-linux-gnu-static-debug-v20231003175140.zip +source_hash = 0089fed317eac2545f86259744f72126f249775a1e95539abeece2eaf121a08f diff --git a/subprojects/tpt-libs-prebuilt-x86_64-linux-gnu-static-release-v20230819222922.wrap b/subprojects/tpt-libs-prebuilt-x86_64-linux-gnu-static-release-v20230819222922.wrap deleted file mode 100644 index 638f3ed7a..000000000 --- a/subprojects/tpt-libs-prebuilt-x86_64-linux-gnu-static-release-v20230819222922.wrap +++ /dev/null @@ -1,6 +0,0 @@ -[wrap-file] -directory = tpt-libs-prebuilt-x86_64-linux-gnu-static-release-v20230819222922 - -source_url = https://github.com/The-Powder-Toy/tpt-libs/releases/download/v20230819222922/tpt-libs-prebuilt-x86_64-linux-gnu-static-release-v20230819222922.zip -source_filename = tpt-libs-prebuilt-x86_64-linux-gnu-static-release-v20230819222922.zip -source_hash = ce353e62fae0c3ea9756044d2d6257f73462f700f4f419fe09e8324015c8b0bb diff --git a/subprojects/tpt-libs-prebuilt-x86_64-linux-gnu-static-release-v20231003175140.wrap b/subprojects/tpt-libs-prebuilt-x86_64-linux-gnu-static-release-v20231003175140.wrap new file mode 100644 index 000000000..c3c023e37 --- /dev/null +++ b/subprojects/tpt-libs-prebuilt-x86_64-linux-gnu-static-release-v20231003175140.wrap @@ -0,0 +1,6 @@ +[wrap-file] +directory = tpt-libs-prebuilt-x86_64-linux-gnu-static-release-v20231003175140 + +source_url = https://github.com/The-Powder-Toy/tpt-libs/releases/download/v20231003175140/tpt-libs-prebuilt-x86_64-linux-gnu-static-release-v20231003175140.zip +source_filename = tpt-libs-prebuilt-x86_64-linux-gnu-static-release-v20231003175140.zip +source_hash = 272a81522aec8a34e61b52a92ab0bef29cf3e4ffdfb343086efa9b410806073a diff --git a/subprojects/tpt-libs-prebuilt-x86_64-windows-mingw-dynamic-debug-v20230819222922.wrap b/subprojects/tpt-libs-prebuilt-x86_64-windows-mingw-dynamic-debug-v20230819222922.wrap deleted file mode 100644 index 5c2856f2f..000000000 --- a/subprojects/tpt-libs-prebuilt-x86_64-windows-mingw-dynamic-debug-v20230819222922.wrap +++ /dev/null @@ -1,6 +0,0 @@ -[wrap-file] -directory = tpt-libs-prebuilt-x86_64-windows-mingw-dynamic-debug-v20230819222922 - -source_url = https://github.com/The-Powder-Toy/tpt-libs/releases/download/v20230819222922/tpt-libs-prebuilt-x86_64-windows-mingw-dynamic-debug-v20230819222922.zip -source_filename = tpt-libs-prebuilt-x86_64-windows-mingw-dynamic-debug-v20230819222922.zip -source_hash = 268db7c9f1af6ae97f2324b2189bd52353a9f79fae20bd67c29b13dc70c840e1 diff --git a/subprojects/tpt-libs-prebuilt-x86_64-windows-mingw-dynamic-debug-v20231003175140.wrap b/subprojects/tpt-libs-prebuilt-x86_64-windows-mingw-dynamic-debug-v20231003175140.wrap new file mode 100644 index 000000000..3075a30bf --- /dev/null +++ b/subprojects/tpt-libs-prebuilt-x86_64-windows-mingw-dynamic-debug-v20231003175140.wrap @@ -0,0 +1,6 @@ +[wrap-file] +directory = tpt-libs-prebuilt-x86_64-windows-mingw-dynamic-debug-v20231003175140 + +source_url = https://github.com/The-Powder-Toy/tpt-libs/releases/download/v20231003175140/tpt-libs-prebuilt-x86_64-windows-mingw-dynamic-debug-v20231003175140.zip +source_filename = tpt-libs-prebuilt-x86_64-windows-mingw-dynamic-debug-v20231003175140.zip +source_hash = fd097a3c6d1d043fb8475b602330fd2ceb5bf12ac2695ba5e6baa885ac5ce439 diff --git a/subprojects/tpt-libs-prebuilt-x86_64-windows-mingw-dynamic-release-v20230819222922.wrap b/subprojects/tpt-libs-prebuilt-x86_64-windows-mingw-dynamic-release-v20230819222922.wrap deleted file mode 100644 index ec7a7a86d..000000000 --- a/subprojects/tpt-libs-prebuilt-x86_64-windows-mingw-dynamic-release-v20230819222922.wrap +++ /dev/null @@ -1,6 +0,0 @@ -[wrap-file] -directory = tpt-libs-prebuilt-x86_64-windows-mingw-dynamic-release-v20230819222922 - -source_url = https://github.com/The-Powder-Toy/tpt-libs/releases/download/v20230819222922/tpt-libs-prebuilt-x86_64-windows-mingw-dynamic-release-v20230819222922.zip -source_filename = tpt-libs-prebuilt-x86_64-windows-mingw-dynamic-release-v20230819222922.zip -source_hash = b6c84b87234acbf2c7d8ce53427541e68089e135c15c949f686988b943406933 diff --git a/subprojects/tpt-libs-prebuilt-x86_64-windows-mingw-dynamic-release-v20231003175140.wrap b/subprojects/tpt-libs-prebuilt-x86_64-windows-mingw-dynamic-release-v20231003175140.wrap new file mode 100644 index 000000000..07d30a3bb --- /dev/null +++ b/subprojects/tpt-libs-prebuilt-x86_64-windows-mingw-dynamic-release-v20231003175140.wrap @@ -0,0 +1,6 @@ +[wrap-file] +directory = tpt-libs-prebuilt-x86_64-windows-mingw-dynamic-release-v20231003175140 + +source_url = https://github.com/The-Powder-Toy/tpt-libs/releases/download/v20231003175140/tpt-libs-prebuilt-x86_64-windows-mingw-dynamic-release-v20231003175140.zip +source_filename = tpt-libs-prebuilt-x86_64-windows-mingw-dynamic-release-v20231003175140.zip +source_hash = 1d3be03fcc47059bd35b751f3a56ccebec94df08d3404465468dbb7168cf68dd diff --git a/subprojects/tpt-libs-prebuilt-x86_64-windows-mingw-static-debug-v20230819222922.wrap b/subprojects/tpt-libs-prebuilt-x86_64-windows-mingw-static-debug-v20230819222922.wrap deleted file mode 100644 index 2e31f2195..000000000 --- a/subprojects/tpt-libs-prebuilt-x86_64-windows-mingw-static-debug-v20230819222922.wrap +++ /dev/null @@ -1,6 +0,0 @@ -[wrap-file] -directory = tpt-libs-prebuilt-x86_64-windows-mingw-static-debug-v20230819222922 - -source_url = https://github.com/The-Powder-Toy/tpt-libs/releases/download/v20230819222922/tpt-libs-prebuilt-x86_64-windows-mingw-static-debug-v20230819222922.zip -source_filename = tpt-libs-prebuilt-x86_64-windows-mingw-static-debug-v20230819222922.zip -source_hash = 19157890ebed425e4d47edf30fc23e795b5ed0753fb87d0412e09485289cd817 diff --git a/subprojects/tpt-libs-prebuilt-x86_64-windows-mingw-static-debug-v20231003175140.wrap b/subprojects/tpt-libs-prebuilt-x86_64-windows-mingw-static-debug-v20231003175140.wrap new file mode 100644 index 000000000..fad92b56b --- /dev/null +++ b/subprojects/tpt-libs-prebuilt-x86_64-windows-mingw-static-debug-v20231003175140.wrap @@ -0,0 +1,6 @@ +[wrap-file] +directory = tpt-libs-prebuilt-x86_64-windows-mingw-static-debug-v20231003175140 + +source_url = https://github.com/The-Powder-Toy/tpt-libs/releases/download/v20231003175140/tpt-libs-prebuilt-x86_64-windows-mingw-static-debug-v20231003175140.zip +source_filename = tpt-libs-prebuilt-x86_64-windows-mingw-static-debug-v20231003175140.zip +source_hash = c22edbee65046a45b1e157c28cfca7d875374add7d7d70e62e82a29258e532ac diff --git a/subprojects/tpt-libs-prebuilt-x86_64-windows-mingw-static-release-v20230819222922.wrap b/subprojects/tpt-libs-prebuilt-x86_64-windows-mingw-static-release-v20230819222922.wrap deleted file mode 100644 index 3c6eb493d..000000000 --- a/subprojects/tpt-libs-prebuilt-x86_64-windows-mingw-static-release-v20230819222922.wrap +++ /dev/null @@ -1,6 +0,0 @@ -[wrap-file] -directory = tpt-libs-prebuilt-x86_64-windows-mingw-static-release-v20230819222922 - -source_url = https://github.com/The-Powder-Toy/tpt-libs/releases/download/v20230819222922/tpt-libs-prebuilt-x86_64-windows-mingw-static-release-v20230819222922.zip -source_filename = tpt-libs-prebuilt-x86_64-windows-mingw-static-release-v20230819222922.zip -source_hash = 7fcd6561e6355f63112f35179bd9150027880af19ed752fb4d2fbe76953cbb0b diff --git a/subprojects/tpt-libs-prebuilt-x86_64-windows-mingw-static-release-v20231003175140.wrap b/subprojects/tpt-libs-prebuilt-x86_64-windows-mingw-static-release-v20231003175140.wrap new file mode 100644 index 000000000..e4492012c --- /dev/null +++ b/subprojects/tpt-libs-prebuilt-x86_64-windows-mingw-static-release-v20231003175140.wrap @@ -0,0 +1,6 @@ +[wrap-file] +directory = tpt-libs-prebuilt-x86_64-windows-mingw-static-release-v20231003175140 + +source_url = https://github.com/The-Powder-Toy/tpt-libs/releases/download/v20231003175140/tpt-libs-prebuilt-x86_64-windows-mingw-static-release-v20231003175140.zip +source_filename = tpt-libs-prebuilt-x86_64-windows-mingw-static-release-v20231003175140.zip +source_hash = 9d0d54ec137cfd846e7ba239b1ced30976b7c4d89fde019edd1bce5dc8f0d649 diff --git a/subprojects/tpt-libs-prebuilt-x86_64-windows-msvc-dynamic-debug-v20230819222922.wrap b/subprojects/tpt-libs-prebuilt-x86_64-windows-msvc-dynamic-debug-v20230819222922.wrap deleted file mode 100644 index 8a3363010..000000000 --- a/subprojects/tpt-libs-prebuilt-x86_64-windows-msvc-dynamic-debug-v20230819222922.wrap +++ /dev/null @@ -1,6 +0,0 @@ -[wrap-file] -directory = tpt-libs-prebuilt-x86_64-windows-msvc-dynamic-debug-v20230819222922 - -source_url = https://github.com/The-Powder-Toy/tpt-libs/releases/download/v20230819222922/tpt-libs-prebuilt-x86_64-windows-msvc-dynamic-debug-v20230819222922.zip -source_filename = tpt-libs-prebuilt-x86_64-windows-msvc-dynamic-debug-v20230819222922.zip -source_hash = 699e2a315ee4b562304cb33a9594349afb3118a8c101f2f46c4d7d959e30939f diff --git a/subprojects/tpt-libs-prebuilt-x86_64-windows-msvc-dynamic-debug-v20231003175140.wrap b/subprojects/tpt-libs-prebuilt-x86_64-windows-msvc-dynamic-debug-v20231003175140.wrap new file mode 100644 index 000000000..e069507b1 --- /dev/null +++ b/subprojects/tpt-libs-prebuilt-x86_64-windows-msvc-dynamic-debug-v20231003175140.wrap @@ -0,0 +1,6 @@ +[wrap-file] +directory = tpt-libs-prebuilt-x86_64-windows-msvc-dynamic-debug-v20231003175140 + +source_url = https://github.com/The-Powder-Toy/tpt-libs/releases/download/v20231003175140/tpt-libs-prebuilt-x86_64-windows-msvc-dynamic-debug-v20231003175140.zip +source_filename = tpt-libs-prebuilt-x86_64-windows-msvc-dynamic-debug-v20231003175140.zip +source_hash = abb58a981204af56aad5e4811fd79632f49f9feed219795324732ca83b4c1c2f diff --git a/subprojects/tpt-libs-prebuilt-x86_64-windows-msvc-dynamic-release-v20230819222922.wrap b/subprojects/tpt-libs-prebuilt-x86_64-windows-msvc-dynamic-release-v20230819222922.wrap deleted file mode 100644 index bb93adffb..000000000 --- a/subprojects/tpt-libs-prebuilt-x86_64-windows-msvc-dynamic-release-v20230819222922.wrap +++ /dev/null @@ -1,6 +0,0 @@ -[wrap-file] -directory = tpt-libs-prebuilt-x86_64-windows-msvc-dynamic-release-v20230819222922 - -source_url = https://github.com/The-Powder-Toy/tpt-libs/releases/download/v20230819222922/tpt-libs-prebuilt-x86_64-windows-msvc-dynamic-release-v20230819222922.zip -source_filename = tpt-libs-prebuilt-x86_64-windows-msvc-dynamic-release-v20230819222922.zip -source_hash = 90aab0c8cabef2f917d4c28a1fbc4d412db72ebfe938273f4a83a02479d745b8 diff --git a/subprojects/tpt-libs-prebuilt-x86_64-windows-msvc-dynamic-release-v20231003175140.wrap b/subprojects/tpt-libs-prebuilt-x86_64-windows-msvc-dynamic-release-v20231003175140.wrap new file mode 100644 index 000000000..32dad8283 --- /dev/null +++ b/subprojects/tpt-libs-prebuilt-x86_64-windows-msvc-dynamic-release-v20231003175140.wrap @@ -0,0 +1,6 @@ +[wrap-file] +directory = tpt-libs-prebuilt-x86_64-windows-msvc-dynamic-release-v20231003175140 + +source_url = https://github.com/The-Powder-Toy/tpt-libs/releases/download/v20231003175140/tpt-libs-prebuilt-x86_64-windows-msvc-dynamic-release-v20231003175140.zip +source_filename = tpt-libs-prebuilt-x86_64-windows-msvc-dynamic-release-v20231003175140.zip +source_hash = aad3687cb32442ed426632f86f987c3777b1c8f7a1011180b36a08701226d67d diff --git a/subprojects/tpt-libs-prebuilt-x86_64-windows-msvc-static-debug-v20230819222922.wrap b/subprojects/tpt-libs-prebuilt-x86_64-windows-msvc-static-debug-v20230819222922.wrap deleted file mode 100644 index 7219f64d5..000000000 --- a/subprojects/tpt-libs-prebuilt-x86_64-windows-msvc-static-debug-v20230819222922.wrap +++ /dev/null @@ -1,6 +0,0 @@ -[wrap-file] -directory = tpt-libs-prebuilt-x86_64-windows-msvc-static-debug-v20230819222922 - -source_url = https://github.com/The-Powder-Toy/tpt-libs/releases/download/v20230819222922/tpt-libs-prebuilt-x86_64-windows-msvc-static-debug-v20230819222922.zip -source_filename = tpt-libs-prebuilt-x86_64-windows-msvc-static-debug-v20230819222922.zip -source_hash = 19ec2095425dd120d575f411f1505c27f37341b5c03c5d700fe1496e8fcbc8aa diff --git a/subprojects/tpt-libs-prebuilt-x86_64-windows-msvc-static-debug-v20231003175140.wrap b/subprojects/tpt-libs-prebuilt-x86_64-windows-msvc-static-debug-v20231003175140.wrap new file mode 100644 index 000000000..c196ee43f --- /dev/null +++ b/subprojects/tpt-libs-prebuilt-x86_64-windows-msvc-static-debug-v20231003175140.wrap @@ -0,0 +1,6 @@ +[wrap-file] +directory = tpt-libs-prebuilt-x86_64-windows-msvc-static-debug-v20231003175140 + +source_url = https://github.com/The-Powder-Toy/tpt-libs/releases/download/v20231003175140/tpt-libs-prebuilt-x86_64-windows-msvc-static-debug-v20231003175140.zip +source_filename = tpt-libs-prebuilt-x86_64-windows-msvc-static-debug-v20231003175140.zip +source_hash = e04c3ef2b070ac9f9ba858bba7447b610689cff321502707b7abece6a4796744 diff --git a/subprojects/tpt-libs-prebuilt-x86_64-windows-msvc-static-release-v20230819222922.wrap b/subprojects/tpt-libs-prebuilt-x86_64-windows-msvc-static-release-v20230819222922.wrap deleted file mode 100644 index 212a2057e..000000000 --- a/subprojects/tpt-libs-prebuilt-x86_64-windows-msvc-static-release-v20230819222922.wrap +++ /dev/null @@ -1,6 +0,0 @@ -[wrap-file] -directory = tpt-libs-prebuilt-x86_64-windows-msvc-static-release-v20230819222922 - -source_url = https://github.com/The-Powder-Toy/tpt-libs/releases/download/v20230819222922/tpt-libs-prebuilt-x86_64-windows-msvc-static-release-v20230819222922.zip -source_filename = tpt-libs-prebuilt-x86_64-windows-msvc-static-release-v20230819222922.zip -source_hash = 56704d9556538357334e9e98c0c4008340e470a4f6943b53962be9f4c63d08c0 diff --git a/subprojects/tpt-libs-prebuilt-x86_64-windows-msvc-static-release-v20231003175140.wrap b/subprojects/tpt-libs-prebuilt-x86_64-windows-msvc-static-release-v20231003175140.wrap new file mode 100644 index 000000000..76aaf4b31 --- /dev/null +++ b/subprojects/tpt-libs-prebuilt-x86_64-windows-msvc-static-release-v20231003175140.wrap @@ -0,0 +1,6 @@ +[wrap-file] +directory = tpt-libs-prebuilt-x86_64-windows-msvc-static-release-v20231003175140 + +source_url = https://github.com/The-Powder-Toy/tpt-libs/releases/download/v20231003175140/tpt-libs-prebuilt-x86_64-windows-msvc-static-release-v20231003175140.zip +source_filename = tpt-libs-prebuilt-x86_64-windows-msvc-static-release-v20231003175140.zip +source_hash = 18a6192d03cfea79de3daad00d578f56c4800a2674d64904429a5c4b67213df9 From 8385796ca1c68bd13d72c58ee2ee164557f1b392 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20B=C3=A1lint=20Misius?= Date: Sun, 1 Oct 2023 10:53:59 +0200 Subject: [PATCH 03/27] Bump android toolchain version to 21 --- .github/build.sh | 4 ++-- android/AndroidManifest.template.xml | 2 +- android/cross/arm.ini | 2 +- android/cross/x86.ini | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/build.sh b/.github/build.sh index b6ccdece8..8e17c3c93 100755 --- a/.github/build.sh +++ b/.github/build.sh @@ -143,9 +143,9 @@ elif [[ $BSH_HOST_PLATFORM == darwin ]]; then elif [[ $BSH_HOST_PLATFORM == android ]]; then case $BSH_HOST_ARCH in x86_64) android_toolchain_prefix=x86_64-linux-android ; android_system_version=21; android_arch_abi=x86_64 ;; - x86) android_toolchain_prefix=i686-linux-android ; android_system_version=19; android_arch_abi=x86 ;; + x86) android_toolchain_prefix=i686-linux-android ; android_system_version=21; android_arch_abi=x86 ;; aarch64) android_toolchain_prefix=aarch64-linux-android ; android_system_version=21; android_arch_abi=arm64-v8a ;; - arm) android_toolchain_prefix=armv7a-linux-androideabi; android_system_version=19; android_arch_abi=armeabi-v7a;; + arm) android_toolchain_prefix=armv7a-linux-androideabi; android_system_version=21; android_arch_abi=armeabi-v7a;; esac android_toolchain_dir=$ANDROID_NDK_LATEST_HOME/toolchains/llvm/prebuilt/linux-x86_64 CC=$android_toolchain_dir/bin/$android_toolchain_prefix$android_system_version-clang diff --git a/android/AndroidManifest.template.xml b/android/AndroidManifest.template.xml index 40b5d93c7..9f998578b 100644 --- a/android/AndroidManifest.template.xml +++ b/android/AndroidManifest.template.xml @@ -7,7 +7,7 @@ android:installLocation="auto" > Date: Mon, 2 Oct 2023 17:26:57 +0200 Subject: [PATCH 04/27] Use mbedtls on windows --- android/res/mipmap-mdpi/meson.build | 6 +- meson.build | 3 +- src/Config.template.h | 1 + src/client/http/requestmanager/CurlError.h | 1 + src/client/http/requestmanager/Libcurl.cpp | 23 +++-- .../http/requestmanager/RequestManager.h | 10 ++ .../requestmanager/WindowsCertProvider.cpp | 95 +++++++++++++++++++ src/client/http/requestmanager/meson.build | 6 ++ 8 files changed, 131 insertions(+), 14 deletions(-) create mode 100644 src/client/http/requestmanager/WindowsCertProvider.cpp diff --git a/android/res/mipmap-mdpi/meson.build b/android/res/mipmap-mdpi/meson.build index 1e0a807bf..4cb9810c3 100644 --- a/android/res/mipmap-mdpi/meson.build +++ b/android/res/mipmap-mdpi/meson.build @@ -1,5 +1 @@ -android_resources += configure_file( - input: rendered_icons['icon_exe'], - output: 'ic_launcher.png', - copy: true, -) +android_resources += fs.copyfile(rendered_icons['icon_exe'], 'ic_launcher.png') diff --git a/meson.build b/meson.build index 2d56592d9..cf9776775 100644 --- a/meson.build +++ b/meson.build @@ -18,6 +18,7 @@ if get_option('prepare') subdir_done() endif +fs = import('fs') to_array = generator( executable('toarray', sources: 'resources/ToArray.cpp', native: true), output: [ '@PLAINNAME@.cpp', '@PLAINNAME@.h' ], @@ -342,7 +343,7 @@ if host_platform == 'windows' do_copy = true endif if do_copy - configure_file(input: dll_input, output: dll_output, copy: true) + fs.copyfile(dll_input, dll_output) endif endforeach endif diff --git a/src/Config.template.h b/src/Config.template.h index 1676bb841..279583a2c 100644 --- a/src/Config.template.h +++ b/src/Config.template.h @@ -17,6 +17,7 @@ constexpr bool INSTALL_CHECK = @INSTALL_CHECK@; constexpr bool IGNORE_UPDATES = @IGNORE_UPDATES@; constexpr bool ENFORCE_HTTPS = @ENFORCE_HTTPS@; constexpr bool SECURE_CIPHERS_ONLY = @SECURE_CIPHERS_ONLY@; +constexpr bool USE_SYSTEM_CERT_PROVIDER = @USE_SYSTEM_CERT_PROVIDER@; constexpr bool FFTW_PLAN_MEASURE = @FFTW_PLAN_MEASURE@; constexpr bool ALLOW_QUIT = @ALLOW_QUIT@; constexpr bool ALLOW_WINDOW_FRAME_OPS = @ALLOW_WINDOW_FRAME_OPS@; diff --git a/src/client/http/requestmanager/CurlError.h b/src/client/http/requestmanager/CurlError.h index 959b54e8d..f859c5480 100644 --- a/src/client/http/requestmanager/CurlError.h +++ b/src/client/http/requestmanager/CurlError.h @@ -9,6 +9,7 @@ namespace http using runtime_error::runtime_error; }; + void UseSystemCertProvider(CURL *easy); void SetupCurlEasyCiphers(CURL *easy); void HandleCURLcode(CURLcode code); void HandleCURLMcode(CURLMcode code); diff --git a/src/client/http/requestmanager/Libcurl.cpp b/src/client/http/requestmanager/Libcurl.cpp index 64dc244e5..828daf23c 100644 --- a/src/client/http/requestmanager/Libcurl.cpp +++ b/src/client/http/requestmanager/Libcurl.cpp @@ -462,14 +462,6 @@ namespace http { HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_PROXY, proxy.c_str())); } - if (cafile.size()) - { - HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_CAINFO, cafile.c_str())); - } - if (capath.size()) - { - HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_CAPATH, capath.c_str())); - } HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_PRIVATE, (void *)handle)); HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_USERAGENT, userAgent.c_str())); HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_HEADERDATA, (void *)handle)); @@ -562,5 +554,20 @@ namespace http #elif defined(CURL_AT_LEAST_VERSION) && CURL_AT_LEAST_VERSION(7, 44, 0) HandleCURLcode(curl_easy_setopt(easy, CURLOPT_SSL_OPTIONS, CURLSSLOPT_NO_REVOKE)); #endif + + auto &capath = http::RequestManager::Ref().Capath(); + auto &cafile = http::RequestManager::Ref().Cafile(); + if (capath.size()) + { + HandleCURLcode(curl_easy_setopt(easy, CURLOPT_CAPATH, capath.c_str())); + } + else if (cafile.size()) + { + HandleCURLcode(curl_easy_setopt(easy, CURLOPT_CAINFO, cafile.c_str())); + } + else if constexpr (USE_SYSTEM_CERT_PROVIDER) + { + UseSystemCertProvider(easy); + } } } diff --git a/src/client/http/requestmanager/RequestManager.h b/src/client/http/requestmanager/RequestManager.h index addd05805..c55e8f3a0 100644 --- a/src/client/http/requestmanager/RequestManager.h +++ b/src/client/http/requestmanager/RequestManager.h @@ -89,6 +89,16 @@ namespace http return disableNetwork; } + const ByteString &Cafile() const + { + return cafile; + } + + const ByteString &Capath() const + { + return capath; + } + static RequestManagerPtr Create(ByteString newProxy, ByteString newCafile, ByteString newCapath, bool newDisableNetwork); }; } diff --git a/src/client/http/requestmanager/WindowsCertProvider.cpp b/src/client/http/requestmanager/WindowsCertProvider.cpp new file mode 100644 index 000000000..33d8f7423 --- /dev/null +++ b/src/client/http/requestmanager/WindowsCertProvider.cpp @@ -0,0 +1,95 @@ +#include "CurlError.h" +#include "common/String.h" +#include // crypt32.lib is pulled in by tpt-libs +#include +#include + +namespace http +{ + // see https://stackoverflow.com/questions/9507184/can-openssl-on-windows-use-the-system-certificate-store + void UseSystemCertProvider(CURL *easy) + { + struct DoOnce + { + ByteString allPems; + + void InitPem() + { + struct StoreDeleter + { + typedef HCERTSTORE pointer; + + void operator ()(HCERTSTORE p) const + { + ::CertCloseStore(p, 0); + } + }; + using StorePtr = std::unique_ptr; + struct ContextDeleter + { + typedef PCCERT_CONTEXT pointer; + + void operator ()(PCCERT_CONTEXT p) const + { + ::CertFreeCertificateContext(p); + } + }; + using ContextPtr = std::unique_ptr; + + auto die = [](ByteString message) { + std::cerr << "failed to enumerate system certificates: " << message << ": " << GetLastError() << std::endl; + }; + auto store = StorePtr(::CertOpenSystemStore(0, L"ROOT"), StoreDeleter{}); + if (!store) + { + return die("CertOpenSystemStore failed"); + } + ContextPtr context; + while (true) + { + context = ContextPtr(::CertEnumCertificatesInStore(store.get(), context.release()), ContextDeleter{}); + if (!context) + { + if (::GetLastError() != DWORD(CRYPT_E_NOT_FOUND)) + { + return die("CertEnumCertificatesInStore failed"); + } + break; + } + DWORD pemLength; + // get required buffer size first + if (!CryptBinaryToStringA(context->pbCertEncoded, context->cbCertEncoded, CRYPT_STRING_BASE64HEADER, NULL, &pemLength)) + { + return die("CryptBinaryToStringA failed"); + } + std::vector pem(pemLength); + // actually get the data + if (!CryptBinaryToStringA(context->pbCertEncoded, context->cbCertEncoded, CRYPT_STRING_BASE64HEADER, &pem[0], &pemLength)) + { + return die("CryptBinaryToStringA failed"); + } + allPems += ByteString(&pem[0], &pem[0] + pem.size() - 1); // buffer includes the zero terminator, omit that + } + if (!allPems.size()) + { + die("no system certificates"); + } + } + + DoOnce() + { + InitPem(); + } + }; + + static DoOnce doOnce; + if (doOnce.allPems.size()) + { + curl_blob blob; + blob.data = &doOnce.allPems[0]; + blob.len = doOnce.allPems.size(); + blob.flags = CURL_BLOB_COPY; + HandleCURLcode(curl_easy_setopt(easy, CURLOPT_CAINFO_BLOB, &blob)); + } + } +} diff --git a/src/client/http/requestmanager/meson.build b/src/client/http/requestmanager/meson.build index 4dc0dfbad..c2de3e7b1 100644 --- a/src/client/http/requestmanager/meson.build +++ b/src/client/http/requestmanager/meson.build @@ -2,11 +2,17 @@ client_files += files( 'Common.cpp', ) +use_system_cert_provider = false if not enable_http client_files += files('Null.cpp') elif host_platform == 'emscripten' client_files += files('Emscripten.cpp') else client_files += files('Libcurl.cpp') + if host_platform == 'windows' + use_system_cert_provider = true + client_files += files('WindowsCertProvider.cpp') + endif endif conf_data.set('NOHTTP', (not enable_http).to_string()) +conf_data.set('USE_SYSTEM_CERT_PROVIDER', use_system_cert_provider.to_string()) From b89d29b744f89c36086c72affe9edb77a5b01754 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20B=C3=A1lint=20Misius?= Date: Tue, 3 Oct 2023 12:59:41 +0200 Subject: [PATCH 05/27] Enable libcurl on android --- .github/build.sh | 1 - android/AndroidManifest.template.xml | 3 +- android/PowderActivity.template.java | 35 ++++++++ meson.build | 3 - .../requestmanager/AndroidCertProvider.cpp | 86 +++++++++++++++++++ src/client/http/requestmanager/meson.build | 4 + src/gui/game/Tool.h | 2 +- src/meson.build | 12 +++ 8 files changed, 140 insertions(+), 6 deletions(-) create mode 100644 src/client/http/requestmanager/AndroidCertProvider.cpp diff --git a/.github/build.sh b/.github/build.sh index 8e17c3c93..452034477 100755 --- a/.github/build.sh +++ b/.github/build.sh @@ -369,7 +369,6 @@ zipalign = andriod_sdk_build_tools / 'zipalign' apksigner = andriod_sdk_build_tools / 'apksigner' ANDROID_INI meson_configure+=$'\t'--cross-file=.github/android-ghactions.ini - meson_configure+=$'\t'-Dhttp=false fi meson_configure+=$'\t'-Dc_args=[$c_args] meson_configure+=$'\t'-Dcpp_args=[$c_args] diff --git a/android/AndroidManifest.template.xml b/android/AndroidManifest.template.xml index 9f998578b..68ce6bbdc 100644 --- a/android/AndroidManifest.template.xml +++ b/android/AndroidManifest.template.xml @@ -33,7 +33,7 @@ android:name="android.hardware.type.pc" android:required="false" /> - + @ANDROID_PERMISSIONS@ aliases = ks.aliases(); + while (aliases.hasMoreElements()) { + String alias = (String)aliases.nextElement(); + java.security.cert.X509Certificate cert = (java.security.cert.X509Certificate)ks.getCertificate(alias); + allPems += "-----BEGIN CERTIFICATE-----\n" + Base64.getMimeEncoder().encodeToString(cert.getEncoded()) + "\n-----END CERTIFICATE-----\n";; + } + } + } catch (IOException e) { + e.printStackTrace(); + return ""; + } catch (KeyStoreException e) { + e.printStackTrace(); + return ""; + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + return ""; + } catch (java.security.cert.CertificateException e) { + e.printStackTrace(); + return ""; + } + return allPems; + } } diff --git a/meson.build b/meson.build index cf9776775..a3b96320f 100644 --- a/meson.build +++ b/meson.build @@ -173,9 +173,6 @@ elif lua_variant == 'luajit' endif enable_http = get_option('http') -if host_platform == 'android' - enable_http = false -endif if host_platform == 'android' android_ndk_toolchain_prefix = meson.get_external_property('android_ndk_toolchain_prefix') android_platform = meson.get_external_property('android_platform') diff --git a/src/client/http/requestmanager/AndroidCertProvider.cpp b/src/client/http/requestmanager/AndroidCertProvider.cpp new file mode 100644 index 000000000..63ef6ccd9 --- /dev/null +++ b/src/client/http/requestmanager/AndroidCertProvider.cpp @@ -0,0 +1,86 @@ +#include "CurlError.h" +#include "common/String.h" +#include "Config.h" +#include +#include +#include +#include + +static jclass FindClass(JNIEnv *env, const char *name) +{ + jobject nativeActivity = (jobject)SDL_AndroidGetActivity(); if (!nativeActivity) return NULL; + jclass acl = env->GetObjectClass(nativeActivity); if (!acl ) return NULL; + jmethodID getClassLoader = env->GetMethodID(acl, "getClassLoader", "()Ljava/lang/ClassLoader;"); if (!getClassLoader) return NULL; + jobject cls = env->CallObjectMethod(nativeActivity, getClassLoader); if (!cls ) return NULL; + jclass classLoader = env->FindClass("java/lang/ClassLoader"); if (!classLoader ) return NULL; + jmethodID findClass = env->GetMethodID(classLoader, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;"); if (!findClass ) return NULL; + jstring strClassName = env->NewStringUTF(name); if (!strClassName ) return NULL; + jclass clazz = (jclass)(env->CallObjectMethod(cls, findClass, strClassName)); + env->DeleteLocalRef(strClassName); + return clazz; +} + +namespace http +{ + void UseSystemCertProvider(CURL *easy) + { + struct DoOnce + { + ByteString allPems; + + void InitPem() + { + auto die = [](ByteString message) { + __android_log_print(ANDROID_LOG_ERROR, "AndroidCertProvider", "%s", ("failed to enumerate system certificates: " + message).c_str()); + }; + auto *env = (JNIEnv *)SDL_AndroidGetJNIEnv(); + if (!env) + { + return die("SDL_AndroidGetJNIEnv failed"); + } + jclass mPowderActivity = FindClass(env, ByteString::Build(APPID, ".PowderActivity").c_str()); + if (!mPowderActivity) + { + return die("FindClass failed"); + } + jmethodID midGetCertificateBundle = env->GetStaticMethodID(mPowderActivity, "getCertificateBundle", "()Ljava/lang/String;"); + if (!midGetCertificateBundle) + { + return die("GetStaticMethodID failed"); + } + jstring str = (jstring)env->CallStaticObjectMethod(mPowderActivity, midGetCertificateBundle); + if (!str) + { + return die("getCertificateBundle failed"); + } + const char *utf = env->GetStringUTFChars(str, 0); + if (utf) + { + allPems = utf; + env->ReleaseStringUTFChars(str, utf); + } + else + { + __android_log_print(ANDROID_LOG_ERROR, "AndroidCertProvider", "out of memory???"); + } + env->DeleteLocalRef(str); + __android_log_print(ANDROID_LOG_ERROR, "AndroidCertProvider", "certificate bundle loaded"); + } + + DoOnce() + { + InitPem(); + } + }; + + static DoOnce doOnce; + if (doOnce.allPems.size()) + { + curl_blob blob; + blob.data = &doOnce.allPems[0]; + blob.len = doOnce.allPems.size(); + blob.flags = CURL_BLOB_COPY; + HandleCURLcode(curl_easy_setopt(easy, CURLOPT_CAINFO_BLOB, &blob)); + } + } +} diff --git a/src/client/http/requestmanager/meson.build b/src/client/http/requestmanager/meson.build index c2de3e7b1..94ae54646 100644 --- a/src/client/http/requestmanager/meson.build +++ b/src/client/http/requestmanager/meson.build @@ -13,6 +13,10 @@ else use_system_cert_provider = true client_files += files('WindowsCertProvider.cpp') endif + if host_platform == 'android' + use_system_cert_provider = true + client_files += files('AndroidCertProvider.cpp') + endif endif conf_data.set('NOHTTP', (not enable_http).to_string()) conf_data.set('USE_SYSTEM_CERT_PROVIDER', use_system_cert_provider.to_string()) diff --git a/src/gui/game/Tool.h b/src/gui/game/Tool.h index 97c3c9dd9..273b347b1 100644 --- a/src/gui/game/Tool.h +++ b/src/gui/game/Tool.h @@ -10,7 +10,7 @@ class Simulation; class Brush; class VideoBuffer; -class Particle; +struct Particle; class Tool { diff --git a/src/meson.build b/src/meson.build index 5894519a0..1ad17e6b3 100644 --- a/src/meson.build +++ b/src/meson.build @@ -49,6 +49,18 @@ conf_data.set('APPID', app_id) conf_data.set('APPDATA', get_option('app_data')) conf_data.set('APPVENDOR', get_option('app_vendor')) +if host_platform == 'android' + android_permissions = [ + '', + ] + if enable_http + android_permissions += [ + '', + ] + endif + conf_data.set('ANDROID_PERMISSIONS', '\n'.join(android_permissions)) +endif + powder_files = files( 'SDLCompat.cpp', 'PowderToySDL.cpp', From e635a45251af9abe3d82afdaac07217192d914d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20B=C3=A1lint=20Misius?= Date: Tue, 3 Oct 2023 17:34:43 +0200 Subject: [PATCH 06/27] Make Lua hook timeout configurable --- src/lua/LegacyLuaAPI.cpp | 2 +- src/lua/LuaScriptInterface.cpp | 3 +++ src/lua/LuaScriptInterface.h | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/lua/LegacyLuaAPI.cpp b/src/lua/LegacyLuaAPI.cpp index b9702b219..32e009e16 100644 --- a/src/lua/LegacyLuaAPI.cpp +++ b/src/lua/LegacyLuaAPI.cpp @@ -259,7 +259,7 @@ int luacon_elementwrite(lua_State* l) void luacon_hook(lua_State * l, lua_Debug * ar) { auto *luacon_ci = static_cast(commandInterface); - if (ar->event == LUA_HOOKCOUNT && Platform::GetTime() - luacon_ci->luaExecutionStart > 3000) + if (ar->event == LUA_HOOKCOUNT && int(Platform::GetTime() - luacon_ci->luaExecutionStart) > luacon_ci->luaHookTimeout) { luaL_error(l, "Error: Script not responding"); luacon_ci->luaExecutionStart = Platform::GetTime(); diff --git a/src/lua/LuaScriptInterface.cpp b/src/lua/LuaScriptInterface.cpp index adc8e2416..3a14b1a30 100644 --- a/src/lua/LuaScriptInterface.cpp +++ b/src/lua/LuaScriptInterface.cpp @@ -1,6 +1,7 @@ #include "bzip2/bz2wrap.h" #include "common/VariantIndex.h" #include "Config.h" +#include "prefs/GlobalPrefs.h" #include "LuaScriptInterface.h" @@ -272,6 +273,8 @@ LuaScriptInterface::LuaScriptInterface(GameController * c, GameModel * m): currentCommand(false), textInputRefcount(0) { + auto &prefs = GlobalPrefs::Ref(); + luaHookTimeout = prefs.Get("LuaHookTimeout", 3000); luacon_model = m; luacon_controller = c; luacon_sim = m->GetSimulation(); diff --git a/src/lua/LuaScriptInterface.h b/src/lua/LuaScriptInterface.h index a030fc2ec..708537405 100644 --- a/src/lua/LuaScriptInterface.h +++ b/src/lua/LuaScriptInterface.h @@ -212,6 +212,7 @@ public: static void LuaSetProperty(lua_State* l, StructProperty property, intptr_t propertyAddress, int stackPos); static void LuaSetParticleProperty(lua_State* l, int particleID, StructProperty property, intptr_t propertyAddress, int stackPos); + int luaHookTimeout; ui::Window * Window; lua_State *l; long unsigned int luaExecutionStart = 0; From b6680a03b208dee233ea8eb895f1749da6a8d953 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20B=C3=A1lint=20Misius?= Date: Tue, 3 Oct 2023 17:37:03 +0200 Subject: [PATCH 07/27] Fix a few warnings --- src/simulation/elements/PHOT.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/simulation/elements/PHOT.cpp b/src/simulation/elements/PHOT.cpp index 56432a48b..fc7b21641 100644 --- a/src/simulation/elements/PHOT.cpp +++ b/src/simulation/elements/PHOT.cpp @@ -80,9 +80,9 @@ static int update(UPDATE_FUNC_ARGS) auto rrr = sim->rng.between(0, 359) * 3.14159f / 180.0f; int rr; if (TYP(r) == PT_ISOZ) - rr = sim->rng.between(128, 255) / 127.0f; + rr = int(sim->rng.between(128, 255) / 127.0f); else - rr = sim->rng.between(128, 355) / 127.0f; + rr = int(sim->rng.between(128, 355) / 127.0f); parts[ID(r)].vx = rr*cosf(rrr); parts[ID(r)].vy = rr*sinf(rrr); sim->pv[y/CELL][x/CELL] -= 15.0f * CFDS; From d04768fa0ec501b1804374bda910ff74d38cf7da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20B=C3=A1lint=20Misius?= Date: Wed, 4 Oct 2023 07:55:31 +0200 Subject: [PATCH 08/27] Give untagged build artifacts a distinct app ID Their app ID would clash with that of stable otherwise, preventing them from being installed without disrupting stable installs. --- .github/prepare.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/prepare.py b/.github/prepare.py index 1b067f012..d145ae510 100755 --- a/.github/prepare.py +++ b/.github/prepare.py @@ -51,16 +51,23 @@ if int(build_options['mod_id']) == 0 and os.path.exists('.github/mod_id.txt'): build_options['mod_id'] = f.read() if int(build_options['mod_id']) == 0: - if release_type == 'beta': + if release_type == 'stable': + pass + elif release_type == 'beta': build_options['app_name' ] += ' Beta' build_options['app_comment'] += ' - Beta' build_options['app_exe' ] += 'beta' build_options['app_id' ] += 'beta' - if release_type == 'snapshot': + elif release_type == 'snapshot': build_options['app_name' ] += ' Snapshot' build_options['app_comment'] += ' - Snapshot' build_options['app_exe' ] += 'snapshot' build_options['app_id' ] += 'snapshot' + else: + build_options['app_name' ] += ' Dev' + build_options['app_comment'] += ' - Dev' + build_options['app_exe' ] += 'dev' + build_options['app_id' ] += 'dev' set_output('mod_id' , build_options['mod_id' ]) set_output('app_name' , build_options['app_name' ]) From 8cfe7cdd93e893c46989ba97a5e4955b0beb54df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20B=C3=A1lint=20Misius?= Date: Wed, 4 Oct 2023 15:51:39 +0200 Subject: [PATCH 09/27] Clean up window frame settings somewhat Another rat's nest; I'm still not entirely satisfied. This introduces "frame personalities": one for embedded frames (emscripten), one for handheld devices and everything else that doesn't really work with windows (android), and one for everything else. For now these affect which frame options are configurable by the user and what values they are forced to take if they are not configurable, and whether optimal scale is guessed based on screen size. Also introduce a future TouchUI config node to allow switching between normal and touch-optimized UI on android. Again, because chromebooks and other android devices with mouse and keyboard support are a thing. Also enable debugging of debug builds of android. It took me hours to attach a stupid debugger to the process; see: - https://www.sh-zam.com/2019/05/debugging-krita-on-android.html - https://source.android.com/docs/core/tests/debug/gdb#app-startup I also had to adb forward the port that lldb was supposedly talking to lldb-server over because otherwise it wouldn't attach; I don't get it either. --- android/AndroidManifest.template.xml | 1 + src/Config.template.h | 10 ++++- src/PowderToy.cpp | 42 +++++++++--------- src/PowderToyFontEditor.cpp | 9 +--- src/PowderToySDL.cpp | 64 +++++++++++++++------------ src/PowderToySDL.h | 9 ++-- src/gui/WindowFrameOps.h | 26 +++++++++++ src/gui/interface/Engine.cpp | 2 - src/gui/interface/Engine.h | 34 +++++++++----- src/gui/options/OptionsController.cpp | 4 +- src/gui/options/OptionsController.h | 2 +- src/gui/options/OptionsModel.cpp | 10 ++--- src/gui/options/OptionsModel.h | 4 +- src/gui/options/OptionsView.cpp | 18 +++++--- src/gui/options/OptionsView.h | 2 +- src/meson.build | 17 +++++-- 16 files changed, 156 insertions(+), 98 deletions(-) create mode 100644 src/gui/WindowFrameOps.h diff --git a/android/AndroidManifest.template.xml b/android/AndroidManifest.template.xml index 68ce6bbdc..c84b868c1 100644 --- a/android/AndroidManifest.template.xml +++ b/android/AndroidManifest.template.xml @@ -40,6 +40,7 @@ android:allowBackup="true" android:theme="@android:style/Theme.NoTitleBar.Fullscreen" android:hardwareAccelerated="true" + @ANDROID_PROPERTIES@ > 1) - { - prefs.Set("Scale", scale); - SDL_SetWindowSize(sdl_window, WINDOWW * scale, WINDOWH * scale); - showLargeScreenDialog = true; - } - } - StopTextInput(); auto &engine = ui::Engine::Ref(); engine.g = new Graphics(); engine.Scale = scale; engine.GraveExitsConsole = graveExitsConsole; - engine.SetResizable(resizable); - engine.Fullscreen = fullscreen; - engine.SetAltFullscreen(altFullscreen); - engine.SetForceIntegerScaling(forceIntegerScaling); + engine.SetWindowFrameOps(currentFrameOps); engine.MomentumScroll = momentumScroll; engine.ShowAvatars = showAvatars; engine.Begin(); engine.SetFastQuit(prefs.Get("FastQuit", true)); + engine.TouchUI = prefs.Get("TouchUI", DEFAULT_TOUCH_UI); + + if (Client::Ref().IsFirstRun() && FORCE_WINDOW_FRAME_OPS == forceWindowFrameOpsNone) + { + scale = GuessBestScale(); + if (scale > 1) + { + prefs.Set("Scale", scale); + showLargeScreenDialog = true; + } + } + + SDLSetScreen(scale, { + prefs.Get("Resizable", false), + prefs.Get("Fullscreen", false), + prefs.Get("AltFullscreen", false), + prefs.Get("ForceIntegerScaling", true), + }, vsyncHint); bool enableBluescreen = USE_BLUESCREEN && !true_arg(arguments["disable-bluescreen"]); if (enableBluescreen) diff --git a/src/PowderToyFontEditor.cpp b/src/PowderToyFontEditor.cpp index f84f9f23b..a2c1be11b 100644 --- a/src/PowderToyFontEditor.cpp +++ b/src/PowderToyFontEditor.cpp @@ -51,10 +51,6 @@ int main(int argc, char * argv[]) scale = buf; } } - resizable = false; - fullscreen = false; - altFullscreen = false; - forceIntegerScaling = true; // TODO: maybe bind the maximum allowed scale to screen size somehow if(scale < 1 || scale > 10) @@ -69,10 +65,7 @@ int main(int argc, char * argv[]) auto &engine = ui::Engine::Ref(); engine.g = new Graphics(); engine.Scale = scale; - engine.SetResizable(resizable); - engine.Fullscreen = fullscreen; - engine.SetAltFullscreen(altFullscreen); - engine.SetForceIntegerScaling(forceIntegerScaling); + engine.SetWindowFrameOps({ false, false, false, false }); engine.Begin(); engine.SetFastQuit(true); diff --git a/src/PowderToySDL.cpp b/src/PowderToySDL.cpp index 2c77c5a20..34127d00e 100644 --- a/src/PowderToySDL.cpp +++ b/src/PowderToySDL.cpp @@ -13,11 +13,8 @@ SDL_Window *sdl_window = NULL; SDL_Renderer *sdl_renderer = NULL; SDL_Texture *sdl_texture = NULL; int scale = 1; -bool fullscreen = false; -bool altFullscreen = false; -bool forceIntegerScaling = true; bool vsyncHint = false; -bool resizable = false; +WindowFrameOps currentFrameOps = { false, false, false, false }; bool momentumScroll = true; bool showAvatars = true; uint64_t lastTick = 0; @@ -91,7 +88,7 @@ void blit(pixel *vid) { SDL_UpdateTexture(sdl_texture, NULL, vid, WINDOWW * sizeof (Uint32)); // need to clear the renderer if there are black edges (fullscreen, or resizable window) - if (fullscreen || resizable) + if (currentFrameOps.fullscreen || currentFrameOps.resizable) SDL_RenderClear(sdl_renderer); SDL_RenderCopy(sdl_renderer, sdl_texture, NULL, NULL); SDL_RenderPresent(sdl_renderer); @@ -144,22 +141,36 @@ void SDLClose() SDL_Quit(); } -void SDLSetScreen(int scale_, bool resizable_, bool fullscreen_, bool altFullscreen_, bool forceIntegerScaling_, bool vsyncHint_) +void SDLSetScreen(int scale_, WindowFrameOps newFrameOps, bool vsyncHint_) { + if (FORCE_WINDOW_FRAME_OPS == forceWindowFrameOpsEmbedded) + { + newFrameOps.resizable = false; + newFrameOps.fullscreen = false; + newFrameOps.changeResolution = false; + newFrameOps.forceIntegerScaling = false; + } + if (FORCE_WINDOW_FRAME_OPS == forceWindowFrameOpsHandheld) + { + newFrameOps.resizable = false; + newFrameOps.fullscreen = true; + newFrameOps.changeResolution = false; + newFrameOps.forceIntegerScaling = false; + } // bool changingScale = scale != scale_; - bool changingFullscreen = fullscreen_ != fullscreen || (altFullscreen_ != altFullscreen && fullscreen); - bool changingResizable = resizable != resizable_; + bool changingFullscreen = newFrameOps.fullscreen != currentFrameOps.fullscreen || (newFrameOps.changeResolution != currentFrameOps.changeResolution && currentFrameOps.fullscreen); + bool changingResizable = currentFrameOps.resizable != newFrameOps.resizable; bool changingVsync = vsyncHint != vsyncHint_; scale = scale_; - fullscreen = fullscreen_; - altFullscreen = altFullscreen_; - resizable = resizable_; - forceIntegerScaling = forceIntegerScaling_; + currentFrameOps.fullscreen = newFrameOps.fullscreen; + currentFrameOps.changeResolution = newFrameOps.changeResolution; + currentFrameOps.resizable = newFrameOps.resizable; + currentFrameOps.forceIntegerScaling = newFrameOps.forceIntegerScaling; vsyncHint = vsyncHint_; // Recreate the window when toggling fullscreen, due to occasional issues // Also recreate it when enabling resizable windows, to fix bugs on windows, // see https://github.com/jacob1/The-Powder-Toy/issues/24 - if (changingFullscreen || altFullscreen || (changingResizable && resizable && !fullscreen) || changingVsync) + if (changingFullscreen || currentFrameOps.changeResolution || (changingResizable && currentFrameOps.resizable && !currentFrameOps.fullscreen) || changingVsync) { RecreateWindow(); return; @@ -168,23 +179,23 @@ void SDLSetScreen(int scale_, bool resizable_, bool fullscreen_, bool altFullscr SDL_RestoreWindow(sdl_window); SDL_SetWindowSize(sdl_window, WINDOWW * scale, WINDOWH * scale); - SDL_RenderSetIntegerScale(sdl_renderer, forceIntegerScaling && fullscreen ? SDL_TRUE : SDL_FALSE); + SDL_RenderSetIntegerScale(sdl_renderer, currentFrameOps.forceIntegerScaling && currentFrameOps.fullscreen ? SDL_TRUE : SDL_FALSE); unsigned int flags = 0; - if (fullscreen) - flags = altFullscreen ? SDL_WINDOW_FULLSCREEN : SDL_WINDOW_FULLSCREEN_DESKTOP; + if (currentFrameOps.fullscreen) + flags = currentFrameOps.changeResolution ? SDL_WINDOW_FULLSCREEN : SDL_WINDOW_FULLSCREEN_DESKTOP; SDL_SetWindowFullscreen(sdl_window, flags); - if (fullscreen) + if (currentFrameOps.fullscreen) SDL_RaiseWindow(sdl_window); - SDL_SetWindowResizable(sdl_window, resizable ? SDL_TRUE : SDL_FALSE); + SDL_SetWindowResizable(sdl_window, currentFrameOps.resizable ? SDL_TRUE : SDL_FALSE); } bool RecreateWindow() { unsigned int flags = 0; unsigned int rendererFlags = 0; - if (fullscreen) - flags = altFullscreen ? SDL_WINDOW_FULLSCREEN : SDL_WINDOW_FULLSCREEN_DESKTOP; - if (resizable && !fullscreen) + if (currentFrameOps.fullscreen) + flags = currentFrameOps.changeResolution ? SDL_WINDOW_FULLSCREEN : SDL_WINDOW_FULLSCREEN_DESKTOP; + if (currentFrameOps.resizable && !currentFrameOps.fullscreen) flags |= SDL_WINDOW_RESIZABLE; if (vsyncHint) rendererFlags |= SDL_RENDERER_PRESENTVSYNC; @@ -219,7 +230,7 @@ bool RecreateWindow() return false; } SDL_RenderSetLogicalSize(sdl_renderer, WINDOWW, WINDOWH); - if (forceIntegerScaling && fullscreen) + if (currentFrameOps.forceIntegerScaling && currentFrameOps.fullscreen) SDL_RenderSetIntegerScale(sdl_renderer, SDL_TRUE); sdl_texture = SDL_CreateTexture(sdl_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, WINDOWW, WINDOWH); SDL_RaiseWindow(sdl_window); @@ -390,14 +401,9 @@ void EngineProcess() drawingTimer = 0; auto wantVsync = bool(std::get_if(&fpsLimit)); - if (scale != engine.Scale || - fullscreen != engine.Fullscreen || - altFullscreen != engine.GetAltFullscreen() || - forceIntegerScaling != engine.GetForceIntegerScaling() || - resizable != engine.GetResizable() || - vsyncHint != wantVsync) + if (scale != engine.Scale || currentFrameOps != engine.GetWindowFrameOps() || vsyncHint != wantVsync) { - SDLSetScreen(engine.Scale, engine.GetResizable(), engine.Fullscreen, engine.GetAltFullscreen(), engine.GetForceIntegerScaling(), wantVsync); + SDLSetScreen(engine.Scale, engine.GetWindowFrameOps(), wantVsync); } blit(engine.g->Data()); diff --git a/src/PowderToySDL.h b/src/PowderToySDL.h index e54dc4703..85613f661 100644 --- a/src/PowderToySDL.h +++ b/src/PowderToySDL.h @@ -1,6 +1,7 @@ #pragma once #include "common/String.h" #include "graphics/Pixel.h" +#include "gui/WindowFrameOps.h" #include "FpsLimit.h" #include #include @@ -12,10 +13,8 @@ extern SDL_Window *sdl_window; extern SDL_Renderer *sdl_renderer; extern SDL_Texture *sdl_texture; extern int scale; -extern bool fullscreen; -extern bool altFullscreen; -extern bool forceIntegerScaling; -extern bool resizable; +extern bool vsyncHint; +extern WindowFrameOps currentFrameOps; extern bool momentumScroll; extern bool showAvatars; extern uint64_t lastTick; @@ -41,7 +40,7 @@ void CalculateMousePosition(int *x, int *y); void blit(pixel *vid); void SDLOpen(); void SDLClose(); -void SDLSetScreen(int scale_, bool resizable_, bool fullscreen_, bool altFullscreen_, bool forceIntegerScaling_); +void SDLSetScreen(int scale_, WindowFrameOps newFrameOps, bool vsyncHint_); void SetFpsLimit(FpsLimit newFpsLimit); bool RecreateWindow(); void LoadWindowPosition(); diff --git a/src/gui/WindowFrameOps.h b/src/gui/WindowFrameOps.h new file mode 100644 index 000000000..483b8f1c3 --- /dev/null +++ b/src/gui/WindowFrameOps.h @@ -0,0 +1,26 @@ +#pragma once + +struct WindowFrameOps +{ + bool resizable; + bool fullscreen; + bool changeResolution; + bool forceIntegerScaling; + + bool operator ==(const WindowFrameOps &other) const + { + if (resizable != other.resizable ) return false; + if (fullscreen != other.fullscreen) return false; + if (fullscreen) + { + if (changeResolution != other.changeResolution ) return false; + if (forceIntegerScaling != other.forceIntegerScaling) return false; + } + return true; + } + + bool operator !=(const WindowFrameOps &other) const + { + return !(*this == other); + } +}; diff --git a/src/gui/interface/Engine.cpp b/src/gui/interface/Engine.cpp index fd3a212b5..febe140a6 100644 --- a/src/gui/interface/Engine.cpp +++ b/src/gui/interface/Engine.cpp @@ -15,8 +15,6 @@ Engine::Engine(): Scale(1), Fullscreen(false), FrameIndex(0), - altFullscreen(false), - resizable(false), state_(NULL), windowTargetPosition(0, 0), FastQuit(1), diff --git a/src/gui/interface/Engine.h b/src/gui/interface/Engine.h index 4a39ce781..a048309e1 100644 --- a/src/gui/interface/Engine.h +++ b/src/gui/interface/Engine.h @@ -5,6 +5,7 @@ #include "common/ExplicitSingleton.h" #include "graphics/Pixel.h" #include "gui/interface/Point.h" +#include "gui/WindowFrameOps.h" #include #include "FpsLimit.h" @@ -47,16 +48,8 @@ namespace ui void SetDrawingFrequencyLimit(int limit) {drawingFrequencyLimit = limit;} inline int GetDrawingFrequencyLimit() {return drawingFrequencyLimit;} - void SetFullscreen(bool fullscreen) { Fullscreen = fullscreen; } - inline bool GetFullscreen() { return Fullscreen; } - void SetAltFullscreen(bool altFullscreen) { this->altFullscreen = altFullscreen; } - inline bool GetAltFullscreen() { return altFullscreen; } - void SetForceIntegerScaling(bool forceIntegerScaling) { this->forceIntegerScaling = forceIntegerScaling; } - inline bool GetForceIntegerScaling() { return forceIntegerScaling; } void SetScale(int scale) { Scale = scale; } inline int GetScale() { return Scale; } - void SetResizable(bool resizable) { this->resizable = resizable; } - inline bool GetResizable() { return resizable; } void SetFastQuit(bool fastquit) { FastQuit = fastquit; } inline bool GetFastQuit() {return FastQuit; } @@ -93,9 +86,6 @@ namespace ui unsigned int FrameIndex; private: FpsLimit fpsLimit; - bool altFullscreen; - bool forceIntegerScaling = true; - bool resizable; bool textInput = false; int lastTextEditingStart = INT_MAX; @@ -131,9 +121,31 @@ namespace ui String textEditingBuf; + WindowFrameOps windowFrameOps = { false, false, false, false }; + public: bool MomentumScroll = true; bool ShowAvatars = true; + bool TouchUI = false; + + inline WindowFrameOps GetWindowFrameOps() const + { + return windowFrameOps; + } + + inline void SetWindowFrameOps(WindowFrameOps newWindowFrameOps) + { + windowFrameOps = newWindowFrameOps; + } + + void SetFullscreen (bool newFullscreen ) { windowFrameOps.fullscreen = newFullscreen; } + void SetChangeResolution (bool setChangeResolution ) { windowFrameOps.changeResolution = setChangeResolution; } + void SetForceIntegerScaling(bool newForceIntegerScaling) { windowFrameOps.forceIntegerScaling = newForceIntegerScaling; } + void SetResizable (bool newResizable ) { windowFrameOps.resizable = newResizable; } + inline bool GetFullscreen () const { return windowFrameOps.fullscreen; } + inline bool GetChangeResolution () const { return windowFrameOps.changeResolution; } + inline bool GetForceIntegerScaling() const { return windowFrameOps.forceIntegerScaling; } + inline bool GetResizable () const { return windowFrameOps.resizable; } }; } diff --git a/src/gui/options/OptionsController.cpp b/src/gui/options/OptionsController.cpp index 4a67e2bd1..b6191927d 100644 --- a/src/gui/options/OptionsController.cpp +++ b/src/gui/options/OptionsController.cpp @@ -77,9 +77,9 @@ void OptionsController::SetFullscreen(bool fullscreen) model->SetFullscreen(fullscreen); } -void OptionsController::SetAltFullscreen(bool altFullscreen) +void OptionsController::SetChangeResolution(bool newChangeResolution) { - model->SetAltFullscreen(altFullscreen); + model->SetChangeResolution(newChangeResolution); } void OptionsController::SetForceIntegerScaling(bool forceIntegerScaling) diff --git a/src/gui/options/OptionsController.h b/src/gui/options/OptionsController.h index d211f981c..88c7aed01 100644 --- a/src/gui/options/OptionsController.h +++ b/src/gui/options/OptionsController.h @@ -25,7 +25,7 @@ public: void SetEdgeMode(int edgeMode); void SetTemperatureScale(int temperatureScale); void SetFullscreen(bool fullscreen); - void SetAltFullscreen(bool altFullscreen); + void SetChangeResolution(bool newChangeResolution); void SetForceIntegerScaling(bool forceIntegerScaling); void SetScale(int scale); void SetGraveExitsConsole(bool graveExitsConsole); diff --git a/src/gui/options/OptionsModel.cpp b/src/gui/options/OptionsModel.cpp index 7c49960b1..27442a9ce 100644 --- a/src/gui/options/OptionsModel.cpp +++ b/src/gui/options/OptionsModel.cpp @@ -191,15 +191,15 @@ void OptionsModel::SetFullscreen(bool fullscreen) notifySettingsChanged(); } -bool OptionsModel::GetAltFullscreen() +bool OptionsModel::GetChangeResolution() { - return ui::Engine::Ref().GetAltFullscreen(); + return ui::Engine::Ref().GetChangeResolution(); } -void OptionsModel::SetAltFullscreen(bool altFullscreen) +void OptionsModel::SetChangeResolution(bool newChangeResolution) { - ui::Engine::Ref().SetAltFullscreen(altFullscreen); - GlobalPrefs::Ref().Set("AltFullscreen", altFullscreen); + ui::Engine::Ref().SetChangeResolution(newChangeResolution); + GlobalPrefs::Ref().Set("AltFullscreen", newChangeResolution); notifySettingsChanged(); } diff --git a/src/gui/options/OptionsModel.h b/src/gui/options/OptionsModel.h index 23f340471..7adebe427 100644 --- a/src/gui/options/OptionsModel.h +++ b/src/gui/options/OptionsModel.h @@ -45,8 +45,8 @@ public: void SetResizable(bool resizable); bool GetFullscreen(); void SetFullscreen(bool fullscreen); - bool GetAltFullscreen(); - void SetAltFullscreen(bool oldFullscreen); + bool GetChangeResolution(); + void SetChangeResolution(bool newChangeResolution); bool GetForceIntegerScaling(); void SetForceIntegerScaling(bool forceIntegerScaling); bool GetFastQuit(); diff --git a/src/gui/options/OptionsView.cpp b/src/gui/options/OptionsView.cpp index b8700ebf9..cbb119220 100644 --- a/src/gui/options/OptionsView.cpp +++ b/src/gui/options/OptionsView.cpp @@ -228,8 +228,9 @@ OptionsView::OptionsView() : ui::Window(ui::Point(-1, -1), ui::Point(320, 340)) }, [this] { c->SetTemperatureScale(temperatureScale->GetOption().second); }); - addSeparator(); + if (FORCE_WINDOW_FRAME_OPS != forceWindowFrameOpsHandheld) { + addSeparator(); std::vector> options; int currentScale = ui::Engine::Ref().GetScale(); int scaleIndex = 1; @@ -252,7 +253,7 @@ OptionsView::OptionsView() : ui::Window(ui::Point(-1, -1), ui::Point(320, 340)) c->SetScale(scale->GetOption().second); }); } - if (ALLOW_WINDOW_FRAME_OPS) + if (FORCE_WINDOW_FRAME_OPS == forceWindowFrameOpsNone) { resizable = addCheckbox(0, "Resizable \bg- allow resizing and maximizing window", "", [this] { c->SetResizable(resizable->GetChecked()); @@ -260,8 +261,8 @@ OptionsView::OptionsView() : ui::Window(ui::Point(-1, -1), ui::Point(320, 340)) fullscreen = addCheckbox(0, "Fullscreen \bg- fill the entire screen", "", [this] { c->SetFullscreen(fullscreen->GetChecked()); }); - altFullscreen = addCheckbox(1, "Set optimal screen resolution", "", [this] { - c->SetAltFullscreen(altFullscreen->GetChecked()); + changeResolution = addCheckbox(1, "Set optimal screen resolution", "", [this] { + c->SetChangeResolution(changeResolution->GetChecked()); }); forceIntegerScaling = addCheckbox(1, "Force integer scaling \bg- less blurry", "", [this] { c->SetForceIntegerScaling(forceIntegerScaling->GetChecked()); @@ -427,7 +428,10 @@ void OptionsView::NotifySettingsChanged(OptionsModel * sender) customGravityY = sender->GetCustomGravityY(); decoSpace->SetOption(sender->GetDecoSpace()); edgeMode->SetOption(sender->GetEdgeMode()); - scale->SetOption(sender->GetScale()); + if (scale) + { + scale->SetOption(sender->GetScale()); + } if (resizable) { resizable->SetChecked(sender->GetResizable()); @@ -436,9 +440,9 @@ void OptionsView::NotifySettingsChanged(OptionsModel * sender) { fullscreen->SetChecked(sender->GetFullscreen()); } - if (altFullscreen) + if (changeResolution) { - altFullscreen->SetChecked(sender->GetAltFullscreen()); + changeResolution->SetChecked(sender->GetChangeResolution()); } if (forceIntegerScaling) { diff --git a/src/gui/options/OptionsView.h b/src/gui/options/OptionsView.h index fb67e64c1..8272ed3d8 100644 --- a/src/gui/options/OptionsView.h +++ b/src/gui/options/OptionsView.h @@ -29,7 +29,7 @@ class OptionsView: public ui::Window ui::DropDown * scale; ui::Checkbox * resizable; ui::Checkbox * fullscreen; - ui::Checkbox * altFullscreen; + ui::Checkbox * changeResolution; ui::Checkbox * forceIntegerScaling; ui::Checkbox * fastquit = nullptr; ui::DropDown * decoSpace; diff --git a/src/meson.build b/src/meson.build index 1ad17e6b3..96595a170 100644 --- a/src/meson.build +++ b/src/meson.build @@ -22,19 +22,25 @@ conf_data.set('USE_UPDATESERVER', (update_server != '').to_string()) enforce_https = get_option('enforce_https') allow_quit = true -allow_window_frame_ops = true +force_window_frame_ops = 'forceWindowFrameOpsNone' allow_data_folder = true if host_platform == 'emscripten' allow_quit = false - allow_window_frame_ops = false + force_window_frame_ops = 'forceWindowFrameOpsEmbedded' allow_data_folder = false endif +default_touch_ui = false +if host_platform == 'android' + default_touch_ui = true # TODO: some more sophisticated heuristic at runtime instead + force_window_frame_ops = 'forceWindowFrameOpsHandheld' +endif secure_ciphers_only = get_option('secure_ciphers_only') if not is_debug and not enforce_https error('refusing to build a release binary without enforcing HTTPS, configure with -Denforce_https=true to fix this error') endif conf_data.set('ALLOW_QUIT', allow_quit.to_string()) -conf_data.set('ALLOW_WINDOW_FRAME_OPS', allow_window_frame_ops.to_string()) +conf_data.set('FORCE_WINDOW_FRAME_OPS', force_window_frame_ops) +conf_data.set('DEFAULT_TOUCH_UI', default_touch_ui.to_string()) conf_data.set('ALLOW_DATA_FOLDER', allow_data_folder.to_string()) conf_data.set('ENFORCE_HTTPS', enforce_https.to_string()) conf_data.set('SECURE_CIPHERS_ONLY', secure_ciphers_only.to_string()) @@ -58,7 +64,12 @@ if host_platform == 'android' '', ] endif + android_properties = [] + if is_debug + android_properties += [ 'android:debuggable="true"' ] + endif conf_data.set('ANDROID_PERMISSIONS', '\n'.join(android_permissions)) + conf_data.set('ANDROID_PROPERTIES', '\n'.join(android_properties)) endif powder_files = files( From 1a8ebd0981d1250a30db1bb87cdad07cfec150c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20B=C3=A1lint=20Misius?= Date: Wed, 4 Oct 2023 19:31:58 +0200 Subject: [PATCH 10/27] Fix occasional crashes upon opening settings By zero-initializing pointers in OptionsView so they don't crash when they don't get initialized, which up until very recently they always had. In the cases of the emscripten and android ports, certain components are never created. --- src/gui/options/OptionsView.h | 50 +++++++++++++++++------------------ 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/src/gui/options/OptionsView.h b/src/gui/options/OptionsView.h index 8272ed3d8..d598140e4 100644 --- a/src/gui/options/OptionsView.h +++ b/src/gui/options/OptionsView.h @@ -15,31 +15,31 @@ class OptionsModel; class OptionsController; class OptionsView: public ui::Window { - OptionsController * c; - ui::Checkbox * heatSimulation; - ui::Checkbox * ambientHeatSimulation; - ui::Checkbox * newtonianGravity; - ui::Checkbox * waterEqualisation; - ui::DropDown * airMode; - ui::Textbox * ambientAirTemp; - ui::Button * ambientAirTempPreview; - ui::DropDown * gravityMode; - ui::DropDown * edgeMode; - ui::DropDown * temperatureScale; - ui::DropDown * scale; - ui::Checkbox * resizable; - ui::Checkbox * fullscreen; - ui::Checkbox * changeResolution; - ui::Checkbox * forceIntegerScaling; - ui::Checkbox * fastquit = nullptr; - ui::DropDown * decoSpace; - ui::Checkbox * showAvatars; - ui::Checkbox * momentumScroll; - ui::Checkbox * mouseClickRequired; - ui::Checkbox * includePressure; - ui::Checkbox * perfectCircle; - ui::Checkbox * graveExitsConsole; - ui::ScrollPanel * scrollPanel; + OptionsController *c{}; + ui::Checkbox *heatSimulation{}; + ui::Checkbox *ambientHeatSimulation{}; + ui::Checkbox *newtonianGravity{}; + ui::Checkbox *waterEqualisation{}; + ui::DropDown *airMode{}; + ui::Textbox *ambientAirTemp{}; + ui::Button *ambientAirTempPreview{}; + ui::DropDown *gravityMode{}; + ui::DropDown *edgeMode{}; + ui::DropDown *temperatureScale{}; + ui::DropDown *scale{}; + ui::Checkbox *resizable{}; + ui::Checkbox *fullscreen{}; + ui::Checkbox *changeResolution{}; + ui::Checkbox *forceIntegerScaling{}; + ui::Checkbox *fastquit{}; + ui::DropDown *decoSpace{}; + ui::Checkbox *showAvatars{}; + ui::Checkbox *momentumScroll{}; + ui::Checkbox *mouseClickRequired{}; + ui::Checkbox *includePressure{}; + ui::Checkbox *perfectCircle{}; + ui::Checkbox *graveExitsConsole{}; + ui::ScrollPanel *scrollPanel{}; float customGravityX, customGravityY; void UpdateAmbientAirTempPreview(float airTemp, bool isValid); void AmbientAirTempToTextBox(float airTemp); From 0fb36012a286a78e2c3945aa93d5a4c255bd3fe2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20B=C3=A1lint=20Misius?= Date: Thu, 5 Oct 2023 19:42:20 +0200 Subject: [PATCH 11/27] Clean up window creation somewhat Fixes most of the rat's nest situation mentioned in 8cfe7cdd93e8. --- src/PowderToy.cpp | 47 ++++----- src/PowderToyFontEditor.cpp | 19 ++-- src/PowderToySDL.cpp | 195 ++++++++++++++++++----------------- src/PowderToySDL.h | 8 +- src/gui/WindowFrameOps.h | 32 +++--- src/gui/interface/Engine.cpp | 5 +- src/gui/interface/Engine.h | 28 ++--- 7 files changed, 155 insertions(+), 179 deletions(-) diff --git a/src/PowderToy.cpp b/src/PowderToy.cpp index e49a8a1f6..8ef3dd403 100644 --- a/src/PowderToy.cpp +++ b/src/PowderToy.cpp @@ -81,12 +81,13 @@ void SaveWindowPosition() void LargeScreenDialog() { StringBuilder message; + auto scale = ui::Engine::Ref().windowFrameOps.scale; message << "Switching to " << scale << "x size mode since your screen was determined to be large enough: "; - message << desktopWidth << "x" << desktopHeight << " detected, " << WINDOWW*scale << "x" << WINDOWH*scale << " required"; + message << desktopWidth << "x" << desktopHeight << " detected, " << WINDOWW * scale << "x" << WINDOWH * scale << " required"; message << "\nTo undo this, hit Cancel. You can change this in settings at any time."; new ConfirmPrompt("Large screen detected", message.Build(), { nullptr, []() { GlobalPrefs::Ref().Set("Scale", 1); - ui::Engine::Ref().SetScale(1); + ui::Engine::Ref().windowFrameOps.scale = 1; } }); } @@ -285,7 +286,14 @@ int Main(int argc, char *argv[]) explicitSingletons->globalPrefs = std::make_unique(); auto &prefs = GlobalPrefs::Ref(); - scale = prefs.Get("Scale", 1); + + WindowFrameOps windowFrameOps{ + prefs.Get("Scale", 1), + prefs.Get("Resizable", false), + prefs.Get("Fullscreen", false), + prefs.Get("AltFullscreen", false), + prefs.Get("ForceIntegerScaling", true), + }; auto graveExitsConsole = prefs.Get("GraveExitsConsole", true); momentumScroll = prefs.Get("MomentumScroll", true); showAvatars = prefs.Get("ShowAvatars", true); @@ -307,8 +315,8 @@ int Main(int argc, char *argv[]) auto kioskArg = arguments["kiosk"]; if (kioskArg.has_value()) { - currentFrameOps.fullscreen = true_string(kioskArg.value()); - prefs.Set("Fullscreen", currentFrameOps.fullscreen); + windowFrameOps.fullscreen = true_string(kioskArg.value()); + prefs.Set("Fullscreen", windowFrameOps.fullscreen); } if (true_arg(arguments["redirect"])) @@ -326,8 +334,8 @@ int Main(int argc, char *argv[]) { try { - scale = scaleArg.value().ToNumber(); - prefs.Set("Scale", scale); + windowFrameOps.scale = scaleArg.value().ToNumber(); + prefs.Set("Scale", windowFrameOps.scale); } catch (const std::runtime_error &e) { @@ -366,40 +374,29 @@ int Main(int argc, char *argv[]) explicitSingletons->engine = std::make_unique(); // TODO: maybe bind the maximum allowed scale to screen size somehow - if(scale < 1 || scale > SCALE_MAXIMUM) - scale = 1; - - SDLOpen(); - - StopTextInput(); + if(windowFrameOps.scale < 1 || windowFrameOps.scale > SCALE_MAXIMUM) + windowFrameOps.scale = 1; auto &engine = ui::Engine::Ref(); engine.g = new Graphics(); - engine.Scale = scale; engine.GraveExitsConsole = graveExitsConsole; - engine.SetWindowFrameOps(currentFrameOps); engine.MomentumScroll = momentumScroll; engine.ShowAvatars = showAvatars; engine.Begin(); engine.SetFastQuit(prefs.Get("FastQuit", true)); engine.TouchUI = prefs.Get("TouchUI", DEFAULT_TOUCH_UI); - if (Client::Ref().IsFirstRun() && FORCE_WINDOW_FRAME_OPS == forceWindowFrameOpsNone) { - scale = GuessBestScale(); - if (scale > 1) + windowFrameOps.scale = GuessBestScale(); + if (windowFrameOps.scale) { - prefs.Set("Scale", scale); + prefs.Set("Scale", windowFrameOps.scale); showLargeScreenDialog = true; } } + engine.windowFrameOps = windowFrameOps; - SDLSetScreen(scale, { - prefs.Get("Resizable", false), - prefs.Get("Fullscreen", false), - prefs.Get("AltFullscreen", false), - prefs.Get("ForceIntegerScaling", true), - }, vsyncHint); + SDLOpen(); bool enableBluescreen = USE_BLUESCREEN && !true_arg(arguments["disable-bluescreen"]); if (enableBluescreen) diff --git a/src/PowderToyFontEditor.cpp b/src/PowderToyFontEditor.cpp index a2c1be11b..6abf05eaa 100644 --- a/src/PowderToyFontEditor.cpp +++ b/src/PowderToyFontEditor.cpp @@ -41,31 +41,30 @@ int main(int argc, char * argv[]) }); explicitSingletons = std::make_unique(); - scale = 1; + WindowFrameOps windowFrameOps; if (argc >= 3) { std::istringstream ss(argv[2]); int buf; if (ss >> buf) { - scale = buf; + windowFrameOps.scale = buf; } } // TODO: maybe bind the maximum allowed scale to screen size somehow - if(scale < 1 || scale > 10) - scale = 1; + if (windowFrameOps.scale < 1 || windowFrameOps.scale > 10) + { + windowFrameOps.scale = 1; + } explicitSingletons->engine = std::make_unique(); - SDLOpen(); - - StopTextInput(); - auto &engine = ui::Engine::Ref(); engine.g = new Graphics(); - engine.Scale = scale; - engine.SetWindowFrameOps({ false, false, false, false }); + engine.windowFrameOps = windowFrameOps; + + SDLOpen(); engine.Begin(); engine.SetFastQuit(true); diff --git a/src/PowderToySDL.cpp b/src/PowderToySDL.cpp index 34127d00e..c5323e52f 100644 --- a/src/PowderToySDL.cpp +++ b/src/PowderToySDL.cpp @@ -12,9 +12,8 @@ int desktopHeight = 1024; SDL_Window *sdl_window = NULL; SDL_Renderer *sdl_renderer = NULL; SDL_Texture *sdl_texture = NULL; -int scale = 1; bool vsyncHint = false; -WindowFrameOps currentFrameOps = { false, false, false, false }; +WindowFrameOps currentFrameOps; bool momentumScroll = true; bool showAvatars = true; uint64_t lastTick = 0; @@ -71,7 +70,7 @@ unsigned int GetTicks() return SDL_GetTicks(); } -void CalculateMousePosition(int *x, int *y) +static void CalculateMousePosition(int *x, int *y) { int globalMx, globalMy; SDL_GetGlobalMouseState(&globalMx, &globalMy); @@ -79,9 +78,9 @@ void CalculateMousePosition(int *x, int *y) SDL_GetWindowPosition(sdl_window, &windowX, &windowY); if (x) - *x = (globalMx - windowX) / scale; + *x = (globalMx - windowX) / currentFrameOps.scale; if (y) - *y = (globalMy - windowY) / scale; + *y = (globalMy - windowY) / currentFrameOps.scale; } void blit(pixel *vid) @@ -102,11 +101,7 @@ void SDLOpen() Platform::Exit(-1); } - if (!RecreateWindow()) - { - fprintf(stderr, "Creating SDL window: %s\n", SDL_GetError()); - Platform::Exit(-1); - } + SDLSetScreen(); int displayIndex = SDL_GetWindowDisplayIndex(sdl_window); if (displayIndex >= 0) @@ -123,6 +118,8 @@ void SDLOpen() { WindowIcon(sdl_window); } + + StopTextInput(); } void SDLClose() @@ -141,8 +138,10 @@ void SDLClose() SDL_Quit(); } -void SDLSetScreen(int scale_, WindowFrameOps newFrameOps, bool vsyncHint_) +void SDLSetScreen() { + auto newFrameOps = ui::Engine::Ref().windowFrameOps; + auto newVsyncHint = std::holds_alternative(ui::Engine::Ref().GetFpsLimit()); if (FORCE_WINDOW_FRAME_OPS == forceWindowFrameOpsEmbedded) { newFrameOps.resizable = false; @@ -157,95 +156,107 @@ void SDLSetScreen(int scale_, WindowFrameOps newFrameOps, bool vsyncHint_) newFrameOps.changeResolution = false; newFrameOps.forceIntegerScaling = false; } -// bool changingScale = scale != scale_; - bool changingFullscreen = newFrameOps.fullscreen != currentFrameOps.fullscreen || (newFrameOps.changeResolution != currentFrameOps.changeResolution && currentFrameOps.fullscreen); - bool changingResizable = currentFrameOps.resizable != newFrameOps.resizable; - bool changingVsync = vsyncHint != vsyncHint_; - scale = scale_; - currentFrameOps.fullscreen = newFrameOps.fullscreen; - currentFrameOps.changeResolution = newFrameOps.changeResolution; - currentFrameOps.resizable = newFrameOps.resizable; - currentFrameOps.forceIntegerScaling = newFrameOps.forceIntegerScaling; - vsyncHint = vsyncHint_; - // Recreate the window when toggling fullscreen, due to occasional issues - // Also recreate it when enabling resizable windows, to fix bugs on windows, - // see https://github.com/jacob1/The-Powder-Toy/issues/24 - if (changingFullscreen || currentFrameOps.changeResolution || (changingResizable && currentFrameOps.resizable && !currentFrameOps.fullscreen) || changingVsync) + + auto currentFrameOpsNorm = currentFrameOps.Normalize(); + auto newFrameOpsNorm = newFrameOps.Normalize(); + auto recreate = !sdl_window || + // Recreate the window when toggling fullscreen, due to occasional issues + newFrameOpsNorm.fullscreen != currentFrameOpsNorm.fullscreen || + // Also recreate it when enabling resizable windows, to fix bugs on windows, + // see https://github.com/jacob1/The-Powder-Toy/issues/24 + newFrameOpsNorm.resizable != currentFrameOpsNorm.resizable || + newFrameOpsNorm.changeResolution != currentFrameOpsNorm.changeResolution || + newVsyncHint != vsyncHint; + + if (!(recreate || + newFrameOpsNorm.scale != currentFrameOpsNorm.scale || + newFrameOpsNorm.forceIntegerScaling != currentFrameOpsNorm.forceIntegerScaling)) { - RecreateWindow(); return; } - if (changingResizable) - SDL_RestoreWindow(sdl_window); - SDL_SetWindowSize(sdl_window, WINDOWW * scale, WINDOWH * scale); - SDL_RenderSetIntegerScale(sdl_renderer, currentFrameOps.forceIntegerScaling && currentFrameOps.fullscreen ? SDL_TRUE : SDL_FALSE); - unsigned int flags = 0; - if (currentFrameOps.fullscreen) - flags = currentFrameOps.changeResolution ? SDL_WINDOW_FULLSCREEN : SDL_WINDOW_FULLSCREEN_DESKTOP; - SDL_SetWindowFullscreen(sdl_window, flags); - if (currentFrameOps.fullscreen) - SDL_RaiseWindow(sdl_window); - SDL_SetWindowResizable(sdl_window, currentFrameOps.resizable ? SDL_TRUE : SDL_FALSE); -} + auto size = WINDOW * newFrameOpsNorm.scale; -bool RecreateWindow() -{ - unsigned int flags = 0; - unsigned int rendererFlags = 0; - if (currentFrameOps.fullscreen) - flags = currentFrameOps.changeResolution ? SDL_WINDOW_FULLSCREEN : SDL_WINDOW_FULLSCREEN_DESKTOP; - if (currentFrameOps.resizable && !currentFrameOps.fullscreen) - flags |= SDL_WINDOW_RESIZABLE; - if (vsyncHint) - rendererFlags |= SDL_RENDERER_PRESENTVSYNC; - - if (sdl_texture) - SDL_DestroyTexture(sdl_texture); - if (sdl_renderer) - SDL_DestroyRenderer(sdl_renderer); - if (sdl_window) + if (recreate) { - SaveWindowPosition(); - SDL_DestroyWindow(sdl_window); - } - - sdl_window = SDL_CreateWindow(APPNAME, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, WINDOWW * scale, WINDOWH * scale, - flags); - if (!sdl_window) - { - return false; - } - sdl_renderer = SDL_CreateRenderer(sdl_window, -1, rendererFlags); - if (!sdl_renderer) - { - fprintf(stderr, "SDL_CreateRenderer failed; available renderers:\n"); - int num = SDL_GetNumRenderDrivers(); - for (int i = 0; i < num; ++i) + if (sdl_texture) { - SDL_RendererInfo info; - SDL_GetRenderDriverInfo(i, &info); - fprintf(stderr, " - %s\n", info.name); + SDL_DestroyTexture(sdl_texture); + sdl_texture = NULL; } - return false; + if (sdl_renderer) + { + SDL_DestroyRenderer(sdl_renderer); + sdl_renderer = NULL; + } + if (sdl_window) + { + SaveWindowPosition(); + SDL_DestroyWindow(sdl_window); + sdl_window = NULL; + } + + unsigned int flags = 0; + unsigned int rendererFlags = 0; + if (newFrameOpsNorm.fullscreen) + { + flags = newFrameOpsNorm.changeResolution ? SDL_WINDOW_FULLSCREEN : SDL_WINDOW_FULLSCREEN_DESKTOP; + } + if (newFrameOpsNorm.resizable) + { + flags |= SDL_WINDOW_RESIZABLE; + } + if (vsyncHint) + { + rendererFlags |= SDL_RENDERER_PRESENTVSYNC; + } + sdl_window = SDL_CreateWindow(APPNAME, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, size.X, size.Y, flags); + if (!sdl_window) + { + fprintf(stderr, "SDL_CreateWindow failed: %s\n", SDL_GetError()); + Platform::Exit(-1); + } + sdl_renderer = SDL_CreateRenderer(sdl_window, -1, rendererFlags); + if (!sdl_renderer) + { + fprintf(stderr, "SDL_CreateRenderer failed; available renderers:\n"); + int num = SDL_GetNumRenderDrivers(); + for (int i = 0; i < num; ++i) + { + SDL_RendererInfo info; + SDL_GetRenderDriverInfo(i, &info); + fprintf(stderr, " - %s\n", info.name); + } + Platform::Exit(-1); + } + SDL_RenderSetLogicalSize(sdl_renderer, WINDOWW, WINDOWH); + sdl_texture = SDL_CreateTexture(sdl_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, WINDOWW, WINDOWH); + if (!sdl_texture) + { + fprintf(stderr, "SDL_CreateTexture failed: %s\n", SDL_GetError()); + Platform::Exit(-1); + } + SDL_RaiseWindow(sdl_window); + SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1"); + //Uncomment this to enable resizing + //SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear"); + //SDL_SetWindowResizable(sdl_window, SDL_TRUE); + + LoadWindowPosition(); + UpdateFpsLimit(); } - SDL_RenderSetLogicalSize(sdl_renderer, WINDOWW, WINDOWH); - if (currentFrameOps.forceIntegerScaling && currentFrameOps.fullscreen) - SDL_RenderSetIntegerScale(sdl_renderer, SDL_TRUE); - sdl_texture = SDL_CreateTexture(sdl_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, WINDOWW, WINDOWH); - SDL_RaiseWindow(sdl_window); - SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1"); - //Uncomment this to enable resizing - //SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear"); - //SDL_SetWindowResizable(sdl_window, SDL_TRUE); - LoadWindowPosition(); - UpdateFpsLimit(); - - return true; + SDL_SetWindowSize(sdl_window, size.X, size.Y); + SDL_RenderSetIntegerScale(sdl_renderer, newFrameOpsNorm.forceIntegerScaling ? SDL_TRUE : SDL_FALSE); + if (newFrameOpsNorm.fullscreen) + { + SDL_RaiseWindow(sdl_window); + } + currentFrameOps = newFrameOps; + vsyncHint = newVsyncHint; } -void EventProcess(const SDL_Event &event) +static void EventProcess(const SDL_Event &event) { auto &engine = ui::Engine::Ref(); switch (event.type) @@ -399,13 +410,7 @@ void EngineProcess() { engine.Draw(); drawingTimer = 0; - - auto wantVsync = bool(std::get_if(&fpsLimit)); - if (scale != engine.Scale || currentFrameOps != engine.GetWindowFrameOps() || vsyncHint != wantVsync) - { - SDLSetScreen(engine.Scale, engine.GetWindowFrameOps(), wantVsync); - } - + SDLSetScreen(); blit(engine.g->Data()); } auto now = uint64_t(SDL_GetTicks()) * UINT64_C(1'000'000); diff --git a/src/PowderToySDL.h b/src/PowderToySDL.h index 85613f661..43e3f69e0 100644 --- a/src/PowderToySDL.h +++ b/src/PowderToySDL.h @@ -12,9 +12,6 @@ extern int desktopHeight; extern SDL_Window *sdl_window; extern SDL_Renderer *sdl_renderer; extern SDL_Texture *sdl_texture; -extern int scale; -extern bool vsyncHint; -extern WindowFrameOps currentFrameOps; extern bool momentumScroll; extern bool showAvatars; extern uint64_t lastTick; @@ -36,16 +33,13 @@ void ClipboardPush(ByteString text); ByteString ClipboardPull(); int GetModifiers(); unsigned int GetTicks(); -void CalculateMousePosition(int *x, int *y); void blit(pixel *vid); void SDLOpen(); void SDLClose(); -void SDLSetScreen(int scale_, WindowFrameOps newFrameOps, bool vsyncHint_); +void SDLSetScreen(); void SetFpsLimit(FpsLimit newFpsLimit); -bool RecreateWindow(); void LoadWindowPosition(); void SaveWindowPosition(); void LargeScreenDialog(); void TickClient(); -void EventProcess(const SDL_Event &event); void UpdateFpsLimit(); diff --git a/src/gui/WindowFrameOps.h b/src/gui/WindowFrameOps.h index 483b8f1c3..cceac8920 100644 --- a/src/gui/WindowFrameOps.h +++ b/src/gui/WindowFrameOps.h @@ -1,26 +1,22 @@ #pragma once +#include struct WindowFrameOps { - bool resizable; - bool fullscreen; - bool changeResolution; - bool forceIntegerScaling; + int scale = 1; + bool resizable = false; + bool fullscreen = false; + bool changeResolution = false; + bool forceIntegerScaling = false; - bool operator ==(const WindowFrameOps &other) const + WindowFrameOps Normalize() const { - if (resizable != other.resizable ) return false; - if (fullscreen != other.fullscreen) return false; - if (fullscreen) - { - if (changeResolution != other.changeResolution ) return false; - if (forceIntegerScaling != other.forceIntegerScaling) return false; - } - return true; - } - - bool operator !=(const WindowFrameOps &other) const - { - return !(*this == other); + return { + fullscreen ? 1 : scale , + fullscreen ? false : resizable , + fullscreen , + fullscreen ? changeResolution : false, + fullscreen ? forceIntegerScaling : false, + }; } }; diff --git a/src/gui/interface/Engine.cpp b/src/gui/interface/Engine.cpp index febe140a6..08887d23d 100644 --- a/src/gui/interface/Engine.cpp +++ b/src/gui/interface/Engine.cpp @@ -12,8 +12,6 @@ using namespace ui; Engine::Engine(): drawingFrequencyLimit(0), - Scale(1), - Fullscreen(false), FrameIndex(0), state_(NULL), windowTargetPosition(0, 0), @@ -333,5 +331,6 @@ void Engine::StopTextInput() void Engine::TextInputRect(Point position, Point size) { - ::SetTextInputRect(position.X * Scale, position.Y * Scale, size.X * Scale, size.Y * Scale); + auto scale = windowFrameOps.scale; + ::SetTextInputRect(position.X * scale, position.Y * scale, size.X * scale, size.Y * scale); } diff --git a/src/gui/interface/Engine.h b/src/gui/interface/Engine.h index a048309e1..b2145cfd0 100644 --- a/src/gui/interface/Engine.h +++ b/src/gui/interface/Engine.h @@ -48,8 +48,6 @@ namespace ui void SetDrawingFrequencyLimit(int limit) {drawingFrequencyLimit = limit;} inline int GetDrawingFrequencyLimit() {return drawingFrequencyLimit;} - void SetScale(int scale) { Scale = scale; } - inline int GetScale() { return Scale; } void SetFastQuit(bool fastquit) { FastQuit = fastquit; } inline bool GetFastQuit() {return FastQuit; } @@ -79,9 +77,7 @@ namespace ui int drawingFrequencyLimit; Graphics * g; - int Scale; bool GraveExitsConsole; - bool Fullscreen; unsigned int FrameIndex; private: @@ -121,31 +117,21 @@ namespace ui String textEditingBuf; - WindowFrameOps windowFrameOps = { false, false, false, false }; - public: bool MomentumScroll = true; bool ShowAvatars = true; bool TouchUI = false; + WindowFrameOps windowFrameOps; - inline WindowFrameOps GetWindowFrameOps() const - { - return windowFrameOps; - } - - inline void SetWindowFrameOps(WindowFrameOps newWindowFrameOps) - { - windowFrameOps = newWindowFrameOps; - } - + void SetScale (int newScale ) { windowFrameOps.scale = newScale; } void SetFullscreen (bool newFullscreen ) { windowFrameOps.fullscreen = newFullscreen; } void SetChangeResolution (bool setChangeResolution ) { windowFrameOps.changeResolution = setChangeResolution; } void SetForceIntegerScaling(bool newForceIntegerScaling) { windowFrameOps.forceIntegerScaling = newForceIntegerScaling; } void SetResizable (bool newResizable ) { windowFrameOps.resizable = newResizable; } - inline bool GetFullscreen () const { return windowFrameOps.fullscreen; } - inline bool GetChangeResolution () const { return windowFrameOps.changeResolution; } - inline bool GetForceIntegerScaling() const { return windowFrameOps.forceIntegerScaling; } - inline bool GetResizable () const { return windowFrameOps.resizable; } + int GetScale () const { return windowFrameOps.scale; } + bool GetFullscreen () const { return windowFrameOps.fullscreen; } + bool GetChangeResolution () const { return windowFrameOps.changeResolution; } + bool GetForceIntegerScaling() const { return windowFrameOps.forceIntegerScaling; } + bool GetResizable () const { return windowFrameOps.resizable; } }; - } From 79760f5c8953ca392333dac7dbeea9adee0642e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20B=C3=A1lint=20Misius?= Date: Thu, 5 Oct 2023 20:08:17 +0200 Subject: [PATCH 12/27] Fix input method candidates being aligned wrong in some cases Namely when the main window is resizeable and its size isn't the same as it would be with the active scale mode with resizing disabled. Also fix window position not being restored when the main window is resizeable. --- src/PowderToySDL.cpp | 17 ++++++++++------- src/gui/interface/Engine.cpp | 3 +-- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/PowderToySDL.cpp b/src/PowderToySDL.cpp index c5323e52f..37b8dc8b5 100644 --- a/src/PowderToySDL.cpp +++ b/src/PowderToySDL.cpp @@ -42,11 +42,15 @@ void StopTextInput() void SetTextInputRect(int x, int y, int w, int h) { + // Why does SDL_SetTextInputRect not take logical coordinates??? + int wx, wy, wwx, why; + SDL_RenderLogicalToWindow(sdl_renderer, x, y, &wx, &wy); + SDL_RenderLogicalToWindow(sdl_renderer, x + w, y + h, &wwx, &why); SDL_Rect rect; - rect.x = x; - rect.y = y; - rect.w = w; - rect.h = h; + rect.x = wx; + rect.y = wy; + rect.w = wwx - wx; + rect.h = why - wy; SDL_SetTextInputRect(&rect); } @@ -241,13 +245,12 @@ void SDLSetScreen() //Uncomment this to enable resizing //SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear"); //SDL_SetWindowResizable(sdl_window, SDL_TRUE); - - LoadWindowPosition(); - UpdateFpsLimit(); } SDL_SetWindowSize(sdl_window, size.X, size.Y); SDL_RenderSetIntegerScale(sdl_renderer, newFrameOpsNorm.forceIntegerScaling ? SDL_TRUE : SDL_FALSE); + LoadWindowPosition(); + UpdateFpsLimit(); if (newFrameOpsNorm.fullscreen) { SDL_RaiseWindow(sdl_window); diff --git a/src/gui/interface/Engine.cpp b/src/gui/interface/Engine.cpp index 08887d23d..0091d3484 100644 --- a/src/gui/interface/Engine.cpp +++ b/src/gui/interface/Engine.cpp @@ -331,6 +331,5 @@ void Engine::StopTextInput() void Engine::TextInputRect(Point position, Point size) { - auto scale = windowFrameOps.scale; - ::SetTextInputRect(position.X * scale, position.Y * scale, size.X * scale, size.Y * scale); + ::SetTextInputRect(position.X, position.Y, size.X, size.Y); } From bb8605fa3b03b566ea56ac96f0d50ca2bcbdac97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20B=C3=A1lint=20Misius?= Date: Thu, 5 Oct 2023 21:18:01 +0200 Subject: [PATCH 13/27] Fix ubuntu 20.04 pipelines By not using SDL_RenderLogicalToWindow if it's not available. Because of course ubuntu 20.04 has sdl 2.0.10, which of course doesn't yet have SDL_RenderLogicalToWindow which was added in 2.0.18, which is of course needed because of course SDL_SetTextInputRect takes window coordinates rather than logical coordinates. At least official static linux builds are not affected because tpt-libs uses much newer sdl. --- src/PowderToySDL.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/PowderToySDL.cpp b/src/PowderToySDL.cpp index 37b8dc8b5..bb7428d2a 100644 --- a/src/PowderToySDL.cpp +++ b/src/PowderToySDL.cpp @@ -43,14 +43,23 @@ void StopTextInput() void SetTextInputRect(int x, int y, int w, int h) { // Why does SDL_SetTextInputRect not take logical coordinates??? + SDL_Rect rect; +#if SDL_VERSION_ATLEAST(2, 0, 18) int wx, wy, wwx, why; SDL_RenderLogicalToWindow(sdl_renderer, x, y, &wx, &wy); SDL_RenderLogicalToWindow(sdl_renderer, x + w, y + h, &wwx, &why); - SDL_Rect rect; rect.x = wx; rect.y = wy; rect.w = wwx - wx; rect.h = why - wy; +#else + // TODO: use SDL_RenderLogicalToWindow when ubuntu deigns to update to sdl 2.0.18 + auto scale = ui::Engine::Ref().windowFrameOps.scale; + rect.x = x * scale; + rect.y = y * scale; + rect.w = w * scale; + rect.h = h * scale; +#endif SDL_SetTextInputRect(&rect); } From 7bb8344d3b4b09a449e0f8eea4e2f96be065e235 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20B=C3=A1lint=20Misius?= Date: Thu, 5 Oct 2023 21:22:25 +0200 Subject: [PATCH 14/27] Fix the Maximized property of windows shortcuts not being respected By not resizing the window if it's resizeable and is somehow already maximized. --- src/PowderToySDL.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/PowderToySDL.cpp b/src/PowderToySDL.cpp index bb7428d2a..45b4b1ae8 100644 --- a/src/PowderToySDL.cpp +++ b/src/PowderToySDL.cpp @@ -255,10 +255,12 @@ void SDLSetScreen() //SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear"); //SDL_SetWindowResizable(sdl_window, SDL_TRUE); } - - SDL_SetWindowSize(sdl_window, size.X, size.Y); SDL_RenderSetIntegerScale(sdl_renderer, newFrameOpsNorm.forceIntegerScaling ? SDL_TRUE : SDL_FALSE); - LoadWindowPosition(); + if (!(newFrameOpsNorm.resizable && SDL_GetWindowFlags(sdl_window) & SDL_WINDOW_MAXIMIZED)) + { + SDL_SetWindowSize(sdl_window, size.X, size.Y); + LoadWindowPosition(); + } UpdateFpsLimit(); if (newFrameOpsNorm.fullscreen) { From bc51bdf634874bc3c16019ad32048858bae78690 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20B=C3=A1lint=20Misius?= Date: Thu, 5 Oct 2023 23:19:59 +0200 Subject: [PATCH 15/27] Add shortcut to toggle fullscreen --- src/gui/game/GameView.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/gui/game/GameView.cpp b/src/gui/game/GameView.cpp index 7d375b3e7..a25978cf4 100644 --- a/src/gui/game/GameView.cpp +++ b/src/gui/game/GameView.cpp @@ -1459,6 +1459,9 @@ void GameView::OnKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl, else introText = 0; break; + case SDL_SCANCODE_F11: + ui::Engine::Ref().SetFullscreen(!ui::Engine::Ref().GetFullscreen()); + break; case SDL_SCANCODE_H: if(ctrl) { From 29ea81164288f5b95b6a829aa4015d71f5183b1e Mon Sep 17 00:00:00 2001 From: jacob1 Date: Thu, 5 Oct 2023 21:32:09 -0400 Subject: [PATCH 16/27] Add enums for gravity/air/edge modes, add more constants to Lua Constants for the new enums were added, along with walls (in the sim.walls table), x/y center, and a few movement constants --- src/client/GameSave.cpp | 6 ++-- src/gui/game/GameController.cpp | 22 ++++++------ src/gui/game/GameModel.cpp | 8 ++--- src/lua/LuaScriptInterface.cpp | 59 ++++++++++++++++++++++++++++++-- src/simulation/Air.cpp | 14 ++++---- src/simulation/Simulation.cpp | 30 ++++++++-------- src/simulation/SimulationData.h | 15 ++++++++ src/simulation/elements/STKM.cpp | 8 ++--- 8 files changed, 115 insertions(+), 47 deletions(-) diff --git a/src/client/GameSave.cpp b/src/client/GameSave.cpp index 5d4533061..1ef394ff8 100644 --- a/src/client/GameSave.cpp +++ b/src/client/GameSave.cpp @@ -1251,8 +1251,8 @@ void GameSave::readPSv(const std::vector &dataVec) auto partP = blockP * CELL; if (ver<46) { - gravityMode = 0; - airMode = 0; + gravityMode = GRAV_VERTICAL; + airMode = AIR_ON; } PlaneAdapter> particleIDMap(RES, 0); @@ -2295,7 +2295,7 @@ std::pair> GameSave::serialiseOPS() const bson_append_string(&b, "platform", IDENT_PLATFORM); bson_append_string(&b, "ident", IDENT); bson_append_finish_object(&b); - if (gravityMode == 3) + if (gravityMode == GRAV_CUSTOM) { bson_append_double(&b, "customGravityX", double(customGravityX)); bson_append_double(&b, "customGravityY", double(customGravityY)); diff --git a/src/gui/game/GameController.cpp b/src/gui/game/GameController.cpp index b0c9e23f4..751168ce6 100644 --- a/src/gui/game/GameController.cpp +++ b/src/gui/game/GameController.cpp @@ -773,20 +773,20 @@ void GameController::ResetSpark() void GameController::SwitchGravity() { - gameModel->GetSimulation()->gravityMode = (gameModel->GetSimulation()->gravityMode+1)%4; + gameModel->GetSimulation()->gravityMode = (gameModel->GetSimulation()->gravityMode + 1) % NUM_GRAV_MODES; switch (gameModel->GetSimulation()->gravityMode) { - case 0: + case GRAV_VERTICAL: gameModel->SetInfoTip("Gravity: Vertical"); break; - case 1: + case GRAV_OFF: gameModel->SetInfoTip("Gravity: Off"); break; - case 2: + case GRAV_RADIAL: gameModel->SetInfoTip("Gravity: Radial"); break; - case 3: + case GRAV_CUSTOM: gameModel->SetInfoTip("Gravity: Custom"); break; } @@ -794,23 +794,23 @@ void GameController::SwitchGravity() void GameController::SwitchAir() { - gameModel->GetSimulation()->air->airMode = (gameModel->GetSimulation()->air->airMode+1)%5; + gameModel->GetSimulation()->air->airMode = (gameModel->GetSimulation()->air->airMode + 1) % NUM_AIR_MODES; switch (gameModel->GetSimulation()->air->airMode) { - case 0: + case AIR_ON: gameModel->SetInfoTip("Air: On"); break; - case 1: + case AIR_PRESSURE_OFF: gameModel->SetInfoTip("Air: Pressure Off"); break; - case 2: + case AIR_VELOCITY_OFF: gameModel->SetInfoTip("Air: Velocity Off"); break; - case 3: + case AIR_OFF: gameModel->SetInfoTip("Air: Off"); break; - case 4: + case AIR_NO_UPDATE: gameModel->SetInfoTip("Air: No Update"); break; } diff --git a/src/gui/game/GameModel.cpp b/src/gui/game/GameModel.cpp index 3c0e3c0ae..81250ff6e 100644 --- a/src/gui/game/GameModel.cpp +++ b/src/gui/game/GameModel.cpp @@ -51,7 +51,7 @@ GameModel::GameModel(): activeColourPreset(0), colourSelector(false), colour(255, 0, 0, 255), - edgeMode(0), + edgeMode(EDGE_VOID), ambientAirTemp(R_TEMP + 273.15f), decoSpace(0) { @@ -91,7 +91,7 @@ GameModel::GameModel(): ren->decorations_enable = prefs.Get("Renderer.Decorations", true); //Load config into simulation - edgeMode = prefs.Get("Simulation.EdgeMode", 0); // TODO: EdgeMode enum + edgeMode = prefs.Get("Simulation.EdgeMode", (int)EDGE_VOID); sim->SetEdgeMode(edgeMode); ambientAirTemp = float(R_TEMP) + 273.15f; { @@ -1332,10 +1332,10 @@ void GameModel::FrameStep(int frames) void GameModel::ClearSimulation() { //Load defaults - sim->gravityMode = 0; + sim->gravityMode = GRAV_VERTICAL; sim->customGravityX = 0.0f; sim->customGravityY = 0.0f; - sim->air->airMode = 0; + sim->air->airMode = AIR_ON; sim->legacy_enable = false; sim->water_equal_test = false; sim->SetEdgeMode(edgeMode); diff --git a/src/lua/LuaScriptInterface.cpp b/src/lua/LuaScriptInterface.cpp index 3a14b1a30..67e14bfb4 100644 --- a/src/lua/LuaScriptInterface.cpp +++ b/src/lua/LuaScriptInterface.cpp @@ -1215,6 +1215,8 @@ void LuaScriptInterface::initSimulationAPI() SETCONST(l, NCELL); SETCONST(l, XRES); SETCONST(l, YRES); + SETCONST(l, XCNTR); + SETCONST(l, YCNTR); SETCONST(l, NPART); SETCONST(l, NT); SETCONST(l, ST); @@ -1229,6 +1231,9 @@ void LuaScriptInterface::initSimulationAPI() SETCONSTF(l, MIN_TEMP); SETCONSTF(l, MAX_PRESSURE); SETCONSTF(l, MIN_PRESSURE); + SETCONST(l, ISTP); + SETCONSTF(l, CFDS); + SETCONSTF(l, SIM_MAXVELOCITY); SETCONST(l, TOOL_HEAT); SETCONST(l, TOOL_COOL); @@ -1239,6 +1244,7 @@ void LuaScriptInterface::initSimulationAPI() SETCONST(l, TOOL_MIX); SETCONST(l, TOOL_CYCL); lua_pushinteger(l, luacon_sim->tools.size()); lua_setfield(l, -2, "TOOL_WIND"); + SETCONST(l, DECO_DRAW); SETCONST(l, DECO_CLEAR); SETCONST(l, DECO_ADD); @@ -1250,6 +1256,53 @@ void LuaScriptInterface::initSimulationAPI() SETCONST(l, PMAPBITS); SETCONST(l, PMAPMASK); + SETCONST(l, CIRCLE_BRUSH); + SETCONST(l, SQUARE_BRUSH); + SETCONST(l, TRI_BRUSH); + SETCONST(l, BRUSH_NUM); + + SETCONST(l, EDGE_VOID); + SETCONST(l, EDGE_SOLID); + SETCONST(l, EDGE_LOOP); + SETCONST(l, NUM_EDGE_MODES); + + SETCONST(l, AIR_ON); + SETCONST(l, AIR_PRESSURE_OFF); + SETCONST(l, AIR_VELOCITY_OFF); + SETCONST(l, AIR_OFF); + SETCONST(l, AIR_NO_UPDATE); + SETCONST(l, NUM_AIR_MODES); + + SETCONST(l, GRAV_VERTICAL); + SETCONST(l, GRAV_OFF); + SETCONST(l, GRAV_RADIAL); + SETCONST(l, GRAV_CUSTOM); + SETCONST(l, NUM_GRAV_MODES); + + lua_newtable(l); + SETCONST(l, WL_ERASE); + SETCONST(l, WL_WALLELEC); + SETCONST(l, WL_EWALL); + SETCONST(l, WL_DETECT); + SETCONST(l, WL_STREAM); + SETCONST(l, WL_FAN); + SETCONST(l, WL_ALLOWLIQUID); + SETCONST(l, WL_DESTROYALL); + SETCONST(l, WL_WALL); + SETCONST(l, WL_ALLOWAIR); + SETCONST(l, WL_ALLOWPOWDER); + SETCONST(l, WL_ALLOWALLELEC); + SETCONST(l, WL_EHOLE); + SETCONST(l, WL_ALLOWGAS); + SETCONST(l, WL_GRAV); + SETCONST(l, WL_ALLOWENERGY); + SETCONST(l, WL_BLOCKAIR); + SETCONST(l, WL_ERASEALL); + SETCONST(l, WL_STASIS); + SETCONST(l, WL_FLOODHELPER); + SETCONST(l, UI_WALLCOUNT); + lua_setfield(l, -2, "walls"); + //Declare FIELD_BLAH constants { int particlePropertiesCount = 0; @@ -2301,7 +2354,7 @@ int LuaScriptInterface::simulation_edgeMode(lua_State * l) lua_pushnumber(l, luacon_model->GetEdgeMode()); return 1; } - int edgeMode = luaL_optint(l, 1, 0); + int edgeMode = luaL_optint(l, 1, EDGE_VOID); luacon_model->SetEdgeMode(edgeMode); return 0; } @@ -2314,7 +2367,7 @@ int LuaScriptInterface::simulation_gravityMode(lua_State * l) lua_pushnumber(l, luacon_sim->gravityMode); return 1; } - int gravityMode = luaL_optint(l, 1, 0); + int gravityMode = luaL_optint(l, 1, GRAV_VERTICAL); luacon_sim->gravityMode = gravityMode; return 0; } @@ -2347,7 +2400,7 @@ int LuaScriptInterface::simulation_airMode(lua_State * l) lua_pushnumber(l, luacon_sim->air->airMode); return 1; } - int airMode = luaL_optint(l, 1, 0); + int airMode = luaL_optint(l, 1, AIR_ON); luacon_sim->air->airMode = airMode; return 0; } diff --git a/src/simulation/Air.cpp b/src/simulation/Air.cpp index 8a0996163..166ea561e 100644 --- a/src/simulation/Air.cpp +++ b/src/simulation/Air.cpp @@ -119,7 +119,7 @@ void Air::update_air(void) { const float advDistanceMult = 0.7f; - if (airMode != 4) //airMode 4 is no air/pressure update + if (airMode != AIR_NO_UPDATE) //airMode 4 is no air/pressure update { for (auto i=0; i= CELL && nx < XRES-CELL); bool y_ok = (ny >= CELL && ny < YRES-CELL); @@ -2076,15 +2076,15 @@ void Simulation::GetGravityField(int x, int y, float particleGrav, float newtonG switch (gravityMode) { default: - case 0: //normal, vertical gravity + case GRAV_VERTICAL: //normal, vertical gravity pGravX = 0; pGravY = particleGrav; break; - case 1: //no gravity + case GRAV_OFF: //no gravity pGravX = 0; pGravY = 0; break; - case 2: //radial gravity + case GRAV_RADIAL: //radial gravity { pGravX = 0; pGravY = 0; @@ -2098,7 +2098,7 @@ void Simulation::GetGravityField(int x, int y, float particleGrav, float newtonG } } break; - case 3: //custom gravity + case GRAV_CUSTOM: //custom gravity pGravX = particleGrav * customGravityX; pGravY = particleGrav * customGravityY; break; @@ -2885,7 +2885,7 @@ killed: fin_yf += dy; fin_x = (int)(fin_xf+0.5f); fin_y = (int)(fin_yf+0.5f); - if (edgeMode == 2) + if (edgeMode == EDGE_LOOP) { bool x_ok = (fin_xf >= CELL-.5f && fin_xf < XRES-CELL-.5f); bool y_ok = (fin_yf >= CELL-.5f && fin_yf < YRES-CELL-.5f); @@ -2901,7 +2901,7 @@ killed: // nothing found fin_xf = parts[i].x + parts[i].vx; fin_yf = parts[i].y + parts[i].vy; - if (edgeMode == 2) + if (edgeMode == EDGE_LOOP) { bool x_ok = (fin_xf >= CELL-.5f && fin_xf < XRES-CELL-.5f); bool y_ok = (fin_yf >= CELL-.5f && fin_yf < YRES-CELL-.5f); @@ -2945,7 +2945,7 @@ killed: parts[i].y += parts[i].vy; int nx = (int)((float)parts[i].x+0.5f); int ny = (int)((float)parts[i].y+0.5f); - if (edgeMode == 2) + if (edgeMode == EDGE_LOOP) { bool x_ok = (nx >= CELL && nx < XRES-CELL); bool y_ok = (ny >= CELL && ny < YRES-CELL); @@ -3218,7 +3218,7 @@ killed: goto movedone; } } - if (elements[t].Falldown>1 && !grav->IsEnabled() && gravityMode==0 && parts[i].vy>fabsf(parts[i].vx)) + if (elements[t].Falldown>1 && !grav->IsEnabled() && gravityMode==GRAV_VERTICAL && parts[i].vy>fabsf(parts[i].vx)) { s = 0; // stagnant is true if FLAG_STAGNANT was set for this particle in previous frame @@ -3942,8 +3942,8 @@ Simulation::Simulation(): gravWallChanged(false), CGOL(0), GSPEED(1), - edgeMode(0), - gravityMode(0), + edgeMode(EDGE_VOID), + gravityMode(GRAV_VERTICAL), customGravityX(0), customGravityY(0), legacy_enable(0), diff --git a/src/simulation/SimulationData.h b/src/simulation/SimulationData.h index 08138e38f..90dbed540 100644 --- a/src/simulation/SimulationData.h +++ b/src/simulation/SimulationData.h @@ -133,6 +133,21 @@ constexpr int NGT_BRAN = 23; constexpr auto REPLACE_MODE = UINT32_C(0x00000001); constexpr auto SPECIFIC_DELETE = UINT32_C(0x00000002); +enum EdgeMode +{ + EDGE_VOID, EDGE_SOLID, EDGE_LOOP, NUM_EDGE_MODES +}; + +enum AirMode +{ + AIR_ON, AIR_PRESSURE_OFF, AIR_VELOCITY_OFF, AIR_OFF, AIR_NO_UPDATE, NUM_AIR_MODES +}; + +enum GravityMode +{ + GRAV_VERTICAL, GRAV_OFF, GRAV_RADIAL, GRAV_CUSTOM, NUM_GRAV_MODES +}; + struct part_type; struct part_transition; diff --git a/src/simulation/elements/STKM.cpp b/src/simulation/elements/STKM.cpp index 4c88356e7..78455a74c 100644 --- a/src/simulation/elements/STKM.cpp +++ b/src/simulation/elements/STKM.cpp @@ -147,13 +147,13 @@ int Element_STKM_run_stickman(playerst *playerp, UPDATE_FUNC_ARGS) switch (sim->gravityMode) { default: - case 0: + case GRAV_VERTICAL: gvy = 1; break; - case 1: + case GRAV_OFF: gvy = gvx = 0.0f; break; - case 2: + case GRAV_RADIAL: { float gravd; gravd = 0.01f - hypotf((parts[i].x - XCNTR), (parts[i].y - YCNTR)); @@ -161,7 +161,7 @@ int Element_STKM_run_stickman(playerst *playerp, UPDATE_FUNC_ARGS) gvy = ((float)(parts[i].y - YCNTR) / gravd); } break; - case 3: + case GRAV_CUSTOM: gvx = sim->customGravityX; gvy = sim->customGravityY; break; From fde1211cd9ba6dcc44bfa8e11acf2b2741e9f392 Mon Sep 17 00:00:00 2001 From: jacob1 Date: Thu, 5 Oct 2023 21:34:01 -0400 Subject: [PATCH 17/27] Add ctrl+e shortcut to cycle through edge modes --- README.md | 1 + src/gui/game/GameController.cpp | 26 ++++++++++++++++++++++++++ src/gui/game/GameController.h | 2 ++ src/gui/game/GameView.cpp | 5 ++++- 4 files changed, 33 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index af48ad012..925cc2e95 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,7 @@ Controls | I | Invert Pressure and Velocity map | | W | Cycle gravity modes (use with Ctrl when STK2 is out) | | Y | Cycle air modes | +| Ctrl + E | Cycle edge modes | | B | Enter decoration editor menu | | Ctrl + B | Toggle decorations on/off | | N | Toggle Newtonian Gravity on/off | diff --git a/src/gui/game/GameController.cpp b/src/gui/game/GameController.cpp index 751168ce6..283f99567 100644 --- a/src/gui/game/GameController.cpp +++ b/src/gui/game/GameController.cpp @@ -1012,6 +1012,32 @@ int GameController::GetTemperatureScale() return gameModel->GetTemperatureScale(); } +int GameController::GetEdgeMode() +{ + return gameModel->GetEdgeMode(); +} + +void GameController::SetEdgeMode(int edgeMode) +{ + if (edgeMode < 0 || edgeMode >= NUM_EDGE_MODES) + edgeMode = 0; + + gameModel->SetEdgeMode(edgeMode); + + switch (edgeMode) + { + case EDGE_VOID: + gameModel->SetInfoTip("Edge Mode: Void"); + break; + case EDGE_SOLID: + gameModel->SetInfoTip("Edge Mode: Solid"); + break; + case EDGE_LOOP: + gameModel->SetInfoTip("Edge Mode: Loop"); + break; + } +} + void GameController::SetActiveColourPreset(int preset) { gameModel->SetActiveColourPreset(preset); diff --git a/src/gui/game/GameController.h b/src/gui/game/GameController.h index 6a1ebeca6..cb64d7a61 100644 --- a/src/gui/game/GameController.h +++ b/src/gui/game/GameController.h @@ -116,6 +116,8 @@ public: bool GetDebugHUD(); void SetTemperatureScale(int temperatureScale); int GetTemperatureScale(); + int GetEdgeMode(); + void SetEdgeMode(int edgeMode); void SetDebugFlags(unsigned int flags) { debugFlags = flags; } void SetActiveMenu(int menuID); std::vector GetMenuList(); diff --git a/src/gui/game/GameView.cpp b/src/gui/game/GameView.cpp index a25978cf4..8597c5397 100644 --- a/src/gui/game/GameView.cpp +++ b/src/gui/game/GameView.cpp @@ -1427,7 +1427,10 @@ void GameView::OnKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl, c->ReloadSim(); break; case SDL_SCANCODE_E: - c->OpenElementSearch(); + if (ctrl) + c->SetEdgeMode(c->GetEdgeMode() + 1); + else + c->OpenElementSearch(); break; case SDL_SCANCODE_F: if (ctrl) From 814b73a5eda7dacdc30b75d7605b5279d676f87b Mon Sep 17 00:00:00 2001 From: jacob1 Date: Thu, 5 Oct 2023 23:59:09 -0400 Subject: [PATCH 18/27] Change sim.walls to use real wall identifiers, and also have reverse lookup --- src/lua/LuaScriptInterface.cpp | 32 +++++++++++--------------------- 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/src/lua/LuaScriptInterface.cpp b/src/lua/LuaScriptInterface.cpp index 67e14bfb4..bb2bdd323 100644 --- a/src/lua/LuaScriptInterface.cpp +++ b/src/lua/LuaScriptInterface.cpp @@ -1280,28 +1280,18 @@ void LuaScriptInterface::initSimulationAPI() SETCONST(l, NUM_GRAV_MODES); lua_newtable(l); - SETCONST(l, WL_ERASE); - SETCONST(l, WL_WALLELEC); - SETCONST(l, WL_EWALL); - SETCONST(l, WL_DETECT); - SETCONST(l, WL_STREAM); - SETCONST(l, WL_FAN); - SETCONST(l, WL_ALLOWLIQUID); - SETCONST(l, WL_DESTROYALL); - SETCONST(l, WL_WALL); - SETCONST(l, WL_ALLOWAIR); - SETCONST(l, WL_ALLOWPOWDER); - SETCONST(l, WL_ALLOWALLELEC); - SETCONST(l, WL_EHOLE); - SETCONST(l, WL_ALLOWGAS); - SETCONST(l, WL_GRAV); - SETCONST(l, WL_ALLOWENERGY); - SETCONST(l, WL_BLOCKAIR); - SETCONST(l, WL_ERASEALL); - SETCONST(l, WL_STASIS); - SETCONST(l, WL_FLOODHELPER); - SETCONST(l, UI_WALLCOUNT); + for (int i = 0; i < UI_WALLCOUNT; i++) + { + tpt_lua_pushByteString(l, luacon_sim->wtypes[i].identifier); + lua_pushinteger(l, i); + lua_settable(l, -3); + + lua_pushinteger(l, i); + tpt_lua_pushByteString(l, luacon_sim->wtypes[i].identifier); + lua_settable(l, -3); + } lua_setfield(l, -2, "walls"); + SETCONST(l, UI_WALLCOUNT); //Declare FIELD_BLAH constants { From 75412736404ffc202dd82b345dbdd76175e09724 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20B=C3=A1lint=20Misius?= Date: Fri, 6 Oct 2023 15:04:29 +0200 Subject: [PATCH 19/27] Add blurry scaling option This looks slightly nicer on very pixel-dense screens (scale factors 5 and up) than nearest neighbour fractional upscaling does. Also fix window icon disappearing at times and the window being resized after configuration changes. We should maybe start preserving window size also at some point, the way we do position now. --- src/PowderToy.cpp | 1 + src/PowderToySDL.cpp | 20 +++++++++++--------- src/gui/WindowFrameOps.h | 2 ++ src/gui/interface/Engine.h | 2 ++ src/gui/options/OptionsController.cpp | 5 +++++ src/gui/options/OptionsController.h | 1 + src/gui/options/OptionsModel.cpp | 12 ++++++++++++ src/gui/options/OptionsModel.h | 2 ++ src/gui/options/OptionsView.cpp | 7 +++++++ src/gui/options/OptionsView.h | 1 + 10 files changed, 44 insertions(+), 9 deletions(-) diff --git a/src/PowderToy.cpp b/src/PowderToy.cpp index 8ef3dd403..0a0470eff 100644 --- a/src/PowderToy.cpp +++ b/src/PowderToy.cpp @@ -293,6 +293,7 @@ int Main(int argc, char *argv[]) prefs.Get("Fullscreen", false), prefs.Get("AltFullscreen", false), prefs.Get("ForceIntegerScaling", true), + prefs.Get("BlurryScaling", false), }; auto graveExitsConsole = prefs.Get("GraveExitsConsole", true); momentumScroll = prefs.Get("MomentumScroll", true); diff --git a/src/PowderToySDL.cpp b/src/PowderToySDL.cpp index 45b4b1ae8..d5a0483c3 100644 --- a/src/PowderToySDL.cpp +++ b/src/PowderToySDL.cpp @@ -127,11 +127,6 @@ void SDLOpen() } } - if constexpr (SET_WINDOW_ICON) - { - WindowIcon(sdl_window); - } - StopTextInput(); } @@ -179,6 +174,7 @@ void SDLSetScreen() // see https://github.com/jacob1/The-Powder-Toy/issues/24 newFrameOpsNorm.resizable != currentFrameOpsNorm.resizable || newFrameOpsNorm.changeResolution != currentFrameOpsNorm.changeResolution || + newFrameOpsNorm.blurryScaling != currentFrameOpsNorm.blurryScaling || newVsyncHint != vsyncHint; if (!(recreate || @@ -189,6 +185,10 @@ void SDLSetScreen() } auto size = WINDOW * newFrameOpsNorm.scale; + if (sdl_window && newFrameOpsNorm.resizable) + { + SDL_GetWindowSize(sdl_window, &size.X, &size.Y); + } if (recreate) { @@ -229,6 +229,12 @@ void SDLSetScreen() fprintf(stderr, "SDL_CreateWindow failed: %s\n", SDL_GetError()); Platform::Exit(-1); } + if constexpr (SET_WINDOW_ICON) + { + WindowIcon(sdl_window); + } + SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1"); + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, newFrameOpsNorm.blurryScaling ? "linear" : "nearest"); sdl_renderer = SDL_CreateRenderer(sdl_window, -1, rendererFlags); if (!sdl_renderer) { @@ -250,10 +256,6 @@ void SDLSetScreen() Platform::Exit(-1); } SDL_RaiseWindow(sdl_window); - SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1"); - //Uncomment this to enable resizing - //SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear"); - //SDL_SetWindowResizable(sdl_window, SDL_TRUE); } SDL_RenderSetIntegerScale(sdl_renderer, newFrameOpsNorm.forceIntegerScaling ? SDL_TRUE : SDL_FALSE); if (!(newFrameOpsNorm.resizable && SDL_GetWindowFlags(sdl_window) & SDL_WINDOW_MAXIMIZED)) diff --git a/src/gui/WindowFrameOps.h b/src/gui/WindowFrameOps.h index cceac8920..1ac533c98 100644 --- a/src/gui/WindowFrameOps.h +++ b/src/gui/WindowFrameOps.h @@ -8,6 +8,7 @@ struct WindowFrameOps bool fullscreen = false; bool changeResolution = false; bool forceIntegerScaling = false; + bool blurryScaling = false; WindowFrameOps Normalize() const { @@ -17,6 +18,7 @@ struct WindowFrameOps fullscreen , fullscreen ? changeResolution : false, fullscreen ? forceIntegerScaling : false, + blurryScaling , }; } }; diff --git a/src/gui/interface/Engine.h b/src/gui/interface/Engine.h index b2145cfd0..4649f2f0e 100644 --- a/src/gui/interface/Engine.h +++ b/src/gui/interface/Engine.h @@ -128,10 +128,12 @@ namespace ui void SetChangeResolution (bool setChangeResolution ) { windowFrameOps.changeResolution = setChangeResolution; } void SetForceIntegerScaling(bool newForceIntegerScaling) { windowFrameOps.forceIntegerScaling = newForceIntegerScaling; } void SetResizable (bool newResizable ) { windowFrameOps.resizable = newResizable; } + void SetBlurryScaling (bool newBlurryScaling ) { windowFrameOps.blurryScaling = newBlurryScaling; } int GetScale () const { return windowFrameOps.scale; } bool GetFullscreen () const { return windowFrameOps.fullscreen; } bool GetChangeResolution () const { return windowFrameOps.changeResolution; } bool GetForceIntegerScaling() const { return windowFrameOps.forceIntegerScaling; } bool GetResizable () const { return windowFrameOps.resizable; } + bool GetBlurryScaling () const { return windowFrameOps.blurryScaling; } }; } diff --git a/src/gui/options/OptionsController.cpp b/src/gui/options/OptionsController.cpp index b6191927d..9cc876f4e 100644 --- a/src/gui/options/OptionsController.cpp +++ b/src/gui/options/OptionsController.cpp @@ -87,6 +87,11 @@ void OptionsController::SetForceIntegerScaling(bool forceIntegerScaling) model->SetForceIntegerScaling(forceIntegerScaling); } +void OptionsController::SetBlurryScaling(bool newBlurryScaling) +{ + model->SetBlurryScaling(newBlurryScaling); +} + void OptionsController::SetShowAvatars(bool showAvatars) { model->SetShowAvatars(showAvatars); diff --git a/src/gui/options/OptionsController.h b/src/gui/options/OptionsController.h index 88c7aed01..56bc30678 100644 --- a/src/gui/options/OptionsController.h +++ b/src/gui/options/OptionsController.h @@ -27,6 +27,7 @@ public: void SetFullscreen(bool fullscreen); void SetChangeResolution(bool newChangeResolution); void SetForceIntegerScaling(bool forceIntegerScaling); + void SetBlurryScaling(bool newBlurryScaling); void SetScale(int scale); void SetGraveExitsConsole(bool graveExitsConsole); void SetResizable(bool resizable); diff --git a/src/gui/options/OptionsModel.cpp b/src/gui/options/OptionsModel.cpp index 27442a9ce..9cce68ac0 100644 --- a/src/gui/options/OptionsModel.cpp +++ b/src/gui/options/OptionsModel.cpp @@ -215,6 +215,18 @@ void OptionsModel::SetForceIntegerScaling(bool forceIntegerScaling) notifySettingsChanged(); } +bool OptionsModel::GetBlurryScaling() +{ + return ui::Engine::Ref().GetBlurryScaling(); +} + +void OptionsModel::SetBlurryScaling(bool newBlurryScaling) +{ + ui::Engine::Ref().SetBlurryScaling(newBlurryScaling); + GlobalPrefs::Ref().Set("BlurryScaling", newBlurryScaling); + notifySettingsChanged(); +} + bool OptionsModel::GetFastQuit() { return ui::Engine::Ref().GetFastQuit(); diff --git a/src/gui/options/OptionsModel.h b/src/gui/options/OptionsModel.h index 7adebe427..1e39d6c17 100644 --- a/src/gui/options/OptionsModel.h +++ b/src/gui/options/OptionsModel.h @@ -49,6 +49,8 @@ public: void SetChangeResolution(bool newChangeResolution); bool GetForceIntegerScaling(); void SetForceIntegerScaling(bool forceIntegerScaling); + bool GetBlurryScaling(); + void SetBlurryScaling(bool newBlurryScaling); bool GetFastQuit(); void SetFastQuit(bool fastquit); int GetDecoSpace(); diff --git a/src/gui/options/OptionsView.cpp b/src/gui/options/OptionsView.cpp index cbb119220..0bebe8a57 100644 --- a/src/gui/options/OptionsView.cpp +++ b/src/gui/options/OptionsView.cpp @@ -268,6 +268,9 @@ OptionsView::OptionsView() : ui::Window(ui::Point(-1, -1), ui::Point(320, 340)) c->SetForceIntegerScaling(forceIntegerScaling->GetChecked()); }); } + blurryScaling = addCheckbox(0, "Blurry scaling \bg- more blurry, better on very big screens", "", [this] { + c->SetBlurryScaling(blurryScaling->GetChecked()); + }); addSeparator(); if (ALLOW_QUIT) { @@ -448,6 +451,10 @@ void OptionsView::NotifySettingsChanged(OptionsModel * sender) { forceIntegerScaling->SetChecked(sender->GetForceIntegerScaling()); } + if (blurryScaling) + { + blurryScaling->SetChecked(sender->GetBlurryScaling()); + } if (fastquit) { fastquit->SetChecked(sender->GetFastQuit()); diff --git a/src/gui/options/OptionsView.h b/src/gui/options/OptionsView.h index d598140e4..409f8fa09 100644 --- a/src/gui/options/OptionsView.h +++ b/src/gui/options/OptionsView.h @@ -31,6 +31,7 @@ class OptionsView: public ui::Window ui::Checkbox *fullscreen{}; ui::Checkbox *changeResolution{}; ui::Checkbox *forceIntegerScaling{}; + ui::Checkbox *blurryScaling{}; ui::Checkbox *fastquit{}; ui::DropDown *decoSpace{}; ui::Checkbox *showAvatars{}; From dd5e5b1f3a562b5c68e7bc8eae1a8c00e81e9982 Mon Sep 17 00:00:00 2001 From: jacob1 Date: Sun, 8 Oct 2023 12:18:57 -0400 Subject: [PATCH 20/27] misc: Fix sim.partNeighbors table being 0-indexed, rename SIM_MAXVELOCITY to MAX_VELOCITY --- src/SimulationConfig.h | 2 +- src/lua/LuaScriptInterface.cpp | 4 ++-- src/simulation/Simulation.cpp | 8 ++++---- src/simulation/elements/VSNS.cpp | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/SimulationConfig.h b/src/SimulationConfig.h index bee3ff9c0..1fd9aef83 100644 --- a/src/SimulationConfig.h +++ b/src/SimulationConfig.h @@ -31,7 +31,7 @@ constexpr int MAXSIGNS = 16; constexpr int ISTP = CELL / 2; constexpr float CFDS = 4.0f / CELL; -constexpr float SIM_MAXVELOCITY = 1e4f; +constexpr float MAX_VELOCITY = 1e4f; //Air constants constexpr float AIR_TSTEPP = 0.3f; diff --git a/src/lua/LuaScriptInterface.cpp b/src/lua/LuaScriptInterface.cpp index bb2bdd323..b16be178f 100644 --- a/src/lua/LuaScriptInterface.cpp +++ b/src/lua/LuaScriptInterface.cpp @@ -1233,7 +1233,7 @@ void LuaScriptInterface::initSimulationAPI() SETCONSTF(l, MIN_PRESSURE); SETCONST(l, ISTP); SETCONSTF(l, CFDS); - SETCONSTF(l, SIM_MAXVELOCITY); + SETCONSTF(l, MAX_VELOCITY); SETCONST(l, TOOL_HEAT); SETCONST(l, TOOL_COOL); @@ -1370,7 +1370,7 @@ void LuaScriptInterface::set_map(int x, int y, int width, int height, float valu int LuaScriptInterface::simulation_partNeighbours(lua_State * l) { lua_newtable(l); - int id = 0; + int id = 1; int x = lua_tointeger(l, 1), y = lua_tointeger(l, 2), r = lua_tointeger(l, 3), rx, ry, n; if(lua_gettop(l) == 5) // this is one more than the number of arguments because a table has just been pushed onto the stack with lua_newtable(l); { diff --git a/src/simulation/Simulation.cpp b/src/simulation/Simulation.cpp index 32d45bb21..1950bf77a 100644 --- a/src/simulation/Simulation.cpp +++ b/src/simulation/Simulation.cpp @@ -2864,11 +2864,11 @@ killed: } else { - if (mv > SIM_MAXVELOCITY) + if (mv > MAX_VELOCITY) { - parts[i].vx *= SIM_MAXVELOCITY/mv; - parts[i].vy *= SIM_MAXVELOCITY/mv; - mv = SIM_MAXVELOCITY; + parts[i].vx *= MAX_VELOCITY/mv; + parts[i].vy *= MAX_VELOCITY/mv; + mv = MAX_VELOCITY; } // interpolate to see if there is anything in the way dx = parts[i].vx*ISTP/mv; diff --git a/src/simulation/elements/VSNS.cpp b/src/simulation/elements/VSNS.cpp index 2b54de686..baefbe56b 100644 --- a/src/simulation/elements/VSNS.cpp +++ b/src/simulation/elements/VSNS.cpp @@ -109,7 +109,7 @@ static int update(UPDATE_FUNC_ARGS) if (TYP(r) == PT_FILT) { int vel = parts[ID(r)].ctype - 0x10000000; - if (vel >= 0 && vel < SIM_MAXVELOCITY) + if (vel >= 0 && vel < MAX_VELOCITY) { doDeserialization = true; Vs = float(vel); From 3428ccc80a7d0bc5f5356e37d2f2f85a6e28fa77 Mon Sep 17 00:00:00 2001 From: Saveliy Skresanov Date: Mon, 2 Oct 2023 23:31:27 +0700 Subject: [PATCH 21/27] Center sensors, search and pause icons. --- resources/font.bz2 | Bin 48889 -> 48917 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/resources/font.bz2 b/resources/font.bz2 index 63da2c61aeca24ea4d4df49bb5be05eba249a74d..7f66b8aa42c2a66e6781bb983b06152f96810608 100644 GIT binary patch literal 48917 zcmce;1z1!~`#5}-M(Gx55mp)`lw6b&L0JSOBqRj{47yxE1wjN6NeMv^mJ*QeQV9j6 zyF|LXR zUul>p4*w4D-xE>%MmV0&*{X5?z_;+WKGHBg3jxGq7aKetVgg8=A*?V`jWY>dTpv2| z=2{LGk~=&7e6K-r)QKDM|=T*h&&qNyl;sB05vucpgS5U3k;Px z0zgrx0Cov+CBzYu4-m?Mb-ekv>0y8X4^$EWMoS)I%VFJnT>FynIzn_>tr7qX^sl$N z4T0^jlK?`W1VrwvZ-8?=yKWUs$Ln2o;911Ui@DdVD~Yfb=7DpNc&1)w$Om9(sIVmZ zMWN%!QzxU2VfpAgYLkV9ef_RO2FH6X0V1qE#C^JH5GWP`xFrk#R3LZ&xA3G7zRMhm zg$aVOFdkr-0PE%|fwN#nG88`nAYcIC%!oTf#`MThx2pvb&j3JfGavwL1i;wGFmMOJ z^Ik`QAnS(g5Ty8(__FIYWu*Whfmrtml7vhExK0QP`p? z!1D!g)W8Y=fC32!;5gLYSee5M`&xqu`$|iXrC+s~Bu*<%H=PPj4J=X=@iqCW>Ir%d zV&O^-teXOO3J6GYlyEgROvs4vb^KW@b81alWZa}*Eb z5Cy)m42Hx5bQ~91K!(Cvz9y@p2gZvszDZ0B5Cgzz$%NDtRl+x`lF84v;3JWAh)+^5 z0H6n(LE>)_gZT+;@cwtAa7{WREUTIzMTr#^D2DV@mP%2aij9hWakZUEZY?=}6#!bm zzKIt(d|;nIW)l;m`a|M{000lsf~}ass?37mfGH$jy@d4SNd82rm=gQ;jg5+8^4pxZ zskzE-8jJL*Q&!HD@H{59mQSr;fv;o4_^FW>Td%cQ#;+h&A<4c^09VAPuT!^(g+OtV zvp<9YDyqT&nGhuhL_p=SsxW6Nf>K2V>sE^}oq|dbJjCYO3UpWHZQj+dNE_AEO+hU4 z)bDM(LY8mhQpXhE6Du5(y86vH){OL;Wpb)Tq7d==OHNC5$0&-9Rt@8aaT$ig8jYGu ztVxiNljjT4%_<5U7BcOK2mOe+i~-~72Zi5>8C>a8Ga={ z^xgCIZ_IAJ6cvc`_|Db-!nUJ;qNA}Y!%@HKW}~Sm40Z`Ax z9kP8}Be_;p@IG`@92~Xx9R(_Ch7>IwQVSJR(}Z$4M}yZ0jpPq<~OGuNyKUnXyNeTeM<1A zbDCG!l>>vM?N2{{mbd-J1clVSW|$tx+~1&v={+|tu>Ual2%aMK{LA~bn&-wpaizw%b{~b zP+)OaU81-CD0kj}oPMygz0Dwv!o`!!EZd7JiYQ-zEj-MFIsT||XxmK`#0C8i$ukc~ zvW#lss2@;IABUT%BQZ9Xaz2~TrvHL&JnwQ}{YOj{wYa}w4XYuqb>B=6Ew()dvTyGPVk_7z$2vC%T0068vID+XC5E?TAJu8m$Pb>o zYbbL+goCntr!8ss-Qou~NL!ESKm>2@)zOI~W{ct$)bB?jh9@zcmT4>xo5RqjNSO=8 z#2pxxVqkb3<&*Yx!SI$)SLL(7k9EHt5=i97iJie9kL{8ph=Iiyi>sBpb{r_j_6s*d zd!xn63%`^B)UNX79t?Bgk!jl%oA2-5IPjDQhNHOdy=(v5UQixW#^(L4#a|w-3vI+> zp)HvDu#`4AH$K>gX~&KZ?ieJhkW1k+gW3stw|(Q;nGou3+LF2O%ZsBu%V~>24@^-e zFO6Y}vf}INdUagI>jMRSAse>97To;7c{eBpL%Xi7Hz(yTZS90&`UMv=#1SVBGOoYM zcNR1swco~w-#HrBQj7siW!PoivkeoHkz~~mjM!pvwNvAS9a@qtC zrV8$%OBx5LOjb{;u zhc>3|NR6dp_?W8o_))b=e?uiu!~G3o&_0;->lXEX7(WOtovX}ml0Er{F~g?Rbts0G z<8IsE-7w_Ug1qUow0&TjQKIM-o!2|N$!Mxl< zq3t^e{3d2m3>{y)yS0W22>Vh)@mx{Zg`egy?xJTGd(uC*XKlY@SYGhY<~sY6^hYNb zHZWj$D-k_WSwlxX6ywRaqKC)dV>lRX1ZjoG+8++)^zMT!?9~BGQ!fAc_!#JqwaL*0 zqFnobgo$Mjq($HFDG!QT_kq8d7-$@D9jy;#I-^6F{-Cb3923Z?(!3-73H0ugbgg4* zC=00&Kjgb*;%5v`{6uGUQ2E#F3(fe_qCXLp|+F)geeoC}~W9f=O!--s$) zY%pgg%nLEAy+!L7A&xyxqV*a^)D4&~V>)8*pmF3`1o>c0mMUnLwlHRqO3#+s4rbZ= zd@)I9um(9Yi?(yLE^pCzFuz{G2;Mh&{+t8^xc%XMBtJwQ&XquK4^Fn3q!}rXQgw@` zOasF=U(0pHoJHQYTtAGjXfa(%DLs$jby~NArgr%-fT-VG#>WtI!RW{7LA3AEM#&ij z*wP@0IZwBcE?bE^T!HLE^No=FJ(~q5C3g2#4`z@1@sy5=Ar4blN*pm2U&tQ+6^1cq z)f*Zmf$qFK7;QuZ;M(K!{`!U7U{ER< z4?{lTrp;;Kgz-pp-(lAOjw$D=XELZ6$M5CKWzryDjETP844~Is;emmVQb{+a@>cB# zzMa~4~Wxc#xBlA(5J`91wXsqr%z13I*yLr?Zm%ZA8dOveyysIS#@ zxVA%k7lCE`=%Y+VYs}%=1*J2jzNay!WM{*X9_WSUFXnhQ4}yL?1H-CI%TvHmhnmu% z7C@*;?4F^o6z2TAqGP9K+3;gYj%sH~boTGKH&9B9DX)|YDxpnYGhv7Pf*9%@?_=qQCb* z`eW2v3ulyOvwAVRF&=e+mSLQ2cGBOEn5nvHu#@Uhjkb9^PjC*kO#E$P1-uO} zhJQ@1&%^3zSGZZ9shv%PH@(=WabY6dJYk9QH8)>U`U$)E56`1l+EayK-=Cg1SClQj zG#6M9(PJJKeAjL6LzJo-ylAtx+=*ZF`BF6l#fm{^bsQF(xu&_cKby`=od|z6EikqZQ_C{+dxCS}g>$R?lub62;`5?9KB#XHP{YfN;MQ zLux1)q_OxVS&FIC?fs%}bl3GRHV^^|SeTiXIT|FY;^s@ggwv5)X5iIaGu4>GOy_7t zq+dcq`d2k#jc3@lkx#qJf226DHXJkSKxUYVP|&x(Q+aB1<)cSt0u*?gwJQ}cN3A#@ zPbOKR`eAwSctBG)e%8`^X}vS)wWe~E_rzr7JS8=@_UuOXuxo$rQ8usd>?KZ12fd${ z-Y7R;yIQx`o)%wlN$UMW&u_Z2WM5fvmP168F5!>|3TCgVs5Ce4=7v()3*Wjk$tv~J zX=+P!@8{lHr&;c>-C9Y|Y~$1&(K79Gez6SKb@@A|SBfS1EX1j`L|-csNRwznr>x=v zfocvxQo139HQB{_7S?meW#Yr15U>_sP>QmYfX&yrIIp(Po^0B*p02x+@nPzTNZHFf zX;j~ITlFQK6Q;h6Hfm(fiZoc4$UBAm%g?>#A_yU13G|_&9)IqE z<`gY6_YT1)fx&a$N?}TupzpjdauC40S$H1uOC_q|FG!wU9PX>F2*RKDl;-Yu=;)T? z&(||lbB{Z{fYCP9e3(|}ngyGLc_W{7dM8Ov(knLchG-`_{ao8=C(&u{htm$1&yzbu zi{9hTxA~}-$J2KzJ=N^fvz+AqubJJMjAob5$xS;pf=ymJ+4S}1UnlIC3cGhIJ*V+` z@#mtBxwL#+@{Zd%->($tSg;j0-kIjQJxrO=%ky1PC#NxLTBI7R0Ly0KY}2B11@~=p z3Key(*|vIL0-*TX6-IlHp?Tjrci;YKDLncet9j7{1 z%UttzxPDr?@HWJCI+?gMDwe}B&pXCyY~)=iIg!RU7x&&?pLzqQ6iO4Sg;O*ko4{)>S1nkP zE|g6rm&?@zUeg=$c;uSWj#lIfQmJRm;2AOcKHRu7)(F^tvRA$LQ8LZ~zkgtgGS$wP zwU_xW$K_F&{TaCX?JL^#8rRZ}t*%?&R3o~GOFw)o@qUliEt3j$Z9z@T^A7G^e#%1!eTunzR z(wpR|&^WG{18(PI-pZ*oq&JewT^33^OD?C}ltvC#ylX&FiKaD|t1TO(@@NG}ymBu0 z9dpQcra1o7*X#e!E&=U_q8owA#fXR#u|gk+Dy782gK+*OA{3!=pg_=4_`mU>;HjAX zlSs`-W9Spmd4gA+m*6E*>jc`5qP(e=nQj>9MxpYO!>Do zj^zD2-awxWI`!QDH>LurnI;!XZ+RL(H3hX7)Z4RMHQXrmL@6n#p6azK4Y@}v&XUWc z^;<0ZxTZcT41p3w2P3}(4l`{tv~W=()_G~A4GQ;Y1t{|*RJh_e^Ka$SC#L$Zf+A=E zeNBLq=KnpMqHQM%g|rzu=>7|8|4m1IBBHa6L`_XnC9y&~wM#Xfc|}H}VhF4s#D2hA ze4_FY&~W~ZwzQrF&Yc~8B}sB~2I;{*BY#aJ6oTg^i}Q*6Mpmwy=i6G(RH=> zW$lChk#lb!sP!j>1hBsF1O*7>g~*G)1`2$x**@{+9yi&hm{_jTcN7+f1Lr5iqVJN z_8Iz%(WQSt{il!F_mLU-V-O0oxPCz|e2kJ_QP$Z59XS-Iw7EHIV6uII*9tsD>C=zG z$Ej91Hy_<}FjaMa9m23NzX&~Xo=jwoc$&@bGpm~PPdR`}nkWTpF&G&L#iR7L6m{VE ztRw2krJGs#k;U3F=j4Js$wT-xU#e<~lh@9R3eI=9y^^w(KYn^i#Vk}biVQAa{`F#c z&B8{gK)02+86x7&=knE!L2W`-2)h@j-p~WpOqM49rbMBqSeI_dy#6>8yhz-PsHMBj zE#PV-zX2~jW&BXuSaHZUoah8e@M%VWs@D_`$zESLP6U;Os)HqEs@KO2FPjnY=9Mnw z`QNa$VUU)~(>Z(3`iTQ=71~M;I8c;@H{1srjrFH}qY)YZTvG^|MQ1RE-v46cf0N>W z6aE3z17qt94%s)tyTto8>E0)SR#?IV-TA|;{%l4qX`MejS~r@-zL?qT8$|nT`R4da z_l)bP>a5!Ix#!&S+V#gcp2yKgW^%FIyUB97p8HvQQOWzqNlB-QlnNy%Z(9-5nBzS= zbIoVbqo=4V@mOJD_tQ}*J5@e)DE+l@*sGdHRMccH*|1A2n%$4;Sk0>noNmd>GxWb# zf1;sbaat=hC7G7Cbs?(Qo8u;nmn6Z(ZGSvM<0dG>KTFoyY<0qt&yY5GwudPvHkS0FkMD&M{+G{3 z@;;hYsqQi^_c!B7^Oi~Ki>1*JXGWYD&^q%wWOMp^Xwd%4K8uK$HIUUWWGW{jkhJ3-l%x;(gEW+xQMC^YV$g_tS$ z>2jQ+GGk``M2J8BknW+jf^j7-LYvA(_`x-AqStcj%1;x?jj@!^8b3|cK2G*tMJXrf zy~YairTSAjXghgW0wSHdkyh=@W|f>vJV1H>d=n9qS=kI z-V8fOeFNf$&@*sh7Wk;fs0K3Bm{lQVk96_Y8tL?FoKQ37!Uw4?{Am?Q(-Z9wQD}oW z*R51dXzhh(DTE+-)5{@2Hv*_AaTsL1A@^u%>)A5`(|d|o^9yVwtzO-tlGnugdQAG_ zh6u0RH7+$C*?A3fFZZC*#QfCxmt0A7esH9)##ePD-0u;y*(`L82|hCLdMykY#ifY_ zr;@iuQC1@B_({(D!n0bOo9PctGVsO;fW1X6NzEHoTLp+<5aQlkjs6TRTwXUGH+t5fFEwI^s` zy5-AUJh+XH#{?B|Plj45QaM7W5~~;B%JS?1)!fR03efNH4~eryuf%1CA96bpPa7p# z;eMlXl(5qEiw~uHc~>#5-ytpBl3@L|HkVX+mgm@II2D;w#1(&`#P|eta>8ShK*`7u zJQNf#g4P?9e5et^VDPqR{OOUP7a428PSw0q~r8nd7AMn0K`sYz|ah%q??{2fhA9a$~R^K=#*6;chb~(UH zF|jRrkLKbywUmF7Mk4vKU$TyZ-#zb5g@X2m5EsF0AT-Q(}i z#Y;_JCl8jvRVEy6rPM<82%^-Iz<7mI?Fw}G{ch*C2hoLV%PTwMBmIu5l+_E()<$2& z)>8^RDi$(V$V7*3{wREem^DdhuWEiaKjt1ojzcoj=Jqo=V^ych>7I=p(_mzS?(XC9 zK|DN*uAjNZ<|hV!td?`P|J$`eI@b0zz}2;@IJZK)^bLvdwMU=d*5g0XW&N39t|0i- zgzf|SA|l+XD%^TCdN3=tJZD&~dQhC72+J!iKxVX$?R0XQf00pSX=Yc7{tsmQ8BQZ4 zb{mzlhVVmIEe`!{y9haJ#>INY|cddXGvE4HhqNb zb87Xyiy03-R9JL$+!CEk;}ggBW*u>8yPMbn6S|ri=I4@C*0a*dz-S|bhaF~BCE^^H z)L6oxpKc#%d~!MPQ+iJn&#Qa(M)_XuSj)jzklkD77fUwZr4Xc?s<@ZS?e^3^SpJT| zY+u7{u$3&6N_0VqP%4fF`5gEtm+cMt4ccO%g5o>-k5n?dtEh3@(i;Xwxlp|(zyjFj zdwq#L*!}h=w$2+jK8t*9r!hP6(i|Q^>wbc@)ZZQY(`MFCVr0QeI;}=5?vWQadcB* zMU&@lSnGYb8Pphb=45t6%x2Y(l1yHuls6j4H(g@k=h&`&9;rZoQ5 zpLk7T+PCs7d2Mcl@!`0pqutkT82Chaxu6B-+>;@Grl^l`# zi?i55f=x}>XUU|lqXhd$O6?N=ts7Z`nld*1nW94%RXqLdVK{8@=B-bUpP*pyGwPL z*_M3ve-5opqj;(;Z3hr7>%ZzA8=L8hdY3`{OwVbumoQyn$IMYAI9s7#Jh-voQYIyg z3qrKx&$pQO)K>!wJZP*lYW@C`aIh;bkn(tiAujgXh&8pE@JD^z5h@zrO16bc90F-G z4LpAOD>|Kb=E(5FSiI_`#FF>=aBt7tb;5+Wxs#`GYT@) z6-+R%{e1sQt*Hh)J%*El-#lal4Nhh~si%S1e*)XjSiy{t;IK1w{(ddaenx~8NNHfh zzshwSk%0Y;e6WuOTyw@4YZv%#yQo}`<(^Hu2iz&zC>|7iKriEbk%H$Vp^oULoA&LO zN~Wd}^*u||-t-GSak=3n^Eco?S;6*p;H>zU%u^XZ1-^8-2#B)L=h}Lm%U`YuSe^2Z z&lPx;_GN-Lm6uprxt<=>WE?8?)U z>2#-cFWtFU#*WL6AQgeeU-O2(-H^LRog&Y-NT9~%@MzO1m;!m(~ee&Pg@aFu^v=&SynsBCy;LP@UP0BG?>gp1g{l#EE zd}C@cp<|}r2~0USu=6)@rEUI8Su7}6;SJd zpOH(V@KT0D!7Nl6efKNFJtOx<-Rts;GjgB6r-<=Tl~82}SciAeqT8QC=`=JnK_{;E zr7DZMmojjR3I&W@QIJ|rFqjE8k_sP zL}pUnRNM>Z@Zg?y{Vj!x4b8PDLULE1JA6~}^XVF1Jhxku@oCF2cDZq$Q9vz3jx=f# zimflU#qHiWxaLxEaX!tc<@N|G*0)lGX4zu{1=`{Btq$|HF(=t>rDbSVGAq)QNfSKu9E^5d6eev*DTvJYAK26)SU+Okj%JbaNcwW3$} zeX(@*;~1rZ<-}RS*PIu2PIv1+q}^ivpb2@cut!+8+dhp@$iGTa zjXXJxJh|aF^RGxM7Li9?LP$N9(nN(l@7a@=Vb$hI{xCNZlSh2OV?idKeI&+tDbe?pi^Tm z!55skRc<3IC8ISKS%0VL-X-=+>>=#aZn}f4`iA4I65kiaqbwD6mUjo-BIfcR>s{uo z&1ob*LzzGP{`I%;$IdK_Z1iu)j{6}>xo5Z@dmleWSmMLW_lylpeh=m3;EXG-T#IkR z-0?P~x0c*pkg3LDT&RE&cE-v-)fkCP^5IGYr0|brB{fTI77A^hn0KoB5OUozzz>OS zcKkK55}e(uOtaPWfg)qo+*VKfN?3uy@l!~@$Xo3h>SGL!t=<46D@{%8?y;#yZ2@)M z?EZu-nG%~*@nW_Y#qJB>gc&rPsYc+Z{hV)a-FaX)BPNY6=G3z5tCzR9oe}hX{lVzw z_Fi1u?x2Li&A6he$Qsq>g(mrvBX>OJ#JU42~t zJz*``%m}CTEMgDbioW7LyI%7$zfXG48=K?GisKjU871yjD*g~qt{$)Hc^*823~O7y z(foE{<6G0{+0c(yL#po;n`gKaSvgI#w6!$FYAP2q^UfV}3K#C-5A9$`nHKnAWnx`k zuIbqRxaP9M2}OQ)o|ivvT2l!M)P9g6GQAsbY7(*f=Y= zC#SlOx_c>w(cves!wD|1Zj(sFU;=yS|-RU~98=)!% znpv=l;cJ$s?l0GLY-QUXA5nTEb$yq@mxnd%AuyE??;vNEL@SqHu-YwhF4C8QW`Zz^ zt}Lc9>8sj(Pc!DCN4Vp=)@4Ws4sQnc6+Y<3Ue3>6wmzk*zF^ZIQk6>cwQpqf=Tn=_t7CHl#Wutq{g>E-Zv!U*h!Nmf-|M^pXaLjz zUL~aQ4zM#d_<9+ERf(>`g+bl{2MxIZ;tHi9$c#-Twh_<;hyq}nW#kY<4QzQ5)%hJj z17O7iDFE2AbPhOgyFUOIa13$KgBVp1#kg;`1;DOq=t0mhZXe#$SMWLkA+*QkndWLT zXvnUps!7~`dJ&>=XE#k%AoQ+HZbn4;2c~h-nzD`DSBrU3UlaBW>!V7FPG&JzZ@5+Q ztGY1~yl&ORQf4I*U~?LZt?}dFr0Paw z!88T*WN9CETosEu1p8uHl<>SDiz+dQV05 zneMART|yvTg1<04kP5EAuP{b!RlYs%Y+HZ4N})RN0#26Kijp%PgCzVjx!BN6j(6%S z7K8@ALbAIRieBBF?v_1N_Jh_E*|+dtm{TT_)# z){(NwNRnzSMyK5GW#My!T0gIkA()f8Z2`tyTY#j%rV^MI9fEY|A@Fs;IuwUoU?M zZ~$ST`lRoJkU)X{TnLEw7XaAly}yQY2wPc3kcy%KBd{}i?*QUpD~AJsM{oks1g0HP zxOniN1C|ajLP19nW8Mca+8%}a8=(U_4-rAr!hf$mylLBxH`F!9+Uh+PixDHWV@au! z!@>m^JD~`;Uuy#H-FAp3B<%0w-b(4<5)NJ1M@C5cVjrYpUO~SMXp?l!!Rk!<9fxp=758RXHRJVvlrSX?qut*z38R-}d zcq2>pB$vrbozoog!#8wTnDtZw+-JkT$qxZ8w(XUW zj(KViv3STNSjN{&y94Q1Zgk~ziU(G@twABJ$U6f}dPtCE4w)d&(-0&DT0__wJ&Uvm z?9X8+Dc6+(q`W;Sf#iVzkc%jpT7%8($V&mH+j*d{4Y(EnCY|fCcYvh}nI9cRF5b$sn*c!x7&SnT$Hp>JUb2>qlKrVj) zG0Fft&yMheLw6K{xQ%4(mmEP*;*Fq#lq}E%(d_gq0s&0l0F|%~)dEBl-Qu$|3YmTs zn$CgFXg+|th5}?D2{1LQ#-xF|82yzAzz>@RI~Ok&An?ObV2TS+>QRTn$GzyH4D-d+ zu3f`f!+^cdo|6v@b_X6DFAk~SiU@yTcjJxDfTsP|@&Hb^;v&0i1#9iBHBg9%YVjYeOn6X zjnhlz38$D(YLJf^yRLe2BFCvDLz(*vSBRGDj7~?tn(2qsEGhMw*`>>z#`C{qvVTUAlluQ2 zynz18AbXDE>4E=+V;YliyZ%1{`G2A3x~+a&*i~cw>t|@3Ug`_mCDaehJP+``3!?{5_K!I||1(jt#I&#K60#+PS>btvz12(0nE zxbov>M@U;pcY@?+@#SIduo#!3H)jW>-J1u?v$Ecr8hmq;blW&Ja*3S`YeQz4a;Boj zV`XKxV9@#brJ2s#IRlGqFS;|k&B{jP4{k%QnwOY`tv{j7)z4{ktM!*XsP}dg>E$UX zz1n!tob%xML366u&yJ0}^Au;KqGrSN2H4>T%~;l~^L6Z;pDXS|{nd>9p#Bhx!`r_G zOS$w1nC*|*o}>dVo`eAwL$02jqZQ0@K~)DstM6l~^k&U^d3n9y2@?pD289DS*7*3m z9fjm?ob7c`q;uvP#>JJDDlPse1T^x8NFK84uaQL2J}J6CP_Mq@AnJZ+XLoi)@ySf* zB{VaC51iL&gJOMFbMwFeyYp}6O>J@JE^gF}&(7EKORrCbNY_VZ4a7a!#~wpoN0EpH zVZ?meot%{aErBC!_&*YX79d7<6b*er1F@i9pe1-ltQ5uGd_AXH|0`p^1%Dh=nBO!y zHrj$e1nkS~wz%tDQfyza-v?w+u*baHz&c7GhkW`nWg5tNUq7d}oL$|CJ74>Hl{48T z?D6VPHOoWnI|_ai2C7u{?^`Am!?t-PB<`euOJdYy9v2HI>%m~B3#trG?e{Yvct5AD zL-w`~X4z+`uatL}!O)f1oz`x=1?}51FUkh>_bRFe_R4=-w4YxG3wtoY{*WC@WgkQY zI)faX-UG1M_N(z5dTqbU{Z0x`6}9?{QHywVVu#C93B&!*H*!I;Zf+>Fz`q*CjjW3K z(Q-%A1}mN!@Nu+Na5%y6{ECzvkmc`e+{5Wa&c4h6}_KAL}!bQ1GD);-853&|v5}}J$@e-PEPrviY3jP^sx=VL1 z|BAfzr%OjX6FJlB+Jq3ZyvMaMr(O@k&Rv(*#m#L@Iq}X@9_YBtfdPw=?i(!Df6;lA z^bc(6s8)I&sEz7T?F6;vkLD~G+GXb)b)Ynx|HIM_z{G|AHW-w$%B15uztM->)3l_e zjG&%bf8sC11NX*V_a5C8A4rmr`@sFP_my|aGgXf(v3-~C($3m?E`l?TT|w95_oQQg4X$1uN4xB0CfhEn`b-MUQ%LH zQey4Im{)?T0{}WkJ#jKH5B567%seAA=;|Jm6`kMvRnJZ8>k$D`1S=eB){I4 zT1G9`dNwU{7ZJ3>>+8V4wC%WgmV+n$l4q>tQYDHJAfs3ySo`N^*;!EchY6yZr=C9; zcxV4!q#(}D{Y&}zm2%^<+xdCdqZgSh+owH#q-jnXthW-fvH&>jzjh-IL7;Olb}uX# zD+>jq4A%OFVVc64q~VJXEqoWvcW$NNk{aK>g^L}Ug4=a3WpbP6*=ZQxcYk(&L5R&6 z1?bcUq81)3NKWoeNO;Wm)V=utC#LT2-5CQqca7d(q=_b3SMJMrrO*@gk=syFu%q4) zaaXoj*R<;`sr&`|h#9MIn~aHuL&KixKWUu0FK;N?*qH1+c%ALYuJYW5OsGF?-~yPG zGC)QKXoHuYS~)ozV>UKk@XLMV%hmzPL^PY6{3O^4)zZJ~_t&qWU8@MxoV)`7x*!m( zBVUET?TqRbcw0_R9`#K>$Pe!2P@quVPg#TTQD41-FRG00iRy9mi|Ps9{~D7fo1Fac zOMOsA5rHNZ1^)1h#&}TQLvx#U?Aup|kM0-MhI7j*V&2+$Qu)BXzP2@5)-j0D{faD+@CfDyL8YjKJp*dM+52W+zWn%=fW_?Atv)N?jJc zx376AN0zfqebZ+bCfl?cA81J=Qg!2&nrB6H3luGWCyjAjuh%in$ULj4AkY>&dHd3e70p0-;Rl) zr5KTCOoP6)&x;lcVE5!Ts!u&*15EMH)@y3i=VF()s>;z!Z|({QZ0&JMHv9U%-F90j zG16=&yNPw|eBi>@)S59$wKQBg2jJJtX-_~bm5!-eXpS^YAv3=*bF-gtvb zmsfKlscYe!Dgs6d_SPTFCpY@VZ@-C?Z0{MjVzYVYahtMB2SR4)ZWjt8C#97XPi1}4 zu&|!itwN%57RI+KasG1d9ppEmjx?o4-HcPbRym_3R{!oZGWwo7Fh5h`*QX>?B0KHb z?0@;pO`{&o6c4Q|{WxoFT3d&hT)9tSH;jFp}cJ|-ZC zX!v^#&b5)rwjpk{AzzFm5z9PLg_CN>M+H#QvH8VEkfdk7x%?+D_UQy!4-yZ4_)skm z%IMqd!dYZDqskO=oJ@zx6rQ1r+slVr-NnQZp^ux9{-YXqL3qJ5ze&28l-j6RM2fv; zRL$rZ3#BZHXdPbNkRS5}n=4GoE0f#j6{H516sU@OhKUeD7> zjVW$jx>;T=lFri&@sgFw-a$4oxG5|?Hx-Ua+Z{KH73!vjIe3XLP{_mhacH8H9=}wh zJJAj^-e}y_no1#gWfgxet1gOw-k4^Vu&t(1xjkL*5tJMAe)$%C_}@I|F7s#HPl_~py-XOh3U9LI_d z`Etd6B&k`>h{ISBnWVDO)ShkLkj!v^5cl$ zTLW&!C!GQfj%S*w75l4w*t8jP{nA-c`QZfgqeUm@wv+-whJ!NJDD8rVuygx;2?eYEpaUlQj@d2>I z+wz0c{s)Ku56|oWITrR`4t;ohAMC7eNW{ylb(aM=`9oH=>-|Lywqus6Y*J(t#B>RX z{^E=e>EZGIX>;7Ym8f7&t*Lo6bpX1+#fK=zL-2(JLKl6yH}z}mbm~p)M;zV1R}6V{ zPpqwy8wW`#gx;cU5W})(_Z}u7*j{PHHDj1bnMmoPC8#4g-3yHR5xS63go@t9e+#F4 zG$9>%E^OMREK|RYwoMajJ>r=3+u3c?Cae$8%DXnuyH)2am*&$#`P52tl}|cB^(V)d z9^l#X2kn&*#guWlPo1bEcufa=f|cGA);=a5nDRCKwr*em+{8*Wp)Msmk6t8zraUe_ z1Qr6G$z~5`52jEeWG7_D3E95_=m%_@SU`b6db)P|IsToBf`ruuTm_QQe_bxnN`ZYyW z#E*)kVfVcUt1`Jm4-7wT{*10$tBBs{SCp{m@gSVnv!2`T7SR+`54JzMn|^QD!g$ap zN5{T>m}oP|@w@vQ&*e{?Us&R@nzsnH+~>~muk)MJT@@M6-JBa(&RBIJzfZse-&&Z1 zArc`Hg^=WAK{xtkUGBE^yeY|X)9+G&8(%VF3%}tf`mIRr;PF=?#O9XS_{kCzd&0cK zqI9#L-ZoC87c`-!dpkdPc7y0A_F6?~bL&rz2Y$P4v&|zn+od86wl0p_sdmQ3%)R|G z5Pmm}tE8jPO)%?CcxUT%@y1n&do@Tmp|TaP_cndD@oz@y%=M76u+{$WFgnVjC#V00SQ7)CZgHo#wyyt`RQkLu^DWme zeeb4Xo3cDumkW}oo3E^28@Ib$*#1&~+Eyx}J;P0`wZn1DS7Xi0ZIU#mOw7R5sW?u; zRsTaea$fK5%!ic!+2Y-t)VizV`0M{FxwMP_i=oKe9EZQE_E#ivL6PO$_6C)-L-MM5%l{D;;GPBOzE2%@JZh{n@!=@KMr+3abOMqlUWn|#;;r;zp<7=)dAOHA*;{=7Yg5o$T^?^nkOpHf4^ggZz1T>565!N9xjW#wIauvM zA>;GM`%ctb@=jau4gY=pcL%RYt=5x6B(LTgmO&5RqF3#2J?Q84f-lDVFgIiV0^HHv zl|NpeqW5w<*A`FJ&RMS~9loTG4B6k^sgQAVem>$RvUP}1^pSlU5K`yCo=628+}}aH z*3W7l=u@ZrUZ<@e#F4Zq?7jOLr@+nMR)2PZ4{(}(&Lf5p&HGl%a8;LSOcp5D^7-k0?^t0k%92QTr&=fE%x0LPF> zmXDfrwC}NI&j&n-l>Rilzzu~i}_zTL@SPypQtkX+(hz=8q5LjZfzMsGaJ;_aJ*R;WzduS~SSZQwrH zew_kAt*lY}d)zV==tS&|fL4m9+|}Hz5SD6kjf;3QPwFaWJ+j`e=%{}F9CM?T?(Vzr zj&cg)^!tyYlR_T$Q>!nMaJsvBlu32f83p+DaPRjB+;toAP-{-=TA%Xc5&ctqITh8q#cn@nMxbTY##-7JHh^$u@G z9`suvONn+%W9Z1Eu9@R$Fz^VssD#(u6b@EJKD~K(PGG1tTi{5d=QkBBx~J<{Exc0_ zo!(ufagr6+)+#tEcy_Y}EoMF2{=N6D56P_Fekk8g#exXODji~E4}PtfqAZTpAjH=> zXG&{PfeP**!?C}Wlnku&48;1{WK2$=C4h~cW;=u`A(5%bwBEOq=R&dHVSl^&e(p;q zQi9REW0P5MMd6zgB!e8kLUE*{<%z;~z z;WUG+hh@{T)jTfv8=Udh2^jM*j#fW3c zlgu}o^6UU1DAA@FQPs{3BFQURDU&g(dL7X`lgA^8Rdfv4a@zl>;^YNG z!SlFO!c^+%K5~g)H?La+7PZ5Ge2Mgc`e6fu>DC^%rYSC_5%D*`)z=N**A$8arzG@r z=8lbV!ddYdTu+wX9*TTx$oGQ!V!blyYdpX8jTIWVb0?NJWywdI0=DZ*md7!~K2V`MhlnKzc~lodu} zqw%VYQh2Bj->PVHf$vh(ZqpnC4@rw2$Es(MWK^YLWe;F~l9pIHzE&jip7uMLViMu^ zGuY7;H&kUv#p9M%-Pu(gN$Ti;;9Y%%fc9iWl&0Zl*VuC^T-q$NF52pa8!D zqOda(G@%WDtyo-1RUIIFBKJDIZOWALhOA~~a1r$gTK^9(JG>c#AAeq+b=VN!u1K7o z-Gl60UC3Q-Zrm>T&nKHf~E0 z8S22P$-b}ho^G``DpTj%-GfY_W1k^H(CKUa&i)dUrYt4XlwNk(DVXxerfLT`scV z-CJQS^9*m5co1%*X%nNmIl!!gi%K|{C-QhRXu1;CwstCDFflgTlsX1Ptn_SvsodZr zsM7KLmxe*$=`t`~l8y7C`CeC3Ol?o5Hxi$s*C>p{eybI%m#K_P;`;28GDEYHS$4?N zdm@vza&`11IYH;{l+!;=ta#INw~h*aD0wb0&~ewozfh|&@sVT~e}f7&HRX%6sYL~t z=*ttPsXI_{B#5H!122IWzphUB1uNb_RPEmsML5A$r%(V=+G4;98sHO06qpQD-$XQ6 z{Xf8@9qACG@jl6~%B=St9$y`kQRFUXep-6L{D8x9OuRi3+PPGjG!ATU#zdrZ! z>x9bwSrE>#KaR;98Vw<4y{7@@`Ikd=PyFMUOvvxUDJb)Z3qN@N2RQIZ%Kq`2qo*mr zX`9SFaG$x>b97a4n)#tO3|b3+Do^g0Narv3w->M-s!76AdAj``2|hSXd{U09Y_r&k^Rx;oY#a~Nc}mQEilH;B`gQu5p_DlTJyDx1FofbO=D#XfXKr_KYO(oLIKSv-K z{3S<9WbGH_nKggL-r>|a_Y=zm-d$ubH-%*xJp)J$2e$lCe`WOd|80~j_!oZzl=;I5 zm;2xTFVgD>{M428wq|J~U-wHm#(oNfP$2vE|z?y$jsr~5p#;eXMM_$bkW}ezLFsPk?rxAy5u{VPL%KmqTBN(XyW!3Q`kvSOJLleW z|DX527@nCuJ7#9j>{{!)*7}_i$n`5bP}JW~z9$ODeDO}T2u+wv=RSM{bt~cLBO~0(w z|D{zLoD0d7cBgqN9Pxa6@Gd(}B8O58dk| z4YY~*>#05x-#Vy@k$CY_@^Mv|N+>#)RWajQatCx);ddg|JjB>OARmTcY@(QJqJem) z#rSF5o3~MjQ-t}mwsUvSf%1e0$&~BIMX0wplTqOTv26aDi|U67fYWzn5a`$v$}GUz@=V)JV4#%`Q;1mKJpZ zK@lF5-l5({6_vhOfrZ8U`eX?=8Bk#Jl>ToeQkQf?wzWH4K5k@rI*`Zw*G2}+W06Hm z&`B=b+?sKr$u&Uz;_nHrPuDcPN&lEv|A)YHoLFS~uz6ns7W&SSMY#MUlC@TZ=zSVr zs`HD+b1af*rWCv%c1U%Pdem`fgyr?ui>7@ZKPT%D?F_< z!hnM#<`)#avtb4?X7*G{O7KqQyi68izzonq2ke=p@{kJg&`$3H&^K`c=(zQ~FnBj; zxeFSkubN3m{9l6(nHXXU;aDuQ5tYSVHi~olr<*Wpvr~%-6d7R==jGaFslL~tt29(- z#i$}mI>)<1&-E}$w9n$4U(%zo!GCaAkA=i6S`h(U3SUyGdQ zsK_mad)-X;d)mKsAh&npy+Hq-ulL_=nqPk<1`crUw!iWkQ^%8(Bv|yAE3JQa{e~)# zw&rlL4d>KS-b%8~{BZRVK-h1r?*1Xizv=$m8zAOB{{B4n8{kZ+Ee2mJg%5#@obVU? z47S;(>IKln>+zOYh(^z!BooUhj+5x|WvhD0FAZ#*$%~Q>oQHh0)o5gbA7q8ng}o zEQVU+N(>Qp-ppRwuU_3&yIvN#g|mDtDjHrrDLpE@40E3C%$jcI_S=dX3{*2T3jc(P zr$Qhf7%jlRtF^V&x4)t_mwiEA$I0^GfqCrdtjeWAKl$8`cyY*L)VXw{U;qeG-NF|)uRV5gyOJ$pU2@ElLc!(r;cf- zj+rr)95?%(?cp?ZTvFEqy^@6AsGvO4k=@&lLYq~%R~^5R!d};Ce@vCawKjpst(Xf# zaU98G3BS;UMwJUQx-Z?tx!W{P;@OZ3Gf(BQ#@*s-9qReTz|asESNVajuV-^}lcj|P zo+_R&JUm=;TdReo1s)zAJUl#98zjaO2w=fup*OcRSpdm^7%WIkD-ck{Qx%5Cf&vPF z#Hd1I(3_i^Ei8dNs*nQyFGWL211|cvqJccXMJ?_w`nRI*FWL;b=--O|by0YDMy?JQ zJLA7IbhLgilkWDde-3zpe=&O?2O+=tK-kYnvQy*IS^*=O?ALD2d9!A{H$sV27X0T3 z!uf~w{C+=c_M{)T?4BEOamSB#MN-M;NN0#fQvN%&<>Ulc=J9htoBS1*z>yQjIr*Eh zpV}CXvWS+4ww%jNS<}j%?<^k|1}0fe`ag`8Q1hT{ne4vFv8ze7TT~-xmW4mg4@i*G z%0zsfmSwc0{9&s}M!l_gq_*iy(eoYcdLCvY1Ly$o$)F2WWBmc@BmjL7?xkBI2+zDI z-MLMYu=r58ve1xYLf#h;W*aKksq6b{qK$WIaL$<#N5+ot{es>;nGLR$?lMi6jW(yW) zEYN@&lJT3;UpdGN^fD4<$@tkR!dDQHRl*Tm^ii;CLAeOh9oZl{)|1VjCtNm*5!^P; zYb3++3*ZGKIx0H$bGmcCr_7^>Z`^NG6MQK!B1Ns6@hB$MVKZB0A-L$1gT1?CGdRrN zo@2LT&B~B#ft#2#OoYIFbXC;0F`4RgsS$1RVzbDW;qcs@^JV>~C}n(t-K$Hy!rjsh zTPLogy8h;_D|h7C+Oab&*FN~hZTFqi*xkPNnu*=?=Qd0-9~O={UU60nsjR-%6(1cH zY>}0)#&@9B9SFkU}niW<~CLHVQWRRN;tEA#} zUQQDuWTdJ`GzwOVdbqY`WURlvbtKl&I$|$jX|HQ;9pPzi@93zGCoo@Om3dT7QtM>r zZ>wa&G&I`9k9V~d{S?McUXLYiX|2)W!F$H$38y#`$AVNh2dPoaq`X70Ap9Dp;p#(d zD6jx=Z~`9!QJk!II4^d{44ZT2!M9;`*V79M8CR#&W$BFM${Pi0|b$Ii=>1*?s-uJD3FISbnYZmJW65bXXzZ zm-)N-6^__AxjxhJ;o_3?{iJC~GyT_SHBbe74;p5xWT$Hqm+$45oS zB(#4wV=8-R9apN;mL~C1wl9IzWPLD8Jh6UMkaZc`F_W8Z3K}E<_PGEP1R@g{;s!W4 z?FPA*6iVqvIb*&d1Ra5SvEqbM6`2TQWVS!_(0_*lOF%F>}n&Mww2R2x06@5lS5NZ+#SP5*Mt&7$DFQxn-eGQSqCTeMaC1y*Y&eE z*TpW=OXT&ZR+?P5wLx9W)(z&#U;0)LYVcA0_+ycf8U}L2tTJb_bPdgobu~;)?Z<-a zYNbpa0kXpH$|H?Dgc-tCn7h!B8kY z1SlRpus5fD)>;hyhY*^5J!}tOA~+}nK5)Au@bGZ)le<02Z`}-WSPex8G4k{KFWu{= zdWQ0+0BT+CN_ZDcU7okMC!hE2+xu?z7thEazj*P2(pTg7oaqKXf24nN(v-=Wrf}4n zle>O;m-*@R&Z%?Vta;o3@BYP0S0q$@Hmu~HWgB8mO(#1hDSYw#*8;-g&jUYkahjOQ z=^825q<7|XNMp)lQf}o#Xh(KIM^mRj!|y}6I_6{K{JQ+$gm=LCOdJ#HQo>cF;$kwGtO<3{FJ= zDi&Rgx4+UW@t|LZ2J0Qo4m?_MG@PbZ zsx;W`Y%r7+XM8Rd78BZ8>tr&-3+tq2N8)pz~02@KR`|-Z-5(n8kNq= z|A_8G8ioPZ0-}e3!07-(D~i6%k^QxX#`rd8ee(MGZA1V1`HfgqxA84^t$F#RNyVjW z!>s;^eVvTUExC}iN+%uVGX@6MvEZbH#F!+2b|mH(D;}#bvGyvJbQ=tO%Ucz<@0n(^ zS+7Lnmx4;}rfBJX@qW>B*dGjS;Z01$Ibu-D6hLVNDh&%B3{mZbmK{$d|~ZV@pE$mw0ODhx8Iko ziCO6r8Z>x0U6_S4e)s|uv~~9LEc*27CHnPkOWQ(3Yg=?=)P6TWz30Y{huJf;^Kvo| z<>ZEkN7mLA$&17^HCNJe#8kAkTF9DIlwazNXIeimh-b3Nz2qFMR60N3eVpIi`hMu$ z;0l9YH}flY*7^xQnkh!B<(*s@&Jv*4)y1=To#YQR>({~$^Fp+akq4afvNF^uS=i#5OZgeJYog9yj`IDNh4S9%NKk%NBJkoT!lmmuWPx3sLc%Fw0N8DWkW zFQ?0gI&YRgtd9^P}fB2SS(W5QQ0|R)aFe5)%9>Bj(d+Va)OGFH*8?ZOM zzk~MCPw4A~k98LjJN4fP9T2&#E{S3Gw70`GoE!Hp8wIbDB!+JWhVuIR$!RE`Eks7f zI%lynv(mA%2Zb;4R(|b_*NYu5P_8+)XHFfbySVorD@H1)L-86y)D6RQO6t!+*1?Tt;%(iBuNi|M+VpxUt= z=QTsCpqkaee#lB}PT!HQz6Em(BC(wKd3JvR5drM?jc!#(7yCh&U@ANaOq zgcE4Izss7Jr}?5Rcp4S{?e^mvC)=KONlvfTo<9?Nl~F6;^K-zI^HTMy#uDY<&*`BOIaIP z_BSFq2n&V?cZWp#Jk1P7b|E zE}&}$%&*X6Lcs#Mbjb8M-|8IG4Z7P#T~w|^tO7ZMNYOlu5Qx0W1WU3&`iw40?cDT( zQqGweydYu(-Z)SiG&C`|ozwK0$9p@(*OhHCTF}^cUj_fumm)w*ceCSqc)_;vu#rG7{H+75iiTBwO2((yVG&Rd5QMiw@1}WS=D=nB$E^V`RHGKrQVC)H|r^ zX4ZH;6-wjdz11!qDDf2*iv_szJ?@WX9(rlM-dp)B=LH~u4OcNVHrjm`R?zC-U} z>eoZ-m=(R3I-}KRuZ@QDkTJy$)pc}BdcODc_8Oduwdidn06julBD{pHB+l-yMym7y zBngZ|C|db?XC7)kLB5S>j~^3}^mKK9zhjT~%Ad+XCFQ4~z5W`?g53iPN&((0c)DWv zL5#Yg5$6x*tgK?n1*VbUx`|xG-l* zT1Iy8=g%QovibcNkANi@Q@`oAMGH>Ol}pc)U1s*{TeOQS7j?qN?rjVE4s`^~&mz%i zP?pwgoLni?yxawQ`>GyPCza708TGykn@>`R@_JQEtZ zqJ~(>%!^~eu8g-7SKU!GvOwR|HJVjY-&Ch$ZI>a~+qMu%Wj<1<;!&bJoQI`Tq@I-7 zUenQEkT)>o@v3At$}-CNL0pi0vj99SF{(rH$m-^L(ksgf;1gbsjq;+NBMO)Uf&6U< z5@4Xu(%!nAwSa+F3{(vt_Q)f^rVlUdWje34jBNWH_<9YI9rVN}n?NQjyq z!gs5zn7Gby%GwW$~+vH>gwSE1%)WqD4!I6QVLo!l>z|$*`7mBIKr~%ZnXv3kpjxDaw9pCM} zYF#58UN4@&{WfQ4!m#Xs&Y3HBuiDAIj*gBK!wq(;m+F+PY^?_btT=`^xjJRx zM;Nl7Z3r|N$;ikAQJ%;NigC)xi77j?`{WFd{T}=`^Xi^-@9qK90*fbe)ZbKmLO!pF zGboi?jK^bcAHGtovrigd?D&YcX23bjqhAj+VCuBLrn_7zKWz>NNy!%Y9uj?E4@wCj z8Qhp`-aq3kIJxy{nl(G)AfO3}e)jQ{_ka~IRDh6tWa;pB-}@Tho|29$HHSt`kVaR_ zAtn#@_&5p^6O-UAt|)AMZc$QrQf_KgYGwx0==tdLg4{xYX0yB&EiZt_{&X2HE{Mrf;DI+W(ibfS(IB<;MP{sDV^(hp zSYQtX5@2GA?lxCYo1v0U-8q)dP(<2OC{QhTIzD4#(_h5KYQt5zia_S!2Sa;!6N8*_ zEnbHpE%Y&*`^H_}pF_}IN7n;}cfq8hbEl~ALz|r(bt%W39E!TKvT_NVL3y&QckyWW zwe5|~q1N&yRuiwSx1G(VY7DlgH_OE#W83NdYGO4BL0l0S+mzmg2=IF?91dBlSyj92 z=#amN?_FCnXlb#zpx*=NT12yxJu<4lzyCcI&P2?HzK!hXqcWSap<&0}7t)z|1pp-^ z=Qd}zrf244Wu#|kzx^1NR8dU@^e7Y4bZyE=S8&~QyYhvqwa6rzK_TAFzNna}m;_vz zHP~6))QiZ}Q$u|IU-ir}7Cj+jZkiGmNVG7RZ<=_Pqy(|vk2*Q@$`wmx zG*GvI+uy^Y14?G-NWyH(n{Yds4SCZjruqvwxyYk{HQF(DLNwM|tZ~-hQmazM5+f-y zl`5mScfGtB_)pQ}lbi@DH=65wJb4*L1| z1+=zp9;Ys_T{{@~C$&Y^H0AC5ZjkG&?|wB%c};^2f>(}kuI(|m?*}D));wXwL2N`G zc$_a-dhp)OGZb}pYsW@L#I*%sMjJhSZ8T7-*E>4@)jSUQUkfx``E3UNuyoJgar>oV6bHGaVaN+Q5dmc$y1I>^yyQX056VkqDnR0f)mOY-#CFK_<-`oM6ntnHFm~*-ip2s08y!uw&MP2p8*1w6T zOiJ)E4{OSV%ADA&c(#nIv%?qZjL&7jU?C3-7NbbR z1H7q~{IODlf$zTiGtSW;2{^RB0L%Q?o%_+$GcW&c`A)Hf{Q4mg2pU_6yLSy7apfM2 z4jV4K3Vi-yrw3?P4T(vod9{(3%9&5*jUFsI+i#V|5g9=TcS? zmU;j$1}sj=%X=Adx#^{#z98^}6oYYV^fhDJ;;E;4wpLC9RVyuqfp1;41~LbHa6jd- zfF`ep5A9Xj2yFmy=LZDx&7cogI$#mD)-Vxn z|I;K3soD)d(d-eqgYe-nC=h(?t{ZlhO=8)E@q>&)S|_XS)Aj3zGf~M~r7v8rbYwrg z_;6~rqF~}Bjc}kdT|XZAh9u>qZLG?4?42cEz^3lteN>IEUEeQDyf}Bcgzl{Meta%A znR%D}w;^8782l~Q($g7r7_|B-!gLsv1h;x56;862tTPAIpoI}2gm!v~(etuq~X-*xR{`ULU3nP>YndnhpKeq02EGU-QHdR>0koxY4 zjX)4cf(=W2V)}+CIXxEEWxtt}$lIIrP1uJ=;Bc}YOkH!!Ptpj5NYk~kYF|!QGhjLmiw171sFpHa^a{<0cim1$bboCNcL$xrOcXC&qJCp zw~kIUzm}5+$>z;fM&ZQ%Mh0J%USq^*=YYPN1_g-MiKi8)xiPM3`x^pOE=wKQkbU$fA>Z1T5EZrlthBn`6Ba zs|o(cn+MIW<^_3y|3u4^8_9l@o5H7NOCwiU?G(bkk)5!s=o~4D@5s53LO=%(&Od?{ z#uov%GKv7wY`Ev)@yo`22hHhU6<;e+$03Rl|8+#xSl5U#sTBnmn)Fe-glXtkr6>bw z-v3mh#=Xm)R9;!IQiuDN%u6u5GbR0}x;SD(UOtxIU-(o;c5-`kOYyYxV2R96Yq1ovHKs9%U*|)yuz$(D)1Q+Zi+(!ZM z8Vf;Qg3XteRRB8Y&YXJ{kOqM30GJ#|b_iVOWe&!j#rJ>C7(8Gw{?{e%0YNYSVXP3u z0R8>JvzUiiw53-}QCj`H(L>DWR_7>$TF!6c%41@E%-q<)}6gOelRmEsfh z#B#hC+p?2vQrQ0lc6uV!M!*FfN0pP^3Yd1I7tn%1_eT~Gc<!S$cK(i@jKJ=-)VpxKq~)W^xsKH{yO82EJVZr zn2jO*o$0S6zsnW)FYX2wDCGWjeiw}K`w@PhK&L9G_#derRTRaa#PxPD)nnNd;IELX z($?h;dp=YyE0^!K82D%U=fBO2h|$idJWdjFuH~Ol4N-J`kSm0B>iyFV5?ck_Pv)o4kGse05*$$+fJFgCqh6Kz&foUcryN&*?+l$F#Nq`z+LFLYz$$x(mVr%8M-4!7FZ@Vk^C+kXN$Z!=1xo7O@yE)G6BY`;> z``SP1%HzKGu0?JlzUvY1z?}bti;%yK3J0&c?G9#X|8h3+j}AR+{nRbY?bFMP5U}aJ z!;*jWdj;Oj?d;?E@fL^6PWM z^Y9~GhwLQ_}&mdKkB?`eSH3q^n=LlR|GhsG+33Rn-qK}UP%OUb964fdbCUF zn<5{z6)aOXF6iAe)dH*IvsfjEn+RlT7Z(>dVcKV%L-Ff27sc1Kelj^D$p`JWm+0u9 zK7C4TxN2Q05B{89m;c$jtgfzZxS;H4X{+bxgjS$#Y8eh6K(;zjwRUbAQ*B0MN$5l} zW<(~2WMm{33gz2a!@hjS3e!sk3p!Ok17Sl)g42uZ-h6!AYafu2=@#%g9<7J+aG~2% zH4z&@HZ`ao`lEYLUg52_irnEMP8rMOLMZFw0Z*6aw8)ivAs=fzlW8C4WVEg9~?w4fp8tYmLK;Ml9wNpO)?Iikzcw&`!$&^^ypa z?oYQ|`dhB(4wmj9#3HxRE8L%NoXnJGM5Wc`MfsGKjTMybtn9RJvh?*`B4+AF3)bD~ zRK^k#Z<2pT3{Ll7&SDK7xg^sK>|Q3F_C@G_J+E-)OddGaDf#ime#K;dG71pu4u~nA z3X2Sm7O5{7mi5@TS@#=Ecl(C2ioaT3dCeyAbj`rPfMp=Lv_Zpp>W+^fnju;(A{V%a z0Z8R_eonI%ke$d^o{47d0FrhoduL})3CT(*-HYKo`O(6fas?lkeZlREyf%f=ZuRwf zx@Hw0fV}+jiji56kpKx;jN^HJsW&K<_~Cc>!lUcQFuz!8_pEV^TQ|b<#(~??dl+Sz+x%>x1vINE#M9pEqiGUkN9U*|Y?cM9+`1E`>aK=?+ZSIPyB8vAu$Ii$iY z{E6DIv6fB1%#qMH*0T2UGqvsz?^oG?e`O=aC%EkpJKUy%f_Fg7)PXyj+!Wd6xNQ)Z zSq1M;#4b^(xm42*tWh>NI1st{i|ClX0nQuJf%oHNY<_vmyM9x%onJQ`)E7p6`)b5B zM7MU!O>H8%G2(ibc{Y&MtS!p%(#*}bd+w5kd*5>v!PxENw;cGM79o9y1=P1Q5kZw#`{oyI|8Mh?^t{d#s$h=P|DwXUO=@LLxn~Y0*OyZ7eV_ntP zZ(jZs2OocC;OECZ2j_u(fNm&p#CMQ)6*?K&nO`j>B!qQ*4@lYWm;CYL$IoGy98d_BJkqWqk^u+=i)94xBb7lV* z-9vH@<)K&Ogo1lQ{8pZn6e{^*JL|2ncvvCu2yRAzsoB`{jJU>LDYl@2n~dl|uzbY9 z+JrxW3X9==h(Huh)S$6@?0CtUDv@PaHg4)}zj<^!c;>2ce0fbLd{a+2f5oX$WVm_D zt#Wp8(^#~5(a=#+HFLme#(XqyaW*B6c^lNWbfqyG*?DFYBaN(ic* zkx5C($9+vLp;EqDv9n{6tFW`PGu$SB;Ir;W7t^dqP$=~9uGc41_}zwaIMrxK;VXL z&9q`o*(lD)zzCDwNR&KNMWyshQQE>C3<}9Fg3A|M?T%vDI=V~6tzBI@5rgwC%Q#8`+ngj4n_Kimk{cS&ZAEx0^VU^-rkQO|DTBOxEKZy zR@!g2kyqOxn%w41*3|CFt?SlxQPs&z|HcI;K^n3{wttL4c6N3q4z0(n>#hwX=k?CHM8yc1dKs3XHjyappNNR_; zeVFwtr+4gXll|uBv$9u(&*~u9dvqz+TV}f`_Uf4{cGreoJFcWuA^whOV8s6v@j2pi zHi@Wcsmf#G_Q%RAzW__U^(~dOaqM>6lP*^-)GJ#yFRgL(mR3r%MkS=W?Q!}5{`c@m zP(8rslyCw#{z}4l&^>qZHw32(eNa<9o#fvk2OiP*^C;IL%7oop{l>=*Gw&|F_G!;& zUC%0S(B|CXt7^X|N8GONUB24gG@JFi_J4RgD{pb)`hW?C^?Bw@AC2=T7E8PmG}E}^ zHIwr`4ff=Vf9p85(-_UF-q>yc*!<=d zQ#sPHhJ%@ZcoEXR=*31V5pWkn^EJDXKecw+tQc)EIN|c>=WL4cQY3Fmug}1sjG9OuffvxlNM-+1fDM5& zyw|`mG@r#b%uE6BIv{W2-~idkrEp$S)n1n%1O+$SB($pdTFngDX}a7N%*i%p7w za%Nd2vyOJD69)jzTdR~yxvDSM*^X+LPHqd?rKQ!58a=xrAUFah zk1oMkQ9DjIMpkZiW=2j<0VdOAgmJ#%0A(JN{6s?t(2pc6Krftcf#cl#??L734Ivl?G&`!wMHYpA|doGX}dZxmYQc zxba-lvmzF5O4UVTMRIa-va1`>tmHTnivoqD-?ovFlQYD|-wXPgnQ2&K0pN@pAbBCI zcs*oc@xdPjfe+8}UB8_Ckk%buLP}Pato?mbMNJNX^ZGeDrGnV4pas>2X*2H=_Xz_{ z5JSxiBCSUIC9UpeK_CGP36S8!XMz4VWF>s&UKLtP9>Dz9@1IQ|PJ@E^1lW@UK?m%i z3y@&9i*>vXe?#g|!stFbS-N?WuKI>!Px$Og9d*mwJ8haZz|avVAeh7M0>#z$SM%&Y zKAWz#8JMhzw!M>2-z)@k{On>m?1yE3$AbX-B5zO%e6IT4hf|o7Hd&tFX$F8oNHP$z zy~H>84x!zMMZ-UgYs%^5oro`=m<6dF+Lo&C4jX3zPJPjCIT;dlW0MJD?N9> z6#xmHmQDl<4fd7t;5mcmB_i_R1229jjc1q)6I|e<_`f++g($-T+HH#eWxDKZ7_&+n;$ zbWkPP4!yN?)PsaEhS_X(u;?BjZ7A@jCn(N|9+edqnmA;vqa@P;1?ieU*i94CPt8Hl zH&4S6$cn!c|Kvj$A|@(v4pV6Tbk0TCDz?GLygFPldzgD~RSpD;wUX3rGWpcBXp@`x zmh8meCfDOOE*tr#@l)dC^P8f+TPj)EoIjcJ_aS14GFWU<+H?2Sj@naRUjl(}Uf54- z?yH+=Un>>2HLic-h<7!{npGQa0c{#MJ9navgv6Dlh1*`x(9pabuiKhh4Y#us)pJJo;vYXR#V*y2k4;RNsAl&)D!>D9 zU*D9cq35_!YZsEojWDFX;WzIg@gkMcp{x5BjlM_g$GxWE_qB#!PSBL-Wm!ylZ4`(S zCfG#;;3bfe7D8w)7g1gh0RU|P#>jBF1eQSX-}U~;nU5*OUMTybre zVd@l&RM1vXKipPc(A$-Sft$gc`vhQa&>WWsCLr}(29;CM%Bq{2mnG#l%~2|rX!T(b z5JaUzB?bfNY|8V@)NU4v4T%&1Q4~&?Snq1nCH- z(={Gk)r(@f=%Tiv;q-P*ua5xb6#CCSrys-g#dJXc(<*)iz$*{?Kz<=v`Tld-m?kj6 z)Q2qzyG0g~b~m6lUfo zL10XUCB5kqMp{;17@75gdc{NpmoqYQ!}dqy#^~Dp}YxSwXG&ZdJ zG92CDdD~hxeD}VF+S;|Ly#gWxeT#xLywSEuAF?GR00CGo>M%c6E5%#MA7?Na&QqXw zVK!4^wc8QboN?)G-A2(vkza{R&CN^-&&_#Fh+55Ps%C2sUH#HcUpW4W5;*E<&g0?r zV=WT4^*m>WPxWp9u5*0HJ|k0?y3R`as}&ck$eT@L$LiRefa>b%M!HzWm&$?Z<+ifN z0eZKLMvfD>t?L^`xtothM<-Pa3Kg_6q-!^anKy>>)EqL$jh6F9i<%opx>cf<#75`K z%!cDJdlQ#eIP83w%v(D|9=xLMW-u)3|X-cy0nhlcx9x z@A`gN@|PFCry!_oz)Rnqvp$HQKbZF*M$m&MsC!R<51Ig9eGgLZJOKVmg5m)h`t1Vn z&RJkF2-gG11;C3O<6Q5Ii|;JiGl?N*(n}OZltP{ehn1S0zAE+0$PO7go`icnqmQ&VWY* z11bZzsB&$?h;o&|>>{KtIR!*y5z%|02?f37kKm==CW)qQbH0P0R8i*oc9;xWsRl;MJmt%~S6BhZqu`s3^M?F*9O z^_vcp!0F$>@8@_j_Q>|gjKYU!xww;=je94@LH=+B$>IF_^hWPTxZa&P3>-^3sDh zZqHE;Jtor@2vK*HrZ?6Bh7M#41A)NMJRk%fXb~dN9RZBJzY&xaDVUG%&2{6lm{}U) zyuIBmlvVewrO_1I(#;MgZqK`S?=A|$Qa*L=$> zHytnCCNC~6Dc&Ae66x+yRZ*ExRaLc%P(6FLv~99Y<9tKua1>3T@-`?yWWC-nm-kET z3Mc6w}0LmTk(+jwc7m?3|t*;0>u%DPKn*x+82SCCNz5G9?!g{SP+ zHCmLD-G>hmP`ZMQoMeFJ0H5+@$EmsLj;xx>gj%-b7x|=2xQp5;WEB04qM}i@{=uIE zKULuJa$mzop?58xog5X2M-^*K4f!g7fick&CK%vz4q6cb~FJ0s$K z-1JaV8*V2bs<+rpsU72L&|q923RVJ8i`d(O;E4N!SUOg4jc9OvAjmB6!<}604upH) zJd6%~0D7=CQo+Ab^*e(Y(h1{b^(07Lu&!MKK%&=6Hs1k`*6p5`H#n`R*tK!qxddyy z-^7g)TL|6zec1mKt>}>okn;I!lLX&Hs8HaTZIG>B!}5%eiYjf2zBAp+J=rd}oW8=l zW4QXe2$+>Ezh0)sC=p|Q3rEchmJ}gM34aWj%z_*~;su*8T;GnkHT=9)Q`oJolg->& zI5~wGzX`gBXBw|AU^5F}5b;lOf zw8sJ86+9oF9#n%NkCPy7&PRitUjHVvOhO^&$rBvaB=*vYVBlj3-F3)pdD*9|W!y?Bug|*jPmPHBs?DyS*i!DfQSH0HAW1x30 zp$v$uh!CHF+xZR128JE~TpwHJP)snM2LjaO zPa&W1N4~~dAutq5ut1`R=%soSZ`K2Pm|FnXC+J^#m=}{ZK%WipRUdA&ol!Z@-ZAc; zr8(D+-5%c>BHUux@$vETH!l{H)LS}KtZa)0#T$2bUr{sun%JM)w_R6EUuOmB9-F$= zM-P@wn31O6)c0+gL-?xB1uKWRYO_coNM!w4%ZE;QI~ue7Yc_1);U}DmZdq^hhJF2G z;xZIgf)9S2XJ>Pi+1TvgP{la~D#t-6ck<~JQd=~$k*w;Zy1GW8Iv}V5rf%}Hg$mjq z4#h#Cg+LqS9(_Gz+OU@j1L)R)eB6ql+@3xkFF3FoThY}4n22ovUh*lk$$X0+t(pNR zJ5R9*H+|M5Tr`N}UO5wUa|5D+dh>{F;lRnl6_3E4KLe?6`N)a$ovOhvUTMCn-3bl1 zoALA5@#^4-*9MCdC(|re(}UUP8TSC{T6Ni+8ce<6*r~kO~E-w z$me%tsTq5ZQYg>M4_Z#&3*rVzNeMwjWOuSMKyD@labZjI1R@^;eA?cL%K)y2ld17a zL->hVvbK6`xY&bb^<4E9RaIu=CjxKHS=dKAI+DpE2GyNP5gGez8sS- zbCk~1)7AGayI_PBe|;*k`LO4lb(+xHQfha5CBtrT_@(=URok}*-L_82vVyWh6Nbq& zauQL|jxq|9muu@en^foJPc&?`lxw;gR1?*7iX_6LNS>MY`v+`1_e(zb#?SBMdQP~& zb=!U9eD#05UI(huR@(q|Hn>RFq{dJAS9d`NYM18L6oQ&nAdy3Y9R~o zrv9}W09;8y=Jvk{a4`1KZP?wXJh4tdT3SHrkrXHS;MG04%=GcR%5+#|2_)t|mjj?mK+^cD04eq&>O zf&W-vAPi&`j1B9_)#HCP!v2b$Grt87rSE{)#L{2U(qE~aSo6Qzfb{o??=vdvtKs$4 zu<=)+;*1K5o(}x=+`s`L;f9Km+ec&0$n~U3;dh&9bpYk4v{jtAZQ_b0qLfq@@!bS@^2G$z#Qg7K<*1j=AnMMV*3?oTfTjIJvw}_6AP}~ zzdoLEb0Lr?th8^Tt%C0Ikbxtpc|O~kcW{eyqAwE>Z(TjVK_)GCzmdMiMS0-GoASfp z?+1XzchS6EyGpsrkO$$%Al_;r9|8gdI!?GVBL*SQnOlrTn9uoIlFJ{G*ttj6Wj(td7_}it$HA z?))P$HvJz#oOdATKTFg7D?Ue1_OqObAheJ1Pj`V0+MOEiwUQA_g?`BW#l=BZ0qGiHbXE$$M^qz^PihAehXno4~ zkAGk8V!!AZ0)O}E@{#)`diMzeQTPrvm-*yGBqOateDE4pg_c7QIT4580$GZr0@*r# z4##@KwrZhBJ)MtDYD^yew|xlEEtsrrImc)HuetIg5PImDm0Tk zdUn}Y|3evix_UaVI3>)HIs7%4vtXX>D*d3KTXvxOcLx(^*JN` z11aj7zGfF;AmZs+Orm)$9*ensboNvq`=~p#X_JJ%s$ZCP<2<8~=c%ZJk?0E2U)L|+ z&f^SEM{q`^@nBj=#4cEpBEC?bd}^Pam{g!OiSD{{`*V2E!*nui+7hHrK`ZV-B8cLa zj?S4(VQ1#B{bon<3;)1{ARdOmVD*daG+jh|&TQIZ=#A`o8>xfyHZW@PskyZ=#R(DJ zrkzm2K5SdZj%g`6s^S+yVgguIzIxHnSrp+2+w)h)qU@2w(EH{XRv%VP)gw(RTgn?5 zkL&mDtB!LMz_HNTA8Qyk!mPQPHy)j%eY@y?kVU7{g5tEjt=MEXEDd~P2C1*3uQ&{vnK{q07CNhR-pEo}Mhe8ze?jn{WqcFV1wzIDCJezRsF zraR^bi!{Cz-CNvzZ2O&pjX!%Onr(vZnx4<>`220-lMfp+LP8n$r+210*dM<8`>n6q zg~jhoiy7W(F^ZVgJ~=+cDkgvDKK&zm?PVXIKOVIwaFNpDkc`DHQKoLdlee}_>Nw)o zu~karBCsL3NZBPf*~RVXmcT`(Qj1-sl&+b$WV8yHea&60rtmU0*8a+w2-D-sUKdJL zJX~pCuk_ksq7tyh2|7d)e3~S1#a2j^mT6ZvXpU{gibadAWQzoWTQQ=avw$(XwP=sG za8>v9+sik2?qAuuqdMZ_o>@oBc=LcWNCIV#1Owd`;Wf@_;sQ-Brin`(ieG=dy?svI z0$?!;Ec3vJrvi&mVEG3=NR@a&&?%}A?GnIKRH52of(fb(tY0_D8nm+D^&#-c%#~71 z6BcObO<_I3FqL_B$JsdI+T^aTa#OeZp6Ugj#Yuz)-LhM&uYLPjJs&t7%+5-kQX z3pBnAR0K9TuK;WZPyjSg%?dIVWH``9GlUEHat|<1d%*B+J4oXOh7gcjK+4$;07s-l z7(^LZ9l%4=tRQ_lKt3C2xErcS8YBzR1XK@k1kg30p=>Ze2do}Gv<>zIH$)F~XdPr9 z*bK0lpg=&_!5ZqaG`cKdQL#|p;v)@BGuVzTTGUJEj7KftlEb56M5+U&SI|^$R96@H z%t+ATk!GN77bpXO`eCM^9MKD&&Q)w!p;%!(=TGKMMql8{MqPX-ur351GYLFvQh0vw zW;ve1n(O)!E;A4vj$?-1BFG((V@8oWf$-*wVNc4&$znbcCzEFT%-9GOmeff(21Gw< z-)^7%I~3S6#2yY(h_fz%P8VAno4ab(m(J)AgyFz8ev)CA^5b9k&R5@zo@FYf+r_2T zD|X{zPC#Ht#+8h1Cb_O%i`^ExZd{zD6YAETG^so3=%S-Qo=LQru9$AGbl{>J7gub| z2@1@~*me|n-BymOqNme^ORcI}3g4dGS;2O!=iTfbd*8JNNIU-%KAAgRe(sh+)154j zUIiBJTz2=){X^@I9zWXkFWrvIvSwA6{zBG$jYR?3alJ9Cw6~X}XdGC`uy5~%oqb;z z9L)|ewY@G-^R3_9c8qD!_NIpp8nLY08n16xNf&wM#oqXprxw%lQZ`=c*5>AYANHIp z@SV9tR$A=l+4!y9r@u>=F*5yG8eglyJ?Y_<1CI)KbE{wM=d$dO@%Z}xS83!&hTT@? zU%xiQ?%w+C9c#wM#d&@cgMhcS9@PmJIjR$MST|TASA3WHj9u4ebpMQN*B5_nob_q5 Z+Whai@wxt<|9|YBq{(Rh&liO literal 48889 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 z Date: Fri, 6 Oct 2023 23:10:21 +0700 Subject: [PATCH 22/27] Center more icons. --- resources/font.bz2 | Bin 48917 -> 48939 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/resources/font.bz2 b/resources/font.bz2 index 7f66b8aa42c2a66e6781bb983b06152f96810608..1860f36e639e230f7c0967d876ceb8cf5e837258 100644 GIT binary patch literal 48939 zcmce;1z1#D_c(lp25FHl5do2w5Rp<+MMAn!x>4x{gYHH`xR1JCAg;nStseB+=a0Xa|U623i`o@%iY6<-J z3o~&i>zgT+LERDnpz?T_{)R-P&UXU<>^TQAH#>eAO(5u+w5SXKJRzs(S0_?Wt>d^4 z6qEvqOjJw?z-zjJ-XFakDrNO`4hjy8+tDGIjvOYWM|;7x3d1XQrIO1Xcwp8vqc+MYeajfo&mK zfV5{KLRT&&E4EuPcYzF{w%L7R!U^P3sp7s$h#RNb#0582Wz2lQ2A7=tLR{HMnHAfG zR2Bo&`^>eUnRp9hU!i=n843bwdH4u;KjDBlF#w1V0N}vbMzOR-M0MCkF)*G$H3tCl z&tQ+m04ZN7*tIzZwi_DA0IFw@W*y|`!?d@F2yT`DRt^OKAi4n*9{uqvG7w=q5R|gM zt{S)vBDeKiwg7QkiPp^o0uBI#l7N^#?k0hm8}dUC48ex5litM5D6#&EsnBJR2=Gb- z7yzIHRgCs69j7tpP>dObK1Lf51CR!Z#gOWSqPg8TIO~XG=&(3j+>qE%UWvH@Ey)k4 zIT7iA7*Z5Ay2lFgq?t!i-g6mY`0<&=VI6dVl0~E_cZG=2nsu?TfI3K!;pdN!vDi7Z zJ@3*9HFqZ?Afmfn!3A2iK#*El>vd3`yiPYzD<91Vi$YK^TIC)E&;x#S#0Mvo#?zJxM$>-P@bfXqx|l8C{w& z7MmV-TF+e>Qc5qd0l#n};#W?9pZc@mXDkv@P6xNg0A<=%IFjUL;DI}515(3hPA(2@ zq@D+%4XtJm(r5YUAY8Zo+1at^gB<+XIoar>Ff61H?>yK@|0yj+FytUvMapT+cIAsv z5qGi_m!M=!y8k2oM=i5iD)V&0)oUq>Sr3Qrs16y=6ThXORod+3=zZ~_D`a1i|H1V~ z;(NuGKt_PVcECYzZ5sBz@xbBf_c#2QJsMZ(hWRk58{t;UkGxPOVe zAilmfTTyCQb;LxCl}cmK_T4Lg5}P-DO~W1eNsFD=LhFYb`(~LW%v%KnRMEtQiW~WE zZqb(9f8zi0Nj=_W=BvGG3UXVzv1?PUxYm<7}CqH+B;7ah%EFL zV)t(>AZh*cnl?~8GJ2Iz%7SWr?jrEkhpfWU^zM*o+<9vW#@R0>>1Xp1Z9`8uJEiRK zN!u=NDhyF5jKf-=#Yc^=dYHI>^EhrAy-5>F>+>Mw8izzm3s{U1p3Q{v^h;1pmDH0k zLaxb^m}-mCc{0y+QK7(Labcd`fM<m#c1>b~}0f`Q72jf&0bmtdfj zna);ic{2M!IXV^es>4O~Q)@iI$E=a{Te>hoKV_rzKee0_WMx{;iEVax6567dLCb-f zVmw7Cyr!DwU7fdw%izpfH~zCT7aXFPy)A4|zNs5fno`{f3TP_A;EktXdzelI>Jw)| zj;1|S4%k}zkLH%<+-6N!fQ{2t2@#;SU ziNT_4!c13R=-z}&>^T>yGmCMhx{GklMV`ds)V|-ji->czhWGS67oZ2XW#y2gPBWp#YsPTfvrT9BCfyO10v%g&Q4zz3`8@usxX7mqZm2_K2g*S;fL59!AV z4K9%h{a{2O{_Q+;o`QP^w~Hg-ECO}8dJ{fWaXkF&U<_wig6&7kLj=D~0rVl~$v^Pm zj5^v1q`(O&bmk8{?7P+Z;}~khc#^+8kwrxcZmfHC`1HZvJNUrh*!Bo640|pMe|qaq zP#pvvG;26uj!2cfas9ldW99d|ghcPuyo5J{%|Azm#qOqAmvf^plAOtUp5UE^->CtJ z)%ME%-k)k~hqJE^S2X&WVu0RHpQS;aDNfyOz>AW zcqCqU|H*<096#2?LfzLUGjeT0Ip?sd90E+2 zU+k=r zG;r;AZUxO~$hSjM&pDwPN5h`~47@Xkt{ZNbz>mspVu1wJpMOtbkd#WgjNIYWJUw`0 zt`UwN)IUduI)5(sY_@*t8@vnc0fg)GfA}-Y7QD5vxeWAdT0+NQsZ&S#Q_V%2D}>cm z8?Z^ssc>6p5`4;ko=<=t5H?ZeW5UAl5Yz{tL-B(@JX$J0FZ+*R{-;O7?Bz6ELM;Zh zJ_Ozw+j<4yM{+^w?NtqwdAO*X&zc2#;V(KsgAwepoT-NM$jCjxFc-C*Z5zq*?PoS; zlQN$NvHk89E$8QDMMRT+RH7%jUF46Gd?jGNRSrHzSoF0dc*FZ8<;GXIvBjli`6b*8 zCX&|-KB*(GpmSD+lQUiXpECyj?c}D}Gsiv|r$G1a8rc8Cyl%zn!u#| zho2uQ9}~?!hgaR7BY6#_pyt_7c`|8eedUZ14yU%5>gA#MzeiJ2wmE(lKw+WFj_7;$ z%x$A=_hQ%!z3TwB{(SR)s9jI#yrd@BZn!MUcvh*Kds+5^Y^)k4o>eH;P<{F*08bn8CrF!wA+{1o&{Lt<4vf_A1KA9HCNu_I9JjcwNY z?Ac|V@9hdcYc9~jv}Cs}`l0i-=hC&FfLzhslE*1hA@XgsgFmgyu#OVE%>{$!@?Aal zLN8rH&l=2j8OmKRGN>_p7w~>IJ)AppPMH}IHX3EZb zc8n2|VXmvz#(aE@Fp$RSEAzloy)Utsvu*0D?ufgYwU|!Jd*yeSs2Zily06}ww7qK3 zlzJ2G-K35+%i~DibCDc#<*j$5)a{>E)W?&$uXvk3DWoPEZmX-QawH}@&n@13_*{js zS=@-yU`Dy?ZDv`;ZX9CFki`%k zt`b4x6``l7PvaFHtw`e)9j+7Zm2@>)Q4hT9D`Y;V(^ENL5$%-}Zq{Cl-F~stZm5Z@ za~~tR-khPM3UJ_ZP*vXOENXin>f2sEK>$2jtPwZf50*W!OG1sFE7NrS_SAlDV&7s# zW~WTbR7^yeC;7R&_*5;G=n@}m6o&XGXJ=;=c~t?7eeM=U?eb%SlEH}Mh2 z26(mJJ`;_fo*$a0aIzeSx6h2T_R>dCZ|!U}U&(TDuX}M%cJw>7xVYz3*v&iUgjy2y zd?IWe!PvK_c#kjU%{^ZxAM38@imZN^+EI>e7&1Jlgz-+4IhVhu#5Phfl9Du4$;e!8 zbcpd`oKRImgD^-M=0^6%+g7193?T>Zuda|$IIMeX1^Whu@4aefs3F$*6e)6ZCf|dP z4o%2|SkPi(#pKAfY=8Ogl2d5+Ye)P&HkThtg=q6D_ZTWg=b64MshHmymFxJ(@;nP*SVa5GM$LbW>RAT7Pa91~3IULUUbulP@8BhQ z@}R~&c_MbPe4e|SzD426)*nAyk{dwWLeo9Gf~k?gg*X{le%Sd}ZB)+D8`7y2_Bj1d&E$O;Tg_1_0Vg9IaUQ|zupjri= z^UdXq1dqx1ciyk-4)4^+L#_RPFnJ~S%f`rutr zPc?!@Um^Njg-VpqHAOuTuCf3Vhs4`GdWuQA9n`el%Ku2nyK5p3TA=~%K1cQqSeU~D zD+*d0WbxaxIly}%UP*L% z%22LAW?_ObRt5!ez5*n=^M?te7g|7$~zocGyG1@&z0S)Xymbrl|t_W4yCJ6v8I z8pVA^4nUrvGysnRuWE+;Zvs^8xdGg~F>JZQ`?~BIju9VCX4XBxQz+3x7cD#T^7K0HE)P$k#CIqa zXZ`#Y8Pq3Kc{%+DReuHj?~wgsG2s+B*2sBefA-~e(lw3c3#cT21mQQVfehb8lYmOn zq?YUx^rsdPk?+Lf$9Eod;l2}NoqtHMKY<5(5-MOJn25^q1%<83bx+iODicemc9=n&X+j4bW+Nc9LMZ0-3)wWL zjhI2R$@QNSb*F0whjzR>oMR8tZ0F^0>$@d^d<7J(>H;i*))wr0Iw4VfV85WS^ ziekqzWY!Rj64;nOUa(xf5vyd|yDHPoo$a3VYU&OKL#Zl*-GK89<0~@NfM{(x@(_XI zwe3qHL2e;Jp}A|WqO(JVoH?yG7;0(5TQ=Ac_-Y)@>gSl?^0g zl$H+qO)=0C6kiG>Ro^apruK#AMSAi(x#_QDY^5no1KdlCXc@_|#Xbsk=pD67EK3z} z#JkQ^I0P5jg7}b|=-9inKDCI7xj)kT(jlNz9Xdiew~k`BmK83G_tsb?sIYsske}+M z-C5;Z^kX(&Ml(g2A0k;@(-wy)-^a(}-1U5YXOcBMc(SO;08@SZiUmyF`j_aKuqOHrmP)#Cs7*4A*2i zsbzo2|B%lLdwf|eW8cDCyu$S^8f`Me(c)3+5>;F^>u1?41k+@OpP5Oi^2vA@w-V`E zIRY(m?(x58l6in@g@T6M{4(h=4YjIl7za(NIDvgQZxEx9VncDsLhKQwAUM`AHwmYc zp#x#xVzzrs{_q|Q4VRct45Pw5cHHER__aXWr9cH2itWg>p>;E4!{963%-*4DjtEOZ z-bgPgf-XMwOa9^(N8^{wu#vcd#*RS2frlRYgkiK?nNUb=G9XkEVlYSjo?+s`2Q~M{ zpa8>c85WY00@a1*6YGF?JS1XB4~(M|eK2lj@!b=_WLRV5n|H-TPE@U4XJkTdv%z2& zMS_grS_){DwVK31}3XO~unkYPPB?3nw@7_n8c)}vd1GjP( zCRl_%F#H7Mf+1~RG(uC{RI>Cv7#PAFDFQOWwAE#UF6LJ__%XEdHB#0ZCuaqUi9aBb z`zne|v)M>2`<FD&*R&R(?jl5wL&Vc9!>k*P&EORJl_usConpEhJOZr6nd$+a>fS zcgi0apXiv;FjIk{;Z8t|>{DJ3Oiv_)`4Kd6eI{gb;RXyEm2UWER^B*lM4*CvCYWO3cJ{U zNsb2B6BE}rDUtO3vp`~dE_vs!S2|OX?MqKRBXJWMu3_LaGJG{=&|$8m-O8n{Xz#l| zAA-ia#hSAe{mORt(86^doM!!>mv2PDnVBYHo2iiVLu->a%Of+L!sB5}4o=RcE}^_r z+lMwWMronMpVB15f1 zK}halqdclilHA*rEBzU?#NOX~{Ormf0~c!b1x#xntUcJZD4qTvXFpflWhk!R6A`*% z#OrGbEEdOb-5nl)P4<@ayxTR-~FL3n@4)3%RLLdBfyY2FUcF3@>8zy(joUP>vgA)TnwH-y_y_@XFvI3 zaMJxhe_>2L@--MdD%!8nQJHk`wlVGqar-X9pROa$f~rA8yTQ?o!?nQU%+*AnpZZkF zi>`_6+j?Fj>N5&DiPxClH^O731-z$-qA#S737I;1+dDk7e=|aLG15l(5|Y}QqMn6S zupC<6h0%&=jrUj*S6V`Cw)GXLeLVR4^ek+2O#wKRkIg8$NuKCNa=DT5UuR z)`~=J1cbRA&0~Jje3V5$=I5L*hhJ+UL;Hn~m_ZYw0wS)r4m^L@J6Th`S$klgcA>%{ z_T!dvB2LDLeu0osM1;0+{GF%iw=|m4vPv&^B+MNQU8pA9^u4=UeH{E`dhO@f>nkq_ zvt(HANmbj@%vYGoA06EOc;gv6|FxDi0V0+Zc{xS}Ia8j`of1LR1^0p(8nW^I?r~;h z>Js{VY-WBEZj<+8mf6gnNga(6|m1RxA@3jz;&^iHdK{Ko3L9!%jUzk@C1(Tijj~!%z9>c8HW>{7u!uD5@->yhh zT0#)8TQe{<)#I)WSmoiOhT#d}+Ek_l%TVJo(p*Cl%YvCU1P%58fYa43>XV;BClAHm zlPB~g!ktqPG+gSF+LJqm8I3{%X^@3bb!q$(K_tNgM7n0>+*X62YwRhPh$GDy??uEEtq*{@_mBf>~{>)>}JdCqjP{;IEwX+|9mD-q%)x_l~C!{F@H`=X5as8YSw^g8IXYpT67R*tL`E8NRJ zkH(vS9!HK@Yvp$y4liQnkQr4wJ(}^_l?3 zw-r*6{*OMCWlen;uIth65m{05G}{F60IfKZ1sMiRa{cnMJ7b1FNBEVx?n3+ z;b5>%rw)E^tMB(6!mZrze9pRS+Y9?r_q@l09(}8&Cctn> zSA$63q$I?Ed=ym`b)BO2-kzyRLB=Ze(e=P^w9E3|$Gs%TPLr+)2>o~|wcrs~hAhJ0 zfF#7?fnjfmc5OKcahW<}Kf}lR*frtMUD}qB{u|mQ3NPT%me>In*gaVWf>eBP z3Hq7{?ANbHqFmTLQ3istc3BR*Ya)ra^e$e-cLTv7r(h+Iy+hFNU1f+cXb6|0mUF)c z7=no0@8OAug^Sz_qH*so4-?72K%ARIkDyxeNEHzpO#JSGJZ5fid}%LrjMaVF6us-U ztTX8`LZCn5a&q$)SFFu4;c{t!WZ61zU!SOuV6za1a1s#`cYGl3dum;;*vp7lcq_3R zi?b320vEp%2wmTP?D_)|kLyP(vNxX>A|gVWN2NJ6w^@d~=b46qFX2v`NGsKRV5fs< z*z__Xa^<>;*I>gPliub*v%0R8d zRjIg+^4tDT#|-+VP&Hc~IpNf(x5!R9U^o<9POHLxxF!9l941$P3Een z?fb?}i@@+s;n6m1(q^8nyWXUSGluauGui_HuWO-H$t#u0%TgEWbKRLAbR0CZFGG*}IT) zW8tHrWY74Eit8Udj<0ObCEjFMTsJ@7{YlyIEzV=rK$MbFp-nGB1^hf{|BI_*ewUJ5 zfOgmRUGZHW)VmQnbP{$}QoQ~l3mGM`Y|Tv91zBDzUv3tHSkL3CL%eIr>29VV>?n`o zZj~-WY+{QsweQz4rx2Bu7Tb5kyw&m)&g(X~p89-{;S)pGOfml_w+c5+{YN)Utjz)~ zVW9(4MpLn-e{0{uWcFyh;^+R{@Nj$c+Cs8L+f`oWj34tX1U)zLbzVZ&sHgcUG_z-! zUDTGg8`q`p^RG$LO45eWUS_ZodS094NK(7f<)e@hk4G{^Eq>&b&!d}{1+Z^|?a9`VR zS^bff>Z1%BNR(5v7*l<+vLZ0Ea)1qT4#}9CGgXNu#W(wEOTRof9<3I*m4Ow;@`CG* zH!U_sUiS5s)e*{lF5`{j5;f%DuU^rHy{Z9On`EZiZh)Cd2H6hA{Dn-S5XA-`bn3j@ z5%p;bkUS=qr5`{@+fXAxp{oE0Ahi{Jx<7G?SNYBqIS>?x}O!bkOzIl7QQp2|ma&nhB z9;olAT=4nWdl|yo@X5u7edp8nC!r~7G!wUs?|*W5QQ2)ir6oIS5W(y$CCByI8K4g# zMv1@DwMTXLr>krC+>zF>!=vqQ>sq`WMWT&3&&UgL7LKl8-dd-a<{1l9ANmnXZMJoD z_EGjR?v9`w%i9lODUSQcl61;yaJ_bcMPwtaqct5R; z1Texr(Bm(ZnPbVC2P~&dt(I0iO|V|DHL+pAlS4)?l0(g^?0pw>mR7d%x@Xz{NKAWRzg%Jc*R3QP*L zHz!cm#qA_jRblo9>2o>{of;44Msj0~u1wW}Ked+j zc->fwt5~UT3Z5SFia+8@WC+bdx`-;9B|6RuDqfx`&qVGD10~J=4%g~8Xw*ydL&F54Fu7C70Fv% zvP8>8>voY(UY5KhdlD&ri5Zy4K*FHWLCVKbtN;*rwQ1ZgMBML6ndqAHCWfD=7wqtf(@3;Q(6LRqa^@h&afM*T2Jl-um-l9XRbvohQbWHA?6NS z0=GJTw^ISp{MRlW>}yeDp^eRIA$^Ob00l@Gln^MwQ@Z$|G{jm0))i2CYH(%%N+`-x z%7&qUr@fwQbjA$G9}Mpq6DsBiS#<%pE$qW{pB1QTBDHcR(A-OJ7ddKnIZ)xl=G}MP zQj8G)W(OCXe?RIU%N}?6kTl)OkmPgzLlfdrsq~Q1&Cmpyc+EJ!YlNB5rr=m83sH5Q z*Mh)ev>k)Ho#8X7sZ%N7xv$?AzaH3>%{PA3PjYwXZJuBcB7t;o7N4?(DUG}DI{98j zp`HjLj%<7SyR5A2kIKukb^xVX5mXY5TD}edWyGR7U|n7UP*~h9NwReSaHJwi0h=xn zB{#@)c^-gWqB?^81 zKibp*KE26&05TnJKLg+}&%|m1I7}tJwTNvt{h-xUid6!XrbVF6j6p-ORtKwwp#7{; z0#w$s7TlF!UqAiNU{s+nn)YC0>pbv9rRW4m8w`!YNeLTDl8OZ-fEqCmrDm1rHV9|p zhFxM;1VU6OfmR2F$iLVLl9_7>>08Fj2g!o+1*0ds$qli;$G~_6u-D%ZcY`$nsWdz5 zD7O|>t$0OMk~TzA&%IRWy1*lwDTAu6&>6Kz^P1|sV@zff`9sY6H9ahHOv{YrhU224 zRinnTnpW~5h5e5^i|0J)xTNeCzBsliXq4H?sqlMStEZ@pDLn74_N8|$|C&@enR(S9 zuQAT77v+I*%=);ibpNcq=wesy*NFSxwqK@cI@hw({5MqiM*C7P&0Lba&TqpsZ=S*N zM7}>h)5d1^YUn$bwZDbxSY{Tc&01_L4{2GrpY`{krG5VrqvTa3bB(VN(vLNit`XXX zYj9d5wTvwlG34LOl2n<0XP{;+97>v2xn+UFtY9-eDyh45wfAYTfxSYH*d9~d(!89{ zx=%`YdaUoi?`5iJk@?S^5BnQfgsAZ0FaNzafHVe@8t45hl>ZlgvP)P%yLiWv z9p=l|nis>7r{=(Jv zI(IdQoPURhM|yZYKeD7^dfk3yw_+7^scmoDZ+~yt+Y`?G=Tyg<`d?jOJ0gEd;0UtK zTDUxLgS}nSIn9^GT=x@YV~Ej6`>ijkA!?lB(dn8_*YSJuc{pD=&U8iZg?e3#SHXRG%ce5Ca&^dh#s3F13!+L)K|Sxk#lkLFa-rY!{n#o^z$qANp~m|* z#|9t16Rf|$=uhiUsUSN2Df!oE6C&Z!q>u6YuDGnXtvpZ@MC@4=q}bV`bwNMvI`o86 zQTjrygoLU}iB8Q@LPCF-TVoGpQr>aTrS&h z*T@HNJ?L=RIJgf=@b8F#;#d-2mcGaOTLZtv@PB0jroi*fyFeZues|f}0PO;%LCLB~ zP`n!NhpTDjY_I=Pd;!#8e(`8htY+Kb^KjaxjnB7nv?ukn4QLIX%Z_8)6;PH=<xmyrBKi;yt$zOi5W{BX9pwu*# zw+74W0i=@$g!<&kTF`4YyPEHmE4Q&vw{=p7W0pH_Rz0&Us8MxnbKE~YPUS=M`?{hG zZbSnixIyS_FmMEI*aL|g_5c7h=-<$T7uA#E(dKh;z@IoEx8k|T?@QFH!bCAD19?Pz z6%!)XdeBMXzlPlUqjCI7*fOMohxL|UfJ8cDNv%?z2a<4*8|yv3%)7qa#0R-eWIwgO zb%X|oK9r3_94B`^7$|*H@pRWN`%>X0-%C3y*;)NV^N%BP)*46RO;P?WC1 zj34Ugbf@}uIn|#z<%t6$|KX^o;o{<%pPx4qP_qZ84juz;kSgf6cA zf$k5ZKSLvU;(;|U$xU3$`vWOT7n=f(h-9v}(fqs+k}dHe7RcMCxF$x^NKCC|$08V< z-$QR4)#%#)EJ(?|rSRR?VSjV3Qp?;*wxV364aUC4DpN)9e52`zbfT!F7R|LbCZ#|C$=bcCMJH6J$v25O6ja-TzvA^G`t7*z|R-!|%r zttZxR3*z+7Pp!=WTdrDp-ZoiTNhcc!NNz~zv;g{LbRftLDy6dvnY;Jiu*<3FfW9#o z($QqoH)aFGm;^#hs|z8Xh~VZ>DaW%r5)uFe9pNNSoHaguQcF?`1)+;5$crj#5qw{A z<-x&ubv*3w(8?|@u9PN`fIqq@kpTN~B9Tsea^@n(&2XS1g+P+KP@yDXs3Ujdw$NjS zW>6V*ctorXhl0|pRRZH(QM>zd&L*D=R4@BVy>`tlxnY4mxLnEYnG#m3D_xLj3t zC>=-qj&+Vr(vI4zn$GIOoHX(W%lT1O*powD3xmaIQIk8pPW%E|c3xgS1E7A3z^{Lf zh=^Dps9)%}_}rKIF%8WX6HwexDCjr$+}GFnV^QB@raf!9@h5m{QTZ8P&-ry^C&<w zxG;+$6C?!8FidxiFRrEOkyBU{9>g6}Ihm^Old@(op@TeKB$VXjzbn~RDrJQ*Dur&C zklEE3LYZD#M=;9I_HyJNk-q@C7B~4 znaSGt%l>KlV7V||gj{YN>q09xAS$M z0$mq*CmG#Z8;L|8O^-boF}UGtsk&_7( zyE{T=p6zm{530ur)wz@ODVfD)e&4)S9O6{3I3uWY(b{wKvovWln&@8N z&Aa16Lu@^T-Q$?T&x6ouRcJ}BXb*5>d7isvFp(h(7nl-)mHl}!eGzPR2-J+hGW^_! z!bp@+*e-8ccYP9X&(q~R&p=*{GRc+zabICJ{@@Gk)R3<@8P+M-?|*(k0zp=?0~X9- zocTgwPRk&pzOeG%je*T);3E4?kLF|=f0IOwFB9s_?muXY5&C{SGeX!QwcBMb!BKjx zrCrX&Pg_4Fqm4mLf$$+{+U&F0M56m)sEy^^M4XZdLsQMv3&Yi(2i;BAw<_k4FJ4AR zCQD<%sva>=dz6)H*<@r~V6)4j0GUCMCvf!p$t;XShQTJgep8KUjj%ZjG3R0dgjOD5 zMc63C%SZv@9w(2&8dPI1k1BRmhMc9I377Xf=Vs%ycv)dOkF|(}P-w-M>y&=`tMId zW9aGAW7p(z5DyaF-8TBr?~5h2*!{)z2kFgE$}yl90^9;KL-O)+ z!ua-BQMSXup~BJ&bcCNDgm4Cy*c2f9$F%EgO)o#(`J_p^ zdo#j}U#J>gOC?aU%R+3Lza(V!@vG3qb~kQWSz4soA2X;STAt)Hl>SsYms_qiaBmD( zR9PO7|9m9=A-rayZ*zm<`$I(+rQk*%eEpPAMtYH3KPkgm5Xm`is;QBe?lXxl;)4fw zTG>1|c~;lorT03#;h}Eu#Lv0Mc8|L_xWLo+LxE5Q<-LMgOJ6*fY!02yQq^?)CUQ|?#H(8?3>Q0|g!zTmMStt8TIeQQnd)_>Ku zZgsTA)7_6lHlQn4`o~HRszS5l8vu!K1&uE&D{%@pZ-)d0*Q0`cV8*aS>D6uajLt@s z1q_N5(kvQmu>sFabn14Aih~AuX2GIg^a=fZrB zFFrn|n2(zgg1h-cx4nHgkvimN>dGg^;g6adgsy>Zf$(xjK9y7e>@>k zeC{Xgu>09z=F^k^zmBhiN1=sIPP60g{^!x>zkr4vs6IUz{THuKk^MSHEpUqb_a7ZV zyZ*B;$X|Bd0N=RnW)S$F5vdawRWE1IU>Hf!@Ufwz_{qvPQeaPFF?<$+Oujlg8RjLa znEhm%Gm4RCl#xHk28)MK);EmtSeG$bJ>)U!x_^W-M5Rzs;7j13M=G1B#rYU%P{N}d z3CX!t_2pxK3x+}20+!h@zP(Mvk3v%35ca!;mHca7ab2Q^4O41)vyM)c@VAwXF{r<_*AL?{m#OHHp4{avqk6eLpu1#rV@9TvK@_b{ zL;_$JHq(?>9`Yys)R-|)M97_N%%ti|CY!AM&Sc&Jofe%IDFi_hK@vg>u2h5wNm8HO zPhQXl(FWm504G%^KTcl!MZ5oe;c*`Af9(VA#YrD0_wz64!%Y;{4`0p~kzC0CnDaJl zEJVnyU?MJlxOep(2FX*slSKND`?DK7H*Vm_+~7xc(}@qN4@_nHe0#|h`)W<90w!-s z*ms(_@s}@2kqRG$D=!VLX_Q6ZUFa3h2Sir)-Wk+h)B%9*r>w+6QjE#kY78SuzMWau zF>v1o8rb>HrihY@_RI>*yl0y_X8j@ev$=@+#|s25DYw0F3AE`$+(?a|5EbTgB~=NA=1a}+ ziC^B@p1Q@f`6-B>Ts(b!1w-qj8#&LOFj1In_fnhieJN%v&M!Sek0hnAIFUJtT6yOS z`)zB46RsTXxh(H}U+mgknTv1FcfPz{k~ZJ}2n zb;P(eZ?lB5-MFtRc6OfcX?>O>N7csb&av2he!fxZxGI(@MFrd3(yb@*ivI+mY)iRc z#rN#sVk{0%}*sZuQYIi;E!B-a$`^Am@KKnB9+Ex~0DMDecd0%%-XI z6q4D$H==)7+3#=qRX>hqULp4tag`ONT8>N_!;{9O_di>bMRy8viQ1W6Zsp?qrOz#f z(kaN0ePqz8GNtVb8Az!f&*VaQ6nbX#Yd^WEnrdYix|x4%~w{ zBZv-Mz&*F(YQ4KZ+z@ziF#qfQlTDKO_3aXGO8P?crqIU+F~Tmb9%?Oy z)#~gL_44g8v90fXj0Ubsfma=|7ZZW>b%XC70p1%=S>^As*T4}DQxY#Dm#$s2@#Q2N9;3ZuR{?yWX_&-vE78OZaAd5&UuAxq|# zy*cg8nCcRk3avD>nBvr=v|a^DR2{8Z*L6i2DD{JF?i+|V?T_*=r7bLp{zdSncJ zqGXL?hYe9k>?BLbiE3YMmyrut_)NZaKRt-v3+$hn6O{eCc&1piFfOe!96|ADFnl=$ z92Z9IXUFEi7;a1YKD)}S>0O{Zk<42pq|!?>ZnLy6F>W;{KOQWK86I}A&bH8+5rWBj zBX4QP!OTMXZgJnn2CN3+-dkb`D_vAjs+MkD%Rse6%}8*Zq==KZkqvX;vnXr}hArNm z-f+(}1A97?DUOz&twDRR7Czr5fL3$TZ{dSDpw@?QMQ3-l!7|n1l&Fnl2Tl9 zqjJNY38F?6AW!tHmb?@N5fKF;{5$xN%cHd?Jl{8Q zm>Wq5+bHQ%*f@3@+T4a!0|>(>Pl#Fd6K4wN^6qPaVFe6Ds{Nxb+HOK8FE0abNC5rTvBSwvN;_1$(^611&6TWxg_JN; z*+%k7-^vL_{+r2%6df-qLm4hKK^zzTY9q?T7=GSlEox;Kt4v20_=Fs~RvJvj^zZ{~ zZ}4rMVRvffBqmux244bEADTwI$6oJ5{!In<^IzvBj%Uj5fEIu>d&gJK@m%sbTDFMfojh=a)*~CS> zq(E>P8*eRYgV0f#WZlA;Pdao<>J5kOXZH8cQiV#TTHhIcyQxEqCKRJRG1r~uEKc>l z6w}ht@WSh~0Lo7jQfsI}Zv_nBqAYuN$2+fmx46~IEcdZaMw#(!VWmKx5X&QRfawxS z9du>Iqhx4<;T?4OMM{;gGq$89U)V($$zebmA?TJS>6FpI!JO;(yq#Ap6UBRM&S*3$ zMoPqZPm_w9Hfy?TT#ZfN`-ezeLJO8nT|@nsxMpsD%)oyB5P@IU;i=MLDo%7@uz5b&56QkK+Q;JGELk8OXJ2QlqXHE9UDihKr}I&4Kf7sI7xDsm)xcVQed{ z3m*uc{&0&Xcrv;#N=fh@mynN~ybT4x5Bm;+w!tFA6ewLtc4O9?>oOKp=|`SjPWM7X zug`>BgU}$Ds*Tu>ws|rJWXO#Um>N7Z6yJ&o9K>L)GWWbur?a){$6$TdmJcV0+o5GLcqUrw83iP zgzEbDwj8oOBQLlT*4Fgi;)4%nA$tegmoE%-Ndx_|cZ|QriK1ut`&$#xCCh=gByO&+ zGBLhSG{D;8|6cT$1fjfO2)O7$EX+^@NgB|5HmofSZR8(lvd%R~my2g1>zo~}D4)86 zM(Y(qgGTKEeWH2MdVvK$Z4YP#+{X`B80n7>5*}ESRbe7vNF=0yC1V(jv=FmqR$8J` z@tiJ97|`}Yqei2y#eIy1hKPhKL`cFBTlAT%sY%9LE@fhUVmr%vKxuIOPExh_ z)wyS}U+pzREv}n4g~RU_6IkW$!X0Q~INj*>Jv}`_dwMSBm*JnBYmjdHb-D!pSj9#7 z`h&CcGv|&&K=ZmY_c_B(`}^nz^w@Wr!POiGA3;lK=LWyP zi+&-{B_y!S6nZMnncSSG&0L#jI!Iue9Kz7<=TAV;BZ}-sjT4Q4KIu?{N#s&KocM>f zp+70-hDX)FCpyiUAxNB*&|OvL6??Z``OOwL_Lpj*4g-WpvR3a2VPV{QX#%Kx^$|!I zTd%t{*t&9&G+@lJU*w@S%P7mrg$Pd{x5%i~jVyz)!$ep+d`a5aJ3I{ahS>Dj*NHdD z4=G=1l%(d|qLMPeeoyfuuv=%|Nht&T7eD{>7pOP>;$Hz}E$IVt<^SCF&woDF3+_rq zf&V};K1d;CUZjg``M7p~{KsuC^kd~D0 zM!J#imTr))@7|zKoO9myJ>PXb|6#N5SarwRYt5SZ%}jN}r+u*E?ys7;zo_>9RM-6v zC;t~69wMMxEA3@dp7Oqb@Xhz%pw|x@(1W@S#3$x1-k}7S^K|tv_Mf&LHB>!=@U|sl zZpq8@2DeJ+`Sl_t)KQyNkZ-Wz_`++VfARE{`@GW=VMEZ2UD0H%Q;mmgGmpe$x3$_t z?WuZDP(N3sbOHoi8x{2P(AO=GTQ|j#bunIcUfAW&xPN$&Q%(Y^KxQ z-hHl~C+wg7Jkc^6XhDPTvG=YV(iHzHd30gZ2{JKvT|Vm^Z+ks=WxJ63>8F8|d;t;s z4Hm0cIcH_DVYbe~nStg2;QsF)3O^M;QZ#oY%{CgiBq@l#RNHkrNWI5@Wv2h9eGxPb z3iLolGz^4yEDq=2?2OZJYVQ;q5{{gH zVn%>Q{pW##AR6KkCl8{DAwCBQb}ItDl6`Xtnvs8^*!O+~9xtnn5m6@bS(HJkI!&xJMU-Tz2~8q+qfQfr zF2eW%wf(}w3+<@IALQs;VVCnQNDRv6Q9ULlHqwr(E_Xn5GV$ljM3>Dl&#lnq08dr7 zGv2CbWvI|oNj^tVwWuY}xU}8t=O?P{CO3mtyWu+Ti4ht$F+D#&B2&B}`lJm0NkRKP zj)-r)pf9MbI1g>*qyJ&I7!%4S`i4zZpA#!|>c9K^k@>#hU(1HQjWSSWHc;i)z6{q( zL4l%*cAvML5!7*+TSari?^+Z?^V7p+`0#@q{Qp;aIQQZH?4M~2AAmC+Qlu;r5?91! zpNu*=_sUR`Z|TeC-=&zhP9Gji{fksPFYk+OU*AUuA>TYl-(X*D#es|(oZ0Kkle6Bq zS$0;ytskwZC|(%Q?*ZcvGkirw(R)V><;rGQcwo;AVkL?>IpZMcYRO`{3I6JZ0UjD< zfmKFjw}Qs+{jlb4NU3t>jW?+f%Z$s6idv}OGF9|>oZS12P`(k&XyV5OaFAI?JLiSZ zt2Xp+j8*=u-fX7P^V}VcQl~vV6eL*8$>+(&Jc*Wm`GvG*h z4c1_c#L(kSFXy7{My=0DIOWI{5<6s!WTRr*wELW?z)RcGUh_Qf8NLk4jYW8;^PVWL z&fQmYKJlEM!9AbV<}Y*Iqr#6zs$A??hh2!F zs@`BrKVy9Jgyzi?M&ksNw4iKJkiE8Z9trU)yaja@LkK&0^aT{{ddqBf5|%oms@Amw zYVYNrI%VIfy>D!)F+J0iVHJ0&z4uYvo?bsWgHPr4AEcl=XMEXs-AGME;GjUzsIL4- z&1G2a+ri_07w9CXNZPklqY7Z(?S17td6ASDnu zsOG2+N2Y`F_4Ni0II6)ZPknuT7MFoC)yT-m;FRV2lyGEZ1mBRr#pU}7fRz8OYM?f7 zqkpOTp;2FOqkpOTSEI<_M*mXvuSPjI-tRKkGMWBGmQ(V#c@Dsy{f*jwubshLvERi) z(E`a>A_+Bekoku9D4F5gmu4*F(oy)}PHw&OtuM}W;GdrC`yST#yLk~FJc<7glmKY> z!Jod1@FFj}V)}0!hf5t7%=xK{RM#<(N%eE|Zr0CFV^d!ei0tTRCs!Upz8#rdgtxX_ zz0R*x!RSJ=cN0}09x8oiBO3gPYB>CJ??+RFDhSy`>{ji09AVVw?>iM=Rl0ONs+tFR z*dtekqY}fAyOPTBzwv&QdC4PQuL5yd#AbHmrRRG9AHXARejwxua9*izV+F^p=& z*#z02)^4cNAucACyWn5DBv(!dj-a6^Z)D1eD9=@946acoBLWTpp0B8FzY=F5_#nUA zv^J^x^P8rwKz4SO*K4I}&Q2vER6joh88GJ|5sxkt`Am{LmQ0e?;^I!zY@b)&5qPAE z*x=6}1U^IqT+;nMDT;>n=?k!qRS40OZqtD95aWI)VR&>Z($6X==SjHvnwUgD+A5g$ zCP~4z4e~r#_rxCFWsYL~hn;IEge?D~miZV>+`>N3c#&DpJ(%W0O0vJUsvUu2wJu}4g3KOvaz4qJT(shLv=HF5 zrlzyCQuo6H^Dex(j*!SnpLlZRls83+IAy;k>D>A5@KD~Zf#08UcK+&i;^OLp?*`he zpzuh_PW%lYZ3=r0=XlK9vzp9jK8>}^sbOP6_&evbU*?~L>+gLH$KrR3o6X!jBYmm# zWkZXmMRvMb+XKf8s&4dcv_@i0X;Kd2ooSHI)RZ~K=9W#?;fRvr(}Dvn_01Stlq#o&CQs;hH040L$4%{n^K&FNAzg*2af9a?Y0+&$#EgXpdK zhUJ7sG^HTb(pi22JGt&CoM(LFh)M#c1cLUuj-21$lA>4krSG27KU5M`iD;(KVm#%FAuZ|n2t z3TE~^Z^l=w>gM(j4mq@tk?-EOELm4;@zE1!&?D*gum2=Tt3K3PD&*{gw$l>CaDWDX_Au`;)b?Ly*uoleY4 zo*wLt27N$;>L(-!QTa5SVTB9`EmLQ9YF^ot^0s7}Y-YF8&7*O_tortDaP)3LeDB!( zPWtaj_W^$P z#QwD-m)YIRdD{%+^wNbolcA!L^3tM$va;&% zh}!C!vRZ)B>ZD(qi0hYDHukhswsdsN@Xn33_kSJ(s9?GxjdxN(H{1u8BftD4qMMz- zCyXW%kpVG25Q0MpwOqj~&ojQ3zK5k0fuR{)!5hPm6i&jdo?RrhfuvLyT~Yio1c(w& z2=#-&P$#ZU5PiXPe0kgrlgEXNI^Rxt`NHk(#Z*nV$rM2G+cCKDxawv&dW&CG-upF# zJF1GwJyTUxRl05pS)D#(vr8l{Gbx?iVRPfHc;xF)J$o}#Fuv_jGq*RbD0s+ub88Vm z88@(I>wG=$#QphuNoiofrm%>JJ(+Rt%QxelDypiP`FT>Yt#uS{_4E^Zz%;Nb_Dl?0 zs(sS=1(u#3eNS&sS9cpYK{vLsm+|HmvLs|BoFI!3S{G~8>p@OmSedCZGtb<-9X47! zO@r0qzMk&>*WY~E_V6pr$LbvS2snksW#-U*&V9N)&(p)vAwhDeex#&Tx4z*FSCgc` zBWRRAsgD=~y1P~u*DhBKjuTE*HQ^M+C-{9;npdSa7U>3uadNwsbbA(-mW4$+CV7ob z^~$+Q`Ll==R;+R@%xD+SFolnL`B}Z?p+UgI&L+7=N?pHZ!6+v}fx&RXw2zLCRo&XL zIv#zl;-0>Ddt({Z$3sAa$iu_KODkL+8tEzdp5I;FAJ_c`BoFZoK}`TPFHUzQyTidZ zunFf84n965@4Q90{`Kta>`d>hOeoE2Nb!N{*OnHYp+Z$Lsq3!*b*RVJBIEIlai)c( zMCys~)0EAd_#FrU?>Vpw#BxXmTo}nx>UV|KP>w6TPF#E841p$8Whf!aRgq3q);i*p z){}++vjyk9Gqc*gs|AWVCwwIT!Amdg!a0QSa99Eg^vFN6zk5t=A#Kv4T`7!f@p$9C7&(nW4+QqLMvb z{%BU4vaY(KzP@qFd`wq&o?1Cq#gXmv(EvFyb^eE_kj@`1Hffv$;ijhNmhSXycmOf+ z*GJXXRm?_y-1XF+-}l16*4NN&U<8PJ>8q^rR&rJWAuolBwzjrqc#IF=c>^0WI%jx% zaBZY*a)kTNPZDr|azbDefPYs~?jSGp$UAZoS9(Pj*^ZtDfEW}q8`;t|rQz4GKGwU3Qg>_9e zVda%IRpp0TT9kX;I@yXgZUE6_(Q!#Pks%LS)y?jl{4jV69q^{<#at{vQE@|2pBxj~ zg=V_1+!A~9L)_{rSoqI8vo1t$Zf-7Bq-l4e3l!GYj!t-o9pJHyjSEyul*aN^ziJ&T z|3GR7<{)xkL?~D?@NJQh7G%DLM;Jz+IHbU|{(uT;?FX2L1R=8ULJK2uoUMd29433; zt&F4{3W_iCg$i6)pLOF*uH1$rH!W?P60P4RFI?EU>Dufz9#37lm{cX$9hZ$@9G}rTF5`}OLd!rqljaL|*+EI*9j}CTY6ifmAi24?`#S)!v{=K z3{)A#Sl%l=fb|nYPK(^WMET?P33utU+8?N9u$1_qvT%-d@u0mVXhh@lD0olBx5>vc zls+IKR9_YdK4_>Ga#UeWiDpckOl;|8DXJwB66hs3A#^wlRmy zEg|F*iMea)D=8|Ld;^g7+q4{8*kUkmv*{1TJNYnN@$n~`F_)E0-XzM#O_WUSoQ_w{ z6m+ax)XrH}X%@`U(c3&m!NCALuyQ0>vQSXaQ$}^K{p2cVoc#D%;(W5})5iJvZ6h7K zS;^EkFphf84ZG8-3&Br(HGqO#{`94)1k6IS38gEe^g#-jWK0iFS2ILi=ocr28H}>`q z=*7o&a&vPQJ&l~pH!PTG?_{@m`fapDXH@1Y{;T@B;VP5Cys1U66Jk=0?P~s4!>J*4 zmzq9iX512!iR<`s;~`H3?5V;drb$BsL&LQ)mn@(f+LCYi9b1# z7cWC+P!X(4tS9uA^$noajfUSp!%VaY!>FQwCqbO zuKD)!vZo8g{on=Un@k`C9tm$!5Sbv7JUL(wVjvMfVE&o^a>nIz4+@gTsFwpR7gw;U zX+m@oGLpVX5IV)=F8ej_ep=1kzUR%rj7$BZyDl-pyKnOVcS?tS70|x&^X*brP5rGO zJ$E7!5*jc66D%CGCtw;$K2V{}-Bx<3JTg42tgI^KG(1k8Cly1jTv3S)%-6E>RE-Vw zHA-K!3CSK9Wz#R+U#+Y$@@wi8UF@ts3%$qL#{Sx@nycS#W~)Xg6W&qV*;$Z3H0u5C z(|$KYKKqwgH?cGxSZGpY=i+gr?ahRD&Vv#(aX(^W?FbeLTv9AG8Ks9(Bt00lVwQt97vSGcZx*aXs{p&etE0;=_`5NJ)X0Q3u1?} zhO?rYdv=Cb@F&7h*p_9#`CJ`GmWvB9PTqZ<2le!jxG zr9mfAewE>zf{d)(?2PQ3oUetlTCo*`4h{}ZPyzjWM?aQ0c?Q(TFyeaO$HWF~*z4&n zEiEmtWPTyncO%RtT6j}1`|;z)h@9MQ$sQ-So6ELg?M+S>&K~>dG9qef4SpQ|NMJh1 z@&{br5Q?fOag~odAz)A!D}ecfx~r2aHRl&?}{;5|> za2p|>F|^Uzn?|*zq07(D>zrdW)b+A9{Yy?(Mpkxq{-Be_M_O$Q3k&lzpM2PC^w`gY zqO7#CQZnv-V-?*P&twwDHyx>)br)&Xyj)96$Ex+vueHo6whyd}t&0y&SO?k}0XAEa zVl5e?*;G_W#GcjJbuJDL~o*#ODf0WJw3|UcC{(FvHWUo;1^&td*^aFn~;=vBx38t4dL+WbK!z!&Fr2N*YJyZymyX8!06itPqq3A z#Bt;ef`Vh^V1@YZtPdm3>#2y694P~fDDQ0(knFPeuJB+KLFuPYx4Wb$VQBp$B4Z%5 zJ+>ul_c%hotcO|x-t=JGJE!+%fKgflGcgKh*`q1WP&?bQR}992bolJXORWLO1gQ%0 zJXA!0D*Ut>nWi;}B?rzAqYW7IVQ=s*`O8l324k;A4+DUi{;r9@rV}ul``K|MM&LDg zyu+@2(>6F$IlFs1m%L(A|2f%r!Rk!G+S=M(j)!ML(1{Bt18HFOCl@bKsN6GpIXb4N z*(3geL0jsY`S69czd7^$p2Y%fFEGzugdnakim-y#PLsVaO|$1th0N0oiHQmo@WqJG zHz?^D)&-|IGgGPED~8ttdx!aKq0<$nQ;zu9Q>op(dhsz)3EzBS^|H-}^2PcS*)1u7 z$-)v1;AO~hU*j^~vvCHP-;(WM5#!4YN6YYoU}f03bfN55j{#$zY$L0s@`TKpX#KMMQ=JEggCMv~TPEwl&4|d%D~yg8|7Y z!GS>=V7|mYeTP;>?)jE>wo>}u^642=*|fTM;fa2G2o3#sLGrdao7;Z&zFPI16}wwR z-Tu|$IPKDbv*tW8NoctL`Xpf+X^_$~ZA- zS)S*(7ZT%Lc~$f0#*}(R57*>FsTljwZI!Re6{cfV2+>)pt})UK^u<{D-_UViIXk<2 z+KnqiwzLzIdBSYCD8cQJyaY_Blg1|7#93xO5A&(%_WdXq$gms&Nd*FZfQR!;>0_dw zSpSB|vEo7%fNPWNY0p!X|E6}+lA>|0a^338Vyg{RZr52| zLt|TXbP*r+AH$V?ZMRfALSYg8%Q?*)g?yYRrWL`efCxxwn{zgtp6uznp?SMBSBBX= zUEws0-Zjy-c6+kr<>gDpk5P7GkDtdXD!m*Y8hZJ1WMqt13m9(nm2=Ik-R3rf)FX&= zbj1}`*W{YWTXI-?X)d`0k|A4A{Xr!-<+eSojK0q}YvQN+qjIdL>co)=IILIaKN_Py zD(WFU9+m{lZ@??tpz(L&sGfDpy4%~Rf~jyouLFU2NClCQ8mt~8H?M>PKYIR&Com1T zdY$70dYwnGSxcb+`}<>e1D*u`oXkzg%RdJ?jp%NxMm_*8aS`4aJ^DG*%OhKUO-Sc2 z+4K5qCas~tA4IKnc4vEbKbQ&<$s|_QG37!lqwSTwa4Wm_&EnBSC47O`?bN%@{jm#Nm({NuEsDRa-s;Rs?$2S^P~` zF2w7XZk$9#MZ0c9MPGKV_|^=qzU{l+E_^$1Cw^3O(DYNjmJMZ;YPgH06{73MwGo*0 z-GQlozj5M(R+p30HJ_xV_A>X;wHTiHT#FCZHlpecwJHhuQ!Jar`6ZIlwwv?tLI3uai~S*i~5K}an)O}@K!N!YqnhR(@g zpnXe-b^AH?IFr|5>A)(-{;i$&56k!>5=g-3?oJ@|>KkRqbW6O*F51N^mqB?858VeX zUuIrGGfiM(?OuF3J&Id*<-|!@;>P(Irc`n)5=G><^lpRi3X#nsmz3fy)Ns|#pK1~; zN3Hw1$ddj+C)ImQxu(CIT>q2)ul;JbH1f4=Pq>`16uESj+$t3C%U#GMKA?#7SRU{m4-^MGmIpWa;6@(s z9uIh!w_H;*_f>)e8gH2ToirDJ-zZRg^v=(jVV*!9W4$%LIY8v-@`U+;-L;+{`b8~$;3W|b+GKo$CiV{jL>lSnC zG2}{kJjVr^>5J(;T=8ss@d|+Rmhjzp&6;2;vTC}Wx0Y*UR8MoGEH`7|;i;b18LIB- z2g4O}ZslxXVUp26>r#BUs2nV6)h2!+1kft`RN|_dmiZYxe!#~O(Wnx@EiTCDhV)J5sFI550 zl%tZDCU(*pfz9n7d>{B=uCH(kHWLlttK7-}M(aNCK^+sdAl5gxj2CX%4@m&al?236 z03sg%lgh7f2|yk&3kUFNKprp)7n&zT4OcO4L*>GLut>F4XSvX-*vd@u{-5Rez%dF-w<9LYF@eg%aK#swu2H>DZR@UyG@B6wFlXOp(jd3`nB(GLouWuA} z9`o$tXlUrpNDHoI>@I`Sm_W!3QG=&1(A~Tk!T=cknadz6B1b{Qu%O7XE><~JL6>Nc zw>{M0JX9hjTqULFe$4plaUJp;heb+CYBGPrbL?&Lij0isBhq><><+wURt`26Ms~Kz z=~<_WqW!zOyIZ2HwlRU~liEYGb>&sHfJY*`*U5E~vb#zS)XEb&3nmTkj3BfRKOjB7 zhI{mezF9T1?1*8I;YlCM&l=6A$RVj{vCshls53K+8`qZCo95 z9v)raR{W7I5wVVrj+45V%)_Tlk!9$^kxIuH7#OjYqZlK{_L#Ue7#L;q)LdqW%A+bl zFIC4?CIG2bH<_mN3vPUAX>P4B^~W&l2GM#Qu_AB~J1o223@|jLQhHAE!swCv7}9_e zI#;KODqt|^8I0|lMS{@dIb&3_Yi(_(eTNENzUNWQ2#qAIC@kkVy;Id%I&WZQ?ChB1 znG7adwK;5;Mlzb6S?nuV`)%JG$xx+Bk9oVG^z$6w=`HdccuOE`+!k7GA_UCr<#|~P z$ZO@qQA414nAH7rCmuzY1iO@d_<8x6 zZ;aO0*K&AG2Gy=zJ&THX`FE~Z8vR$k?OpS$jT~Js$k*LAqNHJW>K*Smaua87ck87I zZGFsllEW*tT^FS_>nEh7C*pAl${J*xc-+aDXoNIXwNf?sDgOI=#~EQ@UDz1mGjQRs zud@Z{^2V6n!+&`jlh>>O2ovl=Sk_tM)HN2Co*#h4FGqW)XOQV%3?b`ILa=FyG#yOy z;Vl)LfT*L<}@gk^q27l6PnO^y^JR0I(5k?HTuA3kNaJ4G0gwx3TidvhhX z*D1Rf{LqTMjx=S1Gj7Mu`!Oe%Ug3|DNQ;i|uqAwZe8r4{myxAqv!s~9ZAnf^^AvA2 z_k$V5dbrq-azFLnx-%On)|Nu9HHfJPbKfz$1wM2vMWC&TXVX$CEIEbM>BR;>@Ai6bM?thVW^bbeqrQ&hav;Vw}=FT%>S~9zdwVn zefubOX6xdl1pj?qa4lAV0b!Q1~NI^nP=dXl9jr;yG|>;P*d~ zr`mzQ{X5|vIJn z#WOwcl>93vk;Z(YdgJs(WA=(w;&$eJfDMVi-AEJwU;}PVddunlN+mx0anrzcgHynp zxZ0x=U!+YkpW7zbz4o|+pM+f2D|7byqa)vsOK|J-e!ewi=dMiBx*i6Q_32Y5`q>ScSQr zGc18U)I0~(vT#P0YR38(Gfc&F0hkm(vPK3>A;Mb(HXVJq27pHWyDt0H<+Vq6H_lk; zlsTK%MBh*T?Q0LOo15!>_PhFp!&_eZvbWo=$wevKuJcs|o36J_bG6Ht_54O&%}WPP zR|7Z*VF%Y*p6n|vD~IRTo|H?EA6FWQD;gjmYiMjkcbjf+?{X<(kH=P=jsv86Hp((i zkhf={A@!refwiKNQPI(nO{LP&(b29l22*7rQo1Lhyds7*2wiQRsjQ?FfK-(MA}*eH z6JKy`zEr&faX5R!3Ht`uNh?9Zz5xV}fu8C{rG^;aK%{W?&{qmSkcK=JzkE>l2SxgU zl7QdDe;P{yHUyx;eE`^yy@Wpj5ld*c&yiPmLQ=}-gt+A7L(e;=-_yt<4Qr*U`k8?i7v2D8KK8J)F(fH$WWY`Qv~MrAWfBbHV8pDVW=z#3(@D&xJC zMCLmt zX*lDDt?AI15*P?KGOVmB*6wKRMeTfB^`>ZS`&Kv3Ha$D;>D+F&q@<*%m}4$C<}jh> z;Oh9cBR4uL7L%>^URzR9Qi`Wq(+ee*%rAzO&xGBd#q|ABeucON$Ptv;Z;oV5ou8}s ze=;^$W9$cm$+D6&{QHlSIINd4KI3S(c5WmbJV5TCqaTn3c$bEt)Ot#VxVAs^apWZA zosP^_JqR5l%$}2TqwJIgy#0-8#b;_a>vMOHs_R;K&u*HQcI0acdflux1mst@WpA2< z!~EscOX{jZZm(@R2&@(X_00|s7t3Eq80B+ z$F#aVQPk4;v$3E_*kX9vqt2_&tbE3zN>R~mA}%u;g)|0nHUzs0IjFmTz!Eqe5Jxm)&9wfWny`SPN%{3n#VrJ06U@e)izTB zGE3QO0Z9KIOz(qy_+r}c&HzAX8G+(z`H#8T-?tT{po^+bzksR!Hi;Y>z|f$>A<+ca z1NU$CiI!OW-MLWiI{T^}=k>fYCHLo{K_`si!1qBxvPN#^$;+DnFtTAiIqUXnxW1`r zPq*uK_6FTgY+Zd5rQ#&zgCMMp^LIp+E>tS2(&JRZ2C>-HFO8=?!}H@kjnmWnVdvR( z^_6m;x!m3t(2aK3*Pb5XXiMBysj}w-LvUUFA49NhBYrKyMfX1R_0B2`40`vp2A33` zhK7c+iKVh;X<0>eWm$1mb#-;U;gD3wOa-+ion_%ZeN4>|jYuH?T)FWOf@7zoT6v9X z(@CJdt7X*0xE;o;Ry&>Gy06nfsi{>eMPAy=@Dmvo(g)56&|rqG2s&ifOTO4TEk9v3 z-rS_l%Xb?#$v4Z30$9$xrm;6JZ%C&;$1Y6F8`N(D{Xfwhk_0-O+mjqG<7)zM|8 zk&K)#>AAU*p$)7S4obk_KweZ`i4~ha35zNj)sC+5bb#e}&>qRjKUD|+0cZ6ekqHkN zOA^woolhvOd4SY^Fr|q>f*7=d!gD+bf^;cH0na6ms#n2x3e8ruf4Xz&q0V+BcV)}F zw{KNKK|y^iXQ-nuXJ~{%Sm`UT?GI?cn5N2X4&5!2I1M+4*;VAgAd#kb_gX@eEFb(- z5@<-Qu}z~OWd3KQBHV#G0n!;r2q-An`$Fv5qak5n3Re%ue=q&ib?(*tSHFNC6;4KF zQ+twf1&J+j@kt4v;t~^6J9LGY4iyx>fB!zBqOmlUqWi|=t*)jKpe3;e&1-AV%y6(pXmJz{>OyGi0Kaivnm_w0-qXJl* z$7lgW{RlSxa)EmOB7u4z$q4j5{x`-w)Gz)!BOq#4;)%-D|I+XdFe>`*EcC>JgITfD z)9+)!-rMHoV?G&&6ev%gRbtx$xTGnLf2`w zJF9oz>`P@893jmr_^VIIHt@%9YsbQ$wH2>+-=Oyd)b)ziG_4W0Y z4e~l>R@+l1TVT~@JA8B;a=1a6y=F{BMMcSj09MWK|5DAHfoxVmAXpMhhTYcGgEn}b z2N)FtbNoa1oO`#ImV@J%6xjoy%92*UBlCeELZMm@7xPYw*ii?i;#~cPW$7F#B?M(sApbD6@_{pj56(Cq zZz(O$OQ}9tu(xaHg-_*!>4PFZxnmw{MLE2?y1IK|s2A@y_HW{O7054uN9r1_($qUk zyi*AD6X@2s_G|uu8^!)<|>%k zb^&E|WR(Cg2o#gl1J@)6J>N4Dpz|%BRxbVtvEIEnu~9G16+{=_m1e|=T*_Hs^Y`l=71sCImQYk7KnZB^_R2^g;10feulhlPFy1fNIy zbVzSv+g1K9W$*!e9#+0;k=LVuFS!sI#0CwALxUR#0rFb` zNxU)HCh|knm-f~ZNiepHXS|2A1|eBI1u5u!P^S-~%JB2P$MHV}Nst7L`~Z)eFobt( zW+mz&T{f%dC z4fA_WBN+BM8wWfrEYUjjNQ8t!J9y;|Dp&xR%fTU>mdv$`dF;8#%0}+|M zt)9GEQvibBZ6B6c-KI0t`$Fs2n`UcLz6T})ywQMvS{MFn01hiWf(SDQfRn*U?-$>@ z+6*?svgF)Ub+A&vZq@0l<<@)Ij4>S3g5K)XyGuzRt;YSlO*-BxP!RY9890kF2vPpqcf^o%oKPX~aPx-K{#>seUV zfTU)W>X;@*VDeVL8@*3J0R`+I1CHnu82E%l*>%Z}M?6FA;&MuqzwM#PO}z4x^uVTS zJwuPXmcz4`;hg+Z(QEsRc+5k^Q);@`%(3Vw=5V3%6%e)WSMWZle~HxxGJQw^M+8Lj z1_A>j2|zr=41{e4c7V`a7HYD zTz`jv3QV>d4ur!o5D>w;auDD#tJW3DgOV~g&trcI_A5M?Ty7gG0AfT`tU#S7!NRb{ zgk#sQEYMTv;LVWP#{b}N~G{1gX!yWzSkE_Dtq&J3n`R?pL-Fb;LkhU1<4>q zps|Xj?cIf!=C;=y5z&rzl3~%uaNb~p7gZ4YWjW`XIWO{o@)qmR#~8fW#M%3 z%kJckBiRgv|83{B7ZK01b%&pqvjz3KRaoy)&~Pw@&z37c^YBRA>~~^;2ZNEVF=t&n z&Kv$7CLyvH**F+zPe%MVI~{5PL}7qh0UGJV_R7=nity5i!lKgRq7Nk{QL%AV6_sUG zRaIN#T8;*9X@O-uxAu%Ars^#Mx0{Q`<2kj_9Kv`By^iz1cM$kakf7I(sotl?j-6&g zBXvB;D~O#3?m%GN+rb780}RX|Oytd>C;_mR0)!X>f~VymTtcOOX6-{*)ZYdm-V^hr zoy4c1tx_C%0Yn@I!r^?%N!Uek+u{pfd$YT~x9dhlTosox@ifh4b+Y;kW3#YSTw=|? z2ShK84zd;&5f^u=_p%q4@%Zr~Ryl#W&0nmz@5gRbNC*U#TV#e0i-(-G*LCyaFXDTD z9C0RfX`U$DAcwN>@X+w^OLNvy#w4I58Ew?r?h6YmUZ6Ns%=5aQ?3DN8U*d0}AmN03 z6BHJfDbVK%PB1VY%8-7Y8q&`ll6mHYT@^Hv-8ed?nhzmW;rc^YH&1JGKBJ#9grov2 z7b;<`m@FF+mh{bb)j&=HY=2Bl*Xt(6#z!Y6#@+I6LGm1n5KzrNk4OM30pX?tWR4ZY z3)EH?TLvI{`9M<)?&N-!Z>dfab-W{N@dx7eCV)cEJ9~r6V`}?G;;K zV?)-+&h&Rh3K+xbG{UzkvaH(Lj4oQx^Byd!-*l z@h%i6p&0eE&h@<&&rrz#L}vmB^km5`8_buW>&f>3VB+$7WEKfV|I3olU+76xeQyz0 zI1+EI?Y~+7d7PykUV}m7-!`sNp@}Ph@)FnGww@6uVR{j{9f~)TEI}GRSwP?;zG(cZ z7k?`JBjWt=|8GJz)E5yF5_0K8OF3a(g`%BPZs7kAi0}4Xny)^yli&bRYG%J^;m3oN z_0Yp*r6xD~`RgyiCOxm7zs^d^A@%q15ebIVzmC{Hbbhf*e=>UKR=%aIJ*zXn=tk7j z2ji5FP4nvF`~&Rl0?Q+>40#a5k+rjsAYv>&ecY_KG79nP<>^fFlWY8iJe2p%3;WeP zMATp5Qn@?c@Q0AwiqM?V@56&pt$Kb#zHcNI1Hcr6s`}4X}NVsV&Y6|BbM3Xk3FIn>Ysy?x_#*cj+(VO3u{ca`y^GsZ^fM0lzdM0HHee zwX(P&p}xJUR^G|V$;HJZ^HAd}3_M_u^~DgGdY4uL?n(GVA5HH5bZ-m!9b;Gc1H0&j zSgfESE~M0hO%@`dMo+^zHa;RU+)xcn^9^o%*go}o4!75-FMj5=6CL3M z2n8r8X7*Jl=d0vO*LFo$`%CT5&R?1RV(kHA?H|*QmD+Ow6J=Ly#Hzh-&!n7g`zrx6 z-dRg_e2;;3JiYO|fPv^WWm`_IdEKXnYj!U6lcv!gbfG--(qE9!m^o$gBH3GoB}JDH zhK5EZ&J;(LN1g(2mMd=te-?Uc&vH~pYlc$Zv%>bF^Qn7QsDvXla6mHE0Lb(^trP0LWH<;oAvBBI62MZY zDVUOnj$H^P#kY5@<+#Q@+>4JG2alTU86Gt?^$Q%riV*(&dy~93&&;Q)P8+IdXW4Am z#1uO(?T)R^Ke!jnlBX=4A8}mk@Q_n7y=+1lSU*bB)6;WGycL&@z&N)_<0qnD>RdUx z^pNk2?_ae8!0YzxQrLKgu2~uh)c)ZKkpbVNr6LL@^2Jr8)c}%bRa9r@l;jl^TuKKl z(^yzuE@Z_fC$>t<%gZYSu-~L#HmPmjLLseq@c(3JjaUT$_nk-l;&Urhi3Jq0sWR{6 z=Z(&xc1ft7!=wLS-hGr|o(d?LraP;7vRO9*_IBIBfdF*%KM)paCR|Zcv&apk#e%Ub zRPgmHUDPdpX25$^yo@L_noQeEM$EqdeuvEvT!al)FH3Kodnn$=i*+$58!73)e}46J z?xsGg8$z5RBRI^>^V!-5mNrMED0KliY&CskrFM%sk7y~2j4RLmE&yi_NOd}&P&B1n z+^sJ?!Ld5Jb(fhUV%a~O_cF2Qi@h7UwbdO*4j9_+IXC7twQ`EEK1dFM5h9BHl6P>1)RA9GICIm`E+y4r7?9pTR?<5u+YiM{uth>Kn;cqm@JGiJG|55LwUVQvVLqk2_ zACUBbkK((&mUiJVGxd__*r_P&Qgs<`mms_e6>1F?8el{~{_j3O{)fyD1;J%mhlUB8 ztp{qk)Y||0(9n)=UzpLKu$7HBFi&r6eztdtsnY2RdMH}Oei^&$ODV?yWJy{fAXnnzuId{!fxOB$(fUw8_ z5{Nc-H@1Io&$oDE7)&{9mSRN}?d^*xKPSbGK>dW|)#mYGaRd4}M5nLLjHnEKtA1@GT?5S8E( zyooBrLE3@82+3dm{Gw_1_9CN;6NaUiYnQ! z^NeGa(^V_FA5_OQjw(+cioqM*o+`QTDfLN+90F|E;E0 zSd70`-1^)br2Mzq`u=v*29H%Dc^#Eo*Y%Unt3&a62xl#^C5e14CNi`biuqf1R9QZR zoFQhAEq%jnQA+f>pe|WP+md2c!8oyk7iBlJ%c$NpO5#EY!`Bd|QW|EmK6SkR=?`1% zIgo}e77P4=_tf#4`+i=}FbqaCck_fF+0yiMm8lTI5Xp}ppV@Pcx`%GUL_6(dU^*m< zDMBzXAiX10P?O_j`T`io%Jls^^{+LAFBsJ)+rqHuv3T|GoIbnS!?;=qW8Q^xbZ;AE6_`_^?=WL2G&-73@zhBwo>XdIL4XfMw`v zRN+0$rNQ(PG||@>`N>lG zk1d5eyLh^H3MWrvzGBY)=$;7+@1D}T-&Bomd{~!h9=$r$-|QaKKbF9oyOYIi<8;?n zss7v|F+uF%KJJO``%YK&@$222-7FuzSRlPC{X)#=XUgZV_UpEKYc<^8{_e+jEyllf z-#=~5kzUld=74oqgDda;WB;FRYL7kj%C~P)?8B(&O#)k#U0mH(Ty*Q$lGQ6HrJSoO z*wHJPWfHi^RBW+}TgR0Y+rWv*Sq3F3=F&%zCF?4;&N)y!aFerY&ki4 zTv}lH>u>JuU5B6b0LwyPSqVC26JGSQU1)y6hv+AYxAHbX{+DH4fOw-CMyR%E0Qt7{Cw$WUw7zhyaZM9{}=!1H+I3 zWVkGlv4KGhG|IdIs2Vu33>s$!DuU<*E6ZVEZD3Ad(1Dl*8e#@20-Jnaoq?+XJhaRW z)C06e3o={{9+F-GAqH|1Qb^2pzM0}TDeyw&1c6|NYfcRdmS_r1?DErA(h2yEUj7VHU>w|`l;pFir(#T6HG0s=!awjJwEYU*0-w%Bze z@B*z+DN`xkUg^N3RVL9QQ=-Lm#X!78H#TN$%*nXbD|W2cwL582ce3j?om{u>WRNZ+ z4Ub7o3m&XsJ6ChAd#CKT(g4}pOY2Xc&YM2}*&U10PbZIGbv^d&=x)!$t?}KHyG8%J zs}U*s*(wshg!MLK#e>ps?xvxlclQ~IBm^|*&rKChc*4|qw4tl9i-Ak}>4TYNd-j-p z5Eb1c&c*2TLL<^$?3(x4n=0G>2iC=zIh#k7REAx&l>M___vSN}+gmf(-L7u?9Delp zvzorQ4G#Nt<7+jzCq2B_c# zN?Svwcunf`hBeBz{A|8uv-xV-%En8{k1Ojw>w9iATGs#VZG5hM=>H$PCutsPXR zUul>p4*w4D-xE>%MmV0&*{X5?z_;+WKGHBg3jxGq7aKetVgg8=A*?V`jWY>dTpv2| z=2{LGk~=&7e6K-r)QKDM|=T*h&&qNyl;sB05vucpgS5U3k;Px z0zgrx0Cov+CBzYu4-m?Mb-ekv>0y8X4^$EWMoS)I%VFJnT>FynIzn_>tr7qX^sl$N z4T0^jlK?`W1VrwvZ-8?=yKWUs$Ln2o;911Ui@DdVD~Yfb=7DpNc&1)w$Om9(sIVmZ zMWN%!QzxU2VfpAgYLkV9ef_RO2FH6X0V1qE#C^JH5GWP`xFrk#R3LZ&xA3G7zRMhm zg$aVOFdkr-0PE%|fwN#nG88`nAYcIC%!oTf#`MThx2pvb&j3JfGavwL1i;wGFmMOJ z^Ik`QAnS(g5Ty8(__FIYWu*Whfmrtml7vhExK0QP`p? z!1D!g)W8Y=fC32!;5gLYSee5M`&xqu`$|iXrC+s~Bu*<%H=PPj4J=X=@iqCW>Ir%d zV&O^-teXOO3J6GYlyEgROvs4vb^KW@b81alWZa}*Eb z5Cy)m42Hx5bQ~91K!(Cvz9y@p2gZvszDZ0B5Cgzz$%NDtRl+x`lF84v;3JWAh)+^5 z0H6n(LE>)_gZT+;@cwtAa7{WREUTIzMTr#^D2DV@mP%2aij9hWakZUEZY?=}6#!bm zzKIt(d|;nIW)l;m`a|M{000lsf~}ass?37mfGH$jy@d4SNd82rm=gQ;jg5+8^4pxZ zskzE-8jJL*Q&!HD@H{59mQSr;fv;o4_^FW>Td%cQ#;+h&A<4c^09VAPuT!^(g+OtV zvp<9YDyqT&nGhuhL_p=SsxW6Nf>K2V>sE^}oq|dbJjCYO3UpWHZQj+dNE_AEO+hU4 z)bDM(LY8mhQpXhE6Du5(y86vH){OL;Wpb)Tq7d==OHNC5$0&-9Rt@8aaT$ig8jYGu ztVxiNljjT4%_<5U7BcOK2mOe+i~-~72Zi5>8C>a8Ga={ z^xgCIZ_IAJ6cvc`_|Db-!nUJ;qNA}Y!%@HKW}~Sm40Z`Ax z9kP8}Be_;p@IG`@92~Xx9R(_Ch7>IwQVSJR(}Z$4M}yZ0jpPq<~OGuNyKUnXyNeTeM<1A zbDCG!l>>vM?N2{{mbd-J1clVSW|$tx+~1&v={+|tu>Ual2%aMK{LA~bn&-wpaizw%b{~b zP+)OaU81-CD0kj}oPMygz0Dwv!o`!!EZd7JiYQ-zEj-MFIsT||XxmK`#0C8i$ukc~ zvW#lss2@;IABUT%BQZ9Xaz2~TrvHL&JnwQ}{YOj{wYa}w4XYuqb>B=6Ew()dvTyGPVk_7z$2vC%T0068vID+XC5E?TAJu8m$Pb>o zYbbL+goCntr!8ss-Qou~NL!ESKm>2@)zOI~W{ct$)bB?jh9@zcmT4>xo5RqjNSO=8 z#2pxxVqkb3<&*Yx!SI$)SLL(7k9EHt5=i97iJie9kL{8ph=Iiyi>sBpb{r_j_6s*d zd!xn63%`^B)UNX79t?Bgk!jl%oA2-5IPjDQhNHOdy=(v5UQixW#^(L4#a|w-3vI+> zp)HvDu#`4AH$K>gX~&KZ?ieJhkW1k+gW3stw|(Q;nGou3+LF2O%ZsBu%V~>24@^-e zFO6Y}vf}INdUagI>jMRSAse>97To;7c{eBpL%Xi7Hz(yTZS90&`UMv=#1SVBGOoYM zcNR1swco~w-#HrBQj7siW!PoivkeoHkz~~mjM!pvwNvAS9a@qtC zrV8$%OBx5LOjb{;u zhc>3|NR6dp_?W8o_))b=e?uiu!~G3o&_0;->lXEX7(WOtovX}ml0Er{F~g?Rbts0G z<8IsE-7w_Ug1qUow0&TjQKIM-o!2|N$!Mxl< zq3t^e{3d2m3>{y)yS0W22>Vh)@mx{Zg`egy?xJTGd(uC*XKlY@SYGhY<~sY6^hYNb zHZWj$D-k_WSwlxX6ywRaqKC)dV>lRX1ZjoG+8++)^zMT!?9~BGQ!fAc_!#JqwaL*0 zqFnobgo$Mjq($HFDG!QT_kq8d7-$@D9jy;#I-^6F{-Cb3923Z?(!3-73H0ugbgg4* zC=00&Kjgb*;%5v`{6uGUQ2E#F3(fe_qCXLp|+F)geeoC}~W9f=O!--s$) zY%pgg%nLEAy+!L7A&xyxqV*a^)D4&~V>)8*pmF3`1o>c0mMUnLwlHRqO3#+s4rbZ= zd@)I9um(9Yi?(yLE^pCzFuz{G2;Mh&{+t8^xc%XMBtJwQ&XquK4^Fn3q!}rXQgw@` zOasF=U(0pHoJHQYTtAGjXfa(%DLs$jby~NArgr%-fT-VG#>WtI!RW{7LA3AEM#&ij z*wP@0IZwBcE?bE^T!HLE^No=FJ(~q5C3g2#4`z@1@sy5=Ar4blN*pm2U&tQ+6^1cq z)f*Zmf$qFK7;QuZ;M(K!{`!U7U{ER< z4?{lTrp;;Kgz-pp-(lAOjw$D=XELZ6$M5CKWzryDjETP844~Is;emmVQb{+a@>cB# zzMa~4~Wxc#xBlA(5J`91wXsqr%z13I*yLr?Zm%ZA8dOveyysIS#@ zxVA%k7lCE`=%Y+VYs}%=1*J2jzNay!WM{*X9_WSUFXnhQ4}yL?1H-CI%TvHmhnmu% z7C@*;?4F^o6z2TAqGP9K+3;gYj%sH~boTGKH&9B9DX)|YDxpnYGhv7Pf*9%@?_=qQCb* z`eW2v3ulyOvwAVRF&=e+mSLQ2cGBOEn5nvHu#@Uhjkb9^PjC*kO#E$P1-uO} zhJQ@1&%^3zSGZZ9shv%PH@(=WabY6dJYk9QH8)>U`U$)E56`1l+EayK-=Cg1SClQj zG#6M9(PJJKeAjL6LzJo-ylAtx+=*ZF`BF6l#fm{^bsQF(xu&_cKby`=od|z6EikqZQ_C{+dxCS}g>$R?lub62;`5?9KB#XHP{YfN;MQ zLux1)q_OxVS&FIC?fs%}bl3GRHV^^|SeTiXIT|FY;^s@ggwv5)X5iIaGu4>GOy_7t zq+dcq`d2k#jc3@lkx#qJf226DHXJkSKxUYVP|&x(Q+aB1<)cSt0u*?gwJQ}cN3A#@ zPbOKR`eAwSctBG)e%8`^X}vS)wWe~E_rzr7JS8=@_UuOXuxo$rQ8usd>?KZ12fd${ z-Y7R;yIQx`o)%wlN$UMW&u_Z2WM5fvmP168F5!>|3TCgVs5Ce4=7v()3*Wjk$tv~J zX=+P!@8{lHr&;c>-C9Y|Y~$1&(K79Gez6SKb@@A|SBfS1EX1j`L|-csNRwznr>x=v zfocvxQo139HQB{_7S?meW#Yr15U>_sP>QmYfX&yrIIp(Po^0B*p02x+@nPzTNZHFf zX;j~ITlFQK6Q;h6Hfm(fiZoc4$UBAm%g?>#A_yU13G|_&9)IqE z<`gY6_YT1)fx&a$N?}TupzpjdauC40S$H1uOC_q|FG!wU9PX>F2*RKDl;-Yu=;)T? z&(||lbB{Z{fYCP9e3(|}ngyGLc_W{7dM8Ov(knLchG-`_{ao8=C(&u{htm$1&yzbu zi{9hTxA~}-$J2KzJ=N^fvz+AqubJJMjAob5$xS;pf=ymJ+4S}1UnlIC3cGhIJ*V+` z@#mtBxwL#+@{Zd%->($tSg;j0-kIjQJxrO=%ky1PC#NxLTBI7R0Ly0KY}2B11@~=p z3Key(*|vIL0-*TX6-IlHp?Tjrci;YKDLncet9j7{1 z%UttzxPDr?@HWJCI+?gMDwe}B&pXCyY~)=iIg!RU7x&&?pLzqQ6iO4Sg;O*ko4{)>S1nkP zE|g6rm&?@zUeg=$c;uSWj#lIfQmJRm;2AOcKHRu7)(F^tvRA$LQ8LZ~zkgtgGS$wP zwU_xW$K_F&{TaCX?JL^#8rRZ}t*%?&R3o~GOFw)o@qUliEt3j$Z9z@T^A7G^e#%1!eTunzR z(wpR|&^WG{18(PI-pZ*oq&JewT^33^OD?C}ltvC#ylX&FiKaD|t1TO(@@NG}ymBu0 z9dpQcra1o7*X#e!E&=U_q8owA#fXR#u|gk+Dy782gK+*OA{3!=pg_=4_`mU>;HjAX zlSs`-W9Spmd4gA+m*6E*>jc`5qP(e=nQj>9MxpYO!>Do zj^zD2-awxWI`!QDH>LurnI;!XZ+RL(H3hX7)Z4RMHQXrmL@6n#p6azK4Y@}v&XUWc z^;<0ZxTZcT41p3w2P3}(4l`{tv~W=()_G~A4GQ;Y1t{|*RJh_e^Ka$SC#L$Zf+A=E zeNBLq=KnpMqHQM%g|rzu=>7|8|4m1IBBHa6L`_XnC9y&~wM#Xfc|}H}VhF4s#D2hA ze4_FY&~W~ZwzQrF&Yc~8B}sB~2I;{*BY#aJ6oTg^i}Q*6Mpmwy=i6G(RH=> zW$lChk#lb!sP!j>1hBsF1O*7>g~*G)1`2$x**@{+9yi&hm{_jTcN7+f1Lr5iqVJN z_8Iz%(WQSt{il!F_mLU-V-O0oxPCz|e2kJ_QP$Z59XS-Iw7EHIV6uII*9tsD>C=zG z$Ej91Hy_<}FjaMa9m23NzX&~Xo=jwoc$&@bGpm~PPdR`}nkWTpF&G&L#iR7L6m{VE ztRw2krJGs#k;U3F=j4Js$wT-xU#e<~lh@9R3eI=9y^^w(KYn^i#Vk}biVQAa{`F#c z&B8{gK)02+86x7&=knE!L2W`-2)h@j-p~WpOqM49rbMBqSeI_dy#6>8yhz-PsHMBj zE#PV-zX2~jW&BXuSaHZUoah8e@M%VWs@D_`$zESLP6U;Os)HqEs@KO2FPjnY=9Mnw z`QNa$VUU)~(>Z(3`iTQ=71~M;I8c;@H{1srjrFH}qY)YZTvG^|MQ1RE-v46cf0N>W z6aE3z17qt94%s)tyTto8>E0)SR#?IV-TA|;{%l4qX`MejS~r@-zL?qT8$|nT`R4da z_l)bP>a5!Ix#!&S+V#gcp2yKgW^%FIyUB97p8HvQQOWzqNlB-QlnNy%Z(9-5nBzS= zbIoVbqo=4V@mOJD_tQ}*J5@e)DE+l@*sGdHRMccH*|1A2n%$4;Sk0>noNmd>GxWb# zf1;sbaat=hC7G7Cbs?(Qo8u;nmn6Z(ZGSvM<0dG>KTFoyY<0qt&yY5GwudPvHkS0FkMD&M{+G{3 z@;;hYsqQi^_c!B7^Oi~Ki>1*JXGWYD&^q%wWOMp^Xwd%4K8uK$HIUUWWGW{jkhJ3-l%x;(gEW+xQMC^YV$g_tS$ z>2jQ+GGk``M2J8BknW+jf^j7-LYvA(_`x-AqStcj%1;x?jj@!^8b3|cK2G*tMJXrf zy~YairTSAjXghgW0wSHdkyh=@W|f>vJV1H>d=n9qS=kI z-V8fOeFNf$&@*sh7Wk;fs0K3Bm{lQVk96_Y8tL?FoKQ37!Uw4?{Am?Q(-Z9wQD}oW z*R51dXzhh(DTE+-)5{@2Hv*_AaTsL1A@^u%>)A5`(|d|o^9yVwtzO-tlGnugdQAG_ zh6u0RH7+$C*?A3fFZZC*#QfCxmt0A7esH9)##ePD-0u;y*(`L82|hCLdMykY#ifY_ zr;@iuQC1@B_({(D!n0bOo9PctGVsO;fW1X6NzEHoTLp+<5aQlkjs6TRTwXUGH+t5fFEwI^s` zy5-AUJh+XH#{?B|Plj45QaM7W5~~;B%JS?1)!fR03efNH4~eryuf%1CA96bpPa7p# z;eMlXl(5qEiw~uHc~>#5-ytpBl3@L|HkVX+mgm@II2D;w#1(&`#P|eta>8ShK*`7u zJQNf#g4P?9e5et^VDPqR{OOUP7a428PSw0q~r8nd7AMn0K`sYz|ah%q??{2fhA9a$~R^K=#*6;chb~(UH zF|jRrkLKbywUmF7Mk4vKU$TyZ-#zb5g@X2m5EsF0AT-Q(}i z#Y;_JCl8jvRVEy6rPM<82%^-Iz<7mI?Fw}G{ch*C2hoLV%PTwMBmIu5l+_E()<$2& z)>8^RDi$(V$V7*3{wREem^DdhuWEiaKjt1ojzcoj=Jqo=V^ych>7I=p(_mzS?(XC9 zK|DN*uAjNZ<|hV!td?`P|J$`eI@b0zz}2;@IJZK)^bLvdwMU=d*5g0XW&N39t|0i- zgzf|SA|l+XD%^TCdN3=tJZD&~dQhC72+J!iKxVX$?R0XQf00pSX=Yc7{tsmQ8BQZ4 zb{mzlhVVmIEe`!{y9haJ#>INY|cddXGvE4HhqNb zb87Xyiy03-R9JL$+!CEk;}ggBW*u>8yPMbn6S|ri=I4@C*0a*dz-S|bhaF~BCE^^H z)L6oxpKc#%d~!MPQ+iJn&#Qa(M)_XuSj)jzklkD77fUwZr4Xc?s<@ZS?e^3^SpJT| zY+u7{u$3&6N_0VqP%4fF`5gEtm+cMt4ccO%g5o>-k5n?dtEh3@(i;Xwxlp|(zyjFj zdwq#L*!}h=w$2+jK8t*9r!hP6(i|Q^>wbc@)ZZQY(`MFCVr0QeI;}=5?vWQadcB* zMU&@lSnGYb8Pphb=45t6%x2Y(l1yHuls6j4H(g@k=h&`&9;rZoQ5 zpLk7T+PCs7d2Mcl@!`0pqutkT82Chaxu6B-+>;@Grl^l`# zi?i55f=x}>XUU|lqXhd$O6?N=ts7Z`nld*1nW94%RXqLdVK{8@=B-bUpP*pyGwPL z*_M3ve-5opqj;(;Z3hr7>%ZzA8=L8hdY3`{OwVbumoQyn$IMYAI9s7#Jh-voQYIyg z3qrKx&$pQO)K>!wJZP*lYW@C`aIh;bkn(tiAujgXh&8pE@JD^z5h@zrO16bc90F-G z4LpAOD>|Kb=E(5FSiI_`#FF>=aBt7tb;5+Wxs#`GYT@) z6-+R%{e1sQt*Hh)J%*El-#lal4Nhh~si%S1e*)XjSiy{t;IK1w{(ddaenx~8NNHfh zzshwSk%0Y;e6WuOTyw@4YZv%#yQo}`<(^Hu2iz&zC>|7iKriEbk%H$Vp^oULoA&LO zN~Wd}^*u||-t-GSak=3n^Eco?S;6*p;H>zU%u^XZ1-^8-2#B)L=h}Lm%U`YuSe^2Z z&lPx;_GN-Lm6uprxt<=>WE?8?)U z>2#-cFWtFU#*WL6AQgeeU-O2(-H^LRog&Y-NT9~%@MzO1m;!m(~ee&Pg@aFu^v=&SynsBCy;LP@UP0BG?>gp1g{l#EE zd}C@cp<|}r2~0USu=6)@rEUI8Su7}6;SJd zpOH(V@KT0D!7Nl6efKNFJtOx<-Rts;GjgB6r-<=Tl~82}SciAeqT8QC=`=JnK_{;E zr7DZMmojjR3I&W@QIJ|rFqjE8k_sP zL}pUnRNM>Z@Zg?y{Vj!x4b8PDLULE1JA6~}^XVF1Jhxku@oCF2cDZq$Q9vz3jx=f# zimflU#qHiWxaLxEaX!tc<@N|G*0)lGX4zu{1=`{Btq$|HF(=t>rDbSVGAq)QNfSKu9E^5d6eev*DTvJYAK26)SU+Okj%JbaNcwW3$} zeX(@*;~1rZ<-}RS*PIu2PIv1+q}^ivpb2@cut!+8+dhp@$iGTa zjXXJxJh|aF^RGxM7Li9?LP$N9(nN(l@7a@=Vb$hI{xCNZlSh2OV?idKeI&+tDbe?pi^Tm z!55skRc<3IC8ISKS%0VL-X-=+>>=#aZn}f4`iA4I65kiaqbwD6mUjo-BIfcR>s{uo z&1ob*LzzGP{`I%;$IdK_Z1iu)j{6}>xo5Z@dmleWSmMLW_lylpeh=m3;EXG-T#IkR z-0?P~x0c*pkg3LDT&RE&cE-v-)fkCP^5IGYr0|brB{fTI77A^hn0KoB5OUozzz>OS zcKkK55}e(uOtaPWfg)qo+*VKfN?3uy@l!~@$Xo3h>SGL!t=<46D@{%8?y;#yZ2@)M z?EZu-nG%~*@nW_Y#qJB>gc&rPsYc+Z{hV)a-FaX)BPNY6=G3z5tCzR9oe}hX{lVzw z_Fi1u?x2Li&A6he$Qsq>g(mrvBX>OJ#JU42~t zJz*``%m}CTEMgDbioW7LyI%7$zfXG48=K?GisKjU871yjD*g~qt{$)Hc^*823~O7y z(foE{<6G0{+0c(yL#po;n`gKaSvgI#w6!$FYAP2q^UfV}3K#C-5A9$`nHKnAWnx`k zuIbqRxaP9M2}OQ)o|ivvT2l!M)P9g6GQAsbY7(*f=Y= zC#SlOx_c>w(cves!wD|1Zj(sFU;=yS|-RU~98=)!% znpv=l;cJ$s?l0GLY-QUXA5nTEb$yq@mxnd%AuyE??;vNEL@SqHu-YwhF4C8QW`Zz^ zt}Lc9>8sj(Pc!DCN4Vp=)@4Ws4sQnc6+Y<3Ue3>6wmzk*zF^ZIQk6>cwQpqf=Tn=_t7CHl#Wutq{g>E-Zv!U*h!Nmf-|M^pXaLjz zUL~aQ4zM#d_<9+ERf(>`g+bl{2MxIZ;tHi9$c#-Twh_<;hyq}nW#kY<4QzQ5)%hJj z17O7iDFE2AbPhOgyFUOIa13$KgBVp1#kg;`1;DOq=t0mhZXe#$SMWLkA+*QkndWLT zXvnUps!7~`dJ&>=XE#k%AoQ+HZbn4;2c~h-nzD`DSBrU3UlaBW>!V7FPG&JzZ@5+Q ztGY1~yl&ORQf4I*U~?LZt?}dFr0Paw z!88T*WN9CETosEu1p8uHl<>SDiz+dQV05 zneMART|yvTg1<04kP5EAuP{b!RlYs%Y+HZ4N})RN0#26Kijp%PgCzVjx!BN6j(6%S z7K8@ALbAIRieBBF?v_1N_Jh_E*|+dtm{TT_)# z){(NwNRnzSMyK5GW#My!T0gIkA()f8Z2`tyTY#j%rV^MI9fEY|A@Fs;IuwUoU?M zZ~$ST`lRoJkU)X{TnLEw7XaAly}yQY2wPc3kcy%KBd{}i?*QUpD~AJsM{oks1g0HP zxOniN1C|ajLP19nW8Mca+8%}a8=(U_4-rAr!hf$mylLBxH`F!9+Uh+PixDHWV@au! z!@>m^JD~`;Uuy#H-FAp3B<%0w-b(4<5)NJ1M@C5cVjrYpUO~SMXp?l!!Rk!<9fxp=758RXHRJVvlrSX?qut*z38R-}d zcq2>pB$vrbozoog!#8wTnDtZw+-JkT$qxZ8w(XUW zj(KViv3STNSjN{&y94Q1Zgk~ziU(G@twABJ$U6f}dPtCE4w)d&(-0&DT0__wJ&Uvm z?9X8+Dc6+(q`W;Sf#iVzkc%jpT7%8($V&mH+j*d{4Y(EnCY|fCcYvh}nI9cRF5b$sn*c!x7&SnT$Hp>JUb2>qlKrVj) zG0Fft&yMheLw6K{xQ%4(mmEP*;*Fq#lq}E%(d_gq0s&0l0F|%~)dEBl-Qu$|3YmTs zn$CgFXg+|th5}?D2{1LQ#-xF|82yzAzz>@RI~Ok&An?ObV2TS+>QRTn$GzyH4D-d+ zu3f`f!+^cdo|6v@b_X6DFAk~SiU@yTcjJxDfTsP|@&Hb^;v&0i1#9iBHBg9%YVjYeOn6X zjnhlz38$D(YLJf^yRLe2BFCvDLz(*vSBRGDj7~?tn(2qsEGhMw*`>>z#`C{qvVTUAlluQ2 zynz18AbXDE>4E=+V;YliyZ%1{`G2A3x~+a&*i~cw>t|@3Ug`_mCDaehJP+``3!?{5_K!I||1(jt#I&#K60#+PS>btvz12(0nE zxbov>M@U;pcY@?+@#SIduo#!3H)jW>-J1u?v$Ecr8hmq;blW&Ja*3S`YeQz4a;Boj zV`XKxV9@#brJ2s#IRlGqFS;|k&B{jP4{k%QnwOY`tv{j7)z4{ktM!*XsP}dg>E$UX zz1n!tob%xML366u&yJ0}^Au;KqGrSN2H4>T%~;l~^L6Z;pDXS|{nd>9p#Bhx!`r_G zOS$w1nC*|*o}>dVo`eAwL$02jqZQ0@K~)DstM6l~^k&U^d3n9y2@?pD289DS*7*3m z9fjm?ob7c`q;uvP#>JJDDlPse1T^x8NFK84uaQL2J}J6CP_Mq@AnJZ+XLoi)@ySf* zB{VaC51iL&gJOMFbMwFeyYp}6O>J@JE^gF}&(7EKORrCbNY_VZ4a7a!#~wpoN0EpH zVZ?meot%{aErBC!_&*YX79d7<6b*er1F@i9pe1-ltQ5uGd_AXH|0`p^1%Dh=nBO!y zHrj$e1nkS~wz%tDQfyza-v?w+u*baHz&c7GhkW`nWg5tNUq7d}oL$|CJ74>Hl{48T z?D6VPHOoWnI|_ai2C7u{?^`Am!?t-PB<`euOJdYy9v2HI>%m~B3#trG?e{Yvct5AD zL-w`~X4z+`uatL}!O)f1oz`x=1?}51FUkh>_bRFe_R4=-w4YxG3wtoY{*WC@WgkQY zI)faX-UG1M_N(z5dTqbU{Z0x`6}9?{QHywVVu#C93B&!*H*!I;Zf+>Fz`q*CjjW3K z(Q-%A1}mN!@Nu+Na5%y6{ECzvkmc`e+{5Wa&c4h6}_KAL}!bQ1GD);-853&|v5}}J$@e-PEPrviY3jP^sx=VL1 z|BAfzr%OjX6FJlB+Jq3ZyvMaMr(O@k&Rv(*#m#L@Iq}X@9_YBtfdPw=?i(!Df6;lA z^bc(6s8)I&sEz7T?F6;vkLD~G+GXb)b)Ynx|HIM_z{G|AHW-w$%B15uztM->)3l_e zjG&%bf8sC11NX*V_a5C8A4rmr`@sFP_my|aGgXf(v3-~C($3m?E`l?TT|w95_oQQg4X$1uN4xB0CfhEn`b-MUQ%LH zQey4Im{)?T0{}WkJ#jKH5B567%seAA=;|Jm6`kMvRnJZ8>k$D`1S=eB){I4 zT1G9`dNwU{7ZJ3>>+8V4wC%WgmV+n$l4q>tQYDHJAfs3ySo`N^*;!EchY6yZr=C9; zcxV4!q#(}D{Y&}zm2%^<+xdCdqZgSh+owH#q-jnXthW-fvH&>jzjh-IL7;Olb}uX# zD+>jq4A%OFVVc64q~VJXEqoWvcW$NNk{aK>g^L}Ug4=a3WpbP6*=ZQxcYk(&L5R&6 z1?bcUq81)3NKWoeNO;Wm)V=utC#LT2-5CQqca7d(q=_b3SMJMrrO*@gk=syFu%q4) zaaXoj*R<;`sr&`|h#9MIn~aHuL&KixKWUu0FK;N?*qH1+c%ALYuJYW5OsGF?-~yPG zGC)QKXoHuYS~)ozV>UKk@XLMV%hmzPL^PY6{3O^4)zZJ~_t&qWU8@MxoV)`7x*!m( zBVUET?TqRbcw0_R9`#K>$Pe!2P@quVPg#TTQD41-FRG00iRy9mi|Ps9{~D7fo1Fac zOMOsA5rHNZ1^)1h#&}TQLvx#U?Aup|kM0-MhI7j*V&2+$Qu)BXzP2@5)-j0D{faD+@CfDyL8YjKJp*dM+52W+zWn%=fW_?Atv)N?jJc zx376AN0zfqebZ+bCfl?cA81J=Qg!2&nrB6H3luGWCyjAjuh%in$ULj4AkY>&dHd3e70p0-;Rl) zr5KTCOoP6)&x;lcVE5!Ts!u&*15EMH)@y3i=VF()s>;z!Z|({QZ0&JMHv9U%-F90j zG16=&yNPw|eBi>@)S59$wKQBg2jJJtX-_~bm5!-eXpS^YAv3=*bF-gtvb zmsfKlscYe!Dgs6d_SPTFCpY@VZ@-C?Z0{MjVzYVYahtMB2SR4)ZWjt8C#97XPi1}4 zu&|!itwN%57RI+KasG1d9ppEmjx?o4-HcPbRym_3R{!oZGWwo7Fh5h`*QX>?B0KHb z?0@;pO`{&o6c4Q|{WxoFT3d&hT)9tSH;jFp}cJ|-ZC zX!v^#&b5)rwjpk{AzzFm5z9PLg_CN>M+H#QvH8VEkfdk7x%?+D_UQy!4-yZ4_)skm z%IMqd!dYZDqskO=oJ@zx6rQ1r+slVr-NnQZp^ux9{-YXqL3qJ5ze&28l-j6RM2fv; zRL$rZ3#BZHXdPbNkRS5}n=4GoE0f#j6{H516sU@OhKUeD7> zjVW$jx>;T=lFri&@sgFw-a$4oxG5|?Hx-Ua+Z{KH73!vjIe3XLP{_mhacH8H9=}wh zJJAj^-e}y_no1#gWfgxet1gOw-k4^Vu&t(1xjkL*5tJMAe)$%C_}@I|F7s#HPl_~py-XOh3U9LI_d z`Etd6B&k`>h{ISBnWVDO)ShkLkj!v^5cl$ zTLW&!C!GQfj%S*w75l4w*t8jP{nA-c`QZfgqeUm@wv+-whJ!NJDD8rVuygx;2?eYEpaUlQj@d2>I z+wz0c{s)Ku56|oWITrR`4t;ohAMC7eNW{ylb(aM=`9oH=>-|Lywqus6Y*J(t#B>RX z{^E=e>EZGIX>;7Ym8f7&t*Lo6bpX1+#fK=zL-2(JLKl6yH}z}mbm~p)M;zV1R}6V{ zPpqwy8wW`#gx;cU5W})(_Z}u7*j{PHHDj1bnMmoPC8#4g-3yHR5xS63go@t9e+#F4 zG$9>%E^OMREK|RYwoMajJ>r=3+u3c?Cae$8%DXnuyH)2am*&$#`P52tl}|cB^(V)d z9^l#X2kn&*#guWlPo1bEcufa=f|cGA);=a5nDRCKwr*em+{8*Wp)Msmk6t8zraUe_ z1Qr6G$z~5`52jEeWG7_D3E95_=m%_@SU`b6db)P|IsToBf`ruuTm_QQe_bxnN`ZYyW z#E*)kVfVcUt1`Jm4-7wT{*10$tBBs{SCp{m@gSVnv!2`T7SR+`54JzMn|^QD!g$ap zN5{T>m}oP|@w@vQ&*e{?Us&R@nzsnH+~>~muk)MJT@@M6-JBa(&RBIJzfZse-&&Z1 zArc`Hg^=WAK{xtkUGBE^yeY|X)9+G&8(%VF3%}tf`mIRr;PF=?#O9XS_{kCzd&0cK zqI9#L-ZoC87c`-!dpkdPc7y0A_F6?~bL&rz2Y$P4v&|zn+od86wl0p_sdmQ3%)R|G z5Pmm}tE8jPO)%?CcxUT%@y1n&do@Tmp|TaP_cndD@oz@y%=M76u+{$WFgnVjC#V00SQ7)CZgHo#wyyt`RQkLu^DWme zeeb4Xo3cDumkW}oo3E^28@Ib$*#1&~+Eyx}J;P0`wZn1DS7Xi0ZIU#mOw7R5sW?u; zRsTaea$fK5%!ic!+2Y-t)VizV`0M{FxwMP_i=oKe9EZQE_E#ivL6PO$_6C)-L-MM5%l{D;;GPBOzE2%@JZh{n@!=@KMr+3abOMqlUWn|#;;r;zp<7=)dAOHA*;{=7Yg5o$T^?^nkOpHf4^ggZz1T>565!N9xjW#wIauvM zA>;GM`%ctb@=jau4gY=pcL%RYt=5x6B(LTgmO&5RqF3#2J?Q84f-lDVFgIiV0^HHv zl|NpeqW5w<*A`FJ&RMS~9loTG4B6k^sgQAVem>$RvUP}1^pSlU5K`yCo=628+}}aH z*3W7l=u@ZrUZ<@e#F4Zq?7jOLr@+nMR)2PZ4{(}(&Lf5p&HGl%a8;LSOcp5D^7-k0?^t0k%92QTr&=fE%x0LPF> zmXDfrwC}NI&j&n-l>Rilzzu~i}_zTL@SPypQtkX+(hz=8q5LjZfzMsGaJ;_aJ*R;WzduS~SSZQwrH zew_kAt*lY}d)zV==tS&|fL4m9+|}Hz5SD6kjf;3QPwFaWJ+j`e=%{}F9CM?T?(Vzr zj&cg)^!tyYlR_T$Q>!nMaJsvBlu32f83p+DaPRjB+;toAP-{-=TA%Xc5&ctqITh8q#cn@nMxbTY##-7JHh^$u@G z9`suvONn+%W9Z1Eu9@R$Fz^VssD#(u6b@EJKD~K(PGG1tTi{5d=QkBBx~J<{Exc0_ zo!(ufagr6+)+#tEcy_Y}EoMF2{=N6D56P_Fekk8g#exXODji~E4}PtfqAZTpAjH=> zXG&{PfeP**!?C}Wlnku&48;1{WK2$=C4h~cW;=u`A(5%bwBEOq=R&dHVSl^&e(p;q zQi9REW0P5MMd6zgB!e8kLUE*{<%z;~z z;WUG+hh@{T)jTfv8=Udh2^jM*j#fW3c zlgu}o^6UU1DAA@FQPs{3BFQURDU&g(dL7X`lgA^8Rdfv4a@zl>;^YNG z!SlFO!c^+%K5~g)H?La+7PZ5Ge2Mgc`e6fu>DC^%rYSC_5%D*`)z=N**A$8arzG@r z=8lbV!ddYdTu+wX9*TTx$oGQ!V!blyYdpX8jTIWVb0?NJWywdI0=DZ*md7!~K2V`MhlnKzc~lodu} zqw%VYQh2Bj->PVHf$vh(ZqpnC4@rw2$Es(MWK^YLWe;F~l9pIHzE&jip7uMLViMu^ zGuY7;H&kUv#p9M%-Pu(gN$Ti;;9Y%%fc9iWl&0Zl*VuC^T-q$NF52pa8!D zqOda(G@%WDtyo-1RUIIFBKJDIZOWALhOA~~a1r$gTK^9(JG>c#AAeq+b=VN!u1K7o z-Gl60UC3Q-Zrm>T&nKHf~E0 z8S22P$-b}ho^G``DpTj%-GfY_W1k^H(CKUa&i)dUrYt4XlwNk(DVXxerfLT`scV z-CJQS^9*m5co1%*X%nNmIl!!gi%K|{C-QhRXu1;CwstCDFflgTlsX1Ptn_SvsodZr zsM7KLmxe*$=`t`~l8y7C`CeC3Ol?o5Hxi$s*C>p{eybI%m#K_P;`;28GDEYHS$4?N zdm@vza&`11IYH;{l+!;=ta#INw~h*aD0wb0&~ewozfh|&@sVT~e}f7&HRX%6sYL~t z=*ttPsXI_{B#5H!122IWzphUB1uNb_RPEmsML5A$r%(V=+G4;98sHO06qpQD-$XQ6 z{Xf8@9qACG@jl6~%B=St9$y`kQRFUXep-6L{D8x9OuRi3+PPGjG!ATU#zdrZ! z>x9bwSrE>#KaR;98Vw<4y{7@@`Ikd=PyFMUOvvxUDJb)Z3qN@N2RQIZ%Kq`2qo*mr zX`9SFaG$x>b97a4n)#tO3|b3+Do^g0Narv3w->M-s!76AdAj``2|hSXd{U09Y_r&k^Rx;oY#a~Nc}mQEilH;B`gQu5p_DlTJyDx1FofbO=D#XfXKr_KYO(oLIKSv-K z{3S<9WbGH_nKggL-r>|a_Y=zm-d$ubH-%*xJp)J$2e$lCe`WOd|80~j_!oZzl=;I5 zm;2xTFVgD>{M428wq|J~U-wHm#(oNfP$2vE|z?y$jsr~5p#;eXMM_$bkW}ezLFsPk?rxAy5u{VPL%KmqTBN(XyW!3Q`kvSOJLleW z|DX527@nCuJ7#9j>{{!)*7}_i$n`5bP}JW~z9$ODeDO}T2u+wv=RSM{bt~cLBO~0(w z|D{zLoD0d7cBgqN9Pxa6@Gd(}B8O58dk| z4YY~*>#05x-#Vy@k$CY_@^Mv|N+>#)RWajQatCx);ddg|JjB>OARmTcY@(QJqJem) z#rSF5o3~MjQ-t}mwsUvSf%1e0$&~BIMX0wplTqOTv26aDi|U67fYWzn5a`$v$}GUz@=V)JV4#%`Q;1mKJpZ zK@lF5-l5({6_vhOfrZ8U`eX?=8Bk#Jl>ToeQkQf?wzWH4K5k@rI*`Zw*G2}+W06Hm z&`B=b+?sKr$u&Uz;_nHrPuDcPN&lEv|A)YHoLFS~uz6ns7W&SSMY#MUlC@TZ=zSVr zs`HD+b1af*rWCv%c1U%Pdem`fgyr?ui>7@ZKPT%D?F_< z!hnM#<`)#avtb4?X7*G{O7KqQyi68izzonq2ke=p@{kJg&`$3H&^K`c=(zQ~FnBj; zxeFSkubN3m{9l6(nHXXU;aDuQ5tYSVHi~olr<*Wpvr~%-6d7R==jGaFslL~tt29(- z#i$}mI>)<1&-E}$w9n$4U(%zo!GCaAkA=i6S`h(U3SUyGdQ zsK_mad)-X;d)mKsAh&npy+Hq-ulL_=nqPk<1`crUw!iWkQ^%8(Bv|yAE3JQa{e~)# zw&rlL4d>KS-b%8~{BZRVK-h1r?*1Xizv=$m8zAOB{{B4n8{kZ+Ee2mJg%5#@obVU? z47S;(>IKln>+zOYh(^z!BooUhj+5x|WvhD0FAZ#*$%~Q>oQHh0)o5gbA7q8ng}o zEQVU+N(>Qp-ppRwuU_3&yIvN#g|mDtDjHrrDLpE@40E3C%$jcI_S=dX3{*2T3jc(P zr$Qhf7%jlRtF^V&x4)t_mwiEA$I0^GfqCrdtjeWAKl$8`cyY*L)VXw{U;qeG-NF|)uRV5gyOJ$pU2@ElLc!(r;cf- zj+rr)95?%(?cp?ZTvFEqy^@6AsGvO4k=@&lLYq~%R~^5R!d};Ce@vCawKjpst(Xf# zaU98G3BS;UMwJUQx-Z?tx!W{P;@OZ3Gf(BQ#@*s-9qReTz|asESNVajuV-^}lcj|P zo+_R&JUm=;TdReo1s)zAJUl#98zjaO2w=fup*OcRSpdm^7%WIkD-ck{Qx%5Cf&vPF z#Hd1I(3_i^Ei8dNs*nQyFGWL211|cvqJccXMJ?_w`nRI*FWL;b=--O|by0YDMy?JQ zJLA7IbhLgilkWDde-3zpe=&O?2O+=tK-kYnvQy*IS^*=O?ALD2d9!A{H$sV27X0T3 z!uf~w{C+=c_M{)T?4BEOamSB#MN-M;NN0#fQvN%&<>Ulc=J9htoBS1*z>yQjIr*Eh zpV}CXvWS+4ww%jNS<}j%?<^k|1}0fe`ag`8Q1hT{ne4vFv8ze7TT~-xmW4mg4@i*G z%0zsfmSwc0{9&s}M!l_gq_*iy(eoYcdLCvY1Ly$o$)F2WWBmc@BmjL7?xkBI2+zDI z-MLMYu=r58ve1xYLf#h;W*aKksq6b{qK$WIaL$<#N5+ot{es>;nGLR$?lMi6jW(yW) zEYN@&lJT3;UpdGN^fD4<$@tkR!dDQHRl*Tm^ii;CLAeOh9oZl{)|1VjCtNm*5!^P; zYb3++3*ZGKIx0H$bGmcCr_7^>Z`^NG6MQK!B1Ns6@hB$MVKZB0A-L$1gT1?CGdRrN zo@2LT&B~B#ft#2#OoYIFbXC;0F`4RgsS$1RVzbDW;qcs@^JV>~C}n(t-K$Hy!rjsh zTPLogy8h;_D|h7C+Oab&*FN~hZTFqi*xkPNnu*=?=Qd0-9~O={UU60nsjR-%6(1cH zY>}0)#&@9B9SFkU}niW<~CLHVQWRRN;tEA#} zUQQDuWTdJ`GzwOVdbqY`WURlvbtKl&I$|$jX|HQ;9pPzi@93zGCoo@Om3dT7QtM>r zZ>wa&G&I`9k9V~d{S?McUXLYiX|2)W!F$H$38y#`$AVNh2dPoaq`X70Ap9Dp;p#(d zD6jx=Z~`9!QJk!II4^d{44ZT2!M9;`*V79M8CR#&W$BFM${Pi0|b$Ii=>1*?s-uJD3FISbnYZmJW65bXXzZ zm-)N-6^__AxjxhJ;o_3?{iJC~GyT_SHBbe74;p5xWT$Hqm+$45oS zB(#4wV=8-R9apN;mL~C1wl9IzWPLD8Jh6UMkaZc`F_W8Z3K}E<_PGEP1R@g{;s!W4 z?FPA*6iVqvIb*&d1Ra5SvEqbM6`2TQWVS!_(0_*lOF%F>}n&Mww2R2x06@5lS5NZ+#SP5*Mt&7$DFQxn-eGQSqCTeMaC1y*Y&eE z*TpW=OXT&ZR+?P5wLx9W)(z&#U;0)LYVcA0_+ycf8U}L2tTJb_bPdgobu~;)?Z<-a zYNbpa0kXpH$|H?Dgc-tCn7h!B8kY z1SlRpus5fD)>;hyhY*^5J!}tOA~+}nK5)Au@bGZ)le<02Z`}-WSPex8G4k{KFWu{= zdWQ0+0BT+CN_ZDcU7okMC!hE2+xu?z7thEazj*P2(pTg7oaqKXf24nN(v-=Wrf}4n zle>O;m-*@R&Z%?Vta;o3@BYP0S0q$@Hmu~HWgB8mO(#1hDSYw#*8;-g&jUYkahjOQ z=^825q<7|XNMp)lQf}o#Xh(KIM^mRj!|y}6I_6{K{JQ+$gm=LCOdJ#HQo>cF;$kwGtO<3{FJ= zDi&Rgx4+UW@t|LZ2J0Qo4m?_MG@PbZ zsx;W`Y%r7+XM8Rd78BZ8>tr&-3+tq2N8)pz~02@KR`|-Z-5(n8kNq= z|A_8G8ioPZ0-}e3!07-(D~i6%k^QxX#`rd8ee(MGZA1V1`HfgqxA84^t$F#RNyVjW z!>s;^eVvTUExC}iN+%uVGX@6MvEZbH#F!+2b|mH(D;}#bvGyvJbQ=tO%Ucz<@0n(^ zS+7Lnmx4;}rfBJX@qW>B*dGjS;Z01$Ibu-D6hLVNDh&%B3{mZbmK{$d|~ZV@pE$mw0ODhx8Iko ziCO6r8Z>x0U6_S4e)s|uv~~9LEc*27CHnPkOWQ(3Yg=?=)P6TWz30Y{huJf;^Kvo| z<>ZEkN7mLA$&17^HCNJe#8kAkTF9DIlwazNXIeimh-b3Nz2qFMR60N3eVpIi`hMu$ z;0l9YH}flY*7^xQnkh!B<(*s@&Jv*4)y1=To#YQR>({~$^Fp+akq4afvNF^uS=i#5OZgeJYog9yj`IDNh4S9%NKk%NBJkoT!lmmuWPx3sLc%Fw0N8DWkW zFQ?0gI&YRgtd9^P}fB2SS(W5QQ0|R)aFe5)%9>Bj(d+Va)OGFH*8?ZOM zzk~MCPw4A~k98LjJN4fP9T2&#E{S3Gw70`GoE!Hp8wIbDB!+JWhVuIR$!RE`Eks7f zI%lynv(mA%2Zb;4R(|b_*NYu5P_8+)XHFfbySVorD@H1)L-86y)D6RQO6t!+*1?Tt;%(iBuNi|M+VpxUt= z=QTsCpqkaee#lB}PT!HQz6Em(BC(wKd3JvR5drM?jc!#(7yCh&U@ANaOq zgcE4Izss7Jr}?5Rcp4S{?e^mvC)=KONlvfTo<9?Nl~F6;^K-zI^HTMy#uDY<&*`BOIaIP z_BSFq2n&V?cZWp#Jk1P7b|E zE}&}$%&*X6Lcs#Mbjb8M-|8IG4Z7P#T~w|^tO7ZMNYOlu5Qx0W1WU3&`iw40?cDT( zQqGweydYu(-Z)SiG&C`|ozwK0$9p@(*OhHCTF}^cUj_fumm)w*ceCSqc)_;vu#rG7{H+75iiTBwO2((yVG&Rd5QMiw@1}WS=D=nB$E^V`RHGKrQVC)H|r^ zX4ZH;6-wjdz11!qDDf2*iv_szJ?@WX9(rlM-dp)B=LH~u4OcNVHrjm`R?zC-U} z>eoZ-m=(R3I-}KRuZ@QDkTJy$)pc}BdcODc_8Oduwdidn06julBD{pHB+l-yMym7y zBngZ|C|db?XC7)kLB5S>j~^3}^mKK9zhjT~%Ad+XCFQ4~z5W`?g53iPN&((0c)DWv zL5#Yg5$6x*tgK?n1*VbUx`|xG-l* zT1Iy8=g%QovibcNkANi@Q@`oAMGH>Ol}pc)U1s*{TeOQS7j?qN?rjVE4s`^~&mz%i zP?pwgoLni?yxawQ`>GyPCza708TGykn@>`R@_JQEtZ zqJ~(>%!^~eu8g-7SKU!GvOwR|HJVjY-&Ch$ZI>a~+qMu%Wj<1<;!&bJoQI`Tq@I-7 zUenQEkT)>o@v3At$}-CNL0pi0vj99SF{(rH$m-^L(ksgf;1gbsjq;+NBMO)Uf&6U< z5@4Xu(%!nAwSa+F3{(vt_Q)f^rVlUdWje34jBNWH_<9YI9rVN}n?NQjyq z!gs5zn7Gby%GwW$~+vH>gwSE1%)WqD4!I6QVLo!l>z|$*`7mBIKr~%ZnXv3kpjxDaw9pCM} zYF#58UN4@&{WfQ4!m#Xs&Y3HBuiDAIj*gBK!wq(;m+F+PY^?_btT=`^xjJRx zM;Nl7Z3r|N$;ikAQJ%;NigC)xi77j?`{WFd{T}=`^Xi^-@9qK90*fbe)ZbKmLO!pF zGboi?jK^bcAHGtovrigd?D&YcX23bjqhAj+VCuBLrn_7zKWz>NNy!%Y9uj?E4@wCj z8Qhp`-aq3kIJxy{nl(G)AfO3}e)jQ{_ka~IRDh6tWa;pB-}@Tho|29$HHSt`kVaR_ zAtn#@_&5p^6O-UAt|)AMZc$QrQf_KgYGwx0==tdLg4{xYX0yB&EiZt_{&X2HE{Mrf;DI+W(ibfS(IB<;MP{sDV^(hp zSYQtX5@2GA?lxCYo1v0U-8q)dP(<2OC{QhTIzD4#(_h5KYQt5zia_S!2Sa;!6N8*_ zEnbHpE%Y&*`^H_}pF_}IN7n;}cfq8hbEl~ALz|r(bt%W39E!TKvT_NVL3y&QckyWW zwe5|~q1N&yRuiwSx1G(VY7DlgH_OE#W83NdYGO4BL0l0S+mzmg2=IF?91dBlSyj92 z=#amN?_FCnXlb#zpx*=NT12yxJu<4lzyCcI&P2?HzK!hXqcWSap<&0}7t)z|1pp-^ z=Qd}zrf244Wu#|kzx^1NR8dU@^e7Y4bZyE=S8&~QyYhvqwa6rzK_TAFzNna}m;_vz zHP~6))QiZ}Q$u|IU-ir}7Cj+jZkiGmNVG7RZ<=_Pqy(|vk2*Q@$`wmx zG*GvI+uy^Y14?G-NWyH(n{Yds4SCZjruqvwxyYk{HQF(DLNwM|tZ~-hQmazM5+f-y zl`5mScfGtB_)pQ}lbi@DH=65wJb4*L1| z1+=zp9;Ys_T{{@~C$&Y^H0AC5ZjkG&?|wB%c};^2f>(}kuI(|m?*}D));wXwL2N`G zc$_a-dhp)OGZb}pYsW@L#I*%sMjJhSZ8T7-*E>4@)jSUQUkfx``E3UNuyoJgar>oV6bHGaVaN+Q5dmc$y1I>^yyQX056VkqDnR0f)mOY-#CFK_<-`oM6ntnHFm~*-ip2s08y!uw&MP2p8*1w6T zOiJ)E4{OSV%ADA&c(#nIv%?qZjL&7jU?C3-7NbbR z1H7q~{IODlf$zTiGtSW;2{^RB0L%Q?o%_+$GcW&c`A)Hf{Q4mg2pU_6yLSy7apfM2 z4jV4K3Vi-yrw3?P4T(vod9{(3%9&5*jUFsI+i#V|5g9=TcS? zmU;j$1}sj=%X=Adx#^{#z98^}6oYYV^fhDJ;;E;4wpLC9RVyuqfp1;41~LbHa6jd- zfF`ep5A9Xj2yFmy=LZDx&7cogI$#mD)-Vxn z|I;K3soD)d(d-eqgYe-nC=h(?t{ZlhO=8)E@q>&)S|_XS)Aj3zGf~M~r7v8rbYwrg z_;6~rqF~}Bjc}kdT|XZAh9u>qZLG?4?42cEz^3lteN>IEUEeQDyf}Bcgzl{Meta%A znR%D}w;^8782l~Q($g7r7_|B-!gLsv1h;x56;862tTPAIpoI}2gm!v~(etuq~X-*xR{`ULU3nP>YndnhpKeq02EGU-QHdR>0koxY4 zjX)4cf(=W2V)}+CIXxEEWxtt}$lIIrP1uJ=;Bc}YOkH!!Ptpj5NYk~kYF|!QGhjLmiw171sFpHa^a{<0cim1$bboCNcL$xrOcXC&qJCp zw~kIUzm}5+$>z;fM&ZQ%Mh0J%USq^*=YYPN1_g-MiKi8)xiPM3`x^pOE=wKQkbU$fA>Z1T5EZrlthBn`6Ba zs|o(cn+MIW<^_3y|3u4^8_9l@o5H7NOCwiU?G(bkk)5!s=o~4D@5s53LO=%(&Od?{ z#uov%GKv7wY`Ev)@yo`22hHhU6<;e+$03Rl|8+#xSl5U#sTBnmn)Fe-glXtkr6>bw z-v3mh#=Xm)R9;!IQiuDN%u6u5GbR0}x;SD(UOtxIU-(o;c5-`kOYyYxV2R96Yq1ovHKs9%U*|)yuz$(D)1Q+Zi+(!ZM z8Vf;Qg3XteRRB8Y&YXJ{kOqM30GJ#|b_iVOWe&!j#rJ>C7(8Gw{?{e%0YNYSVXP3u z0R8>JvzUiiw53-}QCj`H(L>DWR_7>$TF!6c%41@E%-q<)}6gOelRmEsfh z#B#hC+p?2vQrQ0lc6uV!M!*FfN0pP^3Yd1I7tn%1_eT~Gc<!S$cK(i@jKJ=-)VpxKq~)W^xsKH{yO82EJVZr zn2jO*o$0S6zsnW)FYX2wDCGWjeiw}K`w@PhK&L9G_#derRTRaa#PxPD)nnNd;IELX z($?h;dp=YyE0^!K82D%U=fBO2h|$idJWdjFuH~Ol4N-J`kSm0B>iyFV5?ck_Pv)o4kGse05*$$+fJFgCqh6Kz&foUcryN&*?+l$F#Nq`z+LFLYz$$x(mVr%8M-4!7FZ@Vk^C+kXN$Z!=1xo7O@yE)G6BY`;> z``SP1%HzKGu0?JlzUvY1z?}bti;%yK3J0&c?G9#X|8h3+j}AR+{nRbY?bFMP5U}aJ z!;*jWdj;Oj?d;?E@fL^6PWM z^Y9~GhwLQ_}&mdKkB?`eSH3q^n=LlR|GhsG+33Rn-qK}UP%OUb964fdbCUF zn<5{z6)aOXF6iAe)dH*IvsfjEn+RlT7Z(>dVcKV%L-Ff27sc1Kelj^D$p`JWm+0u9 zK7C4TxN2Q05B{89m;c$jtgfzZxS;H4X{+bxgjS$#Y8eh6K(;zjwRUbAQ*B0MN$5l} zW<(~2WMm{33gz2a!@hjS3e!sk3p!Ok17Sl)g42uZ-h6!AYafu2=@#%g9<7J+aG~2% zH4z&@HZ`ao`lEYLUg52_irnEMP8rMOLMZFw0Z*6aw8)ivAs=fzlW8C4WVEg9~?w4fp8tYmLK;Ml9wNpO)?Iikzcw&`!$&^^ypa z?oYQ|`dhB(4wmj9#3HxRE8L%NoXnJGM5Wc`MfsGKjTMybtn9RJvh?*`B4+AF3)bD~ zRK^k#Z<2pT3{Ll7&SDK7xg^sK>|Q3F_C@G_J+E-)OddGaDf#ime#K;dG71pu4u~nA z3X2Sm7O5{7mi5@TS@#=Ecl(C2ioaT3dCeyAbj`rPfMp=Lv_Zpp>W+^fnju;(A{V%a z0Z8R_eonI%ke$d^o{47d0FrhoduL})3CT(*-HYKo`O(6fas?lkeZlREyf%f=ZuRwf zx@Hw0fV}+jiji56kpKx;jN^HJsW&K<_~Cc>!lUcQFuz!8_pEV^TQ|b<#(~??dl+Sz+x%>x1vINE#M9pEqiGUkN9U*|Y?cM9+`1E`>aK=?+ZSIPyB8vAu$Ii$iY z{E6DIv6fB1%#qMH*0T2UGqvsz?^oG?e`O=aC%EkpJKUy%f_Fg7)PXyj+!Wd6xNQ)Z zSq1M;#4b^(xm42*tWh>NI1st{i|ClX0nQuJf%oHNY<_vmyM9x%onJQ`)E7p6`)b5B zM7MU!O>H8%G2(ibc{Y&MtS!p%(#*}bd+w5kd*5>v!PxENw;cGM79o9y1=P1Q5kZw#`{oyI|8Mh?^t{d#s$h=P|DwXUO=@LLxn~Y0*OyZ7eV_ntP zZ(jZs2OocC;OECZ2j_u(fNm&p#CMQ)6*?K&nO`j>B!qQ*4@lYWm;CYL$IoGy98d_BJkqWqk^u+=i)94xBb7lV* z-9vH@<)K&Ogo1lQ{8pZn6e{^*JL|2ncvvCu2yRAzsoB`{jJU>LDYl@2n~dl|uzbY9 z+JrxW3X9==h(Huh)S$6@?0CtUDv@PaHg4)}zj<^!c;>2ce0fbLd{a+2f5oX$WVm_D zt#Wp8(^#~5(a=#+HFLme#(XqyaW*B6c^lNWbfqyG*?DFYBaN(ic* zkx5C($9+vLp;EqDv9n{6tFW`PGu$SB;Ir;W7t^dqP$=~9uGc41_}zwaIMrxK;VXL z&9q`o*(lD)zzCDwNR&KNMWyshQQE>C3<}9Fg3A|M?T%vDI=V~6tzBI@5rgwC%Q#8`+ngj4n_Kimk{cS&ZAEx0^VU^-rkQO|DTBOxEKZy zR@!g2kyqOxn%w41*3|CFt?SlxQPs&z|HcI;K^n3{wttL4c6N3q4z0(n>#hwX=k?CHM8yc1dKs3XHjyappNNR_; zeVFwtr+4gXll|uBv$9u(&*~u9dvqz+TV}f`_Uf4{cGreoJFcWuA^whOV8s6v@j2pi zHi@Wcsmf#G_Q%RAzW__U^(~dOaqM>6lP*^-)GJ#yFRgL(mR3r%MkS=W?Q!}5{`c@m zP(8rslyCw#{z}4l&^>qZHw32(eNa<9o#fvk2OiP*^C;IL%7oop{l>=*Gw&|F_G!;& zUC%0S(B|CXt7^X|N8GONUB24gG@JFi_J4RgD{pb)`hW?C^?Bw@AC2=T7E8PmG}E}^ zHIwr`4ff=Vf9p85(-_UF-q>yc*!<=d zQ#sPHhJ%@ZcoEXR=*31V5pWkn^EJDXKecw+tQc)EIN|c>=WL4cQY3Fmug}1sjG9OuffvxlNM-+1fDM5& zyw|`mG@r#b%uE6BIv{W2-~idkrEp$S)n1n%1O+$SB($pdTFngDX}a7N%*i%p7w za%Nd2vyOJD69)jzTdR~yxvDSM*^X+LPHqd?rKQ!58a=xrAUFah zk1oMkQ9DjIMpkZiW=2j<0VdOAgmJ#%0A(JN{6s?t(2pc6Krftcf#cl#??L734Ivl?G&`!wMHYpA|doGX}dZxmYQc zxba-lvmzF5O4UVTMRIa-va1`>tmHTnivoqD-?ovFlQYD|-wXPgnQ2&K0pN@pAbBCI zcs*oc@xdPjfe+8}UB8_Ckk%buLP}Pato?mbMNJNX^ZGeDrGnV4pas>2X*2H=_Xz_{ z5JSxiBCSUIC9UpeK_CGP36S8!XMz4VWF>s&UKLtP9>Dz9@1IQ|PJ@E^1lW@UK?m%i z3y@&9i*>vXe?#g|!stFbS-N?WuKI>!Px$Og9d*mwJ8haZz|avVAeh7M0>#z$SM%&Y zKAWz#8JMhzw!M>2-z)@k{On>m?1yE3$AbX-B5zO%e6IT4hf|o7Hd&tFX$F8oNHP$z zy~H>84x!zMMZ-UgYs%^5oro`=m<6dF+Lo&C4jX3zPJPjCIT;dlW0MJD?N9> z6#xmHmQDl<4fd7t;5mcmB_i_R1229jjc1q)6I|e<_`f++g($-T+HH#eWxDKZ7_&+n;$ zbWkPP4!yN?)PsaEhS_X(u;?BjZ7A@jCn(N|9+edqnmA;vqa@P;1?ieU*i94CPt8Hl zH&4S6$cn!c|Kvj$A|@(v4pV6Tbk0TCDz?GLygFPldzgD~RSpD;wUX3rGWpcBXp@`x zmh8meCfDOOE*tr#@l)dC^P8f+TPj)EoIjcJ_aS14GFWU<+H?2Sj@naRUjl(}Uf54- z?yH+=Un>>2HLic-h<7!{npGQa0c{#MJ9navgv6Dlh1*`x(9pabuiKhh4Y#us)pJJo;vYXR#V*y2k4;RNsAl&)D!>D9 zU*D9cq35_!YZsEojWDFX;WzIg@gkMcp{x5BjlM_g$GxWE_qB#!PSBL-Wm!ylZ4`(S zCfG#;;3bfe7D8w)7g1gh0RU|P#>jBF1eQSX-}U~;nU5*OUMTybre zVd@l&RM1vXKipPc(A$-Sft$gc`vhQa&>WWsCLr}(29;CM%Bq{2mnG#l%~2|rX!T(b z5JaUzB?bfNY|8V@)NU4v4T%&1Q4~&?Snq1nCH- z(={Gk)r(@f=%Tiv;q-P*ua5xb6#CCSrys-g#dJXc(<*)iz$*{?Kz<=v`Tld-m?kj6 z)Q2qzyG0g~b~m6lUfo zL10XUCB5kqMp{;17@75gdc{NpmoqYQ!}dqy#^~Dp}YxSwXG&ZdJ zG92CDdD~hxeD}VF+S;|Ly#gWxeT#xLywSEuAF?GR00CGo>M%c6E5%#MA7?Na&QqXw zVK!4^wc8QboN?)G-A2(vkza{R&CN^-&&_#Fh+55Ps%C2sUH#HcUpW4W5;*E<&g0?r zV=WT4^*m>WPxWp9u5*0HJ|k0?y3R`as}&ck$eT@L$LiRefa>b%M!HzWm&$?Z<+ifN z0eZKLMvfD>t?L^`xtothM<-Pa3Kg_6q-!^anKy>>)EqL$jh6F9i<%opx>cf<#75`K z%!cDJdlQ#eIP83w%v(D|9=xLMW-u)3|X-cy0nhlcx9x z@A`gN@|PFCry!_oz)Rnqvp$HQKbZF*M$m&MsC!R<51Ig9eGgLZJOKVmg5m)h`t1Vn z&RJkF2-gG11;C3O<6Q5Ii|;JiGl?N*(n}OZltP{ehn1S0zAE+0$PO7go`icnqmQ&VWY* z11bZzsB&$?h;o&|>>{KtIR!*y5z%|02?f37kKm==CW)qQbH0P0R8i*oc9;xWsRl;MJmt%~S6BhZqu`s3^M?F*9O z^_vcp!0F$>@8@_j_Q>|gjKYU!xww;=je94@LH=+B$>IF_^hWPTxZa&P3>-^3sDh zZqHE;Jtor@2vK*HrZ?6Bh7M#41A)NMJRk%fXb~dN9RZBJzY&xaDVUG%&2{6lm{}U) zyuIBmlvVewrO_1I(#;MgZqK`S?=A|$Qa*L=$> zHytnCCNC~6Dc&Ae66x+yRZ*ExRaLc%P(6FLv~99Y<9tKua1>3T@-`?yWWC-nm-kET z3Mc6w}0LmTk(+jwc7m?3|t*;0>u%DPKn*x+82SCCNz5G9?!g{SP+ zHCmLD-G>hmP`ZMQoMeFJ0H5+@$EmsLj;xx>gj%-b7x|=2xQp5;WEB04qM}i@{=uIE zKULuJa$mzop?58xog5X2M-^*K4f!g7fick&CK%vz4q6cb~FJ0s$K z-1JaV8*V2bs<+rpsU72L&|q923RVJ8i`d(O;E4N!SUOg4jc9OvAjmB6!<}604upH) zJd6%~0D7=CQo+Ab^*e(Y(h1{b^(07Lu&!MKK%&=6Hs1k`*6p5`H#n`R*tK!qxddyy z-^7g)TL|6zec1mKt>}>okn;I!lLX&Hs8HaTZIG>B!}5%eiYjf2zBAp+J=rd}oW8=l zW4QXe2$+>Ezh0)sC=p|Q3rEchmJ}gM34aWj%z_*~;su*8T;GnkHT=9)Q`oJolg->& zI5~wGzX`gBXBw|AU^5F}5b;lOf zw8sJ86+9oF9#n%NkCPy7&PRitUjHVvOhO^&$rBvaB=*vYVBlj3-F3)pdD*9|W!y?Bug|*jPmPHBs?DyS*i!DfQSH0HAW1x30 zp$v$uh!CHF+xZR128JE~TpwHJP)snM2LjaO zPa&W1N4~~dAutq5ut1`R=%soSZ`K2Pm|FnXC+J^#m=}{ZK%WipRUdA&ol!Z@-ZAc; zr8(D+-5%c>BHUux@$vETH!l{H)LS}KtZa)0#T$2bUr{sun%JM)w_R6EUuOmB9-F$= zM-P@wn31O6)c0+gL-?xB1uKWRYO_coNM!w4%ZE;QI~ue7Yc_1);U}DmZdq^hhJF2G z;xZIgf)9S2XJ>Pi+1TvgP{la~D#t-6ck<~JQd=~$k*w;Zy1GW8Iv}V5rf%}Hg$mjq z4#h#Cg+LqS9(_Gz+OU@j1L)R)eB6ql+@3xkFF3FoThY}4n22ovUh*lk$$X0+t(pNR zJ5R9*H+|M5Tr`N}UO5wUa|5D+dh>{F;lRnl6_3E4KLe?6`N)a$ovOhvUTMCn-3bl1 zoALA5@#^4-*9MCdC(|re(}UUP8TSC{T6Ni+8ce<6*r~kO~E-w z$me%tsTq5ZQYg>M4_Z#&3*rVzNeMwjWOuSMKyD@labZjI1R@^;eA?cL%K)y2ld17a zL->hVvbK6`xY&bb^<4E9RaIu=CjxKHS=dKAI+DpE2GyNP5gGez8sS- zbCk~1)7AGayI_PBe|;*k`LO4lb(+xHQfha5CBtrT_@(=URok}*-L_82vVyWh6Nbq& zauQL|jxq|9muu@en^foJPc&?`lxw;gR1?*7iX_6LNS>MY`v+`1_e(zb#?SBMdQP~& zb=!U9eD#05UI(huR@(q|Hn>RFq{dJAS9d`NYM18L6oQ&nAdy3Y9R~o zrv9}W09;8y=Jvk{a4`1KZP?wXJh4tdT3SHrkrXHS;MG04%=GcR%5+#|2_)t|mjj?mK+^cD04eq&>O zf&W-vAPi&`j1B9_)#HCP!v2b$Grt87rSE{)#L{2U(qE~aSo6Qzfb{o??=vdvtKs$4 zu<=)+;*1K5o(}x=+`s`L;f9Km+ec&0$n~U3;dh&9bpYk4v{jtAZQ_b0qLfq@@!bS@^2G$z#Qg7K<*1j=AnMMV*3?oTfTjIJvw}_6AP}~ zzdoLEb0Lr?th8^Tt%C0Ikbxtpc|O~kcW{eyqAwE>Z(TjVK_)GCzmdMiMS0-GoASfp z?+1XzchS6EyGpsrkO$$%Al_;r9|8gdI!?GVBL*SQnOlrTn9uoIlFJ{G*ttj6Wj(td7_}it$HA z?))P$HvJz#oOdATKTFg7D?Ue1_OqObAheJ1Pj`V0+MOEiwUQA_g?`BW#l=BZ0qGiHbXE$$M^qz^PihAehXno4~ zkAGk8V!!AZ0)O}E@{#)`diMzeQTPrvm-*yGBqOateDE4pg_c7QIT4580$GZr0@*r# z4##@KwrZhBJ)MtDYD^yew|xlEEtsrrImc)HuetIg5PImDm0Tk zdUn}Y|3evix_UaVI3>)HIs7%4vtXX>D*d3KTXvxOcLx(^*JN` z11aj7zGfF;AmZs+Orm)$9*ensboNvq`=~p#X_JJ%s$ZCP<2<8~=c%ZJk?0E2U)L|+ z&f^SEM{q`^@nBj=#4cEpBEC?bd}^Pam{g!OiSD{{`*V2E!*nui+7hHrK`ZV-B8cLa zj?S4(VQ1#B{bon<3;)1{ARdOmVD*daG+jh|&TQIZ=#A`o8>xfyHZW@PskyZ=#R(DJ zrkzm2K5SdZj%g`6s^S+yVgguIzIxHnSrp+2+w)h)qU@2w(EH{XRv%VP)gw(RTgn?5 zkL&mDtB!LMz_HNTA8Qyk!mPQPHy)j%eY@y?kVU7{g5tEjt=MEXEDd~P2C1*3uQ&{vnK{q07CNhR-pEo}Mhe8ze?jn{WqcFV1wzIDCJezRsF zraR^bi!{Cz-CNvzZ2O&pjX!%Onr(vZnx4<>`220-lMfp+LP8n$r+210*dM<8`>n6q zg~jhoiy7W(F^ZVgJ~=+cDkgvDKK&zm?PVXIKOVIwaFNpDkc`DHQKoLdlee}_>Nw)o zu~karBCsL3NZBPf*~RVXmcT`(Qj1-sl&+b$WV8yHea&60rtmU0*8a+w2-D-sUKdJL zJX~pCuk_ksq7tyh2|7d)e3~S1#a2j^mT6ZvXpU{gibadAWQzoWTQQ=avw$(XwP=sG za8>v9+sik2?qAuuqdMZ_o>@oBc=LcWNCIV#1Owd`;Wf@_;sQ-Brin`(ieG=dy?svI z0$?!;Ec3vJrvi&mVEG3=NR@a&&?%}A?GnIKRH52of(fb(tY0_D8nm+D^&#-c%#~71 z6BcObO<_I3FqL_B$JsdI+T^aTa#OeZp6Ugj#Yuz)-LhM&uYLPjJs&t7%+5-kQX z3pBnAR0K9TuK;WZPyjSg%?dIVWH``9GlUEHat|<1d%*B+J4oXOh7gcjK+4$;07s-l z7(^LZ9l%4=tRQ_lKt3C2xErcS8YBzR1XK@k1kg30p=>Ze2do}Gv<>zIH$)F~XdPr9 z*bK0lpg=&_!5ZqaG`cKdQL#|p;v)@BGuVzTTGUJEj7KftlEb56M5+U&SI|^$R96@H z%t+ATk!GN77bpXO`eCM^9MKD&&Q)w!p;%!(=TGKMMql8{MqPX-ur351GYLFvQh0vw zW;ve1n(O)!E;A4vj$?-1BFG((V@8oWf$-*wVNc4&$znbcCzEFT%-9GOmeff(21Gw< z-)^7%I~3S6#2yY(h_fz%P8VAno4ab(m(J)AgyFz8ev)CA^5b9k&R5@zo@FYf+r_2T zD|X{zPC#Ht#+8h1Cb_O%i`^ExZd{zD6YAETG^so3=%S-Qo=LQru9$AGbl{>J7gub| z2@1@~*me|n-BymOqNme^ORcI}3g4dGS;2O!=iTfbd*8JNNIU-%KAAgRe(sh+)154j zUIiBJTz2=){X^@I9zWXkFWrvIvSwA6{zBG$jYR?3alJ9Cw6~X}XdGC`uy5~%oqb;z z9L)|ewY@G-^R3_9c8qD!_NIpp8nLY08n16xNf&wM#oqXprxw%lQZ`=c*5>AYANHIp z@SV9tR$A=l+4!y9r@u>=F*5yG8eglyJ?Y_<1CI)KbE{wM=d$dO@%Z}xS83!&hTT@? zU%xiQ?%w+C9c#wM#d&@cgMhcS9@PmJIjR$MST|TASA3WHj9u4ebpMQN*B5_nob_q5 Z+Whai@wxt<|9|YBq{(Rh&liO From 0165a9b1216b56e417e647892aaeda5741f3ce5a Mon Sep 17 00:00:00 2001 From: Saveliy Skresanov Date: Fri, 6 Oct 2023 23:10:47 +0700 Subject: [PATCH 23/27] Fix a bug in the font editor where the last row of a symbol is cleared when shifting the whole symbol up. --- src/gui/font/FontEditor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/font/FontEditor.cpp b/src/gui/font/FontEditor.cpp index b7ce036e1..1641b4242 100644 --- a/src/gui/font/FontEditor.cpp +++ b/src/gui/font/FontEditor.cpp @@ -529,7 +529,7 @@ void FontEditor::Translate(std::array, FONT_H> &pixe std::array, FONT_H> old = pixels; for(int j = 0; j < FONT_H; j++) for(int i = 0; i < MAX_WIDTH; i++) - if(i - dx >= 0 && i - dx + 1 < MAX_WIDTH && j - dy >= 0 && j - dy + 1 < FONT_H) + if(i - dx >= 0 && i - dx < MAX_WIDTH && j - dy >= 0 && j - dy < FONT_H) pixels[j][i] = old[j - dy][i - dx]; else pixels[j][i] = 0; From 4377f83184fbdba04f8712544a13bc62611bf3d5 Mon Sep 17 00:00:00 2001 From: Saveliy Skresanov Date: Sat, 30 Sep 2023 20:05:29 +0700 Subject: [PATCH 24/27] Add liquid resist (RSST) and solid resist (RSSS). --- src/simulation/Simulation.cpp | 4 ++- src/simulation/elements/BTRY.cpp | 3 +- src/simulation/elements/DLAY.cpp | 3 +- src/simulation/elements/DTEC.cpp | 3 +- src/simulation/elements/ELEC.cpp | 9 +++++ src/simulation/elements/GRVT.cpp | 19 ++++++++++ src/simulation/elements/LITH.cpp | 6 ++-- src/simulation/elements/LSNS.cpp | 3 +- src/simulation/elements/NEUT.cpp | 8 +++++ src/simulation/elements/PHOT.cpp | 7 ++++ src/simulation/elements/PROT.cpp | 12 +++++++ src/simulation/elements/PSNS.cpp | 3 +- src/simulation/elements/RSSS.cpp | 55 +++++++++++++++++++++++++++++ src/simulation/elements/RSST.cpp | 43 ++++++++++++++++++++++ src/simulation/elements/SPRK.cpp | 13 +++---- src/simulation/elements/SWCH.cpp | 3 +- src/simulation/elements/TSNS.cpp | 3 +- src/simulation/elements/VSNS.cpp | 3 +- src/simulation/elements/meson.build | 2 ++ 19 files changed, 185 insertions(+), 17 deletions(-) create mode 100644 src/simulation/elements/RSSS.cpp create mode 100644 src/simulation/elements/RSST.cpp diff --git a/src/simulation/Simulation.cpp b/src/simulation/Simulation.cpp index 1950bf77a..260223a30 100644 --- a/src/simulation/Simulation.cpp +++ b/src/simulation/Simulation.cpp @@ -1197,7 +1197,7 @@ void Simulation::init_can_move() || destinationType == PT_CLNE || destinationType == PT_PCLN || destinationType == PT_BCLN || destinationType == PT_PBCN || destinationType == PT_WATR || destinationType == PT_DSTW || destinationType == PT_SLTW || destinationType == PT_GLOW || destinationType == PT_ISOZ || destinationType == PT_ISZS || destinationType == PT_QRTZ || destinationType == PT_PQRT - || destinationType == PT_H2 || destinationType == PT_BGLA || destinationType == PT_C5) + || destinationType == PT_H2 || destinationType == PT_BGLA || destinationType == PT_C5 || destinationType == PT_RSST) can_move[PT_PHOT][destinationType] = 2; if (destinationType != PT_DMND && destinationType != PT_INSL && destinationType != PT_VOID && destinationType != PT_PVOD && destinationType != PT_VIBR && destinationType != PT_BVBR && destinationType != PT_PRTI && destinationType != PT_PRTO) { @@ -1238,6 +1238,8 @@ void Simulation::init_can_move() can_move[PT_TRON][PT_SWCH] = 3; can_move[PT_SOAP][PT_OIL] = 0; can_move[PT_OIL][PT_SOAP] = 1; + can_move[PT_ELEC][PT_RSST] = 2; + can_move[PT_ELEC][PT_RSSS] = 2; } /* diff --git a/src/simulation/elements/BTRY.cpp b/src/simulation/elements/BTRY.cpp index 2f5dd934a..c580132b3 100644 --- a/src/simulation/elements/BTRY.cpp +++ b/src/simulation/elements/BTRY.cpp @@ -57,7 +57,8 @@ static int update(UPDATE_FUNC_ARGS) if (!r) continue; auto rt = TYP(r); - if (sim->parts_avg(i,ID(r),PT_INSL) != PT_INSL) + auto pavg = sim->parts_avg(i,ID(r),PT_INSL); + if (pavg!=PT_INSL && pavg!=PT_RSSS) { if ((sim->elements[rt].Properties&PROP_CONDUCTS) && !(rt==PT_WATR||rt==PT_SLTW||rt==PT_NTCT||rt==PT_PTCT||rt==PT_INWR) && parts[ID(r)].life==0) { diff --git a/src/simulation/elements/DLAY.cpp b/src/simulation/elements/DLAY.cpp index bbc14ad0b..f3a071ec3 100644 --- a/src/simulation/elements/DLAY.cpp +++ b/src/simulation/elements/DLAY.cpp @@ -62,7 +62,8 @@ static int update(UPDATE_FUNC_ARGS) if (rx || ry) { auto r = pmap[y+ry][x+rx]; - if (!r || sim->parts_avg(ID(r), i,PT_INSL)==PT_INSL) + auto pavg = sim->parts_avg(ID(r), i, PT_INSL); + if (!r || pavg==PT_INSL || pavg==PT_RSSS) continue; if (TYP(r)==PT_SPRK && parts[i].life==0 && parts[ID(r)].life>0 && parts[ID(r)].life<4 && parts[ID(r)].ctype==PT_PSCN) { diff --git a/src/simulation/elements/DTEC.cpp b/src/simulation/elements/DTEC.cpp index 911bd2dde..f9eb703b0 100644 --- a/src/simulation/elements/DTEC.cpp +++ b/src/simulation/elements/DTEC.cpp @@ -66,7 +66,8 @@ static int update(UPDATE_FUNC_ARGS) if (!r) continue; auto rt = TYP(r); - if (sim->parts_avg(i,ID(r),PT_INSL) != PT_INSL) + auto pavg = sim->parts_avg(i,ID(r),PT_INSL); + if (pavg != PT_INSL && pavg != PT_RSSS) { if ((sim->elements[rt].Properties&PROP_CONDUCTS) && !(rt==PT_WATR||rt==PT_SLTW||rt==PT_NTCT||rt==PT_PTCT||rt==PT_INWR) && parts[ID(r)].life==0) { diff --git a/src/simulation/elements/ELEC.cpp b/src/simulation/elements/ELEC.cpp index 9874019e9..9b3c10086 100644 --- a/src/simulation/elements/ELEC.cpp +++ b/src/simulation/elements/ELEC.cpp @@ -115,6 +115,15 @@ static int update(UPDATE_FUNC_ARGS) parts[ID(r)].tmp2 += 5; parts[ID(r)].life = 1000; break; + case PT_RSST: + if(!rx && !ry) + { + sim->kill_part(ID(r)); + sim->kill_part(i); + + return 1; + } + break; case PT_NONE: //seems to speed up ELEC even if it isn't used break; default: diff --git a/src/simulation/elements/GRVT.cpp b/src/simulation/elements/GRVT.cpp index 55fc9608a..348f06d97 100644 --- a/src/simulation/elements/GRVT.cpp +++ b/src/simulation/elements/GRVT.cpp @@ -59,6 +59,25 @@ static int update(UPDATE_FUNC_ARGS) if (parts[i].tmp <= -100) parts[i].tmp = -100; + int under = pmap[y][x]; + int utype = TYP(under); + int uID = ID(under); + + if(utype == PT_RSST) + { + sim->part_change_type(uID, x, y, PT_SWCH); + sim->kill_part(i); + + return 1; + } + else if(utype == PT_RSSS) + { + sim->part_change_type(uID, x, y, PT_NSCN); + sim->kill_part(i); + + return 1; + } + sim->gravmap[(y/CELL)*XCELLS+(x/CELL)] = 0.2f*parts[i].tmp; return 0; } diff --git a/src/simulation/elements/LITH.cpp b/src/simulation/elements/LITH.cpp index 4ace0e832..10605a255 100644 --- a/src/simulation/elements/LITH.cpp +++ b/src/simulation/elements/LITH.cpp @@ -93,6 +93,8 @@ static int update(UPDATE_FUNC_ARGS) } Particle &neighbor = parts[ID(neighborData)]; + auto pavg = sim->parts_avg(i, ID(neighborData), PT_INSL); + switch (TYP(neighborData)) { case PT_SLTW: @@ -134,7 +136,7 @@ static int update(UPDATE_FUNC_ARGS) break; case PT_SPRK: - if (sim->parts_avg(i, ID(neighborData), PT_INSL) == PT_INSL) + if (pavg == PT_INSL || pavg == PT_RSSS) { break; } @@ -149,7 +151,7 @@ static int update(UPDATE_FUNC_ARGS) break; case PT_NSCN: - if (sim->parts_avg(i, ID(neighborData), PT_INSL) == PT_INSL) + if (pavg == PT_INSL || pavg == PT_RSSS) { break; } diff --git a/src/simulation/elements/LSNS.cpp b/src/simulation/elements/LSNS.cpp index a70f4a22e..794ad3fe5 100644 --- a/src/simulation/elements/LSNS.cpp +++ b/src/simulation/elements/LSNS.cpp @@ -67,7 +67,8 @@ static int update(UPDATE_FUNC_ARGS) if (!r) continue; int rt = TYP(r); - if (sim->parts_avg(i, ID(r), PT_INSL) != PT_INSL) + auto pavg = sim->parts_avg(i, ID(r), PT_INSL); + if (pavg != PT_INSL && pavg != PT_RSSS) { if ((sim->elements[rt].Properties&PROP_CONDUCTS) && !(rt == PT_WATR || rt == PT_SLTW || rt == PT_NTCT || rt == PT_PTCT || rt == PT_INWR) && parts[ID(r)].life == 0) { diff --git a/src/simulation/elements/NEUT.cpp b/src/simulation/elements/NEUT.cpp index bfd0c146a..d367556a5 100644 --- a/src/simulation/elements/NEUT.cpp +++ b/src/simulation/elements/NEUT.cpp @@ -164,6 +164,14 @@ static int update(UPDATE_FUNC_ARGS) else sim->create_part(ID(r), x+rx, y+ry, PT_CAUS); break; + case PT_RSSS: + if(!rx && !ry) + { + sim->part_change_type(ID(r), x, y, PT_RSST); + sim->kill_part(i); + return 1; + } + break; default: break; } diff --git a/src/simulation/elements/PHOT.cpp b/src/simulation/elements/PHOT.cpp index fc7b21641..29a8f94bb 100644 --- a/src/simulation/elements/PHOT.cpp +++ b/src/simulation/elements/PHOT.cpp @@ -107,6 +107,13 @@ static int update(UPDATE_FUNC_ARGS) parts[i].vx = vx; parts[i].vy = vy; } + else if(TYP(r) == PT_RSST && !ry && !rx)//if on RSST + { + sim->part_change_type(ID(r),x,y,PT_RSSS); + sim->kill_part(i); + + return 1; + } else if (TYP(r) == PT_FILT && parts[ID(r)].tmp==9) { parts[i].vx += ((float)sim->rng.between(-500, 500))/1000.0f; diff --git a/src/simulation/elements/PROT.cpp b/src/simulation/elements/PROT.cpp index 5d0c7a2a3..f5a997932 100644 --- a/src/simulation/elements/PROT.cpp +++ b/src/simulation/elements/PROT.cpp @@ -101,6 +101,18 @@ static int update(UPDATE_FUNC_ARGS) else change = 0.0f; parts[uID].temp = restrict_flt(parts[uID].temp + change, MIN_TEMP, MAX_TEMP); break; + case PT_RSST: + { + sim->part_change_type(uID, x, y, PT_METL); + sim->kill_part(i); + } + break; + case PT_RSSS: + { + sim->part_change_type(uID, x, y, PT_PSCN); + sim->kill_part(i); + } + break; case PT_NONE: //slowly kill if it's not inside an element if (parts[i].life) diff --git a/src/simulation/elements/PSNS.cpp b/src/simulation/elements/PSNS.cpp index 3d893f287..06b94113d 100644 --- a/src/simulation/elements/PSNS.cpp +++ b/src/simulation/elements/PSNS.cpp @@ -59,7 +59,8 @@ static int update(UPDATE_FUNC_ARGS) auto r = pmap[y+ry][x+rx]; if (!r) continue; - if (sim->parts_avg(i,ID(r),PT_INSL) != PT_INSL) + auto pavg = sim->parts_avg(i,ID(r),PT_INSL); + if (pavg != PT_INSL && pavg != PT_RSSS) { auto rt = TYP(r); if ((sim->elements[rt].Properties&PROP_CONDUCTS) && !(rt==PT_WATR||rt==PT_SLTW||rt==PT_NTCT||rt==PT_PTCT||rt==PT_INWR) && parts[ID(r)].life==0) diff --git a/src/simulation/elements/RSSS.cpp b/src/simulation/elements/RSSS.cpp new file mode 100644 index 000000000..a853ddd13 --- /dev/null +++ b/src/simulation/elements/RSSS.cpp @@ -0,0 +1,55 @@ +#include "simulation/ElementCommon.h" +#include "simulation/Air.h" + +static int update(UPDATE_FUNC_ARGS); + +void Element::Element_RSSS() +{ + Identifier = "DEFAULT_PT_RSSS"; + Name = "RSSS"; + Colour = 0xC43626_rgb; + MenuVisible = 1; + MenuSection = SC_SOLIDS; + Enabled = 1; + + Advection = 0.0f; + AirDrag = 0.00f * CFDS; + AirLoss = 0.90f; + Loss = 0.00f; + Collision = 0.0f; + Gravity = 0.0f; + Diffusion = 0.00f; + HotAir = 0.000f * CFDS; + Falldown = 0; + + Flammable = 0; + Explosive = 0; + Meltable = 0; + Hardness = 0; + + Weight = 100; + + HeatConduct = 251; + Description = "Solidified resist."; + + Properties = TYPE_SOLID|PROP_NEUTPASS; + + LowPressure = IPL; + LowPressureTransition = NT; + HighPressure = IPH; + HighPressureTransition = NT; + LowTemperature = ITL; + LowTemperatureTransition = NT; + HighTemperature = ITH; + HighTemperatureTransition = NT; + + Update = &update; +} + +static int update(UPDATE_FUNC_ARGS) +{ + sim->air->bmap_blockair[y/CELL][x/CELL] = 1; + sim->air->bmap_blockairh[y/CELL][x/CELL] = 0x8; + + return 0; +} diff --git a/src/simulation/elements/RSST.cpp b/src/simulation/elements/RSST.cpp new file mode 100644 index 000000000..bfe304284 --- /dev/null +++ b/src/simulation/elements/RSST.cpp @@ -0,0 +1,43 @@ +#include "simulation/ElementCommon.h" + +void Element::Element_RSST() +{ + Identifier = "DEFAULT_PT_RSST"; + Name = "RSST"; + Colour = 0xF95B49_rgb; + MenuVisible = 1; + MenuSection = SC_LIQUID; + Enabled = 1; + + Advection = 0.3f; + AirDrag = 0.02f * CFDS; + AirLoss = 0.98f; + Loss = 0.80f; + Collision = 0.0f; + Gravity = 0.15f; + Diffusion = 0.00f; + HotAir = 0.000f * CFDS; + Falldown = 2; + + Flammable = 0; + Explosive = 0; + Meltable = 0; + Hardness = 50; + + Weight = 40; + + DefaultProperties.temp = R_TEMP + 20.0f + 273.15f; + HeatConduct = 44; + Description = "Resist."; + + Properties = TYPE_LIQUID|PROP_NEUTPASS; + + LowPressure = IPL; + LowPressureTransition = NT; + HighPressure = IPH; + HighPressureTransition = NT; + LowTemperature = ITL; + LowTemperatureTransition = NT; + HighTemperature = ITH; + HighTemperatureTransition = NT; +} diff --git a/src/simulation/elements/SPRK.cpp b/src/simulation/elements/SPRK.cpp index 4b43a5869..cc06f8aae 100644 --- a/src/simulation/elements/SPRK.cpp +++ b/src/simulation/elements/SPRK.cpp @@ -89,7 +89,8 @@ static int update(UPDATE_FUNC_ARGS) { int Element_ETRD_nearestSparkablePart(Simulation *sim, int targetId); auto nearp = Element_ETRD_nearestSparkablePart(sim, i); - if (nearp!=-1 && sim->parts_avg(i, nearp, PT_INSL)!=PT_INSL) + auto pavg = sim->parts_avg(i, nearp, PT_INSL); + if (nearp!=-1 && pavg!=PT_INSL && pavg!=PT_RSSS) { sim->CreateLine(x, y, (int)(parts[nearp].x+0.5f), (int)(parts[nearp].y+0.5f), PT_PLSM); parts[i].life = 20; @@ -197,7 +198,7 @@ static int update(UPDATE_FUNC_ARGS) switch (receiver) { case PT_SWCH: - if (pavg!=PT_INSL && parts[i].life<4) + if (pavg!=PT_INSL && pavg!=PT_RSSS && parts[i].life<4) { if(sender==PT_PSCN && parts[ID(r)].life<10) { parts[ID(r)].life = 10; @@ -210,7 +211,7 @@ static int update(UPDATE_FUNC_ARGS) } break; case PT_SPRK: - if (pavg!=PT_INSL && parts[i].life<4) + if (pavg!=PT_INSL && pavg!=PT_RSSS && parts[i].life<4) { if (parts[ID(r)].ctype==PT_SWCH) { @@ -243,7 +244,7 @@ static int update(UPDATE_FUNC_ARGS) } continue; case PT_PPIP: - if (parts[i].life == 3 && pavg!=PT_INSL) + if (parts[i].life == 3 && pavg!=PT_INSL && pavg!=PT_RSSS) { void Element_PPIP_flood_trigger(Simulation * sim, int x, int y, int sparkedBy); if (sender == PT_NSCN || sender == PT_PSCN || sender == PT_INST) @@ -251,7 +252,7 @@ static int update(UPDATE_FUNC_ARGS) } continue; case PT_NTCT: case PT_PTCT: case PT_INWR: - if (sender==PT_METL && pavg!=PT_INSL && parts[i].life<4) + if (sender==PT_METL && pavg!=PT_INSL && pavg!=PT_RSSS && parts[i].life<4) { parts[ID(r)].temp = 473.0f; if (receiver==PT_NTCT||receiver==PT_PTCT) @@ -270,7 +271,7 @@ static int update(UPDATE_FUNC_ARGS) continue; } - if (pavg == PT_INSL) continue; //Insulation blocks everything past here + if ((pavg == PT_INSL) || (pavg == PT_RSSS)) continue; //Insulation blocks everything past here if (!((sim->elements[receiver].Properties&PROP_CONDUCTS)||receiver==PT_INST||receiver==PT_QRTZ)) continue; //Stop non-conducting receivers, allow INST and QRTZ as special cases if (abs(rx)+abs(ry)>=4 &&sender!=PT_SWCH&&receiver!=PT_SWCH) continue; //Only switch conducts really far if (receiver==sender && receiver!=PT_INST && receiver!=PT_QRTZ) goto conduct; //Everything conducts to itself, except INST. diff --git a/src/simulation/elements/SWCH.cpp b/src/simulation/elements/SWCH.cpp index c41525b28..ed8806bfe 100644 --- a/src/simulation/elements/SWCH.cpp +++ b/src/simulation/elements/SWCH.cpp @@ -65,7 +65,8 @@ static int update(UPDATE_FUNC_ARGS) auto r = pmap[y+ry][x+rx]; if (!r) continue; - if (sim->parts_avg(i,ID(r),PT_INSL)!=PT_INSL) + auto pavg = sim->parts_avg(i,ID(r),PT_INSL); + if (pavg!=PT_INSL && pavg!=PT_RSSS) { auto rt = TYP(r); if (rt==PT_SWCH) diff --git a/src/simulation/elements/TSNS.cpp b/src/simulation/elements/TSNS.cpp index 7da107e06..488638514 100644 --- a/src/simulation/elements/TSNS.cpp +++ b/src/simulation/elements/TSNS.cpp @@ -67,7 +67,8 @@ static int update(UPDATE_FUNC_ARGS) if (!r) continue; int rt = TYP(r); - if (sim->parts_avg(i, ID(r), PT_INSL) != PT_INSL) + auto pavg = sim->parts_avg(i, ID(r), PT_INSL); + if (pavg != PT_INSL && pavg != PT_RSSS) { if ((sim->elements[rt].Properties&PROP_CONDUCTS) && !(rt == PT_WATR || rt == PT_SLTW || rt == PT_NTCT || rt == PT_PTCT || rt == PT_INWR) && parts[ID(r)].life == 0) { diff --git a/src/simulation/elements/VSNS.cpp b/src/simulation/elements/VSNS.cpp index baefbe56b..ad7b32f8d 100644 --- a/src/simulation/elements/VSNS.cpp +++ b/src/simulation/elements/VSNS.cpp @@ -65,7 +65,8 @@ static int update(UPDATE_FUNC_ARGS) if (!r) continue; int rt = TYP(r); - if (sim->parts_avg(i, ID(r), PT_INSL) != PT_INSL) + auto pavg = sim->parts_avg(i, ID(r), PT_INSL); + if (pavg != PT_INSL && pavg != PT_RSSS) { if ((sim->elements[rt].Properties &PROP_CONDUCTS) && !(rt == PT_WATR || rt == PT_SLTW || rt == PT_NTCT || rt == PT_PTCT || rt == PT_INWR) && parts[ID(r)].life == 0) { diff --git a/src/simulation/elements/meson.build b/src/simulation/elements/meson.build index 05cc5792f..4f1dc9c64 100644 --- a/src/simulation/elements/meson.build +++ b/src/simulation/elements/meson.build @@ -191,6 +191,8 @@ simulation_elem_names = [ 'VSNS', 'ROCK', 'LITH', + 'RSST', + 'RSSS' ] simulation_elem_src = [] From c4db637887f84c606ca3cdbbb57f1a2285d511fc Mon Sep 17 00:00:00 2001 From: Saveliy Skresanov Date: Sun, 1 Oct 2023 21:00:53 +0700 Subject: [PATCH 25/27] Add reactions of resist with other elements. --- src/simulation/elements/GLOW.cpp | 6 ++++++ src/simulation/elements/PTNM.cpp | 4 ++++ src/simulation/elements/RSST.cpp | 29 ++++++++++++++++++++++++++++- 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/simulation/elements/GLOW.cpp b/src/simulation/elements/GLOW.cpp index 7df7367c4..e3fbf493b 100644 --- a/src/simulation/elements/GLOW.cpp +++ b/src/simulation/elements/GLOW.cpp @@ -66,6 +66,12 @@ static int update(UPDATE_FUNC_ARGS) parts[ID(r)].life = 10; return 1; } + else if (TYP(r) == PT_GEL) + { + sim->kill_part(i); + sim->part_change_type(ID(r),x+rx,y+ry,PT_RSST); + return 1; + } } } } diff --git a/src/simulation/elements/PTNM.cpp b/src/simulation/elements/PTNM.cpp index 1593b124f..cd7c7cab9 100644 --- a/src/simulation/elements/PTNM.cpp +++ b/src/simulation/elements/PTNM.cpp @@ -236,6 +236,10 @@ static int update(UPDATE_FUNC_ARGS) case PT_SMKE: // SMKE -> CO2 sim->part_change_type(ID(r), x + rx, y + ry, PT_CO2); break; + + case PT_RSST: // RSST -> BIZR + sim->part_change_type(ID(r), x + rx, y + ry, PT_BIZR); + break; } } } diff --git a/src/simulation/elements/RSST.cpp b/src/simulation/elements/RSST.cpp index bfe304284..426197167 100644 --- a/src/simulation/elements/RSST.cpp +++ b/src/simulation/elements/RSST.cpp @@ -1,5 +1,7 @@ #include "simulation/ElementCommon.h" +int update(UPDATE_FUNC_ARGS); + void Element::Element_RSST() { Identifier = "DEFAULT_PT_RSST"; @@ -24,7 +26,7 @@ void Element::Element_RSST() Meltable = 0; Hardness = 50; - Weight = 40; + Weight = 34; DefaultProperties.temp = R_TEMP + 20.0f + 273.15f; HeatConduct = 44; @@ -40,4 +42,29 @@ void Element::Element_RSST() LowTemperatureTransition = NT; HighTemperature = ITH; HighTemperatureTransition = NT; + + Update = &update; +} + +int update(UPDATE_FUNC_ARGS) +{ + for(int rx = -1; rx < 2; rx++) + { + for(int ry = -1; ry < 2; ry++) + { + auto r = pmap[y+ry][x+rx]; + + if (!r) + continue; + + if(TYP(r) == PT_GUNP) + { + sim->part_change_type(i, x, y, PT_FIRW); + sim->kill_part(ID(r)); + return 1; + } + } + } + + return 0; } From 15a22c6906c77952c0d11d48c6d03a3096647956 Mon Sep 17 00:00:00 2001 From: Saveliy Skresanov Date: Mon, 2 Oct 2023 22:41:22 +0700 Subject: [PATCH 26/27] Add ctype mechanics. --- src/simulation/elements/NEUT.cpp | 19 ++++++++++++++++++- src/simulation/elements/PHOT.cpp | 20 ++++++++++++++++++-- 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/src/simulation/elements/NEUT.cpp b/src/simulation/elements/NEUT.cpp index d367556a5..1652e4fda 100644 --- a/src/simulation/elements/NEUT.cpp +++ b/src/simulation/elements/NEUT.cpp @@ -167,8 +167,25 @@ static int update(UPDATE_FUNC_ARGS) case PT_RSSS: if(!rx && !ry) { - sim->part_change_type(ID(r), x, y, PT_RSST); + int ct_under, tmp_under; + + ct_under = parts[ID(r)].ctype; + tmp_under = parts[ID(r)].tmp; + + //If there's a correct ctype set, use it + if(ct_under > 0 && ct_under < PT_NUM) + { + sim->create_part(ID(r), x, y, ct_under); + + //If there's a correct tmp set, use it for ctype + if(tmp_under > 0 && ct_under < PT_NUM) + parts[ID(r)].ctype = tmp_under; + } + else + sim->part_change_type(ID(r), x, y, PT_RSST); + sim->kill_part(i); + return 1; } break; diff --git a/src/simulation/elements/PHOT.cpp b/src/simulation/elements/PHOT.cpp index 29a8f94bb..7fae3824d 100644 --- a/src/simulation/elements/PHOT.cpp +++ b/src/simulation/elements/PHOT.cpp @@ -107,9 +107,25 @@ static int update(UPDATE_FUNC_ARGS) parts[i].vx = vx; parts[i].vy = vy; } - else if(TYP(r) == PT_RSST && !ry && !rx)//if on RSST + else if(TYP(r) == PT_RSST && !ry && !rx)//if on RSST, make it solid { - sim->part_change_type(ID(r),x,y,PT_RSSS); + int ct_under, tmp_under; + + ct_under = parts[ID(r)].ctype; + tmp_under = parts[ID(r)].tmp; + + //If there's a correct ctype set, use it + if(ct_under > 0 && ct_under < PT_NUM) + { + sim->create_part(ID(r), x, y, ct_under); + + //If there's a correct tmp set, use it for ctype + if(tmp_under > 0 && ct_under < PT_NUM) + parts[ID(r)].ctype = tmp_under; + } + else + sim->part_change_type(ID(r), x, y, PT_RSSS); + sim->kill_part(i); return 1; From f5f275e6574f035e053d6907abac6d70374d8d21 Mon Sep 17 00:00:00 2001 From: Saveliy Skresanov Date: Mon, 9 Oct 2023 00:20:15 +0700 Subject: [PATCH 27/27] Add descriptions for RSST and RSSS. --- src/simulation/elements/RSSS.cpp | 2 +- src/simulation/elements/RSST.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/simulation/elements/RSSS.cpp b/src/simulation/elements/RSSS.cpp index a853ddd13..10c8ceaa7 100644 --- a/src/simulation/elements/RSSS.cpp +++ b/src/simulation/elements/RSSS.cpp @@ -30,7 +30,7 @@ void Element::Element_RSSS() Weight = 100; HeatConduct = 251; - Description = "Solidified resist."; + Description = "Solidified resist. Blocks pressure and insulates SPRK. Liquefies on contact with NEUT."; Properties = TYPE_SOLID|PROP_NEUTPASS; diff --git a/src/simulation/elements/RSST.cpp b/src/simulation/elements/RSST.cpp index 426197167..6640bb5e8 100644 --- a/src/simulation/elements/RSST.cpp +++ b/src/simulation/elements/RSST.cpp @@ -30,7 +30,7 @@ void Element::Element_RSST() DefaultProperties.temp = R_TEMP + 20.0f + 273.15f; HeatConduct = 44; - Description = "Resist."; + Description = "Resist. Solidifies on contact with PHOT, and reacts with other energy particles."; Properties = TYPE_LIQUID|PROP_NEUTPASS;