diff --git a/Jenkinsfile b/Jenkinsfile index 0eac63bc..690ad963 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,31 +1,216 @@ #!/usr/bin/env groovy -import groovy.transform.Field - +// This pipeline is designed to run on Esri-internal CI infrastructure. // -- PIPELINE LIBRARIES @Library('psl') import com.esri.zrh.jenkins.PipelineSupportLibrary import com.esri.zrh.jenkins.PslFactory +import com.esri.zrh.jenkins.psl.UploadTrackingPsl +import com.esri.zrh.jenkins.JenkinsTools +import com.esri.zrh.jenkins.ToolInfo +import com.esri.zrh.jenkins.ce.CityEnginePipelineLibrary +import com.esri.zrh.jenkins.ce.PrtAppPipelineLibrary +import groovy.transform.Field -@Field def psl = PslFactory.create(this) - +@Field def psl = PslFactory.create(this, UploadTrackingPsl.ID) +@Field def cepl = new CityEnginePipelineLibrary(this, psl) +@Field def papl = new PrtAppPipelineLibrary(cepl) // -- SETUP psl.runsHere('production') env.PIPELINE_ARCHIVING_ALLOWED = "true" +properties([ disableConcurrentBuilds() ]) + +// -- GLOBAL DEFINITIONS + +@Field final String REPO = 'git@github.com:esri/serlio.git' +@Field final String REPO_CREDS = 'jenkins-github-serlio-deployer-key' +@Field final String SOURCES = "serlio.git/src" +@Field final String BUILD_TARGET = 'package' +@Field final String SOURCE_STASH = 'serlio-src' + +@Field final List CHECKOUT_CONFIG = [ [ ba: psl.BA_CHECKOUT ] ] +// TODO: abusing grp field to distinguish maya versions per task +@Field final List CONFIGS = [ + [ os: cepl.CFG_OS_RHEL7, bc: cepl.CFG_BC_REL, tc: cepl.CFG_TC_GCC93, cc: cepl.CFG_CC_OPT, arch: cepl.CFG_ARCH_X86_64, grp: 'maya2019', maya: PrtAppPipelineLibrary.Dependencies.MAYA2019 ], + [ os: cepl.CFG_OS_RHEL7, bc: cepl.CFG_BC_REL, tc: cepl.CFG_TC_GCC93, cc: cepl.CFG_CC_OPT, arch: cepl.CFG_ARCH_X86_64, grp: 'maya2020', maya: PrtAppPipelineLibrary.Dependencies.MAYA2020 ], + [ os: cepl.CFG_OS_RHEL7, bc: cepl.CFG_BC_REL, tc: cepl.CFG_TC_GCC93, cc: cepl.CFG_CC_OPT, arch: cepl.CFG_ARCH_X86_64, grp: 'maya2022', maya: PrtAppPipelineLibrary.Dependencies.MAYA2022 ], + [ os: cepl.CFG_OS_WIN10, bc: cepl.CFG_BC_REL, tc: cepl.CFG_TC_VC1427, cc: cepl.CFG_CC_OPT, arch: cepl.CFG_ARCH_X86_64, grp: 'maya2019', maya: PrtAppPipelineLibrary.Dependencies.MAYA2019 ], + [ os: cepl.CFG_OS_WIN10, bc: cepl.CFG_BC_REL, tc: cepl.CFG_TC_VC1427, cc: cepl.CFG_CC_OPT, arch: cepl.CFG_ARCH_X86_64, grp: 'maya2020', maya: PrtAppPipelineLibrary.Dependencies.MAYA2020 ], + [ os: cepl.CFG_OS_WIN10, bc: cepl.CFG_BC_REL, tc: cepl.CFG_TC_VC1427, cc: cepl.CFG_CC_OPT, arch: cepl.CFG_ARCH_X86_64, grp: 'maya2022', maya: PrtAppPipelineLibrary.Dependencies.MAYA2022 ], +] + +@Field final List TEST_CONFIGS = [ + [ os: cepl.CFG_OS_RHEL7, bc: cepl.CFG_BC_REL, tc: cepl.CFG_TC_GCC93, cc: cepl.CFG_CC_OPT, arch: cepl.CFG_ARCH_X86_64, maya: PrtAppPipelineLibrary.Dependencies.MAYA2022 ], + [ os: cepl.CFG_OS_WIN10, bc: cepl.CFG_BC_REL, tc: cepl.CFG_TC_VC1427, cc: cepl.CFG_CC_OPT, arch: cepl.CFG_ARCH_X86_64, maya: PrtAppPipelineLibrary.Dependencies.MAYA2022 ], +] + +@Field final List INSTALLER_CONFIG = [ [ os: cepl.CFG_OS_WIN10, bc: cepl.CFG_BC_REL, tc: cepl.CFG_TC_VC1427, cc: cepl.CFG_CC_OPT, arch: cepl.CFG_ARCH_X86_64 ] ] +@Field final List INSTALLER_MAYA_VERS = [ 'maya2019', 'maya2020', 'maya2022' ] + +// -- PIPELINE + +stage('prepare'){ + cepl.runParallel(getCheckoutTask()) +} + +stage('test') { + cepl.runParallel(getTestTasks()) +} + +stage('build') { + cepl.runParallel(getBuildTasks()) +} + +stage('installers') { + cepl.runParallel(getInstallersTasks()) +} + +papl.finalizeRun('serlio', env.BRANCH_NAME) + +// -- TASK GENERATORS + +Map getCheckoutTask(){ + Map tasks = [:] + tasks << taskGenSerlioSourceCheckout() + return tasks +} + +Map getTestTasks() { + Map tasks = [:] + tasks << taskGenSerlioTests() + return tasks +} + +Map getBuildTasks() { + Map tasks = [:] + tasks << taskGenSerlio() + return tasks +} -// -- LOAD & RUN PIPELINE +Map getInstallersTasks() { + Map tasks = [:] + tasks << taskGenSerlioInstallers() + return tasks +} -def impl +Map taskGenSerlioSourceCheckout() { + return cepl.generateTasks('srl-src', this.&taskSourceCheckout, CHECKOUT_CONFIG) +} -node { - checkout scm - impl = load('pipeline.groovy') +Map taskGenSerlio() { + return cepl.generateTasks('srl-bld', this.&taskBuildSerlio, CONFIGS) } -stage('serlio') { - impl.pipeline() +Map taskGenSerlioTests() { + return cepl.generateTasks('srl-tst', this.&taskBuildSerlioTests, TEST_CONFIGS) } + +Map taskGenSerlioInstallers() { + return cepl.generateTasks('srl-msi', this.&taskBuildSerlioInstaller, INSTALLER_CONFIG) +} + +// -- TASK BUILDERS + +def taskSourceCheckout(cfg) { + cepl.cleanCurrentDir() + papl.checkout(REPO, env.BRANCH_NAME, REPO_CREDS) + stash(name: SOURCE_STASH) +} + +def taskBuildCMake(cfg, target){ + final List deps = [ cfg.maya ] + List defs = [ + [ key: 'maya_DIR', val: cfg.maya.p ], + [ key: 'SRL_VERSION_BUILD', val: env.BUILD_NUMBER ] + ] + cepl.cleanCurrentDir() + unstash(name: SOURCE_STASH) + deps.each { d -> papl.fetchDependency(d, cfg) } + papl.jpe.dir(path: 'build') { + papl.runCMakeBuild(SOURCES, target, cfg, defs) + } +} + +def taskBuildSerlio(cfg) { + final String appName = 'serlio' + + taskBuildCMake(cfg, BUILD_TARGET) + def buildProps = papl.jpe.readProperties(file: 'build/deployment.properties') + final String artifactPattern = "${buildProps.package_file}.*" + + if(cfg.os == cepl.CFG_OS_WIN10){ + dir(path: 'build'){ + stashFile = cepl.findOneFile(artifactPattern) + stash(includes: artifactPattern, name: cfg.grp) + stashPath = "${stashFile.path}" + echo("file path to stash: '${stashPath}'") + } + } + + final def artifactVersion = { p -> buildProps.package_version_base } + + // TODO: abusing grp again to label artifact + def classifierExtractor = { p -> + return cepl.getArchiveClassifier(cfg) + '-' + cfg.grp + } + papl.publish(appName, env.BRANCH_NAME, artifactPattern, artifactVersion, cfg, classifierExtractor) +} + +def taskBuildSerlioTests(cfg) { + final String appName = 'serlio-test' + taskBuildCMake(cfg, 'build_and_run_tests') + papl.jpe.junit('build/test/serlio_test_report.xml') +} + +def taskBuildSerlioInstaller(cfg) { + final String appName = 'serlio-installer' + cepl.cleanCurrentDir() + unstash(name: SOURCE_STASH) + + String antArgs = "" + + // fetch outputs from builds + dir(path: 'build'){ + dir(path: 'tmp'){ + INSTALLER_MAYA_VERS.each { mv -> + unstash(name: mv) + def zipFile = cepl.findOneFile("*${mv}*.zip") + final String zipFileName = zipFile.name + unzip(zipFile: zipFileName) + antArgs += "-D\"${mv}.dir\"=..\\..\\build\\tmp\\${zipFileName.take(zipFileName.lastIndexOf('.'))} " + } + } + } + antArgs += "-D\"serlio.version.build\"=${env.BUILD_NUMBER} " + antArgs += "-D\"build.dir\"=..\\..\\build " + antArgs += "-D\"out.folder\"=out " + antArgs += "-f serlio.git\\deploy" + + // Toolchain definition for building MSI installers. + final JenkinsTools compiler = cepl.getToolchainTool(cfg) + final def toolchain = [ + new ToolInfo(JenkinsTools.ANT, cfg), + new ToolInfo(JenkinsTools.NINJA, cfg), + new ToolInfo(JenkinsTools.WIX, cfg), + new ToolInfo(compiler, cfg) + ] + + // Setup environment according to above toolchain definition. + withTool(toolchain) { + psl.runAnt(antArgs) + + def buildProps = papl.jpe.readProperties(file: 'build/build_msi/deployment.properties') + final String artifactPattern = "out/${buildProps.package_file}.*" + final def artifactVersion = { p -> buildProps.package_version_base } + + // TODO: abusing grp again to label artifact + def classifierExtractor = { p -> + return cepl.getArchiveClassifier(cfg) + } + papl.publish(appName, env.BRANCH_NAME, artifactPattern, artifactVersion, cfg, classifierExtractor) + } +} \ No newline at end of file diff --git a/README.md b/README.md index 44ba75ad..315131bd 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,28 @@ # ![](doc/img/serlio_32.png) Serlio - CityEngine Plugin for Autodesk Maya -Serlio is a plugin for [Autodesk Maya](https://www.autodesk.com/maya). It provides a modifier node which enables the execution of [CityEngine](http://www.esri.com/software/cityengine) ‘rules’ within a Maya scene. Therefore, a 3D environment artist does not have to leave their familiar Maya toolset anymore to make use of CityEngine’s procedural modeling power. Complicated export-import pipelines are no longer needed, which also means that the procedural building models do not need to be “baked” anymore. The buildings stay procedural during the entire modeling workflow. Consequently, the 3D environment artist can change the height, style and appearance of buildings easily with a parametric interface at any point during production. +Serlio is a plugin for [Autodesk Maya](https://www.autodesk.com/maya). It provides a modifier node which enables the execution of [CityEngine](https://www.esri.com/software/cityengine) ‘rules’ within a Maya scene. Therefore, a 3D environment artist does not have to leave their familiar Maya toolset anymore to make use of CityEngine’s procedural modeling power. Complicated export-import pipelines are no longer needed, which also means that the procedural building models do not need to be “baked” in future. The buildings stay procedural during the entire modeling workflow. Consequently, the 3D environment artist can change many attributes, for example the height, style and appearance of buildings can be altered easily with a parametric interface at any point during production. Serlio requires so-called rule packages (RPK) as input, which are authored in CityEngine. An RPK includes assets and a CGA rule file which encodes an architectural style. Comprehensive RPK examples are available below and can be used “out-of-the-box” in Serlio. -Serlio is well suited for managing the procedural generation of architectural 3D content in digital sets. However, Serlio is restricted to the procedural generation of single buildings / objects. Serlio does not include the city layouting and street network editing tools of CityEngine i.e. the rich CityEngine toolset to design a city from scratch (or based on geographic data) is still needed. +Serlio is well suited for managing the procedural generation of architectural 3D content in digital sets. However, Serlio is restricted to the procedural generation of singular objects - particularly buildings. Serlio does not include the city layouting and street network editing tools of CityEngine i.e. the rich CityEngine toolset to design a city from scratch (or based on geographic data) is still needed. -*Serlio is free for non-commercial use.* Commercial use requires at least one commercial license of the latest CityEngine version installed in the organization. No redistribution is allowed. Please refer to the licensing section below for more detailed licensing information. -## Documentation -* [Home Page with Examples](https://esri.github.io/cityengine/serlio) -* [Installation and Quick Start](doc/usage.md) -* [Building Serlio](doc/build.md) -* [ChangeLog](doc/changelog.md) +## Quick Start +1. Install Serlio by downloading the latest [installer](https://github.com/Esri/serlio/releases/latest). Please see [below](#linux-2) for installation on Linux. +1. Start Maya, a new `Serlio` menu item will appear. +1. In Maya, select a mesh and use the `Serlio` menu to assign a rule package (RPK), for example [this one](/doc/data/extrude.rpk) which creates a simple extrusion based on a "height" parameter. You can [author your own RPKs with CityEngine](https://doc.arcgis.com/en/cityengine/latest/help/help-rule-package.htm). +1. Make sure the geometry is still selected and go to the `serlio` tab in the Attribute editor. Here you can edit the rule parameters. + +## Table of Contents + +* [User Manual](#user-manual) +* [Examples](https://esri.github.io/cityengine/serlio) +* [Developer Manual](#developer-manual) +* [Release Notes](#release-notes) +* [Known Limitations](#known-limitations) +* [Licensing information](#licensing-information) External documentation: * [CityEngine Tutorials](https://doc.arcgis.com/en/cityengine/latest/tutorials/introduction-to-the-cityengine-tutorials.htm) @@ -22,9 +30,275 @@ External documentation: * [CityEngine Manual](https://doc.arcgis.com/en/cityengine/latest/help/cityengine-help-intro.htm) * [CityEngine SDK API Reference](https://esri.github.io/cityengine-sdk/html/index.html) +## User Manual +Please refer to the [release notes](#release-notes) for the supported CityEngine version. +### Installation + +#### Software Requirements +- Windows 10 and 11 (64bit) +- CityEngine 2021.1 or older +- Autodesk Maya 2019, 2020 or 2022 + +#### Windows: Provided Installer +1. Download the MSI installer for the latest [release](https://github.com/Esri/serlio/releases/latest). +1. Run the MSI installer. +1. Start Maya. +1. You should now see the new menu item `Serlio`. + +#### Linux: Provided Binaries +1. Acquire the Serlio binaries for the latest [release](https://github.com/Esri/serlio/releases/latest). +2. Continue with the [steps linked below](#linux-2) in the developer documentation. + +### Using the Serlio plugin +#### Add rule files +1. Create and select a polygon mesh. +1. Go to the `Serlio` menu and select "Attach CityEngine Rule Package". +1. Select a `.rpk` rule file: + 1. Use [this basic rule](/doc/data/extrude.rpk) which creates a simple extrusion based on a "height" parameter + 1. Use a rule from the [examples](https://esri.github.io/cityengine/serlio#examples) + 1. [Export your own rule file from CityEngine](https://doc.arcgis.com/en/cityengine/latest/help/help-rule-package.htm). +1. The selected rule will be applied to the mesh. It depends on the rule how multiple faces are handled. + +#### Remove rule files +1. Select the generated model(s). +1. Go to the `Serlio` menu and select "Remove CityEngine Rule Package". +1. Only the initial shape mesh with default materials remains. + +#### Creating materials +Currently we only support one material type per mesh (see [known limitations](#known-limitations)). + +##### Viewport (Stingray) materials +1. Select the generated model(s). +1. Go to the `Serlio` menu and select "Create Materials". +1. The materials for all selected models will be generated and displayed in the viewport. + +##### Arnold materials +1. Select the generated model(s). +1. Go to the `Serlio` menu and select "Create Arnold Materials". +1. The Arnold materials for all selected models will be generated. +1. Add a light source from "Arnold" > "Lights". +1. In order to see the rendered view either: + * Render the current frame once: "Arnold" > "Render" or + * Switch the renderer in the Viewport to "Arnold" and hit the start button. + +#### Working with Attributes in the inspector +1. Select a generated model in the Viewport or the Outliner. +1. Go to the `Serlio` tab in Attribute Editor. +1. Change the rule, seed and rule attributes in the Attribute Editor. +1. The model will update according to the new attribute values. +1. Use the arrow on the right of an attribute to reset the attribute to its default value. The default value might depend on the seed and/or other attributes. + +## Developer Manual + +### Software Requirements + +#### All Platforms +* License for CityEngine (2019.0 or later), e.g. to author Rule Packages. +* CMake 3.13 or later (http://www.cmake.org) +* Autodesk Maya 2019, 2020 or 2022 or the corresponding development kit + +#### Windows +* Windows 7, 8.1 or 10 (64bit) +* Required C++ compiler: Visual Studio 2019 with Toolset MSVC 14.27 or later +* WiX Toolset 3.11.1: Optional, required for building .msi installers + +#### Linux +* RedHat Enterprise Linux 7.x or compatible +* Required C++ compiler: GCC 9.3 or later (RedHat Enterprise Linux DevToolSet 9.1) + +### Build Instructions + +#### Windows + +##### Building with Visual Studio +1. Open a Visual Studio x64 Command Shell in the `serlio` root directory, i.e. at `\esri-cityengine-sdk\examples\serlio`. +2. Create a build directory with `mkdir build` and change into it with `cd build`. +3. Run `cmake` to generate a Visual Studio solution: + ``` + cmake -G "Visual Studio 16 2019" ../src + ``` + Use options `-Dprt_DIR=\cmake` and `-Dmaya_DIR=` to override the default locations of CityEngine SDK and Maya. +1. Open the generated `serlio_parent.sln` in Visual Studio. +2. Switch the solution configuration to "Release" or "RelWithDebInfo" ("Debug" is not supported). +3. Call `build` on the `INSTALL` project. +1. Proceed with the Installation Instructions below. + +##### Building on the Command Line +1. Open a Visual Studio x64 Command Shell in the `serlio` root directory, i.e. at `\esri-cityengine-sdk\examples\serlio`. +2. Create a build directory with `mkdir build` and change into it with `cd build`. +3. Run `cmake` to generate the Makefiles: + ``` + cmake -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=RelWithDebInfo ../src + ``` + Use options `-Dprt_DIR=\cmake` and `-Dmaya_DIR=` to override the default locations of CityEngine SDK and Maya. +4. Run make to build the desired target, e.g. + ``` + nmake install + ``` +5. The build result will appear in the `install` directory in parallel to the `build` directory. We will use this as the plugin directory below. + +##### Building MSI Installers +1. WiX Toolset 3 (3.11.1 or later) and Apache Ant (1.10.x or later) is required for building MSI installers. +2. Start by building Serlio with release configurations as described above. +3. Open a Command Shell in the `serlio\deploy` directory. +4. Run `ant` in the current directioy. Make sure to set at least one valid install path: + ``` + ant -D"maya2022.dir"=../install + ``` +5. The installer will appear in `serlio\build\build_msi`. + +#### Linux +1. Open a terminal (e.g. bash). +1. Change into the example directory: `cd /esri-cityengine-sdk/examples/serlio` +1. Create a build directory and change into it: `mkdir build && cd build` +1. Run cmake (adjust the Maya path if necessary): `cmake -Dmaya_DIR=/usr/autodesk/maya2022 ../src` +1. Compile: `make install` +1. The build result will appear in the `install` directory in parallel to the `build` directory. We will use this as the plugin directory below. + +### Install local build +#### Windows +1. Locate the `install` directory where you [built](build.md) the plugin, let's call it `PLUGINDIR`. +1. Locate the Maya.env file in your home, usually its in `\Documents\maya\2020`. +1. Edit Maya.env as follows: + ``` + :: replace with the actual path + PATH=\plug-ins;%PATH% + MAYA_PLUG_IN_PATH=\plug-ins + MAYA_SCRIPT_PATH=\scripts + XBMLANGPATH=\icons + ``` +1. Start Maya. +1. Open the plugin manager: "Windows" -> "Settings/Preferences" > "Plug-in Manager". +1. Enable `serlio.mll`. +1. The plugin should load and a new menu item `Serlio` should appear in Maya. + +#### Linux +1. Let's call the directory with the Serlio binaries `PLUGINDIR` (downloaded binaries or locally built `install` folder). +1. Locate the Maya.env file in your home, e.g.: `~/maya/2020/Maya.env`. +1. Edit Maya.env as follows: + ``` + PLUGINDIR= # replace with the actual path + MAYA_PLUG_IN_PATH=$PLUGINDIR/plug-ins + MAYA_SCRIPT_PATH=$PLUGINDIR/scripts + XBMLANGPATH=$PLUGINDIR/icons/%B + ``` +1. Start Maya (Note: you may want to start Maya from a shell to see the Serlio log output). +1. Open the plugin manager: "Windows" > "Settings/Preferences" > "Plug-in Manager". +1. Enable `serlio.so`. +1. The plugin should load and a new menu item `Serlio` should appear in Maya. + +## Release Notes + +### v2.0.0 (2022-06-20) +Required CityEngine version: 2021.1 or older. +#### Added: +* Support for Maya 2020 and 2022. (#73) +* Command to remove Serlio nodes and materials from mesh. +* Support and UI for resetting user-set attributes. (#50) +* Support for dynamic enums. +* Support for RGB-based opacity maps. (#15, #33, #18) +* Support for legacy usage of the _@Range_ annotation +* UX to display warnings and errors in rule files: + * RPK/CGB and PRT version mismatch + * Asset errors + * CGA errors + * Generate errors +* Help tab with links to: + * Serlio Website + * CGA Reference + * RPK Manual +* About dialog with version number and license info. +* Node Behavior and UUID tab to attributes + +#### Changed: +* Updated Procedural Runtime (PRT) to 2.6 (corresponds to CityEngine 2021.1) and exclude non-relevant extensions. +* Avoid unpacking of rule package (performance improvement). (#74) +* Improved rule attribute ordering (matching CityEngine). +* Stopped supporting generation of rules without Maya construction history. +* Automatically switch viewport to textured mode after generating materials. +* Replace rule package instead of stacking Serlio nodes, when calling "Add rule package..". (#13) +* Improved UI feedback on node for invalid rule package paths +* Improved generation performance. +* Fixed metadata storage on scene save/load +* Fixed scaling of geometry. +* Fixed random seed handling. (#51) +* Fixed rule package reloading, when start rule changes. (#17) +* Fixed undo/redo for material creation and rule switching. +* Fixed crash in case PRT generates an empty mesh. +* Fixed crash when modifying rule package path. +* Reset material to default, when PRT generates an empty mesh. +* Fixed enum attributes. (#23) +* Fixed file picker. (#55) +* Fixed error message in MEL console. +* Fixed faintly visible transparent stingray materials. +* Fixed Maya attribute naming issues. +* Fixed bug that could create duplicate tweak nodes. + +#### Development: +* Updated compilers (now using C++ 17) +* Updated test framework and build system +* Bundled installers for all Maya versions (2019-2022) into one + +#### Examples: +* Added Street Segment example +* Updated Favela example + +### v1.1.0 (2020-06-02) +* BREAKING CHANGE: Switched to official Autodesk IDs for Serlio custom nodes. (#26) +* Added creation of Arnold materials. (#11, #40, #65) +* Correctly compute default values of rule attributes based on initial shape geometry. +* Show error message if required Maya plugins (e.g. 'shaderFXPlugin') are not loaded. (#65) +* Updated to CityEngine SDK 2019.1. (#42) +* Introduced clang-format. (#37) + +### v1.0.1 (2019-08-21) +* Merged support for creating MSI installers via CMake. +* Fixed wrong build type of codec library in MSI installers. +* Improved error handling when loading the plugin (check codec library). +* Do not install unnecessary PRT codecs for Serlio. +* Improved error handling (prevent crash) if a specified Rule Package (RPK) is not readable. + +### v1.0.0 (2019-07-31) +* Optimized the encoding of PRT geometry with many meshes (e.g. results in a speedup of about 5x for the "Parthenon" CityEngine example). +* Do not change Maya selection after user touches the attribute sliders. +* Do not pass Maya's automatically created color child attributes to PRT. + +### v1.0.0-beta.1 (2019-07-26) +* Added attribute sorting in the Maya node editor like in CityEngine. +* Fixed saving of string rule attributes in Maya scene. +* Fixed connectivity of generated meshes and normal orientation. +* Fixed handling of rule attribute annotations (enum, range). +* Fixed tex-coords handling in case some meshes do not have any. +* Performance optimizations. +* Rebranding to "Serlio" in UI. +* Publication of source code on github. + +### v0.5.0 (2019-06-12) +* First release after complete rewrite based on Maya "modifier node" example. +* Better UX and conformance with behavior of other Maya geometry tools (e.g. undo). +* Improved performance and Material support. + +### v0.0.0 (2012-2018) +* Experimental Maya plugin released as source code example for CityEngine SDK. + +## Known Limitations + +* Serlio 2.0: In Maya 2019 on Windows, Serlio does not support reading USD assets from RPKs. +* Modifying the input shape after a Serlio node is attached is not supported. +* Scaling transformations on the initial shape mesh will scale the entire generated model. Make sure that all scaling transformations on the initial shape mesh are frozen before applying a rule ("Modify" > "Freeze Transformations"). +* Maya uses centimeters as default working units, we recommend changing these to meters in + "Windows" > "Settings/Preferences" > "Preferences" > "Settings" > "Working Units". + * We also recommend multiplying the value of the "Near Clip Plane" and "Far Clip Plane" attributes in the `perspShape` of the perspective camera by a factor of 100. +* Duplicating a generated Serlio building multiple times with copy/paste can lead to wrong materials due to a naming bug in Maya. However, there are two workarounds: + 1. Use smart duplicate instead: Go to "Edit" > "Duplicate Special" and tick "Assign unique name to children nodes". + 1. Manually rename all pasted meshes to something unique and regenerate the rule. + +## Licensing Information + +Serlio is free for personal, educational, and non-commercial use. Commercial use requires at least one commercial license of the latest CityEngine version installed in the organization. Redistribution or web service offerings are not allowed unless expressly permitted. -## Licensing +Serlio is under the same license as the included [CityEngine SDK](https://github.com/esri/cityengine-sdk#licensing). An exception is the Serlio source code (without CityEngine SDK, binaries, or object code), which is licensed under the Apache License, Version 2.0 (the “License”); you may not use this work except in compliance with the License. You may obtain a copy of the License at https://www.apache.org/licenses/LICENSE-2.0 -Serlio is under the same license as the included [CityEngine SDK](https://github.com/Esri/esri-cityengine-sdk#licensing). +All content in the [Examples](https://esri.github.io/cityengine/serlio#examples) directory/section is licensed under the APACHE 2.0 license as well. -An exception is the Serlio source code (without CityEngine SDK, binaries, or object code), which is licensed under the Apache License, Version 2.0 (the “License”); you may not use this work except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0. +For questions or enquiries regarding licensing, please contact the Esri CityEngine team (cityengine-info@esri.com). diff --git a/build.ps1 b/build.ps1 index 79ec13a1..8ce94b51 100644 --- a/build.ps1 +++ b/build.ps1 @@ -1,5 +1,5 @@ param( -# Target. One of 'All', 'Archive', 'Installer' plus the optional suffix 'FromScratch'. +# Target. One of 'All', 'Archive' plus the optional suffix 'FromScratch'. [String]$TARGET = 'AllFromScratch', # Release With Debug Info yes/no. (Ignored by installer builds.) [Bool]$DEBUGINFO = $false, @@ -12,7 +12,6 @@ param( # Default download locations for required tools. May be overwritten if desired. [String]$BUILD_NINJA_URL = 'https://github.com/ninja-build/ninja/releases/download/v1.9.0/ninja-win.zip', [String]$CMAKE_URL = 'https://github.com/Kitware/CMake/releases/download/v3.15.0/cmake-3.15.0-win64-x64.zip', -[String]$WIX_TOOLSET_URL = 'https://github.com/wixtoolset/wix3/releases/download/wix3111rtm/wix311-binaries.zip' ) Set-StrictMode -Version Latest @@ -21,18 +20,15 @@ Set-StrictMode -Version Latest $BUILD_FOLDER = "$PSScriptRoot\build" $TOOLS_FOLDER = "$BUILD_FOLDER\tools" $ARCHIVE_BUILD_FOLDER = "$BUILD_FOLDER\build_zip" -$INSTALLER_BUILD_FOLDER = "$BUILD_FOLDER\build_msi" $ARTIFACTS_FOLDER = "$BUILD_FOLDER\out" # Folders for the build tools $NINJA_FOLDER = "$TOOLS_FOLDER\ninja" $CMAKE_FOLDER = "$TOOLS_FOLDER\cmake" -$WIX_FOLDER = "$TOOLS_FOLDER\wix" # Relevant executables $NINJA_EXE = 'ninja.exe' $CMAKE_EXE = 'cmake.exe' -$WIX_EXE = 'candle.exe' function NukeAll { NukeFolder($BUILD_FOLDER) @@ -46,14 +42,13 @@ function NukeTools { function NukeBuilds { NukeFolder($ARCHIVE_BUILD_FOLDER) - NukeFolder($INSTALLER_BUILD_FOLDER) NukeFolder($ARTIFACTS_FOLDER) Write-Host ">>> Folder structure for builds destroyed." -ForegroundColor Green } function MakeDirs { # Create the desired folder structure. - $folders = $BUILD_FOLDER, $TOOLS_FOLDER, $NINJA_FOLDER, $CMAKE_FOLDER, $WIX_FOLDER, $ARCHIVE_BUILD_FOLDER, $INSTALLER_BUILD_FOLDER, $ARTIFACTS_FOLDER + $folders = $BUILD_FOLDER, $TOOLS_FOLDER, $NINJA_FOLDER, $CMAKE_FOLDER, $ARCHIVE_BUILD_FOLDER, $ARTIFACTS_FOLDER foreach ($f in $folders) { if (!(Test-Path $f)) { New-Item -ItemType Directory -Path $f | Out-Null @@ -65,7 +60,6 @@ function MakeDirs { function FetchTools { $ninja = Triple $BUILD_NINJA_URL $NINJA_FOLDER $NINJA_EXE $cmake = Triple $CMAKE_URL $CMAKE_FOLDER $CMAKE_EXE - $wix = Triple $WIX_TOOLSET_URL $WIX_FOLDER $WIX_EXE $tool_list = @() Write-Host ">>> Fetching tools..." -ForegroundColor Green @@ -81,13 +75,6 @@ function FetchTools { $tool_list += ,$cmake } - if ($WIX_ON_PATH) { - Write-Host ">>>>> WIX already on PATH. Skipping!" -ForegroundColor Green - } else { - $tool_list += ,$wix - } - - foreach ($t in $tool_list) { $u = $t.Item1 $archive = $u.Split('/') | Select-Object -Last 1 @@ -130,14 +117,6 @@ function SetupEnv { $path += "$cmakePath;" } - if ($WIX_ON_PATH) { - Write-Host ">>>>> WIX already on PATH. Skipping." -ForegroundColor Green - } else { - $wixPath = FindFile 'candle.exe' $WIX_FOLDER - Write-Host ">>>>> Found candle.exe in $wixPath. Good!" -ForegroundColor Green - $path += "$wixPath;" - } - $env:Path = "$path$env:Path" } @@ -166,30 +145,6 @@ function BuildArchive { Set-Location -Path $cwd } -function BuildInstaller { - Write-Host ">>> Building MSI installer...!" -ForegroundColor Green - $cwd = Get-Location - Set-Location -Path $INSTALLER_BUILD_FOLDER - # Call cmake - Write-Host ">>>>> Calling 'cmake' now." -ForegroundColor Green - $mdir = If ([System.String]::IsNullOrWhiteSpace($MAYA_DIR)) { "" } else { "-Dmaya_DIR='$MAYA_DIR'" } - $cesdkdir = If ([System.String]::IsNullOrWhiteSpace($CESDK_DIR)) { "" } else { "-Dprt_DIR='$CESDK_DIR'" } - cmake -G Ninja -DWIN_INSTALLER=True $mdir $cesdkdir -DSRL_VERSION_BUILD="$BUILD_NO" -DCMAKE_BUILD_TYPE=Release ../../src - # ...and ninja - Write-Host ">>>>> Calling 'ninja' now." -ForegroundColor Green - ninja package - # Move the built installer to the out folder - $installer = FindFile '*.msi' $INSTALLER_BUILD_FOLDER - if($installer) { - Move-Item -Path "$INSTALLER_BUILD_FOLDER\*.msi" -Destination $ARTIFACTS_FOLDER -Force - Write-Host ">>>>> Installer build done. MSI can be found in $ARTIFACTS_FOLDER\." -ForegroundColor Green - } else { - Write-Host ">>>>> Strange, no .msi found..." -ForegroundColor Red - throw 'Installer build failed.' - } - Set-Location -Path $cwd -} - ## Do it! function DoIt { if ($TARGET.EndsWith('FromScratch')) { @@ -207,9 +162,6 @@ function DoIt { FetchTools SetupEnv - if($TARGET.StartsWith('All') -or $TARGET.StartsWith('Installer')) { - BuildInstaller - } if($TARGET.StartsWith('All') -or $TARGET.StartsWith('Archive')) { BuildArchive } @@ -288,7 +240,6 @@ $ErrorActionPreference = "Stop" $NINJA_ON_PATH = ExeOnPath $NINJA_EXE # VS Command Prompt also puts cmake on PATH, but it's an older version than required. $CMAKE_ON_PATH = ExeOnPath $CMAKE_EXE '3.13' -$WIX_ON_PATH = ExeOnPath $WIX_EXE # Do the build. DoIt diff --git a/deploy/PackageContents.xml.in b/deploy/PackageContents.xml.in index 5027bb7d..0f99d84b 100644 --- a/deploy/PackageContents.xml.in +++ b/deploy/PackageContents.xml.in @@ -1,52 +1,50 @@ - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + diff --git a/deploy/build.xml b/deploy/build.xml new file mode 100644 index 00000000..56b14f8e --- /dev/null +++ b/deploy/build.xml @@ -0,0 +1,144 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/deploy/cpack_installer.cmake b/deploy/cpack_installer.cmake deleted file mode 100644 index 1757f5cf..00000000 --- a/deploy/cpack_installer.cmake +++ /dev/null @@ -1,50 +0,0 @@ -# setup wix installer -include(${CMAKE_CURRENT_LIST_DIR}/cpack_common.cmake) - -# Windows installer needs slightly different folder layout -set(INSTALL_FOLDER_PREFIX "Contents/${maya_VERSION_MAJOR}") - -set(CPACK_GENERATOR WIX) - -# UPGRADE_GUID. This GUID must remain constant, it helps the installer -# to identify different (previous) installations of the same software. -# The GUID must be different for different Maya versions to allow for -# side-by-side installations. -set(CPACK_WIX_UPGRADE_GUID "9B170749-ECDF-4F66-9E2F-C9045727${maya_VERSION_MAJOR}") - -set(CPACK_WIX_PRODUCT_GUID "*") - -# This sets the path to the license file explicitly. If not set, it -# defaults to CPACK_RESOURCE_FILE_LICENSE, which we could use instead. -set(CPACK_WIX_LICENSE_RTF "${CMAKE_CURRENT_LIST_DIR}/resources/license.rtf") - -# (1) Installer Icon -set(CPACK_WIX_PRODUCT_ICON "${CMAKE_CURRENT_LIST_DIR}/resources/serlio.ico") -# -# (2) Banner, visible on all Wizard pages except first and last. Must be 493x58 pixels. -set(CPACK_WIX_UI_BANNER "${CMAKE_CURRENT_LIST_DIR}/resources/banner.png") -# -# (3) Dialog background, appears on first and last page of the Wizard. Must be 493x312 pixels. -set(CPACK_WIX_UI_DIALOG "${CMAKE_CURRENT_LIST_DIR}/resources/dialog.png") - -# XML doesn't like naked '&'. -set(PACKAGE_VENDOR_ESCAPED "Esri R&D Center Zurich") -set(CPACK_WIX_SKIP_PROGRAM_FOLDER true) - -# Fill in the PackageContents template -configure_file(${CMAKE_CURRENT_LIST_DIR}/PackageContents.xml.in ${PROJECT_BINARY_DIR}/PackageContents.xml) - -# We need to overwrite a couple of variables from cpack_common because slightly different values are required. -set(CPACK_PACKAGE_INSTALL_DIRECTORY "C:/ProgramData/Autodesk/ApplicationPlugins/serlio-${SRL_VERSION_MMP_PRE}") - -# Careful: CPACK_PACKAGE_NAME is also used in the PackageContents.xml template above. -# Make sure that this line always appears after the 'configure_file' directive. -set(CPACK_PACKAGE_NAME "Serlio for Maya ${maya_VERSION_MAJOR}") -# We need to set the CPACK_PACKAGE_VERSION to a format that MSI understands (MAJOR.MINOR.PATCH). -set(CPACK_PACKAGE_VERSION ${SRL_VERSION_MMP}) - -# Add it to the WiX installer. -install(FILES ${PROJECT_BINARY_DIR}/PackageContents.xml DESTINATION "/") - -# Inject patch to force root drive to C:\ (see https://stackoverflow.com/a/52561165/1097883) -set(CPACK_WIX_PATCH_FILE "${CMAKE_CURRENT_LIST_DIR}/wix_patches/force_rootdrive.wxpatch") \ No newline at end of file diff --git a/deploy/resources/banner.png b/deploy/resources/banner.png index 07f23afa..7cf015c4 100644 Binary files a/deploy/resources/banner.png and b/deploy/resources/banner.png differ diff --git a/deploy/resources/dialog.png b/deploy/resources/dialog.png index 1dcfd00d..52b75c35 100644 Binary files a/deploy/resources/dialog.png and b/deploy/resources/dialog.png differ diff --git a/deploy/resources/serlio.ico b/deploy/resources/serlio.ico index bb14afb3..f0064c94 100644 Binary files a/deploy/resources/serlio.ico and b/deploy/resources/serlio.ico differ diff --git a/deploy/serlio.wxs.in b/deploy/serlio.wxs.in new file mode 100644 index 00000000..a1093d54 --- /dev/null +++ b/deploy/serlio.wxs.in @@ -0,0 +1,47 @@ + + + + + + + + + + + + + ProductIcon.ico + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/deploy/wix_patches/force_rootdrive.wxpatch b/deploy/wix_patches/force_rootdrive.wxpatch deleted file mode 100644 index 4e3290d5..00000000 --- a/deploy/wix_patches/force_rootdrive.wxpatch +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/doc/build.md b/doc/build.md deleted file mode 100644 index eadca2da..00000000 --- a/doc/build.md +++ /dev/null @@ -1,79 +0,0 @@ -# Build Serlio from Source - - -## Software Requirements - -### All Platforms -* License for CityEngine (2019.0 or later), e.g. to author Rule Packages. -* CMake 3.13 or later (http://www.cmake.org) -* Autodesk Maya 2018 or 2019 installation or the corresponding development kit - -### Windows -* Windows 7, 8.1 or 10 (64bit) -* Required C++ compiler: Visual Studio 2017 with Toolset MSVC 14.11 or later -* WiX Toolset 3.11.1: Optional, required for building .msi installers -* Required flags for extension libraries release mode: `/bigobj /GR /EHsc /MD` - -### Linux -* RedHat Enterprise Linux 7.x or compatible -* Required C++ compiler: GCC 6.3 or later (RedHat Enterprise Linux DevToolSet 6.1) -* Required flags for extension libraries: `-std=c++14 -D_GLIBCXX_USE_CXX11_ABI=0 -march=nocona -fvisibility=hidden -fvisibility-inlines-hidden -Wl,--exclude-libs,ALL` - - -## Build Instructions - -### Windows - -#### Quick build for the impatient -1. Open a Visual Studio 2017 x64 Command Shell in the `serlio` root directory. -2. Call `powershell .\build.ps1`. - -#### Building with Visual Studio -1. Open a Visual Studio 2017 x64 Command Shell in the `serlio` root directory, i.e. at `\esri-cityengine-sdk\examples\serlio`. -2. Create a build directory with `mkdir build` and change into it with `cd build`. -3. Run `cmake` to generate a Visual Studio solution: - ``` - cmake -G "Visual Studio 15 2017 Win64" ../src - ``` - Use options `-Dprt_DIR=\cmake` and `-Dmaya_DIR=` to override the default locations of CityEngine SDK and Maya. -1. Open the generated `serlio_parent.sln` in Visual Studio. -2. Switch the solution configuration to "Release" or "RelWithDebInfo" ("Debug" is not supported with release CE SDK). -3. Call `build` on the `INSTALL` project. -1. Proceed with the Installation Instructions below. - -#### Building on the Command Line -1. Open a Visual Studio 2017 x64 Command Shell in the `serlio` root directory, i.e. at `\esri-cityengine-sdk\examples\serlio`. -2. Create a build directory with `mkdir build` and change into it with `cd build`. -3. Run `cmake` to generate the Makefiles: - ``` - cmake -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=RelWithDebInfo ../src - ``` - Use options `-Dprt_DIR=\cmake` and `-Dmaya_DIR=` to override the default locations of CityEngine SDK and Maya. -4. Run make to build the desired target, e.g. - ``` - make install - ``` -5. The build result will appear in the `install` directory in parallel to the `build` directory. We will use this as the plugin directory below. - -#### Building MSI Installers -1. WiX Toolset 3 (3.11.1 or better) is required for building MSI installers. -2. Open a Visual Studio 2017 x64 Command Shell in the `serlio` root directory, i.e. at `\esri-cityengine-sdk\examples\serlio`. -2. Create a build directory with `mkdir build_installers` and change into it with `cd build_installers`. -3. Run `cmake` to generate the Makefiles. Make sure to set `WIN_INSTALLER` to `True`: - ``` - cmake -G "NMake Makefiles" -DWIN_INSTALLER=True -DCMAKE_BUILD_TYPE=Release ../src - ``` - Use options `-Dprt_DIR=\cmake` and `-Dmaya_DIR=` to override the default locations of CityEngine SDK and Maya. -4. Run make to build the package target, i.e. - ``` - make package - ``` -5. The installer will appear in `build_installers`. - -### Linux -1. Open a terminal (e.g. bash) -1. Change into the example directory: `cd /esri-cityengine-sdk/examples/serlio` -1. Create a build directory and change into it: `mkdir build && cd build` -1. Run cmake (adjust the maya path if necessary): `cmake -Dmaya_DIR=/usr/autodesk/maya2018 ../src` -1. Compile: `make install` -1. The build result will appear in the `install` directory in parallel to the `build` directory. We will use this as the plugin directory below. diff --git a/doc/changelog.md b/doc/changelog.md deleted file mode 100644 index 5ed33369..00000000 --- a/doc/changelog.md +++ /dev/null @@ -1,39 +0,0 @@ -# Serlio ChangeLog - -## v1.1.0 (2020-06-02) -* BREAKING CHANGE: Switched to official Autodesk IDs for Serlio custom nodes. (#26) -* Added creation of Arnold materials. (#11, #40, #65) -* Correctly compute default values of rule attributes based on initial shape geometry. -* Show error message if required Maya plugins (e.g. 'shaderFXPlugin') are not loaded. (#65) -* Updated to CityEngine SDK 2019.1. (#42) -* Introduced clang-format. (#37) - -## v1.0.1 (2019-08-21) -* Merged support for creating MSI installers via CMake. -* Fixed wrong build type of codec library in MSI installers. -* Improved error handling when loading the plugin (check codec library). -* Do not install unnecessary PRT codecs for Serlio. -* Improved error handling (prevent crash) if a specified Rule Package (RPK) is not readable. - -## v1.0.0 (2019-07-31) -* Optimized the encoding of PRT geometry with many meshes (e.g. results in a speedup of about 5x for the "Parthenon" CityEngine example). -* Do not change maya selection after user touches the attribute sliders. -* Do not pass maya's automatically created color child attributes to PRT. - -## v1.0.0-beta.1 (2019-07-26) -* Added attribute sorting in the Maya node editor like in CityEngine. -* Fixed saving of string rule attributes in Maya scene. -* Fixed connectivity of generated meshes and normal orientation. -* Fixed handling of rule attribute annotations (enum, range). -* Fixed tex-coords handling in case some meshes do not have any. -* Performance optimizations. -* Rebranding to "Serlio" in UI. -* Publication of source code on github. - -## v0.5.0 (2019-06-12) -* First release after complete rewrite based on Maya "modifier node" example. -* Better UX and conformance with behavior of other Maya geometry tools (e.g. undo). -* Improved performance and Material support. - -## v0.0.0 (2012-2018) -* Experimental maya plugin released as source code example for CityEngine SDK. \ No newline at end of file diff --git a/doc/data/extrude.rpk b/doc/data/extrude.rpk new file mode 100644 index 00000000..bd8c2116 Binary files /dev/null and b/doc/data/extrude.rpk differ diff --git a/doc/img/serlio_32.png b/doc/img/serlio_32.png index d51bbff7..58f037a0 100644 Binary files a/doc/img/serlio_32.png and b/doc/img/serlio_32.png differ diff --git a/doc/usage.md b/doc/usage.md deleted file mode 100644 index 9b1f1b59..00000000 --- a/doc/usage.md +++ /dev/null @@ -1,48 +0,0 @@ -# Quick Start - -## Installation - -### Windows: Provided Binaries -1. Download the MSI installer for your Maya version (2018 or 2019) from the [desired release](https://github.com/Esri/serlio/releases) -1. Run the MSI installer -1. Start Maya -1. You should now see the new menu item "Serlio". - -### Windows: Compile from Source -1. Locate the `install` directory where you [built](build.md) the plugin, let's call it `PLUGINDIR` -1. Locate the Maya.env file in your home, usually its in `\Documents\maya\2019` -1. Edit Maya.env as follows: - ``` - :: replace with the actual path - PATH=\plug-ins;%PATH% - MAYA_PLUG_IN_PATH=\plug-ins - MAYA_SCRIPT_PATH=\scripts - ``` -1. Start maya -1. Open the plugin manager: Windows -> Settings/Preferences -> Plug-in Manager -1. Enable `serlio.mll` -1. The plugin should load and a new menu item `Serlio` should appear in Maya. - -### Linux -1. Acquire the Serlio binaries, either: - * ... download the [desired release](https://github.com/Esri/serlio/releases) - * ... or [build](build.md) them yourself, which will result in an `install` directory -1. Either way, let's call the directory with the Serlio binaries `PLUGINDIR` -1. Locate the Maya.env file in your home, e.g.: `~/maya/2019/Maya.env` -1. Edit Maya.env as follows: - ``` - PLUGINDIR= # replace with the actual path - MAYA_PLUG_IN_PATH=$PLUGINDIR/plug-ins - MAYA_SCRIPT_PATH=$PLUGINDIR/scripts - ``` -1. Start Maya (Note: you may want to start maya from a shell to see the serlio log output). -1. Open the plugin manager: Windows -> Settings/Preferences -> Plug-in Manager -1. Enable `libserlio.so` -1. The plugin should load and a new menu item `Serlio` should appear in Maya. - -## Usage Instructions - -1. Use CityEngine to export a Rule Package (RPK). -1. In Maya, select a mesh and use the `Serlio` menu to assign the RPK. This will run the rules for each face in the mesh. -1. Use the Hypergraph to navigate to the "serlio" node where you can edit the rule parameters. -1. To create materials, apply one of the two commands in the serlio menu on the generated model. Please note the the two material systems are mutually exclusive at this point. diff --git a/pipeline.groovy b/pipeline.groovy deleted file mode 100644 index b97adac4..00000000 --- a/pipeline.groovy +++ /dev/null @@ -1,150 +0,0 @@ -import groovy.transform.Field -import com.esri.zrh.jenkins.PipelineSupportLibrary -import com.esri.zrh.jenkins.PslFactory -import com.esri.zrh.jenkins.psl.UploadTrackingPsl -import com.esri.zrh.jenkins.JenkinsTools -import com.esri.zrh.jenkins.ToolInfo -import com.esri.zrh.jenkins.ce.CityEnginePipelineLibrary -import com.esri.zrh.jenkins.ce.PrtAppPipelineLibrary - -@Field def psl = PslFactory.create(this, UploadTrackingPsl.ID) -@Field def cepl = new CityEnginePipelineLibrary(this, psl) -@Field def papl = new PrtAppPipelineLibrary(cepl) - - -// -- GLOBAL DEFINITIONS - -@Field final String REPO = 'git@github.com:ArcGIS/serlio.git' -@Field final String REPO_CREDS = 'jenkins-github-serlio-deployer-key' -@Field final String SOURCES = "serlio.git/src" -@Field final String BUILD_TARGET = 'package' - -// TODO: abusing grp field to distinguish maya versions per task -@Field final List CONFIGS = [ - [ os: cepl.CFG_OS_RHEL7, bc: cepl.CFG_BC_REL, tc: cepl.CFG_TC_GCC63, cc: cepl.CFG_CC_OPT, arch: cepl.CFG_ARCH_X86_64, grp: 'maya2018', maya: PrtAppPipelineLibrary.Dependencies.MAYA2018 ], - [ os: cepl.CFG_OS_RHEL7, bc: cepl.CFG_BC_REL, tc: cepl.CFG_TC_GCC63, cc: cepl.CFG_CC_OPT, arch: cepl.CFG_ARCH_X86_64, grp: 'maya2019', maya: PrtAppPipelineLibrary.Dependencies.MAYA2019 ], - [ os: cepl.CFG_OS_WIN10, bc: cepl.CFG_BC_REL, tc: cepl.CFG_TC_VC141, cc: cepl.CFG_CC_OPT, arch: cepl.CFG_ARCH_X86_64, grp: 'maya2018', maya: PrtAppPipelineLibrary.Dependencies.MAYA2018 ], - [ os: cepl.CFG_OS_WIN10, bc: cepl.CFG_BC_REL, tc: cepl.CFG_TC_VC141, cc: cepl.CFG_CC_OPT, arch: cepl.CFG_ARCH_X86_64, grp: 'maya2019', maya: PrtAppPipelineLibrary.Dependencies.MAYA2019 ], -] - -@Field final List TEST_CONFIGS = [ - [ os: cepl.CFG_OS_RHEL7, bc: cepl.CFG_BC_REL, tc: cepl.CFG_TC_GCC63, cc: cepl.CFG_CC_OPT, arch: cepl.CFG_ARCH_X86_64 ], - [ os: cepl.CFG_OS_WIN10, bc: cepl.CFG_BC_REL, tc: cepl.CFG_TC_VC141, cc: cepl.CFG_CC_OPT, arch: cepl.CFG_ARCH_X86_64 ], -] - - -// -- PIPELINE - -@Field String myBranch = env.BRANCH_NAME - -// entry point for standalone pipeline -def pipeline(String branchName = null) { - cepl.runParallel(getTasks(branchName)) -} - -// entry point for embedded pipeline -Map getTasks(String branchName = null) { - if (branchName) myBranch = branchName - - Map tasks = [:] - tasks << taskGenSerlio() - tasks << taskGenSerlioTests() - tasks << taskGenSerlioInstallers() - return tasks -} - - -// -- TASK GENERATORS - -Map taskGenSerlio() { - return cepl.generateTasks('serlio', this.&taskBuildSerlio, CONFIGS) -} - -Map taskGenSerlioTests() { - return cepl.generateTasks('serlio-test', this.&taskBuildSerlioTests, TEST_CONFIGS) -} - -Map taskGenSerlioInstallers() { - return cepl.generateTasks('serlio-installers', this.&taskBuildSerlioInstaller, CONFIGS.findAll { it.os == cepl.CFG_OS_WIN10}) -} - -// -- TASK BUILDERS - -def taskBuildSerlio(cfg) { - final String appName = 'serlio' - final List DEPS = [ PrtAppPipelineLibrary.Dependencies.CESDK, cfg.maya ] - List defs = [ - [ key: 'prt_DIR', val: PrtAppPipelineLibrary.Dependencies.CESDK.p ], - [ key: 'maya_DIR', val: cfg.maya.p ], - [ key: 'SRL_VERSION_BUILD', val: env.BUILD_NUMBER ] - ] - papl.buildConfig(REPO, myBranch, SOURCES, BUILD_TARGET, cfg, DEPS, defs, REPO_CREDS) - - def buildProps = papl.jpe.readProperties(file: 'build/deployment.properties') - final String artifactPattern = "${buildProps.package_file}.*" - final def artifactVersion = { p -> buildProps.package_version_base } - - // TODO: abusing grp again to label artifact - def classifierExtractor = { p -> - return cepl.getArchiveClassifier(cfg) + '-' + cfg.grp - } - papl.publish(appName, myBranch, artifactPattern, artifactVersion, cfg, classifierExtractor) -} - -def taskBuildSerlioTests(cfg) { - final String appName = 'serlio-test' - final List DEPS = [ PrtAppPipelineLibrary.Dependencies.CESDK ] - List defs = [ - [ key: 'prt_DIR', val: PrtAppPipelineLibrary.Dependencies.CESDK.p ], - [ key: 'SRL_VERSION_BUILD', val: env.BUILD_NUMBER ] - ] - - papl.buildConfig(REPO, myBranch, SOURCES, 'build_and_run_tests', cfg, DEPS, defs, REPO_CREDS) - papl.jpe.junit('build/test/serlio_test_report.xml') -} - -def taskBuildSerlioInstaller(cfg) { - final String appName = 'serlio-installer' - cepl.cleanCurrentDir() - papl.checkout(REPO, myBranch, REPO_CREDS) - final List deps = [ PrtAppPipelineLibrary.Dependencies.CESDK, cfg.maya ] - deps.each { d -> papl.fetchDependency(d, cfg) } - - // Toolchain definition for building MSI installers. - final JenkinsTools compiler = cepl.getToolchainTool(cfg) - final def toolchain = [ - new ToolInfo(JenkinsTools.CMAKE313, cfg), - new ToolInfo(JenkinsTools.NINJA, cfg), - new ToolInfo(JenkinsTools.WIX, cfg), - new ToolInfo(compiler, cfg) - ] - - // Setup environment according to above toolchain definition. - withTool(toolchain) { - dir('serlio.git') { - String cmd = JenkinsTools.generateSetupPreamble(this, cfg, toolchain.collect { it.tool }) - cmd += "\n" - cmd += "powershell .\\build.ps1" - cmd += " -MAYA_DIR ${cfg.maya.p.call(cfg)}" // <-- !!! - cmd += " -CESDK_DIR ${PrtAppPipelineLibrary.Dependencies.CESDK.p.call(cfg)}" - cmd += " -BUILD_NO ${env.BUILD_NUMBER}" - cmd += " -TARGET InstallerFromScratch" - - psl.runCmd(cmd) - - def buildProps = papl.jpe.readProperties(file: 'build/build_msi/deployment.properties') - final String artifactPattern = "out/${buildProps.package_file}.*" - final def artifactVersion = { p -> buildProps.package_version_base } - - // TODO: abusing grp again to label artifact - def classifierExtractor = { p -> - return cepl.getArchiveClassifier(cfg) + '-' + cfg.grp - } - papl.publish(appName, myBranch, artifactPattern, artifactVersion, cfg, classifierExtractor) - } - } -} - -// -- make embeddable - -return this diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 32002113..4ebc3789 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -10,8 +10,8 @@ include(common.cmake) ### version -set(SRL_VERSION_MAJOR 1) -set(SRL_VERSION_MINOR 1) +set(SRL_VERSION_MAJOR 2) +set(SRL_VERSION_MINOR 0) set(SRL_VERSION_PATCH 0) if (NOT SRL_VERSION_BUILD) @@ -39,11 +39,7 @@ set(SERLIO_TARGET serlio) set(TEST_TARGET serlio_test) ### configure packaging -if (WIN_INSTALLER) # <-- To be set on the command line - include(${CMAKE_CURRENT_SOURCE_DIR}/../deploy/cpack_installer.cmake) -else () - include(${CMAKE_CURRENT_SOURCE_DIR}/../deploy/cpack_archives.cmake) -endif () +include(${CMAKE_CURRENT_SOURCE_DIR}/../deploy/cpack_archives.cmake) add_subdirectory(codec) add_subdirectory(serlio) diff --git a/src/codec/CMakeLists.txt b/src/codec/CMakeLists.txt index 3c0ee354..1242246f 100644 --- a/src/codec/CMakeLists.txt +++ b/src/codec/CMakeLists.txt @@ -6,7 +6,8 @@ cmake_policy(SET CMP0015 NEW) add_library(${CODEC_TARGET} SHARED CodecMain.cpp - encoder/MayaEncoder.cpp) + encoder/MayaEncoder.cpp + encoder/TextureEncoder.cpp) if (CMAKE_GENERATOR MATCHES "Visual Studio.+") target_sources(${CODEC_TARGET} @@ -22,25 +23,18 @@ target_include_directories(${CODEC_TARGET} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} PRIVATE ${PRT_INCLUDE_PATH}) -target_compile_definitions(${CODEC_TARGET} PRIVATE - -DSRL_VERSION=\"${SRL_VERSION}\" # quoted to use it as string literal - -DPRT_VERSION_MAJOR=${PRT_VERSION_MAJOR} - -DPRT_VERSION_MINOR=${PRT_VERSION_MINOR}) +set_common_target_definitions(${CODEC_TARGET}) if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") target_compile_options(${CODEC_TARGET} PRIVATE -bigobj -GR -EHsc) -elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") - target_compile_options(${CODEC_TARGET} PRIVATE -std=c++14 -stdlib=libc++ -fvisibility=hidden -fvisibility-inlines-hidden -Wl,--exclude-libs,ALL) elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Linux") - target_compile_options(${CODEC_TARGET} PRIVATE -std=c++14 -D_GLIBCXX_USE_CXX11_ABI=0 -march=nocona -fvisibility=hidden -fvisibility-inlines-hidden -Wl,--exclude-libs,ALL) + target_compile_options(${CODEC_TARGET} PRIVATE -D_GLIBCXX_USE_CXX11_ABI=0 -march=nocona -fvisibility=hidden -fvisibility-inlines-hidden -Wl,--exclude-libs,ALL) endif () target_link_libraries(${CODEC_TARGET} ${PRT_LINK_LIBRARIES}) if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") target_link_libraries(${CODEC_TARGET} IPHlpApi Psapi DbgHelp) -elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") - # none elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Linux") target_link_libraries(${CODEC_TARGET} z pthread dl rt) endif () diff --git a/src/codec/CodecMain.cpp b/src/codec/CodecMain.cpp index e5d24b5b..9a706b88 100644 --- a/src/codec/CodecMain.cpp +++ b/src/codec/CodecMain.cpp @@ -3,7 +3,7 @@ * * See https://github.com/esri/serlio for build and usage instructions. * - * Copyright (c) 2012-2019 Esri R&D Center Zurich + * Copyright (c) 2012-2022 Esri R&D Center Zurich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/src/codec/CodecMain.h b/src/codec/CodecMain.h index 713517bb..8996aff3 100644 --- a/src/codec/CodecMain.h +++ b/src/codec/CodecMain.h @@ -3,7 +3,7 @@ * * See https://github.com/esri/serlio for build and usage instructions. * - * Copyright (c) 2012-2019 Esri R&D Center Zurich + * Copyright (c) 2012-2022 Esri R&D Center Zurich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/src/codec/encoder/IMayaCallbacks.h b/src/codec/encoder/IMayaCallbacks.h index 3bf29f22..57fb3071 100644 --- a/src/codec/encoder/IMayaCallbacks.h +++ b/src/codec/encoder/IMayaCallbacks.h @@ -3,7 +3,7 @@ * * See https://github.com/esri/serlio for build and usage instructions. * - * Copyright (c) 2012-2019 Esri R&D Center Zurich + * Copyright (c) 2012-2022 Esri R&D Center Zurich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -68,4 +68,16 @@ class IMayaCallbacks : public prt::Callbacks { const int32_t* shapeIDs ) = 0; // clang-format on + + /** + * Writes an asset (e.g. in-memory texture) to an implementation-defined path. Assets with same uri will be assumed + * to contain identical data. + * + * @param uri the original asset within the RPK + * @param fileName local fileName derived from the URI by the asset encoder. can be used to cache the asset. + * @param [out] result file system path of the locally cached asset. Expected to be valid for the whole process + * life-time. + */ + virtual void addAsset(const wchar_t* uri, const wchar_t* fileName, const uint8_t* buffer, size_t size, + wchar_t* result, size_t& resultSize) = 0; }; diff --git a/src/codec/encoder/MayaEncoder.cpp b/src/codec/encoder/MayaEncoder.cpp index 69777eb3..c769ce29 100644 --- a/src/codec/encoder/MayaEncoder.cpp +++ b/src/codec/encoder/MayaEncoder.cpp @@ -3,7 +3,7 @@ * * See https://github.com/esri/serlio for build and usage instructions. * - * Copyright (c) 2012-2019 Esri R&D Center Zurich + * Copyright (c) 2012-2022 Esri R&D Center Zurich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,10 +17,12 @@ * limitations under the License. */ -#include "encoder/MayaEncoder.h" #include "encoder/IMayaCallbacks.h" +#include "encoder/MayaEncoder.h" +#include "encoder/TextureEncoder.h" #include "prtx/Attributable.h" +#include "prtx/DataBackend.h" #include "prtx/Exception.h" #include "prtx/ExtensionManager.h" #include "prtx/GenerateContext.h" @@ -33,9 +35,11 @@ #include "prtx/ShapeIterator.h" #include "prtx/URI.h" +#include "prt/MemoryOutputCallbacks.h" #include "prt/prt.h" #include +#include #include #include #include @@ -68,25 +72,6 @@ constexpr bool DBG = false; constexpr const wchar_t* ENC_NAME = L"Autodesk(tm) Maya(tm) Encoder"; constexpr const wchar_t* ENC_DESCRIPTION = L"Encodes geometry into the Maya format."; -struct SerializedGeometry { - prtx::DoubleVector coords; - prtx::DoubleVector normals; - std::vector counts; - std::vector vertexIndices; - std::vector normalIndices; - - std::vector uvs; - std::vector uvCounts; - std::vector uvIndices; - - SerializedGeometry(uint32_t numCounts, uint32_t numIndices, uint32_t uvSets) - : uvs(uvSets), uvCounts(uvSets), uvIndices(uvSets) { - counts.reserve(numCounts); - vertexIndices.reserve(numIndices); - normalIndices.reserve(numIndices); - } -}; - const prtx::EncodePreparator::PreparationFlags PREP_FLAGS = prtx::EncodePreparator::PreparationFlags() .instancing(false) @@ -117,8 +102,73 @@ std::pair, std::vector> toPtrVec(const std::vector return std::make_pair(pv, ps); } -std::wstring uriToPath(const prtx::TexturePtr& t) { - return t->getURI()->getPath(); +template +std::basic_string callAPI(FUNC f, OBJ& obj, ARGS&&... args) { + std::vector buffer(1024, 0x0); + size_t size = buffer.size(); + std::invoke(f, obj, args..., buffer.data(), size); + if (size == 0) + return {}; // error case + else if (size > buffer.size()) { + buffer.resize(size); + std::invoke(f, obj, args..., buffer.data(), size); + } + return {buffer.data()}; +} + +std::wstring getTexturePath(const prtx::TexturePtr& texture, IMayaCallbacks* callbacks, prt::Cache* cache) { + if (!texture || !texture->isValid()) + return {}; + + const prtx::URIPtr& uri = texture->getURI(); + const std::wstring& uriStr = uri->wstring(); + const std::wstring& scheme = uri->getScheme(); + + if (!uri->isComposite() && (scheme == prtx::URI::SCHEME_FILE || scheme == prtx::URI::SCHEME_UNC)) { + // textures from the local file system or a mounted share on Windows can be directly passed to Serlio + return uri->getNativeFormat(); + } + else if (uri->isComposite() && (scheme == prtx::URI::SCHEME_RPK)) { + // textures from within an RPK can be directly copied out, no need for encoding + // just need to make sure we have useful filename for embedded texture blocks without names + + const prtx::BinaryVectorPtr data = prtx::DataBackend::resolveBinaryData(cache, uriStr); + const std::wstring fileName = uri->getBaseName() + uri->getExtension(); + const std::wstring assetPath = callAPI(&IMayaCallbacks::addAsset, *callbacks, uriStr.c_str(), + fileName.c_str(), data->data(), data->size()); + return assetPath; + } + else { + // all other textures (builtin or from memory) need to be extracted and potentially re-encoded + try { + prtx::PRTUtils::MemoryOutputCallbacksUPtr moc(prt::MemoryOutputCallbacks::create()); + + prtx::AsciiFileNamePreparator namePrep; + const prtx::NamePreparator::NamespacePtr& namePrepNamespace = namePrep.newNamespace(); + const std::wstring validatedFilename = + TextureEncoder::encode(texture, moc.get(), namePrep, namePrepNamespace, {}); + + if (moc->getNumBlocks() == 1) { + size_t bufferSize = 0; + const uint8_t* buffer = moc->getBlock(0, &bufferSize); + + const std::wstring assetPath = callAPI(&IMayaCallbacks::addAsset, *callbacks, uriStr.c_str(), + validatedFilename.c_str(), buffer, bufferSize); + if (!assetPath.empty()) + return assetPath; + else + srl_log_warn("Received invalid asset path while trying to write asset with URI: %1%") % uriStr; + } + else { + srl_log_warn("Failed to get texture at %1%, texture will be missing") % uriStr; + } + } + catch (std::exception& e) { + srl_log_warn("Failed to encode or write texture at %1% to the local filesystem: %2%") % uriStr % e.what(); + } + } + + return {}; } // we blacklist all CGA-style material attribute keys, see prtx/Material.h @@ -206,14 +256,14 @@ const std::set MATERIAL_ATTRIBUTE_BLACKLIST = { }; void convertMaterialToAttributeMap(prtx::PRTUtils::AttributeMapBuilderPtr& aBuilder, const prtx::Material& prtxAttr, - const prtx::WStringVector& keys) { - if (DBG) + const prtx::WStringVector& keys, IMayaCallbacks* cb, prt::Cache* cache) { + if constexpr (DBG) srl_log_debug(L"-- converting material: %1%") % prtxAttr.name(); for (const auto& key : keys) { if (MATERIAL_ATTRIBUTE_BLACKLIST.count(key) > 0) continue; - if (DBG) + if constexpr (DBG) srl_log_debug(L" key: %1%") % key; switch (prtxAttr.getType(key)) { @@ -265,7 +315,7 @@ void convertMaterialToAttributeMap(prtx::PRTUtils::AttributeMapBuilderPtr& aBuil case prtx::Material::PT_TEXTURE: { const auto& t = prtxAttr.getTexture(key); - const std::wstring p = uriToPath(t); + const std::wstring p = getTexturePath(t, cb, cache); aBuilder->setString(key.c_str(), p.c_str()); break; } @@ -273,16 +323,23 @@ void convertMaterialToAttributeMap(prtx::PRTUtils::AttributeMapBuilderPtr& aBuil case prtx::Material::PT_TEXTURE_ARRAY: { const auto& ta = prtxAttr.getTextureArray(key); - prtx::WStringVector pa(ta.size()); - std::transform(ta.begin(), ta.end(), pa.begin(), uriToPath); + prtx::WStringVector texPaths; + texPaths.reserve(ta.size()); + + for (const auto& tex : ta) { + const std::wstring texPath = getTexturePath(tex, cb, cache); + if (!texPath.empty()) + texPaths.push_back(texPath); + } + + const std::vector pTexPaths = toPtrVec(texPaths); + aBuilder->setStringArray(key.c_str(), pTexPaths.data(), pTexPaths.size()); - std::vector ppa = toPtrVec(pa); - aBuilder->setStringArray(key.c_str(), ppa.data(), ppa.size()); break; } default: - if (DBG) + if constexpr (DBG) srl_log_debug(L"ignored atttribute '%s' with type %d") % key % prtxAttr.getType(key); break; } @@ -353,167 +410,228 @@ struct AttributeMapNOPtrVectorOwner { } }; -struct TextureUVMapping { - std::wstring key; - uint8_t index; - int8_t uvSet; -}; - -const std::vector TEXTURE_UV_MAPPINGS = []() -> std::vector { - // clang-format off - return { - // shader key | idx | uv set | CGA key - { L"diffuseMap", 0, 0 }, // colormap - { L"bumpMap", 0, 1 }, // bumpmap - { L"diffuseMap", 1, 2 }, // dirtmap - { L"specularMap", 0, 3 }, // specularmap - { L"opacityMap", 0, 4 }, // opacitymap - { L"normalMap", 0, 5 } // normalmap +class SerializedGeometry { +public: + SerializedGeometry(const prtx::GeometryPtrVector& geometries, + const std::vector& materials) { + reserveMemory(geometries, materials); + serialize(geometries, materials); + } -#if PRT_VERSION_MAJOR > 1 - , - { L"emissiveMap", 0, 6 }, // emissivemap - { L"occlusionMap", 0, 7 }, // occlusionmap - { L"roughnessMap", 0, 8 }, // roughnessmap - { L"metallicMap", 0, 9 } // metallicmap -#endif - }; - // clang-format on -}(); - -// return the highest required uv set (where a valid texture is present) -uint32_t scanValidTextures(const prtx::MaterialPtr& mat) { - int8_t highestUVSet = -1; - for (const auto& t : TEXTURE_UV_MAPPINGS) { - const auto& ta = mat->getTextureArray(t.key); - if (ta.size() > t.index && ta[t.index]->isValid()) - highestUVSet = std::max(highestUVSet, t.uvSet); + bool isEmpty() const { + return mCoords.empty() || mCounts.empty() || mVertexIndices.empty(); } - if (highestUVSet < 0) - return 0; - else - return highestUVSet + 1; -} -const prtx::DoubleVector EMPTY_UVS; -const prtx::IndexVector EMPTY_IDX; +private: + void reserveMemory(const prtx::GeometryPtrVector& geometries, + const std::vector& materials) { + // Allocate memory for geometry + uint32_t numCounts = 0; + uint32_t numIndices = 0; + uint32_t maxNumUVSets = 0; + + auto matsIt = materials.cbegin(); + for (const auto& geo : geometries) { + const prtx::MeshPtrVector& meshes = geo->getMeshes(); + const prtx::MaterialPtrVector& mats = *matsIt; + auto matIt = mats.cbegin(); + for (const auto& mesh : meshes) { + numCounts += mesh->getFaceCount(); + const auto& vtxCnts = mesh->getFaceVertexCounts(); + numIndices = std::accumulate(vtxCnts.begin(), vtxCnts.end(), numIndices); + + const prtx::MaterialPtr& mat = *matIt; + const uint32_t requiredUVSetsByMaterial = scanValidTextures(mat); + maxNumUVSets = std::max(maxNumUVSets, std::max(mesh->getUVSetsCount(), requiredUVSetsByMaterial)); + ++matIt; + } + ++matsIt; + } + + mCounts.reserve(numCounts); + mVertexIndices.reserve(numIndices); + mNormalIndices.reserve(numIndices); -} // namespace + // Allocate memory for uvs + std::vector numUvs(maxNumUVSets); + std::vector numUvCounts(maxNumUVSets); + std::vector numUvIndices(maxNumUVSets); -namespace detail { + for (const auto& geo : geometries) { + const prtx::MeshPtrVector& meshes = geo->getMeshes(); + for (const auto& mesh : meshes) { + const uint32_t numUVSets = mesh->getUVSetsCount(); -SerializedGeometry serializeGeometry(const prtx::GeometryPtrVector& geometries, - const std::vector& materials) { - // PASS 1: scan - uint32_t numCounts = 0; - uint32_t numIndices = 0; - uint32_t maxNumUVSets = 0; - auto matsIt = materials.cbegin(); - for (const auto& geo : geometries) { - const prtx::MeshPtrVector& meshes = geo->getMeshes(); - const prtx::MaterialPtrVector& mats = *matsIt; - auto matIt = mats.cbegin(); - for (const auto& mesh : meshes) { - numCounts += mesh->getFaceCount(); - const auto& vtxCnts = mesh->getFaceVertexCounts(); - numIndices = std::accumulate(vtxCnts.begin(), vtxCnts.end(), numIndices); - - const prtx::MaterialPtr& mat = *matIt; - const uint32_t requiredUVSetsByMaterial = scanValidTextures(mat); - maxNumUVSets = std::max(maxNumUVSets, std::max(mesh->getUVSetsCount(), requiredUVSetsByMaterial)); - ++matIt; + for (uint32_t uvSet = 0; uvSet < numUVSets; uvSet++) { + numUvs[uvSet] += static_cast(mesh->getUVCoords(uvSet).size()); + + const auto& faceUVCounts = mesh->getFaceUVCounts(uvSet); + numUvCounts[uvSet] += static_cast(faceUVCounts.size()); + numUvIndices[uvSet] = + std::accumulate(faceUVCounts.begin(), faceUVCounts.end(), numUvIndices[uvSet]); + } + } + } + + mUvs.resize(maxNumUVSets); + mUvCounts.resize(maxNumUVSets); + mUvIndices.resize(maxNumUVSets); + + for (uint32_t uvSet = 0; uvSet < maxNumUVSets; uvSet++) { + mUvs[uvSet].reserve(numUvs[uvSet]); + mUvCounts[uvSet].reserve(numUvCounts[uvSet]); + mUvIndices[uvSet].reserve(numUvIndices[uvSet]); } - ++matsIt; } - SerializedGeometry sg(numCounts, numIndices, maxNumUVSets); - // PASS 2: copy - uint32_t vertexIndexBase = 0u; - uint32_t normalIndexBase = 0u; - std::vector uvIndexBases(maxNumUVSets, 0u); - for (const auto& geo : geometries) { - const prtx::MeshPtrVector& meshes = geo->getMeshes(); - for (const auto& mesh : meshes) { - // append points - const prtx::DoubleVector& verts = mesh->getVertexCoords(); - sg.coords.insert(sg.coords.end(), verts.begin(), verts.end()); - - // append normals - const prtx::DoubleVector& norms = mesh->getVertexNormalsCoords(); - sg.normals.insert(sg.normals.end(), norms.begin(), norms.end()); - - // append uv sets (uv coords, counts, indices) with special cases: - // - if mesh has no uv sets but maxNumUVSets is > 0, insert "0" uv face counts to keep in sync - // - if mesh has less uv sets than maxNumUVSets, copy uv set 0 to the missing higher sets - const uint32_t numUVSets = mesh->getUVSetsCount(); - const prtx::DoubleVector& uvs0 = (numUVSets > 0) ? mesh->getUVCoords(0) : EMPTY_UVS; - const prtx::IndexVector faceUVCounts0 = - (numUVSets > 0) ? mesh->getFaceUVCounts(0) : prtx::IndexVector(mesh->getFaceCount(), 0); - if (DBG) - log_debug("-- mesh: numUVSets = %1%") % numUVSets; - - for (uint32_t uvSet = 0; uvSet < sg.uvs.size(); uvSet++) { - // append texture coordinates - const prtx::DoubleVector& uvs = (uvSet < numUVSets) ? mesh->getUVCoords(uvSet) : EMPTY_UVS; - const auto& src = uvs.empty() ? uvs0 : uvs; - auto& tgt = sg.uvs[uvSet]; - tgt.insert(tgt.end(), src.begin(), src.end()); - - // append uv face counts - const prtx::IndexVector& faceUVCounts = - (uvSet < numUVSets && !uvs.empty()) ? mesh->getFaceUVCounts(uvSet) : faceUVCounts0; - assert(faceUVCounts.size() == mesh->getFaceCount()); - auto& tgtCnts = sg.uvCounts[uvSet]; - tgtCnts.insert(tgtCnts.end(), faceUVCounts.begin(), faceUVCounts.end()); - if (DBG) - log_debug(" -- uvset %1%: face counts size = %2%") % uvSet % faceUVCounts.size(); - - // append uv vertex indices - for (uint32_t fi = 0, faceCount = static_cast(faceUVCounts.size()); fi < faceCount; ++fi) { - const uint32_t* faceUVIdx0 = (numUVSets > 0) ? mesh->getFaceUVIndices(fi, 0) : EMPTY_IDX.data(); - const uint32_t* faceUVIdx = - (uvSet < numUVSets && !uvs.empty()) ? mesh->getFaceUVIndices(fi, uvSet) : faceUVIdx0; - const uint32_t faceUVCnt = faceUVCounts[fi]; - if (DBG) - log_debug(" fi %1%: faceUVCnt = %2%, faceVtxCnt = %3%") % fi % faceUVCnt % - mesh->getFaceVertexCount(fi); - for (uint32_t vi = 0; vi < faceUVCnt; vi++) - sg.uvIndices[uvSet].push_back(uvIndexBases[uvSet] + faceUVIdx[vi]); + void serialize(const prtx::GeometryPtrVector& geometries, const std::vector& materials) { + const uint32_t maxNumUVSets = static_cast(mUvs.size()); + + const prtx::DoubleVector EMPTY_UVS; + const prtx::IndexVector EMPTY_IDX; + + // Copy data into serialized geometry + uint32_t vertexIndexBase = 0u; + uint32_t normalIndexBase = 0u; + std::vector uvIndexBases(maxNumUVSets, 0u); + for (const auto& geo : geometries) { + const prtx::MeshPtrVector& meshes = geo->getMeshes(); + for (const auto& mesh : meshes) { + // append points + const prtx::DoubleVector& verts = mesh->getVertexCoords(); + mCoords.insert(mCoords.end(), verts.begin(), verts.end()); + + // append normals + const prtx::DoubleVector& norms = mesh->getVertexNormalsCoords(); + mNormals.insert(mNormals.end(), norms.begin(), norms.end()); + + // append uv sets (uv coords, counts, indices) with special cases: + // - if mesh has no uv sets but maxNumUVSets is > 0, insert "0" uv face counts to keep in sync + // - if mesh has less uv sets than maxNumUVSets, copy uv set 0 to the missing higher sets + const uint32_t numUVSets = mesh->getUVSetsCount(); + const prtx::DoubleVector& uvs0 = (numUVSets > 0) ? mesh->getUVCoords(0) : EMPTY_UVS; + const prtx::IndexVector faceUVCounts0 = + (numUVSets > 0) ? mesh->getFaceUVCounts(0) : prtx::IndexVector(mesh->getFaceCount(), 0); + if constexpr (DBG) + srl_log_debug("-- mesh: numUVSets = %1%") % numUVSets; + + for (uint32_t uvSet = 0; uvSet < mUvs.size(); uvSet++) { + // append texture coordinates + const prtx::DoubleVector& uvs = (uvSet < numUVSets) ? mesh->getUVCoords(uvSet) : EMPTY_UVS; + const auto& src = uvs.empty() ? uvs0 : uvs; + auto& tgt = mUvs[uvSet]; + tgt.insert(tgt.end(), src.begin(), src.end()); + + // append uv face counts + const prtx::IndexVector& faceUVCounts = + (uvSet < numUVSets && !uvs.empty()) ? mesh->getFaceUVCounts(uvSet) : faceUVCounts0; + assert(faceUVCounts.size() == mesh->getFaceCount()); + auto& tgtCnts = mUvCounts[uvSet]; + tgtCnts.insert(tgtCnts.end(), faceUVCounts.begin(), faceUVCounts.end()); + if constexpr (DBG) + srl_log_debug(" -- uvset %1%: face counts size = %2%") % uvSet % faceUVCounts.size(); + + // append uv vertex indices + for (uint32_t fi = 0, faceCount = static_cast(faceUVCounts.size()); fi < faceCount; + ++fi) { + const uint32_t* faceUVIdx0 = (numUVSets > 0) ? mesh->getFaceUVIndices(fi, 0) : EMPTY_IDX.data(); + const uint32_t* faceUVIdx = + (uvSet < numUVSets && !uvs.empty()) ? mesh->getFaceUVIndices(fi, uvSet) : faceUVIdx0; + const uint32_t faceUVCnt = faceUVCounts[fi]; + if constexpr (DBG) + srl_log_debug(" fi %1%: faceUVCnt = %2%, faceVtxCnt = %3%") % fi % faceUVCnt % + mesh->getFaceVertexCount(fi); + for (uint32_t vi = 0; vi < faceUVCnt; vi++) + mUvIndices[uvSet].push_back(uvIndexBases[uvSet] + faceUVIdx[vi]); + } + + uvIndexBases[uvSet] += static_cast(src.size()) / 2; + } // for all uv sets + + // append counts and indices for vertices and vertex normals + for (uint32_t fi = 0, faceCount = mesh->getFaceCount(); fi < faceCount; ++fi) { + const uint32_t vtxCnt = mesh->getFaceVertexCount(fi); + mCounts.push_back(vtxCnt); + const uint32_t* vtxIdx = mesh->getFaceVertexIndices(fi); + const uint32_t* nrmIdx = mesh->getFaceVertexNormalIndices(fi); + for (uint32_t vi = 0; vi < vtxCnt; vi++) { + mVertexIndices.push_back(vertexIndexBase + vtxIdx[vi]); + mNormalIndices.push_back(normalIndexBase + nrmIdx[vi]); + } } - uvIndexBases[uvSet] += static_cast(src.size()) / 2; - } // for all uv sets - - // append counts and indices for vertices and vertex normals - for (uint32_t fi = 0, faceCount = mesh->getFaceCount(); fi < faceCount; ++fi) { - const uint32_t vtxCnt = mesh->getFaceVertexCount(fi); - sg.counts.push_back(vtxCnt); - const uint32_t* vtxIdx = mesh->getFaceVertexIndices(fi); - const uint32_t* nrmIdx = mesh->getFaceVertexNormalIndices(fi); - for (uint32_t vi = 0; vi < vtxCnt; vi++) { - sg.vertexIndices.push_back(vertexIndexBase + vtxIdx[vi]); - sg.normalIndices.push_back(normalIndexBase + nrmIdx[vi]); - } - } + vertexIndexBase += (uint32_t)verts.size() / 3u; + normalIndexBase += (uint32_t)norms.size() / 3u; + } // for all meshes + } // for all geometries + } - vertexIndexBase += (uint32_t)verts.size() / 3u; - normalIndexBase += (uint32_t)norms.size() / 3u; - } // for all meshes - } // for all geometries + struct TextureUVMapping { + std::wstring key; + uint8_t index; + int8_t uvSet; + }; - return sg; -} -} // namespace detail + // return the highest required uv set (where a valid texture is present) + uint32_t scanValidTextures(const prtx::MaterialPtr& mat) { + + // clang-format off + static const std::vector TEXTURE_UV_MAPPINGS = []() -> std::vector { + return { + // shader key | idx | uv set | CGA key + { L"diffuseMap", 0, 0 }, // colormap + { L"bumpMap", 0, 1 }, // bumpmap + { L"diffuseMap", 1, 2 }, // dirtmap + { L"specularMap", 0, 3 }, // specularmap + { L"opacityMap", 0, 4 }, // opacitymap + { L"normalMap", 0, 5 } // normalmap + + #if PRT_VERSION_MAJOR > 1 + , + { L"emissiveMap", 0, 6 }, // emissivemap + { L"occlusionMap", 0, 7 }, // occlusionmap + { L"roughnessMap", 0, 8 }, // roughnessmap + { L"metallicMap", 0, 9 } // metallicmap + #endif + }; + }(); + // clang-format on + + int8_t highestUVSet = -1; + for (const auto& t : TEXTURE_UV_MAPPINGS) { + const auto& ta = mat->getTextureArray(t.key); + if (ta.size() > t.index && ta[t.index]->isValid()) + highestUVSet = std::max(highestUVSet, t.uvSet); + } + if (highestUVSet < 0) + return 0; + else + return highestUVSet + 1; + } + +public: + prtx::DoubleVector mCoords; + prtx::DoubleVector mNormals; + std::vector mCounts; + std::vector mVertexIndices; + std::vector mNormalIndices; + + std::vector mUvs; + std::vector mUvCounts; + std::vector mUvIndices; +}; + +} // namespace MayaEncoder::MayaEncoder(const std::wstring& id, const prt::AttributeMap* options, prt::Callbacks* callbacks) : prtx::GeometryEncoder(id, options, callbacks) {} void MayaEncoder::init(prtx::GenerateContext&) { prt::Callbacks* cb = getCallbacks(); - if (DBG) + if constexpr (DBG) srl_log_debug(L"MayaEncoder::init: cb = %x") % (size_t)cb; auto* oh = dynamic_cast(cb); - if (DBG) + if constexpr (DBG) srl_log_debug(L" oh = %x") % (size_t)oh; if (oh == nullptr) throw prtx::StatusException(prt::STATUS_ILLEGAL_CALLBACK_OBJECT); @@ -546,11 +664,15 @@ void MayaEncoder::encode(prtx::GenerateContext& context, size_t initialShapeInde prtx::EncodePreparator::InstanceVector instances; encPrep->fetchFinalizedInstances(instances, PREP_FLAGS); - convertGeometry(initialShape, instances, cb); + convertGeometry(initialShape, instances, cb, context.getCache()); } void MayaEncoder::convertGeometry(const prtx::InitialShape& initialShape, - const prtx::EncodePreparator::InstanceVector& instances, IMayaCallbacks* cb) { + const prtx::EncodePreparator::InstanceVector& instances, IMayaCallbacks* cb, + prt::Cache* cache) { + if (instances.empty()) + return; + const bool emitMaterials = getOptions()->getBool(EO_EMIT_MATERIALS); const bool emitReports = getOptions()->getBool(EO_EMIT_REPORTS); @@ -571,11 +693,14 @@ void MayaEncoder::convertGeometry(const prtx::InitialShape& initialShape, shapeIDs.push_back(inst.getShapeId()); } - const SerializedGeometry sg = detail::serializeGeometry(geometries, materials); + const SerializedGeometry sg(geometries, materials); + + if (sg.isEmpty()) + return; - if (DBG) { - log_debug("resolvemap: %s") % prtx::PRTUtils::objectToXML(initialShape.getResolveMap()); - log_debug("encoder #materials = %s") % materials.size(); + if constexpr (DBG) { + srl_log_debug("resolvemap: %s") % prtx::PRTUtils::objectToXML(initialShape.getResolveMap()); + srl_log_debug("encoder #materials = %s") % materials.size(); } uint32_t faceCount = 0; @@ -598,15 +723,15 @@ void MayaEncoder::convertGeometry(const prtx::InitialShape& initialShape, faceRanges.push_back(faceCount); if (emitMaterials) { - convertMaterialToAttributeMap(amb, *(mat.get()), mat->getKeys()); + convertMaterialToAttributeMap(amb, *(mat.get()), mat->getKeys(), cb, cache); matAttrMaps.v.push_back(amb->createAttributeMapAndReset()); } if (emitReports) { convertReportsToAttributeMap(amb, *repIt); reportAttrMaps.v.push_back(amb->createAttributeMapAndReset()); - if (DBG) - log_debug("report attr map: %1%") % prtx::PRTUtils::objectToXML(reportAttrMaps.v.back()); + if constexpr (DBG) + srl_log_debug("report attr map: %1%") % prtx::PRTUtils::objectToXML(reportAttrMaps.v.back()); } faceCount += m->getFaceCount(); @@ -621,21 +746,21 @@ void MayaEncoder::convertGeometry(const prtx::InitialShape& initialShape, assert(reportAttrMaps.v.empty() || reportAttrMaps.v.size() == faceRanges.size() - 1); assert(shapeIDs.size() == faceRanges.size() - 1); - auto puvs = toPtrVec(sg.uvs); - auto puvCounts = toPtrVec(sg.uvCounts); - auto puvIndices = toPtrVec(sg.uvIndices); + auto puvs = toPtrVec(sg.mUvs); + auto puvCounts = toPtrVec(sg.mUvCounts); + auto puvIndices = toPtrVec(sg.mUvIndices); - cb->addMesh(initialShape.getName(), sg.coords.data(), sg.coords.size(), sg.normals.data(), sg.normals.size(), - sg.counts.data(), sg.counts.size(), sg.vertexIndices.data(), sg.vertexIndices.size(), - sg.normalIndices.data(), sg.normalIndices.size(), + cb->addMesh(initialShape.getName(), sg.mCoords.data(), sg.mCoords.size(), sg.mNormals.data(), sg.mNormals.size(), + sg.mCounts.data(), sg.mCounts.size(), sg.mVertexIndices.data(), sg.mVertexIndices.size(), + sg.mNormalIndices.data(), sg.mNormalIndices.size(), puvs.first.data(), puvs.second.data(), puvCounts.first.data(), puvCounts.second.data(), - puvIndices.first.data(), puvIndices.second.data(), sg.uvs.size(), + puvIndices.first.data(), puvIndices.second.data(), sg.mUvs.size(), faceRanges.data(), faceRanges.size(), matAttrMaps.v.empty() ? nullptr : matAttrMaps.v.data(), reportAttrMaps.v.empty() ? nullptr : reportAttrMaps.v.data(), shapeIDs.data()); - if (DBG) + if constexpr (DBG) srl_log_debug(L"MayaEncoder::convertGeometry: end"); } diff --git a/src/codec/encoder/MayaEncoder.h b/src/codec/encoder/MayaEncoder.h index b7769bc8..cc44d938 100644 --- a/src/codec/encoder/MayaEncoder.h +++ b/src/codec/encoder/MayaEncoder.h @@ -3,7 +3,7 @@ * * See https://github.com/esri/serlio for build and usage instructions. * - * Copyright (c) 2012-2019 Esri R&D Center Zurich + * Copyright (c) 2012-2022 Esri R&D Center Zurich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -50,7 +50,8 @@ class MayaEncoder : public prtx::GeometryEncoder { private: void convertGeometry(const prtx::InitialShape& initialShape, - const prtx::EncodePreparator::InstanceVector& instances, IMayaCallbacks* callbacks); + const prtx::EncodePreparator::InstanceVector& instances, IMayaCallbacks* callbacks, + prt::Cache* cache); }; class MayaEncoderFactory : public prtx::EncoderFactory, public prtx::Singleton { diff --git a/src/codec/encoder/TextureEncoder.cpp b/src/codec/encoder/TextureEncoder.cpp new file mode 100644 index 00000000..9bd87111 --- /dev/null +++ b/src/codec/encoder/TextureEncoder.cpp @@ -0,0 +1,199 @@ +/** + * Serlio - Esri CityEngine Plugin for Autodesk Maya + * + * See https://github.com/esri/serlio for build and usage instructions. + * + * Copyright (c) 2012-2022 Esri R&D Center Zurich + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "TextureEncoder.h" + +#include "prtx/Exception.h" +#include "prtx/ExtensionManager.h" +#include "prtx/PRTUtils.h" +#include "prtx/Texture.h" +#include "prtx/URI.h" + +#include "prt/EncoderInfo.h" + +#include +#include +#include +#include + +namespace TextureEncoder { + +namespace IDs { + +const std::wstring PNG = L"com.esri.prt.codecs.PNGEncoder"; +const std::wstring JPG = L"com.esri.prt.codecs.JPGEncoder"; +const std::wstring TIF = L"com.esri.prt.codecs.TIFFEncoder"; +const std::wstring DXT = L"com.esri.prt.codecs.DxtEncoder"; +const std::wstring RAW = L"com.esri.prt.codecs.RAWEncoder"; + +} // namespace IDs + +// key names for texture encoder options provided by PRT +namespace OptionNames { + +constexpr const wchar_t* NAME = L"textureName"; +constexpr const wchar_t* FLIPH = L"textureFlipH"; +constexpr const wchar_t* BASE64 = L"textureBase64"; +constexpr const wchar_t* MAXDIM = L"textureMaxDimension"; +constexpr const wchar_t* SCALING = L"textureScalingFactor"; +constexpr const wchar_t* FIXED_DIMENSIONS = L"textureFixedDimensions"; + +constexpr const wchar_t* JPG_QUALITY = L"textureQuality"; +constexpr const wchar_t* JPG_FORCE_JFIF = L"forceJFIFHeaders"; +constexpr const wchar_t* PNG_COMPRESSION = L"textureCompression"; + +constexpr const wchar_t* EXISTING_FILES = L"existingFiles"; +constexpr const wchar_t* EXISTING_FILES_OVERWRITE = L"OVERWRITE"; +constexpr const wchar_t* EXISTING_FILES_SKIP = L"SKIP"; + +} // namespace OptionNames + +std::wstring const& selectEncoderID(Format format) { + switch (format) { + case Format::JPG: + return IDs::JPG; + case Format::PNG: + return IDs::PNG; + case Format::TIF: + return IDs::TIF; + default: + throw std::invalid_argument("unsupported format"); + } +} + +std::wstring const getBestMatchingEncoder(const prtx::Texture& tex) { + const prtx::URIPtr& uri = tex.getURI(); + + std::wstring const extension = uri->getExtension(); + if (!extension.empty()) { + std::vector availableEncoders; + prtx::ExtensionManager::instance().listEncoderIds(availableEncoders); + + std::wstring bestId; + double bestMerit = std::numeric_limits::lowest(); + for (const auto& encId : availableEncoders) { + prtx::PRTUtils::EncoderInfoUPtr encInfo(prtx::ExtensionManager::instance().createEncoderInfo(encId)); + if (encInfo->getType() == prt::CT_TEXTURE) { + const std::wstring_view extensions(encInfo->getExtensions()); + const bool hasCompatibleFileExtension = (extensions.find(extension + L';') != std::wstring_view::npos); + if (hasCompatibleFileExtension && (encInfo->getMerit() > bestMerit)) { + bestId = encId; + bestMerit = encInfo->getMerit(); + } + } + } + + if (!bestId.empty()) + return bestId; + } + + // fallback behavior + if (extension == L".png") + return IDs::PNG; + else if (tex.getFormat() == prtx::Texture::RGB8 || tex.getFormat() == prtx::Texture::GREY8) + return IDs::JPG; + else + return IDs::PNG; +} + +std::wstring getExtensionForEncoder(std::wstring const& textureEncoderID, std::wstring const& currentExt) { + const prtx::PRTUtils::EncoderInfoUPtr encoderInfo( + prtx::ExtensionManager::instance().createEncoderInfo(textureEncoderID)); + const std::wstring_view extensions(encoderInfo->getExtensions()); + const bool hasCompatibleFileExtension = (extensions.find(currentExt + L';') != std::wstring_view::npos); + return hasCompatibleFileExtension ? currentExt : std::wstring(extensions.substr(0, extensions.find_first_of(L';'))); +} + +std::wstring replaceExtension(std::wstring const& texName, std::wstring const& extension) { + const prtx::URIPtr nameUri = prtx::URIUtils::createFileURI(prtx::URIUtils::percentEncode(L"/" + texName)); + const prtx::URIPtr newExtensionUri = prtx::URIUtils::replaceExtension(nameUri, extension); + return newExtensionUri->getPath(); +} + +std::wstring getBaseName(const prtx::URIPtr& texURI, const std::wstring& namePrefix) { + const std::wstring queryBaseName = texURI->getQuery(prtx::URI::QUERY_TEXTURE_NAME); + const std::wstring uriBaseName = queryBaseName.empty() ? texURI->getBaseName() : queryBaseName; + + if (texURI->getScheme() == prtx::URI::SCHEME_MEMORY && namePrefix.size() > 0) + return namePrefix + L'_' + uriBaseName; + + return uriBaseName; +} + +std::wstring constructNameForTexture(const prtx::TexturePtr& texture, const std::wstring& namePrefix) { + if (!texture || !texture->isValid()) + throw prtx::StatusException(prt::STATUS_ILLEGAL_VALUE); + + prtx::URIPtr texURI = texture->getURI(); + std::wstring const baseName = getBaseName(texURI, namePrefix); + std::wstring const extension = texURI->getExtension(); + return baseName + extension; +} + +prtx::PRTUtils::AttributeMapUPtr getEncOpts(const std::wstring& encoderId, const std::wstring& filename, + prt::SimpleOutputCallbacks::OpenMode openMode) { + prtx::PRTUtils::AttributeMapBuilderPtr builder(prt::AttributeMapBuilder::create()); + builder->setString(OptionNames::NAME, filename.c_str()); + builder->setBool(OptionNames::FLIPH, true); + auto const evExistingFiles = openMode == prt::SimpleOutputCallbacks::OPENMODE_ALWAYS + ? OptionNames::EXISTING_FILES_OVERWRITE + : OptionNames::EXISTING_FILES_SKIP; + builder->setString(OptionNames::EXISTING_FILES, evExistingFiles); + + const prtx::PRTUtils::EncoderInfoPtr encInfo(prtx::ExtensionManager::instance().createEncoderInfo(encoderId)); + prtx::PRTUtils::AttributeMapPtr rawEncOpts{builder->createAttributeMap()}; + const prt::AttributeMap* validOpts = nullptr; + encInfo->createValidatedOptionsAndStates(rawEncOpts.get(), &validOpts); + return prtx::PRTUtils::AttributeMapUPtr(validOpts); +} + +std::wstring encode(const prtx::TexturePtr& texture, prt::SimpleOutputCallbacks* soh, + prtx::NamePreparator& namePreparator, const prtx::NamePreparator::NamespacePtr& namespaceFilenames, + const std::wstring& memTexFileNamePrefix, const Format& targetFormat) { + if (!texture || !texture->isValid()) + throw prtx::StatusException(prt::STATUS_ILLEGAL_VALUE); + + std::wstring textureEncoderID; + if (targetFormat == Format::AUTO) + textureEncoderID = getBestMatchingEncoder(*texture); + else + textureEncoderID = selectEncoderID(targetFormat); + + const std::wstring texName = constructNameForTexture(texture, memTexFileNamePrefix); + const std::wstring extension = getExtensionForEncoder(textureEncoderID, texture->getURI()->getExtension()); + const std::wstring texNameWithExtension = replaceExtension(texName, extension); + const std::wstring uniqueName = namePreparator.legalizedAndUniquified( + texNameWithExtension.substr(1), prtx::NamePreparator::ENTITY_FILE, namespaceFilenames); + + prtx::PRTUtils::AttributeMapUPtr encOpts = + getEncOpts(textureEncoderID, uniqueName, prt::SimpleOutputCallbacks::OpenMode::OPENMODE_ALWAYS); + prtx::EncoderPtr texEnc = prtx::ExtensionManager::instance().createEncoder(textureEncoderID, encOpts.get(), soh); + texEnc->encode({texture}); + + prt::Status status = prt::STATUS_UNSPECIFIED_ERROR; + wchar_t const* const validatedName = encOpts->getString(OptionNames::NAME, &status); + if (status != prt::STATUS_OK) + throw prtx::StatusException(status); + if (validatedName == nullptr) + throw prtx::StatusException(prt::STATUS_ENCODE_FAILED); + + return std::wstring(validatedName); +} + +} // namespace TextureEncoder diff --git a/src/codec/encoder/TextureEncoder.h b/src/codec/encoder/TextureEncoder.h new file mode 100644 index 00000000..710e47e0 --- /dev/null +++ b/src/codec/encoder/TextureEncoder.h @@ -0,0 +1,37 @@ +/** + * Serlio - Esri CityEngine Plugin for Autodesk Maya + * + * See https://github.com/esri/serlio for build and usage instructions. + * + * Copyright (c) 2012-2022 Esri R&D Center Zurich + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "prtx/NamePreparator.h" +#include "prtx/Texture.h" + +#include "prt/Callbacks.h" + +#include + +namespace TextureEncoder { + +enum class Format : uint8_t { AUTO, JPG, PNG, TIF }; + +std::wstring encode(const prtx::TexturePtr& tex, prt::SimpleOutputCallbacks* soh, prtx::NamePreparator& namePreparator, + const prtx::NamePreparator::NamespacePtr& namespaceFilenames, + const std::wstring& memTexFileNamePrefix, const Format& targetFormat = Format::AUTO); + +} // namespace TextureEncoder diff --git a/src/common.cmake b/src/common.cmake index 86256815..ef456e60 100644 --- a/src/common.cmake +++ b/src/common.cmake @@ -16,29 +16,38 @@ if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") set(SRL_WINDOWS 1) elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Linux") set(SRL_LINUX 1) -elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") - set(SRL_MACOS 1) endif () +### common target functions + +function(set_common_target_definitions TGT) + set_target_properties(${TGT} PROPERTIES CXX_STANDARD 17) + target_compile_definitions(${TGT} PRIVATE + -DSRL_VERSION=\"${SRL_VERSION}\" # quoted to use it as string literal + -DSRL_VERSION_MAJOR=\"${SRL_VERSION_MAJOR}\" # quoted to use it as string literal + -DSRL_VERSION_MINOR=\"${SRL_VERSION_MINOR}\" # quoted to use it as string literal + -DSRL_PROJECT_NAME=\"${SRL_PROJECT_NAME}\" + -DPRT_VERSION_MAJOR=${PRT_VERSION_MAJOR} + -DPRT_VERSION_MINOR=${PRT_VERSION_MINOR}) +endfunction() + + ### look for the PRT libraries # if prt_DIR is not provided, download PRT from its github home if (NOT prt_DIR) if (SRL_WINDOWS) set(PRT_OS "win10") - set(PRT_TC "vc141") + set(PRT_TC "vc1427") elseif (SRL_LINUX) set(PRT_OS "rhel7") - set(PRT_TC "gcc63") - elseif (SRL_MACOS) - set(PRT_OS "osx12") - set(PRT_TC "ac81") + set(PRT_TC "gcc93") endif () - set(PRT_VERSION "2.1.5705") + set(PRT_VERSION "2.6.8135") set(PRT_CLS "${PRT_OS}-${PRT_TC}-x86_64-rel-opt") - set(PRT_URL "https://github.com/esri/esri-cityengine-sdk/releases/download/${PRT_VERSION}/esri_ce_sdk-${PRT_VERSION}-${PRT_CLS}.zip") + set(PRT_URL "https://github.com/esri/cityengine-sdk/releases/download/${PRT_VERSION}/esri_ce_sdk-${PRT_VERSION}-${PRT_CLS}.zip") FetchContent_Declare(prt URL ${PRT_URL}) FetchContent_GetProperties(prt) @@ -65,49 +74,56 @@ endfunction() if (NOT maya_DIR) if (WIN32) - if (EXISTS "C:/Program Files/Autodesk/Maya2019") - set(maya_DIR "C:/Program Files/Autodesk/Maya2019") - else () - set(maya_DIR "C:/Program Files/Autodesk/Maya2018") - endif () + set(AUTODESK_INSTALL_LOCATION "C:/Program Files/Autodesk") + set(MAYA_BASE_NAME Maya) else () - if (EXISTS "/opt/autodesk/maya2019") - set(maya_DIR "/opt/autodesk/maya2019") - else () - set(maya_DIR "/opt/autodesk/maya2018") - endif () + set(AUTODESK_INSTALL_LOCATION "/usr/autodesk") + set(MAYA_BASE_NAME maya) + endif () + if (EXISTS "${AUTODESK_INSTALL_LOCATION}/${MAYA_BASE_NAME}2022") + set(maya_DIR "${AUTODESK_INSTALL_LOCATION}/${MAYA_BASE_NAME}2022") + elseif (EXISTS "${AUTODESK_INSTALL_LOCATION}/${MAYA_BASE_NAME}2020") + set(maya_DIR "${AUTODESK_INSTALL_LOCATION}/${MAYA_BASE_NAME}2020") + elseif (EXISTS "${AUTODESK_INSTALL_LOCATION}/${MAYA_BASE_NAME}2019") + set(maya_DIR "${AUTODESK_INSTALL_LOCATION}/${MAYA_BASE_NAME}2019") endif () -endif () -message(STATUS "Using maya_DIR = ${maya_DIR} (use '-Dmaya_DIR=xxx' to override)") - -find_path(maya_INCLUDE_PATH NAMES "maya/MApiVersion.h" PATHS "${maya_DIR}/include" NO_DEFAULT_PATH) - -set(MAYA_LIB_DIR "${maya_DIR}/lib") -find_library(maya_LINK_LIB_FOUNDATION NAMES "Foundation" PATHS "${MAYA_LIB_DIR}") -if (maya_LINK_LIB_FOUNDATION) - list(APPEND maya_LINK_LIBRARIES ${maya_LINK_LIB_FOUNDATION}) -endif () -find_library(maya_LINK_LIB_OPENMAYA NAMES "OpenMaya" PATHS "${MAYA_LIB_DIR}") -if (maya_LINK_LIB_OPENMAYA) - list(APPEND maya_LINK_LIBRARIES ${maya_LINK_LIB_OPENMAYA}) -endif () -find_library(maya_LINK_LIB_OPENMAYAUI NAMES "OpenMayaUI" PATHS "${MAYA_LIB_DIR}") -if (maya_LINK_LIB_OPENMAYAUI) - list(APPEND maya_LINK_LIBRARIES ${maya_LINK_LIB_OPENMAYAUI}) -endif () -find_library(maya_LINK_LIB_METADATA NAMES "MetaData" PATHS "${MAYA_LIB_DIR}") -if (maya_LINK_LIB_METADATA) - list(APPEND maya_LINK_LIBRARIES ${maya_LINK_LIB_METADATA}) endif () # temporary heuristic to detect maya version number -if (maya_DIR MATCHES "[Mm]aya2018") - set(maya_VERSION_MAJOR "2018") -elseif (maya_DIR MATCHES "[Mm]aya2019") +if (maya_DIR MATCHES "[Mm]aya2019") set(maya_VERSION_MAJOR "2019") +elseif (maya_DIR MATCHES "[Mm]aya2020") + set(maya_VERSION_MAJOR "2020") +elseif (maya_DIR MATCHES "[Mm]aya2022") + set(maya_VERSION_MAJOR "2022") endif () function(srl_add_dependency_maya TGT) + if (NOT maya_DIR) + message(FATAL_ERROR "Could not detect maya installation below ${AUTODESK_INSTALL_LOCATION}") + endif() + message(STATUS "Using maya_DIR = ${maya_DIR} (use '-Dmaya_DIR=xxx' to override)") + + find_path(maya_INCLUDE_PATH NAMES "maya/MApiVersion.h" PATHS "${maya_DIR}/include" NO_DEFAULT_PATH) + + set(MAYA_LIB_DIR "${maya_DIR}/lib") + find_library(maya_LINK_LIB_FOUNDATION NAMES "Foundation" PATHS "${MAYA_LIB_DIR}") + if (maya_LINK_LIB_FOUNDATION) + list(APPEND maya_LINK_LIBRARIES ${maya_LINK_LIB_FOUNDATION}) + endif () + find_library(maya_LINK_LIB_OPENMAYA NAMES "OpenMaya" PATHS "${MAYA_LIB_DIR}") + if (maya_LINK_LIB_OPENMAYA) + list(APPEND maya_LINK_LIBRARIES ${maya_LINK_LIB_OPENMAYA}) + endif () + find_library(maya_LINK_LIB_OPENMAYAUI NAMES "OpenMayaUI" PATHS "${MAYA_LIB_DIR}") + if (maya_LINK_LIB_OPENMAYAUI) + list(APPEND maya_LINK_LIBRARIES ${maya_LINK_LIB_OPENMAYAUI}) + endif () + find_library(maya_LINK_LIB_METADATA NAMES "MetaData" PATHS "${MAYA_LIB_DIR}") + if (maya_LINK_LIB_METADATA) + list(APPEND maya_LINK_LIBRARIES ${maya_LINK_LIB_METADATA}) + endif () + if (maya_INCLUDE_PATH) target_include_directories(${TGT} PRIVATE ${maya_INCLUDE_PATH}) endif () @@ -115,6 +131,24 @@ function(srl_add_dependency_maya TGT) endfunction() +### Catch Test Framework + +function(srl_add_dependency_catch TGT) + set(CATCH_URL "https://github.com/catchorg/Catch2.git") + set(CATCH_VER "v2.13.8") + FetchContent_Declare(catch GIT_REPOSITORY ${CATCH_URL} GIT_TAG ${CATCH_VER}) + + FetchContent_GetProperties(catch) + if(NOT catch_POPULATED) + message(STATUS "Fetching Catch ${CATCH_VER} from ${CATCH_URL}...") + FetchContent_Populate(catch) + add_subdirectory(${catch_SOURCE_DIR} ${catch_BINARY_DIR}) + endif() + + target_include_directories(${TGT} PRIVATE ${Catch2_SOURCE_DIR}/single_include) +endfunction() + + ### targets installation location if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) diff --git a/src/serlio/CMakeLists.txt b/src/serlio/CMakeLists.txt index aa3db37f..cf1c0275 100644 --- a/src/serlio/CMakeLists.txt +++ b/src/serlio/CMakeLists.txt @@ -12,14 +12,18 @@ add_library(${SERLIO_TARGET} SHARED modifiers/PRTMesh.cpp modifiers/PRTModifierAction.cpp modifiers/PRTModifierCommand.cpp + modifiers/PRTModifierEnum.cpp modifiers/PRTModifierNode.cpp modifiers/polyModifier/polyModifierCmd.cpp modifiers/polyModifier/polyModifierFty.cpp modifiers/polyModifier/polyModifierNode.cpp materials/ArnoldMaterialNode.cpp materials/MaterialInfo.cpp + materials/MaterialNode.cpp materials/MaterialUtils.cpp materials/StingrayMaterialNode.cpp + materials/MaterialCommand.cpp + utils/AssetCache.cpp utils/Utilities.cpp utils/ResolveMapCache.cpp utils/MayaUtilities.cpp @@ -36,14 +40,18 @@ if (CMAKE_GENERATOR MATCHES "Visual Studio.+") modifiers/PRTMesh.h modifiers/PRTModifierAction.h modifiers/PRTModifierCommand.h + modifiers/PRTModifierEnum.h modifiers/PRTModifierNode.h modifiers/polyModifier/polyModifierCmd.h modifiers/polyModifier/polyModifierFty.h modifiers/polyModifier/polyModifierNode.h materials/ArnoldMaterialNode.h materials/MaterialInfo.h + materials/MaterialNode.h materials/MaterialUtils.h materials/StingrayMaterialNode.h + materials/MaterialCommand.h + utils/AssetCache.h utils/Utilities.h utils/ResolveMapCache.h utils/MayaUtilities.h @@ -61,16 +69,15 @@ set_target_properties(${SERLIO_TARGET} PROPERTIES if (WIN32) # On Windows, Maya requires plugins to have the extension "mll" set_target_properties(${SERLIO_TARGET} PROPERTIES SUFFIX ".mll") +else() + # On linux, we need to remove the "lib" prefix otherwise the plugin will be named "libserlio" + set_target_properties(${SERLIO_TARGET} PROPERTIES PREFIX "") endif () ### setup compiler flags -set_target_properties(${CLIENT_TARGET} PROPERTIES - CXX_STANDARD 14) - -target_compile_definitions(${SERLIO_TARGET} PRIVATE - -DSRL_VERSION=\"${SRL_VERSION}\") # quoted to use it as string literal +set_common_target_definitions(${SERLIO_TARGET}) target_include_directories(${SERLIO_TARGET} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} @@ -139,10 +146,13 @@ install(FILES ${SRL_PRT_LIBRARIES} DESTINATION ${INSTALL_FOLDER_PREFIX}/plug-ins # PRT: whitelist required extension libraries set(SRL_PRT_EXT_LIBRARIES ${PRT_EXT_LIBRARIES}) -list(FILTER SRL_PRT_EXT_LIBRARIES INCLUDE REGEX "com\\.esri\\.prt\\.codecs|com\\.esri\\.prt\\.adaptors|VueExport") +list(FILTER SRL_PRT_EXT_LIBRARIES INCLUDE REGEX "com\\.esri\\.prt\\.(codecs|adaptors|oda|usd)|tbb|usd_ms") install(FILES ${SRL_PRT_EXT_LIBRARIES} DESTINATION ${INSTALL_FOLDER_PREFIX}/plug-ins/ext) +install(DIRECTORY "${PRT_EXTENSION_PATH}/usd" DESTINATION ${INSTALL_FOLDER_PREFIX}/plug-ins/ext) # USD resource files # doc install(DIRECTORY ${PROJECT_SOURCE_DIR}/../doc DESTINATION ${INSTALL_FOLDER_PREFIX}) install(FILES ${PROJECT_SOURCE_DIR}/../README.md ${PROJECT_SOURCE_DIR}/../LICENSE DESTINATION ${INSTALL_FOLDER_PREFIX}) +# icons +install(FILES icons/serlio.xpm DESTINATION ${INSTALL_FOLDER_PREFIX}/icons) \ No newline at end of file diff --git a/src/serlio/PRTContext.cpp b/src/serlio/PRTContext.cpp index 609122c7..7e42eab3 100644 --- a/src/serlio/PRTContext.cpp +++ b/src/serlio/PRTContext.cpp @@ -3,7 +3,7 @@ * * See https://github.com/esri/serlio for build and usage instructions. * - * Copyright (c) 2012-2019 Esri R&D Center Zurich + * Copyright (c) 2012-2022 Esri R&D Center Zurich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,15 +19,12 @@ #include "PRTContext.h" -#include "utils/LogHandler.h" - #include namespace { constexpr bool DBG = false; -constexpr const wchar_t* SRL_TMP_PREFIX = L"serlio_"; constexpr const wchar_t* PRT_EXT_SUBDIR = L"ext"; constexpr prt::LogLevel PRT_LOG_LEVEL = prt::LOG_INFO; constexpr bool ENABLE_LOG_CONSOLE = true; @@ -38,7 +35,6 @@ bool verifyMayaEncoder() { const auto mayaEncOpts = prtu::createValidatedOptions(ENC_ID_MAYA); return static_cast(mayaEncOpts); } - } // namespace PRTContext& PRTContext::get() { @@ -48,31 +44,31 @@ PRTContext& PRTContext::get() { PRTContext::PRTContext(const std::vector& addExtDirs) : mPluginRootPath(prtu::getPluginRoot()) { if (ENABLE_LOG_CONSOLE) { - theLogHandler = prt::ConsoleLogHandler::create(prt::LogHandler::ALL, prt::LogHandler::ALL_COUNT); - prt::addLogHandler(theLogHandler); + mLogHandler = std::make_unique(); + prt::addLogHandler(mLogHandler.get()); } if (ENABLE_LOG_FILE) { - const std::wstring logPath = mPluginRootPath + prtu::getDirSeparator() + L"serlio.log"; - theFileLogHandler = + const std::wstring logPath = (mPluginRootPath / L"serlio.log").wstring(); + mFileLogHandler = prt::FileLogHandler::create(prt::LogHandler::ALL, prt::LogHandler::ALL_COUNT, logPath.c_str()); - prt::addLogHandler(theFileLogHandler); + prt::addLogHandler(mFileLogHandler); } // Not the best place, but here we are sure the console logger is running and we are before PRT init info LOG_INF << "Initializing Serlio Version " << SRL_VERSION << " ..."; if (DBG) - LOG_DBG << "initialized prt logger, plugin root path is " << mPluginRootPath; + LOG_DBG << "initialized prt logger, plugin root path is " << mPluginRootPath.wstring(); - std::vector extensionPaths = {mPluginRootPath + PRT_EXT_SUBDIR}; + std::vector extensionPaths = {(mPluginRootPath / PRT_EXT_SUBDIR).wstring()}; extensionPaths.insert(extensionPaths.end(), addExtDirs.begin(), addExtDirs.end()); if (DBG) LOG_DBG << "looking for prt extensions at\n" << extensionPaths; prt::Status status = prt::STATUS_UNSPECIFIED_ERROR; const auto extensionPathPtrs = prtu::toPtrVec(extensionPaths); - thePRT.reset(prt::init(extensionPathPtrs.data(), extensionPathPtrs.size(), PRT_LOG_LEVEL, &status)); + mPRTHandle.reset(prt::init(extensionPathPtrs.data(), extensionPathPtrs.size(), PRT_LOG_LEVEL, &status)); // early sanity check for maya encoder if (!verifyMayaEncoder()) { @@ -80,31 +76,33 @@ PRTContext::PRTContext(const std::vector& addExtDirs) : mPluginRoo status = prt::STATUS_ENCODER_NOT_FOUND; } - if (!thePRT || status != prt::STATUS_OK) { + if (!mPRTHandle || status != prt::STATUS_OK) { LOG_FTL << "Could not initialize PRT: " << prt::getStatusDescription(status); - thePRT.reset(); + mPRTHandle.reset(); } else { - theCache.reset(prt::CacheObject::create(prt::CacheObject::CACHE_TYPE_DEFAULT)); - mResolveMapCache = std::make_unique(prtu::getProcessTempDir(SRL_TMP_PREFIX)); + mPRTCache.reset(prt::CacheObject::create(prt::CacheObject::CACHE_TYPE_DEFAULT)); + mResolveMapCache = std::make_unique(); } } +bool PRTContext::isAlive() const { + return static_cast(mPRTHandle); +} + PRTContext::~PRTContext() { // the cache needs to be destructed before PRT, so reset them explicitely in the right order here - theCache.reset(); - thePRT.reset(); + mPRTCache.reset(); + mPRTHandle.reset(); - if (ENABLE_LOG_CONSOLE && (theLogHandler != nullptr)) { - prt::removeLogHandler(theLogHandler); - theLogHandler->destroy(); - theLogHandler = nullptr; + if (ENABLE_LOG_CONSOLE && (mLogHandler != nullptr)) { + prt::removeLogHandler(mLogHandler.get()); } - if (ENABLE_LOG_FILE && (theFileLogHandler != nullptr)) { - prt::removeLogHandler(theFileLogHandler); - theFileLogHandler->destroy(); - theFileLogHandler = nullptr; + if (ENABLE_LOG_FILE && (mFileLogHandler != nullptr)) { + prt::removeLogHandler(mFileLogHandler); + mFileLogHandler->destroy(); + mFileLogHandler = nullptr; } } diff --git a/src/serlio/PRTContext.h b/src/serlio/PRTContext.h index 51af8115..07ffcff0 100644 --- a/src/serlio/PRTContext.h +++ b/src/serlio/PRTContext.h @@ -3,7 +3,7 @@ * * See https://github.com/esri/serlio for build and usage instructions. * - * Copyright (c) 2012-2019 Esri R&D Center Zurich + * Copyright (c) 2012-2022 Esri R&D Center Zurich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,16 +21,19 @@ #include "serlioPlugin.h" +#include "utils/AssetCache.h" +#include "utils/LogHandler.h" #include "utils/ResolveMapCache.h" #include "utils/Utilities.h" #include #include -struct PRTContext; +class PRTContext; using PRTContextUPtr = std::unique_ptr; -struct SRL_TEST_EXPORTS_API PRTContext final { +class SRL_TEST_EXPORTS_API PRTContext final { +public: static PRTContext& get(); explicit PRTContext(const std::vector& addExtDirs = {}); @@ -40,14 +43,13 @@ struct SRL_TEST_EXPORTS_API PRTContext final { PRTContext& operator=(PRTContext&&) = delete; ~PRTContext(); - bool isAlive() const { - return static_cast(thePRT); - } + bool isAlive() const; - const std::wstring mPluginRootPath; // the path where serlio dso resides - ObjectUPtr thePRT; - CacheObjectUPtr theCache; - prt::ConsoleLogHandler* theLogHandler = nullptr; - prt::FileLogHandler* theFileLogHandler = nullptr; + const std::filesystem::path mPluginRootPath; // the path where serlio dso resides + AssetCache mAssetCache; + ObjectUPtr mPRTHandle; + CacheObjectUPtr mPRTCache; + logging::LogHandlerUPtr mLogHandler; + prt::FileLogHandler* mFileLogHandler = nullptr; ResolveMapCacheUPtr mResolveMapCache; }; diff --git a/src/serlio/icons/serlio.xpm b/src/serlio/icons/serlio.xpm new file mode 100644 index 00000000..efaa3ce4 --- /dev/null +++ b/src/serlio/icons/serlio.xpm @@ -0,0 +1,2127 @@ +/* XPM */ +static char *dummy[]={ +"382 444 1680 2", +"Qt c None", +".k c #ffffff", +"ab c #80ffff", +"at c #55aaaa", +"f1 c #55ffaa", +"#R c #aaffff", +"aa c #80bfbf", +"#z c #80ffbf", +"#Q c #66cc99", +"#h c #66cccc", +"#y c #55aaaa", +"bH c #80d5d5", +"bY c #6db6b6", +".Y c #6ddbb6", +"#g c #60bf9f", +"h8 c #60bfbf", +"wL c #60dfbf", +"ym c #80dfbf", +"er c #55c6aa", +".B c #71c6c6", +".X c #4db399", +"bn c #4db3b3", +"d6 c #66b3b3", +"ty c #66ccb3", +"yn c #66cccc", +"aT c #74d1b9", +".A c #55aaaa", +"dL c #55bfaa", +"h. c #6abfbf", +"vF c #6ad5bf", +"gG c #62b1b1", +"hV c #62c4b1", +"aD c #62c4c4", +"aS c #5bb6a4", +"vP c #6dc8b6", +"dp c #55bbaa", +"ai c #66ccbb", +"aC c #50af9f", +"uB c #60bfbf", +"v0 c #60cfbf", +"c6 c #5ab4a5", +"#X c #69c3b4", +"ch c #63c6b8", +"ah c #51aea1", +"fM c #5ec9bc", +"wb c #6bc9bc", +"fL c #59b3a6", +"#F c #66ccbf", +"x2 c #55aa9e", +"eW c #61c2b6", +"#W c #51aea2", +"uT c #68c5b9", +"fo c #59b1a6", +"ey c #64c8b1", +"#n c #64c8bc", +"#E c #55aa9f", +"u6 c #60bfb5", +"wu c #60cab5", +".# c #6acabf", +"wM c #52ad99", +"b4 c #52ada3", +".6 c #66ccb8", +"fG c #62c4b1", +"bu c #62c4ba", +"#m c #4caaa1", +"vf c #5ec6b3", +"wG c #68c6b3", +"bM c #52ad9b", +"ex c #52ada4", +"hr c #64bfb6", +".J c #64c8b6", +"t5 c #4fb09e", +"bc c #61c1b9", +"dR c #5ec4b3", +"wU c #66c4bb", +".5 c #52ad9c", +"tG c #63c5b5", +"ea c #50af9f", +"t# c #60bfaf", +"aZ c #60c7b7", +"fz c #64c1b2", +"dv c #64c1b9", +".l c #64c9b9", +".I c #4bad9e", +"xh c #53ad9e", +"vz c #62c3b4", +"bb c #50afa0", +"gL c #55b1a3", +"aI c #63c6b8", +"tU c #60c1b3", +"vL c #60c8b3", +"xb c #60c8ba", +"aY c #51ae9a", +"v1 c #51aea1", +"du c #4eb19d", +"gr c #55b1a3", +"ao c #62c4b7", +"tA c #60bfb3", +"cO c #60c6b3", +"xG c #51ae9b", +"iG c #5dc1ae", +"vV c #64c1b4", +"xq c #64c7b4", +"aH c #4faa9e", +"da c #4fb09e", +"g6 c #61c2b0", +"uw c #61c2b6", +"gd c #53b2a0", +"#5 c #65c4b8", +"tN c #5dbfb4", +"cn c #63c5b4", +"xC c #63c5b9", +"xP c #4faa99", +"v9 c #60c6b5", +"an c #4eac9b", +"cN c #53ac9b", +"uU c #53b1a1", +"uG c #5ec2b1", +"fT c #51ae9d", +"#L c #62c3b8", +"tg c #60bfaf", +"e6 c #60bfb5", +"c. c #60c5b5", +"xX c #4eac9c", +"wi c #63c6b6", +"#4 c #4dad99", +"wv c #4dad9e", +"cm c #52ad9e", +"tt c #61c2b3", +"#K c #50aa9b", +"fy c #50afa0", +"hv c #5fbeaf", +"#t c #64c3b4", +"y# c #4eac9d", +"eF c #5dbfb5", +"bT c #62c4b5", +"b9 c #52ad9f", +"#b c #60c5b7", +".j c #4caa9c", +"wH c #50aa9c", +"gZ c #50afa1", +"bA c #5ec2b3", +"#s c #4fac99", +"vg c #4fac9e", +"e5 c #4fb09e", +"ek c #60bfb2", +"bS c #51aa9d", +".Q c #62c5b7", +"#a c #4ea99c", +"wV c #4ead9c", +"eE c #52ada0", +"s9 c #5fbeb1", +"bi c #5fc2b6", +"f2 c #5ebfb3", +"bz c #4fab9b", +"vq c #4fab9f", +"dZ c #60c0b4", +".v c #60c4b8", +".P c #4daa9a", +"ej c #51ae9e", +"hQ c #5dbeb2", +"a5 c #61c2b6", +"w5 c #50ab9b", +"bh c #4ead9d", +"dD c #5ec0b4", +".u c #4daa9b", +"vA c #4dae9e", +"dY c #50af9c", +"u# c #50afa0", +"ud c #5fc2b3", +"aN c #5fc2b7", +"xc c #4bad9a", +"if c #5ebfb0", +"a4 c #4eaa9b", +"gT c #51ae9f", +"dg c #60c0b5", +"vM c #50ab9d", +"dC c #4fac9e", +"au c #61c6b7", +"xr c #4eaa9c", +"um c #51ae9f", +"s8 c #5cbfae", +"gy c #50af9d", +"c0 c #5ec0b2", +"aM c #4fac9b", +"df c #4ead9c", +"ac c #5fc2b4", +"xD c #4dab9a", +"ux c #51ae9e", +"xl c #61c3b5", +"yl c #61c6b5", +"gi c #4fac9f", +"ct c #60c0b3", +"vS c #60c3b6", +"as c #4eaa9a", +"w. c #4eaa9d", +"tq c #5ebeae", +"ut c #5ec2b2", +"xN c #4da999", +"cZ c #50ac9c", +"hC c #5cbfaf", +"uh c #5cbfb3", +"#S c #60c2b6", +"gj c #5ec0b0", +"cd c #5ec3b3", +"a# c #4eab9b", +"f0 c #51ae9f", +"s7 c #5dbeae", +"v5 c #60c1b4", +"ff c #5fc2b2", +"cs c #4fad9e", +"#A c #61c2b6", +"xJ c #61c5b6", +"xU c #4ba899", +"#P c #4da99a", +"fF c #50af9d", +"bZ c #5fc4b5", +"wf c #62c4b5", +"cc c #4eab9c", +"u2 c #4eae9c", +"tB c #5dbfb1", +"eP c #60bfb4", +"uN c #60c2b4", +"#i c #63c5b7", +"x8 c #4da99b", +"iM c #5cbdaf", +"ye c #61c6b7", +"#x c #4daa99", +"fe c #4fad9f", +"bI c #60c4b5", +"wD c #4eab9a", +"g0 c #5cbfb1", +"ul c #5fc1b3", +"bX c #4eac9b", +"h1 c #5bbfb1", +"uX c #5ebfb1", +"es c #5ec2b1", +".Z c #61c2b4", +"x1 c #61c5b4", +"vb c #50ad9c", +"eO c #4fae9d", +"tO c #51ae9d", +"bo c #5fc3b3", +"wz c #62c3b3", +"#f c #4ea999", +"wQ c #4eac9c", +"bG c #4daa9a", +"d7 c #60c2b5", +".C c #62c5b7", +"vo c #4fae9b", +"eq c #4eae9c", +"tf c #5bbeae", +"a9 c #60c3b4", +".W c #4daa9b", +"tY c #50af9d", +"s4 c #5abcaf", +"g5 c #4fad9e", +"hz c #4fb09e", +"hq c #52b09e", +"hS c #52b0a1", +"jz c #52b3a1", +"jR c #52b3a3", +"j6 c #54b3a3", +"mX c #54b5a3", +"n# c #54b5a6", +"nD c #57b5a6", +"nE c #57b5a8", +"nG c #57b8a8", +"oj c #59b8a8", +"ol c #59b8ab", +"ok c #59baab", +"pj c #59baad", +"se c #59bdad", +"rE c #5cbdad", +"s1 c #5cbdb0", +"hJ c #5ebfb0", +"vj c #5ebfb3", +"dM c #5ec2b3", +"bm c #4eac9a", +"vx c #4eac9d", +"d5 c #50ad9e", +"up c #5dc1b2", +"aU c #5fc3b4", +".z c #4da899", +"x# c #4dab9c", +"t8 c #4fad9e", +"wZ c #61c1b5", +".a c #61c4b7", +"dq c #60c2b3", +"a8 c #4eaa99", +"vJ c #4eac9b", +"tj c #5bbeb0", +"t4 c #5ebeb2", +"xm c #4ca99b", +"dK c #4fac9d", +"ui c #4fae9d", +"hk c #5dbfb0", +"aE c #5fc3b5", +"c7 c #5ec2b3", +"aR c #4dab9a", +"vT c #4dad9d", +"gF c #50ad9f", +"vE c #60c2b4", +"do c #4eac9c", +"aj c #60c3b3", +"xg c #60c3b5", +"xy c #4ba899", +"tm c #5dbfaf", +"aB c #4dac9c", +"v6 c #4fac9c", +"gn c #4fae9e", +"cy c #5fc2b2", +"c5 c #50ad9d", +"#Y c #5fc3b6", +"xK c #4da99a", +"ag c #4caa9b", +"f8 c #51ae9f", +"ci c #60c2b3", +"vZ c #60c2b5", +".m c #62c4b7", +"wg c #4eab9c", +"cx c #4dab9c", +"fp c #5cc1b2", +"#G c #60c3b4", +"xS c #4daa99", +"uO c #4fac9d", +"fK c #50af9e", +"b5 c #5fc2b3", +"#V c #4ba99b", +"wo c #4dab9b", +"cg c #4faa9b", +"eX c #5dc1b0", +"uJ c #5dc1b2", +"#o c #5fc3b4", +"x3 c #4ca998", +"uY c #4ead9c", +"yf c #4ba999", +"fn c #50ad9d", +"bN c #60c2b4", +"#D c #4daa9a", +"wA c #4daa9c", +"f9 c #5cbfb1", +"ez c #5ec1b3", +"b3 c #4eab9b", +"v. c #50ab9d", +"fU c #5ebfb1", +".7 c #62c3b5", +".i c #4ba898", +"eV c #4fae9c", +"iR c #5dbeb0", +"bv c #61c2b4", +"#l c #4dab99", +"wN c #4eab9b", +"tK c #50af9f", +"wt c #60c2b4", +"tw c #5bbfaf", +"u5 c #5dc1b1", +"eb c #5fc1b3", +"bL c #4daa9c", +"vk c #4dac9c", +".K c #61c3b6", +"go c #5cc0b0", +".4 c #4ca998", +"w0 c #4ca99a", +"ew c #4ead9c", +"tV c #50ad9e", +"bd c #5fc2b5", +"ih c #5dbfb0", +"dS c #5ec1b3", +"bt c #4fab9c", +"vu c #4fad9e", +"ve c #60c1b2", +".H c #4ca899", +"e# c #4fae9d", +"wT c #5ec2b3", +"a0 c #60c2b3", +"w8 c #4dab9a", +"fN c #5ebfb0", +"ya c #4da999", +"ba c #4dab9b", +"vG c #4eab9d", +"dw c #5fc1b3", +"gs c #5cc0b1", +"dQ c #4dac9c", +"ue c #4fac9e", +"aJ c #5fc4b4", +"w4 c #5fc4b5", +"xi c #4da99b", +"aX c #4caa9a", +"gK c #50ae9e", +"db c #5ec1b1", +"vQ c #4dac9d", +"te c #5bbcae", +"dt c #4fab9b", +"ap c #60c4b6", +"xv c #4caa9a", +"uq c #4ead9c", +"gz c #5ebfb1", +"gq c #4fae9f", +"tC c #5dbfb0", +"cP c #5fc1b3", +"vK c #5fc3b3", +".t c #4da99a", +"v2 c #4dab9a", +"gU c #5cc0b0", +"d# c #4eac9c", +"fH c #5ec0b3", +"#6 c #5fc4b4", +"xp c #61c4b4", +"xH c #4eab9a", +"uC c #4fac9d", +"u. c #5fc1b1", +"gc c #4fad9e", +"co c #60c3b4", +"am c #4daa99", +"wc c #4eaa9b", +"gH c #5dbeb1", +"fA c #5ec0b1", +".b c #60c3b6", +"xQ c #4ca999", +"cM c #4dab9c", +"uK c #4fad9c", +"#M c #5fc2b5", +"xB c #61c2b5", +"fS c #4ead9d", +"c# c #5fc3b2", +"#3 c #4cab9a", +"wl c #4eab9a", +"iT c #5dbeaf", +"v8 c #5ec1b3", +"gM c #5ebeb2", +"e7 c #5ec0b2", +"cl c #4fac9c", +"uV c #4fad9d", +"#u c #60c4b5", +"xY c #4da999", +"#J c #4ca99a", +"ww c #4eab9b", +"fx c #4fad9e", +"tu c #5dbeb0", +"bU c #5fc1b5", +"hu c #5dbeb0", +"eG c #5ec0b2", +"b8 c #4eab9b", +"u7 c #4eac9c", +"uQ c #5ec0b2", +"#c c #61c4b5", +".h c #4ca998", +"#r c #4caa99", +"e4 c #4fad9c", +"tH c #50ad9f", +"wq c #5ec1b3", +"bB c #60c1b3", +"wI c #4dab9b", +"bR c #4cab9a", +"vh c #4eab9c", +"hd c #5dbfb1", +"el c #5dc0b1", +"u1 c #5fc0b3", +"x7 c #60c3b4", +".R c #60c3b6", +"## c #4ba998", +"eD c #4eac9d", +"tR c #50ae9e", +"hT c #5cbeaf", +"bj c #5fc1b4", +"wW c #4dab9b", +"by c #4eaa9b", +"d0 c #5ec0b1", +"va c #5fc0b3", +".w c #61c3b6", +"vr c #4dac9c", +"to c #5cbeaf", +"ei c #4eac9c", +"ti c #5bbeaf", +"a6 c #60c1b4", +".O c #4ca998", +"w6 c #4caa9a", +"t1 c #4fae9e", +"t0 c #5dbfb0", +"dE c #5dc0b2", +"vn c #5fc0b3", +"yd c #60c2b5", +"bg c #4dab9b", +"vB c #4eac9b", +"yg c #4ca999", +"dX c #4fab9d", +"w1 c #5fc1b4", +"aO c #5fc2b4", +"xd c #4da999", +"ua c #4fad9c", +"gS c #4eac9e", +"dh c #5ec0b2", +"a3 c #4eaa9a", +"vN c #4eab9c", +"h5 c #5cbeae", +".c c #60c4b5", +"xs c #4daa9a", +"dB c #4dac9c", +"un c #50ac9e", +"av c #5fc3b3", +"x. c #61c3b5", +"gx c #4ead9d", +"c1 c #5fc0b2", +"aL c #4ca99b", +"vW c #4eac9b", +"vI c #5ec2b3", +"de c #4eab9c", +"uy c #4ead9c", +"i1 c #5cbdae", +"ad c #60c3b4", +"xk c #60c3b5", +"xE c #4ba99a", +"ar c #4daa99", +"w# c #4dab9b", +"gh c #50ae9d", +"cu c #5fc1b3", +".g c #4ba999", +"cY c #4eac9c", +"uH c #4fad9d", +"us c #5dc0b1", +"#T c #5fc3b5", +"xx c #61c4b5", +"xO c #4ca898", +"a. c #4daa9a", +"fZ c #4ead9e", +"hA c #5cbeaf", +"tr c #5dbfaf", +"v4 c #5ec1b3", +"ce c #5ec2b3", +"wj c #4eaa9b", +"tc c #5bbeae", +"cr c #4eab9b", +"uR c #4eac9b", +"ge c #5dc0b0", +"fg c #5dc0b1", +"#B c #60c3b4", +"xV c #4ca999", +"fE c #4ead9c", +"we c #5fc2b4", +"b0 c #60c2b4", +"wr c #4cab9a", +"tE c #50ad9e", +"eQ c #5ec0b2", +"uM c #5ec1b2", +".n c #5fc2b4", +"xR c #61c4b6", +"x9 c #4ca998", +"u3 c #4ead9c", +"tk c #5cbeae", +"#O c #4daa99", +"cb c #4eac9c", +"iq c #5cbeaf", +"wn c #5ec2b4", +"wE c #4daa9b", +"fd c #50ad9d", +"tD c #5dbeaf", +"uc c #5dbeb0", +"#j c #60c3b5", +"et c #5dc0b2", +"bJ c #60c1b3", +"x0 c #61c4b6", +"yh c #4ba899", +"vc c #4eac9c", +"wy c #5fc3b4", +"#w c #4caa9a", +"wR c #4caa9b", +"u9 c #5ec1b2", +"bW c #4dac9b", +"eN c #4dac9d", +"tZ c #50ae9e", +"tP c #50ae9f", +".0 c #61c3b6", +"bp c #5fc1b3", +".d c #61c2b5", +"d8 c #5ec0b1", +"wK c #5fc1b4", +"#e c #4ca999", +"w2 c #4caa9a", +"vi c #5dbfb2", +"bF c #4dab9b", +"ep c #4eac9c", +"t9 c #4eac9d", +"hO c #5cbdb0", +"tp c #5dbeb0", +".D c #60c3b6", +"b. c #5fc1b4", +"ug c #5dc0b2", +"dN c #5ec0b3", +"wY c #5fc3b4", +".V c #4daa9a", +"t7 c #5dbeb1", +"vt c #5ec0b2", +"bl c #4daa9a", +"d4 c #4eab9c", +"uj c #4fac9d", +"j. c #5bbdae", +"tx c #5cbeb0", +"gY c #50ae9e", +"dr c #5ec1b3", +"aV c #5ec1b4", +"h# c #5dbfb0", +"w7 c #60c3b4", +".y c #4ca998", +"xn c #4daa99", +"a7 c #4eaa9b", +"vD c #5ec0b2", +"dJ c #4fac9c", +"uu c #4fad9d", +"gE c #50ae9d", +"hE c #5bbdaf", +"c8 c #5fc1b3", +"aF c #60c2b4", +"xz c #4daa9a", +"uk c #5dc0b1", +"vO c #5ec0b2", +"xf c #5fc2b4", +"yb c #4ba899", +"aQ c #4eaa9a", +"dn c #4eac9b", +"uo c #5ebfb1", +"uE c #4ead9d", +"gm c #50ad9e", +"ak c #60c3b4", +"cz c #5ec2b3", +"xu c #5fc2b4", +"xL c #4da999", +"aA c #4daa9a", +"uA c #5dc0b0", +"tX c #5ec0b0", +"vY c #5fc0b2", +"c4 c #4dac9c", +"uP c #4fad9d", +"f7 c #50ad9d", +"#Z c #60c3b5", +"yk c #5bbbac", +"f3 c #5ec0b1", +"fq c #5ec0b2", +"cj c #5ec1b3", +"xF c #60c4b4", +"xT c #4ca898", +"uI c #5ec0b1", +"wa c #5fc1b2", +"af c #4caa9a", +"wp c #4eab9b", +"cw c #4eac9b", +"uZ c #4fad9c", +"fJ c #4fad9d", +"tT c #5dc0b0", +".s c #4ca998", +"je c #5bbdad", +"eY c #5ebfb2", +"b6 c #5fc1b4", +"#H c #5fc3b4", +"x4 c #4ca899", +"yi c #4ca89a", +"uS c #5ec1b1", +"wk c #5fc2b3", +"#U c #4daa99", +"wB c #4eab9a", +"cf c #4eab9b", +"fm c #4fad9c", +".f c #54b5a4", +"tQ c #5dbfb0", +"tL c #4fad9f", +"tb c #5cbeae", +"eA c #5fc0b2", +"bO c #60c1b4", +"#p c #60c2b5", +"xW c #60c3b5", +"#C c #4ca899", +"wO c #4daa9b", +"tM c #5cbeb0", +"u4 c #5fc0b2", +"ws c #5fc1b2", +"b2 c #4dab9a", +"vl c #4eac9b", +"eU c #4fad9d", +"tW c #50ae9e", +".8 c #5fc3b5", +"ec c #5ec0b2", +"bw c #60c2b4", +"y. c #61c3b6", +"#k c #4da999", +"tJ c #5cbfb1", +"vd c #5ec0b3", +"wF c #5fc1b3", +"bK c #4eab9b", +"vv c #4eac9c", +"ev c #4fad9d", +"t6 c #50ae9e", +"tF c #5dbeaf", +"be c #5ec1b3", +".L c #5fc2b4", +"ji c #5bbcae", +"dT c #5ec1b2", +"wS c #60c2b4", +".3 c #4ca999", +"w9 c #4ca99a", +"bs c #4caa9a", +"vH c #4dab9b", +"e. c #4ead9c", +"th c #5cbeb0", +"gk c #5dc0b1", +"vp c #5dc0b2", +"uf c #4fad9d", +"dx c #5fc0b2", +"a1 c #60c2b4", +".G c #4ba999", +"xj c #4baa99", +"b# c #4daa9a", +"vR c #4eab9b", +"vy c #5fc0b3", +"w3 c #60c2b5", +"dP c #4eac9d", +"ur c #4eac9e", +"gJ c #4fae9e", +"fV c #5dc0b1", +"aK c #5fc3b5", +"xw c #4daa9a", +"dc c #5fc1b2", +"xa c #60c3b4", +"aW c #4daa99", +"v3 c #4eab9b", +"ds c #4fab9c", +"uD c #4fac9c", +"gp c #50ad9d", +"tz c #5cbfaf", +"aq c #5fc2b4", +"xI c #4ba899", +"g7 c #5dbeb1", +"cQ c #5ec0b3", +"vU c #5fc1b4", +"xo c #5fc2b5", +"aG c #4daa99", +"wd c #4dab9a", +"d. c #4eac9c", +"uL c #4ead9c", +"gb c #4fae9d", +"uv c #5ec0b2", +"#7 c #61c3b4", +"al c #4daa99", +"iA c #5bbdae", +"hs c #5cbeaf", +"tv c #5cbfaf", +"fO c #5cbfb0", +"fB c #5dc0b1", +"uF c #5dc1b1", +"cp c #5ec1b2", +"v7 c #5fc2b3", +"xA c #5fc3b4", +"wm c #4caa9b", +"cL c #4eab9c", +"uW c #4eac9d", +"fR c #4eac9e", +"yj c #54b4a5", +"yc c #58b8aa", +"jk c #5cbeae", +"hW c #5cbeb0", +"h9 c #5dbeb0", +"t3 c #5ec0b1", +"ca c #5fc0b3", +"#N c #60c2b5", +"xZ c #4ba998", +"#2 c #4caa99", +"ck c #4dab9a", +"u8 c #4ead9c", +"e8 c #5ebfb2", +"wh c #5fc1b3", +"xM c #61c3b6", +"fw c #4fac9e", +"tI c #50ad9e", +"eH c #5dc0b1", +"bV c #5ec2b3", +"#v c #5fc3b4", +"#I c #4da999", +"wJ c #4daa9a", +"b7 c #4eab9b", +"e3 c #4fac9c", +"tS c #4fac9d", +"fI c #5ec0b0", +"em c #5ec0b1", +"u0 c #5ec1b1", +"bC c #5fc2b4", +"#d c #60c3b5", +"#q c #4caa99", +"wX c #4caa9a", +"bQ c #4cab9a", +"vs c #4dac9b", +"eC c #4ead9c", +"t2 c #4ead9d", +"v# c #5ec0b3", +"wC c #5ec1b4", +"x6 c #5fc2b5", +".S c #61c3b6", +"#. c #4daa9a", +"bx c #4daa9b", +"eh c #4eab9d", +"vC c #4fab9c", +"tn c #5cbdaf", +"g. c #5dbfb0", +"d1 c #5dc0b1", +"vm c #5ec0b2", +"bk c #5fc1b3", +"wP c #5fc2b3", +".x c #60c3b5", +".N c #4ca898", +"xe c #4da999", +"bf c #4eaa9a", +"dW c #4fab9c", +"ub c #4fac9c", +"dF c #5ec1b1", +"vw c #5fc1b2", +".e c #5fc2b3", +"xt c #4baa9a", +"a2 c #4caa9b", +"vX c #4dab9b", +"dA c #4ead9d", +"uz c #4ead9e", +"gw c #4fae9e", +"ta c #5bbdaf", +"ts c #5bbeb0", +"hw c #5cbfb1", +"c2 c #5dc1b3", +"di c #5ec1b3", +"aw c #5fc2b4", +"aP c #5fc3b5", +".o c #60c4b6", +"t. c #4aa797", +"tl c #4aa798", +"s2 c #4aa897", +"sW c #4aa898", +"s6 c #4aa998", +"s5 c #4ba797", +"s3 c #4ba798", +".r c #4ba898", +".9 c #4ba899", +"sA c #4ba998", +".M c #4ba999", +"sK c #4baa99", +"sQ c #4baa9a", +"td c #4ca898", +"sH c #4ca899", +"sY c #4ca998", +".F c #4ca999", +"#1 c #4ca99a", +"sk c #4caa99", +"#9 c #4caa9a", +"rQ c #4caa9b", +"dV c #4cab9a", +"dI c #4cab9b", +"eg c #4cab9c", +"sZ c #4da999", +"sj c #4da99a", +"s0 c #4da99b", +"r9 c #4daa99", +"az c #4daa9a", +"br c #4daa9b", +"ef c #4daa9c", +"dH c #4dab9a", +"bE c #4dab9b", +"dz c #4dab9c", +"eu c #4dac9b", +"d3 c #4dac9c", +"eM c #4dac9d", +"sR c #4dad9c", +"gX c #4dad9d", +"dO c #4eaa9b", +"d9 c #4eaa9c", +"cq c #4eab9b", +"c3 c #4eab9c", +"eS c #4eab9d", +"dU c #4eac9b", +"dm c #4eac9c", +"eL c #4eac9d", +"e1 c #4eac9e", +"eo c #4ead9c", +"e2 c #4ead9d", +"ft c #4ead9e", +"f6 c #4eae9d", +"gW c #4eae9e", +"ie c #4eaf9e", +"eR c #4fab9d", +"fc c #4fac9c", +"eT c #4fac9d", +"fv c #4fac9e", +"fY c #4fad9c", +"fb c #4fad9d", +"fu c #4fad9e", +"f5 c #4fad9f", +"fl c #4fae9d", +"fk c #4fae9e", +"gv c #4fae9f", +"gP c #4faf9e", +"gQ c #4faf9f", +"on c #4fafa0", +"hp c #4fb09f", +"ga c #50ad9d", +"fX c #50ad9e", +"fW c #50ad9f", +"hj c #50ae9d", +"fQ c #50ae9e", +"gu c #50ae9f", +"g4 c #50aea0", +"gg c #50af9e", +"gl c #50af9f", +"gR c #50afa0", +"hU c #50afa1", +"hc c #50b09f", +"hb c #50b0a0", +"hZ c #50b0a1", +"id c #50b1a0", +"iO c #50b1a1", +"ht c #51ae9e", +"hi c #51ae9f", +"hN c #51aea0", +"hM c #51af9e", +"hh c #51af9f", +"gV c #51afa0", +"hK c #51afa1", +"ho c #51b09f", +"hn c #51b0a0", +"hD c #51b0a1", +"ib c #51b0a2", +"h2 c #51b1a0", +"h4 c #51b1a1", +"iS c #51b1a2", +"ke c #51b1a3", +"iC c #51b2a1", +"jb c #51b2a2", +"jN c #51b2a3", +"oD c #52aea0", +"hB c #52afa0", +"hL c #52afa1", +"hy c #52b0a0", +"hR c #52b0a1", +"h7 c #52b0a2", +"h3 c #52b1a0", +"h0 c #52b1a1", +"hY c #52b1a2", +"i6 c #52b1a3", +"ic c #52b2a1", +"i4 c #52b2a2", +"d2 c #52b2a3", +"jW c #52b2a4", +"js c #52b3a2", +"jw c #52b3a3", +"jZ c #52b3a4", +"i7 c #53b0a2", +"jg c #53b1a1", +"iN c #53b1a2", +"i5 c #53b1a3", +"iY c #53b2a2", +"jf c #53b2a3", +"dG c #53b2a4", +"jX c #53b3a2", +".q c #53b3a3", +".2 c #53b3a4", +"b1 c #53b3a5", +"k# c #53b4a4", +"kd c #53b4a5", +"mQ c #53b5a4", +"mW c #53b5a5", +"jB c #54b0a3", +"jD c #54b1a2", +"rJ c #54b2a2", +"j5 c #54b2a3", +"ae c #54b2a4", +"j2 c #54b3a3", +".U c #54b3a4", +"bP c #54b3a5", +"ka c #54b4a3", +"ay c #54b4a4", +"fs c #54b4a5", +"f4 c #54b4a6", +"ee c #54b5a4", +"lu c #54b5a5", +"ml c #54b5a6", +"iB c #54b5a7", +"nn c #54b6a5", +"om c #54b6a6", +"lF c #54b6a7", +"qb c #55afa0", +"iz c #55b1a2", +"r6 c #55b1a3", +"pt c #55b2a3", +"e0 c #55b3a4", +"mc c #55b3a5", +"fa c #55b3a6", +"ln c #55b4a4", +"eB c #55b4a5", +"fD c #55b4a6", +"it c #55b4a7", +"gO c #55b5a4", +"g3 c #55b5a5", +"fP c #55b5a6", +"gI c #55b5a7", +"mY c #55b6a5", +"hx c #55b6a6", +"ig c #55b6a7", +"kf c #55b6a8", +"lL c #55b7a7", +"iu c #56b1a3", +"iP c #56b2a3", +"rR c #56b3a3", +"nm c #56b4a5", +"gf c #56b4a6", +"oo c #56b4a7", +"nF c #56b5a5", +"g# c #56b5a6", +"ha c #56b5a7", +"hm c #56b5a8", +"nu c #56b6a5", +"ia c #56b6a6", +"hI c #56b6a7", +"ms c #56b6a8", +"nB c #56b6a9", +"ij c #56b7a6", +"kc c #56b7a7", +"l1 c #56b7a8", +"lP c #56b7a9", +"nc c #56b8a8", +"lM c #56b8a9", +"iQ c #57b2a2", +"ju c #57b2a4", +"kH c #57b3a3", +"po c #57b3a5", +"ry c #57b4a4", +"mB c #57b4a6", +"n8 c #57b5a5", +"jo c #57b5a7", +"nC c #57b6a6", +"jU c #57b6a7", +"lt c #57b6a8", +"nt c #57b6a9", +"m1 c #57b7a7", +"l0 c #57b7a8", +"lh c #57b7a9", +"mR c #57b7aa", +"lO c #57b8a8", +"k0 c #57b8a9", +"kA c #57b8aa", +"kZ c #57b9a9", +"kb c #57b9aa", +"lm c #57b9ab", +"j7 c #57baaa", +"oE c #58b0a2", +"oN c #58b2a3", +"sP c #58b3a5", +"ku c #58b4a5", +"m5 c #58b5a7", +"m4 c #58b6a8", +"ni c #58b7a8", +"lN c #58b7a9", +"nA c #58b8a8", +"kg c #58b8a9", +"j9 c #58b8aa", +"j8 c #58b8ab", +"kh c #58b9a9", +"jV c #58b9aa", +"j4 c #58b9ab", +"k. c #58b9ac", +"j3 c #58baaa", +"jY c #58baab", +"jM c #58baac", +"j1 c #58bbab", +"jA c #58bbac", +"jt c #59b3a5", +"sx c #59b4a6", +"pk c #59b5a6", +"qq c #59b5a7", +"pd c #59b6a7", +"kI c #59b8a9", +"lY c #59b8aa", +"li c #59b9a9", +"jS c #59b9aa", +"jL c #59b9ab", +"jr c #59b9ac", +"j0 c #59baaa", +"jv c #59baab", +"i2 c #59baac", +"iH c #59baad", +"jK c #59bbab", +"iU c #59bbac", +"ii c #59bbad", +"i3 c #59bbae", +"ja c #59bcac", +"iW c #59bcad", +"iX c #59bcae", +"q6 c #5ab3a5", +"r3 c #5ab4a6", +"kW c #5ab5a8", +"mm c #5ab6a7", +"ns c #5ab7a8", +"l2 c #5ab9aa", +"jT c #5abaab", +"j# c #5abaac", +"iV c #5abaad", +"jQ c #5abbab", +"is c #5abbac", +"i. c #5abbad", +"hX c #5abbae", +"ir c #5abcac", +"hF c #5abcad", +"he c #5abcae", +"hf c #5abcaf", +"hG c #5abdad", +"hg c #5abdae", +"hl c #5abdaf", +"oI c #5bb3a4", +"ql c #5bb3a5", +"ip c #5bb4a6", +"i0 c #5bb5a6", +"q2 c #5bb5a7", +"iZ c #5bb6a6", +"mG c #5bb6a8", +"jl c #5bbbac", +"h6 c #5bbbad", +"i# c #5bbbae", +"jj c #5bbcac", +"hH c #5bbcad", +"g1 c #5bbcae", +"g9 c #5bbcaf", +"hP c #5bbdad", +"gA c #5bbdae", +"fj c #5bbdaf", +"fi c #5bbdb0", +"gD c #5bbeae", +"fh c #5bbeaf", +"e9 c #5bbeb0", +"f. c #5bbfaf", +"f# c #5bbfb0", +"ik c #5cb5a6", +"kz c #5cb5a7", +"sD c #5cb6a8", +"kN c #5cb6a9", +"mu c #5cb7a8", +"ne c #5cb8a9", +"nN c #5cb9a9", +"k7 c #5cbaad", +"rU c #5cbbac", +"rp c #5cbbad", +"g8 c #5cbcae", +"g2 c #5cbcaf", +"gC c #5cbdae", +"fC c #5cbdaf", +"fr c #5cbdb0", +"gB c #5cbeae", +"eK c #5cbeaf", +"dk c #5cbeb0", +"dj c #5cbeb1", +"eJ c #5cbfaf", +"dd c #5cbfb0", +"cX c #5cbfb1", +"cR c #5cbfb2", +"c9 c #5cc0b0", +"cT c #5cc0b1", +"cU c #5cc0b2", +"rl c #5db6a7", +"lg c #5db6a8", +"nf c #5db7aa", +"lU c #5dbbac", +"gN c #5dbdaf", +"gt c #5dbdb0", +"eZ c #5dbeaf", +"dl c #5dbeb0", +"dy c #5dbeb1", +"eI c #5dbfaf", +"cV c #5dbfb0", +"cE c #5dbfb1", +"cA c #5dbfb2", +"cS c #5dc0b0", +"cD c #5dc0b1", +"cv c #5dc0b2", +"cK c #5dc0b3", +"cH c #5dc1b1", +"cI c #5dc1b2", +"cJ c #5dc1b3", +"qk c #5eb3a5", +"qw c #5eb3a6", +"oR c #5eb4a6", +"sV c #5eb6a7", +"qr c #5eb7a9", +"le c #5eb7aa", +"mK c #5eb8a9", +"m. c #5eb8aa", +"rI c #5ebcad", +"sa c #5ebdae", +"ed c #5ebfb0", +"cG c #5ebfb1", +"cB c #5ebfb2", +"en c #5ec0b0", +"cC c #5ec0b1", +"bD c #5ec0b2", +"cF c #5ec0b3", +"cW c #5ec1b1", +"bq c #5ec1b2", +"ax c #5ec1b3", +"qR c #5fb3a5", +"pw c #5fb8ab", +"r. c #5fb9ab", +"rg c #5fbbae", +"k1 c #5fbdae", +"wx c #5fc0b3", +"#8 c #5fc1b3", +"#0 c #5fc2b3", +".E c #5fc2b4", +"jJ c #60b6aa", +"oB c #60b8a9", +"kM c #60b8aa", +"oc c #60b9aa", +"qM c #60b9ab", +"q1 c #60b9ac", +"mt c #60baab", +"x5 c #60c2b3", +".T c #60c2b4", +".1 c #60c3b4", +".p c #60c3b5", +"jH c #61b8aa", +"kX c #61b9aa", +"n2 c #61b9ac", +"lQ c #61bdaf", +"qa c #62b6a7", +"iF c #62b7aa", +"rZ c #62b8aa", +"ss c #62b9ab", +"mo c #62b9ac", +"o3 c #62baab", +"o8 c #62baac", +"rY c #62bdb0", +"iL c #63b6aa", +"iD c #63b7a9", +"iI c #63b8aa", +"pn c #63b9ad", +"kS c #64b9aa", +"kY c #64b9ab", +"sB c #64b9ac", +"mp c #64baab", +"sG c #64baac", +"nS c #64bbae", +"kT c #64bdb0", +"q5 c #65b9ab", +"mw c #65baac", +"lH c #65bfb1", +"oA c #66baac", +"jE c #67b9ac", +"jG c #67baad", +"kP c #67bbad", +"oV c #67bbae", +"nH c #67bdaf", +"rD c #67c0b3", +"qx c #68b9ac", +"qU c #68bbae", +"mv c #68bcaf", +"k5 c #68bdaf", +"mq c #68beb0", +"kJ c #69c0b2", +"qS c #6abaad", +"kr c #6abdaf", +"mh c #6abeb0", +"n9 c #6abeb1", +"r2 c #6ac2b4", +"rF c #6bbcae", +"oz c #6bbcaf", +"lC c #6bc1b4", +"mE c #6cbeb2", +"oY c #6dbdb0", +"su c #6dbeb1", +"nX c #6dbeb2", +"mi c #6dc1b3", +"q# c #6ebbae", +"pV c #6ebcaf", +"p4 c #6ec0b3", +"qG c #6fbbaf", +"pU c #6fbcb0", +"qH c #6fbdb0", +"kG c #6fbfb2", +"lG c #6fc0b3", +"si c #6fc3b6", +"pT c #70bdb1", +"sJ c #70beb3", +"kq c #70bfb3", +"mV c #70c0b4", +"mD c #70c1b4", +"kB c #70c3b6", +"oy c #71beb2", +"qX c #71bfb3", +"no c #71c1b4", +"np c #71c2b4", +"lx c #71c3b7", +"pS c #72bdb1", +"rb c #72bfb3", +"pR c #73bdb1", +"pQ c #73beb2", +"qY c #73bfb2", +"od c #73c1b4", +"pi c #73c1b5", +"me c #73c3b7", +"pP c #74bfb2", +"pO c #75bfb4", +"n3 c #75c2b6", +"ox c #76c0b4", +"rh c #76c1b4", +"rm c #76c1b5", +"rx c #76c6b9", +"pN c #77c0b4", +"so c #77c2b6", +"m8 c #77c3b7", +"m7 c #77c4b7", +"ny c #77c4b8", +"lq c #77c6ba", +"r5 c #77c7ba", +"oF c #78c1b4", +"qc c #78c1b5", +"sl c #78c1b6", +"rV c #78c2b6", +"kF c #78c3b6", +"mz c #78c4b8", +"pM c #79c1b5", +"nT c #79c3b8", +"nz c #79c4b8", +"pL c #7ac2b5", +"qN c #7ac3b7", +"m# c #7ac7ba", +"qv c #7bc1b6", +"q. c #7bc2b6", +"op c #7bc3b7", +"ow c #7bc3b8", +"nI c #7bc5b9", +"pK c #7dc2b7", +"oJ c #7dc3b7", +"rc c #7dc4b8", +"pe c #7dc5b9", +"sb c #7ec4b9", +"sM c #7ec5b9", +"mT c #7ec6bb", +"o. c #7ec6bc", +"p5 c #7fc5ba", +"lT c #7fc6bb", +"lj c #7fc9be", +"lA c #80c7bc", +"rM c #80cabe", +"rs c #80cabf", +"oO c #81c5b9", +"ov c #81c6bb", +"nY c #81c8bd", +"l7 c #81cabe", +"pW c #82c5ba", +"oq c #82c5bb", +"rt c #82c7bb", +"pc c #82c8bd", +"pJ c #83c6ba", +"or c #83c6bb", +"os c #83c6bc", +"o4 c #83c7bc", +"sp c #83c8bd", +"r8 c #83cbc1", +"jP c #84c7bc", +"sI c #84c7bd", +"jO c #84c8bd", +"nO c #84c9be", +"qp c #84c9bf", +"nx c #85cabe", +"lb c #85ccc2", +"ot c #86c7bc", +"ou c #86c8bd", +"pp c #86c8be", +"p9 c #87c7bc", +"oe c #87cac0", +"oS c #88c8bd", +"rK c #88cabf", +"l3 c #88ccc2", +"qQ c #89c7bd", +"pI c #89c8be", +"q7 c #89c9be", +"ro c #89cec3", +"r# c #8acac0", +"n4 c #8acbc1", +"nb c #8accc2", +"qy c #8bc9bf", +"sO c #8bcbc1", +"na c #8bccc1", +"o2 c #8cccc1", +"pX c #8dcac0", +"qd c #8dcbc0", +"pl c #8dccc1", +"nU c #8dcdc3", +"k8 c #8dcec4", +"rT c #8dcfc6", +"jq c #8fccc2", +"jp c #8fccc3", +"qC c #8fcdc2", +"kv c #8fcdc3", +"qB c #8fcdc4", +"nJ c #8fcec4", +"pH c #90ccc2", +"rz c #90cdc2", +"lV c #90cfc6", +"rH c #90d1c7", +"r7 c #91cdc4", +"oW c #91cec4", +"mH c #91cec5", +"rf c #91d0c7", +"il c #92cdc3", +"ky c #92cdc4", +"i8 c #92cec4", +"i9 c #93cdc4", +"lp c #93cec4", +"l6 c #93cec5", +"mJ c #93cfc5", +"o# c #93cfc6", +"k2 c #93d2c8", +"qL c #94d0c7", +"qm c #95cec5", +"sC c #95cfc6", +"qT c #95d0c7", +"p8 c #96cec5", +"pG c #96cfc5", +"nZ c #96d0c7", +"q9 c #96d1c8", +"lR c #96d2c9", +"qF c #97cec5", +"pY c #97cfc6", +"oZ c #98d1c8", +"kl c #98d1c9", +"lv c #98d2c8", +"mM c #98d2c9", +"qu c #99cfc6", +"sU c #99d1c7", +"o9 c #99d1c8", +"lZ c #99d2c9", +"rX c #99d4cb", +"oG c #9ad0c7", +"q4 c #9ad1c9", +"kU c #9ad4cc", +"qj c #9bd0c8", +"rk c #9cd2ca", +"pF c #9dd2c9", +"of c #9dd4cb", +"sd c #9dd6ce", +"sr c #9ed4cb", +"n5 c #9ed4cc", +"lI c #9ed5ce", +"oK c #9fd3ca", +"q3 c #9fd4cb", +"rP c #9fd7cf", +"r4 c #a0d4cb", +"sL c #a0d4cc", +"mr c #a0d7ce", +"qe c #a1d4cb", +"nV c #a1d5cd", +"kK c #a1d8cf", +"sF c #a2d5cd", +"ph c #a2d6ce", +"rC c #a2d8d0", +"iy c #a3d4cd", +"pE c #a3d5cc", +"iv c #a3d5cd", +"jy c #a3d6cd", +"nK c #a3d7cf", +"oP c #a4d4cd", +"la c #a4d6cd", +"jx c #a4d6ce", +"pZ c #a5d5cd", +"sX c #a5d6ce", +"kk c #a5d7cf", +"nv c #a5d7d0", +"nq c #a5d8d0", +"lD c #a5d9d1", +"nw c #a6d8d0", +"r1 c #a6dad2", +"qW c #a7d8cf", +"sh c #a7d8d0", +"oa c #a7d9d1", +"mj c #a7d9d2", +"kC c #a7dad2", +"ps c #a9d9d2", +"pD c #aad7d0", +"n0 c #aad9d2", +"st c #abdad2", +"rN c #acd9d2", +"sy c #acdad2", +"md c #acdad3", +"nP c #acdbd3", +"ly c #acdcd4", +"l# c #addad3", +"r0 c #aedad3", +"qz c #afdad3", +"pf c #afdbd4", +"qh c #afdcd5", +"mf c #afddd5", +"og c #b0dcd5", +"pC c #b1dad4", +"qn c #b1dbd4", +"pb c #b1dcd6", +"p0 c #b2dbd4", +"lr c #b2ded8", +"rw c #b2dfd8", +"oT c #b3dbd4", +"qV c #b3ddd6", +"n6 c #b3ddd7", +"qP c #b4dbd5", +"rq c #b4ddd6", +"rd c #b5ddd7", +"sn c #b5ded8", +"ma c #b5dfd9", +"o5 c #b6ded8", +"km c #b6dfd8", +"qt c #b7ddd6", +"pB c #b7ddd7", +"px c #b7ded8", +"o7 c #b7dfd8", +"ks c #b7dfd9", +"nL c #b7dfda", +"qf c #b8ded7", +"sw c #b8dfd9", +"mF c #b8dfda", +"lk c #b8e1db", +"oX c #b9dfd8", +"kj c #b9e0da", +"mZ c #b9e1da", +"m0 c #bae0da", +"m3 c #bbe1db", +"mS c #bbe1dc", +"rr c #bbe2dc", +"mU c #bce1db", +"m2 c #bce1dc", +"l8 c #bce2dd", +"oH c #bde0da", +"pu c #bde1db", +"rL c #bde3dd", +"p1 c #bee1db", +"sN c #bee1dc", +"n1 c #bee2dc", +"pv c #bfe3dd", +"qE c #c0e1dc", +"ru c #c0e2dd", +"nQ c #c0e3de", +"lc c #c0e5df", +"oL c #c1e2dd", +"o0 c #c1e3de", +"pm c #c1e4de", +"kp c #c2e4de", +"mC c #c2e4df", +"pq c #c3e4de", +"ri c #c3e4df", +"l4 c #c3e5e0", +"rn c #c3e6e1", +"qI c #c5e4df", +"oh c #c5e5e0", +"pA c #c6e4df", +"sz c #c6e5e0", +"jn c #c7e5e0", +"qO c #c7e6e1", +"n7 c #c7e6e2", +"k9 c #c7e7e2", +"im c #c8e5e0", +"jd c #c8e5e1", +"jc c #c8e6e1", +"kw c #c8e6e2", +"rS c #c8e8e3", +"lw c #c9e6e1", +"m9 c #c9e7e2", +"n. c #c9e7e3", +"lo c #cae7e2", +"l5 c #cae8e3", +"lW c #cae8e4", +"nl c #cbe8e4", +"s# c #cbe9e5", +"p2 c #cce7e3", +"p. c #cce8e3", +"re c #cce9e5", +"sm c #cde8e4", +"qK c #cde9e5", +"k3 c #cdeae6", +"kO c #cee9e5", +"rG c #ceeae6", +"sq c #cfe9e5", +"q8 c #cfeae6", +"qo c #d0e9e5", +"sf c #d0eae5", +"ob c #d0eae6", +"lS c #d0ebe7", +"sE c #d1eae6", +"pz c #d2eae6", +"nj c #d2ebe7", +"qA c #d3eae6", +"nk c #d3ebe7", +"qs c #d4ebe7", +"rA c #d4ebe8", +"mx c #d4ece8", +"kV c #d4ede9", +"qi c #d5ebe7", +"nR c #d5ece9", +"rW c #d5edea", +"qZ c #d6ece8", +"s. c #d6ece9", +"sT c #d6ede9", +"ra c #d7ede9", +"lJ c #d7eeeb", +"jC c #d8edea", +"kQ c #d8eeea", +"p3 c #d9edea", +"mO c #d9eeeb", +"sc c #d9efec", +"sS c #daeeeb", +"m6 c #daefeb", +"iE c #dbeeeb", +"kR c #dbefec", +"kL c #dbf0ed", +"jI c #dcefec", +"oU c #ddefec", +"nW c #ddf0ed", +"kx c #def0ed", +"mn c #def0ee", +"lE c #def1ee", +"jm c #dff0ed", +"mI c #dff0ee", +"pa c #dff1ee", +"rB c #dff2ef", +"kn c #e0f1ee", +"mA c #e0f1ef", +"rj c #e1f1ee", +"pg c #e1f2ef", +"o6 c #e2f2ef", +"mk c #e2f2f0", +"kD c #e2f3f0", +"nh c #e3f2f0", +"ng c #e3f3f0", +"oM c #e4f2f0", +"jh c #e4f3f0", +"sg c #e4f3f1", +"in c #e5f3f0", +"lB c #e5f3f1", +"lz c #e5f4f2", +"ki c #e6f3f1", +"mL c #e6f4f2", +"p7 c #e7f3f1", +"jF c #e7f4f2", +"oQ c #e8f4f2", +"mg c #e8f5f3", +"qD c #e9f4f2", +"oC c #e9f5f3", +"kE c #eaf5f3", +"p6 c #eaf5f4", +"my c #eaf6f4", +"o1 c #ebf6f4", +"ls c #ebf6f5", +"iK c #ecf6f4", +"iJ c #ecf6f5", +"rv c #ecf7f5", +"oi c #edf7f5", +"mb c #eef7f6", +"qg c #eff7f6", +"nr c #eff8f6", +"sv c #f0f8f6", +"ll c #f0f8f7", +"rO c #f1f8f7", +"mP c #f2f9f8", +"mN c #f3f9f8", +"l9 c #f3f9f9", +"iw c #f4faf9", +"nM c #f5faf9", +"ld c #f5fafa", +"io c #f6fbfa", +"pr c #f7fbfa", +"k6 c #f7fbfb", +"p# c #f8fbfb", +"lf c #f8fcfb", +"py c #f9fcfb", +"l. c #f9fcfc", +"nd c #fafcfc", +"lX c #fafdfc", +"qJ c #fbfdfc", +"k4 c #fbfdfd", +"kt c #fcfdfd", +"q0 c #fcfefd", +"ko c #fdfefe", +"lK c #fefefe", +"ix c #ffffff", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt.#.a.b.c.d.e.f.g.h.i.j.kQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt.l.m.n.o.p.p.p.p.p.q.r.r.r.r.s.t.u.kQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt.v.w.x.p.p.p.p.p.p.p.p.q.r.r.r.r.r.r.r.y.z.AQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt.B.C.D.p.p.p.p.E.p.p.E.p.p.p.q.r.F.r.F.F.r.F.r.r.G.H.IQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt.J.K.L.p.p.E.p.p.p.p.p.p.p.p.p.E.q.r.r.r.r.r.M.r.M.M.r.M.N.O.PQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt.Q.R.S.T.p.E.p.p.E.p.E.p.p.E.E.p.E.p.U.F.r.F.r.r.r.r.r.r.F.r.F.F.r.V.W.XQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt.Y.Z.0.1.p.E.p.p.p.E.T.p.1.p.E.p.p.T.p.1.p.2.M.F.M.F.F.r.F.r.r.r.r.r.r.F.r.F.3.4.5QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt.6.7.8.p.E.E.p.p.E.E.T.E.p.p.E.p.E.p.E.p.E.E.p.q.r.r.r.r.r.r.r.r.r.9.r.9.9.F.9.F.F.r#.###aQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt#b#c#d.T.p.T.1.p.E.p.E.p.p.p.E.E.p.p.E.T.p.T.1.p.E.U.F.F.F.F.F.F.F.F.F.r.F.r.r.r.r.r.r.F.r.F.F#e#f#gQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt#h#i#j.E.1.E.p.E.E.p.E.T.p.E.T.E.E.p.p.E.1.E.p.E.E.p.E.T.U.F.r.F.r.r.r.r.r.r.F.r.F.F.F.F.F.F.r.F.r.r.F.r#k#l#mQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt#n#o#p.E.T.p.E.p.T.E.p.1.E.p.E.E.p.E.T.E.T.p.E.p.T.E.p.1.E.p.U.F.M.F.M.M.F.M.F.F.9.F.9.9.F.9.F.F.F.F.F.F.M.F.M.M#q#r#sQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt#t#u#v.p.E.1.E.E.E.p.E.T.E.E.E.E.T.p.E.p.E.1.E.E.E.p.E.T.E.E.E.E.q.r.F.r.F.F.r.F.r.r.F.r.F.F.r.F.r.r.M.r.M.M.M.M.M.M.F.M.F#w#x#yQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt#z#A#B.p.T.E.E.E.p.E.p.T.E.E.1.p.E.T.E.p.T.E.E.E.p.E.p.T.E.E.1.p.E.T.E.2.M.M.M.M.M.F.M.F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.r.F.r.r.M#C#D#EQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt#F#G#H.E.1.E.E.T.E.T.E.E.E.E.E.p.E.E.E.E.1.E.E.T.E.T.E.E.E.E.E.p.E.E.E.E.1.U.F.F.F.F.F.F.F.F.F.M.F.M.M.r.M.r.r.F.r.F.F.r.F.r.r.F.r.F.F.F.F.F#I#J#KQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt#L#M#N.E.1.E.E.E.E.1.E.E.E.E.T.T.E.E.T.E.1.E.E.E.E.1.E.E.E.E.T.T.E.E.T.E.1.E.E.U.F.9.F.9.9.F.9.F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.F#O#P#QQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt#R#S#T.E.T.E.E.E.T.E.E.E.E.E.E.T.E.E.E.E.T.E.E.E.T.E.E.E.E.E.E.T.E.E.E.E.T.E.E.E.T.E.U.F.F.F.F.F.M.F.M.M.F.M.F.F.M.F.M.M.F.M.F.F.M.F.M.M.M.M.M.M.F.M.F.F.M.F.M.M#U#V#WQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt#X#Y#Z.E.T.E.E.E.E.T#0.E.T.T.E#0.E.E.E.E.T.E.E.E.E.T#0.E.T.T.E#0.E.E.E.E.T.E.E.E.E.T#0.E.U.F.M.F.M.M.F.M.F.F.F.F.F.F.F.F.F.F.F.F.F.F#1.F#1#1.F#1.F.F.F.F.F.F.M.F.M.M.F.M#2#3#4QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt#5#6#7.T.E#0.E#8.E.T.E#0.E.E.E.E.E.E.T.T.E#0.E#8.E.T.E#0.E.E.E.E.E.E.T.T.E#0.E#8.E.T.E#0.E.E.U.F.F.F.F.F#9.F#9#9#1#9#1#1.F#1.F.F.M.F.M.M.F.M.F.F.M.F.M.M.F.M.F.F#9.F#9#9.F#9.F.F.Ma.a#aaQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtabacad.E.E#0#8.E.E.T.E#0.E.E.E.T.E#8#0.E.E#0#8.E.E.T.E#0.E.E.E.T.E#8#0.E.E#0#8.E.E.T.E#0.E.E.E.T.Eae#1.F#1.F.F.F.F.F.F.M.F.M.M.F.M.F.F.F.F.F.F#9.F#9#9#1#9#1#1.F#1.F.F.F.F.F.F#9.F#9#9.F#9.FafagahQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtaiajak.E.E.E.E.E.E.E#0.E#8.E.E#8.E#0.E.E.E.E.E.E.E.E#0.E#8.E.E#8.E#0.E.E.E.E.E.E.E.E#0.E#8.E.E#8.E#0.E.U.F#9.F#9#9.F#9.F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.F.F#1.F#1#1.F#1.F.F.F.F.F.F.F.F.F.F.FalamanQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtaoapaq.E#8#0.E#8.E.E#8.E.T.E#0.E.E.E.E.E#8#0.E#8.E.E#8.E.T.E#0.E.E.E.E.E#8#0.E#8.E.E#8.E.T.E#0.E.E.E.E.E#8.U.F.F.F.F.F#9.F#9#9.F#9.F.F.F.F.F.F#9.F#9#9.F#9.F.F.F.F.F.F.F.F.F.F#9.F#9#9.F#9.F.F#9.F#9#9.F#9.F.FarasatQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt.kauavaw#8.E#8.E.E#8.E#8.E.E#8.Eax.E#0#8#8.E#8.E.E#8.E#8.E.E#8.Eax.E#0#8#8.E#8.E.E#8.E#8.E.E#8.Eax.E#0#8#8.E#8.Eayaz.Faz.F.F#1.F#1#1#9#1#9#9.F#9.F.F#9.F#9#9.F#9.F.F#9.F#9#9.F#9.F.F.F.F.F.F.F.F.F.F#9.F#9#9.F#9.F.F#9.FaAaBaCQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtaDaEaF#8.E.E#8.E#0.E#8.E.E.E#8#8.E#0.E#8.E.E#8.E#0.E#8.E.E.E#8#8.E#0.E#8.E.E#8.E#0.E#8.E.E.E#8#8.E#0.E#8.E.E#8.E#0.E.U#9#9#9#9#9.F#9.F.F.F.F.F.F#9.F#9#9.F#9.F.F#9.F#9#9.F#9.F.F#1.F#1#1#9#1#9#9.F#9.F.Faz.Fazaz.Faz.F.F#1.F#1#1aG.taHQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtaIaJaK#8#0#8.E#8.Eax#8.E#0ax#8#0ax#0.E#8#0#8.E#8.Eax#8.E#0ax#8#0ax#0.E#8#0#8.E#8.Eax#8.E#0ax#8#0ax#0.E#8#0#8.E#8.Eax#8.E.U.F#1.F#1#1.F#1.F.F#1.F#1#1#9#1#9#9.F#9.F.F#1.F#1#1.F#1.F.F#9.F#9#9.F#9.F.F#9.F#9#9.F#9.F.F.F.F.F.Faz.Fazaz#1az#1aLaMabQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtaNaOaP#8ax.E.Eax#8.E#8#0.E#8.E#8.E.E.E#8ax.E.Eax#8.E#8#0.E#8.E#8.E.E.E#8ax.E.Eax#8.E#8#0.E#8.E#8.E.E.E#8ax.E.Eax#8.E#8#0.E#8ay#9az#9azaz#9az#9#9#1#9#1#1.F#1.F.F#9.F#9#9az#9azaz.Faz.F.F#1.F#1#1az#1azaz#1az#1#1#9#1#9#9#9#9#9#9.F#9.F.Faz.Fazaz#1aQaRaSQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtaTaUaV#8#8ax.E.Eax#0ax.E#8ax.Eax#8.Eax#8#8ax.E.Eax#0ax.E#8ax.Eax#8.Eax#8#8ax.E.Eax#0ax.E#8ax.Eax#8.Eax#8#8ax.E.Eax#0ax.E#8ax.Eax#8ay#9.F#9.F.F.F.F.F.Faz.Fazazazazazaz.Faz.F.F#9.F#9#9.F#9.F.F#9.F#9#9.F#9.F.F.F.F.F.Faz.Fazaz.Faz.F.F#9.F#9#9#9#9#9#9.F#9.FaWaXaYQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtaZa0a1ax#8.E#8#8#8#8.E#8.E#8#8.E#0#8.Eax#8.E#8#8#8#8.E#8.E#8#8.E#0#8.Eax#8.E#8#8#8#8.E#8.E#8#8.E#0#8.Eax#8.E#8#8#8#8.E#8.E#8#8.E#0#8.E.2az#9az#9#9#9#9#9#9#1#9#1#1#9#1#9#9az#9azaz#9az#9#9az#9azaz#9az#9#9#1#9#1#1az#1azaz#9az#9#9#1#9#1#1az#1azaz.Faz.F.F#1.F#1#1aza2a3a4.kQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQta5a6.e#8#8#8#0ax.Eax#0axax#8.Eax#8#8ax#8#8#8#0ax.Eax#0axax#8.Eax#8#8ax#8#8#8#0ax.Eax#0axax#8.Eax#8#8ax#8#8#8#0ax.Eax#0axax#8.Eax#8#8ax#8#8ae.Faz.Fazaz.Faz.F.Faz.Fazaz.Faz.F.F#1.F#1#1#9#1#9#9az#9azaz.Faz.F.F#9.F#9#9#9#9#9#9.F#9.F.F#9.F#9#9#9#9#9#9#9#9#9#9az#9azaz.Faz.F.Fa7a8.AQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt.Ba9b.#0#0ax#8ax.E#8#8ax#8.E#8#0#8axax#0#0ax#8ax.E#8#8ax#8.E#8#0#8axax#0#0ax#8ax.E#8#8ax#8.E#8#0#8axax#0#0ax#8ax.E#8#8ax#8.E#8#0#8axax#0#0ax#8axay#9#9#9#9#9#9#9#9#9az#9azaz#9az#9#9az#9azazazazazaz#1az#1#1#9#1#9#9az#9azazazazazaz#9az#9#9az#9azaz#1az#1#1az#1azazazazazaz#9az#9#9#9#9b#babbQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtbcbdbe#8.E#8ax#8ax#0axax#8#8#0axaxaxax#8.E#8ax#8ax#0axax#8#8#0axaxaxax#8.E#8ax#8ax#0axax#8#8#0axaxaxax#8.E#8ax#8ax#0axax#8#8#0axaxaxax#8.E#8ax#8ax#0.2az#9az#9#9az#9azaz#9az#9#9.F#9.F.F#9.F#9#9#1#9#1#1#9#1#9#9az#9azaz#9az#9#9#1#9#1#1az#1azaz#1az#1#1az#1azaz#9az#9#9.F#9.F.Faz.Fazaz#9az#9#9bfbgbhQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtbibjbk#8#8#8ax#8ax#0ax#8#8ax#0axax#8#8#8#8#8ax#8ax#0ax#8#8ax#0axax#8#8#8#8#8ax#8ax#0ax#8#8ax#0axax#8#8#8#8#8ax#8ax#0ax#8#8ax#0axax#8#8#8#8#8ax#8ax#0ax#8.Uaz#1az#1#1#9#1#9#9az#9azaz#9az#9#9az#9azazazazazazazazazaz#9az#9#9az#9azaz#9az#9#9az#9azaz#9az#9#9az#9azazazazazaz#9az#9#9az#9azaz#1az#1#1#9#1#9blbmbnQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt.Ybobpax#8axaxaxax#8bqaxax#8axbqaxax#8ax#8axaxaxax#8bqaxax#8axbqaxax#8ax#8axaxaxax#8bqaxax#8axbqaxax#8ax#8axaxaxax#8bqaxax#8axbqaxax#8ax#8axaxaxax#8bqaxax#8ax.q#9az#9azaz#9az#9#9br#9brbr#9br#9#9#9#9#9#9#9#9#9#9#9#9#9#9az#9azaz#9az#9#9az#9azaz#9az#9#9az#9azaz#9az#9#9#9#9#9#9#9#9#9#9#9#9#9#9az#9azaz#9az#9#9brbsbt.5QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtbubvbw#8bq#8ax#8#8#8ax#8ax#8#8bqax#8#8#8bq#8ax#8#8#8ax#8ax#8#8bqax#8#8#8bq#8ax#8#8#8ax#8ax#8#8bqax#8#8#8bq#8ax#8#8#8ax#8ax#8#8bqax#8#8#8bq#8ax#8#8#8ax#8ax#8#8bqax.Uaz#9az#9#9az#9azaz#9az#9#9az#9azazazazazazbrazbrbrazbrazazazazazaz#9az#9#9az#9azazazazazaz#9az#9#9az#9azazazazazazbrazbrbrazbrazaz#9az#9#9az#9azaz#9az#9bxbybzQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtbAbBbCax#8axax#8#8axbqaxbDax#8axbq#8axax#8axax#8#8axbqaxbDax#8axbq#8axax#8axax#8#8axbqaxbDax#8axbq#8axax#8axax#8#8axbqaxbDax#8axbq#8axax#8axax#8#8axbqaxbDax#8axbq#8ax.2#9az#9azazbEazbEbEbrbEbrbr#9br#9#9#9#9#9#9az#9azaz#9az#9#9#9#9#9#9br#9brbrazbrazaz#9az#9#9az#9azazazazazaz#9az#9#9az#9azaz#9az#9#9az#9azazbEazbEbEbrbEbrbr#9brbFbG#gQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtbHbIbJax#8#8bDbq#8axbqbD#8ax#8#8bqax#8ax#8#8bDbq#8axbqbD#8ax#8#8bqax#8ax#8#8bDbq#8axbqbD#8ax#8#8bqax#8ax#8#8bDbq#8axbqbD#8ax#8#8bqax#8ax#8#8bDbq#8axbqbD#8ax#8#8bqax#8ax#8#8.2brazbrazaz#9az#9#9#9#9#9#9br#9brbrazbrazazbEazbEbEbrbEbrbr#9br#9#9az#9azazbrazbrbr#9br#9#9bE#9bEbEbrbEbrbr#9br#9#9#9#9#9#9br#9brbrazbrazaz#9az#9#9#9#9#9#9br#9brbrbKbLbMQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt#nbNbObqbDaxbqax#8axax#8axaxbqbqaxbD#8bqbDaxbqax#8axax#8axaxbqbqaxbD#8bqbDaxbqax#8axax#8axaxbqbqaxbD#8bqbDaxbqax#8axax#8axaxbqbqaxbD#8bqbDaxbqax#8axax#8axaxbqbqaxbD#8bqbDaxbqaxbPbrbEbrbEbEazbEazazazazazazazazazaz#9az#9#9br#9brbr#9br#9#9br#9brbr#9br#9#9#9#9#9#9br#9brbr#9br#9#9az#9azazbEazbEbEazbEazazbrazbrbrbEbrbEbEazbEazazazazazazazazazaz#9azbQbRbSQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtbTbUbVbqax#8ax#8axbDbqaxbDbq#8bDax#8axbqax#8ax#8axbDbqaxbDbq#8bDax#8axbqax#8ax#8axbDbqaxbDbq#8bDax#8axbqax#8ax#8axbDbqaxbDbq#8bDax#8axbqax#8ax#8axbDbqaxbDbq#8bDax#8axbqax#8ax#8axbD.q#9az#9azazbEazbEbE#9bE#9#9az#9azazbEazbEbEazbEazazazazazazbrazbrbrbEbrbEbEazbEazazbEazbEbEazbEazaz#9az#9#9az#9azazazazazaz#9az#9#9az#9azazbEazbEbE#9bE#9#9az#9azazbEazbEbEazbWbXbYQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt#zbZb0bD#8bD#8bqbDbDaxbD#8axbD#8bDax#8bD#8bD#8bqbDbDaxbD#8axbD#8bDax#8bD#8bD#8bqbDbDaxbD#8axbD#8bDax#8bD#8bD#8bqbDbDaxbD#8axbD#8bDax#8bD#8bD#8bqbDbDaxbD#8axbD#8bDax#8bD#8bD#8bqbDbDaxbD#8b1bE#9bE#9#9br#9brbrbEbrbEbE#9bE#9#9bE#9bEbE#9bE#9#9bE#9bEbEazbEazaz#9az#9#9az#9azazbEazbEbE#9bE#9#9bE#9bEbEbEbEbEbEazbEazazbEazbEbE#9bE#9#9br#9brbrbEbrbEbE#9bE#9#9bE#9bEbE#9bE#9b2b3b4QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt#Fb5b6bDbDaxbqaxbDaxaxbD#8bqaxbDaxaxaxbDbDaxbqaxbDaxaxbD#8bqaxbDaxaxaxbDbDaxbqaxbDaxaxbD#8bqaxbDaxaxaxbDbDaxbqaxbDaxaxbD#8bqaxbDaxaxaxbDbDaxbqaxbDaxaxbD#8bqaxbDaxaxaxbDbDaxbqaxbDaxaxbD#8bqax.2bEbEbEbEbEazbEazazazazazazbEazbEbEazbEazazbEazbEbEazbEazazbrazbrbrbEbrbEbEazbEazazbEazbEbEazbEazazbrazbrbrazbrazazbEazbEbEbEbEbEbEbEbEbEbEazbEazazazazazazbEazbEbEazbEazazbEazbEbEazb7b8b9QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtc.c#cabDbqbDbqaxbDbqbDaxbDaxbDbD#8bqbDbDbqbDbqaxbDbqbDaxbDaxbDbD#8bqbDbDbqbDbqaxbDbqbDaxbDaxbDbD#8bqbDbDbqbDbqaxbDbqbDaxbDaxbDbD#8bqbDbDbqbDbqaxbDbqbDaxbDaxbDbD#8bqbDbDbqbDbqaxbDbqbDaxbDaxbDbD#8.qazbrazbrbr#9br#9#9br#9brbrbEbrbEbEazbEazazbrazbrbrazbrazazbEazbEbEazbEazazbEazbEbE#9bE#9#9az#9azazbEazbEbEbrbEbrbr#9br#9#9az#9azazbrazbrbr#9br#9#9br#9brbrbEbrbEbEazbEazazbrazbrbrazbrazazcbcc#hQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt#RcdcebDaxbDaxaxaxbDbDbq#8bDbDaxbDbqaxbDaxbDaxaxaxbDbDbq#8bDbDaxbDbqaxbDaxbDaxaxaxbDbDbq#8bDbDaxbDbqaxbDaxbDaxaxaxbDbDbq#8bDbDaxbDbqaxbDaxbDaxaxaxbDbDbq#8bDbDaxbDbqaxbDaxbDaxaxaxbDbDbq#8bDbDaxbDbqaxbDb1bEbEbEbEbEbEbEbEbEbrbEbrbrazbrazazbEazbEbEbEbEbEbE#9bE#9#9br#9brbrbEbrbEbEbrbEbrbrbEbrbEbEbEbEbEbEazbEazazbEazbEbEbrbEbrbrbEbrbEbEbEbEbEbEbEbEbEbEbrbEbrbrazbrazazbEazbEbEbEbEbEbE#9bE#9#9br#9cfcg#WQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtchcicjaxbDbDbqbDbqbDbDax#8bDbqbDbqbDbDaxbDbDbqbDbqbDbDax#8bDbqbDbqbDbDaxbDbDbqbDbqbDbDax#8bDbqbDbqbDbDaxbDbDbqbDbqbDbDax#8bDbqbDbqbDbDaxbDbDbqbDbqbDbDax#8bDbqbDbqbDbDaxbDbDbqbDbqbDbDax#8bDbqbDbqbDbDaxbDbD.2bEazbEazazazazazazbEazbEbEbEbEbEbEazbEazazbEazbEbEazbEazazbEazbEbEazbEazazazazazazbEazbEbEazbEazazbEazbEbEbEbEbEbEazbEazazbEazbEbEazbEazazazazazazbEazbEbEbEbEbEbEazbEazazbEazbEbEazbEazazbEazbEbEckclcmQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtcncocpbDaxbqbDaxbDbDaxbDbqbDbDaxbDbqbDbDaxbqbDaxbDbDaxbDbqbDbDaxbDbqbDbDaxbqbDaxbDbDaxbDbqbDbDaxbDbqbDbDaxbqbDaxbDbDaxbDbqbDbDaxbDbqbDbDaxbqbDaxbDbDaxbDbqbDbDaxbDbqbDbDaxbqbDaxbDbDaxbDbqbDbDaxbDbqbDbDaxbqbDax.2bEbEbEbEbEbEbEbEbEbrbEbrbrbEbrbEbEbEbEbEbEbrbEbrbrbEbrbEbEbEbEbEbEbrbEbrbrcqbrcqcqbEcqbEbEbrbEbrbrbEbrbEbEazbEazazbrazbrbrbEbrbEbEbEbEbEbEbEbEbEbEbrbEbrbrbEbrbEbEbEbEbEbEbrbEbrbrbEbrbEbEbEbEbEbEbrbEbrcrcsaaQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtabctcubDaxcvbDbDcvbDbDbDbqbDbqcvbqbDbDbDaxcvbDbDcvbDbDbDbqbDbqcvbqbDbDbDaxcvbDbDcvbDbDbDbqbDbqcvbqbDbDbDaxcvbDbDcvbDbDbDbqbDbqcvbqbDbDbDaxcvbDbDcvbDbDbDbqbDbqcvbqbDbDbDaxcvbDbDcvbDbDbDbqbDbqcvbqbDbDbDaxcvbDbDcvbDbD.2brbEbrbEbEazbEazazbEazbEbEazbEazazbrazbrbrbEbrbEbEbEbEbEbEazbEazazbEazbEbEbEbEbEbEazbEazazbEazbEbEbEbEbEbEbEbEbEbEbEbEbEbEbrbEbrbrbEbrbEbEazbEazazbEazbEbEazbEazazbrazbrbrbEbrbEbEbEbEbEbEazbEazazbEazbEbEbEcwcxahQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtaicyczbDbqcAcBbDbDbDcCbqcvaxcDcDcDcEcFcBbDcGcDcvcHcHbDcDcCaxcAcAcBcEcvcEcDbDcvbDcIcIcvcIcGbDcEcBcBcAcJcvcIbDcAcCbDbDcEcCcAcKbDbDbDcDcJbDbqcDcGcBbqbqcBbDcDcIbDbDbDcAcFbDbDcBcEcEbqcDcCbqcvaxbDcEbDbDaxbDbqbDbDbDbqbqbDbqbDb1bEbEbEbEbEbEbEbEbEcqbEcqcqbEcqbEbEcqbEcqcqbEcqbEbEbrbEbrbrbrbrbrbrbEbrbEbEcqbEcqcqbEcqbEbEbEbEbEbEbrbEbrbrcqbrcqcqbEcqbEbEbEbEbEbEbEbEbEbEbEbEbEbEcqbEcqcqbEcqbEbEcqbEcqcqbEcqbEbEbrbEbrbrbrbrbrbrbEbrbEbEcqbEcqcLcMcNQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtcOcPcQbqbDcvcCcRcAbDcBcAcGcAcDcDcScvcDcIcBcAcBcTcCbDcCcTcEcTcIbDcDcCcAbDcAcDcvcEcEcDbDcUcvcUcCcGcTcGcAbqcEcUcvcRcAcIbDcDcEcAcvcvcVcAbDcDbDcRcBcTcDcWcDcEcAcvcDcAcEcDbDcDbDcDcCcRcBbDcBcXbDcvcDcGcDcvcEcIbDcvbDcvbDbqbDcvbDcvbq.2bEbEbEbEbEbEbEbEbEbEbEbEbEbrbEbrbrbEbrbEbEbrbEbrbrbEbrbEbEcqbEcqcqbEcqbEbEbrbEbrbrbEbrbEbEbrbEbrbrcqbrcqcqbEcqbEbEbrbEbrbrbEbrbEbEbEbEbEbEbEbEbEbEbEbEbEbEbrbEbrbrbEbrbEbEbrbEbrbrbEbrbEbEcqbEcqcqbEcqbEbEbrbEbrbrbEbrcYcZatQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt.kc0c1c2bqcvbDbDbDcCcAcCcAcEcBcDcBbDcGcAbDcXcCcGcDcBcDcBcGcEcBcDcCcGcEcXcHcvbDbDcAcAcBcDcEcvcEbqbDbDcvcUbqcEcvcGcEcEbDcvcAcCcAcWcCcCcEcAbDcUcGcAbDcAbDcvcDcEcDbDbDcBcBcvbqcUcBbDbDcCbDcGcAcEcBcHcBcDbDcvbqcEbDbDbDbDbDbDbDbDbDbqbDbD.UcqbrcqbrbrbEbrbEbEbEbEbEbEbEbEbEbEbEbEbEbEcqbEcqcqbEcqbEbEbEbEbEbEbEbEbEbEbEbEbEbEc3bEc3c3bEc3bEbEbEbEbEbEbEbEbEbEbEbEbEbEcqbEcqcqbrcqbrbrbEbrbEbEbEbEbEbEbEbEbEbEbEbEbEbEcqbEcqcqbEcqbEbEbEbEbEbEbEbEbEbEbEbEbEbEc3bEc3c3c4c5c6QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtaDc7c8cvcDbDbDbDcvbDcvcvcDcvbDcDcDcRcBcXcXcBcBcBcTcCcvcvcTcvcDc9cBcEcBcXcEcvcEcvcvbDcXcCcDcvcAcXcEcEcEcUcDcEcvbDcAcvcUcGcVcEcBcVcvcRcvcDcDcCcEbDcXcEcEcAcXcRbDcDcvcTcCcAc9cGcAcGcRcBcAcDc9cTbDcDcBcRcBcTcEcEbDcEcEcCcvcvcDcvbDcDbDcvbDcv.2bEbEbEbEbEbEbEbEbEc3bEc3c3bEc3bEbEbEbEbEbEbEbEbEbEbEbEbEbEcqbEcqcqbrcqbrbrbEbrbEbEbEbEbEbEc3bEc3c3bEc3bEbEbEbEbEbEbEbEbEbEbEbEbEbEbEbEbEbEbEbEbEbEc3bEc3c3bEc3bEbEbEbEbEbEbEbEbEbEbEbEbEbEcqbEcqcqbrcqbrbrbEbrbEbEbEbEbEbEc3bEd.d#daQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtaIdbdcbDcDbDbDbDbDcDbDbDbDcvcEcvcEcVcAcvcScEcCcCcEcXbDcEcGcCcEcEcCc9cDbDcEcBcBcBcGcDcvcEcEcEcDbDbDcXcAcBcDcEcEcEbDcDcGcvcvcvcGcGcGddbDbDddcvcvbDcCcDcCcEcEcEcAcAcvcDbDcAcEcvbDbDcBc9cBcAcBcBcDcDbDcDcEcEcScBcBbDcAcEcEbDbDbDcvcvcGddcvbDcDbD.UcqbEcqbEbEbEbEbEbEbEbEbEbEcqbEcqcqbEcqbEbEc3bEc3c3bEc3bEbEcqbEcqcqbEcqbEbEbEbEbEbEc3bEc3c3bEc3bEbEbEbEbEbEc3bEc3c3c3c3c3c3cqc3cqcqbEcqbEbEbEbEbEbEbEbEbEbEcqbEcqcqbEcqbEbEc3bEc3c3bEc3bEbEcqbEcqcqbEcqbEbEbEbEbEbEc3bEc3c3bEc3bEbEbEdedfabQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt.kdgdhdibDbDcDbDbDcvbDcDbDbDbDcvcVcBdjcAbDcvddcDcvcDcEddcCcEcBcXcEbDddcCbDcvcVcEbDcAcEcVcBcEcCcEc9cGcEcEcEcEcDcAbDcvcEcVcEcvbDcvcTbDdkcvcvcGcVcEbDcXcvcTcvcCcAcDcXcCddcEcGcAcTcvcAcAcDc9bDcBcCcAcVcBdjcBcBcEcDbDcDcvcAcXcBcEcBcRddcEdlbDbDcvcDbDbD.2bEbEbEbEbEdmbEdmdmc3dmc3c3bEc3bEbEbEbEbEbEbEbEbEbEbEbEbEbEbEbEbEbEc3bEc3c3bEc3bEbEbEbEbEbEcqbEcqcqbEcqbEbEbEbEbEbEbEbEbEbEbEbEbEbEbEbEbEbEdmbEdmdmc3dmc3c3bEc3bEbEbEbEbEbEbEbEbEbEbEbEbEbEbEbEbEbEc3bEc3c3bEc3bEbEbEbEbEbEcqbEcqcqbEcqbEdndodpQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtaTdqdrbDbDcDbDbDcDbDbDcDcDbDcvcDcEbDcDcDcDddcvcGddcAcvcDcDcCcAcScVcEcBcEcEcEcBcBcScCcDcTcTcEcUcEcEcEbDcGcGddcEcDcDbDcAcScEcAcAcVdlbDcEbDbDcTcvcvcEcBcGcVcVcEcvcTcXcCcAcCcCcXcAcBddcEcEcXcXbDcvcXcEcDcDcBcBcDcBbDcXcBcEc9c9bDcvcVcEcAcBcAbDddbDbDcVcCcv.2c3bEc3bEbEbEbEbEbEbEbEbEbEc3bEc3c3bEc3bEbEdmbEdmdmc3dmc3c3bEc3bEbEbEbEbEbEc3bEc3c3bEc3bEbEdmbEdmdmc3dmc3c3bEc3bEbEbEbEbEbEc3bEc3c3bEc3bEbEbEbEbEbEbEbEbEbEc3bEc3c3bEc3bEbEdmbEdmdmc3dmc3c3bEc3bEbEbEbEbEbEc3bEc3c3bEc3bEbEdmbEdmdmc3dmc3c3bEdsdtduQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtdvdwdxcDcDbDcEbDcDcEbDcDbDbDcvbDbDbDbDcDcTcDcXcEcEcEcEcVcAbDcvcEcEcAcvcScXcAcXbDddddcBcEcCbDcUcGcEcDbDcEddcCcEcEcXdycDc9bDcEcTbDcAcAcBcDcVcEcEcEcDcEcvcTcvcvcEcGcEcEbDddcXcAdjcDcScVcAcEcEcGcRcAbDbDcAcEc9cDddcGcEcEbDcDcAcBcTcDbDbDcEcScXcAcXcEc9cEcEcDcG.Udzdmc3dmdmbEdmbEbEc3bEc3c3bEc3bEbEbEbEbEbEc3bEc3c3bEc3bEbEc3bEc3c3bEc3bEbEbEbEbEbEc3bEc3c3bEc3bEbEcqbEcqcqdmcqdmdmbEdmbEbEc3bEc3c3dmc3dmdmbEdmbEbEc3bEc3c3bEc3bEbEbEbEbEbEc3bEc3c3bEc3bEbEc3bEc3c3bEc3bEbEbEbEbEbEc3bEc3c3bEc3bEbEcqbEcqcqdmcqdmdAdBdC.kQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtdDdEdFbDcEbDbDcvcDbDbDcvbDcDcEcDbDcEcDbDcEbDcvcvcDcBcDcXcDcTddcVcGdjcXcEdycvbDcAcDcCcAcXcAcEdlcEcBcVcScCddbDcDcTc9cBcCcXcGcDdkc9cvcEcDbDcXbDcAcRcEcvcEcTbDcDcXcTbDcXcVcBcEcGcEcAcEbDcAcDbDcDddcEbDddcTcvdkcAbDcvcDcBcDcAcDc9cXcDcBdycEcBdkcCbDcvcDcCcAcTcAcEcEdGbrdHazazdIdmbEdmdmbEdmbEbEc3bEc3c3dmc3dmdmcqdmcqcqbEcqbEbEc3bEc3c3dmc3dmdmcqdmcqcqdmcqdmdmbEdmbEbEbEbEbEbEbEbEbEbEc3bEc3c3bEc3bEbEbEbEbEbEdmbEdmdmbEdmbEbEc3bEc3c3dmc3dmdmcqdmcqcqbEcqbEbEc3bEc3c3dmc3dmdmcqdmcqcqdmcqdmdmbEdmbEbEbEbEbEbEbEbEbEbEc3bEdJdKdLQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt.BdMdNcEbDcEbDbDcEbDcEbDcDcEcEbDcEbDbDcEbDcEbDbDcEcGdlcvddcEcEcDcXcGcDcVcEcVcEcAdjcvcEcAc9dycEcAcXcEcEdycBdycDcCcVcDcXcDcEddddcEcVcEcGcXcEcXbDbDcEcAcVcAcDcEcEcEdlcvbDcXcvcEcGcvcEcGcVcEdddydycAcXcCcCdkcEcVcEcEddcEdjbDcXcEcEcDddcBcDcVcAcEcAcBdycEddbDcScEcEcAcEcDayc3bEc3azazdOdIdzc3dmc3dmdmbEdmbEbEdmbEdmdmbEdmbEbEdmbEdmdmbEdmbEbEbEbEbEbEbEbEbEbEc3bEc3c3bEc3bEbEdmbEdmdmdmdmdmdmbEdmbEbEdmbEdmdmbEdmbEbEc3bEc3c3dmc3dmdmbEdmbEbEdmbEdmdmbEdmbEbEdmbEdmdmbEdmbEbEbEbEbEbEbEbEbEbEc3bEc3c3bEc3bEbEdmbEdmdmdmdmdmdmbEdmbEbEdPdQbbQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtdRdSdTcvcEbDbDbDcEcEbDcDbDcEcDbDcDbDcDcvcEbDbDbDcEcEbDcXcGcEcDcGcVcGddcvcXcDcDcDcVcEcEcXbDdkcDcAcEcAcScDdkcAcBcEdycEcDcSbDdkddcDc9cDcEcAcEcEcBcGdddybDcDcEcEcDcAcXcBcDcvdlbDcEbDcXdycAcEbDcVcVbDcEbDcTcEcXcEcvcCdlcVcEddcBdjcXbDcDbDcXcAddcDcCcBcVcEcAcXbDddc9cEddbDcScvaedzdmdzc3dm#9dUbEazbEdVdVdIdmbEdmdmc3dmc3c3dmc3dmdmbEdmbEbEc3bEc3c3dmc3dmdmbEdmbEbEdmbEdmdmc3dmc3c3c3c3c3c3bEc3bEbEdmbEdmdmc3dmc3c3dmc3dmdmbEdmbEbEbEbEbEbEdmbEdmdmc3dmc3c3dmc3dmdmbEdmbEbEc3bEc3c3dmc3dmdmbEdmbEbEdmbEdmdmc3dmc3c3c3c3c3c3bEc3bEbEdmbEdmdmc3dmdWdXdYQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtdZd0d1cEcEbDcDcEcEcDcEcDbDcEcDcEbDcEcDcEcEbDcDcEcEcDcEcDbDcEcXcEcGcXcVdldlcGddcXcXcXcXcXcBcEcTcVcEdycDcEdycvc9cVddddcXddcEcEcVdycEcVcTcXddbDcEcEcEcXcEcXcEdyddcXcvcEcXcXcXbDcVcEdlcTcEcDbDcEcTcEcGcDcVcEcEbDcTdkcXcSdjcScCcVddcDcAddcXdkdkcAcTdyddddddcEcBcEcXcVcDdydddkdkcDd2dHc3dVc3c3bEc3bEbrbrdHdzdzd3c3dmdmbEdmbEbEc3bEc3c3bEc3bEbEdmbEdmdmbEdmbEbEdmbEdmdmbEdmbEbEbEbEbEbEdmbEdmdmc3dmc3c3bEc3bEbEbEbEbEbEc3bEc3c3bEc3bEbEc3bEc3c3dmc3dmdmbEdmbEbEc3bEc3c3bEc3bEbEdmbEdmdmbEdmbEbEdmbEdmdmbEdmbEbEbEbEbEbEdmbEdmdmc3dmc3c3bEc3bEbEbEbEbEbEc3d4d5d6QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt.Yd7d8cEbDcEcDbDcEbDcEcDbDbDcEcEcDbDcEcEbDcEcDbDcEbDcEcDbDbDcEcEcVbDddddbDcXcXcEdlcGdlcVcEbDcXdycTcBcVcVcGcEcDcAcEcAcEcDcCcCcXcVcXcEdydybDdycEcCcXcDcXcTcBcBddcEcDcEcXddbDdkc9bDcXcAcEcEcDcvdlcEcVbDdkcXcGcXcDcBcVbDcVcDcvcGdjcEcXcCdldlcCcVcEcvdkbDdjcDcAcBddcEc9cBcVcVcBdycDcBdk.Udmc3dUdmd3dUdmdmc3d9c3c3c3azdzdVbEdmbEdmdmdmdmdmdmbEdmbEbEc3bEc3c3dmc3dmdmc3dmc3c3dmc3dmdmdmdmdmdmbEdmbEbEdmbEdmdmc3dmc3c3dmc3dmdmdmdmdmdmdmdmdmdmc3dmc3c3bEc3bEbEdmbEdmdmdmdmdmdmbEdmbEbEc3bEc3c3dmc3dmdmc3dmc3c3dmc3dmdmdmdmdmdmbEdmbEbEdmbEdmdmc3dmc3c3dmc3dmdmdmdmdme.e#eaQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtbuebeccDcEcDcEcEbDcEcEcDcEcDcEcEcCbDcEcDcEcDcEcEbDcEcEcDcEcDcEcEcCbDdlcDdlcVcXdkcEcXcXcEcEdddlcXedcEcXddcXcTcVddcGdkcXcDdkcEcEcVcEcCcXcScXcEcEdycBddcVcEdkc9cXdkcScBcXcEcEcDcXdkcDcEdkc9cEcXcDcXcGcEdlcSdlcVdkcXcvdjcXcDcVcTcVdkcCcvdjcTdjcXcVcXcBddddcEdjdddjdjcCcAddcDddc9cEcXbDdjdyeedmefdmdzdzdHegdHbEdmbrc3c3bEdmdmcqegd3dzegdmdzdmdmbEdmbEbEdmbEdmdmdzdmdzdzbEdzbEbEdmbEdmdmbEdmbEbEdmbEdmdmdmdmdmdmbEdmbEbEdmbEdmdmdzdmdzdzbEdzbEbEdmbEdmdmdmdmdmdmdzdmdzdzdmdzdmdmbEdmbEbEdmbEdmdmdzdmdzdzbEdzbEbEdmbEdmdmbEdmbEbEdmbEdmdmdmdmdmdmbEdmbEbEdmbEdmdmdzdmdzdzbEeheiejQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtekelemcEcCcEcDcEcEbDcDcEbDcEcEbDcEcDcEcEcCcEcDcEcEbDcDcEbDcEcEbDcEcDcEcEcVcVcScVcEcEcVdlbDcXdkcEcXcVdydlcDdlcTcXcXcDcTcXcGddcVcAcEcDcEcEendydddkcVcAcXcXbDdydycCcEdddlcXcVddcVcVcEcCcDdycvdkddbDdkcDcEcEcEcEcVdldlbDcDcEcGcXcXcAcXcVcVcEcVcEcTcXcXcAcXcVcCddcEcEcEcXdjdjcGcEc9ddcVcDc9cDcBayeod3dmdmdmc3dmc3d3c3dmdzc3dmd9dmc3cqdmd3dmdzdmdzc3dmc3dmdmdmdmdmdmc3dmc3c3dmc3dmdmdmdmdmdmc3dmc3c3dmc3dmdmbEdmbEbEc3bEc3c3dmc3dmdmdmdmdmdmdmdmdmdmc3dmc3c3dmc3dmdmdmdmdmdmc3dmc3c3dmc3dmdmdmdmdmdmc3dmc3c3dmc3dmdmdmdmdmdmc3dmc3c3dmc3dmdmbEdmbEbEc3bEc3c3dmc3dmdmdmdmdmdmdmdmdmdmepeqerQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtbHesetcCcEcDcEcEcEcCcEcEcEcEcEcEcEcDcEcCcEcDcEcEcEcCcEcEcEcEcEcEcEcDcEcCcEcDcEcEddcGdkcVcVcVdkcXdlddcXcEcVcXdldldleddkcEcXcXdjdjcXddcVcEcVddcEcEcEcDdddydkcXddddcXcEdyendyddcXdkcXcDcEddcEcEdjdjcEc9cXcVcXcDddcVcXcGcXcEdldlcEcEcEcTcXcDcEcVcVcVcEcCdkcEcXcXcVcVdjcXcVcVcEcTdjdjdkcEdjcEdddddkcEaec3dmdzdmd3bEdmbrbrdUbEd3dmdIeudzefd9dzd9brd3dzd3d3dmd3dmdmbEdmbEbEdmbEdmdmdmdmdmdmbEdmbEbEdmbEdmdmdmdmdmdmdmdmdmdmdmdmdmdmc3dmc3c3dmc3dmdmbEdmbEbEdmbEdmdmdzdmdzdzc3dzc3c3dmc3dmdmdmdmdmdmbEdmbEbEdmbEdmdmdmdmdmdmbEdmbEbEdmbEdmdmdmdmdmdmdmdmdmdmdmdmdmdmc3dmc3c3dmc3dmdmbEdmbEbEdmbEevewexQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQteyezeAcEcEcEcEcCcEcDcEcEcEcDcDcEcDcEcCcEcEcEcEcCcEcDcEcEcEcDcDcEcDcEcCcEcEcEcEcCcEcDcVddcEddcEdkcVcEcDdkdldlcXcScEcVcXdkdycVcVcEcDdkcVcXcXcXddedcVcVcEcEcEcEcDcEcEcVenddcXcXdycGdycEcVcXdkcTcTddc9cEcGdjcEdydkcScXcTcEdkcEcXcEcXcEdlcVcEcEcEcXcDcEcDcXcVcVcDcDdycEcXcDcVcVcVcXcGcVcEcVdkdjcDcXcEcDcXeBc3c3dmd3c3dmdmdmc3dmc3c3dmdmdmdmd3d3dmc3c3c3c3dmd3c3d3c3c3brc3c3c3dmc3dmdmdmdmdmdmdmdmdmdmdmdmdmdmc3dmc3c3dmc3dmdmdmdmdmdmdmdmdmdmc3dmc3c3dmc3dmdmdmdmdmdmdmdmdmdmdmdmdmdmdmdmdmdmc3dmc3c3c3c3c3c3dmc3dmdmdmdmdmdmdmdmdmdmdmdmdmdmc3dmc3c3dmc3dmdmdmdmdmdmdmdmdmdmc3dmc3c3dmc3dmdmdmdmdmdmeCeDeEQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQteFeGeHcDcEcVcEcEcDcEcVcEcEcEcCcEcEcEcEcDcEcVcEcEcDcEcVcEcEcEcCcEcEcEcEcDcEcVcEcEcDcEcVdkcVcVcDcVcXdkdddddkdkcEdkcScEddcEcXcXcGcXdldkdlddcXcVdkcXcTcEeIcVcXcEedcEcEdydyc9cVcVddddcEddcVcEdydycGcEcXddcXcEcEeJcEdjcDdjddcXdkdkcScEddcXcEcDcEcVdlcEcVcEeKdlcXcXcCcXcVdjcEdddkdlcXdkcXcVcVcVddcEcGcVdjcEdkcXaeeoeLc3dmeLeLeLdmeoeodmdmc3efdUdzdzdmegdmdmd9c3c3c3c3c3d3eueMdmeLeLdmeLdmdmc3dmc3c3dmc3dmdmc3dmc3c3dmc3dmdmdmdmdmdmdzdmdzdzdmdzdmdmdmdmdmdmdmdmdmdmdmdmdmdmdzdmdzdzdmdzdmdmc3dmc3c3dmc3dmdmeLdmeLeLdmeLdmdmc3dmc3c3dmc3dmdmc3dmc3c3dmc3dmdmdmdmdmdmdzdmdzdzdmdzdmdmdmdmdmdmdmdmdmdmdmdmdmdmdzdmdzeNeObYQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtaaePeQcEcDcEcEcEcEcDcVcEcEcEcEcDcEcEcEcEcDcEcEcEcEcDcVcEcEcEcEcDcEcEcEcEcDcEcEcEcEcDcVcEcEcEdkcVdkcVdlcEcVcVcEdkddcVdkdldkdkcXcVcXcXcXcXcXcXcXdkdlcVeKcEdjdjcVcTcVdddjcVcXcEdkdycEcDeIcEcVddddcXdydydddycScVcVddddcTcVddcEdjdjcDcXdkcEddcDcEcEcXcXcEeIcEcVcEdkcDdkcXdjcXcEcXcVdjcEcDdddycXcVcVcDcVcXddcEddcVcXbPeLdmeLdmeRc3eSdmdmeod3eod3dmeTc3c3c3dUdmdUeudmdmc3c3bEc3cqdmcqeud3dmdmdmdmdmdmdmdmeLdmeLeLdmeLdmdmdmdmdmdmdmdmdmdmdmdmdmdmeLdmeLeLc3eLc3c3dmc3dmdmdmdmdmdmdmdmdmdmdmdmdmdmdmdmdmdmdmdmdmdmdmdmdmdmdmdmdmdmdmdmdmdmeLdmeLeLdmeLdmdmdmdmdmdmdmdmdmdmdmdmdmdmeLdmeLeLc3eLc3c3dmc3dmdmdmdmdmdmdmdmdmdmdmeUeVb4QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQteWeXeYcEcVcEcEcEcEcVcEcEcEcVcDcVcEcVcEcEcVcEcEcEcEcVcEcEcEcVcDcVcEcVcEcEcVcEcEcEcEcVcEcEcEcVcDcVdydldydddddkcVcEcXeIcXddcEdkdddlcEcVcEdlcVdkcXdkcXdddldkdlddcDcVdkeKcXcXddcVddcVdkdlcEdycEeIcDdlcVeIcVddeJdydydyddcVdkddcXeJc9eJcEcVcEdjdlcXdkddcEcVcVcXcVddcXcVdleZdlcEcVcXcXcXcVddcVcXcVeKcEdlcXddcXcVcVcVddcEcXe0eLdmeLeoeoeoeLeTeTe1eLeLe2eoeMdmdmc3dmdmdmdmdmdmdmd3d3c3c3eSbEeLeMbreLc3c3dmc3dmdmdmdmdmdmeLdmeLeLdmeLdmdmc3dmc3c3dmc3dmdmdmdmdmdmdmdmdmdmdmdmdmdmeLdmeLeLdmeLdmdmdmdmdmdmdmdmdmdmdmdmdmdmeLdmeLeLc3eLc3c3dmc3dmdmdmdmdmdmeLdmeLeLdmeLdmdmc3dmc3c3dmc3dmdmdmdmdmdmdmdmdmdmdmdmdmdmeLdmeLeLdmeLdmdmdmdmdme3e4e5QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQte6e7e8cEcEcEcVcEcEddcEcEcEcEddcEcEcEcEcEcEcEcVcEcEddcEcEcEcEddcEcEcEcEcEcEcEcVcEcEddcEcEcEcEddcEcEcEdddjdycEeKdldye9dkcEdkdleJcEdkdddkdkdkdkeKdlcEddddddcEcXdddldkdlcEdkdkdyddcXcXeJcVcVcVdjddcEdydydyddcVcVeJcXcEf.dydydycVdddkddddddcEcEcEdkcEcAe9ddcXcXcEddcEcXcXcXdlcVcEcVcEdleKcXcXcEcXf#cVdjcEdycXcXcEcVdjcXdddlfafbdmeTeLeoeoeod3eLdmc3dmfce1dmeLe1dmeLdmc3eTdmc3fcdUeLdmdmc3c3c3c3dUdmdmbEbEbEdmdmeLdmeLeLdmeLdmdmdmdmdmdmeLdmeLeLeTeLeTeTeLeTeLeLdmeLdmdmdmdmdmdmdmdmdmdmeLdmeLeLdmeLdmdmeTdmeTeTdmeTdmdmdmdmdmdmdmdmdmdmdmdmdmdmeLdmeLeLdmeLdmdmdmdmdmdmeLdmeLeLeTeLeTeTeLeTeLeLdmeLdmdmdmdmdmdmdmdmdmdmeLdmeLeLdmeLdmdmeTdmfdfe#hQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt#RfffgcEcVddcEdkcEcEcEcVcEcEcVcEcVcEcEcEcVddcEdkcEcEcEcVcEcEcVcEcVcEcEcEcVddcEdkcEcEcEcVcEcEcVcEcVcEcEcEcVfhcVeKcXcXdjcVdddydkcVcVdkdlcEeZf#cEfidkcVcVdkdkcEcVdkeKdkcXcXddeKcEe9cEdlcXdldjcXcVddeJcVdkcEdkdddleKdydydkeIddcEeJdydldydddycVf#cVfjddddcVcVdjcEdkddeJcXcEddcVf#cEe9cXcEdlcVcXdlcVcXddcEcVcEcVeJcVfjdycEcXcVcVcX.UeLeLeTdmeTfbeLfkfle2fleLeLeLeTeLdmeodmd3eodmc3eTdmdmdmd3dUeudmc3c3eRc3c3eTdUeLcqdmbEdmdmdmeLdmeLeLdmeLdmdmdmdmdmdmdmdmdmdmdmdmdmdmdmdmdmdmfbdmfbfbeLfbeLeLdmeLdmdmdmdmdmdmdmdmdmdmdmdmdmdmdmdmdmdmeTdmeTeTdmeTdmdmdmdmdmdmeLdmeLeLdmeLdmdmdmdmdmdmdmdmdmdmdmdmdmdmdmdmdmdmfbdmfbfbeLfbeLeLdmeLdmdmdmdmdmdmdmdmdmdmfmfnfoQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtchfpfqcVcVdkcEcEcEcEcVcEcEcVcEcEddddcEcVcVdkcEcEcEcEcVcEcEcVcEcEddddcEcVcVdkcEcEcEcEcVcEcEcVcEcEddddcEcVcVdkcEdydldyeKcXcXeJdddjdkdkdddldkficVcEcVdleJdkcVdkdkcVddddcEeZdde9cXcXcXcXeZdldlddcEcXdddddjddeIeKdjcVdjdycVdycEeIcEcXeJddddcVdlfrdddycVcVeJddcXcVdddddddddjcVdddkdkddcEcEddcXcEddcXdleKeKcEcVeKdkcXcXcXcEcVcEcEeKdlcXfsftfbfufbfbdmeTdmfcdmeodmdme2dmeLfveLeTdmdme2eofbfbeSeTeSeLdmeMdmdmeudmc3c3fcdmfcfcd3dmd3dmfbdmfbfbeLfbeLeLdmeLdmdmdmdmdmdmeLdmeLeLdmeLdmdmdmdmdmdmdmdmdmdmeLdmeLeLdmeLdmdmfbdmfbfbeLfbeLeLdmeLdmdmdmdmdmdmeTdmeTeTdmeTdmdmfbdmfbfbeLfbeLeLdmeLdmdmdmdmdmdmeLdmeLeLdmeLdmdmdmdmdmdmdmdmdmdmeLdmeLeLdmeLdmdmfbdmfbfbeLfbfwfxfyQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtfzfAfBcVcEcEcEcEcVcVcEdkcEcVdkcEcVcEcEcVcEcEcEcEcVcVcEdkcEcVdkcEcVcEcEcVcEcEcEcEcVcVcEdkcEcVdkcEcVcEcEcVcEcEcEcEcVdkdyfrddeJeKcXddddcXdkdydddddydkeIcVeKcXeZfCddeJdkcVeIdkdkdlcVcVddcXdkdldddkdleZcXdleKdkdjcXcXcVeJdde9dkdkfrcEcVcVdyeJcVddddcEeJdldydkdkcVdkcXddddddcVcEdjdjcAdkeKdkfCcXcVdkcXcVcXcEeZcVcXcEdleZddcXe9cVeIddcEcVdkfDftfkfbflfkfbfudmdme1e2fueLdme2eodmeTeLc3fce1d3eLeLdmeLdmc3eSdmeLeMdUd3d3dmdmdmdmdmdzcqc3eMd3eLbEdmeLdmeLeLfbeLfbfbdmfbdmdmeLdmeLeLfbeLfbfbdmfbdmdmeLdmeLeLdmeLdmdmdmdmdmdmeLdmeLeLdmeLdmdmeLdmeLeLdmeLdmdmdmdmdmdmeLdmeLeLdmeLdmdmeLdmeLeLfbeLfbfbdmfbdmdmeLdmeLeLfbeLfbfbdmfbdmdmeLdmeLeLdmeLdmdmdmdmdmdmeLdmeLeLdmeLdmdmeLfEfFaaQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtfGfHfIdkcVcEdkcVcEdkcEcEcVcVcEcEcVcEcVdkcVcEdkcVcEdkcEcEcVcVcEcEcVcEcVdkcVcEdkcVcEdkcEcEcVcVcEcEcVcEcVdkcVcEdkcVcEdkcEdkdkdkdkdyeJdydlfjeKdkeKeJddfjdyddcVcVdkcEeKcVeIfheJcEfidkdkfCcEdleZcVcEcXddcXddfjeZdle9cVcEdkcXcXddddcVddeKdycVfrcVcEeKeIcVe9cVddeJddcEdyddcVcEfhddcEfhcVcEe9cEdjdldlcXdkcVcEcVe9cVcDe9ddcEfCdlcEcVcVdlcXeIcXdde9eBfbdmfcfceLfufbfbfbfbeTdmfceTdme1e1fle2fbfbfvfueLe1eLe2d3dmeLc3eSeLfbeLfbe2eLe2eMeLeTeLdmfbeLeoeMeLdmeLdmdmdmdmdmdmeLdmeLeLdmeLdmdmdmdmdmdmeTdmeTeTdmeTdmdmeLdmeLeLfbeLfbfbeLfbeLeLdmeLdmdmeLdmeLeLfbeLfbfbeLfbeLeLfbeLfbfbeLfbeLeLdmeLdmdmdmdmdmdmeLdmeLeLdmeLdmdmdmdmdmdmeTdmeTeTdmeTdmdmeLdmeLeLfbeLfbfbeLfbeLeLdmeLdmdmeLdmeLfJfKfLQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtfMfNfOcEdkcEcEdkcEdkcVcEdkcEdkcEcVdkdkcEdkcEcEdkcEdkcVcEdkcEdkcEcVdkdkcEdkcEcEdkcEdkcVcEdkcEdkcEcVdkdkcEdkcEcEdkcEdkcVcEdkdkfhdkeKfrfrdjfrdddyfjcXfheJddeKdjfrdddkdkdkcVdkcXcVe9dddkdkdkfidleKdlddfCdkcXfjcXcXfCdkfCddcXdkcXdkcXeIdkdkddeKdkdydkdydkeIcVdkcXeKddeJfhdkdyfrddcVfidddkcVddfhdddkdjdkfrfrdkeKcEcEfhcXdkddcXe9dlfCcEeKdkdkcXe9cVfPfQe2fQdmfceTeLftfbflfbflfbeTfkfceLfbeLflfleofbdmc3fudmfufbe2e2eLeLc3eLdmdmdmd3dmd3eRdmeTeTc3c3dUd3dmdmfbfbfbfbfbfbdmfbdmdmfbdmfbfbdmfbdmdmeLdmeLeLfbeLfbfbdmfbdmdmfbdmfbfbdmfbdmdmfbdmfbfbeLfbeLeLdmeLdmdmdmdmdmdmeTdmeTeTdmeTdmdmfbdmfbfbfbfbfbfbdmfbdmdmfbdmfbfbdmfbdmdmeLdmeLeLfbeLfbfbdmfbdmdmfbdmfbfbdmfbdmdmfbdmfbfbeLfbeLeLdmfRfSfTQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtaDfUfVcEddcEcVcVdkcEcVcEdkdkcEcVcEdkcVcEddcEcVcVdkcEcVcEdkdkcEcVcEdkcVcEddcEcVcVdkcEcVcEdkdkcEcVcEdkcVcEddcEcVcVdkcEcVcEdkdkcEdlcVfheJdkdkdkeKeKfrdjcVcVfjeKddeJcXfrdldjfhdydkdkdkcVcVdle9dkdkdkcVfidkdleKdlddcVfjcXcVcXfCdkcXdddlfjeKcXddcXeIeIeKdjeIdjdkfjcVeIdyeKeIcXf#cEcVcVfrcVdlcVe9dkdkeJcXdkcVcEddcEdddleKdkeJcEfhdkcXddcEdkeZdlddcEeKcVfDfufQfWfQfQdmfbfbe2e2eLeLeLflfbfXfbfvfbe1ftfle2flfbeTfbdmdme1eLeLeLfleLfbfXeLfbeLdmfYeMe2fbeSeTeSdmeLc3eMc3dmeLdmdmfbdmfbfbeTfbeTeTfbeTfbfbdmfbdmdmdmdmdmdmfbdmfbfbeLfbeLeLfbeLfbfbdmfbdmdmeLdmeLeLfbeLfbfbeLfbeLeLfbeLfbfbeLfbeLeLeLeLeLeLdmeLdmdmfbdmfbfbeTfbeTeTfbeTfbfbdmfbdmdmdmdmdmdmfbdmfbfbeLfbeLeLfbeLfbfbdmfbdmdmeLdmeLeLfbeLfbfbfZf0f1QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtf2f3dkcEdkcVdkdkcEcVdkdkcVdkcVcEdkcVdkcEdkcVdkdkcEcVdkdkcVdkcVcEdkcVdkcEdkcVdkdkcEcVdkdkcVdkcVcEdkcVdkcEdkcVdkdkcEcVdkdkcVdkcVcEficVfjddfreJfjfjddeKfCdkeKfreJddeKeJfjdkeKdkfifidydkfifieZeKeZcEdkdkdkdkfieZfCfCcEeJdkfjdddkddcXdkeKfCdkdkdddkdkcXeJdkeKdkdkeKdkfjdldkdddkdde9e9cDdlfhfrdddkcVcVdkeJdkcEfheJdkdkcEeJfieKcVfCcVcEdkddddcVe9eZfCfCdlf4eTftftftf5fbfueLfbfteTfte1fuftf6fleTfbdme2fte2e2e1eMe2eLeLfbeTfbfudme2dmd3fbeTeTfbdUfbd3d3eMdmeSeLeTdzfbfcc3fcdzeLdmeLdmdmeLdmeLeLeLeLeLeLdmeLdmdmeLdmeLeLfbeLfbfbdmfbdmdmeLdmeLeLeLeLeLeLfbeLfbfbdmfbdmdmfbdmfbfbdmfbdmdmeLdmeLeLfbeLfbfbeLfbeLeLdmeLdmdmeLdmeLeLeLeLeLeLdmeLdmdmeLdmeLeLfbeLfbfbdmfbdmdmeLdmeLeLeLeLeLeLfbeLfbfbdmfbdmdmfbdmf7f8c6QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt#Rf9g.cEdkdkcEdkcVcVdkcEdkcVcEcVdkdkcVcEdkdkcEdkcVcVdkcEdkcVcEcVdkdkcVcEdkdkcEdkcVcVdkcEdkcVcEcVdkdkcVcEdkdkcEdkcVcVdkcEdkcVcEcVdkdkeKdkfjfjdkdkcVeZfhdkfheJdkeKfifCdlddfjfjcVdkddeJfidkfrdldkddeKfieIdle9e9cEe9eIdkeKdldkeZcXcVdkdkddcXfCfCcEfCeZcVdkcXdkddcVcVfheKcVdkdkdkcEfrdleIe9cXdkcVcEeJfrdkdlddfie9dlfhddcSfhcXdkcEcXdlfCdleKcEeKeKcEe9cVddfCg#fQfQfbfQfkfQfkfQfQfufQfufufcfteLe2fufbflfbflgafkfueLfkeoeoe2dmeLfvgae1fufbe1fbeMeLfbfveTeTfbe2e2fbeLeTeLeLeTeLfce2eMfbd3eMfbeLfbfbfbfbfbfbfbfbfbfbeLfbeLeLdmeLdmdmfbdmfbfbfbfbfbfbdmfbdmdmeLdmeLeLfbeLfbfbeLfbeLeLfbeLfbfbfbfbfbfbeLfbeLeLfbeLfbfbeLfbeLeLfbeLfbfbfbfbfbfbfbfbfbfbeLfbeLeLdmeLdmdmfbdmfbfbfbfbfbfbdmfbdmdmeLdmeLeLfbeLfbfbeLfbeLeLgbgcgdQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtbcgecEdkcVdkcVdkdkcVdkdkcVdkcVdkdkcVcEdkcVdkcVdkdkcVdkdkcVdkcVdkdkcVcEdkcVdkcVdkdkcVdkdkcVdkcVdkdkcVcEdkcVdkcVdkdkcVdkdkcVdkcVdkdkcVcEfheZfheZfjdkcVfjdkcVfheKfhfCeKdkficVfrdlfhfjeKeKeKddfreKfrfidldkeKdkeKeIe9fheJfificVfieZeKe9eZcXdkcVdkddfCfjeZe9dkeZfjdddkfrddcVe9eIdkcVfjfrcVeKfrdleKddeKfhcVcEfjcVfrdlfifhddfjfhdddkdddkficVcXfCddfCeJeKe9dde9e9gfggfufQftfueLftfuftfkfufkfQfbfXfQfke1fkfbe1fleLflfXeTfudmeLf6eofkfbeLfbe1eLeLeMeLeofldmeTeTeLfbeLdme2eLeofbeTfbeTfbdme2d3d3fbbEfbfbeLfbeLeLeLeLeLeLfbeLfbfbfbfbfbfbeLfbeLeLfbeLfbfbdmfbdmdmfbdmfbfbeLfbeLeLdmeLdmdmfbdmfbfbeLfbeLeLfbeLfbfbfbfbfbfbdmfbdmdmfbdmfbfbeLfbeLeLeLeLeLeLfbeLfbfbfbfbfbfbeLfbeLeLfbeLfbfbdmfbdmdmfbdmfbfbeLfbeLeLdmeLdmdmfbdmfbghgiabQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtgjgkdkdkcVdkcVdkdkcEcVdkcVdkdkcEdkcVdkdkcVdkcVdkdkcEcVdkcVdkdkcEdkcVdkdkcVdkcVdkdkcEcVdkcVdkdkcEdkcVdkdkcVdkcVdkdkcEcVdkcVdkdkcEdkcVdkdkcVdkeKfheKdkeKe9eKdkdkdldkeJfhfheKfrdlfrdkdydlfreJdkfjdddkdlfrfrdkfrcVdkdkcVeIeKcVfhdkdkdkcVdkeKddfCeKfjfjcXdddkcVfCfCcXfCeKfjdkdkdkeJeKeKcXcVfrcVfrdkcVfreIeKe9eJdkdlfrfrcVcEdkdlfhe9dkfhcVdkeKdkdkeJeKdkdkeKdkcVfDfQfkfQggfQfQfkfQfkftfQftftglfufQfQfbfQfkfkftfle1e1fufvfbgagafkfbfue2fle1fvfbe1fbfbfbfbfbfbeLfbeSeSfbeLfcfYdmfbdmc3eSc3eLeLfbeLe2e2fbdmfbfbfbfbfbfbeLfbeLeLfbeLfbfbfbfbfbfbeLfbeLeLfbeLfbfbfbfbfbfbeLfbeLeLfbeLfbfbfbfbfbfbeLfbeLeLfbeLfbfbdmfbdmdmeLdmeLeLfbeLfbfbfbfbfbfbfbfbfbfbeLfbeLeLfbeLfbfbfbfbfbfbeLfbeLeLfbeLfbfbfbfbfbfbeLfbeLeLfbeLfbfbfbfbfbfbeLgmgndpQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtgocVdkcVdkdkdkcVdkdkdkdkdkdkdkcVdkcVdkcVdkdkdkcVdkdkdkdkdkdkdkcVdkcVdkcVdkdkdkcVdkdkdkdkdkdkdkcVdkcVdkcVdkdkdkcVdkdkdkdkdkdkdkcVdkcVdkcVdkfjfjeKfjdkfhfhfjfifheKfjdldkeKfhfhfheJfCfrfrfrfjfhfreKfjeJfjeJfifrfidlfifrfidkfCfCeKeJdkdkdkdkeKfifCeIe9fCfjfjdkdkdkeKfCeKfCdkfjfjdkddeKdkfheKfifjdkcVdkdldkeIfjeKe9cVfhdkfrfre9e9djdde9eJdkcVfhdkeKcVfidkeKeKdkdkbPe1fQftfQfkfufQfufufbfufkfkftfQftfufue1fueLfkftfufkflfkfufueLfbeTeLfue2fue2fbfufbgae1fbeLe2e2eMfbeTfbfbfbfYe2fce2fbeTfbeTeTc3fceLeMe2dzfbfbeLfbeLeLfbeLfbfbeLfbeLeLeLeLeLeLfbeLfbfbfbfbfbfbeLfbeLeLfbeLfbfbfbfbfbfbeLfbeLeLfbeLfbfbfbfbfbfbfbfbfbfbfbfbfbfbeLfbeLeLfbeLfbfbeLfbeLeLfbeLfbfbeLfbeLeLeLeLeLeLfbeLfbfbfbfbfbfbeLfbeLeLfbeLfbfbfbfbfbfbeLfbeLeLfbeLfbgpgqgrQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtgsdkdkdkcVdkcVdldkdkcVcVdkcVdkcVdkdkdkdkcVdkcVdldkdkcVcVdkcVdkcVdkdkdkdkcVdkcVdldkdkcVcVdkcVdkcVdkdkdkdkcVdkcVdldkdkcVcVdkcVdkcVdkdkdkdkcVdkeZfCfjfjeKeKdkcVfheZfifhe9dkeKfjcVgtfhfheJeJfrdkfCcVfjfrfrfjeKfheKeKfifrdkdle9cVfidkfCeKeKfhcVdkcVfrfCdkeZeIfCeZe9cVdkdkdkfjeZfCeZdldkfjdddddkddeKeIfjfrfrfrcVdkcVdlfjeKddcVfhcVfrdle9dkdkfhdddkcVeKfhdkcVcVfrdldkfPgufuguftfkgufufkfQgufQgugufQgvfQfufkfkfkfQfQfQfXfuftfuftfbfufbfueLfbeTfbfufufuflfbfufbfbftfbe2fbe2eLfbeSeLfueLfuftfbftfbe2fbeTeTfceLfYeMeMfbeLfbfbfufbfufufbfufbfbfbfbfbfbfbfbfbfbeLfbeLeLeLeLeLeLfbeLfbfbfbfbfbfbe2fbe2e2fbe2fbfbeLfbeLeLfueLfufufbfufbfbfbfbfbfbeLfbeLeLfbeLfbfbfufbfufufbfufbfbfbfbfbfbfbfbfbfbeLfbeLeLeLeLeLeLfbeLfbfbfbfbfbfbe2fbe2e2fbe2fbfbeLgwgxgy.kQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQt.kgzeKdldkcVdkeKdkeKdkcVdkeKdkdkcVdkeKdldkcVdkeKdkeKdkcVdkeKdkdkcVdkeKdldkcVdkeKdkeKdkcVdkeKdkdkcVdkeKdldkcVdkeKdkeKdkcVdkeKdkdkcVdkeKdldkcVdkeKdkgAfjeZfCgAdkfjeKfreKeKfheKfigAfjeKdkcVfrfhfjfheKfCfCdlfjdlfhfhfheKdkdddkfCfjfrdkfieKfrfCcVfCfhdkgAfhcVfrgBfCfCdddkeKeKdkdddkgCdkgCfCeZdkeKdkdkeIeKeKeZfieIfjgAdkfCfrcVdkfhe9e9eJfhfhgte9dldkfjfrgDfhcVfheKfidkdkfDfQggfQgggufQgufkfkfkfQfkfkfue2fufufkftfkgufufQfufufQfvfkfbf5flfkfkfXfufXfke1fke2e2fue2fbfbeLfue1ftfbeMfle2fbfbeTeTeSfbeLeMfbeSeTfbeTfYfbfce2fbeoe2e2fbe2e2eLe2eLeLfbeLfbfbeLfbeLeLfbeLfbfbfufbfufufbfufbfbeLfbeLeLfbeLfbfbeLfbeLeLfbeLfbfbfbfbfbfbeLfbeLeLfbeLfbfbfbfbfbfbfbfbfbfbe2fbe2e2eLe2eLeLfbeLfbfbeLfbeLeLfbeLfbfbfufbfufufbfufbfbeLfbeLeLfbeLfbfbeLfbeLeLfbeLfbfbgEgFgGQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQt.kgHdkdkcVeKdkdkdkdkcVdkdkdkdkcVdkdkdkdkcVeKdkdkdkdkcVdkdkdkdkcVdkdkdkdkcVeKdkdkdkdkcVdkdkdkdkcVdkdkdkdkcVeKdkdkdkdkcVdkdkdkdkcVdkdkdkdkcVeKdkdkdkdkdkeKfjfjfCeKfCe9dkdkcVgAdkeKfjfjeKfjdkfidkdlfreKfjfjeJgCfrfCfjfhdlfjfjeKdkeJeKeKfjfrdlfjdkfifCfCeIe9fhfieKdkfrfifCfCeZfhdkdkdkdkddfCfCe9fCdddkdkdkdkddeKdkeKfifjcVdkfrfCdkeIfreKe9e9cVeKdkdke9e9cVfifhfhe9cVfhdkgIglfkgvfugvguf5fQgufkfkfQfkfQglfQfQfQfbfQgaf5fQgvgufQfufQfbfXgafbfufuflflflfbfkgafufuf6f5fkflfufbfbgafufufue2e2fbfbeLfbeLe2fueoftfueLfveLeSfcdzfbe2e2fbe2fbfbfbfbfbfbfbfbfbfufbfufufbfufbfbfbfbfbfbfbfbfbfbfbfbfbfbfufbfufufbfufbfbfbfbfbfbfbfbfbfbe2fbe2e2fue2fufueLfueLeLfbeLfbfbfbfbfbfbfbfbfbfbfbfbfbfbfufbfufufbfufbfbfbfbfbfbfbfbfbfbfbfbfbfbfufbfufufbfufbfbfbfbfbfbfbfbgJgKgLQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtabgMdkeKdkdkdkeKcVeKdkeKeKdleKdkeKdldkeKdkdkdkeKcVeKdkeKeKdleKdkeKdldkeKdkdkdkeKcVeKdkeKeKdleKdkeKdldkeKdkdkdkeKcVeKdkeKeKdleKdkeKdldkeKdkdkdkeKcVeKfhgDgDdkeKfjgAgNe9gAfjdkfjeKcVeKfheKeKdkfjfjeKdlfjfCfhfjfhgCdkfCfCeKeKgNeKfjeKfCeKeKfrfjfrfhddeKfifjfjgNgCe9gDdlfifjdkfCdkgAcVgCfheKeKdkeKfCgCgNfieKfjdkdkfCddeKeKeKeKfrfjdkfCdlfhdkfhe9eKgDeJeKfrfCfCdleKe9gDdkdkgOgugPgufkfQfkglgQgQgugvfQgvfQgRfQfQfQfQfQfQfkfkfkfkgugvfQfQgufbfWgve1gvfbfbfkfbfQfQfbfbfufbf5e2fkf5fbfXfufueLfbeLe2fbeLfbeTeTfYfbfce2fbeoe2e2eTeLeLfbdmfte2e2fufbfbfbfbfbfbe2fbe2e2fbe2fbfbfufbfufueLfueLeLfbeLfbfbfbfbfbfbfufbfufufbfufbfbeLfbeLeLfbeLfbfbfbfbfbfbfbfbfbfbe2fbe2e2fue2fufufbfufbfbfbfbfbfbe2fbe2e2fbe2fbfbfufbfufueLfueLeLfbeLfbfbfbfbfbfbfufbfufufbfufbfbeLfbeLeLgwgSgTQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtgUeKdkdkdldkeKdkdkdkdkdldkdkeKdkdkeKdkdkdldkeKdkdkdkdkdldkdkeKdkdkeKdkdkdldkeKdkdkdkdkdldkdkeKdkdkeKdkdkdldkeKdkdkdkdkdldkdkeKdkdkeKdkdkdldkeKdkdkdkfjeKe9e9eKfjfjeKfjfCeZfjgAfjdkdkdkeKfjfCfhfheKgAfjfjfCfrfCfhfrfjfrfCfCfCgAfrfrfhfjfjeZeKgBfrfjfjfjfrfifigCeKdkeKe9dkdlfifjdkfjfCfCeKe9dkeKdkdleKfCfCgtdkeKfjdkdkdkeKeKeKfjdkdkgAdkdkdldkdkeKe9e9e9gtdkdkfhdkfrfje9gIgVgPglgvgWgPfkglglglfQfQgggufQglgufkguggfQgufQfufugaf5fkfQgufQgugugafWfkfbfuflf6flfkfbfXfWftf5e1e1fle2fXfbfufbfuf5f5ftfufkf5fufufXe2fueogXe2gXeTeTeTfYfbfbeTe2fufufbfufbfbfufbfufufbfufbfbfufbfufufbfufbfbfbfbfbfbfufbfufueLfueLeLfbeLfbfbfufbfufufufufufufufufufue2fue2e2fbe2fbfbfbfbfbfbfufbfufufbfufbfbfufbfufufbfufbfbfufbfufufbfufbfbfbfbfbfbfufbfufueLfueLeLfbeLfbfbfufbfufufufufugYgZ", +"QtQtQtQtQtQtQtQtQtQtQtg0eKdkdkeKdkeKdkdldkeKeKdkfCeKdldkeKdkdkeKdkeKdkdldkeKeKdkfCeKdldkeKdkdkeKdkeKdkdldkeKeKdkfCeKdldkeKdkdkeKdkeKdkdldkeKeKdkfCeKdldkeKdkdkeKdkeKdkdldkeKgAfCg1gAgNfjfhdkfheKfjgAfCdkfCgAgAe9fjeKdlfheKfjeKgAfjeKfjfCdkfCfheKgCfCfrfrgCfjfrfhfjfjfjeKdkgBfjdkfjfhgtdkfjfCdkgCfhgDdkfrdkfjgBfig1gCgNfjeKdkdleKfCgCfCdkfCeKeKfrg2eKdkfheKfjeKgAdkfCdkeKfrdkfjeKgAfhdlfreKe9frg3glglglguglg4gug4gvglglglgRguglgufkfkfQfkfQfkfQglfkfkfQgWfbfbfkfQfQgufQfugugagvfQflflfkfuflfufXgvfufbf5e2flflfbfbfufugafuf5e2fke2eTeTfbfbeTfue2fbe2ftfufvfvdmfvfce2e2fbfbe2fbfbfbfbe2fbe2e2fbe2fbfbfufbfufufbfufbfbfbfbfbfbfufbfufufbfufbfbfbfbfbfbfufbfufufbfufbfbfbfbfbfbfufbfufufufufufufbfufbfbfbfbfbfbfbfbfbfbe2fbe2e2fbe2fbfbfufbfufufbfufbfbfbfbfbfbfufbfufufbfufbfbfbfbfbfbfufbfufug5", +"QtQtQtQtQtQtQtQtQtQtg6g7eKdldkeKeKdkeKeKfCdkeKdkdkeKdkdkeKdldkeKeKdkeKeKfCdkeKdkdkeKdkdkeKdldkeKeKdkeKeKfCdkeKdkdkeKdkdkeKdldkeKeKdkeKeKfCdkeKdkdkeKdkdkeKdldkeKeKdkeKeKfCdkgDfCfCgAfjeKgAfCfjgDgDdkeKgBg8fjgCfjfjgAdkdkeKdlfhfheKfieKgAg1fieKfrfrfhfjfhgCfCfieKeKfhfCfhg9eKeKeKeKfjfjfrfhdkdkeKeKfCgBeKfCfigBfifigCfCfCeKdldkgAgCdkeKgCgCe9gCdkdkeKdkdkfCdkfheKeKfieKeKfCfCeKdkdkfhe9e9gDeKfrgfg4gggRfkglggglggggfkgggPgWgugPglglgugugufQgvfQgvgvgugugugufQgvfkfQgufkguguf5gufWfXfuf5fuflgPfugugufufQf5f5flfkflflfbfbfbfuf5flfufke2fufbfbfbeTfbfbgXe2e2e2fteLfvfvfcfue2fbfue2fufufufufufufbfufbfbfufbfufufufufufufbfufbfbfkfbfkfkfufkfufufbfufbfbfbfbfbfbfufbfufufbfufbfbfbfbfbfbe2fbe2e2fue2fufufbfufbfbfufbfufufufufufufbfufbfbfufbfufufufufufufbfufbfbfkfbfkfkfufkfufufbfufbfbfbfbfbfbg5", +"QtQtQtQtQtQtQtQtQth.h#fCdkeKdkdkeKdkdkeKdkeKeKdkfCdkeKfCdkeKdkdkeKdkdkeKdkeKeKdkfCdkeKfCdkeKdkdkeKdkdkeKdkeKeKdkfCdkeKfCdkeKdkdkeKdkdkeKdkeKeKdkfCdkeKfCdkeKdkdkeKdkdkeKdkeKgDfhg1fjfCfCfjgBfjfCgDe9dkeKfjeKgAfjg1fjfhfjfjgAdkdkfheKfjfjeKgAeKdkfCfhgCg2fjfhfCfrfCfCfjgAfrfhfjdkfCfigBgCfifCe9frfjfifjgCdkeKgDfhfhfifjfjfCgCdkfCgAdkdkeKdleKgAfCgCfjfhfCdkeKfrdkfheKfjfjdkgAfCfrg2fheKfCe9fhfhhag4hbgQhcgRguglglglg4g4gRgQgggvggggglgugugggufkgvgvfQgvfkfQgufQgugvgafufkfQfQfkfQfQgvfbfXf5fufkfufufkfbfufWgQfugPgPe2gPflfbfufufufugvftgWgPftfufvfue2fbfuftfbe2fbeTeTdmfcfbeTeofteLfbfufbfbfufbfufufbfufbfbfbfbfbfbfufbfufufbfufbfbfufbfufufkfufkfkfbfkfbfbfufbfufufkfufkfkfufkfufufufufufufbfufbfbfbfbfbfbfufbfufufbfufbfbfufbfufufbfufbfbfbfbfbfbfufbfufufbfufbfbfufbfufufkfufkfkfbfkfbfbg5", +"QtQtQtQtQtQtQtQtQthddkeKdkeKfjeKeKfCeKdkfCeKdkeKeKdkdkeKdkeKfjeKeKfCeKdkfCeKdkeKeKdkdkeKdkeKfjeKeKfCeKdkfCeKdkeKeKdkdkeKdkeKfjeKeKfCeKdkfCeKdkeKeKdkdkeKdkeKfjeKeKfCeKdkfCeKfjgBgBfjfhfCfjgDhegCfCg1gAfjg1fhdkeKeKdkfjfhfjgCg1gAgAfCeKdkfjeKfifhfhfjdkgAfrfChffheKfCgCfCg9eKfjfCdkfhdkgBeKeKhgfCfCfjfhfigCfjfCgBgBdkfhfjfifCg1gBeKfCeKdkfCeKdkeKeKdkfCfhdkeKfjeKeKfCfCdkfjeKfifjfCdkfrfhfrfCfjg3hhggggggfQg4ggglglfQglguggglgPgug4glgvhhhigRhhgugugugvfkfkgufQguguhhguhhglgugugvgRglgufkgufWgvgvgvflfkflfbfQfbfbgagvflftfkflfufbfXfufufuflfue2fufufbfvfYfbfue2fufufkfufQfQfvhjfbfufbftfbfbfufbfufufQfufQfQfufQfufufkfufkfkfufkfufufbfufbfbfbfbfbfbfufbfufufbfufbfbfbfbfbfbfufbfufufbfufbfbfufbfufufQfufQfQfufQfufufbfufbfbfufbfufufQfufQfQfufQfufufkfufkfkfufkfufufbfufbfbfbfbfbfbfufbfufug5", +"QtQtQtQtQtQtQtQthkeKfjfCdkfCdkdkeKdkfCeKdkfCdkfjdkeKfjfCdkfCdkdkeKdkfCeKdkfCdkfjdkeKfjfCdkfCdkdkeKdkfCeKdkfCdkfjdkeKfjfCdkfCdkdkeKdkfCeKdkfCdkfjdkeKfjfCdkfCdkdkeKdkfCeKdkfChgg9fjgAgAgCfhgAfCfjgCfjfCgAfjg1fjgAdkfhfjfCfjg8e9fjgAdkg1fjdkfCfhhlfjgAfjfjdkfCfjfrfhfjfCgCfCgCfifjfjfhg9g2dkg9eKeKfjfjfCfje9fjeKfjfCfhgAgCfhgAfifigBfCfCfhdkfCdkhedkeKfjfCfCgCfidkgAdkg1fCfrfCfhfjfigAfjfCfrfCfhhmhbglhnggggglgug4glglglhohhglgVggguhpgugQgQfQguggguhhguhhglguhngvgufQgufkfQfQfkfkfkgufkgRgufQfufXfkgvfkgPgPfkfkfWfufkfXgafbfQe2ggfQfbhifufuf5flfuftflfufQfXeThjfbfbgWfbfkf6fufueTfcfbfYfQflftfQfufufbfufbfbfbfbfbfbfufbfufufbfufbfbfkfbfkfkfufkfufufbfufbfbfQfbfQfQfbfQfbfbfufbfufufQfufQfQfbfQfbfbfkfbfkfkfbfkfbfbfQfbfQfQfufQfufufbfufbfbfbfbfbfbfufbfufufbfufbfbfkfbfkfkfufkfufufbfufbfbhq", +"QtQtQtQtQtQtQthrhseKdkeKdkeKeKfCdkeKdkfCfCeKeKdkfCeKdkeKdkeKeKfCdkeKdkfCfCeKeKdkfCeKdkeKdkeKeKfCdkeKdkfCfCeKeKdkfCeKdkeKdkeKeKfCdkeKdkfCfCeKeKdkfCeKdkeKdkeKeKfCdkeKdkfCfCeKgAfjg9fjfhgBeKgAgAgAfjgDfCgCfCgAgAfCfjfhfjeKfjeKeKg8fjgCfjg1fjfheKdkg8eKfhfhfhgAgAfCfreKfrfjfCgCgCdkgCgCfrfCfrfheKg9eKeKeKfjgCfhfhfrg9fjeKgBeKeKeKfjfieKfigCfjfhgCfCfjeKdkeKdkeKeKgCe9gCdkfCfCfCeKdkfCeKe9fhdkgAgAg#g4hbgVhbhnggglhhglg4guglgRgQglgRglgVhbg4g4gQgvhcgRglgufQfQgugugugvglgvglhbgvglgufXhtgvglglguglgufWgufXgvguflfkfuflgPfbfkfQf5gQf5fkgvfkfkfkfugvgafufufbfufufkfWfufkfvfkfufuf6ftfkfueTfkfbfbftfcfteLfkfufkfkfufkfufufQfufQfQfufQfufufufufufufbfufbfbfkfbfkfkfufkfufufkfufkfkfbfkfbfbfufbfufufkfufkfkfufkfufufkfufkfkfbfkfbfbfufbfufufkfufkfkfufkfufufQfufQfQfufQfufufufufufufbfufbfbfkfbfkfkg5", +"QtQtQtQtQtQtQthufCdkfCeKfjfCdkeKfjfCeKfjeKdkfCeKfCdkfCeKfjfCdkeKfjfCeKfjeKdkfCeKfCdkfCeKfjfCdkeKfjfCeKfjeKdkfCeKfCdkfCeKfjfCdkeKfjfCeKfjeKdkfCeKfCdkfCeKfjfCdkeKfjfCeKfjeKdkgCgAfjfjgAhgg1gCfjgDhegAgAhgfCfCfCgAfCe9g1gAg1g1fhgAfjg1gAhegAe9fjeKg1fjfCfhhlfjeKgAg9g1fjfjgCfCfCfCfCfCfCfjg9g2frfjhlg9gBfjgBeKgCgAfCfifjgBgAgCdkfhfjfjfjfhfjfifjgCfCe9g8gAfjfCdlgCfjgCfhgAfhdkfCeKfCeKfCfhhlfheKg#gugRgug4gVhhgVglhogRggg4g4gVg4glhogRhhglg4g4g4gvg4gvguglguhiglgghhfQglfkfkhbglglglfbglfkfkgvfQguguglfuhhfQfuhtfugvf6fkfufufufXf5gvf5gWfkfufbfufbfXf5fufkfkfQfkfQgufvfQfvfufufbftfufvf5fvfufQfvfkgae2fQdmfbfkfbfkfkfbfkfbfbfufbfufufQfufQfQfufQfufufbfufbfbfufbfufufufufufufbfufbfbfufbfufufQfufQfQfufQfufufufufufufufufufufQfufQfQfbfQfbfbfkfbfkfkfbfkfbfbfufbfufufQfufQfQfufQfufufbfufbfbg5", +"QtQtQtQtQtQthvhwfjeKdkfCeKeKfjeKfCeKdkeKfCfjeKdkfjeKdkfCeKeKfjeKfCeKdkeKfCfjeKdkfjeKdkfCeKeKfjeKfCeKdkeKfCfjeKdkfjeKdkfCeKeKfjeKfCeKdkeKfCfjeKdkfjeKdkfCeKeKfjeKfCeKdkeKfCfjgAfhhegAfCgAgAgAhehgg9gAfjgCgAfjgDfCgAgCfCg8gCgAg1gAgAgAeKeKg1fjgAe9g1gAe9fCeKeKhlfhfCeKfjfjfCg1eKfjhlfheKg9fhgChffjfCfCfheKfCfjeKeKfjfCfrfCfCfhfjgBfCeKdkeKgAfjfhfifjeKdkg8gCeKfjeKfCeKdkeKgAfhgCfiheeKfrfCeKfChlhxhnhyglhhgVhbgVhnhbgRhngRgVggg4gugugRfkhcglhhglgVgVgugVggggguggguglhiguhhglguglgvguglgRglglglgQgQglgvglguguglgufQglgvhhf5f5gPf5fkguhigvglfQgvggfkgvf5gufufXfufkfbflgPfbgufuhtfuhjgafbhje2fbfueTfufvfQftgaflfufbfufufkfufkfkfkfkfkfkfufkfufufQfufQfQfufQfufufkfufkfkfQfkfQfQfkfQfkfkfufkfufufbfufbfbfkfbfkfkfQfkfQfQfbfQfbfbfufbfufufQfufQfQfufQfufufkfufkfkfkfkfkfkfufkfufufQfufQfQfufQfufuhz", +"QtQtQtQtQtQthAeKfjeKfjfjeKfjfCeKfjeKfjfjeKdkfjeKfjeKfjfjeKfjfCeKfjeKfjfjeKdkfjeKfjeKfjfjeKfjfCeKfjeKfjfjeKdkfjeKfjeKfjfjeKfjfCeKfjeKfjfjeKdkfjeKfjeKfjfjeKfjfCeKfjeKfjfjeKdkhefjg1fjhehgfjhegAgAg9hgg9hegBfjhefhhggDfjhegCheg1gBfjgAgAfjgAdkheeKhegCg1g1gAhlfCeKg1fhhlg1fhfjhlgAfjeKhlhffhgAfCfhgAfjg9hlfCfhfjfhfjeKfjhgfCfjgAfCg9gBfjg1gBdkheeKhgeKfjg1gBhlg8gChleKhefjeKdkhgfCgAgChefjeKg9fCg#hngRhngugVgug4gRg4hngRgVgVhhgVhBhngugVgQgRgQglgVglgRgRgvguglguhogVgugVgugugugvgugvhhguhhhhgvhhgufXgQgvglgQglgQglhhguglf5gvgPfkgvgPfugufufXf5fkf5fkggftfQfQgufQhtguftggftfufkfvfkfufvfbftftflftfQfXfufXeLfufte2fuftfkfufQfQfufQfufufkfufkfkfQfkfQfQfufQfufufkfufkfkfufkfufufufufufufQfufQfQfQfQfQfQfufQfufufkfufkfkfufkfufufQfufQfQfufQfufufufufufufQfufQfQfufQfufufkfufkfkfQfkfQfQfufQfufuhz", +"QtQtQtQtQthCeKfCeKfCfCeKeKfjeKfjfCeKfCeKfjfCeKfCeKfCfCeKeKfjeKfjfCeKfCeKfjfCeKfCeKfCfCeKeKfjeKfjfCeKfCeKfjfCeKfCeKfCfCeKeKfjeKfjfCeKfCeKfjfCeKfCeKfCfCeKeKfjeKfjfCeKfCeKfjfCgAg1fjg9g9gAgAgAgAhgfjgAgAfjg9g1gAgCgDgAfjgDgDhefChegCgAg8fhfjg1eKfCgAg1g8gAgChegAg1g1eKfCfhfjfjgAfCeKfCg1fCeKg9eKhffjgCfCgCfjg2fhg2fjg9g9eKeKgAeKhgfCfhfCfjg9fCgCgCgDfjfCfjfjfjfjg1gCeKg8fhfjfCeKfCgCgCgCgCeKfjgAfPhngRhnhnhnhnglhnhbgRhbg4g4hDgVgRgVhhgVgVgVg4hcgRgRgVgRhhhhglgVhcgRgvhcgRgRhhguhiglgQhhgQglguhbguguhhguglhhgvglgvgugugufWfWhigvguglgPglgPgPgufkfQfkf5gvfkfkgPfWfkfkgufQgugufkfkfufvfXfufQfQfkhjgWfke2fkfvfvfQeTfQfkgWfQfkfkfufkfufufQfufQfQfufQfufufufufufufQfufQfQfkfQfkfkfkfkfkfkfufkfufufkfufkfkfQfkfQfQfufQfufufQfufQfQfkfQfkfkfufkfufufQfufQfQfkfQfkfkfufkfufufQfufQfQfufQfufufufufufuhq", +"QtQtQtQt#hhEfjfCeKgAfCfCgAfCfCfCeKfjeKgAeKfjfjfCeKgAfCfCgAfCfCfCeKfjeKgAeKfjfjfCeKgAfCfCgAfCfCfCeKfjeKgAeKfjfjfCeKgAfCfCgAfCfCfCeKfjeKgAeKfjfjfCeKgAfCfCgAfCfCfCeKfjeKgAeKfjhgg9g1hFg9g9g1gAgAgCgAhegAhgfjheg9g1gAhegCgAhGg1fCgAgAgAgAgAgAgAgAg1gAgAfCg1heg1g1g8gAg1eKhHgAhlhlfjfhhHfjg1gAg9g1fCfhhlfjgAgChfgAg2fChgg2g9hegCgCfCfjfjgAgAfjg9g9gCeKhggCgAhGfjfjfjgCfjgCfjfhhehgfCeKgAfCgCgAfjfjhIgRhngRhnhngRhngRgVhhgVhnhnguhng4g4gVgRgVglgRg4gRgRglhbgVgVglgVglgvgRgQgRgQglgRguglgugufugvgQgvglglglglglfkgQgQgQgQglgQglglfufQguf5glfuglggftggf5fWglfXfQfQfkggfkfuf5fufWf5fkfugPgPfkfkfXfXfufQfuftfkftfkfufufufufkeLfkfufufkfufkfkfkfkfkfkfkfkfkfkfQfkfQfQfufQfufufQfufQfQfufQfufufQfufQfQfufQfufufufufufufkfufkfkfQfkfQfQfufQfufufkfufkfkfkfkfkfkfufkfufufkfufkfkfkfkfkfkfkfkfkfkfQfkfQfQg5", +"QtQtQtQthJfCeKfCfjfjeKeKfjeKfjeKfCfjfjfCeKfCeKfCfjfjeKeKfjeKfjeKfCfjfjfCeKfCeKfCfjfjeKeKfjeKfjeKfCfjfjfCeKfCeKfCfjfjeKeKfjeKfjeKfCfjfjfCeKfCeKfCfjfjeKeKfjeKfjeKfCfjfjfCeKfCfhg1hehggAg1hegAg9fjgAgAgAgAgAfjfCgAheg9gAfjgAgBhlfhfChefjg1gCfCfCg8g1gAgAgAfjeKg1gBg1heheg1gAg1gAfChlfjfheKhlfhg1gAg1g9g9g9fhfCeKfChfgAfCfCg9fChffjgCgAgAgAfCfCfCfCgAg9gBeKg1gBfjeKfjfjfjg8eKfCeKg8hefjeKeKfjeKgAg#hbgVhngRgRhbgRhbhbhDhbhDhKhyhDhnhnhKhDhKgVhnhLgVgVg4gVg4glglgRgRguhhglglgVgVgVhhhhgRhhglglhhgghMglgvhhgugugVgugVgRhhgRglhbgQglglfkfWguf5gvgQgvgPgvglfkhNguhtg4guggglgggug4hihNgufQfuggfkfufufufufufQfufkfQfQfQfQfXfufQfkfkfQfkfQfQfufQfufugufugugufQgufQfQfkfQfkfkfufkfufufkfufkfkgufkgugufQgufQfQgufQgugufQgufQfQfufQfufufufufufufQfufQfQfQfQfQfQfkfQfkfkfQfkfQfQfufQfufugufugugufQgufQfQhz", +"QtQtQtQthOgAfjgAfCeKfjgAfCgAeKfjgAfCfCeKfjgAfjgAfCeKfjgAfCgAeKfjgAfCfCeKfjgAfjgAfCeKfjgAfCgAeKfjgAfCfCeKfjgAfjgAfCeKfjgAfCgAeKfjgAfCfCeKfjgAfjgAfCeKfjgAfCgAeKfjgAfCfCeKfjgAhehHg9fhg1hFg1hegAhehFg9hefjhghehehGgAfjhgg1hehHgAhegAgAg1gDfjgAfjheg1gBg1hPg1hHfhfjgAg1g1gChehHg1gAfCgAfjhgfjhggAg1gAg1g9eKg1hgfjheg9eKfjgAg9g1fhhlg1g9gCeKgAgAfjhGfCfCfCg1gCgAfhg1gAfjfjgBfjgAfjg1g8gBg1hFfCgAeKfPhnhyhnhyhngVhhhDhDgRhDgVgRgVguguhNhbg4gRhngRhngRgRhBgRgVglhKglhbhngRgVgRgRg4gRgQglhnguhhhiglglguguhhgvgVgRglhDglglguglgvgvglguglhbglfQhhfQgRglg4g4gvgRfWfufWf5gvfXgvfkfkfkftgufufuhtgvfQfkglflgvgufkgufufkfbflftftfQfufQfQfufQfufugufugugufkgufkfkfufkfufufQfufQfQfQfQfQfQgufQgugufugufufufufufufufkfufkfkfufkfufufQfufQfQgufQgugufkgufkfkfufkfufufQfufQfQfufQfufugufugugufkgufkfkfufkfufuhq", +"QtQtQthQfCfjfCeKfCfjfCfjeKfjfCfCgAeKgAfjfCfjfCeKfCfjfCfjeKfjfCfCgAeKgAfjfCfjfCeKfCfjfCfjeKfjfCfCgAeKgAfjfCfjfCeKfCfjfCfjeKfjfCfCgAeKgAfjfCfjfCeKfCfjfCfjeKfjfCfCgAeKgAfjfCfjg1fjg1g9heg9gCg1gCg1hefjhFhefjhggAgBg1hggAhlgAhgg9gAgAgAhegAg1hefCgAfCheg1gAgAg1g1g1hHgAgAfjfChefjgCg1g1fjfjeKfjg2fjhgeKhHfjg1hfg1eKfjhfgChlgCfjgCg9g1fChgfifjgAgCeKfChlfjfjfjfCg9gCgAeKgAgAfCfjfjfjfjg1g1gAeKg1fCg#hDgRhDgRhDhbgRhnglhngRhngVhnhDhnhyhRhhhLhDhnhnhKhngVgVhBhhgRhnhcgRgVgQhohhglgVglgRgRgQhngRglgVguguhiglhhhhglglhhhhglglglglgVglgRgRgvgRgRgufkfuglgQgugPguggggggfQhthNglhig4glgvglg4fQg4fQgugQgufkfkggfkfQhifkhjfkfbgvfkgugufkgufkfkfQfkfQfQfQfQfQfQfkfQfkfkgufkgugufugufufufkfufkfkfQfkfQfQfQfQfQfQgufQgugugugugugufQgufQfQfkfQfkfkfQfkfQfQfkfQfkfkgufkgugufkgufkfkfQfkfQfQfQfQfQfQfkfQfkfkhS", +"QtQtQthTeKgAfjgAgAfCgAfjgAeKgAgAfjfjfCgAeKgAfjgAgAfCgAfjgAeKgAgAfjfjfCgAeKgAfjgAgAfCgAfjgAeKgAgAfjfjfCgAeKgAfjgAgAfCgAfjgAeKgAgAfjfjfCgAeKgAfjgAgAfCgAfjgAeKgAgAfjfjfCgAeKgAhehHhHg1hFfjg1fhhGhHhgheg1hFgAhFg9g1g1gCgAhehGfjhFhGg9hgg9hegCgAhlhghgg1gAgAhegBheg1gAg1gAgAeKgAg1hPg1g1heg1gAgAhFgAhlhlfCg1fhgAg1hHhHg2g1hlhefhhPgAfjhffChFfCg1hfhehegChPfjhgfCg1gCg9gAfCg1gCgAhlgAgAfjgAgAg1gBhgfPhbhDgRhDhDhbhRhnhnhRhngVhDhbhDhbhnhbhnglgRhnhbhbhbhDhnhbgRhLglhKhKguhKgQglhogRgVhBglgVgRhphKgQgVgVgugVglglguggfQglglgvhhhhglfQglgQgRgQhUhUgQgRglglhifQgRg4gQglgPgPfkgufkfkfQgvgvgvgPgPfkfkgugvgRguftguftfufQfufQfQfkfQfkfkgufkgugufkgufkfkfufkfufufQfufQfQfkfQfkfkgufkgugufkgufkfkgufkgugufkgufkfkfkfkfkfkfkfkfkfkfkfkfkfkgufkgugufugufufufQfufQfQfkfQfkfkgufkgugufkgufkfkfufkfufufQfufQfQhz", +"QtQthVhWfjfCfjfCfjfCgAfjfCgAfjfCeKfCgAfjfjfCfjfCfjfCgAfjfCgAfjfCeKfCgAfjfjfCfjfCfjfCgAfjfCgAfjfCeKfCgAfjfjfCfjfCfjfCgAfjfCgAfjfCeKfCgAfjfjfCfjfCfjfCgAfjfCgAfjfCeKfCgAfjfjfCg1g1heg8hFhXg8hFfjfjfhg1hHhgheg1heg9g9g1hgg1g9hghlg1fCgAhGg9hggAgAgAheg1hFhegAgAgAfCfCg1g1fjg1g1g1g1gAfCheheg8gAg1g1gAfCgAfjhlfjhlg1g1g1hefjfChghlfjeKgCgAgAheg2g9g9hlfjhPfjfChPfjfCfCfjgCg9gAgCgAfjfjfCgAfhfCgAgAhIhYhnhRhZhbhnhbhyhyh0hnhyhyhKhnhDhRhDhDhDhKhDhDhDhDhhgVgVhnhngRhnhnglhKhbhphhhcglglgVhhgVhLg4hKg4g4glgugVhihNhiglhhgVgRgRgVhDgVgVgVglgVgQgQglgQglglglfQhhhhguglgRgVglgRglgugugug4g4guglggglgufQhNhNgvg4gvgWfQfkfQfQhNfQgugufugufufufQfufQfQgufQgugugugugugugugugugufkgufkfkfQfkfQfQfQfQfQfQgufQgugugugugugugugugugufQgufQfQgufQgugufkgufkfkfQfkfQfQgufQgugufugufufufQfufQfQgufQguguguguguguhS", +"QtQth1fCfCgAgAfjgAgAfCgAgAfCgAgAfjgAfjfCfCgAgAfjgAgAfCgAgAfCgAgAfjgAfjfCfCgAgAfjgAgAfCgAgAfCgAgAfjgAfjfCfCgAgAfjgAgAfCgAgAfCgAgAfjgAfjfCfCgAgAfjgAgAfCgAgAfCgAgAfjgAfjfCfCgAhFhehFhHgAhFhHg1hHhFg9g1fjgAg9hPhFgAhFhFg9g1gAgAg1hghghGhlg1gAhGhHg9hegAgChGg1fChggAhghegAg1g8hehHfCgAgAfChegAg1g1gAg1hHg1g1fCgAhgfig1gAfjhHhHg1gAhFhlhghlgCfjhPg1gAhFg1g2hegAgCgAhPhlhgfjg9fCgAfjg9g1gAgChGgAfjgAfPh2h3h4hDhyhRgVhRhDhDhDhRhYhbhRgRhbhbhbhnhbhnhbhDhhgRhyhbhbhbhbhngRhKhngVhLhhhKhnhchchngRglhNgRhKgRhhhKglhoglhhgVglgVgugRgVgQgVhbglhhglglhhgVglhigugRgRgRgRfkgVfkgvgQgQgPgvgggvggfQfkhtfkgQfkgvfQfQguhig4gugugugufkfkfQfkfkgufkgugufQgufQfQfkfQfkfkgufkgugufkgufkfkfQfkfQfQgufQgugugugugugufkgufkfkfkfkfkfkfQfkfQfQfkfQfkfkfQfkfQfQgufQgugufQgufQfQfkfQfkfkgufkgugufQgufQfQfkfQfkfkgufkguguhz", +"QtQth5gAg1fCgAfCfCgAfjfCgAfCfCgAgAfCgAgAg1fCgAfCfCgAfjfCgAfCfCgAgAfCgAgAg1fCgAfCfCgAfjfCgAfCfCgAgAfCgAgAg1fCgAfCfCgAfjfCgAfCfCgAgAfCgAgAg1fCgAfCfCgAfjfCgAfCfCgAgAfCgAgAg1fChHgAg1gAgAgAhHhHg1hFhHg1g1gAg1heg1gCgChFheg9hFg1g1g1g1gAhHhehXgAhggAgAhFhggCheg8gAhghGfChGgAhHg1gAg1g8hHg1g1gAfCg1g1g1g1g1hHh6fCgAfCfChghlfjg1g9fCgAgAg1gAhghefChgfCgCg1hfg2hgfCg9hehegCgAgAg1fjgAfjfCgAgAfCg1g8gAgIh7hnh0h0h0hbhyhDhDhbhbhbhbhDhnhRhRhnhRhhhhhDhnhDhDhZhDhRgVgRhKhbhbhngRhnhngVhLgVgVgVhKgVhoh2hhhDhDhKhnhKhKgQhnglglguguglglgVgQgVgVglgVhhhhglhhglglgQgQgQglhUglgRgRfQgVglglglguglglg4guhNgRfkgugvgvglgPg4hNfWgug4g4gggufQfQglfQglglguglgugufkgufkfkfkfkfkfkgufkgugufQgufQfQfkfQfkfkfkfkfkfkgufkgugufQgufQfQgufQgugugugugugufkgufkfkgufkgugugugugugufQgufQfQglfQglglguglgugufkgufkfkfkfkfkfkhS", +"Qth8h9gAfjgAgAfjg1fjgAg1fjgAgAfCgAfjfCgAfjgAgAfjg1fjgAg1fjgAgAfCgAfjfCgAfjgAgAfjg1fjgAg1fjgAgAfCgAfjfCgAfjgAgAfjg1fjgAg1fjgAgAfCgAfjfCgAfjgAgAfjg1fjgAg1fjgAgAfCgAfjfCgAfjgAhFhei.hehFi.gAgAhHgAhFg1g1hFg1hFhHg1h6hghPhHhehehFg1g1fjgAhgg9hghGhghFg9g1hFhehHhegChGhlg1gAhggAhehehXgAhei#g1hHgAfChFgAg1heg1gAhHfjg1heg1g1hlhgg1fjhHg1g1g1fjhghehfhXgAhPhHg9g1hgg2hehlgChPfjhPhghghFg9g1gCgAgAg1iaibhYhDh4ichDhRhRhRhDhRhRhDhnhDhnhyhyhnhnhyhKhnhDhDhbibhDhbhDgRhRhDhngVhnhnhngVgRgRhDglgVhKgVhbhngVgVhigVhLhDgRidh2hKhbgVhNgVgVhNguhngRhbhnhDgVgVgVgugVgVgRglgRglglglfQfQhhgugug4guieglgPgvhNfkhig4gugQggglfkfQfkfkgufkgugufQgufQfQgufQguguglguglglguglguguguguguguglguglglguglgugugugugugufQgufQfQfQfQfQfQgufQgugufkgufkfkgufkgugufQgufQfQfkfQfkfkgufkgugufQgufQfQgufQguguglguglglguglguguhS", +"QtifgAfjg1gAfCgAgAgAfCgAfCgAg1gAgAg1gAfjg1gAfCgAgAgAfCgAfCgAg1gAgAg1gAfjg1gAfCgAgAgAfCgAfCgAg1gAgAg1gAfjg1gAfCgAgAgAfCgAfCgAg1gAgAg1gAfjg1gAfCgAgAgAfCgAfCgAg1gAgAg1gAfjg1gAhHhehei.g1hFgAgAg1gAhFh6hHg1i.hHg1hFhFhFg9hGg1hHhFhFhPhFhFheh6g1gAgAgAg1gAhFgAhGhFhHg1hXheg1hFhgg1gAgAgAg1heg8g1h6hHhPg1gAfjhegAg1heg1gAg1hFfCgAhehggAg1g1g9g1hHg2g1g1gAg9hPfCgAheg1gAhFhgfjg1hegChPhPgDfjg1fjgCg1ighbhRhnh7hDh7hDhDhDhbhRhZhnhRhbgVhyh4hDh4hRhRh4hRhRgVhDhDhDhDhZhDhDhDgVhnhDhDh2hDhDh2hKhnhDhLhnhKhKhchnhcglhLgugVhDhKhngRgVglhNglgRgVglgVgRgVgRgRgVhbgVgPglgVgQgRgVhZgRhbhngRglhihNgVg4glglgRguhNhNglgRhbglg4hcglglgVguglglguglgugufkgufkfkgufkgugugugugugufkgufkfkgufkgugugugugugufkgufkfkgufkguguglguglglguglguguguguguguguguguguglguglglguglguguglguglglguglgugufkgufkfkgufkguguguguguguhz", +"Qtihg1gAfCg1fjg1fCgAg1gAgAg1fCfjgAfCg1gAfCg1fjg1fCgAg1gAgAg1fCfjgAfCg1gAfCg1fjg1fCgAg1gAgAg1fCfjgAfCg1gAfCg1fjg1fCgAg1gAgAg1fCfjgAfCg1gAfCg1fjg1fCgAg1gAgAg1fCfjgAfCg1gAfCg1hei.hHiihehehFh6g1hehFgAi.hFhHh6hXhFg1hFi.hFhHi#gAg1hFg1hHhFg1hFhei#gAheg1gAhGhFg1hgg1gAg1heg1i#hgheg1gAg1gAheg1g1g1hPg1g1gAfCg1heg1g1hPheg1gAh6g1fjhgfjg1hHg9g1fjg1g9hgi#g1hehegCfjgAg9gAhgfjg1hfhXgChHhHhPhGg1g9ijh4h3h4hyhyhRhnh7hDh4hDh0hRhyh4hRgVh4hRh4h4hbhDhnhbhnhnh0h4hDh4hDhDhbhDglgRgVgRhnhnhbhDhDhKgRgVglgRhngRidh2hnhnhKgVgVgVhhhchnglikiliminioioinimiliphngVhngVhhglhhglhbhhhbhZgRhbglfkglgugVgRg4hcglgvfkgVfkfkfQfkgugggvfQgugufkgufkfkglfkglglguglgugufQgufQfQglfQglglfQglfQfQgufQguguglguglglfQglfQfQglfQglglfkglfkfkglfkglglguglgugufkgufkfkfQfkfQfQgufQgugufkgufkfkglfkglglguglgugufQgufQfQhS", +"Qtiqfjg1gAgAgAgAg1gAgAgAfCgAgAg1fjgAfjg1gAgAgAgAg1gAgAgAfCgAgAg1fjgAfjg1gAgAgAgAg1gAgAgAfCgAgAg1fjgAfjg1gAgAgAgAg1gAgAgAfCgAgAg1fjgAfjg1gAgAgAgAg1gAgAgAfCgAgAg1fjgAfjg1gAgAirhHi.hFheheg1i.i.i.hFhHhei.hFhFhHgAhHhHisheg9hFhFg1g1gAg1i.hPhFhFheg1g1hHhHg1hegAhehghghgg1g1hehegAhXhghGhFgAgAgAhHhegAhehHgAgAgAhHg1hPheheg8hHgAh6fjhHfjheg1g1g1gAhHhHgAgAfChggAhefjgAgAg1hPhFhFg1hehggAgAfCgAgDithDhYh4h4h4hDhRh0h7h7hDhDh0h4hDh0hRh0h0gVhRh4hDh4hYhyhRhyhygVhBhDhDh4hKh4h4gVhDhRgVh4hKhDhDhnh2hKgVhLgVhKhDhchnhnglhbhhhnhniuiviwixixixixixixixixiwiyizgRgVhnhDgVhngVhngRhNhbhUhnhbglhnhihhgRhhgRglhbglgRhcguglhNg4gRguglglguglgugugugugugufQgufQfQglfQglglguglguguglguglglguglguguguguguguglguglglguglguguglguglglfQglfQfQgufQguguglguglglguglguguglguglglguglgugugugugugufQgufQfQglfQglglhS", +"#RiAgAg1gAfjg1gAg1gAg1gAg1g1fCgAg1g1gAg1gAfjg1gAg1gAg1gAg1g1fCgAg1g1gAg1gAfjg1gAg1gAg1gAg1g1fCgAg1g1gAg1gAfjg1gAg1gAg1gAg1g1fCgAg1g1gAg1gAfjg1gAg1gAg1gAg1g1fCgAg1g1gAg1gAfji.hFh6hFi.hFi.heg1hFi.i.hFi.hFhei.hHi.hFh6hFhFi.g8gAi.g1hFh6hPgAhHhFh6i.hFhHh6h6g9heg1hehGhFhFg9g1hgg1hei#hGhFhFfjhGg1hHhehXhehehXhHhHhGg1heheheg8hHg1h6hgg1gAg9i#hgg1hHgAhHg1g1fChgg1hehPg1hPgAhHhegAhghHheg1g1fCiBhRh7h4hDhDhbhDh2h4ibh2hDhDiCh7h0h4h0hDhRhRhRhRhDhBhRhDhRhRhRhRhnh4hDhDhDhKh4ibh4h4glhDhbgRhKhbhbhnhbgVhDhnhDh4hnhKglhngViDiEixixixixixixixixixixixixiEiFgRhbgVgVhDgVhbgVgVgVhigRgVgRhZgRgVhngVhbglgRhcg4glhcglglgVgvglfkfkgufkguguglguglglguglgugufQgufQfQgufQgugugugugugufkgufkfkgufkguguglguglglguglguguguguguguguguguguglguglglguglguguglguglglfkglfkfkgufkguguglguglglguglgugufQgufQfQhS", +"iGgAfjgAg1g1gAfjg1gAgAgAgAgAg1gAg1gAfjgAg1g1gAfjg1gAgAgAgAgAg1gAg1gAfjgAg1g1gAfjg1gAgAgAgAgAg1gAg1gAfjgAg1g1gAfjg1gAgAgAgAgAg1gAg1gAfjgAg1g1gAfjg1gAgAgAgAgAg1gAg1gAfjgAg1g1i.hFiHhHhFhFhHhGi.hei.heiii.i.h6hFhei.hFhFgAgAhHhFishHhHhehFh6g1g1hghFhGhPhFhehFh6hHi#g1hegAhFi#hGg9g1g1g1gAgAg1hFhGhFhGfjgAhXg1g1hehHhPgAhHhHgAheheg1g1g1gAg1i#gAg9hehgfjhggAg1g1gAg1gAhlgAhXg1gAgAgAgAhPg1g1gAhXigh4hYhRh0h4hYh0h4h4hDh4h0h0hRhDhKh7h0hDh4hRhYhRh4h2gVh0hnhnhDhyhRhRhRgVh0h4hBh4hDhDhDhDhRhRhnhDhDh4hDidhnhKh2hKhnhDhKh4iIiJixixixixixixixixixixixixixixiKiLgVgRgRgVhnhnhDgVgVhnhnhbglhnglglhUhhgVgRhngRhhgRgVgRglguhNguguguglguglglguglguguglguglglguglguguglguglglglglglglglglglglguglguguguguguguglguglglglglglglfQglfQfQgufQguguglguglglguglguguguguguguglguglglguglguguglguglglguglguguhS", +"iMgAg1g1gAfjg1gAg1gAg1g1gAg1g1gAg1gAg1g1gAfjg1gAg1gAg1g1gAg1g1gAg1gAg1g1gAfjg1gAg1gAg1g1gAg1g1gAg1gAg1g1gAfjg1gAg1gAg1g1gAg1g1gAg1gAg1g1gAfjg1gAg1gAg1g1gAg1g1gAg1gAg1g1gAfji.hFi.i.iHi.hFisi.hHi.hei.iihehei.hHi.hHi.g1gAi.g1gAhHi.hFi.hehei.gAi#g1hFishFhFhFheg1hFi#hehHhehFhehFhGg1hFhHhXg1gAhXhFhFg1hGfjhXgAi#gAhHh6hHg1g1hHg1heg1g1g1g1h6hHg1gAhehehgg1hegAhHhgg1i.gAhlhXgAhXgAhHheg1hFg1igiCh7h4hRh7h7hDh7h7hYhDh0hYhRh0h0iNhDiNhDh0h4hDhYhRhRh2hDgVh4hDh4hYhDhRhKhRgVhDgVhDh4hDiOh4gVhDhRgVhKhDhnhKidhKh2hDhLiPiEixixixixixixixixixixixixixixixixiEiQgVhyhygRhygRgVgVgVgVgVgVglgRgRhbgRhnhbgRhbgugVgRgugRg4gRguglglguglguguguguguguglguglglguglguguglguglglguglguguguguguguglguglglhhglhhhhguhhguguglguglglguglguguglguglglguglguguguguguguglguglglguglguguguguguguglguglglguglguguhS", +"iRgAg1gAg1g1gAg1gAg1g1gAgAg1gAheg1gAg1gAg1g1gAg1gAg1g1gAgAg1gAheg1gAg1gAg1g1gAg1gAg1g1gAgAg1gAheg1gAg1gAg1g1gAg1gAg1g1gAgAg1gAheg1gAg1gAg1g1gAg1gAg1g1gAgAg1gAheg1gAg1gAg1g1irh6i.i.i.hehehXhFiih6irh6hFi.i.i.hehFi.h6hFhFhehFheg1hHg1hFhHhFhFhXg1g1g1hHhHh6hPhFhehFheg1g1i#hgh6hGhFhehGhGhFg1hFhHheg1hehehFgAhFhGhFhHheg1i#gAi.h6gAg1hPhHhegAg1hHh6h6gAgAg1hHheg1g1g1hHhHg1hFg1hghehegAgAg1hPhaiNiCiNh4iChYh0hYiSibhYhDh0ichDh0hYhRh0hYhYhDh4h0h0hRhYhRhRhRh0h4h4hDh4hRhRh7hDiNhYh4hYh4h4hDh4hZhDhRhRh0h0hDh3hKgRhKivixixixixixixixixixixixixixixixixixixivhKgVhnhngVhohngVhbgVgVgVgVhnhnhnhhhbhbgRhbgRgRhRguhRhDhbgVglglguglguguhhguhhhhguhhguguguguguguhhguhhhhglhhglglglglglglguglguguglguglglglglglglguglguguglguglglglglglglguglgugugVgugVgVglgVglglguglguguhhguhhhhguhhguguguguguguhS", +"iTg1gAhFgAheg1g1gAhFg1g1hFg1g1g1gAg1gAhFgAheg1g1gAhFg1g1hFg1g1g1gAg1gAhFgAheg1g1gAhFg1g1hFg1g1g1gAg1gAhFgAheg1g1gAhFg1g1hFg1g1g1gAg1gAhFgAheg1g1gAhFg1g1hFg1g1g1gAg1gAhFgAhei.i.hHiUh6i.iUi.i.hXhFiVhFi.hGiii.i.hFiUhei.iii.i.h6gAi.hHhFhFiWhFhFhFisi#i#i.i.hFh6hFi.hFhFhFhXi#h6g1iig1hFirhFhFhFhFg1hghFhehFhehFhGhFhFhFiWhXhXi#hHhHhHhFgAiXhHheg1heg1h6i.g1i#g1hghehghHhHhFhHg1gAhFg1hehFhHhHgIibiYhDiYichDh0h7hDhRh7iSiSh4h4h0h0hDh0hYh7iSh7h4h0hYichYhYhDhYhRgVhnhDh0h4hRhRhRhRgVh0hDhDhDhKh4iOh4hDh4hnh4h4hDh4iZiwixixixixixixixixixixixixixixixixixixiwi0hngVhKhNhKgVglhhhbhnhDhnhKhKgRhRgVgRhbgRhnhbhbhbhnhnguglguguglguglglglglglglglglglglglglglglguglguguhhguhhhhguhhguguglguglglguglguguguguguguglguglglgVglgVgVgugVguguglguglglglglglglguglguguglguglglglglglglglglglglglglglglhS", +"i1g1g1g1gAg1gAg1hFg1gAgAg1gAhegAg1g1g1g1gAg1gAg1hFg1gAgAg1gAhegAg1g1g1g1gAg1gAg1hFg1gAgAg1gAhegAg1g1g1g1gAg1gAg1hFg1gAgAg1gAhegAg1g1g1g1gAg1gAg1hFg1gAgAg1gAhegAg1g1g1g1gAg1hFi.i2i.hFhHi.hHiWhFi.hXhXi.hHh6hHi.iUi.hehFhFhei.hHi.i.heg1hFi.gAh6iWhHi.hHi.g1hegAi.h6h6ishGhHhHhFisi#hHg1g1gAi3hehFhFhFhFg1g1g1g1irhehGhGi.hFhegAhXhXi#h6hPg1hPg1iWhHheg1heg1i.hHg1g1g1hehgg1gAhehFhHgAgAi#gAhehxh0h7hYibhYi4hYhYh4i4hYi5iNhYi5hYiCi4ichYhYhYi6h0h4h7h4h7hDhRhYhYhDhRhRh4h2iNhyhYibhRh7hRhRh0gVhnhDhDh4hZhDh0hDi7hYi8ixixixixixixixixixixixixixixixixixixixixi9hDhbhRhnhLhRhDhRhnhbgVhbgVgRgVgVgVgVhngVhbhbhRhnh4hngRgVguguglguglglguglgugugVgugVgVglgVglglglglglglguglguguglguglglgVglgVgVglgVglglgVglgVgVglgVglglguglguguguguguguglguglglgVglgVgVgugVguguglguglglguglgugugVgugVgVglgVglglhS", +"j.gAg1gAhFhFg1hFg1gAg1hFg1hFgAg1hFgAg1gAhFhFg1hFg1gAg1hFg1hFgAg1hFgAg1gAhFhFg1hFg1gAg1hFg1hFgAg1hFgAg1gAhFhFg1hFg1gAg1hFg1hFgAg1hFgAg1gAhFhFg1hFg1gAg1hFg1hFgAg1hFgAg1gAhFhFisiUi.hFi.iUi.i.hFisi.i.i.i.isj#i.iii.hHh6iUheiUiii.hFhFj#hHiUiUi.hFg1gAg1iWisiWhFi.isgAi.g1hFiWhHirhFg1hFi.i.ishehehFhghFhGishFg1jag1g1g1iri.irhgg1hFhPhXg1iihFg1i.h6hPg1iUheiWhHg1hFhHg1gAhFhFh6hFhegAgAhFhXhFhggIi5jbiNjbh0iNh0i6i5h7i5hDhRh7hKhRhRhYhDhYh4hDh4h0h0hYh0iSh4h0h4hYhYh0ibh0h0hDh0hDhDh0hDhRhDhRhnhKhRhYhDhYhYh4h0h4h0jcixixixixixixixixixixixixixixixixixixixixjdhKhDhDgRh2hbhKhDhNhNhngVhbhbhDhnibhRgVhRgVhnguhngRgRhnguglglguglgugugVgugVgVglgVglglguglgugugVgugVgVglgVglglgVglgVgVgugVguguguguguguglguglglguglguguglguglglgVglgVgVglgVglglguglguguglguglglguglgugugVgugVgVglgVglglguglguguhS", +"jegAhFg1g1g1g1gAg1hHg1g1gAg1g1g1hFgAhFg1g1g1g1gAg1hHg1g1gAg1g1g1hFgAhFg1g1g1g1gAg1hHg1g1gAg1g1g1hFgAhFg1g1g1g1gAg1hHg1g1gAg1g1g1hFgAhFg1g1g1g1gAg1hHg1g1gAg1g1g1hFgAhFg1g1g1ish6hFisishFhehXi.i.i.hHjah6hFi.i.heiVi.ish6hGh6hFhehFheisheh6i.i.hHi.hHi.g1hHi#hHisiihHisi.i.i.hFhHhFirhFhehFhFhFi.isg1iig1i#hFi.hGg1irhXhHheg1i#hFirhGhFg1g1hXhXg1g1h6g1h6gAg1g1heiWg1i.g1h6hei.gAhehFhHheg1gAg1hmjfhYi4h7hYh0hRhYh0iSh4hYiChYich0hYi5hRiNi5i4hYiYhYh0ibhYhRh0hYh4iCjgh4iNhYhDhYhRh4hYh4hYhYh4i6hDhRh7hnhYhDhDh4h4h4jhixixixixixixixixixixixixixixixixixixixixinhnhnh7hDh0hRhDhDh0h7gVhRhnhnhnhnhbhbhRhnhRhDhbgVhnhbhDglgVgVglgVglglgRglgRgRglgRglglglglglglgVglgVgVgugVguguglguglglglglglglglglglglgVglgVgVgVgVgVgVglgVglglglglglglgVglgVgVglgVglglgVglgVgVglgVglglgRglgRgRglgRglglglglglglhS", +"jig1g1hFgAhFhHhFhFg1hFg1hFgAhFhFg1g1g1hFgAhFhHhFhFg1hFg1hFgAhFhFg1g1g1hFgAhFhHhFhFg1hFg1hFgAhFhFg1g1g1hFgAhFhHhFhFg1hFg1hFgAhFhFg1g1g1hFgAhFhHhFhFg1hFg1hFgAhFhFg1g1g1hFgAhFisisisi.iihFiUhFisiUi.i.i.iUhFi.iriUjai.i.i.iihHiUi.i.hei.irhFhFh6i.i.i.iUi.hFgAiUishFishFishFi.hHhFhFh6hFi.irhFiriri#i.i#iWgAhFi.iihFhFirg1jag1iihFhei.hehFhFhFjjirhFhXiihHi.hHiWhFi.heg1iWhehFh6i.i.g1hFhehFhghFhxh0d2i4hYi5hYi4jbi4iNh0jfi6hYi4hYh4hYh4h0h0hYhYhYhYiCiCh4h0i6iShYhYhDiNhDhDh0hYhYhYhRh0hnh4hYh4hYh7hDh7h4h0hRhngVhDioixixixixixixixixixixixixixixixixixixixixioh2hDhnhDgVhnhnhDhDhDhbhnhngVhRhnhRhngRhRgRgRhngVgVgVhnglglglgVglgVgVglgVglglguglguguglguglglglglglglgVglgVgVglgVglglgVglgVgVglgVglglglglglglglglglglglglglglgVglgVgVgugVguguglguglglglglglglgVglgVgVglgVglglguglguguglguglglhS", +"jkg1hFg1hHg1g1gAg1g1hFg1g1hFg1g1gAg1hFg1hHg1g1gAg1g1hFg1g1hFg1g1gAg1hFg1hHg1g1gAg1g1hFg1g1hFg1g1gAg1hFg1hHg1g1gAg1g1hFg1g1hFg1g1gAg1hFg1hHg1g1gAg1g1hFg1g1hFg1g1gAg1hFg1hHg1i.iWi.i.iih6i.iUhFhFhFhXiUi.i.i.i.i.hFhFisi.i.isi.h6hHisi.i.irhehehFi.i.iUi.h6iUi.i.hFh6hFhFisi.i.hFi.i.iUi#i#hFi.hFhPhFiri#ish6h6hehXi#irhFhehFg1g1g1hehFhXisi.i.hGg1g1iihXg1hehHhHgAg1hFhHhFhehehHh6g1iWg1g1ishehIjfh7jfhRibd2h7jbjbi4hYhYjbiNhYjfjfhYi5i4iNiNiNi6i5i4i4h0hYhYhYi6i6hRhYhYh4iSh4hYiShYibh7hYhRhRhnhRh4hDhRh4h7h0hRhRiwixixixixixixixixixixixixixixixixixixixixiwh7h7h0h0hDhRhRhRhRhRhDhDh2h2hDhnhRh7hnhRhohbhZhbhKhKibgRgVgVgugVguguglguglglgVglgVgVgVgVgVgVgVgVgVgVgugVgugugRgugRgRglgRglglgVglgVgVgVgVgVgVgVgVgVgVglgVglglgVglgVgVglgVglglgRglgRgRgVgRgVgVgugVguguglguglglgVglgVgVgVgVgVgVhS", +"g1hFg1g1g1hFhFg1hFhFg1hFhFg1hFhFg1hFg1g1g1hFhFg1hFhFg1hFhFg1hFhFg1hFg1g1g1hFhFg1hFhFg1hFhFg1hFhFg1hFg1g1g1hFhFg1hFhFg1hFhFg1hFhFg1hFg1g1g1hFhFg1hFhFg1hFhFg1hFhFg1hFg1g1g1hFiUjli2iUi.iUisisisiUi.iUhFi.hFi.i2i.iUiih6iUjai.iUisi.iih6ish6jaiUhFirhFheiii.i.i.iUg1hFg1i.g1isiWhHisisi#i.ishFhFiWi.iri.hFheiri.g1iWhFg1iri.i.hFhFhFjag1hXg1i.iri#hFishFjahFhXhFiih6i.hHg1h6hFiWg1iWiWg1i.hXhei.fPi4d2iYhYjfi5hYiNhYi5jfi4iYh0i4h0iShYi4iChYi4h4i4hYh0i6iSi4h4hYh4h0hYhYh7hYhRh0hYh4h4h0h0h4hYhYhYhRh4hRh4h4h4hRhYh4jmixixixixixixixixixixixixixixixixixixixixjmhnhDhDhDidhDh4hDhDhKhnhDhnhDhbh4hbhnhRhnhRhLhnhDhnhbhbglglglgVglgVgVglgVglglglglglglgVglgVgVglgVglglgRglgRgRgVgRgVgVgVgVgVgVglgVglglglglglglgRglgRgRglgRglglglglglglgVglgVgVglgVglglglglglglgVglgVgVglgVglglglglglglgVglgVgVhS", +"hFg1hFhFi.g1hFg1g1hFhHg1hFg1g1hFhFg1hFhFi.g1hFg1g1hFhHg1hFg1g1hFhFg1hFhFi.g1hFg1g1hFhHg1hFg1g1hFhFg1hFhFi.g1hFg1g1hFhHg1hFg1g1hFhFg1hFhFi.g1hFg1g1hFhHg1hFg1g1hFhFg1hFhFi.g1ishHhHiUisi.i2iViiisisishFjaiUi.jahXhXiii.h6iUi.i.iUiUi.i.j#i.isi.i.heiUhFheishFi.i.i.i.i.iUi2h6hFh6h6iWishFisi.i#hFhFhHisiWiihFhFhFhFisjlh6iWg1hFhFhFhFirhFi.hXiri#i#irirhFhFg1hXirhFhXi.hFi.g1i.g1g1iWhFg1iWg1h6g#iNi4jfi4iYi4i4i4hYi4i4i4h4i5jbi4i4hYi5d2d2hYi6iYiYhYi5i5iNh0i6hYhYi4hYhYhYh7i6h7h7h4hYh0h4i4hRd2i4iNhYhYhRh4hYh4h4jnixixixixixixixixixixixixixixixixixixixixjni7i7hDi7ibibh4ibh0h0hRhRh7hRhDhnhDhDhDh2h7h7hRhRhRhRhbgVglglhnglhnhngVhngVgVglgVglglglglglglgVglgVgVglgVglglglglglglglglglglgVglgVgVgRgVgRgRgVgRgVgVgVgVgVgVglgVglglgVglgVgVgVgVgVgVglgVglglhnglhnhngVhngVgVglgVglglglglglglhS", +"hFg1g1hFhHhFhFg1hFg1hFi.g1hFhHg1hFg1g1hFhHhFhFg1hFg1hFi.g1hFhHg1hFg1g1hFhHhFhFg1hFg1hFi.g1hFhHg1hFg1g1hFhHhFhFg1hFg1hFi.g1hFhHg1hFg1g1hFhHhFhFg1hFg1hFi.g1hFhHg1hFg1g1hFhHhFiUiiisisiii.i.iUj#i.iUi.i.iiisiUiUi.iUiiisi.i.i.ish6iUhFi.i.isisiii.iii.jaiUi.hFirheiih6i.iUh6iUhFg1ishFisj#hFiWishXhFg1i.ish6hFirhFiri#irish6ishFg1iihXhFirhFhFjahFhFhXiii.hFirhHhFjag1hXiihHhei.h6i.i.hFi.heiWhFjoiNiYd2.q.qiNd2d2d2iNiNi5jfi4hYi4jbjbh0h0jbiNiSi6i5h4i4ichYi5h0i5i6hYi4iChYh4h0h0h0hYhYh7h0h4hYh4h0i6hDiNhYiYhYi4i4jpixixixixixixixixixixixixixixixixixixixixjqhDhbh2hnhnhRhYhDhRh0hbh0h2hnh7hDhRhRhDhDhbh2hbgVgVgVhnglgVgVglgVglglgVglgVgVhngVhnhngRhngRgRgVgRgVgVhngVhnhngVhngVgVgVgVgVgVglgVglglglglglglgVglgVgVglgVglglgVglgVgVglgVglglglglglglgVglgVgVglgVglglgVglgVgVhngVhnhngRhngRgRhS", +"hFi.hFg1i.hFg1hFhFhHg1hFg1hFi.hFhFi.hFg1i.hFg1hFhFhHg1hFg1hFi.hFhFi.hFg1i.hFg1hFhFhHg1hFg1hFi.hFhFi.hFg1i.hFg1hFhFhHg1hFg1hFi.hFhFi.hFg1i.hFg1hFhFhHg1hFg1hFi.hFhFi.hFg1i.hFi.iUiUisi.iUhHhFiUiUiUi2i.hXjrisi.i.i.isi.isi.iUiHi.isi2iUhFi2jai.i.i.isi.jai.i.i2iUiUisiri.iii.i.jaiWisg1iUh6hFi2iWhFisisi.j#hFh6isishHhFirhFiriUi.i.i.iWg1ishHhFirirhHhHiig1hFisirhFi.hFg1iihFhXiii.g1h6iWg1hFiifPiNi6i4d2d2iNd2jfjfiYd2h0i4jfjbjfiNjfiNiYhYiYiYi5i5hYi5jbhYi5hYhYhYiYiNiYi4i5jsi4iYi4hYiSi4hYh0h0iNh4hYh4hRi6hRhYhYjtiwixixixixixixixixixixixixixixixixixixiwjuhYhYh0h0h0hYh0h0hRhRiSh7iOh4h0hDh7i7h0hRh0iChRh4hRhRhYgVhnhngVhngVgVglgVglglgRglgRgRgVgRgVgVglgVglglgRglgRgRgVgRgVgVglgVglglgVglgVgVhngVhnhngVhngVgVgRgVgRgRgVgRgVgVhngVhnhngVhngVgVhngVhnhngVhngVgVglgVglglgRglgRgRgVgRgVgVhS", +"hFg1i.hFg1i.g1i.g1hFi.hFhHi.g1hHhFg1i.hFg1i.g1i.g1hFi.hFhHi.g1hHhFg1i.hFg1i.g1i.g1hFi.hFhHi.g1hHhFg1i.hFg1i.g1i.g1hFi.hFhHi.g1hHhFg1i.hFg1i.g1i.g1hFi.hFhHi.g1hHhFg1i.hFg1i.i.jvi.jvi2iUiUj#ishHiUi.i2jviVi2iij#i.iUiVi.isiUi.isiUi.isiUi.iHi.i2hXiUi.i.i.i.i.i.iUhei2ishFisi.i.isiUiihFhHi.i.jliWisi.isi.ish6i.i.iWj#hFiri.hFiri.i.i.iWg1i.hFi.hFhFisirhFishXhHiri.i.hFg1i.hXishXiii.i.h6iVhehId2hYjfhYhYjfh0iNjfi4jf.qd2i4iYi4h0jwh0i4iYhYhYjbh0iYhYjfd2i5i4iNhYhYhYh0h0hYh4i6jbhYi4iYhYhYhYhRiSi4hYi4i4hYhYhYh7iSjxixixixixixixixixixixixixixixixixixixjyh0hRh4hYh4h0h0h2hYhDhni4hniNh0h7h4h0h7hni7hDhDhDhbhDhZhDgRgVgVglgVglglhnglhnhngVhngVgVgRgVgRgRhngRhnhnglhnglglgVglgVgVhngVhnhnglhnglglhnglhnhnglhnglglhnglhnhngVhngVgVglgVglglgRglgRgRgVgRgVgVglgVglglhnglhnhngVhngVgVgRgVgRgRjz", +"hHhFhHi.hFhHhFhHi.hFhHhFg1hFhFi.hHhFhHi.hFhHhFhHi.hFhHhFg1hFhFi.hHhFhHi.hFhHhFhHi.hFhHhFg1hFhFi.hHhFhHi.hFhHhFhHi.hFhHhFg1hFhFi.hHhFhHi.hFhHhFhHi.hFhHhFg1hFhFi.hHhFhHi.hFhHjAisjvjvisiUi.isi2j#hFish6i2i.j#i2isj#isiUiihHiUiUiUisjai.i2isisiUh6iUjaisi.hXisisi.i.i.isi2jaiUirhFj#i.i.iih6iUiUi.jlhFjliihFisish6ishFjlisi#iWhFiHirhHiri.hFhFiWjliHiiirirhFhFhFi.hFhFh6isi.hHhFiri.hFi.iii#heheg#jfiYjfi4.qi6d2i5hYiNd2jfjfi4i5d2d2jfjfiNiNi4hY.qi4jbjfi6i6iNhYi5i6jfiYhYiYiNiYi5i5jfhYi4jfhYi4i6h7i6h7hYiNiShYi4iSd2jBjCixixixixixixixixixixixixixixixixjCjDh0h0hYh0hYhYhRh0h0hYh0h4hYibh7hYiSh7h0hYh0hYh0hLhRh7hRh0gVhnhngVhngVgVgVgVgVgVgRgVgRgRhngRhnhngVhngVgVhngVhnhngRhngRgRgVgRgVgVhngVhnhngVhngVgVhngVhnhngRhngRgRgVgRgVgVhngVhnhngVhngVgVhngVhnhngVhngVgVgVgVgVgVgRgVgRgRhngRhnhnhS", +"i.i.hFi.hFhHi.hFi.hHi.hFi.i.g1hFi.i.hFi.hFhHi.hFi.hHi.hFi.i.g1hFi.i.hFi.hFhHi.hFi.hHi.hFi.i.g1hFi.i.hFi.hFhHi.hFi.hHi.hFi.i.g1hFi.i.hFi.hFhHi.hFi.hHi.hFi.i.g1hFi.i.hFi.hFhHi2jAi2jvisjvi2i2i.iUjrj#iij#iii.iVi2iUiUi2iUi2iii.jai2iUisi2i.isisiiisiriHiUi2i2i.i2isiiiUiijairiUhFi2iUi.iiiiiih6iUi2i2iUi.isjli.isi.isisi.iVj#g1iii.iHirisiririsiUi.i.i.irisishejai.isiihFiii.i.isi.hFi.jaiiiig1iajfiNjfiNjfi4jfhYiNiNhYiNiN.qiNd2iYd2jfd2hYiNi6i6iNi4i5hYhYjfi4iYiYd2i4i6jbi4i4iYhYhDiYiSiShYhYhYhYd2h7i4hYiNiYhYiNh4hYjEjFixixixixixixixixixixixixixixjFjGi4hYh4h0h4hYiShDhRhDh7hYh4hYh7h7hYi7hYi4ibiCh4h4ich4h0iNhDhnglglgVglgVgVhngVhnhngVhngVgVglgVglglgVglgVgVgVgVgVgVglgVglglgVglgVgVhngVhnhngRhngRgRgVgRgVgVgVgVgVgVhngVhnhngRhngRgRhngRhnhnglhnglglgVglgVgVhngVhnhngVhngVgVglgVglglhS", +"i.hFhHhFi.i.hFhHi.hFhHhFhFhFi.hHi.hFhHhFi.i.hFhHi.hFhHhFhFhFi.hHi.hFhHhFi.i.hFhHi.hFhHhFhFhFi.hHi.hFhHhFi.i.hFhHi.hFhHhFhFhFi.hHi.hFhHhFi.i.hFhHi.hFhHhFhFhFi.hHi.hFhHhFi.i.iUisi2iUisiUiUisjvisjviUisiUi2j#isisi2iUjliUiUi.i2i.j#hFisiii2isiUisiUisisi.i.iUi2isi2iUisisiihFiiiri2iUishFhFiriii.i.i.isiUi.i2hFhHiiiWhHiihHisiVjli.i.hFhFisi.iriri.i.hHisishFisiri.hFhHhFiWi.hFi.i.irh6irirhFiiha.q.q.qd2iY.q.q.qd2i5.qi6i5d2iNd2hY.qiSjfd2jfd2iYiYhYiYd2d2iNiShYi4i4iNiYd2jfjfi4hYhYiYi5i5iYi6i4jfi6i4iShYi4hYiYi4hYiYhYjHjIixixixixixixixixixixixixjIjJh7hYhYiSiSi4h4hYi4h0iYh0i4iSi4ibibh0ibh7i7iNhYi4h0hYich4h7h7gVgVgVhngVhnhngRhngRgRhngRhnhngVhngVgVhngVhnhnhnhnhnhnhnhnhnhngVhngVgVgRgVgRgRhngRhnhnhnhnhnhngRhngRgRgVgRgVgVhngVhnhngVhngVgVgVgVgVgVhngVhnhngRhngRgRhngRhnhngVhngVgVjz", +"i.hFi.i.hFhHi.hFi.hFi.i.hFi.hFhFi.hFi.i.hFhHi.hFi.hFi.i.hFi.hFhFi.hFi.i.hFhHi.hFi.hFi.i.hFi.hFhFi.hFi.i.hFhHi.hFi.hFi.i.hFi.hFhFi.hFi.i.hFhHi.hFi.hFi.i.hFi.hFhFi.hFi.i.hFhHjvjKjvjvjLjMiUjMiUiUjviUjvjLiUisi2isj#isi2iUiUi2iUiUj#i2j#i2hFisi2jai2iUisiHiii2iii.iUiUi2isi.j#iij#iii.i2i2iUi2hFhFj#iii.i2i.isj#iUi.hFiiiHiWisishHisiUi.iii.hFishFishFi.iUisiiisi.iHiri.j#irhHiUhFhFhFiiisiri.isiajfi6iYi6i5i4iNd2hYiYjbd2d2d2d2jfjfjfjfi6jfd2d2jfd2d2iYjNd2i4i6jOiKixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixiKjPhRi7ibhDibibi4gRhnhngRhngRgRgVgRgVgVhngVhnhngRhngRgRhngRhnhngVhngVgVgRgVgRgRhngRhnhnhDhnhDhDgVhDgVgVhngVhnhngRhngRgRhngRhnhngVhngVgVgRgVgRgRhngRhnhngRhngRgRgVgRgVgVhngVhnhngRhngRgRjz", +"i.hHi.hFi.i.hFi.hFi.i.hHhFi.hHisi.hHi.hFi.i.hFi.hFi.i.hHhFi.hHisi.hHi.hFi.i.hFi.hFi.i.hHhFi.hHisi.hHi.hFi.i.hFi.hFi.i.hHhFi.hHisi.hHi.hFi.i.hFi.hFi.i.hHhFi.hHisi.hHi.hFi.i.jMi2jvjvjvisiUi2jQjvi2iUi2jvjvi2jvi2iUj#j#isisi.isiUiUj#iUisj#j#iUi.jaiUiUisiUi.isi2i.isiVjaiUi2isi2iiiii.i.i.i.isisi2isi.i.i.iiiUi.iUi.i.hHhFj#hHi2iiisi.isisiViWiViiiHiHiririshHjQi.hFi.iiiHishFisjaisi.hHhFhFi.ia.qjf.qjfjf.qd2jfiYiNiYjfjf.qjfd2jf.qjfiYiYiNi4jfd2d2d2d2d2.qiYiKixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixiKh0h0i6hRi5hYhYhDhnhngVhngVgVhDgVhDhDgRhDgRgRgVgRgVgVhDgVhDhDhnhDhnhnhnhnhnhngVhngVgVhngVhnhnhnhnhnhngVhngVgVhngVhnhnhnhnhnhngVhngVgVhDgVhDhDhnhDhnhngVhngVgVhDgVhDhDgRhDgRgRgVgRgVgVjR", +"hFishFishFisi.i.hFishFi.isi.i.i.hFishFishFisi.i.hFishFi.isi.i.i.hFishFishFisi.i.hFishFi.isi.i.i.hFishFishFisi.i.hFishFi.isi.i.i.hFishFishFisi.i.hFishFi.isi.i.i.hFishFishFisjvi2i2jKi2jvjvi2i2i2jAjvjAjvjKjvjvi2iUjSiUi2jTiHi2i.iUjviUiUisjvj#i2isjvhFiUiUi2isi2i2jQiiisjai2iUi2iUjKi.iiiUiUiUi.iUi2iri2isiUi.iii.i2i.i.isi2j#i.iWiUisisisisi.iVi.iUisiHi.isisisiUisiUisiiisiHishFisirisjQiiiijUiY.2iN.2dGjbdGi6jf.qi5iYiYjf.qjfi6i5i6i5jfiYiN.qiYd2.qd2d2i6jfixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixi4h0hDh0hYiNiShngRgRhngRhnhnhnhnhnhnhnhnhnhnhnhnhnhngVhngVgVhDgVhDhDgRhDgRgRhngRhnhngVhngVgVgVgVgVgVhngVhnhnhDhnhDhDgRhDgRgRhngRhnhnhnhnhnhngRhngRgRhngRhnhnhnhnhnhnhnhnhnhnhnhnhnhnhS", +"i.i.i.i.hFi.hFhFisi.hFhFi.hFishHi.i.i.i.hFi.hFhFisi.hFhFi.hFishHi.i.i.i.hFi.hFhFisi.hFhFi.hFishHi.i.i.i.hFi.hFhFisi.hFhFi.hFishHi.i.i.i.hFi.hFhFisi.hFhFi.hFishHi.i.i.i.hFi.jQiUjVjvi2i2i2i2jvjKi2i2i2jMiUi2iUiUjvjviUiUi2iUjTisiHj#i.iUiUi2iUiUjvj#iWisiVi.iUiri2i2i.iHisishFi.i2iUiUiUi.i.ish6iUiii.i2iUi2iUhFiUi.iii.iUhFi2isi2j#iViHiWi.hFisj#i.i.i.j#i.iUhFisisisiUi.i.i.hFisiHirhFisirishad2jf.qiYiY.qiYiYhYdGd2.2jWjf.qjX.q.2.qd2jf.qjfd2iYiN.qiNjfjfd2ixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixi6d2d2d2i6i6h0hDgVgVhngVhnhngVhngVgVhDgVhDhDhnhDhnhnhnhnhnhngVhngVgVhngVhnhnhDhnhDhDhnhDhnhnhDhnhDhDhnhDhnhngVhngVgVgVgVgVgVhDgVhDhDhDhDhDhDgVhDgVgVhngVhnhngVhngVgVhDgVhDhDhnhDhnhnjz", +"iUhFi.hFisisi.isi.hFi.isi.ishFi.iUhFi.hFisisi.isi.hFi.isi.ishFi.iUhFi.hFisisi.isi.hFi.isi.ishFi.iUhFi.hFisisi.isi.hFi.isi.ishFi.iUhFi.hFisisi.isi.hFi.isi.ishFi.iUhFi.hFisisjvjLjLjQi2jSjMjvjKiUjvjvi2jvjvjSjvjYi2iUi2jvi2jvjvjLjYisi2isi2jvi2iUiUiUiUjTiHjTiUi2i2jai2jajQjQisi2iHi.iVi2i2i2i2isiUi.iUi.iUi2i2isi.hFi.iUiiiUiUi2i.hFj#hFjTiUi.jvi.hFisisi2j#iWiijviiishFisishFjQisi.i.i2isishFha.qjfjZ.qd2.2d2jf.qjfjfiYi6i5iYi6i5jXjfiY.qhY.qi6i6jfi5iY.qjfi4ixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixiYh0hYi4h7h7i4gVhnhngVhngVgVhDgVhDhDhnhDhnhngVhngVgVhDgVhDhDhnhDhnhnhDhnhDhDgVhDgVgVgVgVgVgVhngVhnhngVhngVgVhngVhnhnhDhnhDhDhnhDhnhngVhngVgVhngVhnhngVhngVgVhDgVhDhDhnhDhnhngVhngVgVjR", +"ishFisisi.i.i.hFi.isi.ishFi.i.i.ishFisisi.i.i.hFi.isi.ishFi.i.i.ishFisisi.i.i.hFi.isi.ishFi.i.i.ishFisisi.i.i.hFi.isi.ishFi.i.i.ishFisisi.i.i.hFi.isi.ishFi.i.i.ishFisisi.i.jMi2jvjLi2jLiUi2i2jMjvi2jKjvjKi2jviUjLjYjMjviUi2isi2jviUjTjvj#iHi2hFi2iUi2iUi2iUiViHishFjvj#iUi2isiUisi2i2j#iUiVi2i2i2iUjQisisiUiUi.i2i2i2isisi.j#iiiUi.i2i.i2i2i2i.iii2isiUisisisj#j#i.iUisi.isisiri.jQiijQiWi.i.ia.qdGdGjfjfd2i6.q.q.qiY.qdGjfdGd2jfdG.qdG.2.2.2.2d2d2d2jf.2jf.2ixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixd2hYhYhYiYi4i5hnhRhRhnhRhnhnhDhnhDhDhnhDhnhnhnhnhnhnhDhnhDhDgVhDgVgVhngVhnhnhDhnhDhDhnhDhnhnhDhnhDhDhDhDhDhDhDhDhDhDhnhDhnhnhDhnhDhDhnhDhnhnhRhnhRhRhnhRhnhnhDhnhDhDhnhDhnhnhnhnhnhnjR", +"i.isi.ishFisisisisi.iUi.ishFisiUi.isi.ishFisisisisi.iUi.ishFisiUi.isi.ishFisisisisi.iUi.ishFisiUi.isi.ishFisisisisi.iUi.ishFisiUi.isi.ishFisisisisi.iUi.ishFisiUi.isi.ishFisj0j0j0i2jvjvjLjKjvjYjvjYiUjYi2jvjvjKjvi2jYi2jYiUjvjvjvjvjvjviUjvjTjTjTiHjMi2iUiUjTiUj#jLj#i2iij#iUiUiUi.iUiUi2i.jvi2i2i2i2jQi.isisisisiUj1i2i2iUjviUiiiUi.i2iUi.i2i2isj#jviii2iWisiUi.jvi.iUisjTiUiUisisiUi.jQi.i2hId2.q.2jf.q.qdGjfjfdGd2j2j2jXaeiYiYd2iYd2d2jfjXjXjX.q.qd2d2jfjXixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixh7hYi4h0h0h0hYhnhnhnhRhnhRhRhnhRhnhngVhngVgVhngVhnhnhnhnhnhnhDhnhDhDhnhDhnhnhRhnhRhRhnhRhnhnhnhnhnhnhnhnhnhnhnhnhnhnhDhnhDhDgVhDgVgVhngVhnhnhnhnhnhnhRhnhRhRhnhRhnhngVhngVgVhngVhnhnjz", +"hFi.iUi.isi.i.hFisi.isi.i.iUi.i.hFi.iUi.isi.i.hFisi.isi.i.iUi.i.hFi.iUi.isi.i.hFisi.isi.i.iUi.i.hFi.iUi.isi.i.hFisi.isi.i.iUi.i.hFi.iUi.isi.i.hFisi.isi.i.iUi.i.hFi.iUi.isi.jLjvj0i2jYi2iUjYjvjvjQi2jYjvjYi2i2jvjKisjvi2jvj3i2i2iUi2jvjvjvi2i2iUjTj#iUj#j#jYi2iUisi2iUj#i2iHiHjaiUi2jvi2iUjKisisisiHi2iUi2i.i.i2jTisjKiii.i2i2i2iUisiUi.jKiiiiiUi2i2jvi.i.iUiii.hFisiUisjvj#j#iiiUi.isish6jai.hadGjf.2i6jf.qjfjWdGjfjW.qiYjWjX.q.2dGjfdGjWdGjW.q.q.q.UiYiY.2d2ixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixh0i4d2i4iShYhYhDhDhDgVhDgVgVhDgVhDhDhRhDhRhRhRhRhRhRhDhRhDhDgVhDgVgVhDgVhDhDhnhDhnhnhDhnhDhDhDhDhDhDhRhDhRhRhnhRhnhnhDhnhDhDhnhDhnhnhDhnhDhDhDhDhDhDgVhDgVgVhDgVhDhDhRhDhRhRhRhRhRhRjR", +"i.isisi.i.isiUisiUisi.isiUi.isisi.isisi.i.isiUisiUisi.isiUi.isisi.isisi.i.isiUisiUisi.isiUi.isisi.isisi.i.isiUisiUisi.isiUi.isisi.isisi.i.isiUisiUisi.isiUi.isisi.isisi.i.isjYjLj4jLjvj0jYjMj0jYjLjLjvi2jLjvjvjvjYjvi2jvjKi2jvjvjMjYjvjKi2isjYisjYjvi2jvjviHjTjviUiUiUjviUi2jYjTjYi2i.iUjYisiUjQi2i2jQi2iVi2i2iUjKisi.iUjKiUisi2i2i2i2i2i.jQjAjTi2iUi.isi2i2isisiiiUisishHisi2isjAjTj#i2iUisj#iaiYjfjfjZjf.U.qaej5j2j2jfaed2j5d2jXjX.qjfjXdGi4dGjWi6dGiNjf.qiNixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixi5iNjfjfi5i6i4hDhnhnhDhnhDhDhnhDhnhnhnhnhnhnhDhnhDhDhnhDhnhnhDhnhDhDhRhDhRhRhRhRhRhRhnhRhnhnhnhnhnhnhDhnhDhDgVhDgVgVhngVhnhnhRhnhRhRhDhRhDhDhnhDhnhnhDhnhDhDhnhDhnhnhnhnhnhnhDhnhDhDjz", +"iUi.isiUi2i.isi.i.iUisi.isi.i.iUiUi.isiUi2i.isi.i.iUisi.isi.i.iUiUi.isiUi2i.isi.i.iUisi.isi.i.iUiUi.isiUi2i.isi.i.iUisi.isi.i.iUiUi.isiUi2i.isi.i.iUisi.isi.i.iUiUi.isiUi2i.j0jrjrjYjvjvjvjLjYj3j3jMjvjYjYi2jvi2i2jYjvi2jYi2jvjYjYi2jvjVjLjMjvi2isjYjvi2jvi2i2jvjviHisjYj4i2iUi2i2jYi2j#i2iVi2iUiUisi2jKjvi2j#iHiVi2i2i2jQi.iiiUiUiUisi2i2isisisisjAiUi.i2i2i.i2iUj#isjAi2isisisisjvjTiVisi.i2gIdG.qj2dGdGjwjf.q.q.q.q.qjf.qi4jfdGjW.2.2.2j5.qaeaedGdGaedGd2jfixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixhYhYjfhYj5j5i4hRhnhnh0hnh0h0hRh0hRhRhnhRhnhnhnhnhnhnhRhnhRhRhDhRhDhDhnhDhnhnhnhnhnhnhDhnhDhDhDhDhDhDhRhDhRhRhRhRhRhRhnhRhnhnhDhnhDhDhRhDhRhRhnhRhnhnh0hnh0h0hRh0hRhRhnhRhnhnhnhnhnhnj6", +"isisi.isisisiUisiUi.iUi2isiUisi.isisi.isisisiUisiUi.iUi2isiUisi.isisi.isisisiUisiUi.iUi2isiUisi.isisi.isisisiUisiUi.iUi2isiUisi.isisi.isisisiUisiUi.iUi2isiUisi.isisi.isisisj7j0jvj4j4jLjvjYjLjvj0j0jMjYjKjYj4jLj4jvjYj4jYjvjYi2jvjKi2jvjvj0jYjYjvjvjAi2jvjYjvi2jvjTiHi2jTjviUiUiUi2i2i2jvjvjvi.iUiUisi2iUjQjMi2jMiUjYi2i2i2jQi.iUjQiUjKisiUiUisiUi2jvjviUjAi2iii2i2i2jTisisjYi2iUisiUi2jTi2jvg#dG.2.qj2e0.qjfjfjfjWjZ.2.q.qjf.qjfjfjWd2iYjWjX.qjfi4dGjfd2.Ud2ixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixi4iYd2iShYhYhYhnhDhDhnhDhnhnhDhnhDhDh0hDh0h0hDh0hDhDhDhDhDhDhRhDhRhRhDhRhDhDhDhDhDhDhDhDhDhDhnhDhnhnhDhnhDhDhnhDhnhnhRhnhRhRhnhRhnhnhnhnhnhnhDhnhDhDhnhDhnhnhDhnhDhDh0hDh0h0hDh0hDhDjR", +"isi2isi.i2isi.isiUisi.isi.isi2isisi2isi.i2isi.isiUisi.isi.isi2isisi2isi.i2isi.isiUisi.isi.isi2isisi2isi.i2isi.isiUisi.isi.isi2isisi2isi.i2isi.isiUisi.isi.isi2isisi2isi.i2isjvjvjYjvjvj4i2jvj8jvjTj8jvi2j9j0jMjvjvj#jLj0i2jvj4jvjKj4jYisj4jKi2jvjYj0i2jvi2jvjYjvjvjYjvi2jYjTiHisiUjviUjviUiUj4jTjTk.i2i2jriUi.i2iUjQiHjviHj#jri2iUjvjQisjMisiUiUiUi2i.jvi.isjMiUisi2i2i2i2i2j#jTjvisiHisisi.jYha.qjfj2.U.q.U.qj2j2.qj5d2.q.2.q.q.2j2dG.Uk#dG.2.2dGjW.qdGjfjfjWixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixj2.qjf.qd2d2jfhDhRhRhDhRhDhDhnhDhnhnhDhnhDhDhDhDhDhDhnhDhnhnhDhnhDhDhRhDhRhRhnhRhnhnhDhnhDhDh0hDh0h0hDh0hDhDhDhDhDhDhDhDhDhDh0hDh0h0hDh0hDhDhRhDhRhRhDhRhDhDhnhDhnhnhDhnhDhDhDhDhDhDjz", +"iUi.i2isi.i2isi2i.iUi2iUisi2i.isiUi.i2isi.i2isi2i.iUi2iUisi2i.isiUi.i2isi.i2isi2i.iUi2iUisi2i.isiUi.i2isi.i2isi2i.iUi2iUisi2i.isiUi.i2isi.i2isi2i.iUi2iUisi2i.isiUi.i2isi.i2jvjVjLjVj4jYj3jVk.jLjVjLjLjvjLj4jVjVjMj3jLjvjLj4i2jvj3jMjVjYjMjLjvj4i2j3jYjYjYjLjvjvjYi2j4jSi2jYjvjviijYi2iUiUi2j#iUjYjrjvjviHk.i2i2i2jKjriUi2i2i2j#i2i2i2jQisjviUi2iUi2i2iUisi2i2isjAiUi2i2i2i2isi2j#jAjLjvi2jMishIayi4ay.qj2.U.qdG.qj2.qj2.qdG.2.2jWj2jWj5j2.q.qiYd2.2.qayka.q.Uixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixi4iYjfi4d2d2jfhDhRhRhnhRhnhnh0hnh0h0hRh0hRhRhDhRhDhDh0hDh0h0hnh0hnhnhDhnhDhDh0hDh0h0hDh0hDhDh0hDh0h0hnh0hnhnh0hnh0h0hDh0hDhDhnhDhnhnhDhnhDhDhRhDhRhRhnhRhnhnh0hnh0h0hRh0hRhRhDhRhDhDj6", +"isisisi2iUisiUisi2isisiUi.iUisi2isisisi2iUisiUisi2isisiUi.iUisi2isisisi2iUisiUisi2isisiUi.iUisi2isisisi2iUisiUisi2isisiUi.iUisi2isisisi2iUisiUisi2isisiUi.iUisi2isisisi2iUisjYjSjVjVjvjYjvj3jvjVj4j0jLj4jLjLj4jvjVj0jvjvi2j3jvjYjLjTjvj9jYjYjYjvjYjKjvjYi2jVjvjLjYjvisj4iUjvjYjvjvjTjvjvj#jYi2i2i2iUi2jYjvjvjMisj4iUi2i2i2jKjQi2i2j#i2jriUjQjKisjvjTiUjAi.i2iUi2jQisjQjMjvi2i2isi2i2isjvi.jAisgI.Uay.Uay.Ud2j2dG.2.2.q.q.qae.qae.2dG.UjW.2j5.qj2.UdGk#.2.2dGjWixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixix.qjfd2j2i6d2.qhDh0h0hDh0hDhDhRhDhRhRhDhRhDhDh0hDh0h0hRh0hRhRh0hRh0h0hDh0hDhDhDhDhDhDhRhDhRhRhDhRhDhDh0hDh0h0hDh0hDhDhRhDhRhRh0hRh0h0hDh0hDhDh0hDh0h0hDh0hDhDhRhDhRhRhDhRhDhDh0hDh0h0j6", +"i2i2iUi2isisi2isi2isi2isi2i2i.isi2i2iUi2isisi2isi2isi2isi2i2i.isi2i2iUi2isisi2isi2isi2isi2i2i.isi2i2iUi2isisi2isi2isi2isi2i2i.isi2i2iUi2isisi2isi2isi2isi2i2i.isi2i2iUi2isisj4jVjVjVjvjvj4j4jTj3j4jVj4jVj4jLjLjLj4j0j8j3jLjLjvjvjLjYjYj4jvjvj4jYjvjKjLjvj4j4jvjYjYjLjYjLiUiUi2jvj4jvjYjvjYjvj#jvj4i2jvi2i2jTi2i2jvjvjri2jrjriUjKjvjvjYjMjvjvi2i2i2jvi2iUjMjMi.i2iUi2j1i2jTjTjLjKi2i2i2isi2i2i.hI.U.2.2.2.2.q.2iY.q.2j2dGj2j2e0.Uj2dGk#jfjZ.2.2j2.UdGj2d2d2aydGixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixd2d2jfd2i5dGi4hRhnhnhDhnhDhDh0hDh0h0hRh0hRhRhDhRhDhDhDhDhDhDhDhDhDhDhnhDhnhnhRhnhRhRh0hRh0h0hDh0hDhDhRhDhRhRhDhRhDhDh0hDh0h0hDh0hDhDhRhDhRhRhnhRhnhnhDhnhDhDh0hDh0h0hRh0hRhRhDhRhDhDjR", +"i2isisisi2i2isisi2iUisiUisisi2isi2isisisi2i2isisi2iUisiUisisi2isi2isisisi2i2isisi2iUisiUisisi2isi2isisisi2i2isisi2iUisiUisisi2isi2isisisi2i2isisi2iUisiUisisi2isi2isisisi2i2jvjLjVjVjLjVjSjvj4jvj4jvj0jvkbj4j0j4jVjYjLjYjvjvkbjYjVjKjvjvj4i2jLjvjVjVjvjvjvjvj4jvj4jvjSjvj4jvjviUj4jYisjYjvjvjYjvjvjTjvi2i2jLiUjTjvjvjTiUisi2jri2i2iUjQjQjMjvj#jvjri2iUi2isjQjMiUi2isi2iUi2i2isjTjMjAisjAisi2i2kcayayk#ay.qaybP.Uay.2.UjfdG.Ujf.qdG.UdGj2.qayj2k#.2.2.U.q.qaed2ixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixj2jfjfjfd2jWjfhDhRhRh0hRh0h0hDh0hDhDh0hDh0h0hDh0hDhDh0hDh0h0h0h0h0h0h0h0h0h0hDh0hDhDhDhDhDhDh0hDh0h0h0h0h0h0hDh0hDhDhRhDhRhRh0hRh0h0hDh0hDhDhRhDhRhRh0hRh0h0hDh0hDhDh0hDh0h0hDh0hDhDj6", +"i2iUi2i2isisi2isi2isi2jvisi2iUisi2iUi2i2isisi2isi2isi2jvisi2iUisi2iUi2i2isisi2isi2isi2jvisi2iUisi2iUi2i2isisi2isi2isi2jvisi2iUisi2iUi2i2isisi2isi2isi2jvisi2iUisi2iUi2i2isisj4jSj9jvj9kbjSj4jVjSjVjYjVj8jvj0kbj0jVj0jVjVjvj8j4jvjVjYjVj4jvjvj4jvj4jLjVjVjvj4jvjvjYjYj4j3jvjSj4jvjLjvj4jVjvjYjYjvjvjYjvj4jTjvi2jvi2iUjvj4jTj4jMisj4i2i2jvi2jQjMjQi2j#i2jLi2jviUisjvjAi2jYisi2i2i2i2isjMjYiUi2jAjU.Ujfayd2.2.2jf.Ub1k#.2.q.U.2j2bPkd.qb1.q.2.Ud2.Uj2dG.2.q.qj5.qixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixked2d2hYjfjwj2hDh0h0hDh0hDhDhRhDhRhRh0hRh0h0hDh0hDhDh0hDh0h0hDh0hDhDhDhDhDhDh0hDh0h0hYh0hYhYhDhYhDhDh0hDh0h0hDh0hDhDh0hDh0h0hDh0hDhDhDhDhDhDh0hDh0h0hDh0hDhDhRhDhRhRh0hRh0h0hDh0hDhDj6", +"i2isi2iUi2i2isi2isi2i2isisi2isjvi2isi2iUi2i2isi2isi2i2isisi2isjvi2isi2iUi2i2isi2isi2i2isisi2isjvi2isi2iUi2i2isi2isi2i2isisi2isjvi2isi2iUi2i2isi2isi2i2isisi2isjvi2isi2iUi2i2jVjVjVj9j9jvjvj4jSjVjVjYjVjVjVj4jLj4j0jVjVjvjvjvjVjVj4jLj4j3jVjvjYjLjvj4jYjLjLj4j0jSjLjYjLj1jYj4j0jYjYjLjLjvjvi2jvjYjYjLjYjvjvjvjvjviUi2i2iUiUjrjTjYjvjvi2iUi2jrjQjrjvj4jvi2j#i2iUjLjrjQi2jvjLjMiUi2i2i2i2isisi2iskffs.UeB.U.Uay.qayk#.2ay.2b1.U.2.U.Uayj2k#k#.Uj2j2ae.Uaej2j2ay.2ixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixd2d2.2i6.q.qjXhYh0h0hDh0hDhDhYhDhYhYhDhYhDhDhDhDhDhDhYhDhYhYh0hYh0h0h0h0h0h0hDh0hDhDh0hDh0h0h0h0h0h0hRh0hRhRh0hRh0h0h0h0h0h0hDh0hDhDhYhDhYhYh0hYh0h0hDh0hDhDhYhDhYhYhDhYhDhDhDhDhDhDj6", +"isjvisjvisjvi2i2isjviUi2jvi2i2i2isjvisjvisjvi2i2isjviUi2jvi2i2i2isjvisjvisjvi2i2isjviUi2jvi2i2i2isjvisjvisjvi2i2isjviUi2jvi2i2i2isjvisjvisjvi2i2isjviUi2jvi2i2i2isjvisjvisjvj9jVjSkgjVj9kgj4j4j4jVjVjVjVj4khjVj4jvkgjYjVjVj4j4jvjvjVjLjVjvjVjVjVjKkhjvjYjVj4j4j4jVjVjYj0jKjVjYj4jvj3jYjLjSj4jMjLjvjVjvjVjSjYjvjvjTjViUi2jvjrjLi2jvjvi2jvjvjvi2jriUjvi2j4jYjYjYi2i2jvisjLjQjYi2jMisjviUi2jvjvjLgI.2kd.qfs.UdG.U.2.2k#.2k#k#.2.Ub1dG.2jf.2.2.2.2.U.U.Uj2bP.UjZk#ixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixj2jf.2jf.q.2d2h0hDhDh0hDh0h0h0h0h0h0h0h0h0h0hYh0hYhYhDhYhDhDhYhDhYhYhDhYhDhDh0hDh0h0hDh0hDhDhDhDhDhDh0hDh0h0hYh0hYhYhDhYhDhDh0hDh0h0h0h0h0h0hDh0hDhDh0hDh0h0h0h0h0h0h0h0h0h0hYh0hYhYjR", +"i2i2jvi2isi2isiUjvjvisisjvisjvisi2i2jvi2isi2isiUjvjvisisjvisjvisi2i2jvi2isi2isiUjvjvisisjvisjvisi2i2jvi2isi2isiUjvjvisisjvisjvisi2i2jvi2isi2isiUjvjvisisjvisjvisi2i2jvi2isi2jSjYkbkhjSjSjVjSkgjVj4j4jVkbjSjVjSjvkhkhjvjvjVjvjVj0j4jvjSj4jvjLjTj4kbjVjKjKjSjvj3jvj4j4j4j4jvjVjvjvjVj3jvjvjYjvjSjvj4jLjSj4jvj4jvjYjYjvjTjTjvisjViUjrjrjLj4jTjvjTi2jLjvi2iUi2i2jvjQjYjMjvjri2jri2iUjYjLiUisjYisjvhIj2.Uay.2.Uay.Uayay.Uayfs.Uaykday.U.U.U.2fsayfsj2.2.2j2.2.q.qdGixixixixkikjkkkljxkmknixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixix.q.U.U.U.U.qjfhYhRhRhYhRhYhYhDhYhDhDhYhDhYhYh0hYh0h0h0h0h0h0hRh0hRhRh0hRh0h0hYh0hYhYh0hYh0h0hYh0hYhYh0hYh0h0hDh0hDhDhDhDhDhDhYhDhYhYhYhYhYhYhRhYhRhRhYhRhYhYhDhYhDhDhYhDhYhYh0hYh0h0j6", +"jviUi2isjvjvi2jvi2isi2jvi2jvisjvjviUi2isjvjvi2jvi2isi2jvi2jvisjvjviUi2isjvjvi2jvi2isi2jvi2jvisjvjviUi2isjvjvi2jvi2isi2jvi2jvisjvjviUi2isjvjvi2jvi2isi2jvi2jvisjvjviUi2isjvjvjVkgj9jSj4jVkbjVjVjVjVjVj4jVjVkgjVjVjVjSjVkhj4jVjSj9jVj3j4j0jVkhjVjVj4jTj8jVj4j0j3jVjSjYj4jLj4jVjVjVjLjKjLjVjYjVjSjYjYjvj4jvjYjVj4jYjYjvjYjvjYjvjvjVjviUjriUjvjvjvj4i2jTjrjvjrjLjKjvi2jKjMj#j3jvi2jLjri2i2jYjMjYi2gIbP.Uayayj2kdaykdkd.Ufsaej5.2.2.Ujfk#.2k#.U.2.Ujfjfayjf.2j2bPj5ixkokpkqj2k#jW.2.q.qbPkrksktixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixix.2.qjfj2kukvkwkxiwioinjckykzhYhDhYhYh0hYh0h0hDh0hDhDhYhDhYhYh0hYh0h0hYh0hYhYhRhYhRhRhDhRhDhDh0hDh0h0hDh0hDhDh0hDh0h0hYh0hYhYh0hYh0h0hDh0hDhDhYhDhYhYhDhYhDhDhYhDhYhYh0hYh0h0hDh0hDhDj6", +"jvisjvjvi2i2i2isi2jvi2jvisi2i2i2jvisjvjvi2i2i2isi2jvi2jvisi2i2i2jvisjvjvi2i2i2isi2jvi2jvisi2i2i2jvisjvjvi2i2i2isi2jvi2jvisi2i2i2jvisjvjvi2i2i2isi2jvi2jvisi2i2i2jvisjvjvi2i2kAjSjVkgj4kgjYj4j4kbjVjSkgjVjLj4j8jvjVkbjYjVj4jVjLj4jVjvjVjVj4j4j4jvjVjVj8jVjvj8j4j4jSjKkhjSjvj4jVjvjVjVj4jSjYjLi2jYjVjvjVjYj3j4j4jvj4jYj4jYjvjYj4jYjvkBkCkDj4jrjviUjvjYj4jvjvjrj4jrjLiUjvi2jvjYjYj#i2jLjvjLjQi2jvkfb1.U.U.UdGkad2ayk#kd.Ufs.UeB.Ukaayfsk#.Ufs.U.U.U.U.U.2bPfsayfskEkFbPay.Ufsk#.2ay.2.Uj2.UkGknixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixbP.2e0kkiwixixixixixixixixiwjxkHhYhYhYhYhYhYhRhYhRhRhYhRhYhYhDhYhDhDh0hDh0h0hYh0hYhYh0hYh0h0hYh0hYhYhYhYhYhYhYhYhYhYh0hYh0h0hYh0hYhYh0hYh0h0hYh0hYhYh0hYh0h0hYh0hYhYhYhYhYhYhRhYhRhRj6", +"jvjvi2jvisjvjvjvjvi2jvi2jvisjvjvjvjvi2jvisjvjvjvjvi2jvi2jvisjvjvjvjvi2jvisjvjvjvjvi2jvi2jvisjvjvjvjvi2jvisjvjvjvjvi2jvi2jvisjvjvjvjvi2jvisjvjvjvjvi2jvi2jvisjvjvjvjvi2jvisjvkhkhkhj9j9j9kgjVkhjVkgkbjVkbjSjVkgkgkIj4jVjVjVjSjVj0khjVjVj9jvjVjVjVjVjLjSj4jVjvj4j9jVjVjVjVjvjSj3j3j0j4j4jVjVjvj3jSjVjVj4jYjvjYjSjSjSjMjvj4jYjvkJkKkLixixixi2jvjVjvjvjrjLjvjYjTjVjLjvjLi2jvisjLjvjvjvjMjYjrjLi2jYig.2b1.U.2.2.U.U.U.Uaykakdkday.Ufs.Uj2ay.qj2j5k#.U.U.U.Uayj2fsk#kMkd.qb1.q.q.UdGbPbPayay.2j2kNkOixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixd2kPkQixixixixixixixixixixixixkRkSh0hDh0hDhDh0hDh0h0h0h0h0h0hYh0hYhYh0hYh0h0hYh0hYhYh0hYh0h0h0h0h0h0hRh0hRhRh0hRh0h0hYh0hYhYhDhYhDhDhYhDhYhYh0hYh0h0hYh0hYhYh0hYh0h0hDh0hDhDh0hDh0h0j6", +"isi2jvi2jvi2i2isjvi2jvi2i2jvjvi2isi2jvi2jvi2i2isjvi2jvi2i2jvjvi2isi2jvi2jvi2i2isjvi2jvi2i2jvjvi2isi2jvi2jvi2i2isjvi2jvi2i2jvjvi2isi2jvi2jvi2i2isjvi2jvi2i2jvjvi2isi2jvi2jvi2kAjVkhj4kAj9j9kAkgj9j0j4jVj9kbjVjVjVkgjLjVj4jLj9jVjVjSjvj0jVjVj4j4j0jVj4jVjvjVjVjVj4jTj8j9jVjVjLjLjvj3i2jVj4jYjVj9jLj0jLjSjYjYjYjYjVjSjYjVkTkUkVkoixixixixixjYjYi2jvjVj4jLi2i2jvjvjvjTk.jLi2jLjrjrjKjvjvj3jMi2jvjLgIfsb1fsdG.2b1.2.U.U.Uayayay.Uk#fsfs.Ufs.U.2.UbPkdkdfs.U.Ufs.Ufsfsfsj2.Uk#j2.Uj2bPbPfsk#.UbPjWkWkxixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixkXjFixixixixixixixixixixixixixixiJkYhYhYhYhYhYhYhYhYhYhYhYhYhDhYhDhDhYhDhYhYh0hYh0h0hYh0hYhYhYhYhYhYhYhYhYhYhYhYhYhYhYhYhYhYh0hYh0h0hYh0hYhYhYhYhYhYhDhYhDhDhYhDhYhYhYhYhYhYhYhYhYhYj6", +"jvjvjvisi2jvjvjvjvjvi2jvjvi2jvjvjvjvjvisi2jvjvjvjvjvi2jvjvi2jvjvjvjvjvisi2jvjvjvjvjvi2jvjvi2jvjvjvjvjvisi2jvjvjvjvjvi2jvjvi2jvjvjvjvjvisi2jvjvjvjvjvi2jvjvi2jvjvjvjvjvisi2jvkZj9k0k0kAkgjVkAj9kAkgkgkgjYj9jVjVjVkbjVjVkgjSj4kIj9kbjVjVj4jVj0khjSj9jVj4jVj4j4jVjVjVjVjVjvj4j4jVj4jVjSjLjVjvj4j3j4kAjSjVjYjLjSjVjvk1k2k3k4ixixixixixixixixjYjYjvi2j4jvi2jvjVjLjvjvjYjYjvjvi2jLjvjSjvjLjrj4jvjYjKig.UbP.Uayfsfsb1ay.2b1bP.U.U.q.Uj2k#k#ay.Uay.Uay.U.2jffs.2.U.U.U.UbPbPfskdbPfsb1fs.Uj2.U.Uayk#.Uk5k6ixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixjIixixixixixixixixixixixixixixixixkRkHhYh0h0hYh0hYhYh0hYh0h0hYh0hYhYhYhYhYhYhYhYhYhYh0hYh0h0h0h0h0h0hYh0hYhYhDhYhDhDhYhDhYhYhYhYhYhYhYhYhYhYh0hYh0h0hYh0hYhYhYhYhYhYh0hYh0h0hYh0hYhYj6", +"jvi2jvjvj4i2jvi2i2jvjvi2jvi2i2jvjvi2jvjvj4i2jvi2i2jvjvi2jvi2i2jvjvi2jvjvj4i2jvi2i2jvjvi2jvi2i2jvjvi2jvjvj4i2jvi2i2jvjvi2jvi2i2jvjvi2jvjvj4i2jvi2i2jvjvi2jvi2i2jvjvi2jvjvj4i2khj9j9k0k0kAjVj4kAkhkhkAj9khkZj4kgj4j4jVjVjVjVjVj9kgkgj4jVjVj9kbjVjvjvjVjVj4j9j4kbjVjVj4j0khkbj8jVj8j4j9jSjvjVjLj4j3j3j4jVjVjVk7k8k9l.ixixixixixixixixixixixkAjYjYjYjYjYjYjvj4jri2jvjvjLjvjvj4k.jvk.jrjLjLi2jvi2jMigbP.2bPbPfsaybPayfs.2.2.Uayay.U.U.U.Ufskdfs.Ufs.U.Ufsfsfs.Uj2b1k#ay.UbPfsfs.2bPfsfs.U.UbP.Uay.UeBl#ixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixlahYh0h0h0h0h0h0hYh0hYhYhYhYhYhYh0hYh0h0h0h0h0h0hYh0hYhYhYhYhYhYhYhYhYhYhYhYhYhYh0hYh0h0hYh0hYhYhYhYhYhYhYhYhYhYiYhYiYiYhYiYhYhYh0hYh0h0h0h0h0h0j6", +"jvjvi2jvjvjvjvjvjvjvjvjLjvjvjvi2jvjvi2jvjvjvjvjvjvjvjvjLjvjvjvi2jvjvi2jvjvjvjvjvjvjvjvjLjvjvjvi2jvjvi2jvjvjvjvjvjvjvjvjLjvjvjvi2jvjvi2jvjvjvjvjvjvjvjvjLjvjvjvi2jvjvi2jvjvjvk0kgj9k0kAj9k0k0jVkAkgkhkAkAj9kAkgkgkgkgjVj9jVjVkbjVkgkgj4jVjSjVkbjVjVkhjVjSjVjVj9j4jVjVj4jVjVjVjVjVj9jVj4j4jSj0jVjLj3j3jLlblcldixixixixixixixixixixixixixixjSjVjYjYjYjYj4j4jYjvj4i2jvjVjLjLjvjvj4j4j4jVjVjLjLjLjvgI.2ay.2b1bPfsbPbPfs.2ayayb1b1.2bP.U.U.2ayfs.Ukdkdkd.U.U.Uayfsj2fskdfs.U.Ufs.U.Uj2j2kdayfs.UbP.U.Ulelfixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixiwlgi4i4hYi4hYhYhYhYhYhYhYhYhYhYhYhYhYhYhYhYhYhYhYhYhYhYhYhYhYhYhYhYhYhYh0hYh0h0hYh0hYhYhYhYhYhYh0hYh0h0hYh0hYhYhYhYhYhYhYhYhYhYi4hYi4i4hYi4hYhYj6", +"jvj4jvjvj4jvi2jvjvjvi2jvjvjvj4jvjvj4jvjvj4jvi2jvjvjvi2jvjvjvj4jvjvj4jvjvj4jvi2jvjvjvi2jvjvjvj4jvjvj4jvjvj4jvi2jvjvjvi2jvjvjvj4jvjvj4jvjvj4jvi2jvjvjvi2jvjvjvj4jvjvj4jvjvj4jvkAk0k0jVj9kAj9j9lhk0khkAjVjVj9khkAj9j9jSj9jVjVjVkAjVjVj9jVjSk0kIj4jVjVj4jVjVjVjVkbjVlikAj9j9kAjVj4jSj0jSj4jVj9j9kAjVljlkllixixixixixixixixixixixixixixixixixkbjSjMjSjvjVjYjVjYjYlmjvjvj4j4j4j4jvjrjLjLjvjMjVjLjLj8igayfsayayb1ayb1b1bPaybPayfsfs.2b1bPayayeeg3.UgOayfsfskd.UayeBayfsfslnfseB.Ufsay.U.U.UbPkd.U.U.UbPfsloixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixlphYhYhYhYhYhYh0hYh0h0hYh0hYhYhYhYhYhYh0hYh0h0hYh0hYhYiYhYiYiYhYiYhYhYhYhYhYhYhYhYhYhYiYhYiYiYhYiYhYhYhYhYhYhYhYhYhYhYh0hYh0h0hYh0hYhYhYhYhYhYj6", +"jvi2j4jvi2jLjvj4i2jvj4jvjvj4jvjvjvi2j4jvi2jLjvj4i2jvj4jvjvj4jvjvjvi2j4jvi2jLjvj4i2jvj4jvjvj4jvjvjvi2j4jvi2jLjvj4i2jvj4jvjvj4jvjvjvi2j4jvi2jLjvj4i2jvj4jvjvj4jvjvjvi2j4jvi2jLkZk0kAkhlhk0k0k0k0j9kZkAkgjVj4j9kAlhkAk0j9j9kgk0jVjVkgkbj9kbjVj9kgk0j4kgkbjVjVj9jVj0khj4kgj9j8jVkbj9j4khj9j0j9lqlrlsixixixixixixixixixixixixixixixixixixixixjYj4jVjVj4jVjVjvjYj4jVjYjvjYj4jVk.jLjvj4jrjvj4jLj4j4jVltlubPluayayfsb1ay.2lubPeBfsbPayfsb1kdbPk#k#ayay.Ukaayayg3fskdayay.Uj2.U.qj2.U.2kd.U.U.U.U.UbPkd.Ub1lvixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixlwhYhYhYhYhYhYiYhYiYiYhYiYhYhYhYhYhYhYiYhYiYiYhYiYhYhYi4hYi4i4h0i4h0h0iYh0iYiYhYiYhYhYh0hYh0h0hYh0hYhYhYhYhYhYhYhYhYhYiYhYiYiYhYiYhYhYhYhYhYhYj6", +"jvjvjvjLjvjvjvjvj4jvjvjvjvjvjvj4jvjvjvjLjvjvjvjvj4jvjvjvjvjvjvj4jvjvjvjLjvjvjvjvj4jvjvjvjvjvjvj4jvjvjvjLjvjvjvjvj4jvjvjvjvjvjvj4jvjvjvjLjvjvjvjvj4jvjvjvjvjvjvj4jvjvjvjLjvjvkAkgk0k0k0k0kZkhjVk0kAkhj9k0j9jVjVk0k0khj9j9j9khjSk0jVkIjVj9jVkbkbjVk0kgjVjVjVkgj9j9kbjVj0kgjSj9j9jVj9jVlxlylzixixixixixixixixixixixixixixixixixixixixixixixjvjYjYjYj9jSjVjSjSjVjvkAjYjYjYjLi2jVj4jvjVjVjvjvjvjvjvigb1lnb1lulnayeBbPayayb1b1bPfsfsbPfsbPayb1ayk#.2fsay.Ulufsfs.U.Ukdk#fs.Uayay.2ayfsfseB.2ayfs.UaybP.UlAixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixlBhYhYiYhYiYiYhYiYhYhYiYhYiYiYhYiYhYhYhYhYhYhYhYhYhYhYhYhYhYhYi4hYi4i4hYi4hYhYhYhYhYhYi4hYi4i4hYi4hYhYiYhYiYiYhYiYhYhYhYhYhYhYhYhYhYhYiYhYiYiYj6", +"j4jLjvjVjvjvj4jvjLjvj4jvjVjLjvjvj4jLjvjVjvjvj4jvjLjvj4jvjVjLjvjvj4jLjvjVjvjvj4jvjLjvj4jvjVjLjvjvj4jLjvjVjvjvj4jvjLjvj4jvjVjLjvjvj4jLjvjVjvjvj4jvjLjvj4jvjVjLjvjvj4jLjvjVjvjvlhlhkgk0j9kZk0k0kZkZkAkgkAkgkAj9j9k0kgkhkAk0kgj9jVkgj9kgjVk0jVjVkAkbj9kgj9kgk0jVkIkbkbj9kbkgjVjSj9lClDlEixixixixixixixixixixixixixixixixixixixixixixixixixixjVjYj4jYj9jVj4jVkbjSjSjVkbj9j4jVj4j4j8jYjLjVjvjvjVjLjvlFayay.2bP.2.2.2bPfsk#fsb1b1fsfsfslubPlnbPayayayb1bP.Uay.U.Ug3.Ufslnkdaykd.U.U.U.Ufskd.Ukdb1b1fsfs.UlGixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixiohYhYhYhYhYhYhYhYhYhYhYhYhYhYhYhYhYhYhYhYhYhYiYhYiYiYhYiYhYhYhYhYhYhYhYhYhYhYiYhYiYiYhYiYhYhYhYhYhYhYhYhYhYhYhYhYhYhYjfhYjfjfhYjfhYhYhYhYhYhYj6", +"jLjvjvjvjvj4jvjvjVjvjvjvjvjvj4jvjLjvjvjvjvj4jvjvjVjvjvjvjvjvj4jvjLjvjvjvjvj4jvjvjVjvjvjvjvjvj4jvjLjvjvjvjvj4jvjvjVjvjvjvjvjvj4jvjLjvjvjvjvj4jvjvjVjvjvjvjvjvj4jvjLjvjvjvjvj4kZk0k0kgkgkgkgj9k0k0k0kZkhjVk0k0j9kAk0kZjVk0k0jVkAkAkgj9khj9kgjVkgjVlhjVjVjVjVjVk0jVkgjVkgjVlHlIlJlKixixixixixixixixixixixixixixixixixixixixixixixixixixixixjVj4jSjYkAjVj0jYjYjYkbjVjSjSjVjvjYj9jYjVjVjvjvjvjvj4j4lLluluayeBbPlnfDaylufslubPbPfsb1b1bPfsfslufslufseBbPb1eBb1bPay.Ufs.Ug3kdlnfsfsfs.U.U.U.UfsfseBkdayeBlGixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixioiYiYhYiYhYhYi4hYi4i4jfi4jfjfiYjfiYiYhYiYhYhYhYhYhYhYi4hYi4i4jfi4jfjfhYjfhYhYhYhYhYhYiYhYiYiYhYiYhYhYhYhYhYhYiYhYiYiYhYiYhYhYiYhYiYiYhYiYhYhYj6", +"jVjvj4jVjvjvj4jvjVjvj4jVjvjVjvjvjVjvj4jVjvjvj4jvjVjvj4jVjvjVjvjvjVjvj4jVjvjvj4jvjVjvj4jVjvjVjvjvjVjvj4jVjvjvj4jvjVjvj4jVjvjVjvjvjVjvj4jVjvjvj4jvjVjvj4jVjvjVjvjvjVjvj4jVjvjvk0k0k0kZk0lMkgk0lNkglOk0k0lhkZkhlPkhlhj9k0lhk0kAk0k0k0kAlhk0j9khk0lik0kglhk0jVk0jVjVk0lQlRlSkoixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixjVjVkAjVj9jSkbkAjVjVjYjYkgjVjVkbjSjVj4jVjVjYj4kbjvjVjvhIk#fslu.Ufsayb1ayfsg3.2fslueBfsfseBb1fD.2bPlubPlufsbP.2b1b1ayb1eBayfsay.2fskdk#fskdeB.Ug3g3.2lnfsfslTixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixlBiYiYhYiYhYhYi4hYi4i4hYi4hYhYhYhYhYhYiYhYiYiYjfiYjfjfhYjfhYhYi4hYi4i4hYi4hYhYiYhYiYiYhYiYhYhYhYhYhYhYiYhYiYiYhYiYhYhYhYhYhYhYiYhYiYiYhYiYhYhYj6", +"j4jvjLjvj4jLjvj4jvjLj4jvjvj4jvjVj4jvjLjvj4jLjvj4jvjLj4jvjvj4jvjVj4jvjLjvj4jLjvj4jvjLj4jvjvj4jvjVj4jvjLjvj4jLjvj4jvjLj4jvjvj4jvjVj4jvjLjvj4jLjvj4jvjLj4jvjvj4jvjVj4jvjLjvj4jLk0k0k0lhlPkZkZk0kgk0k0kAkgk0k0k0k0k0kZkgk0j9j9j9k0lhk0jVlhkhk0j9kAj9kgkgk0kgjVkAlUlVlWlXixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixkbj9j4kAjVlYjVjSjSj9j3kAkAjYj4jSjVjSj3jVjVj9kAjYjYj4jvigeBkdfPk#k#luayluayk#lnb1bPfsfsfslueBfseBeBbPfsbPbPfsbPeBeBfslnkdfs.2fs.U.UfP.UfPfsfseBayfsayayfsfslZixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixjchYhYhYhYhYhYjfhYjfjfi4jfi4i4iYi4iYiYhYiYhYhYi4hYi4i4jfi4jfjfhYjfhYhYiYhYiYiYi4iYi4i4hYi4hYhYjfhYjfjfiYjfiYiYhYiYhYhYjfhYjfjfhYjfhYhYhYhYhYhYj6", +"jvjVjvjVjvjVjVj4jvjVjvj4jVjLj4jvjvjVjvjVjvjVjVj4jvjVjvj4jVjLj4jvjvjVjvjVjvjVjVj4jvjVjvj4jVjLj4jvjvjVjvjVjvjVjVj4jvjVjvj4jVjLj4jvjvjVjvjVjvjVjVj4jvjVjvj4jVjLj4jvjvjVjvjVjvjVl0k0kgl1kglPl1lhlhkZk0k0lhk0k0lOlOk0kZk0kZk0k0kAkAj9k0k0k0kgkhlhk0j9j9lOj9l2l3l4k6ixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixjVkAkbkAj3khj4j9j9j9kAjSjVkAjYkAj3kbjVjVjSkAjSkAjVj4j8kfkdeBkdeBfsfsfsfsfseBfsfsfs.2fsbPbPfsbPfsay.2aykdfsfsfsfsfsayeBfsb1eBb1eBay.Uay.Ufs.2fskdkday.Ukdlul5ixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixl6iYiYjfiYjfjfhYjfhYhYjfhYjfjfhYjfhYhYjfhYjfjfhYjfhYhYhYhYhYhYi4hYi4i4jfi4jfjfhYjfhYhYiYhYiYiYhYiYhYhYhYhYhYhYi4hYi4i4i4i4i4i4iYi4iYiYjfiYjfjfj6", +"jvj4jVj4jvjLjvjvjVjVjvjvjVjvjVjvjvj4jVj4jvjLjvjvjVjVjvjvjVjvjVjvjvj4jVj4jvjLjvjvjVjVjvjvjVjvjVjvjvj4jVj4jvjLjvjvjVjVjvjvjVjvjVjvjvj4jVj4jvjLjvjvjVjVjvjvjVjvjVjvjvj4jVj4jvjLk0k0lMl0kgkgk0kgl1k0k0k0k0lMkgkgkgj9k0lOkZkZlhk0k0khkAj9kglhkZkgkhk0lhl7l8l9ixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixjVjVjVjSkAkbjVj3jVj4khjVjVj9j9kAjVjVjVjYkbjVjSjSj4jSkAigfsfsfskdfsfsfslulufslulufslueBlnayf4eBfslululufDbPayf4bPb1bPbPfsayfDfsf4fDfDfDf4fs.UfPfsayfPkdeBm.lfixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixiwlgjfjfjfjfjfjfi4jfi4i4hYi4hYhYi4hYi4i4jfi4jfjfiYjfiYiYjfiYjfjfjfjfjfjfhYjfhYhYhYhYhYhYjfhYjfjfjfjfjfjfhYjfhYhYjfhYjfjfhYjfhYhYjfhYjfjfjfjfjfjfj6", +"jVjvj4jvjVjVjVjVjLjvj4jVjLjVjvjVjVjvj4jvjVjVjVjVjLjvj4jVjLjVjvjVjVjvj4jvjVjVjVjVjLjvj4jVjLjVjvjVjVjvj4jvjVjVjVjVjLjvj4jVjLjVjvjVjVjvj4jvjVjVjVjVjLjvj4jVjLjVjvjVjVjvj4jvjVjVl1l1lhk0k0k0k0k0k0l1k0k0lhkZlhk0k0lMkgkgjVlOlhk0khkAlhkhkAkhk0lOm#mambixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixjVkhkhkAlYjVj9kbj9kAjVjVjVj9kAjSkAkbkbjVj4jVj4jVjVjVjVkcfPayfDeBmceBeBfseBfsfPfsfsfsk#aybPayb1ayk#fslubPbPlubP.UfsfDlulufDfseBfsln.Ue0b1b1fDbPfsg3fsfs.Umdixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixjxjfi4i4hYi4hYhYjfhYjfjfiYjfiYiYjfiYjfjfhYjfhYhYhYhYhYhYi4hYi4i4hYi4hYhYiYhYiYiYjfiYjfjfiYjfiYiYhYiYhYhYjfhYjfjfhYjfhYhYjfhYjfjfi4jfi4i4hYi4hYhYj6", +"jVjvjVjVjLjVjLjvjLjVjLjVjvjVjLj4jVjvjVjVjLjVjLjvjLjVjLjVjvjVjLj4jVjvjVjVjLjVjLjvjLjVjLjVjvjVjLj4jVjvjVjVjLjVjLjvjLjVjLjVjvjVjLj4jVjvjVjVjLjVjLjvjLjVjLjVjvjVjLj4jVjvjVjVjLjVltkglhl1lhl1k0k0lhlMk0kgl1k0lhlhl0kZkglMkAk0kAkgj9lhk0kZk0memfmgixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixkIkAjVj9jVkAj9jVjVj9lYkAkAjVkhjVjVkAjVjSj9kAj4kAjYjVj4kfeBbPfseB.UbP.Ufsfsfsk#eBf4g3fslulululnfseBfsfsfDlufseBlueBfseBkdkdfDlufDluayeBfs.Uf4k#fDlueBlumhk6ixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixjIixixixixixixixixixixixixixixixixkRkujfjfjfhYjfhYhYjfhYjfjfhYjfhYhYi4hYi4i4jfi4jfjfiYjfiYiYjfiYjfjfjfjfjfjfjfjfjfjfi4jfi4i4jfi4jfjfi4jfi4i4jfi4jfjfiYjfiYiYjfiYjfjfjfjfjfjfhYjfhYhYj6", +"jVjVjLjVjvjVjVjVjVjvjVjVjVjvjVjVjVjVjLjVjvjVjVjVjVjvjVjVjVjvjVjVjVjVjLjVjvjVjVjVjVjvjVjVjVjvjVjVjVjVjLjVjvjVjVjVjVjvjVjVjVjvjVjVjVjVjLjVjvjVjVjVjVjvjVjVjVjvjVjVjVjVjLjVjvjVl0l0l0k0lhl1l1k0l0k0k0lMkglPkgk0l1l1l0k0lhk0lMkglOkhmimjmkixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixjSjVkbkbjVj9jVkhkAjVk0j9kbkAjVjVj4jVkhkhjVjVj9kAkAjVkhhIeBfseBmlfPbPfs.U.UfDfseBfsfsfsluk#lulufsfsfslnayaykdb1lufsluayfDeBb1eB.2b1fDbPfsfsayeBkdkdfDmmmnixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixmojFixixixixixixixixixixixixixixiJmphYi4hYhYjfhYjfjfiYjfiYiYjfiYjfjfhYjfhYhYjfhYjfjfi4jfi4i4iYi4iYiYhYiYhYhYi4hYi4i4jfi4jfjfhYjfhYhYjfhYjfjfi4jfi4i4jfi4jfjfi4jfi4i4hYi4hYhYjfhYjfjfj6", +"jvjLjVjVjVjLjVjvjVj4jVjVjLjVjVjLjvjLjVjVjVjLjVjvjVj4jVjVjLjVjVjLjvjLjVjVjVjLjVjvjVj4jVjVjLjVjVjLjvjLjVjVjVjLjVjvjVj4jVjVjLjVjVjLjvjLjVjVjVjLjVjvjVj4jVjVjLjVjVjLjvjLjVjVjVjLl1l1l0l0lPlhlNl1l1lhkgk0k0l0lMk0k0k0l1lhlhk0k0mqmrkRixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixkAjSj9khk0j9kAkAjSkhkhjVjVlYj9kbkAj9jVjVkhj4kAj9lYkbkAmsg3fsfDbPb1fsbPfsfseBfDfDfDmceBeBeBmlfPfsfsfslufseBeBf4fDfPfslumtlufsfDaykdf4kdfslulueBfDfsmukOixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixfsmvkQixixixixixixixixixixixixkRmwjfjfjfjfjfjfjfjfjfjfjfjfjfhYjfhYhYjfhYjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfi4jfi4i4jfi4jfjfjfjfjfjfhYjfhYhYjfhYjfjfjfjfjfjfjfjfjfjfj6", +"jVjVjVjvjLjVjVjVjVjVjLjVjVj4jVjVjVjVjVjvjLjVjVjVjVjVjLjVjVj4jVjVjVjVjVjvjLjVjVjVjVjVjLjVjVj4jVjVjVjVjVjvjLjVjVjVjVjVjLjVjVj4jVjVjVjVjVjvjLjVjVjVjVjVjLjVjVj4jVjVjVjVjVjvjLjVl1lOlOl1lhl1l0mslhmsl1l1l1l0lhk0k0lhlPk0kgl1mxkoixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixjVkAkgj9kAjVjSkbj9kAkbjVk0khkhjVjSj9kbj4jVjVj9j9jVkAj9lLayfsayeBfDfDeBfDfseBeBfseBe0fDe0fskdeBk#fsfDlueBfsbPluk#ayfsaymymzfslueBfsfDf4eBfskdfDfslGmAixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixfsg3mBkkiwixixixixixixixixiwjxkujfjfjfjfjfjfjfjfjfjfi4jfi4i4jfi4jfjfjfjfjfjfjfjfjfjfiYjfiYiYi4iYi4i4jfi4jfjfhYjfhYhYjfhYjfjfjfjfjfjfjfjfjfjfi4jfi4i4jfi4jfjfjfjfjfjfjfjfjfjfjfjfjfjfj6", +"jVjLjVjVjVjVjVjLjLjVjVjLjVjLj4jVjVjLjVjVjVjVjVjLjLjVjVjLjVjLj4jVjVjLjVjVjVjVjVjLjLjVjVjLjVjLj4jVjVjLjVjVjVjVjVjLjLjVjVjLjVjLj4jVjVjLjVjVjVjVjVjLjLjVjVjLjVjLj4jVjVjLjVjVjVjVlhlNlNl1l1lhk0k0lPlhlhltlhl1l1k0l1k0k0lMlMkgixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixk0kAkbjVjVkgkgj9kAlYkbkbkbj9kbkhkhkAjVlYlYkAkAj9jVj4kAhIeBfseBfsfsfsfsfsfskdkdfslufPayfsfsfafDeBeBf4eBf4fDlululueBfsfsixkomCmDlulufslufDfDf4mEmFktixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixfDfDfsg3mGmHkwmIiwiolBjcmJmKjf.qjfjfi4jfi4i4i4i4i4i4jfi4jfjfjfjfjfjfi4jfi4i4i4i4i4i4jfi4jfjfjfjfjfjfjfjfjfjfjfjfjfjfi4jfi4i4jfi4jfjfjfjfjfjfjfjfjfjf.qjf.q.qjf.qjfjfi4jfi4i4i4i4i4i4j6", +"jVjVjLjVjVjVjVjVjVjVjVjVjVjVjVjLjVjVjLjVjVjVjVjVjVjVjVjVjVjVjVjLjVjVjLjVjVjVjVjVjVjVjVjVjVjVjVjLjVjVjLjVjVjVjVjVjVjVjVjVjVjVjVjLjVjVjLjVjVjVjVjVjVjVjVjVjVjVjVjLjVjVjLjVjVjVl1lPlPmsl1lhl1l1lOlhl1l0lhlPlhl1l1l1k0l1lhk0ixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixkgkAkbkbkbkgkAkAkgkgkAjSkbk0j9kAjVjVkAj9j9kbkAj9kAkAjVhmmceBfsfseBlufsfsfDbPfDfDfseBmleBfsfsfafDfDmcfsfseBk#f4fslulufsixixixixmLkjkkmMkkksmAixixixixixixixixixixixixixixixixixixixixmNmOkwkwmOmPixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixfsfsfsfsmQeefsi4jfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfi4jfi4i4jfi4jfjfjfjfjfjfi4jfi4i4jfi4jfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfj6", +"jVj9jVjVj9jVjLjVjVjVjLjVjVjVj9jVjVj9jVjVj9jVjLjVjVjVjLjVjVjVj9jVjVj9jVjVj9jVjLjVjVjVjLjVjVjVj9jVjVj9jVjVj9jVjLjVjVjVjLjVjVjVj9jVjVj9jVjVj9jVjLjVjVjVjLjVjVjVj9jVjVj9jVjVj9jVl0l1l1lOl0l1lhlhmsl1l1lhlOk0lPl0lhlhlhl1lhl0ixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixk0kgjVjVjVj9jVk0kbkbk0kgkgj9j9j9mRjVj9kAjVjVlYk0j9j9mRfPgOfDfsfDfseBfseBeBeefsayfsfDkdeBeBmlmlfPfPfsfPfDfDeBeBfsfPfPluixixixixixixixixixixixixixixixixixixixixixixixixixixixixktmSmTjoayayg3aymBmTmUktixixixixixixixixixixixixixixixixixixixixixixixixixixixixg3luf4lufsfsfDjfjfjfjfjfjfjfi4jfi4i4jfi4jfjfjfjfjfjfi4jfi4i4jfi4jfjfjfjfjfjfi4jfi4i4jfi4jfjf.qjf.q.qjf.qjfjfjfjfjfjfjfjfjfjf.qjf.q.qjf.qjfjfjfjfjfjfjfjfjfjfi4jfi4i4jfi4jfjfjfjfjfjfj6", +"jVjLj9jVjSj9jVj9jVjVj9jVjVj9jVjVjVjLj9jVjSj9jVj9jVjVj9jVjVj9jVjVjVjLj9jVjSj9jVj9jVjVj9jVjVj9jVjVjVjLj9jVjSj9jVj9jVjVj9jVjVj9jVjVjVjLj9jVjSj9jVj9jVjVj9jVjVj9jVjVjVjLj9jVjSj9l1mskclOmsl1lPltmslhl1lhmslOk0lhlPlhlPl1lhlhixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixjVkAk0kgkbk0j9jVkbkAkgkbkgkAkgkAlYj9kbkAkAkhmRkAkAkgk0hIlufslufDfDfDfseBfslueBg3fsfsg3fDeBlueBlumlg3fPayfseBfsfPlueBluixixixixixixixixixixixixixixixixixixixixixixixixixixixmxmVf4fPfsmllufPlufsg3eBlGmxixixixixixixixixixixixixixixixixixixixixixixixixixixixmWmWg3fsf4fsfDjfjfjfjfjfjfjf.qjf.q.qjf.qjfjfjfjfjfjf.qjf.q.qjf.qjfjfjfjfjfjf.qjf.q.qjf.qjfjf.qjf.q.qi4.qi4i4.qi4.q.qjf.qjfjfd2jfd2d2jfd2jfjfjfjfjfjfjfjfjfjf.qjf.q.qjf.qjfjfjfjfjfjfmX", +"jVjVjVj9jVjVjVjVj9jVjVjVjVjVjVj9jVjVjVj9jVjVjVjVj9jVjVjVjVjVjVj9jVjVjVj9jVjVjVjVj9jVjVjVjVjVjVj9jVjVjVj9jVjVjVjVj9jVjVjVjVjVjVj9jVjVjVj9jVjVjVjVj9jVjVjVjVjVjVj9jVjVjVj9jVjVl1ltl1l1l1l1l1l0lOltlPl0lhmsl0lOk0l1ltl0lPlhixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixjVkbkbkblhkgkgkgkgk0j9lhkbjVkAkgj9kAkAjVk0k0kbkAkbkhjVhIfsmYeBlufPfDfPfseBeBfseBeBlufPfsfDfsfDeBfDlumleBfsfsfDfDfDeBeBixixixixixixixixixixixixixixixixixixixixixixixixixixmZg#fPfPmcg3fDfsfPlululufseBjUm0ixixixixixixixixixixixixixixixixixixixixixixixixixixfPhxlulueBfsfsjf.q.qjf.qjfjfjfjfjfjfjfjfjfjf.qjf.q.qjf.qjfjf.qjf.q.qjf.qjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjf.qjf.q.qjf.qjfjf.qjf.q.qjf.qjfjfjfjfjfjfjfjfjfjf.qjf.q.qj6", +"kgj9jVk0jVjVj9jVj9jVj9jVk0j9jVjVkgj9jVk0jVjVj9jVj9jVj9jVk0j9jVjVkgj9jVk0jVjVj9jVj9jVj9jVk0j9jVjVkgj9jVk0jVjVj9jVj9jVj9jVk0j9jVjVkgj9jVk0jVjVj9jVj9jVj9jVk0j9jVjVkgj9jVk0jVjVl0msl0l1lhl1msmsl1l1m1ltl1l0l1l1l0l1msl1lhl1ixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixkbjVj9kblNk0kAk0k0kgkgk0lNlhkAk0kAj9j9kAkgk0j9kbk0kAkbigfDeBfseBfsfseBfslueBfDfseBg3eBfsmlfsfPfDfDfDfDfseBfsfPfDfDfPfDixixixixixixixixixixixixixixixixixixixixixixixixixm2luf4fsfsfsfsf4eBf4fsf4lululufPfsm3ixixixixixixixixixixixixixixixixixixixixixixixixixfsfsfsfsfsfDfsjfjfjfjfjfjfjf.Ujf.U.Ujf.Ujfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjf.qjf.q.qjf.qjfjfjfjfjfjfjfjfjfjf.qjf.q.qjf.qjfjfjfjfjfjfjfjfjfjfjfjfjfjf.Ujf.U.Ujf.Ujfjfjfjfjfjfj6", +"j9jVjVjVjVkgjVjVk0jVjVjVjVjVj9jVj9jVjVjVjVkgjVjVk0jVjVjVjVjVj9jVj9jVjVjVjVkgjVjVk0jVjVjVjVjVj9jVj9jVjVjVjVkgjVjVk0jVjVjVjVjVj9jVj9jVjVjVjVkgjVjVk0jVjVjVjVjVj9jVj9jVjVjVjVkgl1kcigltl0ltltl1msl1msl1l0lOlPm1lhl1msl1lOl1ixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixk0k0kgkbl1k0jVkbkbkbkgkgkgkgk0j9kblNkbkAk0kgj9jVkgj9kAhalufPg3fPfPfPg#lululug3fsfsfDfsfseBg3lufPfsg#fPfPg#eBiaeBeBfPfDixixixixixixixixixixixixixixixixixixixixixixixixkRm4mcfPf4fDlufsfsfsfDeBfPfPhxfPlulum5m6ixixixixixixixixixixixixixixixixixixixixixixixixfPmleBmlfsfDfDjfjfjf.qjf.q.qjf.qjfjf.2jf.2.2jf.2jfjf.qjf.q.q.U.q.U.U.q.U.q.qjf.qjfjfjfjfjfjf.qjf.q.q.U.q.U.Ujf.Ujfjfjfjfjfjf.2jf.2.2jf.2jfjfjfjfjfjf.qjf.q.qjf.qjfjf.2jf.2.2jf.2jfjfmX", +"k0jVj9kgjVjVkgjVkgjVj9k0jVkgjVjVk0jVj9kgjVjVkgjVkgjVj9k0jVkgjVjVk0jVj9kgjVjVkgjVkgjVj9k0jVkgjVjVk0jVj9kgjVjVkgjVkgjVj9k0jVkgjVjVk0jVj9kgjVjVkgjVkgjVj9k0jVkgjVjVk0jVj9kgjVjVmsl1msl1l1igmskclPltkcl1msm1l1l0l1l0l0lhmsmsixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixk0k0lhk0lNkglhl1k0k0kbkbl0k0kglhkgk0k0k0k0kbkglMkgk0jVkcaybPlufDfseBfseBeBfPluf4f4fPfPfDg3fsg#fseBlufslufsfDeBfseBlueBixixixixixixixixixixixixixixixixixixixixixixixixm7fsfsluf4f4luf4fPlufsfseBfDmcf4mcf4fPm8ixixixixixixixixixixixixixixixixixixixixixixixixfsfDfsfseBfsmljf.2.2jf.2jfjfjfjfjfjf.qjf.q.qjf.qjfjf.qjf.q.qjf.qjfjfjfjfjfjf.2jf.2.2.U.2.U.Ujf.Ujfjf.qjf.q.qjf.qjfjf.qjf.q.qjf.qjfjfjfjfjfjf.2jf.2.2jf.2jfjfjfjfjfjf.qjf.q.qjf.qjfjfmX", +"j9jVj9jVj9j9jVj9jVjVj9jVjVkgjVk0j9jVj9jVj9j9jVj9jVjVj9jVjVkgjVk0j9jVj9jVj9j9jVj9jVjVj9jVjVkgjVk0j9jVj9jVj9j9jVj9jVjVj9jVjVkgjVk0j9jVj9jVj9j9jVj9jVjVj9jVjVkgjVk0j9jVj9jVj9j9l1ltmsl1msl1l1msl0igltl1lhl1l1mslOmsl1l1ltlPixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixk0lhkAkAkgkglNkgkglNk0l1lhkbkAkgkgkgkAkgk0kblhkbkbk0kghIg3fsg#ayfslufDlulueBg3eBeBg3lufslufPfsg3g3eBmleBfsf4fsfPfPfPfPixixixixixixixixixixixixixixixixixixixixixixixm9fDlufslufsfsgIeBfPg#fsg#lulufseBfPmlf4fPn.ixixixixixixixixixixixixixixixixixixixixixixixfsfPfDfsfDeBfs.U.q.qjf.qjfjf.Ujf.U.Ujf.Ujfjfjfjfjfjf.Ujf.U.Ujf.Ujfjf.qjf.q.qjf.qjfjf.qjf.q.q.2.q.2.2jf.2jfjf.2jf.2.2.q.2.q.qjf.qjfjf.Ujf.U.U.q.U.q.qjf.qjfjf.Ujf.U.Ujf.Ujfjfjfjfjfjfn#", +"jVk0jVk0jVk0kgj9jVk0jVj9k0j9j9jVjVk0jVk0jVk0kgj9jVk0jVj9k0j9j9jVjVk0jVk0jVk0kgj9jVk0jVj9k0j9j9jVjVk0jVk0jVk0kgj9jVk0jVj9k0j9j9jVjVk0jVk0jVk0kgj9jVk0jVj9k0j9j9jVjVk0jVk0jVk0m1msltiglthmmshIhIl1mshImshIl1mshImsl1kcl1msixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixlOl1l0lhk0lOkAlNlhlhlhkgk0l1kbl1kAlMkgkgkgl1kglhk0mRmRhIfsg3lug3fDfseBfsfsg3fsg3g3fsmleBfslufslufDfseBg3g3fPg3fDfDfDfPixixixixixixixixixixixixixixixixixixixixixixixnalug3g3fPfPfPeBfPfsbPfPf4g#fPfsfDfsfsmlfDnbixixixixixixixixixixixixixixixixixixixixixixixg3lufDfPeBfDfsjfjfjf.qjf.q.qjf.qjfjf.qjf.q.q.U.q.U.Ujf.Ujfjf.Ujf.U.Ujf.Ujfjf.2jf.2.2jf.2jfjfjfjfjfjf.qjf.q.q.U.q.U.Ujf.Ujfjf.qjf.q.qjf.qjfjfjfjfjfjf.qjf.q.qjf.qjfjf.qjf.q.q.U.q.U.Uj6", +"jVkgkgj9jVj9jVjVk0k0jVjVkgjVk0jVjVkgkgj9jVj9jVjVk0k0jVjVkgjVk0jVjVkgkgj9jVj9jVjVk0k0jVjVkgjVk0jVjVkgkgj9jVj9jVjVk0k0jVjVkgjVk0jVjVkgkgj9jVj9jVjVk0k0jVjVkgjVk0jVjVkgkgj9jVj9l1msigkcmslthIlhigl1kcmsmsmsltl0ltlhmshIl1l1ixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixk0k0khkgl1nck0k0k0kAl0lhk0lNlNlhk0lNkgkblMk0kgkgkgjVl1hxfsfslufseBg3eBg3lufPlufPfDfsg3g3lug#g3fDfPfPfPfPmleBfPeBeBeBfsixixixixixixixixixixixixixixixixixixixixixixndnefDmlfPhxfPmlfPmllug3fsfPf4fDg3fPfPfsfDfsnfndixixixixixixixixixixixixixixixixixixixixixixfDfPg#g#fPeBfP.Ujfjf.Ujf.U.Ujf.Ujfjf.Ujf.U.U.2.U.2.2.q.2.q.qjf.qjfjf.qjf.q.q.U.q.U.U.q.U.q.q.U.q.U.U.2.U.2.2jf.2jfjfjfjfjfjf.Ujf.U.U.U.U.U.Ujf.Ujfjf.Ujf.U.Ujf.Ujfjf.Ujf.U.U.2.U.2.2mX", +"k0jVj9jVk0k0kgk0j9jVkgk0j9k0jVkgk0jVj9jVk0k0kgk0j9jVkgk0j9k0jVkgk0jVj9jVk0k0kgk0j9jVkgk0j9k0jVkgk0jVj9jVk0k0kgk0j9jVkgk0j9k0jVkgk0jVj9jVk0k0kgk0j9jVkgk0j9k0jVkgk0jVj9jVk0k0hIgImsl1mslLhIigl1hImsmshIl1hIkcm1igmsltl0msixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixk0lOlOlPlNkglNl1lhl1k0k0k0kglhkglMl1l0k0kAkgk0k0k0k0k0hIg#fsfPmlf4g3g3lug3eBg#fsbPfseBfDfDg3fsmYlululufsfsmlfDfPmlg#mlixixixixixixixixixixixixixixixixixixixixixixngg3lululufsfsf4iafsg3g#mlfDf4fPfPfPfPfPfDg#fsnhixixixixixixixixixixixixixixixixixixixixixixfPeBfsg3fsf4fPjf.2.2jf.2jfjf.Ujf.U.U.q.U.q.qjf.qjfjf.Ujf.U.U.2.U.2.2.U.2.U.Ujf.Ujfjfjfjfjfjf.qjf.q.qjf.qjfjf.2jf.2.2.U.2.U.U.q.U.q.qjf.qjfjf.2jf.2.2jf.2jfjf.Ujf.U.U.q.U.q.qjf.qjfjfn#", +"k0jVk0k0j9kgj9jVj9k0j9kgjVkgj9j9k0jVk0k0j9kgj9jVj9k0j9kgjVkgj9j9k0jVk0k0j9kgj9jVj9k0j9kgjVkgj9j9k0jVk0k0j9kgj9jVj9k0j9kgjVkgj9j9k0jVk0k0j9kgj9jVj9k0j9kgjVkgj9j9k0jVk0k0j9kghIltmsgIigmshImshImsigltigmsmshIhIl1l0igl1jUixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixnik0kAlhk0lPlhlNk0lNj9lhl1k0l0k0k0lhkAkglhl1kAk0kbk0kAigfPeBeBfPeBfs.Ulug3lufsg3fDfPgff4mlfPg3fDg3fPg3g#fPfDfPfDfPfPfPixixixixixixixixixixixixixixixixixixixixixixnjg3hxlulufslueBfPeBfPg#fPg3fDlug3eBfsg3fPlug#nkixixixixixixixixixixixixixixixixixixixixixixhIfPfsfPfDlufD.q.U.U.2.U.2.2.U.2.U.U.2.U.2.2jf.2jfjf.Ujf.U.Ujf.Ujfjf.qjf.q.q.U.q.U.U.2.U.2.2.U.2.U.U.U.U.U.U.U.U.U.U.q.U.q.q.U.q.U.U.q.U.q.q.U.q.U.U.2.U.2.2.U.2.U.U.2.U.2.2jf.2jfjfn#", +"kgk0j9k0jVk0k0k0k0jVk0kgk0jVk0k0kgk0j9k0jVk0k0k0k0jVk0kgk0jVk0k0kgk0j9k0jVk0k0k0k0jVk0kgk0jVk0k0kgk0j9k0jVk0k0k0k0jVk0kgk0jVk0k0kgk0j9k0jVk0k0k0k0jVk0kgk0jVk0k0kgk0j9k0jVk0ighIkchIhxhIgIl1igmskchxl0igl1msigigigkchIjUixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixkglhncnclOkAk0l0lhkgl1lhl0l1lhk0kAk0l0lhlhkgk0l0k0k0l0hIfPmlfPfDg#fPeBfseBfPbPg3lug3eBg3lufslufsfsbPg3eBeBlueBlufsfPg3ixixixixixixixixixixixixixixixixixixixixixixnlg3eBeBmlf4mlmlmlfPf4fPfPfPg3fPfDfPlulugIeBmlnlixixixixixixixixixixixixixixixixixixixixixixfsfslFfsfPfPeB.2.q.q.U.q.U.U.q.U.q.qjf.qjfjf.2jf.2.2.2.2.2.2.U.2.U.Ujf.Ujfjf.Ujf.U.U.q.U.q.q.q.q.q.qjf.qjfjf.qjf.q.q.U.q.U.Ujf.Ujfjf.2jf.2.2.q.2.q.q.U.q.U.U.q.U.q.qjf.qjfjf.2jf.2.2n#", +"jVj9k0kgk0j9kgjVkgj9k0kgj9k0kgj9jVj9k0kgk0j9kgjVkgj9k0kgj9k0kgj9jVj9k0kgk0j9kgjVkgj9k0kgj9k0kgj9jVj9k0kgk0j9kgjVkgj9k0kgj9k0kgj9jVj9k0kgk0j9kgjVkgj9k0kgj9k0kgj9jVj9k0kgk0j9g#igighIhxhIl0ighImsl1hImshIhxmshImshImshImsixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixlPlNlNk0l0lNl1l0kgk0l0k0k0lNlhlOk0lhk0lhl0kAlPlNlNl1l0g#nmfsfPeBfsfPeBeBeBfDfDmlfPfPg3g3g3gfg#eBfDfDfDg3g3fPfPfPhxg3mlixixixixixixixixixixixixixixixixixixixixixixmOfPfPg#g#fPg#g#g3fPfPfPfsfDeBf4fPf4fPfPmleBf4mOixixixixixixixixixixixixixixixixixixixixixixg3ayfPnnfPfPfP.U.U.Ujf.Ujfjf.2jf.2.2.U.2.U.U.U.U.U.U.U.U.U.Ujf.Ujfjf.Ujf.U.U.2.U.2.2.U.2.U.U.U.U.U.U.U.U.U.U.2.U.2.2.U.2.U.U.q.U.q.q.U.q.U.U.U.U.U.Ujf.Ujfjf.2jf.2.2.U.2.U.U.U.U.U.Un#", +"kgk0kgjVj9k0k0kgk0k0j9k0k0kgk0k0kgk0kgjVj9k0k0kgk0k0j9k0k0kgk0k0kgk0kgjVj9k0k0kgk0k0j9k0k0kgk0k0kgk0kgjVj9k0k0kgk0k0j9k0k0kgk0k0kgk0kgjVj9k0k0kgk0k0j9k0k0kgk0k0kgk0kgjVj9k0ighIighImslLhIiakcighagIhIigmshIighIigigltgIixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixk0l1l0lhlPlhlNl1lhk0nck0l1lhlOlOlNlhl1kgk0k0kAlhk0lhlhigfseBfsfDfPfPfPgIfDfPfPeBgff4fPf4lug3g3fsg3gflugffDbPfPeBfDmlg3ixixixixixixixixixixixixixixixixixixixixixixmbf4gIeBfPfPfPg#lug#lumlfPmleBfPfDmlfPg3fPg#fPmbixixixixixixixixixixixixixixixixixixixixixixf4gIfPfPfPmllu.2.q.q.U.q.U.U.2.U.2.2.2.2.2.2.U.2.U.U.2.U.2.2.U.2.U.U.U.U.U.U.U.U.U.U.2.U.2.2.q.2.q.q.U.q.U.Ujf.Ujfjf.2jf.2.2.U.2.U.U.2.U.2.2.q.2.q.q.U.q.U.U.2.U.2.2.2.2.2.2.U.2.U.Un#", +"k0kgk0k0k0kgk0j9kgk0kgj9k0j9kgk0k0kgk0k0k0kgk0j9kgk0kgj9k0j9kgk0k0kgk0k0k0kgk0j9kgk0kgj9k0j9kgk0k0kgk0k0k0kgk0j9kgk0kgj9k0j9kgk0k0kgk0k0k0kgk0j9kgk0kgj9k0j9kgk0k0kgk0k0k0kghIhag#fPg#mshIhIhIkckciahIigighIighIhIighIltixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixl1l0nclhl0mslNlhlPlNl0ncnck0l1lOlOlhlhlNlNl1l0lhk0kAlhhIfDf4fDfsfsmlmlmlmlg3fPg3f4g#lufPfPf4fPg3g3fDg3gfgffPfDfPfPfPluixixixixixixixixixixixixixixixixixixixixixixixnofPfPfPfPfPfDfPlug#g#mlialuluf4mlf4f4lumlnpixixixixixixixixixixixixixixixixixixixixixixixfPfPfPgIfPfPml.U.2.2.U.2.U.U.U.U.U.U.q.U.q.q.q.q.q.q.U.q.U.U.2.U.2.2.2.2.2.2.q.2.q.q.U.q.U.U.2.U.2.2.U.2.U.U.U.U.U.U.2.U.2.2.U.2.U.U.U.U.U.U.2.U.2.2.U.2.U.U.U.U.U.U.q.U.q.q.q.q.q.qn#", +"k0kgj9k0kgk0k0kgk0kgk0k0kgk0k0j9k0kgj9k0kgk0k0kgk0kgk0k0kgk0k0j9k0kgj9k0kgk0k0kgk0kgk0k0kgk0k0j9k0kgj9k0kgk0k0kgk0kgk0k0kgk0k0j9k0kgj9k0kgk0k0kgk0kgk0k0kgk0k0j9k0kgj9k0kgk0fPg#fPhIfPfPhIighImsighIhIhxm1iggIhamsighIhIixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixl0lPl1l0l1l0l1lhltltlPlNnclOlhk0l0k0lPlNlhlOlPlhl0l1k0hIeBeBf4f4fDfPeBfPfPeBfPfPfPfPfDfPfsfsf4f4fPfPlug3g#fsfDfDmlfPfPixixixixixixixixixixixixixixixixixixixixixixixnqfPg#fDgIhafPfPfPfPfPg#g3fPg#g3fPfPfPmlfPnqixixixixixixixixixixixixixixixixixixixixixixixlufPlugIfPfPfP.q.U.U.2.U.2.2.U.2.U.U.U.U.U.U.U.U.U.U.U.U.U.U.U.U.U.U.U.U.U.U.U.U.U.U.2.U.2.2.2.2.2.2.U.2.U.U.2.U.2.2.U.2.U.U.2.U.2.2.q.2.q.q.U.q.U.U.2.U.2.2.U.2.U.U.U.U.U.U.U.U.U.Un#", +"k0lhk0kglhk0j9k0k0k0j9k0kgk0lhk0k0lhk0kglhk0j9k0k0k0j9k0kgk0lhk0k0lhk0kglhk0j9k0k0k0j9k0kgk0lhk0k0lhk0kglhk0j9k0k0k0j9k0kgk0lhk0k0lhk0kglhk0j9k0k0k0j9k0kgk0lhk0k0lhk0kglhk0hafPfPhIhIfPg#iafPigighahIhIfPkchIhxiaighmigixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixl1l0lhlhlhl1k0kcl0l1msl0l0lPlPlNmslOlhk0k0lOlNl1lNlhmsfPeBfPmlfPf4fDf4fDfDfDfPfsmlfPmlfPfPiagfg#hxnmfPfPfPfPg3fsfPg#f4ixixixixixixixixixixixixixixixixixixixixixixixnrnsfPg3g#fDg#fPfPfPf4fPfPfDfPg#fPiaialunsnrixixixixixixixixixixixixixixixixixixixixixixixhxhxg#mYfPhIfP.U.U.U.U.U.U.U.q.U.q.q.U.q.U.U.U.U.U.U.2.U.2.2.U.2.U.U.U.U.U.U.2.U.2.2.U.2.U.Uay.Uayay.Uay.U.U.2.U.2.2.U.2.U.Uay.Uayay.Uay.U.U.U.U.U.U.U.U.U.U.q.U.q.q.U.q.U.U.U.U.U.Un#", +"k0kglhk0kglhkglhkgk0lhk0k0lhkgkgk0kglhk0kglhkglhkgk0lhk0k0lhkgkgk0kglhk0kglhkglhkgk0lhk0k0lhkgkgk0kglhk0kglhkglhkgk0lhk0k0lhkgkgk0kglhk0kglhkglhkgk0lhk0k0lhkgkgk0kglhk0kglhiagIfPigfDhIfPigg#g#igg#igighIhaiahIiaigfPhIixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixl0msl1l0lhl1ntlhl1l1l0l0l0lhl0lPlhlhl0l1l0lOlhk0lPlhl0hIg3fsnumlmlfPf4fDf4g3fDfPhxfsg3mlfPmlfPfPiafPhxmlf4g3mlhxlug3g3iJixixixixixixixixixixixixixixixixixixixixixixixnvfPeBfPfPmlg#f4hIfPfPfPeBfPfPmlg#fPg3nwixixixixixixixixixixixixixixixixixixixixixixixiJfPfPfPmlfPlufP.2.U.U.2.U.2.2ay.2ayay.Uay.U.U.2.U.2.2ay.2ayay.2ay.2.2.U.2.U.Uay.Uayay.2ay.2.2ay.2ayay.2ay.2.2ay.2ayay.Uay.U.U.2.U.2.2.2.2.2.2.U.2.U.U.2.U.2.2ay.2ayay.Uay.U.U.2.U.2.2n#", +"kgk0kglhk0k0k0k0lhk0kgk0kgk0k0lhkgk0kglhk0k0k0k0lhk0kgk0kgk0k0lhkgk0kglhk0k0k0k0lhk0kgk0kgk0k0lhkgk0kglhk0k0k0k0lhk0kgk0kgk0k0lhkgk0kglhk0k0k0k0lhk0kgk0kgk0k0lhkgk0kglhk0k0fPiafPigg#hxiaighIgIg#hIg#igfPighIighahIiahxixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixlhkcl1ncl0l0msl0l0l1lhl1l0ncl0l0lhlPlPlhl1ncl0l1l0lOk0gff4fPfDg3iamlfPmllueBfDfDfDeBg#eBfPnmfPfPfDfDfDfPeBfsfPmlmlg3fPnxiJixixixixixixixixixixixixixixixixixixixixixixk4nyhxfPhxhxeBmYg#fPg#hafPhIeBhxfPfPnzk4ixixixixixixixixixixixixixixixixixixixixixixiJnxfPhxfPhxgIfPfP.Ufsfs.Ufs.U.U.U.U.U.U.2.U.2.2ay.2ayay.Uay.U.Uay.Uayay.2ay.2.2.U.2.U.U.U.U.U.U.U.U.U.U.U.U.U.U.2.U.2.2.U.2.U.Uay.Uayay.Uay.U.Ufs.Ufsfs.Ufs.U.U.U.U.U.U.2.U.2.2ay.2ayayn#", +"l0lhk0l0k0kglhk0lhkglhk0l0k0kgk0l0lhk0l0k0kglhk0lhkglhk0l0k0kgk0l0lhk0l0k0kglhk0lhkglhk0l0k0kgk0l0lhk0l0k0kglhk0lhkglhk0l0k0kgk0l0lhk0l0k0kglhk0lhkglhk0l0k0kgk0l0lhk0l0k0kghafPhag#fPhxfPhxhIigg#gIfPfPfPg#fPfPigighaigixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixlPlPntncmsl0msl1m1l0l0l1msl1l1msl1lhlhlPl0l0lhl1msl1nAfPfPeBf4fDf4fDg#fseBeBmlf4fDfPfDfPhIeBigfPfPfDfPmlfPeBg#fPfPhxfPlufPg3fPfPf4gffDfDfPg3fDfsfPg#hxfPfPhxfPfPigfPigfPiaf4g#f4f4fPf4fPfPg#fPg#gIiBhafPfPfPfPfPfPigg#fPfPfPfPfPfPfPfPfPfPg3fPfDfDfPfPmlhxmlg3mllufPmlgIfDf4.U.2.2.U.2.U.Ufs.Ufsfs.Ufs.U.U.2.U.2.2.U.2.U.U.U.U.U.U.2.U.2.2.U.2.U.Ufs.Ufsfs.Ufs.U.U.U.U.U.U.U.U.U.Uay.Uayay.2ay.2.2.U.2.U.U.2.U.2.2.U.2.U.Ufs.Ufsfs.Ufs.U.U.2.U.2.2n#", +"k0k0kgk0k0l0k0kgl0k0kgk0k0k0lhkgk0k0kgk0k0l0k0kgl0k0kgk0k0k0lhkgk0k0kgk0k0l0k0kgl0k0kgk0k0k0lhkgk0k0kgk0k0l0k0kgl0k0kgk0k0k0lhkgk0k0kgk0k0l0k0kgl0k0kgk0k0k0lhkgk0k0kgk0k0l0hxgIfPgIhafPhxfPfPg#igigighIfPg#hxg#igighIfPixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixl1m1l0l1hIl1l0ncncl1l1l1l0l0l0lhl1jUl1l0m1l0lhlhlhlhmshImYfPg3gImlfPfPmlg3eBiaeBeBmlfDfDfDfPfsiahxhahxgIfPfPgIfPfPgfmlfPfPhxg3gImlfPhIfDfPfPhafPfPfPlufPg3iahxg#fDiafDigfPeBhxg#g#g#fDhxfPigg3iggIg#hafPfPfDg#fPfPfPfPmlfPialufPhxg#hxhxhxfPhxfPhxg3f4fDfPigfPhxgIfPhag3fDfD.U.U.Uay.Uayay.Uay.U.Ufs.Ufsfs.Ufs.U.Uay.Uayayfsayfsfsayfsayay.Uay.U.U.2.U.2.2ay.2ayayfsayfsfs.2fs.2.2.U.2.U.Ufs.Ufsfs.Ufs.U.U.U.U.U.Uay.Uayay.Uay.U.Ufs.Ufsfs.Ufs.U.Un#", +"l0k0l0l0k0kgl0k0l0k0l0l0k0l0k0k0l0k0l0l0k0kgl0k0l0k0l0l0k0l0k0k0l0k0l0l0k0kgl0k0l0k0l0l0k0l0k0k0l0k0l0l0k0kgl0k0l0k0l0l0k0l0k0k0l0k0l0l0k0kgl0k0l0k0l0l0k0l0k0k0l0k0l0l0k0kgmlfPfPhxfPg3fPfPhxiafPmlgIfPhxigfPhIhxhIigfPixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixl1jUkcl0m1l0hIl1l1hIncncm1l1m1msl0l0msl1msncm1hIl0l1lhhIlueBmYg3eBg3f4g3fDfPeBfPfPgIgIfPfPf4fPfPfDg3fPg3hxfPfPmlfPfPfPfPg3fPg3fDfPg3lug3g3hIfsfPhxfDfPfPg3fPg3fPg#hxfDhxfPfDmYfPg#fPg#g#hxfDfPg3fPeBfPg#g#hafDigfPfPigighIfPhIg3iag3fDg3hxfPhxf4mlg3fPiag3fDhxfPfDfPfPfPmlha.2fsfs.Ufs.U.U.U.U.U.Uay.Uayay.Uay.U.Uay.Uayay.Uay.U.U.U.U.U.Ufs.Ufsfsfsfsfsfs.Ufs.U.Uay.Uayay.Uay.U.Uay.Uayay.Uay.U.U.2.U.2.2fs.2fsfs.Ufs.U.U.U.U.U.Uay.Uayay.Uay.U.Un#", +"lhkglhk0l0k0k0lhk0k0lhkgk0l0k0l0lhkglhk0l0k0k0lhk0k0lhkgk0l0k0l0lhkglhk0l0k0k0lhk0k0lhkgk0l0k0l0lhkglhk0l0k0k0lhk0k0lhkgk0l0k0l0lhkglhk0l0k0k0lhk0k0lhkgk0l0k0l0lhkglhk0l0k0fPfPg3hxgIiahxfPhag3gIg#iafPfPigigfPigighag#ixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixhIl1hIl1l1l0l0l0l0m1l1l1l1l0l1l0m1l0lPlhncncl1l0l1msl0g#fPf4fPg3g3g3fPg3fsfDg3fDfDfDg3eBeBgIfPfDfPfDigfDeBfPeBigighxfPfPfPfDfPeBeBhxfDhxmlfPfPhIhIgffPfPfPgIfPfPfPfPgIfPf4fDmlfDfPigg3hahafPhafDfPfPg3hxfPg#g#g#g#hafDfPfPgIfPhIhIg#fPiafPigfPgIigfPhxhxhxg3g#fPfPgIfPgImlgIfsfsfs.Ufs.U.Ufs.Ufsfs.2fs.2.2.U.2.U.Ufs.Ufsfs.Ufs.U.Uay.Uayay.Uay.U.U.U.U.U.Ufs.Ufsfs.Ufs.U.Ufs.Ufsfsayfsayay.Uay.U.Ufs.Ufsfsfsfsfsfs.Ufs.U.Ufs.Ufsfs.2fs.2.2.U.2.U.Un#", +"k0l0k0l0k0l0l0lhk0l0k0l0l0lhlhk0k0l0k0l0k0l0l0lhk0l0k0l0l0lhlhk0k0l0k0l0k0l0l0lhk0l0k0l0l0lhlhk0k0l0k0l0k0l0l0lhk0l0k0l0l0lhlhk0k0l0k0l0k0l0l0lhk0l0k0l0l0lhlhk0k0l0k0l0k0l0fPfPfPfPfPfPfPf4f4hxfPfPfPg#fPgIgIfPigfPhxfPixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixl1hIhImsl1hIl1kcm1msnBl0l1hIl1hIkckcm1l0l0hIl0l1l1msmshafsfPf4fPlug3hxeBeBfPeBfDfPf4mlfDeBeBeBeBg3f4eBfDfDfPfDfPfPmlgImlmlfPmlfPgIeBfPfPfPg3fPg3g3fPfDiahxfPfPfPg3mlg3hahIfPhafPfPfPigfDfPhxfPhIhxfDfPfDfDfPfPgIhafPigg#fDfDfPfDeBfPg#g#g#fPiaigigf4fPmlmlhxmlhxfPfDigfDfPfP.U.U.Uay.Uayay.Uay.U.Ufs.Ufsfsfsfsfsfs.Ufs.U.Ufs.Ufsfs.Ufs.U.Ufs.Ufsfs.Ufs.U.U.U.U.U.U.U.U.U.Ufs.Ufsfs.2fs.2.2fs.2fsfs.Ufs.U.U.U.U.U.Uay.Uayay.Uay.U.Ufs.Ufsfsfsfsfsfsn#", +"k0l0l0l0k0lhk0k0l0l0k0k0l0k0l0k0k0l0l0l0k0lhk0k0l0l0k0k0l0k0l0k0k0l0l0l0k0lhk0k0l0l0k0k0l0k0l0k0k0l0l0l0k0lhk0k0l0l0k0k0l0k0l0k0k0l0l0l0k0lhk0k0l0l0k0k0l0k0l0k0k0l0l0l0k0lhg3hxg3fPfPfPhxhxfPfPmlfPfPg3gIhahafPfPgIhxigixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixhIltl0l0hIhIl1l1l1l1m1l0msm1m1l1l1msl1l1kcm1l0l0ltk0hIhxeBeBeBfsg3g3g3fPg3hxg3fPfPgIg#fPmlfPfPfPfPiag#gImleBfPfDfDfDeBeBfPigfPmlfPfPfPhIhxeBhxfPfPhxg3fPgIgfhafDfPnCg#g#fDfPhahIhag#hxhxhxfPhxfPg#iag#g#fPiafPg#hIighahaighahaigfPfPigigigg#hIg#iaiafPfPeBgIfDmlhxhxhxhagIfPfs.U.Ufs.Ufsfs.Ufs.U.UeB.UeBeBfseBfsfsayfsayay.Uay.U.Uay.UayayeBayeBeBfseBfsfsfsfsfsfsfsfsfsfs.Ufs.U.U.U.U.U.Ufs.Ufsfsfsfsfsfs.Ufs.U.Ufs.Ufsfs.Ufs.U.UeB.UeBeBfseBfsfsn#", +"l1k0lhk0l0l1l0l1lhk0l0l0lhl0k0l0l1k0lhk0l0l1l0l1lhk0l0l0lhl0k0l0l1k0lhk0l0l1l0l1lhk0l0l0lhl0k0l0l1k0lhk0l0l1l0l1lhk0l0l0lhl0k0l0l1k0lhk0l0l1l0l1lhk0l0l0lhl0k0l0l1k0lhk0l0l1fDmlfPhxfPg3fPg3fPfPhxfPf4hxf4mlg#luhxhahxgIixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixkchIhIigltl0jUhImshIhIhIl1l0msl0msighIl1l1ncl1m1msm1l1fPfPfPfDfPfDfPfPmlfPg3fPg3eBeBg3fPfPeBf4fPmleBmYeBeBg#fPfPmlg#fPigg#fPhIigigfPfPmlfPfPg#fPhxfPfPfDfPfPfDfPgIg3fPfPhxfPfPg3fPhag3gIhahxigfPighxhxgIhag#hafDfPfDeBg3fPg#fPg#igfDfPfPfPigfPhIighIfPg#jUighaighxfPhxfPfPhx.Ufsfs.Ufs.U.Ufs.Ufsfsayfsayay.Uay.U.Ufs.Ufsfsfsfsfsfsfsfsfsfs.Ufs.U.U.U.U.U.Uay.Uayay.Uay.U.Ufs.UfsfseBfseBeBfseBfsfs.Ufs.U.Ufs.Ufsfs.Ufs.U.Ufs.Ufsfsayfsayay.Uay.U.Un#", +"l0k0l1l0lhl0k0k0lhl0lhl0k0l0lhl0l0k0l1l0lhl0k0k0lhl0lhl0k0l0lhl0l0k0l1l0lhl0k0k0lhl0lhl0k0l0lhl0l0k0l1l0lhl0k0k0lhl0lhl0k0l0lhl0l0k0l1l0lhl0k0k0lhl0lhl0k0l0lhl0l0k0l1l0lhl0fPfPeBfsf4fPmlfPfDg3g3fPfPhxfPf4mlhxgIg3fPfPixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixmskchImshIhIhajUhIjUltl1hIl1hIl1hIhIl1l0mshImsl1l1l1msfPg#eBg3fDeBeBlneBg3f4mlfPmlfPfPfPfPfPfPgIfPmllufPhxfPgIfPgIfPgImlfPfPg3fPg#hxfPhxfPfPhxg#gIhIhahxhxhxfPhxfPgIfPhIfPfPfPfPfPg#fPgIhaiafPg#g#hxg3hxmYgIfPhagIhahIigigigfPighxigfPhafPiggIiggIhxmshxiahIg3hIfPg3hxhxhxfPayeBeBfseBfsfsfsfsfsfsfsfsfsfs.Ufs.U.UeB.UeBeB.UeB.U.Uay.UayayfsayfsfsfsfsfsfsfsfsfsfsfsfsfsfsfsfsfsfsayfsayayfsayfsfsayfsayayeBayeBeBfseBfsfsfsfsfsfsfsfsfsfs.Ufs.U.UnD", +"l0l0lhl1k0l0l0l1l0k0l1l0l0k0l0l1l0l0lhl1k0l0l0l1l0k0l1l0l0k0l0l1l0l0lhl1k0l0l0l1l0k0l1l0l0k0l0l1l0l0lhl1k0l0l0l1l0k0l1l0l0k0l0l1l0l0lhl1k0l0l0l1l0k0l1l0l0k0l0l1l0l0lhl1k0l0fslufPfPlueBmlg3f4fPg3g3fPfPfPhxfPfPgIfPfDfPixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixl1jUhIighIl1l1hIhIl0g#hIhIhImsmsl1l1m1kcm1msmshIl1nchIgIfPf4fPmlfPfPlufsg3fDeBg#gfg3g3fDg3fPg3gIgIfPfPg3g3fPfDg3g3fPg3hagff4g#f4fDfPeBfPg#hxigfPmlg#g3hIfPhxiafPhxfPg3g3g3gIgfhxhxhxfPfPfPgIfPgIhag#hxfPg#hIfPg#gIg#iag#fDfPfDigigfPhag#g#iggIfPhxhIg3hIhIfPhIg3fPhIfPigigfPfsayayeBayeBeBayeBayay.Uay.U.Ufs.Ufsfsfsfsfsfsfsfsfsfs.Ufs.U.UeB.UeBeB.UeB.U.Ufs.Ufsfs.Ufs.U.Uay.UayayeBayeBeB.UeB.U.Ufs.UfsfsayfsayayeBayeBeBayeBayay.Uay.U.Ufs.Ufsfsn#", +"k0l0l1l0l0lhl0k0l0l0l1l0lhl1l0lhk0l0l1l0l0lhl0k0l0l0l1l0lhl1l0lhk0l0l1l0l0lhl0k0l0l0l1l0lhl1l0lhk0l0l1l0l0lhl0k0l0l0l1l0lhl1l0lhk0l0l1l0l0lhl0k0l0l0l1l0lhl1l0lhk0l0l1l0l0lhfPfsfsf4fsg3fPfDeBeBfPfPfPfPeBfPg3g3fPfPf4fPixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixhImshImshIiakchImshIjUhIhIhIhIhIl1l1l1l1hIhIigm1l0ighIgIg3fDfPeBbPf4mclulug3fDfDfPhafPg#g#fPg#hxfPfPfPgfg#gIfPfPfPhxfPfPiafPgIeBmlfPfPfPfPhIighIjUeBg#fPfPhIg#fPhxiahxg#g#hagIhIg#gIiahxiafDfPg3fPgIg#hxhxhIigfPfPiahahahIgIhafPighIiggIhahxgIhahafPfPfPg#hxigiahxigiafPfPg#fseBeB.UeB.U.Ufs.UfsfseBfseBeBeBeBeBeBfseBfsfs.Ufs.U.Ufs.UfsfsfsfsfsfseBfseBeBfseBfsfseBfseBeBfseBfsfsfsfsfsfsayfsayayfsayfsfseBfseBeB.UeB.U.Ufs.UfsfseBfseBeBeBeBeBeBn#", +"l0l1l0k0lhl0l1l0l1l0k0l0l1l0l0l0l0l1l0k0lhl0l1l0l1l0k0l0l1l0l0l0l0l1l0k0lhl0l1l0l1l0k0l0l1l0l0l0l0l1l0k0lhl0l1l0l1l0k0l0l1l0l0l0l0l1l0k0lhl0l1l0l1l0k0l0l1l0l0l0l0l1l0k0lhl0fsfDf4fPfPg3fDeBg3fDfseBeBmlfPfDlug#fPhxfPfPixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixmsl1igkchxjUl0hIlLhIhIkchIigjUhIltjUigjUmsl1l1kchIhIm1fPlufPlueBfPfDfPhafPg#iafPg#eBfPfPf4eBfPlufPfPg3fPgIeBfPeBg3mlfDmlfPfPfPhafPgIg#gImlfPfPg3g#ighxgImlfPfPgIfPhIfPhafPhxhxfPgIgIfPgIhxhxhxgIhxhafPhagIhahag#jUhxiahxgIg#hafPg#hafPhIigfPigfPg3hxg#fPfPhIfPg#hIigigmsfPiafsayayfsayfsfsfsfsfsfsfsfsfsfsfsfsfsfsfsfsfsfsfsfsfsfseBfseBeBeBeBeBeBfseBfsfsayfsayayfsayfsfs.Ufs.U.Ufs.UfsfseBfseBeBfseBfsfsayfsayayfsayfsfsfsfsfsfsfsfsfsfsfsfsfsfsn#", +"l1l0l0l1l1l0l0lhl0l1l0l0l0k0l0l1l1l0l0l1l1l0l0lhl0l1l0l0l0k0l0l1l1l0l0l1l1l0l0lhl0l1l0l0l0k0l0l1l1l0l0l1l1l0l0lhl0l1l0l0l0k0l0l1l1l0l0l1l1l0l0lhl0l1l0l0l0k0l0l1l1l0l0l1l1l0g3fPg3fsfseBf4fPg3lulufDg3eBfDf4fPfDfPlug3g3ixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixigiahImsl1ighIjUial0hIigigkchIhIhIhIjUltjUigl1hIhIl1kcg#g#mlg#lulufDfPfDfDlufPg3mlg#g3fPfPfDfDfPfPfPfPg#g#fPfPfPhagIfPfPfPmlfPhxfPhafPhahafPg#fPighIfPfPfPhIhIg#g#mlg#iaiahxhxhxfPg#mlg#g#gIhIhxhxfPhxfPgIeBhaiafPhafPiaiaigg#hxhxgIhahahag#hIg#hIiggIhahaighafPfPhIighIhIigeBfsfseBfseBeBeBeBeBeBayeBayayfsayfsfseBfseBeBfseBfsfsfsfsfsfsayfsayayeBayeBeBfseBfsfseBfseBeBeBeBeBeBfseBfsfsfsfsfsfseBfseBeBfseBfsfseBfseBeBeBeBeBeBayeBayayfsayfsfsnD", +"l0l0l0l0l0l1l1l0l1l0l1l1l0l1l0l0l0l0l0l0l0l1l1l0l1l0l1l1l0l1l0l0l0l0l0l0l0l1l1l0l1l0l1l1l0l1l0l0l0l0l0l0l0l1l1l0l1l0l1l1l0l1l0l0l0l0l0l0l0l1l1l0l1l0l1l1l0l1l0l0l0l0l0l0l0l1lug3lufsfslufseBf4fPg3f4eBg3g3fDmlmlfPfsf4fDixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixhahxighIigigkcl1hIhIiajUhIhIkcl1hIhIighIhIhIfPhIhIigmshIg#eBeBfDg#lufPfPfPg#eBfDg#fPfPhxlulufDfDfPhaf4gfg#lufPfPfPfPgIfPgffPfPmlfPhxfPfPfPgfgIhag#fPigfPfPfPigighIhamlg#g#fPgIhIhxiafPiag#g#gIgIhIgIiafPfPg#gIhahahagIhahxhxigigfPhIgIgIhafPhIhIfPg#ighIhahagIgIhafPigigigigfseBeBfseBfsfsfsfsfsfseBfseBeBfseBfsfseBfseBeBeBeBeBeBfseBfsfseBfseBeBfseBfsfsfsfsfsfseBfseBeBfseBfsfseBfseBeBfseBfsfsfsfsfsfseBfseBeBfseBfsfsfsfsfsfseBfseBeBfseBfsfsnD", +"l0msl1l0msl0l0l0l1l0l0l0l0l0msl1l0msl1l0msl0l0l0l1l0l0l0l0l0msl1l0msl1l0msl0l0l0l1l0l0l0l0l0msl1l0msl1l0msl0l0l0l1l0l0l0l0l0msl1l0msl1l0msl0l0l0l1l0l0l0l0l0msl1l0msl1l0msl0mlfsfPf4g3eBg3g3fseBeBmlf4fDfsg3g3g3lufDfPf4ixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixgIhIiajUhIiahIkchIhIgIhIhIhxhxiagIhIl1l1l1hIjUg#jUjUigfPmlfPfDfDmlg#f4iaialufPeBfDfPf4fPfPfPmlg#fPfPfPfDfDfPfDlufPg#fPfPiahIhahIhxfPhxfPfPiafPg#hagIfPfPfPmlhIhIigg#igigiggIfPfPfPhIhxhxg#fPfPgImlg#gIhahahaiafPfPfPgIfPfPiggIhIg#hxhIigigighafPhahafPg#g#hIhIhIighakchIhIg#fseBeBfseBfsfsfsfsfsfsfsfsfsfsfsfsfsfsfsfsfsfsfsfsfsfseBfseBeBfseBfsfsfsfsfsfsg3fsg3g3fsg3fsfsfsfsfsfseBfseBeBg3eBg3g3fsg3fsfseBfseBeBfseBfsfsfsfsfsfsfsfsfsfsfsfsfsfsn#", +"l1l0msl0l0l1l0hIl0l1hIl1l0msl0l0l1l0msl0l0l1l0hIl0l1hIl1l0msl0l0l1l0msl0l0l1l0hIl0l1hIl1l0msl0l0l1l0msl0l0l1l0hIl0l1hIl1l0msl0l0l1l0msl0l0l1l0hIl0l1hIl1l0msl0l0l1l0msl0l0l1fseBfsfseBfPg3fslng3fsfseBf4f4fPg3fsg3fDfsfPixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixiahxgIg#iahxhIhIhIgIkchIighIhaiaiahIhIgIl1hIhIl1hIhIg#iafPmlfPeBfDfPmlg#fDfPg#hIigfPfPfDfPfDfPg3fPfPfDfPfDiafDfPfPfPg3fPhxfPiagIgIgImlfDmlg3fPg#fPfPg#gIfPhxfPigiahIfPfPhIfPhIigmlhIfPkchxhxhxfPfPg#mlg#gIhxhahIhahxhIfPfPgIfPgIgIhag#hxigiaighIighaijhafPigfPigigiggIhaigg#fseBeBfseBfsfsg3fsg3g3eBg3eBeBfseBfsfsfPfsfPfPfsfPfsfseBfseBeBfPeBfPfPfsfPfsfseBfseBeBfseBfsfsg3fsg3g3fsg3fsfsfsfsfsfsfsfsfsfseBfseBeBfseBfsfsg3fsg3g3eBg3eBeBfseBfsfsnE", +"l0l0l0msl1l0l1l0msl0l0l1l0l1l0msl0l0l0msl1l0l1l0msl0l0l1l0l1l0msl0l0l0msl1l0l1l0msl0l0l1l0l1l0msl0l0l0msl1l0l1l0msl0l0l1l0l1l0msl0l0l0msl1l0l1l0msl0l0l1l0l1l0msl0l0l0msl1l0fseB.UeBfsfseBfsmlfsg3g3g3fsfDf4mleBf4f4g3luixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixigiahxhIhIhIgIighahxiagIhIhIhIgIkciahxjUgIhIhIighIhIhIg#fPg#g#fPhaeBfPfPeBfPmlfPfPg3g3g3fDfPfDfPgIfPmlg#g3lufDfDfPg#gIg#fPiag#hxg#gIhIfPfPiafPhIhIhxhIfPgIg#gIg#hamlfPfPfPfPighIhIg#hag#fPiahIhxhIfPg#hxfPfPhIhIhIfPhaiag#hxhafPgIgIgIhaiahxg#fPfPiaighagIhIhaiam1hxhIigfPhIfsfPfPfsfPfsfseBfseBeBfseBfsfsg3fsg3g3eBg3eBeBg3eBg3g3fsg3fsfsfsfsfsfseBfseBeBfseBfsfseBfseBeBfseBfsfseBfseBeBg3eBg3g3fsg3fsfsfPfsfPfPfsfPfsfseBfseBeBfseBfsfsg3fsg3g3nD", +"hImsl1hIl1l0msl1l1l0hIl0hIl1l0l1hImsl1hIl1l0msl1l1l0hIl0hIl1l0l1hImsl1hIl1l0msl1l1l0hIl0hIl1l0l1hImsl1hIl1l0msl1l1l0hIl0hIl1l0l1hImsl1hIl1l0msl1l1l0hIl0hIl1l0l1hImsl1hIl1l0fsfsfs.UfsfsfsfseBfsbPbPfsfsfseBfDfseBfsg3g3ixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixigiggIhxiggIgIgIfPgIhafPhxgIhxgIkckchIighIg#hIhIgIighImleBeBfsg#eBmlg#fPmleBfPfPg#g#g#fPfPlugIfPfDfDfDfDg#lug#fPfDgIfPhxhIfPgIfPmlfPfPfPhxfPhaf4fPfPfPfPigfPgIhIhIhahIfPg#fPg#fPigigigmlgIg#gIg#gIhahahxiag#hxfPg#kcg#hxighxhafPgIhagIgIg#hxhafPfPhahxgImshaighagIhIhIhIg#fPeBfsfsfsfsfsfsfPfsfPfPeBfPeBeBfseBfsfsfsfsfsfseBfseBeBfseBfsfseBfseBeBfPeBfPfPfsfPfsfseBfseBeBfseBfsfsfPfsfPfPfsfPfsfseBfseBeBfseBfsfsfsfsfsfsfPfsfPfPeBfPeBeBfseBfsfsn#", +"l1l0l0l0l1hIl0l0hIl1l0l1l1l0hIl0l1l0l0l0l1hIl0l0hIl1l0l1l1l0hIl0l1l0l0l0l1hIl0l0hIl1l0l1l1l0hIl0l1l0l0l0l1hIl0l0hIl1l0l1l1l0hIl0l1l0l0l0l1hIl0l0hIl1l0l1l1l0hIl0l1l0l0l0l1hIfslu.UfsfsfsfseBfsfseBeBfsf4lu.Ug3eBeBeBfDeBixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixgIiagIigfDgIigigigiafPgIhahaiaiaigiahIkcg#hIkchIhIhIgIfPfPfPg3hxfPfPg#fPfPfPg#fPfPfDfPmlfPg#lug#hxg#hxfPiafPiafDfPg#fPfDfPigg#hIgIg#hafPhxhxhIfPfPhIfPighIfPhxfPfPhIgIhIhIfPhIfPfPhIfPhIfPhIg#haigmshIighxfPhIiaiafPg#mlfPiafPhIg#jUg#mshIfPmshahahafPg#iahaiamsigiahIiag#g#eBeBeBfPeBfPfPfsfPfsfsfPfsfPfPfsfPfsfsg3fsg3g3fPg3fPfPfPfPfPfPeBfPeBeBfseBfsfsg3fsg3g3fPg3fPfPfsfPfsfseBfseBeBfPeBfPfPeBfPeBeBeBeBeBeBfPeBfPfPfsfPfsfsfPfsfPfPfsfPfsfsnD", +"hIl1hIhIl0l0hIl1hIl0hIhIl0hIl1l0hIl1hIhIl0l0hIl1hIl0hIhIl0hIl1l0hIl1hIhIl0l0hIl1hIl0hIhIl0hIl1l0hIl1hIhIl0l0hIl1hIl0hIhIl0hIl1l0hIl1hIhIl0l0hIl1hIl0hIhIl0hIl1l0hIl1hIhIl0l0fs.UfseB.U.Ufsk#fseB.UfseB.UeBfsfsfsfsg3eBfsixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixhahIg3hIfPhafPgIhIfPighIiagIg#hxjUg#gIlLgIhIg#fPhIhxhIg#fDf4fDg3f4eBmleBfPg#mlfPfPfPigigfPmlg#lufPg3fPg3hxfPiamlfPgIfDiafPfDigfPfPfPf4fPfPhahxgIgIgIgIfPfPfPfDg3g#hxfPhxfPgIg#mlfPfPfPg#fPigfPgIigfPmlfPfPhIfPhIhIhahIhIhImlhIgIhIhxfPiaiahxiagIfPighahIhIfPhIigfPhxgIhxhahIfsfPfPfsfPfsfseBfseBeBfPeBfPfPfsfPfsfseBfseBeBfseBfsfsfsfsfsfsfPfsfPfPfPfPfPfPfsfPfsfsg3fsg3g3fsg3fsfsfPfsfPfPfsfPfsfsfsfsfsfsfPfsfPfPfsfPfsfseBfseBeBfPeBfPfPfsfPfsfsnD", +"hIl0msl1hIl1l0hIl0l1hIl0l1hIl0hIhIl0msl1hIl1l0hIl0l1hIl0l1hIl0hIhIl0msl1hIl1l0hIl0l1hIl0l1hIl0hIhIl0msl1hIl1l0hIl0l1hIl0l1hIl0hIhIl0msl1hIl1l0hIl0l1hIl0l1hIl0hIhIl0msl1hIl1ay.UfsfseBfsfsfsfsfs.UlnfseBeBeBfseBfsfsfsg3ixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixfPgIg#gIgIgIg#gIhahaiggIgIiagIhIiahaiahIhIiggIhIiggIkchxfDg3g#fDfDfPeBfPfPg#g#g#g#g#fPfPfPgIfPg#g#g#fPg#g3fPg3gIighxiaiaiafPiag3g3igfDgIhxg#iahahafPfPfPfPhIfPiaiafPigfPfPfPfPhahahIg#hIhIighIfPfPfPhahIigg#hIg#hIhIfPiaiahaiahIhIg#ighIiahIiahahag#hIhIiagIhIiaiahahImsighIfPfPfPfsfPfsfsfPfsfPfPfsfPfsfseBfseBeBfPeBfPfPeBfPeBeBfPeBfPfPeBfPeBeBeBeBeBeBfPeBfPfPeBfPeBeBfPeBfPfPg3fPg3g3eBg3eBeBfPeBfPfPfPfPfPfPfsfPfsfsfPfsfPfPfsfPfsfseBfseBeBnE", +"l0hIl0hIl1hIhIhIl0hIl1hIhIl1hIl1l0hIl0hIl1hIhIhIl0hIl1hIhIl1hIl1l0hIl0hIl1hIhIhIl0hIl1hIhIl1hIl1l0hIl0hIl1hIhIhIl0hIl1hIhIl1hIl1l0hIl0hIl1hIhIhIl0hIl1hIhIl1hIl1l0hIl0hIl1hI.U.Ufs.2fsfsfsayayeBfs.UeB.U.UfseBfseB.UeB.UixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixigfDfPfDigmlgIfPfPfPfPhahIfPiaighxfPiafPhahxhIgIgIhxiafPfsfDmlfDeBf4fPf4f4fPf4fPg#lueBfPmlfPfPfPeBfPg#g#g#fPg#fPfPfDgIfPmliaf4iafPg3fPfPfPfPfDfPfDgImlhagIhxgIhxg#fPg#hIhIhxhIfPfPgIhIgImlhImlhIigfPfPigfPg#ighIhIigigfPhxfPhxiag#fPg#g#g#hxhIhIhIfPmsfPf4hIgIhIhxg#hIg#g#hxeBfsfsfPfsfPfPeBfPeBeBfPeBfPfPfPfPfPfPfsfPfsfsfPfsfPfPfsfPfsfsfPfsfPfPfsfPfsfseBfseBeBeBeBeBeBfPeBfPfPfsfPfsfsfPfsfPfPeBfPeBeBfseBfsfsfPfsfPfPeBfPeBeBfPeBfPfPfPfPfPfPn#", +"l1hIhIhIl0msl0l1hIhIl1l0hIl1hIl0l1hIhIhIl0msl0l1hIhIl1l0hIl1hIl0l1hIhIhIl0msl0l1hIhIl1l0hIl1hIl0l1hIhIhIl0msl0l1hIhIl1l0hIl1hIl0l1hIhIhIl0msl0l1hIhIl1l0hIl1hIl0l1hIhIhIl0mseBfs.U.Ufsfsfsfs.2eBayfsfs.UfsbPfsfsfseBfseBixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixighIhIfPfDfPgIigfPgIiahIigg3hagIgIgIhIigfPiagIhaighIfPfPg3fDfPfseBeBeBg#fPfPfPfPigigfPfPeBg#g#fPfPfPfPigfPfPg#fPfPg#lug3fDigfDhxiaiaiahaigg3igfPfDgIg#iagIfPhafPhxhIiagIfPiahIhIhIiafPfPhIhahIfPg#iag#iafPfPhIhIhIhIhIhIigkckchIhxhIjUhIigfPhIfPhahIhxiag#hag#ighIhIhIhIhaiafPeBeBfPeBfPfPfsfPfsfsfPfsfPfPfPfPfPfPg3fPg3g3eBg3eBeBg3eBg3g3fPg3fPfPfPfPfPfPfPfPfPfPfPfPfPfPfsfPfsfseBfseBeBfPeBfPfPfPfPfPfPeBfPeBeBfPeBfPfPfsfPfsfsfPfsfPfPfPfPfPfPnD", +"hIl1hIl1hIhIhIhIhIl0hIhImshIl1hIhIl1hIl1hIhIhIhIhIl0hIhImshIl1hIhIl1hIl1hIhIhIhIhIl0hIhImshIl1hIhIl1hIl1hIhIhIhIhIl0hIhImshIl1hIhIl1hIl1hIhIhIhIhIl0hIhImshIl1hIhIl1hIl1hIhI.U.UbPeBbP.U.2.U.2ayfsfsayfsay.U.UfsfsfsfsfsixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixfPmlfPg3fPhIg#fPfPfDmlfPfPigg3hafPfPfPgIgIhIgIfPgIg#fPmYg#fPg3fPfPfDfDfPg#g#g#fDfDf4fseBfPg3mlg#eBmlfPmlfPfPfPg#fPg#fPfPhIfPgIiggIfPiamlfPiafPfPgIfPiafPfDiamlhagIhxfPfPfPiahIfDmlhIhxighIfPhIfPhIg#iaighIg#hIfPhIigg#gIigiamliaigfPhxhxhxjUhxhIighIhxighIhIhahImsfPhIgIhakcfsfPfPfsfPfsfsfPfsfPfPg3fPg3g3fsg3fsfsfPfsfPfPfPfPfPfPfPfPfPfPeBfPeBeBfseBfsfsg3fsg3g3fsg3fsfsfPfsfPfPfPfPfPfPfPfPfPfPfsfPfsfsfPfsfPfPfsfPfsfsfPfsfPfPg3fPg3g3fsg3fsfsnE", +"hIl0hIhIhIhIl1l1hIhIl1hIl0hImshIhIl0hIhIhIhIl1l1hIhIl1hIl0hImshIhIl0hIhIhIhIl1l1hIhIl1hIl0hImshIhIl0hIhIhIhIl1l1hIhIl1hIl0hImshIhIl0hIhIhIhIl1l1hIhIl1hIl0hImshIhIl0hIhIhIhIk#bP.2bPaybPaybP.U.U.Ufs.2fs.Uayfsfs.U.Uk#.UixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixfPmlmlfPmlfPfPiafPnFgIfPgIhafPgIiag3ighafPgIhxgIiagIhImlfDeBg3fPlug3g3fPeBf4g3g#g3g#g3fPfPfPfPigfPeBeBg#fPfPfPfPgIhxfPfPg#g#g3hIfPgIfPigiahxgIiagIhahagIgIigiagIiagIfPhaigfPgIfPhahIhaighIfPhxfPiahIfPhIg#ighxhIighIhIhIhIhIg#hIhIlLhxhIhxhIhahIhaiamsigiahIhxhIiahahIhahIigfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPeBfPeBeBfPeBfPfPfsfPfsfsg3fsg3g3fPg3fPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPg3fPg3g3fPg3fPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPeBfPeBeBnE", +"hIhIhIhIl1hIhIhIhIl1hIhIhIl1hIhIhIhIhIhIl1hIhIhIhIl1hIhIhIl1hIhIhIhIhIhIl1hIhIhIhIl1hIhIhIl1hIhIhIhIhIhIl1hIhIhIhIl1hIhIhIl1hIhIhIhIhIhIl1hIhIhIhIl1hIhIhIl1hIhIhIhIhIhIl1hI.U.U.Uayay.2bP.2aebP.U.2.Uk#fsfs.2eBeBfsfs.UixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixfPeBfPfPfPfPfPmlg3hIfPg3fPfPfPfPfPgIiaiaiaigfPfDgIigfPfPf4f4fDg3g3g#eBfDfDg3fPfDfPeBeBg#fDfPfDhxigfPfPeBg#fPg#fPfPfPg3igg#fPg#fDgfg#g3fPfPfPgIiafPiag3hafPgIiggIgIfDiag#g#hag#iggIigiagIg#igiaighIg#fPfPg#hIhahIigg#fPg#fPhIfPhIhIhIhIg#g#kchIhxiahIiahIhIfPhIgIhakciahIjUg#fPg3g3fPg3fPfPfPfPfPfPeBfPeBeBfPeBfPfPfPfPfPfPfPfPfPfPeBfPeBeBfPeBfPfPeBfPeBeBfPeBfPfPeBfPeBeBg3eBg3g3fPg3fPfPeBfPeBeBfPeBfPfPg3fPg3g3fPg3fPfPfPfPfPfPeBfPeBeBfPeBfPfPnE", +"l1hIhIhIhIhIhIl1hIhIhIhIhIhIhImsl1hIhIhIhIhIhIl1hIhIhIhIhIhIhImsl1hIhIhIhIhIhIl1hIhIhIhIhIhIhImsl1hIhIhIhIhIhIl1hIhIhIhIhIhIhImsl1hIhIhIhIhIhIl1hIhIhIhIhIhIhImsl1hIhIhIhIhI.U.U.U.U.qj2.Uk#.2.2.U.UbP.U.q.Ufs.2.2ayayfsixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixeBeBeBigfPfPmleBfPfPhxhIhIg3nFfPfPfPfPigiafPfPfPiafPfDfDfPeBfPg3g3fPfPeBeBg3g3fPfPfPfDfDfDfPg#fPfPfPfPmlfPfPg3g#g#fPfPfPg#hxigg3fPfPg#fPfPg#gIigigeBiag#g#hag#fPgIgIgIiaiaiagIhahIfPigighIfPhIg#fPhIg#fPfPhIhIhIg#iahIhIhIhIhIfPhIhIhIhIhImsighIhIighxhIiag#hIiaigighIhIhxhIfPfPfPeBfPeBeBfPeBfPfPfPfPfPfPfPfPfPfPfPfPfPfPeBfPeBeBfPeBfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPg3fPg3g3fPg3fPfPfPfPfPfPeBfPeBeBfPeBfPfPfPfPfPfPfPfPfPfPnE", +"hIhIhIl1hIhIhIhIighIl1hIhIhIhIhIhIhIhIl1hIhIhIhIighIl1hIhIhIhIhIhIhIhIl1hIhIhIhIighIl1hIhIhIhIhIhIhIhIl1hIhIhIhIighIl1hIhIhIhIhIhIhIhIl1hIhIhIhIighIl1hIhIhIhIhIhIhIhIl1hIhI.2ay.2.Uay.U.U.q.Uk#.2bP.2aybP.U.Uayk#fsfsfsixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixfPfPmlfPfseBg#fPfPmlfPfPfPfPiafPg#fPfDfPfPfPgIfPiafPg#fPfPfPfPg3fPg3f4g#g3fPg#fPg3fPfPfPf4fsfDg3g#g#fPiahxfPfPfPeBeBg#fPfPfPfPfPigigg#gIfPg#g#fPg#fPigfPhxiaiafPiahaighagIgIgIiaiagIiagIgIgIigiagIhIg#hIighIhIfPiahIfPhIigiahIigiahIfPhIhIhIhIg#haigg#ighIhIhIhahIhahImsighIfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPg#fPg#g#fPg#fPfPfPfPfPfPg3fPg3g3fPg3fPfPeBfPeBeBfPeBfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPnE", +"hIhIhIhIighIhIhIhIhIhIhIhIl1hIhIhIhIhIhIighIhIhIhIhIhIhIhIl1hIhIhIhIhIhIighIhIhIhIhIhIhIhIl1hIhIhIhIhIhIighIhIhIhIhIhIhIhIl1hIhIhIhIhIhIighIhIhIhIhIhIhIhIl1hIhIhIhIhIhIighIj2j2j2.q.q.2.Uay.2.U.Uk#.U.2.2.UbP.U.U.U.U.UixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixfPfsg3fPfPg3eBfPeBfPeBfPfPfPgImlhxg3g#g3fPfDfPgIfPfPfPhxfPfPfDfPfPg3fPg3g3fsf4eBg3g3fDfPfPfPfPfDfDg3g#fPg#fPfPfPhxigfPg#g#eBg#fPfPgIfPigigfPfPg#gIhaigfPhIgIhIiaiagIiahahagIgIiggIhIfPiaiagIhaigiggIgIhIhIg#hIg#fPhIfPfPfPhIhIg#hIighIhIhIfPhIhIhahIighIhIighIhxhxhahIhIhahIfPfPfPg#fPg#g#fPg#fPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPeBfPeBeBfPeBfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPg#fPg#g#fPg#fPfPfPfPfPfPfPfPfPfPnE", +"hIhIhIhIhIhIhIhIighIhIighIhIhIhIhIhIhIhIhIhIhIhIighIhIighIhIhIhIhIhIhIhIhIhIhIhIighIhIighIhIhIhIhIhIhIhIhIhIhIhIighIhIighIhIhIhIhIhIhIhIhIhIhIhIighIhIighIhIhIhIhIhIhIhIhIhI.q.q.q.2k#j2.q.2.U.U.U.U.q.q.Uk#bPbPb1.U.U.2ixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixfPeBeBg3eBmlfPfPeBfPeBeBfPfPmlfPfPfPg3g3lufPfPlufDfDfPfPf4g#fPfPgffPfPfPfPf4g3g3f4fDg3g#fPg3g3g3fPfPfPfPfPfPg3g#fPfPhxigmlfPeBfPg#fPfPfPigmlfPigfPg#gIg#fPfPgIgIigiafPiag#fPgIhagIiggIgIiaiagIgIhIfPhagIgIiahIhIhIhIighIfPhxhIhIg#hIighIhIfPighIhIhIhIhIhIhIiglLhIighIhIhIhIfPfPfPfPfPfPfPfPfPfPfPg#fPg#g#fPg#fPfPfPfPfPfPg#fPg#g#fPg#fPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPg#fPg#g#fPg#fPfPnE", +"hIfPhIhIgIhIhIhIhIhIhIhIhIhIfPhIhIfPhIhIgIhIhIhIhIhIhIhIhIhIfPhIhIfPhIhIgIhIhIhIhIhIhIhIhIhIfPhIhIfPhIhIgIhIhIhIhIhIhIhIhIhIfPhIhIfPhIhIgIhIhIhIhIhIhIhIhIhIfPhIhIfPhIhIgIhI.U.U.U.Uj2.qj2j2jf.2.2.q.U.U.q.Uk#j2ayaybPaeixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixfsfPeBeBeBeBg3mleBeBfsfPfPfseBeBeBfPfPfPfPfPfPfPg3g#eBfDfPg3g3g3f4fPfPgIhafPfPg3fPfPf4fDfPhxg3hxgIfPfPfPfPfPfPg3g#g#fPfPfPhIhxiaigg#igg#g#fPfPg#hIigfPg#g#gIgIhaigfPgIgIigiaiafPhahagIigiggIhIhIgIiagIhahahIgIiagIhIighIiaighIhIhIial1hIhIhIhIhxhIhIfPfPg#l1hImsighIl1kckcjUfPg#g#fPg#fPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPhIfPhIhIfPhIfPfPfPfPfPfPfPfPfPfPhIfPhIhIfPhIfPfPg#fPg#g#fPg#fPfPfPfPfPfPfPfPfPfPfPfPfPfPnE", +"hIhIgIhIhIighIfPhIhIfPhIhIgIhIhIhIhIgIhIhIighIfPhIhIfPhIhIgIhIhIhIhIgIhIhIighIfPhIhIfPhIhIgIhIhIhIhIgIhIhIighIfPhIhIfPhIhIgIhIhIhIhIgIhIhIighIfPhIhIfPhIhIgIhIhIhIhIgIhIhIigjfjf.U.U.q.U.qj2.2j2.2.qdG.U.U.2.q.U.q.2j2fsixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixeBeBlufseBeBfseBeBfPmleBmleBfDeBeBfseBfPfPmleBfPg3mlfPg3fPg3fPg3g3g3f4fDfsfPhahagIfPfPfPf4fDfPg3g3g3fPfPg3g#fPhIigg#fPg#fPfPfPhxigigfPg#fPfPg#g#fPfPfPigg#igg#igkfhahIfPgIfPgIgIfPhIfPhIhxgIhxfPgIhIfPiagIhxhahIhIgIhIhIg#igiaighIhIg#fPhIhIhIl1ighIhIhIfPhIfPhahIhIighIlLhxfPfPfPfPfPfPfPhIfPhIhIfPhIfPfPfPfPfPfPhIfPhIhIfPhIfPfPfPfPfPfPhIfPhIhIfPhIfPfPg#fPg#g#fPg#fPfPhIfPhIhIfPhIfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPhIfPhIhIfPhIfPfPfPfPfPfPnG", +"hIhIhIighIhIhIhIfPhIhIhIhIhIhIfPhIhIhIighIhIhIhIfPhIhIhIhIhIhIfPhIhIhIighIhIhIhIfPhIhIhIhIhIhIfPhIhIhIighIhIhIhIfPhIhIhIhIhIhIfPhIhIhIighIhIhIhIfPhIhIhIhIhIhIfPhIhIhIighIhI.qj2jfdGjfjfjfae.Uj2.q.Uj2.2ay.U.UbPjf.Uj2j2ixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixfDfsfsg3fsmllueBg3eBeBfPeBfPfPmlfPeBeBg#fPfPeBfPfDmlfPmlfsiafsfPfPlufPfPg3fPf4f4fDfPfPfPg3fPg3f4fPg3g3gfg3g3fPfPfPfDfPfDfPg#g#fPnFhxhIfPfPg#fPhIhIfPigfPigfPgIg#gIfPfDg#fPhxighIhIiahIiagIhIhahxhIgIhIigiaiahahahafPhagIgIgIhIg#hIigighIiahxhIhIfPg#hIhIighIhIg#jUhIhIhIhIhIfPhIhIfPhIfPfPfPfPfPfPfPfPfPfPiafPiaiafPiafPfPhIfPhIhIfPhIfPfPfPfPfPfPfPfPfPfPfPfPfPfPg#fPg#g#fPg#fPfPfPfPfPfPg#fPg#g#fPg#fPfPhIfPhIhIfPhIfPfPfPfPfPfPfPfPfPfPiafPiaianE", +"fPighIfPhIhIfPhIighIfPhIfPighIhIfPighIfPhIhIfPhIighIfPhIfPighIhIfPighIfPhIhIfPhIighIfPhIfPighIhIfPighIfPhIhIfPhIighIfPhIfPighIhIfPighIfPhIhIfPhIighIfPhIfPighIhIfPighIfPhIhI.q.qjfjfjfjfjfjfdGjf.q.U.qj2.qk#.U.U.2ae.q.2ixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixfDfDfslufPmlmcluaylufPfPfsfPfseBfPfPeBeBfPeBfsfPeBeBfPlueBmlfsfsfsfPfPg3fPlug3f4f4fPfPfDfPfDfPfPg3g3fPfPfPeBg#fPfPgIfPfPiafDhxg#g3g3g3fPfPmligfPfPg#g#fPfPigfPhIg#gIg#fPg#fPhafPigigighxgIiagIg#gIgIhagIigiagIfPg#hIiakchxgIhIgIhIhIhIigiafPhIfPfPhIfPigl1hIighIighIhIhIg#g#fPfPfPfPfPfPfPhIfPhIhIfPhIfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPfPhIfPhIhIfPhIfPfPfPfPfPfPfPfPfPfPhIfPhIhIfPhIfPfPfPfPfPfPfPfPfPfPfPfPfPfPhIfPhIhIfPhIfPfPfPfPfPfPnE", +"ighIhIhIhIfPhIhIfPhIhIhIhIhIfPhIighIhIhIhIfPhIhIfPhIhIhIhIhIfPhIighIhIhIhIfPhIhIfPhIhIhIhIhIfPhIighIhIhIhIfPhIhIfPhIhIhIhIhIfPhIighIhIhIhIfPhIhIfPhIhIhIhIhIfPhIighIhIhIhIfPjf.Ui4jf.U.qj2.qjfjfdGjfae.U.q.qj2k#dG.2ay.UixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixfseBfsfDfsg3fDg3g3fPaylumlfPeBeBeBfPeBfPfsmlfPeBg#eBfDeBfPfPmlfPg3fPfPfPfPfPfPfPfPg3f4f4fPg#fPfPfPfPfPfPfPfDiafDg#g3fPfPfPgIfDiaigfDhIg3fPfPg#fPfPhIfPighIg#igg#fPhIigg#hIg#g#g#g#msighIhIhIhIhagIhIhIhxhxighIgIighIfPgIiakcfPhIhIm1hImshag#hIhIhIhIfPfPfPhIg#l1ighIhIigfPfPfPfPfPhIfPhIhIfPhIfPfPhIfPhIhIfPhIfPfPhIfPhIhIhIhIhIhIhIhIhIhIfPhIfPfPfPfPfPfPiafPiaiahIiahIhIfPhIfPfPfPfPfPfPhIfPhIhIfPhIfPfPfPfPfPfPhIfPhIhIfPhIfPfPhIfPhIhIfPhIfPfPnG", +"fPhIfPfPhIhIfPhIfPhIfPfPhIfPhIhIfPhIfPfPhIhIfPhIfPhIfPfPhIfPhIhIfPhIfPfPhIhIfPhIfPhIfPfPhIfPhIhIfPhIfPfPhIhIfPhIfPhIfPfPhIfPhIhIfPhIfPfPhIhIfPhIfPhIfPfPhIfPhIhIfPhIfPfPhIhIjf.qjfjfi4i4jfjf.qj2jfjfdG.qjfae.qaej2j2dGjfixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixg3f4ayf4ayfsfsfsg3bPg3g3fsfsfsfsg3eBfsfPg3fPfsfsfPfseBfPfPeBfPfsfPfsfseBf4g#fPeBfDmlfPgIfPf4g#fPfDfPfPfPfPfPhxf4f4hxfPhIhxfPgIfPfPfDfPfDg#hIfPgIgIhxgIfPfPfPg#eBg#igfPighIigg#fPg#fPg#g#fPigfPfPigiafPiaiahIfPhIkchIhIkchIgIhIfPhakcgIkchIgIiaighIighIhIkcfPhIhIfPg#ighIhIhIfPhIhIfPhIfPfPfPfPfPfPhIfPhIhIfPhIfPfPfPfPfPfPfPfPfPfPfPfPfPfPhIfPhIhIhIhIhIhIfPhIfPfPiafPiaiafPiafPfPhIfPhIhIfPhIfPfPfPfPfPfPhIfPhIhIfPhIfPfPfPfPfPfPhIfPhIhIfPhIfPfPnE", +"fPhIhIhIfPhIhIfPhIhIfPhIhIfPhIfPfPhIhIhIfPhIhIfPhIhIfPhIhIfPhIfPfPhIhIhIfPhIhIfPhIhIfPhIhIfPhIfPfPhIhIhIfPhIhIfPhIhIfPhIhIfPhIfPfPhIhIhIfPhIhIfPhIhIfPhIhIfPhIfPfPhIhIhIfPhI.qj5jfjfjfjfjfjf.UjfiY.qj2dGdGjf.Ujf.q.q.U.qixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixfsg3fseBfsfsayfsfslufDeBeBfsg3mleBlueBlug3g3fPeBg3eBfPeBg#fsnFfPfPfPfsfDfPmliafsfDeBfPfPfPfPfPiaiafDfPfDfDgIfPgIgIfPiaf4fDg3g#eBg3gIfPgIfPfPg#ighIg#gIfPfPiaigg#g#g#fPg#fPfPfPigighIfPighIgIhIfPfPhIfPhIigiahIhahIhafPgIighIgIhIhIg#hxhagIhIighIhIhIhIhIhIighIfPhxhIhIl1ighIhIhIhIfPhIfPfPhIfPhIhIfPhIfPfPfPfPfPfPhIfPhIhIfPhIfPfPhIfPhIhIfPhIfPfPfPfPfPfPhIfPhIhIfPhIfPfPhIfPhIhIfPhIfPfPfPfPfPfPhIfPhIhIhIhIhIhIfPhIfPfPhIfPhIhIfPhIfPfPfPfPfPfPnG", +"hIfPhIfPhIfPfPfPhIfPhIfPfPhIfPhIhIfPhIfPhIfPfPfPhIfPhIfPfPhIfPhIhIfPhIfPhIfPfPfPhIfPhIfPfPhIfPhIhIfPhIfPhIfPfPfPhIfPhIfPfPhIfPhIhIfPhIfPhIfPfPfPhIfPhIfPfPhIfPhIhIfPhIfPhIfPi4i4jfiYj2jfjfjf.qjfjfiY.qiY.qjfdGjfjf.q.U.qixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixfDk#ayayg3bPg3ayayfDfsfPlufsfsfDmlayfsaylufsg3g3g3fsfsg3aymlfsg#eBfPfPeBfPmlfDhxfPfsg3fDfDfPg3fPg3f4fPf4fDfPfDgIgIg3fPfPf4g#g3g#hxfPgIfPfPfDfPf4f4hxg3hIgIfPgIfPfPfPfPhIhIighIigiggIg#igfPhIfPhIigfPigigigg#ighIhIgIhxhIigiggIigiahxiahaiahxhahIhIgImsgIighIighIhxfPhIfPfPg#fPfPfPhIfPhIhIfPhIfPfPhIfPhIhIhIhIhIhIfPhIfPfPhIfPhIhIfPhIfPfPhIfPhIhIfPhIfPfPfPfPfPfPfPfPfPfPhIfPhIhIfPhIfPfPhIfPhIhIfPhIfPfPfPfPfPfPhIfPhIhIfPhIfPfPhIfPhIhIhIhIhIhInE", +"hIfPfPfPhIg#hIhIfPfPhIhIfPhIfPhIhIfPfPfPhIg#hIhIfPfPhIhIfPhIfPhIhIfPfPfPhIg#hIhIfPfPhIhIfPhIfPhIhIfPfPfPhIg#hIhIfPfPhIhIfPhIfPhIhIfPfPfPhIg#hIhIfPfPhIhIfPhIfPhIhIfPfPfPhIg#jfjfi4i4jfj5jfj2jfjfjfjfjfi4j5j5j2j2jfdGjfjfixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixfsayfsfsk#ayg3g3eBg3fsf4fDaylufsg3eBfPg3ayfslumlfsg3fPfPfseBeBfsfsfPfPeBeBfPeBfPfPfPfPiag3g3g3eBfPfPfPgIfPfPfPfDfPhafPfPg3gIfPfPg#g#g#hIgIeBgIfPfPgIfDg#hxg#hIfPfPgIfPhIigg#hIhIhIg#igfPfPigigfPg#hIg#hIigighIhIhahIhIhIighIhIhIkckckchIgIiahaiahahaigighImshIighahIhIhIhIhxhIfPfPhIfPhIhIfPhIfPfPhIfPhIhIhIhIhIhIfPhIfPfPfPfPfPfPhIfPhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIfPhIfPfPfPfPfPfPhIfPhIhIhIhIhIhIfPhIfPfPhIfPhIhIfPhIfPfPhIfPhIhIhIhIhIhInE", +"fPhIfPhIfPfPfPfPfPhIfPfPg#fPhIfPfPhIfPhIfPfPfPfPfPhIfPfPg#fPhIfPfPhIfPhIfPfPfPfPfPhIfPfPg#fPhIfPfPhIfPhIfPfPfPfPfPhIfPfPg#fPhIfPfPhIfPhIfPfPfPfPfPhIfPfPg#fPhIfPfPhIfPhIfPfPiYjfjfjfjfi4jfi4iYjfjfjfjfjf.qi4.qjfjfj5j5jfixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixbP.UbPayayfsayayfseBfsbPeBfs.UfsfsfsfseBeBfPeBfseBayeBeBeBfPfsg3fPmlfPeBeBfPeBfPeBfPfseBeBhxfsg#g3fPfPg3fPigfPfPg3fPfPfPhafDfPgIfPfPiaf4f4g#g#gIgIfPfPfPfPg#g3hIhxfPgIfPfPfPigfPfPhIfPighIighIhIg#g#g#ighIg#hIfPgIigiafPighIgIhIigfPhxgIgIm1gIhIighahxhxhIkchIhImsiahIighIhIfPhIhIfPhIfPfPhIfPhIhIfPhIfPfPfPfPfPfPhIfPhIhIhIhIhIhIhIhIhIhIfPhIfPfPfPfPfPfPhIfPhIhIfPhIfPfPhIfPhIhIhIhIhIhIhIhIhIhIfPhIfPfPhIfPhIhIfPhIfPfPhIfPhIhIfPhIfPfPfPfPfPfPnG", +"fPhIfPfPfPfPhIhIfPfPiafPhIfPg#fPfPhIfPfPfPfPhIhIfPfPiafPhIfPg#fPfPhIfPfPfPfPhIhIfPfPiafPhIfPg#fPfPhIfPfPfPfPhIhIfPfPiafPhIfPg#fPfPhIfPfPfPfPhIhIfPfPiafPhIfPg#fPfPhIfPfPfPfPjfd2iNjfi4jfjfjfj2i4i4j5iYj5jfd2.2jfi4jf.qj5ixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixbPbPfsg3.Uay.UayfDayeBfseBg3fseBeBfsfDfPfseBfseBeBeBeBeBg3eBeBfsfPfsfseBmleBfsfPeBeBeBeBfDfPmlfPfPg3fPg#fPfDmlgIfPgIfPlumlg#fPhafPfPfPgIg#fPhxg#hxhIhxgIgIgIg#hIiahxhxhIgIfPiafPhxhIhxighIg#igg#fPfPfPigfPigfPhIkfl1mshIhIhIhIhahIighxhIhxhIhIkchIigmsighIhIhxhIm1mshIhIhIighIhIhIhIhIhIhIhIhIhIhIhIhIhIhIfPhIfPfPhIfPhIhIfPhIfPfPigfPigighIighIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIighIigighIighIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIfPhIfPfPnG", +"fPfPfPfPhIfPfPfPfPhIfPfPfPhIfPfPfPfPfPfPhIfPfPfPfPhIfPfPfPhIfPfPfPfPfPfPhIfPfPfPfPhIfPfPfPhIfPfPfPfPfPfPhIfPfPfPfPhIfPfPfPhIfPfPfPfPfPfPhIfPfPfPfPhIfPfPfPhIfPfPfPfPfPfPhIfPi6i6i5dGjfiNjfjfi4jfi4i4i4jf.qjfjfjfjfjf.qi4ixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixfsfs.U.U.UlubPayayfsfsayayfsaybPg3eBayfseBfDfsayeBg3fseBmlfsmleBeBfsfPfPfPeBeBmleBfseBfsfPeBfPfPfPeBmlfPfPlufsfPfDfPmlgIhxfsg#fPfPhafDfPfPfPfPf4f4g#fPhIgIgIgIfPgIfPfPfDfDigg3gIgIgIg#hIg#ighIfPhIg#igfPfPhIgIhIigg#igg#fPhafPhahagIhIiaiaighahxigkchIhIhIgIhIgIhahIigkcm1mshIgIgIhIgIhIhIighIigigfPigfPfPhIfPhIhIhIhIhIhIhIhIhIhIfPhIfPfPhIfPhIhIfPhIfPfPhIfPhIhIfPhIfPfPigfPigighIighIhIfPhIfPfPhIfPhIhIgIhIgIgIhIgIhIhIighIigigfPigfPfPhIfPhIhInG", +"hIfPfPfPfPg#fPhIfPfPfPfPg#fPfPiahIfPfPfPfPg#fPhIfPfPfPfPg#fPfPiahIfPfPfPfPg#fPhIfPfPfPfPg#fPfPiahIfPfPfPfPg#fPhIfPfPfPfPg#fPfPiahIfPfPfPfPg#fPhIfPfPfPfPg#fPfPiahIfPfPfPfPg#jfd2i6jfhYi6i5iYiNiNjfjfjfi4jfjfjfiYiNjfd2jfixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixfsfsfsfs.UbPbPeBe0bPayayfDayayfsbPfseBfsfseBfsaylnfsayfDfDmcg3fsfseBfsfPfPeBfseBfPfPmlmlfPeBeBfPfseBfPmlmlfPg3fPiafPfPfPfPfPgIhxlug3mlfDfPfPfPgIgIfPfPfDfPhxg#fPgIgIgIfPg#iahxhIhIhxgIgIgIighIfPfPigg#igigighahIigg#hIhIhIgIhIighahIhaighIhIighahIhxkckcm1ighIhIighIhIkckchIhIhIhIfPhIfPfPhIfPhIhIhIhIhIhIhIhIhIhIhIhIhIhIfPhIfPfPhIfPhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIighIigighIighIhIhIhIhIhIfPhIfPfPhIfPhIhIhIhIhIhIhIhIhIhInG", +"fPfPfPhIg#fPfPfPfPfPiafPfPfPfPfPfPfPfPhIg#fPfPfPfPfPiafPfPfPfPfPfPfPfPhIg#fPfPfPfPfPiafPfPfPfPfPfPfPfPhIg#fPfPfPfPfPiafPfPfPfPfPfPfPfPhIg#fPfPfPfPfPiafPfPfPfPfPfPfPfPhIg#fPhYiYi4jfjfi6jfiYi6iYhYjfiNi4jfjfi4.qjfjfj2jfixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixe0fsfsmcbPfsfs.2bPbP.UbPayayayfDayluayfsbPeBg3ayeBfsayfDlug3fPfsg3eBlufPeBeBg3g3eBmlfPfPlulufPfsfPeBfPfPmleBgIf4eBg3fPfPfDfDfPmlgIfPfPfPfPlug#gIfPmlgIiafPfPg#hxhIhxgIiaiagIgIfPiahxg#hxgIgIgIg#gIhIigiafPhIhIigigg#igg#igighIighImsigmsg#ighIhxiahxiahxhIkckchIkcmshImsighIhIigighIighIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIighIigighIighIhIfPhIfPfPhIfPhIhIhIhIhIhIhIhIhIhIighIigighIighIhIhIhIhIhIhIhIhIhIhIhIhIhInG", +"fPfPfPfPfPfPfPg#fPfPfPfPfPiafPfPfPfPfPfPfPfPfPg#fPfPfPfPfPiafPfPfPfPfPfPfPfPfPg#fPfPfPfPfPiafPfPfPfPfPfPfPfPfPg#fPfPfPfPfPiafPfPfPfPfPfPfPfPfPg#fPfPfPfPfPiafPfPfPfPfPfPfPfPi6hYhYhYd2jfi4jfi6i6i6iYi6iNiNd2jfjfjfi4i4i4ixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixix.Ufs.UfseBfsfsfsbPfs.2.U.UbPeB.Uay.UayaylufsfseBbPeBayfsfsfDfPfDfDfsg3eBeBfslufsfseBg3fPfPfPg3mlfPeBg#eBeBeBeBfPfPfPfPiaiafPg#fPfPfPgIfPfPfPfPg#fPfPgIfDgIfPgIg#g#hxg#hxhIgIgIgIiahIfPg#g#hxhIgIgIiagIhIhIgIighafDhIgIigighahIhIhIgIhImsmshIhIhIhahaighIhIigkchxkchIkchImsgIhIhIhIhIhIhIhIhIhIhIhIighIigighIighIhIhIhIhIhIhIhIhIhIhIhIhIhIgIhIgIgIhIgIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIighIigighIighIhInG", +"fPfPfPfPfPfPfPfPfPfPfPfPfPfPfPg#fPfPfPfPfPfPfPfPfPfPfPfPfPfPfPg#fPfPfPfPfPfPfPfPfPfPfPfPfPfPfPg#fPfPfPfPfPfPfPfPfPfPfPfPfPfPfPg#fPfPfPfPfPfPfPfPfPfPfPfPfPfPfPg#fPfPfPfPfPfPhYi6hYhYiYiYhYjfi4jfi6d2iYiYi5iYd2jfjfi4jfjfixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixfs.U.2.2.2.UfseBfsfsbPfs.2.UbPbP.UbPayayayk#fslufseBbPeBfsf4fDfDeBfDlug3g3mlfPeBlulueBg3g3fPfseBfPfPeBeBeBfPeBeBeBfPfPgIhxfPg3g3iafPfDgIgImlfPfPfPfPfPg#fDfPfPfPgIiafPfPigfPhxiagIgIfPgIfPg#hxighIhxgIgIgIfPg#hIighIhxhIigigg#haigg#igighIigigmshIhIhahIhIhIigighIhxhIigighIighIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIighIigighIighIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhInG", +"fPeBfPfPg3fPg#fPfPfPg#fPfPfPeBfPfPeBfPfPg3fPg#fPfPfPg#fPfPfPeBfPfPeBfPfPg3fPg#fPfPfPg#fPfPfPeBfPfPeBfPfPg3fPg#fPfPfPg#fPfPfPeBfPfPeBfPfPg3fPg#fPfPfPg#fPfPfPeBfPfPeBfPfPg3fPi4i4iYi4i6hYhYi6i6iNiNhYi4iYhYi5jfjfjfiYjfi4ixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixix.U.Ufsfsfs.U.U.Ufs.U.Ufsfs.UbPbP.2.UfseBeBbPayfsayayayeBfDfsfseBfsfDfDfPfPfDg3fsg3g3lulufPfPeBfPfDfPfPeBfPfPeBeBeBnmeBfPfPfPfPfPfPiafPg3nFfPgImlfPgIg3g#nHnInJnKnLnlknnMgIiafPhxighIgIgIgIfPiaiaigg#ighIhIgIgIg#hIhIighIhIigighIl1igl1hIhIg#hIighIhIhIhIigmshamsighIkfhIhIhxhIhIhIhIhIhIhIighIigighIighIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIl1hIl1l1hIl1hIhIhIhIhIhIhIhIhIhIl1hIl1l1hIl1hIhIhIhIhIhIhIhIhIhIighIigighIighIhIhIhIhIhInG", +"fPfPeBfPfPg3fPeBfPfPeBfPfPeBfPfPfPfPeBfPfPg3fPeBfPfPeBfPfPeBfPfPfPfPeBfPfPg3fPeBfPfPeBfPfPeBfPfPfPfPeBfPfPg3fPeBfPfPeBfPfPeBfPfPfPfPeBfPfPg3fPeBfPfPeBfPfPeBfPfPfPfPeBfPfPg3h0iNi4i4iNiYhYhYiYhYiNi4iYi4i4iYi6hYiYiYjfjfixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixix.qfs.U.Uay.2.Ufs.2.U.Ufs.Ufsj2bPfsay.2.UbP.UlneBay.UfsfseBlufDfsfseBfsfsfDfPfPhxmlg3mleBlufsfPfDfDeBfPfPfsmleBfPfPfPfPeBfPeBfPmlfPfPg3nNlGnOlvnPnQnRmgk4ixixixixixixixixfPhxgIgIfPhahxhIiggIigiaiahIigg#hxfPhIhIiggIhIhIg#igg#fPigl1igighahIhIl1lLhIighIighIigg#hahaighIighxhIhIhIhIhIhIhIl1hIl1l1hIl1hIhIhIhIhIhIl1hIl1l1hIl1hIhIhIhIhIhIl1hIl1l1hIl1hIhImshImsmshImshIhIl1hIl1l1hIl1hIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIl1hIl1l1hIl1hIhIhIhIhIhInG", +"fPfPfPg3fPfPfPfPeBfPfPfPfPfPfPeBfPfPfPg3fPfPfPfPeBfPfPfPfPfPfPeBfPfPfPg3fPfPfPfPeBfPfPfPfPfPfPeBfPfPfPg3fPfPfPfPeBfPfPfPfPfPfPeBfPfPfPg3fPfPfPfPeBfPfPfPfPfPfPeBfPfPfPg3fPfPhYhYiYiNh0h0jfi4i4hYhYi6iYiNiYi4i4jfhYd2i6i6ixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixix.Ujf.q.U.U.Ufsfsfs.U.U.U.2.Ufsj2bPbPfsfs.U.U.2fseB.UbPayfslufDeBfDfsf4g3f4f4fsfsfsfDfDg3eBfPeBmlfPeBeBnFeBfPeBeBg3mlfPnSnTnUnVman.nWmPixixixixixixixixixixixixixixixixixfPgIgIgIgIiahIg#hxhahxigiafPhxgIg#g#igighIgIhxgIhIgIhIg#g#fPighIigighIhIhIg#g#hIgIhImsighIg#hmhIhIkchIl1l1hIl1hIhIhIhIhIhIhIhIhIhImshImsmshImshIhIl1hIl1l1hIl1hIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhImshImsmshImshIhIl1hIl1l1hIl1hIhIhIhIhIhIhIhIhIhImshImsmsnG", +"fsg3fPfsfPfPeBfPg3fPeBfPfsg3fPfPfsg3fPfsfPfPeBfPg3fPeBfPfsg3fPfPfsg3fPfsfPfPeBfPg3fPeBfPfsg3fPfPfsg3fPfsfPfPeBfPg3fPeBfPfsg3fPfPfsg3fPfsfPfPeBfPg3fPeBfPfsg3fPfPfsg3fPfsfPfPhYhYh7hYh0h0h4h0iNhYhYhYhYh0iYiYiYd2iNhYiNi6ixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixix.U.Uj2.2.U.U.2.U.2ay.U.2jf.2bP.2bPfs.Ufsay.2.U.2.2.2.UfsfsfsbPfsfDfDfDlueBfseBfsfslufslufPg3f4g3fsfPnsnXnYnZn0n1njjFndixixixixixixixixixixixixixixixixixixixixixixixixixiafPfPgIgIgIgIfPiag#hxighxhxhxgIgIfPhIfPfPigg#ighxgIkcgIiaiaiaighIighIigigl1iglLhIhIighIkfigmshaighIhIhIhIhIhIhIhIl0hIl0l0hIl0hIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIhIl1hIl1l1hIl1hIhIhIhIhIhIhIhIhIhIl1hIl1l1hIl1hIhIhIhIhIhIhIhIhIhIhIhIhIhIl0hIl0l0hIl0hIhIhIhIhIhInG", +"g3fPfPfPfPfsfPfPfsfPfPfPfPfPeBfPg3fPfPfPfPfsfPfPfsfPfPfPfPfPeBfPg3fPfPfPfPfsfPfPfsfPfPfPfPfPeBfPg3fPfPfPfPfsfPfPfsfPfPfPfPfPeBfPg3fPfPfPfPfsfPfPfsfPfPfPfPfPeBfPg3fPfPfPfPfsh0hYh7h7hYhYhYhYh0h0iNiNhYi4hYhYi6iYhYiNiYjfixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixix.UdG.UdGd2.2ae.2.Ufs.Ufs.Ufs.Ufs.2.U.U.U.q.UbPfsfsfs.2fseBeBfsf4g3fPg3fDeBeBfDg3g3eBn2n3n4n5n6n7kRnrixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixigiahIfPg#iggIigighIhIhIgIhIjUhxiggIiagIgIiafPigg#hIgIhxgIjUgIhIhIhIhIhIhIigigigighIg#mskchIm1igigighIhIhIl1hIl1l1hIl1hIhIl0hIl0l0hIl0hIhIl1hIl1l1l0l1l0l0l1l0l1l1hIl1hIhIhIhIhIhImshImsmsl0msl0l0hIl0hIhIhIhIhIhIl0hIl0l0hIl0hIhIhIhIhIhIl1hIl1l1hIl1hIhIl0hIl0l0hIl0hIhInG", +"fsfPeBfsfPfPeBfPfsfPeBfsfPfsfPfPfsfPeBfsfPfPeBfPfsfPeBfsfPfsfPfPfsfPeBfsfPfPeBfPfsfPeBfsfPfsfPfPfsfPeBfsfPfPeBfPfsfPeBfsfPfsfPfPfsfPeBfsfPfPeBfPfsfPeBfsfPfsfPfPfsfPeBfsfPfPhRiYhDh0h7h0hRh4hYhYi4h0iNhYiNi4h0i4hYi6iNiSixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixix.2.Ujf.UdG.Ujf.2.2.q.2.U.2fs.Ud2fs.U.2.U.2.Uj2.2fsdGfsfseBfseBfsg3n8n9o.o#oamUobjhlfixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixgIgImlfPfPgIfPhagIgIgIfPgIiafPiaighafPigigiaighIhIighIfPhIgIgIgIgIgIhaighIfPhIhIigigigg#hIg#ighIhIm1hIl0l0hIl0hIhIhIhIhIhIl1hIl1l1hIl1hIhImshImsmshImshIhIhIhIhIhIl1hIl1l1l0l1l0l0hIl0hIhImshImsmshImshIhIl1hIl1l1hIl1hIhIhIhIhIhIl0hIl0l0hIl0hIhIhIhIhIhIl1hIl1l1hIl1hIhInG", +"eBfPg3fPeBg3fPeBfPfPeBfPfPeBfPfseBfPg3fPeBg3fPeBfPfPeBfPfPeBfPfseBfPg3fPeBg3fPeBfPfPeBfPfPeBfPfseBfPg3fPeBg3fPeBfPfPeBfPfPeBfPfseBfPg3fPeBg3fPeBfPfPeBfPfPeBfPfseBfPg3fPeBg3iSh0h0h0hRh0h0hYhYh0hYhYh0iNiYhYi4i5i6i6hYhYixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixjf.2.q.2.U.Uae.UbP.Uae.2.U.q.U.U.Uay.U.U.2.2.U.2.UocodoeofogohmOoikoixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixfDfDfPfPgIg#iagIhafPhafPfPigfPiggIfPhaighIhIhxgIgIkcgIhIhIhIiahIgIhIgIhIhImshIighIhxhIigighIg#l1kckcl0l1l1hIl1hIhIl0hIl0l0hIl0hIhIhIhIhIhIl0hIl0l0hIl0hIhIl1hIl1l1hIl1hIhImshImsmsl0msl0l0hIl0hIhIl0hIl0l0msl0msmshImshIhIl0hIl0l0l1l0l1l1hIl1hIhIl0hIl0l0hIl0hIhIhIhIhIhIoj", +"fPfsfPfsfPfsfseBfPfsfPeBfsg3eBfPfPfsfPfsfPfsfseBfPfsfPeBfsg3eBfPfPfsfPfsfPfsfseBfPfsfPeBfsg3eBfPfPfsfPfsfPfsfseBfPfsfPeBfsg3eBfPfPfsfPfsfPfsfseBfPfsfPeBfsg3eBfPfPfsfPfsfPfshRhRhRh4hYhRhDh0hYh0hRh7hYh7iSiShYh0iNhYiYhYixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixdGd2d2.2.2jf.2aedG.q.qbP.2d2.2.U.U.2.2.Ufsd2fs.2ioixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixhIighagIgIfPg#gIfPhIg3hIigfDiggIgIiggIgIgIhxiahIgIgIgIgIiagIg#ighIg#hIhIhIiakchIighIighIigigigigigg#hIhIhIl1hIl1l1msl1msmsl1msl1l1l0l1l0l0hIl0hIhIl0hIl0l0hIl0hIhIl0hIl0l0hIl0hIhIhIhIhIhImshImsmsl0msl0l0hIl0hIhIl1hIl1l1hIl1hIhIhIhIhIhIl1hIl1l1msl1msmsl1msl1l1l0l1l0l0nG", +"g3eBfseBfPeBfPfPfsfsfPfPfsfPfsfPg3eBfseBfPeBfPfPfsfsfPfPfsfPfsfPg3eBfseBfPeBfPfPfsfsfPfPfsfPfsfPg3eBfseBfPeBfPfPfsfsfPfPfsfPfsfPg3eBfseBfPeBfPfPfsfsfPfPfsfPfsfPg3eBfseBfPeBh0h0hDhRhRhRh0hYhDiNhYhRhDh0h7h7i6hYh4hYh0iNixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixix.Uae.Uj2d2d2.2.2.q.2dG.U.q.U.2.2.2.U.U.2.2.2fs.UixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixgIfPgIhIfPhaiggIfPfPfPfPiahIiaigigigighIiaighahahxhIhIhIhIhIhIhIigg#hIhIighIgIgIial1hIhIjUjUjUjUhIigl0hIhIl0hIl0l0hIl0hIhIl0hIl0l0l1l0l1l1msl1msmshImshIhIl1hIl1l1l0l1l0l0l1l0l1l1l0l1l0l0l0l0l0l0hIl0hIhIhIhIhIhIl0hIl0l0l0l0l0l0hIl0hIhIl0hIl0l0hIl0hIhIl0hIl0l0l1l0l1l1nG", +"fsfPeBfPfsfseBfseBfPeBfsg3fsfPfsfsfPeBfPfsfseBfseBfPeBfsg3fsfPfsfsfPeBfPfsfseBfseBfPeBfsg3fsfPfsfsfPeBfPfsfseBfseBfPeBfsg3fsfPfsfsfPeBfPfsfseBfseBfPeBfsg3fsfPfsfsfPeBfPfsfsh2hDhRh0hRhRh4hRibh4h0h0hRh0hYh7hYh0h0i6h0iSixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixix.qjf.qd2ae.Uj5d2.q.2jfjf.2.U.q.U.qd2j5.2.2.U.U.2ixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixfDfPfPhxg3gIfPigg#igg#gIfPighIgIgIg#hafDfPgIhxiagIhahxhahxfPhxgIgIiggIigigjUfPg#jUighIigkcg#hIighIjUhIl0l0hIl0hIhIl0hIl0l0msl0msmshImshIhIl0hIl0l0l1l0l1l1l0l1l0l0hIl0hIhIhIhIhIhIl1hIl1l1hIl1hIhIl1hIl1l1l0l1l0l0l1l0l1l1hIl1hIhIl0hIl0l0hIl0hIhIl0hIl0l0msl0msmshImshIhIoj", +"fsfPfsfseBeBg3fPeBfsg3fsfPeBeBeBfsfPfsfseBeBg3fPeBfsg3fsfPeBeBeBfsfPfsfseBeBg3fPeBfsg3fsfPeBeBeBfsfPfsfseBeBg3fPeBfsg3fsfPeBeBeBfsfPfsfseBeBg3fPeBfsg3fsfPeBeBeBfsfPfsfseBeBh2hRhnhDh0hDh0hRhYh4h0hYh4h0h0hYhYh0h7h0h4hYixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixix.q.q.q.qaed2.qdG.2j5j2.q.2.2dG.2ae.qjfbPjf.2.q.UixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixigeBfPfPfPg#fPfPgIg#ignFfPfPmlgIiggIighaigmsigigighIhIhIhIiaiajUg#hIiahIkcigkcighIjUigjUhIkchIl1hIhIl1l0l0l1l0l1l1l0l1l0l0l0l0l0l0hIl0hIhIl0hIl0l0hIl0hIhIl1hIl1l1l0l1l0l0l1l0l1l1l0l1l0l0l0l0l0l0l0l0l0l0l1l0l1l1l0l1l0l0l1l0l1l1l0l1l0l0l1l0l1l1l0l1l0l0l0l0l0l0hIl0hIhIoj", +"eBfseBfsfPfsfsfsfsg3fseBfsfPfsfseBfseBfsfPfsfsfsfsg3fseBfsfPfsfseBfseBfsfPfsfsfsfsg3fseBfsfPfsfseBfseBfsfPfsfsfsfsg3fseBfsfPfsfseBfseBfsfPfsfsfsfsg3fseBfsfPfsfseBfseBfsfPfshRhRhRh4h4hnhDh0h0hDhRhDhRh4hYh0hDh7h7hYhYh7ixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixix.qjfd2d2d2.q.qaed2.Ud2jfjf.qjf.q.q.2dGdGdGj2.q.2ixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixfPfPeBigfPigmlfPmlfPhIfPfPg#iggIgIg#fPgIgIhaiggIithxgIhxhxgIhag#g#hxhxigighIkchIhIighIhxighIgIigigmsl1msmsl0msl0l0l1l0l1l1hIl1hIhIl1hIl1l1l1l1l1l1l0l1l0l0msl0msmsl0msl0l0msl0msmsl1msl1l1hIl1hIhIl1hIl1l1l0l1l0l0hIl0hIhIl1hIl1l1msl1msmsl0msl0l0l1l0l1l1hIl1hIhIl1hIl1l1nG", +"fPeBfseBfseBeBfPfseBfseBeBfseBg3fPeBfseBfseBeBfPfseBfseBeBfseBg3fPeBfseBfseBeBfPfseBfseBeBfseBg3fPeBfseBfseBeBfPfseBfseBeBfseBg3fPeBfseBfseBeBfPfseBfseBeBfseBg3fPeBfseBfseBhRhDhRh0h4hRhRh2hRh0h0hRhDhRh4h0h0h0hDh0hDhRixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixd2jfj5dGd2.q.q.q.2.qae.U.Uj2jfjf.q.q.q.UdG.UjwaeixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixfPg#fPfPhIigigigigfPg#fPg3fPg3igigigg#gIgIg#gIhIhIigmsigiahIhIgIhIhIiagIhaiaighIhIgIhIhahxhIighIhIhIl0l0l0hIl0hIhIl0hIl0l0l0l0l0l0l0l0l0l0l0l0l0l0hIl0hIhIl0hIl0l0l1l0l1l1l0l1l0l0l0l0l0l0l0l0l0l0l1l0l1l1l0l1l0l0msl0msmsl0msl0l0l0l0l0l0hIl0hIhIl0hIl0l0l0l0l0l0l0l0l0l0oj", +"eBfsfsg3eBfsfsfsfsfsg3fsfseBfsfseBfsfsg3eBfsfsfsfsfsg3fsfseBfsfseBfsfsg3eBfsfsfsfsfsg3fsfseBfsfseBfsfsg3eBfsfsfsfsfsg3fsfseBfsfseBfsfsg3eBfsfsfsfsfsg3fsfseBfsfseBfsfsg3eBfshDh4hnhDhRhDh0h2hRh2hRhDhDh0hRhDhRhYh4h0h0hDixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixiYjfd2jfd2jfj2i4.q.qd2.qjfdGdG.qae.qd2.q.q.q.2dGixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixmlfDfPg3g#fPhIfPfPgIigfPhag#gIg#fPfPhagIigmligfPgIgIhIgIhaiggIigiagIhIfPiahxg#hxighIigkchIl1igkciahIl0l1l1l0l1l0l0l1l0l1l1l1l1l1l1l0l1l0l0l1l0l1l1l0l1l0l0l0l0l0l0l0l0l0l0l1l0l1l1msl1msmsl0msl0l0hIl0hIhIl1hIl1l1l0l1l0l0l0l0l0l0l1l0l1l1l0l1l0l0l1l0l1l1l1l1l1l1l0l1l0l0nG", +"fseBfsfsayeBfseBeBfsfseBfsg3eBfsfseBfsfsayeBfseBeBfsfseBfsg3eBfsfseBfsfsayeBfseBeBfsfseBfsg3eBfsfseBfsfsayeBfseBeBfsfseBfsg3eBfsfseBfsfsayeBfseBeBfsfseBfsg3eBfsfseBfsfsayeBhRhnh4hDhDhRhnhRhDhRhRh4hRhnhnhRhDhRhRhRh0hRixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixd2jfi4jfjfd2d2j5jwj2iYd2d2.q.qdGjfjfdGj2j2.2.q.2ixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixfPfPfDfPfPg#hxfPhIfPg#igigfPigfPfPgIfPhagIigitigigg#hahIhIighaighIhIhIhIiahxgIhahaiahIhIhIiahIkcl1igl0l1l1lhl1lhlhl0lhl0l0l1l0l1l1l1l1l1l1l0l1l0l0l1l0l1l1l1l1l1l1msl1msmsl0msl0l0l0l0l0l0l0l0l0l0l0l0l0l0l1l0l1l1l0l1l0l0l0l0l0l0l1l0l1l1lhl1lhlhl0lhl0l0l1l0l1l1l1l1l1l1oj", +"fsfseBfsfsfsfsfsayeBfsayfsfsfseBfsfseBfsfsfsfsfsayeBfsayfsfsfseBfsfseBfsfsfsfsfsayeBfsayfsfsfseBfsfseBfsfsfsfsfsayeBfsayfsfsfseBfsfseBfsfsfsfsfsayeBfsayfsfsfseBfsfseBfsfsfshDhDhDhDh4h2hDhDhnhRhDh0h2h4hRh2hDhDhDhRhYh0ixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixjfd2i4i4i4i6jfjfd2jfd2j5d2d2.q.q.2.qd2jfiYjf.q.qixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixhxfPfPfPfPfPfPfPfPhafPfPhIigfPfPfPfPg#g#fPgIfPg#gIigmlfPgIg#fPgIfPigighIighIhxhIgIhIiahxhahxigigigigl1l0l0l1l0l1l1l0l1l0l0lhl0lhlhl0lhl0l0l0l0l0l0lhl0lhlhl0lhl0l0l0l0l0l0l1l0l1l1l1l1l1l1l0l1l0l0l1l0l1l1l0l1l0l0l1l0l1l1l1l1l1l1l0l1l0l0l1l0l1l1l0l1l0l0lhl0lhlhl0lhl0l0oj", +"fs.UfseBayfseBfsfsfseBfseBfs.Ufsfs.UfseBayfseBfsfsfseBfseBfs.Ufsfs.UfseBayfseBfsfsfseBfseBfs.Ufsfs.UfseBayfseBfsfsfseBfseBfs.Ufsfs.UfseBayfseBfsfsfseBfseBfs.Ufsfs.UfseBayfshyhnhnhnhDh4hDhRhDhDhDhDhnhyhDhRh4h0h0h4hRhDixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixi4i5jfd2jfjwiYjfjfjfi4jfdGi4d2j2i4d2.q.q.q.qj5jwixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixfDg#hxfPfPhxf4fPgIg#fPg#fPg#fPfPfPigfPmlfPg#fPgIhIhxigigmsighIg#g#g#gIigigmsiahIkchIhIkcighakchIjUhIl0lhlhl0lhl0l0l1l0l1l1l0l1l0l0l0l0l0l0l1l0l1l1l0l1l0l0l0l0l0l0l1l0l1l1l0l1l0l0k0l0k0k0l0k0l0l0l0l0l0l0l0l0l0l0k0l0k0k0l0k0l0l0lhl0lhlhl0lhl0l0l1l0l1l1l0l1l0l0l0l0l0l0nG", +"fseBayfseBayeB.UeBfs.UfsfsayeBfsfseBayfseBayeB.UeBfs.UfsfsayeBfsfseBayfseBayeB.UeBfs.UfsfsayeBfsfseBayfseBayeB.UeBfs.UfsfsayeBfsfseBayfseBayeB.UeBfs.UfsfsayeBfsfseBayfseBaygVgVhngRhnhnhDhDh4hDhDhRhnhnhyhDhDhRh4hnhRh0ixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixiYjfhYiNjfi6iYjfi4i4jfjfhYjfjfd2jfiYiYi6.qjfjf.qixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixf4fPfDfDeBfPfPfPigf4igmlfPg#fPfPfPigfPg#fPigigfPigfPhIfPfPigfPigfPigfPhIighaigiggIhxighxhxiagIhaiaial0l0l0l1l0l1l1k0l1k0k0l0k0l0l0l0l0l0l0k0l0k0k0l1k0l1l1l0l1l0l0k0l0k0k0l1k0l1l1lhl1lhlhl1lhl1l1k0l1k0k0l0k0l0l0l1l0l1l1l0l1l0l0l0l0l0l0l1l0l1l1k0l1k0k0l0k0l0l0l0l0l0l0ok", +"fsfseBayfsfsfsfs.UfsfsfseBfsfs.UfsfseBayfsfsfsfs.UfsfsfseBfsfs.UfsfseBayfsfsfsfs.UfsfsfseBfsfs.UfsfseBayfsfsfsfs.UfsfsfseBfsfs.UfsfseBayfsfsfsfs.UfsfsfseBfsfs.UfsfseBayfsfshnhDgVhKhnhnhRgRhnhDhnhRh4hnh4hbhnhDh0h0hDhDixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixd2jbjfi4i5i5d2d2j5d2d2hYi4i4jfi4jfd2d2jfi6d2.q.qixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixfPfPfPfPfPfPhag3fPhafPhxfPf4hIgIfPg#fPfPfPigigighaighaigg#fPfPhaigighafPgIg#fPhafPhaiggIigiahIhIhIkcl0k0k0l0k0l0l0l0l0l0l0l0l0l0l0lhl0lhlhl0lhl0l0k0l0k0k0l0k0l0l0l0l0l0l0lhl0lhlhl0lhl0l0lhl0lhlhl1lhl1l1l0l1l0l0lhl0lhlhl0lhl0l0k0l0k0k0l0k0l0l0l0l0l0l0l0l0l0l0lhl0lhlhoj", +".Uayfs.UfseBayfsayfs.Ufs.UayeBfs.Uayfs.UfseBayfsayfs.Ufs.UayeBfs.Uayfs.UfseBayfsayfs.Ufs.UayeBfs.Uayfs.UfseBayfsayfs.Ufs.UayeBfs.Uayfs.UfseBayfsayfs.Ufs.UayeBfs.Uayfs.UfseBhnhnhRhKgVgVhhhnhKgRhnhDhnhDh4h4h2hDhnhDhDhDixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixd2jfi4i4i4hYjfhYi4i4j5i4i4i4jfhYjfjfjfd2jfd2iYi4ixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixfPfPfPfPfPfPgIg3g#g3fPhxfPfPfPf4gIfPfPfPfPfPhIigigigigfPg#g#g#fPhIigfPgIgImsigighIgIiggIigigighImsgIlhl1l1l0l1l0l0k0l0k0k0l0k0l0l0l1l0l1l1l0l1l0l0l0l0l0l0l1l0l1l1l0l1l0l0k0l0k0k0l0k0l0l0l0l0l0l0l0l0l0l0k0l0k0k0l0k0l0l0lhl0lhlhl1lhl1l1l0l1l0l0k0l0k0k0l0k0l0l0l1l0l1l1oj", +"ayfseBfsay.UfseB.Ufsfsayfsfs.UfsayfseBfsay.UfseB.Ufsfsayfsfs.UfsayfseBfsay.UfseB.Ufsfsayfsfs.UfsayfseBfsay.UfseB.Ufsfsayfsfs.UfsayfseBfsay.UfseB.Ufsfsayfsfs.UfsayfseBfsay.UgVhngRgRhnhnhnhngVgVgVhKgVhnhDh0hDh4gVhDh4hDixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixhYiYd2jfhYi4jwi4i4jfhYd2iNjfjfd2i4d2i4jfi6i5jfiYixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixfPg3hag3g3fPfPmlgIhxgIhafDhahxfPiggIigfPfPg#g3fPg#hIigigfPigfPhIigighIgIhaiggIg#igmsg#hIighIigiggIgIl0lhlhk0lhk0k0l0k0l0l0k0l0k0k0l0k0l0l0lhl0lhlhk0lhk0k0k0k0k0k0l0k0l0l0l0l0l0l0lhl0lhlhk0lhk0k0l1k0l1l1l0l1l0l0k0l0k0k0l0k0l0l0lhl0lhlhk0lhk0k0l0k0l0l0k0l0k0k0l0k0l0l0ol", +".Ufs.U.UfseB.Ufs.Ufs.U.Ufs.Uayfs.Ufs.U.UfseB.Ufs.Ufs.U.Ufs.Uayfs.Ufs.U.UfseB.Ufs.Ufs.U.Ufs.Uayfs.Ufs.U.UfseB.Ufs.Ufs.U.Ufs.Uayfs.Ufs.U.UfseB.Ufs.Ufs.U.Ufs.Uayfs.Ufs.U.UfseBglhKhhgVgRgVhngVhnhRgVgRgVhbhDgVhnhRhDhRgVhDixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixjfhYhYiNhYd2h0hYi4iSi4i4i5d2iNi4jfjfhYd2hYi4i5i4ixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixhxfPfPg3g3fPhxfPfPmlfPf4fPfPeBg#hxhxfPmlhxigfPigigfPigfPfPigmliggIgIgIfPgIhxfPhIigg#igfPhahIfPhIgIhIl0k0k0l0k0l0l0lhl0lhlhk0lhk0k0l0k0l0l0lhl0lhlhl0lhl0l0l0l0l0l0k0l0k0k0k0k0k0k0l0k0l0l0lhl0lhlhl0lhl0l0k0l0k0k0l0k0l0l0l0l0l0l0k0l0k0k0l0k0l0l0lhl0lhlhk0lhk0k0l0k0l0l0ol", +".Ufsayfs.Uayfs.Ufsay.Ufsfs.Ufs.U.Ufsayfs.Uayfs.Ufsay.Ufsfs.Ufs.U.Ufsayfs.Uayfs.Ufsay.Ufsfs.Ufs.U.Ufsayfs.Uayfs.Ufsay.Ufsfs.Ufs.U.Ufsayfs.Uayfs.Ufsay.Ufsfs.Ufs.U.Ufsayfs.UaygVgVgRhhhhgVgVhnhbgVhKhnhnhKgVgVhbhDhDhDhRhDixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixh7iYi4iNhYhYhYd2d2i4d2hYhYjfi4iNi5iYd2iYi4i4hYi4ixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixfseBeBfPfPhxfPfPfPfPhxfPfPhxf4hxfPg3gIfPfPfPfPfDgIhIfPighIhxfPhIfPigighIhIhahIfPhIfPhaigigmsg#msigigk0k0k0l0k0l0l0k0l0k0k0l0k0l0l0l0l0l0l0k0l0k0k0lhk0lhlhk0lhk0k0l0k0l0l0lhl0lhlhk0lhk0k0l0k0l0l0k0l0k0k0lhk0lhlhl0lhl0l0k0l0k0k0k0k0k0k0l0k0l0l0k0l0k0k0l0k0l0l0l0l0l0l0ok", +"fs.Ufs.2fs.U.U.Ufs.2ay.U.2ay.Uayfs.Ufs.2fs.U.U.Ufs.2ay.U.2ay.Uayfs.Ufs.2fs.U.U.Ufs.2ay.U.2ay.Uayfs.Ufs.2fs.U.U.Ufs.2ay.U.2ay.Uayfs.Ufs.2fs.U.U.Ufs.2ay.U.2ay.Uayfs.Ufs.2fs.UglgVglg4hnglhhhbhbhhhngRhnhKhKgVgVgVhKgRhDhDixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixi4h7h7iNjfiSiYhYiSi4i4i4i4hYi4hYjfhYiNi4jfhYiYhYixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixfPfPfPluhxf4mlfPg3fPfPfPfPfPfPfPfPgIfPfPfPfPfPhxfPgIfDgIfPgIfPhxigfPg#igigfPhIg#gIhIfPkciggIiggIhmfPlhl0l0k0l0k0k0lhk0lhlhk0lhk0k0k0k0k0k0l0k0l0l0k0l0k0k0l0k0l0l0k0l0k0k0l0k0l0l0l0l0l0l0lhl0lhlhk0lhk0k0l0k0l0l0k0l0k0k0lhk0lhlhl0lhl0l0k0l0k0k0lhk0lhlhk0lhk0k0k0k0k0k0oj", +"ay.U.U.Ufsayfsay.U.Ufsfs.Ufs.Ufsay.U.U.Ufsayfsay.U.Ufsfs.Ufs.Ufsay.U.U.Ufsayfsay.U.Ufsfs.Ufs.Ufsay.U.U.Ufsayfsay.U.Ufsfs.Ufs.Ufsay.U.U.Ufsayfsay.U.Ufsfs.Ufs.Ufsay.U.U.UfsaygVglglglhnhngVhngVhKhbhnhngVgRgVhRhnhhgVgVhKixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixhYiNiNd2hYh7jfjfiNjfhYiNi4i4i4hYi4i4i4i4hYiNd2jfixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixfPfPfPfPfPfPg3eBf4fPfPg3g3hanFhxomfPhxiag#hxgIgIfPfPfPmligigigfPhxg#fPhIfPg#igigg#hIg#hxlLkckchxgIigk0lhlhk0lhk0k0l0k0l0l0kgl0kgkgk0kgk0k0lhk0lhlhl0lhl0l0k0l0k0k0kgk0kgkgk0kgk0k0k0k0k0k0k0k0k0k0l0k0l0l0l0l0l0l0k0l0k0k0k0k0k0k0lhk0lhlhk0lhk0k0l0k0l0l0kgl0kgkgk0kgk0k0ol", +".2ay.Ufs.U.2.U.2.Ufs.U.2ay.2fs.U.2ay.Ufs.U.2.U.2.Ufs.U.2ay.2fs.U.2ay.Ufs.U.2.U.2.Ufs.U.2ay.2fs.U.2ay.Ufs.U.2.U.2.Ufs.U.2ay.2fs.U.2ay.Ufs.U.2.U.2.Ufs.U.2ay.2fs.U.2ay.Ufs.U.2higlglgVhhglhngRglgVgRhhglgVhbgRgRgRgVhRgVgVixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixh0hYi4hYhYhYi6h7i4hYhYi4hYhYi4hYi4h0i4hYhYi4hYiSixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixfPeBfPg3g3fPfsfPhxg3mlhxmlfPgIfPfPg#hxfPf4fPgIfPfDgIfPfPfPgIfPfDfPigfDigfPg#ighIg#ighIighIfPhIfPfPkcl0k0k0l0k0l0l0k0l0k0k0lhk0lhlhl0lhl0l0k0l0k0k0k0k0k0k0k0k0k0k0lhk0lhlhl0lhl0l0k0l0k0k0l0k0l0l0k0l0k0k0kgk0kgkgk0kgk0k0l0k0l0l0k0l0k0k0l0k0l0l0k0l0k0k0lhk0lhlhl0lhl0l0ok", +".Ufs.2.U.U.Uayfs.U.Uay.Ufs.Uay.U.Ufs.2.U.U.Uayfs.U.Uay.Ufs.Uay.U.Ufs.2.U.U.Uayfs.U.Uay.Ufs.Uay.U.Ufs.2.U.U.Uayfs.U.Uay.Ufs.Uay.U.Ufs.2.U.U.Uayfs.U.Uay.Ufs.Uay.U.Ufs.2.U.U.UgugVguglguhhgRhhhbgVgVhng4gVgVhbgRgVgRgVhnhKixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixhYh0h0i5hYhYi4hYi4i6i4hYiNjfjbiNiYi4icd2hYhYjbhYixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixg3fsf4eBf4g#fDfPfPg3fPfPfDmlf4hxfPfPfPfPfPhxfPmlhxhxgIfPhag#fPiahIhxigighIhahIfPhxhIigfPigigighIighIk0kgkgk0kgk0k0k0k0k0k0k0k0k0k0lhk0lhlhkglhkgkgl0kgl0l0k0l0k0k0k0k0k0k0k0k0k0k0k0k0k0k0kgk0kgkgk0kgk0k0lhk0lhlhk0lhk0k0k0k0k0k0kgk0kgkgk0kgk0k0k0k0k0k0k0k0k0k0lhk0lhlhok", +".U.U.U.2fs.2.U.2.Uay.2.U.2ay.U.2.U.U.U.2fs.2.U.2.Uay.2.U.2ay.U.2.U.U.U.2fs.2.U.2.Uay.2.U.2ay.U.2.U.U.U.2fs.2.U.2.Uay.2.U.2ay.U.2.U.U.U.2fs.2.U.2.Uay.2.U.2ay.U.2.U.U.U.2fs.2glglglgVgRguglhhglglglgVglgRhngRgVgVgVhbhngRixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixh0hYh7h7h7h0h0hYhYhYhYi6h7hYiNiSjfhYhYhYiNi4i4hYixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixg3fPg3g3lug3fsfPfPfPfPfPfPfPg3eBeBfPfDfPfPfPfPhxg3omfPmlfPfPgIgIhafPfPigfPhIigg#igfPigfPfPfPigigighak0lhlhkglhkgkgk0kgk0k0l0k0l0l0k0l0k0k0k0k0k0k0k0k0k0k0lhk0lhlhkglhkgkglhkglhlhk0lhk0k0lhk0lhlhk0lhk0k0kgk0kgkgl0kgl0l0k0l0k0k0lhk0lhlhkglhkgkgk0kgk0k0l0k0l0l0k0l0k0k0ok", +"ay.U.2.U.U.U.Uay.U.U.2.U.U.2.Uayay.U.2.U.U.U.Uay.U.U.2.U.U.2.Uayay.U.2.U.U.U.Uay.U.U.2.U.U.2.Uayay.U.2.U.U.U.Uay.U.U.2.U.U.2.Uayay.U.2.U.U.U.Uay.U.U.2.U.U.2.Uayay.U.2.U.U.UgRglglglongVglguglhhhhglhhglgVgVgVglgVgVhbhhixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixh0h0h0iSh7hYh4iNiNh4hYhYiYi6i6h7hYiNiNhYhYiYi4i4ixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixeBeBfPfPfPg3g3g3g3mlg#fsfDfPfPlug3fPmlhxhxfPfPfPhafPhxfPmliafPgIgIhag#hxhIfPhxigighafPgIfPfPfPigighIk0kgkglhkglhlhk0lhk0k0kgk0kgkgkgkgkgkgkgkgkgkglhkglhlhk0lhk0k0k0k0k0k0kgk0kgkgk0kgk0k0kgk0kgkgk0kgk0k0k0k0k0k0lhk0lhlhk0lhk0k0kgk0kgkglhkglhlhk0lhk0k0kgk0kgkgkgkgkgkgok", +".U.2.Uay.U.2.2.U.q.Uay.U.2.U.U.2.U.2.Uay.U.2.2.U.q.Uay.U.2.U.U.2.U.2.Uay.U.2.2.U.q.Uay.U.2.U.U.2.U.2.Uay.U.2.2.U.q.Uay.U.2.U.U.2.U.2.Uay.U.2.2.U.q.Uay.U.2.U.U.2.U.2.Uay.U.2gvhifQgRgRglglguglguglglhhgRhhhbglhbglgVhnglixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixh7h4hYjgh0h0hYibhYh0iNh4hYhYhYi4hYi6hYhYh4iNiYhYixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixfslug3fPfsfDfPfPlulug3f4fPoofPoofDfPfPlufPmliamlfPfPfPfPfPfPfPfPmlfDhxfPhafPhafPhxiaigigiahIiahIfPfPk0k0k0kgk0kgkgk0kgk0k0k0k0k0k0k0k0k0k0k0k0k0k0k0k0k0k0j9k0j9j9kgj9kgkgk0kgk0k0lhk0lhlhk0lhk0k0lhk0lhlhk0lhk0k0kgk0kgkgk0kgk0k0k0k0k0k0kgk0kgkgk0kgk0k0k0k0k0k0k0k0k0k0ok", +".2.U.2.2.q.U.U.U.U.2.U.U.2ay.U.2.2.U.2.2.q.U.U.U.U.2.U.U.2ay.U.2.2.U.2.2.q.U.U.U.U.2.U.U.2ay.U.2.2.U.2.2.q.U.U.U.U.2.U.U.2ay.U.2.2.U.2.2.q.U.U.U.U.2.U.U.2ay.U.2.2.U.2.2.q.UguhhhhgRgRgRglgRglglglhhgRgvhhglhhglhbglgVgVixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixhRh0h7h0jghYh0hYhYi4ibh7h7h0hYhYhYh0hYi6i6hYiNiNixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixfPlulug3f4fPfPfPfPfDfPg3g3mlg3mlfPfPfPfPfDfPfsg3g3mliafPgIgIfPgIgIiahIiagIfPfPgIgIfPhxigigfPhxhIhIhxkgk0k0j9k0j9j9kgj9kgkgk0kgk0k0k0k0k0k0kgk0kgkgk0kgk0k0k0k0k0k0lhk0lhlhkglhkgkgk0kgk0k0j9k0j9j9kgj9kgkgk0kgk0k0k0k0k0k0kgk0kgkgk0kgk0k0j9k0j9j9kgj9kgkgk0kgk0k0k0k0k0k0ok", +".U.U.U.U.U.2.2.U.q.U.2.q.U.2.U.U.U.U.U.U.U.2.2.U.q.U.2.q.U.2.U.U.U.U.U.U.U.2.2.U.q.U.2.q.U.2.U.U.U.U.U.U.U.2.2.U.q.U.2.q.U.2.U.U.U.U.U.U.U.2.2.U.q.U.2.q.U.2.U.U.U.U.U.U.U.2fkfkfQgugvglgRgRgugRglglgugVglguglglglglhbhbixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixhYhYhDhDh4hRh4h0h0hYhYhYibhYh0h0iNh4hYhYhYh7hYhYixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixfPfseBfPlulufsg3eBfDfDfPfPg3mllumleBf4g#fPfPfPfPlufPmlmlhxfPfPfPfPg3fPfPhxiamliafPhag#fPiafPmlfPfPigk0kgkgk0kgk0k0kgk0kgkgj9kgj9j9k0j9k0k0kgk0kgkgj9kgj9j9k0j9k0k0kgk0kgkgk0kgk0k0k0k0k0k0kgk0kgkgk0kgk0k0kgk0kgkgk0kgk0k0k0k0k0k0kgk0kgkgk0kgk0k0kgk0kgkgj9kgj9j9k0j9k0k0ok", +".Ujf.2.U.q.U.U.2.2.U.U.U.U.2jf.2.Ujf.2.U.q.U.U.2.2.U.U.U.U.2jf.2.Ujf.2.U.q.U.U.2.2.U.U.U.U.2jf.2.Ujf.2.U.q.U.U.2.2.U.U.U.U.2jf.2.Ujf.2.U.q.U.U.2.2.U.U.U.U.2jf.2.Ujf.2.U.q.UguglglgugugufQgRglgRhiggglglglglgVgRgRhiglglixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixh0hRh0h0h0hYhDh0h0h0hRhYhYhRhYhYiSh7h0hYhYi4hYhYixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixeBeBfPfsfPfPlulug3mlf4mlfPfDfDfPfPfPmlf4fPg#fPfPfPgIfPgIigfPgIhxhxhafPfPfPhxomiahIhahahIhxhahIfPfPhak0j9j9k0j9k0k0k0k0k0k0k0k0k0k0kgk0kgkgk0kgk0k0k0k0k0k0j9k0j9j9k0j9k0k0kgk0kgkgjVkgjVjVk0jVk0k0k0k0k0k0kgk0kgkgjVkgjVjVk0jVk0k0j9k0j9j9k0j9k0k0k0k0k0k0k0k0k0k0kgk0kgkgok", +".q.U.q.U.U.q.Ujf.U.2jf.q.U.q.U.U.q.U.q.U.U.q.Ujf.U.2jf.q.U.q.U.U.q.U.q.U.U.q.Ujf.U.2jf.q.U.q.U.U.q.U.q.U.U.q.Ujf.U.2jf.q.U.q.U.U.q.U.q.U.U.q.Ujf.U.2jf.q.U.q.U.U.q.U.q.U.U.qfQgvgugufQggfkguguhhgvgRguguglggglgugVgvgRgRixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixh0h4h0hDh0h4hRh0hDhRh0h0hDh0i4hYh0h0ibhRh0hDhYhYixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixfsfsf4eBfPfPfsfPmllufPfsmlfPfPfPfPfPfPfPmlg3fPfPfPfPfPgIgIfPigg3mlgIhxhIhxfPgIhxg3omigmlfPfPfPgIfPg#k0kgkgk0kgk0k0j9k0j9j9j9j9j9j9k0j9k0k0jVk0jVjVk0jVk0k0kgk0kgkgjVkgjVjVk0jVk0k0j9k0j9j9k0j9k0k0jVk0jVjVk0jVk0k0k0k0k0k0k0k0k0k0kgk0kgkgk0kgk0k0j9k0j9j9j9j9j9j9k0j9k0k0ok", +".U.U.U.q.q.U.2.Ujf.U.U.q.U.2.U.q.U.U.U.q.q.U.2.Ujf.U.U.q.U.2.U.q.U.U.U.q.q.U.2.Ujf.U.U.q.U.2.U.q.U.U.U.q.q.U.2.Ujf.U.U.q.U.2.U.q.U.U.U.q.q.U.2.Ujf.U.U.q.U.2.U.q.U.U.U.q.q.UfufQgvguglgggRgugugufkguhhgvguguglgRguglglgRixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixhRh0h4hRh4hRh0h0h0ibhYhDh0h7h0hYh4h0h0hYh0h7hYhYixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixeBeBfsf4fDfDfDfDfPfPfPmlfPfsgIg3fsfsfPfPfPfPfPfPgIg3gIfPgffDfPfPgIfPighxhxgIfPfPfPfPfPhIgImlgIhxgIigk0jVjVk0jVk0k0kgk0kgkgk0kgk0k0j9k0j9j9j9j9j9j9jVj9jVjVk0jVk0k0k0k0k0k0j9k0j9j9kgj9kgkgj9kgj9j9k0j9k0k0kgk0kgkgj9kgj9j9k0j9k0k0jVk0jVjVk0jVk0k0kgk0kgkgk0kgk0k0j9k0j9j9ok", +"jf.q.2jf.2.U.q.2.q.Ujf.Ujf.q.U.2jf.q.2jf.2.U.q.2.q.Ujf.Ujf.q.U.2jf.q.2jf.2.U.q.2.q.Ujf.Ujf.q.U.2jf.q.2jf.2.U.q.2.q.Ujf.Ujf.q.U.2jf.q.2jf.2.U.q.2.q.Ujf.Ujf.q.U.2jf.q.2jf.2.UfQfkgugufkfQfkgggugvfXgufugugvguglglguglglglixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixopoqorosjPjPjOotououovowoxoyozoAoBi0h4h0hYibhRibixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixeBfsg3fsfsfseBfsfseBlufPg3eBeBlug3eBmlfPfPfPfPmlgIg3gIfPf4fDfDfPfPluhxomomhIhxhxgIfPgIfPfPgIfPgImsgIj9k0k0k0k0k0k0jVk0jVjVkgjVkgkgk0kgk0k0k0k0k0k0kgk0kgkgk0kgk0k0kgk0kgkgjVkgjVjVk0jVk0k0kgk0kgkgk0kgk0k0jVk0jVjVk0jVk0k0j9k0j9j9k0j9k0k0k0k0k0k0jVk0jVjVkgjVkgkgk0kgk0k0ok", +".q.U.U.U.qjf.2.Ujf.q.U.q.2.Ujf.U.q.U.U.U.qjf.2.Ujf.q.U.q.2.Ujf.U.q.U.U.U.qjf.2.Ujf.q.U.q.2.Ujf.U.q.U.U.U.qjf.2.Ujf.q.U.q.2.Ujf.U.q.U.U.U.qjf.2.Ujf.q.U.q.2.Ujf.U.q.U.U.U.qjfglgufbfkgufkfQgufkglgvgugugufkgugugugvgvhiglixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixkoiwoCnWnkjcixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixfDeBfDfPeBg3fsf4fDfPfDhxfPfPfPeBmllufPlug3mlfPfPfPfPg3gImlgIhagIhxfPhIfPfPfPluhxg3hIgIhahxhahxfPg3hIkgj9j9jVj9jVjVk0jVk0k0jVk0jVjVkgjVkgkgj9kgj9j9jVj9jVjVjVjVjVjVkgjVkgkgk0kgk0k0j9k0j9j9jVj9jVjVk0jVk0k0kgk0kgkgjVkgjVjVkgjVkgkgj9kgj9j9jVj9jVjVk0jVk0k0jVk0jVjVkgjVkgkgok", +"jf.qjfjf.U.Ujf.2jf.2jfjf.Ujf.q.2jf.qjfjf.U.Ujf.2jf.2jfjf.Ujf.q.2jf.qjfjf.U.Ujf.2jf.2jfjf.Ujf.q.2jf.qjfjf.U.Ujf.2jf.2jfjf.Ujf.q.2jf.qjfjf.U.Ujf.2jf.2jfjf.Ujf.q.2jf.qjfjf.U.UgWgvfkfkfbfkfkfufkfQgvgggvfXgRgufkgugugugvglixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixmlfsfDkdfslufPfPeBfsf4fseBfsfPfsfPfPlumlmlfPigfPfPfPfPeBfPfPlufPfPfPfDfPfPfPfPhxgIomfPmlhxgIfPgIfPhxk0jVjVk0jVk0k0j9k0j9j9jVj9jVjVk0jVk0k0j9k0j9j9k0j9k0k0k0k0k0k0jVk0jVjVjVjVjVjVk0jVk0k0j9k0j9j9k0j9k0k0jVk0jVjVk0jVk0k0k0k0k0k0jVk0jVjVk0jVk0k0j9k0j9j9jVj9jVjVk0jVk0k0ok", +"jf.U.q.qjf.q.Ujf.2.qjf.U.2jf.Ujfjf.U.q.qjf.q.Ujf.2.qjf.U.2jf.Ujfjf.U.q.qjf.q.Ujf.2.qjf.U.2jf.Ujfjf.U.q.qjf.q.Ujf.2.qjf.U.2jf.Ujfjf.U.q.qjf.q.Ujf.2.qjf.U.2jf.Ujfjf.U.q.qjf.qfufkfkfkfkglglfQgufkfQfufQgvgvgvgugugvgugufQixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixbPfsbPayfsmleBfDfDg3fPfsfDmlfDfPfPeBfPfPfPfPg3mlfPigfPfPfPfPeBfPmlmlfPighIhagIfPfPfPfPg3fPhIfPhIhxhxjVjVjVkgjVkgkgjVkgjVjVk0jVk0k0kgk0kgkgjVkgjVjVj9jVj9j9jVj9jVjVkgjVkgkgj9kgj9j9jVj9jVjVj9jVj9j9jVj9jVjVj9jVj9j9kgj9kgkgjVkgjVjVjVjVjVjVkgjVkgkgjVkgjVjVk0jVk0k0kgk0kgkgok", +".2jf.Ujf.2jfjfjf.Ujf.qjfjf.qjf.q.2jf.Ujf.2jfjfjf.Ujf.qjfjf.qjf.q.2jf.Ujf.2jfjfjf.Ujf.qjfjf.qjf.q.2jf.Ujf.2jfjfjf.Ujf.qjfjf.qjf.q.2jf.Ujf.2jfjfjf.Ujf.qjfjf.qjf.q.2jf.Ujf.2jffufkfkfbfkfkfkfkfuggfkgvfkgugvfkgvfkgufXgggvixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixfDfsfDfsmlaylufseBfDg3fDfsfsfsfsfsfPeBfPfPg3eBfPlufPlufPfDfDfDfPfPfPfPmlmlf4gIfPfPhxfPhxgImlfPhIhImlj9k0k0jVk0jVjVj9jVj9j9jVj9jVjVjVjVjVjVkgjVkgkgjVkgjVjVk0jVk0k0jVk0jVjVk0jVk0k0j9k0j9j9j9j9j9j9jVj9jVjVk0jVk0k0jVk0jVjVj9jVj9j9k0j9k0k0jVk0jVjVj9jVj9j9jVj9jVjVjVjVjVjVok", +".qjfjfjf.U.q.U.qjfjf.2.Ujf.qjf.U.qjfjfjf.U.q.U.qjfjf.2.Ujf.qjf.U.qjfjfjf.U.q.U.qjfjf.2.Ujf.qjf.U.qjfjfjf.U.q.U.qjfjf.2.Ujf.qjf.U.qjfjfjf.U.q.U.qjfjf.2.Ujf.qjf.U.qjfjfjf.U.qfQfkfufufkfkfkfkfkfQfkfQfQfkfkgugufkfkgvfkoDixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixfsfDeBfDg3fDfsbPfsfsfsf4fDfDfDfPf4fPf4fPmlfPfPfPg3fPfPmlfPfPfPigfPeBfPfPfPfPg3fPitighahxhxhxhxhxmlfPjVj9j9jVj9jVjVkgjVkgkgjVkgjVjVjVjVjVjVj9jVj9j9j9j9j9j9j9j9j9j9jVj9jVjVjVjVjVjVjVjVjVjVjVjVjVjVkgjVkgkgj9kgj9j9jVj9jVjVjVjVjVjVj9jVj9j9jVj9jVjVkgjVkgkgjVkgjVjVjVjVjVjVok", +"jf.qjf.qjfjfjfjfjf.Ujfjf.qjf.qjfjf.qjf.qjfjfjfjfjf.Ujfjf.qjf.qjfjf.qjf.qjfjfjfjfjf.Ujfjf.qjf.qjfjf.qjf.qjfjfjfjfjf.Ujfjf.qjf.qjfjf.qjf.qjfjfjfjfjf.Ujfjf.qjf.qjfjf.qjf.qjfjffbgWfkfQfkfufufkfkfufkfkfufkfXfboEoFoGoHjmlXixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixfsbPfsfsk#fDbPfsg3fslumllufDfDfDfDfDfPf4fsfsfDfseBfPfPfPg3lufPlulufPfPfPfPfPmlgIfPfPgIfPgIeBgIfPfPhxkgjVjVkgjVkgkgjVkgjVjVj9jVj9j9k0j9k0k0jVk0jVjVjVjVjVjVjVjVjVjVj9jVj9j9k0j9k0k0jVk0jVjVk0jVk0k0jVk0jVjVjVjVjVjVjVjVjVjVkgjVkgkgjVkgjVjVkgjVkgkgjVkgjVjVj9jVj9j9k0j9k0k0ok", +"jf.qjfjfjfjf.q.qjfjf.qjf.2jf.qjfjf.qjfjfjfjf.q.qjfjf.qjf.2jf.qjfjf.qjfjfjfjf.q.qjfjf.qjf.2jf.qjfjf.qjfjfjfjf.q.qjfjf.qjf.2jf.qjfjf.qjfjfjfjf.q.qjfjf.qjf.2jf.qjfjf.qjfjfjfjffbfkfbgWe2fkf5gufWfkfkoIoJoKoLoMkoixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixfs.UfsbPfsfsfsfseBfDfseBmcfsbPf4fDfDlufDg3fPg3mlmlfPfPfPfPlufsfPmlmlfPfPighagIfPfPfPfPfPfPgIgIhIhxhxjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVj9jVj9j9jVj9jVjVj9jVj9j9j9j9j9j9jVj9jVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVj9jVj9j9jVj9jVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVj9jVj9j9ok", +"jfjfjfjf.qjfjfjfjf.qjfjfjf.qjfjfjfjfjfjf.qjfjfjfjf.qjfjfjf.qjfjfjfjfjfjf.qjfjfjfjf.qjfjfjf.qjfjfjfjfjfjf.qjfjfjfjf.qjfjfjf.qjfjfjfjfjfjf.qjfjfjfjf.qjfjfjf.qjfjfjfjfjfjf.qjffufufufbfbfkoNoOoPjnoQixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixfDfsfsfsayfsbPfsfDfsfDlug3eBfsbPmclufsfDfDfDfsfPfsmlfDlumlfDfPfDfDfPfPmlmlfPfDhIfPfPfPfDfPfPfPfPfPitjVj9j9jVj9jVjVjVjVjVjVj9jVj9j9jVj9jVjVjVjVjVjVjVjVjVjVj9jVj9j9jVj9jVjVj9jVj9j9jVj9jVjVj9jVj9j9j9j9j9j9jVj9jVjVj9jVj9j9jVj9jVjVj9jVj9j9jVj9jVjVjVjVjVjVj9jVj9j9jVj9jVjVok", +".qjfjfjfjfjfjf.qjfjfjfjfjfi4jf.q.qjfjfjfjfjfjf.qjfjfjfjfjfi4jf.q.qjfjfjfjfjfjf.qjfjfjfjfjfi4jf.q.qjfjfjfjfjfjf.qjfjfjfjfjfi4jf.q.qjfjfjfjfjfjf.qjfjfjfjfjfi4jf.q.qjfjfjfjfjfe2fuoRoSoToUkoixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixbPeBfseBfDlufsfseBfsfsfDfseBeBfsfseBlulufPfDfDfDfDg3fPfslufPmlfPfPfPlufPfPeBmlfPfPgIhIfDfPfPfPmlfPgIjVjVjVj9jVj9j9jVj9jVjVjVjVjVjVjSjVjSjSjVjSjVjVj9jVj9j9jVj9jVjVjVjVjVjVjVjVjVjVjVjVjVjVjSjVjSjSjVjSjVjVjVjVjVjVj9jVj9j9jVj9jVjVjVjVjVjVj9jVj9j9jVj9jVjVjVjVjVjVjSjVjSjSok", +"jfjfjf.qjfjfd2jfi4jf.qjfjfjfjfjfjfjfjf.qjfjfd2jfi4jf.qjfjfjfjfjfjfjfjf.qjfjfd2jfi4jf.qjfjfjfjfjfjfjfjf.qjfjfd2jfi4jf.qjfjfjfjfjfjfjfjf.qjfjfd2jfi4jf.qjfjfjfjfjfjfjfjf.qoVoWoXoMixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixfsfsfsfsfsfsfDluayayfsbPf4eBfDeBmleBfDfseBlufPfsfDfDfDfsfDg3f4eBfsf4fPfDfDfsfPeBmlfPfPfPg#iggIgIfDfPjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjLjVjLjLjVjLjVjVjVjVjVjVj9jVj9j9jVj9jVjVj9jVj9j9jVj9jVjVjLjVjLjLjVjLjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVok", +"iYjfjfjfi4jfjfjfjfjfjfjfjf.qjfi4iYjfjfjfi4jfjfjfjfjfjfjfjf.qjfi4iYjfjfjfi4jfjfjfjfjfjfjfjf.qjfi4iYjfjfjfi4jfjfjfjfjfjfjfjf.qjfi4iYjfjfjfi4jfjfjfjfjfjfjfjf.qjfi4oYoZo0o1ixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixkso2o3ayfsfsfsfDfDfseBfsfsfsf4fsfsfseBfDfsg3f4fsmllumlfDfDmlfDfPgImlfPmlhxhxfPfPfPg3fPfPfPigfPigigfPjLjVjVjLjVjLjLjVjLjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVj9jVj9j9jVj9jVjVjVjVjVjVjLjVjLjLjVjLjVjVjVjVjVjVjVjVjVjVjLjVjLjLjVjLjVjVjLjVjLjLjVjLjVjVjVjVjVjVjVjVjVjVok", +"jfjfjfjfjfjfjfjfi4jfjfi4jfjfjfjfjfjfjfjfjfjfjfjfi4jfjfi4jfjfjfjfjfjfjfjfjfjfjfjfi4jfjfi4jfjfjfjfjfjfjfjfjfjfjfjfi4jfjfi4jfjfjfjfjfjfjfjfjfjfjfjfi4jfjfi4kuo4o5oQixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixlKo6o7o2o8fs.2mcfsfsfDlufsfsfsb1fsfsfsfDlueBfsfslulufPfDf4fDfPfsg3g3mlmlhxmlfPfPlufPfPeBmlmlmlfPjVjVjVjVjVjVjVjVjVjVjVjLjVjLjLjVjLjVjVjVjVjVjVjLjVjLjLjVjLjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjLjVjLjLjVjLjVjVok", +"jfi4jfjfi4jfjfjfjfjfjfjfjfjfi4jfjfi4jfjfi4jfjfjfjfjfjfjfjfjfi4jfjfi4jfjfi4jfjfjfjfjfjfjfjfjfi4jfjfi4jfjfi4jfjfjfjfjfjfjfjfjfi4jfjfi4jfjfi4jfjfjfjfoVo9p.p#ixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixlKpapbpcpdfsfsfDfseBeBfseBbPfsfsfsfDfDmlg3fPg3eBg3lumlfDfDfsfPfPmlmlfPg3hxhxigfPhxfPfPg#jVjLjLjVjLjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjVjLjVjLjLjVjLjVjVjVjVjVjVjvjVjvjvjVjvjVjVjVjVjVjVjVjVjVjVjvjVjvjvjVjvjVjVjLjVjLjLjVjLjVjVjVjVjVjVjVjVjVjVjVjVjVjVok", +"i4jfi4jfjfi4jfhYjfjfhYi4jfi4jfjfi4jfi4jfjfi4jfhYjfjfhYi4jfi4jfjfi4jfi4jfjfi4jfhYjfjfhYi4jfi4jfjfi4jfi4jfjfi4jfhYjfjfhYi4jfi4jfjfi4jfi4jfjfj2pepfpgixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixl.obphpifsfDfsf4eBeBfsfseBfsfDfsfDf4fPg3g3fslueBlufPfPfDf4fPfsmlfPfPluhxfPfPg3f4jVj4j4jVj4jVjVjLjVjLjLjLjLjLjLjVjLjVjVjvjVjvjvjVjvjVjVjVjVjVjVjvjVjvjvjVjvjVjVjLjVjLjLjVjLjVjVjvjVjvjvjVjvjVjVjVjVjVjVjVjVjVjVj4jVj4j4jVj4jVjVjLjVjLjLjLjLjLjLjVjLjVjVpj", +"jfjfjfi4i4jfiYjfi4jfjfiYjfiYjfi4jfjfjfi4i4jfiYjfi4jfjfiYjfiYjfi4jfjfjfi4i4jfiYjfi4jfjfiYjfiYjfi4jfjfjfi4i4jfiYjfi4jfjfiYjfiYjfi4jfjfpkplohiwixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixnrpmo#pnfsfseBf4luf4eBfseBfDfsmllufDf4fsg3lumlfDfPfDfPfDfPfPfDfsg3fPfPfPjVjvjvjVjvjVjVj4jVj4j4jVj4jVjVjLjVjLjLj4jLj4j4jLj4jLjLjVjLjVjVjVjVjVjVjLjVjLjLjVjLjVjVjLjVjLjLjVjLjVjVj4jVj4j4jLj4jLjLjVjLjVjVjvjVjvjvjVjvjVjVj4jVj4j4jVj4jVjVjLjVjLjLpj", +"hYi4iYhYjfjfi4jfi4jfhYjfhYi4jfjfhYi4iYhYjfjfi4jfi4jfhYjfhYi4jfjfhYi4iYhYjfjfi4jfi4jfhYjfhYi4jfjfhYi4iYhYjfjfi4jfi4jfhYjfhYi4jfpopppqprixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixlKjIpsm8fsfDfsmlfsg3fsfsfsfsfsfDfsfPmlmlfPfPfPhxfDmlfPg3fPg3g3g#fPjLjVjVjVjVjVjVjvjVjvjvj4jvj4j4jVj4jVjVjVjVjVjVjVjVjVjVjVjVjVjVj4jVj4j4jvj4jvjvjVjvjVjVj4jVj4j4jVj4jVjVjvjVjvjvjVjvjVjVjLjVjLjLjVjLjVjVjVjVjVjVjvjVjvjvj4jvj4j4jVj4jVjVok", +"i4jfjfjfi4hYjfjfhYiYjfi4iYjfhYjfi4jfjfjfi4hYjfjfhYiYjfi4iYjfhYjfi4jfjfjfi4hYjfjfhYiYjfi4iYjfhYjfi4jfjfjfi4hYjfjfhYiYjfi4ptovpuiwixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixllpvnUpweBfsfPeBfDeBg3fPfDhxeBfDfPmllumlfPfDhxfPfDgIf4mlfPj4jLjLjvjLjvjvjVjvjVjVjvjVjvjvjVjvjVjVjLjVjLjLjvjLjvjvjvjvjvjvjVjvjVjVjVjVjVjVjLjVjLjLjvjLjvjvjVjvjVjVj4jVj4j4jvj4jvjvj4jvj4j4jLj4jLjLjvjLjvjvjVjvjVjVjvjVjvjvjVjvjVjVpj", +"hYiYhYhYjfjfhYiYhYjfhYhYjfhYiYjfhYiYhYhYjfjfhYiYhYjfhYhYjfhYiYjfhYiYhYhYjfjfhYiYhYjfhYhYjfhYiYjfhYiYhYhYjfjfhYiYhYjfowpxllixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixpyiKjmpzpAoHpBpCpDpEpFpGpHpIpJpKpLpMpNpNpOpPpQpRpSpTpUpVpQpNpKpWoSpXpYpZp0p1p2p3oCktixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixktmxphp4eBf4fsf4eBf4fDfsfDmleBfPf4luf4fsmlfDfsfDfDfPjVjvjvjVjvjVjVj4jVj4j4jvj4jvjvjVjvjVjVjLjVjLjLjVjLjVjVjVjVjVjVjvjVjvjvjvjvjvjvjVjvjVjVjLjVjLjLjVjLjVjVjvjVjvjvjVjvjVjVjVjVjVjVjvjVjvjvjVjvjVjVj4jVj4j4jvj4jvjvjVjvjVjVpj", +"hYjfi4iYhYi4jfhYjfi4hYjfiYhYjfhYhYjfi4iYhYi4jfhYjfi4hYjfiYhYjfhYhYjfi4iYhYi4jfhYjfi4hYjfiYhYjfhYhYjfi4iYhYi4jfhYp5p6ixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixlXp7pzp1pDp8p9q.q#qaqbfbfkgWgWfuftfkfXfufkfkfufkfkfkfkfufkfkfkfQfkfQfQgvfQgvfXgugugugugvgugvglguglglguguoDiDqcqdqeqfpzqgixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixlBqhnzeBfsfsf4g3g3eBfPeBfDmlfDf4f4fPfsfPfPfPjvjvjvjVjvjVjVjvjVjvjvjVjvjVjVj4jVj4j4jvj4jvjvjLjvjLjLjvjLjvjvj4jvj4j4jLj4jLjLjvjLjvjvj4jvj4j4jvj4jvjvjLjvjLjLj4jLj4j4jvj4jvjvjvjvjvjvjVjvjVjVjvjVjvjvjVjvjVjVj4jVj4j4pj", +"jfhYjfhYiYhYhYhYjfhYiYhYhYi4hYiYjfhYjfhYiYhYhYhYjfhYiYhYhYi4hYiYjfhYjfhYiYhYhYhYjfhYiYhYhYi4hYiYjfhYjfhYiYhYhYhYjfozpxp#ixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixmPqiqfqjp9pSqkfbeTe2e2fbf6e2e2fufbfbfbfbfufbfkftfte2fbfkfufbfufQfufkfkfkfkfufQfkfkfufufQfkgvfQgvfXgvgugugufkgugugufQfXglgugugRgufkgvgvqlpMqmqnqomNixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixmbm0qpqqfsfsfsg3fsfsfPfsfPf4f4f4mlmlfsj4jVjVjvjVjvjvjLjvjLjLjvjLjvjvjvjvjvjvjVjvjVjVjvjVjvjvjVjvjVjVjvjVjvjvjVjvjVjVj4jVj4j4jLj4jLjLjvjLjvjvjVjvjVjVjvjVjvjvj4jvj4j4jVj4jVjVjvjVjvjvjLjvjLjLjvjLjvjvjvjvjvjvok", +"iYhYhYhYjfi4jfiYhYhYiYjfhYiYhYjfiYhYhYhYjfi4jfiYhYhYiYjfhYiYhYjfiYhYhYhYjfi4jfiYhYhYiYjfhYiYhYjfiYhYhYhYjfi4jfiYhYhYiYqriviKixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixnMqsqtquqvqwfbfbfbeTdmeoeTfbeLeTfufue2fbfbeLgWfkfke2fbfbfbfufufkfufkfbfufXfkfugafQfkgWfkfkfkfQfQfugufufkfkfkgvgvgvfQfkguguguggglfkgvgggugugvguguguglgvfQglhhgvqxqyqzqAnMixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixldohqBmKf4f4fsg3fslufPfPfPfPf4f4jvj4j4jvj4jvjvj4jvj4j4jvj4jvjvjvjvjvjvjLjvjLjLj4jLj4j4jLj4jLjLjvjLjvjvjvjvjvjvjvjvjvjvjvjvjvjvj4jvj4j4j4j4j4j4jvj4jvjvjvjvjvjvj4jvj4j4jvj4jvjvj4jvj4j4jvj4jvjvjvjvjvjvpj", +"hYiYhYiYhYhYhYhYhYjfhYhYi4hYiYhYhYiYhYiYhYhYhYhYhYjfhYhYi4hYiYhYhYiYhYiYhYhYhYhYhYjfhYhYi4hYiYhYhYiYhYiYhYhYhYhYhYjfhYhYi4j5qCkRixixixixixixixixixixixixixixixixixixixixixixixixixixqDqEqFqGgadmeLdmeLdmdmd3dmeLeLfbeTeoeLeLeTeLeLfbeLfbfbe2fbeLeLfkeTfbfbfbe2fbfkfke1fkfbfbfbfkfkfQfkfkftfkfbfXfQfkfufQfugvgvfQfQgufQgufkgufkfkggfkfQglfXguguguguguglgvgQgvgug4guhiqHoGqIqgixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixqJqKqLqMf4g3g3g3fDfPfseBfPjVjvjvj4jvj4j4jvj4jvjvjLjvjLjLjVjLjVjVjvjVjvjvjvjvjvjvjvjvjvjvj4jvj4j4jVj4jVjVjLjVjLjLjVjLjVjVjvjVjvjvjvjvjvjvjvjvjvjvjVjvjVjVjvjVjvjvj4jvj4j4jvj4jvjvjLjvjLjLjVjLjVjVpj", +"hYiYhYhYi4hYiYiYhYhYi4hYiYhYi4hYhYiYhYhYi4hYiYiYhYhYi4hYiYhYi4hYhYiYhYhYi4hYiYiYhYhYi4hYiYhYi4hYhYiYhYhYi4hYiYiYhYhYi4hYiYhYi4hYqNqOkoixixixixixixixixixixixixixixixixixixixoQqPqQqRd3c3dmeLdmeLeLeTdmeLeod3dmeTdmeLeLfbe2eTfbeLeLfbfueLfue2e2fbe2eLe2fte2eTfbfufkfbfbfkfkeLfbfkfbfkfufkfufkfufkfkfkfufQfXfugvfQgvfkfXgufXfQfXfkgugufkglfQfXfQglgugufkguggglglgvgvhhgugVg4glqSqmoLllixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixk4kOqTqMf4g3g3g3fPlujvjvjvjvjvjvjvjvjvjvjvjvjvjvjvj4jvj4j4jvj4jvjvj4jvj4j4jLj4jLjLjvjLjvjvjvjvjvjvjvjvjvjvjvjvjvjvjvjvjvjvjLjvjLjLjvjLjvjvjvjvjvjvjvjvjvjvjvjvjvjvjvjvjvjvjvjvjvjvj4jvj4j4pj", +"hYhYhYhYiYhYhYhYhYiYhYhYhYiYhYhYhYhYhYhYiYhYhYhYhYiYhYhYhYiYhYhYhYhYhYhYiYhYhYhYhYiYhYhYhYiYhYhYhYhYhYhYiYhYhYhYhYiYhYhYhYiYhYhYhYhYqUqVioixixixixixixixixixixixixixixoUqWqXdzdzdzdmdmc3bEdmd3dmdzeLeLdmdmeLdmdmdmeTeLe2eLfbe2eTeoeLeoeLeTeLfufufufbfbe2eLfkfbeLfbfcfbfbfbfkfufufuftfXfbfkfkfbfkfkgWfkfufQfQfugugufufugvfQgvfXfQgufkgufkggglfkfkfQggfQgugugufkglgvgvgugvglguguguguglqYpZqZq0ixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixk4kOnZq1f4f4eBjvjLjLjvjLjvjvjLjvjLjLj4jLj4j4jvj4jvjvjvjvjvjvjvjvjvjvj4jvj4j4jvj4jvjvj4jvj4j4jvj4jvjvj4jvj4j4jLj4jLjLjvjLjvjvj4jvj4j4jvj4jvjvjLjvjLjLjvjLjvjvjLjvjLjLj4jLj4j4jvj4jvjvpj", +"iYhYh0hYhYi4hYiYhYhYhYhYi4h0hYiYiYhYh0hYhYi4hYiYhYhYhYhYi4h0hYiYiYhYh0hYhYi4hYiYhYhYhYhYi4h0hYiYiYhYh0hYhYi4hYiYhYhYhYhYi4h0hYiYiYhYh0hYq2q3oCixixixixixixixixixjCq4q5hYhYi4dzcqdzd3dmdmeLdmc3dmeodmdmd3dmeLeLdmdmdmd3c3eodme2fbfbeLfceoeLeLeLfbfufue2eTfufbftfbfkeLeLfbfbfufugWfbfbeLfufkfbfbfbgafufkfkftfkfQfbfufXfufkgufkgvgvgvfQfQgufkfkfQfkfkfQfXguhhfQguguguglglfkgvgQgvgugugRglglglq6q7oHmPixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixktq8q9r.jvjvjvj4jvj4j4jvj4jvjvjvjvjvjvi2jvi2i2jvi2jvjvj4jvj4j4jvj4jvjvjvjvjvjvjvjvjvjvjvjvjvjvi2jvi2i2jvi2jvjvjvjvjvjvjLjvjLjLjvjLjvjvjvjvjvjvj4jvj4j4jvj4jvjvjvjvjvjvi2jvi2i2pj", +"hYhYhYiYi4hYh0hYh0hYiYhYh0hYhYhYhYhYhYiYi4hYh0hYh0hYiYhYh0hYhYhYhYhYhYiYi4hYh0hYh0hYiYhYh0hYhYhYhYhYhYiYi4hYh0hYh0hYiYhYh0hYhYhYhYhYhYiYi4hYjDr#raixixixixprm0rbhYhYhYiYi4hYbEdmbEdzc3bEd3dmdzdmbEdzc3dmdmdmeLdmdmeLeTc3dmd3dmdmeLeLfbe2eTfbdmfbeLeLeTfbfbe2fue2e2e2fue2fkeLfbfbfbfufkftfufbfufbfbfkfbfbfkfuflgvfufQfQfkfXfugugvfkfkgvfXfQfQgvgufkgggugufQfXhifXgugugufkglglgvglgugvhhgugugvglgViNrcrdiJixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixqJrerfrgjvjLjvjvjvjvjvjvjvjvjvjvjvjvjvjvjvjvjvjvjvjvjvjvi2jvi2i2i2i2i2i2jvi2jvjvj4jvj4j4jvj4jvjvj4jvj4j4jvj4jvjvi2jvi2i2jvi2jvjvjLjvjLjLjvjLjvjvjvjvjvjvjvjvjvjvjvjvjvjvpj", +"h0hYhYh0h0hYhYhYhYh0hYhYhYiYhYh0h0hYhYh0h0hYhYhYhYh0hYhYhYiYhYh0h0hYhYh0h0hYhYhYhYh0hYhYhYiYhYh0h0hYhYh0h0hYhYhYhYh0hYhYhYiYhYh0h0hYhYh0h0hYhYhYhYrhrirjrkrlhYh0h0hYhYh0h0hYcqdmdmbEdzc3d3dzbEdzdzdmdmc3dmd3c3dmdmeLeLeLdmeLc3dmdmeLeLdmfYeLfbe2fbeLeLeLeLeTeLfbfbe2fbe2e2eLfueLeLfbfkfkfbfbftfufufufufbfbfufkfufuflfkfkfXfXfkfQgugvfQfkfkfQgufQfQgvfkgufkgggugugufXgufQfQgQguglglgvgvgugRgRglhnhYh0hYh0rml#jFixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixk6rnrorpi2i2i2i2i2jvi2jvjvjvjvjvjvi2jvi2i2jvi2jvjvjvjvjvjvj4jvj4j4jvj4jvjvjvjvjvjvi2jvi2i2i2i2i2i2jvi2jvjvjvjvjvjvi2jvi2i2jvi2jvjvi2jvi2i2i2i2i2i2jvi2jvjvjvjvjvjvpj", +"hYhYhYhYhYhYh0hYh0hYh0h0hYh0hYhYhYhYhYhYhYhYh0hYh0hYh0h0hYh0hYhYhYhYhYhYhYhYh0hYh0hYh0h0hYh0hYhYhYhYhYhYhYhYh0hYh0hYh0h0hYh0hYhYhYhYhYhYhYhYh0hYh0hYh0h0hYh0hYhYhYhYhYhYhYhYbEcqcqbEdmdmdzbEdzc3bEd3dmdmeLdmbEbEcqdzd3dmeLeLdmeLc3dmd3eLdmdmdmeLdmeoe2fbeLeLeLeLfbfue2e2fufbeLeLeLfbfbeLfbfbfbfkftfueLe1fufbfkfkfkfkfufufkflfufQfkfXfufugugvflfQfQfufXfQfkgufkgufkfkfXfQhigufkgufQfkglglgvgvgvhyhDhDh0hYhYhRh4rmrqnrixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixmPrrrsjvjvjvi2jvi2i2jvi2jvjvjvjvjvjvi2jvi2i2jvi2jvjvjvjvjvjvjvjvjvjvjvjvjvjvjvjvjvjvjvjvjvjvi2jvi2i2jvi2jvjvjvjvjvjvjvjvjvjvjvjvjvjvjvjvjvjvi2jvi2i2jvi2jvjvpj", +"hYh0hYhYh0hYhYhYh0hYhYhYhYhYh0h0hYh0hYhYh0hYhYhYh0hYhYhYhYhYh0h0hYh0hYhYh0hYhYhYh0hYhYhYhYhYh0h0hYh0hYhYh0hYhYhYh0hYhYhYhYhYh0h0hYh0hYhYh0hYhYhYh0hYhYhYhYhYh0h0hYh0hYhYh0hYdzdzdzcqcqeudmdmbEbEeSbEd3d3dmdzdmdmdmdmcqd3dmeLdmeLfbdmdmdmc3dmeLeLeLdmeLeoeTeTeLeoe2eLeLeLdmfufbfbfbfbe2eLeLfvfcfbfbfbfbfbftfufufvfXgafkfbfkfkf6flfkfXfXfXfkgufufkfQgvfQfXfQfQfkgugugPfkfQgufQfQgugugugufkglglgvhnh0h4iSiSh0hDh0hYhYj5rtruprixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixrvrwrxjvjvjvjvjvjvjvjvjvjvjvjvjvjvjvjvi2jvi2i2jvi2jvjvjvjvjvjvisjvisisjvisjvjvjvjvjvjvjvjvjvjvi2jvi2i2jvi2jvjvi2jvi2i2jvi2jvjvjvjvjvjvjvjvjvjvjvjvjvjvpj", +"h0hYh0hYhYh0hYhDhYh0hDh0hYh0hYhYh0hYh0hYhYh0hYhDhYh0hDh0hYh0hYhYh0hYh0hYhYh0hYhDhYh0hDh0hYh0hYhYh0hYh0hYhYh0hYhDhYh0hDh0hYh0hYhYh0hYh0hYhYh0hYhDhYh0hDh0hYh0hYhYh0hYh0hYhYh0dzbrdzbrdzdzcqcqbEdmbEdzc3dzdzd3bEdzdmdmdmdmbEc3d3dmdzdmdmdmdmdmc3dmeLd3eLeLeLfce2eTeoeLe2eLeLeLeLfbe2e2eTfbeLftfbeLfbfcfbfbfbfbftfue1fbfkfQfkfkfbfkflgWflfufXfXfkfkfufkfQggfQfkfXfQgvfkgufkfkgggugvfQfQgvgugufQfkhDh4h4h0ibiSiSh0hDhYh7hYhYryrzrAixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixrBrCrDi2jvi2jvjvisjvisisjvisjvjvi2jvi2i2isi2isisjvisjvjvi2jvi2i2jvi2jvjvi2jvi2i2jvi2jvjvjvjvjvjvjvjvjvjvi2jvi2i2jvi2jvjvi2jvi2i2i2i2i2i2jvi2jvjvrE", +"hYhYhYh0h0hYh0hYh0hYhYh0hYh0hYh0hYhYhYh0h0hYh0hYh0hYhYh0hYh0hYh0hYhYhYh0h0hYh0hYh0hYhYh0hYh0hYh0hYhYhYh0h0hYh0hYh0hYhYh0hYh0hYh0hYhYhYh0h0hYh0hYh0hYhYh0hYh0hYh0hYhYhYh0h0hYeucqbEbEdzdzdzcqdzcqdmcqdmbEdmdzbEc3d3d3dmdmdmdmdmc3bEc3dmdzdmdmdmeTdmdmc3eLeLdmeLfYeLfbe2eofbeLeLe2fbfueTfcfbe2fbfteLfueLfbfbfbfbfkfbfuftfufufbfXfkfufQfuflfkfufXfkfXfXfkfkfQfkgvfkfQgufQgvfXfkfkgufkfkgugugufQgugVhYhDhYh4hYhDh4h0hDhDh0h0h0hYi4rFl#mbixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixktrGrHrIi2i2i2i2i2i2i2i2i2i2jvi2jvjvjvjvjvjvi2jvi2i2jvi2jvjvi2jvi2i2jvi2jvjvi2jvi2i2i2i2i2i2jvi2jvjvisjvisisjvisjvjvi2jvi2i2jvi2jvjvi2jvi2i2pj", +"hDh0h0hDh0hYh0h0h0hYhRhYhDh0hYh0hDh0h0hDh0hYh0h0h0hYhRhYhDh0hYh0hDh0h0hDh0hYh0h0h0hYhRhYhDh0hYh0hDh0h0hDh0hYh0h0h0hYhRhYhDh0hYh0hDh0h0hDh0hYh0h0h0hYhRhYhDh0hYh0hDh0h0hDh0hYbrdHcqbEcqdzdzdzdzbEeucqd3bEdmdmdmbEcqbEbEbEbEdmdzdzdmc3d3cqd3dmdmdmfbdmeLc3c3c3dmdmeLdmdmdme2e2fbeLeoeLeLeLfcfcfue2eTfteLeLeLfbfbfbfbe2fuftftftfufbe2fbfufkfufufue2flfbfQfkfkfkguflfufkfXfkfXfXfXfkgufkfQgugvguhigVhDhDhnhYhRh0h7h4h0hDh4hDhYhYhDh4hYrJrKp.q0ixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixldrLrMjvjvjvjvi2jvi2i2jvi2jvjvi2jvi2i2isi2isisjvisjvjvi2jvi2i2jvi2jvjvisjvisisjvisjvjvi2jvi2i2jvi2jvjvjvjvjvjvisjvisisi2isi2i2jvi2jvjvpj", +"h0hYhYhYh0hDhYhYhDh0hYh0h0hYhRhYh0hYhYhYh0hDhYhYhDh0hYh0h0hYhRhYh0hYhYhYh0hDhYhYhDh0hYh0h0hYhRhYh0hYhYhYh0hDhYhYhDh0hYh0h0hYhRhYh0hYhYhYh0hDhYhYhDh0hYh0h0hYhRhYh0hYhYhYh0hDbEbrdIcqcqcqcqeubrdzbEdzcqdmcqbEcqdmbEbEdmbEcqd3bEdmdzdmdmdmbEdmc3d3dzdzdmeLeTdmc3c3dmc3d3eLdmfYeTe2dmeofbeLe2eLfceTfbfue2fbeLeTeLfbe2fbfbfkfkfbfte1fufufbfXfkfbfkfufbflgvflflfXfkfkgufQgvgvfQfufQfXguguguguguggguhnhDh4hDhRhRhDhYhRh4h4hRh4h0iShDh0hDhYhYhYkYrNrOixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixmgrPi2i2isi2isisiUisiUiUi2iUi2i2jvi2jvjvi2jvi2i2isi2isisjvisjvjvi2jvi2i2isi2isisi2isi2i2i2i2i2i2iUi2iUiUjviUjvjvisjvisisi2isi2i2pj", +"hDh0hDhDhYhYhDh0hDhYhDhDhYhDh0hYhDh0hDhDhYhYhDh0hDhYhDhDhYhDh0hYhDh0hDhDhYhYhDh0hDhYhDhDhYhDh0hYhDh0hDhDhYhYhDh0hDhYhDhDhYhDh0hYhDh0hDhDhYhYhDh0hDhYhDhDhYhDh0hYhDh0hDhDhYhY#9brbEdzrQdVbE#9bEcqbrdzdzbrdzcqdIcqbEcqbEbEdzbEbEc3d3bEdzdmdmdmbEdmcqc3dzeLeLdmeLeTdmc3dmd3eLdmdmfYdmeTdmc3dmeLeLe2fbdmfbeLfbe2eLfbe2fue2eLfbfbfufkfbe1fue2fufbfufbfkfkfbe2fkftfQfkfufkfQfufQgvfbfkfkgugufkgufufQgVhDhDhDgVhDhDhZhDh0hRhnh4h4hDh4h0h0h0h0hRh0hYrRl6oUixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixl.rSrTrUi2i2jvi2jvjvjvjvjvjvisjvisisisisisisjvisjvjvi2jvi2i2jvi2jvjviUjviUiUjviUjvjvjvjvjvjvisjvisisjvisjvjvi2jvi2i2iUi2iUiUjviUjvjvpj", +"hRhYh0h0hRh0hYhRhYh0hRhYh0hDhYhDhRhYh0h0hRh0hYhRhYh0hRhYh0hDhYhDhRhYh0h0hRh0hYhRhYh0hRhYh0hDhYhDhRhYh0h0hRh0hYhRhYh0hRhYh0hDhYhDhRhYh0h0hRh0hYhRhYh0hRhYh0hDhYhDhRhYh0h0hRh0azdHazazbrbEbEbEbrdIcqbEcqbEbrdzbrdzbEcqcqdmdmdmc3bEcqdzcqdzd3dmdmdmbEc3c3cqcqdmd3eLeLdmeTdmdmc3dmeLeLdmfYeLfceTe2eLe2eLeLfbfbfYe2fYe2ftfueLfteLfbfufbfbfkfbfufufbfufbfbfkfkfkfkgvfbfbfXfQfufXfkgvfQfkflfufQfQfkguglhRhDhRhDhDh4gVh4hDhDhDhYhYhYhRh4h0i4h0h0h0hYh7hYh4rVpqk4ixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixkorWrXrYi2isi2isisi2isi2i2iUi2iUiUi2iUi2i2i2i2i2i2isi2isisi2isi2i2isi2isisi2isi2i2i2i2i2i2isi2isisiUisiUiUi2iUi2i2isi2isisjvisjvjvi2jvi2i2rE", +"h0hDhYhDh0hDhDhRhYhDh0hRhDh0hRh0h0hDhYhDh0hDhDhRhYhDh0hRhDh0hRh0h0hDhYhDh0hDhDhRhYhDh0hRhDh0hRh0h0hDhYhDh0hDhDhRhYhDh0hRhDh0hRh0h0hDhYhDh0hDhDhRhYhDh0hRhDh0hRh0h0hDhYhDh0hD#9dHdHbrdHazazrQbrbEbEbEdHbEbEbrbrdzdzbrdzcqbEd3d3dmbEbEdzcqd3bEdzbEdmdmdmbEc3d3d3c3eLdzdmeTdmc3dmc3c3d3eLdmdmdmeLfcdmdmeLdmeLeofbfYfbeLfbfte2eLeLfufbe2fbe2fbftfuftfue2fufbfkfufufkf6fbfXfbfufkftfkfQfufQfbfbfXfXhohbhRhbhRhDhnhDhDhDhRhDhRhRh2hDh0h4h4h4h0hDhDhDhYhYh7hYrZr0iwixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixkDr1r2isiUisisjvisjvjvisjvisisjvisjvjvisjvisisjvisjvjvi2jvi2i2i2i2i2i2isi2isisjvisjvjviUjviUiUi2iUi2i2jvi2jvjvi2jvi2i2i2i2i2i2iUi2iUiUisiUisispj", +"h0hDhDhRhYh0h0h0hDhDh0h0hDh0hDhYh0hDhDhRhYh0h0h0hDhDh0h0hDh0hDhYh0hDhDhRhYh0h0h0hDhDh0h0hDh0hDhYh0hDhDhRhYh0h0h0hDhDh0h0hDh0hDhYh0hDhDhRhYh0h0h0hDhDh0h0hDh0hDhYh0hDhDhRhYh0azbEdVrQdHdHdVdHbrbrbrbEbEdHcqcqcqcqbrbrdzdzdzdzbEcqd3dmdmbEdzcqcqbEbEdzdmdzdmdmc3dmd3cqdmeLdzdmfbeLc3dmc3c3eLeLfYfbdmdmfcc3eoe2e2eLdmfbfcfYeTfbeLfueLeLeLeTfbfbfbfuftfuftfufvfue2fbfufkfke2fkflflfQfkfufkfQfkfQfugRgVhnhnhbhDhDhDh0hDhDhDh4h4h4hRhDhDhYhYh4h4h0h0h4h0hDhYhYhYr3r4iKixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixrvrwr5i2isisisisisisi2isi2i2i2i2i2i2i2i2i2i2isi2isisiUisiUiUisiUisisisisisisi2isi2i2i2i2i2i2isi2isisisisisisi2isi2i2isi2isisi2isi2i2isi2isisisisisispj", +"hDh0hRh0hDhDhDhDhRhYhRhDh0hDh0hDhDh0hRh0hDhDhDhDhRhYhRhDh0hDh0hDhDh0hRh0hDhDhDhDhRhYhRhDh0hDh0hDhDh0hRh0hDhDhDhDhRhYhRhDh0hDh0hDhDh0hRh0hDhDhDhDhRhYhRhDh0hDh0hDhDh0hRh0hDhDaz#1azazbEdVazdVbrbrdVbrbrbrbrrQbrdVbEcqcqbrdzdzcqbrdzcqd3cqdmbEc3bEbEc3cqbEdmdmdzdmdmc3bEc3d3d3d3eLeLfbeLc3eLc3d3dmeLeodmfceLdmeLeLeLe2eLfYdmfYe2eLeTfteLfteLe2e2fbfkfbfkfte1fufbe2fufbfufkfufbfufbfbfkfQfkfkfkfkgRhyhDgVhDgVhRhRhnhRhDhRhDhnhDhDhDhDhDh4hDhRhDhRh4h4h0h0h0hYhYhDr6r7rjixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixldlcr8jlisi2isi2i2jvi2jvjvisjvisisisisisisisisisisi2isi2i2jvi2jvjvi2jvi2i2i2i2i2i2isi2isisisisisisiUisiUiUi2iUi2i2isi2isisi2isi2i2isi2isisi2isi2i2jvi2jvjvrE", +"hDh0hDhDh0hRh0h0hRhDh0hDh0hDh0hRhDh0hDhDh0hRh0h0hRhDh0hDh0hDh0hRhDh0hDhDh0hRh0h0hRhDh0hDh0hDh0hRhDh0hDhDh0hRh0h0hRhDh0hDh0hDh0hRhDh0hDhDh0hRh0h0hRhDh0hDh0hDh0hRhDh0hDhDh0hRr9dHaz#9rQazrQbEbrdHdVdHbrdVbrrQrQbEbEdIbEbEbEc3cqdzdzdzbEdzcqd3bEdmbEbEbEcqd3cqd3dmdmdmdmdmdmd3d3dmd3eLdmeLdmeLdmc3c3c3dmeLfYdme2fcdmeLeLe2eLeLeLdmfcfbeLeTfbeLfbeLfbe2e2e2fbfufbe1fufue2fufbfufbfkfbfbfufbfXfkfXglhnhnhDhRhKgVgVhnhDhnhDhRhDhYhRh4h4h4hDh4hRhDhDhYhDh4hDh0i4h0i4hYhYhYo4s.ixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixk4s#rHsaisiUisisisisisisi2isi2i2isi2isisi2isi2i2i2i2i2i2isi2isisiUisiUiUisiUisisisisisisisisisisi2isi2i2isi2isisiUisiUiUisiUisisiUisiUiUisiUisisisisisisi2isi2i2rE", +"hDhDhRhDh0hDhDhDhDh0hnhDhDh0hDhnhDhDhRhDh0hDhDhDhDh0hnhDhDh0hDhnhDhDhRhDh0hDhDhDhDh0hnhDhDh0hDhnhDhDhRhDh0hDhDhDhDh0hnhDhDh0hDhnhDhDhRhDh0hDhDhDhDh0hnhDhDh0hDhnhDhDhRhDh0hD#9#9#9azazaz#9azrQbE#9dVdH#9azdVbrbrbrbEbEdIdIcqbrbEbrdzbrbEdzdzbEbEbEdmdmbEbEcqd3bEbEdmdzdmdmdmc3c3c3dmdmdzeLeLdmdmdmc3dmdmeLeLfYfYfYdmeLdmeLeoeLeLfbdmfbeLfbeTeLfufueLdme2eLfbe2fufte1fue2fvfke2e2fbfufufbfbflftglglhnhngVgVhnhDhKhKhnhnhRhnhDhDh0hDh4hDhnh2hDhDhDhDhYhYh4h4h0hDh4h0hYh0hYsbnkixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixscsdlHi2isisi2isi2i2i2i2i2i2isi2isisiUisiUiUisiUisisi2isi2i2i.i2i.i.i2i.i2i2iUi2iUiUi2iUi2i2i2i2i2i2isi2isisi2isi2i2isi2isisi2isi2i2isi2isisi2isi2i2i2i2i2i2isi2isisse", +"h0hRhnhDhDh0hRh0hDhRhDhRh0hnhDh0h0hRhnhDhDh0hRh0hDhRhDhRh0hnhDh0h0hRhnhDhDh0hRh0hDhRhDhRh0hnhDh0h0hRhnhDhDh0hRh0hDhRhDhRh0hnhDh0h0hRhnhDhDh0hRh0hDhRhDhRh0hnhDh0h0hRhnhDhDh0#1#9#9#9azazdHr9azazazrQbE#9#9dHdHbrbrbrrQbEdzbrdIcqcqbEbEbrbEdzdzcqbEdUd3cqcqdmbEcqc3bEcqdzdmdmdmdzdmdmbEcqc3d3dzd3dmdmdmdmeMeLeLd3dmdmdmdmfYeLdmeofbeLeLfbdmfceTe2eLeTeLeLfue2e2fbfbfbfufbe1ftfvfbe2gafufkfQfufbglhKgVhngRgRhnhbhDhDhDgVhnhDgVhRhRhRh4hYhDh2h4h4hRhRhRh4hYhRhRh4h0h0h4h0hDhYhYowsfixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixsgshsiisisi2isi2i2isi2isisi.isi.i.i.i.i.i.isi.isisi2isi2i2isi2isisisisisisisisisisisisisisi.isi.i.isi.isisisisisisi2isi2i2isi2isisisisisisi2isi2i2isi2isisi.isi.i.i.i.i.i.rE", +"hDhDhDh0h0hDhnhDhnhDh0hDhnhRhDhDhDhDhDh0h0hDhnhDhnhDh0hDhnhRhDhDhDhDhDh0h0hDhnhDhnhDh0hDhnhRhDhDhDhDhDh0h0hDhnhDhnhDh0hDhnhRhDhDhDhDhDh0h0hDhnhDhnhDh0hDhnhRhDhDhDhDhDh0h0hD#9az.F#1sj#9#9skdHr9#9#9azrQazbrdVbr#9dVdHazbrrQbrbrdIdIbEbEcqcqbEcqdHdzdzbEeueubEd3bEbEcqbEcqd3bEdmdmdmdmbEdmd3c3d3eLeLd3dmeLeLc3dmd3eLeLdmdmdmfYeLc3eLdmeLe2eLfYfbeLeTfbfteTeLfue2e2e2e2fbfkfbe2fbe2fvfufkfbfufkgugRgVgVgRhngVhngVgVhnhyhnhDgRhDgVhbhZhDhDhDh0hDhRhnhDh4hDhDhDhDhRh4iSh0h0hYi4h0i4slsmixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixnrsnsoj2.qisi2i2isi2isisisisisisiUisiUiUisiUisisiUisiUiUisiUisisi.isi.i.i.i.i.i.iUi.iUiUi2iUi2i2isi2isisi2isi2i2isi2isisi.isi.i.isi.isisi2isi2i2isi2isisisisisisiUisiUiUisiUisisse", +"hnhRhDhnhnhRhDh0hRhnhDhRhDh0hRhnhnhRhDhnhnhRhDh0hRhnhDhRhDh0hRhnhnhRhDhnhnhRhDh0hRhnhDhRhDh0hRhnhnhRhDhnhnhRhDh0hRhnhDhRhDh0hRhnhnhRhDhnhnhRhDh0hRhnhDhRhDh0hRhnhnhRhDhnhnhR#1azaz#1#1#9#9#9#9#9#9r9dHazazrQazbrbrdVdVdHbrazazbrbrbrdzbEbEdHbEeucqbEdzdzbEdzcqbEbEdmdmbEcqbEcqbEd3dmdmdmdmdmbEc3c3d3eLd3dzdmeLdmeLc3c3c3eLeLdmfYfYeLfcdmdmeLe2eLeLfcfcfYeTfbeLe2fbeLfue2e2fbfkfbfbe2e1fuftfXfkfkhbgRhbgVgVgRgVhngVhbhbhnhKh4gVhDhDgVhnhRhRhDhRh0h0h4h4h4hnh4hRhDhDh0hYh4h0iSh0i4i4hYrmobixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixk6o0spmc.U.2.U.Ui.isisi.isi.i.i.i.i.i.i2i.i2i2iUi2iUiUi.iUi.i.isi.isisiUisiUiUi2iUi2i2i.i2i.i.isi.isisi.isi.i.i.i.i.i.iUi.iUiUisiUisisi.isi.i.isi.isisi.isi.i.i.i.i.i.i2i.i2i2iUi2iUiUrE", +"hDhDhRhDhDhnhnhDhnhRhnhnhDhnhDhRhDhDhRhDhDhnhnhDhnhRhnhnhDhnhDhRhDhDhRhDhDhnhnhDhnhRhnhnhDhnhDhRhDhDhRhDhDhnhnhDhnhRhnhnhDhnhDhRhDhDhRhDhDhnhnhDhnhRhnhnhDhnhDhRhDhDhRhDhDhn.M.Maz#9azaz#1#9#9sj#9#9skazdHr9#9#9az#9rQbrdVdV#9dHazbrrQbrdzbrdVdVdIbrbrcqdzbEbEdzbEbEd3dmbEdmbEbEbEbEd3dmbEdmdmdmdzdmd3d3c3d3dUeLdmdmdmdmc3c3eLeLdmfYdmdmfYeLeLeLeLfYeLeLfcfYeLeTfteTeLeLfue2eLfufue2fbfbftfbe2glglglgRgRhnhKgRgVgVglgVgVhnhngVhyhnhDgVgVhDgVhbhnhnhDhDh0h4h4hnh4hRhRhDhYhRhRh4h4h4h0iSi4sbjCixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixq0sqoWmmj2.Uay.q.q.2dGiUi.i.iUi.iUiUisiUisisi.isi.i.isi.isisi.isi.i.i.i.i.i.isi.isisi.isi.i.isi.isisiUisiUiUi.iUi.i.iUi.iUiUi.iUi.i.isi.isisiUisiUiUi.iUi.i.iUi.iUiUisiUisisi.isi.i.isi.isisrE", +"hDhnhnhDhnhDhRhDhnhDhRhDhRhDhnhnhDhnhnhDhnhDhRhDhnhDhRhDhRhDhnhnhDhnhnhDhnhDhRhDhnhDhRhDhRhDhnhnhDhnhnhDhnhDhRhDhnhDhRhDhRhDhnhnhDhnhnhDhnhDhRhDhnhDhRhDhRhDhnhnhDhnhnhDhnhD.F.F.F#9.F#9azaz.F#9az#9#9#9az#9azazazaz#9rQbEbEdVdVbE#9brbrazbrbrbEbEbrbEbrcqbEbEbEbrbEbEd3bEbEdmdmdmc3bEd3bEcqdmbEdzdmdmdmbEdmd3dmdmdmeLdmeLeLc3c3dmeLeLeLdmfYeLfcfceLeLeLeLeLdmfYfbeTeTeTdmeTeLeLfce2fke2fufkeLglgVgRgRgVhbhhgRhbhbhKgVgRhnhnhbhnhRgVhDhDh2hDhnhnhngVhRhDh0hYh2h4h0h2h2hRhRhRhYhYhYhRh4h0iSh0ppmIixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixjIsrss.U.2.2.2.U.U.Uj2j2ayisi.i.isi.isisiUisiUiUisiUisisisisisisiUisiUiUisiUisisi.isi.i.iUi.iUiUisiUisishFishFhFishFisisisisisisi.isi.i.i.i.i.i.isi.isisi.isi.i.isi.isisiUisiUiUisiUisisisisisisse", +"hnhRhnhDhRhnhDgVhRhngVhnhDhnhRhDhnhRhnhDhRhnhDgVhRhngVhnhDhnhRhDhnhRhnhDhRhnhDgVhRhngVhnhDhnhRhDhnhRhnhDhRhnhDgVhRhngVhnhDhnhRhDhnhRhnhDhRhnhDgVhRhngVhnhDhnhRhDhnhRhnhDhRhn.F.F.F#9.F.F.M#1#9az#9.Faz#9#9#9az#9azskazaz#1azrQbE#9dHbE#9az#9azbrbrrQbEbEdVbEbrcqbrdzbrbrdzbEdIbEd3bEc3dmbEbEd3bEbEdmdzdmdmdmbEc3d3d3dmdmdmdmdmeLc3c3dmd3eLeLdmfYdmdmfceTeLe2eLeLfYdmfbeLeTeTeLe2eLe2dmfcfue2e2gugRg4gVglgRgVhbglgRhnhbhbhngVgRhnhnhnhRgVhDhDhnhDgVgVhnhnhnhRhDh0hDh2hRhnh2h2hDhRh4hDhYhYiSh4h0h4pllBixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixmgstsujf.2j2.q.q.U.2.2.2.qj2j2.2isi.i.iUi.iUiUi.iUi.i.i.i.i.i.isi.isishFishFhFiUhFiUiUi.iUi.i.hFi.hFhFishFisisi.isi.i.iUi.iUiUi.iUi.i.isi.isisiUisiUiUisiUisisi.isi.i.iUi.iUiUi.iUi.i.i.i.i.i.isi.isisrE", +"hDhDhDhnhnhDhnhDhnhDhDhnhRhnhDhnhDhDhDhnhnhDhnhDhnhDhDhnhRhnhDhnhDhDhDhnhnhDhnhDhnhDhDhnhRhnhDhnhDhDhDhnhnhDhnhDhnhDhDhnhRhnhDhnhDhDhDhnhnhDhnhDhnhDhDhnhRhnhDhnhDhDhDhnhnhD#1.F#1#1.F.F.F#9#9#1#9#9az#9az.F#9az#9#9azazdHazazazrQazbrdVbr#9#9dHbrbrbEbEbEbrbrbEdVbEbEbrcqbrdHdzbEbEbEbEdmbEdmbEbEcqd3bEd3dmdmdmdmdmbEcqc3d3dmdmdmeTdmc3dmd3dmeLdmfYdmdmfcdmeLdmeLe2eLfYfbeLeLfYeLeTeLdmfue2e2fkglglglgRglglglgVglglhbhbhbgVhKgVhngVgVhngVgVgVhyhDhDhnhnhngVgVhRh4hRh0hDhRhnh2h4hRh0hRhYhYhDhRh4h4j5o9svixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixmPswqNjfjfjfjf.2jf.2.U.U.q.U.2.2j2dG.2ishFhFishFisisi.isi.i.isi.isisi.isi.i.i.i.i.i.i.i.i.i.isi.isisisisisisi.isi.i.isi.isisi.isi.i.isi.isisi.isi.i.i.i.i.i.isi.isishFishFhFishFisisi.isi.i.isi.isisi.isi.i.rE", +"gVhnhngVhnhDhnhnhnhDgVhDgVhnhRhngVhnhngVhnhDhnhnhnhDgVhDgVhnhRhngVhnhngVhnhDhnhnhnhDgVhDgVhnhRhngVhnhngVhnhDhnhnhnhDgVhDgVhnhRhngVhnhngVhnhDhnhnhnhDgVhDgVhnhRhngVhnhngVhnhD.F.M.F.F#1.F.F.F.F.M#9#9#9sj#9azaz.Faz#9rQ#9azdHdH#9r9azrQazrQrQbr#9bEbrdVazazbEbrdIbrdIbrdIbrbrdObEbEbEbEdIbEbEcqbEc3bEbEbEd3d3d3dmdzdzc3bEbEcqc3dzdmdmdUdmdUdmdmc3dmd3eLdmdmdmfYdmeLdmeLeLeLeLeLdmfbeLeTe2dmdmfufkglglgQgRglglglg4gVglgVhbhbhbhbhnhDgVgRgVgVgVgVhnhRhDhnhnhnh2hDhDhnhRhDhRhDhDhRh2h0hDh2hDhDhYhDh4hRiSh4sxsylfixixixixixixixixixixixixixixixixixixixixixixixixixixixixixixl.szrKnmjfiY.Ujfjf.qjfd2.2jf.2j2.q.Uj2.q.UdGi.iUiUisiUisishFishFhFi.hFi.i.isi.isisisisisisi.isi.i.iUi.iUiUi.iUi.i.hFi.hFhFishFisisi.isi.i.isi.isishFishFhFishFisisi.isi.i.iUi.iUiUisiUisishFishFhFi.hFi.i.isi.isisrE", +"hnhDhDhDhngVhnhDgVhnhDhnhnhDgVhDhnhDhDhDhngVhnhDgVhnhDhnhnhDgVhDhnhDhDhDhngVhnhDgVhnhDhnhnhDgVhDhnhDhDhDhngVhnhDgVhnhDhnhnhDgVhDhnhDhDhDhngVhnhDgVhnhDhnhnhDgVhDhnhDhDhDhngV.FsA.M.M#9.M.F#1.F.Fsk.F#9#9.M#9az#9#9#9az#1az#9#9az#9dHazaz#1brazrQ#9dVbrdVdVbrazbEbrdzrQbrdVbEbEbrbrbrdObEbEdzbEbEbEbEbEdmbEdmbEd3bEbEd3dmdmdmbEbEc3c3d3dmdUdmdmdmdmc3dmeLeLeLdmdmfYfYdmeLeLeTeLeLfYfYfbfcfYeTeofugVgVglglgRglhbglgRgVgVgVgVgVhbhbhbhbgVhKgVhDhngVhnhngVhnhyhDhnhnhDh4gVhnhnhRhRhDhDh4hRh4h4h2hRh0h0hRhDhYh4sBn1koixixixixixixixixixixixixixixixixixixixixixixixixixkonksCsD.qjfiYd2jf.qjfjf.2jfjfjf.qjf.2.2.2.U.2.q.qi.i.i.hFi.hFhFishFisishFishFhFi.hFi.i.i.i.i.i.hFi.hFhFi.hFi.i.i.i.i.i.isi.isisi.isi.i.hFi.hFhFishFisisi.isi.i.hFi.hFhFi.hFi.i.i.i.i.i.hFi.hFhFishFisishFishFhFi.hFi.i.rE", +"gVhngVgVhDhDgVhngVhngVgVhDgVhnhngVhngVgVhDhDgVhngVhngVgVhDgVhnhngVhngVgVhDhDgVhngVhngVgVhDgVhnhngVhngVgVhDhDgVhngVhngVgVhDgVhnhngVhngVgVhDhDgVhngVhngVgVhDgVhnhngVhngVgVhDhD.M.F.F.F.M.M.M#1.M.F#1.Fsk.F.F#9.M#9.Fbr#1#1#9.F#1az#9az#9r9dHaz#1azazaz#9dVdV#9dVdHbrazbrrQbEbrdVbEbEbEbrbEdzazbEbEbEdIbEdzdmbEbEc3bEcqbEbEbEc3dmdmc3bEc3d3c3d3dUdmdmdmdmc3c3d3eLeLdmdmfYeLfcdmeLeLeLe2fbdmfYeLeTgvgvgugRgugVglfQglhbhbgQg4gVguhNgVglhbhnglhbgVg4gVgVgVglhnhngVhnhyhDhnhDgVhnhRhnhRhRhRhDh4h4hnh4h4hRhDhRhDhYhDiSrbsEixixixixixixixixixixixixixixixixixixixixixixknsFsGjfiYjfi5jfi5jfjfd2d2d2.q.qjfjfjf.q.2jfjf.qjfj2.UishFhFishFisisi.isi.i.hFi.hFhFishFisisi.isi.i.isi.isisisisisishFishFhFhHhFhHhHishHisisi.isi.i.isi.isishFishFhFishFisisisisisishFishFhFishFisisi.isi.i.hFi.hFhFishFisisrE", +"gVhDhnhngVhnhDgVhnhngVhDhngVhDgRgVhDhnhngVhnhDgVhnhngVhDhngVhDgRgVhDhnhngVhnhDgVhnhngVhDhngVhDgRgVhDhnhngVhnhDgVhnhngVhDhngVhDgRgVhDhnhngVhnhDgVhnhngVhDhngVhDgRgVhDhnhngVhn.F.M.9sHsH.F.F.Fsk.M.F#1.F#1#1.F.F.F.M.F#9azazsjaz#1az#9az#9#9dHr9dH#9#9azazbEbErQdVdV#9dHbrbrazrQbEdIdIbEdIbEc3brbEbEbEbEbEbEbEd3c3bEbEcqbEbEcqd3c3bEdmdmc3dmc3d3c3dzdmdmeLdmdmdmc3c3eLeLdmfYfceLfcc3c3dmeLeLeLfbfuglgvglgvgugRglgVglglglgRhbgRglgRgVglgVglglhbgRhbgVhngVhnhnhngVhnhyhDhyhDhDh2gVh2hDhDhRhyhRh0hDh4h4hnh4h0h0hRhDhYh4sIinixixixixixixixixixixixixixixixixixiKr0sJiYi6iYjfd2jfd2.qjfi5jfjfjfjfjf.qd2jf.q.Ujfjf.q.2.qjfjfhHhFhFi.hFi.i.hFi.hFhFishFisisi.isi.i.hHi.hHhHi.hHi.i.hFi.hFhFi.hFi.i.i.i.i.i.hFi.hFhFi.hFi.i.hFi.hFhFi.hFi.i.i.i.i.i.hHi.hHhHhFhHhFhFi.hFi.i.hFi.hFhFishFisisi.isi.i.rE", +"hngVhngRhngRgVgVhDgRhngVgRhngVhnhngVhngRhngRgVgVhDgRhngVgRhngVhnhngVhngRhngRgVgVhDgRhngVgRhngVhnhngVhngRhngRgVgVhDgRhngVgRhngVhnhngVhngRhngRgVgVhDgRhngVgRhngVhnhngVhngRhngR.9.M.MsH.MsHsHsAsA.F.M.M.M.F#1sH.F.F.F#9.F.M.F#9#1az#1#9.Faz#9#9#9dHdHsKdH#9#9rQrQbEdV#9#9bEbrazbrazbrrQdzdIdIbrbrbEbrbrbEbEazbEbEbEbEbrdmbEbEbEbEcqbEdzdmdzdmdzc3cqc3d3eLdmd3dUdUdmc3dmeLdmdmd3fYdmfcdmfcc3eLeLeLfufkglfkglgvglgvgugVglgVglglglglhbgRgVg4gVglglglhbhbhnhbhnhngRgRhnhnhDhnhRhDhnhDhnhDgVhnhDhRhDhDhYh4hDh2h0hRh0hRh0h0hDptsLioixixixixixixixixixixixixiwmUsMiYhYi4hYiSi6iYi6hYd2d2d2jfjfjfjfjfiYiYjfd2jf.qjf.qjfjfjfjfjfi.isisi.isi.i.i.i.i.i.hFi.hFhFhFhFhFhFi.hFi.i.hFi.hFhFishFisishFishFhFi.hFi.i.i.i.i.i.i.i.i.i.hHi.hHhHishHisishFishFhFi.hFi.i.isi.isisi.isi.i.i.i.i.i.hFi.hFhFhFhFhFhFrE", +"hngVgVgVhDhnhnhngVgVhnhngVhngVhDhngVgVgVhDhnhnhngVgVhnhngVhngVhDhngVgVgVhDhnhnhngVgVhnhngVhngVhDhngVgVgVhDhnhnhngVgVhnhngVhngVhDhngVgVgVhDhnhnhngVgVhnhngVhngVhDhngVgVgVhDhnsH.F.M.M.M.M.M.MsHsHsA.F.F.M.Msk.F#1.F#1.F.F.F.F#9#9#9sjsj#1#9azaz#1#1#9azdHazdHazazrQbrbEdVdVbEbEdVazbrbEbrbEbEbEbEbrdVbEbEbrbrbEbEdIbEbEbEc3dmbEcqbEbEbEbEdzdzdzdmbEc3cqc3dmdmdzd3dUdmdmc3c3dmdmeLdmfYdmfYdmfcdmfbgugugufkglglglgugugugugVguhNglglglgVgRg4gVgVgVgVglglhbhbgRhbgVgVgRhnhnhnhnhRhRhnhnhDh2hDhnh2hRhRhDhyh0h4hDhRh0h4h0h0h0h0rZsNlKixixixixixixixk4losOsPhYiNiYiYhYd2i4i4i4hYi5i6i5iYd2jfd2jfi4aei5i5iYjfjfd2jfjfjf.U.qjfhHi.i.hFi.hFhFi.hFi.i.hHi.hHhHhFhHhFhFi.hFi.i.i.i.i.i.i.i.i.i.hHi.hHhHhFhHhFhFhHhFhHhHhFhHhFhFi.hFi.i.i.i.i.i.hFi.hFhFhHhFhHhHi.hHi.i.hFi.hFhFi.hFi.i.hHi.hHhHhFhHhFhFrE", +"glhngVhngVgRgVgRgVhngVgRhngRhngVglhngVhngVgRgVgRgVhngVgRhngRhngVglhngVhngVgRgVgRgVhngVgRhngRhngVglhngVhngVgRgVgRgVhngVgRhngRhngVglhngVhngVgRgVgRgVhngVgRhngRhngVglhngVhngVgRsH.r.rsH.F.MsA.MsH.F.MsH.M.F.F.Msk.M.M.FsjsH.F.FsQ#9.F#9#1#1#1#1sj.F#1az#1#9azdVskr9#9azrQazrQ#9rQdVdVdHdVazbEbErQbrdHbEdVbEbrbrbrbEbEbEbEbEdIbEbEdzc3bEbEcqd3dzd3c3c3dzc3c3bEc3d3d3dmdmdUdmdUdmdmc3eLdmeLsRdmdmdmfugufkguguguglglfkfQglgugvgugRglglhiglglhbglgVglg4gVgVgVglgRhnhngVhnhngRhngVglgVhnhnhRhyhnh2hnhbgVhnhRhnhRhDhDhDh4h4h0h4hRhDh0rmsSixixixixsTsUsVhYhYhYhYhYiShYhYhYiYi6hYhYhYi6i6iYiYjfiYd2i4d2jf.q.UjfiYjfiYjfjfd2jfjfi.hFhFi.hFi.i.hHi.hHhHi.hHi.i.i.i.i.i.hFi.hFhFhFhFhFhFhHhFhHhHi.hHi.i.i.i.i.i.i.i.i.i.i.i.i.i.hFi.hFhFhHhFhHhHhFhHhFhFi.hFi.i.hFi.hFhFi.hFi.i.hHi.hHhHi.hHi.i.i.i.i.i.rE", +"gRhngRgVhngVhnhnhngVhngVhngVhngVgRhngRgVhngVhnhnhngVhngVhngVhngVgRhngRgVhngVhnhnhngVhngVhngVhngVgRhngRgVhngVhnhnhngVhngVhngVhngVgRhngRgVhngVhnhnhngVhngVhngVhngVgRhngRgVhngVsWsA.9.r.9sH.M.F.MsA.M.MsH.M.FsAsA.F.M.M#1.F#1sj#1.F.F.F#9.F#9#1#9az#9#1.F#9#9sj#9azdVdHazazazrQrQbE#9dV#9dVbrdVbrbEazdzbrbEbEbrbrbEbrbEazbEdHbEd3dIbEbEbrc3dmbEd3cqdzc3dmc3dmc3dmbEcqc3d3dmdmdUdmdmdmc3d3c3eLeLeLftfQfQfkgugvguguguglfQgvgggugugugugRgVglhiglhhhhhngVgRglgVglhngVgRhbhbgVhbhDgRgRhnglhngVhyhDhyhDh2h2h4hnh2hRhDhDhYhDh4hnh4hnh4hRh0l6p3sXqUhYiSh0hYh0hYhYhYhYhYhYiShYiNhYiYhYi4i5i4i5hYi4jfiYiYiYi4d2jfi5.UjfiYhYjfjfd2hFg1g1hFg1hFhFhFhFhFhFhFhFhFhFi.hFi.i.hHi.hHhHi.hHi.i.i.i.i.i.hFi.hFhFhFhFhFhFhHhFhHhHhHhHhHhHhFhHhFhFi.hFi.i.hFi.hFhFhFhFhFhFg1hFg1g1hFg1hFhFhFhFhFhFhFhFhFhFi.hFi.i.rE", +"gVgVhngRhngRgVglgRhnglgVgRhngRglgVgVhngRhngRgVglgRhnglgVgRhngRglgVgVhngRhngRgVglgRhnglgVgRhngRglgVgVhngRhngRgVglgRhnglgVgRhngRglgVgVhngRhngRgVglgRhnglgVgRhngRglgVgVhngRhngR.r.9.9sAsA.9.rsH.9sY.9sA.MsAsA.MsHsHsH.F.F.M.M.F.F#1sH.Fsk.F.F.F#9#9#9azsZ#9#1#9#9#1#9az#9skaz#9azazazrQbrdVdVdVbrdVbrazbrbrbEbEbEbEbEbEbEbrbEbEazbEbEdIbEdzdmc3bEcqcqbEd3bEc3bEc3cqc3bEc3d3dmdmdzd3eodUeuc3c3c3d3fugPfkgggvfkfXfkfkgvguguggfQglgvgugvgugRguguhiglglglglglgRgRgVglgVglhbhngRgRhbgVhnhngVgVhnhnhyhDhnhDhnhDgVhnhnhRhRhRh4hRhDh4h4hnh4h0h4h0hDhYhYhYhYhYhYi4h0hYh0ibhYhYiShYi4iYiYhYi6i5hYhYi6hYi5hYiYd2i4d2jfjf.Ui5jfjfiYhFi.i.g1i.g1g1i.g1i.i.i.i.i.i.hFi.hFhFhFhFhFhFhHhFhHhHi.hHi.i.g1i.g1g1i.g1i.i.hFi.hFhFi.hFi.i.i.i.i.i.hHi.hHhHi.hHi.i.hFi.hFhFi.hFi.i.g1i.g1g1i.g1i.i.i.i.i.i.hFi.hFhFrE", +"hngVglgVgVhngVhngVgVglgVhnglgVhnhngVglgVgVhngVhngVgVglgVhnglgVhnhngVglgVgVhngVhngVgVglgVhnglgVhnhngVglgVgVhngVhngVgVglgVhnglgVhnhngVglgVgVhngVhngVgVglgVhnglgVhnhngVglgVgVhn.r.r.r.9sWsAsAsH.9sHsH.MsY.9sAsA.M.9sH.FsA.F.FsY.M.Fsk#1sj#1.F.F.FsQ#9#9.Fsj#9.F#9#9az.F#1#9azazaz#9azbrrQazazrQdVdVbr#9dVbrdIbEbEdIbEbr#9dIbEbrbrbrdObEbEbEdIdmc3bEbrc3bEbEcqd3bEdzd3c3cqdmbEbEcqdzd3dmeudmfcdmc3fbfkgugufQfufkfufkfkgvguguglglggglglgugugvgugugugRgRglhhhbhbhhgVgVgVgRgVglgRgRhbhnhnhDgRhnhngVhnhyhRgVhyhDh2h4h2hDhRhRhDhRhRhDhDhDhRh2h4hRh4hYhYiShDhRiSiShYh0h0h0hYhYhYi6iShYiYh0hYiNi4i4jfi5i6i5i5iYiYhYi4i4i4jfjf.qhFg1g1i.g1i.i.hFi.hFhFg1hFg1g1g1g1g1g1hHg1hHhHi.hHi.i.hFi.hFhFhFhFhFhFhHhFhHhHhFhHhFhFg1hFg1g1hFg1hFhFhHhFhHhHi.hHi.i.hFi.hFhFg1hFg1g1i.g1i.i.hFi.hFhFg1hFg1g1g1g1g1g1rE", +"gVglgVhnhnglglgVglgRhngVglgVgRgRgVglgVhnhnglglgVglgRhngVglgVgRgRgVglgVhnhnglglgVglgRhngVglgVgRgRgVglgVhnhnglglgVglgRhngVglgVgRgRgVglgVhnhnglglgVglgRhngVglgVgRgRgVglgVhnhngl.r.r.9.r.r.r.9sWsA.r.r.rsH.9sHsA.M.FsA.M.MsH.FsA.FsA.M.M.F#1.F#1.Fsj.F.F.F.M#9#1#9#1#1#1#9#9az#9#9#9sk#9dH#9brrQazrQdVdVdV#9dV#9azbr#9bEdzdIazbrbEbrbrbEbrazbEbEbEd3dzc3dmbEc3bEcqd3bEbEdzdmdmcqdzc3d3cqeLdmdmdUdmfbfufufkfkgugufkgugvfkfQfugvguglgufkfQglgvgggugRgugugugVglglgQglglgRgRgVgRgVgVhngVgRgRhbgVhKgRgVgRhnhnhyhDhyhDhnhDhnh2h2hDhRhDhRhDh4h4h4hnh4iSh0h0hDhYhYhYhRh0iNhYh0hYh0h7hYhYiSd2i4iYiYhYiNi4i6d2iSiNi6i6dGiYd2iY.qi4hFi.i.hHi.hHhHhFhHhFhFhFhFhFhFhHhFhHhHhFhHhFhFhFhFhFhFg1hFg1g1g1g1g1g1hFg1hFhFi.hFi.i.hFi.hFhFi.hFi.i.hFi.hFhFg1hFg1g1hFg1hFhFi.hFi.i.hHi.hHhHhFhHhFhFhFhFhFhFhHhFhHhHrE", +"glgVgRglglgVgRhngVglgVgVglhngVglglgVgRglglgVgRhngVglgVgVglhngVglglgVgRglglgVgRhngVglgVgVglhngVglglgVgRglglgVgRhngVglgVgVglhngVglglgVgRglglgVgRhngVglgVgVglhngVglglgVgRglglgV.rsW.r.r.r.r.9.MsA.rsA.rsA.9sH.MsH.M.F.M.M.M.F.F.9sHsH.F.F.M.F.M.F#1#1.F.F.F.F.F.M#9#9#1s0#9#9.Faz.FrQdVazdHskaz#9azazrQbE#9#9#9dV#9dVazbEbrazbEdVbEbEbrbEbrbrdHbEbEbEbEbEbEc3dmbEcqcqbEcqdzdzc3c3dmc3bEbEc3d3dmdmeLfufbfufkfkgugugugufufkfXgvgufufkfkguguglglgvgggugugugugRgRgugRglglhhhbgVgVgRgVhKhKhbhnhbgRgVhnhnhnhKhDgRhRgVhygVh4h2hnh4hnh4hnhRhRhDhYhDhDh2h4h2h4hRh0hRhRhYiSiNiNi4iNh0h0hYhYhYhYhYhYiNi4iYi4d2d2jfi4i5i5d2jfjfjfd2g1hFhFg1hFg1g1g1g1g1g1i.g1i.i.hFi.hFhFg1hFg1g1hFg1hFhFhFhFhFhFi.hFi.i.g1i.g1g1hFg1hFhFg1hFg1g1g1g1g1g1hFg1hFhFhHhFhHhHg1hHg1g1hFg1hFhFg1hFg1g1g1g1g1g1i.g1i.i.hFi.hFhFs1", +"gRgVgVgRgVglglgVglgVglglgVglgVgVgRgVgVgRgVglglgVglgVglglgVglgVgVgRgVgVgRgVglglgVglgVglglgVglgVgVgRgVgVgRgVglglgVglgVglglgVglgVgVgRgVgVgRgVglglgVglgVglglgVglgVgVgRgVgVgRgVgldzsWsWs2s2.r.r.r.9.r.r.9sW.rsAsH.r.rsA.9sAsY.M.M.F.MsHsHsA.M.FsY.M.M.MsH#1sj.F.F.F.F.M#9#1#1#9.F.F#1#1#9#9#9azdVr9dH#9azrQrQazrQdVdVdVbrbrbrazdHbrbEdIbEbrdVbEbrbEbEbEbEazbEbEbEdzc3bEdObEbEcqd3cqc3cqefcqcqbEc3d3eTfufkfbfbfXfkfugugufkfQgufkfQgvfQfugvguguglgufkfQfQgvgugugugRgugVgRglglglhbglgRgRgRgRglhKhnhbgVhbhnhngRgVhnhKhnhnhnhDhDhDhnh4hnh4hDhRhDhDhRhDiSh4h4h0h0iSh0h0h0hYiShYibiShYhYhYhYhYiShYhYiSiNi4iYi4hYi4i4jfi6iSiYiYhahFg1g1hFg1hFhFhHhFhHhHg1hHg1g1hFg1hFhFg1hFg1g1g1g1g1g1hFg1hFhFg1hFg1g1hFg1hFhFhFhFhFhFg1hFg1g1hFg1hFhFg1hFg1g1hFg1hFhFhFhFhFhFg1hFg1g1hFg1hFhFhHhFhHhHg1hHg1g1hFg1hFhFs1", +"gRglglgVglgVgVgRglgVgVgRgVglglglgRglglgVglgVgVgRglgVgVgRgVglglglgRglglgVglgVgVgRglgVgVgRgVglglglgRglglgVglgVgVgRglgVgVgRgVglglglgRglglgVglgVgVgRglgVgVgRgVglglglgRglglgVglgVgVsjs3.rsWs2.rsA.r.r.r.9.9.9sA.9sAsAsAsH.r.9.MsYsA.M.MsA.F.F.MsH.F.F.Fsk.M#1#1sj.F.F#9.F.F#9.M#9#1sjsZsj#1#9#1sj#9dV#9#9#9az#9azrQbrbEbrdV#9dVdVdVazbrazazbrdVbEbEcqc3brbEazbEbEdIbEbEc3c3c3bEcqbEbEcqd3c3c3c3cqbEeTfufkfkfQfufQfbfufufkfufkgugufkfkgggvgvgugugvguguguglfQgvgugugugRgVgugRgRg4glhhgVgVhhgRgRhKgVgVhnhhgRgVhDhnhngVgVhnhKhnhDhnhyh4hnhDhnhnhnhnhRh4h0h0hRiShnh4iSh4h0h0hYhRhYhYiNi4hYiNhYhYh7hYhYiSiNi5i4i4iYi4jfi4i4fPhHhHg1g1hHg1hHhHhFhHhFhFhFhFhFhFg1hFg1g1hFg1hFhFhFhFhFhFg1hFg1g1hFg1hFhFg1hFg1g1g1g1g1g1hHg1hHhHhFhHhFhFg1hFg1g1g1g1g1g1hHg1hHhHg1hHg1g1hHg1hHhHhFhHhFhFhFhFhFhFg1hFg1g1s4", +"glgVglgRgVglgVgugVglglglgVglgVgVglgVglgRgVglgVgugVglglglgVglgVgVglgVglgRgVglgVgugVglglglgVglgVgVglgVglgRgVglgVgugVglglglgVglgVgVglgVglgRgVglgVgugVglglglgVglgVgVglgVglgRgVglgVgu#1sWs5s3sW.rs2.r.r.r.r.9.9.9s6.rsWsWsAsA.rsH.9.M.rsA.M.FsA.F.9sH.MsA.F.F.M.M#1#1sH.F#1.F.F.F.M#9#1.FsZsZ.F#9#9#1#9az#9skaz#9#1azrQ#9bEbEdVdVbrdVazazbrrQbrdHdVbEbrbrbEc3bEbEazbEbEdIbEbrc3c3bEbEbEdzbEcqc3bEc3eLfue2fkfkfkfQfufufbfkfufXfufufkgufkfkgggvgvgvgufkgugugugufkgggvgugvgugVguguglglglglglgRgVg4gVgRhNglhnglgVgVgVhbhnhUgRhDhnhnhnhDhnhDh2hDhnhnh4hnhRhDhDh0hYiSh4hDh4h0h4h0hDhYhYhYiSiSh0iSiYhYhYh7hYhYiSi5hYi4iYi4fDjag1hFg1g1hFg1hFhFg1hFg1g1g1g1g1g1hFg1hFhFgAhFgAgAhFgAhFhFg1hFg1g1g1g1g1g1hFg1hFhFg1hFg1g1hFg1hFhFg1hFg1g1hHg1hHhHhFhHhFhFhFhFhFhFg1hFg1g1hFg1hFhFg1hFg1g1g1g1g1g1hFg1hFhFg0", +"gVgRgVglglgVglgVglglgVglgVglglglgVgRgVglglgVglgVglglgVglgVglglglgVgRgVglglgVglgVglglgVglgVglglglgVgRgVglglgVglgVglglgVglgVglglglgVgRgVglglgVglgVglglgVglgVglglglgVgRgVglglgVglgVgu.Ms5s5.r.r.r.rsW.rsW.r.r.9.9.r.9.9sAsAsA.9sH.9.MsH.M.MsYsAsA.MsHsH.F.F.F.M.F.M.M.F#1sH#1.F.F.F#9#9#1sZsj.FsZ#9.Faz#9#9#9sk#9dHazaz#1azbErQbrdVdVdH#9azbrrQazdzazbEdVdIbEbrbrbEbEbEbEbEd3dzc3c3dOdObEbEcqdzd3dmfbfufbfufkfkfkfufkfkfufufufkfkfugufkgugPgufkgvfQfkgvguguguglguggguglgugRgugugugVglgRgVgVhnhhhhgVg4gVhKgRhKglgVhbhnhnhnhDhDhUhKhngVhyhDhnhDhnhDh2hRhRhnhyhRhDhRiSh4hYh4h0h0hDhYhYhRhYhYiShYh0hYhYhYhYhYhYjfi4fsjThHgAhHgAgAg1gAg1g1g1g1g1g1hFg1hFhFg1hFg1g1g1g1g1g1g1g1g1g1hFg1hFhFhFhFhFhFg1hFg1g1g1g1g1g1g1g1g1g1hFg1hFhFg1hFg1g1g1g1g1g1hHg1hHhHgAhHgAgAg1gAg1g1g1g1g1g1hFg1hFhFg1hFg1g1s7", +"guglglguglgVglglglgVglglguglgVglguglglguglgVglglglgVglglguglgVglguglglguglgVglglglgVglglguglgVglguglglguglgVglglglgVglglguglgVglguglglguglgVglglglgVglglguglgVglguglglguglgVglglglgusAs5s3s5.rsW.rsWs2sWs2sW.r.r.r.r.MsAsAsAsA.rsH.9sAsAsA.MsAsA.MsHsA.9.F.F.F.MsY.M#1.M#1#1#1.F#9sQ.F.M.F.F#9#9sZ#9.F#1#9#9#9#9#9#9#9#9#9#9az#9rQdV#9dVbrbrbrdHbrrQdHdIdIdIbEbrbrbrdHbEdHdHd3dIbEbrc3bEbEbEcqdmfteTfbfbfbfbfbe2fufkfQfufufufXfufkfufkgugufQgufkggfkgufuguguglgPglgggQfQgvgugugugVglguglglgVglgRhhhnglhngRgRgVgVgVhngVhnhnhnhnhngVhngVhnhDhDhDh2hDhZh2hnhDh3hRhDhDh4hDh4hnh0h0hYh0hDhYhYhYhYiNh0hYh0i4hYhYjfjYg1g1hFg1hFhFhHhFhHhHgAhHgAgAg1gAg1g1hFg1hFhFhFhFhFhFg1hFg1g1hFg1hFhFg1hFg1g1gAg1gAgAhFgAhFhFg1hFg1g1hHg1hHhHgAhHgAgAhFgAhFhFg1hFg1g1hFg1hFhFhHhFhHhHgAhHgAgAg1gAg1g1hFg1hFhFs8", +"glglgVglglguglgVguglgVglglgVgugVglglgVglglguglgVguglgVglglgVgugVglglgVglglguglgVguglgVglglgVgugVglglgVglglguglgVguglgVglglgVgugVglglgVglglguglgVguglgVglglgVgugVglglgVglglguglgVguglfQ.r.r.rs5s5.r.rsW.rsW.rsAs2.r.rsH.r.r.9sAsAsAsA.9.r.rsHsA.9.r.M.F.M.M.FsH.MsH.F.M.F.M#9.M#1sHsH#1.F.F.F.M#1#9sj#1sZ.Faz#1#9#9#9#9dVdVaz#9#1azaz#9brdVbrdVbrbrbrbrdHbEbrdVdVbEbEbrbrbEdObEazbEbEeuc3bEc3bEdmfbfbfvfufbfufbfbfufufkfbfufQfufbfufXfkfkfufkgufQgPgggufkfQgvfugufkglglglfkglfQgvgvgRgugugVgRgRhhgRhbhhglg4hngVgRgRgRgVhnhngVhnhnhnhnhUhDhnhRhnhDhDhDhDh4iShnhnhnhRhRhDhRiShRiSh0h0h0h0hYhYhYiShYiNiNh0i4.qjvgAg1g1g1g1g1g1gAg1gAgAhFgAhFhFgAhFgAgAg1gAg1g1g1g1g1g1gAg1gAgAg1gAg1g1g1g1g1g1hFg1hFhFg1hFg1g1gAg1gAgAhFgAhFhFg1hFg1g1gAg1gAgAg1gAg1g1g1g1g1g1gAg1gAgAhFgAhFhFgAhFgAgAg1gAg1g1s9", +"guglguguhhgVguglguglgugugVguglglguglguguhhgVguglguglgugugVguglglguglguguhhgVguglguglgugugVguglglguglguguhhgVguglguglgugugVguglglguglguguhhgVguglguglgugugVguglglguglguguhhgVguglguglgufbsA.r.r.r.rt..rsW.rsWsW.rs6sA.r.r.r.9.r.r.9s6.rsWsA.9.rsH.rsH.rsA.MsA.M.MsH.MsHsA.F.M.Msk.M.F.F.F.F.F.F.F#9.M#9.FsZ#1.Faz#1az#9#1#9.M#9dVaz#1azrQaz#9#9brdVdVbr#9az#9dHbEazdVbEbrbEbrbEbrbEbEbEdIbEdzc3eLfce2fbfufbe1fbftfbfbfue2fufkfQfufkfbfufbfufkftfkfugufkfkfkfkfkfQfkguglguguglfkglfQgggvgugRgugugVglguglhhhnhhg4hnhngVgRhbhbhhhbhnhnhbhnhUhDgRhnhRhnhyhDhnhnhDh4iSh0hnh0hDhRhDh4hDiSh4h0h4h0hDhYhYhRhYiNiNj9hFg1hFhFgAhFgAgAhFgAhFhFg1hFg1g1gAg1gAgAhFgAhFhFg1hFg1g1g1g1g1g1hFg1hFhFgAhFgAgAgAgAgAgAhegAheheg1heg1g1hFg1hFhFgAhFgAgAg1gAg1g1hFg1hFhFgAhFgAgAhFgAhFhFg1hFg1g1gAg1gAgAhFgAhFhFt#", +"gugVglglguglglglglglgugVglgugVgugugVglglguglglglglglgugVglgugVgugugVglglguglglglglglgugVglgugVgugugVglglguglglglglglgugVglgugVgugugVglglguglglglglglgugVglgugVgugugVglglguglglglglglgugVdm.r.r.r.r.r.r.r.r.rt..rsWsW.rsWsA.r.r.r.r.9.r.r.9sAsWsA.r.rsH.MsYsY.9.M.MsA.MsHsH.FsA.F.M.M.F.M.Fsj#1.F.F.F.F#9#9#1.Fsj#1#9#9#1#1rQ#9#1#9r9dVazazazrQbEdVdVdVdVdVdVbrazbrbrbEbEbEbEbrbEbrbEbrbEbEbEbEdmeLfbfbdmfbe2fufbeTeTfvfbfbfbfke2fufkfufkfkfufbfufufufkgugugufQfkgggvfQfkfkglgugufkggglfQglguglgugVgugVgRgRhbhhhbgRgRgVg4gVhKgRhnhngVhnhnhnhnhUhDhnhnhyhnhnhyhDh4iShDh4h0h0hRhDhRhDiSiSiSiSiSh0h0h0h0hYk0g1gAg1gAgAgAgAgAgAg1gAg1g1gAg1gAgAhFgAhFhFg1hFg1g1gAg1gAgAg1gAg1g1g1g1g1g1g1g1g1g1g1g1g1g1gAg1gAgAg1gAg1g1gAg1gAgAg1gAg1g1g1g1g1g1gAg1gAgAgAgAgAgAg1gAg1g1gAg1gAgAhFgAhFhFg1hFg1ta#h", +"glguglguglguguglhhguglguguglguglglguglguglguguglhhguglguguglguglglguglguglguguglhhguglguguglguglglguglguglguguglhhguglguguglguglglguglguglguguglhhguglguguglguglglguglguglguguglhhguglguguc3.r.r.r.r.r.r.r.r.r.r.rsWs3sWsWs2s2sA.r.rs3.r.9.r.rsAsAsWsA.r.rsA.rsYsA.MsA.M.F.9sH.FsH.r.F.M.M#1#1.F.F.F.F#9#9.M#9.F#9.Fsj#1#1.F#9#1#1#9#9#9sk#9az#9az#9bEdVdV#9#9dVazbrdHbr#9dIbEdIbEbrbEbrbEdHdHdmeMeLe2eLdme2e2e2fbfvfbeTeTfbfbfbe2fue2fufkfufkfufufkfufufufkfQgufkggfkgggvfufkguglgugufQfQgvgvgugugvgugVgRgRgRgRgRglhnhbhbgRgRgVgRgRgVhyhnhnhnhnhnhZhnhnhngVgVhyhnhDh4hDhDhDhRhRhRhDhYiSiShnhDh4h0h0l1gAgAg1gAg1g1hFg1hFhFg1hFg1g1g1g1g1g1gAg1gAgAgAgAgAgAg1gAg1g1gAg1gAgAhFgAhFhFgAhFgAgAg1gAg1g1g1g1g1g1g1g1g1g1gAg1gAgAhFgAhFhFgAhFgAgAg1gAg1g1hFg1hFhFg1hFg1g1g1g1g1g1gAg1gAgAgAgAgAtbQt", +"glguguguhhglglglguguglglguglguhhglguguguhhglglglguguglglguglguhhglguguguhhglglglguguglglguglguhhglguguguhhglglglguguglglguglguhhglguguguhhglglglguguglglguglguhhglguguguhhglglglguguglglgugldH.r.r.r.r.r.r.r.r.rs5.rs3.rs5.r.r.rs2sW.r.r.r.r.r.MsW.rsAsAsAsA.9sHsAsAsYsA.M.M.M.M.9sH.F.F.F.F.M.F#1#1sj.F.F#1#9.F.M#9.F#9sZsZ#9az.F#1#1#1#9#9dV#9#9azazazbrbE#9dI#9dVdVazbrbrbrdHdIbEdIbEbEbEbrdzdmeLeLeMeLeLeLfbe2fbe2fbe2fbfvfvfbfbfbe2fufkfufQfufkfufufufufkfkfQgugufkggggggfQfufkguglguguglglgQguglgugRgVgVgugRgRhngRhhhnhngVgRhNhKhngRgRhygVhbhnhnhnhDh4hnhRgVhnhnhnhDhDhDh4h2hRh0hRh0hYhDhDhDhxg1gAgAgAgAgAgAg1gAg1g1gAg1gAgAg1gAg1g1fjg1fjfjgAfjgAgAg1gAg1g1g1g1g1g1g1g1g1g1gAg1gAgAgAgAgAgAgAgAgAgAgAgAgAgAg1gAg1g1g1g1g1g1gAg1gAgAgAgAgAgAg1gAg1g1gAg1gAgAg1gAg1g1fjg1fjfjgAfjgAtcQt", +"fQglguglgufQgufQglglguguglguglgufQglguglgufQgufQglglguguglguglgufQglguglgufQgufQglglguguglguglgufQglguglgufQgufQglglguguglguglgufQglguglgufQgufQglglguguglguglgufQglguglgufQgufQglglguguglgugu#9.r.r.r.r.r.r.r.r.r.r.r.rt..rsW.rs3sWs2sAs2.r.r.r.rtd.M.rs6sA.9.rsA.9sAsHsA.r.rsA.M.M.MsH.M.F.rsA.F.M#1.F#1.F#1.F.F.F.F.F.F.F.F.FsZ#9.F#9#9#9#9#1dVdV#1#9#1az#9rQbEdV#9dVbrbrbrdHdHbrdHdIdVdIbrdzfbdmeoe2eoeLeLeLeLeLfbe2e2e2eTfufbeTfbfbfbfufke2fbfufQfufbf5fkfkf5fugufufQfkfQfkfkggfQfkgugugugugugggvgggQgvglgugugVhigRglhngQhhgVhnglhngRgRgRhnhnhyhnhngRhngRhUhDhngVhyhDhDhDh4h4iSh4h0h2hYhDhDayhPfjgAgAg1gAg1g1gAg1gAgAg1gAg1g1gAg1gAgAg1gAg1g1heg1hehegAhegAgAgAgAgAgAgAgAgAgAg1gAg1g1g1g1g1g1g1g1g1g1g1g1g1g1gAg1gAgAfjgAfjfjgAfjgAgAg1gAg1g1gAg1gAgAg1gAg1g1gAg1gAgAg1gAg1g1heg1heteQt", +"guglfQguglguglglglguglguglguglguguglfQguglguglglglguglguglguglguguglfQguglguglglglguglguglguglguguglfQguglguglglglguglguglguglguguglfQguglguglglglguglguglguglguguglfQguglguglglglguglguglguglfXsk.r.r.r.r.r.r.r.r.r.r.r.r.r.rs5s3.rsWs3.rs2s2sA.r.rs3.r.9.M.9sAsAsA.9sAsHsA.rsY.r.MsA.M.F.M.F.M.F.FsA.Fsk#1#1.F.F.F.F.F.F.F#9.F.Fsj.FsZsZ#9#9#1#9#1sK#9sk#1br#1azazrQbEbr#9brdVbraz#9brazdHazbEeLeLdmfbdmdmc3eLeLeLe2eLfbfbfbe2e2fbfvfbfufbfbfbfue2fkfufkfQfQfbfufufkfufkfkfkgugPgvgvgugvfQguguguglglguglgQgQglgQgugugRgRhigRhhhnhnhhgVgVgRgRhDgRhngVhngVhnhDhnhnhnhZh4hDhKhDhRhDh4hDh4hDh4hDjfhFgAg1gAgAg1gAg1g1fjg1fjfjgAfjgAgAgAgAgAgAgAgAgAgAg1gAg1g1fjg1fjfjg1fjg1g1g1g1g1g1gAg1gAgAgAgAgAgAgAgAgAgAfjgAfjfjgAfjgAgAg1gAg1g1gAg1gAgAg1gAg1g1fjg1fjfjgAfjgAgAgAgAgAgAgAgAgAgAg1gAg1tfQt", +"guguglfQglfQgufQguglfkguguglgufkguguglfQglfQgufQguglfkguguglgufkguguglfQglfQgufQguglfkguguglgufkguguglfQglfQgufQguglfkguguglgufkguguglfQglfQgufQguglfkguguglgufkguguglfQglfQgufQguglfkguguglgufkfXsY.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rt..rt.s5s3.r.r.rsWsW.r.r.r.r.M.rs6.rsWsAsA.9sHsHsAsA.M.M.MsH.MsH.MsHsA.F.F.M.Fsk#1#1sH.F.F#9.F#9.M#9.FsZsZ#9azaz#9#9#9#1dV.M#1az#1azrQbrbEdVdVbE#9#9brazbr#9dUeMd3eLdmeoeLdmdmeLe2eLeTeTeLdmfbdme2fbfue2fbfvfvfvfbfbfue2fufkfQfufbf5fbfbfufkfkfkgugugPfkglfkgufkgufkguguguglglglglgugRgugRgRgugRgugRhhhhhnhngVgVhUhKgRhnhnhhhnhngRhnhZhDhDhnhRhRgVhDhDh4hDiNiifjg1fjg1g1gAg1gAgAg1gAg1g1fjg1fjfjg1fjg1g1g1g1g1g1gAg1gAgAgAgAgAgAgAgAgAgAg1gAg1g1fCg1fCfCg1fCg1g1gAg1gAgAg1gAg1g1g1g1g1g1fjg1fjfjg1fjg1g1gAg1gAgAg1gAg1g1fjg1fjfjg1fjg1g1g1g1g1g1gAg1gAtgQt", +"glglfkguguglguglgugufQguglfkguglglglfkguguglguglgugufQguglfkguglglglfkguguglguglgugufQguglfkguglglglfkguguglguglgugufQguglfkguglglglfkguguglguglgugufQguglfkguglglglfkguguglguglgugufQguglfkguglglfk.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rt.s5s5sW.r.rs2s6sAs2.r.rtd.9.M.rsWsAsA.r.9sHsAsAsH.r.M.M.FsA.MsH.M.F.F.M.M#9#1.M.F#1sH.F#1.F.F#9.F.FsZ.F.FsZ.F#1az#9#9#9#9#9#1az#1#1br#9#9br#9dVdHbrazdzdmdmdmeLd3d3d3dmdmdmeoe2e2eLeLeLeLfbfbdme2e2e2eTfvfufbfbfufbfufufkfQfQfkfbfufufufkfkfkgufkfQgQgggggvfQfkguguguglgRgRgQgugRglgRgRgVgugugRhhhhgVhbhnhhglhnhngRgRgRgVgVhnhngRh0h4hnhDhDhKhnhyhYjvgAgAg1gAg1g1gAg1gAgAfjgAfjfjg1fjg1g1gAg1gAgAfjgAfjfjfCfjfCfCfjfCfjfjg1fjg1g1gAg1gAgAgAgAgAgAfjgAfjfjgAfjgAgAfCgAfCfCgAfCgAgAgAgAgAgAg1gAg1g1gAg1gAgAfjgAfjfjg1fjg1g1gAg1gAgAfjgAfjfjfCfjthabQt", +"gufQguglglfQfkgufkguglgufkgugufQgufQguglglfQfkgufkguglgufkgugufQgufQguglglfQfkgufkguglgufkgugufQgufQguglglfQfkgufkguglgufkgugufQgufQguglglfQfkgufkguglgufkgugufQgufQguglglfQfkgufkguglgufkgugufQgufQeL.9.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rt.s5.rsW.rs2.rs2.r.r.r.9.r.9.r.9sWsAsA.rsH.rsH.r.M.M.M.F.M.FsH.FsA.F.F.Msk#1.F#1.F.F.F.F.F.F.F#9.MsZsj#1.F#9az#9#1#9#9skdV#1#9brrQbrbEdVbr#9dHdzdUdUdmdzeLdmeMc3dmdmeTdmdmdme2dmeMeLeLdmeLfbe2fbe2e2fbeTfufbfufbe2e2fufkfufQf5fQfbfufufufkfkfufQgvfkglgvfQgvfugugugugufQglgQglgQguglgVgugVgugRgRhhgVhnhbhngRhngRgRhngRhhhngVhnhDhZhDh4hnhRjVg1gAgAfCgAfCfCgAfCgAgAg1gAg1g1fjg1fjfjgAfjgAgAgAgAgAgAgAgAgAgAgAgAgAgAgAgAgAgAfCgAfCfCfCfCfCfCgAfCgAgAg1gAg1g1gAg1gAgAg1gAg1g1gAg1gAgAfCgAfCfCgAfCgAgAg1gAg1g1fjg1fjfjgAfjgAgAgAgAgAgAgAgAtiQtQt", +"fkgufQfkfkguguglgufkgugufQglgufkfkgufQfkfkguguglgufkgugufQglgufkfkgufQfkfkguguglgufkgugufQglgufkfkgufQfkfkguguglgufkgugufQglgufkfkgufQfkfkguguglgufkgugufQglgufkfkgufQfkfkguguglgufkgugufQglgufkfkgufQdz.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rs5s5.rs5.rsW.r.rs2sA.r.rs3.r.9.MsAsAsA.rsA.rsHsH.rsY.r.MsA.MsA.FsH.F.F.F.F.M.M.F#1.FsH.F.F.F.F.F.M.F#1.FsZ#1#9az#9sj#9#9.F#9#9#1#9#1azrQbrdVbEd3dzd3dmdmc3eLdmdmd3d3eLdmfYeLdme2eoe2eLeLe2eLfbfbe2e2fbfufueTeTfvfbfbfufufkfufQfQfuf5fufbfufufufkfQguglglfkgugvgugugugugugufkglgRgQhhgQgQgugVgugRgRgVhnhhhhgRhnhngRhngRgRgVhngVgVhnhnhnkggAfCgAgAgAgAgAgAfCgAfCfCgAfCgAgAfCgAfCfCfjfCfjfjg1fjg1g1gAg1gAgAfCgAfCfCgAfCgAgAgAgAgAgAg1gAg1g1fjg1fjfjgAfjgAgAfCgAfCfCfCfCfCfCgAfCgAgAgAgAgAgAfCgAfCfCgAfCgAgAfCgAfCfCfjfCfjfjg1fjg1g1gAg1tjQtQt", +"fQgugugugufQfkgufkgufQfkgufkgugufQgugugugufQfkgufkgufQfkgufkgugufQgugugugufQfkgufkgufQfkgufkgugufQgugugugufQfkgufkgufQfkgufkgugufQgugugugufQfkgufkgufQfkgufkgugufQgugugugufQfkgufkgufQfkgufkgugufQgugugudm.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rs5.rs5s3sW.rs2s2sAs2.r.r.r.r.9.MsAsAsWsA.rsH.rsAsH.rsAsA.M.9.F#1.F.FsA.F.Msk#1#1.F#1.F.F.FsQ#9#9.M.F.Fsj#9sZ.F.Faz#9#1#1#1#9#1#1#9azrQdUd3dzdzdzdmdmdUdmdmdzc3dmeMeLdmeLdmdmdmeoe2eLeMeLfbdmfbfbe2e2fufbeTfvfbfbfufbe2e2fbfufkfQf5fufufufufkfkgufkfQgvgvgvfkguguguguguguglgRgQglgRglgugugugRgRgRgRhnhhhnhbhngRgRhngRgVhnhnhnhDhIgAfCgAfCfCgAfCgAgAgAgAgAgAfjgAfjfjgAfjgAgAfjgAfjfjfCfjfCfCgAfCgAgAfjgAfjfjfCfjfCfCgAfCgAgAfjgAfjfjgAfjgAgAgAgAgAgAfjgAfjfjgAfjgAgAfCgAfCfCgAfCgAgAgAgAgAgAfjgAfjfjgAfjgAgAfjgAfjfjfCfjfCfCgAfCt#QtQt", +"gufkfQgufkguglfQfQgugufQgufQfkfQgufkfQgufkguglfQfQgugufQgufQfkfQgufkfQgufkguglfQfQgugufQgufQfkfQgufkfQgufkguglfQfQgugufQgufQfkfQgufkfQgufkguglfQfQgugufQgufQfkfQgufkfQgufkguglfQfQgugufQgufQfkfQgufkfQgufkbE.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rt..r.rs5.r.rsW.rs2.rsA.r.r.r.r.Ms6sA.9sA.rsA.rsHsAsAsY.r.MsH.M.M.MsHsH.F.F.F.Msk#1#1sj#1.F.F.F.F.M.F#9.MsZsZ#1az.F#9br#9#1.M#1#9#1bEcqdzdzc3d3eLdzdzd3dmdmdzdmdmd3eMeLeodmeoe2dme2e2e2eLeLdmfbfbe2e2fbe2fufufbfvfbfbfbfkfbfkfQfQfuf5gufbfufkfufkgugugufQfkfkgvfQgugugvgugugufkgRglhhhhglguguguhNhhgRgRhhhhhhhbhnhUhKhKgRfPgAgAfjgAfjfjfCfjfCfCfjfCfjfjfCfjfCfCfjfCfjfjgAfjgAgAgAgAgAgAfjgAfjfjgAfjgAgAgAgAgAgAfCgAfCfCgAfCgAgAfjgAfjfjfCfjfCfCfjfCfjfjgAfjgAgAfjgAfjfjfCfjfCfCfjfCfjfjfCfjfCfCfjfCfjfjgAfjgAgAgAgAgAgAfjtkQtQtQt", +"fkgufkfQgufkgufugufQfkfkgufkgugufkgufkfQgufkgufugufQfkfkgufkgugufkgufkfQgufkgufugufQfkfkgufkgugufkgufkfQgufkgufugufQfkfkgufkgugufkgufkfQgufkgufugufQfkfkgufkgugufkgufkfQgufkgufugufQfkfkgufkgugufkgufkfQgufk#1.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rt..rsWs5.rtl.rs2s2.rsA.r.r.r.M.rs6.9sWsAsA.rsHsA.rsYsYsA.MsH.MsH.MsHsA.F.F.M.M#1.Fsjsj.F.F#9.F#1.M#9.FsZ.F.F#9.F#9#1br#1#9.MbrbEbrcqdzdzc3d3d3dzdmd3d3dUdUdzdmeMdmeLdmeofYe2dmeodme2e2eLeLdmfbe2e2fufue2fueTeTfbfbfbfbe2fufkfQfufufQfufufufufugufkgugufkgufkgugggugggugugufkglgQglglhhgugRgRgugRgugRhhhhhhgRhngR.UgAfCfCfjfCfjfjgAfjgAgAgAgAgAgAfCgAfCfCgAfCgAgAfCgAfCfCfCfCfCfCgAfCgAgAeKgAeKeKgAeKgAgAfjgAfjfjfCfjfCfCgAfCgAgAfCgAfCfCgAfCgAgAfCgAfCfCfjfCfjfjgAfjgAgAgAgAgAgAfCgAfCfCgAfCgAgAfCgAfCfCfCfCfCfCgAtmQtQtQt", +"gufQgufkfkgufQgufkfQgufkgufkfQfkgufQgufkfkgufQgufkfQgufkgufkfQfkgufQgufkfkgufQgufkfQgufkgufkfQfkgufQgufkfkgufQgufkfQgufkgufkfQfkgufQgufkfkgufQgufkfQgufkgufkfQfkgufQgufkfkgufQgufkfQgufkgufkfQfkgufQgufkfkgufX#9.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rt.s5.r.r.rsWsWsA.rs2.rs3.r.9.r.9sW.rsAsHsH.rsA.F.rsA.MsA.M.FsH.FsA.M.FsKsk.M.M.F#1#1.F.F.F.F.F#9.F.Fsj.Maz.F#1#1#9#9azdzd3dzbEc3dzdzdmdzdzd3d3d3dmdmdmdmdmc3eMeLdmeoeTdmdme2e2e2eTe2eTfbeTfbe2fbe2fufbfufufbfbfbfufbfue2fufQfufQfbfufXfkfkgugugufQgugugvglgufQhiguguglglgRfQguglglglgRgugVgugRgRglhhhnj5g1fCgAgAfCgAfCfCfCfCfCfCfjfCfjfjeKfjeKeKfjeKfjfjfCfjfCfCgAfCgAgAfCgAfCfCfCfCfCfCfCfCfCfCgAfCgAgAfjgAfjfjfCfjfCfCfjfCfjfjfCfjfCfCgAfCgAgAfCgAfCfCfCfCfCfCfjfCfjfjeKfjeKeKfjeKfjfjfCfjfCfCgAfCgAgAtnfGQtQtQt", +"fufkfkfufQgufkfQfkgufkfQfufkgufQfufkfkfufQgufkfQfkgufkfQfufkgufQfufkfkfufQgufkfQfkgufkfQfufkgufQfufkfkfufQgufkfQfkgufkfQfufkgufQfufkfkfufQgufkfQfkgufkfQfufkgufQfufkfkfufQgufkfQfkgufkfQfufkgufQfufkfkfufQgufkfX.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rs5.rsWs5sWs6s6.r.rs2.rs3.r.9.9.9s6.M.9sA.r.r.rsH.r.r.MsA.M.F.F.F.MsH.M.F.M.M.M.FsH#1.F.F.F.F#9#9.F#9.F.F#1#1#1azazbEbEdIdzbEbEc3brcqbEc3d3d3d3dmdUdmdUdzdmc3c3c3dmeTdmfYe2e2e2e2eLfbeLe2fbfbfbfbe2fbeTfueTfbfbfuftfbfufkfbfkfQfQfugufkf5fufufufkgvfQgvgvgvgvgvgugufkglgugvgugugRglhhgRglgugRgRgRh0g1fjfCfjfjeKfjeKeKgAeKgAgAfCgAfCfCgAfCgAgAfjgAfjfjeKfjeKeKfjeKfjfjgAfjgAgAfjgAfjfjfjfjfjfjgAfjgAgAfjgAfjfjeKfjeKeKgAeKgAgAfCgAfCfCfjfCfjfjeKfjeKeKgAeKgAgAfCgAfCfCgAfCgAgAfjgAfjfjeKfjeKeKfjeKfjfjtoQtQtQtQt", +"fkfQgufQfkfufQgufufkgufkfQfQfugufkfQgufQfkfufQgufufkgufkfQfQfugufkfQgufQfkfufQgufufkgufkfQfQfugufkfQgufQfkfufQgufufkgufkfQfQfugufkfQgufQfkfufQgufufkgufkfQfQfugufkfQgufQfkfufQgufufkgufkfQfQfugufkfQgufQfkfufQgueL.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rs3.r.rsWsW.rsAs2sW.rtd.r.9.r.r.9sAsAsA.r.rsHsH.rsAsAtd.M.FsHsH.F.F.F.F.M.M.F.F.F#1.F#1.F#9#9#9#9.FsjsZ#1#9cqcqbEbEdzbEd3bEbEcqc3cqcqc3d3d3d3d3dmdmdUdmdmc3eLeLeTeMeLeoe2e2e2e2eLfueLeLfbe2dme2fbe2fbfueTfbfvfbfufbe2fkfbfkfufufQf5fWfkfugufkgufkgugvglgugufQfkhigugugugvfkglglgQhhguhhhDiseKgAeKgAgAfjgAfjfjeKfjeKeKfjeKfjfjfCfjfCfCfCfCfCfCfjfCfjfjeKfjeKeKfjeKfjfjfCfjfCfCeKfCeKeKfCeKfCfCfjfCfjfjgAfjgAgAfCgAfCfCeKfCeKeKgAeKgAgAfjgAfjfjeKfjeKeKfjeKfjfjfCfjfCfCfCfCfCfCfjfCfjfjeKfjeKeKhQQtQtQtQt", +"fufQfufufQgufufQfufQfufufQfufkfQfufQfufufQgufufQfufQfufufQfufkfQfufQfufufQgufufQfufQfufufQfufkfQfufQfufufQgufufQfufQfufufQfufkfQfufQfufufQgufufQfufQfufufQfufkfQfufQfufufQgufufQfufQfufufQfufkfQfufQfufufQgufufQfue2.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rt..rt.s5.r.rsW.rs2sA.rs3.r.r.r.rs6sAsWsAsAsH.rsH.r.F.rsA.M.M.MsH.MsHsA.F.FsK.M.F#1.F.F.F#1.F.F#9.M.F.M.Fbr#9azbEbEdObEdzbEdzd3cqbrcqdzc3cqdzdzd3dmd3dmd3dmdmeLeLd3eMdmeMeTdme2e2dme2eLeMeLeLeTdme2e2e2e2fbfvfbfvfbfbfue2fkfbfufufufufufufWfkfufufkgufkgvglgvgufkgufQguguglgRgvglgQglgRjMfCfCfjfCfjfjeKfjeKeKfjeKfjfjgAfjgAgAeKgAeKeKfjeKfjfjfCfjfCfCeKfCeKeKgAeKgAgAfCgAfCfCfjfCfjfjfjfjfjfjeKfjeKeKeKeKeKeKfjeKfjfjfCfjfCfCfjfCfjfjeKfjeKeKfjeKfjfjgAfjgAgAeKgAeKeKfjeKfjfjfCfjfCfCeKfCeKtpQtQtQtQtQt", +"fugufkfQfufkfQfkfQfkfugufQfufQfufugufkfQfufkfQfkfQfkfugufQfufQfufugufkfQfufkfQfkfQfkfugufQfufQfufugufkfQfufkfQfkfQfkfugufQfufQfufugufkfQfufkfQfkfQfkfugufQfufQfufugufkfQfufkfQfkfQfkfugufQfufQfufugufkfQfufkfQfkfQfkc3.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rs5.rs5.r.r.r.rs2sA.r.r.r.r.r.M.9sAsA.rsAsHsH.r.r.F.M.M.M.M.M.M.F.FsHsA.F.Msk.M#1.F.F.F.F.F.F.F#9sZbE#9brbEcqbrbEdObEbEbEdzdzdzcqbEcqdzdmbEdzd3dzd3dUdUdmdmdmdmeTeLeTdmeTdmdme2dme2eLeTeTfbfbfbeTe2fbe2fbfufufbfbfbe2fufufbfbfQfkgvgvfugufkfkfufkgugvgvglgvguhigvguglgugugRgRlheKfjfjeKfjeKeKfCeKfCfCfjfCfjfjeKfjeKeKeKeKeKeKfjeKfjfjeKfjeKeKgAeKgAgAfjgAfjfjeKfjeKeKfCeKfCfCfCfCfCfCfjfCfjfjfCfjfCfCeKfCeKeKfjeKfjfjeKfjeKeKfCeKfCfCfjfCfjfjeKfjeKeKeKeKeKeKfjeKfjfjeKfjeKeKgAeKgAtqQtQtQtQtQt", +"fQfufQfufQfufufkfQfufkfufufkfkfkfQfufQfufQfufufkfQfufkfufufkfkfkfQfufQfufQfufufkfQfufkfufufkfkfkfQfufQfufQfufufkfQfufkfufufkfkfkfQfufQfufQfufufkfQfufkfufufkfkfkfQfufQfufQfufufkfQfufkfufufkfkfkfQfufQfufQfufufkfQfufkbE.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rs5.rs5.rsWsW.rs6.rs2sA.r.r.9.9.rs6.rsAsAsW.rsH.rsH.rsY.M.MsA.F.M.9sH.MsHsA.M.M.M.F.F.F.F.F.F.F#9#9bE#9bE#9brbEbrbEbEdObEd3bEbEdzbEcqbrcqdzd3bEd3d3dmd3dUdUdzc3dmeMeTd3eTdmdmdme2e2dme2eLeLe2e2fbe2e2e2fbfufbfvfbfbeTfbe2fbfkfkfuf5fufugufkfufkfufufkgugvgvgvglgufufkgufkmsfCfjfCfCeKfCeKeKfjeKfjfjeKfjeKeKfCeKfCfCfjfCfjfjfCfjfCfCfCfCfCfCeKfCeKeKeKeKeKeKfjeKfjfjeKfjeKeKfjeKfjfjeKfjeKeKfjeKfjfjfjfjfjfjfCfjfCfCeKfCeKeKfjeKfjfjeKfjeKeKfCeKfCfCfjfCfjfjfCfjfCfCfCfCfCfCeKfCtrQtQtQtQtQtQt", +"fkfufufufQfkfQfkfufufQfQfufQfufQfkfufufufQfkfQfkfufufQfQfufQfufQfkfufufufQfkfQfkfufufQfQfufQfufQfkfufufufQfkfQfkfufufQfQfufQfufQfkfufufufQfkfQfkfufufQfQfufQfufQfkfufufufQfkfQfkfufufQfQfufQfufQfkfufufufQfkfQfkfufufQfQbr.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rt..r.r.rs5sW.rsWsAsWsA.r.r.9.r.Ms6.r.9sAsA.rsH.rsHsAsY.M.MsA.M.M.MsHsHsH.F.M.F.M.F#1sjsH#9az#9az#9bEbEbEazbrbEbrcqbEdObEbEbEdzdzbrcqcqcqc3d3bEd3d3dzd3dmdmdzdmdmdmeTeTeTfbdmdme2e2e2e2eTeTe2fbfbe2e2fbfbe2fbfufufbfbfbfufufkfQfQfuf5fQfWf5fufkfufuguguglglgvgvgufPeKeKeKeKeKfjeKfjfjfjfjfjfjeKfjeKeKeKeKeKeKfCeKfCfCeKfCeKeKfjeKfjfjdkfjdkdkeKdkeKeKfCeKfCfCfjfCfjfjfCfjfCfCdkfCdkdkeKdkeKeKeKeKeKeKeKeKeKeKfjeKfjfjfjfjfjfjeKfjeKeKeKeKeKeKfCeKfCfCeKfCeKeKfjeKfjfjdktsttQtQtQtQtQtQt", +"fbfQfkfQfufbfufbfkfQfufbfkfbfQfufbfQfkfQfufbfufbfkfQfufbfkfbfQfufbfQfkfQfufbfufbfkfQfufbfkfbfQfufbfQfkfQfufbfufbfkfQfufbfkfbfQfufbfQfkfQfufbfufbfkfQfufbfkfbfQfufbfQfkfQfufbfufbfkfQfufbfkfbfQfufbfQfkfQfufbfufbfkfQfufbfksZ.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rs5s3.rs3sWsWs6s2s2.r.rs3.r.9.r.9sAsAsAsA.9sA.r.r.rsY.MsA.M.FsH.F.F.F.F.F.M.M.M.F#9az.FazazazbEbE#9azbEazbEazbrbEbEc3bEdzd3bEcqcqbrcqcqdmd3dzd3dmdmd3dmc3dmc3eMeTd3eMeTfbdmeoe2eTeLe2eTe2eTfbdmeTe2e2fbfbeTfbfbeLfbfbfufkfufkfufkfkgvfWgvfugufufkfQgugQjffCfCfjfCfjfjeKfjeKeKdkeKdkdkeKdkeKeKfjeKfjfjeKfjeKeKfjeKfjfjeKfjeKeKfCeKfCfCfjfCfjfjeKfjeKeKeKeKeKeKeKeKeKeKfjeKfjfjfjfjfjfjfCfjfCfCfjfCfjfjeKfjeKeKdkeKdkdkeKdkeKeKfjeKfjfjeKfjeKeKfjeKfjfjeKfjeKeKfCtuQtQtQtQtQtQtQt", +"fufQfbfufkfufkfQfkfufkfufQfufkfufufQfbfufkfufkfQfkfufkfufQfufkfufufQfbfufkfufkfQfkfufkfufQfufkfufufQfbfufkfufkfQfkfufkfufQfufkfufufQfbfufkfufkfQfkfufkfufQfufkfufufQfbfufkfufkfQfkfufkfufQfufkfufufQfbfufkfufkfQfkfufkfufQfv#1.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rs5t..rs5s3.rsWs6sAs2sA.r.9.r.r.rsAsWsA.rsAsHsA.rsH.rsY.rsAsH.MsH.FsA.FsY.F.F.F#1sj#9az#9az#9azbE#9#9br#9azazazbrcqbEc3bEbEbEdzcqbrdzcqdzdmc3d3d3d3dmd3dmdzdzdmeLdmdmeTdmfbfce2e2e2eTe2eTe2dmfbe2e2e2fbfufbfufufufbfkfbfkfkfkfQfugvfugvfkgvfkgufujfgBeKeKdkeKdkdkeKdkeKeKfCeKfCfCeKfCeKeKfCeKfCfCdkfCdkdkeKdkeKeKeKeKeKeKeKeKeKeKfCeKfCfCdkfCdkdkfjdkfjfjfCfjfCfCeKfCeKeKeKeKeKeKeKeKeKeKdkeKdkdkeKdkeKeKfCeKfCfCeKfCeKeKfCeKfCfCdkfCdkdkeKdkeKeKeKeKeKeKtvhrQtQtQtQtQtQtQt", +"fufufkfbfQfbfufbfbfkfbfufbfQfufbfufufkfbfQfbfufbfbfkfbfufbfQfufbfufufkfbfQfbfufbfbfkfbfufbfQfufbfufufkfbfQfbfufbfbfkfbfufbfQfufbfufufkfbfQfbfufbfbfkfbfufbfQfufbfufufkfbfQfbfufbfbfkfbfufbfQfufbfufufkfbfQfbfufbfbfkfbfufbfQfusY.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rs5.rsWs3sWsW.rs2sWsA.r.r.r.9.9.rsAsAsWsA.9.rsHsAsAsY.M.M.MsA.FsH.F.FsA#1#1#1sj#9#9az.FskbEazazbr#9brrQazbEazbEbEbEdObEbEbEdzdzcqbEcqdzc3bEdzd3dzdzd3dmdmdmdmc3eLdmeTdmfbdme2dmdme2e2eTeLeLfbfbe2e2fbfue2fbfbfufbfbfbfufufufkfQgvgvf5fkf5hBhFfCeKeKfjeKfjfjfCfjfCfCdkfCdkdkfjdkfjfjeKfjeKeKfCeKfCfCdkfCdkdkfCdkfCfCfjfCfjfjeKfjeKeKeKeKeKeKeKeKeKeKfCeKfCfCdkfCdkdkfCdkfCfCeKfCeKeKfjeKfjfjfCfjfCfCdkfCdkdkfjdkfjfjeKfjeKeKfCeKfCfCdkfCdkdkfCdkfCfCtwQtQtQtQtQtQtQtQt", +"fQfkfbfufufkfufQfufufbfufkfbfufkfQfkfbfufufkfufQfufufbfufkfbfufkfQfkfbfufufkfufQfufufbfufkfbfufkfQfkfbfufufkfufQfufufbfufkfbfufkfQfkfbfufufkfufQfufufbfufkfbfufkfQfkfbfufufkfufQfufufbfufkfbfufkfQfkfbfufufkfufQfufufbfufkfbfufl.M.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rs5s3.rs2sWsW.r.r.rs3.rtd.9.rsA.9sAsAsHsAsAsA.r.r.rsA.M.M.FsH.Fsk#9#9#1#1#1#9.Fsk#9azazazbEazbEbEazbrbEazazbrbEbEbEbEdzd3bEcqcqcqdzc3bEdzd3d3dUdmdmdzdmeLc3eLeLeLeofbdmeoe2e2eTeTeTftfueTfve2fbfue2fbfvfbfbfbftfufkfkfbfufkfugVi.eKdkeKeKdkeKdkdkeKdkeKeKdkeKdkdkfCdkfCfCeKfCeKeKdkeKdkdkfjdkfjfjeKfjeKeKdkeKdkdkdkdkdkdkdkdkdkdkfjdkfjfjeKfjeKeKeKeKeKeKdkeKdkdkeKdkeKeKdkeKdkdkeKdkeKeKdkeKdkdkfCdkfCfCeKfCeKeKdkeKdkdkfjdkfjfjeKfjeKtxtyQtQtQtQtQtQtQtQt", +"fufbfufQfkfbfbfufbfbfkfufbfufufbfufbfufQfkfbfbfufbfbfkfufbfufufbfufbfufQfkfbfbfufbfbfkfufbfufufbfufbfufQfkfbfbfufbfbfkfufbfufufbfufbfufQfkfbfbfufbfbfkfufbfufufbfufbfufQfkfbfbfufbfbfkfufbfufufbfufbfufQfkfbfbfufbfbfkfufbfufufbeLsH.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rs5s5.rsW.r.rsW.rs2sWsA.r.r.9.r.9s6sAsAsWsAsA.rsH.rsAsY.M.rsA.Msk.M.F.FsK#9#9#1br#9#9sjaz#9azazbE#9azbE#9brazbrazbEbrdObEbEdId3bEbEbEcqdzcqc3d3c3dzd3d3dUdmdzdmc3eLeLeTdmeTeoe2fcdme2e2eTeTeoeTe2e2e2fbfkfbfkfbfkfufufue2fkfkgujTeKfCeKfCfCeKfCeKeKfjeKfjfjeKfjeKeKdkeKdkdkeKdkeKeKfCeKfCfCdkfCdkdkeKdkeKeKeKeKeKeKdkeKdkdkeKdkeKeKeKeKeKeKdkeKdkdkdkdkdkdkeKdkeKeKfCeKfCfCeKfCeKeKfjeKfjfjeKfjeKeKdkeKdkdkeKdkeKeKfCeKfCfCdkfCdkdkeKdktztAQtQtQtQtQtQtQtQtQt", +"fbfufbfbfbfufbfkfufbfufkfbfQfufbfbfufbfbfbfufbfkfufbfufkfbfQfufbfbfufbfbfbfufbfkfufbfufkfbfQfufbfbfufbfbfbfufbfkfufbfufkfbfQfufbfbfufbfbfbfufbfkfufbfufkfbfQfufbfbfufbfbfbfufbfkfufbfufkfbfQfufbfbfufbfbfbfufbfkfufbfufkfbfQfufbfbc3sA.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rt..rs5.rsWsWsAs2.r.r.r.r.9.r.r.rsWsAsAsA.rsAsHsAsA.M.F#1sk#1.F.FsK#9#9#9#1#1sj#9#9azazdHazazbEbErQbrbrbrbrbrbEbEbEdzbEd3bEd3cqcqdzcqc3c3d3d3d3dmdzdUdmdmc3dmeTeTdmeTeofYe2e2e2eoe2eTeTeTfbfudmfbe2fbe2fkfbfbfbfbfQlNdkdkeKdkeKeKdkeKdkdkdkdkdkdkeKdkeKeKdkeKdkdkdkdkdkdkeKdkeKeKdkeKdkdkdkdkdkdkfCdkfCfCeKfCeKeKdkeKdkdkeKdkeKeKeKeKeKeKfCeKfCfCdkfCdkdkeKdkeKeKdkeKdkdkdkdkdkdkeKdkeKeKdkeKdkdkdkdkdkdkeKdkeKeKdkeKdkdkdkdktBQtQtQtQtQtQtQtQtQtQt", +"fbfufufbfufbfbfufbfufbfbfufbfufkfbfufufbfufbfbfufbfufbfbfufbfufkfbfufufbfufbfbfufbfufbfbfufbfufkfbfufufbfufbfbfufbfufbfbfufbfufkfbfufufbfufbfbfufbfufbfbfufbfufkfbfufufbfufbfbfufbfufbfbfufbfufkfbfufufbfufbfbfufbfufbfbfufbfufkfbfubE.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rt.s5s5sW.r.rsWsWs2sA.r.r.9.9.r.9s6sAsA.r.rsA.r.rsA.F#1.9.F.F#1sksQ#9#9#1#9#9#1#1#9az.F#9azazazbE#9#9br#9brazbrbrbEbrbEbEdIdzd3bEbrbEdzbEdzc3d3d3dzd3dUdmdzc3eLc3dmdmdmdmdmfYe2e2dme2eTeTftfteTfve2e2e2fbfkfQfukcdkeKeKeKeKeKeKdkeKdkdkeKdkeKeKdkeKdkdkeKdkeKeKeKeKeKeKdkeKdkdkeKdkeKeKdkeKdkdkdkdkdkdkeKdkeKeKdkeKdkdkdkdkdkdkdkdkdkdkdkdkdkdkeKdkeKeKeKeKeKeKdkeKdkdkeKdkeKeKdkeKdkdkeKdkeKeKeKeKeKeKdkeKdkdkeKdkeKeKdktCQtQtQtQtQtQtQtQtQtQtQt", +"fbe2fbfue2fbfkfbfbfufkfbfufbe2fbfbe2fbfue2fbfkfbfbfufkfbfufbe2fbfbe2fbfue2fbfkfbfbfufkfbfufbe2fbfbe2fbfue2fbfkfbfbfufkfbfufbe2fbfbe2fbfue2fbfkfbfbfufkfbfufbe2fbfbe2fbfue2fbfkfbfbfufkfbfufbe2fbfbe2fbfue2fbfkfbfbfufkfbfufbe2fbfbe2fbbr.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rs3sWs5s3tlsW.rs2s2.r.r.r.9.M.M.9sAsWsAsA.rsA.F.M.M.M.F#1.F#1#9sk#9sK#9#9#1#1az#9#9#9azbEazazazbEaz#9azbrazbEcqbEbEbEdzbEdzdzdzcqbEbEc3dmdzd3eLdzdmdmdmdmc3dmdmeTeLdmfYfbe2e2e2e2eofueTeTfbfufueTe2fkfsdkeKdkdkdldkdldldkdldkdkeKdkeKeKdkeKdkdkdldkdldldkdldkdkdkdkdkdkdkdkdkdkeKdkeKeKeKeKeKeKdkeKdkdkeKdkeKeKeKeKeKeKdkeKdkdkeKdkeKeKdkeKdkdkdldkdldldkdldkdkeKdkeKeKdkeKdkdkdldkdldldkdldkdkdkdkdkdkdkdkdkdktDbHQtQtQtQtQtQtQtQtQtQtQt", +"tEfufbfbfufbfue2fufbe2fbfue2fufufbfufbfbfufbfue2fufbe2fbfue2fufufbfufbfbfufbfue2fufbe2fbfue2fufufbfufbfbfufbfue2fufbe2fbfue2fufufbfufbfbfufbfue2fufbe2fbfue2fufufbfufbfbfufbfue2fufbe2fbfue2fufufbfufbfbfufbfue2fufbe2fbfue2fufufbfufbfb#9.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rs5.rsWs5sWsW.rs2sWsW.r.r.9.r.M.MsAsAsWsYsAsA.F.9.M.M.F#1.F.F#1#9#9#9sk#9#1#1az#9#9#9azazazbEazaz#9brrQbrbEazcqbEbEbEdzbEbEdIdzdzbrcqdzc3bEc3eLdmc3dmdUdmc3dzdmdmdmeTdmfYdme2dmdme2e2eLeTfteLfu.UdleKdleKeKdkeKdkdkeKdkeKeKdleKdldldkdldkdkeKdkeKeKeKeKeKeKdkeKdkdkeKdkeKeKdleKdldldkdldkdkeKdkeKeKdleKdldleKdleKeKdkeKdkdkdldkdldleKdleKeKdkeKdkdkeKdkeKeKdleKdldldkdldkdkeKdkeKeKeKeKeKeKdkeKdkdkeKdkeKtFtGQtQtQtQtQtQtQtQtQtQtQtQt", +"QtfytHtIfbfbfbfbe2fbfufbfufbfbe2fufbfufbfbfbfbfbe2fbfufbfufbfbe2fufbfufbfbfbfbfbe2fbfufbfufbfbe2fufbfufbfbfbfbfbe2fbfufbfufbfbe2fufbfufbfbfbfbfbe2fbfufbfufbfbe2fufbfufbfbfbfbfbe2fbfufbfufbfbe2fufbfufbfbfbfbfbe2fbfufbfufbfbe2fufbfufbeT.F.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rs5.r.rsW.rs2s2sA.r.r.r.r.r.r.9sY.F.F.FsA.F.9.M#1.9.9.F#1#1.Fsk.F#9#9#9#1br#9#9sj#9#9azazazbEbEbrrQbEbrbEbrbEbEdObEbEdzdzd3cqc3cqdzcqc3d3c3dzdzd3dmdmdmdmdmeTc3eTdmeTeodmfcdmeoe2eTeThRfjdkdkdkdkdkdkdkdkdkdkdkdkdkeKdkeKeKdkeKdkdkdkdkdkdkdkdkdkdkcVdkcVcVdkcVdkdkdkdkdkdkeKdkeKeKdkeKdkdkdkdkdkdkdldkdldleKdleKeKdkeKdkdkdkdkdkdkdkdkdkdkdkdkdkdkeKdkeKeKdkeKdkdkdkdkdkdkdkdkdkdkcVdkcVcVdkcVtJe6QtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtfotKtLfbfbfbfue2fbeLfbfufbeLfbfbeLfbfufbfbfbfue2fbeLfbfufbeLfbfbeLfbfufbfbfbfue2fbeLfbfufbeLfbfbeLfbfufbfbfbfue2fbeLfbfufbeLfbfbeLfbfufbfbfbfue2fbeLfbfufbeLfbfbeLfbfufbfbfbfue2fbeLfbfufbeLfbfbeLfbfufbfbfbfue2fbeLfbfufbeLfbfbeLfbfu.F.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rt.s5s5.r.rsW.rs2.r.r.r.r.rsW.9.r.9.FsH.F.F.M.F.9.M#1#1#1#1.Msk.Fsk#9sk#9br#1sj.F#9azazazaz#9bEazrQaz#9brazazcqbEbEbrdzdzd3bEbEcqdzc3dzdzc3dzeLdmdzdUdmdmeLeLc3eLdmdmdmdmfce2e2hnhHdkdkcVdkcVcVdkcVdkdkdkdkdkdkdkdkdkdkcVdkcVcVeKcVeKeKdkeKdkdkeKdkeKeKdkeKdkdkcVdkcVcVdkcVdkdkeKdkeKeKdkeKdkdkdkdkdkdkeKdkeKeKdkeKdkdkcVdkcVcVdkcVdkdkdkdkdkdkdkdkdkdkcVdkcVcVeKcVeKeKdkeKdkdkeKdkeKeKdktMtNQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQt#htOtPeLfbfufbfbfbe2fbfbfbfufbfbeLfbfueLfbfufbfbfbe2fbfbfbfufbfbeLfbfueLfbfufbfbfbe2fbfbfbfufbfbeLfbfueLfbfufbfbfbe2fbfbfbfufbfbeLfbfueLfbfufbfbfbe2fbfbfbfufbfbeLfbfueLfbfufbfbfbe2fbfbfbfufbfbeLfbfueLfbfufbfbfbe2fbfbfbfufbfbeLfbsH.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rs5.rs3.rsWsW.rs6sAsW.r.r.r.r.r.9.F.9.FsHsA.M.F.M#1.M#1.F#1#1.FsksQsk#9sk#1#1br#1sj#9azazazazbEbE#9bEbrrQbEbEcqbrcqbEdzdzd3d3cqdzbrcqcqdzbEd3c3d3d3dmdUdmdmeLeLc3dmeTeTdmfki.dldkdkeKdkeKeKdkeKdkdkcVdkcVcVeKcVeKeKdkeKdkdkcVdkcVcVdkcVdkdkdkdkdkdkdldkdldldkdldkdkcVdkcVcVdkcVdkdkdkdkdkdkcVdkcVcVdlcVdldldkdldkdkeKdkeKeKdkeKdkdkcVdkcVcVeKcVeKeKdkeKdkdkcVdkcVcVdkcVdkdkdkdkdkdktQtAQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQte5tRtSeLfbeLfbfbeLfbeLeLfbfueLfbeLfbeLeLfbeLfbfbeLfbeLeLfbfueLfbeLfbeLeLfbeLfbfbeLfbeLeLfbfueLfbeLfbeLeLfbeLfbfbeLfbeLeLfbfueLfbeLfbeLeLfbeLfbfbeLfbeLeLfbfueLfbeLfbeLeLfbeLfbfbeLfbeLeLfbfueLfbeLfbeLeLfbeLfbfbeLfbeLeLfbfueLeL.9.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rt..rs3.rsWtlsWs2sWsY.r.r.r.9.r.r.M.9.F.F.MsAsA.9.M.F.9.F#1sk#1.FsQ.F#9#9#1#1#1#9#1sj#9azazazazbErQbEbrefbEazbEbEbrcqbEdzbEdId3cqbrcqcqcqbEd3d3dzd3dmdmdmdmdzdmeLdmfbi2cVdkcVcVcVcVcVcVdkcVdkdkdkdkdkdkdkdkdkdkdldkdldldkdldkdkdkdkdkdkcVdkcVcVdkcVdkdkdkdkdkdkdldkdldldkdldkdkdkdkdkdkdkdkdkdkdkdkdkdkcVdkcVcVcVcVcVcVdkcVdkdkdkdkdkdkdkdkdkdkdldkdldldkdldkdkdkdkdkdkcVdkcVtTtUQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtb4tVtWeLfbeLe2fbfbfbeLfbfbe2fbfbeLfbfbeLfbeLe2fbfbfbeLfbfbe2fbfbeLfbfbeLfbeLe2fbfbfbeLfbfbe2fbfbeLfbfbeLfbeLe2fbfbfbeLfbfbe2fbfbeLfbfbeLfbeLe2fbfbfbeLfbfbe2fbfbeLfbfbeLfbeLe2fbfbfbeLfbfbe2fbfbeLfbfbeLfbeLe2fbfbfbeLfbfbe2dU.9.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rs5.r.rs5s3s5.r.r.r.r.F.r.r.r.9.r.F.F.F.F.F.F.FsA.F.M#1#1#1#1sk#1.M.F.Fazaz#9az#1sj#9sjsk#9azazaz#9azbEbrbrbrbrbrbEbEdObEbEd3bEd3bEbEcqc3dmc3dzdmdmdzdmdmdmdUeSjSdldkdldkdkdkdkdkdkcVdkcVcVdkcVdkdkcVdkcVcVdkcVdkdkdkdkdkdkcVdkcVcVcVcVcVcVdkcVdkdkcVdkcVcVdkcVdkdkdkdkdkdkcVdkcVcVdkcVdkdkdldkdldldkdldkdkdkdkdkdkcVdkcVcVdkcVdkdkcVdkcVcVdkcVdkdkdkdkdkdkcVdkcVcVcVcVtXfzQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtbYtYtZfbfbeLfbdmfbeLeLfbfbdmfbe2dmfbfbfbfbeLfbdmfbeLeLfbfbdmfbe2dmfbfbfbfbeLfbdmfbeLeLfbfbdmfbe2dmfbfbfbfbeLfbdmfbeLeLfbfbdmfbe2dmfbfbfbfbeLfbdmfbeLeLfbfbdmfbe2dmfbfbfbfbeLfbdmfbeLeLfbfbdmfbe2dmfbfbfbfbeLfbdmfbeLeLfbfbbE.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rs3t.sWs3tl.r.r.r.r.r.r.r.r.r.r.F.F.9.9.FsA.F.M.F.9#1.9#1#1.F#1.F.FsKsk#9#1#1#1sj#9.F.FazazbEaz#9azrQrQbrbrbEazcqbEbEbEd3d3dIdzbEbEdzdzdmd3dmdzfcdmdUk0dkdkcVdkcVcVdkcVdkdkdkdkdkdkdkdkdkdkcVdkcVcVdkcVdkdkcVdkcVcVdkcVdkdkdkdkdkdkdkdkdkdkdkdkdkdkdldkdldlcVdlcVcVdkcVdkdkcVdkcVcVdkcVdkdkcVdkcVcVdkcVdkdkdkdkdkdkdkdkdkdkcVdkcVcVdkcVdkdkcVdkcVcVdkcVdkdkdkt0chQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtejt1t2eLeLfbfbfbfbeLeLfbfbeLfbeLfbfbeLeLeLfbfbfbfbeLeLfbfbeLfbeLfbfbeLeLeLfbfbfbfbeLeLfbfbeLfbeLfbfbeLeLeLfbfbfbfbeLeLfbfbeLfbeLfbfbeLeLeLfbfbfbfbeLeLfbfbeLfbeLfbfbeLeLeLfbfbfbfbeLeLfbfbeLfbeLfbfbeLeLeLfbfbfbfbeLeLbE.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rt.s5s5tl.r.r.rsH.r.r.r.r.M.M.r.r.9.F.FsA.F.F.F.F#1#1#1#1.F#1.F.FsKaz#9#1#1sjsj#9az#9azazazazbEbErQbrbrazbEcqcqdzbrbEdzd3dzd3cqcqdzc3c3d3d3fPdkdkdkcEdkcEcEcVcEcVcVcEcVcEcEcVcEcVcVdkcVdkdkdkdkdkdkcVdkcVcVcVcVcVcVdkcVdkdkcVdkcVcVdkcVdkdkcEdkcEcEcVcEcVcVdkcVdkdkdkdkdkdkdkdkdkdkcEdkcEcEcVcEcVcVcEcVcEcEcVcEcVcVdkcVdkdkdkdkdkdkcVdkcVcVcVcVcVt3t4QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtt5e#t6eLdmeLdmfbfbeLdmfbdmfbeLdmfbfbfbeLdmeLdmfbfbeLdmfbdmfbeLdmfbfbfbeLdmeLdmfbfbeLdmfbdmfbeLdmfbfbfbeLdmeLdmfbfbeLdmfbdmfbeLdmfbfbfbeLdmeLdmfbfbeLdmfbdmfbeLdmfbfbfbeLdmeLdmfbfbeLdmfbdmfbeLdmfbfbfbeLdmeLdmfbfbeLsk.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rt..r.rsW.r.9.M.F.F.rs3.r.r.9.M.r.9.FsH.M.FsAsA.F.F#1.F#1.Fsk#9.F#9azsk#1az#1#1sjazazazazdIbEazbrrQbrrQrQcqazbrcqdzbEdzd3dIbEdzcqdzcqj2cEcVcEcEdkcEdkdkdkdkdkdkdkdkdkdkdkdkdkdkcVdkcVcVcEcVcEcEcVcEcVcVdkcVdkdkcVdkcVcVdkcVdkdkcEdkcEcEdkcEdkdkdkdkdkdkcVdkcVcVcVcVcVcVcEcVcEcEdkcEdkdkdkdkdkdkdkdkdkdkdkdkdkdkcVdkcVcVcEcVcEcEcVcEcVcVdkcVt7tNQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtert8t9fbfbfbeLfbeLfbeLfbeLdmfbdmeLfbeLfbfbfbeLfbeLfbeLfbeLdmfbdmeLfbeLfbfbfbeLfbeLfbeLfbeLdmfbdmeLfbeLfbfbfbeLfbeLfbeLfbeLdmfbdmeLfbeLfbfbfbeLfbeLfbeLfbeLdmfbdmeLfbeLfbfbfbeLfbeLfbeLfbeLdmfbdmeLfbeLfbfbfbeLfbeL#1.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rt.sWs3sWsW.r.F.r.FsHs3.r.r.r.M.9.9.9.F.MsA.9.F.M.F.M.F#1#1.F#9sksKsk#9#1#1#9sjrQazrQazazazbEazbErQrQbrbEazazbrbEdObEdzdzd3cqhDdkdkdkdkdkcVdkcVcVcVcVcVcVcEcVcEcEcEcEcEcEcVcEcVcVdkcVdkdkcVdkcVcVdkcVdkdkcEdkcEcEcVcEcVcVcVcVcVcVcVcVcVcVdkcVdkdkcEdkcEcEdkcEdkdkdkdkdkdkcVdkcVcVcVcVcVcVcEcVcEcEcEcEcEcEcVcEcVcVdkcVdkdkcVdkcVcVdku..BQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtu#uaubfbdmeLdmfbdmdmeLeLfbdmfbdmeLdmdmfbdmeLdmfbdmdmeLeLfbdmfbdmeLdmdmfbdmeLdmfbdmdmeLeLfbdmfbdmeLdmdmfbdmeLdmfbdmdmeLeLfbdmfbdmeLdmdmfbdmeLdmfbdmdmeLeLfbdmfbdmeLdmdmfbdmeLdmfbdmdmeLeLfbdmfbdmeLdmdmfbdmeLc3.F.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rs5.rsW.9.r.r.F.rs3.r.9.9.M.r.r.9.F.FsAsA.F.9.F#1.F#1.Fsk#1.F.F.F#9az#1#1sjskrQ#1azazazazazbEbEbEbrbrbEbrbEbEbrbEdzgleKcEdkcEdkdkcEdkcEcEdkcEdkdkdddkdddddkdddkdkdkdkdkdkcEdkcEcEdkcEdkdkcVdkcVcVdkcVdkdkcEdkcEcEdkcEdkdkdkdkdkdkcVdkcVcVddcVddddcEddcEcEdkcEdkdkcEdkcEcEdkcEdkdkdddkdddddkdddkdkdkdkdkdkcEdkcEcEdkcEdkucudQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQteaueufeLfbdmeLfbfbfbdmeLeLfbeLfbeLeTdmeLfbdmeLfbfbfbdmeLeLfbeLfbeLeTdmeLfbdmeLfbfbfbdmeLeLfbeLfbeLeTdmeLfbdmeLfbfbfbdmeLeLfbeLfbeLeTdmeLfbdmeLfbfbfbdmeLeLfbeLfbeLeTdmeLfbdmeLfbfbfbdmeLeLfbeLfbeLeTdmeLfbdU.9.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rt.s5.r.rsW.r.r.9.F.rs3.r.r.r.r.9.9.F.F.F.M.F.F.M.F#1.F.F#1.M.Fskskazazsk#1sjaz#9azskazazaz#9bEbErQbrdzrQbEbEcqeTfjdkdkcVdkcVcVcVcVcVcVcEcVcEcEcEcEcEcEcEcEcEcEcVcEcVcVcEcVcEcEdkcEdkdkcVdkcVcVcEcVcEcEdkcEdkdkcVdkcVcVcEcVcEcEcEcEcEcEcEcEcEcEdkcEdkdkcVdkcVcVcVcVcVcVcEcVcEcEcEcEcEcEcEcEcEcEcVcEcVcVcEcVcEcEdkuguhQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtd6uiujeLdmdmeLdmeLfbfbdmdmeLdmdmfbdmdmeLdmdmeLdmeLfbfbdmdmeLdmdmfbdmdmeLdmdmeLdmeLfbfbdmdmeLdmdmfbdmdmeLdmdmeLdmeLfbfbdmdmeLdmdmfbdmdmeLdmdmeLdmeLfbfbdmdmeLdmdmfbdmdmeLdmdmeLdmeLfbfbdmdmeLdmdmfbdmdmeLdU.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rt..r.rsWsW.r.r.FsH.rsH.9.M.r.F.9.9.FsHsAsA.F.9#1.M#1.F.F.F#1.Fsksk#9sk#1#1sj#9sj#9azazazazaz#9bErQbErQeSi.ddcVcVcEcVcEcEcEcEcEcEddcEdddddkdddkdkcVdkcVcVdkcVdkdkcVdkcVcVcEcVcEcEcVcEcVcVdkcVdkdkcEdkcEcEcVcEcVcVcVcVcVcVcEcVcEcEddcEddddcVddcVcVcEcVcEcEcEcEcEcEddcEdddddkdddkdkcVdkcVcVdkcVdkdkcVdkcVukulabQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtumunubdmeTdmdmdmeLdmfbeTdmeLfbdmfbeTdmdmeTdmdmdmeLdmfbeTdmeLfbdmfbeTdmdmeTdmdmdmeLdmfbeTdmeLfbdmfbeTdmdmeTdmdmdmeLdmfbeTdmeLfbdmfbeTdmdmeTdmdmdmeLdmfbeTdmeLfbdmfbeTdmdmeTdmdmdmeLdmfbeTdmeLfbdmfbeTcq.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rs5.r.r.r.r.r.r.r.F.9sH.r.r.r.9.9.F.F.FsH.F.M.F.M.F.M.F#1.F#1sksk#9.Fazskaz#1sj#9sj#9#9azazazazaz#9c3jrcVcEcVcVddcVdddddkdddkdkcEdkcEcEcVcEcVcVcEcVcEcEcEcEcEcEddcEddddcEddcEcEcEcEcEcEcVcEcVcVcEcVcEcEcEcEcEcEdkcEdkdkdkdkdkdkcEdkcEcEcVcEcVcVddcVdddddkdddkdkcEdkcEcEcVcEcVcVcEcVcEcEcEcEcEcEdduoupaaQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtbbuqureTdmeLdmdmeLdmeLdmdmeLdmdmfbdmeLeTdmeLdmdmeLdmeLdmdmeLdmdmfbdmeLeTdmeLdmdmeLdmeLdmdmeLdmdmfbdmeLeTdmeLdmdmeLdmeLdmdmeLdmdmfbdmeLeTdmeLdmdmeLdmeLdmdmeLdmdmfbdmeLeTdmeLdmdmeLdmeLdmdmeLdmdmfbdH.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rt.s5.r.rtl.9.9.r.rsH.r.r.9.r.r.9.9sH.F.FsAsA.M.9.M.F#1#1sk#1.F.Fsk#9azr9#1#1#1#1rQbrazazazlhcEcEcEcEcEcEcEcEcEcEcEcEcEcVcEcVcVcVcVcVcVcEcVcEcEddcEddddcEddcEcEcVcEcVcVdkcVdkdkcEdkcEcEcVcEcVcVcEcVcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcVcEcVcVcVcVcVcVcEcVcEcEddcEddusutabQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtdLdouudmdmfbdmdmdmfbdmeLdmdmdmdmdmdmeLdmdmfbdmdmdmfbdmeLdmdmdmdmdmdmeLdmdmfbdmdmdmfbdmeLdmdmdmdmdmdmeLdmdmfbdmdmdmfbdmeLdmdmdmdmdmdmeLdmdmfbdmdmdmfbdmeLdmdmdmdmdmdmeLdmdmfbdmdmdmfbdmeLdmdmdmdmbr.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rs5.rs5s5s5.r.M.rsH.F.r.r.r.9.9.9.F#1sH.F.F.FsA.9.M.F.F#1#1sksksksQ.F#9azazaz#1rQrQazfPddddcEddcEcEcEcEcEcEddcEddddcEddcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEddcEddddcEddcEcEcEcEcEcEddcEddddcEddcEcEcEcEcEcEddcEddddcEddcEcEcEcEcEcEcEcEcEcEuvfAuwQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt.kuxuyuzdmeTdmdmdmdmdmeLeLdmeTdmdmeTdmeLdmeTdmdmdmdmdmeLeLdmeTdmdmeTdmeLdmeTdmdmdmdmdmeLeLdmeTdmdmeTdmeLdmeTdmdmdmdmdmeLeLdmeTdmdmeTdmeLdmeTdmdmdmdmdmeLeLdmeTdmdmeTdmeLdmeTdmdmdmdmdmeLeLdmeTsj.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rs5.rs5sWs5.9.9.r.rsH.r.r.r.9.9.9.M.F.9.M.F.FsAsA.9.M#1.F#1sksksk#9.Fsk.Fazaz#1dGcEcEcEcVcEcVcVcEcVcEcEcEcEcEcEcVcEcVcVcEcVcEcEddcEddddcEddcEcEcEcEcEcEddcEddddcVddcVcVcEcVcEcEcVcEcVcVcEcVcEcEcEcEcEcEcEcEcEcEcEcEcEcEcVcEcVcVcEcVcEcEcEcEcEcEcVcEcVcVcEcVcEcEddcEuAfpuBQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtduuCuDdmdmdmeLdmdmdmdmdmeLdmdmdmdmdmdmdmdmdmeLdmdmdmdmdmeLdmdmdmdmdmdmdmdmdmeLdmdmdmdmdmeLdmdmdmdmdmdmdmdmdmeLdmdmdmdmdmeLdmdmdmdmdmdmdmdmdmeLdmdmdmdmdmeLdmdmdmdmdmdmdmdmdmeLdmdmdmdmdmeL.F.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rs5s5.rsW.r.r.9.F.9.rsH.9.9.r.r.9.F.F.F.M.F.M.M.F.M#1.Fsk.F#1.F.Fazazh0cEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcVcEcVcVcEcVcEcEcEcEcEcEcEcEcEcEcDcEcDcDcEcDcEcEcEcEcEcEcVcEcVcVcEcVcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEfgffabQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtdpc5uEdmc3dmeLdmc3dmdmc3dmeLdmdmdmdmdmdmc3dmeLdmc3dmdmc3dmeLdmdmdmdmdmdmc3dmeLdmc3dmdmc3dmeLdmdmdmdmdmdmc3dmeLdmc3dmdmc3dmeLdmdmdmdmdmdmc3dmeLdmc3dmdmc3dmeLdmdmdmdmdmdmc3dmeLdmc3dmdmd9.F.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rs5s5s5.rsW.rsW.r.9.r.rsHs3.r.r.M.M.F.F.FsA.F.M.9sK.M.MsK.F#1.F.FfkeKcEcVcEcEcEcEcEcEcVcEcVcVcEcVcEcEcDcEcDcDcEcDcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcVcEcVcVcEcVcEcEcDcEcDcDcEcDcEcEcVcEcVcVcEcVcEcEcEcEcEcEcVcEcVcVcEcVcEcEcDcEcDcDcEuFe7uGQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtabcZuHdmdmdmdmdmdmdmdmc3dmeLdzdmdmdmdmdmdmdmdmdmdmdmdmc3dmeLdzdmdmdmdmdmdmdmdmdmdmdmdmc3dmeLdzdmdmdmdmdmdmdmdmdmdmdmdmc3dmeLdzdmdmdmdmdmdmdmdmdmdmdmdmc3dmeLdzdmdmdmdmdmdmdmdmdmdmdmeu.F.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rs5s5.r.rsW.r.9.r.F.r.r.rtd.r.r.9.F.F.F.F.M.FsA.F.M.M#1#1eTfjcEcEcEcEcEcDcEcDcDcEcDcEcEcEcEcEcEcEcEcEcEcEcEcEcEcDcEcDcDcVcDcVcVcEcVcEcEcDcEcDcDcEcDcEcEcEcEcEcEcEcEcEcEcEcEcEcEcDcEcDcDcEcDcEcEcEcEcEcEcDcEcDcDcEcDcEcEcEcEcEcEcEcEcEuIuJfMQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtdauKuLc3dmc3c3dmeLc3dmc3dmc3dzdmc3dmdmc3dmc3c3dmeLc3dmc3dmc3dzdmc3dmdmc3dmc3c3dmeLc3dmc3dmc3dzdmc3dmdmc3dmc3c3dmeLc3dmc3dmc3dzdmc3dmdmc3dmc3c3dmeLc3dmc3dmc3dzdmc3dmdmc3dmc3c3dmdzsA.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rt..rsW.rsW.9.r.M.F.rsAsA.9sA.r.r.M.F.9.F.MsA.FsAcqhHcEcEcEcEcEcEcEcEcEcEcEcEcEcEcDcEcDcDcCcDcCcCcEcCcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcDcEcDcDcEcDcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcDcEcDcDcCuMuN#zQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtc6uOuPdmdmc3dmdmdmdmdmdmdmdmc3dmdzdmdmdmdmc3dmdmdmdmdmdmdmdmc3dmdzdmdmdmdmc3dmdmdmdmdmdmdmdmc3dmdzdmdmdmdmc3dmdmdmdmdmdmdmdmc3dmdzdmdmdmdmc3dmdmdmdmdmdmdmdmc3dmdzdmdmdmdmc3dmcqsA.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rsW.rsWsW.r.9.FsH.r.r.r.9.r.r.9.F.9.FskjvcEcEcEcCcEcCcCcEcCcEcEcEcEcEcEcEcEcEcEcEcEcEcEcDcEcDcDcEcDcEcEcDcEcDcDcEcDcEcEcEcEcEcEbDcEbDbDcEbDcEcEcEcEcEcEcCcEcCcCcEcCcEcEcEcEcEcEcCcEcCcCcEcCcEcEcEcEcEcEcEcEe8uQttQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtf1csuRdmbEc3dmdmbEdmdmbEdmdmdmdmdzdmbEdmbEc3dmdmbEdmdmbEdmdmdmdmdzdmbEdmbEc3dmdmbEdmdmbEdmdmdmdmdzdmbEdmbEc3dmdmbEdmdmbEdmdmdmdmdzdmbEdmbEc3dmdmbEdmdmbEdmdmdmdmdzdmbEdmbEc3bE.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rs5.rs5.rsWs3sWsW.r.r.F.r.rs3.r.r.r.rsYk0cDcEcDcDcEcDcEcEcCcEcCcCcEcCcEcEcDcEcDcDcEcDcEcEcEcEcEcEcEcEcEcEbDcEbDbDcEbDcEcEcDcEcDcDcEcDcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcEcDcEcDcDcEcDcEcEcCcEcCcCcEcCcEcEuSezuTQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtuUuVuWdmbEc3dmdmc3dmdzdmdmc3c3dmdmdmdmdmbEc3dmdmc3dmdzdmdmc3c3dmdmdmdmdmbEc3dmdmc3dmdzdmdmc3c3dmdmdmdmdmbEc3dmdmc3dmdzdmdmc3c3dmdmdmdmdmbEc3dmdmc3dmdzdmdmc3c3dmdmdmdmdmsk.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rt..rs5.rs5s3.r.r.r.9sH.r.rsA.rjUbDcDbDcDcDcEcDcEcEcEcEcEcEcEcEcEcEbDcEbDbDcDbDcDcDbDcDbDbDcDbDcDcDcEcDcEcEcEcEcEcEcCcEcCcCbDcCbDbDcEbDcEcEcDcEcDcDcEcDcEcEbDcEbDbDcDbDcDcDcEcDcEcEcEcEcEcEcEcEetuX#hQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtahuYuZdmc3bEdmbEdmc3bEdmdmdmbEbEc3bEdmdmc3bEdmbEdmc3bEdmdmdmbEbEc3bEdmdmc3bEdmbEdmc3bEdmdmdmbEbEc3bEdmdmc3bEdmbEdmc3bEdmdmdmbEbEc3bEdmdmc3bEdmbEdmc3bEdmdmdmbEbEc3bEdmaz.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rt..rsW.rs3sW.r.F.r.raycEcEcEcEcEcEbDcEbDbDcDbDcDcDbDcDbDbDcEbDcEcEcEcEcEcEcEcEcEcEcEcEcEcEcDcEcDcDbDcDbDbDcEbDcEcEcEcEcEcEcDcEcDcDcEcDcEcEbDcEbDbDcEbDcEcEcEcEcEcEbDcEbDbDcDbDcDu0u1bAQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtaau2u3c3dmc3dmc3bEdmbEdzdmc3dmdmdmbEdmc3dmc3dmc3bEdmbEdzdmc3dmdmdmbEdmc3dmc3dmc3bEdmbEdzdmc3dmdmdmbEdmc3dmc3dmc3bEdmbEdzdmc3dmdmdmbEdmc3dmc3dmc3bEdmbEdzdmc3dmdmdmbEsk.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rs5s3.rsW.9.rhnbDcDcDcEcDcEcEbDcEbDbDcEbDcEcEcEcEcEcEcDcEcDcDcDcDcDcDbDcDbDbDbDbDbDbDcDbDcDcDcEcDcEcEbDcEbDbDcEbDcEcEbDcEbDbDcDbDcDcDbDcDbDbDcDbDcDcDcEcDcEcEbDcEbDbDcEu4u5u6QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtcmu7u8bEbEc3bEdmbEdmbEbEbEbEdmbEc3bEdmbEbEc3bEdmbEdmbEbEbEbEdmbEc3bEdmbEbEc3bEdmbEdmbEbEbEbEdmbEc3bEdmbEbEc3bEdmbEdmbEbEbEbEdmbEc3bEdmbEbEc3bEdmbEdmbEbEbEbEdmbE.F.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rt..rt.fbdycEcEcEcDcEcDcDcDcDcDcDbDcDbDbDcEbDcEcEbDcEbDbDcEbDcEcEcEcEcEcEcEcEcEcEcEcEcEcEbDcEbDbDcEbDcEcEcDcEcDcDcEcDcEcEbDcEbDbDcEbDcEcEcEcEcEcEcDcEcDcDcDcDcDu9d7bHQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt#Wv.fmdmdmbEc3bEdmc3dmc3c3bEc3dmbEc3dmdmdmbEc3bEdmc3dmc3c3bEc3dmbEc3dmdmdmbEc3bEdmc3dmc3c3bEc3dmbEc3dmdmdmbEc3bEdmc3dmc3c3bEc3dmbEc3dmdmdmbEc3bEdmc3dmc3c3bEc3sA.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rdmeKbDcDbDbDbDbDbDbDbDbDbDbDcEbDcEcEbDcEbDbDcDbDcDcDbDcDbDbDbDbDbDbDbDbDbDbDcDbDcDcDbDcDbDbDcEbDcEcEbDcEbDbDbDbDbDbDcEbDcEcEcDcEcDcDbDcDbDbDbDbDbDbDv#vadZQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt#hvbvccqdmdmbEbEc3bEbEdmbEbEc3bEbEc3bEcqdmdmbEbEc3bEbEdmbEbEc3bEbEc3bEcqdmdmbEbEc3bEbEdmbEbEc3bEbEc3bEcqdmdmbEbEc3bEbEdmbEbEc3bEbEc3bEcqdmdmbEbEc3bEbEdmbE#9.9.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rbrgAcDcDcDcDcDbDcDbDbDcDbDcDcDcvcDcvcvbDcvbDbDbDbDbDbDcDbDcDcDcEcDcEcEbDcEbDbDcEbDcEcEcDcEcDcDbDcDbDbDcDbDcDcDcEcDcEcEbDcEbDbDcDbDcDcDcDcDcDcDbDcDvdvevfQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtvgvhb7c3bEdmc3bEcqdmbEdmc3bEbEc3bEbEbEc3bEdmc3bEcqdmbEdmc3bEbEc3bEbEbEc3bEdmc3bEcqdmbEdmc3bEbEc3bEbEbEc3bEdmc3bEcqdmbEdmc3bEbEc3bEbEbEc3bEdmc3bEcqdmbEc3sA.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rskhFbDbDcEbDcEcEcEcEcEcEbDcEbDbDcDbDcDcDcDcDcDcDcEcDcEcEbDcEbDbDcvbDcvcvbDcvbDbDbDbDbDbDcDbDcDcDbDcDbDbDbDbDbDbDcDbDcDcDbDcDbDbDbDbDbDbDcEbDcEcEvivjh8QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtb4vkvlc3bEc3bEbEc3bEcqdmbEc3dmbEcqbEbEc3bEc3bEbEc3bEcqdmbEc3dmbEcqbEbEc3bEc3bEbEc3bEcqdmbEc3dmbEcqbEbEc3bEc3bEbEc3bEcqdmbEc3dmbEcqbEbEc3bEc3bEbEc3bEaz.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rsAj4cDbDbDbDbDbDbDbDbDbDbDbDbDbDbDbDbDbDbDbDbDbDbDbDbDbDbDcDbDcDcDcDcDcDcDbDcDbDbDcDbDcDcDbDcDbDbDcDbDcDcDcEcDcEcEbDcEbDbDcDbDcDcDbDcDbDbDbDvmvndDQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtbYvobWcqdmbEc3bEbEbEbEbEbEc3bEbEdmbEbEcqdmbEc3bEbEbEbEbEbEc3bEbEdmbEbEcqdmbEc3bEbEbEbEbEbEc3bEbEdmbEbEcqdmbEc3bEbEbEbEbEbEc3bEbEdmbEbEcqdmbEc3bEbE#9.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rl1cEbDcEcEcvcEcvcvbDcvbDbDcEbDcEcEbDcEbDbDbDbDbDbDcDbDcDcDbDcDbDbDbDbDbDbDbDbDbDbDcvbDcvcvbDcvbDbDbDbDbDbDbDbDbDbDbDbDbDbDbDbDbDbDcEbDcEvpdwtGQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtvqvrvscqbEc3cqbEc3bEbEc3bEc3bEc3bEbEbEcqbEc3cqbEc3bEbEc3bEc3bEc3bEbEbEcqbEc3cqbEc3bEbEc3bEc3bEc3bEbEbEcqbEc3cqbEc3bEbEc3bEc3bEc3bEbEbEcqbEc3cq#9.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rfscDbDcDbDbDbDbDbDbDcvbDcvcvbDcvbDbDcDbDcDcDbDcDbDbDbDbDbDbDcDbDcDcDbDcDbDbDcDbDcDcDbDcDbDbDbDbDbDbDcDbDcDcDcvcDcvcvbDcvbDbDcDbDcDcDbDvtdqtyQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtexvuvvbEbEcqbEcqbEbEbEbEcqbEbEcqbEc3bEbEbEcqbEcqbEbEbEbEcqbEbEcqbEc3bEbEbEcqbEcqbEbEbEbEcqbEbEcqbEc3bEbEbEcqbEcqbEbEbEbEcqbEbEcqbEc3bEbEbEcqsk.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.ri4bDbDbDbDbDbDcvbDcvcvbDcvbDbDbDbDbDbDbDbDbDbDcvbDcvcvbDcvbDbDbDbDbDbDbDbDbDbDbDbDbDbDcvbDcvcvbDcvbDbDbDbDbDbDbDbDbDbDbqbDbqbqbDbqvwdhdgQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt#gvxepbrbEbEbrbEcqbEbEbEcqbEbEbrbEc3bEbrbEbEbrbEcqbEbEbEcqbEbEbrbEc3bEbrbEbEbrbEcqbEbEbEcqbEbEbrbEc3bEbrbEbEbrbEcqbEbEbEcqbEbEbrbEc3bEbrbEsH.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rgucEbDbDbqbDbqbqbDbqbDbDcDbDcDcDbDcDbDbDbDbDbDbDcDbDcDcDbDcDbDbDbDbDbDbDbDbDbDbDbDbDbDbDbDbDbDbDbDbDbDbDcvbDcvcvbDcvbDbDcDbDcDcDvydbvzQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtvAvBvCbEbEbrbEcqbrbEcqbEbEbEbEcqbEbEcqbEbEbrbEcqbrbEcqbEbEbEbEcqbEbEcqbEbEbrbEcqbrbEcqbEbEbEbEcqbEbEcqbEbEbrbEcqbrbEcqbEbEbEbEcqbEbEcq.M.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.re2cVbDbDbDbDbDbDbDbqbDbqbqbDbqbDbDbDbDbDbDbqbDbqbqbDbqbDbDbDbDbDbDcvbDcvcvbDcvbDbDbqbDbqbqcvbqcvcvbDcvbDbDbqbDbqbqbDbqbDbDbDbDvDvEvFQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt.5vGvHcqbrbEbrbEbrbrbEbrbEbEbrbEbrbrbEcqbrbEbrbEbrbrbEbrbEbEbrbEbrbrbEcqbrbEbrbEbrbrbEbrbEbEbrbEbrbrbEcqbrbEbrbEbrbrbEbrbEbEbrbEbrbr.F.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rcqeJbDbqbDbDbDbDbDbDbDbDbDbDcvbDcvcvbDcvbDbDbDbDbDbDbDbDbDbDbqbDbqbqaxbqaxaxbDaxbDbDbDbDbDbDcvbDcvcvbDcvbDbDbDbDbDbDcvbDcvc2vIc0.kQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtd6vJd4bEbEbEbEcqbEbrcqazbEcqbEbEbEbEbEbEbEbEbEcqbEbrcqazbEcqbEbEbEbEbEbEbEbEbEcqbEbrcqazbEcqbEbEbEbEbEbEbEbEbEcqbEbrcqazbEcqbEbEdH.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r#9hHbDbDbDbDbDaxbDaxaxcvaxcvcvbDcvbDbDaxbDaxaxbDaxbDbDbDbDbDbDbDbDbDbDbDbDbDbDbqbDbqbqbDbqbDbDbqbDbqbqbDbqbDbDbDbDbDbDaxdcvKvLQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtvMvNbfbEbEazbEbEbEbEazbEazbEazbrbEbEazbEbEazbEbEbEbEazbEazbEazbrbEbEazbEbEazbEbEbEbEazbEazbEazbrbEbEazbEbEazbEbEbEbEazbEazbE#9sA.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.Fi2cvcvbDcvbDbDbDbDbDbDbDbDbDbDbqbDbqbqbDbqbDbDaxbDaxaxcvaxcvcvbqcvbqbqbDbqbDbDbDbDbDbDbDbDbDbDaxbDaxaxcvaxcvcvbDcvbDvOcyvPQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtbbvQvRbrbEazbEbEbrbrbEbEbEbEbEazazbEbEbrbEazbEbEbrbrbEbEbEbEbEazazbEbEbrbEazbEbEbrbrbEbEbEbEbEazazbEbEbrbEazbEbEbrbrbEbEbEaz.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rlNaxbDbDbqbDbqbqbDbqbDbDaxbDaxaxbqaxbqbqbDbqbDbDbDbDbDbDbDbDbDbDaxbDaxaxbqaxbqbqaxbqaxaxbqaxbqbqbDbqbDbDbDbDbDbDaxcuvS.kQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt.AvTa7bEbr#9bEbEbEaz#9brazbEbEbrazbEazbEbr#9bEbEbEaz#9brazbEbEbrazbEazbEbr#9bEbEbEaz#9brazbEbEbrazbEazbEbr#9bEbEbEaz#9br.F.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rfPbqbDbqbqbDbqbDbDaxbDaxaxbDaxbDbDbDbDbDbDaxbDaxaxbqaxbqbqaxbqaxaxbDaxbDbDbDbDbDbDbDbDbDbDbDbDbDbDbqbDbqbq#8bqvUcovVQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt.kaMvWvXbE#9azbEbrbEbEbEazbEazbEbrbEbEazbE#9azbEbrbEbEbEazbEazbEbrbEbEazbE#9azbEbrbEbEbEazbEazbEbrbEbEazbE#9azbEbrbEbEsk.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.riYbD#8bD#8#8bq#8bqbqaxbqaxaxbqaxbqbqbDbqbDbD#8bD#8#8bD#8bDbDbDbDbDbDaxbDaxaxbqaxbqbqaxbqaxaxaxaxaxaxaxaxaxaxvYvZv0QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtv1v2v3azbEazaz#9azbE#9brazbEaz#9brazbEazbEazaz#9azbE#9brazbEaz#9brazbEazbEazaz#9azbE#9brazbEaz#9brazbEazbEazaz#9az.F.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rgVcDbqbDbqbDbD#8bD#8#8bD#8bDbDbDbDbDbDbqbDbqbqbqbqbqbqaxbqaxaxbDaxbDbD#8bD#8#8bD#8bDbDbDbDbDbDbDbDbDbDbDbDv4v5abQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtaSv6aQbEbrbEazbE#9brbE#9brbEbEbE#9brazbEbrbEazbE#9brbE#9brbEbEbE#9brazbEbrbEazbE#9brbE#9brbEbEbE#9brazbEbrbEazdVsY.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rfbcEaxaxaxaxaxaxbDaxbDbDaxbDaxax#8ax#8#8#8#8#8#8ax#8axaxbDaxbDbDaxbDaxaxbqaxbqbqaxbqaxaxaxaxaxax#8ax#8v7v8v9QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtabw.w#az#9azbEaz#9brazazbrazazbEbEaz#9az#9azbEaz#9brazazbrazazbEbEaz#9az#9azbEaz#9brazazbrazazbEbEaz#9az#9azbr.9.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rc3cE#8axaxbDaxbDbDaxbDaxaxbqaxbqbqbqbqbqbqaxbqaxaxbDaxbDbDaxbDaxax#8ax#8#8#8#8#8#8bq#8bqbqbDbqbDbDaxwab5wbQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtdawcwdazbEazbEbr#9#9braz#9#9brazbEbr#9azbEazbEbr#9#9braz#9#9brazbEbr#9azbEazbEbr#9#9braz#9#9brazbEbr#9azdIsH.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rbrfi#8ax#8#8bq#8bqbq#8bq#8#8#8#8#8#8bD#8bDbDbDbDbDbD#8bD#8#8ax#8axaxbqaxbqbqbDbqbDbD#8bD#8#8ax#8axwewf#RQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtc6wgaAaz#9azbEazazbEazaz#9#9az#9br#9#9az#9azbEazazbEazaz#9#9az#9br#9#9az#9azbEazazbEazaz#9#9az#9br#9#9sksA.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.FiUaxbDaxbDbD#8bD#8#8bq#8bqbqaxbqaxax#8ax#8#8ax#8axax#8ax#8#8#8#8#8#8ax#8axaxaxaxaxaxaxaxaxaxwhbUwiQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtata#wj#9#9az#9azbr#9azbEaz#9azbEazbraz#9#9az#9azbr#9azbEaz#9azbEazbraz#9#9az#9azbr#9azbEaz#9azbEazbr#9.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rj4#8#8ax#8axax#8ax#8#8ax#8axaxbDaxbDbDaxbDaxaxaxaxaxaxbDaxbDbDaxbDaxax#8ax#8#8bq#8bqbqaxbqwkbNeWQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtanwlwmbr#9azbr#9az#9br#9#9#9az#9braz#9br#9azbr#9az#9br#9#9#9az#9braz#9br#9azbr#9az#9br#9#9#9az#9sZ.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.riaaxbqbqaxbqaxax#8ax#8#8bq#8bqbq#8bq#8#8#8#8#8#8ax#8axax#8ax#8#8bq#8bqbq#8bq#8#8#8#8#8#8wnbI#hQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtahwowp#9#9az#9az#9azaz#9br#9az#9azazaz#9#9az#9az#9azaz#9br#9az#9azazaz#9#9az#9az#9azaz#9br#9az.F.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.ray#8#8#8#8ax#8axax#8ax#8#8ax#8axax#8ax#8#8ax#8axax#8ax#8#8#8#8#8#8#8#8#8#8ax#8axaxaxbVwq#bQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtaa#Pwraz#9#9#9az#9az#1#9br#9#1#9#9#1#9az#9#9#9az#9az#1#9br#9#1#9#9#1#9az#9#9#9az#9az#1#9br#9.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rh0#8ax#8axax#8ax#8#8bq#8bqbqaxbqaxax#0ax#0#0#8#0#8#8ax#8axaxaxaxaxaxaxaxaxaxbqaxbqwswtwuQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtwvwwck#1#9az#9#9az#9az#9azazaz#9#1azaz#1#9az#9#9az#9az#9azazaz#9#1azaz#1#9az#9#9az#9az#9td.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rfQwx#8#0#8#0#0#8#0#8#8#8#8#8#8#8#8#8#8ax#8axax#0ax#0#0ax#0axax#8ax#8#8#0#8#0#0#8wywzbHQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt#WwAwB#1.Faz#1#9az#1#9#9#1azaz#1#9#1az#1.Faz#1#9az#1#9#9#1azaz#1#9#1az#1.Faz#1#9az#1sQ.9.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.reLcU#8#8ax#8axaxaxaxaxax#0ax#0#0ax#0axax#8ax#8#8#8#8#8#8ax#8axax#8ax#8#8ax#8wCbjbiQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt#hwDwE#9#1az.F#9az#9#9#9#9az#9az#9#9az#9#1az.F#9az#9#9#9#9az#9az#9#9az#9#1az.F#9az#9sA.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rdVdl#0#8#8#8#8#8#8.E#8.E.E#8.E#8#8ax#8axax.Eax.E.Eax.Eaxax#8ax#8#8.E#8.E.EwFbdwGQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtwHwIwJ#9az.Faz.F#9.F#1#9az.F#9#9.F#9#9#9az.Faz.F#9.F#1#9az.F#9#9.F#9#9#9az.FazsHsA.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rskg1ax.Eaxax#8ax#8#8#8#8#8#8ax#8axax#8ax#8#8#8#8#8#8#8#8#8#8.E#8.E.Eax.EwKa9wLQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtwMwNwO#1.F#9az#9az#9.F.Fazaz.F#9.Faz#9#1.F#9az#9az#9.F.Fazaz.F#9.Faz#9#1.F#9sk.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rsAjvax#8ax#8#8.E#8.E.E.E.E.E.E#8.E#8#8.E#8.E.Eax.Eaxax.Eax.E.E#0.E#0wPa6a5QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt#ywQwR#9.F.F#1.F#9az#1.F#9.Faz.F.F#9#9#9.F.F#1.F#9az#1.F#9.Faz.F.F#9#9#9.FsH.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rl0#0#0.E#0.E.E#8.E#8#8ax#8axax.Eax.E.Eax.Eaxax.Eax.E.E#8.E#8#8axwSwTwUQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtwVwWwX#9#9#9.F#9.Faz#1#9#9.Faz.F.F#9#1#9#9#9.F#9.Faz#1#9#9.Faz.F.F#9#1.F.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rfP.E.E.E#8.E#8#8.E#8.E.E#8.E#8#8.E#8.E.E#8.E#8#8.E#8.E.E.E.E.EwYwZ.BQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtbMw0#k.F#9.F#1.F#9.F.F.F.F#9.Faz.F.F.F.F#9.F#1.F#9.F.F.F.F#9.Faz.F.FsH.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.riN#8#8#8#8.E#8.E.Eax.Eaxax.Eax.E.E#8.E#8#8.E#8.E.E#8.E#8#8.ew1aNQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt#g.Ww2.F#1#9.F.F#9#9#9.F#1.F#9#1#9.F#9.F#1#9.F.F#9#9#9.F#1.F#9#1sksA.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rgR#0.E.E.E.E.E.E.E.E#8.E#8#8.E#8.E.E.E.E.E.Eax.Eaxax.Eaxw3w4.lQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtw5w6#.#1.F.F.F.F.F#9#9.F.F.F.M.F#9.F.F#1.F.F.F.F.F#9#9.F.F.F.M.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.reTax.E#8.E#8#8.E#8.E.E.E.E.E.E.E.E.E.E#8.E#8#8.E#8.E.Ew7aEaTQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt.5w8w9.F.F#9.F.F.M#1.F#9#9.F.F#9.F#9#1.F.F#9.F.F.M#1.F#9#9.M.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rbEcX.E.E.E.E.E.E#8.E#8#8.E#8.E.E.E.E.E.E.E.E.E.E.TaPx.au.kQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt.Xx#.V.F#9.F.F.F.F.F.F.F.F.M.F.F.F#9.F.F#9.F.F.F.F.F.F.F.9.9.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r#9fj.E.E.E#8.E#8#8.E#8.E.E.E.E.E.E#8.E#8#8.E#8.ExaapxbQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtxcxdxe.M.F#9.F.F.F#9.F.F.F.M.F.F.M.F.F.M.F#9.F.F.F#9sH.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.Fh6.E.T.E.E.E.E.E.E.E.E.E.E.T.E.T.T.E.T.E.E.ExfxgaDQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtxhxixj.F.M#1.F.M.F.F.M.F.F.F#1.M.F#1.M.F.M#1.F.M.F.9.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rj9.T#0.T#0#0.T#0.T.T.E.T.E.E#0.E#0#0.E#0aPxkxl.kQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt.Axmxn.M.F.F.F.F.F.F.M.F.F.F.M.F.F.F.F.M.F.F.F.F.9.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rgI.E.E.E.E.E.E.E.E.E.E.E.E.E.E.T.E.T.TxoxpxqQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt.kxrxsxt.F.r.F.F.F.9.M.F.r.F.F.M.F.F.F.M.F.r.F.9.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.2.T.E.E.E.E.E.E.E.E.E.E.T.E.T.T.E.Txu#Yv0QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtaYxvxw.F.M.F.F.F.F.F.F.r.F.F.r.F.F.F.F.F.M.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rgV#8.E.T.T.p.T.p.p.E.p.E.E.E.E.E.Exx#SabQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtaSxyxz.F.r.F.M.r.F.F.9.F.r.F.M.r.F.r.F.F.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rfk#0.E.p.E.E.E.E.E.E.E.E.E.E.TxAxBxCQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtabxDxE.F.F.F.M.F.F.M.F.F.M.F.F.9.F.r.M.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rdzcv.E.p.E.p.p.E.p.E.E.1.E.1xF#GchQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtxGxHxI.F.r.r.M.F.r.F.M.r.F.M.F.F.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.razcE.E.E.E.E.E.E.E.E.E.E.p#BxJ#RQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtaCxKxL.F.F.r.r.F.F.r.F.r.F.F.9.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.Fg8.p.T.T.p.T.p.p.p.pxM#uc.QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtabxNxO.M.F.M.r.F.r.F.r.r.F.MsH.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rjL.E.E.E.E.E.E.E.E#H#oeWQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtxPxQal.r.F.r.F.M.r.F.r.r.M.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rk0.p.1.p.1.1.p.1xR#i#zQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtahxSxT.F.r.r.r.r.F.r.F.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.U.p.p.E.p.E#v#cbTQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtaaxUxV.F.F.F.r.r.r.F.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rh0.p.p.p.pxW.7.#QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtxXxYxZ.r.F.F.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rhn.E.p.px0x1bHQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtx2x3x4.r.r.r.F.9.r.r.r.r.r.r.r.r.r.r.r.r.r.rh0x5x6x7.QQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt#Qx8x9.r.r.r.r.r.r.r.r.r.r.r.r.r.r.rbrj4y..KbuQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQty#yayb.r.F.r.r.r.r.r.r.r.rgvycydye.YQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtxPyfygyhyi.Myjyktk#MylymQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtyn#yQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt"}; diff --git a/src/serlio/materials/ArnoldMaterialNode.cpp b/src/serlio/materials/ArnoldMaterialNode.cpp index c25a264d..d263cf63 100644 --- a/src/serlio/materials/ArnoldMaterialNode.cpp +++ b/src/serlio/materials/ArnoldMaterialNode.cpp @@ -3,7 +3,7 @@ * * See https://github.com/esri/serlio for build and usage instructions. * - * Copyright (c) 2012-2019 Esri R&D Center Zurich + * Copyright (c) 2012-2022 Esri R&D Center Zurich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,20 +22,10 @@ #include "materials/MaterialUtils.h" #include "utils/MELScriptBuilder.h" -#include "utils/MayaUtilities.h" - -#include "serlioPlugin.h" - -#include "maya/MFnTypedAttribute.h" -#include "maya/adskDataStream.h" - -#include namespace { const std::wstring MATERIAL_BASE_NAME = L"serlioArnoldMaterial"; - -std::once_flag pluginDependencyCheckFlag; const std::vector PLUGIN_DEPENDENCIES = {"mtoa"}; const MELVariable MEL_VAR_SHADER_NODE(L"shaderNode"); @@ -64,11 +54,13 @@ void setUvTransformAttrs(MELScriptBuilder& sb, const std::wstring& uvSet, const } } -void createMapShader(MELScriptBuilder& sb, const std::string& mapFile, const MaterialTrafo& mapTrafo, +void createMapShader(MELScriptBuilder& sb, const std::string& tex, const MaterialTrafo& mapTrafo, const std::wstring& shaderName, const std::wstring& uvSet, const bool raw, const bool alpha) { - sb.setVar(MEL_VAR_MAP_NODE, MELStringLiteral(shaderName)); + std::filesystem::path texPath(tex); + const std::wstring nodeName = prtu::cleanNameForMaya(texPath.stem().wstring()); + sb.setVar(MEL_VAR_MAP_NODE, MELStringLiteral(nodeName)); - sb.setVar(MEL_VAR_MAP_FILE, MELStringLiteral(prtu::toUTF16FromOSNarrow(mapFile))); + sb.setVar(MEL_VAR_MAP_FILE, MELStringLiteral(prtu::toUTF16FromOSNarrow(tex))); sb.createTextureShadingNode(MEL_VAR_MAP_NODE); sb.setAttr(MEL_VAR_MAP_NODE, L"fileTextureName", MEL_VAR_MAP_FILE); @@ -81,14 +73,47 @@ void createMapShader(MELScriptBuilder& sb, const std::string& mapFile, const Mat sb.createShader(L"aiUvTransform", MEL_VAR_UV_TRAFO_NODE); setUvTransformAttrs(sb, uvSet, mapTrafo); - if (alpha) + if (alpha) { sb.connectAttr(MEL_VAR_MAP_NODE, L"outAlpha", MEL_VAR_UV_TRAFO_NODE, L"passthroughR"); + sb.forceValidTextureAlphaChannel(MEL_VAR_MAP_NODE); + sb.setAttr(MEL_VAR_MAP_NODE, L"alphaIsLuminance", !MaterialUtils::textureHasAlphaChannel(texPath.wstring())); + } else sb.connectAttr(MEL_VAR_MAP_NODE, L"outColor", MEL_VAR_UV_TRAFO_NODE, L"passthrough"); } -void appendToMaterialScriptBuilder(MELScriptBuilder& sb, const MaterialInfo& matInfo, - const std::wstring& shaderBaseName, const std::wstring& shadingEngineName) { +} // namespace + +MTypeId ArnoldMaterialNode::id(SerlioNodeIDs::SERLIO_PREFIX, SerlioNodeIDs::ARNOLD_MATERIAL_NODE); + +MObject ArnoldMaterialNode::mInMesh; +MObject ArnoldMaterialNode::mOutMesh; + +MStatus ArnoldMaterialNode::initialize() { + return initializeAttributes(mInMesh, mOutMesh); +} + +void ArnoldMaterialNode::declareMaterialStrings(MELScriptBuilder& sb) { + sb.declString(MEL_VAR_SHADER_NODE); + sb.declString(MEL_VAR_MAP_FILE); + sb.declString(MEL_VAR_MAP_NODE); + sb.declString(MEL_VAR_BUMP_LUMINANCE_NODE); + sb.declString(MEL_VAR_BUMP_VALUE_NODE); + sb.declString(MEL_VAR_DISPLACEMENT_NODE); + sb.declString(MEL_VAR_NORMAL_MAP_CONVERT_NODE); + sb.declString(MEL_VAR_COLOR_MAP_BLEND_NODE); + sb.declString(MEL_VAR_DIRTMAP_BLEND_NODE); + sb.declString(MEL_VAR_OPACITYMAP_BLEND_NODE); + sb.declString(MEL_VAR_SPECULARMAP_BLEND_NODE); + sb.declString(MEL_VAR_EMISSIVEMAP_BLEND_NODE); + sb.declString(MEL_VAR_ROUGHNESSMAP_BLEND_NODE); + sb.declString(MEL_VAR_METALLICMAP_BLEND_NODE); + sb.declString(MEL_VAR_UV_TRAFO_NODE); +} + +void ArnoldMaterialNode::appendToMaterialScriptBuilder(MELScriptBuilder& sb, const MaterialInfo& matInfo, + const std::wstring& shaderBaseName, + const std::wstring& shadingEngineName) { // create shader sb.setVar(MEL_VAR_SHADER_NODE, MELStringLiteral(shaderBaseName)); sb.setVar(MEL_VARIABLE_SHADING_ENGINE, MELStringLiteral(shadingEngineName)); @@ -267,121 +292,18 @@ void appendToMaterialScriptBuilder(MELScriptBuilder& sb, const MaterialInfo& mat } } -} // namespace - -MTypeId ArnoldMaterialNode::id(SerlioNodeIDs::SERLIO_PREFIX, SerlioNodeIDs::ARNOLD_MATERIAL_NODE); - -MObject ArnoldMaterialNode::aInMesh; -MObject ArnoldMaterialNode::aOutMesh; +std::wstring ArnoldMaterialNode::getBaseName() const { + return MATERIAL_BASE_NAME; +} -MStatus ArnoldMaterialNode::initialize() { - MStatus status; - - MFnTypedAttribute tAttr; - aInMesh = tAttr.create("inMesh", "im", MFnData::kMesh, MObject::kNullObj, &status); - MCHECK(status); - status = addAttribute(aInMesh); - MCHECK(status); - - aOutMesh = tAttr.create("outMesh", "om", MFnData::kMesh, MObject::kNullObj, &status); - MCHECK(status); - status = tAttr.setWritable(false); - MCHECK(status); - status = tAttr.setStorable(false); - MCHECK(status); - status = addAttribute(aOutMesh); - MCHECK(status); - - status = attributeAffects(aInMesh, aOutMesh); - MCHECK(status); - - return MStatus::kSuccess; +MObject ArnoldMaterialNode::getInMesh() const { + return mInMesh; } -MStatus ArnoldMaterialNode::compute(const MPlug& plug, MDataBlock& data) { - if (plug != aOutMesh) - return MStatus::kUnknownParameter; - - MStatus status = MStatus::kSuccess; - - std::call_once(pluginDependencyCheckFlag, [&status]() { - const bool b = MayaPluginUtilities::pluginDependencyCheck(PLUGIN_DEPENDENCIES); - status = b ? MStatus::kSuccess : MStatus::kFailure; - }); - if (status != MStatus::kSuccess) - return status; - - MaterialUtils::forwardGeometry(aInMesh, aOutMesh, data); - - adsk::Data::Stream* inMatStream = MaterialUtils::getMaterialStream(aInMesh, data); - if (inMatStream == nullptr) - return MStatus::kSuccess; - - const adsk::Data::Structure* materialStructure = - adsk::Data::Structure::structureByName(PRT_MATERIAL_STRUCTURE.c_str()); - if (materialStructure == nullptr) - return MStatus::kFailure; - - MString meshName; - const MStatus meshNameStatus = MaterialUtils::getMeshName(meshName, plug); - if (meshNameStatus != MStatus::kSuccess || meshName.length() == 0) - return meshNameStatus; - - MaterialUtils::MaterialCache matCache = - MaterialUtils::getMaterialsByStructure(*materialStructure, MATERIAL_BASE_NAME); - - MELScriptBuilder scriptBuilder; - scriptBuilder.declString(MEL_VARIABLE_SHADING_ENGINE); - scriptBuilder.declString(MEL_VAR_SHADER_NODE); - scriptBuilder.declString(MEL_VAR_MAP_FILE); - scriptBuilder.declString(MEL_VAR_MAP_NODE); - scriptBuilder.declString(MEL_VAR_BUMP_LUMINANCE_NODE); - scriptBuilder.declString(MEL_VAR_BUMP_VALUE_NODE); - scriptBuilder.declString(MEL_VAR_DISPLACEMENT_NODE); - scriptBuilder.declString(MEL_VAR_NORMAL_MAP_CONVERT_NODE); - scriptBuilder.declString(MEL_VAR_COLOR_MAP_BLEND_NODE); - scriptBuilder.declString(MEL_VAR_DIRTMAP_BLEND_NODE); - scriptBuilder.declString(MEL_VAR_OPACITYMAP_BLEND_NODE); - scriptBuilder.declString(MEL_VAR_SPECULARMAP_BLEND_NODE); - scriptBuilder.declString(MEL_VAR_EMISSIVEMAP_BLEND_NODE); - scriptBuilder.declString(MEL_VAR_ROUGHNESSMAP_BLEND_NODE); - scriptBuilder.declString(MEL_VAR_METALLICMAP_BLEND_NODE); - scriptBuilder.declString(MEL_VAR_UV_TRAFO_NODE); - - for (adsk::Data::Handle& inMatStreamHandle : *inMatStream) { - if (!inMatStreamHandle.hasData()) - continue; - - if (!inMatStreamHandle.usesStructure(*materialStructure)) - continue; - - std::pair faceRange; - if (!MaterialUtils::getFaceRange(inMatStreamHandle, faceRange)) - continue; - - auto createShadingEngine = [this, &materialStructure, &scriptBuilder, - &inMatStreamHandle](const MaterialInfo& matInfo) { - const std::wstring shadingEngineBaseName = MATERIAL_BASE_NAME + L"Sg"; - const std::wstring shaderBaseName = MATERIAL_BASE_NAME + L"Sh"; - - MStatus status; - const std::wstring shadingEngineName = MaterialUtils::synchronouslyCreateShadingEngine( - shadingEngineBaseName, MEL_VARIABLE_SHADING_ENGINE, status); - MCHECK(status); - - MaterialUtils::assignMaterialMetadata(*materialStructure, inMatStreamHandle, shadingEngineName); - appendToMaterialScriptBuilder(scriptBuilder, matInfo, shaderBaseName, shadingEngineName); - LOG_DBG << "new arnold shading engine: " << shadingEngineName; - - return shadingEngineName; - }; - - MaterialInfo matInfo(inMatStreamHandle); - std::wstring shadingEngineName = getCachedValue(matCache, matInfo, createShadingEngine, matInfo); - scriptBuilder.setsAddFaceRange(shadingEngineName, meshName.asWChar(), faceRange.first, faceRange.second); - LOG_DBG << "assigned arnold shading engine (" << faceRange.first << ":" << faceRange.second - << "): " << shadingEngineName; - } +MObject ArnoldMaterialNode::getOutMesh() const { + return mOutMesh; +} - return scriptBuilder.execute(); +std::vector ArnoldMaterialNode::getPluginDependencies() const { + return PLUGIN_DEPENDENCIES; } diff --git a/src/serlio/materials/ArnoldMaterialNode.h b/src/serlio/materials/ArnoldMaterialNode.h index 40be10cb..a904922b 100644 --- a/src/serlio/materials/ArnoldMaterialNode.h +++ b/src/serlio/materials/ArnoldMaterialNode.h @@ -3,7 +3,7 @@ * * See https://github.com/esri/serlio for build and usage instructions. * - * Copyright (c) 2012-2019 Esri R&D Center Zurich + * Copyright (c) 2012-2022 Esri R&D Center Zurich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,24 +19,25 @@ #pragma once -#include "maya/MPxNode.h" +#include "MaterialNode.h" class MaterialInfo; -class MaterialTrafo; class MELScriptBuilder; -class ArnoldMaterialNode : public MPxNode { - +class ArnoldMaterialNode : public MaterialNode { public: static MStatus initialize(); - static MTypeId id; - static MObject aInMesh; - static MObject aOutMesh; - - MStatus compute(const MPlug& plug, MDataBlock& data) override; - MPxNode::SchedulingType schedulingType() const noexcept override { - return SchedulingType::kGloballySerial; - } + static MObject mInMesh; + static MObject mOutMesh; + +private: + void declareMaterialStrings(MELScriptBuilder& sb); + void appendToMaterialScriptBuilder(MELScriptBuilder& sb, const MaterialInfo& matInfo, + const std::wstring& shaderBaseName, const std::wstring& shadingEngineName); + std::wstring getBaseName() const override; + MObject getInMesh() const override; + MObject getOutMesh() const override; + std::vector getPluginDependencies() const override; }; diff --git a/src/serlio/materials/MaterialCommand.cpp b/src/serlio/materials/MaterialCommand.cpp new file mode 100644 index 00000000..991df3a1 --- /dev/null +++ b/src/serlio/materials/MaterialCommand.cpp @@ -0,0 +1,183 @@ +/** + * Serlio - Esri CityEngine Plugin for Autodesk Maya + * + * See https://github.com/esri/serlio for build and usage instructions. + * + * Copyright (c) 2012-2022 Esri R&D Center Zurich + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "materials/ArnoldMaterialNode.h" +#include "materials/MaterialCommand.h" +#include "materials/StingrayMaterialNode.h" +#include "utils/MELScriptBuilder.h" + +#include "utils/MayaUtilities.h" + +#include "maya/MArgList.h" +#include "maya/MFloatPointArray.h" +#include "maya/MFnMesh.h" +#include "maya/MGlobal.h" +#include "maya/MItDependencyGraph.h" +#include "maya/MItSelectionList.h" + +bool MaterialCommand::isUndoable() const { + return true; +} + +MStatus MaterialCommand::doIt(const MArgList& argList) { + MStatus status; + + if (argList.length() == 0) { + displayError("Material type expected (stingray/arnold)"); + return MS::kFailure; + } + else if (argList.length() > 1) { + displayError("Only one material type expected"); + return MS::kFailure; + } + + MString materialType = argList.asString(0, &status); + MCHECK(status); + + MTypeId materialTypeId; + if (materialType == "stingray") { + materialTypeId = StingrayMaterialNode::id; + } + else if (materialType == "arnold") { + materialTypeId = ArnoldMaterialNode::id; + } + else { + displayError("Material type expected (stingray/arnold)"); + return MS::kFailure; + } + + // Parse the selection list for selected components of the right type. + MSelectionList selList; + MGlobal::getActiveSelectionList(selList); + MItSelectionList selListIter(selList); + selListIter.setFilter(MFn::kMesh); + + bool found = false; + bool foundMultiple = false; + + for (; !selListIter.isDone(); selListIter.next()) { + MDagPath dagPath; + MObject component; + selListIter.getDagPath(dagPath, component); + + if (!found) { + // Ensure that this DAG path will point to the shape + // of our object. Set the DAG path for the polyModifierCmd. + if ((dagPath.extendToShape() == MStatus::kSuccess) || + (dagPath.extendToShapeDirectlyBelow(0) == MStatus::kSuccess)) { + fDagPath = dagPath; + found = true; + } + } + else { + foundMultiple = true; + break; + } + } + if (foundMultiple) { + displayWarning("Found more than one object with selected components. Only operating on first found object."); + } + + if (found) { + MObject materialDependencyNodeObject = fDGModifier.createNode(materialTypeId); + MFnDependencyNode materialDependencyNode(materialDependencyNodeObject); + + MPlug materialInMesh = materialDependencyNode.findPlug("inMesh", true, &status); + MPlug materialOutMesh = materialDependencyNode.findPlug("outMesh", true, &status); + + MObject rootObj = fDagPath.node(); + MFnDependencyNode rootNode(rootObj); + + MPlug geometryInMesh = rootNode.findPlug("inMesh", true, &status); + MPlug geometryOutMesh = rootNode.findPlug("outMesh", true, &status); + + if (MS::kSuccess != status) { + MGlobal::displayError("Status failed: no inMesh Attribute on node \"" + rootNode.name() + "\""); + return status; + } + // has construction history + if (geometryInMesh.isConnected()) { + MPlugArray parentPlugArray; + MPlug serlioOutMesh; + fGeometryName = rootNode.name(); + + geometryInMesh.connectedTo(parentPlugArray, true, false); + + serlioOutMesh = parentPlugArray[0]; + + fDGModifier.disconnect(serlioOutMesh, geometryInMesh); + fDGModifier.connect(serlioOutMesh, materialInMesh); + fDGModifier.connect(materialOutMesh, geometryInMesh); + } + // has no construction history + else { + MDataHandle meshHandle = geometryOutMesh.asMDataHandle(); + materialInMesh.setMDataHandle(meshHandle); + fDGModifier.connect(materialOutMesh, geometryInMesh); + } + + status = fDGModifier.doIt(); + + if (status == MS::kSuccess) { + setResult("PRT command succeeded!"); + } + else { + displayError("PRT command failed!"); + } + } + else { + displayError("PRT command failed: Unable to find selected components"); + status = MS::kFailure; + } + + return status; +} + +MStatus MaterialCommand::redoIt() { + MStatus status; + status = fDGModifier.doIt(); + + if (status == MS::kSuccess) { + setResult("PRT command succeeded!"); + } + else { + displayError("PRT command failed!"); + } + + return status; +} + +MStatus MaterialCommand::undoIt() { + MStatus status; + MELScriptBuilder scriptBuilder; + + // apply initial shading group to avoid other connected shading groups to disrupt undo process + scriptBuilder.setsUseInitialShadingGroup(fGeometryName.asWChar()); + std::wstring output; + MCHECK(scriptBuilder.executeSync(output)); + + status = fDGModifier.undoIt(); + if (status == MS::kSuccess) { + setResult("PRT undo succeeded!"); + } + else { + setResult("PRT undo failed!"); + } + return status; +} \ No newline at end of file diff --git a/src/serlio/materials/MaterialCommand.h b/src/serlio/materials/MaterialCommand.h new file mode 100644 index 00000000..aa7082f4 --- /dev/null +++ b/src/serlio/materials/MaterialCommand.h @@ -0,0 +1,42 @@ +/** + * Serlio - Esri CityEngine Plugin for Autodesk Maya + * + * See https://github.com/esri/serlio for build and usage instructions. + * + * Copyright (c) 2012-2022 Esri R&D Center Zurich + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include + +#include "PRTContext.h" + +class MaterialCommand : public MPxCommand { +public: + bool isUndoable() const override; + + MStatus doIt(const MArgList&) override; + MStatus redoIt() override; + MStatus undoIt() override; + +private: + MDGModifier fDGModifier; + MDagModifier fDagModifier; + MDagPath fDagPath; + MString fGeometryName; +}; diff --git a/src/serlio/materials/MaterialInfo.cpp b/src/serlio/materials/MaterialInfo.cpp index 0268b01f..e4450044 100644 --- a/src/serlio/materials/MaterialInfo.cpp +++ b/src/serlio/materials/MaterialInfo.cpp @@ -3,7 +3,7 @@ * * See https://github.com/esri/serlio for build and usage instructions. * - * Copyright (c) 2012-2019 Esri R&D Center Zurich + * Copyright (c) 2012-2022 Esri R&D Center Zurich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +19,8 @@ #include "materials/MaterialInfo.h" +#include "MaterialInfo.h" +#include "utils/Utilities.h" #include namespace { @@ -70,6 +72,13 @@ double MaterialColor::b() const noexcept { return data[2]; } +size_t MaterialColor::getHash() const { + size_t seed = 0; + for (double elem : data) + prtu::hash_combine(seed, std::hash{}(elem)); + return seed; +} + bool MaterialColor::operator==(const MaterialColor& other) const noexcept { return this->data == other.data; } @@ -106,6 +115,13 @@ double MaterialTrafo::rw() const noexcept { return data[4]; } +size_t MaterialTrafo::getHash() const { + size_t seed = 0; + for (double elem : data) + prtu::hash_combine(seed, std::hash{}(elem)); + return seed; +} + std::array MaterialTrafo::tuv() const noexcept { return {tu(), tv()}; } @@ -244,3 +260,39 @@ bool MaterialInfo::operator<(const MaterialInfo& rhs) const { return false; // equality } + +size_t MaterialInfo::getHash() const { + std::size_t seed = 0; + + prtu::hash_combine(seed, std::hash{}(bumpMap)); + prtu::hash_combine(seed, std::hash{}(colormap)); + prtu::hash_combine(seed, std::hash{}(dirtmap)); + prtu::hash_combine(seed, std::hash{}(emissiveMap)); + prtu::hash_combine(seed, std::hash{}(metallicMap)); + prtu::hash_combine(seed, std::hash{}(normalMap)); + prtu::hash_combine(seed, std::hash{}(occlusionMap)); + prtu::hash_combine(seed, std::hash{}(opacityMap)); + prtu::hash_combine(seed, std::hash{}(roughnessMap)); + prtu::hash_combine(seed, std::hash{}(specularMap)); + + prtu::hash_combine(seed, std::hash{}(opacity)); + prtu::hash_combine(seed, std::hash{}(metallic)); + prtu::hash_combine(seed, std::hash{}(roughness)); + + prtu::hash_combine(seed, ambientColor.getHash()); + prtu::hash_combine(seed, diffuseColor.getHash()); + prtu::hash_combine(seed, emissiveColor.getHash()); + prtu::hash_combine(seed, specularColor.getHash()); + prtu::hash_combine(seed, specularmapTrafo.getHash()); + prtu::hash_combine(seed, bumpmapTrafo.getHash()); + prtu::hash_combine(seed, dirtmapTrafo.getHash()); + prtu::hash_combine(seed, emissivemapTrafo.getHash()); + prtu::hash_combine(seed, metallicmapTrafo.getHash()); + prtu::hash_combine(seed, normalmapTrafo.getHash()); + prtu::hash_combine(seed, occlusionmapTrafo.getHash()); + prtu::hash_combine(seed, opacitymapTrafo.getHash()); + prtu::hash_combine(seed, roughnessmapTrafo.getHash()); + prtu::hash_combine(seed, specularmapTrafo.getHash()); + + return seed; +} diff --git a/src/serlio/materials/MaterialInfo.h b/src/serlio/materials/MaterialInfo.h index 2272ba6f..3a18dd33 100644 --- a/src/serlio/materials/MaterialInfo.h +++ b/src/serlio/materials/MaterialInfo.h @@ -3,7 +3,7 @@ * * See https://github.com/esri/serlio for build and usage instructions. * - * Copyright (c) 2012-2019 Esri R&D Center Zurich + * Copyright (c) 2012-2022 Esri R&D Center Zurich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,6 +31,13 @@ const std::string PRT_MATERIAL_CHANNEL = "prtMaterialChannel"; const std::string PRT_MATERIAL_STREAM = "prtMaterialStream"; const std::string PRT_MATERIAL_FACE_INDEX_START = "faceIndexStart"; const std::string PRT_MATERIAL_FACE_INDEX_END = "faceIndexEnd"; + +const std::string PRT_MATERIALINFO_MAP_STRUCTURE = "prtMaterialInfoMapStructure"; +const std::string PRT_MATERIALINFO_MAP_CHANNEL = "prtMaterialInfoMapChannel"; +const std::string PRT_MATERIALINFO_MAP_STREAM = "prtMaterialInfoMapStream"; +const std::string PRT_MATERIALINFO_MAP_KEY = "key"; +const std::string PRT_MATERIALINFO_MAP_VALUE = "value"; + const MELVariable MEL_VARIABLE_SHADING_ENGINE(L"shadingGroup"); class MaterialColor { @@ -41,6 +48,8 @@ class MaterialColor { double g() const noexcept; double b() const noexcept; + size_t getHash() const; + bool operator==(const MaterialColor& other) const noexcept; bool operator<(const MaterialColor& rhs) const noexcept; bool operator>(const MaterialColor& rhs) const noexcept; @@ -59,6 +68,8 @@ class MaterialTrafo { double tv() const noexcept; double rw() const noexcept; + size_t getHash() const; + std::array tuv() const noexcept; std::array suvw() const noexcept; @@ -108,4 +119,6 @@ class MaterialInfo { bool equals(const MaterialInfo& o) const; bool operator<(const MaterialInfo& rhs) const; + + size_t getHash() const; }; diff --git a/src/serlio/materials/MaterialNode.cpp b/src/serlio/materials/MaterialNode.cpp new file mode 100644 index 00000000..9f5cb991 --- /dev/null +++ b/src/serlio/materials/MaterialNode.cpp @@ -0,0 +1,152 @@ +/** + * Serlio - Esri CityEngine Plugin for Autodesk Maya + * + * See https://github.com/esri/serlio for build and usage instructions. + * + * Copyright (c) 2012-2022 Esri R&D Center Zurich + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "materials/MaterialNode.h" +#include "materials/MaterialUtils.h" + +#include "utils/MELScriptBuilder.h" + +#include "maya/MFnTypedAttribute.h" +#include "maya/MUuid.h" + +#include + +namespace { +std::once_flag pluginDependencyCheckFlag; + +const MELVariable MEL_UNDO_STATE(L"serlioMaterialUndoState"); +} // namespace + +MStatus MaterialNode::initializeAttributes(MObject& inMesh, MObject& outMesh) { + MStatus status; + + MFnTypedAttribute tAttr; + inMesh = tAttr.create("inMesh", "im", MFnData::kMesh, MObject::kNullObj, &status); + MCHECK(status); + status = addAttribute(inMesh); + MCHECK(status); + + outMesh = tAttr.create("outMesh", "om", MFnData::kMesh, MObject::kNullObj, &status); + MCHECK(status); + status = tAttr.setWritable(false); + MCHECK(status); + status = tAttr.setStorable(false); + MCHECK(status); + status = addAttribute(outMesh); + MCHECK(status); + + status = attributeAffects(inMesh, outMesh); + MCHECK(status); + + return MStatus::kSuccess; +} + +MStatus MaterialNode::compute(const MPlug& plug, MDataBlock& data) { + MObject inMesh = getInMesh(); + MObject outMesh = getOutMesh(); + const std::wstring baseName = getBaseName(); + if (plug != outMesh) + return MStatus::kUnknownParameter; + + MStatus status = MStatus::kSuccess; + const std::vector pluginDependencies = getPluginDependencies(); + + std::call_once(pluginDependencyCheckFlag, [pluginDependencies, &status]() { + const bool b = MayaPluginUtilities::pluginDependencyCheck(pluginDependencies); + status = b ? MStatus::kSuccess : MStatus::kFailure; + }); + if (status != MStatus::kSuccess) + return status; + + MaterialUtils::forwardGeometry(inMesh, outMesh, data); + + MString meshName; + const MStatus meshNameStatus = MaterialUtils::getMeshName(meshName, plug); + if (meshNameStatus != MStatus::kSuccess || meshName.length() == 0) + return meshNameStatus; + + adsk::Data::Stream* inMatStream = MaterialUtils::getMaterialStream(inMesh, data); + if (inMatStream == nullptr) { + MaterialUtils::resetMaterial(meshName.asWChar()); + return MStatus::kSuccess; + } + + const adsk::Data::Structure* materialStructure = + adsk::Data::Structure::structureByName(PRT_MATERIAL_STRUCTURE.c_str()); + if (materialStructure == nullptr) + return MStatus::kFailure; + + MaterialUtils::MaterialCache matCache = MaterialUtils::getMaterialCache(); + + MELScriptBuilder scriptBuilder; + scriptBuilder.declInt(MEL_UNDO_STATE); + scriptBuilder.getUndoState(MEL_UNDO_STATE); + scriptBuilder.setUndoState(false); + + declareMaterialStrings(scriptBuilder); + + for (adsk::Data::Handle& inMatStreamHandle : *inMatStream) { + if (!inMatStreamHandle.hasData()) + continue; + + if (!inMatStreamHandle.usesStructure(*materialStructure)) + continue; + + std::pair faceRange; + if (!MaterialUtils::getFaceRange(inMatStreamHandle, faceRange)) + continue; + + auto createShadingEngine = [this, baseName, &materialStructure, &scriptBuilder, + &inMatStreamHandle](const MaterialInfo& matInfo) { + const std::wstring shadingEngineBaseName = baseName + L"Sg"; + const std::wstring shaderBaseName = baseName + L"Sh"; + + MStatus status; + const std::wstring shadingEngineName = MaterialUtils::synchronouslyCreateShadingEngine( + shadingEngineBaseName, MEL_VARIABLE_SHADING_ENGINE, status); + MCHECK(status); + + MUuid shadingEngineNameUuid = mu::getNodeUuid(MString(shadingEngineName.c_str())); + MCHECK(MaterialUtils::addMaterialInfoMapMetadata(matInfo.getHash(), shadingEngineNameUuid)); + appendToMaterialScriptBuilder(scriptBuilder, matInfo, shaderBaseName, shadingEngineName); + LOG_DBG << "new shading engine: " << shadingEngineName; + + return shadingEngineNameUuid; + }; + + MaterialInfo matInfo(inMatStreamHandle); + const MUuid shadingEngineUuid = getCachedValue(matCache, matInfo.getHash(), createShadingEngine, matInfo); + + MObject shadingEngineNodeObj = mu::getNodeObjFromUuid(shadingEngineUuid, status); + + if (status != MS::kSuccess) { + const MUuid newUuid(createShadingEngine(matInfo)); + shadingEngineNodeObj = mu::getNodeObjFromUuid(newUuid, status); + } + + MFnDependencyNode shadingEngineNode(shadingEngineNodeObj); + const std::wstring shadingEngineName = shadingEngineNode.name().asWChar(); + + scriptBuilder.setsAddFaceRange(shadingEngineName, meshName.asWChar(), faceRange.first, faceRange.second); + LOG_DBG << "assigned shading engine (" << faceRange.first << ":" << faceRange.second + << "): " << shadingEngineName; + } + scriptBuilder.setUndoState(MEL_UNDO_STATE); + return scriptBuilder.execute(); +} diff --git a/src/serlio/materials/MaterialNode.h b/src/serlio/materials/MaterialNode.h new file mode 100644 index 00000000..e4de1b7f --- /dev/null +++ b/src/serlio/materials/MaterialNode.h @@ -0,0 +1,50 @@ +/** + * Serlio - Esri CityEngine Plugin for Autodesk Maya + * + * See https://github.com/esri/serlio for build and usage instructions. + * + * Copyright (c) 2012-2022 Esri R&D Center Zurich + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "maya/MPxNode.h" + +#include + +class MaterialInfo; +class MELScriptBuilder; + +class MaterialNode : public MPxNode { + +public: + MStatus compute(const MPlug& plug, MDataBlock& data) override; + + MPxNode::SchedulingType schedulingType() const noexcept override { + return SchedulingType::kGloballySerial; + } + +protected: + static MStatus initializeAttributes(MObject& inMesh, MObject& outMesh); + +private: + virtual void declareMaterialStrings(MELScriptBuilder& sb) = 0; + virtual void appendToMaterialScriptBuilder(MELScriptBuilder& sb, const MaterialInfo& matInfo, + const std::wstring& shaderBaseName, + const std::wstring& shadingEngineName) = 0; + virtual std::wstring getBaseName() const = 0; + virtual MObject getInMesh() const = 0; + virtual MObject getOutMesh() const = 0; + virtual std::vector getPluginDependencies() const = 0; +}; diff --git a/src/serlio/materials/MaterialUtils.cpp b/src/serlio/materials/MaterialUtils.cpp index 7a331d5d..973e0614 100644 --- a/src/serlio/materials/MaterialUtils.cpp +++ b/src/serlio/materials/MaterialUtils.cpp @@ -1,35 +1,110 @@ +/** + * Serlio - Esri CityEngine Plugin for Autodesk Maya + * + * See https://github.com/esri/serlio for build and usage instructions. + * + * Copyright (c) 2012-2022 Esri R&D Center Zurich + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + #include "materials/MaterialUtils.h" #include "utils/MArrayWrapper.h" #include "utils/MELScriptBuilder.h" -#include "utils/MItDependencyNodesWrapper.h" #include "utils/MayaUtilities.h" +#include "utils/Utilities.h" #include "PRTContext.h" #include "maya/MDataBlock.h" #include "maya/MDataHandle.h" +#include "maya/MFileIO.h" #include "maya/MFnMesh.h" -#include "maya/MItDependencyNodes.h" #include "maya/MPlugArray.h" +#include "maya/MUuid.h" #include "maya/adskDataAssociations.h" namespace { +const MELVariable MEL_UNDO_STATE(L"materialUndoState"); -MObject findNamedObject(const std::wstring& name, MFn::Type fnType) { - MStatus status; - MItDependencyNodes nodeIt(fnType, &status); - MCHECK(status); +constexpr const wchar_t* RGBA8_FORMAT = L"RGBA8"; +constexpr const wchar_t* FORMAT_STRING = L"format"; +constexpr const size_t UUID_UINT8_LENGTH = 16; + +adsk::Data::Structure* createNewMaterialInfoMapStructure() { + // Register our structure since it is not registered yet. + adsk::Data::Structure* fStructure = adsk::Data::Structure::create(); + fStructure->setName(PRT_MATERIALINFO_MAP_STRUCTURE.c_str()); - for (const auto& nodeObj : MItDependencyNodesWrapper(nodeIt)) { - MFnDependencyNode node(nodeObj); - if (std::wcscmp(node.name().asWChar(), name.c_str()) == 0) - return nodeObj; + fStructure->addMember(adsk::Data::Member::eDataType::kUInt64, 1, PRT_MATERIALINFO_MAP_KEY.c_str()); + fStructure->addMember(adsk::Data::Member::eDataType::kUInt8, UUID_UINT8_LENGTH, PRT_MATERIALINFO_MAP_VALUE.c_str()); + + adsk::Data::Structure::registerStructure(*fStructure); + + return fStructure; +} + +adsk::Data::Handle getMaterialInfoMapHandle(const adsk::Data::Structure* fStructure, size_t materialInfoHash, + const MUuid& shadingEngineUuid, MStatus& status) { + adsk::Data::Handle handle(*fStructure); + + handle.setPositionByMemberName(PRT_MATERIALINFO_MAP_KEY.c_str()); + uint64_t* materialInfoHashPtr = handle.asUInt64(); + if (materialInfoHashPtr == nullptr) { + LOG_ERR << "Failed to parse handle value as UInt64"; + status = MS::kFailure; + return handle; + } + *materialInfoHashPtr = materialInfoHash; + + handle.setPositionByMemberName(PRT_MATERIALINFO_MAP_VALUE.c_str()); + uint8_t* shadingEngineUuidPtr = handle.asUInt8(); + if (shadingEngineUuidPtr == nullptr) { + LOG_ERR << "Failed to parse handle value as Uint8"; + status = MS::kFailure; + return handle; + } + uint8_t uuidAsChar[UUID_UINT8_LENGTH]; + shadingEngineUuid.get(uuidAsChar); + for (unsigned int i = 0; i < UUID_UINT8_LENGTH; ++i) { + shadingEngineUuidPtr[i] = uuidAsChar[i]; } - return MObject::kNullObj; + status = MS::kSuccess; + return handle; } +adsk::Data::IndexCount getMaterialInfoMapIndex(const adsk::Data::Stream& stream, const size_t materialInfoHash) { + // Check if there is an obsolete matching duplicate. + for (adsk::Data::Stream::iterator iterator = stream.cbegin(); iterator != stream.cend(); ++iterator) { + iterator->setPositionByMemberName(PRT_MATERIALINFO_MAP_KEY.c_str()); + size_t* hashPtr = iterator->asUInt64(); + + if ((hashPtr != nullptr) && (*hashPtr == materialInfoHash)) + return iterator.index(); + } + + adsk::Data::IndexCount elementCount = stream.elementCount(); + + // Check if there is an unused index in the defined range. + for (adsk::Data::IndexCount i = 0; i < elementCount; ++i) { + if (!stream.hasElement(i)) { + return i; + } + } + + return elementCount; +} } // namespace namespace MaterialUtils { @@ -105,44 +180,68 @@ MStatus getMeshName(MString& meshName, const MPlug& plug) { return MStatus::kSuccess; } -MaterialCache getMaterialsByStructure(const adsk::Data::Structure& materialStructure, const std::wstring& baseName) { - MaterialCache existingMaterialInfos; +MaterialCache getMaterialCache() { + const adsk::Data::Associations* metadata = MFileIO::metadata(); + adsk::Data::Associations materialAssociations(metadata); + adsk::Data::Channel* matChannel = materialAssociations.findChannel(PRT_MATERIALINFO_MAP_CHANNEL); - MStatus status; - MItDependencyNodes shaderIt(MFn::kShadingEngine, &status); - MCHECK(status); - for (const auto& nodeObj : MItDependencyNodesWrapper(shaderIt)) { - MFnDependencyNode node(nodeObj); - - const adsk::Data::Associations* materialMetadata = node.metadata(&status); - MCHECK(status); + MaterialUtils::MaterialCache existingMaterialInfos; - if (materialMetadata == nullptr) - continue; - - adsk::Data::Associations materialAssociations(materialMetadata); - adsk::Data::Channel* matChannel = materialAssociations.findChannel(PRT_MATERIAL_CHANNEL); + if (matChannel == nullptr) + return existingMaterialInfos; - if (matChannel == nullptr) - continue; + adsk::Data::Stream* matStream = matChannel->findDataStream(PRT_MATERIALINFO_MAP_STREAM); + if (matStream == nullptr) + return existingMaterialInfos; - adsk::Data::Stream* matStream = matChannel->findDataStream(PRT_MATERIAL_STREAM); - if ((matStream == nullptr) || (matStream->elementCount() != 1)) + for (adsk::Data::Stream::iterator iterator = matStream->begin(); iterator != matStream->end(); ++iterator) { + iterator->setPositionByMemberName(PRT_MATERIALINFO_MAP_KEY.c_str()); + size_t* hashPtr = iterator->asUInt64(); + if (hashPtr == nullptr) continue; - adsk::Data::Handle matSHandle = matStream->element(0); - if (!matSHandle.usesStructure(materialStructure)) + iterator->setPositionByMemberName(PRT_MATERIALINFO_MAP_VALUE.c_str()); + uint8_t* uuidPtr = iterator->asUInt8(); + if (uuidPtr == nullptr) continue; - if (std::wcsncmp(node.name().asWChar(), baseName.c_str(), baseName.length()) != 0) - continue; - - existingMaterialInfos.emplace(matSHandle, node.name().asWChar()); + existingMaterialInfos.emplace(*hashPtr, uuidPtr); } return existingMaterialInfos; } +MStatus addMaterialInfoMapMetadata(size_t materialInfoHash, const MUuid& shadingEngineUuid) { + const adsk::Data::Associations* metadata = MFileIO::metadata(); + adsk::Data::Associations newMetadata(metadata); + + adsk::Data::Structure* fStructure = adsk::Data::Structure::structureByName(PRT_MATERIALINFO_MAP_STRUCTURE.c_str()); + + if (fStructure == nullptr) + fStructure = createNewMaterialInfoMapStructure(); + + adsk::Data::Stream newStream(*fStructure, PRT_MATERIALINFO_MAP_STREAM); + adsk::Data::Channel newChannel = newMetadata.channel(PRT_MATERIALINFO_MAP_CHANNEL); + adsk::Data::Stream* newStreamPtr = newChannel.findDataStream(PRT_MATERIALINFO_MAP_STREAM); + if (newStreamPtr != nullptr) + newStream = *newStreamPtr; + + MStatus status; + adsk::Data::Handle handle = getMaterialInfoMapHandle(fStructure, materialInfoHash, shadingEngineUuid, status); + if (status != MS::kSuccess) + return status; + + adsk::Data::IndexCount index = getMaterialInfoMapIndex(newStream, materialInfoHash); + + newStream.setElement(index, handle); + newChannel.setDataStream(newStream); + newMetadata.setChannel(newChannel); + + MFileIO::setMetadata(newMetadata); + + return MS::kSuccess; +} + bool getFaceRange(adsk::Data::Handle& handle, std::pair& faceRange) { if (!handle.setPositionByMemberName(PRT_MATERIAL_FACE_INDEX_START.c_str())) return false; @@ -155,22 +254,6 @@ bool getFaceRange(adsk::Data::Handle& handle, std::pair& faceRange) { return true; } -void assignMaterialMetadata(const adsk::Data::Structure& materialStructure, const adsk::Data::Handle& streamHandle, - const std::wstring& shadingEngineName) { - MObject shadingEngineObj = findNamedObject(shadingEngineName, MFn::kShadingEngine); - MFnDependencyNode shadingEngine(shadingEngineObj); - - adsk::Data::Associations newMetadata; - adsk::Data::Channel newChannel = newMetadata.channel(PRT_MATERIAL_CHANNEL); - adsk::Data::Stream newStream(materialStructure, PRT_MATERIAL_STREAM); - newChannel.setDataStream(newStream); - newMetadata.setChannel(newChannel); - adsk::Data::Handle handle(streamHandle); - handle.makeUnique(); - newStream.setElement(0, handle); - shadingEngine.setMetadata(newMetadata); -} - std::wstring synchronouslyCreateShadingEngine(const std::wstring& desiredShadingEngineName, const MELVariable& shadingEngineVariable, MStatus& status) { MELScriptBuilder scriptBuilder; @@ -183,15 +266,33 @@ std::wstring synchronouslyCreateShadingEngine(const std::wstring& desiredShading return output; } -std::wstring getStingrayShaderPath() { - static const std::wstring sfxFile = []() { - // mel command wants forward slashes - const std::wstring shadersPath = prtu::toGenericPath(PRTContext::get().mPluginRootPath + L"../shaders/"); - std::wstring p = shadersPath + L"serlioShaderStingray.sfx"; - LOG_DBG << "stingray shader located at " << p; - return p; +std::filesystem::path getStingrayShaderPath() { + static const std::filesystem::path sfxFile = []() { + const std::filesystem::path shaderPath = + (PRTContext::get().mPluginRootPath.parent_path() / L"shaders/serlioShaderStingray.sfx"); + LOG_DBG << "stingray shader located at " << shaderPath; + return shaderPath; }(); return sfxFile; } +bool textureHasAlphaChannel(const std::wstring& path) { + const AttributeMapUPtr textureMetadata(prt::createTextureMetadata(prtu::toFileURI(path).c_str())); + if (textureMetadata == nullptr) + return false; + const wchar_t* format = textureMetadata->getString(FORMAT_STRING); + if (format != nullptr && std::wcscmp(format, RGBA8_FORMAT) == 0) + return true; + return false; +} + +void resetMaterial(const std::wstring& meshName) { + MELScriptBuilder scriptBuilder; + scriptBuilder.declInt(MEL_UNDO_STATE); + scriptBuilder.getUndoState(MEL_UNDO_STATE); + scriptBuilder.setUndoState(false); + scriptBuilder.setsUseInitialShadingGroup(meshName); + scriptBuilder.setUndoState(MEL_UNDO_STATE); + scriptBuilder.execute(); +} } // namespace MaterialUtils diff --git a/src/serlio/materials/MaterialUtils.h b/src/serlio/materials/MaterialUtils.h index c1ada139..3e127a75 100644 --- a/src/serlio/materials/MaterialUtils.h +++ b/src/serlio/materials/MaterialUtils.h @@ -1,3 +1,22 @@ +/** + * Serlio - Esri CityEngine Plugin for Autodesk Maya + * + * See https://github.com/esri/serlio for build and usage instructions. + * + * Copyright (c) 2012-2022 Esri R&D Center Zurich + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + #pragma once #include "materials/MaterialInfo.h" @@ -18,17 +37,20 @@ adsk::Data::Stream* getMaterialStream(const MObject& aInMesh, MDataBlock& data); MStatus getMeshName(MString& meshName, const MPlug& plug); -using MaterialCache = std::map; -MaterialCache getMaterialsByStructure(const adsk::Data::Structure& materialStructure, const std::wstring& baseName); +using MaterialCache = std::map; + +MaterialCache getMaterialCache(); bool getFaceRange(adsk::Data::Handle& handle, std::pair& faceRange); -void assignMaterialMetadata(const adsk::Data::Structure& materialStructure, const adsk::Data::Handle& streamHandle, - const std::wstring& shadingEngineName); +MStatus addMaterialInfoMapMetadata(size_t materialInfoHash, const MUuid& shadingEngineUuid); std::wstring synchronouslyCreateShadingEngine(const std::wstring& desiredShadingEngineName, const MELVariable& shadingEngineVariable, MStatus& status); -std::wstring getStingrayShaderPath(); +std::filesystem::path getStingrayShaderPath(); + +bool textureHasAlphaChannel(const std::wstring& path); +void resetMaterial(const std::wstring& meshName); } // namespace MaterialUtils \ No newline at end of file diff --git a/src/serlio/materials/StingrayMaterialNode.cpp b/src/serlio/materials/StingrayMaterialNode.cpp index ad85a8a5..827b7510 100644 --- a/src/serlio/materials/StingrayMaterialNode.cpp +++ b/src/serlio/materials/StingrayMaterialNode.cpp @@ -3,7 +3,7 @@ * * See https://github.com/esri/serlio for build and usage instructions. * - * Copyright (c) 2012-2019 Esri R&D Center Zurich + * Copyright (c) 2012-2022 Esri R&D Center Zurich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,49 +17,31 @@ * limitations under the License. */ -#include "materials/StingrayMaterialNode.h" #include "materials/MaterialInfo.h" #include "materials/MaterialUtils.h" - -#include "modifiers/PRTModifierAction.h" +#include "materials/StingrayMaterialNode.h" #include "utils/MELScriptBuilder.h" -#include "utils/MItDependencyNodesWrapper.h" -#include "utils/MayaUtilities.h" - -#include "PRTContext.h" -#include "serlioPlugin.h" - -#include "maya/MFnMesh.h" -#include "maya/MFnTypedAttribute.h" -#include "maya/MGlobal.h" -#include "maya/MItDependencyNodes.h" -#include "maya/MObject.h" -#include "maya/adskDataAssociations.h" -#include "maya/adskDataStream.h" - -#include -#include -#include namespace { constexpr bool DBG = false; const std::wstring MATERIAL_BASE_NAME = L"serlioStingrayMaterial"; - -std::once_flag pluginDependencyCheckFlag; const std::vector PLUGIN_DEPENDENCIES = {"shaderFXPlugin"}; +const MELVariable MEL_UNDO_STATE(L"serlioMaterialUndoState"); const MELVariable MEL_VAR_SHADER_NODE(L"shaderNode"); const MELVariable MEL_VAR_MAP_FILE(L"mapFile"); const MELVariable MEL_VAR_MAP_NODE(L"mapNode"); const MELVariable MEL_VAR_SHADING_NODE_INDEX(L"shadingNodeIndex"); -void setTexture(MELScriptBuilder& sb, const std::wstring& target, const std::wstring& textureNodeBaseName, - const std::wstring& tex) { +void setTexture(MELScriptBuilder& sb, const std::wstring& target, const std::wstring& tex, + const std::wstring& alphaTarget = {}) { if (!tex.empty()) { - sb.setVar(MEL_VAR_MAP_NODE, MELStringLiteral(textureNodeBaseName)); + std::filesystem::path texPath(tex); + const std::wstring nodeName = prtu::cleanNameForMaya(texPath.stem().wstring()); + sb.setVar(MEL_VAR_MAP_NODE, MELStringLiteral(nodeName)); sb.setVar(MEL_VAR_MAP_FILE, MELStringLiteral(tex)); @@ -67,6 +49,10 @@ void setTexture(MELScriptBuilder& sb, const std::wstring& target, const std::wst sb.setAttr(MEL_VAR_MAP_NODE, L"fileTextureName", MEL_VAR_MAP_FILE); sb.connectAttr(MEL_VAR_MAP_NODE, L"outColor", MEL_VAR_SHADER_NODE, L"TEX_" + target); + + if (!alphaTarget.empty()) + sb.setAttr(MEL_VAR_SHADER_NODE, alphaTarget, MaterialUtils::textureHasAlphaChannel(texPath.wstring())); + sb.setAttr(MEL_VAR_SHADER_NODE, L"use_" + target, 1); } else { @@ -74,8 +60,26 @@ void setTexture(MELScriptBuilder& sb, const std::wstring& target, const std::wst } } -void appendToMaterialScriptBuilder(MELScriptBuilder& sb, const MaterialInfo& matInfo, - const std::wstring& shaderBaseName, const std::wstring& shadingEngineName) { +} // namespace + +MTypeId StingrayMaterialNode::id(SerlioNodeIDs::SERLIO_PREFIX, SerlioNodeIDs::STRINGRAY_MATERIAL_NODE); + +MObject StingrayMaterialNode::mInMesh; +MObject StingrayMaterialNode::mOutMesh; +MStatus StingrayMaterialNode::initialize() { + return initializeAttributes(mInMesh, mOutMesh); +} + +void StingrayMaterialNode::declareMaterialStrings(MELScriptBuilder& sb) { + sb.declString(MEL_VAR_SHADER_NODE); + sb.declString(MEL_VAR_MAP_FILE); + sb.declString(MEL_VAR_MAP_NODE); + sb.declInt(MEL_VAR_SHADING_NODE_INDEX); +} + +void StingrayMaterialNode::appendToMaterialScriptBuilder(MELScriptBuilder& sb, const MaterialInfo& matInfo, + const std::wstring& shaderBaseName, + const std::wstring& shadingEngineName) { // create shader sb.setVar(MEL_VAR_SHADER_NODE, MELStringLiteral(shaderBaseName)); sb.setVar(MEL_VARIABLE_SHADING_ENGINE, MELStringLiteral(shadingEngineName)); @@ -85,7 +89,7 @@ void appendToMaterialScriptBuilder(MELScriptBuilder& sb, const MaterialInfo& mat sb.connectAttr(MEL_VAR_SHADER_NODE, L"outColor", MEL_VARIABLE_SHADING_ENGINE, L"surfaceShader"); // stingray specifics - const MELStringLiteral sfxFile(MaterialUtils::getStingrayShaderPath()); + const MELStringLiteral sfxFile(MaterialUtils::getStingrayShaderPath().generic_wstring()); sb.addCmdLine(L"shaderfx -sfxnode " + MEL_VAR_SHADER_NODE.mel() + L" -loadGraph " + sfxFile.mel() + L";"); sb.setAttr(MEL_VAR_SHADER_NODE, L"initgraph", true); @@ -93,7 +97,7 @@ void appendToMaterialScriptBuilder(MELScriptBuilder& sb, const MaterialInfo& mat sb.addCmdLine(MEL_VAR_SHADING_NODE_INDEX.mel() + L" = `shaderfx -sfxnode " + MEL_VAR_SHADER_NODE.mel() + L" -getNodeIDByName " + nodeIDName.mel() + L"`;"); - const std::wstring blendMode = (matInfo.opacityMap.empty() && (matInfo.opacity >= 1.0)) ? L"0" : L"1"; + const std::wstring blendMode = (matInfo.opacityMap.empty() && (matInfo.opacity >= 1.0)) ? L"0" : L"2"; sb.addCmdLine(L"shaderfx -sfxnode " + MEL_VAR_SHADER_NODE.mel() + L" -edit_stringlist " + MEL_VAR_SHADING_NODE_INDEX.mel() + L" blendmode " + blendMode + L";"); @@ -124,118 +128,27 @@ void appendToMaterialScriptBuilder(MELScriptBuilder& sb, const MaterialInfo& mat // ignored: bumpMap, specularMap, occlusionmap // TODO: avoid wide/narrow conversion of map strings - setTexture(sb, L"color_map", shaderBaseName, prtu::toUTF16FromOSNarrow(matInfo.colormap)); - setTexture(sb, L"dirt_map", shaderBaseName, prtu::toUTF16FromOSNarrow(matInfo.dirtmap)); - setTexture(sb, L"emissive_map", shaderBaseName, prtu::toUTF16FromOSNarrow(matInfo.emissiveMap)); - setTexture(sb, L"metallic_map", shaderBaseName, prtu::toUTF16FromOSNarrow(matInfo.metallicMap)); - setTexture(sb, L"normal_map", shaderBaseName, prtu::toUTF16FromOSNarrow(matInfo.normalMap)); - setTexture(sb, L"roughness_map", shaderBaseName, prtu::toUTF16FromOSNarrow(matInfo.roughnessMap)); - setTexture(sb, L"opacity_map", shaderBaseName, prtu::toUTF16FromOSNarrow(matInfo.opacityMap)); + setTexture(sb, L"color_map", prtu::toUTF16FromOSNarrow(matInfo.colormap)); + setTexture(sb, L"dirt_map", prtu::toUTF16FromOSNarrow(matInfo.dirtmap)); + setTexture(sb, L"emissive_map", prtu::toUTF16FromOSNarrow(matInfo.emissiveMap)); + setTexture(sb, L"metallic_map", prtu::toUTF16FromOSNarrow(matInfo.metallicMap)); + setTexture(sb, L"normal_map", prtu::toUTF16FromOSNarrow(matInfo.normalMap)); + setTexture(sb, L"roughness_map", prtu::toUTF16FromOSNarrow(matInfo.roughnessMap)); + setTexture(sb, L"opacity_map", prtu::toUTF16FromOSNarrow(matInfo.opacityMap), L"opacity_map_uses_alpha_channel"); } -} // namespace - -MTypeId StingrayMaterialNode::id(SerlioNodeIDs::SERLIO_PREFIX, SerlioNodeIDs::STRINGRAY_MATERIAL_NODE); - -MObject StingrayMaterialNode::aInMesh; -MObject StingrayMaterialNode::aOutMesh; -const MString OUTPUT_GEOMETRY = MString("og"); - -MStatus StingrayMaterialNode::initialize() { - MStatus status; - - MFnTypedAttribute tAttr; - aInMesh = tAttr.create("inMesh", "im", MFnData::kMesh, MObject::kNullObj, &status); - MCHECK(status); - addAttribute(aInMesh); - - aOutMesh = tAttr.create("outMesh", "om", MFnData::kMesh, MObject::kNullObj, &status); - MCHECK(status); - tAttr.setWritable(false); - tAttr.setStorable(false); - addAttribute(aOutMesh); - - attributeAffects(aInMesh, aOutMesh); - - return MStatus::kSuccess; +std::wstring StingrayMaterialNode::getBaseName() const { + return MATERIAL_BASE_NAME; } -MStatus StingrayMaterialNode::compute(const MPlug& plug, MDataBlock& data) { - if (plug != aOutMesh) - return MStatus::kUnknownParameter; - - MStatus status = MStatus::kSuccess; - - std::call_once(pluginDependencyCheckFlag, [&status]() { - const bool b = MayaPluginUtilities::pluginDependencyCheck(PLUGIN_DEPENDENCIES); - status = b ? MStatus::kSuccess : MStatus::kFailure; - }); - if (status != MStatus::kSuccess) - return status; - - MaterialUtils::forwardGeometry(aInMesh, aOutMesh, data); - - adsk::Data::Stream* inMatStream = MaterialUtils::getMaterialStream(aInMesh, data); - if (inMatStream == nullptr) - return MStatus::kSuccess; - - const adsk::Data::Structure* materialStructure = - adsk::Data::Structure::structureByName(PRT_MATERIAL_STRUCTURE.c_str()); - if (materialStructure == nullptr) - return MStatus::kFailure; - - MString meshName; - MStatus meshNameStatus = MaterialUtils::getMeshName(meshName, plug); - if (meshNameStatus != MStatus::kSuccess || meshName.length() == 0) - return meshNameStatus; - - MaterialUtils::MaterialCache matCache = - MaterialUtils::getMaterialsByStructure(*materialStructure, MATERIAL_BASE_NAME); - - MELScriptBuilder scriptBuilder; - scriptBuilder.declString(MEL_VARIABLE_SHADING_ENGINE); - - // declare MEL variables required by appendToMaterialScriptBuilder() - scriptBuilder.declString(MEL_VAR_SHADER_NODE); - scriptBuilder.declString(MEL_VAR_MAP_FILE); - scriptBuilder.declString(MEL_VAR_MAP_NODE); - scriptBuilder.declInt(MEL_VAR_SHADING_NODE_INDEX); - - for (adsk::Data::Handle& materialHandle : *inMatStream) { - if (!materialHandle.hasData()) - continue; - - if (!materialHandle.usesStructure(*materialStructure)) - continue; - - std::pair faceRange; - if (!MaterialUtils::getFaceRange(materialHandle, faceRange)) - continue; - - auto createShadingEngine = [this, &materialStructure, &scriptBuilder, - &materialHandle](const MaterialInfo& matInfo) { - const std::wstring shadingEngineBaseName = MATERIAL_BASE_NAME + L"Sg"; - const std::wstring shaderBaseName = MATERIAL_BASE_NAME + L"Sh"; - - MStatus status; - const std::wstring shadingEngineName = MaterialUtils::synchronouslyCreateShadingEngine( - shadingEngineBaseName, MEL_VARIABLE_SHADING_ENGINE, status); - MCHECK(status); - - MaterialUtils::assignMaterialMetadata(*materialStructure, materialHandle, shadingEngineName); - appendToMaterialScriptBuilder(scriptBuilder, matInfo, shaderBaseName, shadingEngineName); - LOG_DBG << "new stingray shading engine: " << shadingEngineName; - - return shadingEngineName; - }; +MObject StingrayMaterialNode::getInMesh() const { + return mInMesh; +} - MaterialInfo matInfo(materialHandle); - std::wstring shadingEngineName = getCachedValue(matCache, matInfo, createShadingEngine, matInfo); - scriptBuilder.setsAddFaceRange(shadingEngineName, meshName.asWChar(), faceRange.first, faceRange.second); - LOG_DBG << "assigned stingray shading engine (" << faceRange.first << ":" << faceRange.second - << "): " << shadingEngineName; - } +MObject StingrayMaterialNode::getOutMesh() const { + return mOutMesh; +} - LOG_DBG << "scheduling stringray material script"; - return scriptBuilder.execute(); // note: script is executed asynchronously +std::vector StingrayMaterialNode::getPluginDependencies() const { + return PLUGIN_DEPENDENCIES; } diff --git a/src/serlio/materials/StingrayMaterialNode.h b/src/serlio/materials/StingrayMaterialNode.h index 3266ff6a..befd853a 100644 --- a/src/serlio/materials/StingrayMaterialNode.h +++ b/src/serlio/materials/StingrayMaterialNode.h @@ -3,7 +3,7 @@ * * See https://github.com/esri/serlio for build and usage instructions. * - * Copyright (c) 2012-2019 Esri R&D Center Zurich + * Copyright (c) 2012-2022 Esri R&D Center Zurich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,24 +19,25 @@ #pragma once -#include "maya/MPxNode.h" -#include "maya/MString.h" -#include "maya/adskDataHandle.h" +#include "MaterialNode.h" -#include - -class MaterialColor; -struct PRTContext; class MaterialInfo; -class MaterialTrafo; class MELScriptBuilder; -class StingrayMaterialNode : public MPxNode { +class StingrayMaterialNode : public MaterialNode { public: static MStatus initialize(); - MStatus compute(const MPlug& plug, MDataBlock& data) override; - static MTypeId id; - static MObject aInMesh; - static MObject aOutMesh; + + static MObject mInMesh; + static MObject mOutMesh; + +private: + void declareMaterialStrings(MELScriptBuilder& sb); + void appendToMaterialScriptBuilder(MELScriptBuilder& sb, const MaterialInfo& matInfo, + const std::wstring& shaderBaseName, const std::wstring& shadingEngineName); + std::wstring getBaseName() const override; + MObject getInMesh() const override; + MObject getOutMesh() const override; + std::vector getPluginDependencies() const override; }; diff --git a/src/serlio/modifiers/MayaCallbacks.cpp b/src/serlio/modifiers/MayaCallbacks.cpp index 4b187b34..16f0dfcf 100644 --- a/src/serlio/modifiers/MayaCallbacks.cpp +++ b/src/serlio/modifiers/MayaCallbacks.cpp @@ -3,7 +3,7 @@ * * See https://github.com/esri/serlio for build and usage instructions. * - * Copyright (c) 2012-2019 Esri R&D Center Zurich + * Copyright (c) 2012-2022 Esri R&D Center Zurich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,6 +22,8 @@ #include "materials/MaterialInfo.h" +#include "PRTContext.h" +#include "utils/AssetCache.h" #include "utils/LogHandler.h" #include "utils/MayaUtilities.h" #include "utils/Utilities.h" @@ -31,6 +33,7 @@ #include "maya/MFloatArray.h" #include "maya/MFloatPointArray.h" #include "maya/MFloatVectorArray.h" +#include "maya/MFnDependencyNode.h" #include "maya/MFnMesh.h" #include "maya/MFnMeshData.h" #include "maya/adskDataAssociations.h" @@ -42,6 +45,8 @@ namespace { constexpr bool DBG = false; +constexpr const wchar_t* MAYA_ASSET_FOLDER = L"assets"; +constexpr const wchar_t* SERLIO_ASSET_FOLDER = L"serlio_assets"; void checkStringLength(const wchar_t* string, const size_t& maxStringLength) { if (wcslen(string) >= maxStringLength) { @@ -62,27 +67,24 @@ MFloatPointArray toMayaFloatPointArray(double const* a, size_t s) { const unsigned int numPoints = static_cast(s) / 3; MFloatPointArray mfpa(numPoints); for (unsigned int i = 0; i < numPoints; ++i) { - mfpa.set(MFloatPoint(static_cast(a[i * 3 + 0]), static_cast(a[i * 3 + 1]), - static_cast(a[i * 3 + 2])), + mfpa.set(MFloatPoint(static_cast(a[i * 3 + 0] * mu::PRT_TO_SERLIO_SCALE), + static_cast(a[i * 3 + 1] * mu::PRT_TO_SERLIO_SCALE), + static_cast(a[i * 3 + 2] * mu::PRT_TO_SERLIO_SCALE)), i); } return mfpa; } -} // namespace - struct TextureUVOrder { MString mayaUvSetName; uint8_t mayaUvSetIndex; uint8_t prtUvSetIndex; }; -// maya pbr stingray shader only supports first 4 uvsets -> reoder so first 4 are most important ones -// other shaders support >4 sets const std::vector TEXTURE_UV_ORDERS = []() -> std::vector { // clang-format off return { - // maya uvset name | maya idx | prt idx | CGA key + // first 4 uv sets are selected to be compatible with the Maya PBR Stingray shader { L"map1", 0, 0 }, // colormap { L"dirtMap", 1, 2 }, // dirtmap { L"normalMap", 2, 5 }, // normalmap @@ -98,48 +100,19 @@ const std::vector TEXTURE_UV_ORDERS = []() -> std::vectorsecond++; + } +} +} // namespace + +prt::Status MayaCallbacks::generateError(size_t /*isIndex*/, prt::Status /*status*/, const wchar_t* message) { + LOG_ERR << "GENERATE ERROR: " << message; + detectAndAppendCGACErrors(prt::CGAErrorLevel::CGAERROR, message, cgacErrors); + return prt::STATUS_OK; +} + +prt::Status MayaCallbacks::assetError(size_t /*isIndex*/, prt::CGAErrorLevel level, const wchar_t* /*key*/, + const wchar_t* /*uri*/, const wchar_t* message) { + LOG_ERR << "ASSET ERROR: " << message; + detectAndAppendCGACErrors(level, message, cgacErrors); + return prt::STATUS_OK; +} + +prt::Status MayaCallbacks::cgaError(size_t /*isIndex*/, int32_t /*shapeID*/, prt::CGAErrorLevel level, + int32_t /*methodId*/, int32_t /*pc*/, const wchar_t* message) { + LOG_ERR << "CGA ERROR: " << message; + detectAndAppendCGACErrors(level, message, cgacErrors); + return prt::STATUS_OK; +} + +prt::Status MayaCallbacks::cgaPrint(size_t /*isIndex*/, int32_t /*shapeID*/, const wchar_t* txt) { + LOG_INF << "CGA PRINT: " << txt; + return prt::STATUS_OK; +} + +prt::Status MayaCallbacks::cgaReportBool(size_t /*isIndex*/, int32_t /*shapeID*/, const wchar_t* /*key*/, + bool /*value*/) { + return prt::STATUS_OK; +} + +prt::Status MayaCallbacks::cgaReportFloat(size_t /*isIndex*/, int32_t /*shapeID*/, const wchar_t* /*key*/, + double /*value*/) { + return prt::STATUS_OK; +} + +prt::Status MayaCallbacks::cgaReportString(size_t /*isIndex*/, int32_t /*shapeID*/, const wchar_t* /*key*/, + const wchar_t* /*value*/) { + return prt::STATUS_OK; +} + +const CGACErrors& MayaCallbacks::getCGACErrors() const { + return cgacErrors; +} + +void MayaCallbacks::addMesh(const wchar_t*, const double* vtx, size_t vtxSize, const double* nrm, size_t nrmSize, + const uint32_t* faceCounts, size_t faceCountsSize, const uint32_t* vertexIndices, + size_t vertexIndicesSize, const uint32_t* normalIndices, size_t normalIndicesSize, + double const* const* uvs, size_t const* uvsSizes, uint32_t const* const* uvCounts, + size_t const* uvCountsSizes, uint32_t const* const* uvIndices, size_t const* uvIndicesSizes, + size_t uvSetsCount, const uint32_t* faceRanges, size_t faceRangesSize, + const prt::AttributeMap** materials, const prt::AttributeMap** reports, const int32_t*) { + MStatus stat; + adsk::Data::Structure* fStructure = adsk::Data::Structure::structureByName(PRT_MATERIAL_STRUCTURE.c_str()); + + if ((fStructure == nullptr) && (materials != nullptr) && (faceRangesSize > 1)) { + fStructure = createNewMayaStructure(materials); // Structure to use for creation + } + + MFnMesh inputMesh(inMeshObj); + + adsk::Data::Associations newMetadata(inputMesh.metadata(&stat)); + newMetadata.makeUnique(); + MCHECK(stat); + + if (fStructure != nullptr && faceRangesSize > 1) { + fillMetadata(fStructure, faceRanges, faceRangesSize, materials, reports, newMetadata); + } + + MFloatPointArray mayaVertices = toMayaFloatPointArray(vtx, vtxSize); + MIntArray mayaFaceCounts = toMayaIntArray(faceCounts, faceCountsSize); + MIntArray mayaVertexIndices = toMayaIntArray(vertexIndices, vertexIndicesSize); + + if (DBG) { + LOG_DBG << "-- MayaCallbacks::addMesh"; + LOG_DBG << " faceCountsSize = " << faceCountsSize; + LOG_DBG << " vertexIndicesSize = " << vertexIndicesSize; + LOG_DBG << " mayaVertices.length = " << mayaVertices.length(); + LOG_DBG << " mayaFaceCounts.length = " << mayaFaceCounts.length(); + LOG_DBG << " mayaVertexIndices.length = " << mayaVertexIndices.length(); + } + + updateMayaMesh(uvs, uvsSizes, uvCounts, uvCountsSizes, uvIndices, uvIndicesSizes, uvSetsCount, nrm, nrmSize, + normalIndices, normalIndicesSize, mayaVertices, mayaFaceCounts, mayaVertexIndices, outMeshObj, + newMetadata); +} + prt::Status MayaCallbacks::attrBool(size_t /*isIndex*/, int32_t /*shapeID*/, const wchar_t* key, bool value) { mAttributeMapBuilder->setBool(key, value); return prt::STATUS_OK; @@ -401,8 +530,58 @@ prt::Status MayaCallbacks::attrString(size_t /*isIndex*/, int32_t /*shapeID*/, c return prt::STATUS_OK; } +void MayaCallbacks::addAsset(const wchar_t* uri, const wchar_t* fileName, const uint8_t* buffer, size_t size, + wchar_t* result, size_t& resultSize) { + if (uri == nullptr || std::wcslen(uri) == 0 || fileName == nullptr || std::wcslen(fileName) == 0) { + LOG_WRN << "Skipping asset caching for invalid uri '" << uri << "' or filename '" << fileName << '"'; + resultSize = 0; + return; + } + + std::filesystem::path assetDir = getAssetDir(); + + const std::filesystem::path& assetPath = + (!assetDir.empty()) ? PRTContext::get().mAssetCache.put(uri, fileName, assetDir, buffer, size) + : std::filesystem::path(); + + if (assetPath.empty()) { + resultSize = 0; + return; + } + + const std::wstring pathStr = assetPath.generic_wstring(); + + if (resultSize <= pathStr.size()) { // also check for null-terminator + resultSize = pathStr.size() + 1; // ask for space for null-terminator + return; + } + + copyStringToWCharPtr(pathStr, result, resultSize); +} + +// PRT version >= 2.3 +#if PRT_VERSION_GTE(2, 3) + +prt::Status MayaCallbacks::attrBoolArray(size_t /*isIndex*/, int32_t /*shapeID*/, const wchar_t* key, + const bool* values, size_t size, size_t /*nRows*/) { + mAttributeMapBuilder->setBoolArray(key, values, size); + return prt::STATUS_OK; +} + +prt::Status MayaCallbacks::attrFloatArray(size_t /*isIndex*/, int32_t /*shapeID*/, const wchar_t* key, + const double* values, size_t size, size_t /*nRows*/) { + mAttributeMapBuilder->setFloatArray(key, values, size); + return prt::STATUS_OK; +} + +prt::Status MayaCallbacks::attrStringArray(size_t /*isIndex*/, int32_t /*shapeID*/, const wchar_t* key, + const wchar_t* const* values, size_t size, size_t /*nRows*/) { + mAttributeMapBuilder->setStringArray(key, values, size); + return prt::STATUS_OK; +} + // PRT version >= 2.1 -#if PRT_VERSION_GTE(2, 1) +#elif PRT_VERSION_GTE(2, 1) prt::Status MayaCallbacks::attrBoolArray(size_t /*isIndex*/, int32_t /*shapeID*/, const wchar_t* key, const bool* values, size_t size) { diff --git a/src/serlio/modifiers/MayaCallbacks.h b/src/serlio/modifiers/MayaCallbacks.h index b9027953..9aff6908 100644 --- a/src/serlio/modifiers/MayaCallbacks.h +++ b/src/serlio/modifiers/MayaCallbacks.h @@ -3,7 +3,7 @@ * * See https://github.com/esri/serlio for build and usage instructions. * - * Copyright (c) 2012-2019 Esri R&D Center Zurich + * Copyright (c) 2012-2022 Esri R&D Center Zurich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,49 +33,59 @@ #include #include +struct CGACError { + prt::CGAErrorLevel errorLevel; + bool shouldBeLogged; + std::wstring errorString; + + CGACError(prt::CGAErrorLevel errorLevel, bool shouldBeLogged, const std::wstring& errorString) + : errorLevel(errorLevel), shouldBeLogged(shouldBeLogged), errorString(errorString) {} + + bool operator<(const CGACError& other) const { + // make sure errors are in front + if (errorLevel != other.errorLevel) + return errorLevel < other.errorLevel; + // sort alphabetically if both have the same error level + return errorString < other.errorString; + } +}; +using CGACErrors = std::map; + class MayaCallbacks : public IMayaCallbacks { public: MayaCallbacks(const MObject& inMesh, const MObject& outMesh, AttributeMapBuilderUPtr& amb) : inMeshObj(inMesh), outMeshObj(outMesh), mAttributeMapBuilder(amb) {} // prt::Callbacks interface - prt::Status generateError(size_t /*isIndex*/, prt::Status /*status*/, const wchar_t* message) override { - LOG_ERR << "GENERATE ERROR: " << message; - return prt::STATUS_OK; - } - prt::Status assetError(size_t /*isIndex*/, prt::CGAErrorLevel /*level*/, const wchar_t* /*key*/, - const wchar_t* /*uri*/, const wchar_t* message) override { - LOG_ERR << "ASSET ERROR: " << message; - return prt::STATUS_OK; - } + prt::Status generateError(size_t /*isIndex*/, prt::Status /*status*/, const wchar_t* message) override; + prt::Status assetError(size_t /*isIndex*/, prt::CGAErrorLevel level, const wchar_t* /*key*/, const wchar_t* /*uri*/, + const wchar_t* message) override; + prt::Status cgaError(size_t /*isIndex*/, int32_t /*shapeID*/, prt::CGAErrorLevel /*level*/, int32_t /*methodId*/, - int32_t /*pc*/, const wchar_t* message) override { - LOG_ERR << "CGA ERROR: " << message; - return prt::STATUS_OK; - } - prt::Status cgaPrint(size_t /*isIndex*/, int32_t /*shapeID*/, const wchar_t* txt) override { - LOG_INF << "CGA PRINT: " << txt; - return prt::STATUS_OK; - } - prt::Status cgaReportBool(size_t /*isIndex*/, int32_t /*shapeID*/, const wchar_t* /*key*/, - bool /*value*/) override { - return prt::STATUS_OK; - } + int32_t /*pc*/, const wchar_t* message) override; + prt::Status cgaPrint(size_t /*isIndex*/, int32_t /*shapeID*/, const wchar_t* txt) override; + prt::Status cgaReportBool(size_t /*isIndex*/, int32_t /*shapeID*/, const wchar_t* /*key*/, bool /*value*/) override; prt::Status cgaReportFloat(size_t /*isIndex*/, int32_t /*shapeID*/, const wchar_t* /*key*/, - double /*value*/) override { - return prt::STATUS_OK; - } + double /*value*/) override; prt::Status cgaReportString(size_t /*isIndex*/, int32_t /*shapeID*/, const wchar_t* /*key*/, - const wchar_t* /*value*/) override { - return prt::STATUS_OK; - } + const wchar_t* /*value*/) override; + prt::Status attrBool(size_t /*isIndex*/, int32_t /*shapeID*/, const wchar_t* /*key*/, bool /*value*/) override; prt::Status attrFloat(size_t /*isIndex*/, int32_t /*shapeID*/, const wchar_t* /*key*/, double /*value*/) override; prt::Status attrString(size_t /*isIndex*/, int32_t /*shapeID*/, const wchar_t* /*key*/, const wchar_t* /*value*/) override; -// PRT version >= 2.1 -#if PRT_VERSION_GTE(2, 1) +// PRT version >= 2.3 +#if PRT_VERSION_GTE(2, 3) + + prt::Status attrBoolArray(size_t /*isIndex*/, int32_t /*shapeID*/, const wchar_t* /*key*/, const bool* /*values*/, + size_t /*size*/, size_t /*nRows*/) override; + prt::Status attrFloatArray(size_t /*isIndex*/, int32_t /*shapeID*/, const wchar_t* /*key*/, + const double* /*values*/, size_t /*size*/, size_t /*nRows*/) override; + prt::Status attrStringArray(size_t /*isIndex*/, int32_t /*shapeID*/, const wchar_t* /*key*/, + const wchar_t* const* /*values*/, size_t /*size*/, size_t /*nRows*/) override; + +#elif PRT_VERSION_GTE(2, 1) prt::Status attrBoolArray(size_t /*isIndex*/, int32_t /*shapeID*/, const wchar_t* /*key*/, const bool* /*values*/, size_t /*size*/) override; @@ -86,7 +96,8 @@ class MayaCallbacks : public IMayaCallbacks { #endif // PRT version >= 2.1 -public: + const CGACErrors& getCGACErrors() const; + // clang-format off void addMesh(const wchar_t* name, const double* vtx, size_t vtxSize, @@ -106,7 +117,11 @@ class MayaCallbacks : public IMayaCallbacks { const int32_t* shapeIDs) override; // clang-format on + void addAsset(const wchar_t* uri, const wchar_t* fileName, const uint8_t* buffer, size_t size, wchar_t* result, + size_t& resultSize) override; + private: + CGACErrors cgacErrors; MObject outMeshObj; MObject inMeshObj; diff --git a/src/serlio/modifiers/PRTMesh.cpp b/src/serlio/modifiers/PRTMesh.cpp index c4ac8756..5687e5b1 100644 --- a/src/serlio/modifiers/PRTMesh.cpp +++ b/src/serlio/modifiers/PRTMesh.cpp @@ -3,7 +3,7 @@ * * See https://github.com/esri/serlio for build and usage instructions. * - * Copyright (c) 2012-2019 Esri R&D Center Zurich + * Copyright (c) 2012-2022 Esri R&D Center Zurich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -42,9 +42,9 @@ PRTMesh::PRTMesh(const MObject& mesh) { const unsigned int vertexArrayLength = vertexArray.length(); mVertexCoordsVec.reserve(3 * vertexArrayLength); for (unsigned int i = 0; i < vertexArrayLength; ++i) { - mVertexCoordsVec.push_back(vertexArray[i].x); - mVertexCoordsVec.push_back(vertexArray[i].y); - mVertexCoordsVec.push_back(vertexArray[i].z); + mVertexCoordsVec.push_back(vertexArray[i].x / mu::PRT_TO_SERLIO_SCALE); + mVertexCoordsVec.push_back(vertexArray[i].y / mu::PRT_TO_SERLIO_SCALE); + mVertexCoordsVec.push_back(vertexArray[i].z / mu::PRT_TO_SERLIO_SCALE); } // faces diff --git a/src/serlio/modifiers/PRTMesh.h b/src/serlio/modifiers/PRTMesh.h index b3fcb80d..cac1f418 100644 --- a/src/serlio/modifiers/PRTMesh.h +++ b/src/serlio/modifiers/PRTMesh.h @@ -3,7 +3,7 @@ * * See https://github.com/esri/serlio for build and usage instructions. * - * Copyright (c) 2012-2019 Esri R&D Center Zurich + * Copyright (c) 2012-2022 Esri R&D Center Zurich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,6 +21,7 @@ #include "maya/MTypes.h" +#include #include class PRTMesh { diff --git a/src/serlio/modifiers/PRTModifierAction.cpp b/src/serlio/modifiers/PRTModifierAction.cpp index c359f5f1..d3dc2f06 100644 --- a/src/serlio/modifiers/PRTModifierAction.cpp +++ b/src/serlio/modifiers/PRTModifierAction.cpp @@ -3,7 +3,7 @@ * * See https://github.com/esri/serlio for build and usage instructions. * - * Copyright (c) 2012-2019 Esri R&D Center Zurich + * Copyright (c) 2012-2022 Esri R&D Center Zurich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,7 +18,6 @@ */ #include "modifiers/PRTModifierAction.h" -#include "modifiers/MayaCallbacks.h" #include "modifiers/PRTModifierCommand.h" #include "modifiers/RuleAttributes.h" @@ -28,19 +27,18 @@ #include "prt/StringUtils.h" +#include "maya/MDataHandle.h" #include "maya/MFloatPointArray.h" #include "maya/MFnCompoundAttribute.h" #include "maya/MFnMesh.h" #include "maya/MFnNumericAttribute.h" +#include "maya/MFnStringArrayData.h" #include "maya/MFnStringData.h" #include "maya/MFnTypedAttribute.h" +#include "maya/MGlobal.h" #include -#define CHECK_STATUS(st) \ - if ((st) != MS::kSuccess) { \ - break; \ - } namespace { constexpr bool DBG = false; @@ -55,14 +53,60 @@ constexpr const wchar_t* FILE_CGA_PRINT = L"CGAPrint.txt"; constexpr const wchar_t* NULL_KEY = L"#NULL#"; constexpr const wchar_t* MIN_KEY = L"min"; constexpr const wchar_t* MAX_KEY = L"max"; -constexpr const wchar_t* RESTRICTED_KEY = L"restricted"; + +constexpr const wchar_t* ATTRIBUTE_USER_SET_SUFFIX = L"_user_set"; +constexpr const wchar_t* ATTRIBUTE_FORCE_DEFAULT_SUFFIX = L"_force_default"; const AttributeMapUPtr EMPTY_ATTRIBUTES(AttributeMapBuilderUPtr(prt::AttributeMapBuilder::create())->createAttributeMap()); +enum class RangeType { RANGE, ENUM, INVALID }; +RangeType GetRangeType(const prt::Annotation* an) { + const size_t numArgs = an->getNumArguments(); + + if (numArgs == 0) + return RangeType::INVALID; + + prt::AnnotationArgumentType commonType = an->getArgument(0)->getType(); + + bool hasMin = false; + bool hasMax = false; + bool hasKey = false; + bool onlyOneTypeInUse = true; + + for (int argIdx = 0; argIdx < numArgs; argIdx++) { + const prt::AnnotationArgument* arg = an->getArgument(argIdx); + if (arg->getType() != commonType) + onlyOneTypeInUse = false; + + const wchar_t* key = arg->getKey(); + if (std::wcscmp(key, MIN_KEY) == 0) + hasMin = true; + else if (std::wcscmp(key, MAX_KEY) == 0) + hasMax = true; + if (std::wcscmp(key, NULL_KEY) != 0) + hasKey = true; + } + + //old Range + if ((numArgs == 2) && (commonType == prt::AnnotationArgumentType::AAT_FLOAT)) + return RangeType::RANGE; + + //new Range + if ((numArgs >= 2) && (hasMin && hasMax)) + return RangeType::RANGE; + + //legacy Enum + if (!hasKey && onlyOneTypeInUse) + return RangeType::ENUM; + + return RangeType::INVALID; +} + AttributeMapUPtr getDefaultAttributeValues(const std::wstring& ruleFile, const std::wstring& startRule, const prt::ResolveMap& resolveMap, prt::CacheObject& cache, - const PRTMesh& prtMesh) { + const PRTMesh& prtMesh, const int32_t seed, + const prt::AttributeMap& attributeMap) { AttributeMapBuilderUPtr mayaCallbacksAttributeBuilder(prt::AttributeMapBuilder::create()); MayaCallbacks mayaCallbacks(MObject::kNullObj, MObject::kNullObj, mayaCallbacksAttributeBuilder); @@ -71,9 +115,7 @@ AttributeMapUPtr getDefaultAttributeValues(const std::wstring& ruleFile, const s isb->setGeometry(prtMesh.vertexCoords(), prtMesh.vcCount(), prtMesh.indices(), prtMesh.indicesCount(), prtMesh.faceCounts(), prtMesh.faceCountsCount()); - const int32_t seed = mu::computeSeed(prtMesh.vertexCoords(), prtMesh.vcCount()); - - isb->setAttributes(ruleFile.c_str(), startRule.c_str(), seed, L"", EMPTY_ATTRIBUTES.get(), &resolveMap); + isb->setAttributes(ruleFile.c_str(), startRule.c_str(), seed, L"", &attributeMap, &resolveMap); const InitialShapeUPtr shape(isb->createInitialShapeAndReset()); const InitialShapeNOPtrVector shapes = {shape.get()}; @@ -89,22 +131,59 @@ AttributeMapUPtr getDefaultAttributeValues(const std::wstring& ruleFile, const s return AttributeMapUPtr(mayaCallbacksAttributeBuilder->createAttributeMap()); } -} // namespace +bool getIsUserSet(const MFnDependencyNode& node, const MFnAttribute& attribute) { + MString userSetAttributeName = attribute.name() + ATTRIBUTE_USER_SET_SUFFIX; -PRTModifierAction::PRTModifierAction() { - AttributeMapBuilderUPtr optionsBuilder(prt::AttributeMapBuilder::create()); + MStatus attrStat; + MObject userSetAttributeObj = node.attribute(userSetAttributeName, &attrStat); + if (attrStat == MS::kSuccess) { + const MPlug plug(node.object(), userSetAttributeObj); + bool isUserSet = plug.asBool(&attrStat); + MCHECK(attrStat); + return isUserSet; + } + return false; +} - mMayaEncOpts = prtu::createValidatedOptions(ENC_ID_MAYA); +MStatus setIsUserSet(const MFnDependencyNode& node, const MFnAttribute& attribute, bool value) { + MString userSetAttributeName = attribute.name() + ATTRIBUTE_USER_SET_SUFFIX; - optionsBuilder->setString(L"name", FILE_CGA_ERROR); - const AttributeMapUPtr errOptions(optionsBuilder->createAttributeMapAndReset()); - mCGAErrorOptions = prtu::createValidatedOptions(ENC_ID_CGA_ERROR, errOptions.get()); + MStatus attrStat; + MObject userSetAttributeObj = node.attribute(userSetAttributeName, &attrStat); + if (attrStat == MS::kSuccess) { + MPlug plug(node.object(), userSetAttributeObj); - optionsBuilder->setString(L"name", FILE_CGA_PRINT); - const AttributeMapUPtr printOptions(optionsBuilder->createAttributeMapAndReset()); - mCGAPrintOptions = prtu::createValidatedOptions(ENC_ID_CGA_PRINT, printOptions.get()); + MCHECK(plug.setBool(value)); + } + return attrStat; +} + +bool getAndResetForceDefault(const MFnDependencyNode& node, const MFnAttribute& attribute) { + MString userSetAttributeName = attribute.name() + ATTRIBUTE_FORCE_DEFAULT_SUFFIX; + + MStatus attrStat; + MObject userSetAttributeObj = node.attribute(userSetAttributeName, &attrStat); + if (attrStat == MS::kSuccess) { + MPlug plug(node.object(), userSetAttributeObj); + bool isUserSet = plug.asBool(&attrStat); + MCHECK(attrStat); + MCHECK(plug.setBool(false)); + return isUserSet; + } + return false; } +std::wstring removeSuffix(std::wstring const& fullString) { + for (const std::wstring suffix : {ATTRIBUTE_USER_SET_SUFFIX, ATTRIBUTE_FORCE_DEFAULT_SUFFIX}) { + if ((fullString.length() >= suffix.length()) && + (fullString.compare(fullString.length() - suffix.length(), suffix.length(), suffix) == 0)) + return fullString.substr(0, fullString.length() - suffix.length()); + } + return fullString; +} + +enum class PrtAttributeType { BOOL, FLOAT, COLOR, STRING, ENUM }; + std::list getNodeAttributesCorrespondingToCGA(const MFnDependencyNode& node) { std::list rawAttrs; std::list ignoreList; @@ -117,8 +196,8 @@ std::list getNodeAttributesCorrespondingToCGA(const MFnDependencyNode& const MFnAttribute attr(attrObj); - // CGA rule attributes are maya dynamic attributes - if (!attr.isDynamic()) + // CGA rule attributes are maya dynamic attributes and not hidden + if (!attr.isDynamic() || attr.isHidden()) continue; // maya annoyance: color attributes automatically get per-component plugs/child attrs @@ -139,47 +218,23 @@ std::list getNodeAttributesCorrespondingToCGA(const MFnDependencyNode& return rawAttrs; } -const RuleAttribute RULE_NOT_FOUND{}; - -MStatus PRTModifierAction::fillAttributesFromNode(const MObject& node) { +template +MStatus iterateThroughAttributesAndApply(const MObject& node, const RuleAttributeMap& ruleAttributes, T attrFunction) { MStatus stat; const MFnDependencyNode fNode(node, &stat); MCHECK(stat); - auto resolveMap = getResolveMap(); - if (!resolveMap) - return MStatus::kInvalidParameter; - - const wchar_t* ruleFileURI = resolveMap->getString(mRuleFile.c_str()); - if (ruleFileURI == nullptr) - return MStatus::kInvalidParameter; - - const RuleFileInfoUPtr info(prt::createRuleFileInfo(ruleFileURI)); - - auto reverseLookupAttribute = [this](const std::wstring& mayaFullAttrName) { - auto it = std::find_if(mRuleAttributes.begin(), mRuleAttributes.end(), - [&mayaFullAttrName](const auto& ra) { return (ra.mayaFullName == mayaFullAttrName); }); - if (it != mRuleAttributes.end()) - return *it; - return RULE_NOT_FOUND; - }; - const std::list cgaAttributes = getNodeAttributesCorrespondingToCGA(fNode); - const AttributeMapUPtr defaultAttributeValues = - getDefaultAttributeValues(mRuleFile, mStartRule, *getResolveMap(), *PRTContext::get().theCache, *inPrtMesh); - AttributeMapBuilderUPtr aBuilder(prt::AttributeMapBuilder::create()); - for (const auto& attrObj : cgaAttributes) { MFnAttribute fnAttr(attrObj); - const MPlug plug(node, attrObj); const MString fullAttrName = fnAttr.name(); - const RuleAttribute ruleAttr = reverseLookupAttribute(fullAttrName.asWChar()); - assert(!ruleAttr.fqName.empty()); // poor mans check for RULE_NOT_FOUND + auto ruleAttrIt = ruleAttributes.find(fullAttrName.asWChar()); + assert(ruleAttrIt != ruleAttributes.end()); // Rule not found + const RuleAttribute ruleAttr = (ruleAttrIt != ruleAttributes.end()) ? ruleAttrIt->second : RuleAttribute(); - const std::wstring fqAttrName = ruleAttr.fqName; - const auto ruleAttrType = ruleAttr.mType; + [[maybe_unused]] const auto ruleAttrType = ruleAttr.mType; if (attrObj.hasFn(MFn::kNumericAttribute)) { MFnNumericAttribute nAttr(attrObj); @@ -187,27 +242,204 @@ MStatus PRTModifierAction::fillAttributesFromNode(const MObject& node) { if (nAttr.unitType() == MFnNumericData::kBoolean) { assert(ruleAttrType == prt::AAT_BOOL); - bool val; - MCHECK(plug.getValue(val)); - - const auto defVal = defaultAttributeValues->getBool(fqAttrName.c_str()); - if (val != defVal) - aBuilder->setBool(fqAttrName.c_str(), val); + attrFunction(fNode, fnAttr, ruleAttr, PrtAttributeType::BOOL); } else if (nAttr.unitType() == MFnNumericData::kDouble) { assert(ruleAttrType == prt::AAT_FLOAT); - double val; - MCHECK(plug.getValue(val)); - - const auto defVal = defaultAttributeValues->getFloat(fqAttrName.c_str()); - if (val != defVal) - aBuilder->setFloat(fqAttrName.c_str(), val); + attrFunction(fNode, fnAttr, ruleAttr, PrtAttributeType::FLOAT); } else if (nAttr.isUsedAsColor()) { assert(ruleAttrType == prt::AAT_STR); - const wchar_t* defColStr = defaultAttributeValues->getString(fqAttrName.c_str()); + attrFunction(fNode, fnAttr, ruleAttr, PrtAttributeType::COLOR); + } + } + else if (attrObj.hasFn(MFn::kTypedAttribute)) { + assert(ruleAttrType == prt::AAT_STR); + + attrFunction(fNode, fnAttr, ruleAttr, PrtAttributeType::STRING); + } + else if (attrObj.hasFn(MFn::kEnumAttribute)) { + attrFunction(fNode, fnAttr, ruleAttr, PrtAttributeType::ENUM); + } + } + return MStatus::kSuccess; +} + +MStatus addHiddenBoolParameter(MFnDependencyNode& node, MFnAttribute& tAttr, const MString& suffix) { + MStatus stat; + + MFnNumericAttribute nAttr; + MObject attr = + nAttr.create(tAttr.name() + suffix, tAttr.shortName() + suffix, MFnNumericData::kBoolean, false, &stat); + MCHECK(stat); + + if (!(node.hasAttribute(nAttr.shortName()))) { + MCHECK(nAttr.setHidden(true)); + MCHECK(nAttr.setStorable(true)); + stat = node.addAttribute(attr); + } + return stat; +} + +short getDefaultEnumIdx(const prt::Annotation* annot, const PRTEnumDefaultValue& defaultValue) { + short idx = 0; + for (size_t arg = 0; arg < annot->getNumArguments(); arg++) { + + const wchar_t* key = annot->getArgument(arg)->getKey(); + if (std::wcscmp(key, NULL_KEY) != 0) { + continue; + } + + switch (annot->getArgument(arg)->getType()) { + case prt::AAT_BOOL: { + const bool val = annot->getArgument(arg)->getBool(); + if (val == std::get(defaultValue)) + return idx; + idx++; + break; + } + case prt::AAT_FLOAT: { + const double val = annot->getArgument(arg)->getFloat(); + if (val == std::get(defaultValue)) + return idx; + idx++; + break; + } + case prt::AAT_STR: { + const MString val = annot->getArgument(arg)->getStr(); + if (val == std::get(defaultValue)) + return idx; + idx++; + break; + } + default: + break; + } + } + return 0; +} + +bool cgacLogProblems(CGACErrors errorList) { + for (const auto& [error, count] : errorList) { + if (error.shouldBeLogged) { + if (error.errorLevel == prt::CGAErrorLevel::CGAERROR) { + LOG_ERR << error.errorString.c_str(); + MGlobal::displayError(error.errorString.c_str()); + } + else { + MGlobal::displayWarning(error.errorString.c_str()); + } + } + } + return false; +} + +CGACErrors createCGACErrorFromString(const MString& stringMessage) { + CGACErrors cgacErrors; + cgacErrors.try_emplace({prt::CGAErrorLevel::CGAERROR, true, stringMessage.asWChar()}, 1); + return cgacErrors; +} + +MStringArray cgacProblemsToStringArray(CGACErrors errorList) { + MStringArray errorStringArrray; + for (const auto& [error, count] : errorList) { + errorStringArrray.append(std::to_wstring(count).c_str()); + const MString errorLevel = (error.errorLevel == prt::CGAErrorLevel::CGAERROR) ? "Error" : "Warning"; + errorStringArrray.append(errorLevel); + errorStringArrray.append(error.errorString.c_str()); + } + return errorStringArrray; +} + +void updateCgacProblemData(MPlug& cgacProblemPlug, const CGACErrors& cgacProblems) { + MStringArray newCgacErrorStringArray = cgacProblemsToStringArray(cgacProblems); + + MObject errorDataObject; + MCHECK(cgacProblemPlug.getValue(errorDataObject)); + MFnStringArrayData stringArrayData(errorDataObject); + MStringArray oldCgacErrorStringArray = stringArrayData.array(); + + if (oldCgacErrorStringArray != newCgacErrorStringArray) { + cgacLogProblems(cgacProblems); + + MFnStringArrayData newStringArrayData; + MObject newErrorDataObject = newStringArrayData.create(newCgacErrorStringArray); + cgacProblemPlug.setMObject(newErrorDataObject); + } +} + +template +T getPlugValueAndRemoveAttr(MFnDependencyNode& node, const MString& briefName, const T& defaultValue) { + T plugValue = defaultValue; + + if (DBG) { + LOG_DBG << "node attrs:"; + mu::forAllAttributes(node, [&node](const MFnAttribute& a) { + MString val; + node.findPlug(a.object(), true).getValue(val); + LOG_DBG << a.name().asWChar() << " = " << val.asWChar(); + }); + } + + if (node.hasAttribute(briefName)) { + const MPlug plug = node.findPlug(briefName, true); + if (plug.isDynamic()) { + T d; + if (plug.getValue(d) == MS::kSuccess) + plugValue = d; + } + node.removeAttribute(node.attribute(briefName)); + } + + return plugValue; +} +} // namespace + +PRTModifierAction::PRTModifierAction() { + AttributeMapBuilderUPtr optionsBuilder(prt::AttributeMapBuilder::create()); + + mMayaEncOpts = prtu::createValidatedOptions(ENC_ID_MAYA); + + optionsBuilder->setString(L"name", FILE_CGA_ERROR); + const AttributeMapUPtr errOptions(optionsBuilder->createAttributeMapAndReset()); + mCGAErrorOptions = prtu::createValidatedOptions(ENC_ID_CGA_ERROR, errOptions.get()); + + optionsBuilder->setString(L"name", FILE_CGA_PRINT); + const AttributeMapUPtr printOptions(optionsBuilder->createAttributeMapAndReset()); + mCGAPrintOptions = prtu::createValidatedOptions(ENC_ID_CGA_PRINT, printOptions.get()); +} + +MStatus PRTModifierAction::fillAttributesFromNode(const MObject& node) { + AttributeMapBuilderSPtr aBuilder(prt::AttributeMapBuilder::create(), PRTDestroyer()); + + const auto fillAttributeFromNode = [this, aBuilder](const MFnDependencyNode& fnNode, + const MFnAttribute& fnAttribute, + const RuleAttribute& ruleAttribute, + const PrtAttributeType attrType) mutable { + MPlug plug(fnNode.object(), fnAttribute.object()); + const std::wstring fqAttrName = ruleAttribute.fqName; + const prt::AnnotationArgumentType ruleAttrType = ruleAttribute.mType; + + switch (attrType) { + case PrtAttributeType::BOOL: { + bool boolVal; + MCHECK(plug.getValue(boolVal)); + + if (getIsUserSet(fnNode, fnAttribute)) + aBuilder->setBool(fqAttrName.c_str(), boolVal); + break; + } + case PrtAttributeType::FLOAT: { + double doubleVal; + MCHECK(plug.getValue(doubleVal)); + + if (getIsUserSet(fnNode, fnAttribute)) + aBuilder->setFloat(fqAttrName.c_str(), doubleVal); + break; + } + case PrtAttributeType::COLOR: { MObject rgb; MCHECK(plug.getValue(rgb)); MFnNumericData fRGB(rgb); @@ -216,46 +448,244 @@ MStatus PRTModifierAction::fillAttributesFromNode(const MObject& node) { MCHECK(fRGB.getData3Float(col[0], col[1], col[2])); const std::wstring colStr = prtu::getColorString(col); - if (std::wcscmp(colStr.c_str(), defColStr) != 0) + if (getIsUserSet(fnNode, fnAttribute)) aBuilder->setString(fqAttrName.c_str(), colStr.c_str()); + break; + } + case PrtAttributeType::STRING: { + MString stringVal; + MCHECK(plug.getValue(stringVal)); + + if (getIsUserSet(fnNode, fnAttribute)) + aBuilder->setString(fqAttrName.c_str(), stringVal.asWChar()); + break; } + case PrtAttributeType::ENUM: { + auto it = mEnums.find(ruleAttribute.mayaFullName); + if (it == mEnums.end()) + break; + const PRTModifierEnum& currEnum = it->second; + + short enumVal; + MCHECK(plug.getValue(enumVal)); + + if (getIsUserSet(fnNode, fnAttribute)) { + switch (ruleAttrType) { + case prt::AAT_STR: + aBuilder->setString(fqAttrName.c_str(), currEnum.getOptionName(enumVal).asWChar()); + break; + case prt::AAT_FLOAT: + aBuilder->setFloat(fqAttrName.c_str(), currEnum.getOptionName(enumVal).asDouble()); + break; + case prt::AAT_BOOL: + aBuilder->setBool(fqAttrName.c_str(), currEnum.getOptionName(enumVal).asInt() != 0); + break; + default: + LOG_ERR << "Cannot handle attribute type " << ruleAttrType << " for attr " << fqAttrName; + } + } + break; + } + + default: + break; } - else if (attrObj.hasFn(MFn::kTypedAttribute)) { - assert(ruleAttrType == prt::AAT_STR); + }; - MString val; - MCHECK(plug.getValue(val)); + iterateThroughAttributesAndApply(node, mRuleAttributes, fillAttributeFromNode); + mGenerateAttrs.reset(aBuilder->createAttributeMap()); - const auto defVal = defaultAttributeValues->getString(fqAttrName.c_str()); - if (std::wcscmp(val.asWChar(), defVal) != 0) - aBuilder->setString(fqAttrName.c_str(), val.asWChar()); + return MStatus::kSuccess; +} + +MStatus PRTModifierAction::updateUserSetAttributes(const MObject& node) { + const auto updateUserSetAttribute = [this](const MFnDependencyNode& fnNode, const MFnAttribute& fnAttribute, + const RuleAttribute& ruleAttribute, const PrtAttributeType attrType) { + const AttributeMapUPtr defaultAttributeValues = + getDefaultAttributeValues(mRuleFile, mStartRule, *getResolveMap(), *PRTContext::get().mPRTCache, + *inPrtMesh, mRandomSeed, *mGenerateAttrs); + + if (getAndResetForceDefault(fnNode, fnAttribute)) { + setIsUserSet(fnNode, fnAttribute, false); + return; } - else if (attrObj.hasFn(MFn::kEnumAttribute)) { - MFnEnumAttribute eAttr(attrObj); - - short di; - short i; - MCHECK(eAttr.getDefault(di)); - MCHECK(plug.getValue(i)); - if (i != di) { - switch (ruleAttrType) { - case prt::AAT_STR: - aBuilder->setString(fqAttrName.c_str(), eAttr.fieldName(i).asWChar()); - break; - case prt::AAT_FLOAT: - aBuilder->setFloat(fqAttrName.c_str(), eAttr.fieldName(i).asDouble()); - break; - case prt::AAT_BOOL: - aBuilder->setBool(fqAttrName.c_str(), eAttr.fieldName(i).asInt() != 0); - break; - default: - LOG_ERR << "Cannot handle attribute type " << ruleAttrType << " for attr " << fqAttrName; - } + + const MPlug plug(fnNode.object(), fnAttribute.object()); + bool isDefaultValue = false; + const std::wstring fqAttrName = ruleAttribute.fqName; + + switch (attrType) { + case PrtAttributeType::BOOL: { + const bool defBoolVal = defaultAttributeValues->getBool(fqAttrName.c_str()); + bool boolVal; + MCHECK(plug.getValue(boolVal)); + + isDefaultValue = (defBoolVal == boolVal); + break; + } + case PrtAttributeType::FLOAT: { + const double defDoubleVal = defaultAttributeValues->getFloat(fqAttrName.c_str()); + double doubleVal; + MCHECK(plug.getValue(doubleVal)); + + isDefaultValue = (defDoubleVal == doubleVal); + break; + } + case PrtAttributeType::COLOR: { + const prtu::Color defCol = prtu::parseColor(defaultAttributeValues->getString(fqAttrName.c_str())); + + MObject rgb; + MCHECK(plug.getValue(rgb)); + MFnNumericData fRGB(rgb); + + prtu::Color col; + MCHECK(fRGB.getData3Float(col[0], col[1], col[2])); + + isDefaultValue = (defCol == col); + break; + } + case PrtAttributeType::STRING: { + const auto defStringVal = defaultAttributeValues->getString(fqAttrName.c_str()); + if (defStringVal == nullptr) + break; + + MString stringVal; + MCHECK(plug.getValue(stringVal)); + + isDefaultValue = (std::wcscmp(stringVal.asWChar(), defStringVal) == 0); + break; } + case PrtAttributeType::ENUM: { + auto it = mEnums.find(ruleAttribute.mayaFullName); + if (it == mEnums.end()) + break; + const PRTModifierEnum& currEnum = it->second; + + const short defEnumVal = currEnum.getDefaultEnumValue(*defaultAttributeValues, ruleAttribute); + short enumVal; + MCHECK(plug.getValue(enumVal)); + + isDefaultValue = (defEnumVal == enumVal); + break; + } + + default: + break; } - } - mGenerateAttrs.reset(aBuilder->createAttributeMap()); + if (!isDefaultValue) + setIsUserSet(fnNode, fnAttribute, true); + }; + + iterateThroughAttributesAndApply(node, mRuleAttributes, updateUserSetAttribute); + + return MStatus::kSuccess; +} + +MStatus PRTModifierAction::updateUI(const MObject& node, MObject& cgacProblemObject) { + const auto updateUIFromAttributes = [this, node](const MFnDependencyNode& fnNode, const MFnAttribute& fnAttribute, + const RuleAttribute& ruleAttribute, + const PrtAttributeType attrType) { + const AttributeMapUPtr defaultAttributeValues = + getDefaultAttributeValues(mRuleFile, mStartRule, *getResolveMap(), *PRTContext::get().mPRTCache, + *inPrtMesh, mRandomSeed, *mGenerateAttrs); + MPlug plug(fnNode.object(), fnAttribute.object()); + const std::wstring fqAttrName = ruleAttribute.fqName; + + switch (attrType) { + case PrtAttributeType::BOOL: { + const bool defBoolVal = defaultAttributeValues->getBool(fqAttrName.c_str()); + bool boolVal; + MCHECK(plug.getValue(boolVal)); + + const bool isDefaultValue = (defBoolVal == boolVal); + + if (!getIsUserSet(fnNode, fnAttribute) && !isDefaultValue) + plug.setBool(defBoolVal); + break; + } + case PrtAttributeType::FLOAT: { + const double defDoubleVal = defaultAttributeValues->getFloat(fqAttrName.c_str()); + double doubleVal; + MCHECK(plug.getValue(doubleVal)); + + const bool isDefaultValue = (defDoubleVal == doubleVal); + + if (!getIsUserSet(fnNode, fnAttribute) && !isDefaultValue) + plug.setDouble(defDoubleVal); + break; + } + case PrtAttributeType::COLOR: { + const wchar_t* defColStr = defaultAttributeValues->getString(fqAttrName.c_str()); + + MObject rgb; + MCHECK(plug.getValue(rgb)); + MFnNumericData fRGB(rgb); + + prtu::Color col; + MCHECK(fRGB.getData3Float(col[0], col[1], col[2])); + const std::wstring colStr = prtu::getColorString(col); + + prtu::Color defaultColor = prtu::parseColor(defColStr); + MFnNumericData fdefaultColor; + MObject defaultColorObj = fdefaultColor.create(MFnNumericData::Type::k3Float); + fdefaultColor.setData3Float(defaultColor[0], defaultColor[1], defaultColor[2]); + + const bool isDefaultValue = (std::wcscmp(colStr.c_str(), defColStr) == 0); + + if (!getIsUserSet(fnNode, fnAttribute) && !isDefaultValue) + plug.setMObject(defaultColorObj); + break; + } + case PrtAttributeType::STRING: { + const auto defStringVal = defaultAttributeValues->getString(fqAttrName.c_str()); + if (defStringVal == nullptr) + return; + + MString stringVal; + MCHECK(plug.getValue(stringVal)); + + const bool isDefaultValue = (std::wcscmp(stringVal.asWChar(), defStringVal) == 0); + + if (!getIsUserSet(fnNode, fnAttribute) && !isDefaultValue) + plug.setString(defStringVal); + break; + } + case PrtAttributeType::ENUM: { + auto it = mEnums.find(ruleAttribute.mayaFullName); + if (it == mEnums.end()) + break; + PRTModifierEnum& currEnum = it->second; + + short enumVal; + MCHECK(plug.getValue(enumVal)); + + short newEnumVal = enumVal; + if (currEnum.isDynamic()) + newEnumVal = currEnum.updateOptions(node, mRuleAttributes, *defaultAttributeValues, enumVal); + + const short defEnumVal = currEnum.getDefaultEnumValue(*defaultAttributeValues, ruleAttribute); + + const bool isDefaultValue = (defEnumVal == enumVal); + const bool hasNewValue = (enumVal != newEnumVal); + + if ((!getIsUserSet(fnNode, fnAttribute) && !isDefaultValue)) + plug.setShort(defEnumVal); + else if (hasNewValue) + plug.setShort(newEnumVal); + + break; + } + + default: + break; + } + }; + + MPlug cgacProblemPlug(node, cgacProblemObject); + updateCgacProblemData(cgacProblemPlug, mCGACProblems); + iterateThroughAttributesAndApply(node, mRuleAttributes, updateUIFromAttributes); + return MStatus::kSuccess; } @@ -274,52 +704,75 @@ ResolveMapSPtr PRTModifierAction::getResolveMap() { return resolveMap; } -MStatus PRTModifierAction::updateRuleFiles(const MObject& node, const MString& rulePkg) { +MStatus PRTModifierAction::updateRuleFiles(const MObject& node, const MString& rulePkg, MObject& cgacProblemObject) { + MPlug cgacProblemPlug(node, cgacProblemObject); + mRulePkg = rulePkg; mEnums.clear(); mRuleFile.clear(); mStartRule.clear(); mRuleAttributes.clear(); + PRTContext::get().mPRTCache.get()->flushAll(); + + std::filesystem::path rulePkgPath(mRulePkg.asWChar()); + if (!std::filesystem::exists(rulePkgPath)) { + CGACErrors cgacProblems = + createCGACErrorFromString(MString("could not find rule package ") + mRulePkg.asWChar()); + updateCgacProblemData(cgacProblemPlug, cgacProblems); + return MS::kFailure; + } ResolveMapSPtr resolveMap = getResolveMap(); if (!resolveMap) { - LOG_ERR << "failed to get resolve map from rule package " << mRulePkg.asWChar(); + CGACErrors cgacProblems = + createCGACErrorFromString(MString("failed to get resolve map from rule package ") + mRulePkg.asWChar()); + updateCgacProblemData(cgacProblemPlug, cgacProblems); return MS::kFailure; } mRuleFile = prtu::getRuleFileEntry(resolveMap); if (mRuleFile.empty()) { - LOG_ERR << "could not find rule file in rule package " << mRulePkg.asWChar(); + CGACErrors cgacProblems = + createCGACErrorFromString(MString("could not find rule file in rule package ") + mRulePkg.asWChar()); + updateCgacProblemData(cgacProblemPlug, cgacProblems); return MS::kFailure; } prt::Status infoStatus = prt::STATUS_UNSPECIFIED_ERROR; const wchar_t* ruleFileURI = resolveMap->getString(mRuleFile.c_str()); if (ruleFileURI == nullptr) { - LOG_ERR << "could not find rule file URI in resolve map of rule package " << mRulePkg.asWChar(); + CGACErrors cgacProblems = createCGACErrorFromString( + MString("could not find rule file URI in resolve map of rule package ") + mRulePkg.asWChar()); + updateCgacProblemData(cgacProblemPlug, cgacProblems); return MS::kFailure; } - RuleFileInfoUPtr info(prt::createRuleFileInfo(ruleFileURI, PRTContext::get().theCache.get(), &infoStatus)); + RuleFileInfoUPtr info(prt::createRuleFileInfo(ruleFileURI, PRTContext::get().mPRTCache.get(), &infoStatus)); if (!info || infoStatus != prt::STATUS_OK) { - LOG_ERR << "could not get rule file info from rule file " << mRuleFile; + CGACErrors cgacProblems = + createCGACErrorFromString(MString("could not get rule file info from rule file ") + mRulePkg.asWChar()); + updateCgacProblemData(cgacProblemPlug, cgacProblems); return MS::kFailure; } mStartRule = prtu::detectStartRule(info); + mGenerateAttrs = getDefaultAttributeValues(mRuleFile, mStartRule, *getResolveMap(), *PRTContext::get().mPRTCache, + *inPrtMesh, mRandomSeed, *EMPTY_ATTRIBUTES); + if (DBG) + LOG_DBG << "default attrs: " << prtu::objectToXML(mGenerateAttrs); if (node != MObject::kNullObj) { - mGenerateAttrs = getDefaultAttributeValues(mRuleFile, mStartRule, *getResolveMap(), *PRTContext::get().theCache, - *inPrtMesh); - if (DBG) - LOG_DBG << "default attrs: " << prtu::objectToXML(mGenerateAttrs); - // derive necessary data from PRT rule info to populate node with dynamic rule attributes - mRuleAttributes = getRuleAttributes(mRuleFile, info.get()); - sortRuleAttributes(mRuleAttributes); + RuleAttributeSet ruleAttributes = getRuleAttributes(mRuleFile, info.get()); + for (const RuleAttribute& ruleAttr : ruleAttributes) { + mRuleAttributes[ruleAttr.mayaFullName] = ruleAttr; + } - createNodeAttributes(node, info.get()); + createNodeAttributes(ruleAttributes, node, info.get()); + for (auto& enumPair : mEnums) { + enumPair.second.updateOptions(node, mRuleAttributes, *mGenerateAttrs); + } } return MS::kSuccess; @@ -350,19 +803,28 @@ MStatus PRTModifierAction::doIt() { InitialShapeNOPtrVector shapes = {shape.get()}; const prt::Status generateStatus = prt::generate(shapes.data(), shapes.size(), nullptr, encIDs.data(), encIDs.size(), encOpts.data(), - outputHandler.get(), PRTContext::get().theCache.get(), nullptr); - if (generateStatus != prt::STATUS_OK) - LOG_ERR << "prt generate failed: " << prt::getStatusDescription(generateStatus); + outputHandler.get(), PRTContext::get().mPRTCache.get(), nullptr); + + mCGACProblems = outputHandler->getCGACErrors(); + + if (generateStatus != prt::STATUS_OK) { + std::string generateFailedMessage = "prt generate failed: "; + generateFailedMessage.append(prt::getStatusDescription(generateStatus)); + + LOG_ERR << generateFailedMessage; + MGlobal::displayError(generateFailedMessage.c_str()); + } return status; } -MStatus PRTModifierAction::createNodeAttributes(const MObject& nodeObj, const prt::RuleFileInfo* info) { +MStatus PRTModifierAction::createNodeAttributes(const RuleAttributeSet& ruleAttributes, const MObject& nodeObj, + const prt::RuleFileInfo* info) { MStatus stat; MFnDependencyNode node(nodeObj, &stat); MCHECK(stat); - for (const RuleAttribute& p : mRuleAttributes) { + for (const RuleAttribute& p : ruleAttributes) { const std::wstring fqName = p.fqName; // only use attributes of current style @@ -391,8 +853,17 @@ MStatus PRTModifierAction::createNodeAttributes(const MObject& nodeObj, const pr const wchar_t* anName = an->getName(); if (std::wcscmp(anName, ANNOT_ENUM) == 0) return {AttributeTrait::ENUM, {{}, an}}; - else if (std::wcscmp(anName, ANNOT_RANGE) == 0) - return {AttributeTrait::RANGE, {{}, an}}; + else if (std::wcscmp(anName, ANNOT_RANGE) == 0) { + const RangeType annotationRangeType = GetRangeType(an); + switch (annotationRangeType) { + case RangeType::ENUM: + return {AttributeTrait::ENUM, {{}, an}}; + case RangeType::RANGE: + return {AttributeTrait::RANGE, {{}, an}}; + case RangeType::INVALID: + return {AttributeTrait::PLAIN, {}}; + } + } else if (std::wcscmp(anName, ANNOT_COLOR) == 0) return {AttributeTrait::COLOR, {}}; else if (std::wcscmp(anName, ANNOT_DIR) == 0) { @@ -424,8 +895,9 @@ MStatus PRTModifierAction::createNodeAttributes(const MObject& nodeObj, const pr case prt::Attributable::PT_BOOL: { const bool value = mGenerateAttrs->getBool(fqName.c_str()); if (attrTrait.first == AttributeTrait::ENUM) { - mEnums.emplace_front(); - MCHECK(addEnumParameter(attrTrait.second.mAnnot, node, attr, p, value, mEnums.front())); + auto currEnumItr = mEnums.try_emplace(p.mayaFullName); + PRTModifierEnum& currEnum = currEnumItr.first->second; + MCHECK(addEnumParameter(attrTrait.second.mAnnot, node, attr, p, value, currEnum)); } else { MCHECK(addBoolParameter(node, attr, p, value)); @@ -437,15 +909,17 @@ MStatus PRTModifierAction::createNodeAttributes(const MObject& nodeObj, const pr switch (attrTrait.first) { case AttributeTrait::ENUM: { - mEnums.emplace_front(); - MCHECK(addEnumParameter(attrTrait.second.mAnnot, node, attr, p, value, mEnums.front())); + auto currEnumItr = mEnums.try_emplace(p.mayaFullName); + PRTModifierEnum& currEnum = currEnumItr.first->second; + MCHECK(addEnumParameter(attrTrait.second.mAnnot, node, attr, p, value, currEnum)); break; } case AttributeTrait::RANGE: { auto tryParseRangeAnnotation = [](const prt::Annotation* an) -> std::pair { auto minMax = std::make_pair(std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()); - for (int argIdx = 0; argIdx < an->getNumArguments(); argIdx++) { + const size_t numArgs = an->getNumArguments(); + for (int argIdx = 0; argIdx < numArgs; argIdx++) { const prt::AnnotationArgument* arg = an->getArgument(argIdx); const wchar_t* key = arg->getKey(); if (std::wcscmp(key, MIN_KEY) == 0) { @@ -455,6 +929,13 @@ MStatus PRTModifierAction::createNodeAttributes(const MObject& nodeObj, const pr minMax.second = arg->getFloat(); } } + + //parse old style range + if ((std::isnan(minMax.first) || std::isnan(minMax.second)) && (numArgs == 2)) { + minMax.first = an->getArgument(0)->getFloat(); + minMax.second = an->getArgument(1)->getFloat(); + } + return minMax; }; @@ -486,10 +967,12 @@ MStatus PRTModifierAction::createNodeAttributes(const MObject& nodeObj, const pr const MString mvalue(value.c_str()); switch (attrTrait.first) { - case AttributeTrait::ENUM: - mEnums.emplace_front(); - MCHECK(addEnumParameter(attrTrait.second.mAnnot, node, attr, p, mvalue, mEnums.front())); + case AttributeTrait::ENUM: { + auto currEnumItr = mEnums.try_emplace(p.mayaFullName); + PRTModifierEnum& currEnum = currEnumItr.first->second; + MCHECK(addEnumParameter(attrTrait.second.mAnnot, node, attr, p, mvalue, currEnum)); break; + } case AttributeTrait::FILE: case AttributeTrait::DIR: MCHECK(addFileParameter(node, attr, p, mvalue, attrTrait.second.mString)); @@ -524,8 +1007,8 @@ MStatus PRTModifierAction::createNodeAttributes(const MObject& nodeObj, const pr void PRTModifierAction::removeUnusedAttribs(MFnDependencyNode& node) { auto isInUse = [this](const MString& attrName) { - auto it = std::find_if(mRuleAttributes.begin(), mRuleAttributes.end(), - [&attrName](const auto& ra) { return (ra.mayaFullName == attrName.asWChar()); }); + const std::wstring attrNameWithoutSuffix = removeSuffix(attrName.asWChar()); + auto it = mRuleAttributes.find(attrNameWithoutSuffix); return (it != mRuleAttributes.end()); }; @@ -560,85 +1043,24 @@ void PRTModifierAction::removeUnusedAttribs(MFnDependencyNode& node) { } } -MStatus PRTModifierEnum::fill(const prt::Annotation* annot) { - mRestricted = true; - MStatus stat; - - for (size_t arg = 0; arg < annot->getNumArguments(); arg++) { - - const wchar_t* key = annot->getArgument(arg)->getKey(); - if (std::wcscmp(key, NULL_KEY) != 0) { - if (std::wcscmp(key, RESTRICTED_KEY) == 0) { - mRestricted = annot->getArgument(arg)->getBool(); - } - continue; - } - - switch (annot->getArgument(arg)->getType()) { - case prt::AAT_BOOL: { - bool val = annot->getArgument(arg)->getBool(); - MCHECK(mAttr.addField(MString(std::to_wstring(val).c_str()), mBVals.length())); - mBVals.append(val); - mFVals.append(std::numeric_limits::quiet_NaN()); - mSVals.append(""); - break; - } - case prt::AAT_FLOAT: { - double val = annot->getArgument(arg)->getFloat(); - MCHECK(mAttr.addField(MString(std::to_wstring(val).c_str()), mFVals.length())); - mBVals.append(false); - mFVals.append(val); - mSVals.append(""); - break; - } - case prt::AAT_STR: { - const wchar_t* val = annot->getArgument(arg)->getStr(); - MCHECK(mAttr.addField(MString(val), mSVals.length())); - mBVals.append(false); - mFVals.append(std::numeric_limits::quiet_NaN()); - mSVals.append(MString(val)); - break; - } - default: - break; - } - } - - return MS::kSuccess; -} - -template -T PRTModifierAction::getPlugValueAndRemoveAttr(MFnDependencyNode& node, const MString& briefName, - const T& defaultValue) { - T plugValue = defaultValue; - - if (DBG) { - LOG_DBG << "node attrs:"; - mu::forAllAttributes(node, [&node](const MFnAttribute& a) { - MString val; - node.findPlug(a.object(), true).getValue(val); - LOG_DBG << a.name().asWChar() << " = " << val.asWChar(); - }); - } - - if (node.hasAttribute(briefName)) { - const MPlug plug = node.findPlug(briefName, true); - if (plug.isDynamic()) { - T d; - if (plug.getValue(d) == MS::kSuccess) - plugValue = d; - } - node.removeAttribute(node.attribute(briefName)); - } - return plugValue; -} - MStatus PRTModifierAction::addParameter(MFnDependencyNode& node, MObject& attr, MFnAttribute& tAttr) { if (!(node.hasAttribute(tAttr.shortName()))) { + MStatus stat; + MCHECK(tAttr.setKeyable(true)); MCHECK(tAttr.setHidden(false)); MCHECK(tAttr.setStorable(true)); - MCHECK(node.addAttribute(attr)); + stat = node.addAttribute(attr); + if (stat != MS::kSuccess) + return stat; + + // add hidden user_set attribute + stat = addHiddenBoolParameter(node, tAttr, ATTRIBUTE_USER_SET_SUFFIX); + if (stat != MS::kSuccess) + return stat; + + // add hidden force_default attribute + return addHiddenBoolParameter(node, tAttr, ATTRIBUTE_FORCE_DEFAULT_SUFFIX); } return MS::kSuccess; } @@ -652,15 +1074,14 @@ MStatus PRTModifierAction::addBoolParameter(MFnDependencyNode& node, MObject& at attr = nAttr.create(ruleAttr.mayaFullName.c_str(), ruleAttr.mayaBriefName.c_str(), MFnNumericData::kBoolean, defaultValue, &stat); nAttr.setNiceNameOverride(ruleAttr.mayaNiceName.c_str()); - if (stat != MS::kSuccess) - throw stat; + MCHECK(stat); - MCHECK(addParameter(node, attr, nAttr)); + stat = addParameter(node, attr, nAttr); MPlug plug(node.object(), attr); MCHECK(plug.setValue(plugValue)); - return MS::kSuccess; + return stat; } MStatus PRTModifierAction::addFloatParameter(MFnDependencyNode& node, MObject& attr, const RuleAttribute& ruleAttr, @@ -672,82 +1093,42 @@ MStatus PRTModifierAction::addFloatParameter(MFnDependencyNode& node, MObject& a attr = nAttr.create(ruleAttr.mayaFullName.c_str(), ruleAttr.mayaBriefName.c_str(), MFnNumericData::kDouble, defaultValue, &stat); nAttr.setNiceNameOverride(ruleAttr.mayaNiceName.c_str()); - if (stat != MS::kSuccess) - throw stat; + MCHECK(stat); - if (!prtu::isnan(min)) { + if (!prtu::isnan(min)) MCHECK(nAttr.setMin(min)); - } - if (!prtu::isnan(max)) { + if (!prtu::isnan(max)) MCHECK(nAttr.setMax(max)); - } - MCHECK(addParameter(node, attr, nAttr)); + stat = addParameter(node, attr, nAttr); MPlug plug(node.object(), attr); MCHECK(plug.setValue(plugValue)); - return MS::kSuccess; -} - -MStatus PRTModifierAction::addEnumParameter(const prt::Annotation* annot, MFnDependencyNode& node, MObject& attr, - const RuleAttribute& ruleAttr, bool defaultValue, PRTModifierEnum& e) { - short idx = 0; - for (int i = static_cast(e.mBVals.length()); --i >= 0;) { - if ((e.mBVals[i] != 0) == defaultValue) { - idx = static_cast(i); - break; - } - } - - return addEnumParameter(annot, node, attr, ruleAttr, idx, e); -} - -MStatus PRTModifierAction::addEnumParameter(const prt::Annotation* annot, MFnDependencyNode& node, MObject& attr, - const RuleAttribute& ruleAttr, double defaultValue, PRTModifierEnum& e) { - short idx = 0; - for (int i = static_cast(e.mFVals.length()); --i >= 0;) { - if (e.mFVals[i] == defaultValue) { - idx = static_cast(i); - break; - } - } - - return addEnumParameter(annot, node, attr, ruleAttr, idx, e); + return stat; } MStatus PRTModifierAction::addEnumParameter(const prt::Annotation* annot, MFnDependencyNode& node, MObject& attr, - const RuleAttribute& ruleAttr, const MString& defaultValue, + const RuleAttribute& ruleAttr, const PRTEnumDefaultValue& defaultValue, PRTModifierEnum& e) { - short idx = 0; - for (int i = static_cast(e.mSVals.length()); --i >= 0;) { - if (e.mSVals[i] == defaultValue) { - idx = static_cast(i); - break; - } - } - - return addEnumParameter(annot, node, attr, ruleAttr, idx, e); -} - -MStatus PRTModifierAction::addEnumParameter(const prt::Annotation* annot, MFnDependencyNode& node, MObject& attr, - const RuleAttribute& ruleAttr, short defaultValue, PRTModifierEnum& e) { MStatus stat; - short plugValue = getPlugValueAndRemoveAttr(node, ruleAttr.mayaBriefName.c_str(), defaultValue); - attr = e.mAttr.create(ruleAttr.mayaFullName.c_str(), ruleAttr.mayaBriefName.c_str(), defaultValue, &stat); + const short defaultEnumIndex = getDefaultEnumIdx(annot, defaultValue); + + short plugValue = getPlugValueAndRemoveAttr(node, ruleAttr.mayaBriefName.c_str(), defaultEnumIndex); + attr = e.mAttr.create(ruleAttr.mayaFullName.c_str(), ruleAttr.mayaBriefName.c_str(), defaultEnumIndex, &stat); e.mAttr.setNiceNameOverride(ruleAttr.mayaNiceName.c_str()); MCHECK(stat); MCHECK(e.fill(annot)); - MCHECK(addParameter(node, attr, e.mAttr)); + stat = addParameter(node, attr, e.mAttr); MPlug plug(node.object(), attr); MCHECK(plug.setValue(plugValue)); - return MS::kSuccess; + return stat; } MStatus PRTModifierAction::addFileParameter(MFnDependencyNode& node, MObject& attr, const RuleAttribute& ruleAttr, @@ -765,12 +1146,12 @@ MStatus PRTModifierAction::addFileParameter(MFnDependencyNode& node, MObject& at MCHECK(sAttr.setNiceNameOverride(ruleAttr.mayaNiceName.c_str())); MCHECK(stat); MCHECK(sAttr.setUsedAsFilename(true)); - MCHECK(addParameter(node, attr, sAttr)); + stat = addParameter(node, attr, sAttr); MPlug plug(node.object(), attr); MCHECK(plug.setValue(plugValue)); - return MS::kSuccess; + return stat; } MStatus PRTModifierAction::addColorParameter(MFnDependencyNode& node, MObject& attr, const RuleAttribute& ruleAttr, @@ -792,12 +1173,12 @@ MStatus PRTModifierAction::addColorParameter(MFnDependencyNode& node, MObject& a nAttr.setDefault(color[0], color[1], color[2]); MCHECK(stat); - MCHECK(addParameter(node, attr, nAttr)); + stat = addParameter(node, attr, nAttr); MPlug plug(node.object(), attr); MCHECK(plug.setValue(plugValue)); - return MS::kSuccess; + return stat; } MStatus PRTModifierAction::addStrParameter(MFnDependencyNode& node, MObject& attr, const RuleAttribute& ruleAttr, @@ -814,7 +1195,7 @@ MStatus PRTModifierAction::addStrParameter(MFnDependencyNode& node, MObject& att sAttr.setNiceNameOverride(ruleAttr.mayaNiceName.c_str()); MCHECK(stat); - MCHECK(addParameter(node, attr, sAttr)); + stat = addParameter(node, attr, sAttr); MPlug plug(node.object(), attr); MCHECK(plug.setValue(plugValue)); @@ -822,5 +1203,5 @@ MStatus PRTModifierAction::addStrParameter(MFnDependencyNode& node, MObject& att if (DBG) LOG_DBG << sAttr.name().asWChar() << " = " << plugValue.asWChar(); - return MS::kSuccess; + return stat; } diff --git a/src/serlio/modifiers/PRTModifierAction.h b/src/serlio/modifiers/PRTModifierAction.h index 2d5559c1..2f395703 100644 --- a/src/serlio/modifiers/PRTModifierAction.h +++ b/src/serlio/modifiers/PRTModifierAction.h @@ -3,7 +3,7 @@ * * See https://github.com/esri/serlio for build and usage instructions. * - * Copyright (c) 2012-2019 Esri R&D Center Zurich + * Copyright (c) 2012-2022 Esri R&D Center Zurich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,7 +19,9 @@ #pragma once +#include "modifiers/MayaCallbacks.h" #include "modifiers/PRTMesh.h" +#include "modifiers/PRTModifierEnum.h" #include "modifiers/RuleAttributes.h" #include "modifiers/polyModifier/polyModifierFty.h" @@ -30,7 +32,6 @@ #include "prt/API.h" #include "maya/MDoubleArray.h" -#include "maya/MFnEnumAttribute.h" #include "maya/MIntArray.h" #include "maya/MObject.h" #include "maya/MPlugArray.h" @@ -39,26 +40,11 @@ #include #include +#include class PRTModifierAction; -class PRTModifierEnum { - friend class PRTModifierAction; - -public: - PRTModifierEnum() = default; - - MStatus fill(const prt::Annotation* annot); - -public: - MFnEnumAttribute mAttr; - -private: - MStringArray mSVals; - MDoubleArray mFVals; - MIntArray mBVals; - bool mRestricted = true; -}; // class PRTModifierEnum +using PRTEnumDefaultValue = std::variant; class PRTModifierAction : public polyModifierFty { friend class PRTModifierEnum; @@ -66,8 +52,10 @@ class PRTModifierAction : public polyModifierFty { public: explicit PRTModifierAction(); - MStatus updateRuleFiles(const MObject& node, const MString& rulePkg); + MStatus updateRuleFiles(const MObject& node, const MString& rulePkg, MObject& cgacProblemObject); MStatus fillAttributesFromNode(const MObject& node); + MStatus updateUserSetAttributes(const MObject& node); + MStatus updateUI(const MObject& node, MObject& cgacProblemObject); void setMesh(MObject& _inMesh, MObject& _outMesh); void setRandomSeed(int32_t randomSeed) { mRandomSeed = randomSeed; @@ -91,20 +79,22 @@ class PRTModifierAction : public polyModifierFty { // Set in updateRuleFiles(rulePkg) MString mRulePkg; + CGACErrors mCGACProblems; std::wstring mRuleFile; std::wstring mStartRule; const std::wstring mRuleStyle = L"Default"; // Serlio atm only supports the "Default" style int32_t mRandomSeed = 0; - RuleAttributes mRuleAttributes; // TODO: could be cached together with ResolveMap + RuleAttributeMap mRuleAttributes; // TODO: could be cached together with ResolveMap ResolveMapSPtr getResolveMap(); // init in fillAttributesFromNode() AttributeMapUPtr mGenerateAttrs; - std::list mEnums; - // std::map mBriefName2prtAttr; - MStatus createNodeAttributes(const MObject& node, const prt::RuleFileInfo* info); + std::map mEnums; + + MStatus createNodeAttributes(const RuleAttributeSet& ruleAttributes, const MObject& node, + const prt::RuleFileInfo* info); void removeUnusedAttribs(MFnDependencyNode& node); static MStatus addParameter(MFnDependencyNode& node, MObject& attr, MFnAttribute& tAttr); @@ -117,15 +107,8 @@ class PRTModifierAction : public polyModifierFty { static MStatus addFileParameter(MFnDependencyNode& node, MObject& attr, const RuleAttribute& name, const MString& defaultValue, const std::wstring& ext); static MStatus addEnumParameter(const prt::Annotation* annot, MFnDependencyNode& node, MObject& attr, - const RuleAttribute& name, bool defaultValue, PRTModifierEnum& e); - static MStatus addEnumParameter(const prt::Annotation* annot, MFnDependencyNode& node, MObject& attr, - const RuleAttribute& name, double defaultValue, PRTModifierEnum& e); - static MStatus addEnumParameter(const prt::Annotation* annot, MFnDependencyNode& node, MObject& attr, - const RuleAttribute& name, const MString& defaultValue, PRTModifierEnum& e); - static MStatus addEnumParameter(const prt::Annotation* annot, MFnDependencyNode& node, MObject& attr, - const RuleAttribute& name, short defaultValue, PRTModifierEnum& e); + const RuleAttribute& name, const PRTEnumDefaultValue& defaultValue, + PRTModifierEnum& e); static MStatus addColorParameter(MFnDependencyNode& node, MObject& attr, const RuleAttribute& name, const MString& defaultValue); - template - static T getPlugValueAndRemoveAttr(MFnDependencyNode& node, const MString& briefName, const T& defaultValue); }; diff --git a/src/serlio/modifiers/PRTModifierCommand.cpp b/src/serlio/modifiers/PRTModifierCommand.cpp index f786369e..a474ef7f 100644 --- a/src/serlio/modifiers/PRTModifierCommand.cpp +++ b/src/serlio/modifiers/PRTModifierCommand.cpp @@ -3,7 +3,7 @@ * * See https://github.com/esri/serlio for build and usage instructions. * - * Copyright (c) 2012-2019 Esri R&D Center Zurich + * Copyright (c) 2012-2022 Esri R&D Center Zurich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -40,7 +40,6 @@ MStatus PRTModifierCommand::doIt(const MArgList& argList) { mRulePkg = argList.asString(0); } else { - cerr << "Expecting one parameter: the rpk name path" << endl; displayError(" Expecting one parameter: the operation type."); return MS::kFailure; } @@ -74,8 +73,7 @@ MStatus PRTModifierCommand::doIt(const MArgList& argList) { } } if (foundMultiple) { - displayWarning("Found more than one object with selected components."); - displayWarning("Only operating on first found object."); + displayWarning("Found more than one object with selected components. Only operating on first found object."); } // Initialize the polyModifierCmd node type - mesh node already set @@ -148,17 +146,3 @@ MStatus PRTModifierCommand::initModifierNode(MObject modifierNode) { return status; } - -MStatus PRTModifierCommand::directModifier(MObject mesh) { - MStatus status; - PRTModifierAction fPRTModifierAction; - - fPRTModifierAction.setMesh(mesh, mesh); - fPRTModifierAction.setRandomSeed(mInitialSeed); - fPRTModifierAction.updateRuleFiles(MObject::kNullObj, mRulePkg); - - // Now, perform the PRT action - status = fPRTModifierAction.doIt(); - - return status; -} diff --git a/src/serlio/modifiers/PRTModifierCommand.h b/src/serlio/modifiers/PRTModifierCommand.h index a28db547..01a7cae4 100644 --- a/src/serlio/modifiers/PRTModifierCommand.h +++ b/src/serlio/modifiers/PRTModifierCommand.h @@ -3,7 +3,7 @@ * * See https://github.com/esri/serlio for build and usage instructions. * - * Copyright (c) 2012-2019 Esri R&D Center Zurich + * Copyright (c) 2012-2022 Esri R&D Center Zurich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,7 +33,6 @@ class PRTModifierCommand : public polyModifierCmd { MStatus undoIt() override; MStatus initModifierNode(MObject modifierNode) override; - MStatus directModifier(MObject mesh) override; private: MString mRulePkg; diff --git a/src/serlio/modifiers/PRTModifierEnum.cpp b/src/serlio/modifiers/PRTModifierEnum.cpp new file mode 100644 index 00000000..f58e94f7 --- /dev/null +++ b/src/serlio/modifiers/PRTModifierEnum.cpp @@ -0,0 +1,305 @@ +/** + * Serlio - Esri CityEngine Plugin for Autodesk Maya + * + * See https://github.com/esri/serlio for build and usage instructions. + * + * Copyright (c) 2012-2022 Esri R&D Center Zurich + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "modifiers/PRTModifierEnum.h" + +#include "utils/MayaUtilities.h" + +#include "maya/MFnDependencyNode.h" + +#include + +namespace { + +constexpr const wchar_t* NULL_KEY = L"#NULL#"; +constexpr const wchar_t* RESTRICTED_KEY = L"restricted"; +constexpr const wchar_t* VALUES_ATTR_KEY = L"valuesAttr"; + +} // namespace + +// This function updates all enum options and returns a pair, where the first argument indicates if the options have +// changed and the second argument corresponds to the new index of the currently selected item +short PRTModifierEnum::updateOptions(const MObject& node, const RuleAttributeMap& mRuleAttributes, + const prt::AttributeMap& defaultAttributeValues, short selectedEnumIdx) { + const MString fullAttrName = mAttr.name(); + const auto ruleAttrIt = mRuleAttributes.find(fullAttrName.asWChar()); + assert(ruleAttrIt != mRuleAttributes.end()); // Rule not found + const RuleAttribute ruleAttr = (ruleAttrIt != mRuleAttributes.end()) ? ruleAttrIt->second : RuleAttribute(); + + const std::vector& newEnumOptions = getEnumOptions(ruleAttr, defaultAttributeValues); + + const bool hasNewCustomDefaultValue = updateCustomEnumValue(ruleAttr, defaultAttributeValues); + + if ((newEnumOptions == mEnumOptions) && !hasNewCustomDefaultValue) + return selectedEnumIdx; + + const std::wstring oldSelectedOption = getOptionName(selectedEnumIdx).asWChar(); + + mEnumOptions = newEnumOptions; + + int customDefaultIdx = 0; + int newSelectedEnumIdx = 0; + int currIdx = 1; + + for (const std::wstring& option : mEnumOptions) { + if (option == mCustomDefaultValue) + customDefaultIdx = currIdx; + if (option == oldSelectedOption) + newSelectedEnumIdx = currIdx; + currIdx++; + } + + if (customDefaultIdx == 0) { + MCHECK(mu::setEnumOptions(node, mAttr, mEnumOptions, mCustomDefaultValue)); + } + else { + MCHECK(mu::setEnumOptions(node, mAttr, mEnumOptions, {})); + } + + return newSelectedEnumIdx; +} + +bool PRTModifierEnum::isDynamic() const { + return mValuesAttr.length() > 0; +} + +size_t PRTModifierEnum::getOptionIndex(const std::wstring& optionName) const { + const auto iter = std::find(mEnumOptions.begin(), mEnumOptions.end(), optionName); + // return first index, if element is not available + if (iter == mEnumOptions.end()) + return 0; + return std::distance(mEnumOptions.begin(), iter) + 1; +} + +MString PRTModifierEnum::getOptionName(size_t optionIndex) const { + if (optionIndex == 0) { + return MString(mCustomDefaultValue.c_str()); + } + else { + if (optionIndex > mEnumOptions.size()) + return {}; + return MString(mEnumOptions[optionIndex - 1].c_str()); + } +} + +short PRTModifierEnum::getDefaultEnumValue(const prt::AttributeMap& defaultAttributeValues, + const RuleAttribute& ruleAttr) const { + const std::wstring fqAttrName = ruleAttr.fqName; + const prt::AnnotationArgumentType ruleAttrType = ruleAttr.mType; + + switch (ruleAttrType) { + case prt::AAT_STR: { + const wchar_t* defStringVal = defaultAttributeValues.getString(fqAttrName.c_str()); + + if (defStringVal != nullptr) + return static_cast(getOptionIndex(defStringVal)); + break; + } + case prt::AAT_FLOAT: { + const double defDoubleVal = defaultAttributeValues.getFloat(fqAttrName.c_str()); + return static_cast(getOptionIndex(std::to_wstring(defDoubleVal))); + break; + } + case prt::AAT_BOOL: { + const bool defBoolVal = defaultAttributeValues.getBool(fqAttrName.c_str()); + return static_cast(getOptionIndex(std::to_wstring(defBoolVal))); + break; + } + default: + LOG_ERR << "Cannot handle attribute type " << ruleAttrType << " for attr " << fqAttrName; + } + return 0; +} + +std::vector PRTModifierEnum::getEnumOptions(const RuleAttribute& ruleAttr, + const prt::AttributeMap& defaultAttributeValues) { + if (isDynamic()) { + return getDynamicEnumOptions(ruleAttr, defaultAttributeValues); + } + else { + std::vector enumOptions; + + short minVal; + short maxVal; + MCHECK(mAttr.getMin(minVal)); + MCHECK(mAttr.getMax(maxVal)); + + for (short currIdx = 1; currIdx <= maxVal; currIdx++) + enumOptions.emplace_back(mAttr.fieldName(currIdx).asWChar()); + + return enumOptions; + } +} + +bool PRTModifierEnum::updateCustomEnumValue(const RuleAttribute& ruleAttr, + const prt::AttributeMap& defaultAttributeValues) { + const std::wstring fqAttrName = ruleAttr.fqName; + const prt::AnnotationArgumentType ruleAttrType = ruleAttr.mType; + + std::wstring defWStringVal; + + switch (ruleAttrType) { + case prt::AAT_STR: { + const wchar_t* defStringVal = defaultAttributeValues.getString(fqAttrName.c_str()); + if (defStringVal == nullptr) + return false; + defWStringVal = defStringVal; + break; + } + case prt::AAT_FLOAT: { + const double defDoubleVal = defaultAttributeValues.getFloat(fqAttrName.c_str()); + defWStringVal = std::to_wstring(defDoubleVal).c_str(); + break; + } + case prt::AAT_BOOL: { + const bool defBoolVal = defaultAttributeValues.getBool(fqAttrName.c_str()); + defWStringVal = std::to_wstring(defBoolVal).c_str(); + break; + } + default: { + LOG_ERR << "Cannot handle attribute type " << ruleAttrType << " for attr " << fqAttrName; + return false; + } + } + if (mCustomDefaultValue == defWStringVal) + return false; + mCustomDefaultValue = defWStringVal; + return true; +} + +std::vector PRTModifierEnum::getDynamicEnumOptions(const RuleAttribute& ruleAttr, + const prt::AttributeMap& defaultAttributeValues) { + std::vector enumOptions; + if (!isDynamic()) + return enumOptions; + const MString fullAttrName = mAttr.name(); + + const std::wstring attrStyle = prtu::getStyle(ruleAttr.fqName); + std::wstring attrImport = prtu::getImport(ruleAttr.fqName); + if (!attrImport.empty()) + attrImport += prtu::IMPORT_DELIMITER; + + std::wstring valuesAttr = attrStyle + prtu::STYLE_DELIMITER + attrImport; + valuesAttr.append(mValuesAttr); + + const prt::Attributable::PrimitiveType type = defaultAttributeValues.getType(valuesAttr.c_str()); + + switch (type) { + case prt::Attributable::PT_STRING_ARRAY: { + size_t arr_length = 0; + const wchar_t* const* stringArray = defaultAttributeValues.getStringArray(valuesAttr.c_str(), &arr_length); + + for (short enumIndex = 0; enumIndex < arr_length; enumIndex++) { + if (stringArray[enumIndex] == nullptr) + continue; + std::wstring_view currStringView = stringArray[enumIndex]; + + // remove newlines from strings, because they break the maya UI + const size_t cutoffIndex = currStringView.find_first_of(L"\r\n"); + currStringView = currStringView.substr(0, cutoffIndex); + enumOptions.emplace_back(currStringView); + } + break; + } + case prt::Attributable::PT_FLOAT_ARRAY: { + size_t arr_length = 0; + const double* doubleArray = defaultAttributeValues.getFloatArray(valuesAttr.c_str(), &arr_length); + + for (short enumIndex = 0; enumIndex < arr_length; enumIndex++) { + const double currDouble = doubleArray[enumIndex]; + enumOptions.emplace_back(std::to_wstring(currDouble)); + } + break; + } + case prt::Attributable::PT_BOOL_ARRAY: { + size_t arr_length = 0; + const bool* boolArray = defaultAttributeValues.getBoolArray(valuesAttr.c_str(), &arr_length); + + for (short enumIndex = 0; enumIndex < arr_length; enumIndex++) { + const bool currBool = boolArray[enumIndex]; + enumOptions.emplace_back(std::to_wstring(currBool)); + } + break; + } + case prt::Attributable::PT_STRING: { + const wchar_t* currString = defaultAttributeValues.getString(valuesAttr.c_str()); + if (currString == nullptr) + break; + enumOptions.emplace_back(currString); + break; + } + case prt::Attributable::PT_FLOAT: { + const double currFloat = defaultAttributeValues.getFloat(valuesAttr.c_str()); + enumOptions.emplace_back(std::to_wstring(currFloat)); + break; + } + case prt::Attributable::PT_BOOL: { + const bool currBool = defaultAttributeValues.getBool(valuesAttr.c_str()); + enumOptions.emplace_back(std::to_wstring(currBool)); + break; + } + default: + break; + } + return enumOptions; +} + +MStatus PRTModifierEnum::fill(const prt::Annotation* annot) { + mRestricted = true; + MStatus stat; + + uint32_t enumIndex = 1; + for (size_t arg = 0; arg < annot->getNumArguments(); arg++) { + + const wchar_t* key = annot->getArgument(arg)->getKey(); + if (std::wcscmp(key, NULL_KEY) != 0) { + if (std::wcscmp(key, RESTRICTED_KEY) == 0) + mRestricted = annot->getArgument(arg)->getBool(); + + if (std::wcscmp(key, VALUES_ATTR_KEY) == 0) { + mValuesAttr = annot->getArgument(arg)->getStr(); + // Add empty option, because it is not considered an enum by addAttr in mel otherwise (bug) + MCHECK(mAttr.addField(" ", 1)); + } + continue; + } + + switch (annot->getArgument(arg)->getType()) { + case prt::AAT_BOOL: { + const bool val = annot->getArgument(arg)->getBool(); + MCHECK(mAttr.addField(MString(std::to_wstring(val).c_str()), enumIndex++)); + break; + } + case prt::AAT_FLOAT: { + const double val = annot->getArgument(arg)->getFloat(); + MCHECK(mAttr.addField(MString(std::to_wstring(val).c_str()), enumIndex++)); + break; + } + case prt::AAT_STR: { + const wchar_t* val = annot->getArgument(arg)->getStr(); + MCHECK(mAttr.addField(MString(val), enumIndex++)); + break; + } + default: + break; + } + } + + return MS::kSuccess; +} \ No newline at end of file diff --git a/src/serlio/modifiers/PRTModifierEnum.h b/src/serlio/modifiers/PRTModifierEnum.h new file mode 100644 index 00000000..5ecc07df --- /dev/null +++ b/src/serlio/modifiers/PRTModifierEnum.h @@ -0,0 +1,59 @@ +/** + * Serlio - Esri CityEngine Plugin for Autodesk Maya + * + * See https://github.com/esri/serlio for build and usage instructions. + * + * Copyright (c) 2012-2022 Esri R&D Center Zurich + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "modifiers/RuleAttributes.h" + +#include "utils/Utilities.h" + +#include "maya/MFnEnumAttribute.h" +#include "maya/MObject.h" +#include "maya/MString.h" + +class PRTModifierEnum { + friend class PRTModifierAction; + +public: + PRTModifierEnum() = default; + + MStatus fill(const prt::Annotation* annot); + short updateOptions(const MObject& node, const RuleAttributeMap& ruleAttributes, + const prt::AttributeMap& defaultAttributeValues, short selectedEnumIdx = 0); + + bool isDynamic() const; + size_t getOptionIndex(const std::wstring& optionName) const; + MString getOptionName(size_t optionIndex) const; + short getDefaultEnumValue(const prt::AttributeMap& defaultAttributeValues, const RuleAttribute& ruleAttr) const; + +public: + MFnEnumAttribute mAttr; + +private: + bool mRestricted = true; + std::wstring mValuesAttr; + std::wstring mCustomDefaultValue; + std::vector mEnumOptions; + + std::vector getEnumOptions(const RuleAttribute& ruleAttr, + const prt::AttributeMap& defaultAttributeValues); + std::vector getDynamicEnumOptions(const RuleAttribute& ruleAttr, + const prt::AttributeMap& defaultAttributeValues); + bool updateCustomEnumValue(const RuleAttribute& ruleAttr, const prt::AttributeMap& defaultAttributeValues); +}; // class PRTModifierEnum diff --git a/src/serlio/modifiers/PRTModifierNode.cpp b/src/serlio/modifiers/PRTModifierNode.cpp index 1128ae42..cd8897cf 100644 --- a/src/serlio/modifiers/PRTModifierNode.cpp +++ b/src/serlio/modifiers/PRTModifierNode.cpp @@ -3,7 +3,7 @@ * * See https://github.com/esri/serlio for build and usage instructions. * - * Copyright (c) 2012-2019 Esri R&D Center Zurich + * Copyright (c) 2012-2022 Esri R&D Center Zurich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,6 +26,7 @@ #include "maya/MDataHandle.h" #include "maya/MFnMeshData.h" #include "maya/MFnNumericAttribute.h" +#include "maya/MFnStringArrayData.h" #include "maya/MFnStringData.h" #include "maya/MFnTypedAttribute.h" @@ -38,11 +39,13 @@ namespace { const MString NAME_RULE_PKG = "Rule_Package"; const MString NAME_RANDOM_SEED = "Random_Seed"; +const MString CGAC_PROBLEMS = "CGAC_Problems"; } // namespace // Unique Node TypeId MTypeId PRTModifierNode::id(SerlioNodeIDs::SERLIO_PREFIX, SerlioNodeIDs::PRT_GEOMETRY_NODE); MObject PRTModifierNode::rulePkg; +MObject PRTModifierNode::cgacProblems; MObject PRTModifierNode::currentRulePkg; MObject PRTModifierNode::mRandomSeed; @@ -94,6 +97,9 @@ MStatus PRTModifierNode::compute(const MPlug& plug, MDataBlock& data) { MDataHandle currentRulePkgData = data.inputValue(currentRulePkg, &status); MCheckStatus(status, "ERROR getting currentRulePkg"); + const bool ruleFileWasChanged = (rulePkgData.asString() != currentRulePkgData.asString()); + currentRulePkgData.setString(rulePkgData.asString()); + // Copy the inMesh to the outMesh, so you can // perform operations directly on outMesh // @@ -104,21 +110,28 @@ MStatus PRTModifierNode::compute(const MPlug& plug, MDataBlock& data) { // Set the mesh object and component List on the factory fPRTModifierAction.setMesh(iMesh, oMesh); - if (rulePkgData.asString() != currentRulePkgData.asString()) { - fPRTModifierAction.updateRuleFiles(thisMObject(), rulePkgData.asString()); + if (!ruleFileWasChanged) + fPRTModifierAction.updateUserSetAttributes(thisMObject()); + + MDataHandle randomSeed = data.inputValue(mRandomSeed, &status); + fPRTModifierAction.setRandomSeed(randomSeed.asInt()); + + if (ruleFileWasChanged) { + status = fPRTModifierAction.updateRuleFiles(thisMObject(), rulePkgData.asString(), cgacProblems); + + if (status != MStatus::kSuccess) { + return status; + } } status = fPRTModifierAction.fillAttributesFromNode(thisMObject()); if (status != MStatus::kSuccess) return status; - MDataHandle randomSeed = data.inputValue(mRandomSeed, &status); - fPRTModifierAction.setRandomSeed(randomSeed.asInt()); - // Now, perform the PRT status = fPRTModifierAction.doIt(); - currentRulePkgData.setString(rulePkgData.asString()); + fPRTModifierAction.updateUI(thisMObject(), cgacProblems); // Mark the output mesh as clean outputData.setClean(); @@ -170,6 +183,7 @@ MStatus PRTModifierNode::initialize() MStatus stat2; MStatus stat; MFnStringData stringData; + MFnStringArrayData stringArrayData; MFnTypedAttribute fAttr; rulePkg = fAttr.create(NAME_RULE_PKG, "rulePkg", MFnData::kString, stringData.create(&stat2), &stat); @@ -202,6 +216,14 @@ MStatus PRTModifierNode::initialize() MCHECK(fAttr.setConnectable(false)); MCHECK(addAttribute(currentRulePkg)); + cgacProblems = + fAttr.create(CGAC_PROBLEMS, "cgacProblems", MFnData::kStringArray, stringArrayData.create(&stat2), &stat); + MCHECK(stat2); + MCHECK(stat); + MCHECK(fAttr.setHidden(true)); + MCHECK(fAttr.setConnectable(false)); + MCHECK(addAttribute(cgacProblems)); + // Set up a dependency between the input and the output. This will cause // the output to be marked dirty when the input changes. The output will // then be recomputed the next time the value of the output is requested. diff --git a/src/serlio/modifiers/PRTModifierNode.h b/src/serlio/modifiers/PRTModifierNode.h index 5b7eb70a..df57629d 100644 --- a/src/serlio/modifiers/PRTModifierNode.h +++ b/src/serlio/modifiers/PRTModifierNode.h @@ -3,7 +3,7 @@ * * See https://github.com/esri/serlio for build and usage instructions. * - * Copyright (c) 2012-2019 Esri R&D Center Zurich + * Copyright (c) 2012-2022 Esri R&D Center Zurich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -38,6 +38,7 @@ class PRTModifierNode : public polyModifierNode { public: // non-dynamic node attributes static MObject rulePkg; + static MObject cgacProblems; static MObject currentRulePkg; static MTypeId id; static MObject mRandomSeed; diff --git a/src/serlio/modifiers/RuleAttributes.cpp b/src/serlio/modifiers/RuleAttributes.cpp index 6933d488..557b73df 100644 --- a/src/serlio/modifiers/RuleAttributes.cpp +++ b/src/serlio/modifiers/RuleAttributes.cpp @@ -3,7 +3,7 @@ * * See https://github.com/esri/serlio for build and usage instructions. * - * Copyright (c) 2012-2019 Esri R&D Center Zurich + * Copyright (c) 2012-2022 Esri R&D Center Zurich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -34,36 +35,76 @@ namespace { constexpr bool DBG = false; -constexpr const wchar_t* PRT_ATTR_FULL_NAME_PREFIX = L"PRT"; +constexpr const wchar_t* PRT_ATTR_FULL_NAME_PREFIX = L"PRT_"; -const std::wstring MAYA_COMPATIBLE_CHARS = L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; -std::wstring cleanForMaya(const std::wstring& name) { - auto r = name; - replace_all_not_of(r, MAYA_COMPATIBLE_CHARS); - return r; +std::wstring getFullName(const std::wstring& fqAttrName, std::map& mayaNameDuplicateCountMap) { + const std::wstring fullName = PRT_ATTR_FULL_NAME_PREFIX + prtu::cleanNameForMaya(fqAttrName); + // make sure maya names are unique + return fullName + prtu::getDuplicateCountSuffix(fullName, mayaNameDuplicateCountMap); } -std::wstring getFullName(const std::wstring& fqAttrName) { - return PRT_ATTR_FULL_NAME_PREFIX + cleanForMaya(fqAttrName); -} - -std::wstring getBriefName(const std::wstring& fqAttrName) { - return cleanForMaya(prtu::removeStyle(fqAttrName)); +std::wstring getBriefName(const std::wstring& fqAttrName, std::map& mayaNameDuplicateCountMap) { + const std::wstring briefName = prtu::cleanNameForMaya(prtu::removeStyle(fqAttrName)); + // make sure maya names are unique + return briefName + prtu::getDuplicateCountSuffix(briefName, mayaNameDuplicateCountMap); } std::wstring getNiceName(const std::wstring& fqAttrName) { - return cleanForMaya(prtu::removeImport(prtu::removeStyle(fqAttrName))); + return prtu::cleanNameForMaya(prtu::removeImport(prtu::removeStyle(fqAttrName))); } } // namespace -RuleAttributes getRuleAttributes(const std::wstring& ruleFile, const prt::RuleFileInfo* ruleFileInfo) { - RuleAttributes ra; +std::map getImportOrderMap(const prt::RuleFileInfo* ruleFileInfo) { + std::map importOrderMap; + int importOrder = 0; + for (size_t i = 0; i < ruleFileInfo->getNumAnnotations(); i++) { + const prt::Annotation* an = ruleFileInfo->getAnnotation(i); + const wchar_t* anName = an->getName(); + if (std::wcscmp(anName, ANNOT_IMPORTS) == 0) { + for (int argIdx = 0; argIdx < an->getNumArguments(); argIdx++) { + const prt::AnnotationArgument* anArg = an->getArgument(argIdx); + if (anArg->getType() == prt::AAT_STR) { + const wchar_t* anKey = anArg->getKey(); + if (std::wcscmp(anKey, ANNOT_IMPORTS_KEY) == 0) { + const wchar_t* importRuleCharPtr = anArg->getStr(); + if (importRuleCharPtr != nullptr) { + std::wstring importRule = importRuleCharPtr; + importOrderMap[importRule] = importOrder++; + } + } + } + } + } + } + return importOrderMap; +} - std::wstring mainCgaRuleName = prtu::filename(ruleFile); - size_t idxExtension = mainCgaRuleName.find(L".cgb"); - if (idxExtension != std::wstring::npos) - mainCgaRuleName = mainCgaRuleName.substr(0, idxExtension); +void setGlobalGroupOrder(RuleAttributeVec& ruleAttributes) { + AttributeGroupOrder globalGroupOrder; + for (const auto& attribute : ruleAttributes) { + for (auto it = std::rbegin(attribute.groups); it != std::rend(attribute.groups); ++it) { + std::vector g(it, std::rend(attribute.groups)); + std::reverse(g.begin(), g.end()); + auto ggoIt = globalGroupOrder.emplace(std::make_pair(attribute.ruleFile, g), ORDER_NONE).first; + ggoIt->second = std::min(attribute.groupOrder, ggoIt->second); + } + } + + for (auto& attribute : ruleAttributes) { + const auto it = globalGroupOrder.find(std::make_pair(attribute.ruleFile, attribute.groups)); + attribute.globalGroupOrder = (it != globalGroupOrder.end()) ? it->second : ORDER_NONE; + } +} + +RuleAttributeSet getRuleAttributes(const std::wstring& ruleFile, const prt::RuleFileInfo* ruleFileInfo) { + RuleAttributeVec ra; + + std::wstring mainCgaRuleName = std::filesystem::path(ruleFile).stem().wstring(); + + const std::map importOrderMap = getImportOrderMap(ruleFileInfo); + + std::map mayaNameDuplicateCountMap; for (size_t i = 0; i < ruleFileInfo->getNumAttributes(); i++) { const prt::RuleFileInfo::Entry* attr = ruleFileInfo->getAttribute(i); @@ -73,10 +114,10 @@ RuleAttributes getRuleAttributes(const std::wstring& ruleFile, const prt::RuleFi RuleAttribute p; p.fqName = attr->getName(); - p.mayaBriefName = getBriefName(p.fqName); - p.mayaFullName = getFullName(p.fqName); p.mayaNiceName = getNiceName(p.fqName); p.mType = attr->getReturnType(); + p.mayaBriefName = getBriefName(p.fqName, mayaNameDuplicateCountMap); + p.mayaFullName = getFullName(p.fqName, mayaNameDuplicateCountMap); // TODO: is this correct? import name != rule file name std::wstring ruleName = p.fqName; @@ -92,18 +133,21 @@ RuleAttributes getRuleAttributes(const std::wstring& ruleFile, const prt::RuleFi p.memberOfStartRuleFile = true; } + const auto importOrder = importOrderMap.find(p.ruleFile); + p.ruleOrder = (importOrder != importOrderMap.end()) ? importOrder->second : ORDER_NONE; + bool hidden = false; for (size_t a = 0; a < attr->getNumAnnotations(); a++) { const prt::Annotation* an = attr->getAnnotation(a); const wchar_t* anName = an->getName(); - if (!(std::wcscmp(anName, ANNOT_HIDDEN))) + if (std::wcscmp(anName, ANNOT_HIDDEN) == 0) hidden = true; - else if (!(std::wcscmp(anName, ANNOT_ORDER))) { + else if (std::wcscmp(anName, ANNOT_ORDER) == 0) { if (an->getNumArguments() >= 1 && an->getArgument(0)->getType() == prt::AAT_FLOAT) { p.order = static_cast(an->getArgument(0)->getFloat()); } } - else if (!(std::wcscmp(anName, ANNOT_GROUP))) { + else if (std::wcscmp(anName, ANNOT_GROUP) == 0) { for (int argIdx = 0; argIdx < an->getNumArguments(); argIdx++) { if (an->getArgument(argIdx)->getType() == prt::AAT_STR) { p.groups.push_back(an->getArgument(argIdx)->getStr()); @@ -127,23 +171,13 @@ RuleAttributes getRuleAttributes(const std::wstring& ruleFile, const prt::RuleFi LOG_DBG << p; } - return ra; -} + setGlobalGroupOrder(ra); + RuleAttributeSet sortedRuleAttributes(ra.begin(), ra.end()); -AttributeGroupOrder getGlobalGroupOrder(const RuleAttributes& ruleAttributes) { - AttributeGroupOrder globalGroupOrder; - for (const auto& attribute : ruleAttributes) { - for (auto it = std::rbegin(attribute.groups); it != std::rend(attribute.groups); ++it) { - std::vector g(it, std::rend(attribute.groups)); - std::reverse(g.begin(), g.end()); - auto ggoIt = globalGroupOrder.emplace(g, ORDER_NONE).first; - ggoIt->second = std::min(attribute.groupOrder, ggoIt->second); - } - } - return globalGroupOrder; + return sortedRuleAttributes; } -void sortRuleAttributes(RuleAttributes& ra) { +bool RuleAttributeCmp::operator()(const RuleAttribute& lhs, const RuleAttribute& rhs) const { auto lowerCaseOrdering = [](std::wstring a, std::wstring b) { std::transform(a.begin(), a.end(), a.begin(), ::tolower); std::transform(b.begin(), b.end(), b.begin(), ::tolower); @@ -152,11 +186,14 @@ void sortRuleAttributes(RuleAttributes& ra) { auto compareRuleFile = [&](const RuleAttribute& a, const RuleAttribute& b) { // sort main rule attributes before the rest - if (a.memberOfStartRuleFile) + if (a.memberOfStartRuleFile && !b.memberOfStartRuleFile) return true; - if (b.memberOfStartRuleFile) + if (b.memberOfStartRuleFile && !a.memberOfStartRuleFile) return false; + if (a.ruleOrder != b.ruleOrder) + return a.ruleOrder < b.ruleOrder; + return lowerCaseOrdering(a.ruleFile, b.ruleFile); }; @@ -186,15 +223,6 @@ void sortRuleAttributes(RuleAttributes& ra) { return a.groups[i]; }; - const AttributeGroupOrder globalGroupOrder = getGlobalGroupOrder(ra); - if (DBG) - LOG_DBG << "globalGroupOrder:\n" << globalGroupOrder; - - auto getGroupOrder = [&globalGroupOrder](const RuleAttribute& ap) { - const auto it = globalGroupOrder.find(ap.groups); - return (it != globalGroupOrder.end()) ? it->second : ORDER_NONE; - }; - auto compareGroups = [&](const RuleAttribute& a, const RuleAttribute& b) { if (isChildOf(a, b)) return false; // child a should be sorted after parent b @@ -202,8 +230,8 @@ void sortRuleAttributes(RuleAttributes& ra) { if (isChildOf(b, a)) return true; // child b should be sorted after parent a - const auto globalOrderA = getGroupOrder(a); - const auto globalOrderB = getGroupOrder(b); + const auto globalOrderA = a.globalGroupOrder; + const auto globalOrderB = b.globalGroupOrder; if (globalOrderA != globalOrderB) return (globalOrderA < globalOrderB); @@ -215,7 +243,7 @@ void sortRuleAttributes(RuleAttributes& ra) { }; auto compareAttributeOrder = [&](const RuleAttribute& a, const RuleAttribute& b) { - if (a.order == ORDER_NONE && b.order == ORDER_NONE) + if (a.order == b.order) return lowerCaseOrdering(a.fqName, b.fqName); return a.order < b.order; @@ -231,14 +259,14 @@ void sortRuleAttributes(RuleAttributes& ra) { return compareAttributeOrder(a, b); }; - std::sort(ra.begin(), ra.end(), attributeOrder); + return attributeOrder(lhs, rhs); } std::wostream& operator<<(std::wostream& ostr, const RuleAttribute& ap) { auto orderVal = [](int order) { return (order == ORDER_NONE) ? L"none" : std::to_wstring(order); }; ostr << L"RuleAttribute '" << ap.fqName << L"':" << L" order = " << orderVal(ap.order) << L", groupOrder = " - << orderVal(ap.groupOrder) << L", ruleFile = '" << ap.ruleFile << L"'" << L", groups = [ " - << join(ap.groups, L" ") << L" ]\n"; + << orderVal(ap.groupOrder) << L", globalGroupOrder = " << orderVal(ap.globalGroupOrder) << L", ruleFile = '" + << ap.ruleFile << L"'" << L", groups = [ " << join(ap.groups, L" ") << L" ]\n"; return ostr; } @@ -251,7 +279,7 @@ std::ostream& operator<<(std::ostream& ostr, const RuleAttribute& ap) { std::wostream& operator<<(std::wostream& wostr, const AttributeGroupOrder& ago) { for (const auto& i : ago) { - wostr << L"[ " << join(i.first, L" ") << L"] = " << i.second << L"\n"; + wostr << L"[ " << i.first.first << " " << join(i.first.second, L" ") << L"] = " << i.second << L"\n"; } return wostr; } diff --git a/src/serlio/modifiers/RuleAttributes.h b/src/serlio/modifiers/RuleAttributes.h index f18758c9..d51523b3 100644 --- a/src/serlio/modifiers/RuleAttributes.h +++ b/src/serlio/modifiers/RuleAttributes.h @@ -3,7 +3,7 @@ * * See https://github.com/esri/serlio for build and usage instructions. * - * Copyright (c) 2012-2019 Esri R&D Center Zurich + * Copyright (c) 2012-2022 Esri R&D Center Zurich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -40,12 +41,14 @@ constexpr const wchar_t* ANNOT_DIR = L"@Directory"; constexpr const wchar_t* ANNOT_FILE = L"@File"; constexpr const wchar_t* ANNOT_ORDER = L"@Order"; constexpr const wchar_t* ANNOT_GROUP = L"@Group"; +constexpr const wchar_t* ANNOT_IMPORTS = L"_$IMPORTS"; +constexpr const wchar_t* ANNOT_IMPORTS_KEY = L"fullPrefix"; constexpr int ORDER_FIRST = std::numeric_limits::min(); constexpr int ORDER_NONE = std::numeric_limits::max(); using AttributeGroup = std::vector; -using AttributeGroupOrder = std::map; +using AttributeGroupOrder = std::map, int>; struct RuleAttribute { std::wstring fqName; // fully qualified rule name (i.e. including style prefix) @@ -57,17 +60,24 @@ struct RuleAttribute { AttributeGroup groups; // groups can be nested int order = ORDER_NONE; int groupOrder = ORDER_NONE; + int globalGroupOrder = ORDER_NONE; std::wstring ruleFile; + int ruleOrder = ORDER_NONE; bool memberOfStartRuleFile = false; }; -using RuleAttributes = std::vector; +struct RuleAttributeCmp { + bool operator()(const RuleAttribute& lhs, const RuleAttribute& rhs) const; +}; + +using RuleAttributeVec = std::vector; +using RuleAttributeSet = std::set; +using RuleAttributeMap = std::map; -SRL_TEST_EXPORTS_API RuleAttributes getRuleAttributes(const std::wstring& ruleFile, - const prt::RuleFileInfo* ruleFileInfo); -AttributeGroupOrder getGlobalGroupOrder(const RuleAttributes& ruleAttributes); -void sortRuleAttributes(RuleAttributes& ra); +SRL_TEST_EXPORTS_API RuleAttributeSet getRuleAttributes(const std::wstring& ruleFile, + const prt::RuleFileInfo* ruleFileInfo); +void setGlobalGroupOrder(RuleAttributeVec& ruleAttributes); std::wostream& operator<<(std::wostream& ostr, const RuleAttribute& ap); std::ostream& operator<<(std::ostream& ostr, const RuleAttribute& ap); std::wostream& operator<<(std::wostream& wostr, const AttributeGroupOrder& ago); \ No newline at end of file diff --git a/src/serlio/modifiers/polyModifier/polyModifierCmd.cpp b/src/serlio/modifiers/polyModifier/polyModifierCmd.cpp index d4592a14..6717b052 100644 --- a/src/serlio/modifiers/polyModifier/polyModifierCmd.cpp +++ b/src/serlio/modifiers/polyModifier/polyModifierCmd.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include @@ -121,23 +122,6 @@ MStatus polyModifierCmd::initModifierNode( MObject /* modifierNode */ ) return MS::kSuccess; } -MStatus polyModifierCmd::directModifier( MObject /* mesh */ ) -// -// Description: -// -// Override this method in a derived class to provide an implementation for -// directly modifying the mesh (writing on the mesh itself). This method is -// only called in the case where history does not exist and history is turned -// off (ie. DG operations are not desirable). -// -// The argument 'MObject mesh', is not used by this base class implementation. -// However, it may be used by derived classes. To avoid compiler warnings -// of unreferenced parameters, we comment out the parameter name. -// -{ - return MS::kSuccess; -} - MStatus polyModifierCmd::doModifyPoly() { MStatus status = MS::kFailure; @@ -148,26 +132,10 @@ MStatus polyModifierCmd::doModifyPoly() // collectNodeState(); - if( !fHasHistory && !fHasRecordHistory ) - { - MObject meshNode = fDagPath.node(); - - // Pre-process the mesh - Cache old mesh (including tweaks, if applicable) - // - cacheMeshData(); - cacheMeshTweaks(); - - // Call the directModifier - // - status = directModifier( meshNode ); - } - else - { - MObject modifierNode; - createModifierNode( modifierNode ); - initModifierNode( modifierNode ); - status = connectNodes( modifierNode ); - } + MObject modifierNode; + createModifierNode( modifierNode ); + initModifierNode( modifierNode ); + status = connectNodes( modifierNode ); } return status; @@ -177,25 +145,14 @@ MStatus polyModifierCmd::redoModifyPoly() { MStatus status = MS::kSuccess; - if( !fHasHistory && !fHasRecordHistory ) - { - MObject meshNode = fDagPath.node(); - - // Call the directModifier - No need to pre-process the mesh data again - // since we already have it. - // - status = directModifier( meshNode ); - } - else + // Call the redo on the DG and DAG modifiers + // + if( !fHasHistory ) { - // Call the redo on the DG and DAG modifiers - // - if( !fHasHistory ) - { - fDagModifier.doIt(); - } - status = fDGModifier.doIt(); + fDagModifier.doIt(); } + status = fDGModifier.doIt(); + return status; } @@ -204,28 +161,21 @@ MStatus polyModifierCmd::undoModifyPoly() { MStatus status = MS::kSuccess; - if( !fHasHistory && !fHasRecordHistory ) + fDGModifier.undoIt(); + + // undoCachedMesh must be called before undoTweakProcessing because + // undoCachedMesh copies the original mesh *without* tweaks back onto + // the existing mesh. Any changes done before the copy will be lost. + // + if( !fHasHistory ) { - status = undoDirectModifier(); + status = undoCachedMesh(); + MCheckStatus( status, "undoCachedMesh" ); + fDagModifier.undoIt(); } - else - { - fDGModifier.undoIt(); - - // undoCachedMesh must be called before undoTweakProcessing because - // undoCachedMesh copies the original mesh *without* tweaks back onto - // the existing mesh. Any changes done before the copy will be lost. - // - if( !fHasHistory ) - { - status = undoCachedMesh(); - MCheckStatus( status, "undoCachedMesh" ); - fDagModifier.undoIt(); - } - status = undoTweakProcessing(); - MCheckStatus( status, "undoTweakProcessing" ); - } + status = undoTweakProcessing(); + MCheckStatus( status, "undoTweakProcessing" ); return status; } @@ -271,7 +221,6 @@ void polyModifierCmd::collectNodeState() // // - HasHistory (Construction History exists) // - HasTweaks - // - HasRecordHistory (Construction History is turned on) // fDagPath.extendToShape(); MObject meshNodeShape = fDagPath.node(); @@ -316,10 +265,6 @@ void polyModifierCmd::collectNodeState() } } } - - int result; - MGlobal::executeCommand( "constructionHistory -q -tgl", result ); - fHasRecordHistory = (0 != result); } MStatus polyModifierCmd::createModifierNode( MObject& modifierNode ) @@ -739,7 +684,7 @@ MStatus polyModifierCmd::processTweaks( modifyPolyData& data ) // Only have to clear the tweaks off the duplicate mesh if we do not have history // and we want history. // - if( !fHasHistory && fHasRecordHistory ) + if( !fHasHistory ) { depNodeFn.setObject( data.upstreamNodeShape ); upstreamTweakPlug = depNodeFn.findPlug( "pnts", true); @@ -748,7 +693,7 @@ MStatus polyModifierCmd::processTweaks( modifyPolyData& data ) { for( i = 0; i < numTweaks; i++ ) { - tweak = meshTweakPlug.elementByLogicalIndex( fTweakIndexArray[i] ); + tweak = upstreamTweakPlug.elementByLogicalIndex( fTweakIndexArray[i] ); tweak.setValue( nullVector ); } } @@ -858,114 +803,6 @@ MStatus polyModifierCmd::connectNodes( MObject modifierNode ) return status; } -MStatus polyModifierCmd::cacheMeshData() -{ - MStatus status = MS::kSuccess; - - MFnDependencyNode depNodeFn; - MFnDagNode dagNodeFn; - - MObject meshNode = fDagPath.node(); - MObject dupMeshNode; - MPlug dupMeshNodeOutMeshPlug; - - // Duplicate the mesh - // - dagNodeFn.setObject( meshNode ); - dupMeshNode = dagNodeFn.duplicate(); - - MDagPath dupMeshDagPath; - MDagPath::getAPathTo( dupMeshNode, dupMeshDagPath ); - dupMeshDagPath.extendToShape(); - - depNodeFn.setObject( dupMeshDagPath.node() ); - dupMeshNodeOutMeshPlug = depNodeFn.findPlug( "outMesh", true, &status ); - MCheckStatus( status, "Could not retrieve outMesh" ); - - // Retrieve the meshData - // - status = dupMeshNodeOutMeshPlug.getValue( fMeshData ); - MCheckStatus( status, "Could not retrieve meshData" ); - - // Delete the duplicated node - // - MGlobal::deleteNode( dupMeshNode ); - - return status; -} - -MStatus polyModifierCmd::cacheMeshTweaks() -{ - MStatus status = MS::kSuccess; - - // Clear tweak undo information (to be rebuilt) - // - fTweakIndexArray.clear(); - fTweakVectorArray.clear(); - - // Extract the tweaks and store them in our local tweak cache members - // - if( fHasTweaks ) - { - // Declare our function sets - // - MFnDependencyNode depNodeFn; - - MObject meshNode = fDagPath.node(); - MPlug meshTweakPlug; - - // Declare our tweak processing variables - // - MPlug tweak; - MPlug tweakChild; - MObject tweakData; - MObjectArray tweakDataArray; - MFloatVector tweakVector; - - MPlugArray tempPlugArray; - - unsigned i; - - depNodeFn.setObject( meshNode ); - meshTweakPlug = depNodeFn.findPlug( "pnts", true); - - // ASSERT: meshTweakPlug should be an array plug! - // - MStatusAssert( (meshTweakPlug.isArray()), - "meshTweakPlug.isArray() -- meshTweakPlug is not an array plug" ); - unsigned numElements = meshTweakPlug.numElements(); - - // Gather meshTweakPlug data - // - for( i = 0; i < numElements; i++ ) - { - // MPlug::numElements() only returns the number of physical elements - // in the array plug. Thus we must use elementByPhysical index when using - // the index i. - // - tweak = meshTweakPlug.elementByPhysicalIndex(i); - - // If the method fails, the element is NULL. Only append the index - // if it is a valid plug. - // - if( !tweak.isNull() ) - { - // Cache the logical index of this element plug - // - unsigned logicalIndex = tweak.logicalIndex(); - - // Collect tweak data and cache the indices and float vectors - // - getFloat3PlugValue( tweak, tweakVector ); - fTweakIndexArray.append( logicalIndex ); - fTweakVectorArray.append( tweakVector ); - } - } - } - - return status; -} - MStatus polyModifierCmd::undoCachedMesh() { MStatus status; @@ -973,7 +810,6 @@ MStatus polyModifierCmd::undoCachedMesh() // Only need to restore the cached mesh if there was no history. Also // check to make sure that we are in the record history state. // - MStatusAssert( (fHasRecordHistory), "fHasRecordHistory == true" ); if( !fHasHistory ) { @@ -1017,7 +853,7 @@ MStatus polyModifierCmd::undoCachedMesh() // Need to force a DG evaluation now that the input has been changed. // - MString cmd( "dgeval -src " ); + MString cmd( "dgeval " ); cmd += meshNodeName; cmd += ".inMesh"; status = MGlobal::executeCommand( cmd, false, false ); @@ -1078,93 +914,6 @@ MStatus polyModifierCmd::undoTweakProcessing() return status; } -MStatus polyModifierCmd::undoDirectModifier() -{ - MStatus status; - - MFnDependencyNode depNodeFn; - MFnDagNode dagNodeFn; - - MObject meshNode = fDagPath.node(); - depNodeFn.setObject( meshNode ); - - // For the case with tweaks, we cannot write the mesh directly back onto - // the cachedInMesh, since the shape can have out of date information from the - // cachedInMesh. Thus we temporarily create an duplicate mesh, place our - // old mesh on the outMesh attribute of our duplicate mesh, connect the - // duplicate mesh shape to the mesh shape, and force a DG evaluation. - // - // For the case without tweaks, we can simply write onto the outMesh, since - // the shape relies solely on an outMesh when there is no history nor tweaks. - // - if( fHasTweaks ) - { - // Retrieve the inMesh and name of our mesh node (for the DG eval) - // - depNodeFn.setObject( meshNode ); - MPlug meshNodeInMeshPlug = depNodeFn.findPlug( "inMesh", true, &status ); - MCheckStatus( status, "Could not retrieve inMesh" ); - MString meshNodeName = depNodeFn.name(); - - // Duplicate our current mesh - // - dagNodeFn.setObject( meshNode ); - MObject dupMeshNode = dagNodeFn.duplicate(); - - // The dagNodeFn::duplicate() returns a transform, but we need a shape - // so retrieve the DAG path and extend it to the shape. - // - MDagPath dupMeshDagPath; - MDagPath::getAPathTo( dupMeshNode, dupMeshDagPath ); - dupMeshDagPath.extendToShape(); - - // Retrieve the outMesh of the duplicate mesh and set our mesh data back - // on it. - // - depNodeFn.setObject( dupMeshDagPath.node() ); - MPlug dupMeshNodeOutMeshPlug = depNodeFn.findPlug( "outMesh", true, &status ); - MCheckStatus( status, "Could not retrieve outMesh" ); - status = dupMeshNodeOutMeshPlug.setValue( fMeshData ); - - // Temporarily connect the duplicate mesh node to our mesh node - // - MDGModifier dgModifier; - dgModifier.connect( dupMeshNodeOutMeshPlug, meshNodeInMeshPlug ); - status = dgModifier.doIt(); - MCheckStatus( status, "Could not connect dupMeshNode -> meshNode" ); - - // Need to force a DG evaluation now that the input has been changed. - // - MString cmd("dgeval -src "); - cmd += meshNodeName; - cmd += ".inMesh"; - status = MGlobal::executeCommand( cmd, false, false ); - MCheckStatus( status, "Could not force DG eval" ); - - // Disconnect and delete the duplicate mesh node now - // - dgModifier.undoIt(); - MGlobal::deleteNode( dupMeshNode ); - - // Restore the tweaks on the mesh - // - status = undoTweakProcessing(); - } - else - { - // Restore the original mesh by writing the old mesh data (fMeshData) back - // onto the outMesh of our meshNode - // - depNodeFn.setObject( meshNode ); - MPlug meshNodeOutMeshPlug = depNodeFn.findPlug( "outMesh", true, &status ); - MCheckStatus( status, "Could not retrieve outMesh" ); - status = meshNodeOutMeshPlug.setValue( fMeshData ); - MCheckStatus( status, "Could not set meshData" ); - } - - return status; -} - MStatus polyModifierCmd::getFloat3PlugValue( MPlug plug, MFloatVector & value ) { // Retrieve the value as an MObject diff --git a/src/serlio/modifiers/polyModifier/polyModifierCmd.h b/src/serlio/modifiers/polyModifier/polyModifierCmd.h index 9b9bf52b..46488976 100644 --- a/src/serlio/modifiers/polyModifier/polyModifierCmd.h +++ b/src/serlio/modifiers/polyModifier/polyModifierCmd.h @@ -125,44 +125,12 @@ // (Figure 2. Node with Tweaks) // // -// The last of the questions deals with whether or not the user has construction -// history turned on or off. This will change how the node should be modified -// as well as what the node will look like in the DG following the operation. With -// history turned on, the user has selected that they would like to keep a -// history chain. So in that case, the resulting mesh would look like the above -// diagrams following the operation. On the other hand, with history turned off, -// the user has selected that they would not like to see a history chain. From here -// there are two possible choices to modify the mesh: -// -// (1) Operate on the mesh directly -// (2) Use the DG, like in the above diagrams, then collapse the nodes down into the mesh. -// -// The only exception to note out of this case is that if the node already possesses -// history (as would be answered by the first question), this preference is ignored. -// If a node has history, we continue to use history. The user is imposed with the -// task of deleting the history on the object first if they would not like to continue -// using history. -// -// -// With History: -// -// ____ ____ -// / \ / \ -// | Hist | O --------> O | mesh | O -// \____/ | | \____/ | -// outMesh inMesh outMesh -// -// -// Without History: -// -// ____ -// / \ -// O | mesh | O (All history compressed onto the inMesh attribute) -// | \____/ | -// inMesh outMesh -// -// -// (Figure 3. Node with History preference) +// Since we don't care if the user has turned the construction history off, we +// always generate an modifier node. Otherwise, the user is unable to make any +// changes to the serlio node. The user is imposed with the task of deleting +// the history on the object first if they would not like to continue +// using history. This deviates from the original polyModifierCmd implementation, +// where the history is collapsed, but makes more sense for our use case. // // // This section has described the "why" part of the question regarding this command. @@ -181,17 +149,12 @@ // // 1) History // -// For history, there are 4 cases that need to be considered: +// For history, there are 2 cases that need to be considered: // -// (a) History (yes) - RecordHistory (yes) -// (b) History (yes) - RecordHistory (no) -// (c) History (no) - RecordHistory (yes) -// (d) History (no) - RecordHistory (no) +// (a) History (yes) +// (b) History (no) // -// For (a) and (b), this command treats the node identically. Regardless of -// whether recording history is turned on or off, if history already exists -// on the node, we treat the node as though recording history is on. As such -// the command performs the following steps: +// For (a), The command performs the following steps: // // (i) Create a modifier node. // (ii) Find the node directly upstream to the mesh node. @@ -200,7 +163,7 @@ // (v) Connect the modifier node to the mesh node. // (vi) Done! // -// For (c), polyModifierCmd needs to generate an input mesh to drive the +// For (b), polyModifierCmd needs to generate an input mesh to drive the // modifier node. To do this, the mesh node is duplicated and connected // like the upstream node in the previous two cases: // @@ -210,47 +173,19 @@ // (iv) Connect the modifier node to the mesh node // (v) Done! // -// For (d), this command is a bit more complicated. There are two approaches -// that can be done to respect the fact that no history is desired. The first -// involves using the approach in case (c) and simply "baking" or "flattening" -// the nodes down into the mesh node. Unfortunately, this presents some -// serious problems with undo, as the Maya API in its current state does not -// support construction history manipulation. Resorting to the MEL command: -// "delete -ch" would be possible, however undoing the operation would not be -// trivial as calling an undo from within an undo could destabilize the undo -// queue. -// -// The second alternative and one that is currently implemented by this class -// is to respect the "No Construction History" preference strictly by -// not modifying the history chain at all and simply operating directly on the -// mesh. In order to do this and maintain generality, a hook is provided for -// derived classes to override and place in the code used to directly modify the -// mesh. polyModifierCmd will only call this method under the circumstances -// of case (d). To prevent code duplication between the operations done in the -// modifierNode and the command's directModifier implementation, the concept of -// a factory is used. It is recommended that an instance of such a factory is -// stored locally on the command much like it will be on the node. See -// polyModifierNode.h and polyModifierFty.h for more details. -// -// // 2) Tweaks // // Tweaks are handled as noted above in the description section. However, how // they are treated is dependent on the state of history. Using the four cases // above: // -// For (a), (b) and (c), it is as described in the description section: +// It is as described in the description section: // // (i) Create a tweak node. // (ii) Extract the tweaks from the mesh node. // (iii) Copy the tweaks onto the tweak node. // (iv) Clear the tweaks from the mesh node. -// (v) Clear the tweaks from the duplicate mesh node (for case (c) only!) -// -// For (d), we have yet another limitation. Tweaks are not handled in this case -// because of the same circumstances which give rise to the limitation in the -// history section. As such, topological changes may result in some odd behaviour -// unless the workaround provided in the limitations section is used. +// (v) Clear the tweaks from the duplicate mesh node (for case (b) only!) // // // How to use: @@ -287,26 +222,23 @@ // // 4) Add an instance of your polyModifierFty to the command // 5) Cache any input parameters for the factory on the command -// 6) Override the polyModifierCmd::directModifier() method -// 7) Place your factory setup code and call its doIt() in directModifier() // // --- // -// 8) Override the MPxCommand::doIt() method -// 9) Place your setup code inside the doIt() -// 10) Place the polyModifierCmd setup code inside the doIt() +// 6) Override the MPxCommand::doIt() method +// 7) Place your setup code inside the doIt() +// 8) Place the polyModifierCmd setup code inside the doIt() // (ie. setMeshNode(), setModifierNodeType()) -// 11) Call polyModifierCmd::doModifyPoly() inside the doIt() +// 9) Call polyModifierCmd::doModifyPoly() inside the doIt() // // --- // -// 12) Override the MPxCommand::redoIt() method -// 13) Call polyModifierCmd::redoModifyPoly() in redoIt() +// 10) Override the MPxCommand::redoIt() method +// 11) Call polyModifierCmd::redoModifyPoly() in redoIt() // // --- // -// 14) Override the MPxCommand::undoIt() method -// 15) Call polyModifierCmd::undoModifyPoly() in undoIt() +// 12) Override the MPxCommand::undoIt() method // // For more details on each of these steps, please visit the associated method/class // headers. @@ -316,11 +248,11 @@ // // There is one limitation in polyModifierCmd: // -// (1) Duplicate mesh created under the "No History / History turned on" case not undoable +// (1) Duplicate mesh created under the "No History" case not undoable // // Case (1): // -// Under the "No History / History turned on" case, history is allowed so the DG +// Under the "No History" case, history is allowed so the DG // is used to perform the operation. However, every polyModifierNode requires // an input mesh and without any prior history, a mesh input needs to be created. // polyModifierCmd compensates for this by duplicating the meshNode and marking @@ -388,18 +320,6 @@ class polyModifierCmd : public MPxCommand // virtual MStatus initModifierNode( MObject modifierNode ); - // directModifier - Derived classes should override this method to provide - // direct modifications on the meshNode in the case where - // no history exists and construction history is turned off. - // (ie. no DG operations desired) - // - // This method is called only if history does not exist and - // history is turned off. At this point, a handle to the - // meshNode is passed in so a derived class may directly - // modify the mesh. - // - virtual MStatus directModifier( MObject mesh ); - MStatus doModifyPoly(); MStatus redoModifyPoly(); MStatus undoModifyPoly(); @@ -469,16 +389,10 @@ class polyModifierCmd : public MPxCommand // MStatus connectNodes( MObject modifierNode ); - // Mesh caching methods - Only used in the directModifier case - // - MStatus cacheMeshData(); - MStatus cacheMeshTweaks(); - // Undo methods // MStatus undoCachedMesh(); MStatus undoTweakProcessing(); - MStatus undoDirectModifier(); ///////////////////////////////////// // polyModifierCmd Utility Methods // @@ -508,17 +422,12 @@ class polyModifierCmd : public MPxCommand // bool fHasHistory; bool fHasTweaks; - bool fHasRecordHistory; // Cached Tweak Data (for undo) // MIntArray fTweakIndexArray; MFloatVectorArray fTweakVectorArray; - // Cached Mesh Data (for undo in the 'No History'/'History turned off' case) - // - MObject fMeshData; - // DG and DAG Modifier // // - We need both DAG and DG modifiers since the MDagModifier::createNode() diff --git a/src/serlio/scripts/AEserlioTemplate.mel b/src/serlio/scripts/AEserlioTemplate.mel index 25ca516e..846c2cd3 100644 --- a/src/serlio/scripts/AEserlioTemplate.mel +++ b/src/serlio/scripts/AEserlioTemplate.mel @@ -3,7 +3,7 @@ * * See https://github.com/esri/serlio for build and usage instructions. * - * Copyright (c) 2012-2019 Esri R&D Center Zurich + * Copyright (c) 2012-2022 Esri R&D Center Zurich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,43 +17,75 @@ * limitations under the License. */ -proc string prtNode(string $attr) { +proc string prtGetNodeName(string $attr) { return `match "^[^\.]*" $attr`; } -proc string prtPlug(string $attr) { +proc string prtRemoveNodeName(string $attr) { return `substitute "^[^.]*\\." $attr ""`; } proc string prtControlName(string $attr) { - return substituteAllString(`prtPlug($attr)`, ".", "_"); + return substituteAllString(`prtRemoveNodeName($attr)`, ".", "_"); } proc string niceName(string $longName) { return `attributeName -nice $longName`; } +proc int prtIsStringAttr(string $attr){ + string $datatype[] = `addAttr -query -dataType $attr`; + return `strcmp "string" $datatype[0]` == 0; +} + +proc int prtIsFileAttr(string $attr){ + return `addAttr -q -uaf ($attr)`; +} + +proc int prtIsColorAttr(string $attr){ + return `addAttr -q -uac ($attr)`; +} + +proc int prtIsEnumAttr(string $attr){ + return (`addAttr -q -at ($attr)` == "enum"); +} + +proc int prtAttributeExists(string $attr){ + string $node = plugNode($attr); + string $attributeName = plugAttr($attr); + return`attributeExists $attributeName $node`; +} + +proc int prtControlExists(string $control){ + return `control -exists $control`; +} + +proc prtSetVisibility(int $visible, string $control){ + control -edit -visible $visible $control; +} + +proc prtSetBackgroundColor(int $enabled, float $grayScaleColor, string $control){ + control -edit -bgc $grayScaleColor $grayScaleColor $grayScaleColor -ebg $enabled $control; +} + global proc prtReloadRPK(string $attr) { - $node = prtNode($attr); + $node = prtGetNodeName($attr); $attrCurrentRule = $node + ".currentRule_Package"; setAttr -type "string" $attrCurrentRule ""; dgdirty $node; + evalDeferred "refreshEditorTemplates()"; } global proc int prtRPKChange(string $attr, string $varname) { - $varname = prtPlug($varname); + $varname = prtRemoveNodeName($varname); $oldpkg = eval("$tmp=$" + $varname); - $node = prtNode($attr); + $node = prtGetNodeName($attr); $newpkg = `getAttr ($node + ".Rule_Package")`; return $oldpkg == $newpkg; } -global proc prtShowFileDialog(string $attr) { - $node = prtNode($attr); - $plug = prtPlug($attr); - $filters = `attributeQuery -n $node -nn $plug`; - +global proc prtShowFileDialog(string $attr, string $filters) { string $file[]; if(startsWith($filters, "@Directory")) { @@ -62,7 +94,7 @@ global proc prtShowFileDialog(string $attr) { $file = `fileDialog2 -fm 1 -cap "Select File" -ff $filters`; } - if(size($file)) { + if(size($file) > 0) { setAttr -type "string" $attr $file[0]; if($attr == "Rule_Package") { evalDeferred "refreshEditorTemplates()"; @@ -70,52 +102,281 @@ global proc prtShowFileDialog(string $attr) { } } -global proc prtFileBrowse(string $attr, string $varname){ - $varname = prtPlug($varname); +proc string[] getProblems(string $node){ + string $attr = $node + ".CGAC_Problems"; + + if (!prtAttributeExists($attr)) + return {}; + + string $cgacProblems[] = `getAttr($attr)`; + return $cgacProblems; +} + +proc int problemsHaveErrors(string $cgacProblems[]){ + for($i = 0; $i < size($cgacProblems); $i += 3){ + if($cgacProblems[$i + 1] == "Error") + return true; + } + return false; +} + +global proc updateCGACProblems(string $uuid, string $window, string $rulePathLayout, string $problemLayout){ + string $nodes[] = `ls $uuid`; + string $node = $nodes[0]; + + string $attr = $node + ".Rule_Package"; + + string $rulePath = `getAttr $attr`; + string $cgacProblems[] = getProblems($node); + + string $title = "Problems - Node: " + $node; + window -e -title $title $window; + scrollField -e -text $rulePath $rulePathLayout; + + string $previousErrorItems[] = `rowColumnLayout -q -childArray $problemLayout`; + for ($errorItem in $previousErrorItems) + deleteUI $errorItem; + + for ($i = 0; $i < size($cgacProblems); $i += 3) { + string $errorCount = $cgacProblems[$i]; + string $errorType = $cgacProblems[$i + 1]; + string $errorString = $cgacProblems[$i + 2]; + + int $displayErrorIcon = ($errorType == "Error"); + string $icon = "caution.png"; + if ($displayErrorIcon) + $icon = "error.png"; + + iconTextStaticLabel -h 32 -w 28 -st "iconOnly" -i $icon -parent $problemLayout; + scrollField -height 60 -wordWrap true -text $errorString -editable false -parent $problemLayout; + text -label ("count: " + $errorCount) -parent $problemLayout; + } +} + +global proc prtCreateCGACProblemWindow(string $attr){ + string $node = prtGetNodeName($attr); + string $uuids[] = `ls -uuid $node`; + + string $window = `window + -resizeToFitChildren true + -iconName "Serlio" + -widthHeight 500 210`; + + string $scrollLayout = `scrollLayout + -horizontalScrollBarThickness 16 + -verticalScrollBarThickness 16 + -childResizable true + -parent $window`; + + string $ruleFileLayout = `rowLayout + -numberOfColumns 2 + -adjustableColumn 2 + -parent $scrollLayout`; + + text -label "Rule Package:" -parent $ruleFileLayout; + $rulePathLayout = `scrollField + -height 40 + -wordWrap true + -editable false + -parent $ruleFileLayout`; + + separator -height 10 -parent $scrollLayout; + + string $problemLayout = `rowColumnLayout + -numberOfColumns 3 + -adjustableColumn 2 + -columnSpacing 1 5 + -columnSpacing 2 5 + -columnSpacing 3 5 + -rowSpacing 1 5 + -parent $scrollLayout`; + + updateCGACProblems($uuids[0], $window, $rulePathLayout, $problemLayout); + showWindow $window; + + string $changeCommand = "updateCGACProblems \"" + $uuids[0] + "\" \"" + $window + "\" \"" + $rulePathLayout + "\" \"" + $problemLayout +"\""; + string $deleteWindow = "deleteUI \"" + $window +"\""; + scriptJob -parent $window -nodeNameChanged $node $changeCommand; + scriptJob -parent $window -attributeChange ($node + ".Rule_Package") $changeCommand; + scriptJob -parent $window -attributeChange ($node + ".CGAC_Problems") $changeCommand; + scriptJob -parent $window -nodeDeleted $node $deleteWindow; +} + +global proc updateCGACProblemIcon(string $attr){ + string $node = prtGetNodeName($attr); + string $cgacProblems[] = getProblems($node); + int $hasProblems = (size($cgacProblems) > 0); + + string $control = prtControlName($attr) + "_CGAC_Problems"; + if (!prtControlExists($control)) + return; + + int $displayErrorIcon = problemsHaveErrors($cgacProblems); + string $icon = "caution.png"; + if ($displayErrorIcon) + $icon = "error.png"; + + symbolButton -e -visible $hasProblems -i $icon $control; +} + +global proc prtFileBrowse(string $attr, string $varname, string $filters){ + $varname = prtRemoveNodeName($varname); + $filters = prtRemoveNodeName($filters); setUITemplate -pst attributeEditorTemplate; - rowLayout -nc 4; + rowLayout + -nc 5 + -adj 2 + -cw 3 25 + -cw 4 25 + -cw 5 25; text -label `niceName($attr)`; string $control = prtControlName($attr); textField -fileName `getAttr $attr` $control; connectControl -fileName $control $attr; - symbolButton -image "navButtonBrowse.xpm" -c ("prtShowFileDialog(\"" + $attr + "\")") ($control + "_browse"); - button -label "Reload" -command ("prtReloadRPK(\"" + $attr + "\")"); + + string $node = prtGetNodeName($attr); + + symbolButton -ann "show problems" -i "caution.png" -visible false -c ("prtCreateCGACProblemWindow(\"" + $attr + "\")") ($control + "_CGAC_Problems"); + updateCGACProblemIcon($attr); + + string $changeCommand = "updateCGACProblemIcon " + $attr; + scriptJob -rp -p $control -ac ($node + ".CGAC_Problems") $changeCommand; + + symbolButton -image "navButtonBrowse.xpm" -c ("prtShowFileDialog(\"" + $attr + "\",\"" + $filters + "\" )") ($control + "_browse"); + symbolButton -ann "reload rule package" -image "refresh.png" -c ("prtReloadRPK(\"" + $attr + "\")") ($control + "_reload"); setParent ..; setUITemplate -ppt; } -global proc prtFileBrowseReplace(string $attr, string $varname){ +global proc prtFileBrowseReplace(string $attr, string $varname, string $filters){ + $filters = prtRemoveNodeName($filters); if(prtRPKChange($attr, $varname)) { string $control = prtControlName($attr); connectControl $control $attr; - symbolButton -edit -c ("prtShowFileDialog(\"" + $attr + "\")") ($control + "_browse"); + symbolButton -edit -c ("prtShowFileDialog(\"" + $attr + "\",\"" + $filters + "\" )") ($control + "_browse"); + symbolButton -edit -c ("prtReloadRPK(\"" + $attr + "\")") ($control + "_reload"); + symbolButton -edit -c ("prtCreateCGACProblemWindow(\"" + $attr + "\")") ($control + "_CGAC_Problems"); + updateCGACProblemIcon($attr); } } -global proc prtFileBrowseReplaceRPK(string $attr, string $varname){ +global proc prtFileBrowseReplaceRPK(string $attr, string $varname, string $filters){ if(prtRPKChange($attr, $varname)) { - prtFileBrowseReplace($attr, $varname); + prtFileBrowseReplace($attr, $varname, $filters); } else { - $varname = prtPlug($varname); + $varname = prtRemoveNodeName($varname); $newpkg = `getAttr $attr`; evalDeferred ("$" + $varname + "=\"" + $newpkg + "\"; refreshEditorTemplates();"); } } -global proc prtColorChooser(string $attr, string $varname) { - setUITemplate -pst attributeEditorTemplate; +global proc prtUpdateEditHighlights(string $attr){ + if (!prtAttributeExists($attr)) + return; + + int $userSet = `getAttr ($attr + "_user_set")`; string $control = prtControlName($attr); - colorSliderGrp -label `niceName($attr)` $control; + + prtSetVisibility($userSet, $control + "_user_set"); + prtSetVisibility($userSet, $control + "_force_default_reset"); + prtSetBackgroundColor($userSet, 0.32, $control + "_column_layout"); + prtSetBackgroundColor(false, 0.4, $control); +} + +global proc prtForceDefault(string $attr){ + setAttr ($attr + "_force_default") true; +} + +global proc redrawEnum(string $attr){ + string $control = prtControlName($attr); + if (!prtControlExists($control)) + return; + + setUITemplate -pst attributeEditorTemplate; + + //remove all items in the current column layout + deleteUI ($control + "_user_set"); + deleteUI ($control + "_force_default_reset"); + deleteUI $control; + + //add all items back to the current column layout + iconTextStaticLabel -p ($control + "_column_layout") -st "iconOnly" -visible false -i "pencilCursor.png" -w 25 -h 25 -enable false ($control + "_user_set"); + + $label = `niceName $attr`; + attrEnumOptionMenuGrp -p ($control + "_column_layout") -label $label -attribute $attr $control; + symbolButton -p ($control + "_column_layout") -image "undo_s.png" -visible false -annotation "reset rule attribute to default value" -c ("prtForceDefault (\"" + $attr +"\")") ($control + "_force_default_reset"); connectControl $control $attr; + + string $changeCommand = "prtUpdateEditHighlights " + $attr; + scriptJob -p $control -ac ($attr + "_user_set") $changeCommand; + prtUpdateEditHighlights($attr); +} + +global proc prtAttributeControl(string $attr, string $varname){ + setUITemplate -pst attributeEditorTemplate; + string $control = prtControlName($attr); + int $nrOfColumns = 4; + int $isFileAttribute = `addAttr -q -uaf ($attr)`; + + if($isFileAttribute){ + $nrOfColumns = 5; + } + + rowColumnLayout -numberOfColumns $nrOfColumns -adjustableColumn 2 ($control + "_column_layout"); + + $label = `niceName $attr`; + + iconTextStaticLabel -st "iconOnly" -visible false -i "pencilCursor.png" -w 25 -h 25 -enable false ($control + "_user_set"); + + if (prtIsColorAttr($attr)){ + colorSliderGrp-label $label $control; + } else if (prtIsEnumAttr($attr)){ + attrEnumOptionMenuGrp -label $label -attribute $attr $control; + string $enumOptions = `addAttr -q -en $attr`; + } else { + attrControlGrp -label $label -attribute $attr $control; + } + + if ($isFileAttribute){ + symbolButton -image "navButtonBrowse.xpm" -c ("prtShowFileDialog(\"" + $attr + "\",\"All Files (*.*)\" )") ($control + "_browse"); + } + symbolButton -image "undo_s.png" -visible false -annotation "reset rule attribute to default value" -c ("prtForceDefault (\"" + $attr +"\")") ($control + "_force_default_reset"); + + if(prtIsStringAttr($attr)){ + connectControl -index 2 $control $attr; + } else { + connectControl $control $attr; + } + string $changeCommand = "prtUpdateEditHighlights " + $attr; + scriptJob -p $control -ac ($attr + "_user_set") $changeCommand; + setParent ..; setUITemplate -ppt; + prtUpdateEditHighlights($attr); } -global proc prtColorChooserReplace(string $attr, string $varname){ +global proc prtAttributeControlReplace(string $attr, string $varname){ if(prtRPKChange($attr, $varname)) { string $control = prtControlName($attr); - connectControl $control $attr; + if (prtIsFileAttr($attr)){ + symbolButton -edit -c ("prtShowFileDialog(\"" + $attr + "\",\"All Files (*.*)\" )") ($control + "_browse"); + } + if(prtIsStringAttr($attr)){ + connectControl -index 2 $control $attr; + } else if (prtIsColorAttr($attr)){ + connectControl $control $attr; + } else if (prtIsEnumAttr($attr)){ + attrEnumOptionMenuGrp -edit -attribute $attr $control; + connectControl $control $attr; + } else { + attrControlGrp -edit -attribute $attr $control; + connectControl $control $attr; + } + symbolButton -edit -c ("prtForceDefault (\"" + $attr +"\")") ($control + "_force_default_reset"); + string $changeCommand = "prtUpdateEditHighlights " + $attr; + scriptJob -p $control -ac ($attr + "_user_set") $changeCommand; } + prtUpdateEditHighlights($attr); } global proc AEserlioTemplate(string $node) { @@ -127,7 +388,8 @@ global proc AEserlioTemplate(string $node) { editorTemplate -beginLayout "CGA Rules" -collapse 0; string $varname = ("AEprtTemplate_" + $node); eval ("global string $" + $varname + "=\"" + `getAttr ($node + ".Rule_Package")` + "\""); - editorTemplate -callCustom "prtFileBrowse" "prtFileBrowseReplaceRPK" "Rule_Package" $varname; + string $filter = niceName($node + ".Rule_Package"); + editorTemplate -callCustom "prtFileBrowse" "prtFileBrowseReplaceRPK" "Rule_Package" $varname $filter; editorTemplate -l `niceName($node+".Random_Seed")` -adc "Random_Seed"; @@ -176,22 +438,17 @@ global proc AEserlioTemplate(string $node) { } - if(`addAttr -q -uaf ($longNameWithNode) `) { - editorTemplate -callCustom "prtFileBrowse" "prtFileBrowseReplace" $attr $varname; - } else if(`addAttr -q -uac ($longNameWithNode) `) { - editorTemplate -callCustom "prtColorChooser" "prtColorChooserReplace" $attr $varname; + editorTemplate -callCustom "prtAttributeControl" "prtAttributeControlReplace" $attr $varname; + if(`addAttr -q -uac ($longNameWithNode) `) $skip = 3; - } else { - editorTemplate -l `niceName($longNameWithNode)` -adc $attr; - } } if ($currentGroupName != "") editorTemplate -endLayout; editorTemplate -endLayout; - - editorTemplate -aec; - editorTemplate -endScrollLayout; + AEdependNodeTemplate $node; + editorTemplate -aec; + editorTemplate -endScrollLayout; } \ No newline at end of file diff --git a/src/serlio/scripts/serlioCreateUI.mel b/src/serlio/scripts/serlioCreateUI.mel index abf1306f..b1599f77 100644 --- a/src/serlio/scripts/serlioCreateUI.mel +++ b/src/serlio/scripts/serlioCreateUI.mel @@ -3,7 +3,7 @@ * * See https://github.com/esri/serlio for build and usage instructions. * - * Copyright (c) 2012-2019 Esri R&D Center Zurich + * Copyright (c) 2012-2022 Esri R&D Center Zurich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,10 +17,12 @@ * limitations under the License. */ -proc string[] appendAarray(string $a0[], string $a1[]) { +proc string[] appendArray(string $a0[], string $a1[]) { string $result[] = $a0; for($e in $a1) - $result[size($result)] = $e; + if(!stringArrayContains($e, $result)){ + $result[size($result)] = $e; + } return $result; } @@ -29,20 +31,49 @@ proc string[] collectInitialShapes(string $nodes[]) { for($node in $nodes) { string $type = `nodeType $node`; if($type == "mesh") { - $result = appendAarray($result, {$node}); + $result = appendArray($result, {$node}); } else if($type == "transform") { string $tmp[] = collectInitialShapes(`listRelatives -ni -pa -children $node`); - $result = appendAarray($result, $tmp); + $result = appendArray($result, $tmp); } } return $result; } +proc int hasNodeTypeInHistory(string $node, string $nodeTypes[]){ + string $hist[] = `listHistory -f false $node`; + string $future[] = `listHistory -f true $node`; + $hist = appendArray($hist, $future); + for ($node in $hist){ + string $nodeType = `nodeType $node`; + if(stringArrayContains($nodeType, $nodeTypes)) + return true; + } + return false; +} + +proc deleteNodeTypesFromHistory(string $node, string $nodeTypes[]){ + string $nodeHistory[] = `listHistory $node`; + + for($dpNode in $nodeHistory){ + string $dpNodeType = `nodeType $dpNode`; + if(stringArrayContains($dpNodeType, $nodeTypes)){ + string $previousDpNodePlug = `connectionInfo -sfd ($dpNode +".inMesh")`; + string $nextDpNodePlugs[] = `connectionInfo -dfs ($dpNode +".outMesh")`; + if ($previousDpNodePlug != "") { + for($nextDpNodePlug in $nextDpNodePlugs) + connectAttr -force $previousDpNodePlug $nextDpNodePlug; + } + delete $dpNode; + } + } +} + global proc createPrtNode() { string $select[] = `ls -sl`; string $initialShapes[] = collectInitialShapes($select); - if(!(size($initialShapes))) { + if(size($initialShapes) == 0) { confirmDialog -title "Missing selection" -message "Please select shapes first in order to apply a rule." -button "OK"; return; } @@ -50,52 +81,139 @@ global proc createPrtNode() { $filters = "Rule Package (*.rpk);;All Files (*.*)"; string $rulePackage[] = `fileDialog2 -fm 1 -cap "Select Rule Package" -ff $filters`; - - if(size($rulePackage)) { + int $alreadyHasExistingPrtNode = false; + if(size($rulePackage) > 0) { for($node in $initialShapes) { select -r $node; - serlioAssign $rulePackage; + string $nodeHistory[] = `listHistory $node`; + + for($dpNode in $nodeHistory){ + string $dpNodeType = `nodeType $dpNode`; + if($dpNodeType == "serlio"){ + setAttr -type "string" ($dpNode + ".Rule_Package") $rulePackage[0]; + evalDeferred "refreshEditorTemplates()"; + $alreadyHasExistingPrtNode = true; + } + } + + if (!$alreadyHasExistingPrtNode && !hasNodeTypeInHistory($node, {"serlio"})) + serlioAssign $rulePackage; + + $alreadyHasExistingPrtNode = false; } } select -r $select; } -global proc createPrtMaterialNode() { +global proc removePrtNode() { string $select[] = `ls -sl`; string $initialShapes[] = collectInitialShapes($select); - if(!(size($initialShapes))) { - confirmDialog -title "Missing selection" -message "Please select shapes first in order to create materials." -button "OK"; + if(size($initialShapes) == 0) { + confirmDialog -title "Missing selection" -message "Please select at least one shape to remove the associated rule package." -button "OK"; return; - } - + } + for($node in $initialShapes) { - $prtMaterialName = `createNode serlioMaterial`; - $im = `connectionInfo -sfd ($node +".inMesh")`; - if (size($im)>0) { - connectAttr -force ( $prtMaterialName + ".outMesh" ) ( $node + ".inMesh" ); - connectAttr -force ( $im ) ( $prtMaterialName + ".inMesh" ); - } + select -r $node; + hyperShade -assign "lambert1"; + deleteNodeTypesFromHistory($node, {"serlio", "serlioMaterial", "serlioArnoldMaterial"}); + } + + select -r $select; +} + +global proc displayTextures(){ + string $panels[] = `getPanel -typ "modelPanel"`; + for ($panel in $panels){ + string $camera = `modelEditor -q -camera $panel`; + if (`camera -q -orthographic $camera` == false) + modelEditor -e -dtx true $panel; } } -global proc createArnoldMaterialNode() { +global proc createMaterialNode(string $materialType) { string $select[] = `ls -sl`; string $initialShapes[] = collectInitialShapes($select); - if(!(size($initialShapes))) { + if(size($initialShapes) == 0) { confirmDialog -title "Missing selection" -message "Please select shapes first in order to create materials." -button "OK"; return; } for($node in $initialShapes) { - $prtMaterialName = `createNode serlioArnoldMaterial`; - $im = `connectionInfo -sfd ($node +".inMesh")`; - if (size($im)>0) { - connectAttr -force ( $prtMaterialName + ".outMesh" ) ( $node + ".inMesh" ); - connectAttr -force ( $im ) ( $prtMaterialName + ".inMesh" ); - } + select -r $node; + if(hasNodeTypeInHistory($node, {"serlio"}) && !hasNodeTypeInHistory($node, {"serlioMaterial","serlioArnoldMaterial"})) + serlioCreateMaterial $materialType; } + displayTextures(); + select -r $select; +} + +global proc createHelpMenuItems(){ + string $serlioWebsite = getPluginResource("serlio", "SERLIO_HOME"); + string $cgaReference = getPluginResource("serlio", "CGA_REFERENCE"); + string $rulePackageManual = getPluginResource("serlio", "RPK_MANUAL"); + + menuItem -label "Serlio Website" -c ("showHelp -absolute \"" + $serlioWebsite + "\""); + menuItem -label "CityEngine CGA Reference" -c ("showHelp -absolute \"" + $cgaReference + "\""); + menuItem -label "CityEngine Rule Package Manual" -c ("showHelp -absolute \"" + $rulePackageManual + "\""); +} + +global proc createAboutDialog(){ + string $pluginPath = `pluginInfo -query -path serlio`; + string $iconPath = $pluginPath + "../../icons/serlio.xpm"; + string $serlioVersion = `pluginInfo -query -version serlio`; + string $serlioVendor = `pluginInfo -query -vendor serlio`; + string $legalText = "Serlio is free for personal, educational, and non-commercial use. " + + "Commercial use requires at least one commercial license of the latest CityEngine version installed in the organization. " + + "Redistribution or web service offerings are not allowed unless expressly permitted.\n" + + "Serlio is under the same license as the included CityEngine SDK."; + + string $window = `window -title "About Serlio" + -resizeToFitChildren true + -iconName "Serlio" + -widthHeight 500 210`; + + string $form = `formLayout -numberOfDivisions 100`; + + string $serlioImage = `iconTextStaticLabel -h 32 -w 28 -st "iconOnly" -i $iconPath`; + string $versionText = `text -label ("Version: " + $serlioVersion)`; + string $vendorText = `text -label ("Vendor: " + $serlioVendor)`; + string $legalField = `scrollField -h 85 -wordWrap true + -text $legalText + -editable false`; + + string $okButton = `button -label "OK" -command ("deleteUI -window " + $window)`; + + formLayout -edit + -attachForm $serlioImage "top" 5 + -attachForm $serlioImage "left" 5 + -attachNone $serlioImage "bottom" + -attachNone $serlioImage "right" + + -attachControl $versionText "top" 5 $serlioImage + -attachForm $versionText "left" 5 + -attachNone $versionText "bottom" + -attachNone $versionText "right" + + -attachControl $vendorText "top" 5 $versionText + -attachForm $vendorText "left" 5 + -attachNone $vendorText "bottom" + -attachNone $vendorText "right" + + -attachControl $legalField "top" 5 $vendorText + -attachForm $legalField "left" 5 + -attachControl $legalField "bottom" 5 $okButton + -attachForm $legalField "right" 5 + + -attachNone $okButton "top" + -attachForm $okButton "left" 5 + -attachForm $okButton "bottom" 5 + -attachForm $okButton "right" 5 + $form; + + showWindow $window; } global proc createPrtMenu() { @@ -109,8 +227,14 @@ global proc createPrtMenu() { setParent -m $gPrtMenu; menuItem -divider true; menuItem -label "Attach CityEngine Rule Package..." -c "createPrtNode" -annotation "Attach a CGA rule package to a geometry"; - menuItem -label "Create Materials" -c "createPrtMaterialNode" -annotation "Create Materials"; - menuItem -label "Create Arnold Materials" -c "createArnoldMaterialNode" -annotation "Create Arnold Materials"; + menuItem -label "Remove CityEngine Rule Package" -c "removePrtNode" -annotation "Remove a CGA rule package from a geometry"; + menuItem -label "Create Materials" -c "createMaterialNode(\"stingray\")" -annotation "Create Materials"; + menuItem -label "Create Arnold Materials" -c "createMaterialNode(\"arnold\")" -annotation "Create Arnold Materials"; + menuItem -divider true; + menuItem -subMenu true -label "Help" -i "help.png"; + createHelpMenuItems(); + setParent -menu ..; + menuItem -label "About Serlio" -c "createAboutDialog()" -annotation "Show about dialog"; setParent -m ..; } } diff --git a/src/serlio/scripts/serlioDeleteUI.mel b/src/serlio/scripts/serlioDeleteUI.mel index e3e8ee04..cdf614e3 100644 --- a/src/serlio/scripts/serlioDeleteUI.mel +++ b/src/serlio/scripts/serlioDeleteUI.mel @@ -3,7 +3,7 @@ * * See https://github.com/esri/serlio for build and usage instructions. * - * Copyright (c) 2012-2019 Esri R&D Center Zurich + * Copyright (c) 2012-2022 Esri R&D Center Zurich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/src/serlio/serlioPlugin.cpp b/src/serlio/serlioPlugin.cpp index aa593499..a3deaa13 100644 --- a/src/serlio/serlioPlugin.cpp +++ b/src/serlio/serlioPlugin.cpp @@ -3,7 +3,7 @@ * * See https://github.com/esri/serlio for build and usage instructions. * - * Copyright (c) 2012-2019 Esri R&D Center Zurich + * Copyright (c) 2012-2022 Esri R&D Center Zurich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,13 +17,14 @@ * limitations under the License. */ -#include "serlioPlugin.h" #include "PRTContext.h" +#include "serlioPlugin.h" #include "modifiers/PRTModifierCommand.h" #include "modifiers/PRTModifierNode.h" #include "materials/ArnoldMaterialNode.h" +#include "materials/MaterialCommand.h" #include "materials/StingrayMaterialNode.h" #include "utils/MayaUtilities.h" @@ -42,6 +43,7 @@ constexpr bool DBG = false; constexpr const char* NODE_MODIFIER = "serlio"; constexpr const char* NODE_MATERIAL = "serlioMaterial"; constexpr const char* NODE_ARNOLD_MATERIAL = "serlioArnoldMaterial"; +constexpr const char* CMD_CREATE_MATERIAL = "serlioCreateMaterial"; constexpr const char* CMD_ASSIGN = "serlioAssign"; constexpr const char* MEL_PROC_CREATE_UI = "serlioCreateUI"; constexpr const char* MEL_PROC_DELETE_UI = "serlioDeleteUI"; @@ -71,6 +73,9 @@ MStatus initializePlugin(MObject obj) { auto createModifierCommand = []() { return (void*)new PRTModifierCommand(); }; MCHECK(plugin.registerCommand(CMD_ASSIGN, createModifierCommand)); + auto createMaterialCommand = []() { return (void*)new MaterialCommand(); }; + MCHECK(plugin.registerCommand(CMD_CREATE_MATERIAL, createMaterialCommand)); + auto createModifierNode = []() { return (void*)new PRTModifierNode(); }; MCHECK(plugin.registerNode(NODE_MODIFIER, PRTModifierNode::id, createModifierNode, PRTModifierNode::initialize)); @@ -84,6 +89,8 @@ MStatus initializePlugin(MObject obj) { MCHECK(plugin.registerUI(MEL_PROC_CREATE_UI, MEL_PROC_DELETE_UI)); + MCHECK(plugin.registerUIStrings(mu::registerMStringResources, "")); + return MStatus::kSuccess; } diff --git a/src/serlio/serlioPlugin.h b/src/serlio/serlioPlugin.h index 85f86e9f..720cb016 100644 --- a/src/serlio/serlioPlugin.h +++ b/src/serlio/serlioPlugin.h @@ -3,7 +3,7 @@ * * See https://github.com/esri/serlio for build and usage instructions. * - * Copyright (c) 2012-2019 Esri R&D Center Zurich + * Copyright (c) 2012-2022 Esri R&D Center Zurich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/src/serlio/shaders/serlioShaderStingray.sfx b/src/serlio/shaders/serlioShaderStingray.sfx index 927c9c6d..eca03a9c 100644 --- a/src/serlio/shaders/serlioShaderStingray.sfx +++ b/src/serlio/shaders/serlioShaderStingray.sfx @@ -1,14 +1,14 @@ -SFB_UNX = { /* +SFB_WIN = { /* Version=28 GroupVersion=-1.000000 Advanced=0 HelpID=0 ParentMaterial=0 -NumberOfNodes=74 +NumberOfNodes=81 #NT=20178 0 PC=3 - posx=1 v=2003 -438.892761 - posy=1 v=2003 -1197.870361 + posx=1 v=2003 -972.225708 + posy=1 v=2003 -571.203430 previewswatch=1 v=2002 1 group=-1 ISC=0 @@ -38,8 +38,8 @@ NumberOfNodes=74 #NT=20189 0 PC=3 name=1 v=5000 Normal_Map_Switch - posx=1 v=2003 1172.062012 - posy=1 v=2003 150.317429 + posx=1 v=2003 648.729248 + posy=1 v=2003 706.983521 group=-1 ISC=4 SVT=5022 2003 1 0 0 @@ -91,8 +91,8 @@ NumberOfNodes=74 #NT=20189 0 PC=3 name=1 v=5000 Color_Map_Switch - posx=1 v=2003 959.622864 - posy=1 v=2003 -1218.670410 + posx=1 v=2003 426.289581 + posy=1 v=2003 -592.003357 group=-1 ISC=4 SVT=5022 2003 1 0 0 @@ -108,8 +108,8 @@ NumberOfNodes=74 CPC=0 #NT=20194 0 PC=2 - posx=1 v=2003 854.919678 - posy=1 v=2003 321.746094 + posx=1 v=2003 331.585999 + posy=1 v=2003 878.411560 group=-1 ISC=0 OSC=1 @@ -119,8 +119,8 @@ NumberOfNodes=74 CPC=0 #NT=20195 0 PC=2 - posx=1 v=2003 850.475525 - posy=1 v=2003 202.539703 + posx=1 v=2003 327.141846 + posy=1 v=2003 759.205750 group=-1 ISC=1 SVT=5022 3002 1 0 1 @@ -131,10 +131,11 @@ NumberOfNodes=74 C=7 0 2 2 2 3 0 CPC=0 #NT=20176 0 - PC=3 + PC=4 posx=1 v=2003 1636.499512 posy=1 v=2003 871.666687 normalspace=2 e=0 v=5012 1 + blendmode=2 e=0 v=5012 2 group=-1 ISC=13 SVT=5022 3002 1 0 0 @@ -153,8 +154,8 @@ NumberOfNodes=74 OSC=0 #NT=20189 0 PC=2 - posx=1 v=2003 1106.586426 - posy=1 v=2003 -449.900818 + posx=1 v=2003 1113.251587 + posy=1 v=2003 100.516365 group=-1 ISC=4 SVT=5022 2003 1 0 0 @@ -171,8 +172,8 @@ NumberOfNodes=74 #NT=20177 0 PC=4 name=1 v=5000 color_map - posx=1 v=2003 543.512024 - posy=1 v=2003 -1111.884766 + posx=1 v=2003 10.178637 + posy=1 v=2003 -485.219147 uiorder=2 e=0 v=2002 2 group=-1 ISC=2 @@ -186,8 +187,8 @@ NumberOfNodes=74 #NT=20177 0 PC=5 name=1 v=5000 normal_map - posx=1 v=2003 573.777466 - posy=1 v=2003 154.460297 + posx=1 v=2003 50.444195 + posy=1 v=2003 711.126404 encoding=2 e=0 v=5012 2 uiorder=2 e=0 v=2002 3 group=-1 @@ -262,12 +263,11 @@ NumberOfNodes=74 C=15 0 3 8 7 8 0 CPC=0 #NT=20185 0 - PC=7 + PC=6 name=1 v=5000 use_color_map - posx=1 v=2003 542.361267 - posy=1 v=2003 -1214.742188 + posx=1 v=2003 9.027872 + posy=1 v=2003 -588.075134 type=2 e=0 v=5012 0 - defaultscalar=2 e=0 v=2003 1.000000 uitype=2 e=0 v=5012 1 uiorder=2 e=0 v=2002 11 group=-1 @@ -280,10 +280,10 @@ NumberOfNodes=74 #NT=20185 0 PC=7 name=1 v=5000 diffuse_color - posx=1 v=2003 542.261963 - posy=1 v=2003 -977.162415 + posx=1 v=2003 8.928568 + posy=1 v=2003 -350.497345 type=2 e=0 v=5012 2 - defaultvecthree=2 e=0 v=3002 0.988235,0.937255,0.886275 + defaultvecthree=2 e=0 v=3002 1.000000,1.000000,1.000000 defaultvector=2 e=0 v=3003 0.500000,0.500000,0.500000,0.000000 uiorder=2 e=0 v=2002 21 group=-1 @@ -296,8 +296,8 @@ NumberOfNodes=74 #NT=20185 0 PC=6 name=1 v=5000 use_opacity_map - posx=1 v=2003 574.821472 - posy=1 v=2003 -488.809418 + posx=1 v=2003 910.238281 + posy=1 v=2003 7.857183 type=2 e=0 v=5012 0 uitype=2 e=0 v=5012 1 uiorder=2 e=0 v=2002 12 @@ -311,8 +311,8 @@ NumberOfNodes=74 #NT=20185 0 PC=6 name=1 v=5000 opacity - posx=1 v=2003 577.500122 - posy=1 v=2003 -125.297607 + posx=1 v=2003 1102.915283 + posy=1 v=2003 388.869263 type=2 e=0 v=5012 0 defaultscalar=2 e=0 v=2003 1.000000 uiorder=2 e=0 v=2002 22 @@ -326,8 +326,8 @@ NumberOfNodes=74 #NT=20185 0 PC=6 name=1 v=5000 use_normal_map - posx=1 v=2003 573.491089 - posy=1 v=2003 44.126915 + posx=1 v=2003 50.157818 + posy=1 v=2003 600.793518 type=2 e=0 v=5012 0 uitype=2 e=0 v=5012 1 uiorder=2 e=0 v=2002 13 @@ -428,8 +428,8 @@ NumberOfNodes=74 CPC=0 #NT=20186 0 PC=2 - posx=1 v=2003 1215.337524 - posy=1 v=2003 -989.622620 + posx=1 v=2003 682.004456 + posy=1 v=2003 -362.957672 group=-1 ISC=2 SVT=5022 3002 1 0 0 @@ -441,8 +441,8 @@ NumberOfNodes=74 CPC=0 #NT=20190 0 PC=2 - posx=1 v=2003 780.059753 - posy=1 v=2003 -1055.316772 + posx=1 v=2003 246.726425 + posy=1 v=2003 -428.651733 group=-1 ISC=1 SVT=5022 3002 1 1 0 @@ -455,8 +455,8 @@ NumberOfNodes=74 #NT=20177 0 PC=4 name=1 v=5000 opacity_map - posx=1 v=2003 577.039429 - posy=1 v=2003 -377.170197 + posx=1 v=2003 -5.044054 + posy=1 v=2003 89.496941 uiorder=2 e=0 v=2002 2 group=-1 ISC=2 @@ -464,13 +464,19 @@ NumberOfNodes=74 SVT=5022 2003 2 0 0 OSC=1 SVT=5022 3003 3 - CC=1 - C=29 0 3 9 2 3 0 + CC=4 + C=29 0 3 76 0 1 0 + CPC=0 + C=29 0 3 77 0 1 0 + CPC=0 + C=29 0 3 78 0 1 0 + CPC=0 + C=29 0 3 79 2 3 0 CPC=0 #NT=20186 0 PC=2 - posx=1 v=2003 1279.500244 - posy=1 v=2003 -222.999985 + posx=1 v=2003 1328.665405 + posy=1 v=2003 198.666992 group=-1 ISC=2 SVT=5022 2003 1 0 0 @@ -482,8 +488,8 @@ NumberOfNodes=74 CPC=0 #NT=20196 0 PC=2 - posx=1 v=2003 853.745850 - posy=1 v=2003 -205.730118 + posx=1 v=2003 841.662842 + posy=1 v=2003 319.686646 group=-1 ISC=1 SVT=5022 2003 1 1 0 @@ -564,8 +570,8 @@ NumberOfNodes=74 #NT=20189 0 PC=3 name=1 v=5000 dirt_map_switch - posx=1 v=2003 941.047363 - posy=1 v=2003 -830.847717 + posx=1 v=2003 407.714081 + posy=1 v=2003 -204.182373 group=-1 ISC=4 SVT=5022 2003 1 0 0 @@ -582,8 +588,8 @@ NumberOfNodes=74 #NT=20177 0 PC=4 name=1 v=5000 dirt_map - posx=1 v=2003 544.877319 - posy=1 v=2003 -723.943176 + posx=1 v=2003 11.543928 + posy=1 v=2003 -97.277359 uiorder=2 e=0 v=2002 2 group=-1 ISC=2 @@ -595,12 +601,11 @@ NumberOfNodes=74 C=38 0 3 37 2 3 0 CPC=0 #NT=20185 0 - PC=7 + PC=6 name=1 v=5000 use_dirt_map - posx=1 v=2003 544.976562 - posy=1 v=2003 -833.050415 + posx=1 v=2003 11.643171 + posy=1 v=2003 -206.385086 type=2 e=0 v=5012 0 - defaultscalar=2 e=0 v=2003 1.000000 uitype=2 e=0 v=5012 1 uiorder=2 e=0 v=2002 11 group=-1 @@ -612,8 +617,8 @@ NumberOfNodes=74 CPC=0 #NT=20190 0 PC=3 - posx=1 v=2003 776.305542 - posy=1 v=2003 -638.982544 + posx=1 v=2003 242.972260 + posy=1 v=2003 -12.316059 collapsed=1 v=2001 1 group=-1 ISC=1 @@ -626,8 +631,8 @@ NumberOfNodes=74 CPC=0 #NT=20186 0 PC=2 - posx=1 v=2003 1409.227417 - posy=1 v=2003 -837.289124 + posx=1 v=2003 875.894226 + posy=1 v=2003 -210.623810 group=-1 ISC=2 SVT=5022 3002 1 0 0 @@ -639,8 +644,8 @@ NumberOfNodes=74 CPC=0 #NT=20186 0 PC=2 - posx=1 v=2003 129.678635 - posy=1 v=2003 -1105.106689 + posx=1 v=2003 -403.654968 + posy=1 v=2003 -478.441132 group=-1 ISC=2 SVT=5022 3001 1 0 1 @@ -653,8 +658,8 @@ NumberOfNodes=74 CPC=0 #NT=20187 0 PC=2 - posx=1 v=2003 292.178558 - posy=1 v=2003 -1199.392944 + posx=1 v=2003 -241.154785 + posy=1 v=2003 -572.726013 group=-1 ISC=2 SVT=5022 3001 1 0 1 @@ -668,8 +673,8 @@ NumberOfNodes=74 #NT=20185 0 PC=10 name=1 v=5000 colormap_trafo_suvw - posx=1 v=2003 -65.817390 - posy=1 v=2003 -1162.567627 + posx=1 v=2003 -599.150330 + posy=1 v=2003 -535.901367 type=2 e=0 v=5012 2 defaultvectwo=2 e=0 v=3001 1.000000,1.000000 defaultvecthree=2 e=0 v=3002 1.000000,1.000000,0.000000 @@ -686,8 +691,8 @@ NumberOfNodes=74 CPC=0 #NT=20186 0 PC=2 - posx=1 v=2003 97.178650 - posy=1 v=2003 -702.356812 + posx=1 v=2003 -436.154999 + posy=1 v=2003 -75.690872 group=-1 ISC=2 SVT=5022 3001 1 0 1 @@ -700,8 +705,8 @@ NumberOfNodes=74 CPC=0 #NT=20187 0 PC=2 - posx=1 v=2003 263.428589 - posy=1 v=2003 -792.893066 + posx=1 v=2003 -269.904785 + posy=1 v=2003 -166.227600 group=-1 ISC=2 SVT=5022 3001 1 0 1 @@ -715,8 +720,8 @@ NumberOfNodes=74 #NT=20185 0 PC=10 name=1 v=5000 dirtmap_trafo_suvw - posx=1 v=2003 -68.178497 - posy=1 v=2003 -818.428833 + posx=1 v=2003 -601.511414 + posy=1 v=2003 -191.763519 type=2 e=0 v=5012 2 defaultvectwo=2 e=0 v=3001 1.000000,1.000000 defaultvecthree=2 e=0 v=3002 1.000000,1.000000,0.000000 @@ -733,8 +738,8 @@ NumberOfNodes=74 CPC=0 #NT=20186 0 PC=3 - posx=1 v=2003 105.428665 - posy=1 v=2003 -362.106934 + posx=1 v=2003 -427.904938 + posy=1 v=2003 264.559814 previewswatch=1 v=2002 1 group=-1 ISC=2 @@ -748,8 +753,8 @@ NumberOfNodes=74 CPC=0 #NT=20187 0 PC=2 - posx=1 v=2003 262.928619 - posy=1 v=2003 -462.643188 + posx=1 v=2003 -270.404755 + posy=1 v=2003 164.023895 group=-1 ISC=2 SVT=5022 3001 1 0 1 @@ -763,8 +768,8 @@ NumberOfNodes=74 #NT=20185 0 PC=10 name=1 v=5000 opacitymap_trafo_suvw - posx=1 v=2003 -68.678497 - posy=1 v=2003 -486.928955 + posx=1 v=2003 -602.011414 + posy=1 v=2003 139.738235 type=2 e=0 v=5012 2 defaultvectwo=2 e=0 v=3001 1.000000,1.000000 defaultvecthree=2 e=0 v=3002 1.000000,1.000000,0.000000 @@ -781,8 +786,8 @@ NumberOfNodes=74 CPC=0 #NT=20186 0 PC=2 - posx=1 v=2003 125.928665 - posy=1 v=2003 166.143021 + posx=1 v=2003 -397.405060 + posy=1 v=2003 722.809204 group=-1 ISC=2 SVT=5022 3001 1 0 1 @@ -795,8 +800,8 @@ NumberOfNodes=74 CPC=0 #NT=20187 0 PC=2 - posx=1 v=2003 289.678619 - posy=1 v=2003 79.356758 + posx=1 v=2003 -233.654556 + posy=1 v=2003 636.023010 group=-1 ISC=2 SVT=5022 3001 1 0 1 @@ -810,8 +815,8 @@ NumberOfNodes=74 #NT=20185 0 PC=10 name=1 v=5000 normalmap_trafo_suvw - posx=1 v=2003 -41.928528 - posy=1 v=2003 55.070992 + posx=1 v=2003 -565.261475 + posy=1 v=2003 611.737488 type=2 e=0 v=5012 2 defaultvectwo=2 e=0 v=3001 1.000000,1.000000 defaultvecthree=2 e=0 v=3002 1.000000,1.000000,0.000000 @@ -970,8 +975,8 @@ NumberOfNodes=74 #NT=20185 0 PC=8 name=1 v=5000 colormap_trafo_tuv - posx=1 v=2003 -68.178497 - posy=1 v=2003 -1279.428711 + posx=1 v=2003 -601.511414 + posy=1 v=2003 -652.760681 type=2 e=0 v=5012 1 defaultvector=2 e=0 v=3003 1.000000,1.000000,0.000000,0.000000 minrange=2 e=0 v=2003 -100001.000000 @@ -987,8 +992,8 @@ NumberOfNodes=74 #NT=20185 0 PC=8 name=1 v=5000 dirtmap_trafo_tuv - posx=1 v=2003 -67.678497 - posy=1 v=2003 -922.928833 + posx=1 v=2003 -601.011414 + posy=1 v=2003 -296.263733 type=2 e=0 v=5012 1 defaultvector=2 e=0 v=3003 1.000000,0.000000,0.000000,0.000000 minrange=2 e=0 v=2003 -100001.000000 @@ -1004,8 +1009,8 @@ NumberOfNodes=74 #NT=20185 0 PC=8 name=1 v=5000 opacitymap_trafo_tuv - posx=1 v=2003 -64.428497 - posy=1 v=2003 -595.928955 + posx=1 v=2003 -597.761414 + posy=1 v=2003 30.737833 type=2 e=0 v=5012 1 defaultvector=2 e=0 v=3003 1.000000,1.000000,0.000000,0.000000 minrange=2 e=0 v=2003 -100001.000000 @@ -1021,8 +1026,8 @@ NumberOfNodes=74 #NT=20185 0 PC=8 name=1 v=5000 normalmap_trafo_tuv - posx=1 v=2003 -40.928528 - posy=1 v=2003 -63.679016 + posx=1 v=2003 -564.261475 + posy=1 v=2003 492.988098 type=2 e=0 v=5012 1 defaultvector=2 e=0 v=3003 1.000000,1.000000,0.000000,0.000000 minrange=2 e=0 v=2003 -100001.000000 @@ -1088,8 +1093,8 @@ NumberOfNodes=74 CPC=0 #NT=20179 0 PC=2 - posx=1 v=2003 -451.357483 - posy=1 v=2003 -924.207947 + posx=1 v=2003 -984.690552 + posy=1 v=2003 -297.542847 group=-1 ISC=0 OSC=1 @@ -1099,8 +1104,8 @@ NumberOfNodes=74 CPC=0 #NT=20180 0 PC=2 - posx=1 v=2003 -432.126617 - posy=1 v=2003 -47.511288 + posx=1 v=2003 -955.458862 + posy=1 v=2003 509.155853 group=-1 ISC=0 OSC=1 @@ -1110,8 +1115,8 @@ NumberOfNodes=74 CPC=0 #NT=20181 0 PC=2 - posx=1 v=2003 -450.226135 - posy=1 v=2003 -447.963623 + posx=1 v=2003 -983.559143 + posy=1 v=2003 178.703445 group=-1 ISC=0 OSC=1 @@ -1134,6 +1139,109 @@ NumberOfNodes=74 CPC=0 C=73 0 1 60 1 2 0 CPC=0 +#NT=20187 0 + PC=2 + posx=1 v=2003 605.417053 + posy=1 v=2003 260.416748 + group=-1 + ISC=2 + SVT=5022 2003 1 0 0 + SVT=5022 2003 2 0 0 + OSC=1 + SVT=5022 2003 3 + CC=1 + C=74 0 3 79 3 4 0 + CPC=0 +#NT=20187 0 + PC=2 + posx=1 v=2003 407.916718 + posy=1 v=2003 221.666885 + group=-1 + ISC=2 + SVT=5022 2003 1 0 0 + SVT=5022 2003 2 0 0 + OSC=1 + SVT=5022 2003 3 + CC=1 + C=75 0 3 74 0 1 0 + CPC=0 +#NT=20186 0 + PC=2 + posx=1 v=2003 230.416794 + posy=1 v=2003 156.667099 + group=-1 + ISC=2 + SVT=5022 2003 1 0 1 + SCS=r + SVT=5022 2003 2 1 0 + SDV=0.298900 + OSC=1 + SVT=5022 2003 3 + CC=1 + C=76 0 3 75 0 1 0 + CPC=0 +#NT=20186 0 + PC=2 + posx=1 v=2003 226.666870 + posy=1 v=2003 301.666748 + group=-1 + ISC=2 + SVT=5022 2003 1 0 1 + SCS=g + SVT=5022 2003 2 1 0 + SDV=0.587000 + OSC=1 + SVT=5022 2003 3 + CC=1 + C=77 0 3 75 1 2 0 + CPC=0 +#NT=20186 0 + PC=2 + posx=1 v=2003 227.916870 + posy=1 v=2003 459.167023 + group=-1 + ISC=2 + SVT=5022 2003 1 0 1 + SCS=b + SVT=5022 2003 2 1 0 + SDV=0.114000 + OSC=1 + SVT=5022 2003 3 + CC=1 + C=78 0 3 74 1 2 0 + CPC=0 +#NT=20189 0 + PC=2 + posx=1 v=2003 807.916992 + posy=1 v=2003 107.917221 + group=-1 + ISC=4 + SVT=5022 2003 1 0 0 + SVT=5022 2003 2 1 0 + SDV=1.000000 + SVT=5022 2003 3 0 1 + SCS=a + SVT=5022 2003 4 0 0 + OSC=1 + SVT=5022 2003 5 + CC=1 + C=79 0 5 9 2 3 0 + CPC=0 +#NT=20185 0 + PC=6 + name=1 v=5000 opacity_map_uses_alpha_channel + posx=1 v=2003 527.916992 + posy=1 v=2003 57.916878 + type=2 e=0 v=5012 0 + uitype=2 e=0 v=5012 1 + uiorder=2 e=0 v=2002 12 + group=-1 + ISC=0 + OSC=1 + SVT=5022 2003 1 + CC=1 + C=80 0 1 79 0 1 0 + CPC=0 */ } connections = [ @@ -1143,13 +1251,13 @@ connections = [ instance_id = "abbaabba-abba-abba-abba-abbaabbaabb9" } source = { - instance_id = "abbaabba-abba-abba-abba-abbaabbaab44" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab42" } } { destination = { connector_id = "c5823c75-4ae5-4c71-b070-315fa4d03e8e" - instance_id = "abbaabba-abba-abba-abba-abbaabbaab44" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab42" } source = { instance_id = "abbaabba-abba-abba-abba-abbaabbaab28" @@ -1191,46 +1299,46 @@ connections = [ instance_id = "abbaabba-abba-abba-abba-abbaabbaab11" } source = { - instance_id = "abbaabba-abba-abba-abba-abbaabbaab46" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab44" } } { destination = { connector_id = "f72597c4-7487-419a-affb-df690e6582e1" - instance_id = "abbaabba-abba-abba-abba-abbaabbaab46" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab44" } select = [ "xy" ] source = { - instance_id = "abbaabba-abba-abba-abba-abbaabbaab66" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab64" } } { destination = { connector_id = "0806db0d-2c4a-43ca-99cc-f5a2f036a8e8" - instance_id = "abbaabba-abba-abba-abba-abbaabbaab46" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab44" } source = { - instance_id = "abbaabba-abba-abba-abba-abbaabbaab45" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab43" } } { destination = { connector_id = "c5823c75-4ae5-4c71-b070-315fa4d03e8e" - instance_id = "abbaabba-abba-abba-abba-abbaabbaab45" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab43" } select = [ "xy" ] source = { - instance_id = "abbaabba-abba-abba-abba-abbaabbaab47" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab45" } } { destination = { connector_id = "242d1648-a626-445b-9534-bccec094112f" - instance_id = "abbaabba-abba-abba-abba-abbaabbaab45" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab43" } source = { instance_id = "abbaabba-abba-abba-abba-abbaabbaabb1" @@ -1257,91 +1365,91 @@ connections = [ { destination = { connector_id = "242d1648-a626-445b-9534-bccec094112f" - instance_id = "abbaabba-abba-abba-abba-abbaabbaab44" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab42" } source = { - instance_id = "abbaabba-abba-abba-abba-abbaabbaab40" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab38" } } { destination = { connector_id = "CED7BBF3-0B48-4335-B933-095A41CA0294" - instance_id = "abbaabba-abba-abba-abba-abbaabbaab40" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab38" } source = { - instance_id = "abbaabba-abba-abba-abba-abbaabbaab42" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab40" } } { destination = { connector_id = "4CBB4480-79E8-4CE7-AC0F-8B09BAF12390" - instance_id = "abbaabba-abba-abba-abba-abbaabbaab40" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab38" } select = [ "rgb" ] source = { - instance_id = "abbaabba-abba-abba-abba-abbaabbaab41" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab39" } } { destination = { connector_id = "1ee9af1f-65f2-4739-ad28-5ea6a0e68fc3" - instance_id = "abbaabba-abba-abba-abba-abbaabbaab41" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab39" } source = { - instance_id = "abbaabba-abba-abba-abba-abbaabbaab49" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab47" } } { destination = { connector_id = "f72597c4-7487-419a-affb-df690e6582e1" - instance_id = "abbaabba-abba-abba-abba-abbaabbaab49" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab47" } select = [ "xy" ] source = { - instance_id = "abbaabba-abba-abba-abba-abbaabbaab67" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab65" } } { destination = { connector_id = "0806db0d-2c4a-43ca-99cc-f5a2f036a8e8" - instance_id = "abbaabba-abba-abba-abba-abbaabbaab49" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab47" } source = { - instance_id = "abbaabba-abba-abba-abba-abbaabbaab48" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab46" } } { destination = { connector_id = "c5823c75-4ae5-4c71-b070-315fa4d03e8e" - instance_id = "abbaabba-abba-abba-abba-abbaabbaab48" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab46" } select = [ "xy" ] source = { - instance_id = "abbaabba-abba-abba-abba-abbaabbaab50" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab48" } } { destination = { connector_id = "242d1648-a626-445b-9534-bccec094112f" - instance_id = "abbaabba-abba-abba-abba-abbaabbaab48" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab46" } source = { - instance_id = "abbaabba-abba-abba-abba-abbaabbaab73" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab71" } } { destination = { connector_id = "F2F74E58-402D-472B-87DD-331E00DB416C" - instance_id = "abbaabba-abba-abba-abba-abbaabbaab40" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab38" } source = { - instance_id = "abbaabba-abba-abba-abba-abbaabbaab43" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab41" } } { @@ -1376,6 +1484,60 @@ connections = [ connector_id = "4CBB4480-79E8-4CE7-AC0F-8B09BAF12390" instance_id = "abbaabba-abba-abba-abba-abbaabbaab10" } + source = { + instance_id = "abbaabba-abba-abba-abba-abbaabbaab80" + } + } + { + destination = { + connector_id = "CED7BBF3-0B48-4335-B933-095A41CA0294" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab80" + } + source = { + instance_id = "abbaabba-abba-abba-abba-abbaabbaab81" + } + } + { + destination = { + connector_id = "c5823c75-4ae5-4c71-b070-315fa4d03e8e" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab77" + } + select = [ + "r" + ] + source = { + instance_id = "abbaabba-abba-abba-abba-abbaabbaab30" + } + } + { + destination = { + connector_id = "c5823c75-4ae5-4c71-b070-315fa4d03e8e" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab78" + } + select = [ + "g" + ] + source = { + instance_id = "abbaabba-abba-abba-abba-abbaabbaab30" + } + } + { + destination = { + connector_id = "c5823c75-4ae5-4c71-b070-315fa4d03e8e" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab79" + } + select = [ + "b" + ] + source = { + instance_id = "abbaabba-abba-abba-abba-abbaabbaab30" + } + } + { + destination = { + connector_id = "4CBB4480-79E8-4CE7-AC0F-8B09BAF12390" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab80" + } select = [ "a" ] @@ -1389,51 +1551,96 @@ connections = [ instance_id = "abbaabba-abba-abba-abba-abbaabbaab30" } source = { - instance_id = "abbaabba-abba-abba-abba-abbaabbaab52" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab50" } } { destination = { connector_id = "f72597c4-7487-419a-affb-df690e6582e1" - instance_id = "abbaabba-abba-abba-abba-abbaabbaab52" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab50" } select = [ "xy" ] source = { - instance_id = "abbaabba-abba-abba-abba-abbaabbaab68" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab66" } } { destination = { connector_id = "0806db0d-2c4a-43ca-99cc-f5a2f036a8e8" - instance_id = "abbaabba-abba-abba-abba-abbaabbaab52" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab50" } source = { - instance_id = "abbaabba-abba-abba-abba-abbaabbaab51" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab49" } } { destination = { connector_id = "c5823c75-4ae5-4c71-b070-315fa4d03e8e" - instance_id = "abbaabba-abba-abba-abba-abbaabbaab51" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab49" } select = [ "xy" ] source = { - instance_id = "abbaabba-abba-abba-abba-abbaabbaab53" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab51" } } { destination = { connector_id = "242d1648-a626-445b-9534-bccec094112f" - instance_id = "abbaabba-abba-abba-abba-abbaabbaab51" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab49" + } + source = { + instance_id = "abbaabba-abba-abba-abba-abbaabbaab73" + } + } + { + destination = { + connector_id = "F2F74E58-402D-472B-87DD-331E00DB416C" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab80" } source = { instance_id = "abbaabba-abba-abba-abba-abbaabbaab75" } } + { + destination = { + connector_id = "f72597c4-7487-419a-affb-df690e6582e1" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab75" + } + source = { + instance_id = "abbaabba-abba-abba-abba-abbaabbaab76" + } + } + { + destination = { + connector_id = "f72597c4-7487-419a-affb-df690e6582e1" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab76" + } + source = { + instance_id = "abbaabba-abba-abba-abba-abbaabbaab77" + } + } + { + destination = { + connector_id = "0806db0d-2c4a-43ca-99cc-f5a2f036a8e8" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab76" + } + source = { + instance_id = "abbaabba-abba-abba-abba-abbaabbaab78" + } + } + { + destination = { + connector_id = "0806db0d-2c4a-43ca-99cc-f5a2f036a8e8" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab75" + } + source = { + instance_id = "abbaabba-abba-abba-abba-abbaabbaab79" + } + } { destination = { connector_id = "F2F74E58-402D-472B-87DD-331E00DB416C" @@ -1497,49 +1704,49 @@ connections = [ instance_id = "abbaabba-abba-abba-abba-abbaabbaab12" } source = { - instance_id = "abbaabba-abba-abba-abba-abbaabbaab55" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab53" } } { destination = { connector_id = "f72597c4-7487-419a-affb-df690e6582e1" - instance_id = "abbaabba-abba-abba-abba-abbaabbaab55" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab53" } select = [ "xy" ] source = { - instance_id = "abbaabba-abba-abba-abba-abbaabbaab69" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab67" } } { destination = { connector_id = "0806db0d-2c4a-43ca-99cc-f5a2f036a8e8" - instance_id = "abbaabba-abba-abba-abba-abbaabbaab55" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab53" } source = { - instance_id = "abbaabba-abba-abba-abba-abbaabbaab54" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab52" } } { destination = { connector_id = "c5823c75-4ae5-4c71-b070-315fa4d03e8e" - instance_id = "abbaabba-abba-abba-abba-abbaabbaab54" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab52" } select = [ "xy" ] source = { - instance_id = "abbaabba-abba-abba-abba-abbaabbaab56" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab54" } } { destination = { connector_id = "242d1648-a626-445b-9534-bccec094112f" - instance_id = "abbaabba-abba-abba-abba-abbaabbaab54" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab52" } source = { - instance_id = "abbaabba-abba-abba-abba-abbaabbaab74" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab72" } } { @@ -1557,13 +1764,13 @@ connections = [ instance_id = "abbaabba-abba-abba-abba-abbaabbaabb9" } source = { - instance_id = "abbaabba-abba-abba-abba-abbaabbaab35" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab33" } } { destination = { connector_id = "c5823c75-4ae5-4c71-b070-315fa4d03e8e" - instance_id = "abbaabba-abba-abba-abba-abbaabbaab35" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab33" } source = { instance_id = "abbaabba-abba-abba-abba-abbaabbaabb4" @@ -1596,67 +1803,67 @@ connections = [ instance_id = "abbaabba-abba-abba-abba-abbaabbaab13" } source = { - instance_id = "abbaabba-abba-abba-abba-abbaabbaab58" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab56" } } { destination = { connector_id = "f72597c4-7487-419a-affb-df690e6582e1" - instance_id = "abbaabba-abba-abba-abba-abbaabbaab58" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab56" } select = [ "xy" ] source = { - instance_id = "abbaabba-abba-abba-abba-abbaabbaab70" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab68" } } { destination = { connector_id = "0806db0d-2c4a-43ca-99cc-f5a2f036a8e8" - instance_id = "abbaabba-abba-abba-abba-abbaabbaab58" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab56" } source = { - instance_id = "abbaabba-abba-abba-abba-abbaabbaab57" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab55" } } { destination = { connector_id = "c5823c75-4ae5-4c71-b070-315fa4d03e8e" - instance_id = "abbaabba-abba-abba-abba-abbaabbaab57" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab55" } select = [ "xy" ] source = { - instance_id = "abbaabba-abba-abba-abba-abbaabbaab59" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab57" } } { destination = { connector_id = "242d1648-a626-445b-9534-bccec094112f" - instance_id = "abbaabba-abba-abba-abba-abbaabbaab57" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab55" } source = { - instance_id = "abbaabba-abba-abba-abba-abbaabbaab76" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab74" } } { destination = { connector_id = "242d1648-a626-445b-9534-bccec094112f" - instance_id = "abbaabba-abba-abba-abba-abbaabbaab60" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab58" } source = { - instance_id = "abbaabba-abba-abba-abba-abbaabbaab76" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab74" } } { destination = { connector_id = "242d1648-a626-445b-9534-bccec094112f" - instance_id = "abbaabba-abba-abba-abba-abbaabbaab63" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab61" } source = { - instance_id = "abbaabba-abba-abba-abba-abbaabbaab76" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab74" } } { @@ -1665,13 +1872,13 @@ connections = [ instance_id = "abbaabba-abba-abba-abba-abbaabbaabb4" } source = { - instance_id = "abbaabba-abba-abba-abba-abbaabbaab36" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab34" } } { destination = { connector_id = "242d1648-a626-445b-9534-bccec094112f" - instance_id = "abbaabba-abba-abba-abba-abbaabbaab35" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab33" } source = { instance_id = "abbaabba-abba-abba-abba-abbaabbaab23" @@ -1683,13 +1890,13 @@ connections = [ instance_id = "abbaabba-abba-abba-abba-abbaabbaabb9" } source = { - instance_id = "abbaabba-abba-abba-abba-abbaabbaab38" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab36" } } { destination = { connector_id = "c5823c75-4ae5-4c71-b070-315fa4d03e8e" - instance_id = "abbaabba-abba-abba-abba-abbaabbaab38" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab36" } source = { instance_id = "abbaabba-abba-abba-abba-abbaabbaabb2" @@ -1722,40 +1929,40 @@ connections = [ instance_id = "abbaabba-abba-abba-abba-abbaabbaab14" } source = { - instance_id = "abbaabba-abba-abba-abba-abbaabbaab61" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab59" } } { destination = { connector_id = "f72597c4-7487-419a-affb-df690e6582e1" - instance_id = "abbaabba-abba-abba-abba-abbaabbaab61" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab59" } select = [ "xy" ] source = { - instance_id = "abbaabba-abba-abba-abba-abbaabbaab71" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab69" } } { destination = { connector_id = "0806db0d-2c4a-43ca-99cc-f5a2f036a8e8" - instance_id = "abbaabba-abba-abba-abba-abbaabbaab61" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab59" } source = { - instance_id = "abbaabba-abba-abba-abba-abbaabbaab60" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab58" } } { destination = { connector_id = "c5823c75-4ae5-4c71-b070-315fa4d03e8e" - instance_id = "abbaabba-abba-abba-abba-abbaabbaab60" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab58" } select = [ "xy" ] source = { - instance_id = "abbaabba-abba-abba-abba-abbaabbaab62" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab60" } } { @@ -1764,13 +1971,13 @@ connections = [ instance_id = "abbaabba-abba-abba-abba-abbaabbaabb2" } source = { - instance_id = "abbaabba-abba-abba-abba-abbaabbaab37" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab35" } } { destination = { connector_id = "242d1648-a626-445b-9534-bccec094112f" - instance_id = "abbaabba-abba-abba-abba-abbaabbaab38" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab36" } source = { instance_id = "abbaabba-abba-abba-abba-abbaabbaab25" @@ -1821,40 +2028,40 @@ connections = [ instance_id = "abbaabba-abba-abba-abba-abbaabbaab15" } source = { - instance_id = "abbaabba-abba-abba-abba-abbaabbaab64" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab62" } } { destination = { connector_id = "f72597c4-7487-419a-affb-df690e6582e1" - instance_id = "abbaabba-abba-abba-abba-abbaabbaab64" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab62" } select = [ "xy" ] source = { - instance_id = "abbaabba-abba-abba-abba-abbaabbaab72" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab70" } } { destination = { connector_id = "0806db0d-2c4a-43ca-99cc-f5a2f036a8e8" - instance_id = "abbaabba-abba-abba-abba-abbaabbaab64" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab62" } source = { - instance_id = "abbaabba-abba-abba-abba-abbaabbaab63" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab61" } } { destination = { connector_id = "c5823c75-4ae5-4c71-b070-315fa4d03e8e" - instance_id = "abbaabba-abba-abba-abba-abbaabbaab63" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab61" } select = [ "xy" ] source = { - instance_id = "abbaabba-abba-abba-abba-abbaabbaab65" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab63" } } { @@ -1863,7 +2070,7 @@ connections = [ instance_id = "abbaabba-abba-abba-abba-abbaabbaabb5" } source = { - instance_id = "abbaabba-abba-abba-abba-abbaabbaab39" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab37" } } { @@ -1895,16 +2102,16 @@ constants = [ } { connector_id = "39BC7619-2768-480B-ACFD-63FA66EF6905" - id = "1bbaabba-abba-abba-abba-abbaabbaab40" - instance_id = "abbaabba-abba-abba-abba-abbaabbaab40" + id = "1bbaabba-abba-abba-abba-abbaabbaab38" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab38" value = [ 1.000000 ] } { connector_id = "6ff26be7-68a1-4b89-b9dd-551d216086c2" - id = "0bbaabba-abba-abba-abba-abbaabbaab43" - instance_id = "abbaabba-abba-abba-abba-abbaabbaab43" + id = "0bbaabba-abba-abba-abba-abbaabbaab41" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab41" value = [ 1.000000 1.000000 1.000000 ] @@ -1917,6 +2124,38 @@ constants = [ 1.000000 ] } + { + connector_id = "39BC7619-2768-480B-ACFD-63FA66EF6905" + id = "1bbaabba-abba-abba-abba-abbaabbaab80" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab80" + value = [ + 1.000000 + ] + } + { + connector_id = "242d1648-a626-445b-9534-bccec094112f" + id = "1bbaabba-abba-abba-abba-abbaabbaab77" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab77" + value = [ + 0.298900 + ] + } + { + connector_id = "242d1648-a626-445b-9534-bccec094112f" + id = "1bbaabba-abba-abba-abba-abbaabbaab78" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab78" + value = [ + 0.587000 + ] + } + { + connector_id = "242d1648-a626-445b-9534-bccec094112f" + id = "1bbaabba-abba-abba-abba-abbaabbaab79" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab79" + value = [ + 0.114000 + ] + } { connector_id = "c4d6bc08-c489-430f-a836-ed490e59c3f9" id = "0bbaabba-abba-abba-abba-abbaabbaab32" @@ -1943,8 +2182,8 @@ constants = [ } { connector_id = "c4d6bc08-c489-430f-a836-ed490e59c3f9" - id = "0bbaabba-abba-abba-abba-abbaabbaab36" - instance_id = "abbaabba-abba-abba-abba-abbaabbaab36" + id = "0bbaabba-abba-abba-abba-abbaabbaab34" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab34" value = [ 1.000000 ] @@ -1959,8 +2198,8 @@ constants = [ } { connector_id = "c4d6bc08-c489-430f-a836-ed490e59c3f9" - id = "0bbaabba-abba-abba-abba-abbaabbaab37" - instance_id = "abbaabba-abba-abba-abba-abbaabbaab37" + id = "0bbaabba-abba-abba-abba-abbaabbaab35" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab35" value = [ 1.000000 ] @@ -1975,8 +2214,8 @@ constants = [ } { connector_id = "6ff26be7-68a1-4b89-b9dd-551d216086c2" - id = "0bbaabba-abba-abba-abba-abbaabbaab39" - instance_id = "abbaabba-abba-abba-abba-abbaabbaab39" + id = "0bbaabba-abba-abba-abba-abbaabbaab37" + instance_id = "abbaabba-abba-abba-abba-abbaabbaab37" value = [ 1.000000 1.000000 1.000000 ] @@ -1992,6 +2231,7 @@ nodes = [ } id = "abbaabba-abba-abba-abba-abbaabbaabb9" options = [ + "3b55d6c6-4398-4dbc-b9ef-570aff8696ae" "2b136447-676e-4943-997b-04a28ae68497" ] position = [ @@ -2010,12 +2250,12 @@ nodes = [ ] export = { } - id = "abbaabba-abba-abba-abba-abbaabbaab44" + id = "abbaabba-abba-abba-abba-abbaabbaab42" options = [ ] position = [ - 1409 - -837 + 875 + -210 ] samplers = { } @@ -2033,8 +2273,8 @@ nodes = [ options = [ ] position = [ - 1215 - -989 + 682 + -362 ] samplers = { } @@ -2053,8 +2293,8 @@ nodes = [ "9A84282B-F1A2-46D4-9FC4-5A76FC9B30DD" ] position = [ - 959 - -1218 + 426 + -592 ] samplers = { } @@ -2078,15 +2318,15 @@ nodes = [ ui_type = "checkbox" } type = "float" - value = 1.000000 + value = 0.000000 } } id = "abbaabba-abba-abba-abba-abbaabbaab17" options = [ ] position = [ - 542 - -1214 + 9 + -588 ] samplers = { } @@ -2107,8 +2347,8 @@ nodes = [ "5dd59b3d-1762-4a14-9930-7500230ef3db" ] position = [ - 543 - -1111 + 10 + -485 ] samplers = { texture_map = { @@ -2129,12 +2369,12 @@ nodes = [ ] export = { } - id = "abbaabba-abba-abba-abba-abbaabbaab46" + id = "abbaabba-abba-abba-abba-abbaabbaab44" options = [ ] position = [ - 292 - -1199 + -241 + -572 ] samplers = { } @@ -2160,12 +2400,12 @@ nodes = [ value = [0.000000 0.000000] } } - id = "abbaabba-abba-abba-abba-abbaabbaab66" + id = "abbaabba-abba-abba-abba-abbaabbaab64" options = [ ] position = [ - -68 - -1279 + -601 + -652 ] samplers = { } @@ -2179,12 +2419,12 @@ nodes = [ ] export = { } - id = "abbaabba-abba-abba-abba-abbaabbaab45" + id = "abbaabba-abba-abba-abba-abbaabbaab43" options = [ ] position = [ - 129 - -1105 + -403 + -478 ] samplers = { } @@ -2211,12 +2451,12 @@ nodes = [ value = [1.000000 1.000000 0.000000] } } - id = "abbaabba-abba-abba-abba-abbaabbaab47" + id = "abbaabba-abba-abba-abba-abbaabbaab45" options = [ ] position = [ - -65 - -1162 + -599 + -535 ] samplers = { } @@ -2234,8 +2474,8 @@ nodes = [ options = [ ] position = [ - -438 - -1197 + -972 + -571 ] samplers = { } @@ -2253,8 +2493,8 @@ nodes = [ options = [ ] position = [ - 780 - -1055 + 246 + -428 ] samplers = { } @@ -2278,15 +2518,15 @@ nodes = [ ui_type = "color" } type = "float3" - value = [0.988235 0.937255 0.886275] + value = [1.000000 1.000000 1.000000] } } id = "abbaabba-abba-abba-abba-abbaabbaab18" options = [ ] position = [ - 542 - -977 + 8 + -350 ] samplers = { } @@ -2300,13 +2540,13 @@ nodes = [ ] export = { } - id = "abbaabba-abba-abba-abba-abbaabbaab40" + id = "abbaabba-abba-abba-abba-abbaabbaab38" options = [ "9A84282B-F1A2-46D4-9FC4-5A76FC9B30DD" ] position = [ - 941 - -830 + 407 + -204 ] samplers = { } @@ -2330,15 +2570,15 @@ nodes = [ ui_type = "checkbox" } type = "float" - value = 1.000000 + value = 0.000000 } } - id = "abbaabba-abba-abba-abba-abbaabbaab42" + id = "abbaabba-abba-abba-abba-abbaabbaab40" options = [ ] position = [ - 544 - -833 + 11 + -206 ] samplers = { } @@ -2352,15 +2592,15 @@ nodes = [ ] export = { } - id = "abbaabba-abba-abba-abba-abbaabbaab41" + id = "abbaabba-abba-abba-abba-abbaabbaab39" options = [ "1e067464-12d8-4826-9b72-cfd5765003e3" "fb3f709b-a54a-4e93-ac9f-e9fc76fb8bcd" "5dd59b3d-1762-4a14-9930-7500230ef3db" ] position = [ - 544 - -723 + 11 + -97 ] samplers = { texture_map = { @@ -2381,12 +2621,12 @@ nodes = [ ] export = { } - id = "abbaabba-abba-abba-abba-abbaabbaab49" + id = "abbaabba-abba-abba-abba-abbaabbaab47" options = [ ] position = [ - 263 - -792 + -269 + -166 ] samplers = { } @@ -2412,12 +2652,12 @@ nodes = [ value = [0.000000 0.000000] } } - id = "abbaabba-abba-abba-abba-abbaabbaab67" + id = "abbaabba-abba-abba-abba-abbaabbaab65" options = [ ] position = [ - -67 - -922 + -601 + -296 ] samplers = { } @@ -2431,12 +2671,12 @@ nodes = [ ] export = { } - id = "abbaabba-abba-abba-abba-abbaabbaab48" + id = "abbaabba-abba-abba-abba-abbaabbaab46" options = [ ] position = [ - 97 - -702 + -436 + -75 ] samplers = { } @@ -2463,12 +2703,12 @@ nodes = [ value = [1.000000 1.000000 0.000000] } } - id = "abbaabba-abba-abba-abba-abbaabbaab50" + id = "abbaabba-abba-abba-abba-abbaabbaab48" options = [ ] position = [ - -68 - -818 + -601 + -191 ] samplers = { } @@ -2482,12 +2722,12 @@ nodes = [ ] export = { } - id = "abbaabba-abba-abba-abba-abbaabbaab73" + id = "abbaabba-abba-abba-abba-abbaabbaab71" options = [ ] position = [ - -451 - -924 + -984 + -297 ] samplers = { } @@ -2501,12 +2741,12 @@ nodes = [ ] export = { } - id = "abbaabba-abba-abba-abba-abbaabbaab43" + id = "abbaabba-abba-abba-abba-abbaabbaab41" options = [ ] position = [ - 776 - -638 + 242 + -12 ] samplers = { } @@ -2524,8 +2764,8 @@ nodes = [ options = [ ] position = [ - 1279 - -222 + 1328 + 198 ] samplers = { } @@ -2544,8 +2784,8 @@ nodes = [ "9A84282B-F1A2-46D4-9FC4-5A76FC9B30DD" ] position = [ - 1106 - -449 + 1113 + 100 ] samplers = { } @@ -2576,14 +2816,66 @@ nodes = [ options = [ ] position = [ - 574 - -488 + 910 + 7 ] samplers = { } title = "Use Opacity Map" type = "core/shader_nodes/material_variable" } + { + content_size = [ + 160 + 0 + ] + export = { + } + id = "abbaabba-abba-abba-abba-abbaabbaab80" + options = [ + "9A84282B-F1A2-46D4-9FC4-5A76FC9B30DD" + ] + position = [ + 807 + 107 + ] + samplers = { + } + title = "If Statement" + type = "core/shader_nodes/if" + } + { + content_size = [ + 160 + 0 + ] + export = { + material_variable = { + display_name = "Opacity Map Uses Alpha Channel" + name = "opacity_map_uses_alpha_channel" + ui = { + max = 1 + min = 0.000000 + step = 1 + order = 12 + ui_type = "checkbox" + } + type = "float" + value = 0.000000 + } + } + id = "abbaabba-abba-abba-abba-abbaabbaab81" + options = [ + ] + position = [ + 527 + 57 + ] + samplers = { + } + title = "Opacity Map Uses Alpha Channel" + type = "core/shader_nodes/material_variable" + } { content_size = [ 160 @@ -2598,8 +2890,8 @@ nodes = [ "5dd59b3d-1762-4a14-9930-7500230ef3db" ] position = [ - 577 - -377 + -5 + 89 ] samplers = { texture_map = { @@ -2620,12 +2912,12 @@ nodes = [ ] export = { } - id = "abbaabba-abba-abba-abba-abbaabbaab52" + id = "abbaabba-abba-abba-abba-abbaabbaab50" options = [ ] position = [ - 262 - -462 + -270 + 164 ] samplers = { } @@ -2651,12 +2943,12 @@ nodes = [ value = [0.000000 0.000000] } } - id = "abbaabba-abba-abba-abba-abbaabbaab68" + id = "abbaabba-abba-abba-abba-abbaabbaab66" options = [ ] position = [ - -64 - -595 + -597 + 30 ] samplers = { } @@ -2670,12 +2962,12 @@ nodes = [ ] export = { } - id = "abbaabba-abba-abba-abba-abbaabbaab51" + id = "abbaabba-abba-abba-abba-abbaabbaab49" options = [ ] position = [ - 105 - -362 + -427 + 264 ] samplers = { } @@ -2702,12 +2994,12 @@ nodes = [ value = [1.000000 1.000000 0.000000] } } - id = "abbaabba-abba-abba-abba-abbaabbaab53" + id = "abbaabba-abba-abba-abba-abbaabbaab51" options = [ ] position = [ - -68 - -486 + -602 + 139 ] samplers = { } @@ -2721,18 +3013,113 @@ nodes = [ ] export = { } - id = "abbaabba-abba-abba-abba-abbaabbaab75" + id = "abbaabba-abba-abba-abba-abbaabbaab73" options = [ ] position = [ - -450 - -447 + -983 + 178 ] samplers = { } title = "Texcoord3" type = "core/shader_nodes/texture_coordinate3" } + { + content_size = [ + 160 + 0 + ] + export = { + } + id = "abbaabba-abba-abba-abba-abbaabbaab75" + options = [ + ] + position = [ + 605 + 260 + ] + samplers = { + } + title = "Add" + type = "core/shader_nodes/add" + } + { + content_size = [ + 160 + 0 + ] + export = { + } + id = "abbaabba-abba-abba-abba-abbaabbaab76" + options = [ + ] + position = [ + 407 + 221 + ] + samplers = { + } + title = "Add" + type = "core/shader_nodes/add" + } + { + content_size = [ + 160 + 0 + ] + export = { + } + id = "abbaabba-abba-abba-abba-abbaabbaab77" + options = [ + ] + position = [ + 230 + 156 + ] + samplers = { + } + title = "Multiply" + type = "core/shader_nodes/mul" + } + { + content_size = [ + 160 + 0 + ] + export = { + } + id = "abbaabba-abba-abba-abba-abbaabbaab78" + options = [ + ] + position = [ + 226 + 301 + ] + samplers = { + } + title = "Multiply" + type = "core/shader_nodes/mul" + } + { + content_size = [ + 160 + 0 + ] + export = { + } + id = "abbaabba-abba-abba-abba-abbaabbaab79" + options = [ + ] + position = [ + 227 + 459 + ] + samplers = { + } + title = "Multiply" + type = "core/shader_nodes/mul" + } { content_size = [ 160 @@ -2744,8 +3131,8 @@ nodes = [ options = [ ] position = [ - 853 - -205 + 841 + 319 ] samplers = { } @@ -2775,8 +3162,8 @@ nodes = [ options = [ ] position = [ - 577 - -125 + 1102 + 388 ] samplers = { } @@ -2795,8 +3182,8 @@ nodes = [ "9A84282B-F1A2-46D4-9FC4-5A76FC9B30DD" ] position = [ - 1172 - 150 + 648 + 706 ] samplers = { } @@ -2827,8 +3214,8 @@ nodes = [ options = [ ] position = [ - 573 - 44 + 50 + 600 ] samplers = { } @@ -2847,8 +3234,8 @@ nodes = [ "0a0fb5ad-145d-4229-abd4-5b36562607b3" ] position = [ - 850 - 202 + 327 + 759 ] samplers = { } @@ -2869,8 +3256,8 @@ nodes = [ "5dd59b3d-1762-4a14-9930-7500230ef3db" ] position = [ - 573 - 154 + 50 + 711 ] samplers = { texture_map = { @@ -2891,12 +3278,12 @@ nodes = [ ] export = { } - id = "abbaabba-abba-abba-abba-abbaabbaab55" + id = "abbaabba-abba-abba-abba-abbaabbaab53" options = [ ] position = [ - 289 - 79 + -233 + 636 ] samplers = { } @@ -2922,12 +3309,12 @@ nodes = [ value = [0.000000 0.000000] } } - id = "abbaabba-abba-abba-abba-abbaabbaab69" + id = "abbaabba-abba-abba-abba-abbaabbaab67" options = [ ] position = [ - -40 - -63 + -564 + 492 ] samplers = { } @@ -2941,12 +3328,12 @@ nodes = [ ] export = { } - id = "abbaabba-abba-abba-abba-abbaabbaab54" + id = "abbaabba-abba-abba-abba-abbaabbaab52" options = [ ] position = [ - 125 - 166 + -397 + 722 ] samplers = { } @@ -2973,12 +3360,12 @@ nodes = [ value = [1.000000 1.000000 0.000000] } } - id = "abbaabba-abba-abba-abba-abbaabbaab56" + id = "abbaabba-abba-abba-abba-abbaabbaab54" options = [ ] position = [ - -41 - 55 + -565 + 611 ] samplers = { } @@ -2992,12 +3379,12 @@ nodes = [ ] export = { } - id = "abbaabba-abba-abba-abba-abbaabbaab74" + id = "abbaabba-abba-abba-abba-abbaabbaab72" options = [ ] position = [ - -432 - -47 + -955 + 509 ] samplers = { } @@ -3015,8 +3402,8 @@ nodes = [ options = [ ] position = [ - 854 - 321 + 331 + 878 ] samplers = { } @@ -3030,7 +3417,7 @@ nodes = [ ] export = { } - id = "abbaabba-abba-abba-abba-abbaabbaab35" + id = "abbaabba-abba-abba-abba-abbaabbaab33" options = [ ] position = [ @@ -3130,7 +3517,7 @@ nodes = [ ] export = { } - id = "abbaabba-abba-abba-abba-abbaabbaab58" + id = "abbaabba-abba-abba-abba-abbaabbaab56" options = [ ] position = [ @@ -3161,7 +3548,7 @@ nodes = [ value = [0.000000 0.000000] } } - id = "abbaabba-abba-abba-abba-abbaabbaab70" + id = "abbaabba-abba-abba-abba-abbaabbaab68" options = [ ] position = [ @@ -3180,7 +3567,7 @@ nodes = [ ] export = { } - id = "abbaabba-abba-abba-abba-abbaabbaab57" + id = "abbaabba-abba-abba-abba-abbaabbaab55" options = [ ] position = [ @@ -3212,7 +3599,7 @@ nodes = [ value = [1.000000 1.000000 0.000000] } } - id = "abbaabba-abba-abba-abba-abbaabbaab59" + id = "abbaabba-abba-abba-abba-abbaabbaab57" options = [ ] position = [ @@ -3231,7 +3618,7 @@ nodes = [ ] export = { } - id = "abbaabba-abba-abba-abba-abbaabbaab76" + id = "abbaabba-abba-abba-abba-abbaabbaab74" options = [ ] position = [ @@ -3250,7 +3637,7 @@ nodes = [ ] export = { } - id = "abbaabba-abba-abba-abba-abbaabbaab36" + id = "abbaabba-abba-abba-abba-abbaabbaab34" options = [ ] position = [ @@ -3300,7 +3687,7 @@ nodes = [ ] export = { } - id = "abbaabba-abba-abba-abba-abbaabbaab38" + id = "abbaabba-abba-abba-abba-abbaabbaab36" options = [ ] position = [ @@ -3400,7 +3787,7 @@ nodes = [ ] export = { } - id = "abbaabba-abba-abba-abba-abbaabbaab61" + id = "abbaabba-abba-abba-abba-abbaabbaab59" options = [ ] position = [ @@ -3431,7 +3818,7 @@ nodes = [ value = [0.000000 0.000000] } } - id = "abbaabba-abba-abba-abba-abbaabbaab71" + id = "abbaabba-abba-abba-abba-abbaabbaab69" options = [ ] position = [ @@ -3450,7 +3837,7 @@ nodes = [ ] export = { } - id = "abbaabba-abba-abba-abba-abbaabbaab60" + id = "abbaabba-abba-abba-abba-abbaabbaab58" options = [ ] position = [ @@ -3482,7 +3869,7 @@ nodes = [ value = [1.000000 1.000000 0.000000] } } - id = "abbaabba-abba-abba-abba-abbaabbaab62" + id = "abbaabba-abba-abba-abba-abbaabbaab60" options = [ ] position = [ @@ -3501,7 +3888,7 @@ nodes = [ ] export = { } - id = "abbaabba-abba-abba-abba-abbaabbaab37" + id = "abbaabba-abba-abba-abba-abbaabbaab35" options = [ ] position = [ @@ -3651,7 +4038,7 @@ nodes = [ ] export = { } - id = "abbaabba-abba-abba-abba-abbaabbaab64" + id = "abbaabba-abba-abba-abba-abbaabbaab62" options = [ ] position = [ @@ -3682,7 +4069,7 @@ nodes = [ value = [0.000000 0.000000] } } - id = "abbaabba-abba-abba-abba-abbaabbaab72" + id = "abbaabba-abba-abba-abba-abbaabbaab70" options = [ ] position = [ @@ -3701,7 +4088,7 @@ nodes = [ ] export = { } - id = "abbaabba-abba-abba-abba-abbaabbaab63" + id = "abbaabba-abba-abba-abba-abbaabbaab61" options = [ ] position = [ @@ -3733,7 +4120,7 @@ nodes = [ value = [1.000000 1.000000 0.000000] } } - id = "abbaabba-abba-abba-abba-abbaabbaab65" + id = "abbaabba-abba-abba-abba-abbaabbaab63" options = [ ] position = [ @@ -3752,7 +4139,7 @@ nodes = [ ] export = { } - id = "abbaabba-abba-abba-abba-abbaabbaab39" + id = "abbaabba-abba-abba-abba-abbaabbaab37" options = [ ] position = [ diff --git a/src/serlio/utils/AssetCache.cpp b/src/serlio/utils/AssetCache.cpp new file mode 100644 index 00000000..e6020b39 --- /dev/null +++ b/src/serlio/utils/AssetCache.cpp @@ -0,0 +1,104 @@ +/** + * Serlio - Esri CityEngine Plugin for Autodesk Maya + * + * See https://github.com/esri/serlio for build and usage instructions. + * + * Copyright (c) 2012-2022 Esri R&D Center Zurich + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "AssetCache.h" + +#include "utils/LogHandler.h" + +#include +#include +#include +#include +#include + +namespace { + +bool writeCacheEntry(const std::filesystem::path& assetPath, const uint8_t* buffer, size_t size) noexcept { + if (std::filesystem::exists(assetPath)) + return true; + std::ofstream stream(assetPath, std::ofstream::binary | std::ofstream::trunc); + if (!stream) + return false; + stream.write(reinterpret_cast(buffer), size); + if (!stream) + return false; + stream.close(); + return true; +} + +} // namespace + +std::filesystem::path AssetCache::put(const wchar_t* uri, const wchar_t* fileName, + const std::filesystem::path cacheRootDir, const uint8_t* buffer, size_t size) { + assert(uri != nullptr); + std::wstring stringUri(uri); + + const std::string_view bufferView(reinterpret_cast(buffer), size); + const size_t hash = std::hash{}(bufferView); + const auto key = std::make_pair(stringUri, hash); + + const auto it = mCache.find(key); + + // reuse cached asset if uri and hash match + if (it != mCache.end()) { + const std::filesystem::path& assetPath = it->second; + if (std::filesystem::exists(assetPath)) { + return assetPath; + } + } + + const std::filesystem::path newAssetPath = getCachedPath(fileName, cacheRootDir, hash); + + if (newAssetPath.empty()) { + LOG_ERR << "Invalid URI, cannot cache the asset: " << uri; + return {}; + } + + if (!writeCacheEntry(newAssetPath, buffer, size)) { + LOG_ERR << "Failed to put asset into cache, skipping asset: " << newAssetPath; + return {}; + } + + if (it == mCache.end()) { + mCache.emplace(key, newAssetPath); + } + else { + it->second = newAssetPath; + } + + return newAssetPath; +} + +std::filesystem::path AssetCache::getCachedPath(const wchar_t* fileName, const std::filesystem::path cacheRootDir, + const size_t hash) const { + // we get the filename constructed by the encoder from the URI + assert(fileName != nullptr); + std::filesystem::path assetFile(fileName); + std::filesystem::path cachedAssetName = assetFile.stem(); + std::wstring hashString = std::to_wstring(hash); + + // we then append the hash constructed from the texturecontent + cachedAssetName += L"_" + hashString; + + std::filesystem::path extension = assetFile.extension(); + cachedAssetName += extension; + + const std::filesystem::path cachedAssetPath = cacheRootDir / cachedAssetName; + return cachedAssetPath; +} diff --git a/src/serlio/utils/AssetCache.h b/src/serlio/utils/AssetCache.h new file mode 100644 index 00000000..40aac712 --- /dev/null +++ b/src/serlio/utils/AssetCache.h @@ -0,0 +1,38 @@ +/** + * Serlio - Esri CityEngine Plugin for Autodesk Maya + * + * See https://github.com/esri/serlio for build and usage instructions. + * + * Copyright (c) 2012-2022 Esri R&D Center Zurich + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "utils/Utilities.h" + +#include +#include +#include + +class AssetCache { +public: + std::filesystem::path put(const wchar_t* uri, const wchar_t* fileName, const std::filesystem::path workspaceRoot, + const uint8_t* buffer, size_t size); + +private: + std::filesystem::path getCachedPath(const wchar_t* fileName, const std::filesystem::path workspaceRoot, + const size_t hash) const; + + std::unordered_map, std::filesystem::path, prtu::pair_hash> mCache; +}; diff --git a/src/serlio/utils/LogHandler.h b/src/serlio/utils/LogHandler.h index d078fa20..9b223c12 100644 --- a/src/serlio/utils/LogHandler.h +++ b/src/serlio/utils/LogHandler.h @@ -3,7 +3,7 @@ * * See https://github.com/esri/serlio for build and usage instructions. * - * Copyright (c) 2012-2019 Esri R&D Center Zurich + * Copyright (c) 2012-2022 Esri R&D Center Zurich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -35,38 +35,6 @@ namespace logging { struct Logger {}; - -const std::string LEVELS[] = {"trace", "debug", "info", "warning", "error", "fatal"}; -const std::wstring WLEVELS[] = {L"trace", L"debug", L"info", L"warning", L"error", L"fatal"}; - -// log to std streams -template -struct StreamLogger : Logger { - explicit StreamLogger(std::wostream& out = std::wcout) : Logger(), mOut(out) { - mOut << prefix(); - } - virtual ~StreamLogger() { - mOut << std::endl; - } - StreamLogger& operator<<(std::wostream& (*x)(std::wostream&)) { - mOut << x; - return *this; - } - StreamLogger& operator<<(const std::string& x) { - std::copy(x.begin(), x.end(), std::ostream_iterator(mOut)); - return *this; - } - template - StreamLogger& operator<<(const T& x) { - mOut << x; - return *this; - } - static std::wstring prefix() { - return L"[" + WLEVELS[L] + L"] "; - } - std::wostream& mOut; -}; - // log through the prt logger template struct PRTLogger : Logger { @@ -101,10 +69,8 @@ struct PRTLogger : Logger { class LogHandler : public prt::LogHandler { public: - explicit LogHandler(const std::wstring& name) : mName(name) {} - void handleLogEvent(const wchar_t* msg, prt::LogLevel) override { - std::wcout << L"[" << mName << L"] " << msg << std::endl; + std::cout << prtu::toOSNarrowFromUTF16(msg) << std::endl; } const prt::LogLevel* getLevels(size_t* count) override { @@ -116,16 +82,9 @@ class LogHandler : public prt::LogHandler { *dateTime = true; *level = true; } - - void setName(const std::wstring& n) { - mName = n; - } - -private: - std::wstring mName; }; -using LogHandlerPtr = std::unique_ptr; +using LogHandlerUPtr = std::unique_ptr; } // namespace logging diff --git a/src/serlio/utils/MArrayIteratorTraits.h b/src/serlio/utils/MArrayIteratorTraits.h index a318324c..ece61640 100644 --- a/src/serlio/utils/MArrayIteratorTraits.h +++ b/src/serlio/utils/MArrayIteratorTraits.h @@ -3,7 +3,7 @@ * * See https://github.com/esri/serlio for build and usage instructions. * - * Copyright (c) 2012-2019 Esri R&D Center Zurich + * Copyright (c) 2012-2022 Esri R&D Center Zurich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/src/serlio/utils/MArrayWrapper.h b/src/serlio/utils/MArrayWrapper.h index ccfcfc96..fb2a8391 100644 --- a/src/serlio/utils/MArrayWrapper.h +++ b/src/serlio/utils/MArrayWrapper.h @@ -3,7 +3,7 @@ * * See https://github.com/esri/serlio for build and usage instructions. * - * Copyright (c) 2012-2019 Esri R&D Center Zurich + * Copyright (c) 2012-2022 Esri R&D Center Zurich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -168,9 +168,8 @@ template struct isIterable().begin(), std::declval().end(), bool())>> : public bool_constant {}; -// add inline specifier to isIterableV once we switch to C++17 template -constexpr bool isIterableV = isIterable::value; +inline constexpr bool isIterableV = isIterable::value; } // namespace detail diff --git a/src/serlio/utils/MELScriptBuilder.cpp b/src/serlio/utils/MELScriptBuilder.cpp index f1f759ee..0b2cddf1 100644 --- a/src/serlio/utils/MELScriptBuilder.cpp +++ b/src/serlio/utils/MELScriptBuilder.cpp @@ -3,7 +3,7 @@ * * See https://github.com/esri/serlio for build and usage instructions. * - * Copyright (c) 2012-2019 Esri R&D Center Zurich + * Copyright (c) 2012-2022 Esri R&D Center Zurich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,6 +27,7 @@ namespace { constexpr bool MEL_ENABLE_DISPLAY = false; +const std::wstring ENUM_BANNED_CHARS = L"=:\\;\r\n"; std::wstring composeAttributeExpression(const MELVariable& node, const std::wstring& attribute) { assert(!attribute.empty() && attribute[0] != L'.'); // to catch refactoring bugs @@ -35,6 +36,15 @@ std::wstring composeAttributeExpression(const MELVariable& node, const std::wstr return out.str(); } +void cleanEnumOptionName(std::wstring& optionName) { + if (optionName.empty()) { + optionName = L" "; + } + else { + replaceAllOf(optionName, ENUM_BANNED_CHARS); + } +} + } // namespace void MELScriptBuilder::setAttr(const MELVariable& node, const std::wstring& attribute, const bool val) { @@ -85,16 +95,39 @@ void MELScriptBuilder::setAttr(const MELVariable& node, const std::wstring& attr setAttr(node, attribute, color.r(), color.g(), color.b()); } +void MELScriptBuilder::setAttrEnumOptions(const MELVariable& node, const std::wstring& attribute, + const std::vector& enumOptions, + const std::optional& customDefaultOption) { + std::wstring enumString; + + if (customDefaultOption.has_value()) { + std::wstring customDefaultOptionString = customDefaultOption.value(); + cleanEnumOptionName(customDefaultOptionString); + enumString.append(customDefaultOptionString + L"=0"); + } + for (size_t idx = 0; idx < enumOptions.size(); idx++) { + std::wstring enumOption = enumOptions[idx]; + if (!enumString.empty()) + enumString.append(L":"); + cleanEnumOptionName(enumOption); + enumString.append(enumOption + L"=" + std::to_wstring(idx + 1)); + } + // Don't update to an empty enum + if (enumString.empty()) + enumString.append(L" "); + + commandStream << "addAttr -e -en " << MELStringLiteral(enumString).mel() << " " + << composeAttributeExpression(node, attribute) << ";\n"; + commandStream << "if (`exists redrawEnum`)\n"; + commandStream << "\tredrawEnum(" << composeAttributeExpression(node, attribute) << ");\n"; +} + void MELScriptBuilder::connectAttr(const MELVariable& srcNode, const std::wstring& srcAttr, const MELVariable& dstNode, const std::wstring& dstAttr) { commandStream << "connectAttr -force " << composeAttributeExpression(srcNode, srcAttr) << " " << composeAttributeExpression(dstNode, dstAttr) << ";\n"; } -void MELScriptBuilder::python(const std::wstring& pythonCmd) { - commandStream << "python(\"" << pythonCmd << "\");\n"; -} - void MELScriptBuilder::declInt(const MELVariable& varName) { commandStream << "int " << varName.mel() << ";\n"; } @@ -118,6 +151,10 @@ void MELScriptBuilder::setsAddFaceRange(const std::wstring& setName, const std:: << "];\n"; } +void MELScriptBuilder::setsUseInitialShadingGroup(const std::wstring& meshName) { + commandStream << "sets -forceElement initialShadingGroup " << meshName << ";"; +} + void MELScriptBuilder::createShader(const std::wstring& shaderType, const MELVariable& nodeName) { const auto mel = nodeName.mel(); commandStream << mel << " = `shadingNode -asShader -skipSelect -name " << mel << " " << shaderType << "`;\n"; @@ -128,10 +165,34 @@ void MELScriptBuilder::createTextureShadingNode(const MELVariable& nodeName) { commandStream << mel << "= `shadingNode -asTexture -skipSelect -name " << mel << " file`;\n"; } +void MELScriptBuilder::forceValidTextureAlphaChannel(const MELVariable& nodeName) { + commandStream << "setAttr " << composeAttributeExpression(nodeName, L"alphaIsLuminance") << "(!`getAttr " + << composeAttributeExpression(nodeName, L"fileHasAlpha") << "`);"; +} + +void MELScriptBuilder::getUndoState(const MELVariable& undoName) { + const auto mel = undoName.mel(); + commandStream << mel << " = `undoInfo -q -state`;\n"; +} + +void MELScriptBuilder::setUndoState(const MELVariable& undoName) { + const auto mel = undoName.mel(); + commandStream << "undoInfo -stateWithoutFlush " << mel << ";\n"; +} + +void MELScriptBuilder::setUndoState(bool undoState) { + std::wstring undoString = undoState ? L"on" : L"off"; + commandStream << "undoInfo -stateWithoutFlush " << undoString << ";\n"; +} + void MELScriptBuilder::addCmdLine(const std::wstring& line) { commandStream << line << L"\n"; } +void MELScriptBuilder::getWorkspaceDir() { + commandStream << L"workspace -q -rd;\n"; +} + MStatus MELScriptBuilder::executeSync(std::wstring& output) { MStatus status; MString result = diff --git a/src/serlio/utils/MELScriptBuilder.h b/src/serlio/utils/MELScriptBuilder.h index e0d6b1d7..436cf219 100644 --- a/src/serlio/utils/MELScriptBuilder.h +++ b/src/serlio/utils/MELScriptBuilder.h @@ -3,7 +3,7 @@ * * See https://github.com/esri/serlio for build and usage instructions. * - * Copyright (c) 2012-2019 Esri R&D Center Zurich + * Copyright (c) 2012-2022 Esri R&D Center Zurich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -63,6 +63,10 @@ class MELScriptBuilder { void setAttr(const MELVariable& node, const std::wstring& attribute, const wchar_t* val) = delete; void setAttr(const MELVariable& node, const std::wstring& attribute, const char* val) = delete; + void setAttrEnumOptions(const MELVariable& node, const std::wstring& attribute, + const std::vector& enumOptions, + const std::optional& customDefaultOption); + void connectAttr(const MELVariable& srcNode, const std::wstring& srcAttr, const MELVariable& dstNode, const std::wstring& dstAttr); @@ -73,11 +77,18 @@ class MELScriptBuilder { void setsCreate(const MELVariable& setName); void setsAddFaceRange(const std::wstring& setName, const std::wstring& meshName, int faceStart, int faceEnd); + void setsUseInitialShadingGroup(const std::wstring& meshName); void createShader(const std::wstring& shaderType, const MELVariable& nodeName); void createTextureShadingNode(const MELVariable& nodeName); + void forceValidTextureAlphaChannel(const MELVariable& nodeName); + + void getUndoState(const MELVariable& undoName); + void setUndoState(const MELVariable& undoName); + void setUndoState(bool undoState); + + void getWorkspaceDir(); - void python(const std::wstring& pythonCmd); void addCmdLine(const std::wstring& line); MStatus executeSync(std::wstring& output); diff --git a/src/serlio/utils/MItDependencyNodesWrapper.cpp b/src/serlio/utils/MItDependencyNodesWrapper.cpp index 67d66c0e..a3397fd7 100644 --- a/src/serlio/utils/MItDependencyNodesWrapper.cpp +++ b/src/serlio/utils/MItDependencyNodesWrapper.cpp @@ -3,7 +3,7 @@ * * See https://github.com/esri/serlio for build and usage instructions. * - * Copyright (c) 2012-2019 Esri R&D Center Zurich + * Copyright (c) 2012-2022 Esri R&D Center Zurich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/src/serlio/utils/MItDependencyNodesWrapper.h b/src/serlio/utils/MItDependencyNodesWrapper.h index 8abdfc6f..93113b6b 100644 --- a/src/serlio/utils/MItDependencyNodesWrapper.h +++ b/src/serlio/utils/MItDependencyNodesWrapper.h @@ -3,7 +3,7 @@ * * See https://github.com/esri/serlio for build and usage instructions. * - * Copyright (c) 2012-2019 Esri R&D Center Zurich + * Copyright (c) 2012-2022 Esri R&D Center Zurich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/src/serlio/utils/MayaUtilities.cpp b/src/serlio/utils/MayaUtilities.cpp index a5904348..58677096 100644 --- a/src/serlio/utils/MayaUtilities.cpp +++ b/src/serlio/utils/MayaUtilities.cpp @@ -1,6 +1,105 @@ +/** + * Serlio - Esri CityEngine Plugin for Autodesk Maya + * + * See https://github.com/esri/serlio for build and usage instructions. + * + * Copyright (c) 2012-2022 Esri R&D Center Zurich + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "utils/MELScriptBuilder.h" +#include "utils/MItDependencyNodesWrapper.h" #include "utils/MayaUtilities.h" +#include "maya/MItDependencyNodes.h" +#include "maya/MSelectionList.h" +#include "maya/MStringResource.h" +#include "maya/MStringResourceId.h" +#include "maya/MUuid.h" + +#include #include +#include + +namespace { +constexpr const wchar_t KEY_URL_SEPARATOR = L'='; +const MString INDIRECTION_URL = L"https://raw.githubusercontent.com/Esri/serlio/data/urls.json"; +const MString SERLIO_HOME_KEY = "SERLIO_HOME"; +const MString CGA_REFERENCE_KEY = "CGA_REFERENCE"; +const MString RPK_MANUAL_KEY = "RPK_MANUAL"; + +const std::map fallbackKeyToUrlMap = { + {SERLIO_HOME_KEY.asChar(), "https://esri.github.io/cityengine/serlio"}, + {CGA_REFERENCE_KEY.asChar(), "https://doc.arcgis.com/en/cityengine/latest/cga/cityengine-cga-introduction.htm"}, + {RPK_MANUAL_KEY.asChar(), "https://doc.arcgis.com/en/cityengine/latest/help/help-rule-package.htm"}}; + +std::map getKeyToUrlMap() { + MString pyCmd1; + pyCmd1 += "def getIndirectionStrings():\n"; + pyCmd1 += " from six.moves import urllib\n"; + pyCmd1 += " import json\n"; + // Download indirection links + pyCmd1 += " url = \"" + INDIRECTION_URL + "\"\n"; + pyCmd1 += " try:\n"; + pyCmd1 += " response = urllib.request.urlopen(url, timeout=3)\n"; + pyCmd1 += " jsonString = response.read()\n"; + // Parse json into array + pyCmd1 += " jsonObject = json.loads(jsonString)\n"; + pyCmd1 += " serlioHomeKey = \"" + SERLIO_HOME_KEY + "\"\n"; + pyCmd1 += " cgaReferenceKey = \"" + CGA_REFERENCE_KEY + "\"\n"; + pyCmd1 += " rpkManualKey = \"" + RPK_MANUAL_KEY + "\"\n"; + pyCmd1 += " serlioVersionKey = \"" SRL_VERSION_MAJOR "." SRL_VERSION_MINOR "\"\n"; + pyCmd1 += " serlioHome = jsonObject[serlioVersionKey][serlioHomeKey]\n"; + pyCmd1 += " cgaReference = jsonObject[serlioVersionKey][cgaReferenceKey]\n"; + pyCmd1 += " rpkManual = jsonObject[serlioVersionKey][rpkManualKey]\n"; + pyCmd1 += " return [serlioHomeKey, serlioHome, cgaReferenceKey, cgaReference, rpkManualKey, rpkManual]\n"; + pyCmd1 += " except:\n"; + pyCmd1 += " return []"; + + MStatus status = MGlobal::executePythonCommand(pyCmd1); + if (status != MStatus::kSuccess) + return {}; + + MString pyCmd2 = "getIndirectionStrings()"; + MStringArray result; + status = MGlobal::executePythonCommand(pyCmd2, result); + if ((status != MStatus::kSuccess) || result.length() < 6) + return {}; + + std::map keyToUrlMap; + for (uint32_t i = 0; i + 1 < result.length(); i += 2) { + const std::string key = result[i].asChar(); + const std::string value = result[i + 1].asChar(); + keyToUrlMap[key] = value; + } + + return keyToUrlMap; +} + +MObject findNamedObject(const MString& name, MFn::Type fnType) { + MStatus status; + MItDependencyNodes nodeIt(fnType, &status); + MCHECK(status); + + for (const auto& nodeObj : MItDependencyNodesWrapper(nodeIt)) { + MFnDependencyNode node(nodeObj); + if (node.name() == name) + return nodeObj; + } + + return MObject::kNullObj; +} +} // namespace namespace mu { @@ -22,17 +121,6 @@ int32_t computeSeed(const MFloatPointArray& vertices) { return computeSeed(a); } -int32_t computeSeed(const double* vertices, size_t count) { - MFloatPoint a(0.0, 0.0, 0.0); - for (unsigned int vi = 0; vi < count; vi += 3) { - a[0] += static_cast(vertices[vi + 0]); - a[1] += static_cast(vertices[vi + 1]); - a[2] += static_cast(vertices[vi + 2]); - } - a = a / static_cast(count); - return computeSeed(a); -} - void statusCheck(const MStatus& status, const char* file, int line) { if (MS::kSuccess != status) { LOG_ERR << "maya status error at " << file << ":" << line << ": " << status.errorString().asChar() << " (code " @@ -40,4 +128,87 @@ void statusCheck(const MStatus& status, const char* file, int line) { } } -} // namespace mu \ No newline at end of file +std::filesystem::path getWorkspaceRoot(MStatus& status) { + MELScriptBuilder scriptBuilder; + scriptBuilder.getWorkspaceDir(); + + std::wstring output; + status = scriptBuilder.executeSync(output); + + if (status == MS::kSuccess) { + return std::filesystem::path(output).make_preferred(); + } + else { + return {}; + } +} + +MStatus registerMStringResources() { + std::map keyToUrlMap = getKeyToUrlMap(); + + for (const auto& [key, url] : fallbackKeyToUrlMap) { + auto it = keyToUrlMap.find(key); + if (it == keyToUrlMap.end()) { + const MStringResourceId SerlioHomeURL(SRL_PROJECT_NAME, key.c_str(), url.c_str()); + MStringResource::registerString(SerlioHomeURL); + } + else { + const MStringResourceId SerlioHomeURL(SRL_PROJECT_NAME, key.c_str(), it->second.c_str()); + MStringResource::registerString(SerlioHomeURL); + } + } + + return MS::kSuccess; +} + +MStatus setEnumOptions(const MObject& node, MFnEnumAttribute& enumAttr, const std::vector& enumOptions, + const std::optional& customDefaultOption) { + MStatus stat; + const MFnDependencyNode fNode(node, &stat); + if (stat != MStatus::kSuccess) + return stat; + + const MELVariable melSerlioNode(L"serlioNode"); + + MELScriptBuilder scriptBuilder; + const std::wstring nodeName = fNode.name().asWChar(); + const std::wstring attrName = enumAttr.name().asWChar(); + scriptBuilder.setVar(melSerlioNode, MELStringLiteral(nodeName)); + scriptBuilder.setAttrEnumOptions(melSerlioNode, attrName, enumOptions, customDefaultOption); + + return scriptBuilder.execute(); +} + +MUuid getNodeUuid(const MString& nodeName) { + MObject shadingEngineObj = findNamedObject(nodeName, MFn::kShadingEngine); + MFnDependencyNode shadingEngine(shadingEngineObj); + return shadingEngine.uuid(); +} + +MObject getNodeObjFromUuid(const MUuid& nodeUuid, MStatus& status) { + MSelectionList selList; + status = selList.add(MUuid(nodeUuid)); + MObject shadingEngineNodeObj; + + if (status != MS::kSuccess) + return shadingEngineNodeObj; + + status = selList.getDependNode(0, shadingEngineNodeObj); + return shadingEngineNodeObj; +} + +} // namespace mu + +bool operator==(const MStringArray& lhs, const MStringArray& rhs) { + if (lhs.length() != rhs.length()) + return false; + for (uint32_t index = 0; index < lhs.length(); index++) { + if (lhs[index] != rhs[index]) + return false; + } + return true; +} + +bool operator!=(const MStringArray& lhs, const MStringArray& rhs) { + return !(lhs == rhs); +} diff --git a/src/serlio/utils/MayaUtilities.h b/src/serlio/utils/MayaUtilities.h index 15ef0f71..bcaf66e5 100644 --- a/src/serlio/utils/MayaUtilities.h +++ b/src/serlio/utils/MayaUtilities.h @@ -1,3 +1,22 @@ +/** + * Serlio - Esri CityEngine Plugin for Autodesk Maya + * + * See https://github.com/esri/serlio for build and usage instructions. + * + * Copyright (c) 2012-2022 Esri R&D Center Zurich + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + #pragma once #include "utils/LogHandler.h" @@ -5,14 +24,19 @@ #include "maya/MFloatPointArray.h" #include "maya/MFnAttribute.h" #include "maya/MFnDependencyNode.h" +#include "maya/MFnEnumAttribute.h" #include "maya/MObject.h" #include "maya/MStatus.h" #include "maya/MString.h" +#include + #define MCHECK(status) mu::statusCheck((status), __FILE__, __LINE__); // utility functions with dependencies on the Maya API namespace mu { +// Standard conversion from meters (PRT) to centimeters (maya) +constexpr double PRT_TO_SERLIO_SCALE = 100.0f; int32_t computeSeed(const MFloatPointArray& vertices); int32_t computeSeed(const double* vertices, size_t count); @@ -45,4 +69,17 @@ class NamedType { T value_; }; -} // namespace mu \ No newline at end of file +std::filesystem::path getWorkspaceRoot(MStatus& status); + +MStatus registerMStringResources(); + +MStatus setEnumOptions(const MObject& node, MFnEnumAttribute& enumAttr, const std::vector& enumOptions, + const std::optional& customDefaultOption); + +MUuid getNodeUuid(const MString& nodeName); + +MObject getNodeObjFromUuid(const MUuid& nodeUuid, MStatus& status); +} // namespace mu + +bool operator==(const MStringArray& lhs, const MStringArray& rhs); +bool operator!=(const MStringArray& lhs, const MStringArray& rhs); diff --git a/src/serlio/utils/ResolveMapCache.cpp b/src/serlio/utils/ResolveMapCache.cpp index 3a5cb473..7333d711 100644 --- a/src/serlio/utils/ResolveMapCache.cpp +++ b/src/serlio/utils/ResolveMapCache.cpp @@ -3,7 +3,7 @@ * * See https://github.com/esri/serlio for build and usage instructions. * - * Copyright (c) 2012-2019 Esri R&D Center Zurich + * Copyright (c) 2012-2022 Esri R&D Center Zurich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,8 +17,8 @@ * limitations under the License. */ -#include "utils/ResolveMapCache.h" #include "utils/LogHandler.h" +#include "utils/ResolveMapCache.h" #include "utils/Utilities.h" #include @@ -33,13 +33,6 @@ std::mutex resolveMapCacheMutex; } // namespace -ResolveMapCache::~ResolveMapCache() { - if (!mRPKUnpackPath.empty()) - prtu::remove_all(mRPKUnpackPath); - if (DBG) - LOG_DBG << "Removed RPK unpack directory"; -} - ResolveMapCache::LookupResult ResolveMapCache::get(const std::wstring& rpk) { std::lock_guard lock(resolveMapCacheMutex); @@ -59,10 +52,6 @@ ResolveMapCache::LookupResult ResolveMapCache::get(const std::wstring& rpk) { LOG_DBG << "rpk: cache timestamp: " << it->second.mTimeStamp; if (it->second.mTimeStamp != timeStamp) { mCache.erase(it); - std::wstring filename = prtu::filename(rpk); - - if (!mRPKUnpackPath.empty() && !filename.empty()) - prtu::remove_all(mRPKUnpackPath + prtu::getDirSeparator() + prtu::filename(rpk)); if (DBG) LOG_DBG << "RPK change detected, forcing reload and clearing cache for " << rpk; @@ -82,13 +71,11 @@ ResolveMapCache::LookupResult ResolveMapCache::get(const std::wstring& rpk) { prt::Status status = prt::STATUS_UNSPECIFIED_ERROR; if (DBG) LOG_DBG << "createResolveMap from " << rpk; - rmce.mResolveMap.reset(prt::createResolveMap(rpkURI.c_str(), mRPKUnpackPath.c_str(), &status), PRTDestroyer()); + rmce.mResolveMap.reset(prt::createResolveMap(rpkURI.c_str(), nullptr, &status), PRTDestroyer()); if (status != prt::STATUS_OK) return LOOKUP_FAILURE; it = mCache.emplace(rpk, std::move(rmce)).first; - if (DBG) - LOG_DBG << "Upacked RPK " << rpk << " to " << mRPKUnpackPath; } return {it->second.mResolveMap, cs}; diff --git a/src/serlio/utils/ResolveMapCache.h b/src/serlio/utils/ResolveMapCache.h index 96d2c6a3..15aee536 100644 --- a/src/serlio/utils/ResolveMapCache.h +++ b/src/serlio/utils/ResolveMapCache.h @@ -3,7 +3,7 @@ * * See https://github.com/esri/serlio for build and usage instructions. * - * Copyright (c) 2012-2019 Esri R&D Center Zurich + * Copyright (c) 2012-2022 Esri R&D Center Zurich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,18 +22,18 @@ #include "utils/Utilities.h" #include +#include #include class ResolveMapCache { public: using KeyType = std::wstring; - explicit ResolveMapCache(const std::wstring& unpackPath) : mRPKUnpackPath{unpackPath} {} + ResolveMapCache() = default; ResolveMapCache(const ResolveMapCache&) = delete; ResolveMapCache(ResolveMapCache&&) = delete; ResolveMapCache& operator=(ResolveMapCache const&) = delete; ResolveMapCache& operator=(ResolveMapCache&&) = delete; - ~ResolveMapCache(); enum class CacheStatus { HIT, MISS }; using LookupResult = std::pair; @@ -46,8 +46,6 @@ class ResolveMapCache { }; using Cache = std::map; Cache mCache; - - const std::wstring mRPKUnpackPath; }; using ResolveMapCacheUPtr = std::unique_ptr; \ No newline at end of file diff --git a/src/serlio/utils/Utilities.cpp b/src/serlio/utils/Utilities.cpp index 2cd37d01..417f77b4 100644 --- a/src/serlio/utils/Utilities.cpp +++ b/src/serlio/utils/Utilities.cpp @@ -3,7 +3,7 @@ * * See https://github.com/esri/serlio for build and usage instructions. * - * Copyright (c) 2012-2019 Esri R&D Center Zurich + * Copyright (c) 2012-2022 Esri R&D Center Zurich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,6 +17,7 @@ * limitations under the License. */ +#include "utils/LogHandler.h" #include "utils/Utilities.h" #include "prt/API.h" @@ -30,24 +31,83 @@ struct IUnknown; # include # include #else +# include # include # include #endif +#include #include +#include #include #include #include #include +namespace { +const std::wstring MAYA_SEPARATOR = L"_"; +const std::wstring MAYA_COMPATIBLE_CHARS = L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"; +const std::wstring DIGIT_CHARS = L"0123456789"; + +const std::wstring TOO_NEW_CE_VERSION = L"newer than 2021.1"; +const std::wstring CGAC_VERSION_STRING = L"CGAC version "; +const std::wstring CE_VERSION_STRING = L"CityEngine version "; + +const std::map cgacToCEVersion = { + // clang-format off + {L"1.17", L"2021.1"}, + {L"1.16", L"2021.0"}, + {L"1.15", L"2020.1"}, + {L"1.14", L"2020.0"}, + {L"1.13", L"2019.1"}, + {L"1.12", L"2019.0"}, + {L"1.11", L"2018.1"}, + {L"1.10", L"2018.0"}, + {L"1.9", L"2017.1"}, + {L"1.8", L"2017.0"}, + {L"1.7", L"2016.1"}, + {L"1.6", L"2016.0"}, + {L"1.5", L"2015.0 - 2015.2"}, + {L"1.4", L"2014.1"}, + {L"1.3", L"2014.1"}, + {L"1.2", L"2014.0"}, + {L"1.1", L"2013.1"}, + {L"1.0", L"2013.0"} + // clang-format on +}; + +void replaceCGACVersionBetween(std::wstring& errorString, const std::wstring prefix, const std::wstring suffix) { + size_t versionStartPos = errorString.find(prefix); + if (versionStartPos != std::wstring::npos) + versionStartPos += prefix.length(); + + const size_t versionEndPos = errorString.find(suffix, versionStartPos); + + if ((versionStartPos == std::wstring::npos) || (versionEndPos == std::wstring::npos)) + return; + + const size_t versionLength = versionEndPos - versionStartPos; + const std::wstring cgacV1 = errorString.substr(versionStartPos, versionLength); + + std::wstring CEVersion; + const auto it = cgacToCEVersion.find(cgacV1); + if (it != cgacToCEVersion.end()) { + CEVersion = it->second; + } + else { + CEVersion = TOO_NEW_CE_VERSION; + } + errorString.replace(versionStartPos, versionLength, CEVersion); +} +} // namespace + namespace prtu { // plugin root = location of serlio shared library -std::wstring getPluginRoot() { +std::filesystem::path getPluginRoot() { + std::filesystem::path rootPath; #ifdef _WIN32 char dllPath[_MAX_PATH]; - char drive[8]; - char dir[_MAX_PATH]; HMODULE hModule = 0; GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, @@ -58,62 +118,17 @@ std::wstring getPluginRoot() { throw std::runtime_error("failed to get plugin location"); } - _splitpath_s(dllPath, drive, 8, dir, _MAX_PATH, 0, 0, 0, 0); - std::wstring rootPath = prtu::toUTF16FromOSNarrow(drive); - rootPath.append(prtu::toUTF16FromOSNarrow(dir)); + rootPath = std::filesystem::path(dllPath).parent_path(); #else Dl_info dl_info; dladdr((const void*)getPluginRoot, &dl_info); const std::string tmp(dl_info.dli_fname); - std::wstring rootPath = prtu::toUTF16FromOSNarrow(tmp.substr(0, tmp.find_last_of(prtu::getDirSeparator()))); + rootPath = std::filesystem::path(tmp).parent_path(); #endif - // ensure path separator at end - if (*rootPath.rbegin() != prtu::getDirSeparator()) - rootPath.append(1, prtu::getDirSeparator()); - return rootPath; } -std::wstring filename(const std::wstring& path) { - size_t pos = path.find_last_of(L'/'); - if (pos != std::string::npos) { - return path.substr(pos + 1); - } - else - return path; -} - -template <> -char getDirSeparator() { -#ifdef _WIN32 - static const char SEPARATOR = '\\'; -#else - static const char SEPARATOR = '/'; -#endif - return SEPARATOR; -} - -template <> -wchar_t getDirSeparator() { -#ifdef _WIN32 - static const wchar_t SEPARATOR = L'\\'; -#else - static const wchar_t SEPARATOR = L'/'; -#endif - return SEPARATOR; -} - -template <> -std::string getDirSeparator() { - return std::string(1, getDirSeparator()); -} - -template <> -std::wstring getDirSeparator() { - return std::wstring(1, getDirSeparator()); -} - int fromHex(wchar_t c) { // clang-format off switch (c) { @@ -211,91 +226,15 @@ std::wstring toFileURI(const std::wstring& p) { return schema + u16String; } -void remove_all(const std::wstring& path) { -#ifdef _WIN32 - std::wstring pc = path; - std::replace(pc.begin(), pc.end(), L'/', L'\\'); - const wchar_t* lpszDir = pc.c_str(); - - size_t len = wcslen(lpszDir); - wchar_t* pszFrom = new wchar_t[len + 2]; - wcscpy_s(pszFrom, len + 2, lpszDir); - pszFrom[len] = 0; - pszFrom[len + 1] = 0; - - SHFILEOPSTRUCTW fileop; - fileop.hwnd = NULL; // no status display - fileop.wFunc = FO_DELETE; // delete operation - fileop.pFrom = pszFrom; // source file name as double null terminated string - fileop.pTo = NULL; // no destination needed - fileop.fFlags = FOF_NOCONFIRMATION | FOF_SILENT; // do not prompt the user - fileop.fAnyOperationsAborted = FALSE; - fileop.lpszProgressTitle = NULL; - fileop.hNameMappings = NULL; - - int ret = SHFileOperationW(&fileop); - delete[] pszFrom; -#else - system((std::string("rm -rf ") + toOSNarrowFromUTF16(path)).c_str()); -#endif -} - -std::wstring temp_directory_path() { -#ifdef _WIN32 - DWORD dwRetVal = 0; - wchar_t lpTempPathBuffer[MAX_PATH]; - - dwRetVal = GetTempPathW(MAX_PATH, lpTempPathBuffer); - if (dwRetVal > MAX_PATH || (dwRetVal == 0)) { - return L".\tmp"; - } - else { - return std::wstring(lpTempPathBuffer); - } - -#else - - char const* folder = getenv("TMPDIR"); - if (folder == nullptr) { - folder = getenv("TMP"); - if (folder == nullptr) { - folder = getenv("TEMP"); - if (folder == nullptr) { - folder = getenv("TEMPDIR"); - if (folder == nullptr) - folder = "/tmp"; - } - } - } - - return toUTF16FromOSNarrow(std::string(folder)); -#endif -} - -std::wstring getProcessTempDir(const std::wstring& prefix) { - std::wstring tp = prtu::temp_directory_path(); - wchar_t sep = prtu::getDirSeparator(); - if (*tp.rbegin() != sep) - tp += sep; - std::wstring n = prefix; -#ifdef _WIN32 - n += std::to_wstring(::_getpid()); // prevent warning in win32 -#else - n += std::to_wstring(::getpid()); -#endif - return {tp.append(n)}; -} - time_t getFileModificationTime(const std::wstring& p) { + std::wstring pn = std::filesystem::path(p).make_preferred().wstring(); #ifdef _WIN32 - std::wstring pn = p; - std::replace(pn.begin(), pn.end(), L'/', L'\\'); struct _stat st; int ierr = _wstat(pn.c_str(), &st); #else struct stat st; - int ierr = stat(prtu::toOSNarrowFromUTF16(p).c_str(), &st); + int ierr = stat(prtu::toOSNarrowFromUTF16(pn).c_str(), &st); #endif if (ierr == 0) { @@ -304,12 +243,6 @@ time_t getFileModificationTime(const std::wstring& p) { return -1; } -std::wstring toGenericPath(const std::wstring& osPath) { - std::wstring genPath = osPath; - std::replace(genPath.begin(), genPath.end(), L'\\', L'/'); - return genPath; -} - std::string objectToXML(prt::Object const* obj) { if (obj == nullptr) throw std::invalid_argument("object pointer is not valid"); @@ -338,4 +271,29 @@ AttributeMapUPtr createValidatedOptions(const wchar_t* encID, const prt::Attribu return AttributeMapUPtr(validatedOptions); } +void replaceCGACWithCEVersion(std::wstring& errorString) { + // a typical CGAC version error string looks like: + // Potentially unsupported CGAC version X.YY : major number smaller than current (A.BB) + replaceAllSubstrings(errorString, CGAC_VERSION_STRING, CE_VERSION_STRING); + + replaceCGACVersionBetween(errorString, CE_VERSION_STRING, L" "); + replaceCGACVersionBetween(errorString, L"(", L")"); +} + +std::wstring getDuplicateCountSuffix(const std::wstring& name, std::map& duplicateCountMap) { + auto [iterator, isFirstEntry] = duplicateCountMap.try_emplace(name, 0); + if (!isFirstEntry) + iterator->second++; + return MAYA_SEPARATOR + std::to_wstring(iterator->second); +} + +std::wstring cleanNameForMaya(const std::wstring& name) { + std::wstring r = name; + replaceAllNotOf(r, MAYA_COMPATIBLE_CHARS); + + if (!r.empty() && (DIGIT_CHARS.find(r.front()) != std::wstring::npos)) + return MAYA_SEPARATOR + r; + + return r; +} } // namespace prtu diff --git a/src/serlio/utils/Utilities.h b/src/serlio/utils/Utilities.h index a78d9d90..6cf17b6b 100644 --- a/src/serlio/utils/Utilities.h +++ b/src/serlio/utils/Utilities.h @@ -3,7 +3,7 @@ * * See https://github.com/esri/serlio for build and usage instructions. * - * Copyright (c) 2012-2019 Esri R&D Center Zurich + * Copyright (c) 2012-2022 Esri R&D Center Zurich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,7 +33,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -66,6 +68,7 @@ using CacheObjectUPtr = std::unique_ptr; using AttributeMapUPtr = std::unique_ptr; using AttributeMapVector = std::vector; using AttributeMapBuilderUPtr = std::unique_ptr; +using AttributeMapBuilderSPtr = std::shared_ptr; using AttributeMapBuilderVector = std::vector; using InitialShapeUPtr = std::unique_ptr; using InitialShapeBuilderUPtr = std::unique_ptr; @@ -78,7 +81,7 @@ using ResolveMapSPtr = std::shared_ptr; namespace prtu { -std::wstring getPluginRoot(); +std::filesystem::path getPluginRoot(); template std::vector toPtrVec(const std::vector>& sv) { @@ -94,20 +97,23 @@ std::vector toPtrVec(const std::vector>& sv) { return pv; } -// poor mans std::filesystem - we don't want boost or c++17 dependency right now -SRL_TEST_EXPORTS_API std::wstring filename(const std::wstring& path); -time_t getFileModificationTime(const std::wstring& p); -std::wstring temp_directory_path(); -std::wstring getProcessTempDir(const std::wstring& prefix); -void remove_all(const std::wstring& path); -std::wstring toGenericPath(const std::wstring& osPath); +// hash_combine function from boost library: https://www.boost.org/doc/libs/1_73_0/boost/container_hash/hash.hpp +template +inline void hash_combine(SizeT& seed, SizeT value) { + seed ^= value + 0x9e3779b9 + (seed << 6) + (seed >> 2); +} -template -C getDirSeparator(); -template <> -char getDirSeparator(); -template <> -wchar_t getDirSeparator(); +struct pair_hash { + template + std::size_t operator()(const std::pair& v) const { + std::size_t seed = 0; + hash_combine(seed, std::hash{}(v.first)); + hash_combine(seed, std::hash{}(v.second)); + return seed; + } +}; + +time_t getFileModificationTime(const std::wstring& p); int fromHex(wchar_t c); wchar_t toHex(int i); @@ -188,7 +194,7 @@ SRL_TEST_EXPORTS_API inline std::wstring getStyle(const std::wstring& fqRuleName } SRL_TEST_EXPORTS_API inline std::wstring removePrefix(const std::wstring& fqRuleName, wchar_t delim) { - const auto sepPos = fqRuleName.find(delim); + const auto sepPos = fqRuleName.rfind(delim); if (sepPos == std::wstring::npos) return fqRuleName; if (sepPos == fqRuleName.length() - 1) @@ -206,9 +212,22 @@ SRL_TEST_EXPORTS_API inline std::wstring removeImport(const std::wstring& fqRule return removePrefix(fqRuleName, IMPORT_DELIMITER); } +SRL_TEST_EXPORTS_API inline std::wstring getImport(const std::wstring& fqRuleName) { + const std::wstring ruleWithoutStyle = removeStyle(fqRuleName); + const auto sepPos = ruleWithoutStyle.rfind(IMPORT_DELIMITER); + if (sepPos == std::wstring::npos || sepPos == 0) + return {}; + return ruleWithoutStyle.substr(0, sepPos); +} + +SRL_TEST_EXPORTS_API void replaceCGACWithCEVersion(std::wstring& errorString); + +SRL_TEST_EXPORTS_API std::wstring getDuplicateCountSuffix(const std::wstring& name, + std::map& duplicateCountMap); +SRL_TEST_EXPORTS_API std::wstring cleanNameForMaya(const std::wstring& name); } // namespace prtu -inline void replace_all_not_of(std::wstring& s, const std::wstring& allowedChars) { +SRL_TEST_EXPORTS_API inline void replaceAllNotOf(std::wstring& s, const std::wstring& allowedChars) { std::wstring::size_type pos = 0; while (pos < s.size()) { pos = s.find_first_not_of(allowedChars, pos); @@ -218,6 +237,26 @@ inline void replace_all_not_of(std::wstring& s, const std::wstring& allowedChars } } +SRL_TEST_EXPORTS_API inline void replaceAllOf(std::wstring& s, const std::wstring& bannedChars) { + std::wstring::size_type pos = 0; + while (pos < s.size()) { + pos = s.find_first_of(bannedChars, pos); + if (pos == std::wstring::npos) + break; + s[pos++] = L'_'; + } +} + +template +void replaceAllSubstrings(std::basic_string& str, const std::basic_string& oldStr, + const std::basic_string& newStr) { + typename std::basic_string::size_type pos = 0; + while ((pos = str.find(oldStr, pos)) != std::basic_string::npos) { + str.replace(pos, oldStr.length(), newStr); + pos += newStr.length(); + } +} + inline bool startsWithAnyOf(const std::string& s, const std::vector& sv) { for (const auto& v : sv) { if (s.find(v) == 0) diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index 6ad5c49a..90598f9d 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -5,9 +5,12 @@ add_executable(${TEST_TARGET} ../serlio/PRTContext.cpp ../serlio/utils/Utilities.cpp ../serlio/utils/ResolveMapCache.cpp + ../serlio/utils/AssetCache.cpp ../serlio/modifiers/RuleAttributes.cpp) -set_target_properties(${TEST_TARGET} PROPERTIES CXX_STANDARD 14) +set_target_properties(${TEST_TARGET} PROPERTIES CXX_STANDARD 17) + +set_common_target_definitions(${TEST_TARGET}) target_compile_definitions(${TEST_TARGET} PRIVATE -DSRL_TEST_EXPORTS @@ -18,9 +21,10 @@ if (WIN32) else () target_compile_options(${TEST_TARGET} PRIVATE - -D_GLIBCXX_USE_CXX11_ABI=0 -Wl,--exclude-libs,ALL + -D_GLIBCXX_USE_CXX11_ABI=0 -fvisibility=hidden -fvisibility-inlines-hidden) + target_link_options(${TEST_TARGET} PRIVATE "LINKER:SHELL:--exclude-libs ALL") target_link_libraries(${TEST_TARGET} PRIVATE dl) endif () @@ -29,6 +33,7 @@ target_include_directories(${TEST_TARGET} PRIVATE $) srl_add_dependency_prt(${TEST_TARGET}) +srl_add_dependency_catch(${TEST_TARGET}) # copy libraries next to test excutable so they can be found # TODO: do a proper install of the test executable alongside its dependencies diff --git a/src/test/catch/.clang-format b/src/test/catch/.clang-format deleted file mode 100644 index 5e192e0c..00000000 --- a/src/test/catch/.clang-format +++ /dev/null @@ -1 +0,0 @@ -BasedOnStyle: none diff --git a/src/test/catch/catch.hpp b/src/test/catch/catch.hpp deleted file mode 100644 index 303f664f..00000000 --- a/src/test/catch/catch.hpp +++ /dev/null @@ -1,16865 +0,0 @@ -/* - * Catch v2.9.1 - * Generated: 2019-06-17 11:59:24.363643 - * ---------------------------------------------------------- - * This file has been merged from multiple headers. Please don't edit it directly - * Copyright (c) 2019 Two Blue Cubes Ltd. All rights reserved. - * - * Distributed under the Boost Software License, Version 1.0. (See accompanying - * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - */ -#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED -#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED -// start catch.hpp - - -#define CATCH_VERSION_MAJOR 2 -#define CATCH_VERSION_MINOR 9 -#define CATCH_VERSION_PATCH 1 - -#ifdef __clang__ -# pragma clang system_header -#elif defined __GNUC__ -# pragma GCC system_header -#endif - -// start catch_suppress_warnings.h - -#ifdef __clang__ -# ifdef __ICC // icpc defines the __clang__ macro -# pragma warning(push) -# pragma warning(disable: 161 1682) -# else // __ICC -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wpadded" -# pragma clang diagnostic ignored "-Wswitch-enum" -# pragma clang diagnostic ignored "-Wcovered-switch-default" -# endif -#elif defined __GNUC__ - // Because REQUIREs trigger GCC's -Wparentheses, and because still - // supported version of g++ have only buggy support for _Pragmas, - // Wparentheses have to be suppressed globally. -# pragma GCC diagnostic ignored "-Wparentheses" // See #674 for details - -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wunused-variable" -# pragma GCC diagnostic ignored "-Wpadded" -#endif -// end catch_suppress_warnings.h -#if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) -# define CATCH_IMPL -# define CATCH_CONFIG_ALL_PARTS -#endif - -// In the impl file, we want to have access to all parts of the headers -// Can also be used to sanely support PCHs -#if defined(CATCH_CONFIG_ALL_PARTS) -# define CATCH_CONFIG_EXTERNAL_INTERFACES -# if defined(CATCH_CONFIG_DISABLE_MATCHERS) -# undef CATCH_CONFIG_DISABLE_MATCHERS -# endif -# if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) -# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER -# endif -#endif - -#if !defined(CATCH_CONFIG_IMPL_ONLY) -// start catch_platform.h - -#ifdef __APPLE__ -# include -# if TARGET_OS_OSX == 1 -# define CATCH_PLATFORM_MAC -# elif TARGET_OS_IPHONE == 1 -# define CATCH_PLATFORM_IPHONE -# endif - -#elif defined(linux) || defined(__linux) || defined(__linux__) -# define CATCH_PLATFORM_LINUX - -#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || defined(__MINGW32__) -# define CATCH_PLATFORM_WINDOWS -#endif - -// end catch_platform.h - -#ifdef CATCH_IMPL -# ifndef CLARA_CONFIG_MAIN -# define CLARA_CONFIG_MAIN_NOT_DEFINED -# define CLARA_CONFIG_MAIN -# endif -#endif - -// start catch_user_interfaces.h - -namespace Catch { - unsigned int rngSeed(); -} - -// end catch_user_interfaces.h -// start catch_tag_alias_autoregistrar.h - -// start catch_common.h - -// start catch_compiler_capabilities.h - -// Detect a number of compiler features - by compiler -// The following features are defined: -// -// CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported? -// CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported? -// CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported? -// CATCH_CONFIG_DISABLE_EXCEPTIONS : Are exceptions enabled? -// **************** -// Note to maintainers: if new toggles are added please document them -// in configuration.md, too -// **************** - -// In general each macro has a _NO_ form -// (e.g. CATCH_CONFIG_NO_POSIX_SIGNALS) which disables the feature. -// Many features, at point of detection, define an _INTERNAL_ macro, so they -// can be combined, en-mass, with the _NO_ forms later. - -#ifdef __cplusplus - -# if (__cplusplus >= 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L) -# define CATCH_CPP14_OR_GREATER -# endif - -# if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) -# define CATCH_CPP17_OR_GREATER -# endif - -#endif - -#if defined(CATCH_CPP17_OR_GREATER) -# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS -#endif - -#ifdef __clang__ - -# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - _Pragma( "clang diagnostic push" ) \ - _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \ - _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"") -# define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ - _Pragma( "clang diagnostic pop" ) - -# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ - _Pragma( "clang diagnostic push" ) \ - _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) -# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ - _Pragma( "clang diagnostic pop" ) - -# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ - _Pragma( "clang diagnostic push" ) \ - _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" ) -# define CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS \ - _Pragma( "clang diagnostic pop" ) - -# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \ - _Pragma( "clang diagnostic push" ) \ - _Pragma( "clang diagnostic ignored \"-Wgnu-zero-variadic-macro-arguments\"" ) -# define CATCH_INTERNAL_UNSUPPRESS_ZERO_VARIADIC_WARNINGS \ - _Pragma( "clang diagnostic pop" ) - -#endif // __clang__ - -//////////////////////////////////////////////////////////////////////////////// -// Assume that non-Windows platforms support posix signals by default -#if !defined(CATCH_PLATFORM_WINDOWS) - #define CATCH_INTERNAL_CONFIG_POSIX_SIGNALS -#endif - -//////////////////////////////////////////////////////////////////////////////// -// We know some environments not to support full POSIX signals -#if defined(__CYGWIN__) || defined(__QNX__) || defined(__EMSCRIPTEN__) || defined(__DJGPP__) - #define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS -#endif - -#ifdef __OS400__ -# define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS -# define CATCH_CONFIG_COLOUR_NONE -#endif - -//////////////////////////////////////////////////////////////////////////////// -// Android somehow still does not support std::to_string -#if defined(__ANDROID__) -# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING -#endif - -//////////////////////////////////////////////////////////////////////////////// -// Not all Windows environments support SEH properly -#if defined(__MINGW32__) -# define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH -#endif - -//////////////////////////////////////////////////////////////////////////////// -// PS4 -#if defined(__ORBIS__) -# define CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE -#endif - -//////////////////////////////////////////////////////////////////////////////// -// Cygwin -#ifdef __CYGWIN__ - -// Required for some versions of Cygwin to declare gettimeofday -// see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin -# define _BSD_SOURCE -// some versions of cygwin (most) do not support std::to_string. Use the libstd check. -// https://gcc.gnu.org/onlinedocs/gcc-4.8.2/libstdc++/api/a01053_source.html line 2812-2813 -# if !((__cplusplus >= 201103L) && defined(_GLIBCXX_USE_C99) \ - && !defined(_GLIBCXX_HAVE_BROKEN_VSWPRINTF)) - -# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING - -# endif -#endif // __CYGWIN__ - -//////////////////////////////////////////////////////////////////////////////// -// Visual C++ -#ifdef _MSC_VER - -# if _MSC_VER >= 1900 // Visual Studio 2015 or newer -# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS -# endif - -// Universal Windows platform does not support SEH -// Or console colours (or console at all...) -# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) -# define CATCH_CONFIG_COLOUR_NONE -# else -# define CATCH_INTERNAL_CONFIG_WINDOWS_SEH -# endif - -// MSVC traditional preprocessor needs some workaround for __VA_ARGS__ -// _MSVC_TRADITIONAL == 0 means new conformant preprocessor -// _MSVC_TRADITIONAL == 1 means old traditional non-conformant preprocessor -# if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL) -# define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR -# endif -#endif // _MSC_VER - -#if defined(_REENTRANT) || defined(_MSC_VER) -// Enable async processing, as -pthread is specified or no additional linking is required -# define CATCH_INTERNAL_CONFIG_USE_ASYNC -#endif // _MSC_VER - -//////////////////////////////////////////////////////////////////////////////// -// Check if we are compiled with -fno-exceptions or equivalent -#if defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND) -# define CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED -#endif - -//////////////////////////////////////////////////////////////////////////////// -// DJGPP -#ifdef __DJGPP__ -# define CATCH_INTERNAL_CONFIG_NO_WCHAR -#endif // __DJGPP__ - -//////////////////////////////////////////////////////////////////////////////// -// Embarcadero C++Build -#if defined(__BORLANDC__) - #define CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN -#endif - -//////////////////////////////////////////////////////////////////////////////// - -// Use of __COUNTER__ is suppressed during code analysis in -// CLion/AppCode 2017.2.x and former, because __COUNTER__ is not properly -// handled by it. -// Otherwise all supported compilers support COUNTER macro, -// but user still might want to turn it off -#if ( !defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L ) - #define CATCH_INTERNAL_CONFIG_COUNTER -#endif - -//////////////////////////////////////////////////////////////////////////////// -// Check if string_view is available and usable -// The check is split apart to work around v140 (VS2015) preprocessor issue... -#if defined(__has_include) -#if __has_include() && defined(CATCH_CPP17_OR_GREATER) -# define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW -#endif -#endif - -//////////////////////////////////////////////////////////////////////////////// -// Check if optional is available and usable -#if defined(__has_include) -# if __has_include() && defined(CATCH_CPP17_OR_GREATER) -# define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL -# endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) -#endif // __has_include - -//////////////////////////////////////////////////////////////////////////////// -// Check if variant is available and usable -#if defined(__has_include) -# if __has_include() && defined(CATCH_CPP17_OR_GREATER) -# if defined(__clang__) && (__clang_major__ < 8) - // work around clang bug with libstdc++ https://bugs.llvm.org/show_bug.cgi?id=31852 - // fix should be in clang 8, workaround in libstdc++ 8.2 -# include -# if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) -# define CATCH_CONFIG_NO_CPP17_VARIANT -# else -# define CATCH_INTERNAL_CONFIG_CPP17_VARIANT -# endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) -# else -# define CATCH_INTERNAL_CONFIG_CPP17_VARIANT -# endif // defined(__clang__) && (__clang_major__ < 8) -# endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) -#endif // __has_include - -#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER) -# define CATCH_CONFIG_COUNTER -#endif -#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) && !defined(CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH) -# define CATCH_CONFIG_WINDOWS_SEH -#endif -// This is set by default, because we assume that unix compilers are posix-signal-compatible by default. -#if defined(CATCH_INTERNAL_CONFIG_POSIX_SIGNALS) && !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS) -# define CATCH_CONFIG_POSIX_SIGNALS -#endif -// This is set by default, because we assume that compilers with no wchar_t support are just rare exceptions. -#if !defined(CATCH_INTERNAL_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_WCHAR) -# define CATCH_CONFIG_WCHAR -#endif - -#if !defined(CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_CPP11_TO_STRING) -# define CATCH_CONFIG_CPP11_TO_STRING -#endif - -#if defined(CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_NO_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_CPP17_OPTIONAL) -# define CATCH_CONFIG_CPP17_OPTIONAL -#endif - -#if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) -# define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS -#endif - -#if defined(CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_NO_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_CPP17_STRING_VIEW) -# define CATCH_CONFIG_CPP17_STRING_VIEW -#endif - -#if defined(CATCH_INTERNAL_CONFIG_CPP17_VARIANT) && !defined(CATCH_CONFIG_NO_CPP17_VARIANT) && !defined(CATCH_CONFIG_CPP17_VARIANT) -# define CATCH_CONFIG_CPP17_VARIANT -#endif - -#if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) -# define CATCH_INTERNAL_CONFIG_NEW_CAPTURE -#endif - -#if defined(CATCH_INTERNAL_CONFIG_NEW_CAPTURE) && !defined(CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NEW_CAPTURE) -# define CATCH_CONFIG_NEW_CAPTURE -#endif - -#if !defined(CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) -# define CATCH_CONFIG_DISABLE_EXCEPTIONS -#endif - -#if defined(CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_NO_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_POLYFILL_ISNAN) -# define CATCH_CONFIG_POLYFILL_ISNAN -#endif - -#if defined(CATCH_INTERNAL_CONFIG_USE_ASYNC) && !defined(CATCH_CONFIG_NO_USE_ASYNC) && !defined(CATCH_CONFIG_USE_ASYNC) -# define CATCH_CONFIG_USE_ASYNC -#endif - -#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) -# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS -# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS -#endif -#if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS) -# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS -# define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS -#endif -#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS) -# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS -# define CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS -#endif -#if !defined(CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS) -# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS -# define CATCH_INTERNAL_UNSUPPRESS_ZERO_VARIADIC_WARNINGS -#endif - -#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) -#define CATCH_TRY if ((true)) -#define CATCH_CATCH_ALL if ((false)) -#define CATCH_CATCH_ANON(type) if ((false)) -#else -#define CATCH_TRY try -#define CATCH_CATCH_ALL catch (...) -#define CATCH_CATCH_ANON(type) catch (type) -#endif - -#if defined(CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_NO_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) -#define CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR -#endif - -// end catch_compiler_capabilities.h -#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line -#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) -#ifdef CATCH_CONFIG_COUNTER -# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ ) -#else -# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) -#endif - -#include -#include -#include - -// We need a dummy global operator<< so we can bring it into Catch namespace later -struct Catch_global_namespace_dummy {}; -std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy); - -namespace Catch { - - struct CaseSensitive { enum Choice { - Yes, - No - }; }; - - class NonCopyable { - NonCopyable( NonCopyable const& ) = delete; - NonCopyable( NonCopyable && ) = delete; - NonCopyable& operator = ( NonCopyable const& ) = delete; - NonCopyable& operator = ( NonCopyable && ) = delete; - - protected: - NonCopyable(); - virtual ~NonCopyable(); - }; - - struct SourceLineInfo { - - SourceLineInfo() = delete; - SourceLineInfo( char const* _file, std::size_t _line ) noexcept - : file( _file ), - line( _line ) - {} - - SourceLineInfo( SourceLineInfo const& other ) = default; - SourceLineInfo& operator = ( SourceLineInfo const& ) = default; - SourceLineInfo( SourceLineInfo&& ) noexcept = default; - SourceLineInfo& operator = ( SourceLineInfo&& ) noexcept = default; - - bool empty() const noexcept; - bool operator == ( SourceLineInfo const& other ) const noexcept; - bool operator < ( SourceLineInfo const& other ) const noexcept; - - char const* file; - std::size_t line; - }; - - std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); - - // Bring in operator<< from global namespace into Catch namespace - // This is necessary because the overload of operator<< above makes - // lookup stop at namespace Catch - using ::operator<<; - - // Use this in variadic streaming macros to allow - // >> +StreamEndStop - // as well as - // >> stuff +StreamEndStop - struct StreamEndStop { - std::string operator+() const; - }; - template - T const& operator + ( T const& value, StreamEndStop ) { - return value; - } -} - -#define CATCH_INTERNAL_LINEINFO \ - ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) - -// end catch_common.h -namespace Catch { - - struct RegistrarForTagAliases { - RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); - }; - -} // end namespace Catch - -#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \ - CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \ - CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS - -// end catch_tag_alias_autoregistrar.h -// start catch_test_registry.h - -// start catch_interfaces_testcase.h - -#include - -namespace Catch { - - class TestSpec; - - struct ITestInvoker { - virtual void invoke () const = 0; - virtual ~ITestInvoker(); - }; - - class TestCase; - struct IConfig; - - struct ITestCaseRegistry { - virtual ~ITestCaseRegistry(); - virtual std::vector const& getAllTests() const = 0; - virtual std::vector const& getAllTestsSorted( IConfig const& config ) const = 0; - }; - - bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); - std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); - std::vector const& getAllTestCasesSorted( IConfig const& config ); - -} - -// end catch_interfaces_testcase.h -// start catch_stringref.h - -#include -#include -#include - -namespace Catch { - - /// A non-owning string class (similar to the forthcoming std::string_view) - /// Note that, because a StringRef may be a substring of another string, - /// it may not be null terminated. c_str() must return a null terminated - /// string, however, and so the StringRef will internally take ownership - /// (taking a copy), if necessary. In theory this ownership is not externally - /// visible - but it does mean (substring) StringRefs should not be shared between - /// threads. - class StringRef { - public: - using size_type = std::size_t; - - private: - friend struct StringRefTestAccess; - - char const* m_start; - size_type m_size; - - char* m_data = nullptr; - - void takeOwnership(); - - static constexpr char const* const s_empty = ""; - - public: // construction/ assignment - StringRef() noexcept - : StringRef( s_empty, 0 ) - {} - - StringRef( StringRef const& other ) noexcept - : m_start( other.m_start ), - m_size( other.m_size ) - {} - - StringRef( StringRef&& other ) noexcept - : m_start( other.m_start ), - m_size( other.m_size ), - m_data( other.m_data ) - { - other.m_data = nullptr; - } - - StringRef( char const* rawChars ) noexcept; - - StringRef( char const* rawChars, size_type size ) noexcept - : m_start( rawChars ), - m_size( size ) - {} - - StringRef( std::string const& stdString ) noexcept - : m_start( stdString.c_str() ), - m_size( stdString.size() ) - {} - - ~StringRef() noexcept { - delete[] m_data; - } - - auto operator = ( StringRef const &other ) noexcept -> StringRef& { - delete[] m_data; - m_data = nullptr; - m_start = other.m_start; - m_size = other.m_size; - return *this; - } - - operator std::string() const; - - void swap( StringRef& other ) noexcept; - - public: // operators - auto operator == ( StringRef const& other ) const noexcept -> bool; - auto operator != ( StringRef const& other ) const noexcept -> bool; - - auto operator[] ( size_type index ) const noexcept -> char; - - public: // named queries - auto empty() const noexcept -> bool { - return m_size == 0; - } - auto size() const noexcept -> size_type { - return m_size; - } - - auto numberOfCharacters() const noexcept -> size_type; - auto c_str() const -> char const*; - - public: // substrings and searches - auto substr( size_type start, size_type size ) const noexcept -> StringRef; - - // Returns the current start pointer. - // Note that the pointer can change when if the StringRef is a substring - auto currentData() const noexcept -> char const*; - - private: // ownership queries - may not be consistent between calls - auto isOwned() const noexcept -> bool; - auto isSubstring() const noexcept -> bool; - }; - - auto operator + ( StringRef const& lhs, StringRef const& rhs ) -> std::string; - auto operator + ( StringRef const& lhs, char const* rhs ) -> std::string; - auto operator + ( char const* lhs, StringRef const& rhs ) -> std::string; - - auto operator += ( std::string& lhs, StringRef const& sr ) -> std::string&; - auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&; - - inline auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef { - return StringRef( rawChars, size ); - } - -} // namespace Catch - -inline auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef { - return Catch::StringRef( rawChars, size ); -} - -// end catch_stringref.h -// start catch_type_traits.hpp - - -#include - -namespace Catch{ - -#ifdef CATCH_CPP17_OR_GREATER - template - inline constexpr auto is_unique = std::true_type{}; - - template - inline constexpr auto is_unique = std::bool_constant< - (!std::is_same_v && ...) && is_unique - >{}; -#else - -template -struct is_unique : std::true_type{}; - -template -struct is_unique : std::integral_constant -::value - && is_unique::value - && is_unique::value ->{}; - -#endif -} - -// end catch_type_traits.hpp -// start catch_preprocessor.hpp - - -#define CATCH_RECURSION_LEVEL0(...) __VA_ARGS__ -#define CATCH_RECURSION_LEVEL1(...) CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(__VA_ARGS__))) -#define CATCH_RECURSION_LEVEL2(...) CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(__VA_ARGS__))) -#define CATCH_RECURSION_LEVEL3(...) CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(__VA_ARGS__))) -#define CATCH_RECURSION_LEVEL4(...) CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(__VA_ARGS__))) -#define CATCH_RECURSION_LEVEL5(...) CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(__VA_ARGS__))) - -#ifdef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR -#define INTERNAL_CATCH_EXPAND_VARGS(...) __VA_ARGS__ -// MSVC needs more evaluations -#define CATCH_RECURSION_LEVEL6(...) CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(__VA_ARGS__))) -#define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL6(CATCH_RECURSION_LEVEL6(__VA_ARGS__)) -#else -#define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL5(__VA_ARGS__) -#endif - -#define CATCH_REC_END(...) -#define CATCH_REC_OUT - -#define CATCH_EMPTY() -#define CATCH_DEFER(id) id CATCH_EMPTY() - -#define CATCH_REC_GET_END2() 0, CATCH_REC_END -#define CATCH_REC_GET_END1(...) CATCH_REC_GET_END2 -#define CATCH_REC_GET_END(...) CATCH_REC_GET_END1 -#define CATCH_REC_NEXT0(test, next, ...) next CATCH_REC_OUT -#define CATCH_REC_NEXT1(test, next) CATCH_DEFER ( CATCH_REC_NEXT0 ) ( test, next, 0) -#define CATCH_REC_NEXT(test, next) CATCH_REC_NEXT1(CATCH_REC_GET_END test, next) - -#define CATCH_REC_LIST0(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ ) -#define CATCH_REC_LIST1(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0) ) ( f, peek, __VA_ARGS__ ) -#define CATCH_REC_LIST2(f, x, peek, ...) f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ ) - -#define CATCH_REC_LIST0_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ ) -#define CATCH_REC_LIST1_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0_UD) ) ( f, userdata, peek, __VA_ARGS__ ) -#define CATCH_REC_LIST2_UD(f, userdata, x, peek, ...) f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ ) - -// Applies the function macro `f` to each of the remaining parameters, inserts commas between the results, -// and passes userdata as the first parameter to each invocation, -// e.g. CATCH_REC_LIST_UD(f, x, a, b, c) evaluates to f(x, a), f(x, b), f(x, c) -#define CATCH_REC_LIST_UD(f, userdata, ...) CATCH_RECURSE(CATCH_REC_LIST2_UD(f, userdata, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) - -#define CATCH_REC_LIST(f, ...) CATCH_RECURSE(CATCH_REC_LIST2(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) - -#define INTERNAL_CATCH_EXPAND1(param) INTERNAL_CATCH_EXPAND2(param) -#define INTERNAL_CATCH_EXPAND2(...) INTERNAL_CATCH_NO## __VA_ARGS__ -#define INTERNAL_CATCH_DEF(...) INTERNAL_CATCH_DEF __VA_ARGS__ -#define INTERNAL_CATCH_NOINTERNAL_CATCH_DEF -#define INTERNAL_CATCH_STRINGIZE(...) INTERNAL_CATCH_STRINGIZE2(__VA_ARGS__) -#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR -#define INTERNAL_CATCH_STRINGIZE2(...) #__VA_ARGS__ -#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) -#else -// MSVC is adding extra space and needs another indirection to expand INTERNAL_CATCH_NOINTERNAL_CATCH_DEF -#define INTERNAL_CATCH_STRINGIZE2(...) INTERNAL_CATCH_STRINGIZE3(__VA_ARGS__) -#define INTERNAL_CATCH_STRINGIZE3(...) #__VA_ARGS__ -#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) (INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) + 1) -#endif - -#define INTERNAL_CATCH_MAKE_NAMESPACE2(...) ns_##__VA_ARGS__ -#define INTERNAL_CATCH_MAKE_NAMESPACE(name) INTERNAL_CATCH_MAKE_NAMESPACE2(name) - -#define INTERNAL_CATCH_REMOVE_PARENS(...) INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF __VA_ARGS__) - -#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR -#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) decltype(get_wrapper()) -#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__)) -#else -#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) INTERNAL_CATCH_EXPAND_VARGS(decltype(get_wrapper())) -#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__))) -#endif - -#define INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(...)\ - CATCH_REC_LIST(INTERNAL_CATCH_MAKE_TYPE_LIST,__VA_ARGS__) - -#define INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_0) INTERNAL_CATCH_REMOVE_PARENS(_0) -#define INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_0, _1) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_1) -#define INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_0, _1, _2) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_1, _2) -#define INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_0, _1, _2, _3) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_1, _2, _3) -#define INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_0, _1, _2, _3, _4) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_1, _2, _3, _4) -#define INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_0, _1, _2, _3, _4, _5) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_1, _2, _3, _4, _5) -#define INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_0, _1, _2, _3, _4, _5, _6) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_1, _2, _4, _5, _6) -#define INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_0, _1, _2, _3, _4, _5, _6, _7) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_1, _2, _3, _4, _5, _6, _7) -#define INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_1, _2, _3, _4, _5, _6, _7, _8) -#define INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9) -#define INTERNAL_CATCH_REMOVE_PARENS_11_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10) - -#define INTERNAL_CATCH_VA_NARGS_IMPL(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N - -#define INTERNAL_CATCH_TYPE_GEN\ - template struct TypeList {};\ - template\ - constexpr auto get_wrapper() noexcept -> TypeList { return {}; }\ - \ - template class L1, typename...E1, template class L2, typename...E2> \ - constexpr auto append(L1, L2) noexcept -> L1 { return {}; }\ - template< template class L1, typename...E1, template class L2, typename...E2, typename...Rest>\ - constexpr auto append(L1, L2, Rest...) noexcept -> decltype(append(L1{}, Rest{}...)) { return {}; }\ - template< template class L1, typename...E1, typename...Rest>\ - constexpr auto append(L1, TypeList, Rest...) noexcept -> L1 { return {}; }\ - \ - template< template class Container, template class List, typename...elems>\ - constexpr auto rewrap(List) noexcept -> TypeList> { return {}; }\ - template< template class Container, template class List, class...Elems, typename...Elements>\ - constexpr auto rewrap(List,Elements...) noexcept -> decltype(append(TypeList>{}, rewrap(Elements{}...))) { return {}; }\ - \ - template