diff --git a/BREAKING_CHANGES.md b/BREAKING_CHANGES.md index 12298e9675..d438458986 100644 --- a/BREAKING_CHANGES.md +++ b/BREAKING_CHANGES.md @@ -2,6 +2,70 @@ # develop +## Change + +The signatures of OpenGLFrameBuffer::readPixels() and +OpenGLFrameBuffer::writePixels() have changed, adding a new RowOrder parameter. + +**Possible Issues** + +Code that does not specify this parameter will not compile. + +**Workaround** + +Pass the extra parameter to specify whether the pixel data should be ordered +with the top-most or bottom-most row first. + +**Rationale** + +The previous function calls did not allow the pixel order to be configured. +readPixels() would return pixel data with the bottom-most row first (this is +convention for the OpenGL API), but writePixels() would expect the top-most row +first. This meant that reading and then immediately writing the same data would +have the unexpected effect of flipping the image. Changing readPixels() to +order pixels from top to bottom would be slightly dangerous, as it would +introduce a change of behaviour with no accompanying compiler warning. +Additionally, flipping the pixel storage introduces additional work that can be +safely skipped when the pixel data is going to be written back to the +framebuffer later. + + +## Change + +The behaviour of the default constructed FocusTraverser objects has changed, and +they will now navigate onto disabled components. This only affects navigation by +screen readers and not general keyboard navigation, as the latter depends on the +KeyboardFocusTraverser class. + +**Possible Issues** + +Disabled child components of focus containers that used the JUCE default +FocusTraverser will now be discoverable by screen readers. They will accept +accessibility focus, their title will be reported as well as their disabled +state. + +Children of components that returned a custom ComponentTraverser object are not +affected. + +**Workaround** + +If you wish to hide disabled components from screen readers, you can restore the +old behaviour by overriding `Component::createFocusTraverser()` for your focus +containers, and returning a FocusTraverser object created using the +`FocusTraverser::SkipDisabledComponents::yes` argument. + +**Rationale** + +Disabled components are typically rendered in a dimmed or inactive state, but +are still prominently visible for sighted users. The old behaviour made these +components entirely missing from the accessibility tree, making them +non-discoverable with screen readers. + +This was in contrast to the behaviour of native OS components, that are still +accessible using screen readers, but their disabled/dimmed state is also +reported. + + ## Change The default Visual Studio project settings for "Debug Information Format" have diff --git a/examples/DemoRunner/CMakeLists.txt b/examples/DemoRunner/CMakeLists.txt index eb2b634c2f..4a8d650a31 100644 --- a/examples/DemoRunner/CMakeLists.txt +++ b/examples/DemoRunner/CMakeLists.txt @@ -73,6 +73,7 @@ target_link_libraries(DemoRunner PRIVATE juce::juce_animation juce::juce_audio_utils juce::juce_box2d + juce::juce_build_tools juce::juce_dsp juce::juce_javascript juce::juce_midi_ci diff --git a/examples/DemoRunner/Source/Main.cpp b/examples/DemoRunner/Source/Main.cpp index edc8c955d3..322a785b4e 100644 --- a/examples/DemoRunner/Source/Main.cpp +++ b/examples/DemoRunner/Source/Main.cpp @@ -154,7 +154,8 @@ private: #if JUCE_IOS || JUCE_ANDROID void parentSizeChanged() override { - getMainComponent().resized(); + if (auto* comp = getContentComponent()) + comp->resized(); } #endif diff --git a/examples/GUI/FontFeaturesDemo.h b/examples/GUI/FontFeaturesDemo.h index f63b87b656..c3986c3bae 100644 --- a/examples/GUI/FontFeaturesDemo.h +++ b/examples/GUI/FontFeaturesDemo.h @@ -338,7 +338,9 @@ public: const FontStringPair example[] = { FontStringPair { baseLineFont.withPointHeight (16), - feature.exampleText + " " + String::fromUTF8 ("\xe2\x86\x92") }, + feature.exampleText }, + FontStringPair { baseLineFont.withPointHeight (16), + " " + String::fromUTF8 ("\xe2\x86\x92") }, FontStringPair { exampleFont.withPointHeight (16), feature.exampleText } }; diff --git a/extras/Build/CMake/JUCEUtils.cmake b/extras/Build/CMake/JUCEUtils.cmake index 09fca93962..e218a16c4a 100644 --- a/extras/Build/CMake/JUCEUtils.cmake +++ b/extras/Build/CMake/JUCEUtils.cmake @@ -492,7 +492,16 @@ function(juce_add_binary_data target) endforeach() set(input_file_list "${juce_binary_data_folder}/input_file_list") - file(WRITE "${input_file_list}" "${newline_delimited_input}") + + set(old_input_file_list "") + + if(EXISTS "${input_file_list}") + file(READ "${input_file_list}" old_input_file_list) + endif() + + if(NOT "${old_input_file_list}" STREQUAL "${newline_delimited_input}") + file(WRITE "${input_file_list}" "${newline_delimited_input}") + endif() add_custom_command(OUTPUT ${binary_file_names} COMMAND juce::juceaide binarydata "${JUCE_ARG_NAMESPACE}" "${JUCE_ARG_HEADER_NAME}" diff --git a/extras/Build/juce_build_tools/utils/juce_Icons.cpp b/extras/Build/juce_build_tools/utils/juce_Icons.cpp index 6ae5c59e01..fe28b661ea 100644 --- a/extras/Build/juce_build_tools/utils/juce_Icons.cpp +++ b/extras/Build/juce_build_tools/utils/juce_Icons.cpp @@ -35,22 +35,28 @@ namespace juce::build_tools { - Array asArray (const Icons& icons) + Icons Icons::fromFilesSmallAndBig (const File& small, const File& big) { - Array result; + Icons result; + result.small = Drawable::createFromImageFile (small); + result.big = Drawable::createFromImageFile (big); + return result; + } - if (icons.small != nullptr) - result.add (icons.small.get()); + Array asArray (const Icons& icons) + { + Array result; - if (icons.big != nullptr) - result.add (icons.big.get()); + for (auto getter : { &Icons::getSmall, &Icons::getBig }) + if (auto* got = (icons.*getter)()) + result.add (got); return result; } namespace mac { - static Image fixIconImageSize (Drawable& image) + static Image fixIconImageSize (const Drawable& image) { const int validSizes[] = { 16, 32, 64, 128, 256, 512, 1024 }; @@ -90,7 +96,7 @@ namespace juce::build_tools { MemoryOutputStream data; auto smallest = std::numeric_limits::max(); - Drawable* smallestImage = nullptr; + const Drawable* smallestImage = nullptr; const auto images = asArray (icons); @@ -134,25 +140,25 @@ namespace juce::build_tools int size, bool returnNullIfNothingBigEnough) { - auto* const im = [&]() -> Drawable* + auto* const im = std::invoke ([&]() -> const Drawable* { - if ((icons.small != nullptr) != (icons.big != nullptr)) - return icons.small != nullptr ? icons.small.get() : icons.big.get(); + if ((icons.getSmall() != nullptr) != (icons.getBig() != nullptr)) + return icons.getSmall() != nullptr ? icons.getSmall() : icons.getBig(); - if (icons.small != nullptr && icons.big != nullptr) + if (icons.getSmall() != nullptr && icons.getBig() != nullptr) { - if (icons.small->getWidth() >= size && icons.big->getWidth() >= size) - return icons.small->getWidth() < icons.big->getWidth() ? icons.small.get() : icons.big.get(); + if (icons.getSmall()->getWidth() >= size && icons.getBig()->getWidth() >= size) + return icons.getSmall()->getWidth() < icons.getBig()->getWidth() ? icons.getSmall() : icons.getBig(); - if (icons.small->getWidth() >= size) - return icons.small.get(); + if (icons.getSmall()->getWidth() >= size) + return icons.getSmall(); - if (icons.big->getWidth() >= size) - return icons.big.get(); + if (icons.getBig()->getWidth() >= size) + return icons.getBig(); } return nullptr; - }(); + }); if (im == nullptr) return {}; @@ -304,9 +310,9 @@ namespace juce::build_tools writeStreamToFile (file, [&] (MemoryOutputStream& mo) { writeWinIcon (icons, mo); }); } - Image rescaleImageForIcon (Drawable& d, const int size) + Image rescaleImageForIcon (const Drawable& d, const int size) { - if (auto* drawableImage = dynamic_cast (&d)) + if (auto* drawableImage = dynamic_cast (&d)) { auto im = SoftwareImageType().convert (drawableImage->getImage()); @@ -365,8 +371,8 @@ namespace juce::build_tools static void createiOSIconFiles (const Icons& icons, File appIconSet) { - auto* imageToUse = icons.big != nullptr ? icons.big.get() - : icons.small.get(); + auto* imageToUse = icons.getBig() != nullptr ? icons.getBig() + : icons.getSmall(); if (imageToUse != nullptr) { @@ -504,4 +510,86 @@ namespace juce::build_tools return { assets, targetFolder, RelativePath::buildTargetFolder }; } + //============================================================================== + //============================================================================== + #if JUCE_UNIT_TESTS + + class IconsUnitTests : public UnitTest + { + public: + IconsUnitTests() : UnitTest ("Generate icon files", UnitTestCategories::graphics) {} + + void runTest() override + { + const ScopedJuceInitialiser_GUI scope; + + beginTest ("Load icons from vector file"); + { + TemporaryFile tempFile ("vector"); + + { + auto stream = tempFile.getFile().createOutputStream(); + expect (stream != nullptr); + stream->write (svg, std::size (svg)); + } + + const auto icons = Icons::fromFilesSmallAndBig (tempFile.getFile(), {}); + + expect (icons.getSmall() != nullptr); + expect (icons.getBig() == nullptr); + + expect (dynamic_cast (icons.getSmall()) == nullptr, + "Vector data should not be rasterised on load"); + } + + beginTest ("Load icons from raster file"); + { + TemporaryFile tempFile ("raster"); + + { + auto stream = tempFile.getFile().createOutputStream(); + expect (stream != nullptr); + stream->write (png, std::size (png)); + } + + const auto icons = Icons::fromFilesSmallAndBig ({}, tempFile.getFile()); + + expect (icons.getSmall() == nullptr); + expect (icons.getBig() != nullptr); + + expect (dynamic_cast (icons.getBig()) != nullptr, + "Raster data is loaded as a DrawableImage"); + } + } + + private: + static constexpr uint8_t svg[] = R"svg( + + + + + )svg"; + + static constexpr uint8_t png[] + { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, + 0x08, 0x06, 0x00, 0x00, 0x00, 0xc4, 0x52, 0x57, 0xd3, 0x00, 0x00, 0x00, + 0x5e, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x55, 0x8d, 0x49, 0x0e, 0x00, + 0x21, 0x08, 0x04, 0xfd, 0x89, 0xe2, 0x12, 0x13, 0xf5, 0xea, 0xff, 0x7f, + 0x46, 0x4b, 0x9b, 0xe8, 0x38, 0x87, 0x0a, 0x84, 0x5e, 0x70, 0x21, 0x04, + 0x25, 0xde, 0x7b, 0xcd, 0x39, 0x6b, 0x4a, 0x69, 0xef, 0xc4, 0x89, 0x08, + 0x48, 0xef, 0x1d, 0x63, 0x0c, 0xcc, 0x39, 0xd1, 0x5a, 0xe3, 0xed, 0x13, + 0x2d, 0x71, 0xa1, 0xd1, 0x0c, 0xea, 0xac, 0x12, 0x31, 0x46, 0x58, 0xe5, + 0x86, 0x22, 0x67, 0xad, 0xf5, 0x9f, 0x3c, 0x86, 0x52, 0x0a, 0xee, 0x4f, + 0xa6, 0xdf, 0x6a, 0xee, 0x5b, 0x64, 0xe5, 0x49, 0xbf, 0x50, 0x5c, 0x2f, + 0xb3, 0x44, 0xdf, 0x94, 0x9e, 0x62, 0xe2, 0x00, 0x00, 0x00, 0x00, 0x49, + 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + }; + }; + + static IconsUnitTests iconsUnitTests; + + #endif + } // namespace juce::build_tools diff --git a/extras/Build/juce_build_tools/utils/juce_Icons.h b/extras/Build/juce_build_tools/utils/juce_Icons.h index 708ecfba94..57bab078da 100644 --- a/extras/Build/juce_build_tools/utils/juce_Icons.h +++ b/extras/Build/juce_build_tools/utils/juce_Icons.h @@ -35,20 +35,29 @@ namespace juce::build_tools { - struct Icons + class Icons { + public: + Icons() = default; + + static Icons fromFilesSmallAndBig (const File& small, const File& big); + + const Drawable* getSmall() const { return small.get(); } + const Drawable* getBig() const { return big.get(); } + + private: std::unique_ptr small; std::unique_ptr big; }; - Array asArray (const Icons&); + Array asArray (const Icons&); void writeMacIcon (const Icons&, const File&); void writeWinIcon (const Icons&, const File&); Image getBestIconForSize (const Icons& icons, int size, bool returnNullIfNothingBigEnough); - Image rescaleImageForIcon (Drawable& d, int size); + Image rescaleImageForIcon (const Drawable& d, int size); RelativePath createXcassetsFolderFromIcons (const Icons& icons, const File& targetFolder, diff --git a/extras/Build/juceaide/Main.cpp b/extras/Build/juceaide/Main.cpp index e7eef131be..34e9847294 100644 --- a/extras/Build/juceaide/Main.cpp +++ b/extras/Build/juceaide/Main.cpp @@ -124,19 +124,18 @@ IconParseResults parseIconArguments (juce::ArgumentList&& args) args.checkMinNumArguments (2); const auto output = args.arguments.removeAndReturn (0); - const auto popDrawable = [&args]() -> std::unique_ptr + const auto popFile = [&args]() -> juce::File { if (args.size() == 0) return {}; - const auto firstArgText = args.arguments.removeAndReturn (0).text; - return juce::Drawable::createFromImageFile (firstArgText); + return args.arguments.removeAndReturn (0).text; }; - auto smallIcon = popDrawable(); - auto bigIcon = popDrawable(); + const auto smallIcon = popFile(); + const auto bigIcon = popFile(); - return { { std::move (smallIcon), std::move (bigIcon) }, output.text }; + return { juce::build_tools::Icons::fromFilesSmallAndBig (smallIcon, bigIcon), output.text }; } int writeMacIcon (juce::ArgumentList&& argumentList) diff --git a/extras/Projucer/Source/Project/jucer_Project.cpp b/extras/Projucer/Source/Project/jucer_Project.cpp index 2e9bd40d3e..24c93b7e84 100644 --- a/extras/Projucer/Source/Project/jucer_Project.cpp +++ b/extras/Projucer/Source/Project/jucer_Project.cpp @@ -1632,19 +1632,6 @@ Project::Item Project::Item::createCopy() { Item i (*this); i.state = i. String Project::Item::getID() const { return state [Ids::ID]; } void Project::Item::setID (const String& newID) { state.setProperty (Ids::ID, newID, nullptr); } -std::unique_ptr Project::Item::loadAsImageFile() const -{ - const MessageManagerLock mml (ThreadPoolJob::getCurrentThreadPoolJob()); - - if (! mml.lockWasGained()) - return nullptr; - - if (isValid()) - return Drawable::createFromImageFile (getFile()); - - return {}; -} - Project::Item Project::Item::createGroup (Project& project, const String& name, const String& uid, bool isModuleCode) { Item group (project, ValueTree (Ids::GROUP), isModuleCode); diff --git a/extras/Projucer/Source/Project/jucer_Project.h b/extras/Projucer/Source/Project/jucer_Project.h index 96d60a31de..d1d7f1e8f1 100644 --- a/extras/Projucer/Source/Project/jucer_Project.h +++ b/extras/Projucer/Source/Project/jucer_Project.h @@ -453,9 +453,6 @@ public: void setID (const String& newID); Item findItemWithID (const String& targetId) const; // (recursive search) - String getImageFileID() const; - std::unique_ptr loadAsImageFile() const; - //============================================================================== Value getNameValue(); String getName() const; diff --git a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Android.h b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Android.h index 17a2a8f608..26bb662708 100644 --- a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Android.h +++ b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Android.h @@ -1492,15 +1492,15 @@ private: { const auto icons = getIcons(); - if (icons.big != nullptr && icons.small != nullptr) + if (icons.getBig() != nullptr && icons.getSmall() != nullptr) { - auto step = jmax (icons.big->getWidth(), icons.big->getHeight()) / 8; + auto step = jmax (icons.getBig()->getWidth(), icons.getBig()->getHeight()) / 8; writeIcon (folder.getChildFile ("drawable-xhdpi/icon.png"), build_tools::getBestIconForSize (icons, step * 8, false)); writeIcon (folder.getChildFile ("drawable-hdpi/icon.png"), build_tools::getBestIconForSize (icons, step * 6, false)); writeIcon (folder.getChildFile ("drawable-mdpi/icon.png"), build_tools::getBestIconForSize (icons, step * 4, false)); writeIcon (folder.getChildFile ("drawable-ldpi/icon.png"), build_tools::getBestIconForSize (icons, step * 3, false)); } - else if (auto* icon = (icons.big != nullptr ? icons.big.get() : icons.small.get())) + else if (auto* icon = (icons.getBig() != nullptr ? icons.getBig() : icons.getSmall())) { writeIcon (folder.getChildFile ("drawable-mdpi/icon.png"), build_tools::rescaleImageForIcon (*icon, icon->getWidth())); } @@ -1895,9 +1895,9 @@ private: if (! app->hasAttribute ("android:icon")) { - std::unique_ptr bigIcon (getBigIcon()), smallIcon (getSmallIcon()); + const auto icons = getIcons(); - if (bigIcon != nullptr || smallIcon != nullptr) + if (icons.getBig() != nullptr || icons.getSmall() != nullptr) app->setAttribute ("android:icon", "@drawable/icon"); } diff --git a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_MSVC.h b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_MSVC.h index 4f78627e20..cc9b5e44c5 100644 --- a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_MSVC.h +++ b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_MSVC.h @@ -478,6 +478,7 @@ public: fastMathValue (config, Ids::fastMath, getUndoManager()), debugInformationFormatValue (config, Ids::debugInformationFormat, getUndoManager(), "ProgramDatabase"), pluginBinaryCopyStepValue (config, Ids::enablePluginBinaryCopyStep, getUndoManager(), false), + intrinsicFunctionsEnabledValue (config, Ids::intrinsicFunctions, getUndoManager(), false), vstBinaryLocation (config, Ids::vstBinaryLocation, getUndoManager()), vst3BinaryLocation (config, Ids::vst3BinaryLocation, getUndoManager()), aaxBinaryLocation (config, Ids::aaxBinaryLocation, getUndoManager()), @@ -577,6 +578,7 @@ public: bool shouldUseMultiProcessorCompilation() const { return multiProcessorCompilationValue.get(); } bool isFastMathEnabled() const { return fastMathValue.get(); } bool isPluginBinaryCopyStepEnabled() const { return pluginBinaryCopyStepValue.get(); } + bool isIntrinsicFunctionsEnabled() const { return intrinsicFunctionsEnabledValue.get(); } static bool shouldBuildTarget (build_tools::ProjectType::Target::Type targetType, Architecture arch) { @@ -649,6 +651,9 @@ public: { optimisationOff, optimiseMinSize, optimiseMaxSpeed, optimiseFull }), "The optimisation level for this configuration"); + props.add (new ChoicePropertyComponent (intrinsicFunctionsEnabledValue, "Intrinsic Functions"), + "Replaces some function calls with intrinsic or otherwise special forms of the function that help your application run faster."); + props.add (new TextPropertyComponent (intermediatesPathValue, "Intermediates Path", 2048, false), "An optional path to a folder to use for the intermediate build files. Note that Visual Studio allows " "you to use macros in this path, e.g. \"$(TEMP)\\MyAppBuildFiles\\$(Configuration)\", which is a handy way to " @@ -749,7 +754,7 @@ public: ValueTreePropertyWithDefault warningLevelValue, warningsAreErrorsValue, prebuildCommandValue, postbuildCommandValue, generateDebugSymbolsValue, enableIncrementalLinkingValue, useRuntimeLibDLLValue, multiProcessorCompilationValue, intermediatesPathValue, characterSetValue, architectureTypeValue, fastMathValue, debugInformationFormatValue, - pluginBinaryCopyStepValue; + pluginBinaryCopyStepValue, intrinsicFunctionsEnabledValue; struct LocationProperties { @@ -1126,6 +1131,9 @@ public: auto cppStandard = owner.project.getCppStandardString(); cl->createNewChildElement ("LanguageStandard")->addTextElement ("stdcpp" + cppStandard); + + if (config.isIntrinsicFunctionsEnabled()) + cl->createNewChildElement ("IntrinsicFunctions")->addTextElement ("true"); } { diff --git a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExporter.cpp b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExporter.cpp index 4b298ffc3a..a6d9091cdf 100644 --- a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExporter.cpp +++ b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExporter.cpp @@ -867,14 +867,20 @@ void ProjectExporter::createDefaultConfigs() } } -std::unique_ptr ProjectExporter::getBigIcon() const +build_tools::Icons ProjectExporter::getIcons() const { - return project.getMainGroup().findItemWithID (settings [Ids::bigIcon]).loadAsImageFile(); -} + const MessageManagerLock mml (ThreadPoolJob::getCurrentThreadPoolJob()); -std::unique_ptr ProjectExporter::getSmallIcon() const -{ - return project.getMainGroup().findItemWithID (settings [Ids::smallIcon]).loadAsImageFile(); + if (! mml.lockWasGained()) + return {}; + + const auto getFile = [this] (auto id) + { + return project.getMainGroup().findItemWithID (settings[id]).getFile(); + }; + + return build_tools::Icons::fromFilesSmallAndBig (getFile (Ids::smallIcon), + getFile (Ids::bigIcon)); } //============================================================================== diff --git a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExporter.h b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExporter.h index eff3dd63f8..e5540a54e8 100644 --- a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExporter.h +++ b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExporter.h @@ -238,9 +238,7 @@ public: void addProjectPathToBuildPathList (StringArray&, const build_tools::RelativePath&, int index = -1) const; - std::unique_ptr getBigIcon() const; - std::unique_ptr getSmallIcon() const; - build_tools::Icons getIcons() const { return { getSmallIcon(), getBigIcon() }; } + build_tools::Icons getIcons() const; String getExporterIdentifierMacro() const { diff --git a/extras/Projucer/Source/Utility/Helpers/jucer_PresetIDs.h b/extras/Projucer/Source/Utility/Helpers/jucer_PresetIDs.h index e9d22f226e..62336c8b7b 100644 --- a/extras/Projucer/Source/Utility/Helpers/jucer_PresetIDs.h +++ b/extras/Projucer/Source/Utility/Helpers/jucer_PresetIDs.h @@ -125,6 +125,7 @@ namespace Ids DECLARE_ID (cppLibType); DECLARE_ID (codeSigningIdentity); DECLARE_ID (fastMath); + DECLARE_ID (intrinsicFunctions); DECLARE_ID (linkTimeOptimisation); DECLARE_ID (vstBinaryLocation); DECLARE_ID (vst3BinaryLocation); diff --git a/extras/UnitTestRunner/CMakeLists.txt b/extras/UnitTestRunner/CMakeLists.txt index 00b6e24163..552cd7ac3b 100644 --- a/extras/UnitTestRunner/CMakeLists.txt +++ b/extras/UnitTestRunner/CMakeLists.txt @@ -50,6 +50,7 @@ target_compile_definitions(UnitTestRunner PRIVATE target_link_libraries(UnitTestRunner PRIVATE juce::juce_analytics juce::juce_audio_utils + juce::juce_build_tools juce::juce_dsp juce::juce_midi_ci juce::juce_opengl diff --git a/extras/UnitTestRunner/Source/Main.cpp b/extras/UnitTestRunner/Source/Main.cpp index 1225c36dd9..f6a8831c92 100644 --- a/extras/UnitTestRunner/Source/Main.cpp +++ b/extras/UnitTestRunner/Source/Main.cpp @@ -60,15 +60,27 @@ class ConsoleUnitTestRunner final : public UnitTestRunner //============================================================================== int main (int argc, char **argv) { + constexpr auto helpOption = "--help|-h"; + constexpr auto listOption = "--list-categories|-l"; + constexpr auto categoryOption = "--category|-c"; + constexpr auto seedOption = "--seed|-s"; + constexpr auto nameOption = "--name|-n"; + ArgumentList args (argc, argv); - if (args.containsOption ("--help|-h")) + if (args.containsOption (helpOption)) { - std::cout << argv[0] << " [--help|-h] [--list-categories] [--category=category] [--seed=seed]" << std::endl; + std::cout << argv[0] + << " [" << helpOption << "]" + << " [" << listOption << "]" + << " [" << categoryOption << "=category]" + << " [" << seedOption << "=seed]" + << " [" << nameOption << "=name]" + << std::endl; return 0; } - if (args.containsOption ("--list-categories")) + if (args.containsOption (listOption)) { for (auto& category : UnitTest::getAllCategories()) std::cout << category << std::endl; @@ -79,13 +91,19 @@ int main (int argc, char **argv) ConsoleLogger logger; Logger::setCurrentLogger (&logger); + const ScopeGuard onExit { [&] + { + Logger::setCurrentLogger (nullptr); + DeletedAtShutdown::deleteAll(); + }}; + ConsoleUnitTestRunner runner; - auto seed = [&args] + const auto seed = std::invoke ([&] { - if (args.containsOption ("--seed")) + if (args.containsOption (seedOption)) { - auto seedValueString = args.getValueForOption ("--seed"); + auto seedValueString = args.getValueForOption (seedOption); if (seedValueString.startsWith ("0x")) return seedValueString.getHexValue64(); @@ -94,10 +112,12 @@ int main (int argc, char **argv) } return Random::getSystemRandom().nextInt64(); - }(); + }); - if (args.containsOption ("--category")) - runner.runTestsInCategory (args.getValueForOption ("--category"), seed); + if (args.containsOption (categoryOption)) + runner.runTestsInCategory (args.getValueForOption (categoryOption), seed); + else if (args.containsOption (nameOption)) + runner.runTestsWithName (args.getValueForOption (nameOption), seed); else runner.runAllTests (seed); @@ -108,24 +128,28 @@ int main (int argc, char **argv) auto* result = runner.getResult (i); if (result->failures > 0) - failures.push_back (result->unitTestName + " / " + result->subcategoryName + ": " + String (result->failures) + " test failure" + (result->failures > 1 ? "s" : "")); + { + const auto testName = result->unitTestName + " / " + result->subcategoryName; + const auto testSummary = String (result->failures) + " test failure" + (result->failures > 1 ? "s" : ""); + const auto newLineAndTab = newLine + "\t"; + + failures.push_back (testName + ": " + testSummary + newLineAndTab + + result->messages.joinIntoString (newLineAndTab)); + } } + logger.writeToLog (newLine + String::repeatedString ("-", 65)); + if (! failures.empty()) { - logger.writeToLog (newLine + "Test failure summary:" + newLine); + logger.writeToLog ("Test failure summary:"); for (const auto& failure : failures) - logger.writeToLog (failure); + logger.writeToLog (newLine + failure); - Logger::setCurrentLogger (nullptr); return 1; } - logger.writeToLog (newLine + "All tests completed successfully"); - Logger::setCurrentLogger (nullptr); - - DeletedAtShutdown::deleteAll(); - + logger.writeToLog ("All tests completed successfully"); return 0; } diff --git a/modules/juce_analytics/analytics/juce_Analytics.h b/modules/juce_analytics/analytics/juce_Analytics.h index 57c728fd86..fc65ee8ffd 100644 --- a/modules/juce_analytics/analytics/juce_Analytics.h +++ b/modules/juce_analytics/analytics/juce_Analytics.h @@ -103,9 +103,9 @@ public: */ void setSuspended (bool shouldBeSuspended); - #ifndef DOXYGEN + /** @cond */ JUCE_DECLARE_SINGLETON_INLINE (Analytics, false) - #endif + /** @endcond */ private: //============================================================================== diff --git a/modules/juce_audio_basics/buffers/juce_AudioDataConverters.h b/modules/juce_audio_basics/buffers/juce_AudioDataConverters.h index 966380603a..a63ac17564 100644 --- a/modules/juce_audio_basics/buffers/juce_AudioDataConverters.h +++ b/modules/juce_audio_basics/buffers/juce_AudioDataConverters.h @@ -76,8 +76,9 @@ public: class NonConst; /**< Used as a template parameter for AudioData::Pointer. Indicates that the pointer can be used for non-const data. */ class Const; /**< Used as a template parameter for AudioData::Pointer. Indicates that the samples can only be used for const data.. */ - #ifndef DOXYGEN + //============================================================================== + /** @cond */ class BigEndian { public: @@ -332,7 +333,7 @@ public: static void* toVoidPtr (VoidType* v) noexcept { return const_cast (v); } enum { isConst = 1 }; }; - #endif + /** @endcond */ //============================================================================== /** @@ -799,7 +800,7 @@ public: }; //============================================================================== -#ifndef DOXYGEN +/** @cond */ /** A set of routines to convert buffers of 32-bit floating point data to and from various integer formats. @@ -867,6 +868,6 @@ public: private: AudioDataConverters(); }; -#endif +/** @endcond */ } // namespace juce diff --git a/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.h b/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.h index 427783d6f7..ec7140ce9c 100644 --- a/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.h +++ b/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.h @@ -150,7 +150,7 @@ struct JUCE_API FloatVectorOperationsBase static FloatType JUCE_CALLTYPE findMaximum (const FloatType* src, CountType numValues) noexcept; }; -#if ! DOXYGEN +/** @cond */ namespace detail { @@ -177,7 +177,7 @@ struct NameForwarder : public Bases... }; } // namespace detail -#endif +/** @endcond */ //============================================================================== /** diff --git a/modules/juce_audio_basics/midi/juce_MidiBuffer.h b/modules/juce_audio_basics/midi/juce_MidiBuffer.h index 4b7a22df66..7994ea76f3 100644 --- a/modules/juce_audio_basics/midi/juce_MidiBuffer.h +++ b/modules/juce_audio_basics/midi/juce_MidiBuffer.h @@ -292,7 +292,7 @@ public: MidiBufferIterator findNextSamplePosition (int samplePosition) const noexcept; //============================================================================== - #ifndef DOXYGEN + /** @cond */ /** This class is now deprecated in favour of MidiBufferIterator. Used to iterate through the events in a MidiBuffer. @@ -349,7 +349,7 @@ public: const MidiBuffer& buffer; MidiBufferIterator iterator; }; - #endif + /** @endcond */ /** The raw data holding this buffer. Obviously access to this data is provided at your own risk. Its internal format could diff --git a/modules/juce_audio_basics/midi/juce_MidiMessage.h b/modules/juce_audio_basics/midi/juce_MidiMessage.h index 89c5e088ee..65a118edb0 100644 --- a/modules/juce_audio_basics/midi/juce_MidiMessage.h +++ b/modules/juce_audio_basics/midi/juce_MidiMessage.h @@ -880,7 +880,7 @@ public: static MidiMessage createSysExMessage (Span data); //============================================================================== - #ifndef DOXYGEN + /** @cond */ /** Reads a midi variable-length integer. The `data` argument indicates the data to read the number from, @@ -889,7 +889,7 @@ public: */ [[deprecated ("This signature has been deprecated in favour of the safer readVariableLengthValue.")]] static int readVariableLengthVal (const uint8* data, int& numBytesUsed) noexcept; - #endif + /** @endcond */ /** Holds information about a variable-length value which was parsed from a stream of bytes. @@ -996,17 +996,17 @@ public: private: //============================================================================== - #ifndef DOXYGEN + /** @cond */ union PackedData { uint8* allocatedData; uint8 asBytes[sizeof (uint8*)]; }; + /** @endcond */ PackedData packedData; double timeStamp = 0; int size; - #endif inline bool isHeapAllocated() const noexcept { return size > (int) sizeof (packedData); } inline uint8* getData() const noexcept { return isHeapAllocated() ? packedData.allocatedData : (uint8*) packedData.asBytes; } diff --git a/modules/juce_audio_basics/midi/ump/juce_UMP.h b/modules/juce_audio_basics/midi/ump/juce_UMP.h index 6816c91c51..88abe5cfc6 100644 --- a/modules/juce_audio_basics/midi/ump/juce_UMP.h +++ b/modules/juce_audio_basics/midi/ump/juce_UMP.h @@ -47,11 +47,9 @@ #include "juce_UMPDispatcher.h" #include "juce_UMPStringUtils.h" -#ifndef DOXYGEN - +/** @cond */ namespace juce { namespace ump = universal_midi_packets; } - -#endif +/** @endcond */ diff --git a/modules/juce_audio_basics/midi/ump/juce_UMPConversion.h b/modules/juce_audio_basics/midi/ump/juce_UMPConversion.h index c94ba9ff3a..453f8847db 100644 --- a/modules/juce_audio_basics/midi/ump/juce_UMPConversion.h +++ b/modules/juce_audio_basics/midi/ump/juce_UMPConversion.h @@ -32,8 +32,7 @@ ============================================================================== */ -#ifndef DOXYGEN - +/** @cond */ namespace juce::universal_midi_packets { @@ -358,5 +357,4 @@ struct Conversion }; } // namespace juce::universal_midi_packets - -#endif +/** @endcond */ diff --git a/modules/juce_audio_basics/midi/ump/juce_UMPConverters.h b/modules/juce_audio_basics/midi/ump/juce_UMPConverters.h index a9bc807eee..e137513750 100644 --- a/modules/juce_audio_basics/midi/ump/juce_UMPConverters.h +++ b/modules/juce_audio_basics/midi/ump/juce_UMPConverters.h @@ -32,8 +32,7 @@ ============================================================================== */ -#ifndef DOXYGEN - +/** @cond */ namespace juce::universal_midi_packets { /** @@ -212,5 +211,4 @@ namespace juce::universal_midi_packets SingleGroupMidi1ToBytestreamTranslator translator; }; } // namespace juce::universal_midi_packets - -#endif +/** @endcond */ diff --git a/modules/juce_audio_basics/midi/ump/juce_UMPDispatcher.h b/modules/juce_audio_basics/midi/ump/juce_UMPDispatcher.h index 4ea5c56b41..3ba42a9d4f 100644 --- a/modules/juce_audio_basics/midi/ump/juce_UMPDispatcher.h +++ b/modules/juce_audio_basics/midi/ump/juce_UMPDispatcher.h @@ -32,8 +32,7 @@ ============================================================================== */ -#ifndef DOXYGEN - +/** @cond */ namespace juce::universal_midi_packets { @@ -205,5 +204,4 @@ private: }; } // namespace juce::universal_midi_packets - -#endif +/** @endcond */ diff --git a/modules/juce_audio_basics/midi/ump/juce_UMPIterator.h b/modules/juce_audio_basics/midi/ump/juce_UMPIterator.h index dce6c483d9..c2386b5468 100644 --- a/modules/juce_audio_basics/midi/ump/juce_UMPIterator.h +++ b/modules/juce_audio_basics/midi/ump/juce_UMPIterator.h @@ -32,8 +32,7 @@ ============================================================================== */ -#ifndef DOXYGEN - +/** @cond */ namespace juce::universal_midi_packets { @@ -128,5 +127,4 @@ private: }; } // namespace juce::universal_midi_packets - -#endif +/** @endcond */ diff --git a/modules/juce_audio_basics/midi/ump/juce_UMPMidi1ToBytestreamTranslator.h b/modules/juce_audio_basics/midi/ump/juce_UMPMidi1ToBytestreamTranslator.h index 2ab1e5e83f..45167ff2e1 100644 --- a/modules/juce_audio_basics/midi/ump/juce_UMPMidi1ToBytestreamTranslator.h +++ b/modules/juce_audio_basics/midi/ump/juce_UMPMidi1ToBytestreamTranslator.h @@ -32,8 +32,7 @@ ============================================================================== */ -#ifndef DOXYGEN - +/** @cond */ namespace juce::universal_midi_packets { @@ -300,5 +299,4 @@ private: }; } // namespace juce::universal_midi_packets - -#endif +/** @endcond */ diff --git a/modules/juce_audio_basics/midi/ump/juce_UMPMidi1ToMidi2DefaultTranslator.h b/modules/juce_audio_basics/midi/ump/juce_UMPMidi1ToMidi2DefaultTranslator.h index 8d6916ab71..fa7bee3e40 100644 --- a/modules/juce_audio_basics/midi/ump/juce_UMPMidi1ToMidi2DefaultTranslator.h +++ b/modules/juce_audio_basics/midi/ump/juce_UMPMidi1ToMidi2DefaultTranslator.h @@ -32,8 +32,7 @@ ============================================================================== */ -#ifndef DOXYGEN - +/** @cond */ namespace juce::universal_midi_packets { @@ -196,5 +195,4 @@ private: }; } // namespace juce::universal_midi_packets - -#endif +/** @endcond */ diff --git a/modules/juce_audio_basics/midi/ump/juce_UMPProtocols.h b/modules/juce_audio_basics/midi/ump/juce_UMPProtocols.h index 94c44f396e..9f260bf43a 100644 --- a/modules/juce_audio_basics/midi/ump/juce_UMPProtocols.h +++ b/modules/juce_audio_basics/midi/ump/juce_UMPProtocols.h @@ -32,8 +32,7 @@ ============================================================================== */ -#ifndef DOXYGEN - +/** @cond */ namespace juce::universal_midi_packets { @@ -63,5 +62,4 @@ enum class MidiProtocol : uint8_t }; } // namespace juce::universal_midi_packets - -#endif +/** @endcond */ diff --git a/modules/juce_audio_basics/midi/ump/juce_UMPSysEx7.h b/modules/juce_audio_basics/midi/ump/juce_UMPSysEx7.h index 29ee563642..39deca2ce6 100644 --- a/modules/juce_audio_basics/midi/ump/juce_UMPSysEx7.h +++ b/modules/juce_audio_basics/midi/ump/juce_UMPSysEx7.h @@ -32,8 +32,7 @@ ============================================================================== */ -#ifndef DOXYGEN - +/** @cond */ namespace juce::universal_midi_packets { @@ -82,5 +81,4 @@ struct SysEx7 }; } // namespace juce::universal_midi_packets - -#endif +/** @endcond */ diff --git a/modules/juce_audio_basics/midi/ump/juce_UMPUtils.h b/modules/juce_audio_basics/midi/ump/juce_UMPUtils.h index a1fe67542f..c51bb84e22 100644 --- a/modules/juce_audio_basics/midi/ump/juce_UMPUtils.h +++ b/modules/juce_audio_basics/midi/ump/juce_UMPUtils.h @@ -32,8 +32,7 @@ ============================================================================== */ -#ifndef DOXYGEN - +/** @cond */ namespace juce::universal_midi_packets { @@ -146,5 +145,4 @@ struct Utils }; } // namespace juce::universal_midi_packets - -#endif +/** @endcond */ diff --git a/modules/juce_audio_basics/midi/ump/juce_UMPView.h b/modules/juce_audio_basics/midi/ump/juce_UMPView.h index 1e3d4af7cc..cbc3199c22 100644 --- a/modules/juce_audio_basics/midi/ump/juce_UMPView.h +++ b/modules/juce_audio_basics/midi/ump/juce_UMPView.h @@ -32,8 +32,7 @@ ============================================================================== */ -#ifndef DOXYGEN - +/** @cond */ namespace juce::universal_midi_packets { @@ -97,5 +96,4 @@ private: }; } // namespace juce::universal_midi_packets - -#endif +/** @endcond */ diff --git a/modules/juce_audio_basics/midi/ump/juce_UMPacket.h b/modules/juce_audio_basics/midi/ump/juce_UMPacket.h index ee7e50977c..178198e0c9 100644 --- a/modules/juce_audio_basics/midi/ump/juce_UMPacket.h +++ b/modules/juce_audio_basics/midi/ump/juce_UMPacket.h @@ -32,8 +32,7 @@ ============================================================================== */ -#ifndef DOXYGEN - +/** @cond */ namespace juce::universal_midi_packets { @@ -209,5 +208,4 @@ using PacketX3 = Packet<3>; using PacketX4 = Packet<4>; } // namespace juce::universal_midi_packets - -#endif +/** @endcond */ diff --git a/modules/juce_audio_basics/midi/ump/juce_UMPackets.h b/modules/juce_audio_basics/midi/ump/juce_UMPackets.h index 67f5a6bded..5fed8f4290 100644 --- a/modules/juce_audio_basics/midi/ump/juce_UMPackets.h +++ b/modules/juce_audio_basics/midi/ump/juce_UMPackets.h @@ -32,8 +32,7 @@ ============================================================================== */ -#ifndef DOXYGEN - +/** @cond */ namespace juce::universal_midi_packets { @@ -101,5 +100,4 @@ private: }; } // namespace juce::universal_midi_packets - -#endif +/** @endcond */ diff --git a/modules/juce_audio_basics/mpe/juce_MPEZoneLayout.h b/modules/juce_audio_basics/mpe/juce_MPEZoneLayout.h index 312afe8281..d50111fcac 100644 --- a/modules/juce_audio_basics/mpe/juce_MPEZoneLayout.h +++ b/modules/juce_audio_basics/mpe/juce_MPEZoneLayout.h @@ -226,9 +226,9 @@ public: /** Removes a listener. */ void removeListener (Listener* const listenerToRemove) noexcept; - #ifndef DOXYGEN + /** @cond */ using Zone = MPEZone; - #endif + /** @endcond */ private: //============================================================================== diff --git a/modules/juce_audio_basics/native/juce_CoreAudioLayouts_mac.h b/modules/juce_audio_basics/native/juce_CoreAudioLayouts_mac.h index 5e234d9f6e..ed4fb9e632 100644 --- a/modules/juce_audio_basics/native/juce_CoreAudioLayouts_mac.h +++ b/modules/juce_audio_basics/native/juce_CoreAudioLayouts_mac.h @@ -32,10 +32,11 @@ ============================================================================== */ +/** @cond */ namespace juce { -#if ! defined (DOXYGEN) && (JUCE_MAC || JUCE_IOS) +#if JUCE_MAC || JUCE_IOS struct CoreAudioLayouts { @@ -361,3 +362,4 @@ private: #endif } // namespace juce +/** @endcond */ diff --git a/modules/juce_audio_basics/native/juce_CoreAudioTimeConversions_mac.h b/modules/juce_audio_basics/native/juce_CoreAudioTimeConversions_mac.h index b9e63c882f..c7f72d59d7 100644 --- a/modules/juce_audio_basics/native/juce_CoreAudioTimeConversions_mac.h +++ b/modules/juce_audio_basics/native/juce_CoreAudioTimeConversions_mac.h @@ -36,7 +36,7 @@ // This file will be included directly by macOS/iOS-specific .cpps #pragma once -#if ! DOXYGEN +/** @cond */ #include @@ -89,4 +89,4 @@ private: } // namespace juce -#endif +/** @endcond */ diff --git a/modules/juce_audio_basics/utilities/juce_SmoothedValue.h b/modules/juce_audio_basics/utilities/juce_SmoothedValue.h index 474c5856a3..b2412a0ba3 100644 --- a/modules/juce_audio_basics/utilities/juce_SmoothedValue.h +++ b/modules/juce_audio_basics/utilities/juce_SmoothedValue.h @@ -342,7 +342,7 @@ public: } //============================================================================== - #ifndef DOXYGEN + /** @cond */ /** Using the new methods: lsv.setValue (x, false); -> lsv.setTargetValue (x); @@ -362,7 +362,7 @@ public: setTargetValue (newValue); } - #endif + /** @endcond */ private: //============================================================================== diff --git a/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.h b/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.h index 2cb0bf9c5a..4c1e6e5171 100644 --- a/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.h +++ b/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.h @@ -486,7 +486,7 @@ public: int getXRunCount() const noexcept; //============================================================================== - #ifndef DOXYGEN + /** @cond */ [[deprecated ("Use setMidiInputDeviceEnabled instead.")]] void setMidiInputEnabled (const String&, bool); [[deprecated ("Use isMidiInputDeviceEnabled instead.")]] @@ -499,7 +499,7 @@ public: void setDefaultMidiOutput (const String&); [[deprecated ("Use getDefaultMidiOutputIdentifier instead.")]] const String& getDefaultMidiOutputName() const noexcept { return defaultMidiOutputDeviceInfo.name; } - #endif + /** @endcond */ private: //============================================================================== diff --git a/modules/juce_audio_devices/audio_io/juce_AudioIODeviceType.h b/modules/juce_audio_devices/audio_io/juce_AudioIODeviceType.h index 90e858de07..12254cb99b 100644 --- a/modules/juce_audio_devices/audio_io/juce_AudioIODeviceType.h +++ b/modules/juce_audio_devices/audio_io/juce_AudioIODeviceType.h @@ -177,10 +177,10 @@ public: /** Creates an Oboe device type if it's available on this platform, or returns null. */ static AudioIODeviceType* createAudioIODeviceType_Oboe(); - #ifndef DOXYGEN + /** @cond */ [[deprecated ("You should call the method which takes a WASAPIDeviceMode instead.")]] static AudioIODeviceType* createAudioIODeviceType_WASAPI (bool exclusiveMode); - #endif + /** @endcond */ protected: explicit AudioIODeviceType (const String& typeName); diff --git a/modules/juce_audio_processors/format_types/LV2_SDK/generate_lv2_bundle_sources.py b/modules/juce_audio_processors/format_types/LV2_SDK/generate_lv2_bundle_sources.py index ca906075ec..f31b73d5b4 100644 --- a/modules/juce_audio_processors/format_types/LV2_SDK/generate_lv2_bundle_sources.py +++ b/modules/juce_audio_processors/format_types/LV2_SDK/generate_lv2_bundle_sources.py @@ -97,7 +97,7 @@ FUNCTION_TEMPLATE = """/* #pragma once -#ifndef DOXYGEN +/** @cond */ #include @@ -130,7 +130,7 @@ std::vector juce::lv2::Bundle::getAllBundles() }}; }} -#endif""" +/** @endcond */""" def chunks(lst, n): diff --git a/modules/juce_audio_processors/format_types/juce_AU_Shared.h b/modules/juce_audio_processors/format_types/juce_AU_Shared.h index fceec44d1f..b41e0b12cf 100644 --- a/modules/juce_audio_processors/format_types/juce_AU_Shared.h +++ b/modules/juce_audio_processors/format_types/juce_AU_Shared.h @@ -32,8 +32,7 @@ ============================================================================== */ -#ifndef DOXYGEN - +/** @cond */ // This macro can be set if you need to override this internal name for some reason.. #ifndef JUCE_STATE_DICTIONARY_KEY #define JUCE_STATE_DICTIONARY_KEY "jucePluginState" @@ -711,5 +710,4 @@ struct AudioUnitHelpers }; } // namespace juce - -#endif +/** @endcond */ diff --git a/modules/juce_audio_processors/format_types/juce_LV2Common.h b/modules/juce_audio_processors/format_types/juce_LV2Common.h index 10a64b8ef0..051ebc15fe 100644 --- a/modules/juce_audio_processors/format_types/juce_LV2Common.h +++ b/modules/juce_audio_processors/format_types/juce_LV2Common.h @@ -34,7 +34,7 @@ #pragma once -#ifndef DOXYGEN +/** @cond */ #include "juce_lv2_config.h" @@ -672,5 +672,4 @@ static inline String sanitiseStringAsTtlName (const String& input) } } // namespace juce::lv2_shared - -#endif +/** @endcond */ diff --git a/modules/juce_audio_processors/format_types/juce_LV2Resources.h b/modules/juce_audio_processors/format_types/juce_LV2Resources.h index c560973bc8..834cf3143a 100644 --- a/modules/juce_audio_processors/format_types/juce_LV2Resources.h +++ b/modules/juce_audio_processors/format_types/juce_LV2Resources.h @@ -38,7 +38,7 @@ #pragma once -#ifndef DOXYGEN +/** @cond */ #include @@ -10238,4 +10238,4 @@ to an instance of LV2_Extension_Data_Feature. }; } -#endif +/** @endcond */ diff --git a/modules/juce_audio_processors/format_types/juce_VST3Common.h b/modules/juce_audio_processors/format_types/juce_VST3Common.h index 107f61321f..98623188b5 100644 --- a/modules/juce_audio_processors/format_types/juce_VST3Common.h +++ b/modules/juce_audio_processors/format_types/juce_VST3Common.h @@ -34,8 +34,7 @@ #pragma once -#ifndef DOXYGEN - +/** @cond */ namespace juce { @@ -1663,5 +1662,4 @@ private: JUCE_END_NO_SANITIZE } // namespace juce - -#endif +/** @endcond */ diff --git a/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.h b/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.h index c9e7ec3d81..f0af5ea98f 100644 --- a/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.h +++ b/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.h @@ -52,7 +52,7 @@ public: ~VST3PluginFormat() override; //============================================================================== - #ifndef DOXYGEN + /** @cond */ /** Attempts to reload a VST3 plugin's state from some preset file data. @see VSTPluginFormat::loadFromFXBFile @@ -62,7 +62,7 @@ public: "Then, call ExtensionsVisitor::VST3::setPreset() to set the state using the " "contents of a vstpreset file.")]] static bool setStateFromVSTPresetFile (AudioPluginInstance*, const MemoryBlock&); - #endif + /** @endcond */ //============================================================================== static String getFormatName() { return "VST3"; } diff --git a/modules/juce_audio_processors/format_types/juce_VST3Utilities.h b/modules/juce_audio_processors/format_types/juce_VST3Utilities.h index a8782c570c..14867972b0 100644 --- a/modules/juce_audio_processors/format_types/juce_VST3Utilities.h +++ b/modules/juce_audio_processors/format_types/juce_VST3Utilities.h @@ -34,8 +34,7 @@ #pragma once -#ifndef DOXYGEN - +/** @cond */ namespace juce { @@ -239,5 +238,4 @@ auto becomeVSTComSmartPtrOwner (ObjectType* t) JUCE_END_NO_SANITIZE } // namespace juce - -#endif // DOXYGEN +/** @endcond */ diff --git a/modules/juce_audio_processors/processors/juce_AudioPluginInstance.h b/modules/juce_audio_processors/processors/juce_AudioPluginInstance.h index 234e02c5ea..2f70906db4 100644 --- a/modules/juce_audio_processors/processors/juce_AudioPluginInstance.h +++ b/modules/juce_audio_processors/processors/juce_AudioPluginInstance.h @@ -118,7 +118,7 @@ public: */ HostedParameter* getHostedParameter (int index) const; - #ifndef DOXYGEN + /** @cond */ /** Use the new typesafe visitor-based interface rather than this function. Returns a pointer to some kind of platform-specific data about the plugin. @@ -150,7 +150,7 @@ public: [[deprecated]] bool isParameterOrientationInverted (int parameterIndex) const override; [[deprecated]] bool isMetaParameter (int parameterIndex) const override; [[deprecated]] AudioProcessorParameter::Category getParameterCategory (int parameterIndex) const override; - #endif + /** @endcond */ protected: //============================================================================== diff --git a/modules/juce_audio_processors/processors/juce_AudioProcessor.h b/modules/juce_audio_processors/processors/juce_AudioProcessor.h index 0b8cb7e785..00df5b2f7b 100644 --- a/modules/juce_audio_processors/processors/juce_AudioProcessor.h +++ b/modules/juce_audio_processors/processors/juce_AudioProcessor.h @@ -1487,7 +1487,7 @@ protected: void sendParamChangeMessageToListeners (int parameterIndex, float newValue); public: - #ifndef DOXYGEN + /** @cond */ // These methods are all deprecated in favour of using AudioProcessorParameter // and AudioProcessorParameterGroup [[deprecated]] virtual int getNumParameters(); @@ -1520,7 +1520,7 @@ public: [[deprecated]] virtual const String getOutputChannelName (int channelIndex) const; [[deprecated]] virtual bool isInputChannelStereoPair (int index) const; [[deprecated]] virtual bool isOutputChannelStereoPair (int index) const; - #endif + /** @endcond */ private: //============================================================================== diff --git a/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.cpp b/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.cpp index 2d4c97c53b..42eaf06e0b 100644 --- a/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.cpp +++ b/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.cpp @@ -1193,18 +1193,25 @@ private: jassert (bufIndex >= 0); } - if (inputChan < numOuts && isBufferNeededLater (reversed, ourRenderingIndex, inputChan, src)) + const auto nodeDelay = getNodeDelay (src.nodeID); + const auto needsDelay = nodeDelay < maxLatency; + + if ((inputChan < numOuts || needsDelay) + && isBufferNeededLater (reversed, ourRenderingIndex, inputChan, src)) { - // can't mess up this channel because it's needed later by another node, - // so we need to use a copy of it.. + // We can't modify this channel because it's needed later by another node, + // so we need to use a copy of it. + // If the input channel index matches any output channel index, this implies that + // the output would overwrite the content of the input buffer. + // If the input needs to be delayed by some amount, this will modify the buffer + // in-place which will produce the wrong delay if a subsequent input needs a + // different delay value. auto newFreeBuffer = getFreeBuffer (audioBuffers); sequence.addCopyChannelOp (bufIndex, newFreeBuffer); bufIndex = newFreeBuffer; } - auto nodeDelay = getNodeDelay (src.nodeID); - - if (nodeDelay < maxLatency) + if (needsDelay) sequence.addDelayChannelOp (bufIndex, maxLatency - nodeDelay); return bufIndex; @@ -2144,6 +2151,8 @@ public: void runTest() override { + const ScopedJuceInitialiser_GUI scope; + const auto midiChannel = AudioProcessorGraph::midiChannelIndex; beginTest ("isConnected returns true when two nodes are connected"); @@ -2330,6 +2339,66 @@ public: // not a supported usage pattern. } + beginTest ("When a delayed channel is used as an input to multiple nodes, the delay is applied appropriately for each node"); + { + AudioProcessorGraph graph; + graph.setBusesLayout ({ { AudioChannelSet::stereo() }, { AudioChannelSet::mono() } }); + + const auto nodeA = graph.addNode (BasicProcessor::make (BasicProcessor::getStereoInMonoOut(), MidiIn::no, MidiOut::no)); + const auto nodeB = graph.addNode (BasicProcessor::make (BasicProcessor::getStereoInMonoOut(), MidiIn::no, MidiOut::no)); + const auto nodeC = graph.addNode (BasicProcessor::make (BasicProcessor::getStereoInMonoOut(), MidiIn::no, MidiOut::no)); + const auto input = graph.addNode (std::make_unique (AudioProcessorGraph::AudioGraphIOProcessor::IODeviceType::audioInputNode)); + const auto output = graph.addNode (std::make_unique (AudioProcessorGraph::AudioGraphIOProcessor::IODeviceType::audioOutputNode)); + + constexpr auto latencySamples = 2; + nodeA->getProcessor()->setLatencySamples (latencySamples); + + // [input 0 1] 0 and 1 denote input/output channels + // | | + // | | + // [nodeA 0 1] | nodeA has latency applied + // | /| + // | / | + // [nodeB 0 1] | each node sums all input channels onto the first output channel + // | / + // | / + // [nodeC 0 1] + // | + // | + // [out 0] + + expect (graph.addConnection ({ { input->nodeID, 0}, { nodeA->nodeID, 0} })); + expect (graph.addConnection ({ { input->nodeID, 1}, { nodeB->nodeID, 1} })); + expect (graph.addConnection ({ { input->nodeID, 1}, { nodeC->nodeID, 1} })); + + expect (graph.addConnection ({ { nodeA->nodeID, 0}, { nodeB->nodeID, 0} })); + expect (graph.addConnection ({ { nodeB->nodeID, 0}, { nodeC->nodeID, 0} })); + + expect (graph.addConnection ({ { nodeC->nodeID, 0}, { output->nodeID, 0} })); + + graph.rebuild(); + + constexpr auto blockSize = 128; + graph.prepareToPlay (44100.0, blockSize); + expect (graph.getLatencySamples() == latencySamples); + + AudioBuffer audio (2, blockSize); + audio.clear(); + audio.setSample (1, 0, 1.0f); + + MidiBuffer midi; + graph.processBlock (audio, midi); + + // The impulse should arrive at nodes B and C simultaneously, so the end result should + // be a double-amplitude impulse with the latency of node A applied + + for (auto i = 0; i < blockSize; ++i) + { + const auto expected = i == latencySamples ? 2.0f : 0.0f; + expect (exactlyEqual (audio.getSample (0, i), expected)); + } + } + beginTest ("large render sequence can be built"); { AudioProcessorGraph graph; @@ -2368,7 +2437,7 @@ private: class BasicProcessor final : public AudioProcessor { public: - explicit BasicProcessor (const AudioProcessor::BusesProperties& layout, MidiIn mIn, MidiOut mOut) + explicit BasicProcessor (const BusesProperties& layout, MidiIn mIn, MidiOut mOut) : AudioProcessor (layout), midiIn (mIn), midiOut (mOut) {} const String getName() const override { return "Basic Processor"; } @@ -2382,7 +2451,7 @@ private: void setCurrentProgram (int) override {} const String getProgramName (int) override { return {}; } void changeProgramName (int, const String&) override {} - void getStateInformation (juce::MemoryBlock&) override {} + void getStateInformation (MemoryBlock&) override {} void setStateInformation (const void*, int) override {} void prepareToPlay (double, int) override {} void releaseResources() override {} @@ -2391,14 +2460,20 @@ private: void reset() override {} void setNonRealtime (bool) noexcept override {} - void processBlock (AudioBuffer&, MidiBuffer&) override + void processBlock (AudioBuffer& audio, MidiBuffer&) override { blockPrecision = singlePrecision; + + for (auto i = 1; i < audio.getNumChannels(); ++i) + audio.addFrom (0, 0, audio.getReadPointer (i), audio.getNumSamples()); } - void processBlock (AudioBuffer&, MidiBuffer&) override + void processBlock (AudioBuffer& audio, MidiBuffer&) override { blockPrecision = doublePrecision; + + for (auto i = 1; i < audio.getNumChannels(); ++i) + audio.addFrom (0, 0, audio.getReadPointer (i), audio.getNumSamples()); } static std::unique_ptr make (const BusesProperties& layout, @@ -2419,6 +2494,12 @@ private: .withOutput ("out", AudioChannelSet::stereo()); } + static BusesProperties getStereoInMonoOut() + { + return BusesProperties().withInput ("in", AudioChannelSet::stereo()) + .withOutput ("out", AudioChannelSet::mono()); + } + static BusesProperties getMultichannelProperties (int numChannels) { return BusesProperties().withInput ("in", AudioChannelSet::discreteChannels (numChannels)) diff --git a/modules/juce_audio_processors/processors/juce_AudioProcessorParameterGroup.h b/modules/juce_audio_processors/processors/juce_AudioProcessorParameterGroup.h index 0a888bdcd2..b5a4b6b75e 100644 --- a/modules/juce_audio_processors/processors/juce_AudioProcessorParameterGroup.h +++ b/modules/juce_audio_processors/processors/juce_AudioProcessorParameterGroup.h @@ -235,13 +235,13 @@ public: addChild (std::forward (remainingChildren)...); } - #ifndef DOXYGEN + /** @cond */ [[deprecated ("This class now has a move operator, so if you're trying to move them around, you " "should use that, or if you really need to swap two groups, just call std::swap. " "However, remember that swapping a group that's already owned by an AudioProcessor " "will most likely crash the host, so don't do that.")]] void swapWith (AudioProcessorParameterGroup& other) { std::swap (*this, other); } - #endif + /** @endcond */ private: //============================================================================== diff --git a/modules/juce_audio_processors/processors/juce_GenericAudioProcessorEditor.h b/modules/juce_audio_processors/processors/juce_GenericAudioProcessorEditor.h index 13df38ca2e..5830c75282 100644 --- a/modules/juce_audio_processors/processors/juce_GenericAudioProcessorEditor.h +++ b/modules/juce_audio_processors/processors/juce_GenericAudioProcessorEditor.h @@ -58,10 +58,10 @@ public: void paint (Graphics&) override; void resized() override; - #ifndef DOXYGEN + /** @cond */ [[deprecated ("This constructor has been changed to take a reference instead of a pointer.")]] GenericAudioProcessorEditor (AudioProcessor* p) : GenericAudioProcessorEditor (*p) {} - #endif + /** @endcond */ private: //============================================================================== diff --git a/modules/juce_audio_processors/scanning/juce_KnownPluginList.h b/modules/juce_audio_processors/scanning/juce_KnownPluginList.h index 98148a3027..1bda8ad0ca 100644 --- a/modules/juce_audio_processors/scanning/juce_KnownPluginList.h +++ b/modules/juce_audio_processors/scanning/juce_KnownPluginList.h @@ -218,7 +218,7 @@ public: void setCustomScanner (std::unique_ptr newScanner); //============================================================================== - #ifndef DOXYGEN + /** @cond */ // These methods have been deprecated! When getting the list of plugin types you should instead use // the getTypes() method which returns a copy of the internal PluginDescription array and can be accessed // in a thread-safe way. @@ -234,7 +234,7 @@ public: [[deprecated]] void addToMenu (PopupMenu& menu, SortMethod sortMethod, const String& currentlyTickedPluginID = {}) const; [[deprecated]] int getIndexChosenByMenu (int menuResultCode) const; [[deprecated]] std::unique_ptr createTree (SortMethod sortMethod) const; - #endif + /** @endcond */ private: //============================================================================== diff --git a/modules/juce_audio_processors/utilities/ARA/juce_ARADebug.h b/modules/juce_audio_processors/utilities/ARA/juce_ARADebug.h index 370b2b3852..43231d96ef 100644 --- a/modules/juce_audio_processors/utilities/ARA/juce_ARADebug.h +++ b/modules/juce_audio_processors/utilities/ARA/juce_ARADebug.h @@ -36,9 +36,11 @@ #include -#if ! (defined (JUCE_API) || defined (DOXYGEN)) - #define JUCE_API +/** @cond */ +#ifndef JUCE_API + #define JUCE_API #endif +/** @endcond */ #if (JucePlugin_Enable_ARA || (JUCE_PLUGINHOST_ARA && (JUCE_PLUGINHOST_VST3 || JUCE_PLUGINHOST_AU))) && (JUCE_MAC || JUCE_WINDOWS || JUCE_LINUX) diff --git a/modules/juce_audio_processors/utilities/ARA/juce_ARADocumentController.cpp b/modules/juce_audio_processors/utilities/ARA/juce_ARADocumentController.cpp index a22b27c353..79927fb607 100644 --- a/modules/juce_audio_processors/utilities/ARA/juce_ARADocumentController.cpp +++ b/modules/juce_audio_processors/utilities/ARA/juce_ARADocumentController.cpp @@ -141,8 +141,7 @@ protected: void doRequestProcessingAlgorithmForAudioSource (ARA::PlugIn::AudioSource* audioSource, ARA::ARAInt32 algorithmIndex) noexcept override; -#ifndef DOXYGEN - + /** @cond */ //============================================================================== bool doRestoreObjectsFromArchive (ARA::PlugIn::HostArchiveReader* archiveReader, const ARA::PlugIn::RestoreObjectsFilter* filter) noexcept override; bool doStoreObjectsToArchive (ARA::PlugIn::HostArchiveWriter* archiveWriter, const ARA::PlugIn::StoreObjectsFilter* filter) noexcept override; @@ -211,8 +210,10 @@ protected: void willUpdatePlaybackRegionProperties (ARA::PlugIn::PlaybackRegion* playbackRegion, ARAPlaybackRegion::PropertiesPtr newProperties) noexcept override; void didUpdatePlaybackRegionProperties (ARA::PlugIn::PlaybackRegion* playbackRegion) noexcept override; void willDestroyPlaybackRegion (ARA::PlugIn::PlaybackRegion* playbackRegion) noexcept override; + /** @endcond */ public: + /** @cond */ //============================================================================== /** @internal */ void internalNotifyAudioSourceAnalysisProgressStarted (ARAAudioSource* audioSource) override; @@ -244,7 +245,7 @@ public: ARAContentUpdateScopes scopeFlags, bool notifyARAHost) override; -#endif + /** @endcond */ private: //============================================================================== diff --git a/modules/juce_audio_processors/utilities/juce_AudioProcessorValueTreeState.h b/modules/juce_audio_processors/utilities/juce_AudioProcessorValueTreeState.h index c9758bf965..365b5e021c 100644 --- a/modules/juce_audio_processors/utilities/juce_AudioProcessorValueTreeState.h +++ b/modules/juce_audio_processors/utilities/juce_AudioProcessorValueTreeState.h @@ -279,7 +279,7 @@ public: ~AudioProcessorValueTreeState() override; //============================================================================== - #ifndef DOXYGEN + /** @cond */ /** Previous calls to @code @@ -326,7 +326,7 @@ public: bool isDiscrete = false, AudioProcessorParameter::Category parameterCategory = AudioProcessorParameter::genericParameter, bool isBoolean = false); - #endif + /** @endcond */ /** This function adds a parameter to the attached AudioProcessor and that parameter will be managed by this AudioProcessorValueTreeState object. diff --git a/modules/juce_audio_processors/utilities/juce_ExtensionsVisitor.h b/modules/juce_audio_processors/utilities/juce_ExtensionsVisitor.h index 47641b7317..d2ea46a6ed 100644 --- a/modules/juce_audio_processors/utilities/juce_ExtensionsVisitor.h +++ b/modules/juce_audio_processors/utilities/juce_ExtensionsVisitor.h @@ -32,7 +32,7 @@ ============================================================================== */ -#ifndef DOXYGEN +/** @cond */ // Forward declarations to avoid leaking implementation details. namespace Steinberg::Vst @@ -40,7 +40,7 @@ namespace Steinberg::Vst class IComponent; } // namespace Steinberg::Vst -#endif +/** @endcond */ //============================================================================== #if TARGET_OS_IPHONE diff --git a/modules/juce_audio_processors/utilities/juce_FlagCache.h b/modules/juce_audio_processors/utilities/juce_FlagCache.h index 79af99222b..379926fd78 100644 --- a/modules/juce_audio_processors/utilities/juce_FlagCache.h +++ b/modules/juce_audio_processors/utilities/juce_FlagCache.h @@ -32,8 +32,7 @@ ============================================================================== */ -#if ! DOXYGEN - +/** @cond */ namespace juce { @@ -187,5 +186,4 @@ private: }; } // namespace juce - -#endif +/** @endcond */ diff --git a/modules/juce_audio_processors/utilities/juce_PluginHostType.h b/modules/juce_audio_processors/utilities/juce_PluginHostType.h index 0470c3e52b..b61fc6e65b 100644 --- a/modules/juce_audio_processors/utilities/juce_PluginHostType.h +++ b/modules/juce_audio_processors/utilities/juce_PluginHostType.h @@ -251,12 +251,12 @@ public: //============================================================================== - #ifndef DOXYGEN + /** @cond */ // @internal static AudioProcessor::WrapperType jucePlugInClientCurrentWrapperType; static std::function jucePlugInIsRunningInAudioSuiteFn; static String hostIdReportedByWrapper; - #endif + /** @endcond */ private: static HostType getHostType(); diff --git a/modules/juce_audio_processors/utilities/juce_VST3ClientExtensions.h b/modules/juce_audio_processors/utilities/juce_VST3ClientExtensions.h index 3e7f2d334a..2a1c846cf9 100644 --- a/modules/juce_audio_processors/utilities/juce_VST3ClientExtensions.h +++ b/modules/juce_audio_processors/utilities/juce_VST3ClientExtensions.h @@ -32,7 +32,7 @@ ============================================================================== */ -#ifndef DOXYGEN +/** @cond */ // Forward declaration to avoid leaking implementation details. namespace Steinberg @@ -41,7 +41,7 @@ namespace Steinberg using TUID = char[16]; } // namespace Steinberg -#endif // DOXYGEN +/** @endcond */ namespace juce { diff --git a/modules/juce_audio_utils/gui/juce_KeyboardComponentBase.h b/modules/juce_audio_utils/gui/juce_KeyboardComponentBase.h index de40acc9fd..fabf56e704 100644 --- a/modules/juce_audio_utils/gui/juce_KeyboardComponentBase.h +++ b/modules/juce_audio_utils/gui/juce_KeyboardComponentBase.h @@ -204,11 +204,11 @@ public: */ NoteAndVelocity getNoteAndVelocityAtPosition (Point position, bool includeChildComponents = false); - #ifndef DOXYGEN + /** @cond */ /** Returns the key at a given coordinate, or -1 if the position does not intersect a key. */ [[deprecated ("This method has been deprecated in favour of getNoteAndVelocityAtPosition.")]] int getNoteAtPosition (Point p) { return getNoteAndVelocityAtPosition (p).note; } - #endif + /** @endcond */ /** Returns the rectangle for a given key. */ Rectangle getRectangleForKey (int midiNoteNumber) const; diff --git a/modules/juce_box2d/juce_box2d.h b/modules/juce_box2d/juce_box2d.h index 3e6f5437a6..3ee9a76d47 100644 --- a/modules/juce_box2d/juce_box2d.h +++ b/modules/juce_box2d/juce_box2d.h @@ -80,6 +80,7 @@ JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wconversion", JUCE_END_IGNORE_WARNINGS_GCC_LIKE -#ifndef DOXYGEN // for some reason, Doxygen sees this as a re-definition of Box2DRenderer - #include "utils/juce_Box2DRenderer.h" -#endif // DOXYGEN +// For some reason, Doxygen sees this as a re-definition of Box2DRenderer +/** @cond */ +#include "utils/juce_Box2DRenderer.h" +/** @endcond */ diff --git a/modules/juce_core/containers/juce_Array.h b/modules/juce_core/containers/juce_Array.h index c39622d550..ffc0234520 100644 --- a/modules/juce_core/containers/juce_Array.h +++ b/modules/juce_core/containers/juce_Array.h @@ -1107,11 +1107,11 @@ public: //============================================================================== - #ifndef DOXYGEN + /** @cond */ [[deprecated ("This method has been replaced by a more flexible templated version and renamed " "to swapWith to be more consistent with the names used in other classes.")]] void swapWithArray (Array& other) noexcept { swapWith (other); } - #endif + /** @endcond */ private: //============================================================================== diff --git a/modules/juce_core/containers/juce_ElementComparator.h b/modules/juce_core/containers/juce_ElementComparator.h index a6b649cc96..2c935e5b70 100644 --- a/modules/juce_core/containers/juce_ElementComparator.h +++ b/modules/juce_core/containers/juce_ElementComparator.h @@ -35,8 +35,7 @@ namespace juce { -#ifndef DOXYGEN - +/** @cond */ /** This is an internal helper class which converts a juce ElementComparator style class (using a "compareElements" method) into a class that's compatible with std::sort (i.e. using an operator() to compare the elements) @@ -57,8 +56,7 @@ private: SortFunctionConverter& operator= (const SortFunctionConverter&) = delete; }; - -#endif +/** @endcond */ //============================================================================== diff --git a/modules/juce_core/containers/juce_FixedSizeFunction.h b/modules/juce_core/containers/juce_FixedSizeFunction.h index 2d185ee9e5..e316f9af73 100644 --- a/modules/juce_core/containers/juce_FixedSizeFunction.h +++ b/modules/juce_core/containers/juce_FixedSizeFunction.h @@ -35,8 +35,7 @@ namespace juce { -#ifndef DOXYGEN - +/** @cond */ namespace detail { template @@ -91,8 +90,7 @@ namespace detail template class FixedSizeFunction; - -#endif +/** @endcond */ /** A type similar to `std::function` that holds a callable object. diff --git a/modules/juce_core/containers/juce_Optional.h b/modules/juce_core/containers/juce_Optional.h index a7fb632b95..4168e75668 100644 --- a/modules/juce_core/containers/juce_Optional.h +++ b/modules/juce_core/containers/juce_Optional.h @@ -42,9 +42,9 @@ constexpr auto nullopt = std::nullopt; // link time code generation. JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4702) -#ifndef DOXYGEN +/** @cond */ #define JUCE_OPTIONAL_OPERATORS X(==) X(!=) X(<) X(<=) X(>) X(>=) -#endif +/** @endcond */ /** A simple optional type. @@ -175,7 +175,7 @@ Optional> makeOptional (Value&& v) return std::forward (v); } -#ifndef DOXYGEN +/** @cond */ #define X(op) \ template bool operator op (const Optional& lhs, const Optional& rhs) { return lhs.opt op rhs.opt; } \ template bool operator op (const Optional& lhs, Nullopt rhs) { return lhs.opt op rhs; } \ @@ -187,6 +187,6 @@ JUCE_OPTIONAL_OPERATORS #undef X #undef JUCE_OPTIONAL_OPERATORS -#endif +/** @endcond */ } // namespace juce diff --git a/modules/juce_core/containers/juce_OwnedArray.h b/modules/juce_core/containers/juce_OwnedArray.h index a9022ad5f4..4031bcfa5c 100644 --- a/modules/juce_core/containers/juce_OwnedArray.h +++ b/modules/juce_core/containers/juce_OwnedArray.h @@ -806,11 +806,11 @@ public: using ScopedLockType = typename TypeOfCriticalSectionToUse::ScopedLockType; //============================================================================== - #ifndef DOXYGEN + /** @cond */ [[deprecated ("This method has been replaced by a more flexible templated version and renamed " "to swapWith to be more consistent with the names used in other classes.")]] void swapWithArray (OwnedArray& other) noexcept { swapWith (other); } - #endif + /** @endcond */ private: //============================================================================== diff --git a/modules/juce_core/containers/juce_ReferenceCountedArray.h b/modules/juce_core/containers/juce_ReferenceCountedArray.h index ecf82f667e..ef7b1985e2 100644 --- a/modules/juce_core/containers/juce_ReferenceCountedArray.h +++ b/modules/juce_core/containers/juce_ReferenceCountedArray.h @@ -854,11 +854,11 @@ public: using ScopedLockType = typename TypeOfCriticalSectionToUse::ScopedLockType; //============================================================================== - #ifndef DOXYGEN + /** @cond */ [[deprecated ("This method has been replaced by a more flexible templated version and renamed " "to swapWith to be more consistent with the names used in other classes.")]] void swapWithArray (ReferenceCountedArray& other) noexcept { swapWith (other); } - #endif + /** @endcond */ private: //============================================================================== diff --git a/modules/juce_core/containers/juce_Variant.h b/modules/juce_core/containers/juce_Variant.h index 3e70efd3f6..9a853eb7c0 100644 --- a/modules/juce_core/containers/juce_Variant.h +++ b/modules/juce_core/containers/juce_Variant.h @@ -295,12 +295,14 @@ public: static var readFromStream (InputStream& input); //============================================================================== - #if JUCE_ALLOW_STATIC_NULL_VARIABLES && ! defined (DOXYGEN) + #if JUCE_ALLOW_STATIC_NULL_VARIABLES + /** @cond */ [[deprecated ("This was a static empty var object, but is now deprecated as it's too easy to accidentally " "use it indirectly during a static constructor leading to hard-to-find order-of-initialisation " "problems. Use var() or {} instead. For returning an empty var from a function by reference, " "use a function-local static var and return that.")]] static const var null; + /** @endcond */ #endif private: diff --git a/modules/juce_core/detail/juce_LruCache.h b/modules/juce_core/detail/juce_LruCache.h index 213a86ed70..7154c5606d 100644 --- a/modules/juce_core/detail/juce_LruCache.h +++ b/modules/juce_core/detail/juce_LruCache.h @@ -32,8 +32,7 @@ ============================================================================== */ -#ifndef DOXYGEN - +/** @cond */ namespace juce { @@ -84,5 +83,4 @@ private: }; } // namespace juce - -#endif +/** @endcond */ diff --git a/modules/juce_core/files/juce_DirectoryIterator.h b/modules/juce_core/files/juce_DirectoryIterator.h index 9b05bd5abe..399177735c 100644 --- a/modules/juce_core/files/juce_DirectoryIterator.h +++ b/modules/juce_core/files/juce_DirectoryIterator.h @@ -35,8 +35,7 @@ namespace juce { -#ifndef DOXYGEN - +/** @cond */ //============================================================================== /** This class is now deprecated in favour of RangedDirectoryIterator. @@ -203,7 +202,6 @@ private: JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DirectoryIterator) }; - -#endif +/** @endcond */ } // namespace juce diff --git a/modules/juce_core/files/juce_File.h b/modules/juce_core/files/juce_File.h index 9d4c3264a9..f59e8c25c3 100644 --- a/modules/juce_core/files/juce_File.h +++ b/modules/juce_core/files/juce_File.h @@ -35,9 +35,11 @@ namespace juce { -#if ! DOXYGEN && (JUCE_MAC || JUCE_IOS) +/** @cond */ +#if JUCE_MAC || JUCE_IOS using OSType = unsigned int; #endif +/** @endcond */ //============================================================================== /** @@ -1153,7 +1155,8 @@ public: bool foldersFirst; }; - #if JUCE_ALLOW_STATIC_NULL_VARIABLES && ! defined (DOXYGEN) + #if JUCE_ALLOW_STATIC_NULL_VARIABLES + /** @cond */ /* These static objects are deprecated because it's too easy to accidentally use them indirectly during a static constructor, which leads to very obscure order-of-initialisation bugs. Use File::getSeparatorChar() and File::getSeparatorString(), and instead of File::nonexistent, @@ -1162,6 +1165,7 @@ public: [[deprecated]] static const juce_wchar separator; [[deprecated]] static const StringRef separatorString; [[deprecated]] static const File nonexistent; + /** @endcond */ #endif private: diff --git a/modules/juce_core/json/juce_JSONSerialisation.h b/modules/juce_core/json/juce_JSONSerialisation.h index 3e2a497041..1f6109c3fc 100644 --- a/modules/juce_core/json/juce_JSONSerialisation.h +++ b/modules/juce_core/json/juce_JSONSerialisation.h @@ -499,16 +499,14 @@ struct VariantConverter } }; -#ifndef DOXYGEN - +/** @cond */ template <> struct VariantConverter { static String fromVar (const var& v) { return v.toString(); } static var toVar (const String& s) { return s; } }; - -#endif +/** @endcond */ /** A helper type that can be used to implement specialisations of VariantConverter that use diff --git a/modules/juce_core/juce_core.h b/modules/juce_core/juce_core.h index fd66714894..4f0a443dee 100644 --- a/modules/juce_core/juce_core.h +++ b/modules/juce_core/juce_core.h @@ -394,7 +394,7 @@ JUCE_END_IGNORE_WARNINGS_MSVC #include "unit_tests/juce_UnitTestCategories.h" #endif -#ifndef DOXYGEN +/** @cond */ namespace juce { /* @@ -415,7 +415,7 @@ namespace juce static this_will_fail_to_link_if_some_of_your_compile_units_are_built_in_release_mode compileUnitMismatchSentinel; #endif } -#endif +/** @endcond */ JUCE_END_IGNORE_WARNINGS_MSVC diff --git a/modules/juce_core/maths/juce_MathsFunctions.h b/modules/juce_core/maths/juce_MathsFunctions.h index 9f5484ef3c..75916abfdc 100644 --- a/modules/juce_core/maths/juce_MathsFunctions.h +++ b/modules/juce_core/maths/juce_MathsFunctions.h @@ -68,14 +68,14 @@ using uint32 = unsigned int; using uint64 = unsigned long long; #endif -#ifndef DOXYGEN - /** A macro for creating 64-bit literals. - Historically, this was needed to support portability with MSVC6, and is kept here - so that old code will still compile, but nowadays every compiler will support the - LL and ULL suffixes, so you should use those in preference to this macro. - */ - #define literal64bit(longLiteral) (longLiteral##LL) -#endif +/** @cond */ +/** A macro for creating 64-bit literals. + Historically, this was needed to support portability with MSVC6, and is kept here + so that old code will still compile, but nowadays every compiler will support the + LL and ULL suffixes, so you should use those in preference to this macro. +*/ +#define literal64bit(longLiteral) (longLiteral##LL) +/** @endcond */ #if JUCE_64BIT /** A signed integer type that's guaranteed to be large enough to hold a pointer without truncating it. */ @@ -129,7 +129,7 @@ Type juce_hypot (Type a, Type b) noexcept #endif } -#ifndef DOXYGEN +/** @cond */ template <> inline float juce_hypot (float a, float b) noexcept { @@ -139,7 +139,7 @@ inline float juce_hypot (float a, float b) noexcept return hypotf (a, b); #endif } -#endif +/** @endcond */ //============================================================================== /** Commonly used mathematical constants @@ -165,7 +165,7 @@ struct MathConstants static constexpr FloatType sqrt2 = static_cast (1.4142135623730950488L); }; -#ifndef DOXYGEN +/** @cond */ /** A double-precision constant for pi. */ [[deprecated ("This is deprecated in favour of MathConstants::pi.")]] const constexpr double double_Pi = MathConstants::pi; @@ -173,7 +173,7 @@ const constexpr double double_Pi = MathConstants::pi; /** A single-precision constant for pi. */ [[deprecated ("This is deprecated in favour of MathConstants::pi.")]] const constexpr float float_Pi = MathConstants::pi; -#endif +/** @endcond */ /** Converts an angle in degrees to radians. */ template @@ -763,7 +763,7 @@ namespace TypeHelpers */ template struct ParameterType { using type = const Type&; }; - #ifndef DOXYGEN + /** @cond */ template struct ParameterType { using type = Type&; }; template struct ParameterType { using type = Type*; }; template <> struct ParameterType { using type = char; }; @@ -779,7 +779,7 @@ namespace TypeHelpers template <> struct ParameterType { using type = bool; }; template <> struct ParameterType { using type = float; }; template <> struct ParameterType { using type = double; }; - #endif + /** @endcond */ /** These templates are designed to take a type, and if it's a double, they return a double type; for anything else, they return a float type. @@ -796,20 +796,20 @@ namespace TypeHelpers */ template struct UnsignedTypeWithSize {}; - #ifndef DOXYGEN + /** @cond */ template <> struct UnsignedTypeWithSize<1> { using type = uint8; }; template <> struct UnsignedTypeWithSize<2> { using type = uint16; }; template <> struct UnsignedTypeWithSize<4> { using type = uint32; }; template <> struct UnsignedTypeWithSize<8> { using type = uint64; }; - #endif + /** @endcond */ } //============================================================================== -#ifndef DOXYGEN - [[deprecated ("Use roundToInt instead.")]] inline int roundDoubleToInt (double value) noexcept { return roundToInt (value); } - [[deprecated ("Use roundToInt instead.")]] inline int roundFloatToInt (float value) noexcept { return roundToInt (value); } - [[deprecated ("Use std::abs() instead.")]] inline int64 abs64 (int64 n) noexcept { return std::abs (n); } -#endif +/** @cond */ +[[deprecated ("Use roundToInt instead.")]] inline int roundDoubleToInt (double value) noexcept { return roundToInt (value); } +[[deprecated ("Use roundToInt instead.")]] inline int roundFloatToInt (float value) noexcept { return roundToInt (value); } +[[deprecated ("Use std::abs() instead.")]] inline int64 abs64 (int64 n) noexcept { return std::abs (n); } +/** @endcond */ /** Converts an enum to its underlying integral type. Similar to std::to_underlying, which is only available in C++23 and above. diff --git a/modules/juce_core/memory/juce_Atomic.h b/modules/juce_core/memory/juce_Atomic.h index 0e71521c43..3d6a1d5ca2 100644 --- a/modules/juce_core/memory/juce_Atomic.h +++ b/modules/juce_core/memory/juce_Atomic.h @@ -35,13 +35,13 @@ namespace juce { -#ifndef DOXYGEN - namespace AtomicHelpers - { - template struct DiffTypeHelper { using Type = T; }; - template struct DiffTypeHelper { using Type = std::ptrdiff_t; }; - } -#endif +/** @cond */ +namespace AtomicHelpers +{ + template struct DiffTypeHelper { using Type = T; }; + template struct DiffTypeHelper { using Type = std::ptrdiff_t; }; +} +/** @endcond */ //============================================================================== /** @@ -147,11 +147,11 @@ struct Atomic final std::atomic value; //============================================================================== - #ifndef DOXYGEN + /** @cond */ [[deprecated ("This method has been deprecated as there is no equivalent method in " "std::atomic. Use compareAndSetBool instead.")]] Type compareAndSetValue (Type, Type) noexcept; - #endif + /** @endcond */ }; } // namespace juce diff --git a/modules/juce_core/memory/juce_HeapBlock.h b/modules/juce_core/memory/juce_HeapBlock.h index f459fadc81..4a157178ed 100644 --- a/modules/juce_core/memory/juce_HeapBlock.h +++ b/modules/juce_core/memory/juce_HeapBlock.h @@ -35,7 +35,8 @@ namespace juce { -#if ! (DOXYGEN || JUCE_EXCEPTIONS_DISABLED) +#if ! JUCE_EXCEPTIONS_DISABLED +/** @cond */ namespace HeapBlockHelper { template @@ -44,6 +45,7 @@ namespace HeapBlockHelper template <> struct ThrowOnFail { static void checkPointer (void* data) { if (data == nullptr) throw std::bad_alloc(); } }; } +/** @endcond */ #endif //============================================================================== diff --git a/modules/juce_core/memory/juce_Memory.h b/modules/juce_core/memory/juce_Memory.h index 894d07ec66..42d5cb42b0 100644 --- a/modules/juce_core/memory/juce_Memory.h +++ b/modules/juce_core/memory/juce_Memory.h @@ -178,7 +178,8 @@ inline const Type* addBytesToPointer (const Type* basePointer, IntegerType bytes avoiding problems when an object is created in one module and passed across to another where it is deleted. By piggy-backing on the JUCE_LEAK_DETECTOR macro, these allocators can be injected into most juce classes. */ -#if JUCE_MSVC && (defined (JUCE_DLL) || defined (JUCE_DLL_BUILD)) && ! (JUCE_DISABLE_DLL_ALLOCATORS || DOXYGEN) +#if JUCE_MSVC && (defined (JUCE_DLL) || defined (JUCE_DLL_BUILD)) && ! JUCE_DISABLE_DLL_ALLOCATORS + /** @cond */ extern JUCE_API void* juceDLL_malloc (size_t); extern JUCE_API void juceDLL_free (void*); @@ -187,6 +188,7 @@ inline const Type* addBytesToPointer (const Type* basePointer, IntegerType bytes static void* operator new (size_t, void* p) { return p; } \ static void operator delete (void* p) { juce::juceDLL_free (p); } \ static void operator delete (void*, void*) {} + /** @endcond */ #endif //============================================================================== diff --git a/modules/juce_core/memory/juce_MemoryBlock.h b/modules/juce_core/memory/juce_MemoryBlock.h index 29eaf014d8..2ea4ebf53f 100644 --- a/modules/juce_core/memory/juce_MemoryBlock.h +++ b/modules/juce_core/memory/juce_MemoryBlock.h @@ -281,14 +281,14 @@ public: bool fromBase64Encoding (StringRef encodedString); //============================================================================== - #ifndef DOXYGEN + /** @cond */ [[deprecated ("Use the replaceAll method instead, which will also replace the data when numBytes == 0.")]] void replaceWith (const void* srcData, size_t numBytes) { if (numBytes > 0) replaceAll (srcData, numBytes); } - #endif + /** @endcond */ private: //============================================================================== diff --git a/modules/juce_core/memory/juce_ReferenceCountedObject.h b/modules/juce_core/memory/juce_ReferenceCountedObject.h index 079ae9a3ab..1c31662577 100644 --- a/modules/juce_core/memory/juce_ReferenceCountedObject.h +++ b/modules/juce_core/memory/juce_ReferenceCountedObject.h @@ -440,10 +440,10 @@ public: operator ReferencedType*() const noexcept { return referencedObject; } #endif - #ifndef DOXYGEN + /** @cond */ [[deprecated ("Use the get method instead.")]] ReferencedType* getObject() const { return get(); } - #endif + /** @endcond */ private: //============================================================================== diff --git a/modules/juce_core/memory/juce_ScopedPointer.h b/modules/juce_core/memory/juce_ScopedPointer.h index 107190bff1..31c9c1d4bf 100644 --- a/modules/juce_core/memory/juce_ScopedPointer.h +++ b/modules/juce_core/memory/juce_ScopedPointer.h @@ -32,8 +32,7 @@ ============================================================================== */ -#ifndef DOXYGEN - +/** @cond */ namespace juce { @@ -228,5 +227,4 @@ void deleteAndZero (ScopedPointer&) { static_assert (sizeof (Type) == 123 JUCE_END_IGNORE_DEPRECATION_WARNINGS } // namespace juce - -#endif +/** @endcond */ diff --git a/modules/juce_core/memory/juce_SharedResourcePointer.h b/modules/juce_core/memory/juce_SharedResourcePointer.h index 78b514bae2..d80fa29bdc 100644 --- a/modules/juce_core/memory/juce_SharedResourcePointer.h +++ b/modules/juce_core/memory/juce_SharedResourcePointer.h @@ -128,10 +128,10 @@ public: /** Returns a reference to the shared object. */ SharedObjectType& operator*() const noexcept { return *sharedObject; } - #ifndef DOXYGEN + /** @cond */ [[deprecated ("If you are relying on this function please inform the JUCE team as we are planing on removing this in a subsequent release")]] int getReferenceCount() const noexcept { return (int) sharedObject.use_count(); } - #endif + /** @endcond */ /** Returns the SharedResourcePointer if one already exists, or a null optional otherwise. */ static std::optional getSharedObjectWithoutCreating() diff --git a/modules/juce_core/memory/juce_Singleton.h b/modules/juce_core/memory/juce_Singleton.h index 5c472c5137..70db5c4876 100644 --- a/modules/juce_core/memory/juce_Singleton.h +++ b/modules/juce_core/memory/juce_Singleton.h @@ -135,7 +135,7 @@ struct SingletonHolder : private MutexType // (inherited so we can use the empt std::atomic instance { nullptr }; }; -#ifndef DOXYGEN +/** @cond */ #define JUCE_PRIVATE_DECLARE_SINGLETON(Classname, mutex, doNotRecreate, inlineToken, getter) \ static inlineToken juce::SingletonHolder singletonHolder; \ friend juce::SingletonHolder; \ @@ -143,7 +143,7 @@ struct SingletonHolder : private MutexType // (inherited so we can use the empt static Classname* JUCE_CALLTYPE getInstanceWithoutCreating() noexcept { return singletonHolder.instance; } \ static void JUCE_CALLTYPE deleteInstance() noexcept { singletonHolder.deleteInstance(); } \ void clearSingletonInstance() noexcept { singletonHolder.clear (this); } -#endif +/** @endcond */ //============================================================================== /** @@ -281,14 +281,14 @@ struct SingletonHolder : private MutexType // (inherited so we can use the empt JUCE_PRIVATE_DECLARE_SINGLETON (Classname, juce::DummyCriticalSection, false, inline, getWithoutChecking) //============================================================================== -#ifndef DOXYGEN - // These are ancient macros, and have now been updated with new names to match the JUCE style guide, - // so please update your code to use the newer versions! - #define juce_DeclareSingleton(Classname, doNotRecreate) JUCE_DECLARE_SINGLETON(Classname, doNotRecreate) - #define juce_DeclareSingleton_SingleThreaded(Classname, doNotRecreate) JUCE_DECLARE_SINGLETON_SINGLETHREADED(Classname, doNotRecreate) - #define juce_DeclareSingleton_SingleThreaded_Minimal(Classname) JUCE_DECLARE_SINGLETON_SINGLETHREADED_MINIMAL(Classname) - #define juce_ImplementSingleton(Classname) JUCE_IMPLEMENT_SINGLETON(Classname) - #define juce_ImplementSingleton_SingleThreaded(Classname) JUCE_IMPLEMENT_SINGLETON(Classname) -#endif +/** @cond */ +// These are ancient macros, and have now been updated with new names to match the JUCE style guide, +// so please update your code to use the newer versions! +#define juce_DeclareSingleton(Classname, doNotRecreate) JUCE_DECLARE_SINGLETON(Classname, doNotRecreate) +#define juce_DeclareSingleton_SingleThreaded(Classname, doNotRecreate) JUCE_DECLARE_SINGLETON_SINGLETHREADED(Classname, doNotRecreate) +#define juce_DeclareSingleton_SingleThreaded_Minimal(Classname) JUCE_DECLARE_SINGLETON_SINGLETHREADED_MINIMAL(Classname) +#define juce_ImplementSingleton(Classname) JUCE_IMPLEMENT_SINGLETON(Classname) +#define juce_ImplementSingleton_SingleThreaded(Classname) JUCE_IMPLEMENT_SINGLETON(Classname) +/** @endcond */ } // namespace juce diff --git a/modules/juce_core/misc/juce_Functional.h b/modules/juce_core/misc/juce_Functional.h index 4accad5368..b33a61e4b4 100644 --- a/modules/juce_core/misc/juce_Functional.h +++ b/modules/juce_core/misc/juce_Functional.h @@ -35,7 +35,7 @@ namespace juce { -#ifndef DOXYGEN +/** @cond */ namespace detail { template @@ -47,7 +47,7 @@ namespace detail template constexpr auto equalityComparableToNullptr() != nullptr)>> = true; } // namespace detail -#endif +/** @endcond */ //============================================================================== /** Some helper methods for checking a callable object before invoking with @@ -98,7 +98,7 @@ template @@ -107,7 +107,7 @@ static constexpr auto toFnPtr (Functor functor, Return (Functor::*) (Args...) co return static_cast (functor); } } // namespace detail -#endif +/** @endcond */ /** Converts a captureless lambda to its equivalent function pointer type. */ template diff --git a/modules/juce_core/misc/juce_Uuid.h b/modules/juce_core/misc/juce_Uuid.h index 37d1e51588..98e61cc651 100644 --- a/modules/juce_core/misc/juce_Uuid.h +++ b/modules/juce_core/misc/juce_Uuid.h @@ -151,7 +151,7 @@ private: } // namespace juce -#ifndef DOXYGEN +/** @cond */ namespace std { template <> struct hash @@ -159,4 +159,4 @@ namespace std size_t operator() (const juce::Uuid& u) const noexcept { return (size_t) u.hash(); } }; } -#endif +/** @endcond */ diff --git a/modules/juce_core/misc/juce_WindowsRegistry.h b/modules/juce_core/misc/juce_WindowsRegistry.h index 59f5b02607..d950f055b4 100644 --- a/modules/juce_core/misc/juce_WindowsRegistry.h +++ b/modules/juce_core/misc/juce_WindowsRegistry.h @@ -135,12 +135,12 @@ public: bool registerForCurrentUserOnly, WoW64Mode mode = WoW64_Default); - #ifndef DOXYGEN + /** @cond */ // DEPRECATED: use the other methods with a WoW64Mode parameter of WoW64_64bit instead. [[deprecated]] static String getValueWow64 (const String&, const String& defaultValue = String()); [[deprecated]] static bool valueExistsWow64 (const String&); [[deprecated]] static bool keyExistsWow64 (const String&); - #endif + /** @endcond */ private: WindowsRegistry() = delete; diff --git a/modules/juce_core/native/juce_JNIHelpers_android.h b/modules/juce_core/native/juce_JNIHelpers_android.h index 3f1955f05c..fb73ae67c4 100644 --- a/modules/juce_core/native/juce_JNIHelpers_android.h +++ b/modules/juce_core/native/juce_JNIHelpers_android.h @@ -367,6 +367,7 @@ DECLARE_JNI_CLASS (AndroidContext, "android/content/Context") METHOD (startActivityForResult, "startActivityForResult", "(Landroid/content/Intent;I)V") \ METHOD (getFragmentManager, "getFragmentManager", "()Landroid/app/FragmentManager;") \ METHOD (setContentView, "setContentView", "(Landroid/view/View;)V") \ + METHOD (addContentView, "addContentView", "(Landroid/view/View;Landroid/view/ViewGroup$LayoutParams;)V") \ METHOD (getActionBar, "getActionBar", "()Landroid/app/ActionBar;") \ METHOD (getWindow, "getWindow", "()Landroid/view/Window;") \ METHOD (isInMultiWindowMode, "isInMultiWindowMode", "()Z") \ @@ -690,13 +691,22 @@ DECLARE_JNI_CLASS (AndroidViewGroup, "android/view/ViewGroup") METHOD (getDecorView, "getDecorView", "()Landroid/view/View;") \ METHOD (getAttributes, "getAttributes", "()Landroid/view/WindowManager$LayoutParams;") \ METHOD (setFlags, "setFlags", "(II)V") \ - METHOD (clearFlags, "clearFlags", "(I)V") + METHOD (clearFlags, "clearFlags", "(I)V") \ + METHOD (setStatusBarColor, "setStatusBarColor", "(I)V") \ + METHOD (setNavigationBarColor, "setNavigationBarColor", "(I)V") \ DECLARE_JNI_CLASS (AndroidWindow, "android/view/Window") #undef JNI_CLASS_MEMBERS #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \ - METHOD (getDefaultDisplay, "getDefaultDisplay", "()Landroid/view/Display;") + METHOD (setNavigationBarContrastEnforced, "setNavigationBarContrastEnforced", "(Z)V") \ + +DECLARE_JNI_CLASS_WITH_MIN_SDK (AndroidWindow29, "android/view/Window", 29) +#undef JNI_CLASS_MEMBERS + +#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \ + METHOD (getDefaultDisplay, "getDefaultDisplay", "()Landroid/view/Display;") \ + METHOD (removeViewImmediate, "removeViewImmediate", "(Landroid/view/View;)V") \ DECLARE_JNI_CLASS (AndroidWindowManager, "android/view/WindowManager") #undef JNI_CLASS_MEMBERS diff --git a/modules/juce_core/native/juce_Network_mac.mm b/modules/juce_core/native/juce_Network_mac.mm index dc9f157099..932751c099 100644 --- a/modules/juce_core/native/juce_Network_mac.mm +++ b/modules/juce_core/native/juce_Network_mac.mm @@ -140,15 +140,18 @@ public: ~SharedSession() { std::unique_lock lock { mutex }; - [session.get() finishTasksAndInvalidate]; - condvar.wait (lock, [&] { return state == State::stopped; }); + + if (session != nullptr) + [session.get() finishTasksAndInvalidate]; + + condvar.wait (lock, [&] { return session == nullptr; }); } NSUniquePtr addTask (NSURLRequest* request, SessionListener* listener) { std::unique_lock lock { mutex }; - if (state != State::running) + if (session == nullptr) return nullptr; NSUniquePtr task { [[session.get() dataTaskWithRequest: request] retain] }; @@ -170,28 +173,28 @@ private: DBG (nsStringToJuce ([error description])); #endif - const auto toNotify = [&] + const auto toNotify = std::invoke ([&] { const std::scoped_lock lock { mutex }; - state = State::stopRequested; + session.reset(); // Take a copy of listenerForTask so that we don't need to hold the lock while // iterating through the remaining listeners. - return listenerForTask; - }(); + return std::exchange (listenerForTask, {}); + }); for (const auto& pair : toNotify) pair.second->didComplete (error); - const std::scoped_lock lock { mutex }; - listenerForTask.clear(); - state = State::stopped; - - // Important: we keep the lock held while calling condvar.notify_one(). + // Important: we keep the lock held while calling condvar.notify_all(). // If we don't, then it's possible that when the destructor runs, it will wake // before we notify the condvar on this thread, allowing the destructor to continue // and destroying the condition variable. When didBecomeInvalid resumes, the condition // variable will have been destroyed. - condvar.notify_one(); + // Use notify_all() rather than notify_one() so that all threads waiting + // in removeTask() can make progress in the case that the session is + // invalidated unexpectedly. + const std::scoped_lock lock { mutex }; + condvar.notify_all(); } void didComplete (NSURLSessionTask* task, [[maybe_unused]] NSError* error) @@ -213,7 +216,7 @@ private: listenerForTask.erase ([task taskIdentifier]); } - condvar.notify_one(); + condvar.notify_all(); } void didReceiveResponse (NSURLSessionTask* task, @@ -324,13 +327,6 @@ private: } }; - enum class State - { - running, - stopRequested, - stopped, - }; - std::mutex mutex; std::condition_variable condvar; @@ -343,8 +339,6 @@ private: }; std::map listenerForTask; - - State state = State::running; }; class TaskToken diff --git a/modules/juce_core/native/juce_ObjCHelpers_mac.h b/modules/juce_core/native/juce_ObjCHelpers_mac.h index d52fae0607..aa4e45d218 100644 --- a/modules/juce_core/native/juce_ObjCHelpers_mac.h +++ b/modules/juce_core/native/juce_ObjCHelpers_mac.h @@ -392,7 +392,7 @@ private: }; //============================================================================== -#ifndef DOXYGEN +/** @cond */ template struct ObjCLifetimeManagedClass : public ObjCClass { @@ -434,7 +434,7 @@ struct ObjCLifetimeManagedClass : public ObjCClass template ObjCLifetimeManagedClass ObjCLifetimeManagedClass::objCLifetimeManagedClass; -#endif +/** @endcond */ // this will return an NSObject which takes ownership of the JUCE instance passed-in // This is useful to tie the life-time of a juce instance to the life-time of an NSObject diff --git a/modules/juce_core/network/juce_URL.h b/modules/juce_core/network/juce_URL.h index 421a054a28..746d393adf 100644 --- a/modules/juce_core/network/juce_URL.h +++ b/modules/juce_core/network/juce_URL.h @@ -684,7 +684,7 @@ public: static URL createWithoutParsing (const String& url); //============================================================================== - #ifndef DOXYGEN + /** @cond */ using OpenStreamProgressCallback = bool (void* context, int bytesSent, int totalBytes); /** This method has been deprecated. @@ -701,7 +701,7 @@ public: int* statusCode = nullptr, int numRedirectsToFollow = 5, String httpRequestCmd = {}) const; - #endif + /** @endcond */ private: //============================================================================== diff --git a/modules/juce_core/serialisation/juce_Serialisation.h b/modules/juce_core/serialisation/juce_Serialisation.h index be6912260f..e11e7409bf 100644 --- a/modules/juce_core/serialisation/juce_Serialisation.h +++ b/modules/juce_core/serialisation/juce_Serialisation.h @@ -148,8 +148,7 @@ template constexpr auto serialisationSize (const T& t) -> std::enab The following are specialisations of SerialisationTraits for commonly-used types. */ -#ifndef DOXYGEN - +/** @cond */ template struct SerialisationTraits> { @@ -583,6 +582,6 @@ namespace detail } } // namespace detail -#endif +/** @endcond */ } // namespace juce diff --git a/modules/juce_core/system/juce_CompilerSupport.h b/modules/juce_core/system/juce_CompilerSupport.h index 6a8acdf0b3..6a08fab27b 100644 --- a/modules/juce_core/system/juce_CompilerSupport.h +++ b/modules/juce_core/system/juce_CompilerSupport.h @@ -113,14 +113,14 @@ #endif //============================================================================== -#ifndef DOXYGEN - // These are old flags that are now supported on all compatible build targets - #define JUCE_CXX14_IS_AVAILABLE 1 - #define JUCE_COMPILER_SUPPORTS_OVERRIDE_AND_FINAL 1 - #define JUCE_COMPILER_SUPPORTS_VARIADIC_TEMPLATES 1 - #define JUCE_COMPILER_SUPPORTS_INITIALIZER_LISTS 1 - #define JUCE_COMPILER_SUPPORTS_NOEXCEPT 1 - #define JUCE_DELETED_FUNCTION = delete - #define JUCE_CONSTEXPR constexpr - #define JUCE_NODISCARD [[nodiscard]] -#endif +// These are old flags that are now supported on all compatible build targets +/** @cond */ +#define JUCE_CXX14_IS_AVAILABLE 1 +#define JUCE_COMPILER_SUPPORTS_OVERRIDE_AND_FINAL 1 +#define JUCE_COMPILER_SUPPORTS_VARIADIC_TEMPLATES 1 +#define JUCE_COMPILER_SUPPORTS_INITIALIZER_LISTS 1 +#define JUCE_COMPILER_SUPPORTS_NOEXCEPT 1 +#define JUCE_DELETED_FUNCTION = delete +#define JUCE_CONSTEXPR constexpr +#define JUCE_NODISCARD [[nodiscard]] +/** @endcond */ diff --git a/modules/juce_core/system/juce_CompilerWarnings.h b/modules/juce_core/system/juce_CompilerWarnings.h index 1f49054797..8d758a34c4 100644 --- a/modules/juce_core/system/juce_CompilerWarnings.h +++ b/modules/juce_core/system/juce_CompilerWarnings.h @@ -36,6 +36,7 @@ #include "juce_TargetPlatform.h" +/** @cond */ /** Return the Nth argument. By passing a variadic pack followed by N other parameters, we can select one of those N parameter based on the length of the parameter pack. @@ -160,6 +161,7 @@ /** Quote the argument, turning it into a string. */ #define JUCE_TO_STRING(x) #x +/** @endcond */ #if JUCE_CLANG || JUCE_GCC #define JUCE_IGNORE_GCC_IMPL_(compiler, warning) #define JUCE_IGNORE_GCC_IMPL_0(compiler, warning) diff --git a/modules/juce_core/system/juce_PlatformDefs.h b/modules/juce_core/system/juce_PlatformDefs.h index 3312736598..47cdf01046 100644 --- a/modules/juce_core/system/juce_PlatformDefs.h +++ b/modules/juce_core/system/juce_PlatformDefs.h @@ -129,12 +129,14 @@ namespace juce #endif //============================================================================== -#if JUCE_MSVC && ! defined (DOXYGEN) +#if JUCE_MSVC + /** @cond */ #define JUCE_BLOCK_WITH_FORCED_SEMICOLON(x) \ __pragma(warning(push)) \ __pragma(warning(disable:4127)) \ do { x } while (false) \ __pragma(warning(pop)) + /** @endcond */ #else /** This is the good old C++ trick for creating a macro that forces the user to put a semicolon after it when they use it. @@ -160,6 +162,7 @@ namespace juce /** This will always cause an assertion failure. It is only compiled in a debug build, (unless JUCE_LOG_ASSERTIONS is enabled for your build). @see jassert + @hiderefby */ #define jassertfalse JUCE_BLOCK_WITH_FORCED_SEMICOLON (JUCE_LOG_CURRENT_ASSERTION; if (juce::juce_isRunningUnderDebugger()) JUCE_BREAK_IN_DEBUGGER; JUCE_ANALYZER_NORETURN) @@ -170,6 +173,7 @@ namespace juce careful that the expression you pass to it doesn't perform any actions that are vital for the correct behaviour of your program! @see jassertfalse + @hiderefby */ #define jassert(expression) JUCE_BLOCK_WITH_FORCED_SEMICOLON (if (! (expression)) jassertfalse;) @@ -202,10 +206,10 @@ namespace juce #define JUCE_ASSERTIONS_ENABLED_OR_LOGGED JUCE_ASSERTIONS_ENABLED || JUCE_LOG_ASSERTIONS //============================================================================== -#ifndef DOXYGEN - #define JUCE_JOIN_MACRO_HELPER(a, b) a ## b - #define JUCE_STRINGIFY_MACRO_HELPER(a) #a -#endif +/** @cond */ +#define JUCE_JOIN_MACRO_HELPER(a, b) a ## b +#define JUCE_STRINGIFY_MACRO_HELPER(a) #a +/** @endcond */ /** A good old-fashioned C macro concatenation helper. This combines two items (which may themselves be macros) into a single string, @@ -269,8 +273,10 @@ namespace juce static void operator delete (void*) = delete; //============================================================================== -#if JUCE_MSVC && ! defined (DOXYGEN) +#if JUCE_MSVC + /** @cond */ #define JUCE_COMPILER_WARNING(msg) __pragma (message (__FILE__ "(" JUCE_STRINGIFY (__LINE__) ") : Warning: " msg)) + /** @endcond */ #else /** This macro allows you to emit a custom compiler warning message. @@ -312,8 +318,10 @@ namespace juce #endif //============================================================================== -#if JUCE_ANDROID && ! defined (DOXYGEN) +#if JUCE_ANDROID + /** @cond */ #define JUCE_MODAL_LOOPS_PERMITTED 0 + /** @endcond */ #elif ! defined (JUCE_MODAL_LOOPS_PERMITTED) /** Some operating environments don't provide a modal loop mechanism, so this flag can be used to disable any functions that try to run a modal loop. */ @@ -321,11 +329,13 @@ namespace juce #endif //============================================================================== +/** @cond */ #if JUCE_GCC || JUCE_CLANG #define JUCE_PACKED __attribute__ ((packed)) -#elif ! defined (DOXYGEN) +#else #define JUCE_PACKED #endif +/** @endcond */ //============================================================================== #if JUCE_GCC || DOXYGEN diff --git a/modules/juce_core/system/juce_StandardHeader.h b/modules/juce_core/system/juce_StandardHeader.h index 9cd78c0005..a3dc2228be 100644 --- a/modules/juce_core/system/juce_StandardHeader.h +++ b/modules/juce_core/system/juce_StandardHeader.h @@ -53,10 +53,10 @@ */ #define JUCE_VERSION ((JUCE_MAJOR_VERSION << 16) + (JUCE_MINOR_VERSION << 8) + JUCE_BUILDNUMBER) -#if ! DOXYGEN +/** @cond */ #define JUCE_VERSION_ID \ [[maybe_unused]] volatile auto juceVersionId = "juce_version_" JUCE_STRINGIFY(JUCE_MAJOR_VERSION) "_" JUCE_STRINGIFY(JUCE_MINOR_VERSION) "_" JUCE_STRINGIFY(JUCE_BUILDNUMBER); -#endif +/** @endcond */ //============================================================================== #include @@ -173,6 +173,6 @@ JUCE_END_IGNORE_WARNINGS_MSVC /** This macro is added to all JUCE public function declarations. */ #define JUCE_PUBLIC_FUNCTION JUCE_API JUCE_CALLTYPE -#ifndef DOXYGEN - #define JUCE_NAMESPACE juce // This old macro is deprecated: you should just use the juce namespace directly. -#endif +/** @cond */ +#define JUCE_NAMESPACE juce // This old macro is deprecated: you should just use the juce namespace directly. +/** @endcond */ diff --git a/modules/juce_core/system/juce_SystemStats.h b/modules/juce_core/system/juce_SystemStats.h index 31d1aa410f..ac7f2ca9b0 100644 --- a/modules/juce_core/system/juce_SystemStats.h +++ b/modules/juce_core/system/juce_SystemStats.h @@ -294,10 +294,10 @@ public: #endif //============================================================================== - #ifndef DOXYGEN + /** @cond */ [[deprecated ("This method was spelt wrong! Please change your code to use getCpuSpeedInMegahertz instead.")]] static int getCpuSpeedInMegaherz() { return getCpuSpeedInMegahertz(); } - #endif + /** @endcond */ private: SystemStats() = delete; // uses only static methods diff --git a/modules/juce_core/text/juce_CharPointer_UTF16.h b/modules/juce_core/text/juce_CharPointer_UTF16.h index 7a0f82243d..dd5c49d39f 100644 --- a/modules/juce_core/text/juce_CharPointer_UTF16.h +++ b/modules/juce_core/text/juce_CharPointer_UTF16.h @@ -350,7 +350,8 @@ public: return CharacterFunctions::compareIgnoreCaseUpTo (*this, other, maxChars); } - #if JUCE_MSVC && ! defined (DOXYGEN) + #if JUCE_MSVC + /** @cond */ int compareIgnoreCase (CharPointer_UTF16 other) const noexcept { return _wcsicmp (data, other.data); @@ -366,6 +367,7 @@ public: const CharType* const t = wcsstr (data, stringToFind.getAddress()); return t == nullptr ? -1 : (int) (t - data); } + /** @endcond */ #endif /** Returns the character index of a substring, or -1 if it isn't found. */ diff --git a/modules/juce_core/text/juce_CharacterFunctions.h b/modules/juce_core/text/juce_CharacterFunctions.h index 4487b09b09..7a1edcd456 100644 --- a/modules/juce_core/text/juce_CharacterFunctions.h +++ b/modules/juce_core/text/juce_CharacterFunctions.h @@ -36,10 +36,12 @@ namespace juce { //============================================================================== -#if JUCE_WINDOWS && ! defined (DOXYGEN) +#if JUCE_WINDOWS + /** @cond */ #define JUCE_NATIVE_WCHAR_IS_UTF8 0 #define JUCE_NATIVE_WCHAR_IS_UTF16 1 #define JUCE_NATIVE_WCHAR_IS_UTF32 0 + /** @endcond */ #else /** This macro will be set to 1 if the compiler's native wchar_t is an 8-bit type. */ #define JUCE_NATIVE_WCHAR_IS_UTF8 0 @@ -56,10 +58,10 @@ namespace juce using juce_wchar = uint32; #endif -#ifndef DOXYGEN - /** This macro is deprecated, but preserved for compatibility with old code. */ - #define JUCE_T(stringLiteral) (L##stringLiteral) -#endif +// This macro is deprecated, but preserved for compatibility with old code. +/** @cond */ +#define JUCE_T(stringLiteral) (L##stringLiteral) +/** @endcond */ #if JUCE_DEFINE_T_MACRO /** The 'T' macro is an alternative for using the "L" prefix in front of a string literal. @@ -72,8 +74,7 @@ namespace juce #define T(stringLiteral) JUCE_T(stringLiteral) #endif -#ifndef DOXYGEN - +/** @cond */ //============================================================================== // GNU libstdc++ does not have std::make_unsigned namespace internal @@ -86,8 +87,7 @@ namespace internal template <> struct make_unsigned { using type = unsigned long; }; template <> struct make_unsigned { using type = unsigned long long; }; } - -#endif +/** @endcond */ //============================================================================== /** diff --git a/modules/juce_core/text/juce_NewLine.h b/modules/juce_core/text/juce_NewLine.h index 2cc97d49ca..de7af27d5d 100644 --- a/modules/juce_core/text/juce_NewLine.h +++ b/modules/juce_core/text/juce_NewLine.h @@ -85,10 +85,12 @@ extern NewLine newLine; @endcode */ inline String& operator<< (String& string1, const NewLine&) { return string1 += NewLine::getDefault(); } -inline String& operator+= (String& s1, const NewLine&) { return s1 += NewLine::getDefault(); } +inline String& operator+= (String& s, const NewLine&) { return s += NewLine::getDefault(); } inline String operator+ (const NewLine&, const NewLine&) { return String (NewLine::getDefault()) + NewLine::getDefault(); } -inline String operator+ (String s1, const NewLine&) { return s1 += NewLine::getDefault(); } -inline String operator+ (const NewLine&, const char* s2) { return String (NewLine::getDefault()) + s2; } +inline String operator+ (String s, const NewLine&) { return s += NewLine::getDefault(); } +inline String operator+ (const NewLine&, String s) { return NewLine::getDefault() + s; } +inline String operator+ (const NewLine&, const char* s) { return String (NewLine::getDefault()) + s; } +inline String operator+ (const char* s, const NewLine&) { return s + String (NewLine::getDefault()); } } // namespace juce diff --git a/modules/juce_core/text/juce_String.h b/modules/juce_core/text/juce_String.h index 761e3de9ef..25afe617fc 100644 --- a/modules/juce_core/text/juce_String.h +++ b/modules/juce_core/text/juce_String.h @@ -32,7 +32,8 @@ ============================================================================== */ -#if ! defined (DOXYGEN) && (JUCE_MAC || JUCE_IOS) +#if JUCE_MAC || JUCE_IOS + /** @cond */ // Annoyingly we can only forward-declare a typedef by forward-declaring the // aliased type #if __has_attribute(objc_bridge) @@ -44,6 +45,7 @@ typedef const struct JUCE_CF_BRIDGED_TYPE(NSString) __CFString * CFStringRef; #undef JUCE_CF_BRIDGED_TYPE + /** @endcond */ #endif namespace juce @@ -1051,11 +1053,11 @@ public: */ String (double doubleValue, int numberOfDecimalPlaces, bool useScientificNotation = false); - #ifndef DOXYGEN + /** @cond */ // Automatically creating a String from a bool opens up lots of nasty type conversion edge cases. // If you want a String representation of a bool you can cast the bool to an int first. explicit String (bool) = delete; - #endif + /** @endcond */ /** Reads the value of the string as a decimal number (up to 32 bits in size). @@ -1360,12 +1362,14 @@ public: int getReferenceCount() const noexcept; //============================================================================== - #if JUCE_ALLOW_STATIC_NULL_VARIABLES && ! defined (DOXYGEN) + #if JUCE_ALLOW_STATIC_NULL_VARIABLES + /** @cond */ [[deprecated ("This was a static empty string object, but is now deprecated as it's too easy to accidentally " "use it indirectly during a static constructor, leading to hard-to-find order-of-initialisation " "problems. If you need an empty String object, just use String() or {}. For returning an empty " "String from a function by reference, use a function-local static String object and return that.")]] static const String empty; + /** @endcond */ #endif private: @@ -1470,11 +1474,11 @@ JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, float number); /** Appends a decimal number to the end of a string. */ JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, double number); -#ifndef DOXYGEN +/** @cond */ // Automatically creating a String from a bool opens up lots of nasty type conversion edge cases. // If you want a String representation of a bool you can cast the bool to an int first. String& JUCE_CALLTYPE operator<< (String&, bool) = delete; -#endif +/** @endcond */ //============================================================================== /** Case-sensitive comparison of two strings. */ @@ -1530,7 +1534,7 @@ JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, StringRef } // namespace juce -#ifndef DOXYGEN +/** @cond */ namespace std { template <> struct hash @@ -1538,4 +1542,4 @@ namespace std size_t operator() (const juce::String& s) const noexcept { return s.hash(); } }; } -#endif +/** @endcond */ diff --git a/modules/juce_core/text/juce_StringRef.h b/modules/juce_core/text/juce_StringRef.h index 16ce3f724d..a254d845a3 100644 --- a/modules/juce_core/text/juce_StringRef.h +++ b/modules/juce_core/text/juce_StringRef.h @@ -141,10 +141,12 @@ public: /** The text that is referenced. */ String::CharPointerType text; - #if JUCE_STRING_UTF_TYPE != 8 && ! defined (DOXYGEN) + #if JUCE_STRING_UTF_TYPE != 8 + /** @cond */ // Sorry, non-UTF8 people, you're unable to take advantage of StringRef, because // you've chosen a character encoding that doesn't match C++ string literals. String stringCopy; + /** @endcond */ #endif }; diff --git a/modules/juce_core/threads/juce_Thread.h b/modules/juce_core/threads/juce_Thread.h index a61d7b22e3..71baab4d82 100644 --- a/modules/juce_core/threads/juce_Thread.h +++ b/modules/juce_core/threads/juce_Thread.h @@ -608,9 +608,9 @@ private: std::atomic priority; #endif - #ifndef DOXYGEN + /** @cond */ friend void JUCE_API juce_threadEntryPoint (void*); - #endif + /** @endcond */ bool startThreadInternal (Priority); bool createNativeThread (Priority); diff --git a/modules/juce_core/threads/juce_TimeSliceThread.h b/modules/juce_core/threads/juce_TimeSliceThread.h index 0130a92332..c39a2aa705 100644 --- a/modules/juce_core/threads/juce_TimeSliceThread.h +++ b/modules/juce_core/threads/juce_TimeSliceThread.h @@ -147,9 +147,9 @@ public: bool contains (const TimeSliceClient*) const; //============================================================================== - #ifndef DOXYGEN + /** @cond */ void run() override; - #endif + /** @endcond */ //============================================================================== private: diff --git a/modules/juce_core/time/juce_Time.cpp b/modules/juce_core/time/juce_Time.cpp index 3df84e081c..db1f2420b9 100644 --- a/modules/juce_core/time/juce_Time.cpp +++ b/modules/juce_core/time/juce_Time.cpp @@ -59,36 +59,6 @@ namespace TimeHelpers #endif } - static std::tm millisToUTC (int64 millis) noexcept - { - #if JUCE_WINDOWS - std::tm result; - millis /= 1000; - - if (_gmtime64_s (&result, &millis) != 0) - zerostruct (result); - - return result; - - #else - std::tm result; - auto now = (time_t) (millis / 1000); - - if (gmtime_r (&now, &result) == nullptr) - zerostruct (result); - - return result; - #endif - } - - static int getUTCOffsetSeconds (const int64 millis) noexcept - { - auto utc = millisToUTC (millis); - utc.tm_isdst = -1; // Treat this UTC time as local to find the offset - - return (int) ((millis / 1000) - (int64) mktime (&utc)); - } - static int extendedModulo (const int64 value, const int modulo) noexcept { return (int) (value >= 0 ? (value % modulo) @@ -181,6 +151,32 @@ namespace TimeHelpers + t.tm_sec; } + static int64 mktime_local (const std::tm& t) noexcept + { + auto t1 = t; + const auto result = mktime (&t1); + + // If any field changed in the struct passed to mktime, it indicates the + // original time was invalid or ambiguous in the local timezone. + // + // Common scenarios where this validation catches errors: + // Daylight Saving Time transitions: + // Times like 1:30 AM may not exist, mktime() may adjust them to + // 2:30 AM for example + // Invalid dates or out-of-range values: + // Feb 30, Apr 31, etc. may get normalised to valid dates + // hour=25, minute=70, etc. may get normalised to valid times + + jassert ( t.tm_year == t1.tm_year + && t.tm_mon == t1.tm_mon + && t.tm_mday == t1.tm_mday + && t.tm_hour == t1.tm_hour + && t.tm_min == t1.tm_min + && t.tm_sec == t1.tm_sec); + + return (int64) result; + } + static Atomic lastMSCounterValue { (uint32) 0 }; static String getUTCOffsetString (int utcOffsetSeconds, bool includeSemiColon) @@ -213,9 +209,9 @@ Time::Time (int year, int month, int day, t.tm_hour = hours; t.tm_min = minutes; t.tm_sec = seconds; - t.tm_isdst = -1; + t.tm_isdst = useLocalTime ? -1 : 0; - millisSinceEpoch = 1000 * (useLocalTime ? (int64) mktime (&t) + millisSinceEpoch = 1000 * (useLocalTime ? TimeHelpers::mktime_local (t) : TimeHelpers::mktime_utc (t)) + milliseconds; } @@ -383,7 +379,7 @@ String Time::getTimeZone() const { String zone[2]; - #if JUCE_WINDOWS && (JUCE_MSVC || JUCE_CLANG) + #if JUCE_WINDOWS && (JUCE_MSVC || JUCE_CLANG) _tzset(); for (int i = 0; i < 2; ++i) @@ -393,13 +389,13 @@ String Time::getTimeZone() const _get_tzname (&length, name, sizeof (name) - 1, i); zone[i] = name; } - #else + #else tzset(); auto zonePtr = (const char**) tzname; zone[0] = zonePtr[0]; zone[1] = zonePtr[1]; - #endif + #endif if (isDaylightSavingTime()) { @@ -416,7 +412,9 @@ String Time::getTimeZone() const int Time::getUTCOffsetSeconds() const noexcept { - return TimeHelpers::getUTCOffsetSeconds (millisSinceEpoch); + // Treat local time as UTC to measure the difference + const auto local = TimeHelpers::millisToLocal (millisSinceEpoch); + return (int) (TimeHelpers::mktime_utc (local) - (millisSinceEpoch / 1000)); } String Time::getUTCOffsetString (bool includeSemiColon) const @@ -640,6 +638,13 @@ public: expect (t.getUTCOffsetString (true) == "Z" || t.getUTCOffsetString (true).length() == 6); expect (t.getUTCOffsetString (false) == "Z" || t.getUTCOffsetString (false).length() == 5); + if (Time{}.getTimeZone() == "GMT") + { + // Tests the point of transition to BST + expect (Time (2025, 2, 30, 0, 59, 59, 999, false).toISO8601 (true) == "2025-03-30T00:59:59.999Z"); + expect (Time (2025, 2, 30, 1, 00, 00, 000, false).toISO8601 (true) == "2025-03-30T02:00:00.000+01:00"); + } + expect (TimeHelpers::getUTCOffsetString (-(3 * 60 + 15) * 60, true) == "-03:15"); expect (TimeHelpers::getUTCOffsetString (-(3 * 60 + 30) * 60, true) == "-03:30"); expect (TimeHelpers::getUTCOffsetString (-(3 * 60 + 45) * 60, true) == "-03:45"); @@ -648,6 +653,7 @@ public: expect (Time::fromISO8601 (t.toISO8601 (true)) == t); expect (Time::fromISO8601 (t.toISO8601 (false)) == t); + expect (Time::fromISO8601 (Time (0).toISO8601 (true)) == Time (0)); expect (Time::fromISO8601 ("2016-02-16") == Time (2016, 1, 16, 0, 0, 0, 0, false)); expect (Time::fromISO8601 ("20160216Z") == Time (2016, 1, 16, 0, 0, 0, 0, false)); diff --git a/modules/juce_core/unit_tests/juce_UnitTest.cpp b/modules/juce_core/unit_tests/juce_UnitTest.cpp index 23e7c06e5b..0e5658011a 100644 --- a/modules/juce_core/unit_tests/juce_UnitTest.cpp +++ b/modules/juce_core/unit_tests/juce_UnitTest.cpp @@ -66,6 +66,20 @@ Array UnitTest::getTestsInCategory (const String& category) return unitTests; } +Array UnitTest::getTestsWithName (const String& name) +{ + if (name.isEmpty()) + return getAllTests(); + + Array unitTests; + + for (auto* test : getAllTests()) + if (test->getName() == name) + unitTests.add (test); + + return unitTests; +} + StringArray UnitTest::getAllCategories() { StringArray categories; @@ -196,6 +210,11 @@ void UnitTestRunner::runTestsInCategory (const String& category, int64 randomSee runTests (UnitTest::getTestsInCategory (category), randomSeed); } +void UnitTestRunner::runTestsWithName (const String& name, int64 randomSeed) +{ + runTests (UnitTest::getTestsWithName (name), randomSeed); +} + void UnitTestRunner::logMessage (const String& message) { Logger::writeToLog (message); diff --git a/modules/juce_core/unit_tests/juce_UnitTest.h b/modules/juce_core/unit_tests/juce_UnitTest.h index aef0b6e739..4a4186becc 100644 --- a/modules/juce_core/unit_tests/juce_UnitTest.h +++ b/modules/juce_core/unit_tests/juce_UnitTest.h @@ -106,6 +106,9 @@ public: /** Returns the set of UnitTests in a specified category. */ static Array getTestsInCategory (const String& category); + /** Returns the set of UnitTests with a specified name. */ + static Array getTestsWithName (const String& name); + /** Returns a StringArray containing all of the categories of UnitTests that have been registered. */ static StringArray getAllCategories(); @@ -369,6 +372,14 @@ public: */ void runTestsInCategory (const String& category, int64 randomSeed = 0); + /** Runs all the UnitTest objects with a specified name. + This calls runTests() for all the objects listed in UnitTest::getTestsWithName(). + + If you want to run the tests with a predetermined seed, you can pass that into + the randomSeed argument, or pass 0 to have a randomly-generated seed chosen. + */ + void runTestsWithName (const String& name, int64 randomSeed = 0); + /** Sets a flag to indicate whether an assertion should be triggered if a test fails. This is true by default. */ diff --git a/modules/juce_core/xml/juce_XmlElement.h b/modules/juce_core/xml/juce_XmlElement.h index 1805b47cba..d0d6427bf1 100644 --- a/modules/juce_core/xml/juce_XmlElement.h +++ b/modules/juce_core/xml/juce_XmlElement.h @@ -874,7 +874,7 @@ public: return AttributeIterator { attributes.get() }; } - #ifndef DOXYGEN + /** @cond */ [[deprecated]] void macroBasedForLoop() const noexcept {} [[deprecated ("This has been deprecated in favour of the toString method.")]] @@ -897,7 +897,7 @@ public: StringRef dtdToUse, StringRef encodingType = "UTF-8", int lineWrapLength = 60) const; - #endif + /** @endcond */ private: //============================================================================== @@ -926,7 +926,7 @@ private: }; //============================================================================== -#ifndef DOXYGEN +/** @cond */ /** DEPRECATED: A handy macro to make it easy to iterate all the child elements in an XmlElement. @@ -979,6 +979,6 @@ private: #define forEachXmlChildElementWithTagName(parentXmlElement, childElementVariableName, requiredTagName) \ for (auto* (childElementVariableName) : ((parentXmlElement).macroBasedForLoop(), (parentXmlElement).getChildWithTagNameIterator ((requiredTagName)))) -#endif +/** @endcond */ } // namespace juce diff --git a/modules/juce_data_structures/values/juce_ValueTree.h b/modules/juce_data_structures/values/juce_ValueTree.h index 87d0368993..f2da0c413d 100644 --- a/modules/juce_data_structures/values/juce_ValueTree.h +++ b/modules/juce_data_structures/values/juce_ValueTree.h @@ -617,10 +617,12 @@ public: */ int getReferenceCount() const noexcept; - #if JUCE_ALLOW_STATIC_NULL_VARIABLES && ! defined (DOXYGEN) + #if JUCE_ALLOW_STATIC_NULL_VARIABLES + /** @cond */ /* An invalid ValueTree that can be used if you need to return one as an error condition, etc. */ [[deprecated ("If you need an empty ValueTree object, just use ValueTree() or {}.")]] static const ValueTree invalid; + /** @endcond */ #endif private: diff --git a/modules/juce_data_structures/values/juce_ValueTreePropertyWithDefault.h b/modules/juce_data_structures/values/juce_ValueTreePropertyWithDefault.h index 389df86a9f..035492a663 100644 --- a/modules/juce_data_structures/values/juce_ValueTreePropertyWithDefault.h +++ b/modules/juce_data_structures/values/juce_ValueTreePropertyWithDefault.h @@ -335,11 +335,11 @@ private: }; //============================================================================== -#ifndef DOXYGEN +/** @cond */ using ValueWithDefault [[deprecated ("This class has been renamed to better describe what is does. " "This declaration is here for backwards compatibility and new " "code should use the new class name.")]] = ValueTreePropertyWithDefault; -#endif +/** @endcond */ } // namespace juce diff --git a/modules/juce_dsp/containers/juce_AudioBlock.h b/modules/juce_dsp/containers/juce_AudioBlock.h index dc42aeaed3..6eea893eac 100644 --- a/modules/juce_dsp/containers/juce_AudioBlock.h +++ b/modules/juce_dsp/containers/juce_AudioBlock.h @@ -35,7 +35,7 @@ namespace juce::dsp { -#ifndef DOXYGEN +/** @cond */ namespace SampleTypeHelpers // Internal classes needed for handling sample type classes { template > @@ -56,7 +56,7 @@ namespace SampleTypeHelpers // Internal classes needed for handling sample type using Type = typename T::value_type; }; } -#endif +/** @endcond */ //============================================================================== /** diff --git a/modules/juce_dsp/containers/juce_SIMDRegister.h b/modules/juce_dsp/containers/juce_SIMDRegister.h index 03160e50b6..1eabdf25b2 100644 --- a/modules/juce_dsp/containers/juce_SIMDRegister.h +++ b/modules/juce_dsp/containers/juce_SIMDRegister.h @@ -35,11 +35,11 @@ namespace juce::dsp { -#ifndef DOXYGEN - // This class is needed internally. - template - struct CmplxSIMDOps; -#endif +/** @cond */ +// This class is needed internally. +template +struct CmplxSIMDOps; +/** @endcond */ //============================================================================== /** diff --git a/modules/juce_dsp/containers/juce_SIMDRegister_Impl.h b/modules/juce_dsp/containers/juce_SIMDRegister_Impl.h index 70195be2a0..f14608dff3 100644 --- a/modules/juce_dsp/containers/juce_SIMDRegister_Impl.h +++ b/modules/juce_dsp/containers/juce_SIMDRegister_Impl.h @@ -54,7 +54,7 @@ private: size_t idx; }; -#ifndef DOXYGEN +/** @cond */ //============================================================================== /* This class is used internally by SIMDRegister to abstract away differences in operations which are different for complex and pure floating point types. */ @@ -167,7 +167,7 @@ struct CmplxSIMDOps> return SIMDNativeOps::add (a, SIMDNativeOps::cmplxmul (b, c)); } }; -#endif +/** @endcond */ //============================================================================== namespace util diff --git a/modules/juce_dsp/frequency/juce_FFT.h b/modules/juce_dsp/frequency/juce_FFT.h index 9280c0c785..3987d6a9fd 100644 --- a/modules/juce_dsp/frequency/juce_FFT.h +++ b/modules/juce_dsp/frequency/juce_FFT.h @@ -118,11 +118,11 @@ public: int getSize() const noexcept { return size; } //============================================================================== - #ifndef DOXYGEN - /* internal */ + /** @internal */ + /** @cond */ struct Instance; template struct EngineImpl; - #endif + /** @endcond */ private: //============================================================================== diff --git a/modules/juce_dsp/juce_dsp.h b/modules/juce_dsp/juce_dsp.h index a76bc37189..aefc25ae9d 100644 --- a/modules/juce_dsp/juce_dsp.h +++ b/modules/juce_dsp/juce_dsp.h @@ -217,19 +217,19 @@ namespace util /** Use this function to prevent denormals on intel CPUs. This function will work with both primitives and simple containers. */ - #if JUCE_DSP_ENABLE_SNAP_TO_ZERO + #if JUCE_DSP_ENABLE_SNAP_TO_ZERO inline void snapToZero (float& x) noexcept { JUCE_SNAP_TO_ZERO (x); } - #ifndef DOXYGEN + /** @cond */ inline void snapToZero (double& x) noexcept { JUCE_SNAP_TO_ZERO (x); } inline void snapToZero (long double& x) noexcept { JUCE_SNAP_TO_ZERO (x); } - #endif - #else + /** @endcond */ + #else inline void snapToZero ([[maybe_unused]] float& x) noexcept {} - #ifndef DOXYGEN + /** @cond */ inline void snapToZero ([[maybe_unused]] double& x) noexcept {} inline void snapToZero ([[maybe_unused]] long double& x) noexcept {} + /** @endcond */ #endif - #endif } } diff --git a/modules/juce_dsp/native/juce_SIMDNativeOps_avx.h b/modules/juce_dsp/native/juce_SIMDNativeOps_avx.h index 9489a6a1c5..3d5f8cb302 100644 --- a/modules/juce_dsp/native/juce_SIMDNativeOps_avx.h +++ b/modules/juce_dsp/native/juce_SIMDNativeOps_avx.h @@ -32,11 +32,10 @@ ============================================================================== */ +/** @cond */ namespace juce::dsp { -#ifndef DOXYGEN - JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wignored-attributes") #ifdef _MSC_VER @@ -660,8 +659,7 @@ struct SIMDNativeOps static forcedinline __m256i JUCE_VECTOR_CALLTYPE truncate (__m256i a) noexcept { return a; } }; -#endif - JUCE_END_IGNORE_WARNINGS_GCC_LIKE } // namespace juce::dsp +/** @endcond */ diff --git a/modules/juce_dsp/native/juce_SIMDNativeOps_neon.h b/modules/juce_dsp/native/juce_SIMDNativeOps_neon.h index 26fbc4deb8..1cd9e73876 100644 --- a/modules/juce_dsp/native/juce_SIMDNativeOps_neon.h +++ b/modules/juce_dsp/native/juce_SIMDNativeOps_neon.h @@ -32,11 +32,10 @@ ============================================================================== */ +/** @cond */ namespace juce::dsp { -#ifndef DOXYGEN - JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wignored-attributes") #ifdef _MSC_VER @@ -53,7 +52,7 @@ JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wignored-attributes") #define DEFINE_NEON_SIMD_CONST(type, class_type, name) \ const type SIMDNativeOps:: name [16 / sizeof (type)] __attribute__ ((aligned (16))) -#endif +#endif // _MSC_VER template struct SIMDNativeOps; @@ -541,8 +540,8 @@ struct SIMDNativeOps static forcedinline vSIMDType truncate (vSIMDType a) noexcept { return fb::truncate (a); } }; #endif // JUCE_64BIT -#endif // #ifndef DOXYGEN JUCE_END_IGNORE_WARNINGS_GCC_LIKE } // namespace juce::dsp +/** @endcond */ diff --git a/modules/juce_dsp/native/juce_SIMDNativeOps_sse.h b/modules/juce_dsp/native/juce_SIMDNativeOps_sse.h index faa2c46666..03fc816441 100644 --- a/modules/juce_dsp/native/juce_SIMDNativeOps_sse.h +++ b/modules/juce_dsp/native/juce_SIMDNativeOps_sse.h @@ -32,11 +32,10 @@ ============================================================================== */ +/** @cond */ namespace juce::dsp { -#ifndef DOXYGEN - JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wignored-attributes") #ifdef _MSC_VER @@ -53,7 +52,7 @@ JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wignored-attributes") #define DEFINE_SSE_SIMD_CONST(type, class_type, name) \ const type SIMDNativeOps:: name [16 / sizeof (type)] __attribute__ ((aligned (16))) -#endif +#endif // _MSC_VER template struct SIMDNativeOps; @@ -730,8 +729,7 @@ struct SIMDNativeOps } }; -#endif - JUCE_END_IGNORE_WARNINGS_GCC_LIKE } // namespace juce::dsp +/** @endcond */ diff --git a/modules/juce_dsp/processors/juce_IIRFilter_Impl.h b/modules/juce_dsp/processors/juce_IIRFilter_Impl.h index f7cadf792e..3ea4547775 100644 --- a/modules/juce_dsp/processors/juce_IIRFilter_Impl.h +++ b/modules/juce_dsp/processors/juce_IIRFilter_Impl.h @@ -32,11 +32,10 @@ ============================================================================== */ +/** @cond */ namespace juce::dsp::IIR { -#ifndef DOXYGEN - template template Coefficients& Coefficients::assignImpl (const NumericType* values) @@ -244,6 +243,5 @@ void Filter::check() reset(); } -#endif - } // namespace juce::dsp::IIR +/** @endcond */ diff --git a/modules/juce_dsp/processors/juce_Oversampling.h b/modules/juce_dsp/processors/juce_Oversampling.h index ad8dc60de1..822f877985 100644 --- a/modules/juce_dsp/processors/juce_Oversampling.h +++ b/modules/juce_dsp/processors/juce_Oversampling.h @@ -198,9 +198,9 @@ public: size_t factorOversampling = 1; size_t numChannels = 1; - #ifndef DOXYGEN + /** @cond */ struct OversamplingStage; - #endif + /** @endcond */ private: //============================================================================== diff --git a/modules/juce_dsp/processors/juce_ProcessorChain.h b/modules/juce_dsp/processors/juce_ProcessorChain.h index c637a22029..86ed604668 100644 --- a/modules/juce_dsp/processors/juce_ProcessorChain.h +++ b/modules/juce_dsp/processors/juce_ProcessorChain.h @@ -35,8 +35,8 @@ namespace juce::dsp { +/** @cond */ //============================================================================== -#ifndef DOXYGEN /** The contents of this namespace are used to implement ProcessorChain and should not be used elsewhere. Their interfaces (and existence) are liable to change! */ @@ -60,7 +60,7 @@ namespace detail template inline constexpr auto useContextDirectly = ! Context::usesSeparateInputAndOutputBlocks() || Ix == 0; } -#endif +/** @endcond */ /** This variadically-templated class lets you join together any number of processor classes into a single processor which will call process() on them all in sequence. @@ -168,7 +168,7 @@ inline bool isBypassed (const ProcessorChain& chain) noexcept } // namespace juce::dsp -#ifndef DOXYGEN +/** @cond */ namespace std { @@ -185,4 +185,4 @@ struct tuple_element> : tuple_elem JUCE_END_IGNORE_WARNINGS_GCC_LIKE } // namespace std -#endif +/** @endcond */ diff --git a/modules/juce_dsp/processors/juce_StateVariableFilter.h b/modules/juce_dsp/processors/juce_StateVariableFilter.h index b360102320..e615b57c84 100644 --- a/modules/juce_dsp/processors/juce_StateVariableFilter.h +++ b/modules/juce_dsp/processors/juce_StateVariableFilter.h @@ -74,7 +74,7 @@ namespace juce::dsp::StateVariableFilter using ParametersPtr = typename Parameters::Ptr; //============================================================================== - #ifndef DOXYGEN + /** @cond */ /** Creates a filter with default parameters. */ [[deprecated ("The classes in the StateVariableFilter namespace are deprecated. you should " "use the equivalent functionality in the StateVariableTPTFilter class.")]] @@ -84,7 +84,7 @@ namespace juce::dsp::StateVariableFilter [[deprecated ("The classes in the StateVariableFilter namespace are deprecated. you should " "use the equivalent functionality in the StateVariableTPTFilter class.")]] Filter (ParametersPtr parametersToUse) : parameters (std::move (parametersToUse)) { reset(); } - #endif + /** @endcond */ /** Creates a copy of another filter. */ Filter (const Filter&) = default; diff --git a/modules/juce_events/interprocess/juce_ChildProcessManager.h b/modules/juce_events/interprocess/juce_ChildProcessManager.h index caf3994e6e..c458349877 100644 --- a/modules/juce_events/interprocess/juce_ChildProcessManager.h +++ b/modules/juce_events/interprocess/juce_ChildProcessManager.h @@ -56,9 +56,9 @@ namespace juce class JUCE_API ChildProcessManager final : private DeletedAtShutdown { public: - #ifndef DOXYGEN + /** @cond */ JUCE_DECLARE_SINGLETON_SINGLETHREADED_MINIMAL_INLINE (ChildProcessManager) - #endif + /** @endcond */ /** Creates a new ChildProcess and starts it with the provided arguments. diff --git a/modules/juce_events/messages/juce_ApplicationBase.h b/modules/juce_events/messages/juce_ApplicationBase.h index 65682f8377..3635f281c3 100644 --- a/modules/juce_events/messages/juce_ApplicationBase.h +++ b/modules/juce_events/messages/juce_ApplicationBase.h @@ -288,7 +288,7 @@ public: //============================================================================== - #ifndef DOXYGEN + /** @cond */ // The following methods are for internal use only... static int main(); static int main (int argc, const char* argv[]); @@ -305,7 +305,7 @@ public: int shutdownApp(); static void JUCE_CALLTYPE sendUnhandledException (const std::exception*, const char* sourceFile, int lineNumber); bool sendCommandLineToPreexistingInstance(); - #endif + /** @endcond */ private: //============================================================================== diff --git a/modules/juce_events/messages/juce_MessageManager.h b/modules/juce_events/messages/juce_MessageManager.h index 0c63acc209..762c98df66 100644 --- a/modules/juce_events/messages/juce_MessageManager.h +++ b/modules/juce_events/messages/juce_MessageManager.h @@ -389,11 +389,11 @@ public: }; //============================================================================== - #ifndef DOXYGEN // Internal methods - do not use! + /** @cond */ void deliverBroadcastMessage (const String&); ~MessageManager() noexcept; - #endif + /** @endcond */ private: //============================================================================== diff --git a/modules/juce_graphics/colour/juce_PixelFormats.h b/modules/juce_graphics/colour/juce_PixelFormats.h index cd5bc4d168..70ebf300da 100644 --- a/modules/juce_graphics/colour/juce_PixelFormats.h +++ b/modules/juce_graphics/colour/juce_PixelFormats.h @@ -343,9 +343,9 @@ private: Components components; }; } -#ifndef DOXYGEN - JUCE_PACKED -#endif +/** @cond */ +JUCE_PACKED +/** @endcond */ ; @@ -585,9 +585,9 @@ private: #endif } -#ifndef DOXYGEN - JUCE_PACKED -#endif +/** @cond */ +JUCE_PACKED +/** @endcond */ ; forcedinline void PixelARGB::blend (PixelRGB src) noexcept @@ -737,9 +737,9 @@ private: //============================================================================== uint8 a; } -#ifndef DOXYGEN +/** @cond */ JUCE_PACKED -#endif +/** @endcond */ ; #if JUCE_MSVC diff --git a/modules/juce_graphics/detail/juce_SimpleShapedText.cpp b/modules/juce_graphics/detail/juce_SimpleShapedText.cpp index c70bd43ba0..dd24382b3c 100644 --- a/modules/juce_graphics/detail/juce_SimpleShapedText.cpp +++ b/modules/juce_graphics/detail/juce_SimpleShapedText.cpp @@ -615,10 +615,10 @@ static RangedValues resolveFontsWithFallback (Span strin for (const auto [r, f] : fonts) { - const auto constrained = r.constrainRange ({ 0, (int64) string.size() }); + const auto intersected = r.getIntersectionWith ({ 0, (int64) string.size() }); auto rf = findSuitableFontsForText (f, - { string.data() + constrained.getStart(), - (size_t) constrained.getLength() }); + { string.data() + intersected.getStart(), + (size_t) intersected.getLength() }); for (const auto [subRange, font] : rf) { diff --git a/modules/juce_graphics/fonts/juce_FunctionPointerDestructor.h b/modules/juce_graphics/fonts/juce_FunctionPointerDestructor.h index 8855d1f974..3313f1dd0e 100644 --- a/modules/juce_graphics/fonts/juce_FunctionPointerDestructor.h +++ b/modules/juce_graphics/fonts/juce_FunctionPointerDestructor.h @@ -32,8 +32,7 @@ ============================================================================== */ -#ifndef DOXYGEN - +/** @cond */ namespace juce { @@ -49,5 +48,4 @@ struct FunctionPointerDestructor }; } // namespace juce - -#endif +/** @endcond */ diff --git a/modules/juce_graphics/fonts/juce_GlyphArrangement.cpp b/modules/juce_graphics/fonts/juce_GlyphArrangement.cpp index 768b72ee32..5e9802859b 100644 --- a/modules/juce_graphics/fonts/juce_GlyphArrangement.cpp +++ b/modules/juce_graphics/fonts/juce_GlyphArrangement.cpp @@ -188,28 +188,40 @@ void GlyphArrangement::addLineOfText (const Font& font, const String& text, floa static void addGlyphsFromShapedText (GlyphArrangement& ga, const detail::ShapedText& st, float x, float y) { st.accessTogetherWith ([&] (auto shapedGlyphs, auto positions, auto font, auto glyphRange, auto) - { - for (size_t i = 0; i < shapedGlyphs.size(); ++i) - { - const auto glyphIndex = (int64) i + glyphRange.getStart(); + { + for (auto it = shapedGlyphs.begin(); it != shapedGlyphs.end();) + { + const auto& glyph = *it; + const auto isNotPlaceholder = [] (auto& shapedGlyph) + { + return ! shapedGlyph.isPlaceholderForLigature(); + }; - auto& glyph = shapedGlyphs[i]; - auto& position = positions[i]; + const auto next = std::find_if (std::next (it), + shapedGlyphs.end(), + isNotPlaceholder); - if (glyph.isPlaceholderForLigature()) - continue; + const auto addWidth = [] (auto acc, auto& shapedGlyph) + { + return acc + shapedGlyph.advance.x; + }; - PositionedGlyph pg { font, - st.getText()[(int) st.getTextRange (glyphIndex).getStart()], - (int) glyph.glyphId, - position.getX() + x, - position.getY() + y, - glyph.advance.getX(), - glyph.isWhitespace() }; + const auto width = std::accumulate (it, next, 0.0f, addWidth); + const auto index = (size_t) std::distance (shapedGlyphs.begin(), it); + const auto position = positions[index]; + const auto glyphIndex = (int64) index + glyphRange.getStart(); - ga.addGlyph (std::move (pg)); - } - }); + ga.addGlyph ({ font, + st.getText()[(int) st.getTextRange (glyphIndex).getStart()], + (int) glyph.glyphId, + position.getX() + x, + position.getY() + y, + width, + glyph.isWhitespace() }); + + it = next; + } + }); } void GlyphArrangement::addCurtailedLineOfText (const Font& font, const String& text, diff --git a/modules/juce_graphics/fonts/juce_TypefaceFileCache.h b/modules/juce_graphics/fonts/juce_TypefaceFileCache.h index 6a1444d37c..da8996a47a 100644 --- a/modules/juce_graphics/fonts/juce_TypefaceFileCache.h +++ b/modules/juce_graphics/fonts/juce_TypefaceFileCache.h @@ -32,8 +32,7 @@ ============================================================================== */ -#ifndef DOXYGEN - +/** @cond */ namespace juce { @@ -68,5 +67,4 @@ private: }; } // namespace juce - -#endif +/** @endcond */ diff --git a/modules/juce_graphics/geometry/juce_AffineTransform.h b/modules/juce_graphics/geometry/juce_AffineTransform.h index 0e9d182355..7bdce3d408 100644 --- a/modules/juce_graphics/geometry/juce_AffineTransform.h +++ b/modules/juce_graphics/geometry/juce_AffineTransform.h @@ -278,7 +278,7 @@ public: float getDeterminant() const noexcept; //============================================================================== - #ifndef DOXYGEN + /** @cond */ /** This method has been deprecated. You can calculate the scale factor using: @@ -298,7 +298,7 @@ public: [[deprecated ("If you need an identity transform, just use AffineTransform() or {}.")]] static const AffineTransform identity; - #endif + /** @endcond */ //============================================================================== /* The transform matrix is: diff --git a/modules/juce_graphics/geometry/juce_Rectangle.h b/modules/juce_graphics/geometry/juce_Rectangle.h index 898359a282..42b8248d9f 100644 --- a/modules/juce_graphics/geometry/juce_Rectangle.h +++ b/modules/juce_graphics/geometry/juce_Rectangle.h @@ -35,7 +35,7 @@ namespace juce { -#ifndef DOXYGEN +/** @cond */ namespace detail { @@ -61,7 +61,7 @@ inline int ceilAsInt (float n) noexcept { return n < (float) std::numeric_li inline int ceilAsInt (double n) noexcept { return n < (double) std::numeric_limits::max() ? (int) std::ceil (n) : std::numeric_limits::max(); } } // namespace detail -#endif +/** @endcond */ //============================================================================== /** @@ -1013,10 +1013,10 @@ public: detail::parseAfterSpace (toks[3]) }; } - #ifndef DOXYGEN + /** @cond */ [[deprecated ("This has been renamed to transformedBy in order to match the method names used in the Point class.")]] Rectangle transformed (const AffineTransform& t) const noexcept { return transformedBy (t); } - #endif + /** @endcond */ private: template friend class Rectangle; diff --git a/modules/juce_graphics/images/juce_Image.h b/modules/juce_graphics/images/juce_Image.h index eada8c900c..89b9354c94 100644 --- a/modules/juce_graphics/images/juce_Image.h +++ b/modules/juce_graphics/images/juce_Image.h @@ -448,10 +448,12 @@ public: explicit Image (ReferenceCountedObjectPtr) noexcept; //============================================================================== - #if JUCE_ALLOW_STATIC_NULL_VARIABLES && ! defined (DOXYGEN) + #if JUCE_ALLOW_STATIC_NULL_VARIABLES + /** @cond */ /* A null Image object that can be used when you need to return an invalid image. */ [[deprecated ("If you need a default-constructed var, just use Image() or {}.")]] static const Image null; + /** @endcond */ #endif private: diff --git a/modules/juce_graphics/native/juce_Direct2DImage_windows.cpp b/modules/juce_graphics/native/juce_Direct2DImage_windows.cpp index 1c514f03d9..de45cbee6d 100644 --- a/modules/juce_graphics/native/juce_Direct2DImage_windows.cpp +++ b/modules/juce_graphics/native/juce_Direct2DImage_windows.cpp @@ -680,9 +680,12 @@ void Direct2DPixelData::copyPages (ComSmartPtr deviceToUse, Point dstPoint, Rectangle srcRect) { + auto& srcPages = srcData.getPagesStructForDevice (deviceToUse); + srcPages.getPages(); + copyAcrossMultiplePages (dstData.getPagesStructForDevice (deviceToUse), dstPoint, - srcData.getPagesStructForDevice (deviceToUse), + srcPages, srcRect, copyDstFromSrc); diff --git a/modules/juce_gui_basics/buttons/juce_Button.h b/modules/juce_gui_basics/buttons/juce_Button.h index 151a1fc6ea..036ab09833 100644 --- a/modules/juce_gui_basics/buttons/juce_Button.h +++ b/modules/juce_gui_basics/buttons/juce_Button.h @@ -426,10 +426,10 @@ public: }; //============================================================================== - #ifndef DOXYGEN + /** @cond */ [[deprecated ("This method's parameters have changed.")]] void setToggleState (bool, bool); - #endif + /** @endcond */ protected: //============================================================================== diff --git a/modules/juce_gui_basics/components/juce_Component.h b/modules/juce_gui_basics/components/juce_Component.h index 0543b3869a..97c42bc144 100644 --- a/modules/juce_gui_basics/components/juce_Component.h +++ b/modules/juce_gui_basics/components/juce_Component.h @@ -2627,7 +2627,7 @@ public: virtual std::unique_ptr createAccessibilityHandler(); //============================================================================== - #ifndef DOXYGEN + /** @cond */ [[deprecated ("Use the setFocusContainerType that takes a more descriptive enum.")]] void setFocusContainer (bool shouldBeFocusContainer) noexcept { @@ -2637,7 +2637,7 @@ public: [[deprecated ("Use the contains that takes a Point.")]] void contains (int, int) = delete; - #endif + /** @endcond */ private: @@ -2645,7 +2645,7 @@ private: friend class ComponentPeer; friend class detail::MouseInputSourceImpl; - #ifndef DOXYGEN + /** @cond */ static Component* currentlyFocusedComponent; //============================================================================== @@ -2758,7 +2758,7 @@ protected: virtual ComponentPeer* createNewPeer (int styleFlags, void* nativeWindowToAttachTo); /** @internal */ static std::unique_ptr createIgnoredAccessibilityHandler (Component&); - #endif + /** @endcond */ }; } // namespace juce diff --git a/modules/juce_gui_basics/components/juce_FocusTraverser.cpp b/modules/juce_gui_basics/components/juce_FocusTraverser.cpp index 44dd629a30..0ece10edc7 100644 --- a/modules/juce_gui_basics/components/juce_FocusTraverser.cpp +++ b/modules/juce_gui_basics/components/juce_FocusTraverser.cpp @@ -36,6 +36,11 @@ namespace juce { //============================================================================== +FocusTraverser::FocusTraverser (SkipDisabledComponents skipDisabledComponentsIn) + : skipDisabledComponents (skipDisabledComponentsIn) +{ +} + Component* FocusTraverser::getNextComponent (Component* current) { jassert (current != nullptr); @@ -43,7 +48,8 @@ Component* FocusTraverser::getNextComponent (Component* current) return detail::FocusHelpers::navigateFocus (current, current->findFocusContainer(), detail::FocusHelpers::NavigationDirection::forwards, - &Component::isFocusContainer); + &Component::isFocusContainer, + skipDisabledComponents); } Component* FocusTraverser::getPreviousComponent (Component* current) @@ -53,7 +59,8 @@ Component* FocusTraverser::getPreviousComponent (Component* current) return detail::FocusHelpers::navigateFocus (current, current->findFocusContainer(), detail::FocusHelpers::NavigationDirection::backwards, - &Component::isFocusContainer); + &Component::isFocusContainer, + skipDisabledComponents); } Component* FocusTraverser::getDefaultComponent (Component* parentComponent) @@ -61,9 +68,11 @@ Component* FocusTraverser::getDefaultComponent (Component* parentComponent) if (parentComponent != nullptr) { std::vector components; + detail::FocusHelpers::findAllComponents (parentComponent, components, - &Component::isFocusContainer); + &Component::isFocusContainer, + skipDisabledComponents); if (! components.empty()) return components.front(); @@ -77,7 +86,8 @@ std::vector FocusTraverser::getAllComponents (Component* parentCompo std::vector components; detail::FocusHelpers::findAllComponents (parentComponent, components, - &Component::isFocusContainer); + &Component::isFocusContainer, + skipDisabledComponents); return components; } @@ -116,14 +126,23 @@ struct FocusTraverserTests final : public UnitTest [] (const Component* c1, const Component& c2) { return c1 == &c2; })); } - beginTest ("Disabled components are ignored"); + beginTest ("Disabled components are not ignored by default"); { - checkIgnored ([] (Component& c) { c.setEnabled (false); }); + TestComponent parent; + parent.children[2].setEnabled (false); + parent.children[5].setEnabled (false); + expect (traverser.getAllComponents (&parent).size() == parent.children.size()); + } + + beginTest ("Disabled components can be ignored"); + { + FocusTraverser ignoringTraverser { FocusTraverser::SkipDisabledComponents::yes }; + checkIgnored ([] (Component& c) { c.setEnabled (false); }, ignoringTraverser); } beginTest ("Invisible components are ignored"); { - checkIgnored ([] (Component& c) { c.setVisible (false); }); + checkIgnored ([] (Component& c) { c.setVisible (false); }, traverser); } beginTest ("Explicit focus order comes before unspecified"); @@ -253,21 +272,21 @@ private: } } - void checkIgnored (const std::function& makeIgnored) + void checkIgnored (const std::function& makeIgnored, FocusTraverser& traverserToUse) { TestComponent parent; auto iter = parent.children.begin(); makeIgnored (*iter); - expect (traverser.getDefaultComponent (&parent) == std::addressof (*std::next (iter))); + expect (traverserToUse.getDefaultComponent (&parent) == std::addressof (*std::next (iter))); iter += 5; makeIgnored (*iter); - expect (traverser.getNextComponent (std::addressof (*std::prev (iter))) == std::addressof (*std::next (iter))); - expect (traverser.getPreviousComponent (std::addressof (*std::next (iter))) == std::addressof (*std::prev (iter))); + expect (traverserToUse.getNextComponent (std::addressof (*std::prev (iter))) == std::addressof (*std::next (iter))); + expect (traverserToUse.getPreviousComponent (std::addressof (*std::next (iter))) == std::addressof (*std::prev (iter))); - auto allComponents = traverser.getAllComponents (&parent); + auto allComponents = traverserToUse.getAllComponents (&parent); expect (std::find (allComponents.cbegin(), allComponents.cend(), &parent.children.front()) == allComponents.cend()); expect (std::find (allComponents.cbegin(), allComponents.cend(), std::addressof (*iter)) == allComponents.cend()); diff --git a/modules/juce_gui_basics/components/juce_FocusTraverser.h b/modules/juce_gui_basics/components/juce_FocusTraverser.h index 86d67952ae..627b7b069e 100644 --- a/modules/juce_gui_basics/components/juce_FocusTraverser.h +++ b/modules/juce_gui_basics/components/juce_FocusTraverser.h @@ -62,6 +62,25 @@ namespace juce class JUCE_API FocusTraverser : public ComponentTraverser { public: + /** Controls whether the FocusTraverser will allow navigation to disabled components. + */ + enum class SkipDisabledComponents + { + no, ///< Disabled components can receive focus. + yes ///< Disabled components can't receive focus. + }; + + /** Creates a FocusTraverser that will not skip disabled components. */ + FocusTraverser() = default; + + /** Creates a FocusTraverser. + + @param skipDisabledComponents If set to SkipDisabledComponents::yes, the traverser will ignore + disabled components. This makes such components non-discoverable + using screen readers. + */ + explicit FocusTraverser (SkipDisabledComponents skipDisabledComponents); + /** Destructor. */ ~FocusTraverser() override = default; @@ -97,6 +116,9 @@ public: The default implementation will return all visible and enabled child components. */ std::vector getAllComponents (Component* parentComponent) override; + +private: + SkipDisabledComponents skipDisabledComponents = SkipDisabledComponents::no; }; } // namespace juce diff --git a/modules/juce_gui_basics/components/juce_ModalComponentManager.h b/modules/juce_gui_basics/components/juce_ModalComponentManager.h index f0a043379b..cafed82074 100644 --- a/modules/juce_gui_basics/components/juce_ModalComponentManager.h +++ b/modules/juce_gui_basics/components/juce_ModalComponentManager.h @@ -84,9 +84,9 @@ public: }; //============================================================================== - #ifndef DOXYGEN + /** @cond */ JUCE_DECLARE_SINGLETON_SINGLETHREADED_MINIMAL_INLINE (ModalComponentManager) - #endif + /** @endcond */ //============================================================================== /** Returns the number of components currently being shown modally. diff --git a/modules/juce_gui_basics/desktop/juce_Desktop.h b/modules/juce_gui_basics/desktop/juce_Desktop.h index 5c3d47e3e0..e6e7454626 100644 --- a/modules/juce_gui_basics/desktop/juce_Desktop.h +++ b/modules/juce_gui_basics/desktop/juce_Desktop.h @@ -406,10 +406,12 @@ public: /** True if the OS supports semitransparent windows */ static bool canUseSemiTransparentWindows() noexcept; - #if JUCE_MAC && ! defined (DOXYGEN) + #if JUCE_MAC + /** @cond */ [[deprecated ("This macOS-specific method has been deprecated in favour of the cross-platform " " isDarkModeActive() method.")]] static bool isOSXDarkModeActive() { return Desktop::getInstance().isDarkModeActive(); } + /** @endcond */ #endif /** Returns true if the desktop environment allows resizing the window by clicking and dragging diff --git a/modules/juce_gui_basics/desktop/juce_Displays.cpp b/modules/juce_gui_basics/desktop/juce_Displays.cpp index e61de1cff8..624bd58fd5 100644 --- a/modules/juce_gui_basics/desktop/juce_Displays.cpp +++ b/modules/juce_gui_basics/desktop/juce_Displays.cpp @@ -383,14 +383,14 @@ void Displays::updateToLogical() } } -#ifndef DOXYGEN - // explicit template instantiations - template Point Displays::physicalToLogical (Point, const Display*) const noexcept; - template Point Displays::physicalToLogical (Point, const Display*) const noexcept; +/** @cond */ +// explicit template instantiations +template Point Displays::physicalToLogical (Point, const Display*) const noexcept; +template Point Displays::physicalToLogical (Point, const Display*) const noexcept; - template Point Displays::logicalToPhysical (Point, const Display*) const noexcept; - template Point Displays::logicalToPhysical (Point, const Display*) const noexcept; -#endif +template Point Displays::logicalToPhysical (Point, const Display*) const noexcept; +template Point Displays::logicalToPhysical (Point, const Display*) const noexcept; +/** @endcond */ //============================================================================== // Deprecated methods diff --git a/modules/juce_gui_basics/desktop/juce_Displays.h b/modules/juce_gui_basics/desktop/juce_Displays.h index e047b96e80..b35494c39d 100644 --- a/modules/juce_gui_basics/desktop/juce_Displays.h +++ b/modules/juce_gui_basics/desktop/juce_Displays.h @@ -91,6 +91,9 @@ public: occupying the top portion of the screen is likely to have insets for the status bar but not the navigation bar, whereas an activity on the bottom may have navigation insets but not status insets. + + The insets may also change as a result of rotating the screen, as this will rotate any + physical screen cutouts, and could also cause system UI elements to be repositioned. */ BorderSize safeAreaInsets; @@ -211,7 +214,7 @@ public: /** An Array containing the Display objects for all of the connected displays. */ Array displays; - #ifndef DOXYGEN + /** @cond */ /** @internal */ void refresh(); @@ -224,7 +227,7 @@ public: [[deprecated]] const Display& findDisplayForRect (Rectangle, bool isPhysical = false) const noexcept; [[deprecated]] const Display& findDisplayForPoint (Point, bool isPhysical = false) const noexcept; [[deprecated]] const Display& getMainDisplay() const noexcept; - #endif + /** @endcond */ private: friend class Desktop; diff --git a/modules/juce_gui_basics/detail/juce_FocusHelpers.h b/modules/juce_gui_basics/detail/juce_FocusHelpers.h index 7b64f36cc5..1a3cc24ad9 100644 --- a/modules/juce_gui_basics/detail/juce_FocusHelpers.h +++ b/modules/juce_gui_basics/detail/juce_FocusHelpers.h @@ -45,10 +45,10 @@ struct FocusHelpers return order > 0 ? order : std::numeric_limits::max(); } - template static void findAllComponents (const Component* parent, std::vector& components, - FocusContainerFn isFocusContainer) + bool (Component::* isFocusContainer)() const, + FocusTraverser::SkipDisabledComponents skipDisabledComponents) { if (parent == nullptr || parent->getNumChildComponents() == 0) return; @@ -56,8 +56,12 @@ struct FocusHelpers std::vector localComponents; for (auto* c : parent->getChildren()) - if (c->isVisible() && c->isEnabled()) + { + constexpr auto no = FocusTraverser::SkipDisabledComponents::no; + + if (c->isVisible() && (c->isEnabled() || skipDisabledComponents == no)) localComponents.push_back (c); + } const auto compareComponents = [&] (const Component* a, const Component* b) { @@ -81,23 +85,23 @@ struct FocusHelpers components.push_back (c); if (! (c->*isFocusContainer)()) - findAllComponents (c, components, isFocusContainer); + findAllComponents (c, components, isFocusContainer, skipDisabledComponents); } } enum class NavigationDirection { forwards, backwards }; - template static Component* navigateFocus (const Component* current, const Component* focusContainer, NavigationDirection direction, - FocusContainerFn isFocusContainer) + bool (Component::* isFocusContainer)() const, + FocusTraverser::SkipDisabledComponents skipDisabledComponents) { if (focusContainer == nullptr) return nullptr; std::vector components; - findAllComponents (focusContainer, components, isFocusContainer); + findAllComponents (focusContainer, components, isFocusContainer, skipDisabledComponents); const auto iter = std::find (components.cbegin(), components.cend(), current); diff --git a/modules/juce_gui_basics/drawables/juce_Drawable.h b/modules/juce_gui_basics/drawables/juce_Drawable.h index eaf0a2e7f7..ed04be5d4e 100644 --- a/modules/juce_gui_basics/drawables/juce_Drawable.h +++ b/modules/juce_gui_basics/drawables/juce_Drawable.h @@ -35,7 +35,7 @@ namespace juce { -#ifndef DOXYGEN +/** @cond */ namespace detail { class BoundsChangeListener final : private ComponentListener @@ -60,7 +60,7 @@ private: ErasedScopeGuard componentListenerGuard; }; } // namespace detail -#endif +/** @endcond */ //============================================================================== /** diff --git a/modules/juce_gui_basics/filebrowser/juce_FileChooser.h b/modules/juce_gui_basics/filebrowser/juce_FileChooser.h index e5973065dd..6c8da6c969 100644 --- a/modules/juce_gui_basics/filebrowser/juce_FileChooser.h +++ b/modules/juce_gui_basics/filebrowser/juce_FileChooser.h @@ -316,9 +316,9 @@ public: const String& fileExtension); //============================================================================== - #ifndef DOXYGEN + /** @cond */ class Native; - #endif + /** @endcond */ private: //============================================================================== diff --git a/modules/juce_gui_basics/keyboard/juce_KeyboardFocusTraverser.cpp b/modules/juce_gui_basics/keyboard/juce_KeyboardFocusTraverser.cpp index 14098abc70..b76a65026b 100644 --- a/modules/juce_gui_basics/keyboard/juce_KeyboardFocusTraverser.cpp +++ b/modules/juce_gui_basics/keyboard/juce_KeyboardFocusTraverser.cpp @@ -47,7 +47,8 @@ namespace KeyboardFocusTraverserHelpers detail::FocusHelpers::NavigationDirection direction) { if (auto* comp = detail::FocusHelpers::navigateFocus (current, container, direction, - &Component::isKeyboardFocusContainer)) + &Component::isKeyboardFocusContainer, + FocusTraverser::SkipDisabledComponents::yes)) { if (isKeyboardFocusable (comp, container)) return comp; @@ -85,7 +86,8 @@ std::vector KeyboardFocusTraverser::getAllComponents (Component* par std::vector components; detail::FocusHelpers::findAllComponents (parentComponent, components, - &Component::isKeyboardFocusContainer); + &Component::isKeyboardFocusContainer, + FocusTraverser::SkipDisabledComponents::yes); auto removePredicate = [parentComponent] (const Component* comp) { diff --git a/modules/juce_gui_basics/menus/juce_PopupMenu.cpp b/modules/juce_gui_basics/menus/juce_PopupMenu.cpp index 73a0e9a1f8..1f6b591890 100644 --- a/modules/juce_gui_basics/menus/juce_PopupMenu.cpp +++ b/modules/juce_gui_basics/menus/juce_PopupMenu.cpp @@ -126,7 +126,10 @@ struct ItemComponent final : public Component : item (i), parentWindow (parent), options (o), customComp (i.customComponent) { if (item.isSectionHeader) + { customComp = *new HeaderItemComponent (item.text, options); + setEnabled (false); + } if (customComp != nullptr) { @@ -1423,7 +1426,7 @@ public: private: Point lastMousePos; double scrollAcceleration = 0; - uint32 lastScrollTime; + uint32 lastScrollTime = 0, lastMoveTime = 0; bool isDown = false; // Although most mouse movements can be handled inside mouse event callbacks, scrolling of menus @@ -1454,7 +1457,7 @@ private: window.showSubMenuFor (window.currentChild); } - highlightItemUnderMouse (globalMousePos, localMousePos); + highlightItemUnderMouse (globalMousePos, localMousePos, timeNow); const bool overScrollArea = scrollIfNecessary (localMousePos, timeNow); const bool isOverAny = window.isOverAnyMenu(); @@ -1498,55 +1501,63 @@ private: } } - void highlightItemUnderMouse (Point globalMousePos, Point localMousePos) + void highlightItemUnderMouse (Point globalMousePos, Point localMousePos, uint32 timeNow) { + const auto mouseTimedOut = lastMoveTime != 0 && 350 < (timeNow - lastMoveTime); const auto mouseHasMoved = 2 < lastMousePos.getDistanceFrom (globalMousePos); - - if (! mouseHasMoved) - return; - const auto isMouseOver = window.reallyContains (localMousePos, true); - if (isMouseOver) + if (mouseHasMoved && isMouseOver) + { window.disableMouseMoves = false; + lastMoveTime = timeNow; + } - if (window.disableMouseMoves || (window.activeSubMenu != nullptr && window.activeSubMenu->isOverChildren())) + if (! mouseHasMoved && ! mouseTimedOut) return; - const bool isMovingTowardsMenu = isMouseOver && globalMousePos != lastMousePos - && isMovingTowardsSubmenu (globalMousePos); + if (window.disableMouseMoves) + return; + + if (window.activeSubMenu != nullptr && window.activeSubMenu->isOverChildren()) + return; + + const auto isMovingTowardsMenu = isMouseOver + && globalMousePos != lastMousePos + && isMovingTowardsSubmenu (globalMousePos); lastMousePos = globalMousePos; - if (! isMovingTowardsMenu) + if (isMovingTowardsMenu) + return; + + auto* componentUnderMouse = window.getComponentAt (localMousePos); + auto* childComponentUnderMouse = componentUnderMouse != &window ? componentUnderMouse : nullptr; + + auto* itemUnderMouse = std::invoke ([&]() -> ItemComponent* { - auto* c = window.getComponentAt (localMousePos); + if (auto* candidate = dynamic_cast (childComponentUnderMouse)) + return candidate; - if (c == &window) - c = nullptr; + if (childComponentUnderMouse != nullptr) + return childComponentUnderMouse->findParentComponentOfClass(); - auto* itemUnderMouse = dynamic_cast (c); + return nullptr; + }); - if (itemUnderMouse == nullptr && c != nullptr) - itemUnderMouse = c->findParentComponentOfClass(); + if (itemUnderMouse == window.currentChild) + return; - if (itemUnderMouse != window.currentChild - && (isMouseOver || (window.activeSubMenu == nullptr) || ! window.activeSubMenu->isVisible())) - { - if (isMouseOver && (c != nullptr) && (window.activeSubMenu != nullptr)) - window.activeSubMenu->hide (nullptr, true); + if (! isMouseOver && window.activeSubMenu != nullptr && window.activeSubMenu->isVisible()) + return; - if (! isMouseOver) - { - if (! window.mouseHasBeenOver()) - return; + if (isMouseOver && childComponentUnderMouse != nullptr && window.activeSubMenu != nullptr) + window.activeSubMenu->hide (nullptr, true); - itemUnderMouse = nullptr; - } + if (! isMouseOver && ! window.mouseHasBeenOver()) + return; - window.setCurrentlyHighlightedChild (itemUnderMouse); - } - } + window.setCurrentlyHighlightedChild (isMouseOver ? itemUnderMouse : nullptr); } bool isMovingTowardsSubmenu (Point newGlobalPos) const diff --git a/modules/juce_gui_basics/menus/juce_PopupMenu.h b/modules/juce_gui_basics/menus/juce_PopupMenu.h index a8234453e9..2bd58a77a9 100644 --- a/modules/juce_gui_basics/menus/juce_PopupMenu.h +++ b/modules/juce_gui_basics/menus/juce_PopupMenu.h @@ -1050,10 +1050,10 @@ public: }; //============================================================================== - #ifndef DOXYGEN + /** @cond */ [[deprecated ("Use the new method.")]] int drawPopupMenuItem (Graphics&, int, int, bool, bool, bool, bool, bool, const String&, const String&, Image*, const Colour*) { return 0; } - #endif + /** @endcond */ private: //============================================================================== diff --git a/modules/juce_gui_basics/mouse/juce_MouseInputSource.h b/modules/juce_gui_basics/mouse/juce_MouseInputSource.h index a49ccc7f70..ffc893df87 100644 --- a/modules/juce_gui_basics/mouse/juce_MouseInputSource.h +++ b/modules/juce_gui_basics/mouse/juce_MouseInputSource.h @@ -285,13 +285,13 @@ public: static const Point offscreenMousePos; //============================================================================== - #ifndef DOXYGEN + /** @cond */ [[deprecated ("This method has been replaced with the isLongPressOrDrag and hasMovedSignificantlySincePressed " "methods. If you want the same behaviour you should use isLongPressOrDrag which accounts for the " "amount of time that the input source has been held down for, but if you only want to know whether " "it has been moved use hasMovedSignificantlySincePressed instead.")]] bool hasMouseMovedSignificantlySincePressed() const noexcept; - #endif + /** @endcond */ private: //============================================================================== diff --git a/modules/juce_gui_basics/native/accessibility/juce_Accessibility_android.cpp b/modules/juce_gui_basics/native/accessibility/juce_Accessibility_android.cpp index ae04c50bda..a2cb22b0eb 100644 --- a/modules/juce_gui_basics/native/accessibility/juce_Accessibility_android.cpp +++ b/modules/juce_gui_basics/native/accessibility/juce_Accessibility_android.cpp @@ -333,7 +333,7 @@ public: env->CallVoidMethod (info, AndroidAccessibilityNodeInfo.setEnabled, - ! state.isIgnored()); + ! state.isIgnored() && accessibilityHandler.getComponent().isEnabled()); env->CallVoidMethod (info, AndroidAccessibilityNodeInfo.setVisibleToUser, true); diff --git a/modules/juce_gui_basics/native/java/app/com/rmsl/juce/ComponentPeerView.java b/modules/juce_gui_basics/native/java/app/com/rmsl/juce/ComponentPeerView.java index 10a3a26ede..70e7e140c7 100644 --- a/modules/juce_gui_basics/native/java/app/com/rmsl/juce/ComponentPeerView.java +++ b/modules/juce_gui_basics/native/java/app/com/rmsl/juce/ComponentPeerView.java @@ -34,6 +34,9 @@ package com.rmsl.juce; +import static android.view.WindowInsetsController.APPEARANCE_LIGHT_CAPTION_BARS; +import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS; +import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS; import static android.view.WindowInsetsController.BEHAVIOR_DEFAULT; import static android.view.WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_SWIPE; import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE; @@ -42,6 +45,7 @@ import android.app.Activity; import android.app.Application; import android.content.Context; import android.graphics.Canvas; +import android.graphics.Color; import android.graphics.ColorMatrix; import android.graphics.ColorMatrixColorFilter; import android.graphics.Paint; @@ -114,36 +118,7 @@ public final class ComponentPeerView extends ViewGroup colorMatrix.set (colorTransform); paint.setColorFilter (new ColorMatrixColorFilter (colorMatrix)); - java.lang.reflect.Method method = null; - - try - { - method = getClass().getMethod ("setLayerType", int.class, Paint.class); - } - catch (SecurityException e) - { - } - catch (NoSuchMethodException e) - { - } - - if (method != null) - { - try - { - int layerTypeNone = 0; - method.invoke (this, layerTypeNone, null); - } - catch (java.lang.IllegalArgumentException e) - { - } - catch (java.lang.IllegalAccessException e) - { - } - catch (java.lang.reflect.InvocationTargetException e) - { - } - } + setLayerType (LAYER_TYPE_NONE, null); Choreographer.getInstance().postFrameCallback (this); } @@ -804,14 +779,26 @@ public final class ComponentPeerView extends ViewGroup { } - public void setSystemUiVisibilityCompat (Window window, boolean visible) + public void setSystemUiVisibilityCompat (Window window, boolean visible, boolean isLight) { + if (window != null) + { + // Although this is deprecated in Android 35+, it still seems to be necessary + // to adjust the colour of the nav bar icons when in button-mode. + window.setNavigationBarColor (isLight ? Color.BLACK : Color.WHITE); + } + if (30 <= Build.VERSION.SDK_INT) { WindowInsetsController controller = getWindowInsetsController(); if (controller != null) { + final int mask = (35 <= Build.VERSION.SDK_INT ? APPEARANCE_LIGHT_CAPTION_BARS : 0) + | APPEARANCE_LIGHT_NAVIGATION_BARS + | APPEARANCE_LIGHT_STATUS_BARS; + controller.setSystemBarsAppearance (isLight ? mask : 0, mask); + if (visible) { controller.show (WindowInsets.Type.systemBars()); @@ -843,14 +830,18 @@ public final class ComponentPeerView extends ViewGroup for (View view : views) { + final int lightStyle = (26 <= Build.VERSION.SDK_INT ? SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR : 0) + | SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; final int prevFlags = view.getSystemUiVisibility(); final int fullScreenFlags = SYSTEM_UI_FLAG_HIDE_NAVIGATION | SYSTEM_UI_FLAG_FULLSCREEN | SYSTEM_UI_FLAG_IMMERSIVE_STICKY; - final int newFlags = visible ? (prevFlags & ~fullScreenFlags) - : (prevFlags | fullScreenFlags); + final int withVisibility = visible ? (prevFlags & ~fullScreenFlags) + : (prevFlags | fullScreenFlags); + final int withColour = isLight ? (withVisibility | lightStyle) + : (withVisibility & ~lightStyle); - view.setSystemUiVisibility (newFlags); + view.setSystemUiVisibility (withColour); } } diff --git a/modules/juce_gui_basics/native/javaopt/app/com/rmsl/juce/JuceActivity.java b/modules/juce_gui_basics/native/javaopt/app/com/rmsl/juce/JuceActivity.java index 8bd0290466..566e46a04a 100644 --- a/modules/juce_gui_basics/native/javaopt/app/com/rmsl/juce/JuceActivity.java +++ b/modules/juce_gui_basics/native/javaopt/app/com/rmsl/juce/JuceActivity.java @@ -60,13 +60,21 @@ public class JuceActivity extends Activity ? ( SYSTEM_UI_FLAG_LAYOUT_STABLE | SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) - : SYSTEM_UI_FLAG_LAYOUT_STABLE; + : 0; decorView.setSystemUiVisibility (decorView.getSystemUiVisibility() | flags); } if (30 <= Build.VERSION.SDK_INT) getWindow().setDecorFitsSystemWindows (false); + + if (29 <= Build.VERSION.SDK_INT) + { + if (Build.VERSION.SDK_INT < 35) + getWindow().setStatusBarContrastEnforced (false); + + getWindow().setNavigationBarContrastEnforced (false); + } } @Override diff --git a/modules/juce_gui_basics/native/juce_Windowing_android.cpp b/modules/juce_gui_basics/native/juce_Windowing_android.cpp index 8e2b87c736..5f02e315c3 100644 --- a/modules/juce_gui_basics/native/juce_Windowing_android.cpp +++ b/modules/juce_gui_basics/native/juce_Windowing_android.cpp @@ -39,847 +39,836 @@ namespace juce // See juce_core/native/java/README.txt on how to generate this byte-code. const uint8 javaComponentPeerView[] { - 0x1f, 0x8b, 0x08, 0x08, 0x8a, 0x87, 0x2f, 0x68, 0x00, 0x03, 0x63, 0x6c, + 0x1f, 0x8b, 0x08, 0x08, 0xbc, 0xe2, 0x6c, 0x68, 0x00, 0x03, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x65, 0x73, 0x2e, 0x64, 0x65, 0x78, 0x00, 0xa5, 0x7c, - 0x0b, 0x7c, 0x5c, 0x55, 0xb5, 0xf7, 0xda, 0x67, 0x5e, 0xc9, 0xe4, 0x35, - 0x99, 0xb4, 0x4d, 0xdf, 0x9d, 0xa6, 0x69, 0x09, 0xa5, 0x49, 0x26, 0x69, - 0xd2, 0x24, 0x4d, 0x4b, 0xd3, 0x3c, 0xda, 0xe6, 0xd1, 0x36, 0x4d, 0xa6, - 0x69, 0x9b, 0x14, 0xe8, 0x24, 0x99, 0x36, 0xd3, 0x4e, 0x66, 0xa6, 0x33, - 0x93, 0x34, 0x85, 0x82, 0x2d, 0x14, 0xc1, 0x8a, 0xdc, 0xe2, 0x05, 0x2d, - 0x82, 0x5a, 0xe5, 0x25, 0x0a, 0x5a, 0x10, 0x3f, 0x51, 0x50, 0xc1, 0x2b, - 0x8a, 0x5e, 0x5e, 0x22, 0x28, 0x7c, 0x3c, 0x44, 0x28, 0x8a, 0x8a, 0x17, - 0xbc, 0x22, 0x72, 0xaf, 0x5e, 0xf9, 0xfe, 0x6b, 0xef, 0x3d, 0x93, 0x33, - 0x79, 0x80, 0x7e, 0xb7, 0xf9, 0xfd, 0xcf, 0x5a, 0x7b, 0xad, 0xb5, 0xdf, - 0x6b, 0xaf, 0xbd, 0xf7, 0x99, 0xe9, 0x0c, 0x06, 0xc6, 0x9c, 0xde, 0x95, - 0x35, 0x54, 0x7f, 0xdd, 0xf2, 0x77, 0x9e, 0xb4, 0xcc, 0x69, 0x7b, 0xf2, - 0xa2, 0xf0, 0xdc, 0xc1, 0x9a, 0xdb, 0x6e, 0xf9, 0xc2, 0x33, 0xc1, 0xc3, - 0xb7, 0x9e, 0x9a, 0x1f, 0x3f, 0xe2, 0x23, 0x8a, 0x12, 0xd1, 0x58, 0x4f, - 0x95, 0x9b, 0xf4, 0xbf, 0xfb, 0xbb, 0x89, 0xae, 0x16, 0x4a, 0xde, 0x09, - 0x9c, 0xb4, 0x13, 0x1d, 0x04, 0x7d, 0xca, 0x41, 0xb4, 0x04, 0x74, 0x7e, - 0x0e, 0xd1, 0x6f, 0x41, 0xab, 0x72, 0x89, 0xb2, 0x40, 0x8f, 0xcc, 0x24, - 0x3a, 0xbd, 0x96, 0xe8, 0xc5, 0x59, 0x44, 0x25, 0x95, 0x44, 0xcb, 0x81, - 0x52, 0xc0, 0x0b, 0xac, 0x04, 0xfa, 0x80, 0x2b, 0x80, 0xaf, 0x00, 0x5f, - 0x05, 0xee, 0x05, 0xbe, 0x01, 0x7c, 0x07, 0x78, 0x18, 0xf8, 0x11, 0xf0, - 0x24, 0xf0, 0x32, 0xf0, 0x2e, 0x60, 0xac, 0x24, 0x9a, 0x05, 0xcc, 0x01, - 0x16, 0x00, 0x1e, 0xa0, 0x18, 0x28, 0x01, 0x4a, 0x81, 0x0a, 0x60, 0x15, - 0xb0, 0x1a, 0x58, 0x0b, 0xac, 0x07, 0x5a, 0x80, 0x41, 0xe0, 0x52, 0xe0, - 0x28, 0x70, 0x1c, 0xf8, 0x18, 0xf0, 0x09, 0xe0, 0x93, 0xc0, 0x29, 0xe0, - 0x66, 0xe0, 0x0b, 0xc0, 0xed, 0xc0, 0x5d, 0xc0, 0x3d, 0xc0, 0x8f, 0x81, - 0xf7, 0x81, 0xb9, 0x55, 0x44, 0xd5, 0x40, 0x27, 0x10, 0x05, 0x4e, 0x02, - 0x0f, 0x00, 0xcf, 0x02, 0x6f, 0x01, 0x19, 0xd5, 0x68, 0x03, 0x50, 0x07, - 0x6c, 0x05, 0x86, 0x80, 0xcb, 0x81, 0xcf, 0x01, 0xf7, 0x03, 0xbf, 0x04, - 0xfe, 0x0a, 0xb8, 0x56, 0x11, 0x2d, 0x05, 0xb6, 0x01, 0x11, 0xe0, 0x6a, - 0xe0, 0x56, 0xe0, 0x49, 0xe0, 0x2c, 0xf0, 0x77, 0x60, 0x55, 0x0d, 0xd1, - 0x0e, 0x20, 0x0c, 0x9c, 0x04, 0xbe, 0x09, 0xfc, 0x0e, 0x58, 0x58, 0x4b, - 0xd4, 0x03, 0x7c, 0x14, 0xb8, 0x1b, 0x78, 0x1e, 0xc8, 0xa8, 0x43, 0xdf, - 0x80, 0xcb, 0x81, 0xef, 0x01, 0x6f, 0x03, 0x0b, 0x57, 0x13, 0x5d, 0x04, - 0xdc, 0x01, 0xbc, 0x0a, 0xb8, 0xeb, 0x61, 0x03, 0x0c, 0x01, 0xd7, 0x00, - 0x77, 0x01, 0x4f, 0x02, 0x7f, 0x06, 0x66, 0xac, 0x21, 0x2a, 0x03, 0xd6, - 0x03, 0xfd, 0xc0, 0x47, 0x81, 0xbb, 0x80, 0x87, 0x81, 0xb3, 0xc0, 0x7b, - 0x40, 0x21, 0xe6, 0xee, 0x3c, 0xa0, 0x17, 0x18, 0x05, 0x3e, 0x01, 0xdc, - 0x02, 0x7c, 0x03, 0xf8, 0x11, 0xf0, 0x2c, 0xf0, 0x32, 0x70, 0x16, 0xf8, - 0x33, 0x60, 0x39, 0x9f, 0xc8, 0x0e, 0x38, 0x81, 0x3c, 0x60, 0x26, 0x30, - 0x1f, 0xf0, 0x00, 0x25, 0x40, 0x19, 0x50, 0x0d, 0xac, 0x06, 0xd6, 0x01, - 0x2d, 0x40, 0x1b, 0xb0, 0x05, 0xe8, 0x06, 0x76, 0x01, 0x7b, 0x80, 0x00, - 0xb0, 0x1f, 0x38, 0x08, 0x5c, 0x0c, 0x1c, 0x05, 0xae, 0x04, 0x3e, 0x0e, - 0x5c, 0x07, 0xdc, 0x00, 0x7c, 0x16, 0x38, 0x0d, 0xdc, 0x06, 0x7c, 0x05, - 0x38, 0x03, 0xdc, 0x07, 0x3c, 0x00, 0x3c, 0x0c, 0x3c, 0x02, 0xfc, 0x04, - 0x78, 0x1a, 0x78, 0x1e, 0x78, 0x09, 0xf8, 0x15, 0xf0, 0x3a, 0xf0, 0x5f, - 0x40, 0xee, 0x3a, 0xcc, 0x2d, 0xb0, 0x0c, 0x58, 0x09, 0x34, 0x00, 0x9b, - 0x81, 0x5e, 0x60, 0x1f, 0x90, 0x00, 0x8e, 0x01, 0xd7, 0x02, 0x37, 0x01, - 0x5f, 0x02, 0xee, 0x03, 0x1e, 0x06, 0x1e, 0x07, 0x9e, 0x07, 0x5e, 0x07, - 0xfe, 0x08, 0xfc, 0x0f, 0x90, 0xd9, 0x80, 0xfe, 0x02, 0x45, 0x40, 0x05, - 0xb0, 0x11, 0xf0, 0x01, 0xbb, 0x80, 0x04, 0xf0, 0x51, 0xe0, 0x46, 0xe0, - 0x2e, 0xe0, 0x3e, 0xe0, 0x41, 0xe0, 0x09, 0xe0, 0x25, 0xe0, 0x2c, 0xf0, - 0x67, 0x20, 0x77, 0x3d, 0xd1, 0x3c, 0xe0, 0x3c, 0x60, 0x35, 0xd0, 0x09, - 0x0c, 0x03, 0xa3, 0xc0, 0x51, 0xe0, 0x04, 0x70, 0x17, 0xf0, 0x4d, 0xe0, - 0x11, 0xe0, 0x55, 0x80, 0x1a, 0xb1, 0xd6, 0x80, 0x79, 0xc0, 0x0a, 0xa0, - 0x09, 0xd8, 0x0e, 0x1c, 0x00, 0x2e, 0x06, 0x8e, 0x03, 0x37, 0x02, 0x67, - 0x80, 0x07, 0x81, 0x9f, 0x00, 0xbf, 0x00, 0x5e, 0x07, 0xa8, 0x09, 0xed, - 0x05, 0x4a, 0x81, 0x4d, 0x80, 0x1f, 0x18, 0x05, 0x3e, 0x01, 0x7c, 0x03, - 0xf8, 0x3e, 0xf0, 0x33, 0xe0, 0x0d, 0xe0, 0x5d, 0x40, 0x34, 0xc3, 0x8f, - 0x81, 0xc5, 0x40, 0x39, 0x50, 0x0b, 0xac, 0x07, 0xb6, 0x00, 0x17, 0x01, - 0x31, 0xe0, 0x38, 0x70, 0x13, 0xf0, 0x15, 0xe0, 0x3b, 0xc0, 0xd3, 0xc0, - 0xab, 0xc0, 0x5f, 0x00, 0x7b, 0x0b, 0xf2, 0x02, 0x15, 0xc0, 0x56, 0x60, - 0x3b, 0xd0, 0x07, 0x0c, 0x00, 0x97, 0x02, 0xd7, 0x02, 0xa7, 0x81, 0x7b, - 0x81, 0x87, 0x81, 0xa7, 0x80, 0x97, 0x80, 0x3f, 0x01, 0xd6, 0x0d, 0x18, - 0x5f, 0xa0, 0x18, 0x58, 0x0b, 0xb4, 0x01, 0x17, 0x01, 0x47, 0x80, 0x2b, - 0x81, 0x8f, 0x03, 0x37, 0x02, 0xf7, 0x02, 0x0f, 0x02, 0xdf, 0x07, 0x9e, - 0x00, 0x7e, 0x09, 0xfc, 0x07, 0xf0, 0x3e, 0xe0, 0xdc, 0x48, 0x34, 0x1b, - 0x38, 0x0f, 0xa8, 0x06, 0xd6, 0x02, 0x1b, 0x81, 0x5e, 0x60, 0x04, 0x38, - 0x0a, 0x9c, 0x00, 0x6e, 0x01, 0xee, 0x05, 0xbe, 0x05, 0x3c, 0x0c, 0xfc, - 0x08, 0x78, 0x02, 0x78, 0x06, 0x78, 0x15, 0xf8, 0x1d, 0xf0, 0x77, 0x20, - 0x7f, 0x13, 0xfc, 0x07, 0xa8, 0x05, 0xda, 0x81, 0x21, 0xe0, 0x12, 0xe0, - 0x5a, 0xe0, 0x0e, 0xe0, 0x6b, 0xc0, 0x77, 0x81, 0x27, 0x80, 0x17, 0x81, - 0xdf, 0x00, 0xef, 0x02, 0xef, 0x03, 0x99, 0xad, 0x68, 0x0b, 0xb0, 0x14, - 0xa8, 0x02, 0x9a, 0x80, 0x2e, 0x60, 0x0f, 0x30, 0x04, 0x44, 0x80, 0xcb, - 0x80, 0xcf, 0x02, 0x67, 0x80, 0x6f, 0x01, 0x2f, 0x01, 0x7f, 0x05, 0x1c, - 0x6d, 0x18, 0x0b, 0x60, 0x2e, 0xb0, 0x1c, 0xa8, 0x05, 0xb6, 0x01, 0xfb, - 0x80, 0x23, 0xc0, 0x09, 0xe0, 0x56, 0xe0, 0x5e, 0xe0, 0x01, 0xe0, 0x69, - 0xe0, 0xb7, 0x80, 0xbd, 0x9d, 0x68, 0x11, 0xb0, 0x02, 0xa8, 0x07, 0x36, - 0x02, 0x3b, 0x80, 0x0b, 0x80, 0x03, 0xc0, 0xc5, 0xc0, 0x09, 0xe0, 0x46, - 0xe0, 0x76, 0xe0, 0x1e, 0xe0, 0x3b, 0xc0, 0x23, 0xc0, 0xaf, 0x81, 0xac, - 0x0e, 0x8c, 0x1b, 0x70, 0x01, 0x70, 0x29, 0x70, 0x33, 0xf0, 0x1d, 0xe0, - 0x97, 0x80, 0xd8, 0x8c, 0xb1, 0x00, 0xb6, 0x00, 0x3d, 0xc0, 0x85, 0xc0, - 0x10, 0x30, 0x0c, 0x9c, 0x04, 0x1e, 0x00, 0x5e, 0x00, 0xfe, 0x0e, 0xd8, - 0xb6, 0xc0, 0xd7, 0x81, 0x19, 0xc0, 0x52, 0xa0, 0x06, 0xe0, 0x4d, 0x66, - 0x06, 0x30, 0x0f, 0x38, 0x0f, 0x58, 0x01, 0x94, 0x02, 0x65, 0x40, 0x39, - 0xe0, 0x05, 0x2a, 0x00, 0x6c, 0x03, 0xb4, 0x92, 0xf7, 0x18, 0x00, 0x61, - 0x95, 0x10, 0x36, 0x09, 0x21, 0x92, 0x10, 0x12, 0x09, 0x21, 0x90, 0x10, - 0xf6, 0x08, 0xe1, 0x8d, 0x10, 0xbe, 0x08, 0x21, 0x89, 0xb0, 0xd4, 0x09, - 0xcb, 0x93, 0xf4, 0x52, 0x61, 0x97, 0x27, 0xb8, 0x22, 0xc1, 0xa5, 0x08, - 0x2e, 0x41, 0x98, 0x46, 0xc2, 0x74, 0x10, 0x86, 0x95, 0x30, 0x44, 0x84, - 0x6e, 0x12, 0xba, 0x43, 0x68, 0x26, 0xa1, 0x59, 0xb4, 0x55, 0xef, 0x75, - 0xdb, 0x80, 0x2e, 0x00, 0x5b, 0x20, 0x61, 0x6b, 0xa4, 0xed, 0x40, 0x0f, - 0xb0, 0x03, 0xd8, 0x09, 0xec, 0x02, 0x7a, 0x81, 0x3e, 0x60, 0x37, 0x70, - 0x01, 0x70, 0x21, 0x70, 0x11, 0xb0, 0x07, 0xf0, 0x03, 0xfd, 0xc0, 0x00, - 0x30, 0x08, 0x04, 0x80, 0xbd, 0xc0, 0x3e, 0x60, 0x08, 0x08, 0x02, 0xfb, - 0x81, 0x03, 0x40, 0x08, 0x18, 0x06, 0xc2, 0x40, 0x84, 0xd4, 0x7e, 0xcb, - 0xfb, 0x6c, 0x0c, 0x38, 0x0c, 0x5c, 0x0f, 0x9c, 0x06, 0xbe, 0x00, 0x7c, - 0x11, 0xb8, 0x85, 0xd4, 0xf8, 0x25, 0xff, 0x15, 0x68, 0x7a, 0xaa, 0x5c, - 0x8d, 0xa9, 0xd0, 0xe9, 0x59, 0x9a, 0x67, 0x79, 0xa1, 0xe6, 0x4f, 0x83, - 0x9f, 0xad, 0xf9, 0x2f, 0x81, 0x9f, 0xa3, 0xf9, 0x33, 0xe0, 0xe7, 0x6a, - 0xfe, 0x7e, 0x13, 0xff, 0x90, 0x89, 0x7f, 0xb4, 0x5c, 0xcd, 0x97, 0xa1, - 0xcb, 0x9f, 0xaf, 0x79, 0x2e, 0x67, 0x81, 0xe6, 0x9f, 0x02, 0xef, 0x01, - 0xb5, 0x6b, 0x9b, 0x65, 0x40, 0x06, 0xf0, 0x9c, 0x96, 0xbb, 0xb4, 0x9c, - 0xf9, 0x7c, 0x13, 0x3f, 0xc7, 0xc4, 0x2f, 0xd0, 0x7c, 0xb1, 0xe6, 0x5f, - 0x41, 0xde, 0x73, 0x35, 0xff, 0x86, 0x2e, 0xc7, 0x63, 0xb2, 0x5f, 0x62, - 0xe2, 0x97, 0x6a, 0x7e, 0xb1, 0xe6, 0xb9, 0xef, 0xe7, 0x68, 0xfe, 0x1d, - 0x9d, 0x77, 0x99, 0xa9, 0x6d, 0x5c, 0xee, 0xdf, 0xb4, 0x7c, 0xb9, 0x96, - 0x73, 0x79, 0x55, 0xba, 0x5f, 0x6c, 0xc3, 0x7e, 0x67, 0x85, 0x43, 0x16, - 0x91, 0xf2, 0xb5, 0xd3, 0xda, 0x7e, 0x8d, 0xa9, 0xae, 0x06, 0x5d, 0xd7, - 0x12, 0xcd, 0x73, 0xde, 0x12, 0xcd, 0x67, 0x7b, 0x95, 0x7d, 0xa3, 0xb6, - 0x5f, 0xae, 0xf9, 0x19, 0x5e, 0x55, 0x3e, 0xf3, 0xf3, 0xb5, 0x4d, 0xb3, - 0xb6, 0x29, 0xd2, 0x3c, 0xd7, 0xb5, 0x54, 0xf3, 0xc5, 0x5e, 0x95, 0x97, - 0xfd, 0xd8, 0xab, 0xed, 0x37, 0x99, 0xfa, 0xc2, 0x3e, 0x5d, 0xeb, 0x55, - 0xfd, 0x65, 0xbe, 0xc1, 0xab, 0xfc, 0xa7, 0x4d, 0xdb, 0x5c, 0xac, 0x79, - 0x6e, 0xe7, 0x25, 0x9a, 0xe7, 0xf2, 0x8f, 0x68, 0x7e, 0x13, 0xec, 0x2f, - 0xd5, 0xbc, 0x0f, 0xfc, 0x65, 0x9a, 0xe7, 0xbe, 0x7c, 0x44, 0xf3, 0x7b, - 0x20, 0x3f, 0xaa, 0x79, 0x6e, 0xcf, 0x31, 0xcd, 0x47, 0xc1, 0x5f, 0xae, - 0xf9, 0x23, 0xe0, 0x8f, 0x6b, 0xfe, 0x38, 0xf8, 0x2b, 0x34, 0x7f, 0xd2, - 0xc4, 0x9f, 0x02, 0x7f, 0x65, 0xb2, 0x0d, 0xe0, 0x3f, 0x9a, 0xac, 0x0b, - 0xfc, 0xc7, 0x35, 0x7f, 0xc6, 0x24, 0xbf, 0xdf, 0xc4, 0x3f, 0x04, 0xfe, - 0xa4, 0xe6, 0x1f, 0x35, 0xc9, 0x9f, 0x31, 0xf1, 0x2f, 0x9a, 0xf8, 0xb3, - 0x26, 0xbe, 0xd6, 0x54, 0xfe, 0x9b, 0xe0, 0xaf, 0xd6, 0xfc, 0x3b, 0xe0, - 0xaf, 0x49, 0x8e, 0x15, 0x02, 0xcf, 0x27, 0x34, 0x9f, 0x5d, 0x31, 0x9e, - 0x77, 0x7e, 0xc5, 0x78, 0xde, 0x62, 0x93, 0x7c, 0x85, 0x89, 0xaf, 0x02, - 0x7f, 0x55, 0xb2, 0x4c, 0x8c, 0xdb, 0xbf, 0x68, 0x7e, 0x8d, 0xc9, 0xe6, - 0xb8, 0x49, 0xde, 0x6c, 0x92, 0xb3, 0x8f, 0x9d, 0x48, 0xd6, 0x0b, 0xfe, - 0x5a, 0xcd, 0x77, 0x98, 0xea, 0xdd, 0x09, 0xfe, 0xba, 0xe4, 0x5c, 0x98, - 0xf2, 0xf2, 0xda, 0xfc, 0x98, 0xe6, 0x43, 0x26, 0xf9, 0x58, 0xc5, 0xb8, - 0xfc, 0xa8, 0xa9, 0x9c, 0x6b, 0xcc, 0xfd, 0x32, 0x8d, 0xcf, 0xf5, 0x90, - 0x7f, 0x52, 0xf3, 0x37, 0x83, 0xff, 0x57, 0xcd, 0xdf, 0x6a, 0xb2, 0xbf, - 0xcf, 0xc4, 0x3f, 0x58, 0xa1, 0xe2, 0x53, 0xbb, 0xf6, 0xb1, 0x1b, 0x34, - 0xcf, 0x7e, 0xf5, 0x29, 0xcd, 0xff, 0xa0, 0x62, 0x9c, 0x7f, 0x0a, 0xfc, - 0xa7, 0x35, 0xff, 0x22, 0xf8, 0x53, 0x9a, 0x67, 0x1f, 0xbb, 0x51, 0xf3, - 0x67, 0x21, 0xff, 0x8c, 0xe6, 0xdf, 0x06, 0x7f, 0xb3, 0xe6, 0xff, 0x06, - 0xfe, 0x26, 0xcd, 0x5b, 0x2b, 0xc7, 0xe5, 0x3c, 0xce, 0x9f, 0xd5, 0x7c, - 0x36, 0xe4, 0x9f, 0xd3, 0xfc, 0xfc, 0xca, 0x71, 0xfb, 0x31, 0x53, 0x5e, - 0xee, 0xef, 0xe7, 0x35, 0xcf, 0x7d, 0xcc, 0x41, 0x74, 0xfb, 0x3e, 0x29, - 0x7a, 0x29, 0x02, 0x5d, 0x2e, 0xe8, 0x08, 0xf1, 0xfa, 0xad, 0xa7, 0x07, - 0x35, 0x9d, 0x2b, 0x98, 0x0a, 0x9a, 0xaf, 0xe9, 0x02, 0x4d, 0x17, 0x6a, - 0xba, 0x48, 0x53, 0x8f, 0x50, 0xf6, 0x2b, 0x04, 0xef, 0x65, 0xcd, 0xf4, - 0x18, 0x31, 0xcd, 0xa7, 0x27, 0x25, 0xad, 0xa2, 0xb0, 0x94, 0x57, 0xd3, - 0x71, 0xc1, 0xfb, 0x5c, 0x3e, 0xfd, 0x1b, 0x31, 0x2d, 0xa3, 0x47, 0x24, - 0x55, 0xfa, 0x72, 0xad, 0xf7, 0x82, 0x5e, 0xac, 0x29, 0xa7, 0x2b, 0xd0, - 0xe2, 0xf3, 0x24, 0xad, 0xa4, 0x4b, 0x04, 0xef, 0x8d, 0x4a, 0x5f, 0xa9, - 0xf5, 0x95, 0xd0, 0x7c, 0x54, 0x70, 0xec, 0x32, 0x68, 0x9e, 0xe0, 0xb8, - 0x55, 0x4c, 0x0f, 0x10, 0xd3, 0x72, 0xfa, 0x81, 0xa4, 0x49, 0x79, 0x25, - 0x2d, 0x97, 0xd4, 0x4b, 0x15, 0x92, 0xb6, 0x53, 0x9b, 0xa4, 0x59, 0xd4, - 0x2e, 0x38, 0x66, 0xad, 0xa1, 0x51, 0xd8, 0xdb, 0xb0, 0x9b, 0x76, 0x0a, - 0x8e, 0xe5, 0x39, 0xf4, 0x3c, 0x31, 0x5d, 0x46, 0xff, 0x05, 0x9a, 0x89, - 0xf6, 0x3a, 0x25, 0xbd, 0x88, 0x7c, 0xd0, 0x3b, 0x11, 0xc1, 0x38, 0x9d, - 0xa5, 0xe5, 0x59, 0x18, 0xc1, 0xed, 0x82, 0xc7, 0x53, 0xa5, 0xf3, 0x51, - 0x6f, 0xa9, 0x60, 0xba, 0x93, 0xba, 0x24, 0xdd, 0x45, 0x17, 0x08, 0xde, - 0xc3, 0x32, 0xe9, 0x2f, 0xa4, 0xe8, 0x7b, 0x92, 0x6e, 0xa0, 0xdd, 0x90, - 0xcf, 0xc4, 0x4e, 0xcb, 0xf9, 0x0a, 0xb1, 0xc3, 0x32, 0x9d, 0x83, 0x1c, - 0x6f, 0x4a, 0xda, 0x4a, 0x5b, 0x04, 0xef, 0x47, 0x5e, 0x29, 0x9f, 0x8b, - 0x72, 0x7f, 0x2e, 0xe9, 0x39, 0xf4, 0xa2, 0x4e, 0xbf, 0xa5, 0xe9, 0xdf, - 0x89, 0xf7, 0x2a, 0xa5, 0x67, 0xfa, 0x0b, 0x4d, 0x9f, 0x93, 0xd4, 0x49, - 0xaf, 0xe9, 0xf4, 0x7f, 0x4a, 0x6a, 0xa1, 0x3f, 0x91, 0xda, 0xdb, 0xde, - 0xd1, 0xf4, 0xcf, 0x92, 0x0a, 0xb2, 0x0a, 0x45, 0x6d, 0x82, 0xf7, 0x9f, - 0x42, 0x7a, 0x9c, 0x98, 0x1a, 0xf4, 0x6b, 0x4d, 0xff, 0x5b, 0xd2, 0x26, - 0xb2, 0x48, 0x7d, 0x39, 0x5d, 0x04, 0xba, 0x10, 0x27, 0x10, 0x6e, 0xdf, - 0x42, 0xec, 0xfa, 0x0d, 0x32, 0x3d, 0x48, 0xeb, 0x25, 0xad, 0xa4, 0x66, - 0xc1, 0x71, 0x7b, 0x2b, 0x7d, 0x97, 0x14, 0xdd, 0x26, 0x78, 0xff, 0x70, - 0xd3, 0xaf, 0x88, 0x63, 0xbe, 0x41, 0xc3, 0x82, 0xf7, 0x90, 0x72, 0x2a, - 0xd4, 0xf4, 0x42, 0x4d, 0xf7, 0x0a, 0xde, 0x0f, 0xfd, 0x74, 0x8e, 0xe0, - 0xfd, 0x60, 0xb3, 0x2c, 0x7f, 0x29, 0x46, 0xa4, 0x52, 0xa6, 0xcb, 0x68, - 0xab, 0xe0, 0x3d, 0x40, 0x8d, 0xf7, 0x39, 0x38, 0xc9, 0x28, 0x5a, 0x46, - 0x3f, 0x92, 0x34, 0x83, 0x5e, 0xd6, 0xf4, 0x97, 0x92, 0xba, 0xe8, 0x55, - 0xe2, 0xbd, 0x24, 0x48, 0x73, 0x04, 0xd3, 0x0e, 0xea, 0x96, 0xf4, 0x00, - 0x0d, 0x09, 0x3e, 0x8f, 0xa9, 0x72, 0xce, 0x83, 0x27, 0xd9, 0x05, 0x9f, - 0xcd, 0x54, 0x7a, 0x85, 0x4e, 0x97, 0xea, 0x74, 0xa9, 0x4e, 0x97, 0xe1, - 0x94, 0xe4, 0x24, 0xe5, 0xef, 0xdf, 0x93, 0x74, 0x07, 0x3d, 0x2c, 0xe9, - 0x0a, 0xfa, 0x1f, 0x49, 0x37, 0x52, 0x8b, 0xb4, 0xdb, 0x44, 0x1b, 0x84, - 0x4a, 0x6f, 0x14, 0xca, 0x6e, 0x93, 0xa4, 0x2d, 0x74, 0x99, 0xa6, 0x1f, - 0xd1, 0xf4, 0xa8, 0xa6, 0xc7, 0xe4, 0x7a, 0xd8, 0x2e, 0xcb, 0x2f, 0xd7, - 0xfd, 0x29, 0xd7, 0xed, 0x2f, 0xc7, 0x49, 0x69, 0x97, 0x5c, 0x1f, 0x3e, - 0xa9, 0xf7, 0xe2, 0x64, 0xf3, 0xb8, 0xa4, 0xa5, 0xf4, 0x53, 0x9d, 0x7e, - 0x5a, 0xd2, 0x01, 0xea, 0x90, 0xeb, 0x66, 0x9b, 0xb4, 0xab, 0x40, 0x39, - 0xe7, 0xcb, 0xf5, 0xa2, 0xf2, 0x55, 0x42, 0x7e, 0x87, 0xa6, 0x5f, 0x92, - 0x74, 0x21, 0xdd, 0x29, 0x69, 0x19, 0x05, 0x85, 0xa2, 0xfb, 0x05, 0x9f, - 0x43, 0x55, 0x7f, 0xab, 0xc0, 0x71, 0x3e, 0x5e, 0x67, 0xff, 0x57, 0x52, - 0x07, 0xbd, 0xa0, 0xd3, 0xbf, 0xd1, 0xf4, 0x0d, 0x4d, 0xff, 0x20, 0x69, - 0x09, 0xfd, 0x55, 0xa7, 0xff, 0x26, 0x69, 0x1f, 0x15, 0xc9, 0x72, 0xfc, - 0xb4, 0x4c, 0x52, 0x2f, 0xed, 0x94, 0x74, 0x37, 0xf9, 0xe5, 0x3a, 0xac, - 0x22, 0x2b, 0x29, 0x6a, 0xd3, 0xd4, 0x2e, 0x69, 0x83, 0xac, 0xb7, 0x1a, - 0x27, 0xc9, 0x5b, 0x25, 0xb5, 0xd1, 0x6d, 0x92, 0xae, 0xa6, 0xdb, 0x25, - 0xcd, 0xa6, 0x2f, 0x4b, 0xda, 0x45, 0x5f, 0x91, 0x74, 0x06, 0xdd, 0x25, - 0xe9, 0x30, 0xdd, 0x2d, 0xe9, 0x12, 0xfa, 0xaa, 0xa6, 0x5f, 0xd3, 0xf9, - 0xcf, 0x48, 0x1a, 0xa2, 0x7b, 0x24, 0xad, 0xa6, 0x7b, 0x25, 0x3d, 0x97, - 0xbe, 0x2e, 0x69, 0x1d, 0xdd, 0xa7, 0xed, 0xbe, 0xa1, 0xe9, 0xff, 0x91, - 0xd4, 0x4e, 0xdf, 0xd4, 0xe9, 0xfb, 0x25, 0x2d, 0xa3, 0x87, 0x34, 0xfd, - 0xa1, 0xa6, 0x8f, 0x4a, 0xda, 0x4f, 0xff, 0x2e, 0xe9, 0x4a, 0x7a, 0x42, - 0xd2, 0x7a, 0xfa, 0x99, 0xa4, 0x45, 0xf4, 0x8c, 0xa4, 0x73, 0xe9, 0x59, - 0x49, 0x73, 0xe8, 0x15, 0x49, 0x17, 0xd0, 0x59, 0x52, 0x71, 0xe8, 0x75, - 0x1d, 0xaf, 0x7e, 0xad, 0xed, 0x7f, 0x2b, 0xe9, 0x7c, 0xfa, 0x9d, 0xa4, - 0x16, 0xfa, 0xbd, 0xa4, 0x7b, 0xe8, 0x3f, 0x24, 0x2d, 0xa0, 0x3f, 0x4a, - 0xea, 0xa6, 0x77, 0x25, 0x9d, 0x49, 0xef, 0xeb, 0xfc, 0x24, 0xc7, 0x73, - 0x16, 0x09, 0x49, 0xf3, 0xc8, 0x90, 0x54, 0xad, 0x57, 0x1e, 0x57, 0x87, - 0x50, 0xed, 0xcb, 0xd0, 0x34, 0x53, 0x53, 0xa7, 0xa4, 0x35, 0x94, 0x25, - 0xe9, 0x2a, 0xca, 0x16, 0x6a, 0x7c, 0x72, 0xb4, 0x3e, 0x57, 0xe7, 0xcf, - 0xd3, 0xd4, 0xa5, 0x69, 0xbe, 0xa4, 0x6d, 0xe4, 0x96, 0xb4, 0x96, 0x0a, - 0x24, 0xdd, 0x47, 0x33, 0xb4, 0x7c, 0xa6, 0x50, 0xe3, 0x33, 0x5b, 0x52, - 0x3f, 0x2d, 0xd5, 0xb4, 0x44, 0xd2, 0xb5, 0x54, 0x25, 0xe9, 0x1a, 0xaa, - 0xd6, 0x74, 0x95, 0xa6, 0x35, 0x5a, 0x5f, 0xab, 0xd3, 0x75, 0x9a, 0xae, - 0x96, 0x74, 0x1e, 0xd5, 0x4b, 0xba, 0x9e, 0xd6, 0x48, 0xba, 0x85, 0xd6, - 0x4a, 0xba, 0x9f, 0xd6, 0x49, 0xaa, 0xe2, 0x50, 0xb5, 0x8e, 0x43, 0x9c, - 0x6e, 0x94, 0xf4, 0x42, 0x6a, 0xd2, 0xfb, 0x41, 0xb3, 0xb6, 0x6f, 0x95, - 0x74, 0x88, 0x36, 0x4b, 0x7a, 0x01, 0xf5, 0x68, 0xba, 0x43, 0xef, 0x13, - 0x7d, 0x92, 0x76, 0xd2, 0x1e, 0x49, 0xfb, 0xa8, 0x5f, 0xa8, 0xfd, 0x65, - 0x40, 0xdb, 0x0d, 0x6a, 0x1a, 0x90, 0xb4, 0x82, 0xf6, 0x09, 0xe5, 0x27, - 0x11, 0xa1, 0xfc, 0x26, 0xaa, 0xd3, 0x07, 0x35, 0x8d, 0x69, 0x1a, 0x17, - 0xca, 0xef, 0x12, 0x3a, 0x3d, 0x22, 0x94, 0xff, 0x8d, 0x0a, 0xe5, 0xef, - 0x87, 0xf4, 0xf8, 0x8f, 0x09, 0xe5, 0xef, 0x87, 0xf5, 0x3c, 0x5c, 0x29, - 0xf8, 0x4c, 0xbe, 0x88, 0x0e, 0x48, 0x7a, 0x0e, 0x1d, 0x11, 0x7c, 0x2e, - 0x5f, 0x4e, 0x6f, 0x13, 0xef, 0x63, 0x06, 0x2d, 0x91, 0xfb, 0xd9, 0x62, - 0xba, 0x42, 0xf0, 0x39, 0x5b, 0xc5, 0xad, 0x46, 0x44, 0xde, 0x97, 0x24, - 0x55, 0xf6, 0xcd, 0xf0, 0xa7, 0x1f, 0x13, 0x53, 0x2b, 0xfd, 0x44, 0xd2, - 0x08, 0x3d, 0x25, 0xa9, 0xda, 0xb7, 0x58, 0xbe, 0x52, 0xd2, 0x12, 0x0a, - 0x09, 0x3e, 0x7f, 0x2f, 0xa5, 0x62, 0xc1, 0x77, 0x49, 0x55, 0xde, 0x46, - 0xdc, 0xdc, 0xbe, 0x23, 0xe9, 0x79, 0x74, 0xae, 0xe0, 0x33, 0xb9, 0x9f, - 0x66, 0x49, 0x5a, 0x4c, 0x5e, 0xa1, 0xee, 0xaf, 0xbc, 0x80, 0x93, 0xe7, - 0xff, 0x3c, 0x7e, 0xe0, 0x62, 0xf9, 0xc8, 0x56, 0x95, 0xe6, 0xfb, 0x6f, - 0xbe, 0x4b, 0xe9, 0x13, 0xe5, 0xe3, 0xf7, 0xa2, 0xc7, 0xb5, 0x7e, 0xc5, - 0x34, 0xfa, 0x17, 0xb4, 0xbe, 0x74, 0x1a, 0xfd, 0x6f, 0xb5, 0x9e, 0xef, - 0xd4, 0x2e, 0x52, 0xfa, 0x23, 0xe5, 0xaa, 0x7e, 0x17, 0xea, 0xff, 0x8b, - 0xd6, 0x97, 0x6b, 0xfd, 0x39, 0xa6, 0xf6, 0x95, 0x40, 0x5f, 0xdd, 0xa9, - 0xd2, 0x5e, 0xad, 0x5f, 0x66, 0xd2, 0xd7, 0x42, 0xbf, 0x55, 0xeb, 0x2b, - 0xb4, 0x9c, 0xcb, 0x3f, 0xae, 0xcb, 0xdf, 0x09, 0x7d, 0x58, 0xeb, 0x2b, - 0x4d, 0xf5, 0x27, 0xf3, 0x47, 0xa1, 0x3f, 0xa6, 0xf5, 0x7c, 0xd7, 0x12, - 0x13, 0xf4, 0x57, 0x43, 0x7f, 0xa7, 0xd6, 0xf3, 0xfd, 0x8b, 0xfb, 0xb4, - 0x10, 0xb8, 0x46, 0x97, 0x7f, 0x1a, 0xfa, 0x5f, 0x69, 0xbd, 0x90, 0x7f, - 0x44, 0x8f, 0x61, 0xa0, 0x38, 0x6e, 0x46, 0x5d, 0x1c, 0x95, 0x73, 0xb1, - 0xdb, 0x65, 0x20, 0x32, 0xe3, 0xcc, 0xa9, 0xe5, 0x87, 0x1c, 0x07, 0x61, - 0x97, 0xfb, 0x4f, 0xd8, 0x47, 0xfe, 0x49, 0xfb, 0xa8, 0xb4, 0xb7, 0xe3, - 0x69, 0x41, 0xfa, 0xf9, 0x15, 0xaa, 0xef, 0x07, 0x5d, 0xab, 0xe1, 0xd1, - 0x4e, 0xd0, 0x3a, 0xa6, 0x62, 0x35, 0x9f, 0x10, 0x85, 0x85, 0x4a, 0x8a, - 0xc3, 0xae, 0x17, 0x21, 0xc9, 0xb6, 0x15, 0x19, 0x1b, 0x51, 0xea, 0x59, - 0xf8, 0x5b, 0x91, 0xa5, 0x90, 0xdc, 0xd6, 0xb0, 0xf7, 0x65, 0xec, 0x7d, - 0x9c, 0x83, 0xcf, 0x5d, 0xd9, 0x24, 0xd3, 0xc2, 0x69, 0xe3, 0x34, 0xdb, - 0x47, 0xbd, 0x2e, 0xb2, 0xd8, 0xc2, 0x9e, 0xd7, 0x51, 0x7e, 0xbe, 0xe1, - 0xb6, 0xe5, 0xdb, 0xac, 0x68, 0x01, 0xdf, 0xbf, 0x5f, 0x5b, 0xc1, 0xe7, - 0xae, 0x64, 0x1b, 0xfb, 0x44, 0x2e, 0xf5, 0x19, 0xd9, 0xd4, 0x67, 0xc9, - 0xa1, 0x83, 0x9e, 0xcd, 0xb0, 0xce, 0x25, 0xbe, 0xa7, 0x27, 0x6f, 0xf0, - 0x6a, 0xdc, 0x59, 0x66, 0xc3, 0x1f, 0xf3, 0x6f, 0x21, 0x3f, 0xf7, 0x29, - 0xe6, 0xfa, 0x39, 0xd2, 0xd9, 0xa2, 0x4f, 0x64, 0xa5, 0xf4, 0x9c, 0xeb, - 0xbd, 0x15, 0xea, 0x3e, 0xef, 0x13, 0xd9, 0xe4, 0x33, 0xb8, 0xd4, 0xad, - 0x58, 0x5d, 0xb9, 0xc8, 0xe3, 0x90, 0x7a, 0x51, 0x3a, 0xb5, 0x3e, 0x99, - 0x3f, 0x7b, 0x1a, 0x7d, 0x26, 0xf4, 0x3c, 0x66, 0x33, 0x4b, 0xd5, 0xfb, - 0x10, 0x5f, 0x43, 0x36, 0xad, 0xec, 0x0c, 0x82, 0x66, 0x21, 0x0a, 0x60, - 0xac, 0x06, 0xce, 0x0c, 0xc5, 0xbc, 0xcf, 0x52, 0x20, 0x23, 0xdb, 0xc6, - 0x6d, 0xe3, 0x51, 0x98, 0x9b, 0x61, 0x50, 0xd8, 0xf3, 0x4b, 0xdc, 0x23, - 0x9d, 0x19, 0x6e, 0xaa, 0xcb, 0xc8, 0xa1, 0xb9, 0x19, 0x96, 0x94, 0xa4, - 0x16, 0x7c, 0x89, 0x45, 0x64, 0x94, 0x58, 0x0a, 0x32, 0x1a, 0x71, 0x7e, - 0x17, 0x52, 0x33, 0x13, 0xe3, 0x5f, 0x2b, 0xac, 0x54, 0x90, 0xb1, 0x96, - 0x7c, 0xeb, 0x73, 0xc8, 0xd7, 0x98, 0x25, 0x47, 0xd7, 0xb0, 0x3b, 0x0d, - 0x5f, 0x53, 0x16, 0x9d, 0x19, 0xe5, 0x94, 0xc5, 0xee, 0xb4, 0x87, 0xbd, - 0xc3, 0xb4, 0xd8, 0xee, 0xdb, 0x90, 0x43, 0xb5, 0x19, 0x98, 0x01, 0xd7, - 0x2b, 0x3c, 0x77, 0x8e, 0xe7, 0x1c, 0x8e, 0xf7, 0xc3, 0xde, 0x57, 0xc9, - 0xe6, 0xc8, 0xc6, 0xf8, 0x1f, 0xc0, 0x49, 0x95, 0xb5, 0xbe, 0x96, 0x5c, - 0x2a, 0xb2, 0xcf, 0xc5, 0x2d, 0xb8, 0x80, 0xec, 0x19, 0x61, 0xef, 0xb7, - 0xe8, 0x4a, 0xbb, 0xaf, 0x05, 0xf2, 0x0d, 0xaa, 0x87, 0x01, 0x72, 0xdb, - 0xfa, 0x5a, 0xb2, 0xe4, 0x38, 0x18, 0xb2, 0x9f, 0x2b, 0x4a, 0x95, 0x3f, - 0x87, 0x5d, 0x7b, 0x31, 0x73, 0x4e, 0xd0, 0x7d, 0x4c, 0xad, 0xab, 0xd1, - 0xc2, 0x7a, 0x2b, 0x5a, 0x9e, 0xcf, 0xbe, 0x61, 0xc1, 0x0c, 0xb8, 0x8d, - 0xb0, 0xf7, 0x57, 0x18, 0x23, 0xd8, 0x30, 0xb5, 0x3a, 0xad, 0x07, 0xbd, - 0xb9, 0x64, 0xb1, 0xe6, 0xca, 0x79, 0xe4, 0x31, 0xad, 0xd5, 0x63, 0x7a, - 0xd0, 0xb5, 0x49, 0x79, 0x8b, 0x27, 0x2c, 0xfd, 0x30, 0xa9, 0x5f, 0x57, - 0xaa, 0xe6, 0xf4, 0xa0, 0xa7, 0x13, 0xeb, 0xf0, 0xa0, 0x67, 0x0b, 0x9e, - 0x6a, 0x4e, 0x55, 0x5b, 0x36, 0xea, 0xb6, 0x1c, 0x74, 0xe5, 0x20, 0xcd, - 0x5e, 0x97, 0xcd, 0x54, 0xc8, 0xb6, 0x08, 0x53, 0x5b, 0x2c, 0xdc, 0x96, - 0x97, 0x71, 0x7a, 0x70, 0xca, 0x31, 0x5b, 0x22, 0x9c, 0x16, 0x1e, 0x25, - 0xab, 0x45, 0xf9, 0x3c, 0x9f, 0x55, 0xba, 0x4b, 0xd5, 0x7b, 0x38, 0x5f, - 0x67, 0x1e, 0x76, 0x3f, 0x0b, 0xd6, 0xad, 0xaf, 0x33, 0x1f, 0x33, 0x98, - 0x49, 0x11, 0x57, 0x3d, 0xcf, 0x1a, 0xf5, 0x41, 0x93, 0x8f, 0xfe, 0xf2, - 0xdb, 0x2f, 0x27, 0xf9, 0xb6, 0xe5, 0x13, 0x97, 0x1a, 0x44, 0x0f, 0xb3, - 0x71, 0x2a, 0x9a, 0x49, 0x51, 0x4f, 0x1e, 0xca, 0xea, 0xdb, 0x96, 0x87, - 0x5d, 0xbf, 0x0c, 0x7a, 0x37, 0xf9, 0xba, 0xf3, 0xc8, 0xe7, 0xcb, 0xa7, - 0x68, 0x43, 0x0b, 0xb9, 0x9a, 0xfa, 0x3a, 0x5d, 0x90, 0xe6, 0xc1, 0x43, - 0x33, 0x61, 0xe7, 0xb4, 0x14, 0x58, 0xdd, 0x14, 0xf3, 0x65, 0x91, 0xa8, - 0xf4, 0xc9, 0x92, 0x79, 0x2d, 0x5a, 0x65, 0xbf, 0xf6, 0xe8, 0x71, 0x89, - 0x7a, 0x6b, 0xc8, 0x65, 0xf4, 0x09, 0x37, 0xd6, 0x41, 0x3e, 0x7a, 0x6e, - 0x41, 0x3e, 0x1e, 0x97, 0xfd, 0xba, 0xdf, 0x3e, 0x0f, 0xb7, 0x35, 0x93, - 0x7c, 0x8b, 0x5d, 0xd8, 0x5f, 0xb1, 0x27, 0x79, 0x9c, 0x18, 0x21, 0x58, - 0x43, 0xde, 0xe7, 0xc9, 0x47, 0xcb, 0x6b, 0x61, 0xbf, 0x07, 0x28, 0x10, - 0x8b, 0xa8, 0xca, 0x65, 0x87, 0x2e, 0xec, 0xf1, 0x21, 0xcd, 0x31, 0xc0, - 0x90, 0xfd, 0x1e, 0x29, 0x55, 0xef, 0x62, 0x7c, 0x7b, 0x0a, 0x30, 0x7e, - 0x7c, 0x7b, 0xca, 0xa2, 0x59, 0x86, 0x8c, 0x8d, 0x86, 0x5b, 0xb0, 0x07, - 0xe7, 0x0b, 0x93, 0xce, 0x38, 0xd8, 0x30, 0x46, 0x9e, 0x78, 0x36, 0xea, - 0x75, 0x60, 0x2c, 0xf8, 0x6d, 0x4f, 0xb6, 0x23, 0xdf, 0x21, 0xeb, 0x30, - 0x16, 0x52, 0x15, 0x5a, 0x50, 0x84, 0x5d, 0xc6, 0x37, 0x30, 0x03, 0xad, - 0x5f, 0x49, 0x5e, 0x47, 0x89, 0xc3, 0xb7, 0x67, 0x06, 0xe6, 0xae, 0x0a, - 0x67, 0x5e, 0xf8, 0xd5, 0x80, 0x2a, 0xc9, 0x42, 0x59, 0xd6, 0x83, 0x9d, - 0x87, 0xa9, 0x69, 0xc4, 0xe9, 0xa8, 0x73, 0x38, 0x69, 0x8f, 0xc3, 0xa0, - 0xea, 0x73, 0x6c, 0x28, 0x51, 0xc6, 0x4c, 0x91, 0x8f, 0x79, 0x51, 0x73, - 0x7c, 0x45, 0xa9, 0x8a, 0x45, 0xbe, 0x86, 0xe9, 0xdb, 0xe7, 0x76, 0xad, - 0xb4, 0x61, 0x45, 0xb4, 0x28, 0x0b, 0x1b, 0xb7, 0xd2, 0x7b, 0x31, 0x2d, - 0xb5, 0x64, 0xdb, 0x4a, 0xb2, 0xd2, 0xa5, 0x97, 0x48, 0x69, 0xad, 0x0d, - 0x6b, 0xc7, 0xf5, 0x1c, 0xaf, 0x0b, 0xac, 0x85, 0x1e, 0x9c, 0xa6, 0xb3, - 0x11, 0x89, 0xf2, 0x85, 0x13, 0xe3, 0xcf, 0xe7, 0xd5, 0x6b, 0x4b, 0xd5, - 0x3b, 0xc2, 0xa9, 0xc6, 0xa4, 0x0e, 0x36, 0x6e, 0x47, 0x9e, 0xc3, 0xa4, - 0x13, 0x22, 0x2e, 0x8e, 0x3b, 0x6e, 0x38, 0x64, 0xe7, 0x77, 0x50, 0x4e, - 0xe8, 0x2c, 0x72, 0xa6, 0x88, 0x3e, 0x5d, 0xaa, 0xde, 0x27, 0x16, 0x09, - 0x15, 0x25, 0x05, 0xda, 0x9a, 0xd4, 0x7d, 0x4e, 0xcf, 0x71, 0x9f, 0x28, - 0x80, 0x8e, 0xdf, 0x0e, 0xf7, 0x19, 0x33, 0xb4, 0xef, 0xb3, 0xfe, 0xf6, - 0x52, 0xbe, 0xa7, 0xb2, 0x7e, 0x96, 0x8e, 0x89, 0x6e, 0xb1, 0x1b, 0x5e, - 0xc6, 0xfe, 0x9f, 0x8c, 0xd3, 0x77, 0x97, 0xaa, 0x77, 0xbb, 0x45, 0x88, - 0x9c, 0x51, 0x97, 0x8c, 0x4e, 0xdb, 0x66, 0x91, 0x2f, 0xbf, 0x10, 0xbd, - 0xfb, 0x94, 0x8c, 0x82, 0x75, 0xc8, 0x9d, 0x92, 0x79, 0x6e, 0x82, 0x6c, - 0xdc, 0xe2, 0x24, 0x7b, 0xa1, 0xe8, 0x32, 0xf8, 0x7d, 0xb1, 0xa0, 0x92, - 0xec, 0xb0, 0x67, 0x29, 0x68, 0xd8, 0xb5, 0x24, 0x4d, 0x7e, 0x8f, 0x71, - 0xcf, 0xe2, 0x02, 0x9c, 0xc7, 0xab, 0xc5, 0x5c, 0xda, 0xde, 0x35, 0x93, - 0x6a, 0x8d, 0x59, 0xf0, 0xfb, 0xdd, 0xe0, 0x7c, 0x5d, 0x28, 0xa9, 0xa8, - 0x10, 0x5e, 0x3e, 0x0b, 0x23, 0x71, 0x91, 0x5c, 0x67, 0x7a, 0x6e, 0x2d, - 0x07, 0xbd, 0x87, 0xa8, 0xd2, 0xca, 0xf6, 0x75, 0x86, 0x03, 0x67, 0x40, - 0x1b, 0xb9, 0x5d, 0xbb, 0x3b, 0x67, 0xea, 0x3d, 0x89, 0xff, 0x7d, 0x17, - 0x6d, 0xe7, 0x3e, 0xf8, 0x70, 0xd7, 0x61, 0xdf, 0xe7, 0x71, 0x61, 0xdf, - 0xfe, 0x41, 0xa9, 0xda, 0x27, 0xfb, 0x44, 0xa1, 0xee, 0x77, 0x91, 0xa8, - 0xc0, 0xda, 0xea, 0xe5, 0xb5, 0x25, 0xe6, 0x60, 0x94, 0x66, 0xcb, 0x31, - 0x48, 0xee, 0x6d, 0x5c, 0x8e, 0xda, 0xdb, 0xf6, 0x10, 0x99, 0xf6, 0xbc, - 0x71, 0xb9, 0x5f, 0xca, 0x93, 0x6b, 0xe7, 0xa7, 0xa5, 0x1c, 0x69, 0x78, - 0xed, 0xcc, 0x46, 0x5f, 0x3f, 0x2d, 0xe3, 0x8e, 0x6f, 0xf1, 0x1c, 0x8c, - 0xce, 0x79, 0x32, 0xba, 0x24, 0xed, 0x7e, 0x3e, 0xad, 0xdd, 0x8a, 0x34, - 0xbb, 0x17, 0x74, 0x8c, 0xea, 0xf6, 0xcc, 0x85, 0x97, 0xc7, 0xa1, 0x73, - 0xca, 0xf6, 0x27, 0xf5, 0xaf, 0xa4, 0xe9, 0x8f, 0xa5, 0xf4, 0x56, 0xed, - 0xdf, 0xaf, 0x9b, 0xf5, 0xde, 0x2b, 0xc8, 0x65, 0x71, 0x5a, 0xf2, 0x2c, - 0xe3, 0xf9, 0x7f, 0x9f, 0x96, 0x3f, 0x31, 0xa9, 0xfc, 0xb7, 0xd3, 0xf4, - 0x47, 0x26, 0xe9, 0xff, 0x9c, 0xa6, 0x3f, 0x3e, 0x49, 0xff, 0xdf, 0x69, - 0xfa, 0xcb, 0x53, 0x7a, 0xde, 0xd5, 0x78, 0xfc, 0xde, 0x37, 0xeb, 0x1b, - 0x3e, 0x82, 0x38, 0x96, 0x6d, 0xc9, 0xb7, 0xa8, 0xf9, 0xe2, 0x71, 0xb6, - 0x97, 0x29, 0x1f, 0x57, 0x73, 0xd5, 0x0b, 0x2f, 0xc9, 0x4d, 0xf5, 0x2d, - 0x5b, 0xeb, 0x54, 0xdf, 0x8e, 0xa2, 0x6f, 0xb9, 0xa9, 0x72, 0xdd, 0x66, - 0x5d, 0xc3, 0x65, 0x28, 0x77, 0x3c, 0xdf, 0x9c, 0xb4, 0x7c, 0x23, 0x32, - 0x9f, 0x55, 0xfe, 0x11, 0x2d, 0x2a, 0x23, 0x19, 0xb7, 0xa2, 0x0d, 0x37, - 0x90, 0xab, 0x32, 0x5b, 0xfa, 0x8e, 0xa1, 0x7d, 0x6a, 0x59, 0x99, 0xf6, - 0x29, 0xd7, 0x22, 0x29, 0xe7, 0x9d, 0x9d, 0xf3, 0x9c, 0x57, 0xa6, 0x62, - 0x7b, 0x77, 0xe7, 0x02, 0x44, 0xa5, 0x6b, 0xc9, 0x86, 0x3d, 0x9c, 0xdf, - 0x8b, 0xf5, 0xf9, 0x2d, 0x00, 0xd6, 0xb3, 0xb1, 0xab, 0x1f, 0xb1, 0xf1, - 0x4f, 0x2a, 0xa6, 0xf1, 0xa7, 0x1d, 0x4e, 0x6b, 0x89, 0x21, 0xaa, 0x76, - 0x0d, 0x66, 0x20, 0xce, 0xd9, 0xe5, 0x1e, 0x07, 0x99, 0x65, 0xd7, 0x80, - 0x03, 0xf6, 0x4e, 0xbe, 0x0b, 0x75, 0xee, 0xf2, 0xdb, 0xa0, 0xe3, 0xfd, - 0x8f, 0x3f, 0x15, 0x71, 0x8a, 0x83, 0xae, 0x7f, 0xe5, 0x75, 0x83, 0x92, - 0x32, 0xb1, 0xa3, 0x96, 0x93, 0x3b, 0x3f, 0xda, 0xb0, 0x0d, 0xb7, 0x90, - 0xbe, 0x9e, 0xf9, 0x94, 0x6f, 0x1f, 0x1f, 0xef, 0xfa, 0x32, 0x75, 0xce, - 0x09, 0xbb, 0x3e, 0x81, 0x34, 0xb7, 0x63, 0xb1, 0x08, 0x7b, 0x0c, 0x8c, - 0x7b, 0x36, 0x6e, 0x03, 0xcb, 0x75, 0x7f, 0xd4, 0xfe, 0xd7, 0xa0, 0xfb, - 0x7a, 0xd0, 0xf3, 0x53, 0xd3, 0xbc, 0xd8, 0xa4, 0xac, 0x25, 0x39, 0x0e, - 0xbe, 0xef, 0x61, 0x1c, 0x94, 0xce, 0x2e, 0xff, 0x88, 0x36, 0x6b, 0xdd, - 0xa8, 0xfd, 0x4e, 0xb9, 0x57, 0xe5, 0xe9, 0xf5, 0x95, 0xfc, 0xc7, 0x65, - 0xbb, 0xf3, 0xf3, 0x44, 0x72, 0xdc, 0x7a, 0xf4, 0xb8, 0x6d, 0x77, 0x79, - 0xa4, 0xad, 0xa1, 0xd7, 0x50, 0x5f, 0x19, 0xc9, 0x7b, 0x42, 0xd8, 0x75, - 0x8a, 0xfb, 0x46, 0x32, 0xf6, 0xb9, 0xf2, 0xb0, 0x8b, 0xe4, 0x21, 0x65, - 0x48, 0xbf, 0xd8, 0x53, 0xa6, 0x3e, 0x47, 0xf0, 0x1d, 0x9d, 0x07, 0xbb, - 0x4a, 0x59, 0x5f, 0x2d, 0xcd, 0xa1, 0xee, 0x63, 0x0b, 0x90, 0x9e, 0x8b, - 0x18, 0x86, 0xbd, 0xd6, 0xb5, 0x90, 0xa9, 0x35, 0x8c, 0x79, 0xc9, 0xe4, - 0x98, 0xeb, 0x9a, 0x07, 0x9a, 0x65, 0x3f, 0xe4, 0xb8, 0x19, 0xe5, 0xba, - 0xe7, 0xe4, 0x65, 0xba, 0x33, 0xf3, 0x32, 0x39, 0xca, 0x5a, 0x64, 0xfb, - 0xf7, 0x95, 0xa9, 0xbb, 0x47, 0xf7, 0xd1, 0x05, 0xe9, 0x71, 0x17, 0x56, - 0x61, 0xd7, 0x55, 0x88, 0x9b, 0xee, 0x06, 0x77, 0x7e, 0x65, 0xa6, 0x07, - 0xf7, 0xe7, 0xd9, 0x54, 0x99, 0x39, 0x0b, 0x74, 0x0e, 0xa8, 0x9b, 0xba, - 0xaf, 0xe0, 0x5a, 0x0b, 0xd1, 0x06, 0x9c, 0x83, 0x5c, 0xb3, 0x98, 0x3a, - 0x1c, 0x97, 0x8b, 0x1b, 0x46, 0xed, 0x5f, 0x40, 0x7b, 0xf3, 0x84, 0xb8, - 0x21, 0xe2, 0x2d, 0xa1, 0x9d, 0x4e, 0xa7, 0x2c, 0xe9, 0x4a, 0x94, 0xc4, - 0xf7, 0xe0, 0x6c, 0x1d, 0xf7, 0x0f, 0x97, 0xa9, 0xcf, 0x3d, 0xcc, 0xf5, - 0xaa, 0x3d, 0x26, 0x4f, 0xd4, 0x65, 0x7a, 0xd5, 0x4e, 0x6a, 0x2c, 0xa0, - 0x6a, 0x0f, 0xcf, 0xfb, 0x0c, 0xb4, 0xd7, 0x49, 0xee, 0x25, 0x95, 0x5e, - 0x9c, 0x34, 0x16, 0xef, 0x71, 0x62, 0x07, 0x5b, 0xce, 0xb5, 0xcf, 0x84, - 0x3c, 0xdb, 0x59, 0xeb, 0x2c, 0x4c, 0xf1, 0x61, 0xcf, 0x4b, 0x34, 0x17, - 0x2d, 0x52, 0xad, 0x9b, 0xc5, 0xf9, 0x4c, 0xad, 0xe2, 0xfe, 0xcb, 0x96, - 0x35, 0x9c, 0x4b, 0x3b, 0xbf, 0xcd, 0x2d, 0x73, 0xa0, 0x46, 0x9e, 0xbf, - 0x13, 0x65, 0xea, 0x33, 0xb2, 0xee, 0x06, 0xdd, 0x1e, 0xb8, 0x45, 0x9d, - 0x81, 0x71, 0xb0, 0xe5, 0xd9, 0xb8, 0x97, 0x76, 0x94, 0x19, 0xed, 0xf9, - 0x22, 0x59, 0xb7, 0xb9, 0x67, 0xe6, 0xd9, 0xb8, 0x1f, 0x6a, 0x4e, 0x3e, - 0x59, 0xa6, 0x3e, 0x93, 0xeb, 0x3e, 0x3d, 0xb9, 0x1f, 0x61, 0xd7, 0x6c, - 0xd9, 0x6e, 0x9e, 0x83, 0x2c, 0xca, 0x72, 0x3c, 0x4b, 0xef, 0xa3, 0x05, - 0xb5, 0xb8, 0x03, 0x56, 0x9e, 0x5c, 0x49, 0xee, 0xa2, 0x4a, 0xcf, 0x39, - 0xe4, 0xae, 0xac, 0xf4, 0xcc, 0x23, 0x77, 0x57, 0x25, 0xce, 0x11, 0xee, - 0xfe, 0x4a, 0x0f, 0xe7, 0x2b, 0xc2, 0x6d, 0x2f, 0xea, 0xe2, 0x4f, 0x28, - 0xc3, 0xde, 0x2f, 0xd3, 0xb7, 0x29, 0x2f, 0xb3, 0x08, 0xf7, 0xb7, 0xa8, - 0xab, 0x29, 0x4d, 0x32, 0x6e, 0x73, 0x87, 0x96, 0xac, 0x80, 0x64, 0xbd, - 0x49, 0xd2, 0xfd, 0x45, 0x8c, 0x81, 0x67, 0x01, 0xbf, 0xcb, 0xb4, 0xb2, - 0x5f, 0x64, 0x49, 0x7f, 0x58, 0xc4, 0x14, 0xfe, 0x70, 0x3b, 0xcf, 0xd2, - 0x87, 0xd8, 0xdc, 0x2a, 0x6d, 0x6c, 0xda, 0xa3, 0xbf, 0x5c, 0xa6, 0x3e, - 0x53, 0x8c, 0x7a, 0xff, 0x05, 0x3b, 0x4e, 0x96, 0x85, 0x3f, 0x3b, 0xac, - 0x80, 0xa6, 0x16, 0x73, 0x5b, 0x84, 0x1b, 0x5a, 0xd4, 0x3b, 0x40, 0x5e, - 0x2b, 0xce, 0x6a, 0x88, 0x5a, 0x93, 0xd7, 0xd5, 0xbf, 0xa7, 0xd6, 0xd5, - 0x64, 0xdd, 0x63, 0x1f, 0xa0, 0xfb, 0xf1, 0x07, 0xe8, 0x9e, 0x34, 0xc5, - 0x58, 0xd5, 0xc6, 0x7b, 0x92, 0x3a, 0xef, 0x4f, 0x70, 0x9e, 0x9b, 0x2e, - 0xdf, 0xe3, 0xa9, 0x7c, 0xc9, 0x3d, 0x92, 0xff, 0xf1, 0x1d, 0xf8, 0x3c, - 0x79, 0x1a, 0xe1, 0x55, 0x37, 0x83, 0x8e, 0xb1, 0xcf, 0x92, 0xdb, 0xcb, - 0xfc, 0x62, 0xc9, 0xcf, 0x40, 0xcc, 0x60, 0x5a, 0x40, 0x06, 0xcf, 0x97, - 0x87, 0x25, 0x42, 0x95, 0x24, 0x1c, 0xb2, 0x0c, 0xfe, 0xdc, 0x94, 0xc7, - 0x85, 0x7d, 0x89, 0xcb, 0xe7, 0xef, 0x3c, 0x65, 0x92, 0xaa, 0x77, 0x62, - 0x1b, 0xa3, 0xde, 0xeb, 0xd0, 0xc6, 0xec, 0xd4, 0x9e, 0x9c, 0xae, 0xfb, - 0x78, 0x4a, 0x37, 0x31, 0x1e, 0x1f, 0x6c, 0x78, 0x22, 0x15, 0x8f, 0x2d, - 0xba, 0xfd, 0x0d, 0x3a, 0xae, 0x74, 0x63, 0x2e, 0x5d, 0x32, 0x1e, 0x3b, - 0xc8, 0xa1, 0xfb, 0xa5, 0xee, 0x9d, 0xfc, 0x16, 0x30, 0x77, 0x0a, 0xf9, - 0xad, 0xd3, 0xc8, 0x6f, 0x27, 0x75, 0x7f, 0xb5, 0xc9, 0xd3, 0xc2, 0x37, - 0x51, 0x3e, 0xbf, 0xc7, 0x8b, 0xc2, 0x67, 0x9b, 0x30, 0xdb, 0x59, 0xf0, - 0x35, 0x5e, 0xc7, 0x7d, 0xde, 0xc5, 0x38, 0x35, 0x54, 0xa2, 0xbd, 0xbb, - 0xa9, 0xc2, 0xd2, 0x57, 0xb1, 0x10, 0x29, 0x2f, 0x52, 0xdb, 0x65, 0x6a, - 0x91, 0x8c, 0xbd, 0x7c, 0x43, 0x99, 0x6b, 0x7c, 0x9b, 0x38, 0xf6, 0xe2, - 0x04, 0x2f, 0x16, 0x89, 0x62, 0xea, 0xab, 0x98, 0x47, 0x9e, 0xf5, 0x88, - 0xeb, 0x22, 0x83, 0x16, 0x59, 0x71, 0x1a, 0xf5, 0xc8, 0x77, 0xa0, 0xce, - 0xb0, 0x4b, 0xa0, 0xfe, 0x6c, 0xeb, 0xb8, 0xac, 0x77, 0xd5, 0x02, 0xbe, - 0xed, 0x7a, 0x7e, 0x84, 0x7a, 0x77, 0x57, 0x7b, 0xc8, 0x3d, 0x33, 0xec, - 0x79, 0x88, 0xba, 0xa1, 0x7d, 0x58, 0x3e, 0xbf, 0x8f, 0xf8, 0x55, 0x64, - 0xcb, 0x44, 0x7b, 0x78, 0x25, 0x17, 0xd8, 0x67, 0xd0, 0x92, 0xbd, 0x1d, - 0xb4, 0xcc, 0xce, 0x9f, 0xfe, 0x87, 0x3d, 0x56, 0xdc, 0xab, 0x8a, 0xec, - 0x4e, 0xb4, 0xdb, 0x86, 0xf3, 0x5b, 0xd8, 0xe3, 0x40, 0x64, 0x71, 0xc3, - 0xc3, 0x5f, 0xe0, 0x56, 0xd9, 0xe7, 0x3a, 0x7a, 0x45, 0x3f, 0x7a, 0x33, - 0x1f, 0x37, 0xd8, 0x62, 0x79, 0xe7, 0xe1, 0x7b, 0xf4, 0x2f, 0x68, 0x14, - 0xba, 0x12, 0xc3, 0xd1, 0x53, 0x6b, 0xcf, 0x91, 0xf7, 0x6b, 0x6e, 0x51, - 0x31, 0xee, 0x68, 0x38, 0xbd, 0xe2, 0xde, 0xfd, 0x1a, 0xad, 0xb2, 0x1e, - 0x94, 0xa3, 0x8f, 0x94, 0xc7, 0x8d, 0x36, 0xe2, 0x94, 0x64, 0xb1, 0xca, - 0xcf, 0xd5, 0xc7, 0xff, 0x1d, 0x5d, 0x47, 0xff, 0x54, 0x7a, 0xe2, 0x3f, - 0xa5, 0x1f, 0x90, 0xde, 0x28, 0xe4, 0x67, 0xb4, 0x59, 0x7c, 0x52, 0x37, - 0x9a, 0x46, 0xd7, 0x8f, 0x5a, 0xd6, 0x1d, 0x17, 0xe7, 0x1f, 0x17, 0x2d, - 0xc7, 0x85, 0xd9, 0x6f, 0x78, 0xde, 0x0e, 0x7a, 0x7f, 0x06, 0xbf, 0xc9, - 0xa5, 0x89, 0xf2, 0xa8, 0xf7, 0x16, 0x29, 0x37, 0xfb, 0x92, 0xb4, 0x6f, - 0x78, 0x1a, 0xbe, 0x34, 0xd9, 0xfe, 0xa0, 0xf7, 0x29, 0x69, 0x6f, 0xd3, - 0xe7, 0xdf, 0xb3, 0x7a, 0x2f, 0x4d, 0x8f, 0x8f, 0x16, 0xf4, 0x3c, 0xea, - 0xfd, 0x3c, 0x59, 0x45, 0xae, 0xc9, 0x17, 0x7f, 0xa7, 0xfd, 0x94, 0xd7, - 0x41, 0x2f, 0xfc, 0x31, 0xa9, 0xe3, 0x35, 0xf8, 0x96, 0x8e, 0x21, 0x61, - 0xd7, 0x27, 0xe5, 0x9e, 0xcc, 0x91, 0x32, 0x17, 0xa7, 0xbd, 0xf9, 0xf2, - 0x56, 0x15, 0x76, 0xf1, 0x39, 0x38, 0xec, 0x59, 0x4b, 0x1e, 0xe9, 0x93, - 0x2a, 0x36, 0xff, 0xa5, 0x4c, 0x7d, 0x67, 0x61, 0x8a, 0xba, 0x7b, 0x4e, - 0x23, 0x22, 0xeb, 0xb9, 0xb0, 0xf1, 0x5c, 0xb4, 0x40, 0xea, 0x42, 0x3e, - 0x3e, 0xa1, 0xbf, 0x5f, 0xa6, 0x3e, 0x13, 0xe7, 0xf8, 0x9b, 0x8b, 0x3d, - 0xb0, 0xfb, 0xa7, 0xf0, 0xa4, 0x0c, 0x8e, 0x76, 0xd7, 0xea, 0x9d, 0x32, - 0x57, 0xef, 0x94, 0xa0, 0x36, 0xc7, 0xdb, 0x63, 0x19, 0xfd, 0xd2, 0x7a, - 0x3e, 0xa7, 0xf3, 0xdc, 0x73, 0x6a, 0x3e, 0x8f, 0xf8, 0xbc, 0x78, 0xc9, - 0xdc, 0xcd, 0x68, 0xd1, 0xf5, 0x74, 0x37, 0x89, 0x9b, 0xaa, 0xff, 0xba, - 0x90, 0xb8, 0x14, 0x2e, 0xe3, 0xbb, 0x5c, 0x86, 0xc7, 0xc3, 0xd4, 0xda, - 0x6c, 0x73, 0x66, 0x5c, 0xbe, 0xfd, 0x87, 0xbe, 0xb0, 0x67, 0x31, 0xa7, - 0x6d, 0xcd, 0xd9, 0xce, 0xcc, 0xcb, 0x1f, 0xfb, 0xe1, 0x23, 0xaa, 0xc4, - 0xe7, 0xb2, 0xb2, 0x44, 0xc9, 0x6b, 0xb9, 0x94, 0xad, 0xdb, 0x95, 0x53, - 0xae, 0xee, 0x81, 0xdc, 0x2e, 0x27, 0xda, 0x15, 0x76, 0xcd, 0xe1, 0xdd, - 0x93, 0x78, 0xdf, 0x98, 0x45, 0xa2, 0xa0, 0xfb, 0x3a, 0x55, 0xc3, 0x6a, - 0xdd, 0x4a, 0xa7, 0x6e, 0xa5, 0x93, 0x5b, 0x79, 0x46, 0x95, 0x89, 0xd3, - 0xb7, 0xc5, 0x71, 0x46, 0xd4, 0x8b, 0x02, 0xb4, 0x30, 0x5f, 0xb5, 0x70, - 0x0e, 0x39, 0x66, 0x70, 0x5e, 0x51, 0xcd, 0xb9, 0xbf, 0xad, 0xdb, 0x07, - 0x9a, 0xd1, 0x6c, 0xb3, 0xda, 0xd0, 0xbe, 0x9d, 0xdc, 0x3e, 0xa4, 0x9d, - 0xee, 0x79, 0xcd, 0x59, 0xd6, 0xac, 0xcb, 0x1f, 0xb8, 0xdd, 0xe6, 0xcc, - 0x12, 0xc7, 0x93, 0x25, 0x5a, 0xf5, 0x5c, 0xcf, 0x2b, 0xe7, 0xcf, 0xd7, - 0xd4, 0x1c, 0x59, 0x52, 0x73, 0x14, 0x76, 0x7d, 0x26, 0xf5, 0xae, 0x61, - 0x0d, 0x7c, 0xc3, 0xe7, 0x5d, 0x88, 0xb5, 0x71, 0x21, 0x91, 0x9e, 0xdf, - 0xf1, 0x33, 0x4f, 0xf2, 0x7d, 0xd1, 0x54, 0xef, 0x90, 0x92, 0x77, 0xcd, - 0xa2, 0xf2, 0x09, 0xfe, 0x64, 0xc3, 0x9c, 0xda, 0x94, 0x3f, 0x7d, 0x56, - 0xfb, 0x53, 0xd2, 0xf6, 0xdc, 0x0f, 0xb0, 0xfd, 0x5c, 0xca, 0xf7, 0xfe, - 0xb1, 0xfa, 0xa7, 0x6b, 0x13, 0xfb, 0x99, 0x57, 0xbf, 0x37, 0x9c, 0xec, - 0x67, 0xbe, 0xc6, 0xc5, 0x14, 0xed, 0xfa, 0x12, 0x7c, 0x8d, 0xed, 0x1d, - 0xfa, 0x5c, 0x5d, 0x33, 0x8d, 0x7d, 0x89, 0x7d, 0x65, 0x8b, 0x0d, 0xa7, - 0xe6, 0x13, 0x64, 0xf5, 0xab, 0xf2, 0xed, 0x93, 0xea, 0x4c, 0x9e, 0x2d, - 0xd7, 0xe9, 0x32, 0x22, 0xbe, 0xe5, 0x58, 0x87, 0xdd, 0x02, 0x25, 0xa1, - 0x23, 0x15, 0x16, 0x61, 0xa9, 0xb5, 0xa0, 0x0c, 0xef, 0x33, 0x72, 0x15, - 0x92, 0x8e, 0xc2, 0x44, 0x6d, 0xe5, 0xea, 0xbb, 0x45, 0x05, 0xb4, 0x90, - 0xf6, 0xe0, 0x54, 0xb9, 0xca, 0x55, 0x84, 0x99, 0xb9, 0x51, 0xae, 0xa5, - 0x5a, 0xec, 0x5d, 0xb5, 0xd6, 0x5c, 0x3a, 0x28, 0x77, 0x32, 0xa7, 0x25, - 0xe6, 0xa9, 0x20, 0x2f, 0xb9, 0x0b, 0x62, 0x1e, 0x2f, 0xa8, 0x59, 0x5e, - 0xce, 0xf2, 0x25, 0x49, 0x79, 0x9d, 0x05, 0x6d, 0x2e, 0x2f, 0x22, 0x75, - 0x73, 0xe6, 0x79, 0x2f, 0x95, 0x37, 0x4c, 0x7e, 0x77, 0xe8, 0x25, 0x7e, - 0x7a, 0x20, 0xe3, 0x4f, 0x59, 0xb2, 0x2d, 0x31, 0xd7, 0x6f, 0xe4, 0xfb, - 0x9f, 0x5a, 0x2a, 0xa4, 0x98, 0xeb, 0x0d, 0xe9, 0x1f, 0x8b, 0x88, 0xcf, - 0x5a, 0xfc, 0x4d, 0x1c, 0xa7, 0xa8, 0x45, 0xdc, 0x7e, 0x36, 0xff, 0xbf, - 0xde, 0x2a, 0xb1, 0xfc, 0x3c, 0xdf, 0xee, 0x0a, 0x7b, 0x96, 0x61, 0x35, - 0x96, 0xfc, 0x3a, 0x77, 0xda, 0xb9, 0x60, 0xe9, 0x9e, 0x72, 0xb5, 0x47, - 0xf2, 0x3b, 0x37, 0xb7, 0x28, 0x31, 0xdc, 0xeb, 0xc3, 0x9e, 0x47, 0xf4, - 0xfb, 0xa7, 0xe4, 0x7b, 0x9a, 0xbd, 0xfa, 0x7b, 0x4b, 0xec, 0x93, 0x24, - 0x6f, 0xdb, 0xd2, 0x27, 0x11, 0x29, 0x84, 0x7c, 0x37, 0x74, 0x3e, 0x09, - 0xc3, 0x27, 0xd8, 0x23, 0x2f, 0x90, 0xef, 0xb5, 0x64, 0x0d, 0x36, 0x59, - 0x5d, 0x2e, 0x5d, 0x67, 0x83, 0xa8, 0xfd, 0x33, 0x1d, 0xbd, 0x74, 0x8f, - 0x95, 0x0b, 0xcb, 0x5d, 0x53, 0x5a, 0x5a, 0x46, 0x3f, 0xb3, 0x5a, 0x95, - 0xfa, 0xc1, 0x24, 0xf3, 0xa8, 0x55, 0x4f, 0x54, 0x2e, 0x7d, 0x3f, 0x29, - 0x7b, 0x5e, 0x33, 0x77, 0x9c, 0x10, 0xb3, 0xf2, 0xef, 0xb8, 0xaf, 0x75, - 0xad, 0x28, 0x98, 0x71, 0xfb, 0x55, 0xf4, 0xae, 0x15, 0x2d, 0x47, 0x99, - 0x7d, 0xed, 0x9b, 0xe8, 0xb4, 0x8d, 0x79, 0xba, 0x4d, 0x92, 0x35, 0x74, - 0xdc, 0xa6, 0x54, 0xbd, 0xed, 0xad, 0xf4, 0x80, 0x8d, 0x72, 0x77, 0xb7, - 0x1f, 0x6e, 0x1f, 0xbb, 0xe4, 0xe9, 0xfb, 0xe8, 0xeb, 0x36, 0x5d, 0x39, - 0xfd, 0x1c, 0xe2, 0xab, 0x3a, 0x4a, 0xbd, 0x6b, 0xc7, 0xe8, 0xab, 0x0e, - 0xb4, 0xed, 0xb5, 0x47, 0x2e, 0xd8, 0x7f, 0xe2, 0xc0, 0x0f, 0xda, 0xe9, - 0x59, 0x4e, 0x89, 0xfc, 0xfc, 0xfb, 0x1e, 0xa1, 0xb3, 0x0e, 0x69, 0xfd, - 0x1a, 0x3d, 0xe9, 0x90, 0xc5, 0xdf, 0x21, 0x49, 0x2f, 0x1d, 0xb3, 0xc2, - 0x24, 0x48, 0x57, 0x5b, 0x29, 0xb7, 0xef, 0xce, 0xb1, 0x67, 0xd7, 0x9c, - 0xed, 0x2b, 0x45, 0x86, 0x31, 0xfa, 0x83, 0x85, 0xfb, 0xfd, 0xb6, 0x85, - 0xad, 0x8c, 0x9a, 0x5d, 0x46, 0xdb, 0x21, 0x7a, 0x97, 0xc7, 0xe8, 0xaf, - 0xfc, 0xb8, 0x93, 0xdf, 0x43, 0x7d, 0x8d, 0x1f, 0xf7, 0x18, 0x6c, 0xf6, - 0x65, 0x66, 0xbf, 0xc2, 0x8f, 0x7b, 0xf9, 0x71, 0x86, 0x1f, 0x77, 0x1b, - 0xaa, 0x1e, 0x69, 0xf0, 0x55, 0xf9, 0xbc, 0x4b, 0x89, 0xbe, 0x2e, 0x13, - 0x5d, 0xb2, 0x3d, 0xf4, 0x27, 0x07, 0x1e, 0xff, 0xc9, 0x23, 0xba, 0xbf, - 0x7d, 0x4d, 0xef, 0x6d, 0xc1, 0xf6, 0xcd, 0x57, 0x95, 0xd1, 0x7b, 0x5c, - 0x40, 0x97, 0xb4, 0xd2, 0xe3, 0xd6, 0x95, 0x1c, 0xfc, 0xfb, 0x59, 0xfa, - 0x82, 0x1d, 0x8f, 0x9b, 0xb8, 0x98, 0xab, 0xe9, 0x2e, 0xd9, 0xc4, 0x2f, - 0x1b, 0xf9, 0x6f, 0x95, 0xb5, 0x07, 0x8c, 0x91, 0x5d, 0xbb, 0xe9, 0x39, - 0x8b, 0x2c, 0xfa, 0x91, 0xd7, 0x6e, 0xbf, 0xba, 0x3c, 0x60, 0x5c, 0x7c, - 0x88, 0x9e, 0x90, 0x26, 0x77, 0xd0, 0x1f, 0x05, 0x72, 0xdc, 0xd1, 0x6e, - 0xcc, 0x14, 0xb3, 0x73, 0x6f, 0x34, 0x12, 0x37, 0xdc, 0x68, 0x8c, 0xdd, - 0x20, 0xdc, 0x4e, 0xfa, 0x31, 0x97, 0x74, 0x1b, 0x75, 0xc9, 0xd6, 0xed, - 0x90, 0x99, 0x8d, 0x5f, 0x53, 0xbd, 0xf1, 0x07, 0xe3, 0x90, 0xf1, 0x6f, - 0x96, 0x43, 0x63, 0xc6, 0xef, 0xc7, 0x5e, 0xe9, 0x08, 0x9d, 0x5a, 0xb3, - 0x66, 0xed, 0x9a, 0x35, 0xe7, 0x1f, 0xbe, 0x70, 0xcd, 0x4d, 0x46, 0xae, - 0x98, 0x95, 0x6b, 0xe4, 0x7c, 0x9d, 0x6e, 0xc1, 0x68, 0x9c, 0xa2, 0x1b, - 0x05, 0x7f, 0xec, 0x8c, 0x36, 0x1f, 0x69, 0x5f, 0x4b, 0x77, 0x73, 0x25, - 0xa7, 0xd6, 0xd2, 0xe3, 0x42, 0xce, 0x9b, 0x28, 0x70, 0x9d, 0x28, 0x3d, - 0x40, 0x2f, 0xab, 0xd4, 0x09, 0x31, 0xdb, 0x5d, 0xda, 0x41, 0xa7, 0x90, - 0xed, 0xc8, 0x55, 0xf4, 0x96, 0x9d, 0x4d, 0xe9, 0x53, 0x3c, 0x4b, 0x37, - 0xd2, 0x17, 0x65, 0x46, 0xfa, 0x8c, 0x9d, 0x2d, 0xbf, 0x49, 0x27, 0xec, - 0xaa, 0xeb, 0x6b, 0xaf, 0xa2, 0x3b, 0x59, 0xb4, 0xa2, 0xe3, 0x9a, 0xab, - 0xb6, 0x5e, 0x65, 0xb8, 0x0e, 0xf5, 0x8e, 0xad, 0x15, 0x2e, 0xd7, 0xb7, - 0xe9, 0x15, 0xe4, 0xde, 0x45, 0x27, 0x54, 0x67, 0x2f, 0x6b, 0x5f, 0x93, - 0x5c, 0x0b, 0x2b, 0x49, 0xdd, 0x13, 0x0b, 0x38, 0xfa, 0x83, 0x2e, 0x22, - 0x75, 0x96, 0x9b, 0x0f, 0xdf, 0x4f, 0x7e, 0x0f, 0x4f, 0x68, 0x9b, 0xe4, - 0x3b, 0x17, 0x23, 0x85, 0x6c, 0x99, 0xce, 0xd6, 0x36, 0xc9, 0xef, 0xf6, - 0xd5, 0x6b, 0x5a, 0xad, 0x69, 0x46, 0xca, 0x5e, 0xc5, 0xf8, 0x6a, 0x7d, - 0x93, 0x67, 0xd9, 0x02, 0x5d, 0x66, 0x89, 0xb6, 0xad, 0xd4, 0xf2, 0x6a, - 0xbd, 0x3e, 0x1b, 0x69, 0xab, 0x94, 0x37, 0xeb, 0x76, 0x19, 0xa6, 0x36, - 0x34, 0xd3, 0x16, 0xc9, 0xe7, 0xa7, 0xd2, 0xaa, 0xfc, 0x64, 0x3b, 0xad, - 0x29, 0x5e, 0xbd, 0xfb, 0x4d, 0xde, 0x83, 0x0d, 0xad, 0x33, 0xb4, 0xce, - 0xd0, 0xf1, 0x40, 0x95, 0xef, 0x90, 0xe7, 0x66, 0x25, 0x6b, 0xd6, 0xb4, - 0x55, 0xd3, 0x76, 0x59, 0x82, 0x45, 0xeb, 0x71, 0x5f, 0x32, 0xd5, 0xa3, - 0xde, 0x65, 0x58, 0x24, 0x6d, 0xd7, 0xe3, 0xa5, 0xde, 0xa9, 0x30, 0xcd, - 0xd4, 0x34, 0x47, 0xe7, 0xcd, 0xc7, 0xc9, 0xcd, 0x22, 0xc7, 0x6c, 0xbc, - 0xad, 0x33, 0xd0, 0x5b, 0x4e, 0xd9, 0x4d, 0x7c, 0xb2, 0x2f, 0xb3, 0x75, - 0xbe, 0x79, 0x98, 0x31, 0x41, 0xea, 0xbd, 0xa5, 0xa0, 0xf1, 0xef, 0x35, - 0x2e, 0xd0, 0x75, 0x2e, 0x06, 0x55, 0x63, 0x9c, 0x2f, 0x3f, 0xb7, 0x52, - 0x63, 0x59, 0xad, 0x65, 0xed, 0x52, 0x66, 0x95, 0x73, 0x34, 0x5e, 0x76, - 0xa3, 0x96, 0x35, 0x9a, 0xc6, 0xa3, 0x51, 0xa6, 0xd4, 0xf7, 0xf4, 0x98, - 0xf2, 0x77, 0x91, 0x6c, 0x92, 0x8e, 0xe7, 0x63, 0x74, 0x68, 0xba, 0x59, - 0xf7, 0x9d, 0x35, 0x79, 0x26, 0x7e, 0x6e, 0xca, 0x77, 0xe6, 0x9a, 0xc6, - 0x3c, 0x2f, 0x35, 0x97, 0x4b, 0xb5, 0xde, 0xa5, 0xcb, 0x9c, 0xa7, 0xeb, - 0xa9, 0x4e, 0x59, 0x92, 0xfe, 0xae, 0x41, 0xd2, 0x5a, 0x64, 0x92, 0x70, - 0x92, 0xc8, 0xa1, 0x65, 0xc5, 0xb1, 0xda, 0xe2, 0x90, 0x7f, 0xb8, 0x7f, - 0xd0, 0x5f, 0xdc, 0x54, 0x59, 0x1a, 0xec, 0xaa, 0x1c, 0xd9, 0xd0, 0x53, - 0x31, 0xb2, 0xef, 0x50, 0xcd, 0xe1, 0x95, 0xb1, 0x91, 0xb6, 0x58, 0xcd, - 0xe6, 0xd1, 0xca, 0x8d, 0x23, 0xad, 0x69, 0x76, 0xfb, 0x3b, 0x46, 0x23, - 0x9d, 0x87, 0xb7, 0x54, 0x1d, 0x6a, 0x3b, 0xb4, 0xb1, 0xdf, 0xbb, 0x61, - 0x57, 0xe3, 0xc6, 0xea, 0xea, 0xf5, 0xb5, 0xdb, 0x3a, 0x37, 0x75, 0xa7, - 0xdb, 0x85, 0x76, 0xd6, 0x7a, 0x9b, 0x87, 0x06, 0x56, 0xd5, 0x76, 0x8e, - 0x8d, 0xf5, 0xf4, 0xd6, 0x5c, 0x5c, 0xb5, 0xeb, 0xd0, 0xa6, 0x91, 0xfd, - 0x07, 0xfb, 0x03, 0x3b, 0xe2, 0x24, 0x4a, 0xc8, 0x28, 0x69, 0x23, 0x71, - 0x2e, 0xd9, 0xd7, 0x04, 0xc3, 0xc1, 0xc4, 0xf9, 0x64, 0x9c, 0x5f, 0x4f, - 0xd6, 0xf3, 0xeb, 0xf1, 0xb4, 0xf3, 0xf3, 0xdc, 0x1e, 0xca, 0x69, 0x1a, - 0xf2, 0x87, 0xf7, 0x05, 0x76, 0xf8, 0x13, 0x03, 0x43, 0x81, 0x18, 0xcd, - 0x6a, 0x8a, 0x0c, 0x47, 0x23, 0xe1, 0x40, 0x38, 0xd1, 0x19, 0x08, 0xc4, - 0x7a, 0x82, 0x81, 0x43, 0x65, 0xfb, 0xfd, 0xa3, 0x7e, 0x72, 0x36, 0x45, - 0xc2, 0xe1, 0xc0, 0x40, 0x22, 0x18, 0x09, 0x93, 0xbb, 0xb9, 0xb6, 0xb8, - 0xb8, 0xfb, 0x70, 0x38, 0x31, 0x14, 0x48, 0x04, 0x07, 0x9a, 0x42, 0xfe, - 0x38, 0xaa, 0xda, 0x40, 0xc6, 0x86, 0x56, 0x12, 0xf0, 0xbf, 0xd6, 0x73, - 0x81, 0x56, 0xb2, 0xb4, 0xb6, 0x72, 0xa2, 0x0d, 0x4c, 0x5b, 0x07, 0x98, - 0x0e, 0x12, 0x6d, 0x64, 0xb4, 0x31, 0x3a, 0x68, 0x41, 0xdb, 0xc8, 0x40, - 0x60, 0xfd, 0xc0, 0x40, 0x20, 0x1e, 0x0f, 0xf6, 0x07, 0x43, 0xc1, 0xc4, - 0xe1, 0x2d, 0x91, 0xc1, 0x40, 0x67, 0x2c, 0x32, 0x1a, 0x1c, 0x44, 0x2b, - 0x0a, 0xdb, 0x03, 0x87, 0xfb, 0x23, 0xfe, 0xd8, 0x60, 0x73, 0x30, 0x3e, - 0x1c, 0x8c, 0xc7, 0x3b, 0x82, 0xf1, 0x44, 0x20, 0x0c, 0x85, 0x40, 0x49, - 0x1d, 0x28, 0xbb, 0x83, 0xcb, 0xee, 0x40, 0xd9, 0x1d, 0x6d, 0xad, 0x64, - 0xc5, 0x83, 0x93, 0x1d, 0x48, 0x4a, 0x25, 0x14, 0xd6, 0x0e, 0xd6, 0x80, - 0xed, 0xa0, 0x59, 0x1d, 0xfe, 0xf0, 0x60, 0x2c, 0x12, 0x1c, 0x2c, 0xf7, - 0x47, 0xa3, 0xe5, 0xeb, 0xd1, 0x87, 0x51, 0xd4, 0x57, 0x4f, 0x55, 0xe9, - 0xf2, 0x68, 0x34, 0x14, 0x1c, 0xf0, 0x73, 0x07, 0x8b, 0x93, 0x36, 0x1d, - 0xc1, 0xbd, 0x81, 0x81, 0xc3, 0x03, 0xa1, 0x40, 0x93, 0x3f, 0x14, 0xea, - 0xf7, 0x0f, 0x1c, 0x88, 0xd7, 0xd3, 0x9c, 0xe9, 0x72, 0x99, 0x55, 0x03, - 0x91, 0x30, 0xda, 0x9b, 0x28, 0x6f, 0x62, 0x3a, 0x96, 0x30, 0xab, 0xf6, - 0xc5, 0xfc, 0xd1, 0xa1, 0xe0, 0x40, 0xbc, 0xbc, 0xc9, 0x1f, 0x1e, 0xf5, - 0xa3, 0xc0, 0x85, 0x53, 0xa8, 0x22, 0xa1, 0x48, 0x6c, 0x43, 0x30, 0x94, - 0x08, 0xc4, 0xa6, 0xd7, 0x6f, 0xf6, 0x27, 0x62, 0xc1, 0xb1, 0x7a, 0x3a, - 0xf7, 0x03, 0xf5, 0x69, 0x45, 0xcd, 0x9e, 0x6c, 0xda, 0xe9, 0x0f, 0x86, - 0x13, 0x53, 0x6b, 0x22, 0x52, 0x53, 0x38, 0x59, 0xd3, 0x05, 0x3f, 0xa8, - 0xa7, 0xb9, 0x29, 0x45, 0x24, 0x5e, 0xde, 0x38, 0x12, 0x0c, 0x0d, 0x16, - 0xf7, 0xb4, 0x74, 0x75, 0xb7, 0x6e, 0xdd, 0x52, 0x4f, 0x05, 0xe9, 0xba, - 0xf0, 0x60, 0x28, 0x50, 0x4f, 0x33, 0xcc, 0xc2, 0xd6, 0xc6, 0x60, 0x78, - 0x90, 0xdb, 0x34, 0x5e, 0x3e, 0x8f, 0x54, 0x79, 0xcb, 0x60, 0x30, 0xe1, - 0xef, 0x67, 0xf3, 0xd9, 0xe9, 0x8a, 0xee, 0x40, 0x48, 0xb9, 0x9f, 0xb9, - 0x66, 0xa5, 0x89, 0xfa, 0xc3, 0xda, 0x7d, 0x27, 0xe7, 0x82, 0x2e, 0xac, - 0xca, 0x5b, 0x3a, 0x8d, 0xa6, 0x1b, 0xc3, 0x14, 0xde, 0x27, 0x3b, 0xc0, - 0x05, 0x4c, 0x28, 0xdc, 0x87, 0x47, 0xaa, 0xf0, 0xf1, 0x6e, 0x8d, 0x24, - 0x82, 0x21, 0x1e, 0xbb, 0xa9, 0x85, 0x6b, 0x68, 0x79, 0x4a, 0x38, 0x8a, - 0x25, 0x54, 0xde, 0x34, 0x14, 0x89, 0x05, 0x22, 0x72, 0x00, 0x03, 0xb1, - 0xe2, 0x0d, 0x31, 0xff, 0x70, 0xca, 0xa5, 0xea, 0x69, 0xfe, 0x07, 0xd8, - 0x9a, 0xc7, 0x47, 0x6a, 0xb1, 0x30, 0x5a, 0x46, 0x03, 0xe1, 0xb4, 0xf1, - 0x97, 0x8a, 0xcd, 0x11, 0x1e, 0x1c, 0xad, 0x3b, 0x37, 0x5d, 0xc7, 0xcb, - 0xb8, 0x78, 0x6b, 0x78, 0x43, 0x64, 0x60, 0x24, 0xae, 0x96, 0x7b, 0x72, - 0x41, 0x99, 0x9b, 0x9f, 0x32, 0x35, 0x8f, 0x62, 0x4a, 0xb8, 0x31, 0x16, - 0x19, 0x89, 0xd6, 0xd3, 0xaa, 0xc9, 0x1a, 0x5f, 0x2c, 0x10, 0xd8, 0xda, - 0x1f, 0x0f, 0xc4, 0x46, 0xd1, 0xb7, 0xad, 0xe1, 0x8d, 0xa1, 0x48, 0xbf, - 0x3f, 0xd4, 0xe1, 0x3f, 0x1c, 0x19, 0x49, 0x8c, 0x57, 0xb3, 0xe8, 0x83, - 0xf3, 0xd5, 0xd3, 0xcc, 0x74, 0x83, 0x1d, 0x70, 0x8f, 0x08, 0x5a, 0xe2, - 0x99, 0x4a, 0xdc, 0x1a, 0x8e, 0x07, 0x12, 0xf1, 0x62, 0xdf, 0xe1, 0x68, - 0xda, 0xbc, 0x4e, 0xb2, 0xe0, 0xe5, 0x17, 0x8b, 0x84, 0x42, 0x5c, 0x7e, - 0x45, 0xba, 0x99, 0xdf, 0x1c, 0x7b, 0xca, 0xd3, 0x22, 0xd1, 0x66, 0x7f, - 0xd8, 0xbf, 0x8f, 0xb3, 0x54, 0xfe, 0xc3, 0x59, 0x38, 0x78, 0xb5, 0x86, - 0xf7, 0x46, 0x26, 0x8d, 0xcf, 0x87, 0xe4, 0x49, 0x06, 0xbc, 0x7a, 0x2a, - 0x4b, 0xcf, 0x17, 0x0c, 0x47, 0x47, 0x12, 0xc3, 0x81, 0xc4, 0x50, 0x64, - 0xb0, 0xbc, 0xd1, 0x1f, 0x47, 0xe1, 0x48, 0x8f, 0x87, 0xe0, 0x49, 0xbd, - 0x36, 0xdb, 0xf3, 0x12, 0x8a, 0xc4, 0x54, 0x73, 0x96, 0x4f, 0x6f, 0x36, - 0xa9, 0xc8, 0xd2, 0x0f, 0xb1, 0xdd, 0x2c, 0xf9, 0xd4, 0xe8, 0xd4, 0x77, - 0x0c, 0x44, 0x86, 0xcb, 0x63, 0xc3, 0xf1, 0x50, 0xf9, 0x7e, 0x04, 0xf3, - 0xf2, 0x49, 0x1b, 0x47, 0x71, 0x71, 0xcb, 0x18, 0xc2, 0x4e, 0xd8, 0x1f, - 0x4a, 0xed, 0x15, 0x1d, 0x72, 0xcf, 0xf2, 0xfe, 0x6f, 0x32, 0x57, 0xfc, - 0x6f, 0x32, 0x57, 0xd6, 0x53, 0xf9, 0x87, 0x66, 0x4e, 0xdb, 0x10, 0xeb, - 0x71, 0x40, 0xfd, 0xd0, 0x0c, 0xa6, 0x41, 0x5c, 0xf7, 0xa1, 0xd6, 0x1f, - 0xb8, 0xf3, 0xd5, 0xd3, 0x86, 0x0f, 0x2d, 0x60, 0x9a, 0xbd, 0xb1, 0x38, - 0x7d, 0x3d, 0xd5, 0xfd, 0xff, 0x96, 0xc3, 0xbe, 0xf8, 0x61, 0x59, 0x37, - 0x47, 0x46, 0xe2, 0x81, 0x4d, 0x7e, 0x8e, 0xeb, 0x72, 0x69, 0x7d, 0x98, - 0x3d, 0x47, 0x51, 0xe9, 0x43, 0x3e, 0x7f, 0x6c, 0x5f, 0x00, 0x01, 0x6a, - 0xf1, 0x87, 0x65, 0xa9, 0xa7, 0xa2, 0x8e, 0x41, 0x7f, 0x68, 0x34, 0x78, - 0xa0, 0x1c, 0x71, 0x3a, 0x92, 0x90, 0x5b, 0x6c, 0x79, 0x4b, 0x78, 0x20, - 0x14, 0x89, 0x23, 0x5c, 0xcb, 0x43, 0x07, 0xef, 0x8d, 0x93, 0x6d, 0x5a, - 0x31, 0x19, 0x31, 0xad, 0x5f, 0x3c, 0x85, 0x7e, 0x73, 0x60, 0xb8, 0x5f, - 0x1b, 0x04, 0x60, 0x52, 0x3c, 0xa5, 0x09, 0x7b, 0x7a, 0xa7, 0x9f, 0xe3, - 0x34, 0xfc, 0x08, 0x56, 0x0b, 0xa6, 0xb0, 0xea, 0x0e, 0xee, 0x0b, 0xfb, - 0x13, 0x23, 0x31, 0xb9, 0x57, 0xf1, 0x21, 0xa9, 0x3c, 0x04, 0xc7, 0x41, - 0xfc, 0xf6, 0xc7, 0xba, 0x03, 0x07, 0x47, 0x02, 0xe1, 0x01, 0x68, 0xf2, - 0xcd, 0x1a, 0xd5, 0xa8, 0x45, 0x26, 0xd1, 0x86, 0x91, 0xb0, 0x74, 0x1c, - 0x7f, 0xa8, 0x15, 0x27, 0x85, 0xd8, 0x5e, 0x3f, 0xe7, 0x29, 0x32, 0x19, - 0xb4, 0x22, 0x7a, 0xed, 0xf3, 0x87, 0x94, 0xc3, 0xb4, 0x8c, 0x0d, 0x04, - 0xa2, 0xca, 0xcf, 0x8a, 0xa7, 0xb0, 0x89, 0xed, 0x1b, 0x19, 0xc6, 0x10, - 0x9a, 0xac, 0x0a, 0xcc, 0x56, 0xa8, 0x40, 0x2e, 0xdc, 0xc5, 0x26, 0xe1, - 0x96, 0x48, 0xf7, 0xc8, 0xc0, 0x90, 0xea, 0xaf, 0x29, 0x9f, 0xdb, 0x64, - 0xb2, 0xb5, 0x7f, 0xbf, 0xdc, 0xef, 0x17, 0x98, 0x64, 0xdd, 0x81, 0x81, - 0x91, 0x18, 0x5c, 0x77, 0x9a, 0x2c, 0x6a, 0x4b, 0xe5, 0x88, 0x32, 0x2e, - 0x8b, 0x05, 0xf6, 0xf2, 0x06, 0x8e, 0x66, 0x8c, 0x46, 0xd4, 0x81, 0x49, - 0xf9, 0x82, 0xa9, 0x88, 0xb9, 0x53, 0x98, 0xab, 0xa6, 0xf1, 0xf6, 0x20, - 0x75, 0x72, 0x8b, 0x5d, 0x1f, 0x8b, 0xf9, 0x0f, 0xb3, 0xbb, 0xf2, 0x99, - 0x62, 0x5c, 0xdc, 0x8a, 0x01, 0xf4, 0x23, 0xf2, 0xd5, 0x93, 0xcb, 0x24, - 0x55, 0x76, 0x13, 0x25, 0x6b, 0x28, 0xdb, 0xec, 0xc3, 0xe4, 0xe8, 0x6e, - 0x6e, 0xbf, 0xa8, 0x75, 0x8b, 0x8f, 0xac, 0xbe, 0x5d, 0x9d, 0x2d, 0x94, - 0x37, 0xc1, 0x61, 0x29, 0xdb, 0xbc, 0xb8, 0x48, 0xf4, 0x90, 0xd1, 0x83, - 0xd3, 0x65, 0x0f, 0x8e, 0x9d, 0xd6, 0x1e, 0x3e, 0xe7, 0xda, 0xf8, 0x89, - 0x33, 0x68, 0x4f, 0x1b, 0xd9, 0x7b, 0xda, 0x5a, 0x37, 0x6c, 0xc0, 0x09, - 0xb4, 0xa7, 0x4d, 0x2a, 0xda, 0x58, 0x61, 0xe9, 0xc1, 0xc1, 0x17, 0x8f, - 0x0e, 0x16, 0xf3, 0x41, 0xb5, 0xa7, 0xad, 0x17, 0xd6, 0xcc, 0x74, 0x70, - 0x19, 0x1d, 0xd2, 0xb4, 0x43, 0x99, 0xf2, 0xb9, 0xb6, 0x07, 0x46, 0x10, - 0xb0, 0xdc, 0x21, 0x89, 0xac, 0xaa, 0x43, 0x66, 0xed, 0xe8, 0x65, 0xb6, - 0xb7, 0x4d, 0x3e, 0x71, 0x20, 0xee, 0xe9, 0x45, 0xa5, 0xbd, 0xd2, 0x44, - 0xf4, 0x92, 0xa5, 0x97, 0x4d, 0xf1, 0xe8, 0x60, 0x16, 0x6a, 0x18, 0xda, - 0x7a, 0xdb, 0x38, 0x6d, 0x05, 0x61, 0x01, 0x6b, 0x50, 0xad, 0xbd, 0xb7, - 0x43, 0x8a, 0x6d, 0x4c, 0x59, 0x8e, 0x26, 0xf5, 0xe1, 0x1c, 0xdf, 0xd7, - 0x4a, 0xee, 0xbe, 0xc9, 0x7e, 0x5b, 0xd0, 0x37, 0x85, 0x57, 0x38, 0xd5, - 0x0e, 0x57, 0xec, 0xf5, 0x7a, 0x53, 0x7c, 0x05, 0xf8, 0xac, 0x71, 0xde, - 0x94, 0x48, 0xd3, 0x54, 0x9a, 0x13, 0x2b, 0xcd, 0x89, 0x2a, 0x73, 0xa2, - 0xda, 0x9c, 0x58, 0x65, 0x4e, 0xd4, 0x98, 0x13, 0xb5, 0xe6, 0x44, 0x9d, - 0xa9, 0x35, 0xe6, 0x6a, 0x2a, 0xcd, 0xcd, 0x5c, 0x69, 0xe2, 0xab, 0x4c, - 0x7c, 0xb5, 0x89, 0x5f, 0x65, 0xe2, 0x6b, 0x4c, 0x7c, 0xad, 0x89, 0xaf, - 0x1b, 0xaf, 0x60, 0x43, 0xc8, 0xbf, 0x2f, 0x4e, 0x39, 0x69, 0xbb, 0x3e, - 0xcd, 0xf0, 0x4f, 0x71, 0xba, 0xe0, 0x1c, 0xec, 0xf5, 0x1d, 0xfe, 0xfe, - 0x40, 0x88, 0x2c, 0xfe, 0xc1, 0x41, 0x9a, 0x83, 0xc7, 0xd4, 0xc7, 0x27, - 0x72, 0xf9, 0xf7, 0xc2, 0xb9, 0xd9, 0x29, 0xd5, 0xe6, 0x34, 0x48, 0xf9, - 0x7c, 0x76, 0x6c, 0x1c, 0x49, 0x24, 0x22, 0xe1, 0xce, 0x18, 0x4a, 0x97, - 0xa2, 0xc0, 0x5e, 0x1c, 0x1d, 0xcd, 0x56, 0xf6, 0xfe, 0x08, 0x2c, 0x86, - 0xc9, 0x3e, 0xe0, 0xc7, 0x66, 0x36, 0x48, 0x2e, 0x45, 0x4d, 0x77, 0xb9, - 0x9c, 0x81, 0xb4, 0xeb, 0x9f, 0x0d, 0x97, 0x1d, 0x7f, 0x8c, 0xf2, 0x38, - 0xcc, 0x06, 0x4c, 0x66, 0x85, 0x52, 0x60, 0x3a, 0x06, 0xe8, 0x9b, 0x0d, - 0x65, 0x0d, 0xf0, 0xee, 0xc5, 0x57, 0x85, 0xf5, 0x09, 0xca, 0x4d, 0x25, - 0x9a, 0x22, 0x23, 0xe1, 0x04, 0x0a, 0x87, 0x15, 0x2e, 0x18, 0x71, 0x29, - 0xa3, 0x19, 0xfa, 0x5a, 0x14, 0x6f, 0x94, 0x0d, 0x55, 0x8d, 0xa4, 0x79, - 0x03, 0xb1, 0x80, 0x3f, 0x31, 0x79, 0x4b, 0xe4, 0x03, 0x0c, 0x39, 0x06, - 0x23, 0xf2, 0xb4, 0x4c, 0x19, 0x01, 0x7d, 0x31, 0x00, 0x17, 0x1e, 0x8c, - 0xef, 0x08, 0x26, 0x86, 0xc8, 0xb3, 0x17, 0x67, 0xbd, 0x29, 0xf3, 0xc5, - 0x1b, 0x0f, 0xf3, 0x30, 0x50, 0x26, 0x5b, 0xc8, 0x63, 0x2f, 0x65, 0xef, - 0x1d, 0x3f, 0xfd, 0x0e, 0xd2, 0x3c, 0x2c, 0xea, 0xb4, 0x9c, 0xd2, 0x88, - 0x37, 0x9e, 0xd6, 0x41, 0x9a, 0x3f, 0x51, 0x99, 0x76, 0x37, 0xcd, 0x94, - 0x5a, 0x39, 0x2a, 0xb9, 0x29, 0xb6, 0x15, 0x97, 0x99, 0x31, 0xca, 0x4b, - 0xa5, 0x37, 0xfb, 0xe3, 0x07, 0x50, 0xcd, 0x4c, 0x16, 0x8c, 0x5f, 0x11, - 0x93, 0x83, 0xe6, 0x82, 0xb8, 0xc9, 0x1f, 0x0b, 0x24, 0x3a, 0xb1, 0x99, - 0xc9, 0x92, 0x66, 0xb0, 0x04, 0x1b, 0x87, 0x2c, 0x67, 0x43, 0x24, 0xa6, - 0x06, 0x2c, 0x47, 0x4b, 0xe1, 0x2a, 0xd8, 0x85, 0x28, 0x83, 0x93, 0xf2, - 0xb6, 0x5d, 0xc0, 0x1c, 0x6f, 0x99, 0xbc, 0x17, 0xf2, 0x4d, 0xa6, 0x25, - 0xac, 0x2a, 0x4b, 0x13, 0x76, 0x27, 0xfc, 0xb1, 0x04, 0x39, 0xa5, 0x58, - 0x55, 0x9c, 0x0d, 0xbe, 0x39, 0x30, 0x10, 0x91, 0x5b, 0x2c, 0x65, 0x71, - 0xf8, 0x4d, 0x0e, 0x2b, 0xab, 0xe4, 0xed, 0xc1, 0x17, 0xc4, 0x70, 0xcf, - 0x41, 0x4a, 0x0e, 0x49, 0x60, 0x70, 0x62, 0x28, 0xf4, 0x4c, 0xab, 0x92, - 0x8d, 0xd6, 0x23, 0xb4, 0x29, 0x10, 0xdc, 0x37, 0x94, 0x90, 0xe5, 0x6c, - 0x02, 0x17, 0xe2, 0x54, 0x60, 0xb0, 0x2b, 0xb0, 0x0f, 0xbd, 0x6d, 0xc4, - 0x13, 0x2e, 0x35, 0x95, 0x8a, 0xfb, 0xc1, 0x9d, 0x93, 0xa5, 0x9a, 0xe7, - 0x64, 0x66, 0x52, 0x98, 0x76, 0x0a, 0xa5, 0x65, 0x49, 0x31, 0xdf, 0x05, - 0x30, 0x6e, 0x7c, 0xb8, 0xea, 0x09, 0xc6, 0x12, 0x23, 0xfe, 0x50, 0xf2, - 0x78, 0xc3, 0x1a, 0xd9, 0x55, 0xdc, 0x09, 0x12, 0x7e, 0x6c, 0xca, 0x72, - 0x9a, 0xd2, 0xb4, 0x5c, 0x63, 0x87, 0xde, 0x95, 0xb6, 0x86, 0xbb, 0xe1, - 0x90, 0x81, 0xb0, 0x1c, 0x10, 0x54, 0xe6, 0xc7, 0x28, 0x26, 0x02, 0xb2, - 0x4f, 0xaa, 0x6a, 0x39, 0x2b, 0x5b, 0x60, 0x3b, 0x1a, 0x90, 0xa3, 0x98, - 0x37, 0xde, 0x73, 0xe5, 0xf5, 0xd9, 0xe3, 0x02, 0x34, 0xdc, 0x81, 0x54, - 0x97, 0xff, 0xd0, 0xce, 0x24, 0xb3, 0x4b, 0xb6, 0xa5, 0x2b, 0x12, 0x49, - 0xa4, 0x72, 0xa7, 0xae, 0xb6, 0xdc, 0xfb, 0x7c, 0xb3, 0x40, 0xcd, 0x20, - 0xbb, 0x4b, 0xf7, 0x61, 0x84, 0x82, 0xe1, 0x6e, 0xec, 0x3f, 0x41, 0xf4, - 0x60, 0x66, 0x4a, 0xb2, 0x3d, 0xd8, 0x13, 0x4c, 0x45, 0x1a, 0xf6, 0x47, - 0x35, 0x27, 0x5d, 0x72, 0x69, 0x71, 0x46, 0x1f, 0x8e, 0x2b, 0xa1, 0x2d, - 0x23, 0xc3, 0xec, 0x47, 0xca, 0x71, 0xb6, 0xf3, 0xc5, 0x3b, 0x14, 0x0c, - 0x63, 0xcc, 0xd9, 0x2a, 0x2e, 0xb3, 0x6d, 0x0f, 0x07, 0x79, 0xf1, 0xb2, - 0x95, 0x34, 0x9a, 0x78, 0x41, 0x93, 0xbd, 0x36, 0x55, 0xc5, 0x13, 0x3b, - 0xf5, 0x55, 0x4b, 0x16, 0xa7, 0x54, 0xbe, 0xc8, 0x01, 0x0c, 0xe4, 0xfc, - 0x54, 0x5a, 0xe6, 0x0f, 0x05, 0x70, 0xe0, 0x8c, 0x86, 0xfc, 0x87, 0xd5, - 0xc2, 0xb6, 0x42, 0xbb, 0x53, 0x3e, 0x77, 0x91, 0x7d, 0x48, 0x6e, 0xc7, - 0x34, 0x5b, 0xd1, 0xb4, 0x35, 0xb8, 0x29, 0xc2, 0xad, 0xc8, 0xd3, 0x9a, - 0x68, 0xb4, 0xd3, 0xcf, 0x1e, 0x48, 0xae, 0x94, 0xa0, 0x2b, 0x10, 0xc7, - 0xf1, 0x27, 0x25, 0x69, 0x4c, 0xc5, 0x47, 0xca, 0x51, 0x92, 0x66, 0x1d, - 0x4a, 0x74, 0x12, 0x1e, 0xd0, 0x1c, 0x39, 0x14, 0xa6, 0xac, 0x54, 0x72, - 0x7b, 0x94, 0x66, 0xa4, 0x12, 0xd2, 0x3b, 0x36, 0x05, 0x07, 0x07, 0xd1, - 0x03, 0x5d, 0xab, 0x3c, 0x31, 0xc8, 0x3c, 0x69, 0x82, 0x98, 0x7f, 0x5f, - 0xb2, 0x4c, 0x29, 0x40, 0x31, 0x85, 0x3a, 0x39, 0x12, 0x4a, 0x04, 0xb5, - 0x2b, 0xc8, 0xb5, 0x95, 0xac, 0x4c, 0xbe, 0x75, 0xa1, 0x02, 0x9d, 0xc0, - 0xb9, 0x2f, 0x12, 0x1b, 0xd6, 0x31, 0x65, 0x9e, 0x12, 0xe2, 0x84, 0x15, - 0x09, 0x0f, 0xfa, 0x63, 0x87, 0xd3, 0xb2, 0x3b, 0x86, 0xfc, 0xf1, 0x2d, - 0xbc, 0x90, 0xad, 0x43, 0x88, 0x45, 0x94, 0xcd, 0xcf, 0x64, 0x5b, 0x51, - 0x29, 0x52, 0xdd, 0x91, 0xbd, 0x7a, 0xf1, 0xc4, 0x22, 0xc3, 0x6a, 0xd4, - 0x29, 0x63, 0x08, 0x45, 0xf8, 0x54, 0xb6, 0x48, 0x1c, 0x11, 0x01, 0x2b, - 0x7c, 0xab, 0x3c, 0x73, 0xc5, 0x29, 0x8f, 0xdf, 0x0b, 0x06, 0xfd, 0xa1, - 0x26, 0x7f, 0x34, 0xbe, 0x19, 0x0e, 0x40, 0x39, 0x5a, 0x00, 0x1f, 0x64, - 0x77, 0xcc, 0x1b, 0x4f, 0x2a, 0x67, 0xcc, 0x0c, 0x26, 0x97, 0x1b, 0x65, - 0x4b, 0xf6, 0x22, 0x75, 0x47, 0xa4, 0x7c, 0xc4, 0xf9, 0x40, 0x4c, 0xd6, - 0xb3, 0x5e, 0x45, 0x37, 0xca, 0x40, 0xbd, 0x3d, 0xfe, 0xd0, 0x48, 0x80, - 0xec, 0x41, 0x1c, 0xfb, 0x0e, 0x20, 0x78, 0x07, 0xe3, 0x5b, 0xa3, 0x7e, - 0x1c, 0x8e, 0x61, 0x1e, 0x4f, 0x85, 0x0f, 0xf9, 0xbe, 0x0d, 0x41, 0x07, - 0xa2, 0x08, 0x8e, 0xa3, 0x2d, 0x63, 0xd1, 0x50, 0x24, 0xe6, 0x57, 0x2b, - 0x82, 0x83, 0xd3, 0x20, 0x6a, 0x8d, 0x6b, 0xe7, 0x41, 0x11, 0xfa, 0x9c, - 0x47, 0x85, 0x07, 0xa6, 0x79, 0x4b, 0x98, 0x93, 0x54, 0x74, 0x0f, 0xf1, - 0x6c, 0xd9, 0x42, 0x72, 0x93, 0xb5, 0x87, 0x02, 0xe1, 0x7d, 0xd8, 0x36, - 0xac, 0x61, 0xf6, 0x02, 0x1b, 0x3f, 0xe3, 0x48, 0xc8, 0xb8, 0x18, 0x36, - 0x47, 0x78, 0x7b, 0xa4, 0x9f, 0x77, 0x2d, 0x72, 0x47, 0xf6, 0xee, 0x85, - 0x6f, 0x37, 0x1e, 0x6e, 0x4a, 0x6e, 0x6b, 0x71, 0xca, 0x8f, 0x84, 0x93, - 0x6f, 0x07, 0x9b, 0xe4, 0xbe, 0x85, 0x78, 0x35, 0x2e, 0x6a, 0x0e, 0xc4, - 0xb1, 0x0a, 0x0e, 0xb3, 0x17, 0x8e, 0x0b, 0xb5, 0xa7, 0x9a, 0x72, 0x26, - 0x5d, 0x75, 0xde, 0xb8, 0xa8, 0xdb, 0x3f, 0x1a, 0x48, 0x06, 0x28, 0x15, - 0x71, 0x4c, 0xf6, 0x72, 0xe4, 0xd3, 0x8b, 0xe8, 0x4e, 0x44, 0xa2, 0x51, - 0x88, 0x0a, 0xb1, 0xab, 0xc8, 0x76, 0x4c, 0xb8, 0xce, 0xa3, 0x13, 0x61, - 0x78, 0xe6, 0x21, 0xca, 0x89, 0x98, 0xdf, 0xfb, 0x50, 0x6e, 0x24, 0xed, - 0x84, 0x41, 0xd9, 0x91, 0xb0, 0x5c, 0x59, 0xca, 0xbf, 0x32, 0x23, 0xe1, - 0xe4, 0xb2, 0xc8, 0x91, 0xac, 0xf4, 0xe0, 0x28, 0x46, 0xdd, 0x21, 0x93, - 0x70, 0xed, 0x0c, 0x3e, 0xb3, 0xc8, 0xac, 0xb0, 0xe8, 0x0e, 0x5e, 0x1c, - 0x48, 0x6e, 0xa9, 0x59, 0x48, 0x62, 0xd3, 0x59, 0x8f, 0x15, 0x33, 0x28, - 0x75, 0x48, 0x24, 0x75, 0x3a, 0xd9, 0x15, 0x18, 0x46, 0x5d, 0x32, 0x69, - 0x3e, 0xa5, 0xa0, 0x0d, 0x6a, 0xde, 0x65, 0x1b, 0xec, 0x11, 0xe5, 0x20, - 0xb6, 0xa8, 0x5c, 0x24, 0x39, 0xd1, 0xb4, 0xe5, 0xb1, 0x20, 0x1a, 0x89, - 0x8e, 0x84, 0xa6, 0x3d, 0x2f, 0xe4, 0x63, 0xf7, 0x4b, 0xa4, 0xbd, 0x5f, - 0x23, 0x47, 0x4c, 0xbd, 0xc3, 0xa5, 0xa2, 0x18, 0xb6, 0x18, 0x78, 0x48, - 0x6c, 0xfa, 0xd7, 0xbb, 0x34, 0x3f, 0x26, 0x9b, 0x38, 0xcd, 0x31, 0xcc, - 0xa9, 0xb4, 0xdc, 0x15, 0xca, 0xc6, 0xa9, 0x8b, 0xa7, 0x45, 0x8e, 0x3b, - 0x59, 0xe0, 0x27, 0x94, 0x1b, 0xe7, 0x9d, 0x36, 0xf5, 0xbe, 0x95, 0xb2, - 0xe3, 0x7a, 0xa7, 0x94, 0x1b, 0x6c, 0xa1, 0x39, 0xd5, 0xaa, 0x7a, 0x2c, - 0x57, 0xdc, 0x8c, 0xf8, 0x14, 0x1b, 0x21, 0x15, 0x40, 0xda, 0x3a, 0xcc, - 0x67, 0x30, 0xf6, 0x95, 0xb8, 0xaa, 0x86, 0x4b, 0x44, 0x9b, 0x70, 0x14, - 0xe4, 0xf5, 0x37, 0x1b, 0xa9, 0x29, 0xdf, 0xea, 0x49, 0xbb, 0xd4, 0x26, - 0x42, 0x0e, 0x4e, 0x71, 0x9b, 0x67, 0xc6, 0x93, 0xdb, 0x46, 0x23, 0x36, - 0x83, 0xc6, 0xc0, 0x90, 0x7f, 0x34, 0x88, 0x75, 0x34, 0x2e, 0x4e, 0xdb, - 0x4d, 0xe6, 0x4d, 0x29, 0xe6, 0x13, 0x86, 0x3f, 0x21, 0x7b, 0xe3, 0x0b, - 0xe0, 0xb0, 0x11, 0x43, 0x8c, 0x4a, 0xee, 0x28, 0x38, 0x77, 0x50, 0x56, - 0x5c, 0x6d, 0x1e, 0x5b, 0x64, 0xa8, 0x8d, 0xa7, 0x6d, 0x1a, 0xce, 0x64, - 0x12, 0xc3, 0xc1, 0x83, 0xb5, 0x23, 0x18, 0x0a, 0x6d, 0x89, 0x24, 0xa4, - 0x9f, 0x5a, 0xe3, 0x58, 0xab, 0x68, 0x38, 0x9e, 0xa9, 0x88, 0x96, 0xc3, - 0xa9, 0x54, 0x44, 0x43, 0x16, 0x1e, 0x70, 0xd5, 0x49, 0xae, 0x2a, 0x27, - 0x8e, 0x45, 0x30, 0x9e, 0xcc, 0x8a, 0x8f, 0xf4, 0x27, 0x2f, 0xde, 0x94, - 0x89, 0x44, 0x5c, 0x5e, 0x43, 0x51, 0x6b, 0xaa, 0xcb, 0x64, 0x4f, 0xa8, - 0x43, 0xcc, 0xa2, 0x44, 0xfa, 0xd1, 0x65, 0xe3, 0xc4, 0x03, 0xd9, 0x92, - 0x29, 0x0c, 0x26, 0x9d, 0xcf, 0x4a, 0x26, 0x1b, 0x4d, 0x73, 0xd8, 0x59, - 0xf6, 0x0f, 0x58, 0x72, 0xb8, 0x5d, 0x38, 0xd9, 0x2e, 0xed, 0xa4, 0xb2, - 0x60, 0xb2, 0xde, 0xbc, 0xe1, 0x4f, 0xd1, 0xad, 0xf4, 0xfd, 0xdf, 0x33, - 0xc1, 0xa0, 0x75, 0x52, 0xcc, 0x9e, 0x64, 0x31, 0x29, 0x4c, 0x4f, 0x1c, - 0x9a, 0xee, 0xa9, 0xdc, 0x77, 0x62, 0x87, 0xbb, 0xa7, 0x71, 0x17, 0x7b, - 0x62, 0x28, 0x88, 0xdb, 0xa3, 0xa6, 0x15, 0x94, 0x91, 0x88, 0xa8, 0xb7, - 0x07, 0x64, 0xc1, 0xe4, 0xd2, 0xe2, 0x91, 0xe8, 0x20, 0x16, 0x7b, 0xf2, - 0x94, 0x9a, 0xf2, 0x69, 0xde, 0xdd, 0xf4, 0x79, 0xf4, 0x5c, 0x65, 0xa2, - 0x52, 0xfa, 0xfc, 0xcb, 0x26, 0xea, 0x70, 0xc3, 0x86, 0xa9, 0x33, 0xee, - 0x42, 0xb3, 0xe9, 0x14, 0xfa, 0xc5, 0x66, 0x7d, 0x5a, 0x5d, 0x29, 0x13, - 0xdb, 0xa8, 0xdc, 0xcf, 0x1c, 0x92, 0x6c, 0xdd, 0x4b, 0xd6, 0x51, 0x79, - 0x8a, 0xe3, 0xa7, 0x39, 0x18, 0xba, 0x46, 0x27, 0x9e, 0x9f, 0x3e, 0x2f, - 0x2e, 0xbb, 0xac, 0xb9, 0xf6, 0x92, 0x22, 0x8e, 0x33, 0xb8, 0xc1, 0x14, - 0xad, 0x2e, 0x82, 0x27, 0x15, 0xad, 0x28, 0x1a, 0x40, 0x8b, 0x83, 0x21, - 0xb9, 0xd9, 0x95, 0x0e, 0x23, 0x1c, 0x40, 0x11, 0x43, 0xcd, 0xfe, 0x78, - 0x00, 0x4a, 0x6c, 0xf7, 0xa5, 0xb8, 0x97, 0x21, 0x32, 0x8d, 0x0c, 0xc7, - 0x8b, 0x56, 0xef, 0xf5, 0x87, 0xe2, 0x81, 0x15, 0x45, 0xc3, 0xc1, 0x70, - 0xa9, 0x3f, 0x1a, 0x2c, 0x5a, 0x5d, 0x59, 0xb5, 0xa2, 0x28, 0x3e, 0xe4, - 0x2f, 0xad, 0x40, 0x26, 0x7f, 0x8d, 0x7f, 0xb0, 0xa2, 0xd6, 0x5f, 0xe3, - 0xad, 0x5a, 0xe5, 0xed, 0xaf, 0xa9, 0xab, 0x1b, 0xf4, 0x56, 0xd5, 0x56, - 0x06, 0xaa, 0xea, 0x6a, 0x06, 0x2a, 0xbc, 0x75, 0xfe, 0x9a, 0xea, 0xfe, - 0xbd, 0x35, 0x7b, 0xeb, 0x2a, 0x06, 0xb9, 0x54, 0x34, 0x27, 0x8e, 0xea, - 0x90, 0xa9, 0xb6, 0xac, 0xc2, 0x5b, 0x56, 0x57, 0x3a, 0x18, 0x18, 0x2d, - 0xba, 0x94, 0x8c, 0x55, 0xe2, 0x72, 0xcb, 0xec, 0x6a, 0xa3, 0xc6, 0xf8, - 0x96, 0x28, 0x76, 0xda, 0xbf, 0x6a, 0x14, 0x26, 0xc4, 0x5a, 0x32, 0x56, - 0x43, 0x3a, 0x3f, 0xa3, 0xd0, 0x51, 0x58, 0x57, 0x98, 0x59, 0x18, 0x2f, - 0x6c, 0x28, 0x0c, 0xe2, 0x2f, 0x5b, 0x5a, 0x59, 0xe7, 0xc2, 0x28, 0x77, - 0x9c, 0x75, 0x19, 0x75, 0x60, 0xe7, 0x1b, 0xc5, 0x2e, 0x97, 0x95, 0xbe, - 0x66, 0xcc, 0x37, 0x16, 0x2e, 0x54, 0xd9, 0xed, 0xc8, 0x3e, 0x5c, 0x38, - 0x13, 0xd9, 0xb7, 0x14, 0x66, 0x29, 0x7b, 0x37, 0xec, 0x17, 0x2a, 0x7b, - 0x01, 0x7b, 0x58, 0x8b, 0x85, 0xaa, 0x05, 0x95, 0xca, 0xc0, 0x80, 0xc1, - 0xd8, 0xb8, 0xed, 0x22, 0xa3, 0x96, 0x4b, 0x12, 0xb3, 0x2b, 0xc6, 0x8b, - 0x4c, 0xb6, 0x26, 0x47, 0x99, 0x65, 0xc2, 0xec, 0x50, 0x52, 0x9b, 0x61, - 0xd2, 0xca, 0x9c, 0xf6, 0xd9, 0x95, 0xb3, 0xbd, 0xb3, 0x57, 0xce, 0xae, - 0x9a, 0x5d, 0x3e, 0x9b, 0xbf, 0xe1, 0x23, 0xfa, 0x8f, 0xf1, 0xc7, 0xfd, - 0x42, 0xac, 0x3b, 0x76, 0xda, 0xfa, 0x62, 0x69, 0x43, 0xfe, 0x3b, 0xa5, - 0x9c, 0x5a, 0x8f, 0xd4, 0x35, 0x65, 0x8d, 0xf9, 0xb7, 0x96, 0x71, 0xaa, - 0x09, 0xa9, 0x07, 0xcb, 0x9a, 0xf3, 0x9f, 0x29, 0x23, 0xab, 0xdd, 0x9e, - 0x65, 0x08, 0x37, 0xff, 0xb5, 0x1c, 0x3b, 0x6a, 0x7d, 0xa5, 0xdc, 0xe2, - 0x7c, 0xb3, 0xcc, 0xe6, 0xbc, 0x7a, 0xa5, 0x70, 0x3e, 0x03, 0xbc, 0x03, - 0x5c, 0x5f, 0xb5, 0x41, 0x5c, 0xe3, 0x15, 0xe2, 0xb4, 0xd7, 0x10, 0x0f, - 0x81, 0xbe, 0x02, 0x1c, 0xad, 0x40, 0xba, 0x82, 0xac, 0xc2, 0xc8, 0x33, - 0x84, 0xfc, 0xdb, 0x76, 0xf4, 0xa8, 0xf5, 0xcd, 0xea, 0x2e, 0x71, 0xcd, - 0x2a, 0x58, 0x54, 0x91, 0x21, 0xac, 0x05, 0x27, 0x3d, 0xc2, 0xbd, 0x1d, - 0x85, 0x3e, 0x55, 0xd7, 0x23, 0x9e, 0x83, 0xf8, 0xbe, 0x3a, 0x21, 0xde, - 0xab, 0x11, 0xe2, 0xcd, 0x5a, 0xa8, 0xc5, 0x4c, 0x43, 0x9c, 0xf4, 0xf4, - 0x22, 0xd7, 0xdb, 0x75, 0x7d, 0xe2, 0xfa, 0xd5, 0x64, 0xb1, 0x53, 0x21, - 0xe7, 0x10, 0xee, 0xdd, 0xc8, 0xf3, 0x46, 0xbd, 0xb8, 0xda, 0x73, 0x6a, - 0x0d, 0x1e, 0x67, 0xf8, 0xf1, 0x54, 0xbd, 0x30, 0x1e, 0x5d, 0x23, 0x8c, - 0xb7, 0xd7, 0xa0, 0xf9, 0x59, 0x73, 0xdd, 0x03, 0x30, 0x39, 0xb5, 0x6e, - 0x50, 0xdc, 0xbf, 0x56, 0x88, 0xe7, 0x80, 0xf7, 0x80, 0x53, 0xe7, 0x0b, - 0x71, 0x3f, 0xf0, 0x1e, 0xf0, 0x1c, 0x70, 0xdf, 0x3a, 0xc8, 0x20, 0x7f, - 0x0a, 0xf4, 0xcd, 0x75, 0xe4, 0xa8, 0x59, 0x3c, 0xcf, 0x2d, 0xdb, 0xea, - 0x56, 0x7f, 0x91, 0x8f, 0x79, 0x1e, 0x6b, 0x17, 0x1f, 0xf3, 0x9c, 0xe5, - 0xc7, 0xdf, 0xda, 0x05, 0x8a, 0xbc, 0xbe, 0x03, 0x75, 0xbd, 0xb3, 0x1e, - 0x8f, 0xc7, 0x36, 0xe1, 0x71, 0xdf, 0x56, 0x7e, 0xb4, 0x73, 0x92, 0xb9, - 0xab, 0x1b, 0xf0, 0x38, 0xd9, 0x88, 0xc7, 0x2b, 0x6d, 0x78, 0xfc, 0x8d, - 0x1f, 0x6f, 0xb0, 0xdd, 0x5d, 0x2c, 0x3b, 0xcb, 0x26, 0xa7, 0xd8, 0xf8, - 0x6f, 0xcc, 0x1d, 0x6f, 0xc5, 0xe3, 0x34, 0x3f, 0x1e, 0xe4, 0xc7, 0x73, - 0xad, 0xf6, 0xcb, 0x0d, 0x12, 0x80, 0xc5, 0x38, 0xb5, 0x89, 0xa9, 0xc1, - 0x70, 0xbe, 0xd3, 0xca, 0xd4, 0x71, 0x42, 0xe9, 0xa6, 0xc5, 0x89, 0x71, - 0x18, 0x5a, 0x36, 0x0b, 0x70, 0x9e, 0x48, 0xd7, 0x7d, 0x20, 0x60, 0x7f, - 0xa5, 0x10, 0xd7, 0x77, 0x0a, 0xf1, 0x10, 0xf0, 0x22, 0xf0, 0x68, 0xa3, - 0x10, 0x27, 0xb7, 0x59, 0xc4, 0xad, 0x0d, 0x76, 0x7a, 0x74, 0xfd, 0x4c, - 0x7a, 0x74, 0x9b, 0x85, 0x5e, 0xe9, 0xc2, 0xec, 0xfa, 0xa0, 0x87, 0xee, - 0x1d, 0xe0, 0x41, 0xf0, 0x4f, 0x01, 0x67, 0x81, 0x93, 0xdb, 0x91, 0x06, - 0x9e, 0x02, 0xce, 0x32, 0xdf, 0x80, 0xd1, 0x06, 0xfd, 0x52, 0x0f, 0x46, - 0xba, 0x09, 0xa3, 0x0c, 0x9c, 0x6d, 0x46, 0xbe, 0x16, 0x61, 0x7d, 0xae, - 0x47, 0x58, 0xdf, 0x84, 0xfc, 0xae, 0x0d, 0x36, 0x71, 0xf3, 0x0e, 0x94, - 0xb7, 0xd3, 0x10, 0x6f, 0x03, 0xd7, 0xef, 0x52, 0xff, 0xf7, 0x75, 0x0b, - 0xd1, 0x2b, 0xc0, 0x9b, 0x5b, 0xd4, 0xf7, 0x17, 0xde, 0xda, 0xa2, 0xbe, - 0x87, 0xc0, 0x72, 0xfb, 0xd6, 0x71, 0x3e, 0x7f, 0xab, 0xd2, 0xcf, 0xd7, - 0xb4, 0xcc, 0xa4, 0x5b, 0xaf, 0x65, 0x1d, 0x5a, 0xd6, 0x07, 0xda, 0xbf, - 0x95, 0x52, 0xe5, 0x0f, 0x83, 0x1f, 0xd3, 0x36, 0xc7, 0x4c, 0xf9, 0xae, - 0xd7, 0xb2, 0xcf, 0x6b, 0x7a, 0x2f, 0x68, 0xa8, 0x8b, 0xd2, 0xfe, 0x1d, - 0xd7, 0xe9, 0xe4, 0x37, 0xc4, 0xf9, 0x3b, 0x9b, 0x47, 0x20, 0x3b, 0x39, - 0xc1, 0xee, 0x2e, 0x9d, 0x4e, 0x7e, 0xc3, 0x8d, 0x7f, 0x07, 0xec, 0xe6, - 0x2e, 0xf5, 0x3b, 0x60, 0xb7, 0x82, 0x3e, 0x34, 0xa1, 0x1c, 0xfe, 0x4d, - 0xb0, 0xfb, 0x21, 0x7b, 0x6c, 0x82, 0x7c, 0xb7, 0xce, 0x77, 0x76, 0x82, - 0x9c, 0xff, 0x7f, 0xc1, 0x8b, 0x90, 0xbd, 0x37, 0x41, 0xce, 0xbf, 0x93, - 0xf0, 0x76, 0xd7, 0xf8, 0xef, 0x65, 0x09, 0x13, 0x4d, 0xfe, 0x26, 0x27, - 0xb7, 0x29, 0xf9, 0xbb, 0x9c, 0x3c, 0x26, 0xc9, 0xdf, 0xe6, 0xe4, 0xef, - 0x73, 0x24, 0x7f, 0x9f, 0x93, 0xbf, 0xeb, 0x91, 0xfc, 0x8d, 0x4e, 0xfe, - 0xde, 0x4b, 0xf2, 0x77, 0x3a, 0x85, 0x47, 0xfd, 0x16, 0x19, 0xff, 0x56, - 0xa7, 0xc5, 0xa3, 0x7e, 0x17, 0x8d, 0xff, 0x7f, 0xb3, 0x70, 0xa9, 0xef, - 0xa4, 0xf0, 0xff, 0x23, 0x37, 0x3c, 0xaa, 0x2e, 0xfe, 0x2d, 0x4f, 0xab, - 0x47, 0x7d, 0xb7, 0x97, 0xc7, 0x97, 0x3c, 0xaa, 0x1c, 0xfe, 0xff, 0xeb, - 0x16, 0x97, 0xfa, 0xbe, 0x1f, 0x8f, 0xaf, 0xdd, 0xa3, 0xbe, 0x8b, 0x24, - 0x7f, 0x34, 0xcd, 0xa5, 0x7f, 0x4b, 0x0c, 0xfc, 0xff, 0x03, 0x2a, 0xad, - 0xa4, 0x32, 0x7c, 0x54, 0x00, 0x00 + 0x0b, 0x7c, 0xdc, 0x45, 0xb5, 0xff, 0x99, 0xdf, 0xbe, 0x92, 0xcd, 0x26, + 0xd9, 0xdd, 0x34, 0x4d, 0xfa, 0xde, 0x86, 0xb4, 0xa4, 0xd0, 0x4d, 0x36, + 0x69, 0xd3, 0x26, 0x4d, 0x1f, 0x69, 0xd3, 0xa4, 0x4d, 0x9a, 0xb6, 0x69, + 0xb3, 0x0d, 0x6d, 0x52, 0x68, 0x37, 0xc9, 0xb6, 0x59, 0xba, 0xd9, 0xdd, + 0xec, 0x6e, 0xd2, 0x96, 0xd7, 0x2d, 0x50, 0x6d, 0xa9, 0xa0, 0x55, 0x41, + 0x1e, 0x56, 0x41, 0xde, 0x60, 0x51, 0xbc, 0x56, 0xe5, 0x82, 0x0f, 0x50, + 0x50, 0x54, 0xae, 0xa2, 0x82, 0x82, 0x22, 0x70, 0x05, 0xbd, 0xa8, 0xc8, + 0x43, 0xf1, 0xc2, 0xf5, 0xc5, 0xff, 0x7b, 0x66, 0x66, 0x37, 0xbf, 0x6d, + 0x1a, 0xd0, 0xff, 0x4d, 0x3e, 0xdf, 0xdf, 0x39, 0x73, 0xce, 0x99, 0xf7, + 0x99, 0x33, 0x33, 0xbf, 0xdd, 0x64, 0x30, 0x7c, 0xc0, 0x19, 0x58, 0xb4, + 0x94, 0x12, 0x53, 0x7f, 0xfb, 0x97, 0x44, 0xf7, 0xd6, 0xcf, 0x74, 0x7d, + 0x2b, 0x78, 0xdf, 0x47, 0x2e, 0xbd, 0xf7, 0x73, 0x2b, 0x1e, 0x3b, 0xe6, + 0xdd, 0xba, 0x74, 0x59, 0xca, 0xdd, 0x4d, 0x94, 0x20, 0xa2, 0x03, 0x3d, + 0x8b, 0xbd, 0xa4, 0x7f, 0x3a, 0xb7, 0x12, 0x5d, 0x26, 0x94, 0x7c, 0x1d, + 0x30, 0x64, 0x27, 0x8a, 0x83, 0x1e, 0x76, 0x10, 0x55, 0x80, 0x3e, 0xe0, + 0x22, 0xfa, 0x2d, 0xe8, 0xe3, 0x85, 0x44, 0x05, 0xa0, 0xee, 0x52, 0xa2, + 0x5b, 0x96, 0xc3, 0x7e, 0x2a, 0xd1, 0x57, 0x6b, 0x89, 0xbe, 0x0e, 0x3c, + 0x02, 0x3c, 0x0a, 0x7c, 0x07, 0x78, 0x1d, 0x28, 0xab, 0x23, 0x5a, 0x05, + 0xac, 0x01, 0xda, 0x80, 0x76, 0x60, 0x0b, 0xb0, 0x0d, 0xe8, 0x03, 0x06, + 0x80, 0x24, 0x70, 0x0c, 0xf8, 0x04, 0x70, 0x2f, 0x70, 0x1f, 0xf0, 0x05, + 0xe0, 0x14, 0xf0, 0x00, 0xf0, 0x55, 0xe0, 0x11, 0xe0, 0x31, 0xe0, 0x7b, + 0xc0, 0x0f, 0x80, 0x1f, 0x01, 0x4f, 0x03, 0xcf, 0x02, 0xef, 0x00, 0x9e, + 0x45, 0x44, 0x53, 0x80, 0x72, 0x60, 0x16, 0x30, 0x17, 0x98, 0x0f, 0x2c, + 0x04, 0x02, 0x40, 0x3d, 0xb0, 0x0c, 0x68, 0x06, 0xb6, 0x03, 0x1f, 0x06, + 0xee, 0x01, 0x1e, 0x05, 0x5e, 0x00, 0xde, 0x05, 0xe6, 0x2c, 0x26, 0xea, + 0x00, 0x06, 0x81, 0xcb, 0x80, 0xeb, 0x81, 0x2f, 0x02, 0x8f, 0x03, 0xcf, + 0x03, 0x6f, 0x03, 0x9e, 0x7a, 0x22, 0x3f, 0xb0, 0x0e, 0x88, 0x01, 0xc7, + 0x80, 0x9b, 0x81, 0x53, 0xc0, 0x8b, 0xc0, 0x3f, 0x80, 0xb2, 0x25, 0x44, + 0x8b, 0x80, 0x0b, 0x80, 0x14, 0x70, 0x0d, 0xf0, 0x18, 0xf0, 0x1b, 0xe0, + 0xef, 0xc0, 0x9c, 0xa5, 0x18, 0x0b, 0xe0, 0x20, 0x70, 0x1f, 0xf0, 0x6b, + 0xa0, 0xb4, 0x81, 0x68, 0x39, 0x30, 0x04, 0x5c, 0x0f, 0x3c, 0x05, 0x78, + 0x1a, 0x89, 0x36, 0x01, 0xff, 0x06, 0xdc, 0x07, 0xbc, 0x06, 0x2c, 0x59, + 0x46, 0x34, 0x02, 0x7c, 0x06, 0x78, 0x0a, 0x78, 0x1b, 0x98, 0xd1, 0x44, + 0xd4, 0x04, 0x5c, 0x00, 0x1c, 0x06, 0x6e, 0x03, 0xbe, 0x06, 0x3c, 0x0f, + 0xfc, 0x09, 0x70, 0x60, 0x8e, 0x66, 0x00, 0x75, 0xc0, 0x7a, 0xa0, 0x17, + 0x88, 0x02, 0x17, 0x01, 0x57, 0x02, 0xd7, 0x02, 0xb7, 0x02, 0x77, 0x00, + 0xf7, 0x00, 0x9f, 0x03, 0x4e, 0x01, 0x0f, 0x01, 0x0f, 0x03, 0x8f, 0x02, + 0x4f, 0x00, 0x3f, 0x06, 0x9e, 0x05, 0x9e, 0x07, 0x5e, 0x02, 0x7e, 0x0b, + 0xbc, 0x06, 0xfc, 0x11, 0x78, 0x1b, 0xf8, 0x3b, 0x60, 0x5d, 0x41, 0x94, + 0x0f, 0x14, 0x01, 0xa5, 0xc0, 0x6c, 0xa0, 0x12, 0x58, 0x00, 0xd4, 0x00, + 0xf5, 0x40, 0x13, 0xb0, 0x0a, 0x58, 0x07, 0x74, 0x00, 0x9b, 0x81, 0x6d, + 0x40, 0x2f, 0x70, 0x01, 0x10, 0x06, 0xf6, 0x01, 0x71, 0x20, 0x0d, 0x5c, + 0x02, 0x5c, 0x09, 0x1c, 0x01, 0x3e, 0x04, 0x7c, 0x04, 0xf8, 0x24, 0x70, + 0x17, 0x70, 0x0a, 0x78, 0x04, 0xf8, 0x01, 0xf0, 0x0b, 0xe0, 0x15, 0xe0, + 0xcf, 0x80, 0xb1, 0x92, 0xa8, 0x18, 0x98, 0x09, 0x2c, 0x00, 0xea, 0x81, + 0x35, 0xc0, 0x26, 0xa0, 0x17, 0xd8, 0x03, 0x24, 0x81, 0xcb, 0x80, 0x63, + 0xc0, 0x27, 0x80, 0xdb, 0x80, 0x7f, 0x07, 0x1e, 0x07, 0x9e, 0x06, 0x7e, + 0x0e, 0xfc, 0x19, 0x70, 0xac, 0x22, 0x9a, 0x0e, 0xf8, 0x81, 0x7a, 0x60, + 0x05, 0xb0, 0x19, 0xb8, 0x00, 0x08, 0x03, 0x63, 0xc0, 0x47, 0x80, 0x13, + 0xc0, 0x49, 0xe0, 0x21, 0xe0, 0x47, 0xc0, 0x6b, 0xc0, 0xdb, 0x80, 0x68, + 0xc6, 0x7a, 0x01, 0xfc, 0x40, 0x03, 0xd0, 0x06, 0x0c, 0x00, 0x97, 0x03, + 0x57, 0x03, 0x27, 0x80, 0xfb, 0x80, 0x47, 0x81, 0x9f, 0x02, 0xaf, 0x02, + 0x7f, 0x05, 0xdc, 0xab, 0x89, 0xce, 0x06, 0x16, 0x01, 0xab, 0x81, 0x4d, + 0xc0, 0x4e, 0x60, 0x3f, 0x70, 0x23, 0x70, 0x3b, 0xf0, 0x0d, 0xe0, 0x19, + 0xe0, 0x0f, 0x80, 0x75, 0x0d, 0xfc, 0x1d, 0x68, 0x04, 0x3a, 0x80, 0x5d, + 0xc0, 0x30, 0x70, 0x09, 0x70, 0x0d, 0xf0, 0x49, 0xe0, 0x76, 0xe0, 0x3e, + 0xe0, 0x41, 0xe0, 0xfb, 0xc0, 0xf3, 0xc0, 0x1b, 0x80, 0xa3, 0x05, 0x7e, + 0x0b, 0x2c, 0x00, 0x56, 0x02, 0x9b, 0x80, 0x01, 0x20, 0x09, 0x5c, 0x03, + 0x7c, 0x0a, 0x78, 0x08, 0x78, 0x04, 0xf8, 0x0e, 0xf0, 0x43, 0xe0, 0xb7, + 0xc0, 0x5f, 0x00, 0xd7, 0x5a, 0xcc, 0x33, 0xe0, 0x07, 0x96, 0x03, 0xed, + 0xc0, 0x2e, 0x20, 0x01, 0x5c, 0x0e, 0x1c, 0x07, 0xee, 0x01, 0xbe, 0x0c, + 0x7c, 0x1f, 0x78, 0x05, 0x78, 0x13, 0x78, 0x1b, 0xb0, 0xb5, 0x22, 0x2f, + 0x50, 0x05, 0x54, 0x03, 0xcb, 0x80, 0x0d, 0x40, 0x2f, 0xb0, 0x0f, 0x18, + 0x03, 0x0e, 0x03, 0xd7, 0x03, 0x9f, 0x01, 0x3e, 0x0b, 0x7c, 0x1d, 0x78, + 0x16, 0x78, 0x19, 0x78, 0x0d, 0x70, 0xb4, 0x11, 0x4d, 0x05, 0x66, 0x01, + 0xf3, 0x80, 0x73, 0x81, 0x3a, 0xa0, 0x01, 0x68, 0x03, 0x36, 0x01, 0xfd, + 0xc0, 0x28, 0x70, 0x0c, 0x38, 0x01, 0x7c, 0x1e, 0x78, 0x02, 0x78, 0x01, + 0xf8, 0x23, 0x50, 0x80, 0x80, 0x57, 0x02, 0x54, 0x00, 0x75, 0x40, 0x33, + 0xb0, 0x01, 0xe8, 0x05, 0x06, 0x80, 0x61, 0xe0, 0x12, 0xe0, 0x2a, 0xe0, + 0x06, 0xe0, 0x2e, 0xe0, 0xcb, 0xc0, 0xa3, 0xc0, 0x13, 0xc0, 0x4f, 0x80, + 0x5f, 0x01, 0x62, 0x3d, 0xe2, 0x10, 0x30, 0x0b, 0x58, 0x0d, 0xec, 0x02, + 0xf6, 0x01, 0x07, 0x81, 0xcb, 0x80, 0x0f, 0x03, 0x27, 0x80, 0x2f, 0x01, + 0xdf, 0x07, 0x5e, 0x04, 0x5e, 0x03, 0x6c, 0xed, 0x88, 0x0b, 0x80, 0x1f, + 0x58, 0x02, 0x6c, 0x06, 0xf6, 0x00, 0x97, 0x02, 0x37, 0x01, 0x5f, 0x04, + 0x1e, 0x06, 0x7e, 0x08, 0xfc, 0x02, 0xf8, 0x3d, 0xf0, 0x26, 0xf0, 0x2e, + 0x50, 0xd4, 0x81, 0x31, 0x04, 0xfc, 0xc0, 0x32, 0xa0, 0x15, 0xd8, 0x02, + 0xec, 0x00, 0x2e, 0x02, 0x6e, 0x06, 0xbe, 0x0b, 0xbc, 0x09, 0x78, 0x36, + 0x20, 0x1e, 0x02, 0x5b, 0x80, 0x14, 0x70, 0x1d, 0xf0, 0x20, 0xf0, 0x2b, + 0xe0, 0x77, 0xc0, 0x1f, 0x81, 0xbf, 0x01, 0xa2, 0x13, 0xeb, 0x16, 0xd8, + 0x0c, 0xc4, 0x81, 0x8f, 0x01, 0x37, 0x02, 0xb7, 0x02, 0x77, 0x03, 0xff, + 0x01, 0x7c, 0x1f, 0xe0, 0xcd, 0x63, 0x0a, 0x30, 0x03, 0x38, 0x07, 0x38, + 0x17, 0x58, 0x08, 0xf8, 0x81, 0x6a, 0xa0, 0x06, 0x08, 0x00, 0xd8, 0x0a, + 0x08, 0x61, 0x9a, 0x10, 0x66, 0x09, 0x61, 0x94, 0x10, 0x26, 0x09, 0xa1, + 0x90, 0x10, 0xfa, 0x08, 0xa1, 0x8e, 0x10, 0xda, 0x08, 0xa1, 0x8c, 0x10, + 0xae, 0x08, 0x61, 0x84, 0xb0, 0x84, 0x09, 0x4b, 0x8f, 0xb0, 0x0c, 0x08, + 0xae, 0x4d, 0x70, 0x51, 0x82, 0xab, 0x11, 0x5c, 0x86, 0x30, 0xe5, 0xd4, + 0xa6, 0xf7, 0x28, 0x0c, 0x1d, 0x61, 0x08, 0x08, 0x5d, 0xa3, 0x0d, 0xbc, + 0x87, 0x01, 0x1b, 0x81, 0x4d, 0xc0, 0x66, 0xa0, 0x0b, 0xd8, 0x02, 0x60, + 0x6b, 0x23, 0x6c, 0x79, 0x14, 0x04, 0xb6, 0x01, 0x3d, 0xc0, 0x79, 0xc0, + 0x76, 0x60, 0x07, 0xd0, 0x0b, 0xf4, 0x01, 0x3b, 0x81, 0xf3, 0x81, 0x0b, + 0x80, 0x5d, 0xc0, 0x6e, 0x20, 0x04, 0xf4, 0x03, 0x03, 0xc0, 0x20, 0x10, + 0x06, 0xf6, 0x00, 0x7b, 0x79, 0x8f, 0x04, 0x22, 0xc0, 0x85, 0xa4, 0xf6, + 0xcd, 0x6b, 0x80, 0x1b, 0x81, 0x9b, 0x48, 0x8d, 0x4d, 0xe6, 0xa7, 0x44, + 0xd3, 0x40, 0x8d, 0x1a, 0x2f, 0xa1, 0xd3, 0x53, 0x35, 0xcf, 0xf2, 0x32, + 0xcd, 0x37, 0x80, 0x2f, 0xd7, 0x7c, 0x33, 0xf8, 0x69, 0x9a, 0x5f, 0x0f, + 0x7e, 0xba, 0xe6, 0xbb, 0x4c, 0xfc, 0x76, 0x13, 0xbf, 0xbb, 0x46, 0xcd, + 0x85, 0xa1, 0xcb, 0x9f, 0xa9, 0x79, 0x2e, 0x67, 0x96, 0xe6, 0x87, 0xc0, + 0xfb, 0x40, 0xed, 0xda, 0x66, 0x3e, 0x90, 0xc7, 0xed, 0xd7, 0x72, 0xb7, + 0x96, 0x33, 0xef, 0x31, 0xf1, 0xd3, 0x4c, 0xfc, 0x2c, 0xcd, 0x57, 0x6a, + 0xfe, 0x00, 0xf2, 0x2e, 0xd0, 0xfc, 0x21, 0x5d, 0x8e, 0xcf, 0x64, 0x7f, + 0x96, 0x89, 0x9f, 0xa7, 0xf9, 0xb9, 0x9a, 0xe7, 0xbe, 0x9f, 0xad, 0xf9, + 0xab, 0x75, 0xde, 0xf9, 0xa6, 0xb6, 0x71, 0xb9, 0xd7, 0x6a, 0xf9, 0x39, + 0x5a, 0xce, 0xe5, 0x2d, 0xd6, 0xfd, 0x62, 0x1b, 0xf6, 0xa7, 0x13, 0x35, + 0xea, 0x9c, 0xd2, 0xa4, 0xc7, 0x90, 0xcb, 0x5f, 0xa1, 0xcb, 0x3f, 0x4b, + 0xf3, 0x6c, 0x5f, 0xa5, 0xf9, 0xdb, 0x75, 0x99, 0x2b, 0x4d, 0x75, 0x31, + 0x7f, 0x52, 0xcb, 0x57, 0x69, 0x79, 0x85, 0xe6, 0xb9, 0xcc, 0x79, 0x9a, + 0x3f, 0xa5, 0x6d, 0x56, 0x9b, 0xf2, 0xb2, 0x8f, 0x3e, 0xac, 0xfb, 0xc2, + 0xfc, 0xe3, 0x35, 0xca, 0x27, 0x5a, 0xb4, 0xcd, 0x88, 0xe6, 0xb9, 0x3d, + 0x49, 0xcd, 0x73, 0x99, 0x29, 0xcd, 0x3f, 0x09, 0x3e, 0xad, 0xf9, 0xe7, + 0xc0, 0x8f, 0x6a, 0xfe, 0x15, 0xf0, 0x63, 0x9a, 0xe7, 0xf6, 0xef, 0xd7, + 0xfc, 0x1b, 0xe0, 0x0f, 0x68, 0x9e, 0xdb, 0x73, 0x30, 0x53, 0x17, 0x16, + 0xdc, 0x45, 0x9a, 0x77, 0x81, 0xbf, 0x44, 0xf3, 0x53, 0xc0, 0x5f, 0xac, + 0x79, 0x9f, 0x89, 0xaf, 0x02, 0x7f, 0x69, 0xa6, 0x6d, 0xe0, 0x2f, 0xcb, + 0xb4, 0x0d, 0xfc, 0x95, 0x99, 0x7a, 0x4d, 0xf2, 0xf5, 0x26, 0xbe, 0x0b, + 0xfc, 0x51, 0xcd, 0x6f, 0x37, 0xc9, 0x07, 0x4d, 0x7c, 0xd4, 0xc4, 0xa7, + 0x4d, 0x3c, 0x8f, 0x55, 0xa6, 0xfc, 0x4b, 0x20, 0x3f, 0xa4, 0xf9, 0xc3, + 0xe0, 0x0f, 0x6b, 0xfe, 0x38, 0xf8, 0x0f, 0x68, 0xfe, 0x84, 0x29, 0xef, + 0x49, 0x53, 0xdb, 0x4e, 0x99, 0xe4, 0x5f, 0x35, 0xf1, 0x8f, 0x82, 0xff, + 0x37, 0xcd, 0xb3, 0x5f, 0x1d, 0xd1, 0xfc, 0x13, 0x26, 0x9b, 0x99, 0x90, + 0x1f, 0xd3, 0xfc, 0x53, 0x26, 0x39, 0xfb, 0xd2, 0x15, 0x9a, 0x67, 0x3f, + 0xf9, 0xa0, 0xe6, 0x5f, 0x34, 0xd5, 0xfb, 0x2a, 0xf8, 0xab, 0x34, 0xff, + 0x96, 0x29, 0x2f, 0xaf, 0xc1, 0xcb, 0x33, 0x73, 0x51, 0x3b, 0x2e, 0x77, + 0xd5, 0x8e, 0xcb, 0xa7, 0xd4, 0x8e, 0x97, 0xe3, 0x33, 0xd9, 0xb0, 0xef, + 0x65, 0xf8, 0x2a, 0xc8, 0x3f, 0x94, 0x99, 0x17, 0xf0, 0x57, 0x67, 0xe6, + 0xc5, 0x64, 0xbf, 0xde, 0xc4, 0x77, 0xd5, 0xaa, 0xf8, 0xb3, 0x56, 0xfb, + 0xdb, 0x87, 0x35, 0xcf, 0x3e, 0xf6, 0x11, 0xcd, 0x6f, 0xaf, 0x1d, 0xe7, + 0x07, 0xc1, 0x1f, 0xd7, 0x7c, 0x02, 0xfc, 0x47, 0x35, 0xcf, 0x3e, 0xf6, + 0x31, 0xcd, 0x1f, 0x80, 0xfc, 0xe3, 0x9a, 0x3f, 0x0c, 0xfe, 0x3a, 0xcd, + 0x1f, 0x07, 0x7f, 0xad, 0xe6, 0x6f, 0x30, 0xc9, 0x79, 0x9c, 0x3f, 0xa1, + 0xf9, 0x5b, 0x20, 0xbf, 0x5e, 0xf3, 0xf7, 0x9b, 0xec, 0x5d, 0x26, 0x9e, + 0xfb, 0x7b, 0x83, 0xe6, 0xb9, 0x8f, 0x85, 0x88, 0x62, 0xff, 0x41, 0x8a, + 0xa6, 0x10, 0xd0, 0x8a, 0x40, 0x87, 0x79, 0x2c, 0xb0, 0xaa, 0xbf, 0xa8, + 0x69, 0xb1, 0x60, 0x2a, 0xc8, 0xa3, 0xa9, 0x57, 0xd3, 0x12, 0x4d, 0xa7, + 0x68, 0x5a, 0x2a, 0x94, 0xbd, 0x4f, 0xf0, 0x5e, 0xb4, 0x8a, 0xbe, 0x45, + 0x4c, 0x3d, 0xf4, 0x6d, 0x49, 0x17, 0xd3, 0xa0, 0x94, 0xd7, 0xd3, 0x45, + 0x82, 0xf7, 0x29, 0x0f, 0x3d, 0x48, 0x4c, 0xab, 0xe9, 0xab, 0x92, 0x2a, + 0x7d, 0x8d, 0xd6, 0x07, 0x40, 0x13, 0x9a, 0x72, 0xba, 0x16, 0x2d, 0x9e, + 0x23, 0x69, 0x1d, 0x8d, 0x08, 0xde, 0xdb, 0x94, 0xbe, 0x4e, 0xeb, 0xeb, + 0xa0, 0xb9, 0x44, 0x70, 0x8c, 0x32, 0xc8, 0x2d, 0x38, 0x3e, 0x55, 0xd2, + 0xbf, 0x13, 0xd3, 0x1a, 0x7a, 0x48, 0xd2, 0x8c, 0xbc, 0x8e, 0x66, 0x4b, + 0x1a, 0xa0, 0x79, 0x92, 0xae, 0xa5, 0x95, 0x92, 0x16, 0xd0, 0x2a, 0x50, + 0x1b, 0x76, 0xc3, 0xb5, 0x82, 0x63, 0x75, 0x21, 0x3d, 0x49, 0x4c, 0x2b, + 0xe9, 0x35, 0xd0, 0x7c, 0xec, 0xb4, 0x4e, 0x49, 0xcf, 0xa7, 0xf5, 0xd0, + 0x3b, 0xb1, 0x53, 0x72, 0xba, 0x40, 0xcb, 0x0b, 0x30, 0x72, 0xed, 0x82, + 0xc7, 0x51, 0xa5, 0x3d, 0xa8, 0x6f, 0xae, 0x60, 0xda, 0x43, 0x6d, 0x92, + 0x9e, 0x47, 0x5b, 0x05, 0xef, 0x51, 0xf9, 0xf4, 0x2a, 0x29, 0xfa, 0x07, + 0x49, 0xd7, 0xd2, 0x16, 0xc8, 0x4b, 0xb1, 0x53, 0x72, 0xbe, 0x32, 0xec, + 0x90, 0x4c, 0xa7, 0x21, 0xc7, 0xaf, 0x24, 0x5d, 0x47, 0x6b, 0x04, 0xef, + 0x37, 0x7e, 0x29, 0x9f, 0x8e, 0x72, 0xff, 0x53, 0xd2, 0x79, 0xf4, 0x13, + 0x9d, 0xfe, 0xb5, 0xa6, 0x7f, 0x22, 0xde, 0x8b, 0x94, 0x9e, 0xe9, 0x0f, + 0x34, 0xfd, 0xa1, 0xa4, 0x4e, 0x7a, 0x56, 0xa7, 0xff, 0x5b, 0x52, 0x0b, + 0xbd, 0x42, 0x6a, 0xef, 0xfa, 0xad, 0xa6, 0xbf, 0x93, 0x54, 0xd0, 0xff, + 0x6a, 0xfa, 0x17, 0xe2, 0xfd, 0xa5, 0x8c, 0x1e, 0x95, 0xd4, 0xa0, 0xe7, + 0x34, 0x7d, 0x5d, 0xd2, 0xd5, 0xf4, 0x8e, 0xa4, 0x0b, 0x69, 0x1b, 0xda, + 0x37, 0x1b, 0x11, 0x9e, 0xdb, 0x37, 0x1b, 0xbb, 0xf6, 0x62, 0x99, 0xee, + 0xa7, 0x7a, 0x49, 0x6b, 0xa8, 0x41, 0x70, 0xec, 0xde, 0x48, 0x5f, 0x22, + 0x45, 0x5b, 0x05, 0xef, 0x15, 0x5e, 0xfa, 0x19, 0x31, 0x5d, 0x48, 0x9b, + 0x05, 0xc7, 0x7c, 0x83, 0x06, 0x04, 0xef, 0x1b, 0x0b, 0xc9, 0x25, 0xa9, + 0x9f, 0xba, 0x75, 0x3a, 0xa8, 0xe9, 0x4e, 0xc1, 0xfb, 0xdf, 0x2e, 0x9a, + 0x21, 0x78, 0x5f, 0xd8, 0x20, 0xeb, 0x9b, 0x87, 0x11, 0x9a, 0x2f, 0xd3, + 0xe7, 0x52, 0x8b, 0xe0, 0x7d, 0x41, 0x8d, 0xff, 0xd9, 0x38, 0x99, 0x28, + 0x7a, 0x2e, 0x7d, 0x5d, 0xd2, 0x3c, 0x7a, 0x4a, 0xd3, 0xa7, 0x25, 0x75, + 0xd3, 0x33, 0xc4, 0xfb, 0xdb, 0x5e, 0x2a, 0x12, 0x4c, 0x3b, 0x68, 0x9d, + 0xa4, 0x11, 0xba, 0x40, 0xf0, 0xb9, 0x4a, 0x95, 0x73, 0x2e, 0xfc, 0xe5, + 0xaf, 0xc4, 0x67, 0x2c, 0x95, 0x5e, 0xa8, 0xd3, 0x7e, 0x9d, 0xf6, 0xeb, + 0x74, 0x35, 0x4e, 0x3d, 0x4e, 0x49, 0xd7, 0xd0, 0x97, 0x25, 0xdd, 0x46, + 0x0f, 0x48, 0xba, 0x80, 0xfe, 0x28, 0x69, 0x2b, 0x35, 0x4a, 0xff, 0x6f, + 0xa3, 0x65, 0x42, 0xa5, 0x9b, 0x84, 0xb2, 0x5b, 0x2e, 0x69, 0x0b, 0xa5, + 0x35, 0x1d, 0xd5, 0x74, 0x4c, 0xd3, 0xfd, 0x72, 0x5d, 0x74, 0xcb, 0xf2, + 0x6b, 0x74, 0x7f, 0x6a, 0x74, 0xfb, 0x6b, 0x28, 0x46, 0x1b, 0xe5, 0x3a, + 0xd9, 0x2a, 0xf5, 0x01, 0x9c, 0x64, 0x1e, 0x95, 0xf4, 0x1c, 0x7a, 0x5c, + 0xa7, 0xbf, 0x2b, 0x69, 0x88, 0x9a, 0xe5, 0xfa, 0xd9, 0x2c, 0xed, 0x6a, + 0xb9, 0x67, 0x72, 0xdd, 0xa8, 0x7c, 0x75, 0x90, 0x7f, 0x5a, 0xd3, 0x9b, + 0x25, 0x9d, 0x4d, 0xb7, 0x48, 0x7a, 0x2e, 0xed, 0x12, 0x8a, 0xee, 0x16, + 0x7c, 0x9e, 0x54, 0xfd, 0x5d, 0x8c, 0x12, 0x9c, 0xa4, 0xd6, 0xdb, 0x8f, + 0x24, 0x75, 0xd0, 0x8f, 0x75, 0xfa, 0x97, 0x9a, 0x3e, 0xaf, 0xe9, 0x4b, + 0x92, 0xce, 0xa7, 0x37, 0x74, 0xfa, 0x4d, 0x49, 0x77, 0x50, 0x99, 0x5c, + 0xaf, 0xbb, 0x68, 0xba, 0xa4, 0x7e, 0xea, 0x94, 0xb4, 0x97, 0xce, 0xd3, + 0xeb, 0xd4, 0x4a, 0x8a, 0xda, 0x34, 0xb5, 0x4b, 0xba, 0x52, 0xd6, 0x5b, + 0x8f, 0x93, 0xe1, 0x27, 0x25, 0xb5, 0xd1, 0x09, 0x49, 0x1b, 0xe8, 0x53, + 0x92, 0xba, 0xe8, 0x33, 0x92, 0x76, 0xd1, 0xad, 0x92, 0x4e, 0xa1, 0xdb, + 0x24, 0xdd, 0x47, 0xb7, 0x4b, 0x5a, 0x41, 0x77, 0x68, 0x7a, 0xa7, 0xce, + 0x7f, 0x97, 0xa4, 0x17, 0xd2, 0xdd, 0x92, 0x2e, 0xa2, 0x7b, 0x24, 0x3d, + 0x9b, 0xee, 0x95, 0x74, 0x29, 0x7d, 0x56, 0xdb, 0x9d, 0xd4, 0xf4, 0x3e, + 0x49, 0xed, 0xf4, 0x39, 0x9d, 0xfe, 0xbc, 0xa4, 0xe7, 0xd2, 0x57, 0x34, + 0xfd, 0x9a, 0xa6, 0xdf, 0x90, 0x74, 0x37, 0x7d, 0x53, 0xd2, 0x5a, 0x7a, + 0x4c, 0xd2, 0x46, 0xfa, 0x9e, 0xa4, 0x73, 0xe9, 0xfb, 0x92, 0x4e, 0xa7, + 0x27, 0x24, 0x2d, 0xa4, 0x9f, 0x4a, 0x3a, 0x8b, 0x7e, 0x4e, 0x2a, 0x1e, + 0xfd, 0x42, 0xc7, 0xad, 0xe7, 0xb4, 0xfd, 0x0b, 0x92, 0xce, 0xa4, 0x17, + 0x25, 0xb5, 0xd0, 0x7f, 0x49, 0x7a, 0x01, 0xbd, 0x2c, 0x69, 0x09, 0xfd, + 0x46, 0x52, 0x2f, 0xfd, 0x5e, 0xd2, 0x52, 0x7a, 0x4b, 0xe7, 0xff, 0xb3, + 0xa4, 0x53, 0xe9, 0x7f, 0x24, 0x2d, 0xa6, 0xb7, 0x25, 0x55, 0xeb, 0x97, + 0xc7, 0xf5, 0x6f, 0xba, 0x7d, 0x7f, 0xd7, 0xf4, 0x1f, 0x9a, 0xbe, 0x2b, + 0x69, 0xbd, 0x3c, 0xe8, 0xd6, 0x63, 0x66, 0x84, 0x50, 0xe3, 0x63, 0x08, + 0xa5, 0xb7, 0x64, 0xe6, 0x49, 0x53, 0x9b, 0xa6, 0x76, 0x49, 0xd7, 0x93, + 0x43, 0xd2, 0x25, 0x94, 0x27, 0x69, 0x98, 0xf2, 0xb5, 0xdc, 0x29, 0xd4, + 0xf8, 0x14, 0x4a, 0xba, 0x8b, 0xa6, 0x69, 0x3a, 0x53, 0xd2, 0x26, 0xaa, + 0x92, 0x74, 0x19, 0x2d, 0xd0, 0xf4, 0x1c, 0x4d, 0xcf, 0xd5, 0xfa, 0x85, + 0x3a, 0xed, 0xd7, 0xb4, 0x5a, 0xd2, 0x19, 0x54, 0x23, 0xe9, 0x2a, 0x0a, + 0x48, 0xda, 0x49, 0xb5, 0x92, 0x0e, 0xd1, 0x22, 0x49, 0x55, 0x5c, 0xaa, + 0xd7, 0x71, 0x89, 0xd3, 0x4b, 0x24, 0xdd, 0x49, 0x4b, 0x85, 0xda, 0x27, + 0x1a, 0xb4, 0xfd, 0x0a, 0x49, 0xf7, 0xd0, 0x6a, 0x49, 0xfb, 0xa8, 0x43, + 0xd3, 0x0d, 0x7a, 0xdf, 0xd8, 0x24, 0x69, 0x3b, 0x75, 0x49, 0xba, 0x89, + 0x7a, 0x24, 0xdd, 0x41, 0xdb, 0x25, 0x5d, 0x48, 0x3b, 0xb4, 0x7d, 0xaf, + 0xa6, 0x7d, 0x92, 0x56, 0xd3, 0xf9, 0x42, 0xf9, 0x4b, 0x58, 0x28, 0xff, + 0xd9, 0xa3, 0xd3, 0x7b, 0x35, 0x1d, 0xd2, 0x34, 0x22, 0x94, 0xff, 0x5d, + 0xa8, 0xd3, 0xfb, 0x84, 0xf2, 0xc3, 0xa8, 0x50, 0x7e, 0x3f, 0xac, 0xe7, + 0x21, 0x26, 0x94, 0xdf, 0xc7, 0xf5, 0x7c, 0x5c, 0x2c, 0xf8, 0x2c, 0x3e, + 0x87, 0x42, 0x92, 0xce, 0xa3, 0xa4, 0xe0, 0x73, 0xb7, 0x41, 0xe5, 0x92, + 0xfa, 0xe8, 0xa0, 0xe0, 0xf3, 0xb6, 0x8a, 0x5b, 0x2b, 0xb5, 0x7e, 0x15, + 0xfc, 0xe8, 0x61, 0x62, 0x6a, 0xa5, 0x47, 0x24, 0x1d, 0xa6, 0xef, 0x48, + 0xaa, 0xf6, 0x2f, 0x96, 0x9f, 0x2d, 0xe9, 0x7c, 0xea, 0x17, 0x7c, 0x3f, + 0x54, 0xf9, 0x9b, 0x29, 0x4a, 0xa7, 0x24, 0xad, 0xa2, 0x59, 0x82, 0xcf, + 0xe5, 0xbb, 0xa8, 0x40, 0xd2, 0xb3, 0xa8, 0x52, 0xa8, 0x7b, 0x27, 0x2f, + 0xd8, 0xcc, 0x59, 0xbf, 0x18, 0xb8, 0x16, 0x17, 0xc3, 0x1d, 0x9b, 0x54, + 0x9a, 0xef, 0xad, 0x1e, 0xb7, 0xd2, 0xbb, 0x6a, 0xc6, 0xef, 0x3d, 0x21, + 0xad, 0x5f, 0x38, 0x89, 0x3e, 0xae, 0xf5, 0xfe, 0x49, 0xf4, 0x97, 0x6a, + 0x3d, 0xdf, 0x85, 0xdd, 0xa4, 0xf4, 0x53, 0x6a, 0x54, 0xfd, 0xb7, 0xa3, + 0xfe, 0x0f, 0x69, 0x7d, 0x8d, 0xd6, 0x9f, 0x6d, 0x6a, 0xdf, 0x57, 0xa1, + 0xff, 0xae, 0xd6, 0x07, 0xb4, 0x7e, 0xbe, 0x49, 0xff, 0x04, 0xf4, 0x2f, + 0x69, 0x7d, 0xad, 0x96, 0x73, 0xf9, 0x33, 0x75, 0xf9, 0xaf, 0x42, 0x6f, + 0x6c, 0x56, 0xf2, 0x3a, 0x53, 0xfd, 0x99, 0xfc, 0x56, 0x5c, 0x8a, 0x4b, + 0xb5, 0x9e, 0xef, 0x52, 0xe2, 0x34, 0xfd, 0x4c, 0xe8, 0x57, 0x68, 0x3d, + 0xdf, 0xaf, 0xb8, 0x4f, 0xb3, 0x81, 0x4a, 0x5d, 0xfe, 0x62, 0xe8, 0x47, + 0xb5, 0x5e, 0xc8, 0x5f, 0x9c, 0x29, 0x31, 0x50, 0x1c, 0x27, 0x13, 0x6e, + 0x8e, 0x12, 0x45, 0xd8, 0xdd, 0xf2, 0x10, 0x89, 0x71, 0xe7, 0xd4, 0xf2, + 0xfd, 0x8e, 0x14, 0xec, 0x8a, 0xfe, 0x05, 0xfb, 0x91, 0x7f, 0xd1, 0x3e, + 0x29, 0xed, 0xed, 0x78, 0x5a, 0x90, 0x1e, 0x59, 0xa8, 0xfa, 0x3e, 0xe2, + 0x5e, 0x0e, 0xcf, 0x75, 0x82, 0x36, 0x31, 0x15, 0xcb, 0xf8, 0x64, 0x28, + 0x2c, 0x54, 0x55, 0x19, 0x73, 0xff, 0x12, 0x12, 0x97, 0xad, 0xc2, 0x68, + 0x46, 0xa9, 0x2f, 0xc3, 0xcf, 0x2a, 0x2c, 0x65, 0xe4, 0xb5, 0xc6, 0x02, + 0x2f, 0x60, 0x4f, 0xe4, 0x1c, 0x1c, 0xf7, 0x5c, 0x24, 0xd3, 0xc2, 0x69, + 0xe3, 0x34, 0xdb, 0x27, 0x02, 0x6e, 0xb2, 0xd8, 0x62, 0xbe, 0x5f, 0xa3, + 0x7c, 0x8f, 0xe1, 0xb5, 0x79, 0x6c, 0x56, 0xb4, 0x80, 0xef, 0xd7, 0x17, + 0x2f, 0xe4, 0x73, 0x57, 0xa6, 0x8d, 0x7d, 0xa2, 0x88, 0xfa, 0x0c, 0x17, + 0xf5, 0x59, 0x0a, 0x69, 0xc4, 0xb7, 0x19, 0xd6, 0x45, 0xc4, 0xf7, 0xf0, + 0xcc, 0x0d, 0x5d, 0x8d, 0x3b, 0xcb, 0x6c, 0xf8, 0x65, 0xfe, 0x08, 0xf2, + 0x73, 0x9f, 0x92, 0xee, 0x67, 0x91, 0x76, 0x89, 0x3e, 0x51, 0x90, 0xd5, + 0x73, 0xae, 0xe3, 0x0b, 0xd5, 0x7d, 0x3d, 0x28, 0x5c, 0x14, 0x34, 0xb8, + 0xd4, 0x2d, 0x88, 0xc6, 0x45, 0xc8, 0xe3, 0x90, 0xfa, 0x1b, 0x27, 0xd1, + 0x67, 0xf2, 0xdf, 0x3e, 0x89, 0x3e, 0x1f, 0x7a, 0x1e, 0xb3, 0xfb, 0xa0, + 0x8f, 0xb2, 0xbe, 0xd9, 0x45, 0x8b, 0xba, 0x22, 0xa0, 0x05, 0xd8, 0x25, + 0x30, 0x56, 0x03, 0xf7, 0x0f, 0x25, 0x03, 0xcf, 0x50, 0x38, 0xcf, 0x65, + 0xe3, 0xb6, 0xf1, 0x28, 0x4c, 0xcf, 0x33, 0x28, 0xe6, 0x7b, 0x11, 0x77, + 0x34, 0x67, 0x9e, 0x97, 0x1a, 0xf3, 0x0a, 0x69, 0x7a, 0x9e, 0x25, 0x2b, + 0x69, 0x00, 0x5f, 0x65, 0x11, 0x79, 0x55, 0x96, 0x92, 0xbc, 0x35, 0xd8, + 0x57, 0x85, 0xd4, 0x94, 0x62, 0xfc, 0x1b, 0x84, 0x95, 0x4a, 0xf2, 0x56, + 0x50, 0x70, 0x75, 0x21, 0x05, 0xd7, 0x14, 0xc8, 0xd1, 0x35, 0xec, 0x4e, + 0x23, 0xd8, 0x52, 0x40, 0xf7, 0x8f, 0x71, 0xca, 0x62, 0x77, 0xda, 0x63, + 0x81, 0x38, 0xcd, 0xb5, 0x07, 0xdb, 0x0a, 0xa9, 0x21, 0x0f, 0x33, 0xe0, + 0xfe, 0x2f, 0x9e, 0x3b, 0xc7, 0x33, 0x0e, 0xc7, 0xbb, 0xb1, 0xc0, 0x4b, + 0x64, 0x73, 0xb8, 0x30, 0xfe, 0xc3, 0x38, 0xd1, 0xb2, 0x36, 0xd8, 0x5a, + 0x44, 0x15, 0xf6, 0xe9, 0x94, 0x08, 0x94, 0x90, 0x3d, 0x2f, 0x16, 0x78, + 0x88, 0x3e, 0x60, 0x0f, 0xb6, 0x42, 0xde, 0xa6, 0x7a, 0x18, 0x26, 0xaf, + 0xad, 0xaf, 0xb5, 0x40, 0x8e, 0x83, 0x21, 0xfb, 0xf9, 0xe8, 0x42, 0xe5, + 0xcf, 0x31, 0xf7, 0x10, 0x66, 0xce, 0x09, 0x1a, 0x61, 0x6a, 0x5d, 0x86, + 0x16, 0x36, 0x59, 0xd1, 0x72, 0x0f, 0xfb, 0x86, 0x05, 0x33, 0xe0, 0x35, + 0x62, 0x81, 0x5f, 0x61, 0x8c, 0x60, 0xc3, 0xd4, 0xea, 0xb4, 0x8e, 0x04, + 0x8a, 0xc8, 0x62, 0x2d, 0x92, 0xf3, 0xc8, 0x63, 0xfa, 0xa4, 0x1e, 0xd3, + 0x11, 0x77, 0x87, 0xf2, 0x16, 0x5f, 0x42, 0xfa, 0x61, 0x46, 0xff, 0x33, + 0x3d, 0xa7, 0x23, 0xbe, 0xad, 0x58, 0x87, 0x23, 0xbe, 0x2e, 0x3c, 0xd5, + 0x9c, 0xaa, 0xb6, 0xbc, 0xa0, 0xdb, 0x32, 0xe2, 0x2e, 0x44, 0x9a, 0xbd, + 0xce, 0xc5, 0x54, 0xc8, 0xb6, 0x08, 0x53, 0x5b, 0x2c, 0xdc, 0x96, 0x17, + 0x10, 0xd5, 0x9c, 0x72, 0xcc, 0xce, 0x12, 0x4e, 0x0b, 0x8f, 0x92, 0xd5, + 0xa2, 0x7c, 0x9e, 0xcf, 0x26, 0xbf, 0x5f, 0xa8, 0xde, 0x6f, 0x04, 0xbb, + 0x8a, 0x11, 0x8d, 0x2d, 0x58, 0xb7, 0xc1, 0x2e, 0x0f, 0x66, 0x30, 0x9f, + 0xe2, 0xee, 0x15, 0x3c, 0x6b, 0xd4, 0x07, 0x8d, 0x07, 0xfd, 0xe5, 0x59, + 0x76, 0x52, 0x70, 0x8b, 0x87, 0xb8, 0xd4, 0x7d, 0xe8, 0xa1, 0x8b, 0x2a, + 0x44, 0x29, 0x25, 0x7c, 0xc5, 0x28, 0xab, 0x6f, 0x4b, 0x31, 0x4e, 0x25, + 0xd5, 0xd0, 0x7b, 0x29, 0xd8, 0x5d, 0x4c, 0xc1, 0xa0, 0x87, 0x12, 0xcd, + 0xeb, 0xc8, 0xdd, 0xd2, 0xd7, 0xe5, 0x86, 0xb4, 0x18, 0x1e, 0x9a, 0x0f, + 0x3b, 0xa7, 0xa5, 0xc4, 0xea, 0xa5, 0x64, 0xb0, 0x80, 0x44, 0x5d, 0x50, + 0x96, 0xcc, 0x6b, 0xd1, 0x2a, 0xfb, 0xf5, 0x8e, 0x1e, 0x97, 0x44, 0xa0, + 0x91, 0xdc, 0x46, 0x9f, 0xf0, 0x62, 0x1d, 0x78, 0xd0, 0x73, 0x0b, 0xf2, + 0xf1, 0xb8, 0x18, 0x7e, 0xd5, 0xef, 0xa0, 0x8f, 0xdb, 0x9a, 0x4f, 0xc1, + 0xb9, 0x6e, 0xec, 0x7b, 0x36, 0x4a, 0xfa, 0x9c, 0x18, 0x21, 0x58, 0x43, + 0xde, 0xe7, 0xf3, 0xa0, 0xe5, 0xcb, 0x60, 0xbf, 0x1b, 0x28, 0x11, 0x73, + 0x68, 0xb1, 0xdb, 0x0e, 0x5d, 0xcc, 0xd7, 0x83, 0x34, 0xc7, 0x00, 0x43, + 0xf6, 0xbb, 0xd0, 0xaf, 0xde, 0x07, 0x06, 0x77, 0x97, 0x60, 0xfc, 0xf8, + 0xcd, 0x48, 0x01, 0x4d, 0x35, 0x64, 0x6c, 0x34, 0xbc, 0x82, 0x3d, 0xd8, + 0x23, 0x4c, 0x3a, 0x63, 0xa4, 0xf9, 0x22, 0xf2, 0xa5, 0x5c, 0xa8, 0xd7, + 0x81, 0xb1, 0xe0, 0xb7, 0x3c, 0x2e, 0x87, 0xc7, 0x21, 0xeb, 0x30, 0x66, + 0xd3, 0x62, 0xb4, 0xa0, 0x02, 0xbb, 0x52, 0x70, 0x60, 0x0a, 0x5a, 0x8f, + 0x7d, 0xd6, 0x51, 0xe5, 0x08, 0xee, 0x9e, 0x82, 0xb9, 0x5b, 0x42, 0x09, + 0x8c, 0x53, 0x70, 0x40, 0x95, 0x64, 0xa1, 0x02, 0xeb, 0x48, 0xd7, 0xc5, + 0xd4, 0x32, 0xea, 0x74, 0x34, 0x3a, 0x9c, 0xb4, 0xdb, 0x61, 0x50, 0xfd, + 0xd9, 0x36, 0x94, 0xc8, 0xef, 0x36, 0x3d, 0xc2, 0x83, 0x79, 0x51, 0x73, + 0x3c, 0xc3, 0xaf, 0x62, 0x51, 0xb0, 0x79, 0xf2, 0xf6, 0x79, 0xdd, 0x8b, + 0x6c, 0x58, 0x11, 0xad, 0xca, 0xc2, 0xc6, 0xad, 0x0c, 0x5c, 0x42, 0xf3, + 0x2c, 0x2e, 0x5b, 0x55, 0x41, 0xae, 0xf4, 0x52, 0x29, 0x6d, 0xb0, 0x61, + 0xed, 0xb8, 0x7f, 0xce, 0xeb, 0x02, 0x6b, 0x61, 0x3b, 0x6e, 0x6d, 0x2e, + 0x44, 0x22, 0x8f, 0x70, 0x62, 0xfc, 0xf9, 0x7c, 0x3a, 0xdf, 0xaf, 0xde, + 0x01, 0x9e, 0x69, 0x4c, 0x1a, 0x61, 0xe3, 0x75, 0x14, 0x3b, 0x4c, 0x3a, + 0x21, 0x52, 0xe2, 0xb0, 0xe3, 0xba, 0xfd, 0x76, 0x7e, 0x6f, 0xe2, 0x84, + 0xce, 0x22, 0x67, 0x0a, 0xfb, 0x93, 0x5f, 0xbd, 0x2f, 0xac, 0x10, 0x2a, + 0x4a, 0xf2, 0xed, 0x3b, 0xa3, 0x5b, 0xe2, 0x57, 0x73, 0xdc, 0x27, 0x4a, + 0xa0, 0xe3, 0xb7, 0xb9, 0x7d, 0xc6, 0x14, 0xed, 0xfb, 0x72, 0x4f, 0xf1, + 0xf3, 0x3d, 0x95, 0xf5, 0x53, 0x75, 0x4c, 0xf4, 0x8a, 0x9d, 0xf0, 0x32, + 0xf6, 0xff, 0x4c, 0x9c, 0x6e, 0xf5, 0xab, 0x77, 0xb2, 0x15, 0x88, 0x9c, + 0x09, 0xb7, 0x8c, 0x4e, 0x5b, 0xa6, 0x52, 0xd0, 0x53, 0x86, 0xde, 0xdd, + 0x20, 0xa3, 0x60, 0x23, 0x72, 0x67, 0x65, 0xbe, 0x4f, 0x41, 0x36, 0x6e, + 0xf1, 0x31, 0xf6, 0x42, 0xb1, 0xd5, 0xe0, 0xf7, 0xbc, 0x82, 0xaa, 0x5c, + 0x31, 0xdf, 0x3c, 0xd0, 0x98, 0xfb, 0xac, 0x1c, 0xf9, 0x17, 0x8c, 0x2f, + 0xcc, 0x2d, 0xc1, 0xf9, 0xbb, 0x5e, 0x4c, 0xa7, 0x6d, 0x5b, 0x4b, 0xa9, + 0xc1, 0x98, 0x0a, 0xbf, 0xdf, 0x09, 0x2e, 0xb8, 0x15, 0x25, 0x55, 0x94, + 0xc1, 0xcb, 0xa7, 0x62, 0x24, 0x42, 0x72, 0x9d, 0xe9, 0xb9, 0xb5, 0x8c, + 0x04, 0x0e, 0x52, 0x9d, 0x95, 0xed, 0x1b, 0x0d, 0x07, 0xce, 0x66, 0x36, + 0xf2, 0xba, 0x77, 0x76, 0x95, 0xea, 0x3d, 0x89, 0x7f, 0x7a, 0xd0, 0x76, + 0xee, 0x43, 0x10, 0x77, 0x1b, 0xf6, 0x7d, 0x1e, 0x17, 0xf6, 0xed, 0x9d, + 0x7e, 0xb5, 0x4f, 0xf6, 0x89, 0x32, 0xdd, 0xef, 0x0a, 0x51, 0x8b, 0xb5, + 0xb5, 0x93, 0xd7, 0x96, 0x98, 0x86, 0x51, 0x2a, 0x97, 0x63, 0x90, 0xd9, + 0xdb, 0xb8, 0x1c, 0xb5, 0xb7, 0xf5, 0x13, 0x99, 0xf6, 0xbc, 0x71, 0xf9, + 0x80, 0x94, 0x67, 0xd6, 0x4e, 0xc4, 0xcf, 0x91, 0x86, 0xd7, 0x4e, 0x39, + 0xfa, 0x7a, 0xa3, 0x8c, 0x3b, 0xc1, 0xb9, 0xd3, 0x30, 0x3a, 0xe7, 0xca, + 0xe8, 0x92, 0xb1, 0x8b, 0x4d, 0x6a, 0xb7, 0x30, 0xc7, 0x2e, 0xe5, 0x57, + 0x31, 0xaa, 0xdb, 0x37, 0x1d, 0x5e, 0x3e, 0x0a, 0x9d, 0x53, 0xb6, 0x3f, + 0xa3, 0x3f, 0x90, 0xa3, 0xbf, 0x32, 0xab, 0xb7, 0x6a, 0xff, 0xbe, 0xd4, + 0xac, 0x0f, 0x7c, 0x80, 0xdc, 0x16, 0xa7, 0xa5, 0xd8, 0x32, 0x9e, 0xff, + 0xca, 0x9c, 0xfc, 0x63, 0x13, 0xca, 0x3f, 0x9a, 0xa3, 0xbf, 0x6c, 0x82, + 0xfe, 0x9a, 0x1c, 0xfd, 0x07, 0x27, 0xe8, 0x3f, 0x96, 0xa3, 0x3f, 0x9c, + 0xd5, 0xf3, 0xae, 0xc6, 0xe3, 0x77, 0xbd, 0x59, 0xdf, 0x7c, 0x39, 0xe2, + 0x98, 0xcb, 0xe2, 0xb1, 0xa8, 0xf9, 0xe2, 0x71, 0xfe, 0xb4, 0xf6, 0x71, + 0x35, 0x57, 0xbd, 0xf0, 0x92, 0xa2, 0x6c, 0xdf, 0x6e, 0xd7, 0x3a, 0xd5, + 0xb7, 0x2b, 0xd0, 0xb7, 0xa2, 0x6c, 0xb9, 0xf7, 0x9a, 0x75, 0xcd, 0x87, + 0x50, 0xee, 0x78, 0xbe, 0x2f, 0xe4, 0xe4, 0xdb, 0x2f, 0xf3, 0x59, 0xe5, + 0x2f, 0xd1, 0x57, 0xfc, 0x24, 0xe3, 0x56, 0xa2, 0xf9, 0x7a, 0x72, 0xd7, + 0xb9, 0xa4, 0xef, 0x18, 0xda, 0xa7, 0xbe, 0x9e, 0xf1, 0x29, 0xf7, 0x1c, + 0x29, 0xe7, 0x9d, 0x9d, 0xf3, 0x7c, 0xcb, 0xaf, 0x62, 0x7b, 0x77, 0xd7, + 0x2c, 0x44, 0xa5, 0xe3, 0xb8, 0xe3, 0xb8, 0xe4, 0x7d, 0xb5, 0x2f, 0x64, + 0x01, 0xb0, 0x9e, 0x8d, 0x1d, 0xfd, 0x88, 0x8d, 0x7f, 0x52, 0x31, 0x8d, + 0x3f, 0x9d, 0x70, 0x5a, 0xab, 0x0c, 0xb1, 0x78, 0xc7, 0x60, 0x1e, 0xe2, + 0x9c, 0x5d, 0xee, 0x71, 0x90, 0x59, 0x76, 0x0c, 0x38, 0x60, 0xef, 0xe4, + 0x77, 0x64, 0x5d, 0x3b, 0x42, 0x36, 0xe8, 0x78, 0xff, 0xe3, 0x4f, 0x31, + 0x9c, 0x62, 0xc4, 0x7d, 0x1d, 0xaf, 0x1b, 0x94, 0x94, 0x8f, 0x1d, 0xb5, + 0x86, 0xbc, 0x9e, 0x44, 0x73, 0x37, 0x6e, 0x15, 0x7d, 0x3d, 0x33, 0xc9, + 0x63, 0x1f, 0x1f, 0xef, 0x9f, 0xf8, 0xd5, 0x39, 0x27, 0xe6, 0xfe, 0x08, + 0xd2, 0xdc, 0x8e, 0xa9, 0x22, 0xe6, 0x33, 0x30, 0xee, 0x2e, 0x9c, 0xfa, + 0xcf, 0xd1, 0xfd, 0x51, 0xfb, 0xdf, 0x33, 0xba, 0xaf, 0x23, 0xbe, 0xa7, + 0x4c, 0xf3, 0x62, 0x93, 0xb2, 0x5f, 0x66, 0xc6, 0x21, 0xf8, 0x08, 0xc6, + 0x41, 0xe9, 0xec, 0xf2, 0x97, 0xe8, 0xd7, 0x5a, 0x37, 0x66, 0xff, 0xac, + 0xdc, 0xab, 0x8a, 0xf5, 0xfa, 0xca, 0xfc, 0x70, 0xd9, 0x5e, 0x4f, 0xb1, + 0xc8, 0x8c, 0xdb, 0x6b, 0x7a, 0xdc, 0xb6, 0xb9, 0x7d, 0xd2, 0xd6, 0xd0, + 0x6b, 0xe8, 0x4f, 0x7e, 0x92, 0xf7, 0x84, 0x98, 0xfb, 0x26, 0xee, 0x1b, + 0xc9, 0xd8, 0xe7, 0x2e, 0xc6, 0x2e, 0x52, 0x8c, 0x94, 0x21, 0xfd, 0xe2, + 0x1d, 0xbf, 0xfa, 0xcc, 0x20, 0x78, 0x68, 0x06, 0xec, 0x16, 0xcb, 0xfa, + 0x1a, 0x68, 0x1a, 0x75, 0x5f, 0x3e, 0x0b, 0xe9, 0xe9, 0x88, 0x61, 0xd8, + 0x6b, 0xdd, 0xb3, 0x99, 0x5a, 0x63, 0x98, 0x97, 0x7c, 0x8e, 0xb9, 0xee, + 0x19, 0xa0, 0x05, 0xf6, 0xfd, 0x8e, 0x4f, 0xf3, 0x9b, 0xc8, 0x69, 0xc5, + 0xf9, 0xde, 0xfc, 0xe2, 0x7c, 0x8e, 0xb2, 0x16, 0xd9, 0xfe, 0x77, 0xfd, + 0xea, 0xee, 0xd1, 0x7d, 0x68, 0x56, 0x6e, 0xdc, 0x85, 0x55, 0xcc, 0x7d, + 0x15, 0xe2, 0xa6, 0xb7, 0xd9, 0xeb, 0xa9, 0xcb, 0xf7, 0xe1, 0xbe, 0x5c, + 0x4e, 0x75, 0xf9, 0x53, 0x41, 0xa7, 0x81, 0x7a, 0xa9, 0xfb, 0x4a, 0xae, + 0xb5, 0x0c, 0x6d, 0xc0, 0x39, 0xc8, 0x3d, 0x95, 0xa9, 0xc3, 0x71, 0x85, + 0xb8, 0x6e, 0xcc, 0x7e, 0x1b, 0xda, 0x5b, 0x2c, 0xc4, 0x75, 0xf1, 0x40, + 0x15, 0x6d, 0x77, 0x3a, 0x65, 0x49, 0x47, 0x50, 0x12, 0xbf, 0x17, 0x75, + 0xe9, 0xb8, 0xef, 0xa9, 0x56, 0x9f, 0x9d, 0x99, 0xeb, 0x55, 0x7b, 0x4c, + 0xb1, 0x68, 0xcc, 0x0f, 0xa8, 0x9d, 0xd4, 0x98, 0x45, 0xf5, 0x3e, 0x9e, + 0xf7, 0x29, 0x68, 0xaf, 0x93, 0xbc, 0x67, 0xd5, 0x05, 0x70, 0xd2, 0x98, + 0xbb, 0xdb, 0x89, 0x1d, 0xec, 0x1c, 0xae, 0xbd, 0x14, 0x72, 0x97, 0xb3, + 0xc1, 0x59, 0x96, 0xe5, 0x63, 0xbe, 0xe7, 0x69, 0x3a, 0x5a, 0xa4, 0x5a, + 0x37, 0x95, 0xf3, 0x99, 0x5a, 0xc5, 0xfd, 0x97, 0x2d, 0x6b, 0x5e, 0x40, + 0xdb, 0x1f, 0xe4, 0x96, 0x39, 0x50, 0x23, 0xcf, 0x5f, 0x45, 0xb5, 0xfa, + 0x0c, 0xac, 0xbb, 0x59, 0xb7, 0x07, 0x6e, 0xd1, 0x68, 0x60, 0x1c, 0x6c, + 0xc5, 0x36, 0xee, 0xa5, 0x1d, 0x65, 0x26, 0x7a, 0x6e, 0x27, 0xeb, 0x16, + 0x6f, 0x69, 0xb1, 0x8d, 0xfb, 0xa1, 0xe6, 0xe4, 0x1c, 0xe4, 0x8b, 0x71, + 0xbe, 0x5b, 0x26, 0xf6, 0x23, 0xe6, 0x2e, 0x97, 0xed, 0xe6, 0x39, 0x28, + 0xa0, 0x02, 0xc7, 0xd3, 0xf4, 0x2e, 0x5a, 0xd0, 0x40, 0xeb, 0xa8, 0xee, + 0xf8, 0x22, 0xf2, 0x56, 0xd4, 0xf9, 0xce, 0x26, 0x6f, 0x5d, 0x9d, 0x6f, + 0x06, 0x79, 0xb7, 0xd6, 0xe1, 0x1c, 0xe1, 0xed, 0xaf, 0xf3, 0x71, 0xbe, + 0x0a, 0xdc, 0xf6, 0x12, 0xfc, 0xe1, 0x3a, 0x4e, 0x50, 0x27, 0xe9, 0x41, + 0x2a, 0xce, 0xaf, 0xc0, 0xfd, 0x2d, 0xe1, 0x6e, 0xcd, 0x91, 0x8c, 0xdb, + 0xdc, 0xa3, 0x25, 0x0b, 0x21, 0x69, 0x31, 0x49, 0xba, 0x6f, 0xc5, 0x18, + 0xf8, 0x66, 0xf1, 0xbb, 0x4c, 0x2b, 0xfb, 0x45, 0x81, 0xf4, 0x87, 0x39, + 0x4c, 0xe1, 0x0f, 0x77, 0xf3, 0x2c, 0xbd, 0x8f, 0xcd, 0x9d, 0xd2, 0xc6, + 0xa6, 0x3d, 0x7a, 0x4d, 0xb5, 0xfa, 0xcc, 0x30, 0x11, 0xf8, 0x28, 0x76, + 0x9c, 0x02, 0x0b, 0x7f, 0x36, 0x58, 0x0b, 0x4d, 0x03, 0xe6, 0xb6, 0x02, + 0x37, 0xb4, 0x44, 0x20, 0x4c, 0x01, 0x2b, 0xce, 0x6a, 0x88, 0x5a, 0x13, + 0xd7, 0xd5, 0x0f, 0xb2, 0xeb, 0x6a, 0xa2, 0xee, 0x87, 0xef, 0xa1, 0x7b, + 0xe2, 0x3d, 0x74, 0x3f, 0x36, 0xc5, 0x58, 0xd5, 0xc6, 0xf6, 0x6a, 0xad, + 0x0b, 0xfc, 0x27, 0xce, 0x73, 0x93, 0xe5, 0x7b, 0x32, 0x9b, 0x2f, 0xb3, + 0x47, 0xf2, 0x0f, 0xdf, 0x81, 0xcf, 0x95, 0xa7, 0x11, 0x5e, 0x75, 0x53, + 0xe8, 0x72, 0xf6, 0x59, 0xf2, 0x06, 0x98, 0x9f, 0x2b, 0xf9, 0x29, 0x88, + 0x19, 0x4c, 0x4b, 0xc8, 0xe0, 0xf9, 0xf2, 0xb1, 0x44, 0xa8, 0x92, 0x84, + 0x43, 0x96, 0xc1, 0x9f, 0x8b, 0xf2, 0xb8, 0xb0, 0x2f, 0x71, 0xf9, 0xfc, + 0x3d, 0xa4, 0x7c, 0x52, 0xf5, 0x9e, 0xde, 0xc6, 0x44, 0xe0, 0xe3, 0x68, + 0xa3, 0x2b, 0xbb, 0x27, 0xe7, 0xea, 0xae, 0xc9, 0xea, 0x4e, 0x8f, 0xc7, + 0x23, 0xcd, 0x3f, 0xca, 0xc6, 0x63, 0x8b, 0x6e, 0xff, 0x33, 0x3a, 0xae, + 0x74, 0x63, 0x2e, 0xdd, 0x32, 0x1e, 0x3b, 0xc8, 0xa1, 0xfb, 0xa5, 0xee, + 0x9d, 0xfc, 0xd6, 0xae, 0xe8, 0x0c, 0xf2, 0x3b, 0x27, 0x91, 0xdf, 0x4d, + 0xea, 0xfe, 0xaa, 0xee, 0x5c, 0x9b, 0xab, 0xd5, 0x67, 0xc6, 0x09, 0xf8, + 0x6c, 0x0b, 0x66, 0xbb, 0x00, 0xbe, 0xc6, 0xeb, 0xb8, 0x2f, 0x30, 0x17, + 0xa7, 0x86, 0x3a, 0xb4, 0xf7, 0x02, 0xaa, 0xb5, 0xf4, 0xd5, 0xce, 0x46, + 0x2a, 0x80, 0xd4, 0x79, 0x32, 0x35, 0x47, 0xc6, 0x5e, 0xbe, 0xa1, 0x4c, + 0x37, 0xbe, 0x40, 0x1c, 0x7b, 0x71, 0x82, 0x17, 0x73, 0x44, 0x25, 0xf5, + 0xd5, 0xce, 0x20, 0xdf, 0x6a, 0xc4, 0x75, 0x91, 0x47, 0x73, 0xac, 0x38, + 0x8d, 0xfa, 0xf8, 0x8e, 0x5f, 0xe5, 0x8c, 0xb9, 0x05, 0xea, 0x77, 0x59, + 0xc7, 0x65, 0xbd, 0x4b, 0x66, 0xf1, 0x6d, 0xd7, 0xf7, 0x3d, 0xd4, 0xbb, + 0xb3, 0xde, 0x47, 0xde, 0xd2, 0x98, 0xef, 0x9b, 0xd4, 0x0d, 0xed, 0xb7, + 0xe4, 0xf3, 0x31, 0xc4, 0xaf, 0x0a, 0x5b, 0x3e, 0xda, 0xc3, 0x2b, 0xb9, + 0xc4, 0x3e, 0x85, 0xce, 0xda, 0xd3, 0x4a, 0xf3, 0xed, 0xfc, 0x89, 0x73, + 0xcc, 0x67, 0xc5, 0xbd, 0xaa, 0xc2, 0xee, 0x44, 0xbb, 0x6d, 0x38, 0xbf, + 0xc5, 0x7c, 0x0e, 0x44, 0x16, 0xaf, 0x2d, 0x16, 0x78, 0x94, 0x5a, 0x6c, + 0x23, 0x72, 0x04, 0x5d, 0x28, 0xdb, 0x8b, 0x7a, 0x70, 0xd2, 0xb1, 0x58, + 0xe5, 0x67, 0xdf, 0xe3, 0x3f, 0x87, 0x56, 0xd1, 0xbf, 0x94, 0x3e, 0xfd, + 0x47, 0xe9, 0xcd, 0x73, 0xcb, 0x63, 0x3b, 0x12, 0xf8, 0x29, 0xe6, 0xb6, + 0x68, 0x82, 0x3c, 0x11, 0xb8, 0x43, 0xca, 0xcd, 0xf3, 0x2d, 0xed, 0x9b, + 0x9f, 0xc6, 0x7c, 0x4f, 0xb4, 0x1f, 0x09, 0xfc, 0x44, 0xda, 0xdb, 0xf4, + 0x19, 0x75, 0xb4, 0x5a, 0xed, 0x77, 0xb9, 0x31, 0xcc, 0x82, 0x9e, 0x25, + 0x02, 0x9f, 0x21, 0xab, 0x28, 0x32, 0xf9, 0xcb, 0xc5, 0xda, 0xcf, 0xd8, + 0x57, 0x7b, 0xe1, 0x33, 0x19, 0x1d, 0xaf, 0x93, 0x43, 0x7a, 0x9d, 0xc7, + 0xdc, 0xd7, 0xca, 0x7d, 0x93, 0xa3, 0x59, 0x11, 0x4e, 0x64, 0x33, 0xe5, + 0xcd, 0x27, 0xe6, 0x0e, 0xf2, 0xd9, 0xd5, 0xb7, 0x8a, 0x7c, 0xd2, 0x6f, + 0x54, 0xfc, 0x3c, 0x5a, 0xad, 0xbe, 0x37, 0x70, 0x86, 0xba, 0x7b, 0x6e, + 0x45, 0xd4, 0xd4, 0x63, 0x6d, 0xe3, 0xb1, 0x6e, 0x85, 0xd4, 0x8d, 0x7c, + 0x7c, 0x8a, 0x3e, 0x5e, 0xad, 0x3e, 0x5b, 0xe3, 0x18, 0x59, 0x84, 0x7d, + 0xaa, 0xfb, 0x47, 0x98, 0xed, 0x3c, 0x8e, 0x48, 0x1f, 0xd6, 0xbb, 0x59, + 0x91, 0xde, 0xcd, 0x40, 0x6d, 0x8e, 0x37, 0x0e, 0xe4, 0x0d, 0x4a, 0xeb, + 0x99, 0x9c, 0x2e, 0xf6, 0x4e, 0x5b, 0x7a, 0x33, 0x62, 0xe8, 0xdc, 0xb3, + 0xa6, 0xb7, 0xa1, 0x45, 0x9f, 0xa0, 0xfb, 0x48, 0x7c, 0xb2, 0xfe, 0xaf, + 0xb3, 0x89, 0x4b, 0xe1, 0x32, 0xbe, 0xce, 0x65, 0xf8, 0x7c, 0x4c, 0xad, + 0x6b, 0x6d, 0xce, 0xbc, 0x2b, 0xb6, 0x7d, 0x3b, 0x18, 0xf3, 0xcd, 0xe5, + 0xb4, 0x6d, 0xad, 0xcb, 0x99, 0x7f, 0xc5, 0x13, 0xdf, 0x7e, 0x4c, 0x95, + 0xf8, 0x4c, 0x41, 0x81, 0xa8, 0x7a, 0xa9, 0x88, 0x5c, 0xba, 0x5d, 0x9f, + 0xae, 0x56, 0x77, 0x35, 0x6e, 0x97, 0x13, 0xed, 0x8a, 0xb9, 0xa7, 0xf1, + 0x0e, 0x47, 0x1c, 0xdb, 0xa7, 0x92, 0x28, 0xe9, 0xfe, 0xa8, 0xaa, 0x61, + 0x99, 0x6e, 0xa5, 0x53, 0xb7, 0xd2, 0xc9, 0xad, 0xbc, 0x5f, 0x95, 0x89, + 0x13, 0xb2, 0xc5, 0x71, 0xbf, 0x68, 0x12, 0x25, 0x68, 0xa1, 0x47, 0xb5, + 0x70, 0x1a, 0x39, 0xa6, 0x70, 0x5e, 0x51, 0xcf, 0xb9, 0x1f, 0xd4, 0xed, + 0x03, 0xcd, 0x5b, 0x6b, 0xb3, 0xda, 0xd0, 0xbe, 0xed, 0xdc, 0x3e, 0xa4, + 0x9d, 0xde, 0x19, 0x6b, 0x0b, 0xac, 0x05, 0x57, 0x3c, 0x74, 0xa7, 0xcd, + 0x59, 0x20, 0x0e, 0x67, 0x4a, 0xb4, 0xea, 0xb9, 0x3e, 0x59, 0xcd, 0x9f, + 0x81, 0xa9, 0x39, 0xb2, 0x64, 0xe7, 0x28, 0xe6, 0x3e, 0x91, 0x7d, 0x1f, + 0xb0, 0x12, 0xbe, 0x11, 0x0c, 0xcc, 0xc6, 0x7d, 0x61, 0x37, 0x91, 0x9e, + 0xdf, 0xf1, 0x73, 0x49, 0xe6, 0x9d, 0xce, 0x99, 0xde, 0xf3, 0x64, 0xee, + 0x83, 0x5f, 0x3c, 0xdd, 0x9f, 0x6c, 0x98, 0x53, 0x9b, 0xf2, 0xa7, 0x9b, + 0xb5, 0x3f, 0x65, 0x6c, 0x1f, 0x7c, 0x0f, 0xdb, 0x5b, 0xb2, 0xbe, 0xf7, + 0xcf, 0xd5, 0x3f, 0x59, 0x9b, 0xd8, 0xcf, 0x1e, 0xa9, 0x56, 0x71, 0x75, + 0xa2, 0x9f, 0x05, 0xd7, 0xcc, 0xa5, 0xc4, 0xd6, 0x7b, 0xe1, 0x6b, 0x6c, + 0xef, 0xd0, 0x67, 0xdf, 0xc7, 0x27, 0xb1, 0xaf, 0xb2, 0x2f, 0x6a, 0xb5, + 0xe1, 0x64, 0x7b, 0x35, 0x59, 0x43, 0xaa, 0x7c, 0xfb, 0x84, 0x3a, 0x33, + 0xe7, 0xbf, 0x27, 0x75, 0x19, 0xf1, 0xe0, 0x39, 0x58, 0x87, 0xdd, 0x02, + 0x25, 0xa1, 0x23, 0xb5, 0x16, 0x61, 0x69, 0xb0, 0xa0, 0x8c, 0xc0, 0xcf, + 0xe4, 0x2a, 0xe4, 0x3b, 0xa6, 0x7a, 0xa7, 0xf0, 0x8b, 0x6a, 0xf5, 0x9d, + 0x03, 0xbe, 0xfb, 0x36, 0x38, 0x6c, 0x3c, 0x4f, 0xef, 0x56, 0x19, 0xde, + 0x37, 0x62, 0xbe, 0x6a, 0x8e, 0x50, 0x34, 0x9b, 0x76, 0xe3, 0x3c, 0xe8, + 0x35, 0x96, 0xe0, 0x0c, 0x17, 0x73, 0x7f, 0x92, 0xe3, 0x1d, 0xf6, 0xd0, + 0x6a, 0x2a, 0xb1, 0x9d, 0x25, 0x35, 0x4b, 0x4a, 0x61, 0x85, 0x45, 0x8d, + 0x73, 0xf1, 0xbc, 0xe7, 0x6d, 0xb6, 0xf2, 0x06, 0xdc, 0x72, 0xc5, 0xd6, + 0x64, 0xa0, 0x96, 0x7c, 0xb6, 0x06, 0x7b, 0x11, 0x8d, 0xc8, 0xb7, 0xb1, + 0x4e, 0x5b, 0xd2, 0xb7, 0x88, 0xba, 0x10, 0x0f, 0x93, 0xbe, 0x3a, 0x50, + 0xb3, 0x3c, 0xc0, 0xf2, 0x79, 0x19, 0x39, 0xcf, 0x43, 0xd5, 0xea, 0x0a, + 0x52, 0x37, 0x63, 0xf6, 0x19, 0xbf, 0x7c, 0x37, 0xc6, 0xef, 0x06, 0xbb, + 0x88, 0x9f, 0xcd, 0x90, 0xfd, 0x46, 0xae, 0xcf, 0xa4, 0xfb, 0xbf, 0xe5, + 0x7b, 0xc8, 0x06, 0x5a, 0x40, 0x49, 0xf7, 0x2b, 0xf2, 0x6d, 0xcc, 0x1c, + 0x9a, 0x45, 0x25, 0xb8, 0x6d, 0xec, 0xc6, 0xae, 0xbe, 0x04, 0x13, 0x5b, + 0x22, 0xdc, 0x84, 0xb6, 0xcd, 0xfd, 0xa9, 0x87, 0x7c, 0x31, 0x37, 0x7f, + 0xc3, 0xc6, 0x69, 0x69, 0xb0, 0xdb, 0xe8, 0xe9, 0x45, 0xff, 0xfb, 0x7a, + 0x95, 0xe5, 0xa7, 0x8b, 0xec, 0xee, 0x06, 0x87, 0x95, 0xbe, 0x5c, 0x5b, + 0x65, 0xb9, 0xc4, 0xf3, 0xa5, 0xda, 0x98, 0x6f, 0x3e, 0x56, 0x7b, 0xd5, + 0x53, 0x45, 0x93, 0xce, 0x35, 0x4b, 0xdf, 0xa9, 0x56, 0xfb, 0x24, 0xbf, + 0x77, 0xf3, 0xa2, 0xe7, 0xde, 0xd5, 0x31, 0xdf, 0xe3, 0xfa, 0x1d, 0x54, + 0xe6, 0x5d, 0xcd, 0x3f, 0x74, 0x8c, 0x61, 0x9f, 0x27, 0x79, 0xe3, 0x96, + 0x3e, 0x8f, 0x48, 0x24, 0xe4, 0xfb, 0xa1, 0x66, 0x12, 0x46, 0x50, 0xb0, + 0xc7, 0xef, 0x92, 0xef, 0xb6, 0x64, 0x0d, 0x36, 0x59, 0x5d, 0x11, 0xbd, + 0x63, 0x85, 0x68, 0xc3, 0x4d, 0x9d, 0xbd, 0x74, 0x83, 0x95, 0x0b, 0x2b, + 0x5a, 0xee, 0xf7, 0x57, 0xd3, 0x83, 0x56, 0xab, 0x52, 0xdf, 0x96, 0x61, + 0x3e, 0x6f, 0xd5, 0x8e, 0x50, 0x44, 0xf7, 0x64, 0x64, 0x0f, 0x6b, 0xe6, + 0xae, 0x63, 0x62, 0xaa, 0xe7, 0xae, 0x53, 0xed, 0x2b, 0x44, 0xc9, 0x94, + 0x3b, 0x8f, 0xd0, 0x2f, 0xad, 0x68, 0x39, 0xca, 0xec, 0xdb, 0xb0, 0x9e, + 0x8e, 0xd8, 0x98, 0xa7, 0xab, 0x25, 0x59, 0x4e, 0xbf, 0xd7, 0xaa, 0xde, + 0x0d, 0xed, 0x74, 0xab, 0x8d, 0x8a, 0x76, 0x6e, 0x38, 0xb8, 0xe1, 0xc0, + 0xc5, 0x3f, 0x3e, 0x45, 0x37, 0xd9, 0x74, 0xe5, 0xf4, 0x35, 0x88, 0x8f, + 0x74, 0xfa, 0x03, 0x2b, 0x0e, 0xd0, 0x1d, 0x0e, 0xb4, 0xed, 0xa5, 0xc7, + 0xce, 0xbf, 0xf0, 0xd8, 0xbe, 0x47, 0x37, 0xd0, 0x13, 0x9c, 0x12, 0x1e, + 0xcf, 0xa9, 0xc7, 0xe8, 0x17, 0x0e, 0x69, 0xfd, 0x12, 0x7d, 0xdb, 0x21, + 0x8b, 0xff, 0xb4, 0x24, 0xbd, 0xf4, 0x8a, 0x05, 0x26, 0x11, 0x7a, 0x1d, + 0xfd, 0xef, 0xbb, 0xe7, 0xc0, 0xd3, 0xcb, 0x5f, 0xee, 0xf3, 0x23, 0xc3, + 0x01, 0x7a, 0x8a, 0xe5, 0xf4, 0x33, 0x0b, 0x5b, 0x19, 0x4b, 0x77, 0x18, + 0x1d, 0xfb, 0xe9, 0x97, 0x3c, 0x46, 0xbf, 0xe2, 0xc7, 0x71, 0x7e, 0x17, + 0xf5, 0x09, 0x7e, 0xdc, 0x60, 0xb0, 0xd9, 0x47, 0x99, 0xfd, 0x18, 0x3f, + 0x6e, 0xe4, 0xc7, 0xf5, 0xfc, 0xb8, 0xd6, 0x90, 0xf5, 0x7c, 0x58, 0x1a, + 0x5c, 0x27, 0x9f, 0x1f, 0x57, 0xa2, 0x9b, 0x64, 0xa2, 0x47, 0xb6, 0x87, + 0x7e, 0xe7, 0xc0, 0xe3, 0x59, 0x1b, 0x24, 0x17, 0x6e, 0x58, 0xde, 0x7b, + 0x47, 0x64, 0xc3, 0xc6, 0x23, 0xd5, 0xf4, 0x02, 0x17, 0xd0, 0x23, 0xad, + 0xf4, 0xb8, 0xf5, 0x64, 0x06, 0xff, 0x66, 0x96, 0xfe, 0xd8, 0x8e, 0xc7, + 0x15, 0x5c, 0xcc, 0x51, 0xfa, 0xb8, 0x6c, 0xe2, 0xbd, 0x86, 0xe7, 0xf5, + 0xea, 0x0d, 0x61, 0x63, 0x74, 0xc7, 0x4e, 0xfa, 0x86, 0x45, 0x16, 0xfd, + 0xd8, 0x4b, 0x77, 0x1e, 0xad, 0x09, 0x1b, 0x17, 0xed, 0xa7, 0x2f, 0x49, + 0x93, 0xbb, 0xe8, 0x19, 0x81, 0x1c, 0x77, 0x6d, 0x30, 0x4a, 0x45, 0x79, + 0xd1, 0x8d, 0x46, 0xfa, 0xba, 0x1b, 0x8d, 0x03, 0xd7, 0x09, 0xaf, 0x93, + 0xee, 0xe7, 0x92, 0xee, 0xa0, 0x1e, 0xd9, 0xba, 0x3e, 0x99, 0xd9, 0xf8, + 0x2e, 0x35, 0x19, 0x7f, 0x30, 0xf6, 0x1b, 0x3f, 0xb1, 0xec, 0x3f, 0x60, + 0xbc, 0x73, 0xe0, 0xc5, 0xce, 0xe8, 0x0d, 0xcb, 0x97, 0xaf, 0x58, 0xbe, + 0x7c, 0xe5, 0xc1, 0x0b, 0x96, 0x5f, 0xbf, 0x82, 0x8e, 0x61, 0x18, 0x6e, + 0xa0, 0x43, 0x02, 0x27, 0xe5, 0x97, 0xd1, 0xd8, 0x4b, 0x36, 0xac, 0xa0, + 0x6b, 0xb9, 0xf4, 0x1b, 0x56, 0xd0, 0x29, 0x21, 0x27, 0x4c, 0x94, 0xb8, + 0x8f, 0xf9, 0xf7, 0xd1, 0x63, 0x2a, 0x75, 0x4c, 0x94, 0x7b, 0xfd, 0x9d, + 0xf4, 0x2e, 0xdb, 0x1e, 0xa1, 0xdf, 0xd8, 0xd9, 0x94, 0xae, 0xe1, 0xe9, + 0xb9, 0x91, 0xae, 0x92, 0x19, 0xe9, 0x72, 0x3b, 0x5b, 0x7e, 0x85, 0xde, + 0xb4, 0xa9, 0x3e, 0xaf, 0x38, 0x42, 0xd7, 0xda, 0xb9, 0x31, 0x1f, 0xdc, + 0xd9, 0x77, 0xec, 0xa9, 0xf3, 0x8f, 0x6c, 0x3e, 0x62, 0xb8, 0xf7, 0xf7, + 0x1e, 0x58, 0x21, 0xbc, 0xee, 0x3b, 0x85, 0xa7, 0x8c, 0x7e, 0x86, 0x42, + 0x76, 0xd0, 0x9b, 0x86, 0x6c, 0xef, 0x65, 0x1b, 0x96, 0x67, 0xd6, 0xc2, + 0x22, 0x52, 0x77, 0xc5, 0x12, 0xde, 0x5d, 0x40, 0xe7, 0x90, 0x3a, 0xcf, + 0xcd, 0x84, 0xef, 0x67, 0xbe, 0x6b, 0x27, 0xb4, 0x4d, 0xe6, 0xbd, 0x8b, + 0x91, 0x85, 0x4b, 0xa6, 0x5d, 0xda, 0x26, 0xf3, 0xfd, 0xbd, 0x26, 0x4d, + 0xeb, 0x35, 0xcd, 0xcb, 0xda, 0xab, 0x3d, 0xa4, 0x5e, 0xdf, 0xe6, 0x59, + 0x36, 0x4b, 0x97, 0x59, 0xa5, 0x6d, 0xeb, 0xb4, 0x3c, 0x63, 0xb3, 0x4a, + 0xb7, 0x27, 0x73, 0x5f, 0x65, 0x78, 0xb4, 0xcd, 0x2a, 0x5d, 0x5e, 0xa6, + 0x5d, 0xd6, 0x2c, 0x2f, 0x74, 0x7b, 0x0b, 0xe4, 0x32, 0xcc, 0xdc, 0x81, + 0x0d, 0x6d, 0x63, 0x98, 0x6c, 0x0c, 0xbd, 0x8f, 0xf0, 0xad, 0xaa, 0x20, + 0xdb, 0xce, 0x55, 0x9a, 0xae, 0xd1, 0x74, 0xad, 0x2c, 0xc1, 0xa2, 0xf5, + 0xb8, 0x2b, 0x99, 0xea, 0x53, 0xef, 0x31, 0x2c, 0x92, 0xae, 0xd5, 0xf5, + 0xaa, 0xf7, 0x29, 0x4c, 0xf3, 0x35, 0x2d, 0xd4, 0x79, 0x3d, 0x38, 0xf1, + 0x59, 0xe4, 0x58, 0x8d, 0xb7, 0x79, 0x0a, 0xad, 0x94, 0x29, 0xbb, 0x89, + 0xcf, 0xf4, 0xa9, 0x5c, 0xe7, 0x9b, 0x81, 0x99, 0x12, 0xa4, 0xde, 0x59, + 0x0a, 0x1a, 0xff, 0xce, 0xe2, 0x2c, 0xd4, 0xc9, 0xe5, 0xcd, 0x05, 0x5d, + 0xab, 0xdb, 0x51, 0x2f, 0x6b, 0xc9, 0x8c, 0x63, 0xbd, 0x96, 0xad, 0x95, + 0x32, 0xab, 0x9c, 0x9f, 0xf1, 0xf2, 0x57, 0x6a, 0xd9, 0x4a, 0xd3, 0x98, + 0xac, 0x94, 0x29, 0xf5, 0x5d, 0x3d, 0xa6, 0x5c, 0xae, 0x4d, 0xd2, 0xf1, + 0x7c, 0x8c, 0x56, 0x4d, 0xdb, 0x74, 0xbd, 0xac, 0x29, 0x36, 0xf1, 0xd3, + 0xb3, 0x7e, 0x33, 0xdd, 0x34, 0xee, 0xc5, 0xd9, 0xf9, 0x9c, 0xa7, 0xf5, + 0x6e, 0x5d, 0xe6, 0x0c, 0x5d, 0x4f, 0x7d, 0xd6, 0x92, 0xf4, 0x77, 0x0b, + 0x32, 0xd6, 0x22, 0x9f, 0x84, 0x93, 0x44, 0x21, 0xcd, 0xaf, 0x4c, 0x36, + 0x54, 0x46, 0x43, 0xc3, 0xfd, 0x83, 0xa1, 0xca, 0x96, 0x3a, 0x7f, 0x64, + 0x6b, 0xdd, 0x68, 0x5b, 0x4f, 0xed, 0xe8, 0xde, 0xfd, 0x4b, 0x0f, 0x2e, + 0x4a, 0x8e, 0x76, 0x24, 0x97, 0x6e, 0x1c, 0xab, 0x5b, 0x37, 0xda, 0x9e, + 0x63, 0x77, 0x61, 0xe7, 0x58, 0xbc, 0xeb, 0xe0, 0xa6, 0xc5, 0xfb, 0x3b, + 0xf6, 0xaf, 0xeb, 0x0f, 0xb4, 0xed, 0x58, 0xb3, 0xae, 0xbe, 0x7e, 0x75, + 0xc3, 0x96, 0xae, 0xf5, 0xdd, 0xb9, 0x76, 0xd1, 0xed, 0x0d, 0x81, 0xb5, + 0x43, 0x03, 0x4b, 0x1a, 0xba, 0x0e, 0x1c, 0xe8, 0xe9, 0x5d, 0x7a, 0xd1, + 0xe2, 0x1d, 0xfb, 0xd7, 0x8f, 0x5e, 0x38, 0xd2, 0x1f, 0x3e, 0x2f, 0x85, + 0xbd, 0x91, 0x8c, 0xaa, 0x0e, 0x12, 0x0b, 0xc8, 0xbe, 0x3c, 0x12, 0x8b, + 0xa4, 0x57, 0x92, 0xb1, 0xb2, 0x89, 0xac, 0x2b, 0x9b, 0xf0, 0xb4, 0xf3, + 0x73, 0x41, 0x0f, 0x15, 0xb6, 0x0c, 0x85, 0x62, 0x7b, 0xc3, 0xe7, 0x85, + 0xd2, 0x03, 0x43, 0xe1, 0x24, 0x4d, 0x6d, 0x89, 0x0f, 0x27, 0xe2, 0xb1, + 0x70, 0x2c, 0xdd, 0x15, 0x0e, 0x27, 0x7b, 0x22, 0xe1, 0xfd, 0xd5, 0x17, + 0x86, 0xc6, 0x42, 0xe4, 0x6c, 0x89, 0xc7, 0x62, 0xe1, 0x81, 0x74, 0x24, + 0x1e, 0x23, 0xef, 0xda, 0x86, 0xca, 0xca, 0xee, 0x83, 0xb1, 0xf4, 0x50, + 0x38, 0x1d, 0x19, 0x68, 0x89, 0x86, 0x52, 0xa8, 0xaa, 0x8d, 0x8c, 0xb6, + 0x76, 0x12, 0xed, 0x64, 0xb4, 0x2f, 0x00, 0xda, 0xc9, 0xd2, 0xde, 0xce, + 0x89, 0x0e, 0x30, 0x1d, 0x9d, 0x60, 0x3a, 0x49, 0x74, 0x90, 0xd1, 0xc1, + 0xe8, 0xa4, 0x59, 0x1d, 0xa3, 0x03, 0xe1, 0xd5, 0x03, 0x03, 0xe1, 0x54, + 0x2a, 0xd2, 0x1f, 0x89, 0x46, 0xd2, 0x07, 0x37, 0xc5, 0x07, 0xc3, 0x5d, + 0xc9, 0xf8, 0x58, 0x64, 0x10, 0xad, 0x28, 0xdb, 0x10, 0x3e, 0xd8, 0x1f, + 0x0f, 0x25, 0x07, 0xd7, 0x46, 0x52, 0xc3, 0x91, 0x54, 0xaa, 0x33, 0x92, + 0x4a, 0x87, 0x63, 0x50, 0x08, 0x94, 0xd4, 0x89, 0xb2, 0x3b, 0xb9, 0xec, + 0x4e, 0x94, 0xdd, 0xd9, 0xd1, 0x4e, 0x56, 0x3c, 0x38, 0xd9, 0x89, 0xa4, + 0x54, 0x42, 0x61, 0xed, 0x64, 0xcd, 0xd4, 0xce, 0x50, 0x6c, 0x30, 0x19, + 0x8f, 0x0c, 0xd6, 0x84, 0x12, 0x89, 0x9a, 0xd5, 0x68, 0xfe, 0x18, 0xaa, + 0x6a, 0xa2, 0xc5, 0xb9, 0xf2, 0x44, 0x22, 0x1a, 0x19, 0x08, 0x71, 0xdf, + 0x2a, 0x33, 0x36, 0x9d, 0x91, 0x3d, 0xe1, 0x81, 0x83, 0x03, 0xd1, 0x70, + 0x4b, 0x28, 0x1a, 0xed, 0x0f, 0x0d, 0xec, 0x4b, 0x35, 0xd1, 0xb4, 0xc9, + 0x72, 0x99, 0x55, 0x03, 0xf1, 0x18, 0x9a, 0x9a, 0xae, 0x69, 0x61, 0x7a, + 0x20, 0x6d, 0x56, 0xed, 0x4d, 0x86, 0x12, 0x43, 0x91, 0x81, 0x54, 0x4d, + 0x4b, 0x28, 0x36, 0x16, 0x42, 0x81, 0xb3, 0xcf, 0xa0, 0x8a, 0x47, 0xe3, + 0xc9, 0xb6, 0x48, 0x34, 0x1d, 0x4e, 0x4e, 0xae, 0xdf, 0x18, 0x4a, 0x27, + 0x23, 0x07, 0x9a, 0x68, 0xc1, 0x7b, 0xea, 0x73, 0x8a, 0x2a, 0x9f, 0x68, + 0xda, 0x15, 0x8a, 0xc4, 0xd2, 0x67, 0xd6, 0xc4, 0xa5, 0xa6, 0x6c, 0xa2, + 0x66, 0x2b, 0x5c, 0xa0, 0x89, 0xa6, 0x67, 0x15, 0xf1, 0x54, 0xcd, 0x9a, + 0xd1, 0x48, 0x74, 0xb0, 0xb2, 0xa7, 0x75, 0x6b, 0x77, 0xfb, 0xe6, 0x4d, + 0x4d, 0x54, 0x92, 0xab, 0x8b, 0x0d, 0x46, 0xc3, 0x4d, 0x34, 0xc5, 0x2c, + 0x6c, 0x5f, 0x13, 0x89, 0x0d, 0x72, 0x9b, 0xc6, 0xcb, 0xe7, 0x91, 0xaa, + 0x69, 0x1d, 0x8c, 0xa4, 0x43, 0xfd, 0x6c, 0x5e, 0x9e, 0xab, 0xe8, 0x0e, + 0x47, 0x95, 0xe7, 0x99, 0x6b, 0x56, 0x9a, 0x44, 0x28, 0xa6, 0x3d, 0x77, + 0x62, 0x2e, 0xe8, 0x62, 0xaa, 0xbc, 0x79, 0x93, 0x68, 0xba, 0x31, 0x4c, + 0xb1, 0xbd, 0xb2, 0x03, 0x5c, 0xc0, 0x69, 0x85, 0x07, 0xf1, 0xc8, 0x16, + 0x3e, 0xde, 0xad, 0xd1, 0x74, 0x24, 0xca, 0x63, 0x77, 0x66, 0xe1, 0x72, + 0x3a, 0x27, 0x2b, 0x1c, 0xc3, 0xea, 0xa9, 0x69, 0x19, 0x8a, 0x27, 0xc3, + 0x71, 0x39, 0x80, 0xe1, 0x64, 0x65, 0x5b, 0x32, 0x34, 0x9c, 0x75, 0xa9, + 0x26, 0x9a, 0xf9, 0x1e, 0xb6, 0xe6, 0xf1, 0x91, 0x5a, 0xac, 0x89, 0xd6, + 0xb1, 0x70, 0x2c, 0x67, 0xfc, 0xa5, 0x62, 0x63, 0x9c, 0x07, 0x47, 0xeb, + 0x16, 0xe4, 0xea, 0x78, 0x05, 0x57, 0x6e, 0x8e, 0xb5, 0xc5, 0x07, 0x46, + 0x53, 0x6a, 0xa5, 0x67, 0xd6, 0x92, 0xb9, 0xf9, 0x59, 0x53, 0xf3, 0x28, + 0x66, 0x85, 0xeb, 0x92, 0xf1, 0xd1, 0x44, 0x13, 0x2d, 0x99, 0xa8, 0x09, + 0x26, 0xc3, 0xe1, 0xcd, 0xfd, 0xa9, 0x70, 0x72, 0x0c, 0x7d, 0xdb, 0x1c, + 0x5b, 0x17, 0x8d, 0xf7, 0x87, 0xa2, 0x9d, 0xa1, 0x83, 0xf1, 0xd1, 0xf4, + 0x78, 0x35, 0x73, 0xde, 0x3b, 0x5f, 0x13, 0x95, 0xe6, 0x1a, 0x9c, 0x07, + 0xf7, 0x88, 0xa3, 0x25, 0xbe, 0x33, 0x89, 0xdb, 0x63, 0xa9, 0x70, 0x3a, + 0x55, 0x19, 0x3c, 0x98, 0xc8, 0x99, 0xd7, 0x09, 0x16, 0xbc, 0xfc, 0x92, + 0xf1, 0x68, 0x94, 0xcb, 0xaf, 0xcd, 0x35, 0x0b, 0x99, 0xc3, 0x4e, 0x4d, + 0x4e, 0x10, 0xda, 0x18, 0x8a, 0x85, 0xf6, 0x72, 0x96, 0xba, 0x7f, 0x3a, + 0x0b, 0xc7, 0xad, 0xf6, 0xd8, 0x9e, 0xf8, 0x84, 0xf1, 0x79, 0x9f, 0x3c, + 0x99, 0x58, 0xd7, 0x44, 0xd5, 0xb9, 0xf9, 0x22, 0xb1, 0xc4, 0x68, 0x7a, + 0x38, 0x9c, 0x1e, 0x8a, 0x0f, 0xd6, 0xac, 0x09, 0xa5, 0x50, 0x38, 0xd2, + 0xe3, 0xd1, 0x77, 0x42, 0xaf, 0xcd, 0xf6, 0xbc, 0x84, 0xe2, 0x49, 0xd5, + 0x9c, 0x73, 0x26, 0x37, 0x9b, 0x50, 0xa4, 0xff, 0x7d, 0x6c, 0x37, 0x4a, + 0x3e, 0x3b, 0x3a, 0x4d, 0x9d, 0x03, 0xf1, 0xe1, 0x9a, 0xe4, 0x70, 0x2a, + 0x5a, 0x73, 0x21, 0xe2, 0x78, 0xcd, 0x84, 0x3d, 0xa3, 0xb2, 0xb2, 0xf5, + 0x00, 0xc2, 0x4e, 0x2c, 0x14, 0xcd, 0x6e, 0x13, 0x9d, 0x72, 0xbb, 0x0a, + 0xfc, 0x5f, 0x32, 0xd7, 0xfe, 0x5f, 0x32, 0xd7, 0x35, 0x51, 0xcd, 0xfb, + 0x66, 0xce, 0xd9, 0x0b, 0x9b, 0x68, 0xe1, 0xfb, 0x67, 0x30, 0x0d, 0xe2, + 0xaa, 0xf7, 0xb5, 0x7e, 0xcf, 0x4d, 0xaf, 0x89, 0xda, 0xde, 0xb7, 0x80, + 0x49, 0xb6, 0xc5, 0xca, 0xdc, 0xf5, 0xd4, 0xf8, 0xff, 0x5b, 0x0e, 0xfb, + 0xe2, 0xfb, 0x65, 0xdd, 0x18, 0x1f, 0x4d, 0x85, 0xd7, 0x87, 0x38, 0xae, + 0xcb, 0xa5, 0xf5, 0x7e, 0xf6, 0x1c, 0x45, 0xa5, 0x0f, 0x05, 0x43, 0xc9, + 0xbd, 0x61, 0x04, 0xa8, 0xb9, 0xef, 0x97, 0xa5, 0x89, 0x2a, 0x3a, 0x07, + 0x43, 0xd1, 0xb1, 0xc8, 0xbe, 0x1a, 0xc4, 0xe9, 0x78, 0x5a, 0x6e, 0xb1, + 0x35, 0xad, 0xb1, 0x81, 0x68, 0x3c, 0x85, 0x70, 0x2d, 0xcf, 0x1b, 0xbc, + 0x37, 0x4e, 0xb4, 0x69, 0xc7, 0x64, 0x24, 0xb5, 0x7e, 0xee, 0x19, 0xf4, + 0x1b, 0xc3, 0xc3, 0xfd, 0xda, 0x20, 0x0c, 0x93, 0xca, 0x33, 0x9a, 0xb0, + 0xa7, 0x77, 0x85, 0x38, 0x4e, 0xc3, 0x8f, 0x60, 0x35, 0xeb, 0x0c, 0x56, + 0xdd, 0x91, 0xbd, 0xb1, 0x50, 0x7a, 0x34, 0x29, 0xf7, 0x2a, 0x3e, 0x1f, + 0xd5, 0x44, 0xe1, 0x38, 0x88, 0xdf, 0xa1, 0x64, 0x77, 0x78, 0x64, 0x34, + 0x1c, 0x1b, 0x08, 0x73, 0xdc, 0x1b, 0xd7, 0xb4, 0x8d, 0xc6, 0xa4, 0x97, + 0x84, 0xa2, 0xed, 0x38, 0x16, 0x24, 0xf7, 0x84, 0xd8, 0xa0, 0xc4, 0x64, + 0xc0, 0x62, 0xb9, 0xb6, 0xbc, 0x26, 0xe1, 0xe6, 0xfe, 0x0b, 0xe5, 0x7e, + 0x6b, 0x96, 0xa9, 0x3d, 0x8b, 0x83, 0xa6, 0x94, 0xc9, 0x8d, 0x67, 0x75, + 0x32, 0x19, 0x3a, 0xc8, 0x93, 0xc8, 0x3b, 0xed, 0xb8, 0xb8, 0x1d, 0x35, + 0x85, 0x10, 0x0f, 0x9a, 0xc8, 0x6d, 0x92, 0x2a, 0xbb, 0xd3, 0x25, 0xcb, + 0xc9, 0x65, 0x9e, 0x59, 0x72, 0x74, 0xaf, 0xdd, 0xb0, 0xab, 0x7d, 0x53, + 0x90, 0x8a, 0x4f, 0x9b, 0x40, 0x72, 0x99, 0x9d, 0x8d, 0x44, 0x0f, 0x19, + 0x3d, 0x38, 0x73, 0xf5, 0xe0, 0x04, 0x66, 0xed, 0xe1, 0x23, 0x9f, 0x8d, + 0x9f, 0x52, 0x82, 0xb3, 0x5a, 0x4f, 0x07, 0xd9, 0x7b, 0x3a, 0xda, 0xdb, + 0xda, 0x70, 0x22, 0xeb, 0xe9, 0x90, 0xda, 0x0e, 0xa5, 0xc5, 0x41, 0x10, + 0x8f, 0x4e, 0x16, 0xf3, 0xc1, 0xad, 0xa7, 0xa3, 0x17, 0xd6, 0xcc, 0x74, + 0x72, 0x41, 0x9d, 0xd2, 0xb4, 0x53, 0x99, 0xf2, 0x39, 0xaf, 0x07, 0x46, + 0x10, 0xb0, 0xdc, 0x21, 0x89, 0xac, 0xaf, 0x53, 0x66, 0xed, 0xec, 0x65, + 0xb6, 0xb7, 0x43, 0x3e, 0x3b, 0xe5, 0x93, 0x0b, 0xeb, 0x45, 0xd5, 0xbd, + 0xd2, 0x50, 0xf4, 0x92, 0xa5, 0x97, 0x33, 0xe0, 0xd1, 0xc9, 0x2c, 0x5a, + 0x06, 0x73, 0x5b, 0x6f, 0x07, 0xa7, 0xad, 0x20, 0x2c, 0x60, 0x0d, 0x2a, + 0xb7, 0xf7, 0x76, 0x4a, 0xb1, 0x8d, 0x29, 0xcb, 0x51, 0x56, 0x1f, 0x4e, + 0xb7, 0x7d, 0xed, 0xe4, 0x54, 0x31, 0xbd, 0x32, 0x10, 0x08, 0x64, 0xf9, + 0x5a, 0xf0, 0x05, 0xe3, 0xbc, 0x29, 0x91, 0xa3, 0xa9, 0x33, 0x27, 0x16, + 0x99, 0x13, 0x8b, 0xcd, 0x89, 0x7a, 0x73, 0x62, 0x89, 0x39, 0xb1, 0xd4, + 0x9c, 0x68, 0x30, 0x27, 0x1a, 0x4d, 0xad, 0x31, 0x57, 0x53, 0x67, 0x6e, + 0xe6, 0x22, 0x13, 0xbf, 0xd8, 0xc4, 0xd7, 0x9b, 0xf8, 0x25, 0x26, 0x7e, + 0xa9, 0x89, 0x6f, 0x30, 0xf1, 0x8d, 0xe3, 0x15, 0xb4, 0x45, 0x43, 0x7b, + 0x53, 0x54, 0x98, 0xb3, 0xcf, 0xd1, 0x94, 0xd0, 0x19, 0xf6, 0x53, 0xce, + 0xc1, 0xde, 0xdf, 0x19, 0xea, 0x0f, 0x47, 0xc9, 0x12, 0x1a, 0x1c, 0xa4, + 0x69, 0x78, 0x9c, 0xf9, 0xc0, 0x40, 0xee, 0xd0, 0x1e, 0x38, 0x2e, 0xbb, + 0x9d, 0x0a, 0xc7, 0x83, 0xe4, 0xe1, 0xd3, 0xd2, 0x9a, 0xd1, 0x74, 0x3a, + 0x1e, 0xeb, 0x4a, 0xa2, 0x74, 0x29, 0x0a, 0xef, 0xc1, 0x61, 0xc9, 0x6c, + 0x65, 0xef, 0x8f, 0xc3, 0x62, 0x98, 0xec, 0x03, 0x21, 0x84, 0xef, 0x41, + 0x72, 0x2b, 0x6a, 0xba, 0xb8, 0x14, 0x0e, 0xe4, 0xdc, 0x75, 0x6c, 0x38, + 0xde, 0x87, 0x92, 0x54, 0xcc, 0x81, 0x25, 0x6c, 0x32, 0x2b, 0x93, 0x02, + 0xd3, 0xc6, 0xa7, 0xcf, 0xf2, 0x54, 0x30, 0xc0, 0xf1, 0x9a, 0x0f, 0xc7, + 0xab, 0xd3, 0x54, 0x94, 0x4d, 0xb4, 0xc4, 0x47, 0x63, 0x69, 0x14, 0x0e, + 0x2b, 0x1c, 0xa9, 0x53, 0x52, 0x46, 0x53, 0xf4, 0x45, 0x20, 0xb5, 0x46, + 0x36, 0x54, 0x35, 0x92, 0x66, 0x0c, 0x24, 0xc3, 0xa1, 0xf4, 0xc4, 0x4d, + 0x80, 0xb7, 0x6c, 0x72, 0x0c, 0xc6, 0xe5, 0xf9, 0x90, 0xf2, 0xc2, 0xfa, + 0x28, 0x0c, 0x2e, 0x36, 0x98, 0x3a, 0x2f, 0x92, 0x1e, 0x22, 0xdf, 0x1e, + 0x9c, 0x6e, 0xce, 0x98, 0x2f, 0xb5, 0xe6, 0x20, 0x0f, 0x03, 0xe5, 0xb3, + 0x85, 0x3c, 0xe8, 0x91, 0x6b, 0xcf, 0xf8, 0x79, 0x6f, 0x90, 0x66, 0x60, + 0xd9, 0xe6, 0xe4, 0x94, 0x46, 0x1c, 0x6a, 0xdb, 0x07, 0x69, 0xe6, 0xe9, + 0xca, 0x9c, 0x8b, 0x58, 0xbe, 0xd4, 0xca, 0x51, 0x29, 0xca, 0xb2, 0xed, + 0x38, 0xbe, 0x1f, 0xa0, 0xe2, 0x6c, 0x7a, 0x63, 0x28, 0xb5, 0x0f, 0xd5, + 0x94, 0xb2, 0x60, 0xfc, 0x52, 0x94, 0x19, 0x34, 0x37, 0xc4, 0x2d, 0xa1, + 0x64, 0x38, 0xdd, 0x85, 0xf0, 0x2d, 0x4b, 0x9a, 0xc2, 0x12, 0x84, 0x4a, + 0x59, 0x4e, 0x5b, 0x3c, 0xa9, 0x06, 0xac, 0x50, 0x4b, 0xe1, 0x2a, 0x88, + 0xbb, 0x54, 0xc2, 0x49, 0xde, 0x1a, 0x38, 0xe6, 0xf3, 0x89, 0xbd, 0x35, + 0xa6, 0xaa, 0xc8, 0x11, 0x76, 0xa7, 0x43, 0xc9, 0x34, 0x39, 0xa5, 0x58, + 0x55, 0xe7, 0x02, 0xbf, 0x36, 0x3c, 0x10, 0x97, 0x5b, 0x09, 0x15, 0x20, + 0x95, 0xb9, 0x57, 0x48, 0x95, 0x3c, 0x25, 0x07, 0x23, 0x18, 0xe4, 0x69, + 0x48, 0xc9, 0x81, 0x08, 0x0f, 0x9e, 0x1e, 0xe2, 0x7c, 0x93, 0xaa, 0x64, + 0x53, 0xf5, 0xb8, 0xac, 0x0f, 0x47, 0xf6, 0x0e, 0xa5, 0x65, 0x39, 0xeb, + 0xc1, 0x45, 0x39, 0x15, 0x1e, 0xdc, 0x1a, 0xde, 0x8b, 0x3e, 0xae, 0xc1, + 0x13, 0x8e, 0x74, 0x26, 0x15, 0xf7, 0x83, 0x3b, 0x27, 0x4b, 0x35, 0xcf, + 0x44, 0x69, 0x46, 0x98, 0x73, 0xda, 0xa2, 0xf9, 0x19, 0x31, 0x9f, 0x79, + 0x31, 0x5a, 0x7c, 0x88, 0xe8, 0x89, 0x24, 0xd3, 0xa3, 0xa1, 0x68, 0x66, + 0x1b, 0x67, 0x8d, 0xec, 0x2a, 0xce, 0xbe, 0xe9, 0x10, 0x36, 0x1f, 0x39, + 0x39, 0x39, 0x5a, 0xae, 0xb1, 0x33, 0xae, 0x66, 0x66, 0x73, 0xac, 0x1b, + 0x6e, 0x18, 0x8e, 0xc9, 0x01, 0x41, 0x65, 0x21, 0x8c, 0x62, 0x3a, 0x2c, + 0x27, 0x60, 0x13, 0x0c, 0xc6, 0xc2, 0x72, 0xe8, 0x8a, 0xc7, 0xbb, 0xab, + 0x1c, 0xdc, 0x35, 0x2e, 0x40, 0x6b, 0x1d, 0x48, 0x6d, 0x0d, 0xed, 0xdf, + 0x9e, 0x61, 0x76, 0xc8, 0x06, 0x6c, 0x8d, 0xc7, 0xd3, 0xd9, 0xdc, 0xd9, + 0x7b, 0x1b, 0x77, 0xd9, 0x63, 0x16, 0xa8, 0x69, 0x63, 0xcf, 0xe8, 0x3e, + 0x88, 0x55, 0x3f, 0xdc, 0x8d, 0xcd, 0x24, 0x82, 0x66, 0x97, 0x66, 0x25, + 0xdb, 0x22, 0x3d, 0x91, 0x6c, 0x50, 0x61, 0xd7, 0x53, 0x13, 0xb1, 0x55, + 0xae, 0x22, 0xce, 0x18, 0xc4, 0x5e, 0x1c, 0xdd, 0x34, 0x3a, 0xcc, 0x2e, + 0xa3, 0xbc, 0x65, 0x1b, 0xdf, 0x2a, 0xa3, 0x91, 0x18, 0x06, 0x9a, 0xad, + 0x52, 0x32, 0xdb, 0xb6, 0x58, 0x84, 0xd7, 0x29, 0x5b, 0x49, 0xa3, 0xd3, + 0x6f, 0x1f, 0xb2, 0xd7, 0xa6, 0xaa, 0x78, 0x36, 0xcf, 0x7c, 0x8f, 0x90, + 0xc5, 0x29, 0x55, 0x30, 0xbe, 0x0f, 0xa3, 0x37, 0x33, 0x9b, 0x96, 0xf9, + 0xa3, 0x61, 0x9c, 0xa6, 0x12, 0xd1, 0xd0, 0x41, 0xb5, 0x86, 0xad, 0xd0, + 0x6e, 0x97, 0xcf, 0x1d, 0x64, 0x1f, 0x92, 0xbb, 0x2a, 0x95, 0x2b, 0x9a, + 0xb3, 0xdc, 0xd6, 0xc7, 0xb9, 0x15, 0xc5, 0x5a, 0x93, 0x48, 0x74, 0x85, + 0xd8, 0xed, 0xc8, 0x9d, 0x15, 0x6c, 0x0d, 0xa7, 0x46, 0x87, 0xc7, 0x25, + 0x6b, 0xb2, 0xa1, 0x90, 0x0a, 0x95, 0x64, 0xad, 0x8e, 0x1a, 0x3a, 0x89, + 0x69, 0x5f, 0x1b, 0xdf, 0x1f, 0xa3, 0x82, 0x6c, 0x72, 0x5b, 0x82, 0xa6, + 0x64, 0x13, 0xd2, 0x25, 0xd6, 0x47, 0x06, 0x07, 0xd1, 0x03, 0x5d, 0xab, + 0xdc, 0xf8, 0x65, 0x9e, 0x1c, 0x41, 0x32, 0xb4, 0x37, 0x53, 0xa6, 0x14, + 0xa0, 0x98, 0x32, 0x9d, 0x1c, 0x8d, 0xa6, 0x23, 0xda, 0x15, 0xe4, 0x82, + 0xca, 0x54, 0x26, 0x5f, 0x29, 0x50, 0x89, 0x4e, 0xe0, 0x9c, 0x13, 0x4f, + 0x0e, 0xeb, 0xf0, 0x31, 0x43, 0x09, 0xbb, 0xb1, 0x34, 0x63, 0x83, 0xa1, + 0xe4, 0xc1, 0x9c, 0xec, 0x8e, 0xa1, 0x50, 0x6a, 0x13, 0xaf, 0x5e, 0xeb, + 0x10, 0xc2, 0x0e, 0xb9, 0xf8, 0x99, 0x69, 0x2b, 0x2a, 0x45, 0xaa, 0x3b, + 0xbe, 0x47, 0xaf, 0x98, 0x64, 0x7c, 0x58, 0x8d, 0x3a, 0xe5, 0x0d, 0xa1, + 0x88, 0xa0, 0xca, 0x16, 0x4f, 0x21, 0x0c, 0x60, 0x59, 0x6f, 0x4e, 0x70, + 0x6d, 0x29, 0x2a, 0xe6, 0xf7, 0x5d, 0x91, 0x50, 0xb4, 0x25, 0x94, 0x48, + 0x6d, 0x84, 0x03, 0x50, 0xa1, 0x16, 0xc0, 0x07, 0xd9, 0x1d, 0x8b, 0xc7, + 0x93, 0xca, 0x19, 0xf3, 0x23, 0x99, 0x35, 0x46, 0x2e, 0xc9, 0xee, 0x52, + 0x17, 0x20, 0xf2, 0x20, 0xa4, 0x87, 0x93, 0xb2, 0x9e, 0xd5, 0x2a, 0x90, + 0x51, 0x1e, 0xea, 0xed, 0x09, 0x45, 0x47, 0x11, 0x9f, 0x23, 0xa9, 0xcd, + 0x89, 0x10, 0x4e, 0x7c, 0x30, 0x4b, 0x65, 0x63, 0x85, 0x7c, 0x89, 0x84, + 0x08, 0x03, 0x51, 0x7c, 0x74, 0x60, 0xa8, 0xf5, 0x40, 0x22, 0x1a, 0x4f, + 0x86, 0xd4, 0x4a, 0xe0, 0x48, 0x34, 0x88, 0xda, 0x52, 0xda, 0x69, 0x50, + 0x84, 0x3e, 0xa6, 0x51, 0xd9, 0xbe, 0x49, 0xde, 0x7a, 0x15, 0x66, 0x14, + 0xdd, 0x43, 0x3c, 0x4b, 0xb6, 0xa8, 0xdc, 0x47, 0xed, 0xd1, 0x70, 0x6c, + 0x2f, 0x76, 0x06, 0x6b, 0x8c, 0x67, 0xdf, 0xc6, 0xcf, 0x14, 0x12, 0x32, + 0x08, 0xc6, 0xcc, 0x41, 0xdc, 0x1e, 0xef, 0xe7, 0x8d, 0x89, 0xbc, 0xf1, + 0x3d, 0x7b, 0xe0, 0xd3, 0x6b, 0x0e, 0xb6, 0x64, 0x76, 0xae, 0x14, 0x79, + 0xe2, 0xb1, 0xcc, 0x2b, 0xaf, 0x16, 0xb9, 0x35, 0x21, 0x38, 0x8d, 0x8b, + 0xd6, 0x86, 0x53, 0xf0, 0xfe, 0x83, 0xec, 0x7d, 0xe3, 0x42, 0xed, 0xa1, + 0xa6, 0x9c, 0x19, 0x17, 0x9d, 0x31, 0x2e, 0xea, 0x0e, 0x8d, 0x85, 0x33, + 0xd1, 0x48, 0x85, 0x17, 0x93, 0xbd, 0x1c, 0xf1, 0xdc, 0x22, 0xba, 0xd3, + 0xf1, 0x44, 0x02, 0xa2, 0x32, 0x6c, 0x1c, 0xb2, 0x1d, 0xa7, 0xdd, 0x51, + 0xd1, 0x89, 0x18, 0x3c, 0x72, 0x3f, 0x15, 0xc6, 0xcd, 0x2f, 0x33, 0xa8, + 0x28, 0x9e, 0x73, 0x88, 0x20, 0x57, 0x3c, 0x26, 0x57, 0x94, 0xf2, 0xab, + 0xfc, 0x78, 0x2c, 0xb3, 0x1c, 0x0a, 0x25, 0x2b, 0x3d, 0x37, 0x81, 0x51, + 0x77, 0xc8, 0x24, 0x5c, 0x3a, 0x8f, 0x8f, 0x25, 0x32, 0x2b, 0x2c, 0xba, + 0x23, 0x17, 0x85, 0x33, 0xbb, 0x66, 0x01, 0x92, 0xd8, 0x61, 0x56, 0x63, + 0xa5, 0x0c, 0x4a, 0x1d, 0x12, 0x19, 0x9d, 0x4e, 0x6e, 0x0d, 0x0f, 0xa3, + 0x2e, 0x99, 0x34, 0x1f, 0x44, 0xd0, 0x06, 0x35, 0xef, 0xb2, 0x0d, 0xf6, + 0xb8, 0x72, 0x10, 0x5b, 0x42, 0x2e, 0x8e, 0xc2, 0x44, 0xce, 0xb2, 0x98, + 0x95, 0x88, 0x27, 0x46, 0xa3, 0x93, 0x1e, 0x09, 0x3c, 0xd8, 0xea, 0xd2, + 0x39, 0x2f, 0x8d, 0xc8, 0x91, 0x54, 0x2f, 0x26, 0xa9, 0x22, 0x89, 0xfd, + 0x04, 0x1e, 0x92, 0x9c, 0xfc, 0x9d, 0x25, 0xcd, 0x4c, 0xca, 0x26, 0x4e, + 0x72, 0xd2, 0x72, 0x2a, 0x2d, 0x77, 0x85, 0x5c, 0x38, 0x58, 0xf1, 0xb4, + 0xc8, 0x71, 0x27, 0x0b, 0xfc, 0x84, 0x8a, 0x52, 0xbc, 0xad, 0x66, 0x5f, + 0x22, 0x92, 0x2b, 0xa5, 0xb7, 0x45, 0xb9, 0x9b, 0x96, 0x99, 0x53, 0xed, + 0xaa, 0xc7, 0x72, 0xa5, 0x4d, 0x49, 0x9d, 0x61, 0xd7, 0xa3, 0x12, 0x48, + 0xdb, 0x87, 0xf9, 0x98, 0xc5, 0xbe, 0x92, 0x52, 0xd5, 0x70, 0x89, 0x68, + 0x13, 0x4e, 0x7b, 0xbc, 0xee, 0x4a, 0x53, 0xbc, 0x01, 0x8d, 0x45, 0xf6, + 0xca, 0xa5, 0xb2, 0x26, 0x94, 0x94, 0x95, 0x53, 0x39, 0xc4, 0x67, 0x7c, + 0x83, 0x25, 0xb3, 0x67, 0xf7, 0x14, 0x72, 0x70, 0x8a, 0xbb, 0xc2, 0x2d, + 0x53, 0xbb, 0x08, 0xca, 0x48, 0x21, 0x84, 0xe2, 0x94, 0x27, 0x77, 0xc5, + 0xd2, 0x1c, 0xc5, 0x9a, 0xf0, 0x10, 0x2a, 0x43, 0x05, 0xe3, 0xe2, 0x9c, + 0x5d, 0x67, 0xc6, 0x19, 0xc5, 0x7c, 0xfc, 0x08, 0xa5, 0x65, 0x1d, 0xc1, + 0x30, 0x4e, 0x22, 0x49, 0xc4, 0xb2, 0xcc, 0xce, 0x83, 0x43, 0x09, 0x15, + 0xa4, 0xd4, 0x26, 0xb3, 0x49, 0x86, 0xe4, 0x54, 0xce, 0xe6, 0xe2, 0xcc, + 0x24, 0x31, 0x7c, 0x3c, 0xb8, 0xe7, 0x45, 0xa2, 0xd1, 0x4d, 0xf1, 0xb4, + 0xf4, 0x6b, 0x6b, 0x0a, 0x6b, 0x1b, 0x3d, 0xc2, 0x33, 0x1b, 0xf9, 0x0a, + 0x39, 0x95, 0x8d, 0x7c, 0xc8, 0xc2, 0x13, 0xa4, 0x7a, 0xcf, 0x55, 0x15, + 0xa6, 0xb0, 0x68, 0xc6, 0x93, 0x05, 0xa9, 0xd1, 0xfe, 0xcc, 0xed, 0x93, + 0xf2, 0x91, 0x48, 0xc9, 0xab, 0x22, 0x6a, 0xcd, 0x76, 0x99, 0xec, 0x69, + 0x75, 0xc2, 0x99, 0x93, 0xce, 0x3d, 0xd7, 0xac, 0x3b, 0xfd, 0x8c, 0x76, + 0xd6, 0x19, 0x0c, 0x26, 0x1c, 0xd9, 0xaa, 0x26, 0x1a, 0x4d, 0x72, 0x12, + 0x9a, 0xff, 0x4f, 0x58, 0x72, 0x58, 0x9e, 0x3d, 0xd1, 0x2e, 0xe7, 0x18, + 0x33, 0x6b, 0xa2, 0xde, 0x7c, 0x30, 0x38, 0x43, 0xb7, 0x72, 0xcf, 0x09, + 0xbe, 0xd3, 0x0c, 0xda, 0x27, 0xc4, 0xf6, 0x09, 0x16, 0x13, 0xc2, 0xfa, + 0xe9, 0x43, 0xd3, 0x7d, 0x26, 0x77, 0x3f, 0xbd, 0xc3, 0xdd, 0x93, 0xb8, + 0x8b, 0x3d, 0x3d, 0x14, 0xc1, 0x85, 0x52, 0xd3, 0x5a, 0xca, 0x4b, 0xc7, + 0xd5, 0x0d, 0x9f, 0x2c, 0x98, 0x5c, 0x9a, 0x3b, 0x9a, 0x18, 0x44, 0x70, + 0xc8, 0x1c, 0x61, 0xb3, 0xce, 0xce, 0xbb, 0xa0, 0x3e, 0xac, 0x2e, 0x50, + 0x26, 0x2a, 0xa5, 0x0f, 0xc7, 0x6c, 0xa2, 0x0e, 0x41, 0x6c, 0x98, 0x3d, + 0x00, 0xcf, 0x36, 0x9b, 0x9e, 0x41, 0x3f, 0xd7, 0xac, 0xcf, 0xa9, 0x2b, + 0x6b, 0x62, 0x1b, 0x93, 0xfb, 0x9e, 0x43, 0x92, 0xcd, 0x7b, 0xc8, 0x3a, + 0x26, 0x4f, 0x7b, 0xfc, 0x34, 0x07, 0x4f, 0xf7, 0xd8, 0xe9, 0xe7, 0xac, + 0x9b, 0xc5, 0x65, 0x97, 0xad, 0x6d, 0xb8, 0xb8, 0x82, 0xe3, 0x12, 0x2e, + 0x35, 0x15, 0xcb, 0x2a, 0xe0, 0x49, 0x15, 0x0b, 0x2b, 0x06, 0xd0, 0xe2, + 0x48, 0x54, 0xae, 0x78, 0xff, 0x30, 0xc2, 0x07, 0x14, 0x49, 0xd4, 0x1c, + 0x4a, 0x85, 0xa1, 0xc4, 0xb1, 0xc0, 0x8f, 0xab, 0x1a, 0x22, 0xd9, 0xe8, + 0x70, 0xaa, 0x62, 0xd9, 0x9e, 0x50, 0x34, 0x15, 0x5e, 0x58, 0x31, 0x1c, + 0x89, 0xf9, 0x43, 0x89, 0x48, 0xc5, 0xb2, 0xba, 0xc5, 0x0b, 0x2b, 0x52, + 0x43, 0x21, 0x7f, 0x2d, 0x32, 0x85, 0x96, 0x86, 0x06, 0x6b, 0x1b, 0x42, + 0x4b, 0x03, 0x8b, 0x97, 0x04, 0xfa, 0x97, 0x36, 0x36, 0x0e, 0x06, 0x16, + 0x37, 0xd4, 0x85, 0x17, 0x37, 0x2e, 0x1d, 0xa8, 0x0d, 0x34, 0x86, 0x96, + 0xd6, 0xf7, 0xef, 0x59, 0xba, 0xa7, 0xb1, 0x76, 0x90, 0x4b, 0x45, 0x73, + 0x52, 0xa8, 0x0e, 0x99, 0x1a, 0xaa, 0x6b, 0x03, 0xd5, 0x8d, 0xfe, 0xc1, + 0xf0, 0x58, 0xc5, 0xa5, 0x64, 0x2c, 0x11, 0xef, 0x18, 0xe5, 0xf5, 0xc6, + 0x52, 0xe3, 0x7e, 0x51, 0xe9, 0xb4, 0xdf, 0x6a, 0x94, 0x45, 0xc5, 0x72, + 0x32, 0x96, 0x41, 0x3a, 0x33, 0xaf, 0xcc, 0x51, 0xd6, 0x50, 0x96, 0x5f, + 0xb6, 0xaf, 0x6c, 0x55, 0x59, 0x18, 0xbf, 0x2e, 0x69, 0x65, 0x9d, 0x0e, + 0xa3, 0xa2, 0x71, 0xd6, 0x6d, 0x34, 0x82, 0x9d, 0x69, 0x54, 0xba, 0xdd, + 0x56, 0xba, 0xcd, 0x98, 0x69, 0xcc, 0x9e, 0xad, 0xb2, 0xdb, 0x91, 0x7d, + 0x6f, 0x59, 0x29, 0xb2, 0x6f, 0x2c, 0x2b, 0x50, 0xf6, 0x5e, 0xd8, 0xcf, + 0x56, 0xf6, 0x02, 0xf6, 0xb0, 0x16, 0xb3, 0x55, 0x0b, 0xea, 0x94, 0x81, + 0x01, 0x83, 0xf8, 0xb8, 0xed, 0x1c, 0xa3, 0x81, 0x4b, 0x12, 0xe5, 0xb5, + 0xe3, 0x45, 0x66, 0x5a, 0x53, 0xa8, 0xcc, 0xf2, 0x61, 0x16, 0xcb, 0x68, + 0xf3, 0x4c, 0x5a, 0x99, 0xd3, 0x5e, 0x5e, 0x57, 0x1e, 0x28, 0x5f, 0x54, + 0xbe, 0xb8, 0xbc, 0xa6, 0x9c, 0xbf, 0xc3, 0x29, 0x06, 0x2f, 0xe7, 0x8f, + 0xba, 0x85, 0x58, 0x7d, 0xf9, 0x2d, 0xd6, 0x37, 0x16, 0xae, 0xf1, 0xf0, + 0x17, 0xf7, 0x85, 0x68, 0x41, 0xea, 0x16, 0xff, 0x5a, 0xcf, 0x03, 0x32, + 0xd5, 0x8a, 0xd4, 0x93, 0xfe, 0x36, 0xcf, 0x2b, 0x7e, 0xb2, 0xda, 0xed, + 0x05, 0x86, 0xf0, 0xf2, 0xef, 0xba, 0xcb, 0x0f, 0x59, 0xdf, 0xaa, 0xb6, + 0x38, 0x0f, 0x55, 0xdb, 0x9c, 0x27, 0xea, 0x84, 0xf3, 0x15, 0xe0, 0xe8, + 0x22, 0xe1, 0xbc, 0x7b, 0xd1, 0x7a, 0x71, 0x4b, 0x8d, 0x10, 0xa7, 0x6a, + 0x0c, 0xf1, 0x14, 0xe8, 0x5b, 0xc0, 0xb5, 0x01, 0xa4, 0x03, 0x64, 0x15, + 0x46, 0xb1, 0x21, 0xe4, 0x6f, 0xf7, 0xa1, 0x43, 0xd6, 0x43, 0xf5, 0x41, + 0x71, 0x4b, 0x3d, 0x2c, 0xf8, 0xef, 0x7e, 0xad, 0x25, 0xc7, 0x7d, 0xc2, + 0x7b, 0x1e, 0x0a, 0x7d, 0xb9, 0x61, 0xbb, 0x78, 0x15, 0xe2, 0xc7, 0x1b, + 0x84, 0xb8, 0x7a, 0xa9, 0x10, 0x87, 0x1a, 0xa0, 0x16, 0xa5, 0x86, 0x38, + 0xee, 0xdb, 0x89, 0x5c, 0x87, 0x1b, 0xcf, 0x17, 0x77, 0x37, 0x92, 0xc5, + 0x4e, 0x65, 0x9c, 0x43, 0x78, 0x2f, 0x40, 0x9e, 0xbf, 0x2d, 0x13, 0x47, + 0x7d, 0x27, 0x9b, 0xf0, 0x78, 0x94, 0x1f, 0x2f, 0x2f, 0x13, 0xc6, 0x73, + 0x4d, 0xc2, 0x38, 0xbc, 0x1c, 0xcd, 0x2f, 0x98, 0xee, 0x0d, 0xc3, 0xe4, + 0xe4, 0xca, 0x3d, 0xe2, 0x89, 0xe5, 0x42, 0xbc, 0x0a, 0x5c, 0xbd, 0x42, + 0x88, 0x93, 0xc0, 0x13, 0xc0, 0xd5, 0x2b, 0x21, 0x03, 0x7d, 0x1c, 0xf4, + 0x24, 0x74, 0x2f, 0x83, 0x1e, 0x5a, 0x45, 0x8e, 0xa5, 0x73, 0x67, 0x78, + 0x65, 0x5b, 0xbd, 0xea, 0x77, 0xe4, 0x2a, 0xdf, 0x8b, 0x1d, 0xe2, 0x2a, + 0xdf, 0x3b, 0xfc, 0x38, 0xbe, 0x41, 0xa0, 0xc8, 0xbb, 0x37, 0xa0, 0xae, + 0xa3, 0xab, 0xf1, 0x78, 0x71, 0x1d, 0x1e, 0xaf, 0x6e, 0xc4, 0xe3, 0xf1, + 0x0e, 0x3c, 0x0e, 0x6f, 0xc2, 0xe3, 0xc4, 0x2a, 0x3c, 0x6e, 0x67, 0xed, + 0x5b, 0xed, 0x78, 0x1c, 0x67, 0xc5, 0xdf, 0xd8, 0xee, 0x61, 0x96, 0x9d, + 0x60, 0x93, 0x93, 0x2c, 0x3b, 0xc5, 0xdc, 0x0d, 0xeb, 0x99, 0xe3, 0xc7, + 0x93, 0xfc, 0x78, 0x75, 0xbd, 0xfd, 0x0a, 0x83, 0x04, 0x60, 0x31, 0x4e, + 0xae, 0x63, 0x6a, 0x30, 0x9c, 0x47, 0xdb, 0x99, 0x3a, 0x8e, 0x29, 0xdd, + 0xa4, 0x38, 0x36, 0x0e, 0x43, 0xcb, 0xa6, 0x02, 0x05, 0xc7, 0x72, 0x75, + 0xef, 0x09, 0xd8, 0x1f, 0xc1, 0x08, 0x6d, 0x12, 0xe2, 0x1d, 0xe0, 0xda, + 0xcd, 0x42, 0x3c, 0xb7, 0x1a, 0xa3, 0xb4, 0xd9, 0x22, 0x1e, 0x58, 0x65, + 0xa7, 0xe7, 0x9a, 0x4b, 0xe9, 0x50, 0x97, 0x85, 0x6e, 0xd8, 0x22, 0xc4, + 0x03, 0x5b, 0x85, 0x78, 0x03, 0xba, 0xa3, 0x6b, 0x30, 0x97, 0xe0, 0x8f, + 0x76, 0x0b, 0x71, 0x02, 0x78, 0x1c, 0x78, 0x0b, 0x38, 0x1a, 0x44, 0x1a, + 0x78, 0x72, 0x95, 0x10, 0xf7, 0x83, 0xbe, 0x08, 0x9c, 0x84, 0xed, 0xa1, + 0x16, 0x94, 0x0d, 0x1c, 0x6d, 0x15, 0xd6, 0xe3, 0xdb, 0x84, 0xf5, 0xf6, + 0x6d, 0x42, 0x3c, 0xdc, 0x6a, 0x17, 0x4f, 0x81, 0xbe, 0x75, 0x9e, 0x21, + 0x8e, 0x6e, 0x37, 0xc4, 0xc9, 0xed, 0xf2, 0xb3, 0xf7, 0xe1, 0x8d, 0x44, + 0x69, 0xe0, 0xd0, 0x46, 0xf5, 0xf9, 0xfd, 0x95, 0x1b, 0xd5, 0xe7, 0xf0, + 0x2c, 0xbf, 0xc9, 0xc4, 0xdf, 0xa1, 0xf5, 0xf7, 0x6b, 0xfa, 0x4d, 0x93, + 0xee, 0x69, 0x2d, 0x7b, 0x51, 0xcb, 0x5e, 0x07, 0xfd, 0x9f, 0x8d, 0x94, + 0x2d, 0x5f, 0x6c, 0x22, 0x72, 0x6d, 0x52, 0x36, 0xa5, 0x9b, 0xc6, 0xf3, + 0x55, 0x69, 0xd9, 0x22, 0x4d, 0xdb, 0xf8, 0xef, 0x74, 0xb7, 0x50, 0xce, + 0x4f, 0xb9, 0x4e, 0x67, 0xbe, 0x21, 0xcd, 0x7f, 0x39, 0xe8, 0x86, 0xac, + 0xf2, 0x34, 0xbb, 0x66, 0x9d, 0xce, 0x7c, 0xbb, 0x8b, 0xff, 0x6f, 0x55, + 0x60, 0x8b, 0xfa, 0xbf, 0x55, 0x0d, 0x5b, 0xf8, 0x2f, 0xa5, 0x72, 0xcb, + 0xe1, 0xff, 0x61, 0xd5, 0x09, 0xd9, 0xee, 0xd3, 0xe4, 0x17, 0xe8, 0x7c, + 0x07, 0x4e, 0x93, 0xf3, 0xff, 0x28, 0x4a, 0x40, 0x76, 0xf5, 0x69, 0x72, + 0xfe, 0xfb, 0xff, 0xc3, 0x5b, 0xc6, 0xff, 0x1f, 0x94, 0x30, 0xd1, 0xcc, + 0xff, 0x89, 0xe4, 0x36, 0x65, 0xfe, 0x57, 0x24, 0x8f, 0x49, 0xe6, 0xff, + 0x45, 0xf2, 0xf7, 0x19, 0xf8, 0x2f, 0xea, 0xf8, 0x7f, 0x46, 0xf2, 0x77, + 0x1d, 0x32, 0xff, 0x37, 0x92, 0xbf, 0xfb, 0x91, 0xf9, 0xdf, 0x91, 0xc2, + 0xa7, 0xfe, 0x87, 0x16, 0xff, 0xff, 0x48, 0x8b, 0x4f, 0x95, 0xc3, 0x7f, + 0xdf, 0x2b, 0xdc, 0xea, 0xbb, 0xa1, 0xfc, 0x77, 0xd4, 0x86, 0x4f, 0xd5, + 0xc5, 0xff, 0x5f, 0xd2, 0xea, 0x53, 0xdf, 0x9b, 0xe5, 0xf1, 0x25, 0x9f, + 0x2a, 0x87, 0xff, 0x7e, 0xdb, 0xe2, 0x56, 0xdf, 0x75, 0xe3, 0xf1, 0xb5, + 0xfb, 0xd4, 0xf7, 0x70, 0xf8, 0x6f, 0xbb, 0xb9, 0xe1, 0xdc, 0x56, 0xfe, + 0xbf, 0x96, 0xff, 0x0f, 0xed, 0x4e, 0x37, 0xdd, 0x10, 0x53, 0x00, 0x00 }; //============================================================================== @@ -937,6 +926,13 @@ DECLARE_JNI_CLASS (AndroidWindowManagerLayoutParams, "android/view/WindowManager DECLARE_JNI_CLASS_WITH_MIN_SDK (AndroidWindowManagerLayoutParams28, "android/view/WindowManager$LayoutParams", 28) #undef JNI_CLASS_MEMBERS +#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \ + METHOD (setFitInsetsSides, "setFitInsetsSides", "(I)V") \ + METHOD (setFitInsetsIgnoringVisibility, "setFitInsetsIgnoringVisibility", "(Z)V") \ + +DECLARE_JNI_CLASS_WITH_MIN_SDK (AndroidWindowManagerLayoutParams30, "android/view/WindowManager$LayoutParams", 30) +#undef JNI_CLASS_MEMBERS + #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \ METHOD (getSystemWindowInsetTop, "getSystemWindowInsetTop", "()I") \ METHOD (getSystemWindowInsetBottom, "getSystemWindowInsetBottom", "()I") \ @@ -1326,10 +1322,10 @@ public: getAppContext().get(), (jboolean) component.isOpaque(), (jlong) this))); - if (nativeViewHandle != nullptr) - { - viewGroupIsWindow = false; + userDidSupplyParent = nativeViewHandle != nullptr; + if (userDidSupplyParent) + { // we don't know if the user is holding on to a local ref to this, so // explicitly create a new one LocalRef nativeView { env->NewLocalRef (static_cast (nativeViewHandle)) }; @@ -1356,12 +1352,11 @@ public: } else { - viewGroupIsWindow = true; - LocalRef viewLayoutParams { env->NewObject (AndroidLayoutParams, AndroidLayoutParams.create, -2, -2) }; env->CallVoidMethod (view.get(), AndroidView.setLayoutParams, viewLayoutParams.get()); - auto physicalBounds = (comp.getBoundsInParent().toFloat() * scale).toNearestInt(); + const auto rawPeerBounds = detail::ComponentHelpers::localPositionToRawPeerPos (comp, comp.getBoundsInParent().toFloat()); + const auto physicalBounds = Desktop::getInstance().getDisplays().logicalToPhysical (rawPeerBounds).toNearestInt(); view.callVoidMethod (AndroidView.layout, physicalBounds.getX(), physicalBounds.getY(), physicalBounds.getRight(), physicalBounds.getBottom()); @@ -1370,7 +1365,7 @@ public: AndroidWindowManagerLayoutParams.createDefault) }; if (Desktop::getInstance().getKioskModeComponent() != nullptr) - setNavBarsHidden (true); + refreshSystemBarsAndSetHidden (true); setUpLayoutParams (env, windowLayoutParams, physicalBounds); @@ -1432,16 +1427,58 @@ public: env->CallVoidMethod (view, ComponentPeerView.clear); frontWindow = nullptr; - GlobalRef localView (view); - GlobalRef localViewGroup (viewGroup); + removeView(); + setSystemBarsTransparent(); + } - callOnMessageThread ([env, localView, localViewGroup] + static void removeViewFromActivity (jobject localView) + { + if (localView == nullptr) + return; + + auto* env = getEnv(); + + if (LocalRef parent { env->CallObjectMethod (localView, AndroidView.getParent) }) + env->CallVoidMethod (parent, AndroidViewGroup.removeView, localView); + } + + void removeView() + { + auto* env = getEnv(); + + if (userDidSupplyParent) { - if (env->IsInstanceOf (localViewGroup.get(), AndroidActivity)) - env->CallVoidMethod (localViewGroup.get(), AndroidActivity.setContentView, nullptr); - else - env->CallVoidMethod (localViewGroup.get(), AndroidViewManager.removeView, localView.get()); - }); + if (env->IsInstanceOf (viewGroup, AndroidActivity)) + { + removeViewFromActivity (view); + return; + } + + if (env->IsInstanceOf (viewGroup, AndroidViewGroup)) + { + env->CallVoidMethod (viewGroup, AndroidViewGroup.removeView, view.get()); + return; + } + + // The parent was not an activity or view group? + jassertfalse; + return; + } + + if (fullScreen) + { + removeViewFromActivity (view); + return; + } + + if (env->IsInstanceOf (viewGroup, AndroidWindowManager)) + { + env->CallVoidMethod (viewGroup, AndroidWindowManager.removeViewImmediate, view.get()); + return; + } + + // The view's owner didn't have the expected type! + jassertfalse; } void* getNativeHandle() const override @@ -1466,37 +1503,71 @@ public: void setBounds (const Rectangle& userRect, bool isNowFullScreen) override { - auto bounds = (userRect.toFloat() * scale).toNearestInt(); + auto bounds = Desktop::getInstance().getDisplays().logicalToPhysical (userRect); if (MessageManager::getInstance()->isThisTheMessageThread()) { - fullScreen = isNowFullScreen; + auto* env = getEnv(); - if (viewGroup != nullptr && viewGroupIsWindow) + if (fullScreen != isNowFullScreen && ! userDidSupplyParent) { - auto* env = getEnv(); + removeView(); + + fullScreen = isNowFullScreen; LocalRef windowLayoutParams { env->NewObject (AndroidWindowManagerLayoutParams, AndroidWindowManagerLayoutParams.createDefault) }; setUpLayoutParams (env, windowLayoutParams.get(), bounds); - env->CallVoidMethod (viewGroup.get(), - AndroidViewManager.updateViewLayout, - view.get(), - windowLayoutParams.get()); + if (isNowFullScreen) + { + if (auto activity = getCurrentOrMainActivity()) + env->CallVoidMethod (activity, AndroidActivity.addContentView, view.get(), windowLayoutParams.get()); + } + else if (env->IsInstanceOf (viewGroup, AndroidViewManager)) + { + env->CallVoidMethod (viewGroup.get(), + AndroidViewManager.addView, + view.get(), + windowLayoutParams.get()); + } + else + { + // Not fullscreen but the viewgroup isn't a viewmanager/windowmanager instance + jassertfalse; + } - setNavBarsHidden (navBarsHidden); + refreshSystemBarsAndSetHidden (navBarsHidden); } - else + else if (! fullScreen) { - view.callVoidMethod (AndroidView.layout, - bounds.getX(), - bounds.getY(), - bounds.getRight(), - bounds.getBottom()); + if (viewGroup != nullptr && ! userDidSupplyParent) + { + LocalRef windowLayoutParams { env->NewObject (AndroidWindowManagerLayoutParams, + AndroidWindowManagerLayoutParams.createDefault) }; + setUpLayoutParams (env, windowLayoutParams.get(), bounds); + + env->CallVoidMethod (viewGroup.get(), + AndroidViewManager.updateViewLayout, + view.get(), + windowLayoutParams.get()); + + refreshSystemBarsAndSetHidden (navBarsHidden); + } + else + { + view.callVoidMethod (AndroidView.layout, + bounds.getX(), + bounds.getY(), + bounds.getRight(), + bounds.getBottom()); + + } } + + fullScreen = isNowFullScreen; } else { @@ -1517,7 +1588,7 @@ public: view.callIntMethod (AndroidView.getWidth), view.callIntMethod (AndroidView.getHeight)); - return (bounds.toFloat() / scale).toNearestInt(); + return Desktop::getInstance().getDisplays().physicalToLogical (bounds); } void handleScreenSizeChange() override @@ -1530,19 +1601,20 @@ public: Point getScreenPosition() const { - return getViewLocationOnScreen (getEnv(), view.get()); + const auto physical = getViewLocationOnScreen (getEnv(), view.get()); + return Desktop::getInstance().getDisplays().physicalToLogical (physical); } Point localToGlobal (Point relativePosition) override { - return relativePosition + (getScreenPosition().toFloat() / scale); + return relativePosition + (getScreenPosition().toFloat()); } using ComponentPeer::localToGlobal; Point globalToLocal (Point screenPosition) override { - return screenPosition - (getScreenPosition().toFloat() / scale); + return screenPosition - (getScreenPosition().toFloat()); } using ComponentPeer::globalToLocal; @@ -1564,7 +1636,7 @@ public: void setFullScreen (bool shouldBeFullScreen) override { - setNavBarsHidden (shouldNavBarsBeHidden (shouldBeFullScreen)); + refreshSystemBarsAndSetHidden (shouldNavBarsBeHidden (shouldBeFullScreen)); auto newBounds = std::invoke ([&] { @@ -1594,13 +1666,10 @@ public: // n/a } - bool contains (Point localPos, bool trueIfInAChildWindow) const override + bool contains (Point localPos, bool) const override { - return isPositiveAndBelow (localPos.x, component.getWidth()) - && isPositiveAndBelow (localPos.y, component.getHeight()) - && ((! trueIfInAChildWindow) || view.callBooleanMethod (ComponentPeerView.containsPoint, - (float) localPos.x * scale, - (float) localPos.y * scale)); + const auto scaled = detail::ComponentHelpers::rawPeerPositionToLocal (component, localPos); + return component.getLocalBounds().contains (scaled); } OptionalBorderSize getFrameSizeIfPresent() const override @@ -1644,7 +1713,7 @@ public: //============================================================================== void handleMouseDownCallback (int index, Point sysPos, int64 time) { - lastMousePos = sysPos / scale; + lastMousePos = Desktop::getInstance().getDisplays().physicalToLogical (sysPos); auto pos = globalToLocal (lastMousePos); // this forces a mouse-enter/up event, in case for some reason we didn't get a mouse-up before. @@ -1663,7 +1732,7 @@ public: void handleMouseDragCallback (int index, Point sysPos, int64 time) { - lastMousePos = sysPos / scale; + lastMousePos = Desktop::getInstance().getDisplays().physicalToLogical (sysPos); auto pos = globalToLocal (lastMousePos); jassert (index < 64); @@ -1683,7 +1752,7 @@ public: void handleMouseUpCallback (int index, Point sysPos, int64 time) { - lastMousePos = sysPos / scale; + lastMousePos = Desktop::getInstance().getDisplays().physicalToLogical (sysPos); auto pos = globalToLocal (lastMousePos); jassert (index < 64); @@ -1725,7 +1794,10 @@ public: if (auto* topHandler = component.getAccessibilityHandler()) { - if (auto* virtualHandler = topHandler->getChildAt ((sysPos / scale).roundToInt())) + const auto rawPeerPos = Desktop::getInstance().getDisplays().physicalToLogical (sysPos); + const auto localPos = detail::ComponentHelpers::rawPeerPositionToLocal (component, rawPeerPos); + + if (auto* virtualHandler = topHandler->getChildAt (localPos.roundToInt())) { switch (command) { @@ -1761,7 +1833,7 @@ public: handled = app->backButtonPressed(); if (t.isKioskModeComponent()) - t.setNavBarsHidden (t.navBarsHidden); + t.refreshSystemBarsAndSetHidden (t.navBarsHidden); if (! handled) { @@ -1785,7 +1857,7 @@ public: static void handleAppResumedCallback (JNIEnv*, AndroidComponentPeer& t) { if (t.isKioskModeComponent()) - t.setNavBarsHidden (t.navBarsHidden); + t.refreshSystemBarsAndSetHidden (t.navBarsHidden); } static jlong handleGetFocusedTextInputTargetCallback (JNIEnv*, AndroidComponentPeer& t) @@ -1970,7 +2042,9 @@ public: { LowLevelGraphicsSoftwareRenderer g (temp); g.setOrigin (-clip.getPosition()); - g.addTransform (AffineTransform::scale (t.scale)); + const auto scale = Desktop::getInstance().getDisplays().getPrimaryDisplay()->scale + / Desktop::getInstance().getGlobalScaleFactor(); + g.addTransform (AffineTransform::scale ((float) scale)); t.handlePaint (g); } } @@ -1985,7 +2059,7 @@ public: void repaint (const Rectangle& userArea) override { - auto area = (userArea.toFloat() * scale).toNearestInt(); + const auto area = Desktop::getInstance().getDisplays().logicalToPhysical (userArea.toFloat()).toNearestInt(); GlobalRef localView (view); @@ -2011,6 +2085,12 @@ public: return StringArray ("Software Renderer"); } + void appStyleChanged() override + { + JUCE_ASSERT_MESSAGE_THREAD + refreshSystemBarsAndSetHidden (navBarsHidden); + } + //============================================================================== static Point lastMousePos; static int64 touchesDown; @@ -2110,7 +2190,7 @@ private: if (! env->IsInstanceOf (layoutParams, AndroidWindowManagerLayoutParams)) return; - // When viewGroupIsWindow is true, we're laying out the window within the bounds + // When userDidSupplyParent is false, we're laying out the window within the bounds // provided to the activity, and the userRect is in global screen space. // For fullscreen windows, it's easiest to ask Android to size the view // appropriately by matching the parent view. @@ -2145,9 +2225,14 @@ private: flags |= FLAG_NOT_TOUCH_MODAL | FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_NO_LIMITS - | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS - | FLAG_TRANSLUCENT_NAVIGATION - | FLAG_TRANSLUCENT_STATUS; + | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; + + if (getAndroidSDKVersion() >= 30) + { + env->CallVoidMethod (layoutParams, AndroidWindowManagerLayoutParams30.setFitInsetsSides, (jint) 0); + env->CallVoidMethod (layoutParams, AndroidWindowManagerLayoutParams30.setFitInsetsIgnoringVisibility, (jboolean) true); + } + env->SetIntField (layoutParams, AndroidWindowManagerLayoutParams.flags, flags); env->SetIntField (layoutParams, @@ -2166,11 +2251,10 @@ private: METHOD (setViewName, "setViewName", "(Ljava/lang/String;)V") \ METHOD (setVisible, "setVisible", "(Z)V") \ METHOD (isVisible, "isVisible", "()Z") \ - METHOD (containsPoint, "containsPoint", "(II)Z") \ METHOD (showKeyboard, "showKeyboard", "(III)V") \ METHOD (hideKeyboard, "hideKeyboard", "()V") \ METHOD (closeInputMethodContext, "closeInputMethodContext", "()V") \ - METHOD (setSystemUiVisibilityCompat, "setSystemUiVisibilityCompat", "(Landroid/view/Window;Z)V") \ + METHOD (setSystemUiVisibilityCompat, "setSystemUiVisibilityCompat", "(Landroid/view/Window;ZZ)V") \ CALLBACK (generatedCallback<&AndroidComponentPeer::handleDoFrameCallback>, "handleDoFrame", "(JJ)V") \ CALLBACK (generatedCallback<&AndroidComponentPeer::handlePaintCallback>, "handlePaint", "(JLandroid/graphics/Canvas;Landroid/graphics/Paint;)V") \ CALLBACK (generatedCallback<&AndroidComponentPeer::handleKeyDownCallback>, "handleKeyDown", "(JIII)V") \ @@ -2405,7 +2489,7 @@ private: return (shouldBeFullScreen && isKioskModeComponent()); } - void setNavBarsHidden (bool hidden) + void refreshSystemBarsAndSetHidden (bool hidden) { // The system may show the bars again, e.g when navigating away from the app and // back again. Therefore, we should call setSystemUiVisibilityCompat each time to @@ -2414,7 +2498,27 @@ private: getEnv()->CallVoidMethod (view, ComponentPeerView.setSystemUiVisibilityCompat, activityWindow.get(), - (jboolean) ! navBarsHidden); + (jboolean) ! navBarsHidden, + (jboolean) (getAppStyle() == Style::light)); + + setSystemBarsTransparent(); + } + + void setSystemBarsTransparent() + { + if (activityWindow == nullptr) + return; + + auto* env = getEnv(); + + constexpr jint fullyTransparent = 0; + env->CallVoidMethod (activityWindow, AndroidWindow.setStatusBarColor, fullyTransparent); + env->CallVoidMethod (activityWindow, AndroidWindow.setNavigationBarColor, fullyTransparent); + + env->CallVoidMethod (activityWindow, AndroidWindow.setFlags, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); + + if (getAndroidSDKVersion() >= 29) + env->CallVoidMethod (activityWindow, AndroidWindow29.setNavigationBarContrastEnforced, (jboolean) false); } template @@ -2435,8 +2539,6 @@ private: static constexpr jint TYPE_APPLICATION = 0x2; static constexpr jint TYPE_APPLICATION_PANEL = 1000; static constexpr jint FLAG_NOT_TOUCH_MODAL = 0x20, FLAG_LAYOUT_IN_SCREEN = 0x100; - static constexpr jint FLAG_TRANSLUCENT_STATUS = 0x04000000; - static constexpr jint FLAG_TRANSLUCENT_NAVIGATION = 0x08000000; static constexpr jint FLAG_LAYOUT_NO_LIMITS = 0x200; static constexpr jint FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS = (jint) 0x80000000; static constexpr jint PIXEL_FORMAT_OPAQUE = -1, PIXEL_FORMAT_TRANSPARENT = -2; @@ -2444,9 +2546,8 @@ private: static constexpr jint LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES = 0x1; GlobalRef view, viewGroup, buffer, activityWindow; - bool viewGroupIsWindow = false, fullScreen = false, navBarsHidden = false; + bool userDidSupplyParent = false, fullScreen = false, navBarsHidden = false; int sizeAllocated = 0; - float scale = (float) Desktop::getInstance().getDisplays().getPrimaryDisplay()->scale; //============================================================================== JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AndroidComponentPeer) diff --git a/modules/juce_gui_basics/native/juce_Windowing_windows.cpp b/modules/juce_gui_basics/native/juce_Windowing_windows.cpp index 15e255034a..047c32cfda 100644 --- a/modules/juce_gui_basics/native/juce_Windowing_windows.cpp +++ b/modules/juce_gui_basics/native/juce_Windowing_windows.cpp @@ -2221,6 +2221,41 @@ public: jassertfalse; } + DWORD computeNativeStyleFlags() const + { + const auto titled = ! isKioskMode() && (styleFlags & windowHasTitleBar) != 0; + const auto usesDropShadow = windowUsesNativeShadow(); + const auto hasClose = (styleFlags & windowHasCloseButton) != 0; + const auto hasMin = (styleFlags & windowHasMinimiseButton) != 0; + const auto hasMax = (styleFlags & windowHasMaximiseButton) != 0; + const auto resizable = (styleFlags & windowIsResizable) != 0; + + DWORD result = WS_CLIPSIBLINGS | WS_CLIPCHILDREN; + + if (parentToAddTo != nullptr) + { + result |= WS_CHILD; + } + else if (titled || usesDropShadow) + { + result |= usesDropShadow ? WS_CAPTION : 0; + result |= titled ? (WS_OVERLAPPED | WS_CAPTION) : WS_POPUP; + result |= hasClose ? (WS_SYSMENU | WS_CAPTION) : 0; + result |= hasMin ? (WS_MINIMIZEBOX | WS_CAPTION | WS_SYSMENU) : 0; + result |= hasMax ? (WS_MAXIMIZEBOX | WS_CAPTION | WS_SYSMENU) : 0; + result |= resizable ? WS_THICKFRAME : 0; + } + else + { + // Transparent windows need WS_POPUP and not WS_OVERLAPPED | WS_CAPTION, otherwise + // the top corners of the window will get rounded unconditionally. + // Unfortunately, this disables nice mouse handling for the caption area. + result |= WS_POPUP; + } + + return result; + } + bool hasTitleBar() const { return (styleFlags & windowHasTitleBar) != 0; } double getScaleFactor() const { return scaleFactor; } @@ -2385,47 +2420,24 @@ private: void createWindowOnMessageThread() { - DWORD exstyle = 0; - DWORD type = WS_CLIPSIBLINGS | WS_CLIPCHILDREN; + const auto type = computeNativeStyleFlags(); - const auto titled = (styleFlags & windowHasTitleBar) != 0; - const auto hasClose = (styleFlags & windowHasCloseButton) != 0; - const auto hasMin = (styleFlags & windowHasMinimiseButton) != 0; - const auto hasMax = (styleFlags & windowHasMaximiseButton) != 0; - const auto appearsOnTaskbar = (styleFlags & windowAppearsOnTaskbar) != 0; - const auto resizable = (styleFlags & windowIsResizable) != 0; - const auto usesDropShadow = windowUsesNativeShadow(); - - if (parentToAddTo != nullptr) + const auto exstyle = std::invoke ([&]() -> DWORD { - type |= WS_CHILD; - } - else - { - if (titled || usesDropShadow) - { - type |= usesDropShadow ? WS_CAPTION : 0; - type |= titled ? (WS_OVERLAPPED | WS_CAPTION) : WS_POPUP; - type |= hasClose ? (WS_SYSMENU | WS_CAPTION) : 0; - type |= hasMin ? (WS_MINIMIZEBOX | WS_CAPTION | WS_SYSMENU) : 0; - type |= hasMax ? (WS_MAXIMIZEBOX | WS_CAPTION | WS_SYSMENU) : 0; - type |= resizable ? WS_THICKFRAME : 0; - } - else - { - // Transparent windows need WS_POPUP and not WS_OVERLAPPED | WS_CAPTION, otherwise - // the top corners of the window will get rounded unconditionally. - // Unfortunately, this disables nice mouse handling for the caption area. - type |= WS_POPUP; - } + if (parentToAddTo != nullptr) + return 0; - exstyle |= appearsOnTaskbar ? WS_EX_APPWINDOW : WS_EX_TOOLWINDOW; - } + const auto appearsOnTaskbar = (styleFlags & windowAppearsOnTaskbar) != 0; + return appearsOnTaskbar ? WS_EX_APPWINDOW : WS_EX_TOOLWINDOW; + }); hwnd = CreateWindowEx (exstyle, WindowClassHolder::getInstance()->getWindowClassName(), L"", type, 0, 0, 0, 0, parentToAddTo, nullptr, (HINSTANCE) Process::getCurrentModuleInstanceHandle(), nullptr); + const auto titled = (styleFlags & windowHasTitleBar) != 0; + const auto usesDropShadow = windowUsesNativeShadow(); + if (! titled && usesDropShadow) { // The choice of margins is very particular. @@ -2551,16 +2563,11 @@ private: bool windowUsesNativeShadow() const { - if (hasTitleBar()) - return true; - - // On Windows 11, the native drop shadow also gives us a 1px transparent border and rounded - // corners, which doesn't look great in kiosk mode. Disable the native shadow for - // fullscreen windows. - return Desktop::getInstance().getKioskModeComponent() != &component - && (0 != (styleFlags & windowHasDropShadow)) - && (0 == (styleFlags & windowIsSemiTransparent)) - && (0 == (styleFlags & windowIsTemporary)); + return ! isKioskMode() + && (hasTitleBar() + || ( (0 != (styleFlags & windowHasDropShadow)) + && (0 == (styleFlags & windowIsSemiTransparent)) + && (0 == (styleFlags & windowIsTemporary)))); } void updateShadower() @@ -2753,19 +2760,7 @@ private: if (area == WindowArea::nonclient && captionMouseDown.has_value() && *captionMouseDown != lParam) { captionMouseDown.reset(); - - // When clicking and dragging on the caption area, a new modal loop is started - // inside DefWindowProc. This modal loop appears to consume some mouse events, - // without forwarding them back to our own window proc. In particular, we never - // get to see the WM_NCLBUTTONUP event with the HTCAPTION argument, or any other - // kind of mouse-up event to signal that the loop exited, so - // ModifierKeys::currentModifiers gets left in the wrong state. As a workaround, we - // manually update the modifier keys after DefWindowProc exits, and update the - // capture state if necessary. - const auto result = DefWindowProc (hwnd, WM_NCLBUTTONDOWN, HTCAPTION, lParam); - getMouseModifiers(); - releaseCaptureIfNecessary(); - return result; + return handleNcMouseEventThenFixModifiers (WM_NCLBUTTONDOWN, HTCAPTION, lParam); } const auto position = area == WindowArea::client ? getPointFromLocalLParam (lParam) @@ -2774,6 +2769,22 @@ private: return doMouseMoveAtPoint (isMouseDownEvent, area, position); } + LRESULT handleNcMouseEventThenFixModifiers (UINT msg, WPARAM wParam, LPARAM lParam) + { + // When clicking and dragging on the caption area (including in the edge resize areas), a + // new modal loop is started inside DefWindowProc. This modal loop appears to consume some + // mouse events, without forwarding them back to our own window proc. In particular, we + // never get to see the WM_NCLBUTTONUP event with the HTCAPTION argument, or any other + // kind of mouse-up event to signal that the loop exited, so + // ModifierKeys::currentModifiers gets left in the wrong state. As a workaround, we + // manually update the modifier keys after DefWindowProc exits, and update the + // capture state if necessary. + const auto result = DefWindowProc (hwnd, msg, wParam, lParam); + getMouseModifiers(); + releaseCaptureIfNecessary(); + return result; + } + void updateModifiersFromModProvider() const { #if JUCE_MODULE_AVAILABLE_juce_audio_plugin_client @@ -2813,6 +2824,11 @@ private: doMouseEvent (getPointFromLocalLParam (lParam), MouseInputSource::defaultPressure); } + + // If this is the first event after receiving both a MOUSEACTIVATE and a SETFOCUS, then + // process the postponed focus update. + if (std::exchange (mouseActivateFlags, (uint8_t) 0) == (gotMouseActivate | gotSetFocus)) + handleSetFocus(); } void doMouseUp (Point position, const WPARAM wParam, bool adjustCapture = true) @@ -3543,7 +3559,14 @@ private: const ScopedValueSetter scope (inHandlePositionChanged, true); if (! areOtherTouchSourcesActive()) - doMouseEvent (pos, MouseInputSource::defaultPressure); + { + auto modsToSend = ModifierKeys::getCurrentModifiers(); + + if (! Desktop::getInstance().getMainMouseSource().isDragging()) + modsToSend = modsToSend.withoutMouseButtons(); + + doMouseEvent (pos, MouseInputSource::defaultPressure, 0.0f, modsToSend); + } if (! isValidPeer (this)) return true; @@ -3820,6 +3843,27 @@ private: return {}; } + void handleSetFocus() + { + /* When the HWND receives Focus from the system it sends a + UIA_AutomationFocusChangedEventId notification redirecting the focus to the HWND + itself. This is a built-in behaviour of the HWND. + + This means that whichever JUCE managed provider was active before the entire + window lost and then regained the focus, loses its focused state, and the + window's root element will become focused under which all JUCE managed providers + can be found. + + This needs to be reflected on currentlyFocusedHandler so that the JUCE + accessibility mechanisms can detect that the root window got the focus, and send + another FocusChanged event to the system to redirect focus to a JUCE managed + provider if necessary. + */ + AccessibilityHandler::clearCurrentlyFocusedHandler(); + updateKeyModifiers(); + handleFocusGain(); + } + LRESULT peerWindowProc (HWND h, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) @@ -3877,8 +3921,7 @@ private: // and if Microsoft's own VS Code doesn't have perfect mouse handling I don't // think we can be expected to either! - if ((styleFlags & windowIsResizable) != 0 - && Desktop::getInstance().getKioskModeComponent() != &component) + if ((styleFlags & windowIsResizable) != 0 && ! isKioskMode()) { const ScopedThreadDPIAwarenessSetter scope { hwnd }; @@ -4120,23 +4163,14 @@ private: //============================================================================== case WM_SETFOCUS: - /* When the HWND receives Focus from the system it sends a - UIA_AutomationFocusChangedEventId notification redirecting the focus to the HWND - itself. This is a built-in behaviour of the HWND. + mouseActivateFlags |= gotSetFocus; - This means that whichever JUCE managed provider was active before the entire - window lost and then regained the focus, loses its focused state, and the - window's root element will become focused under which all JUCE managed providers - can be found. + // If we've received a MOUSEACTIVATE, wait until we've seen the relevant mouse event + // before updating the focus. + if ((mouseActivateFlags & gotMouseActivate) != 0) + break; - This needs to be reflected on currentlyFocusedHandler so that the JUCE - accessibility mechanisms can detect that the root window got the focus, and send - another FocusChanged event to the system to redirect focus to a JUCE managed - provider if necessary. - */ - AccessibilityHandler::clearCurrentlyFocusedHandler(); - updateKeyModifiers(); - handleFocusGain(); + handleSetFocus(); break; case WM_KILLFOCUS: @@ -4186,10 +4220,15 @@ private: case WM_POINTERACTIVATE: case WM_MOUSEACTIVATE: + { + mouseActivateFlags = 0; + if (! component.getMouseClickGrabsKeyboardFocus()) return MA_NOACTIVATE; + mouseActivateFlags |= gotMouseActivate; break; + } case WM_SHOWWINDOW: if (wParam != 0) @@ -4319,7 +4358,7 @@ private: if (auto result = onNcLButtonDown (wParam, lParam)) return *result; - break; + return handleNcMouseEventThenFixModifiers (WM_NCLBUTTONDOWN, wParam, lParam); } case WM_NCLBUTTONUP: @@ -4731,6 +4770,26 @@ private: IMEHandler imeHandler; bool shouldIgnoreModalDismiss = false; + /* When the user clicks on a window, the window gets sent WM_MOUSEACTIVATE, WM_ACTIVATE, + and WM_SETFOCUS, before sending a WM_LBUTTONDOWN or other pointer event. + However, if the WM_SETFOCUS message immediately calls SetFocus to move the focus to a + different window (e.g. a foreground modal window), then no mouse event will be sent to the + initially-activated window. This differs from the behaviour on other platforms, where the + mouse event always reaches the activated window. Failing to emit a mouse event breaks user + interaction: in the Toolbars pane of the WidgetsDemo, we create a foreground modal + customisation dialog. The window containing the toolbar is not modal, but still expects to + receive mouse events so that the toolbar buttons can be dragged around. + + To avoid the system eating the mouse event sent to the initially-activated window, we + postpone processing the WM_SETFOCUS until *after* the activation mouse event. + */ + enum MouseActivateFlags : uint8_t + { + gotMouseActivate = 1 << 0, + gotSetFocus = 1 << 1, + }; + uint8_t mouseActivateFlags = 0; + ScopedSuspendResumeNotificationRegistration suspendResumeRegistration; std::optional monitorUpdateTimer; @@ -5824,8 +5883,34 @@ String SystemClipboard::getTextFromClipboard() //============================================================================== void Desktop::setKioskComponent (Component* kioskModeComp, bool enableOrDisable, bool /*allowMenusAndBars*/) { - if (auto* tlw = dynamic_cast (kioskModeComp)) - tlw->setUsingNativeTitleBar (! enableOrDisable); + if (auto* peer = dynamic_cast (kioskModeComp->getPeer())) + { + const auto prevFlags = (DWORD) GetWindowLong (peer->getHWND(), GWL_STYLE); + const auto nextVisibility = prevFlags & WS_VISIBLE; + const auto nextFlags = peer->computeNativeStyleFlags() | nextVisibility; + + if (nextFlags != prevFlags) + { + SetWindowLong (peer->getHWND(), GWL_STYLE, nextFlags); + + // After changing the window style flags, the window border visibility may have changed. + // Call SetWindowPos with no changes other than SWP_FRAMECHANGED to ensure that + // GetWindowInfo returns up-to-date border-size values. + static constexpr auto frameChangeOnly = SWP_NOSIZE + | SWP_NOMOVE + | SWP_NOZORDER + | SWP_NOREDRAW + | SWP_NOACTIVATE + | SWP_FRAMECHANGED + | SWP_NOOWNERZORDER + | SWP_NOSENDCHANGING; + SetWindowPos (peer->getHWND(), nullptr, 0, 0, 0, 0, frameChangeOnly); + } + } + else + { + jassertfalse; + } if (kioskModeComp != nullptr && enableOrDisable) kioskModeComp->setBounds (getDisplays().getDisplayForRect (kioskModeComp->getScreenBounds())->totalArea); diff --git a/modules/juce_gui_basics/widgets/juce_ComboBox.h b/modules/juce_gui_basics/widgets/juce_ComboBox.h index 3e427fbe8c..ca0c89a9ae 100644 --- a/modules/juce_gui_basics/widgets/juce_ComboBox.h +++ b/modules/juce_gui_basics/widgets/juce_ComboBox.h @@ -432,13 +432,13 @@ public: std::unique_ptr createAccessibilityHandler() override; //============================================================================== - #ifndef DOXYGEN + /** @cond */ // These methods' bool parameters have changed: see their new method signatures. [[deprecated]] void clear (bool); [[deprecated]] void setSelectedId (int, bool); [[deprecated]] void setSelectedItemIndex (int, bool); [[deprecated]] void setText (const String&, bool); - #endif + /** @endcond */ private: //============================================================================== diff --git a/modules/juce_gui_basics/widgets/juce_Label.h b/modules/juce_gui_basics/widgets/juce_Label.h index 3560b55ded..0acb0a7a89 100644 --- a/modules/juce_gui_basics/widgets/juce_Label.h +++ b/modules/juce_gui_basics/widgets/juce_Label.h @@ -89,13 +89,15 @@ public: //============================================================================== /** Changes the font to use to draw the text. - @see getFont + Note that when drawing, the label's LookAndFeel may override the font set here. + @see getFont, LookAndFeelMethods */ void setFont (const Font& newFont); - /** Returns the font currently being used. - This may be the one set by setFont(), unless it has been overridden by the current LookAndFeel - @see setFont + /** Returns the Label's current font. + Note that this method will always return the font set by setFont(), even if + the LookAndFeel is overriding the label's font during drawing. + @see setFont, LookAndFeelMethods */ Font getFont() const noexcept; diff --git a/modules/juce_gui_basics/widgets/juce_ListBox.h b/modules/juce_gui_basics/widgets/juce_ListBox.h index 9d73dbedf8..098b9cfa00 100644 --- a/modules/juce_gui_basics/widgets/juce_ListBox.h +++ b/modules/juce_gui_basics/widgets/juce_ListBox.h @@ -616,13 +616,13 @@ public: std::unique_ptr createAccessibilityHandler() override; //============================================================================== - #ifndef DOXYGEN + /** @cond */ [[deprecated ("This method's bool parameter has changed: see the new method signature.")]] void setSelectedRows (const SparseSet&, bool); - #endif [[deprecated ("The name of this function is ambiguous if derived classes supply their own models, use getListBoxModel instead")]] ListBoxModel* getModel() const noexcept { return getListBoxModel(); } + /** @endcond */ private: //============================================================================== diff --git a/modules/juce_gui_basics/widgets/juce_Slider.h b/modules/juce_gui_basics/widgets/juce_Slider.h index 57aab5fd64..7827c6ab6c 100644 --- a/modules/juce_gui_basics/widgets/juce_Slider.h +++ b/modules/juce_gui_basics/widgets/juce_Slider.h @@ -622,10 +622,10 @@ public: /** You can assign a lambda to this callback object to have it called when the slider's drag ends. */ std::function onDragEnd; - /** You can assign a lambda that will be used to convert textual values to the slider's normalised position. */ + /** You can assign a lambda that will be used to convert text to a slider value. */ std::function valueFromTextFunction; - /** You can assign a lambda that will be used to convert the slider's normalised position to a textual value. */ + /** You can assign a lambda that will be used to convert a slider value to text. */ std::function textFromValueFunction; //============================================================================== @@ -746,25 +746,29 @@ public: virtual void valueChanged(); //============================================================================== - /** Subclasses can override this to convert a text string to a value. + /** Returns a slider value for some given text. + + Subclasses can override this to convert a text string to a value. + Alternatively assign a lambda to valueFromTextFunction. When the user enters something into the text-entry box, this method is called to convert it to a value. The default implementation just tries to convert it to a double. - @see getTextFromValue + @see getTextFromValue, valueFromTextFunction, textFromValueFunction */ virtual double getValueFromText (const String& text); - /** Turns the slider's current value into a text string. + /** Returns a text representation for a given slider value. Subclasses can override this to customise the formatting of the text-entry box. + Alternatively assign a lambda to textFromValueFunction. The default implementation just turns the value into a string, using a number of decimal places based on the range interval. If a suffix string has been set using setTextValueSuffix(), this will be appended to the text. - @see getValueFromText + @see getValueFromText, textFromValueFunction, valueFromTextFunction */ virtual String getTextFromValue (double value); @@ -1020,7 +1024,7 @@ public: std::unique_ptr createAccessibilityHandler() override; //============================================================================== - #ifndef DOXYGEN + /** @cond */ // These methods' bool parameters have changed: see the new method signature. [[deprecated]] void setValue (double, bool); [[deprecated]] void setValue (double, bool, bool); @@ -1032,7 +1036,7 @@ public: [[deprecated]] void setMaxValue (double, bool); [[deprecated]] void setMinAndMaxValues (double, double, bool, bool); [[deprecated]] void setMinAndMaxValues (double, double, bool); - #endif + /** @endcond */ private: //============================================================================== diff --git a/modules/juce_gui_basics/windows/juce_AlertWindow.h b/modules/juce_gui_basics/windows/juce_AlertWindow.h index 91b132f14c..add715c1ea 100644 --- a/modules/juce_gui_basics/windows/juce_AlertWindow.h +++ b/modules/juce_gui_basics/windows/juce_AlertWindow.h @@ -481,7 +481,8 @@ public: std::function callback); //============================================================================== - #if JUCE_MODAL_LOOPS_PERMITTED && ! defined (DOXYGEN) + #if JUCE_MODAL_LOOPS_PERMITTED + /** @cond */ /** Shows an operating-system native dialog box. @param title the title to use at the top @@ -494,6 +495,7 @@ public: static bool JUCE_CALLTYPE showNativeDialogBox (const String& title, const String& bodyText, bool isOkCancel); + /** @endcond */ #endif diff --git a/modules/juce_gui_basics/windows/juce_DocumentWindow.h b/modules/juce_gui_basics/windows/juce_DocumentWindow.h index 8d5bae804e..70a2c48bcc 100644 --- a/modules/juce_gui_basics/windows/juce_DocumentWindow.h +++ b/modules/juce_gui_basics/windows/juce_DocumentWindow.h @@ -271,7 +271,7 @@ public: }; //============================================================================== - #ifndef DOXYGEN + /** @cond */ /** @internal */ void paint (Graphics&) override; /** @internal */ @@ -300,7 +300,7 @@ public: void windowControlClickedMinimise() override; /** @internal */ void windowControlClickedMaximise() override; - #endif + /** @endcond */ private: //============================================================================== diff --git a/modules/juce_gui_basics/windows/juce_ResizableWindow.h b/modules/juce_gui_basics/windows/juce_ResizableWindow.h index d053cf2ab7..241bb54f89 100644 --- a/modules/juce_gui_basics/windows/juce_ResizableWindow.h +++ b/modules/juce_gui_basics/windows/juce_ResizableWindow.h @@ -322,12 +322,12 @@ public: }; //============================================================================== - #ifndef DOXYGEN + /** @cond */ [[deprecated ("use setContentOwned and setContentNonOwned instead.")]] void setContentComponent (Component* newContentComponent, bool deleteOldOne = true, bool resizeToFit = false); - #endif + /** @endcond */ using TopLevelWindow::addToDesktop; diff --git a/modules/juce_gui_extra/misc/juce_LiveConstantEditor.h b/modules/juce_gui_extra/misc/juce_LiveConstantEditor.h index 0b5f052cf5..c3e1858d7c 100644 --- a/modules/juce_gui_extra/misc/juce_LiveConstantEditor.h +++ b/modules/juce_gui_extra/misc/juce_LiveConstantEditor.h @@ -32,8 +32,9 @@ ============================================================================== */ -#if JUCE_ENABLE_LIVE_CONSTANT_EDITOR && ! defined (DOXYGEN) +#if JUCE_ENABLE_LIVE_CONSTANT_EDITOR +/** @cond */ //============================================================================== /** You can safely ignore all the stuff in this namespace - it's a bunch of boilerplate code used to implement the JUCE_LIVE_CONSTANT functionality. @@ -251,6 +252,7 @@ namespace juce::LiveConstantEditor } } // namespace juce::LiveConstantEditor +/** @endcond */ #endif diff --git a/modules/juce_gui_extra/misc/juce_PushNotifications.h b/modules/juce_gui_extra/misc/juce_PushNotifications.h index b5bafe2511..a615eb1011 100644 --- a/modules/juce_gui_extra/misc/juce_PushNotifications.h +++ b/modules/juce_gui_extra/misc/juce_PushNotifications.h @@ -54,9 +54,9 @@ namespace juce class JUCE_API PushNotifications : private DeletedAtShutdown { public: - #ifndef DOXYGEN + /** @cond */ JUCE_DECLARE_SINGLETON_INLINE (PushNotifications, false) - #endif + /** @endcond */ //============================================================================== /** Represents a notification that can be sent or received. */ diff --git a/modules/juce_gui_extra/native/juce_WebBrowserComponent_linux.cpp b/modules/juce_gui_extra/native/juce_WebBrowserComponent_linux.cpp index ffea19caa4..f2e8a95d1c 100644 --- a/modules/juce_gui_extra/native/juce_WebBrowserComponent_linux.cpp +++ b/modules/juce_gui_extra/native/juce_WebBrowserComponent_linux.cpp @@ -60,8 +60,14 @@ public: JUCE_GENERATE_FUNCTION_WITH_DEFAULT (webkit_web_view_new_with_settings, juce_webkit_web_view_new_with_settings, (WebKitSettings*), GtkWidget*) - JUCE_GENERATE_FUNCTION_WITH_DEFAULT (webkit_web_view_load_uri, juce_webkit_web_view_load_uri, - (WebKitWebView*, const gchar*), void) + JUCE_GENERATE_FUNCTION_WITH_DEFAULT (webkit_web_view_load_request, juce_webkit_web_view_load_request, + (WebKitWebView*, const WebKitURIRequest*), void) + + JUCE_GENERATE_FUNCTION_WITH_DEFAULT (webkit_uri_request_new, juce_webkit_uri_request_new, + (const gchar*), WebKitURIRequest*) + + JUCE_GENERATE_FUNCTION_WITH_DEFAULT (webkit_uri_request_get_http_headers, juce_webkit_uri_request_get_http_headers, + (WebKitURIRequest*), SoupMessageHeaders*) JUCE_GENERATE_FUNCTION_WITH_DEFAULT (webkit_policy_decision_use, juce_webkit_policy_decision_use, (WebKitPolicyDecision*), void) @@ -311,7 +317,9 @@ private: makeSymbolBinding (juce_webkit_web_view_reload, "webkit_web_view_reload"), makeSymbolBinding (juce_webkit_web_view_stop_loading, "webkit_web_view_stop_loading"), makeSymbolBinding (juce_webkit_uri_request_get_uri, "webkit_uri_request_get_uri"), - makeSymbolBinding (juce_webkit_web_view_load_uri, "webkit_web_view_load_uri"), + makeSymbolBinding (juce_webkit_web_view_load_request, "webkit_web_view_load_request"), + makeSymbolBinding (juce_webkit_uri_request_new, "webkit_uri_request_new"), + makeSymbolBinding (juce_webkit_uri_request_get_http_headers, "webkit_uri_request_get_http_headers"), makeSymbolBinding (juce_webkit_navigation_action_get_request, "webkit_navigation_action_get_request"), makeSymbolBinding (juce_webkit_navigation_policy_decision_get_frame_name, "webkit_navigation_policy_decision_get_frame_name"), makeSymbolBinding (juce_webkit_navigation_policy_decision_get_navigation_action, "webkit_navigation_policy_decision_get_navigation_action"), @@ -425,7 +433,7 @@ class CommandReceiver public: struct Responder { - virtual ~Responder() {} + virtual ~Responder() = default; virtual void handleCommand (const String& cmd, const var& param) = 0; virtual void receiverHadError() = 0; @@ -456,37 +464,24 @@ public: { for (;;) { - auto len = (receivingLength ? sizeof (size_t) : bufferLength.len); - - if (! receivingLength) - buffer.realloc (len); - - auto* dst = (receivingLength ? bufferLength.data : buffer.getData()); - - auto actual = read (inChannel, &dst[pos], static_cast (len - pos)); - - if (actual < 0) - { - if (errno == EINTR) - continue; + char lengthBytes[sizeof (size_t)]{}; + const auto numLengthBytes = readIntoBuffer (lengthBytes); + if (numLengthBytes != std::size (lengthBytes)) break; - } - pos += static_cast (actual); + const auto numBytesExpected = readUnaligned (lengthBytes); + buffer.reserve (numBytesExpected + 1); + buffer.resize (numBytesExpected); - if (pos == len) - { - pos = 0; + if (readIntoBuffer (buffer) != numBytesExpected) + break; - if (! std::exchange (receivingLength, ! receivingLength)) - { - parseJSON (String (buffer.getData(), bufferLength.len)); + buffer.push_back (0); + parseJSON (StringRef (buffer.data())); - if (ret == ReturnAfterMessageReceived::yes) - return; - } - } + if (ret == ReturnAfterMessageReceived::yes) + return; } if (errno != EAGAIN && errno != EWOULDBLOCK && responder != nullptr) @@ -527,7 +522,7 @@ public: } private: - void parseJSON (const String& json) + void parseJSON (StringRef json) { auto object = JSON::fromString (json); @@ -541,15 +536,37 @@ private: } } + /* Try to fill the target buffer by reading from the input channel. + Returns the number of bytes that were successfully read. + */ + size_t readIntoBuffer (Span target) const + { + size_t pos = 0; + + while (pos != target.size()) + { + const auto bytesThisTime = read (inChannel, target.data() + pos, target.size() - pos); + + if (bytesThisTime <= 0) + { + if (bytesThisTime != 0 && errno == EINTR) + continue; + + break; + } + + pos += static_cast (bytesThisTime); + } + + return pos; + } + static Identifier getCmdIdentifier() { static Identifier Id ("cmd"); return Id; } static Identifier getParamIdentifier() { static Identifier Id ("params"); return Id; } + std::vector buffer; Responder* responder = nullptr; int inChannel = 0; - size_t pos = 0; - bool receivingLength = true; - union { char data [sizeof (size_t)]; size_t len; } bufferLength; - HeapBlock buffer; }; #define juce_g_signal_connect(instance, detailed_signal, c_handler, data) \ @@ -758,7 +775,7 @@ public: WebKitSymbols::getInstance()->juce_gtk_container_add ((GtkContainer*) container, webviewWidget); WebKitSymbols::getInstance()->juce_gtk_container_add ((GtkContainer*) plug, container); - WebKitSymbols::getInstance()->juce_webkit_web_view_load_uri (webview, "about:blank"); + goToURLWithHeaders ("about:blank", {}); juce_g_signal_connect (webview, "decide-policy", (GCallback) decidePolicyCallback, this); @@ -800,12 +817,52 @@ public: wk.juce_g_free (s); } + void goToURLWithHeaders (StringRef url, Span headers) + { + auto& wk = *WebKitSymbols::getInstance(); + + auto* request = wk.juce_webkit_uri_request_new (url.text.getAddress()); + const ScopeGuard requestScope { [&] { wk.juce_g_object_unref (request); } }; + + if (! headers.empty()) + { + if (auto* soupHeaders = wk.juce_webkit_uri_request_get_http_headers (request)) + { + for (const String item : headers) + { + const auto key = item.upToFirstOccurrenceOf (":", false, false); + const auto value = item.fromFirstOccurrenceOf (":", false, false); + + if (key.isNotEmpty() && value.isNotEmpty()) + wk.juce_soup_message_headers_append (soupHeaders, key.toRawUTF8(), value.toRawUTF8()); + else + jassertfalse; // malformed headers? + } + } + } + + wk.juce_webkit_web_view_load_request (webview, request); + } + void goToURL (const var& params) { - static Identifier urlIdentifier ("url"); - auto url = params.getProperty (urlIdentifier, var()).toString(); + static const Identifier urlIdentifier ("url"); + const String url = params[urlIdentifier]; - WebKitSymbols::getInstance()->juce_webkit_web_view_load_uri (webview, url.toRawUTF8()); + if (url.isEmpty()) + return; + + static const Identifier headersIdentifier ("headers"); + const auto* headers = params[headersIdentifier].getArray(); + + static const Identifier postDataIdentifier ("postData"); + [[maybe_unused]] const auto* postData = params[postDataIdentifier].getBinaryData(); + // post data is not currently sent + jassert (postData == nullptr); + + goToURLWithHeaders (url, + headers != nullptr ? Span { headers->getRawDataPointer(), (size_t) headers->size() } + : Span{}); } void handleDecisionResponse (const var& params) @@ -842,7 +899,7 @@ public: this); } - void handleResourceRequesteResponse (const var& params) + void handleResourceRequestedResponse (const var& params) { auto& wk = *WebKitSymbols::getInstance(); @@ -909,7 +966,7 @@ public: else if (cmd == "decision") handleDecisionResponse (params); else if (cmd == "init") initialisationData = FromVar::convert (params); else if (cmd == "evaluateJavascript") evaluateJavascript (params); - else if (cmd == ResourceRequestResponse::key) handleResourceRequesteResponse (params); + else if (cmd == ResourceRequestResponse::key) handleResourceRequestedResponse (params); } void receiverHadError() override diff --git a/modules/juce_midi_ci/ci/juce_CIEncoding.h b/modules/juce_midi_ci/ci/juce_CIEncoding.h index f0220973a8..9d8d19ac77 100644 --- a/modules/juce_midi_ci/ci/juce_CIEncoding.h +++ b/modules/juce_midi_ci/ci/juce_CIEncoding.h @@ -88,8 +88,7 @@ struct EncodingUtils } // namespace juce::midi_ci -#ifndef DOXYGEN - +/** @cond */ namespace juce { template <> @@ -113,5 +112,4 @@ namespace juce }; } // namespace juce - -#endif // ifndef DOXYGEN +/** @endcond */ diff --git a/modules/juce_midi_ci/ci/juce_CIPropertyDelegate.h b/modules/juce_midi_ci/ci/juce_CIPropertyDelegate.h index 34f9cbc0db..995820649a 100644 --- a/modules/juce_midi_ci/ci/juce_CIPropertyDelegate.h +++ b/modules/juce_midi_ci/ci/juce_CIPropertyDelegate.h @@ -258,8 +258,7 @@ struct PropertyDelegate } // namespace juce::midi_ci -#ifndef DOXYGEN - +/** @cond */ namespace juce { @@ -284,5 +283,4 @@ struct SerialisationTraits }; } // namespace juce - -#endif // ifndef DOXYGEN +/** @endcond */ diff --git a/modules/juce_midi_ci/detail/juce_CIMessageMeta.h b/modules/juce_midi_ci/detail/juce_CIMessageMeta.h index 01d7b514d1..b2d264b565 100644 --- a/modules/juce_midi_ci/detail/juce_CIMessageMeta.h +++ b/modules/juce_midi_ci/detail/juce_CIMessageMeta.h @@ -181,8 +181,7 @@ struct Meta : Metadata<0x44> {}; } // namespace juce::midi_ci::detail::MessageMeta -#ifndef DOXYGEN - +/** @cond */ namespace juce { @@ -628,5 +627,4 @@ struct SerialisationTraits : VersionBa }; } // namespace juce - -#endif // ifndef DOXYGEN +/** @endcond */ diff --git a/modules/juce_opengl/juce_opengl.cpp b/modules/juce_opengl/juce_opengl.cpp index 9023896a08..8916e4f58d 100644 --- a/modules/juce_opengl/juce_opengl.cpp +++ b/modules/juce_opengl/juce_opengl.cpp @@ -229,24 +229,24 @@ static void clearGLError() noexcept struct OpenGLTargetSaver { - OpenGLTargetSaver (const OpenGLContext& c) noexcept - : context (c), oldFramebuffer (OpenGLFrameBuffer::getCurrentFrameBufferTarget()) + OpenGLTargetSaver() noexcept + : oldFramebuffer (OpenGLFrameBuffer::getCurrentFrameBufferTarget()) { glGetIntegerv (GL_VIEWPORT, oldViewport); } ~OpenGLTargetSaver() noexcept { - context.extensions.glBindFramebuffer (GL_FRAMEBUFFER, oldFramebuffer); + gl::glBindFramebuffer (GL_FRAMEBUFFER, oldFramebuffer); glViewport (oldViewport[0], oldViewport[1], oldViewport[2], oldViewport[3]); } + JUCE_DECLARE_NON_COPYABLE (OpenGLTargetSaver) + JUCE_DECLARE_NON_MOVEABLE (OpenGLTargetSaver) + private: - const OpenGLContext& context; GLuint oldFramebuffer; GLint oldViewport[4]; - - OpenGLTargetSaver& operator= (const OpenGLTargetSaver&); }; } // namespace juce diff --git a/modules/juce_opengl/native/java/app/com/rmsl/juce/JuceOpenGLView.java b/modules/juce_opengl/native/java/app/com/rmsl/juce/JuceOpenGLView.java index 16d8ed3ce6..477339cd5a 100644 --- a/modules/juce_opengl/native/java/app/com/rmsl/juce/JuceOpenGLView.java +++ b/modules/juce_opengl/native/java/app/com/rmsl/juce/JuceOpenGLView.java @@ -63,24 +63,6 @@ public class JuceOpenGLView extends SurfaceView return true; } - @Override - protected void onAttachedToWindow () - { - super.onAttachedToWindow (); - - if (host != 0) - onAttchedWindowNative (host); - } - - @Override - protected void onDetachedFromWindow () - { - if (host != 0) - onDetachedFromWindowNative (host); - - super.onDetachedFromWindow (); - } - @Override protected void dispatchDraw (Canvas canvas) { diff --git a/modules/juce_opengl/native/juce_OpenGLExtensions.h b/modules/juce_opengl/native/juce_OpenGLExtensions.h index 182dd226ed..0555d41e48 100644 --- a/modules/juce_opengl/native/juce_OpenGLExtensions.h +++ b/modules/juce_opengl/native/juce_OpenGLExtensions.h @@ -118,16 +118,18 @@ namespace juce struct OpenGLExtensionFunctions { //============================================================================== - #ifndef DOXYGEN + /** @cond */ [[deprecated ("A more complete set of GL commands can be found in the juce::gl namespace. " "You should use juce::gl::loadFunctions() to load GL functions.")]] static void initialise(); - #endif + /** @endcond */ - #if JUCE_WINDOWS && ! defined (DOXYGEN) + #if JUCE_WINDOWS + /** @cond */ typedef char GLchar; typedef pointer_sized_int GLsizeiptr; typedef pointer_sized_int GLintptr; + /** @endcond */ #endif #define X(name) static decltype (::juce::gl::name)& name; diff --git a/modules/juce_opengl/native/juce_OpenGL_android.h b/modules/juce_opengl/native/juce_OpenGL_android.h index 4b84eb8ed2..37be8c5c61 100644 --- a/modules/juce_opengl/native/juce_OpenGL_android.h +++ b/modules/juce_opengl/native/juce_OpenGL_android.h @@ -40,75 +40,74 @@ namespace juce // See juce_core/native/java/README.txt on how to generate this byte-code. static const uint8 javaJuceOpenGLView[] = { - 0x1f, 0x8b, 0x08, 0x08, 0xac, 0xdb, 0x8b, 0x62, 0x00, 0x03, 0x4a, 0x61, - 0x76, 0x61, 0x44, 0x65, 0x78, 0x42, 0x79, 0x74, 0x65, 0x43, 0x6f, 0x64, - 0x65, 0x2e, 0x64, 0x65, 0x78, 0x00, 0x6d, 0x54, 0x4f, 0x48, 0x14, 0x51, - 0x18, 0xff, 0x66, 0xe6, 0xed, 0x6e, 0xea, 0x3a, 0xae, 0xeb, 0x7f, 0xc1, - 0xd8, 0x20, 0xea, 0x64, 0x6b, 0x7f, 0xac, 0x40, 0x0b, 0x4d, 0xfb, 0xb7, - 0x0d, 0x4a, 0x69, 0x5b, 0x6c, 0x1d, 0x9a, 0x66, 0x27, 0x77, 0x44, 0x67, - 0x96, 0xd9, 0xd9, 0x55, 0x28, 0x44, 0xba, 0x78, 0xf1, 0x54, 0x41, 0xd1, - 0xd9, 0x43, 0x04, 0x45, 0x20, 0x05, 0x75, 0x48, 0xa2, 0x8b, 0xe1, 0xa1, - 0x53, 0xd8, 0x21, 0xa8, 0x43, 0x07, 0x8f, 0x9d, 0xc2, 0x93, 0xf4, 0x7b, - 0x6f, 0x9e, 0xad, 0x85, 0xc3, 0xfe, 0xe6, 0xfb, 0xfb, 0xbe, 0xef, 0xf7, - 0xde, 0xce, 0xfb, 0xf2, 0xf6, 0x6c, 0x6d, 0xcf, 0xd1, 0x5e, 0x7a, 0xbc, - 0x7e, 0xe1, 0x25, 0x7d, 0xb9, 0xba, 0x35, 0x37, 0x59, 0xff, 0xe2, 0xd1, - 0xda, 0xeb, 0x7b, 0x2b, 0x67, 0xb6, 0x8c, 0xbb, 0xef, 0x2f, 0x0e, 0x3f, - 0x89, 0x10, 0x15, 0x89, 0x68, 0x36, 0x7b, 0x2c, 0x49, 0xf2, 0xd9, 0x64, - 0x44, 0x5d, 0x14, 0xfa, 0xf7, 0x00, 0x3f, 0x81, 0x18, 0xc0, 0x14, 0x22, - 0xfc, 0xe8, 0x3a, 0x5e, 0xf5, 0x90, 0xb7, 0xa4, 0xbd, 0x8a, 0xd7, 0x2b, - 0x8d, 0x68, 0x03, 0x32, 0x0a, 0xa9, 0x03, 0x8d, 0xc0, 0x01, 0x60, 0x10, - 0xb8, 0x09, 0xcc, 0x00, 0x0f, 0x81, 0x65, 0xe0, 0x0d, 0xf0, 0x0e, 0x58, - 0x01, 0x3e, 0x02, 0xab, 0xc0, 0x1a, 0xf0, 0x19, 0x58, 0x07, 0xbe, 0xf3, - 0x5a, 0xc0, 0x6f, 0xa0, 0x01, 0x5c, 0x5a, 0x80, 0x7d, 0x40, 0x2f, 0x60, - 0x00, 0xb7, 0x81, 0x39, 0x60, 0x11, 0x78, 0xc0, 0x42, 0x0e, 0x1a, 0xe7, - 0x07, 0x60, 0x3b, 0x14, 0x95, 0x7c, 0x39, 0xf7, 0x7a, 0x29, 0xa3, 0x72, - 0x6f, 0x35, 0x52, 0xff, 0xaa, 0x12, 0xd5, 0x4a, 0xfd, 0x07, 0xf4, 0x3a, - 0xa9, 0x6f, 0x40, 0x8f, 0x4b, 0xfd, 0xd7, 0x0e, 0xff, 0x26, 0x74, 0x5d, - 0xd6, 0xe5, 0xcd, 0x78, 0x9f, 0x66, 0xd1, 0x53, 0x13, 0x75, 0x19, 0x3c, - 0x49, 0xc9, 0xa1, 0x55, 0xca, 0x76, 0xc1, 0x87, 0x89, 0x38, 0xcf, 0x6f, - 0x10, 0x32, 0xcc, 0x8b, 0xa0, 0x6a, 0x93, 0xf4, 0xb7, 0x0a, 0xa9, 0x50, - 0x9b, 0xb4, 0xdb, 0xa5, 0xdd, 0x21, 0xa4, 0x4a, 0x9d, 0xd2, 0xaf, 0xc8, - 0xba, 0xfc, 0x51, 0xa5, 0xfc, 0x24, 0x1d, 0x51, 0x44, 0xb8, 0xef, 0x29, - 0x0b, 0xf7, 0x55, 0x4c, 0x11, 0x1d, 0x11, 0x95, 0x73, 0xd0, 0x72, 0xfb, - 0x39, 0x7b, 0x4d, 0x54, 0x20, 0x5a, 0x62, 0xd5, 0xbe, 0x3c, 0xaa, 0x8b, - 0xf5, 0xaa, 0xa8, 0xfd, 0x1c, 0xaf, 0x46, 0x48, 0x2f, 0xa5, 0xd0, 0x38, - 0x8d, 0x0d, 0x20, 0x0b, 0x65, 0x0f, 0xa3, 0xe1, 0x49, 0xec, 0x9d, 0xdb, - 0xc5, 0x81, 0x38, 0xb1, 0xcb, 0xba, 0x38, 0x86, 0x90, 0xc5, 0x32, 0x0b, - 0xf9, 0x24, 0x13, 0x0d, 0x82, 0x37, 0x3f, 0x91, 0xb7, 0xdb, 0x75, 0x12, - 0xbc, 0xee, 0xae, 0x75, 0x7a, 0x6a, 0xf0, 0x45, 0xe9, 0x72, 0xaf, 0x7c, - 0xcd, 0x07, 0xb9, 0x66, 0xf7, 0xec, 0x3a, 0x64, 0x7b, 0x09, 0x0d, 0xd5, - 0x74, 0x79, 0x16, 0xd5, 0x73, 0x50, 0x85, 0xad, 0x48, 0xfb, 0x7f, 0x5d, - 0xa3, 0x68, 0xbf, 0xe3, 0x3a, 0xc1, 0x69, 0x52, 0x32, 0xd4, 0x94, 0x29, - 0x5b, 0xf6, 0x68, 0xd1, 0x76, 0xcf, 0x1b, 0x59, 0xc7, 0x9e, 0x39, 0x34, - 0x69, 0x56, 0x4c, 0xea, 0x30, 0x4c, 0x37, 0xef, 0x7b, 0x4e, 0x3e, 0x6d, - 0x79, 0x6e, 0x60, 0xbb, 0x41, 0x7a, 0x88, 0xcb, 0xd9, 0xa0, 0x6f, 0x47, - 0x68, 0xc2, 0x37, 0x8b, 0x05, 0xc7, 0x2a, 0xa5, 0x87, 0x4c, 0xb7, 0x62, - 0x96, 0x76, 0x0d, 0x5d, 0xb1, 0x27, 0x1c, 0xcf, 0xed, 0xa3, 0xce, 0xbf, - 0xa1, 0x0a, 0x9a, 0xa4, 0xc7, 0xca, 0xfe, 0x1d, 0xd3, 0xb2, 0x79, 0xc3, - 0x3e, 0xda, 0x6b, 0x58, 0xde, 0x74, 0xda, 0x9f, 0x2e, 0x4d, 0xa5, 0x27, - 0xc1, 0x25, 0xfd, 0x2f, 0xa1, 0x3e, 0x52, 0xb2, 0xa4, 0x66, 0x33, 0xa4, - 0x65, 0x33, 0x06, 0x14, 0x03, 0x8a, 0x91, 0x21, 0x25, 0x47, 0x6a, 0xce, - 0xa0, 0xa8, 0x65, 0xba, 0x96, 0x3d, 0x25, 0x24, 0x38, 0x50, 0xcc, 0x0a, - 0x79, 0x52, 0x3c, 0xef, 0x94, 0x8a, 0x66, 0x60, 0x15, 0x86, 0x7d, 0x73, - 0x86, 0xda, 0x26, 0xcc, 0xa0, 0x60, 0xfb, 0xe3, 0xbe, 0xe9, 0xc2, 0xeb, - 0x63, 0x43, 0x21, 0x31, 0x62, 0x05, 0xaf, 0x14, 0x50, 0xad, 0x6b, 0x06, - 0x4e, 0xc5, 0x1e, 0x2f, 0x38, 0x25, 0x4a, 0x7a, 0xee, 0x60, 0x10, 0x98, - 0x56, 0xc1, 0xce, 0x8f, 0x7b, 0xd7, 0x1c, 0x37, 0xef, 0xcd, 0x50, 0x8b, - 0xf0, 0x71, 0x57, 0xe8, 0x18, 0x11, 0xe9, 0xd4, 0xec, 0xb9, 0xc3, 0x76, - 0x98, 0x7a, 0xce, 0xf7, 0xa6, 0x65, 0x72, 0xe7, 0x6e, 0x5e, 0xb9, 0x22, - 0x8e, 0x18, 0xf8, 0x48, 0x8b, 0x05, 0xbc, 0x61, 0xb4, 0xec, 0x96, 0x4b, - 0x76, 0x9e, 0x0e, 0xaa, 0xc9, 0xd6, 0x98, 0x7e, 0x62, 0xb4, 0x9b, 0xba, - 0x29, 0xa6, 0x5f, 0xa2, 0x11, 0xa5, 0x31, 0xa6, 0x9f, 0x5a, 0xc8, 0xd1, - 0x71, 0xa5, 0x2b, 0xa6, 0x53, 0x3f, 0x85, 0xd6, 0x59, 0xc8, 0x85, 0x1b, - 0xfd, 0xf8, 0x27, 0x19, 0xee, 0x02, 0x9b, 0x9f, 0x67, 0x1b, 0x5a, 0xe4, - 0xbe, 0x4a, 0x2a, 0xa0, 0x00, 0x11, 0x65, 0x91, 0x29, 0xec, 0x19, 0x53, - 0x94, 0x6f, 0x90, 0xbf, 0x98, 0xca, 0x96, 0x22, 0xf2, 0xde, 0xd3, 0x8e, - 0xef, 0x84, 0xcb, 0xed, 0x99, 0xa6, 0x52, 0x75, 0xae, 0x69, 0x54, 0x9d, - 0x6d, 0x8c, 0xaa, 0xf3, 0x6d, 0xbb, 0x06, 0x9f, 0x71, 0x51, 0xaa, 0xce, - 0x39, 0x25, 0x25, 0xe7, 0x04, 0xd7, 0x13, 0xd5, 0x59, 0xa2, 0xa6, 0xc2, - 0xfa, 0x7c, 0xfe, 0x69, 0x32, 0x87, 0xdf, 0x45, 0x4a, 0x85, 0x6b, 0xc5, - 0x3d, 0x4d, 0x84, 0x3a, 0x9f, 0xaf, 0x7f, 0x00, 0x34, 0xf2, 0xd3, 0x47, - 0x98, 0x05, 0x00, 0x00 + 0x1f, 0x8b, 0x08, 0x08, 0x7e, 0xb3, 0x66, 0x68, 0x00, 0x03, 0x63, 0x6c, + 0x61, 0x73, 0x73, 0x65, 0x73, 0x2e, 0x64, 0x65, 0x78, 0x00, 0x6d, 0x94, + 0xbd, 0x6f, 0xd3, 0x50, 0x10, 0xc0, 0xef, 0x3d, 0xbb, 0xa1, 0x5f, 0xb4, + 0x69, 0x4b, 0xa9, 0xe8, 0x50, 0x05, 0x33, 0x20, 0xa1, 0xa4, 0x4e, 0xda, + 0xb4, 0x49, 0x9a, 0x82, 0x8a, 0x1a, 0xbe, 0x42, 0x04, 0x82, 0x56, 0x01, + 0x45, 0x0c, 0xbc, 0xd8, 0x2f, 0x8d, 0xdb, 0xc4, 0xb6, 0x6c, 0x27, 0x8d, + 0x84, 0x68, 0x2b, 0x84, 0x04, 0x62, 0x42, 0x62, 0x64, 0x60, 0x62, 0x60, + 0xeb, 0x9f, 0xd0, 0x81, 0x09, 0x21, 0x31, 0x31, 0xb1, 0xb0, 0xb0, 0x21, + 0x56, 0x24, 0x40, 0x88, 0xb3, 0xfd, 0x42, 0x53, 0x84, 0xa5, 0x9f, 0xef, + 0xde, 0xdd, 0xbd, 0xbb, 0x7b, 0xb2, 0xdf, 0xe9, 0xbc, 0x33, 0x98, 0x9c, + 0xcf, 0xc0, 0xdd, 0x0f, 0x3f, 0xde, 0x7d, 0x23, 0xab, 0x3f, 0xb7, 0x9e, + 0x7e, 0x19, 0x1a, 0x39, 0xd8, 0xfd, 0xfd, 0xe2, 0xe3, 0x7e, 0xf5, 0x71, + 0xf9, 0xe3, 0xe9, 0x68, 0x1f, 0x80, 0x0d, 0x00, 0x9d, 0x72, 0x7a, 0x1c, + 0xc4, 0x63, 0xcb, 0x00, 0x53, 0x10, 0xda, 0xfb, 0x91, 0xf7, 0xc8, 0x31, + 0xe4, 0x2b, 0x42, 0x90, 0x15, 0x7c, 0x0d, 0xa0, 0xbc, 0x4a, 0xc2, 0xf5, + 0x73, 0x7c, 0xdd, 0x97, 0x00, 0xf6, 0x51, 0x6e, 0x52, 0x00, 0x07, 0x69, + 0x21, 0xcf, 0x90, 0xd7, 0xc8, 0x01, 0xf2, 0x09, 0xf9, 0x8e, 0x4c, 0x61, + 0xdc, 0x34, 0x32, 0x83, 0x9c, 0x41, 0xce, 0x22, 0x71, 0x44, 0x45, 0xe6, + 0x91, 0x3c, 0x72, 0x0d, 0xa9, 0x22, 0x75, 0x64, 0x17, 0x79, 0x89, 0xbc, + 0x91, 0xc2, 0x5a, 0x28, 0x00, 0xdb, 0x03, 0x6c, 0x1b, 0x22, 0xa2, 0x2f, + 0xbf, 0xc7, 0xe3, 0x42, 0x46, 0xc4, 0x19, 0x06, 0x84, 0xbe, 0x8c, 0x35, + 0x07, 0x85, 0x5e, 0x40, 0x7d, 0x48, 0xe8, 0x25, 0xd4, 0x87, 0x85, 0xbe, + 0xde, 0x63, 0xbf, 0x87, 0xfa, 0x88, 0xc8, 0xab, 0xd3, 0xb0, 0xce, 0x78, + 0x50, 0x53, 0x0a, 0xf2, 0xca, 0x68, 0x89, 0x06, 0xf5, 0xe5, 0x60, 0xed, + 0xfb, 0x47, 0x03, 0xd9, 0xb5, 0x47, 0x60, 0x2c, 0x90, 0x04, 0x26, 0x84, + 0x3c, 0x11, 0x48, 0x0a, 0x93, 0x22, 0x9e, 0x88, 0x33, 0xf8, 0x0f, 0x15, + 0xf2, 0xba, 0xdc, 0x5d, 0x77, 0x2d, 0xa1, 0x6f, 0x7c, 0x6c, 0x94, 0xc8, + 0x18, 0xed, 0xeb, 0xe7, 0x68, 0xd8, 0xa3, 0x1d, 0x03, 0xac, 0x55, 0x09, + 0x3a, 0x95, 0x82, 0x6c, 0x00, 0x29, 0xd1, 0xeb, 0x49, 0xa4, 0x12, 0x0b, + 0xcf, 0x10, 0xc1, 0x5d, 0x7e, 0xda, 0x05, 0x1a, 0xf6, 0x68, 0xc5, 0x08, + 0xac, 0xc3, 0xda, 0x0a, 0x46, 0xd1, 0x60, 0x07, 0xcd, 0xd2, 0x3e, 0xb0, + 0x57, 0xfa, 0x41, 0xbe, 0x35, 0x02, 0x49, 0x3f, 0xdf, 0x32, 0x2c, 0x42, + 0x1c, 0x2e, 0x11, 0x18, 0x39, 0xff, 0x44, 0x64, 0xee, 0xf6, 0x48, 0x83, + 0x35, 0x11, 0xeb, 0x7f, 0x75, 0x09, 0x22, 0xcb, 0x86, 0x69, 0x78, 0x17, + 0x80, 0x14, 0x61, 0xa2, 0xd8, 0xd2, 0xf8, 0x4d, 0x9b, 0x9b, 0x57, 0x4a, + 0x65, 0x83, 0x6f, 0xcf, 0x6e, 0xb2, 0x36, 0x83, 0x53, 0x25, 0x66, 0xea, + 0x8e, 0x65, 0xe8, 0xaa, 0x66, 0x99, 0x1e, 0x37, 0x3d, 0x75, 0xd5, 0x97, + 0x1d, 0x2f, 0xdf, 0xe3, 0xda, 0x70, 0x98, 0x5d, 0x37, 0x34, 0x57, 0x5d, + 0x65, 0x66, 0x9b, 0xb9, 0xff, 0x75, 0xdd, 0xe6, 0x1b, 0x86, 0x65, 0xe6, + 0x61, 0xfa, 0xaf, 0xab, 0x8d, 0x45, 0xd4, 0xb5, 0x96, 0x53, 0x63, 0x1a, + 0xf7, 0x0b, 0xe6, 0x61, 0xa6, 0xa4, 0x59, 0x4d, 0xd5, 0x69, 0xba, 0x0d, + 0x75, 0x13, 0x7b, 0x51, 0x8f, 0x36, 0x94, 0x07, 0x52, 0x06, 0x5a, 0x2e, + 0x82, 0x54, 0x2e, 0x96, 0x50, 0x29, 0xa1, 0x52, 0x2a, 0x02, 0xa9, 0x00, + 0xad, 0x94, 0x20, 0xa2, 0x31, 0x53, 0xe3, 0x0d, 0x18, 0xd6, 0x0d, 0xd7, + 0x66, 0x9e, 0x56, 0x2f, 0x38, 0x6c, 0x1b, 0xa6, 0x36, 0x98, 0x57, 0xe7, + 0xce, 0xba, 0xc3, 0x4c, 0xb4, 0x3a, 0xd8, 0x7f, 0xd8, 0x07, 0xc8, 0x75, + 0xcb, 0xf5, 0x60, 0xd2, 0x32, 0x2f, 0x7a, 0x18, 0xcb, 0xf5, 0x3b, 0x86, + 0xa9, 0x5b, 0xdb, 0x37, 0x98, 0x67, 0xb4, 0x39, 0x4c, 0x5b, 0x66, 0x81, + 0x7b, 0xcc, 0xb7, 0x5f, 0x76, 0xac, 0xe6, 0x11, 0xdf, 0x30, 0xfa, 0x30, + 0xb3, 0x58, 0xbd, 0x22, 0x3b, 0x3b, 0x85, 0xec, 0x03, 0xa5, 0xca, 0xb4, + 0x2d, 0x6e, 0xea, 0xca, 0x92, 0xa2, 0xf3, 0x8e, 0x12, 0x57, 0xf0, 0x1c, + 0xb6, 0xd1, 0xc0, 0x18, 0xcb, 0x4c, 0x34, 0x2d, 0x9d, 0xa3, 0xc3, 0xe1, + 0x0d, 0xce, 0x5c, 0x8e, 0xce, 0x3a, 0x73, 0x13, 0x98, 0x5b, 0xdb, 0x72, + 0x5b, 0x4d, 0x57, 0x59, 0xaa, 0xb1, 0x86, 0xcb, 0xe3, 0x4a, 0xd3, 0x30, + 0x13, 0xcc, 0x36, 0x94, 0xa5, 0xb9, 0x74, 0x5c, 0x71, 0xeb, 0x2c, 0x91, + 0xc2, 0x4d, 0x2c, 0xc3, 0xf4, 0x54, 0x96, 0x65, 0x92, 0xe9, 0xc5, 0x64, + 0x35, 0x93, 0xcb, 0xe9, 0xc9, 0x74, 0x76, 0x8e, 0xa7, 0x73, 0x19, 0x2d, + 0x95, 0xcc, 0xb1, 0xcc, 0x42, 0xb5, 0x96, 0xa9, 0xe5, 0x52, 0xba, 0x9f, + 0xb5, 0xcd, 0x1d, 0x17, 0xcb, 0xe1, 0xa6, 0xec, 0x6c, 0x2a, 0x39, 0x9b, + 0x4b, 0xe8, 0xbc, 0xad, 0x3c, 0xc4, 0xef, 0x2c, 0x4b, 0x40, 0xe9, 0xde, + 0x9e, 0xfc, 0x56, 0x92, 0x1f, 0xe1, 0xef, 0x20, 0x90, 0xc8, 0x67, 0x89, + 0xc8, 0xbf, 0x24, 0x42, 0xf6, 0xa5, 0xe0, 0x1e, 0x82, 0xf8, 0x27, 0xba, + 0xb2, 0x3b, 0x4b, 0x68, 0xcf, 0x3c, 0x91, 0x7a, 0x66, 0x8a, 0xdc, 0x33, + 0x57, 0xfa, 0xe0, 0x70, 0xb6, 0x44, 0xe0, 0x70, 0xbe, 0x90, 0x58, 0x18, + 0xe7, 0xcf, 0x18, 0x29, 0x16, 0xee, 0xf7, 0xef, 0x03, 0x89, 0x1e, 0xde, + 0x73, 0x1a, 0x0b, 0x6b, 0xf9, 0x33, 0x08, 0x62, 0xe1, 0xde, 0xe0, 0x5e, + 0x45, 0x43, 0xdd, 0x9f, 0x6b, 0x7f, 0x00, 0xa1, 0xe3, 0x13, 0x23, 0x10, + 0x05, 0x00, 0x00 }; //============================================================================== @@ -141,16 +140,22 @@ public: if (surfaceView.get() == nullptr) return; + surfaceHolderCallback = GlobalRef (CreateJavaInterface (this, "android/view/SurfaceHolder$Callback")); + + if (surfaceHolderCallback == nullptr) + return; + + if (LocalRef holder { env->CallObjectMethod (surfaceView, AndroidSurfaceView.getHolder) }) + env->CallVoidMethod (holder, AndroidSurfaceHolder.addCallback, surfaceHolderCallback.get()); + // add the view to the view hierarchy // after this the nativecontext can receive callbacks env->CallVoidMethod ((jobject) component.getPeer()->getNativeHandle(), - AndroidViewGroup.addView, surfaceView.get()); + AndroidViewGroup.addView, + surfaceView.get()); // initialise the geometry of the view - auto bounds = component.getTopLevelComponent()->getLocalArea (&component, component.getLocalBounds()); - bounds *= component.getDesktopScaleFactor(); - - updateWindowPosition (bounds); + updateWindowPosition (component.localAreaToGlobal (component.getLocalBounds())); hasInitialised = true; } @@ -158,6 +163,10 @@ public: { auto env = getEnv(); + if (surfaceView != nullptr && surfaceHolderCallback != nullptr) + if (LocalRef holder { env->CallObjectMethod (surfaceView, AndroidSurfaceView.getHolder) }) + env->CallVoidMethod (holder, AndroidSurfaceHolder.removeCallback, surfaceHolderCallback.get()); + if (jobject viewParent = env->CallObjectMethod (surfaceView.get(), JuceOpenGLViewSurface.getParent)) env->CallVoidMethod (viewParent, AndroidViewGroup.removeView, surfaceView.get()); } @@ -221,16 +230,17 @@ public: //============================================================================== void updateWindowPosition (Rectangle bounds) { - if (lastBounds != bounds) - { - auto env = getEnv(); + const auto physical = Desktop::getInstance().getDisplays().logicalToPhysical (bounds.toFloat()).toNearestInt(); - lastBounds = bounds; - auto r = bounds * Desktop::getInstance().getDisplays().getPrimaryDisplay()->scale; + if (std::exchange (physicalBounds, physical) == physical) + return; - env->CallVoidMethod (surfaceView.get(), JuceOpenGLViewSurface.layout, - (jint) r.getX(), (jint) r.getY(), (jint) r.getRight(), (jint) r.getBottom()); - } + getEnv()->CallVoidMethod (surfaceView.get(), + JuceOpenGLViewSurface.layout, + (jint) physical.getX(), + (jint) physical.getY(), + (jint) physical.getRight(), + (jint) physical.getBottom()); } //============================================================================== @@ -252,43 +262,39 @@ public: const ScopedLock lock; }; + void addListener (NativeContextListener& l) + { + listeners.add (&l); + } + + void removeListener (NativeContextListener& l) + { + listeners.remove (&l); + } + + void notifyWillPause() + { + listeners.call ([&] (auto& l) { l.contextWillPause(); }); + } + + void notifyDidResume() + { + listeners.call ([&] (auto& l) { l.contextDidResume(); }); + } + Component& component; private: #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \ METHOD (constructor, "", "(Landroid/content/Context;J)V") \ METHOD (getParent, "getParent", "()Landroid/view/ViewParent;") \ - METHOD (getHolder, "getHolder", "()Landroid/view/SurfaceHolder;") \ METHOD (layout, "layout", "(IIII)V" ) \ - CALLBACK (generatedCallback<&NativeContext::attachedToWindow>, "onAttchedWindowNative", "(J)V") \ - CALLBACK (generatedCallback<&NativeContext::detachedFromWindow>, "onDetachedFromWindowNative", "(J)V") \ CALLBACK (generatedCallback<&NativeContext::dispatchDraw>, "onDrawNative", "(JLandroid/graphics/Canvas;)V") DECLARE_JNI_CLASS_WITH_BYTECODE (JuceOpenGLViewSurface, "com/rmsl/juce/JuceOpenGLView", 24, javaJuceOpenGLView) #undef JNI_CLASS_MEMBERS //============================================================================== - static void attachedToWindow (JNIEnv* env, NativeContext& t) - { - LocalRef holder (env->CallObjectMethod (t.surfaceView.get(), JuceOpenGLViewSurface.getHolder)); - - if (t.surfaceHolderCallback == nullptr) - t.surfaceHolderCallback = GlobalRef (CreateJavaInterface (&t, "android/view/SurfaceHolder$Callback")); - - env->CallVoidMethod (holder, AndroidSurfaceHolder.addCallback, t.surfaceHolderCallback.get()); - } - - static void detachedFromWindow (JNIEnv* env, NativeContext& t) - { - if (t.surfaceHolderCallback != nullptr) - { - LocalRef holder (env->CallObjectMethod (t.surfaceView.get(), JuceOpenGLViewSurface.getHolder)); - - env->CallVoidMethod (holder.get(), AndroidSurfaceHolder.removeCallback, t.surfaceHolderCallback.get()); - t.surfaceHolderCallback.clear(); - } - } - static void dispatchDraw (JNIEnv*, NativeContext& t, jobject /*canvas*/) { const std::lock_guard lock { t.nativeHandleMutex }; @@ -353,16 +359,14 @@ private: void operator() (ANativeWindow* ptr) const { if (ptr != nullptr) ANativeWindow_release (ptr); } }; - std::unique_ptr getNativeWindow() const + static std::unique_ptr getNativeWindowFromSurfaceHolder (jobject holder) { auto* env = getEnv(); - const LocalRef holder (env->CallObjectMethod (surfaceView.get(), JuceOpenGLViewSurface.getHolder)); - if (holder == nullptr) return nullptr; - const LocalRef jSurface (env->CallObjectMethod (holder.get(), AndroidSurfaceHolder.getSurface)); + const LocalRef jSurface (env->CallObjectMethod (holder, AndroidSurfaceHolder.getSurface)); if (jSurface == nullptr) return nullptr; @@ -381,7 +385,7 @@ private: bool hasInitialised = false; GlobalRef surfaceView; - Rectangle lastBounds; + Rectangle physicalBounds; struct SurfaceDestructor { @@ -395,20 +399,18 @@ private: mutable std::mutex nativeHandleMutex; OpenGLContext* juceContext = nullptr; + ListenerList listeners; std::unique_ptr, SurfaceDestructor> surface { EGL_NO_SURFACE }; std::unique_ptr, ContextDestructor> context { EGL_NO_CONTEXT }; GlobalRef surfaceHolderCallback; - static EGLDisplay display; - static EGLConfig config; + inline static EGLDisplay display = EGL_NO_DISPLAY; + inline static EGLConfig config; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NativeContext) }; -EGLDisplay OpenGLContext::NativeContext::display = EGL_NO_DISPLAY; -EGLDisplay OpenGLContext::NativeContext::config; - //============================================================================== bool OpenGLHelpers::isContextActive() { diff --git a/modules/juce_opengl/native/juce_OpenGL_ios.h b/modules/juce_opengl/native/juce_OpenGL_ios.h index d49f91907f..adb02005ec 100644 --- a/modules/juce_opengl/native/juce_OpenGL_ios.h +++ b/modules/juce_opengl/native/juce_OpenGL_ios.h @@ -213,6 +213,9 @@ public: const ScopedLock lock; }; + void addListener (NativeContextListener&) {} + void removeListener (NativeContextListener&) {} + private: CriticalSection mutex; Component& component; diff --git a/modules/juce_opengl/native/juce_OpenGL_linux.h b/modules/juce_opengl/native/juce_OpenGL_linux.h index 813d7043b2..19e81259f7 100644 --- a/modules/juce_opengl/native/juce_OpenGL_linux.h +++ b/modules/juce_opengl/native/juce_OpenGL_linux.h @@ -404,6 +404,9 @@ public: const ScopedLock lock; }; + void addListener (NativeContextListener&) {} + void removeListener (NativeContextListener&) {} + private: bool tryChooseVisual (const OpenGLPixelFormat& format, const std::vector& optionalAttribs) { diff --git a/modules/juce_opengl/native/juce_OpenGL_mac.h b/modules/juce_opengl/native/juce_OpenGL_mac.h index 0f2eaeb4a7..7e39fb4605 100644 --- a/modules/juce_opengl/native/juce_OpenGL_mac.h +++ b/modules/juce_opengl/native/juce_OpenGL_mac.h @@ -295,6 +295,9 @@ public: double videoRefreshPeriodS = 1.0 / 60.0; }; + void addListener (NativeContextListener&) {} + void removeListener (NativeContextListener&) {} + Component& owner; NSOpenGLContext* renderContext = nil; NSOpenGLView* view = nil; diff --git a/modules/juce_opengl/native/juce_OpenGL_windows.h b/modules/juce_opengl/native/juce_OpenGL_windows.h index 194544d3df..c848eecaf1 100644 --- a/modules/juce_opengl/native/juce_OpenGL_windows.h +++ b/modules/juce_opengl/native/juce_OpenGL_windows.h @@ -196,6 +196,9 @@ public: return nullptr; } + void addListener (NativeContextListener&) {} + void removeListener (NativeContextListener&) {} + private: //============================================================================== void handleAsyncUpdate() override diff --git a/modules/juce_opengl/opengl/juce_OpenGLContext.cpp b/modules/juce_opengl/opengl/juce_OpenGLContext.cpp index 88b80ffef8..27f8ace149 100644 --- a/modules/juce_opengl/opengl/juce_OpenGLContext.cpp +++ b/modules/juce_opengl/opengl/juce_OpenGLContext.cpp @@ -201,6 +201,10 @@ public: ScopedContextActivator activator; activator.activate (context); + #if JUCE_ANDROID + nativeContext->notifyWillPause(); + #endif + if (context.renderer != nullptr) context.renderer->openGLContextClosing(); @@ -443,10 +447,14 @@ public: if (auto* peer = component.getPeer()) { + auto& desktop = Desktop::getInstance(); + const auto localBounds = component.getLocalBounds(); + const auto globalArea = component.getScreenBounds() * desktop.getGlobalScaleFactor(); + #if JUCE_MAC updateScreen(); - const auto displayScale = Desktop::getInstance().getGlobalScaleFactor() * [this] + const auto displayScale = std::invoke ([this] { if (auto* view = getCurrentView()) { @@ -458,16 +466,14 @@ public: } return areaAndScale.get().scale; - }(); - #else - const auto displayScale = Desktop::getInstance().getDisplays() - .getDisplayForRect (component.getTopLevelComponent() - ->getScreenBounds()) - ->scale; - #endif + }); - const auto localBounds = component.getLocalBounds(); - const auto newArea = peer->getComponent().getLocalArea (&component, localBounds).withZeroOrigin() * displayScale; + const auto newArea = globalArea.withZeroOrigin() * displayScale; + #else + const auto newArea = desktop.getDisplays() + .logicalToPhysical (globalArea) + .withZeroOrigin(); + #endif // On Windows some hosts (Pro Tools 2022.7) do not take the current DPI into account // when sizing plugin editor windows. @@ -670,6 +676,10 @@ public: if (context.renderer != nullptr) context.renderer->newOpenGLContextCreated(); + #if JUCE_ANDROID + nativeContext->notifyDidResume(); + #endif + return InitResult::success; } @@ -1669,9 +1679,19 @@ void OpenGLContext::copyTexture (const Rectangle& targetClipArea, JUCE_CHECK_OPENGL_ERROR } +void OpenGLContext::NativeContextListener::addListener (OpenGLContext& ctx, NativeContextListener& l) +{ + ctx.nativeContext->addListener (l); +} + +void OpenGLContext::NativeContextListener::removeListener (OpenGLContext& ctx, NativeContextListener& l) +{ + ctx.nativeContext->removeListener (l); +} + #if JUCE_ANDROID -void OpenGLContext::NativeContext::surfaceCreated (LocalRef) +void OpenGLContext::NativeContext::surfaceCreated (LocalRef holder) { { const std::lock_guard lock { nativeHandleMutex }; @@ -1681,7 +1701,7 @@ void OpenGLContext::NativeContext::surfaceCreated (LocalRef) // has the context already attached? jassert (surface.get() == EGL_NO_SURFACE && context.get() == EGL_NO_CONTEXT); - const auto window = getNativeWindow(); + const auto window = getNativeWindowFromSurfaceHolder (holder); if (window == nullptr) { @@ -1690,7 +1710,11 @@ void OpenGLContext::NativeContext::surfaceCreated (LocalRef) return; } - // create the surface + // Reset the surface (only one window surface may be alive at a time) + context.reset(); + surface.reset(); + + // Create the surface surface.reset (eglCreateWindowSurface (display, config, window.get(), nullptr)); jassert (surface.get() != EGL_NO_SURFACE); diff --git a/modules/juce_opengl/opengl/juce_OpenGLContext.h b/modules/juce_opengl/opengl/juce_OpenGLContext.h index d8e1ff0a9a..f0e552e6f7 100644 --- a/modules/juce_opengl/opengl/juce_OpenGLContext.h +++ b/modules/juce_opengl/opengl/juce_OpenGLContext.h @@ -346,9 +346,10 @@ public: size_t getImageCacheSize() const noexcept; //============================================================================== - #ifndef DOXYGEN + /** @cond */ class NativeContext; - #endif + class NativeContextListener; + /** @endcond */ private: enum class InitResult @@ -400,9 +401,9 @@ private: }; //============================================================================== -#ifndef DOXYGEN +/** @cond */ template void OpenGLContext::executeOnGLThread (FunctionType&& f, bool shouldBlock) { execute (new AsyncWorkerFunctor (f), shouldBlock); } -#endif +/** @endcond */ } // namespace juce diff --git a/modules/juce_opengl/opengl/juce_OpenGLFrameBuffer.cpp b/modules/juce_opengl/opengl/juce_OpenGLFrameBuffer.cpp index 688b000bd8..b824a6b164 100644 --- a/modules/juce_opengl/opengl/juce_OpenGLFrameBuffer.cpp +++ b/modules/juce_opengl/opengl/juce_OpenGLFrameBuffer.cpp @@ -35,9 +35,271 @@ namespace juce { -class OpenGLFrameBuffer::Pimpl +/* + Used on Android to detect when the GL context and associated resources (textures, framebuffers, + etc.) need to be destroyed/created due to the Surface changing state. +*/ +class OpenGLContext::NativeContextListener { public: + virtual ~NativeContextListener() = default; + + virtual void contextWillPause() = 0; + virtual void contextDidResume() = 0; + + static void addListener (OpenGLContext& ctx, NativeContextListener& l); + static void removeListener (OpenGLContext& ctx, NativeContextListener& l); +}; + +class OpenGLFrameBuffer::Pimpl : private OpenGLContext::NativeContextListener +{ +public: + struct SavedState + { + int width = 0, height = 0; + std::vector data; + + static constexpr auto order = RowOrder::fromBottomUp; + }; + + ~Pimpl() override + { + release(); + } + + bool isValid() const noexcept + { + return std::holds_alternative (state); + } + + bool initialise (OpenGLContext& context, int width, int height) + { + jassert (context.isActive()); // The context must be active when creating a framebuffer! + + release(); + auto& transientState = state.emplace (width, height, false, false); + + if (! transientState.createdOk()) + release(); + + if (! isValid()) + return false; + + associatedContext = &context; + NativeContextListener::addListener (*associatedContext, *this); + + return true; + } + + bool initialise (OpenGLContext& context, const Image& image) + { + if (! image.isARGB()) + return initialise (context, image.convertedToFormat (Image::ARGB)); + + Image::BitmapData bitmap (image, Image::BitmapData::readOnly); + + return initialise (context, bitmap.width, bitmap.height) + && writePixels ((const PixelARGB*) bitmap.data, image.getBounds(), RowOrder::fromTopDown); + } + + bool initialise (OpenGLFrameBuffer& other) + { + auto* p = std::get_if (&other.pimpl->state); + + if (p == nullptr || other.pimpl->associatedContext == nullptr) + { + release(); + return true; + } + + const Rectangle area (p->width, p->height); + + if (! initialise (*other.pimpl->associatedContext, area.getWidth(), area.getHeight())) + return false; + + jassert (associatedContext != nullptr); + + auto* transientState = std::get_if (&state); + transientState->bind(); + const ScopeGuard unbinder { [transientState] { transientState->unbind(); }}; + + #if ! JUCE_ANDROID + if (! associatedContext->isCoreProfile()) + glEnable (GL_TEXTURE_2D); + + clearGLError(); + #endif + { + const ScopedTextureBinding scopedTextureBinding; + glBindTexture (GL_TEXTURE_2D, p->textureID); + associatedContext->copyTexture (area, area, area.getWidth(), area.getHeight(), false); + } + + return true; + } + + void release() + { + if (auto* prev = std::exchange (associatedContext, nullptr)) + NativeContextListener::removeListener (*prev, *this); + + state.emplace(); + } + + void saveAndRelease() + { + if (auto* transientState = std::get_if (&state)) + { + if (auto toSave = readPixels ({ transientState->width, transientState->height })) + state.emplace (std::move (*toSave)); + } + } + + bool reloadSavedCopy (OpenGLContext& context) + { + if (auto* savedState = std::get_if (&state)) + { + auto local = std::move (*savedState); + + if (restore (context, local)) + return true; + + state.emplace (std::move (local)); + } + + return false; + } + + int getWidth() const noexcept + { + if (auto* transientState = std::get_if (&state)) + return transientState->width; + + return 0; + } + + int getHeight() const noexcept + { + if (auto* transientState = std::get_if (&state)) + return transientState->height; + + return 0; + } + + GLuint getTextureID() const noexcept + { + if (auto* transientState = std::get_if (&state)) + return transientState->textureID; + + return 0; + } + + GLuint getFrameBufferID() const noexcept + { + if (auto* transientState = std::get_if (&state)) + return transientState->frameBufferID; + + return 0; + } + + bool makeCurrentRenderingTarget() + { + return makeAndGetCurrentRenderingTarget() != nullptr; + } + + void releaseAsRenderingTarget() + { + if (auto* transientState = std::get_if (&state)) + transientState->unbind(); + } + + void clear (Colour colour) + { + auto* transientState = makeAndGetCurrentRenderingTarget(); + + if (transientState == nullptr) + return; + + const ScopeGuard unbinder { [transientState] { transientState->unbind(); }}; + OpenGLHelpers::clear (colour); + } + + void makeCurrentAndClear() + { + auto* transientState = makeAndGetCurrentRenderingTarget(); + + if (transientState == nullptr) + return; + + glClearColor (0, 0, 0, 0); + glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + } + + bool readPixels (PixelARGB* target, const Rectangle& area, RowOrder order) + { + auto* transientState = makeAndGetCurrentRenderingTarget(); + + if (transientState == nullptr) + return false; + + const ScopeGuard unbinder { [transientState] { transientState->unbind(); }}; + + glPixelStorei (GL_PACK_ALIGNMENT, 4); + glReadPixels (area.getX(), area.getY(), area.getWidth(), area.getHeight(), + JUCE_RGBA_FORMAT, GL_UNSIGNED_BYTE, target); + + if (order == RowOrder::fromTopDown) + { + auto* end = target + area.getWidth() * area.getHeight(); + + for (auto y = 0; y < area.getHeight() / 2; ++y) + { + const auto offset = area.getWidth() * y; + auto* rowA = target + offset; + auto* rowB = end - offset - area.getWidth(); + + for (auto x = 0; x < area.getWidth(); ++x) + std::swap (rowA[x], rowB[x]); + } + } + + return true; + } + + bool writePixels (const PixelARGB* data, const Rectangle& area, RowOrder order) + { + if (associatedContext == nullptr) + return false; + + const OpenGLTargetSaver ts; + auto* transientState = makeAndGetCurrentRenderingTarget(); + + if (transientState == nullptr) + return false; + + glDisable (GL_DEPTH_TEST); + glDisable (GL_BLEND); + JUCE_CHECK_OPENGL_ERROR + + OpenGLTexture tex; + tex.loadARGB (data, area.getWidth(), area.getHeight()); + + glViewport (0, 0, transientState->width, transientState->height); + associatedContext->copyTexture (area, + Rectangle (area.getX(), + area.getY(), + tex.getWidth(), + tex.getHeight()), + transientState->width, + transientState->height, + order == RowOrder::fromTopDown, + false); + + JUCE_CHECK_OPENGL_ERROR + return true; + } + +private: /* Stores the currently-bound texture on construction, and re-binds it on destruction. */ struct ScopedTextureBinding { @@ -56,269 +318,266 @@ public: GLint prev{}; }; - Pimpl (OpenGLContext& c, const int w, const int h, - const bool wantsDepthBuffer, const bool wantsStencilBuffer) - : context (c), width (w), height (h), - textureID (0), frameBufferID (0), depthOrStencilBuffer (0), - hasDepthBuffer (false), hasStencilBuffer (false) + class TransientState { - // Framebuffer objects can only be created when the current thread has an active OpenGL - // context. You'll need to create this object in one of the OpenGLContext's callbacks. - jassert (OpenGLHelpers::isContextActive()); - - #if JUCE_WINDOWS || JUCE_LINUX || JUCE_BSD - if (context.extensions.glGenFramebuffers == nullptr) - return; - #endif - - context.extensions.glGenFramebuffers (1, &frameBufferID); - bind(); - + public: + TransientState (const int w, + const int h, + const bool wantsDepthBuffer, + const bool wantsStencilBuffer) + : width (w), + height (h), + textureID (0), + frameBufferID (0), + depthOrStencilBuffer (0) { - const ScopedTextureBinding scopedTextureBinding; + // Framebuffer objects can only be created when the current thread has an active OpenGL + // context. You'll need to create this object in one of the OpenGLContext's callbacks. + jassert (OpenGLHelpers::isContextActive()); - glGenTextures (1, &textureID); - glBindTexture (GL_TEXTURE_2D, textureID); - JUCE_CHECK_OPENGL_ERROR + #if JUCE_WINDOWS || JUCE_LINUX || JUCE_BSD + if (gl::glGenFramebuffers == nullptr) + return; + #endif - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - JUCE_CHECK_OPENGL_ERROR + gl::glGenFramebuffers (1, &frameBufferID); + bind(); + const ScopeGuard unbinder { [this] { unbind(); }}; - glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); - JUCE_CHECK_OPENGL_ERROR + { + const ScopedTextureBinding scopedTextureBinding; + + glGenTextures (1, &textureID); + glBindTexture (GL_TEXTURE_2D, textureID); + JUCE_CHECK_OPENGL_ERROR + + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + JUCE_CHECK_OPENGL_ERROR + + glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); + JUCE_CHECK_OPENGL_ERROR + } + + gl::glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureID, 0); + + if (wantsDepthBuffer || wantsStencilBuffer) + { + gl::glGenRenderbuffers (1, &depthOrStencilBuffer); + gl::glBindRenderbuffer (GL_RENDERBUFFER, depthOrStencilBuffer); + jassert (gl::glIsRenderbuffer (depthOrStencilBuffer)); + + #if JUCE_OPENGL_ES + constexpr auto depthComponentConstant = (GLenum) GL_DEPTH_COMPONENT16; + #else + constexpr auto depthComponentConstant = (GLenum) GL_DEPTH_COMPONENT; + #endif + + gl::glRenderbufferStorage (GL_RENDERBUFFER, + (wantsDepthBuffer && wantsStencilBuffer) ? (GLenum) GL_DEPTH24_STENCIL8 + : depthComponentConstant, + width, + height); + + GLint params = 0; + gl::glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_DEPTH_SIZE, ¶ms); + gl::glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthOrStencilBuffer); + + if (wantsStencilBuffer) + gl::glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthOrStencilBuffer); + } } - context.extensions.glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureID, 0); - - if (wantsDepthBuffer || wantsStencilBuffer) + ~TransientState() { - context.extensions.glGenRenderbuffers (1, &depthOrStencilBuffer); - context.extensions.glBindRenderbuffer (GL_RENDERBUFFER, depthOrStencilBuffer); - jassert (context.extensions.glIsRenderbuffer (depthOrStencilBuffer)); + if (! OpenGLHelpers::isContextActive()) + return; - context.extensions.glRenderbufferStorage (GL_RENDERBUFFER, - (wantsDepthBuffer && wantsStencilBuffer) ? (GLenum) GL_DEPTH24_STENCIL8 - #if JUCE_OPENGL_ES - : (GLenum) GL_DEPTH_COMPONENT16, - #else - : (GLenum) GL_DEPTH_COMPONENT, - #endif - width, height); - - GLint params = 0; - context.extensions.glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_DEPTH_SIZE, ¶ms); - context.extensions.glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthOrStencilBuffer); - - if (wantsStencilBuffer) - context.extensions.glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthOrStencilBuffer); - - hasDepthBuffer = wantsDepthBuffer; - hasStencilBuffer = wantsStencilBuffer; - } - - unbind(); - } - - ~Pimpl() - { - if (OpenGLHelpers::isContextActive()) - { if (textureID != 0) - glDeleteTextures (1, &textureID); + gl::glDeleteTextures (1, &textureID); if (depthOrStencilBuffer != 0) - context.extensions.glDeleteRenderbuffers (1, &depthOrStencilBuffer); + gl::glDeleteRenderbuffers (1, &depthOrStencilBuffer); if (frameBufferID != 0) - context.extensions.glDeleteFramebuffers (1, &frameBufferID); + gl::glDeleteFramebuffers (1, &frameBufferID); JUCE_CHECK_OPENGL_ERROR } - } - bool createdOk() const - { - return frameBufferID != 0 && textureID != 0; - } - - void bind() - { - glGetIntegerv (GL_FRAMEBUFFER_BINDING, &prevFramebuffer); - context.extensions.glBindFramebuffer (GL_FRAMEBUFFER, frameBufferID); - JUCE_CHECK_OPENGL_ERROR - } - - void unbind() - { - context.extensions.glBindFramebuffer (GL_FRAMEBUFFER, (GLuint) prevFramebuffer); - JUCE_CHECK_OPENGL_ERROR - } - - OpenGLContext& context; - const int width, height; - GLuint textureID, frameBufferID, depthOrStencilBuffer; - bool hasDepthBuffer, hasStencilBuffer; - -private: - GLint prevFramebuffer{}; - - bool checkStatus() noexcept - { - const GLenum status = context.extensions.glCheckFramebufferStatus (GL_FRAMEBUFFER); - - return status == GL_NO_ERROR - || status == GL_FRAMEBUFFER_COMPLETE; - } - - JUCE_DECLARE_NON_COPYABLE (Pimpl) -}; - -//============================================================================== -class OpenGLFrameBuffer::SavedState -{ -public: - SavedState (OpenGLFrameBuffer& buffer, const int w, const int h) - : width (w), height (h), - data ((size_t) (w * h)) - { - buffer.readPixels (data, Rectangle (w, h)); - } - - bool restore (OpenGLContext& context, OpenGLFrameBuffer& buffer) - { - if (buffer.initialise (context, width, height)) + bool createdOk() const { - buffer.writePixels (data, Rectangle (width, height)); - return true; + return frameBufferID != 0 && textureID != 0; } - return false; + void bind() + { + glGetIntegerv (GL_FRAMEBUFFER_BINDING, &prevFramebuffer); + gl::glBindFramebuffer (GL_FRAMEBUFFER, frameBufferID); + JUCE_CHECK_OPENGL_ERROR + } + + void unbind() + { + gl::glBindFramebuffer (GL_FRAMEBUFFER, (GLuint) prevFramebuffer); + JUCE_CHECK_OPENGL_ERROR + } + + const int width, height; + GLuint textureID, frameBufferID, depthOrStencilBuffer; + + private: + GLint prevFramebuffer{}; + + JUCE_DECLARE_NON_COPYABLE (TransientState) + }; + + bool restore (OpenGLContext& context, const SavedState& savedState) + { + if (! initialise (context, savedState.width, savedState.height)) + return false; + + writePixels (savedState.data.data(), + Rectangle (savedState.width, savedState.height), + SavedState::order); + return true; } -private: - const int width, height; - HeapBlock data; + std::optional readPixels (const Rectangle& area) + { + SavedState result { area.getWidth(), + area.getHeight(), + std::vector ((size_t) area.getWidth() * (size_t) area.getHeight()) }; - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SavedState) + if (! readPixels (result.data.data(), area, SavedState::order)) + return {}; + + return result; + } + + TransientState* makeAndGetCurrentRenderingTarget() + { + if (auto* transientState = std::get_if (&state)) + { + transientState->bind(); + return transientState; + } + + // trying to use a framebuffer after saving it with saveAndRelease()! Be sure to call + // reloadSavedCopy() to put it back into GPU memory before using it.. + jassertfalse; + + return nullptr; + } + + void contextWillPause() override + { + saveAndRelease(); + } + + void contextDidResume() override + { + if (associatedContext != nullptr) + reloadSavedCopy (*associatedContext); + } + + OpenGLContext* associatedContext = nullptr; + std::variant state; }; //============================================================================== -OpenGLFrameBuffer::OpenGLFrameBuffer() {} -OpenGLFrameBuffer::~OpenGLFrameBuffer() {} +OpenGLFrameBuffer::OpenGLFrameBuffer() + : pimpl (std::make_unique()) +{ +} + +OpenGLFrameBuffer::~OpenGLFrameBuffer() = default; bool OpenGLFrameBuffer::initialise (OpenGLContext& context, int width, int height) { - jassert (context.isActive()); // The context must be active when creating a framebuffer! - - pimpl.reset(); - pimpl.reset (new Pimpl (context, width, height, false, false)); - - if (! pimpl->createdOk()) - pimpl.reset(); - - return pimpl != nullptr; +return pimpl->initialise (context, width, height); } -bool OpenGLFrameBuffer::initialise (OpenGLContext& context, const Image& image) +bool OpenGLFrameBuffer::initialise (OpenGLContext& context, const Image& content) { - if (! image.isARGB()) - return initialise (context, image.convertedToFormat (Image::ARGB)); - - Image::BitmapData bitmap (image, Image::BitmapData::readOnly); - - return initialise (context, bitmap.width, bitmap.height) - && writePixels ((const PixelARGB*) bitmap.data, image.getBounds()); + return pimpl->initialise (context, content); } bool OpenGLFrameBuffer::initialise (OpenGLFrameBuffer& other) { - auto* p = other.pimpl.get(); - - if (p == nullptr) - { - pimpl.reset(); - return true; - } - - const Rectangle area (pimpl->width, pimpl->height); - - if (initialise (p->context, area.getWidth(), area.getHeight())) - { - pimpl->bind(); - - #if ! JUCE_ANDROID - if (! pimpl->context.isCoreProfile()) - glEnable (GL_TEXTURE_2D); - - clearGLError(); - #endif - { - const Pimpl::ScopedTextureBinding scopedTextureBinding; - glBindTexture (GL_TEXTURE_2D, p->textureID); - pimpl->context.copyTexture (area, area, area.getWidth(), area.getHeight(), false); - } - - pimpl->unbind(); - return true; - } - - return false; + return pimpl->initialise (other); } void OpenGLFrameBuffer::release() { - pimpl.reset(); - savedState.reset(); + pimpl->release(); } void OpenGLFrameBuffer::saveAndRelease() { - if (pimpl != nullptr) - { - savedState.reset (new SavedState (*this, pimpl->width, pimpl->height)); - pimpl.reset(); - } + pimpl->saveAndRelease(); } bool OpenGLFrameBuffer::reloadSavedCopy (OpenGLContext& context) { - if (savedState != nullptr) - { - std::unique_ptr state; - std::swap (state, savedState); - - if (state->restore (context, *this)) - return true; - - std::swap (state, savedState); - } - - return false; + return pimpl->reloadSavedCopy (context); } -int OpenGLFrameBuffer::getWidth() const noexcept { return pimpl != nullptr ? pimpl->width : 0; } -int OpenGLFrameBuffer::getHeight() const noexcept { return pimpl != nullptr ? pimpl->height : 0; } -GLuint OpenGLFrameBuffer::getTextureID() const noexcept { return pimpl != nullptr ? pimpl->textureID : 0; } +bool OpenGLFrameBuffer::isValid() const noexcept +{ + return pimpl->isValid(); +} + +int OpenGLFrameBuffer::getWidth() const noexcept +{ + return pimpl->getWidth(); +} + +int OpenGLFrameBuffer::getHeight() const noexcept +{ + return pimpl->getHeight(); +} + +GLuint OpenGLFrameBuffer::getTextureID() const noexcept +{ + return pimpl->getTextureID(); +} bool OpenGLFrameBuffer::makeCurrentRenderingTarget() { - // trying to use a framebuffer after saving it with saveAndRelease()! Be sure to call - // reloadSavedCopy() to put it back into GPU memory before using it.. - jassert (savedState == nullptr); + return pimpl->makeCurrentRenderingTarget(); +} - if (pimpl == nullptr) - return false; - - pimpl->bind(); - return true; +void OpenGLFrameBuffer::releaseAsRenderingTarget() +{ + pimpl->releaseAsRenderingTarget(); } GLuint OpenGLFrameBuffer::getFrameBufferID() const noexcept { - return pimpl != nullptr ? pimpl->frameBufferID : 0; + return pimpl->getFrameBufferID(); +} + +void OpenGLFrameBuffer::clear (Colour colour) +{ + pimpl->clear (colour); +} + +void OpenGLFrameBuffer::makeCurrentAndClear() +{ + pimpl->makeCurrentAndClear(); +} + +bool OpenGLFrameBuffer::readPixels (PixelARGB* targetData, const Rectangle& sourceArea, RowOrder order) +{ + return pimpl->readPixels (targetData, sourceArea, order); +} + +bool OpenGLFrameBuffer::writePixels (const PixelARGB* srcData, const Rectangle& targetArea, RowOrder order) +{ + return pimpl->writePixels (srcData, targetArea, order); } GLuint OpenGLFrameBuffer::getCurrentFrameBufferTarget() noexcept @@ -328,64 +587,4 @@ GLuint OpenGLFrameBuffer::getCurrentFrameBufferTarget() noexcept return (GLuint) fb; } -void OpenGLFrameBuffer::releaseAsRenderingTarget() -{ - if (pimpl != nullptr) - pimpl->unbind(); -} - -void OpenGLFrameBuffer::clear (Colour colour) -{ - if (makeCurrentRenderingTarget()) - { - OpenGLHelpers::clear (colour); - releaseAsRenderingTarget(); - } -} - -void OpenGLFrameBuffer::makeCurrentAndClear() -{ - if (makeCurrentRenderingTarget()) - { - glClearColor (0, 0, 0, 0); - glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - } -} - -bool OpenGLFrameBuffer::readPixels (PixelARGB* target, const Rectangle& area) -{ - if (! makeCurrentRenderingTarget()) - return false; - - glPixelStorei (GL_PACK_ALIGNMENT, 4); - glReadPixels (area.getX(), area.getY(), area.getWidth(), area.getHeight(), - JUCE_RGBA_FORMAT, GL_UNSIGNED_BYTE, target); - - pimpl->unbind(); - return true; -} - -bool OpenGLFrameBuffer::writePixels (const PixelARGB* data, const Rectangle& area) -{ - OpenGLTargetSaver ts (pimpl->context); - - if (! makeCurrentRenderingTarget()) - return false; - - glDisable (GL_DEPTH_TEST); - glDisable (GL_BLEND); - JUCE_CHECK_OPENGL_ERROR - - OpenGLTexture tex; - tex.loadARGB (data, area.getWidth(), area.getHeight()); - - glViewport (0, 0, pimpl->width, pimpl->height); - pimpl->context.copyTexture (area, Rectangle (area.getX(), area.getY(), - tex.getWidth(), tex.getHeight()), - pimpl->width, pimpl->height, true, false); - - JUCE_CHECK_OPENGL_ERROR - return true; -} - } // namespace juce diff --git a/modules/juce_opengl/opengl/juce_OpenGLFrameBuffer.h b/modules/juce_opengl/opengl/juce_OpenGLFrameBuffer.h index 6c6fda54bf..7ad02c41f3 100644 --- a/modules/juce_opengl/opengl/juce_OpenGLFrameBuffer.h +++ b/modules/juce_opengl/opengl/juce_OpenGLFrameBuffer.h @@ -81,13 +81,12 @@ public: void saveAndRelease(); /** Restores the framebuffer content that was previously saved using saveAndRelease(). - After saving to main memory, the original state can be restored by calling restoreToGPUMemory(). */ bool reloadSavedCopy (OpenGLContext& context); //============================================================================== /** Returns true if a valid buffer has been allocated. */ - bool isValid() const noexcept { return pimpl != nullptr; } + bool isValid() const noexcept; /** Returns the width of the buffer. */ int getWidth() const noexcept; @@ -117,25 +116,29 @@ public: /** Selects the framebuffer as the current target, and clears it to transparent. */ void makeCurrentAndClear(); + enum class RowOrder + { + fromBottomUp, //< Standard order for OpenGL, the bottom-most row of pixels is first. + //< Using this pixel ordering may be faster, but may be incompatible + //< with other JUCE functions that operate on image pixel data, as these + //< generally expect the rows to be ordered top-down. + fromTopDown, //< Standard order for JUCE images, the top-most row of pixels is first. + }; + /** Reads an area of pixels from the framebuffer into a 32-bit ARGB pixel array. - The lineStride is measured as a number of pixels, not bytes - pass a stride - of 0 to indicate a packed array. + The RowOrder parameter specifies the order of rows in the resulting array. */ - bool readPixels (PixelARGB* targetData, const Rectangle& sourceArea); + bool readPixels (PixelARGB* targetData, const Rectangle& sourceArea, RowOrder); /** Writes an area of pixels into the framebuffer from a specified pixel array. - The lineStride is measured as a number of pixels, not bytes - pass a stride - of 0 to indicate a packed array. + The RowOrder parameter specifies the order of rows in srcData. */ - bool writePixels (const PixelARGB* srcData, const Rectangle& targetArea); + bool writePixels (const PixelARGB* srcData, const Rectangle& targetArea, RowOrder); private: class Pimpl; std::unique_ptr pimpl; - class SavedState; - std::unique_ptr savedState; - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenGLFrameBuffer) }; diff --git a/modules/juce_opengl/opengl/juce_OpenGLImage.cpp b/modules/juce_opengl/opengl/juce_OpenGLImage.cpp index e36d77c5ca..f43af5b468 100644 --- a/modules/juce_opengl/opengl/juce_OpenGLImage.cpp +++ b/modules/juce_opengl/opengl/juce_OpenGLImage.cpp @@ -116,13 +116,13 @@ private: mode (modeIn) { if (mode != Image::BitmapData::writeOnly) - self->frameBuffer.readPixels (data.get(), getArea()); + self->frameBuffer.readPixels (data.get(), getArea(), order); } ~DataReleaser() override { if (mode != Image::BitmapData::readOnly) - self->frameBuffer.writePixels (data, getArea()); + self->frameBuffer.writePixels (data, getArea(), order); } Rectangle getArea() const @@ -134,6 +134,8 @@ private: HeapBlock data; Rectangle area; Image::BitmapData::ReadWriteMode mode; + + static constexpr auto order = OpenGLFrameBuffer::RowOrder::fromBottomUp; }; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenGLFrameBufferImage) diff --git a/modules/juce_product_unlocking/in_app_purchases/juce_InAppPurchases.h b/modules/juce_product_unlocking/in_app_purchases/juce_InAppPurchases.h index 9e7718b66a..a3983efaf9 100644 --- a/modules/juce_product_unlocking/in_app_purchases/juce_InAppPurchases.h +++ b/modules/juce_product_unlocking/in_app_purchases/juce_InAppPurchases.h @@ -49,9 +49,9 @@ namespace juce class JUCE_API InAppPurchases : private DeletedAtShutdown { public: - #ifndef DOXYGEN + /** @cond */ JUCE_DECLARE_SINGLETON_INLINE (InAppPurchases, false) - #endif + /** @endcond */ //============================================================================== /** Represents a product available in the store. */ @@ -265,7 +265,7 @@ public: void cancelDownloads (const Array& downloads); //============================================================================== - #ifndef DOXYGEN + /** @cond */ [[deprecated ("On Android, it is no longer necessary to specify whether the product being purchased is a subscription " "and only a single subscription can be upgraded/downgraded. Use the updated purchaseProduct method " "which takes a single String argument.")]] @@ -278,14 +278,14 @@ public: upgradeOrDowngradeFromSubscriptionsWithProductIdentifiers[0], creditForUnusedSubscription); } - #endif + /** @endcond */ private: //============================================================================== - #ifndef DOXYGEN + /** @cond */ InAppPurchases(); ~InAppPurchases(); - #endif + /** @endcond */ //============================================================================== ListenerList listeners;